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