src/Pure/System/cygwin.scala
author wenzelm
Mon Aug 23 16:53:22 2010 +0200 (2010-08-23)
changeset 38639 f642faca303e
parent 37175 be764a7adb10
child 39703 545cc67324d8
permissions -rw-r--r--
main session actor as independent thread, to avoid starvation via regular worker pool;
tuned;
     1 /*  Title:      Pure/System/cygwin.scala
     2     Author:     Makarius
     3 
     4 Accessing the Cygwin installation.
     5 */
     6 
     7 package isabelle
     8 
     9 import java.lang.reflect.Method
    10 import java.io.File
    11 import java.net.URL
    12 import java.awt.Component
    13 
    14 
    15 object Cygwin
    16 {
    17   /* registry access */
    18 
    19   // Some black magic involving private WindowsPreferences from Sun, cf.
    20   // http://www.docjar.com/html/api/java/util/prefs/WindowsPreferences.java.html
    21 
    22   private val WindowsPreferences = Class.forName("java.util.prefs.WindowsPreferences")
    23 
    24   private val HKEY_CURRENT_USER = 0x80000001
    25   private val HKEY_LOCAL_MACHINE = 0x80000002
    26   private val KEY_READ = 0x20019
    27   private val NATIVE_HANDLE = 0
    28   private val ERROR_CODE = 1
    29 
    30   private def C_string(s: String): Array[Byte] =
    31     (s + "\0").getBytes("US-ASCII")
    32 
    33   private def J_string(bs: Array[Byte]): String =
    34     new String(bs, 0, bs.length - 1, "US-ASCII")
    35 
    36   private val INT = Integer.TYPE
    37   private val BYTES = (new Array[Byte](0)).getClass
    38 
    39   private def open_key(handle: Int, subkey: Array[Byte], mask: Int): Array[Int] =
    40   {
    41     val m = WindowsPreferences.getDeclaredMethod("WindowsRegOpenKey", INT, BYTES, INT)
    42     m.setAccessible(true)
    43     m.invoke(null, handle.asInstanceOf[Object], subkey.asInstanceOf[Object],
    44       mask.asInstanceOf[Object]).asInstanceOf[Array[Int]]
    45   }
    46 
    47   private def close_key(handle: Int): Int =
    48   {
    49     val m = WindowsPreferences.getDeclaredMethod("WindowsRegCloseKey", INT)
    50     m.setAccessible(true)
    51     m.invoke(null, handle.asInstanceOf[Object]).asInstanceOf[Int]
    52   }
    53 
    54   private def query(handle: Int, name: Array[Byte]) =
    55   {
    56     val m = WindowsPreferences.getDeclaredMethod("WindowsRegQueryValueEx", INT, BYTES)
    57     m.setAccessible(true)
    58     m.invoke(null, handle.asInstanceOf[Object], name.asInstanceOf[Object]).
    59       asInstanceOf[Array[Byte]]
    60   }
    61 
    62   def query_registry(sys: Boolean, path: String, name: String): Option[String] =
    63   {
    64     val handle = if (sys) HKEY_LOCAL_MACHINE else HKEY_CURRENT_USER
    65     val result = open_key(handle, C_string(path), KEY_READ)
    66     if (result(ERROR_CODE) != 0) None
    67     else {
    68       val res = query(result(NATIVE_HANDLE), C_string(name))
    69       if (res == null) None
    70       else Some(J_string(res))
    71     }
    72   }
    73 
    74   def query_registry(path: String, name: String): Option[String] =
    75     query_registry(false, path, name) orElse
    76       query_registry(true, path, name)
    77 
    78 
    79   /* Cygwin installation */
    80 
    81   private val CYGWIN_SETUP1 = "Software\\Cygwin\\setup"
    82   private val CYGWIN_SETUP2 = "Software\\Wow6432Node\\Cygwin\\setup"
    83 
    84   private def sanity_check(root: File)
    85   {
    86     if (!new File(root, "bin\\bash.exe").isFile ||
    87         !new File(root, "bin\\env.exe").isFile ||
    88         !new File(root, "bin\\tar.exe").isFile)
    89       error("Bad Cygwin installation: " + root.toString)
    90   }
    91 
    92   def check_root(): String =
    93   {
    94     val this_cygwin = java.lang.System.getenv("THIS_CYGWIN")
    95     val root =
    96       if (this_cygwin != null && this_cygwin != "") this_cygwin
    97       else
    98         query_registry(CYGWIN_SETUP1, "rootdir") orElse
    99         query_registry(CYGWIN_SETUP2, "rootdir") getOrElse
   100         error("Failed to determine Cygwin installation -- version 1.7 required")
   101     sanity_check(new File(root))
   102     root
   103   }
   104 
   105   def setup(parent: Component, root: File)
   106   {
   107     if (!root.isDirectory && !root.mkdirs) error("Failed to create root directory: " + root)
   108 
   109     val download = new File(root, "download")
   110     if (!download.mkdir) error("Failed to create download directory: " + download)
   111 
   112     val setup_exe = new File(root, "setup.exe")
   113 
   114     try { Download.file(parent, new URL("http://www.cygwin.com/setup.exe"), setup_exe) }
   115     catch { case _: RuntimeException => error("Failed to download Cygwin setup program") }
   116 
   117     val (_, rc) = Standard_System.raw_exec(root, null, true,
   118         setup_exe.toString, "-R", root.toString, "-l", download.toString,
   119           "-P", "make,perl,python", "-q", "-n")
   120     if (rc != 0) error("Cygwin setup failed!")
   121 
   122     sanity_check(root)
   123   }
   124 }
   125