[cig-commits] r7418 - in cs/buildbot/trunk/buildbot: . scripts

leif at geodynamics.org leif at geodynamics.org
Sat Jun 23 02:51:49 PDT 2007


Author: leif
Date: 2007-06-23 02:51:49 -0700 (Sat, 23 Jun 2007)
New Revision: 7418

Added:
   cs/buildbot/trunk/buildbot/cig.ico
Modified:
   cs/buildbot/trunk/buildbot/scripts/packager.py
Log:
Mostly-working auto-generated Windows installer.


Added: cs/buildbot/trunk/buildbot/cig.ico
===================================================================
(Binary files differ)


Property changes on: cs/buildbot/trunk/buildbot/cig.ico
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Modified: cs/buildbot/trunk/buildbot/scripts/packager.py
===================================================================
--- cs/buildbot/trunk/buildbot/scripts/packager.py	2007-06-23 07:00:30 UTC (rev 7417)
+++ cs/buildbot/trunk/buildbot/scripts/packager.py	2007-06-23 09:51:49 UTC (rev 7418)
@@ -1,23 +1,112 @@
 
 import os, sys, platform
 from popen2 import Popen4
+from glob import glob
+from os.path import basename, dirname, isabs, isfile
 from buildbot.meta import Config, getPackageAndVersion
 
 
-def pairUp(l):
-    pairs = []
+class PackingList(object):
+    def __init__(self, config, opSys, python):
+        self.all = []
+        self.stripList = []
+        packingList = self.all
+        stripList = self.stripList
+
+        exe = ""
+        if opSys == "win":
+            exe = ".exe"
+            libglob = "bin/*%s*.dll"
+        elif opSys == "linux":
+            libglob = "lib/lib%s*.so*"
+        elif opSys == "darwin":
+            libglob = "lib/lib%s*.dylib"
+        else:
+            sys.exit("unknown OS: " + opSys)
+        self.exe = exe
+
+        self.directories = []
+        for d in config.packaging.directories:
+            packingList.append(d)
+            self.directories.append(d)
+
+        self.programs = []
+        for p in config.packaging.programs:
+            p = "bin/" + p + exe
+            packingList.append(p)
+            stripList.append(p)
+            self.programs.append(p)
+
+        self.scripts = []
+        for s in config.packaging.scripts:
+            s = "bin/" + s
+            packingList.append(s)
+            self.scripts.append(s)
+
+        self.libraries = []
+        for l in config.packaging.libraries:
+            if l == "mpi":
+                l = "mpich"
+            l = libglob % l
+            libs = glob(l)
+            packingList.extend(libs)
+            stripList.extend(libs)
+            self.libraries.extend(libs)
+
+        self.python = []
+        self.misc = []
+        for p in config.packaging.python:
+            p = "lib/" + python + "/site-packages/" + p
+            # Here we use glob expansion b/c eggs make the actual
+            # directory names hard to determine.
+            entries = glob(p)
+            packingList.extend(entries)
+            for e in entries:
+                if isfile(e):
+                    self.misc.append(e)
+                else:
+                    self.directories.append(e)
+
+        cig = [("CIG", "cig", "http://www.geodynamics.org/")]
+        self.urls = cig + tupleUp(config.packaging.urls, 3)
+
+        return
+
+
+    def addFile(self, f):
+        self.misc.append(f)
+
+    def addDirectory(self, d):
+        self.directories.append(d)
+
+
+    def files(self):
+        for f in self.programs:
+            yield f
+        for f in self.scripts:
+            yield f
+        for f in self.libraries:
+            yield f
+        for f in self.misc:
+            yield f
+        return
+
+
+def tupleUp(l, n):
+    tuples = []
     i = iter(l)
     try:
         while True:
-            x = i.next()
-            y = i.next()
-            pairs.append((x, y))
+            t = []
+            for count in xrange(n):
+                t.append(i.next())
+            tuples.append(tuple(t))
     except StopIteration:
         pass
-    return pairs
+    return tuples
 
 
-def spawn(**cmd):
+def spawn(*cmd):
     print ' '.join(cmd)
     child = Popen4(cmd)
 
@@ -44,39 +133,157 @@
     return output[0]
 
 
+def itwindirs(l):
+    for src in l:
+        if isabs(src):
+            dest = src[1:]
+            src = cygpath("-w", src)
+        else:
+            dest = src
+            src = src.replace("/", "\\")
+        dest = "{app}\\" + dest.replace("/", "\\")
+        yield src, dest
+    return
+
+
+def itwinfiles(l):
+    for f in l:
+        d = dirname(f)
+        f = f.replace("/", "\\")
+        d = d.replace("/", "\\")
+        yield f, d
+    return
+
+
+def installCigIcon(prefix):
+    import buildbot
+    cigIco = dirname(buildbot.__file__) + "/cig.ico"
+    os.system("cp %s %s" % (cigIco, prefix))
+    return
+
+
 def generateBashrc(prefix, package, info):
