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