| author | hoelzl | 
| Thu, 22 Sep 2011 10:02:16 -0400 | |
| changeset 45041 | 0523a6be8ade | 
| parent 43650 | f00da558b78e | 
| child 45667 | 546d78f0d81f | 
| permissions | -rw-r--r-- | 
| 31499 | 1 | /* Title: Pure/System/cygwin.scala | 
| 2 | Author: Makarius | |
| 3 | ||
| 4 | Accessing the Cygwin installation. | |
| 5 | */ | |
| 6 | ||
| 7 | package isabelle | |
| 8 | ||
| 43520 
cec9b95fa35d
explicit import java.lang.System to prevent odd scope problems;
 wenzelm parents: 
41333diff
changeset | 9 | import java.lang.System | 
| 31499 | 10 | import java.lang.reflect.Method | 
| 31826 | 11 | import java.io.File | 
| 34219 | 12 | import java.net.URL | 
| 13 | import java.awt.Component | |
| 31499 | 14 | |
| 15 | ||
| 16 | object Cygwin | |
| 17 | {
 | |
| 18 | /* registry access */ | |
| 19 | ||
| 20 | // Some black magic involving private WindowsPreferences from Sun, cf. | |
| 21 | // http://www.docjar.com/html/api/java/util/prefs/WindowsPreferences.java.html | |
| 22 | ||
| 23 |   private val WindowsPreferences = Class.forName("java.util.prefs.WindowsPreferences")
 | |
| 24 | ||
| 25 | private val HKEY_CURRENT_USER = 0x80000001 | |
| 26 | private val HKEY_LOCAL_MACHINE = 0x80000002 | |
| 27 | private val KEY_READ = 0x20019 | |
| 28 | private val NATIVE_HANDLE = 0 | |
| 29 | private val ERROR_CODE = 1 | |
| 30 | ||
| 31 | private def C_string(s: String): Array[Byte] = | |
| 32 |     (s + "\0").getBytes("US-ASCII")
 | |
| 33 | ||
| 34 | private def J_string(bs: Array[Byte]): String = | |
| 35 | new String(bs, 0, bs.length - 1, "US-ASCII") | |
| 36 | ||
| 37 | private val INT = Integer.TYPE | |
| 38 | private val BYTES = (new Array[Byte](0)).getClass | |
| 39 | ||
| 40 | private def open_key(handle: Int, subkey: Array[Byte], mask: Int): Array[Int] = | |
| 41 |   {
 | |
| 42 |     val m = WindowsPreferences.getDeclaredMethod("WindowsRegOpenKey", INT, BYTES, INT)
 | |
| 43 | m.setAccessible(true) | |
| 44 | m.invoke(null, handle.asInstanceOf[Object], subkey.asInstanceOf[Object], | |
| 45 | mask.asInstanceOf[Object]).asInstanceOf[Array[Int]] | |
| 46 | } | |
| 47 | ||
| 48 | private def close_key(handle: Int): Int = | |
| 49 |   {
 | |
| 50 |     val m = WindowsPreferences.getDeclaredMethod("WindowsRegCloseKey", INT)
 | |
| 51 | m.setAccessible(true) | |
| 52 | m.invoke(null, handle.asInstanceOf[Object]).asInstanceOf[Int] | |
| 53 | } | |
| 54 | ||
| 55 | private def query(handle: Int, name: Array[Byte]) = | |
| 56 |   {
 | |
| 57 |     val m = WindowsPreferences.getDeclaredMethod("WindowsRegQueryValueEx", INT, BYTES)
 | |
| 58 | m.setAccessible(true) | |
| 59 | m.invoke(null, handle.asInstanceOf[Object], name.asInstanceOf[Object]). | |
| 60 | asInstanceOf[Array[Byte]] | |
| 61 | } | |
| 62 | ||
| 63 | def query_registry(sys: Boolean, path: String, name: String): Option[String] = | |
| 64 |   {
 | |
| 65 | val handle = if (sys) HKEY_LOCAL_MACHINE else HKEY_CURRENT_USER | |
| 66 | val result = open_key(handle, C_string(path), KEY_READ) | |
| 67 | if (result(ERROR_CODE) != 0) None | |
| 68 |     else {
 | |
| 69 | val res = query(result(NATIVE_HANDLE), C_string(name)) | |
| 70 | if (res == null) None | |
| 71 | else Some(J_string(res)) | |
| 72 | } | |
| 73 | } | |
| 74 | ||
| 75 | def query_registry(path: String, name: String): Option[String] = | |
| 76 | query_registry(false, path, name) orElse | |
| 77 | query_registry(true, path, name) | |
| 78 | ||
| 79 | ||
| 80 | /* Cygwin installation */ | |
| 81 | ||
| 31826 | 82 | private val CYGWIN_SETUP1 = "Software\\Cygwin\\setup" | 
| 34043 
7129fab1fe4f
more robust Cygwin.config: actually check Wow6432Node, prefer explicit CYGWIN_ROOT in any case;
 wenzelm parents: 
31826diff
changeset | 83 | private val CYGWIN_SETUP2 = "Software\\Wow6432Node\\Cygwin\\setup" | 
| 31499 | 84 | |
| 34220 | 85 | private def sanity_check(root: File) | 
| 86 |   {
 | |
| 87 | if (!new File(root, "bin\\bash.exe").isFile || | |
| 88 | !new File(root, "bin\\env.exe").isFile || | |
| 89 | !new File(root, "bin\\tar.exe").isFile) | |
| 90 |       error("Bad Cygwin installation: " + root.toString)
 | |
| 91 | } | |
| 92 | ||
| 34045 
bc71778a327d
simplified Cygwin setup, assuming 1.7 registry layout (version 1.5 suffers from upcaseenv problem anyway);
 wenzelm parents: 
34043diff
changeset | 93 | def check_root(): String = | 
| 31826 | 94 |   {
 | 
| 43520 
cec9b95fa35d
explicit import java.lang.System to prevent odd scope problems;
 wenzelm parents: 
41333diff
changeset | 95 |     val this_cygwin = System.getenv("THIS_CYGWIN")
 | 
| 34045 
bc71778a327d
simplified Cygwin setup, assuming 1.7 registry layout (version 1.5 suffers from upcaseenv problem anyway);
 wenzelm parents: 
34043diff
changeset | 96 | val root = | 
| 36194 | 97 | if (this_cygwin != null && this_cygwin != "") this_cygwin | 
| 34045 
bc71778a327d
simplified Cygwin setup, assuming 1.7 registry layout (version 1.5 suffers from upcaseenv problem anyway);
 wenzelm parents: 
34043diff
changeset | 98 | else | 
| 
bc71778a327d
simplified Cygwin setup, assuming 1.7 registry layout (version 1.5 suffers from upcaseenv problem anyway);
 wenzelm parents: 
34043diff
changeset | 99 | query_registry(CYGWIN_SETUP1, "rootdir") orElse | 
| 
bc71778a327d
simplified Cygwin setup, assuming 1.7 registry layout (version 1.5 suffers from upcaseenv problem anyway);
 wenzelm parents: 
34043diff
changeset | 100 | query_registry(CYGWIN_SETUP2, "rootdir") getOrElse | 
| 
bc71778a327d
simplified Cygwin setup, assuming 1.7 registry layout (version 1.5 suffers from upcaseenv problem anyway);
 wenzelm parents: 
34043diff
changeset | 101 |         error("Failed to determine Cygwin installation -- version 1.7 required")
 | 
| 34220 | 102 | sanity_check(new File(root)) | 
| 34045 
bc71778a327d
simplified Cygwin setup, assuming 1.7 registry layout (version 1.5 suffers from upcaseenv problem anyway);
 wenzelm parents: 
34043diff
changeset | 103 | root | 
| 31826 | 104 | } | 
| 34203 | 105 | |
| 34219 | 106 | def setup(parent: Component, root: File) | 
| 34203 | 107 |   {
 | 
| 34258 | 108 |     if (!root.isDirectory && !root.mkdirs) error("Failed to create root directory: " + root)
 | 
| 34219 | 109 | |
| 110 | val download = new File(root, "download") | |
| 111 |     if (!download.mkdir) error("Failed to create download directory: " + download)
 | |
| 112 | ||
| 113 | val setup_exe = new File(root, "setup.exe") | |
| 34220 | 114 | |
| 39703 | 115 |     try {
 | 
| 116 |       Download.file(parent, "Downloading", new URL("http://www.cygwin.com/setup.exe"), setup_exe)
 | |
| 117 | } | |
| 43650 | 118 |     catch { case ERROR(_) => error("Failed to download Cygwin setup program") }
 | 
| 34219 | 119 | |
| 34258 | 120 | val (_, rc) = Standard_System.raw_exec(root, null, true, | 
| 121 | setup_exe.toString, "-R", root.toString, "-l", download.toString, | |
| 41333 | 122 | "-P", "libgmp3,make,perl,python", "-q", "-n") | 
| 34219 | 123 |     if (rc != 0) error("Cygwin setup failed!")
 | 
| 34220 | 124 | |
| 125 | sanity_check(root) | |
| 34203 | 126 | } | 
| 31499 | 127 | } | 
| 128 |