-    bashrc = "." package.lower() + "rc"
+    bashrc = "." + package.lower() + "rc"
     s = open(prefix + "/" + bashrc, "w")
 
-    bashrc = {
+    stuff = {
         "line": "-" * len(info["AppVerName"]),
         }
-    bashrc.update(info)
+    stuff.update(info)
 
     s.write(
-"""
+r"""
 
-export PATH=/bin:$PATH
+export PATH=/usr/bin:/bin:$PATH
 
 echo %(line)s
 echo %(AppVerName)s
 echo %(line)s
 
 PS1='\[\e]0;\w\a\]\n\[\e[32m\]\u@\h \[\e[33m\]\w\[\e[0m\]\n\$ '
-""" % bashrc
+""" % stuff
     )
     
     return bashrc
 
 
-def generateISS(info, config, bashrc, python):
+# Minimal set of Cygwin binaries, as determined while preparing for CFEM 2006.
+def minCygwin(python):
+     l = [
+        "[.exe",
+        "bash.exe",
+        "cat.exe",
+        "cp.exe",
+        "cygiconv-2.dll",
+        "cygintl-3.dll",
+        "cygintl-8.dll",
+        "cygncurses-8.dll",
+        "cygpath.exe",
+        "cygreadline6.dll",
+        # This is given special treatment.
+        #"cygwin1.dll",
+        "echo.exe",
+        "gunzip.exe",
+        "lib" + python + ".dll",
+        "ln.exe",
+        "ls.exe",
+        "pwd.exe",
+        "python.exe",
+        python + ".exe",
+        "rm.exe",
+        "sed.exe",
+        "sh.exe",
+        "tar.exe",
+        "vi",
+        "vim.exe",
+        "which.exe",
+        ]
+     l = ["/bin/" + b for b in l]
+     l.extend([
+         "/lib/lapack/cygblas.dll",
+         "/lib/lapack/cyglapack.dll",
+         ])
+     return l
+
+def installMungedCygwinDLL(prefix):
+    # We don't require that the user has Cygwin installed.  At the
+    # same time, we need to avoid conflicts if they *do* have it
+    # installed.
+
+    # Therefore, we install a munged copy of "cygwin1.dll", performing
+    # the following transformations:
+    #     Cygnus Solutions -> Cigwin Solutions
+    #     cygwin1S4 -> cigwin1S4
+    # These are the registry key name and the shared memory object
+    # name, respectively.
+
+    # N.B.: It is significant that the replacement string is the same
+    # length as the original string.  Otherwise, the DLL would become
+    # corrupted.
+
+    # This gives us the freedom to create our own chrooted environment
+    # using Cygwin's mounts, without messing-up the Cygwin registry on
+    # systems that do have Cygwin installed.  Registry clean-up at
+    # uninstall is also made easy.
+
+    # Ugly, yes; but so much easier than building a custom Cygwin from
+    # source...
+    status = os.system("""sed -b """
+                       """-e "s/Cygnus Solutions/Cigwin Solutions/g" """
+                       """-e s/cygwin1S4/cigwin1S4/g """
+                       """/bin/cygwin1.dll > %s/bin/cygwin1.dll""" % prefix)
+    if status != 0:
+        sys.exit("sed: exit %d" % status)
+    return
+
+
+def installMinimalCygwin(prefix, python, pl):
+    
+    binaries = minCygwin(python)
+    for b in binaries:
+        command = "cp %s %s/bin" % (b, prefix)
+        print command
+        status = os.system(command)
+        if status != 0:
+            sys.exit("cp: exit %d" % status)
+        f = basename(b)
+        pl.addFile("bin/" + f)
+    
+    installMungedCygwinDLL(prefix)
+    pl.addFile("bin/cygwin1.dll")
+    
+    pl.addDirectory("/lib/" + python)
+
+    return
+
+
+def generateISS(info, pl, bashrc, python):
     s = open("buildbot.iss", "w")
 
 
     # [Setup]
     s.write(
-"""
-; Inno Setup Script generated by BuildBot
+"""; Inno Setup Script generated by BuildBot
 
 [Setup]
 AppName=%(AppName)s
@@ -109,16 +316,12 @@
 [Files]
 """
     )
-    for d in config.packaging.directories:
-        s.write("""Source: "%(dir)s\*"; DestDir: "{app}\\%(dir)s"; Flags: ignoreversion recursesubdirs\n""" % {'dir': d})
-    for f in config.packaging.programs:
-        s.write("""Source: "bin\\%s"; DestDir: "{app}\\bin"; Flags: ignoreversion\n""" % f)
-    for f in config.packaging.scripts:
-        s.write("""Source: "bin\\%s"; DestDir: "{app}\\bin"; Flags: ignoreversion\n""" % f)
-    for d in config.packaging.python:
-        s.write("""Source: "lib\\%(python)\\site-packages\\%(dir)s\\*"; DestDir: "{app}\\lib\\%(python)\\site-packages\\%(dir)s"; Flags: ignoreversion recursesubdirs\n""" %
-                {'dir': d, 'python', python})
-    s.write("""Source: "%(bashrc)s"; DestDir: "{app}"; Flags: ignoreversion\n""" % {'bashrc': bashrc})
+    for src, dest in itwindirs(pl.directories):
+        s.write("""Source: "%s\\*"; DestDir: "%s"; Flags: ignoreversion recursesubdirs\n""" % (src, dest))
+    for f, d in itwinfiles(pl.files()):
+        s.write("""Source: "%s"; DestDir: "{app}\\%s"; Flags: ignoreversion\n""" % (f, d))
+    for f in [bashrc, "cig.ico"]:
+        s.write("""Source: "%s"; DestDir: "{app}"; Flags: ignoreversion\n""" % f)
 
 
     # [Dirs]
@@ -172,9 +375,7 @@
 
     # [INI]
     s.write("""[INI]\n""")
-    urls = ["cig", "http://www.geodynamics.org/"] + config.urls
-    urls = pairUp(urls)
-    for filename, url in urls:
+    for name, filename, url in pl.urls:
         s.write("""Filename: "{app}\\%(filename)s.url"; Section: "InternetShortcut"; Key: "URL"; String: "%(url)s"\n""" %
                 {'filename': filename, 'url': url})
 
@@ -187,19 +388,35 @@
 Name: "{userdesktop}\\%(AppName)s"; Filename: "{app}\\bin\\bash.exe"; Tasks: desktopicon; Parameters: "--init-file %(bashrc)s -i"; WorkingDir: "{app}"; IconFilename: "{app}\\cig.ico"
 """ % {'AppName': info['AppName'], 'bashrc': bashrc}
     )
-    for filename, url in urls:
-        s.write("""Name: "{group}\CIG"; Filename: "{app}\cig.url"\n""" % (displayName, filename))
+    for name, filename, url in pl.urls:
+        s.write("""Name: "{group}\\%s"; Filename: "{app}\\%s.url"\n""" % (name, filename))
+    s.write("""Name: "{group}\Uninstall %(AppName)s"; Filename: "{uninstallexe}"\n""" % info)
+
+
+    # [Run]
     s.write(
 """
-Name: "{group}\Uninstall %(AppName)s"; Filename: "{uninstallexe}"
+[Run]
+Filename: "{app}\\bin\\bash.exe"; Description: "Launch %(AppName)s"; Parameters: "--init-file %(bashrc)s -i"; WorkingDir: "{app}"; Flags: nowait postinstall skipifsilent
 
-""" % info
+""" % {'AppName': info['AppName'], 'bashrc': bashrc}
     )
 
+
+    # [UninstallDelete]
+    s.write("""[UninstallDelete]\n""")
+    for name, filename, url in pl.urls:
+        s.write("""Type: files; Name: "{app}\%s.url"\n""" % filename)
+    for filename in [".bash_history"]:
+        s.write("""Type: files; Name: "{app}\%s"\n""" % filename)
+
+    s.write("\n; end of file\n")
+
     return
 
     
-def createWindowsInstaller(python, prefix, package, version, config):
+def createWindowsInstaller(python, prefix, package, version, pl,
+                           installer):
 
     sourceDir = cygpath("-w", prefix)
     
@@ -209,13 +426,66 @@
         "SourceDir": sourceDir,
         }
 
+    installMinimalCygwin(prefix, python, pl)
+
+    installCigIcon(prefix)
     bashrc = generateBashrc(prefix, package, info)
 
-    generateISS(python, info, config, bashrc, python)
+    generateISS(info, pl, bashrc, python)
 
+    os.system("unix2dos buildbot.iss")
+    
+    status = os.system("iscc buildbot.iss")
+    if status != 0:
+        sys.exit("iscc: exit %d" % status)
+
+    status = os.system("mv %s/Output/setup.exe %s.exe" % (prefix, installer))
+    if status != 0:
+        sys.exit("mv: exit %d" % status)
+
     return
 
 
+def stripBinaries(pl, opSys):
+    strip = "strip"
+    if opSys == "darwin":
+        # Just plain "strip" renders our Python interpreter unusable
+        # by extension modules.
+        strip = "strip -S"
+    status = os.system(strip + " " + " ".join(pl.stripList))
+    if status != 0:
+        sys.exit("strip: exit %d" % status)
+    return
+
+
+def rewriteScripts(pl, prefix, opSys):
+    # Tweak the shebang line of scripts so they are relative instead
+    # of absolute.
+    
+    if opSys == "win":
+        # chrooted environment
+        relative = "#!/bin/%s"
+    else:
+        relative = "#!/usr/bin/env %s"
+    absolute = "#!" + prefix + "/bin/"
+    
+    for script in pl.scripts:
+        s = open(script, "r")
+        lines = s.readlines()
+        s.close()
+        shebang = lines[0]
+        if shebang.startswith(absolute):
+            interpreter = shebang[len(absolute):]
+            shebang = relative % interpreter
+            s = open(script, "w")
+            s.write(shebang)
+            for line in lines[1:]:
+                s.write(line)
+            s.close()
+            
+    return
+
+
 def mkpkg():
     buildnumber = int(sys.argv[1])
     revision = sys.argv[2]
@@ -224,6 +494,8 @@
     else:
         revision = "forced"
     opSys = platform.system().lower()
+    if opSys.startswith("cygwin"):
+        opSys = "win"
     arch = opSys + "-" + platform.machine()
     tag = "b%04d-%s" % (buildnumber, revision)
     python = os.environ['PYTHON']
@@ -239,29 +511,6 @@
     if config.packaging is None:
         sys.exit('no packaging configuation; try "svn propedit buildbot:config ."')
 
-    packingList = []
-    stripList = []
-
-    for d in config.packaging.directories:
-        packingList.append(d)
-    
-    for p in config.packaging.programs:
-        p = "bin/" + p
-        packingList.append(p)
-        stripList.append(p)
-
-    for s in config.packaging.scripts:
-        packingList.append("bin/" + s)
-
-    for l in config.packaging.libraries:
-        l = "lib/" + l
-        packingList.append(l)
-        stripList.append(l)
-
-    for p in config.packaging.python:
-        p = "lib/" + python + "/site-packages/" + p
-        packingList.append(p)
-
     if opSys == "linux":
         # We only need one of these; do it on Linux only.
         archive = distdir + ".tar.gz"
@@ -269,29 +518,25 @@
         os.system("make dist")
         os.system("mv " + archive + " " + taggedArchive)
 
-    print "strip", stripList
-    print "pack", packingList
-
     workdir = os.getcwd()
     os.chdir(prefix)
 
-    strip = "strip"
-    if opSys == "darwin":
-        # Just plain "strip" renders our Python interpreter unusable
-        # by extension modules.
-        strip = "strip -S"
-    status = os.system(strip + " " + " ".join(stripList))
-    if status != 0:
-        sys.exit("strip: exit %d" % status)
+    pl = PackingList(config, opSys, python)
 
+    print "strip", pl.stripList
+    print "pack", pl.all
+
+    stripBinaries(pl, opSys)
+    rewriteScripts(pl, prefix, opSys)
+
     os.chdir(workdir)
 
+    distdir_arch = distdir + "-" + arch
     if opSys == "darwin" or opSys == "linux":
         # No .dmg on Mac for now.
-        distdir_arch = distdir + "-" + arch
         os.system("rm " + distdir_arch)
         os.system("ln -s " + prefix + " " + distdir_arch)
-        packingList = [distdir_arch + "/" + m for m in packingList]
+        packingList = [distdir_arch + "/" + m for m in pl.all]
         archive = distdir_arch + ".tar.gz"
         taggedArchive = tag + "-" + archive
         os.system("tar cvzf " + archive + " " + " ".join(packingList))
@@ -299,8 +544,9 @@
             sys.exit("tar: exit %d" % status)
 
         os.system("mv " + archive + " " + taggedArchive)
-    elif opSys == "cygwin":
-        createWindowsInstaller(python, prefix, package, version, config)
+    elif opSys == "win":
+        createWindowsInstaller(python, prefix, package, version, pl,
+                               tag + "-" + distdir_arch)
     else:
         sys.exit("unknown OS: " + opSys)
 
@@ -308,4 +554,4 @@
 
 
 if __name__ == "__main__":
-    mkpkg("0001", "1234")
+    mkpkg()



More information about the cig-commits mailing list