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