sbsv2/raptor/util/install-windows/raptorinstallermaker.py
changeset 625 a1925fb7753a
parent 590 360bd6b35136
--- a/sbsv2/raptor/util/install-windows/raptorinstallermaker.py	Wed Jul 28 13:20:46 2010 +0100
+++ b/sbsv2/raptor/util/install-windows/raptorinstallermaker.py	Thu Aug 12 09:00:16 2010 +0100
@@ -1,4 +1,3 @@
-#
 # Copyright (c) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
 # All rights reserved.
 # This component and the accompanying materials are made available
@@ -12,110 +11,23 @@
 # Contributors:
 #
 # Description: 
-#
-#! python
+# Raptor installer maker script - generates a Windows installer for Raptor using
+# the NSIS package in the accompanying directory. Works on Windows and Linux.
 
-# Raptor installer maker!
-
+import optparse
 import os
 import os.path
+import re
+import shutil
+import stat
 import subprocess
-import re
-import optparse
 import sys
 import tempfile
-import shutil
 import unzip
+import zipfile
 
 tempdir = ""
 
-parser = optparse.OptionParser()
-
-parser.add_option("-s", "--sbs-home", dest="sbshome", help="Path to use as SBS_HOME environment variable. If not present the script exits.")
-
-parser.add_option("-w", "--win32-support", dest="win32support", help="Path to Win32 support directory. If not present the script exits.")
-
-parser.add_option("-b", "--bv", dest="bv", help="Path to Binary variation CPP \"root\" directory. Can be a full/relatitve path; prefix with \"WIN32SUPPORT\\\" to be relative to the Win32 support directory. Omitting this value will assume a default to a path inside the Win32 support directory.")
-
-parser.add_option("-c", "--cygwin", dest="cygwin", help="Path to Cygwin \"root\" directory. Can be a full/relatitve path; prefix with \"WIN32SUPPORT\\\" to be relative to the Win32 support directory. Omitting this value will assume a default to a path inside the Win32 support directory.")
-
-parser.add_option("-m", "--mingw", dest="mingw", help="Path to MinGW \"root\" directory. Can be a full/relatitve path; prefix with \"WIN32SUPPORT\\\" to be relative to the Win32 support directory. Omitting this value will assume a default to a path inside the Win32 support directory.")
-
-parser.add_option("-p", "--python", dest="python", help="Path to Python \"root\" directory. Can be a full/relatitve path; prefix with \"WIN32SUPPORT\\\" to be relative to the Win32 support directory. Omitting this value will assume a default to a path inside the Win32 support directory.")
-
-parser.add_option("--prefix", dest="versionprefix", help="A string to use as a prefix to the Raptor version string. This will be present in the Raptor installer's file name, the installer's pages as well as the in output from sbs -v.", type="string", default="")
-
-parser.add_option("--postfix", dest="versionpostfix", help="A string to use as a postfix to the Raptor version string. This will be present in the Raptor installer's file name, the installer's pages as well as the in output from sbs -v.", type="string", default="")
-
-(options, args) = parser.parse_args()
-
-# Required directories inside the win32-support repository
-win32supportdirs = {"bv":"bv", "cygwin":"cygwin", "mingw":"mingw", "python":"python264"}
-
-if options.sbshome == None:
-	print "ERROR: no SBS_HOME passed in. Exiting..."
-	sys.exit(2)
-
-if options.win32support == None:
-	print "ERROR: no win32support directory specified. Unable to proceed. Exiting..."
-	sys.exit(2)
-else:
-	# Check for command line overrides to defaults
-	for directory in win32supportdirs:
-		print "TEST %s" % directory
-		value = getattr(options,directory)
-		print "value =  %s" % str(value)
-		if value != None: # Command line override
-			if value.lower().startswith("win32support"):
-				# Strip off "WIN32SUPPORT\" and join to Win32 support location
-				win32supportdirs[directory] = os.path.join(options.win32support, value[13:]) 
-			else:
-				# Relative to current directory
-				win32supportdirs[directory] = value
-
-		else: # Use default location
-			win32supportdirs[directory] = os.path.join(options.win32support, win32supportdirs[directory])
-	
-	print "\n\nwin32supportdirs = %s\n\n" % win32supportdirs
-
-	# Check that all the specified directories exist and exit if any of them is missing.
-	for directory in win32supportdirs:
-		dir = win32supportdirs[directory]
-		if os.path.isdir(dir):
-			print "Found directory %s" % dir
-		else:
-			print "ERROR: directory %s does not exist. Cannot build installer. Exiting..." % dir
-			sys.exit(2)
-
-def generateinstallerversionheader(sbshome = None):
-	shellenv = os.environ.copy()
-	shellenv["PYTHONPATH"] = os.path.join(sbshome, "python")
-	
-	raptorversioncommand = "python -c \"import raptor_version; print raptor_version.numericversion()\""
-	
-	# Raptor version is obtained from raptor_version module's numericversion function.
-	sbs_version_matcher = re.compile(".*(\d+\.\d+\.\d+).*", re.I)
-	
-	# Create Raptor subprocess
-	versioncommand = subprocess.Popen(raptorversioncommand, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=shellenv)
-	raptorversion = ""
-	# Get all the lines matching the RE
-	for line in versioncommand.stdout.readlines():
-		res = sbs_version_matcher.match(line)
-		if res:
-			raptorversion = res.group(1)
-			print "Successfully determined Raptor version %s" % raptorversion
-
-	versioncommand.wait() # Wait for process to end
-	
-	raptorversion_nsis_header_string = "# Raptor version file\n\n!define RAPTOR_VERSION %s\n" % raptorversion
-	
-	fh = open("raptorversion.nsh", "w")
-	fh.write(raptorversion_nsis_header_string)
-	fh.close()
-	print "Wrote raptorversion.nsh"
-	return 0
-
 def generateinstallerversion(sbshome = None):
 	shellenv = os.environ.copy()
 	shellenv["PYTHONPATH"] = os.path.join(sbshome, "python")
@@ -140,15 +52,25 @@
 	return raptorversion
 	
 def unzipnsis(pathtozip):
-    global tempdir
-    tempdir = tempfile.mkdtemp()
-    un = unzip.unzip()
-    print "Unzipping NSIS to %s..." % tempdir
-    un.extract(pathtozip, tempdir)
-    print "Done."
-    
-    return os.path.join(tempdir, "NSIS", "makensis.exe")
-    
+	global tempdir
+	tempdir = tempfile.mkdtemp()
+	un = unzip.unzip()
+	print "Unzipping NSIS to %s..." % tempdir
+	un.extract(pathtozip, tempdir)
+	print "Done."
+
+	# Ensure the correct executable is called	
+	dotexe=""
+	if "win" in sys.platform.lower():
+		dotexe=".exe"
+	
+	makensispath = os.path.join(tempdir, "NSIS", "makensis" + dotexe)
+	
+	if not "win" in sys.platform.lower():
+		os.chmod(makensispath, stat.S_IRWXU)
+
+	return makensispath
+	
 def runmakensis(nsiscommand):
 	# Create makensis subprocess
 	print "Running NSIS command\n%s" % nsiscommand
@@ -160,23 +82,198 @@
 	global tempdir
 	print "Cleaning up temporary directory %s" % tempdir
 	shutil.rmtree(tempdir,True)
-	try:
-		os.remove("raptorversion.nsh")
-		print "Successfully deleted raptorversion.nsh."
-	except:
-		print "ERROR: failed to remove raptorversion.nsh - remove manually if needed."
 	print "Done."
 
-makensispath = unzipnsis(".\\NSIS.zip")
-# generateinstallerversionheader(options.sbshome)
+def __writeDirTreeToArchive(zip, dirlist, sbshome, win32supportdirs=False):
+	"""Auxilliary function to write all files in each directory trees of dirlist into the
+	open archive "zip" assuming valid sbshome; destination path is tweaked for win32supportdirs, 
+	so set this to true when writing files into $SBS_HOME/win32"""
+	for name in dirlist:
+		files = os.walk(os.path.join(sbshome, name))
+		for dirtuple in files:
+			filenames = dirtuple[2]
+			dirname = dirtuple[0]
+			for file in filenames:
+				# Filter out unwanted files
+				if not file.lower().endswith(".pyc") and \
+				not file.lower().endswith(".project") and \
+				not file.lower().endswith(".cproject") and \
+				not file.lower().endswith(".pydevproject"):
+					origin = os.path.join(dirname, file)
+					
+					# For the win32 support directories, the destination is different
+					if win32supportdirs:
+						destination = os.path.join("sbs", "win32", os.path.basename(name.rstrip(os.sep)), 
+												dirname.replace(name, "").strip(os.sep), file)
+					else:
+						destination = os.path.join("sbs", dirname.rstrip(os.sep).replace(sbshome, "").strip(os.sep), file)
+					
+					print "Compressing", origin, "\tto\t", destination 
+					zip.write(origin, destination)
+
+def writeZip(filename, sbshome, sbsbvdir, sbscygwindir, sbsmingwdir, sbspythondir):
+	"""Write a zip archive with file name "filename" assuming SBS_HOME is sbshome, and  
+	that sbsbvdir, sbscygwindir, sbsmingwdir, sbspythondir are the win32 support directories."""
+	
+	# *Files* in the top level SBS_HOME directory
+	sbshome_files = ["RELEASE-NOTES.html", "license.txt"]
+	
+	# Directories in SBS_HOME
+	sbshome_dirs = ["bin", "examples", "lib", "notes", "python", 
+				"schema", "style", os.sep.join(["win32", "bin"])]
+	
+	# Win32 support directories
+	win32_dirs = [sbsbvdir, sbscygwindir, sbsmingwdir, sbspythondir]
+	
+	try:
+		# Open the zip archive for writing; if a file with the same
+		# name exists, it will be truncated to zero bytes before 
+		# writing commences
+		zip = zipfile.ZipFile(filename, "w", zipfile.ZIP_DEFLATED)
+		
+		# Write the files in the top-level of SBS_HOME into the archive
+		for name in sbshome_files:
+			origin = os.path.join(sbshome, name)
+			destination = os.path.join("sbs", name)
+			print "Compressing", origin, "\tto\t", destination 
+			zip.write(origin, destination)
+		
+		# Write all files in the the directories in the top-level of SBS_HOME into the archive
+		print "Reading the sbs directories..."
+		__writeDirTreeToArchive(zip, sbshome_dirs, sbshome, win32supportdirs=False)
+		print "Writing sbs directories to the archive is complete."
+		
+		# Write all files in the the win32 support directories in the top-level of SBS_HOME into the archive
+		print "Reading the win32 support directories"
+		__writeDirTreeToArchive(zip, win32_dirs, sbshome, win32supportdirs=True)
+		print "Writing win32 support directories to the archive is complete."
+		
+		zip.close()
+		print "Zipoutput: \"" + os.path.join(os.getcwd(), filename) + "\""
+		print "Zip file creation successful."
+	except Exception, e:
+		print "Error: failed to create zip file: %s" % str(e)
+		sys.exit(2)
+
+# Create CLI and parse it
+parser = optparse.OptionParser()
+
+parser.add_option("-s", "--sbs-home", dest="sbshome", help="Path to use as SBS_HOME environment variable. If not present the script exits.")
+
+parser.add_option("-w", "--win32-support", dest="win32support", help="Path to Win32 support directory. If not present the script exits.")
+
+parser.add_option("-b", "--bv", dest="bv", help="Path to Binary variation CPP \"root\" directory. Can be a full/relatitve path; prefix with \"WIN32SUPPORT\\\" to be relative to the Win32 support directory. Omitting this value will assume a default to a path inside the Win32 support directory.")
+
+parser.add_option("-c", "--cygwin", dest="cygwin", help="Path to Cygwin \"root\" directory. Can be a full/relatitve path; prefix with \"WIN32SUPPORT\\\" to be relative to the Win32 support directory. Omitting this value will assume a default to a path inside the Win32 support directory.")
+
+parser.add_option("-m", "--mingw", dest="mingw", help="Path to MinGW \"root\" directory. Can be a full/relatitve path; prefix with \"WIN32SUPPORT\\\" to be relative to the Win32 support directory. Omitting this value will assume a default to a path inside the Win32 support directory.")
+
+parser.add_option("-p", "--python", dest="python", help="Path to Python \"root\" directory. Can be a full/relatitve path; prefix with \"WIN32SUPPORT\\\" to be relative to the Win32 support directory. Omitting this value will assume a default to a path inside the Win32 support directory.")
+
+parser.add_option("--prefix", dest="versionprefix", help="A string to use as a prefix to the Raptor version string. This will be present in the Raptor installer's file name, the installer's pages as well as the in output from sbs -v.", type="string", default="")
+
+parser.add_option("--postfix", dest="versionpostfix", help="A string to use as a postfix to the Raptor version string. This will be present in the Raptor installer's file name, the installer's pages as well as the in output from sbs -v.", type="string", default="")
+
+parser.add_option("--noclean", dest="noclean", help="Do not clean up the temporary directory created during the run.", action="store_true" , default=False)
+
+parser.add_option("--noexe", dest="noexe", help="Do not create a Windows .exe installer of the Raptor installation.", action="store_true" , default=False)
+
+parser.add_option("--nozip", dest="nozip", help="Do not create a zip archive of the Raptor installation.", action="store_true" , default=False)
+
+(options, args) = parser.parse_args()
+
+# Required directories inside the win32-support directory (i.e. the win32-support repository).
+win32supportdirs = {"bv":"bv", "cygwin":"cygwin", "mingw":"mingw", "python":"python264"}
+
+if options.sbshome == None:
+	print "ERROR: no SBS_HOME passed in. Exiting..."
+	sys.exit(2)
+elif not os.path.isdir(options.sbshome):
+	print "ERROR: the specified SBS_HOME directory \"%s\" does not exist. Cannot build installer. Exiting..."
+	sys.exit(2)
+
+if options.win32support == None:
+	print "ERROR: no win32support directory specified. Unable to proceed. Exiting..."
+	sys.exit(2)
+else:
+	# Check for command line overrides to defaults
+	for directory in win32supportdirs:
+		print "Checking for location \"%s\"..." % directory
+		value = getattr(options,directory)
+		print "Directory is %s" % str(value)
+		if value != None: # Command line override
+			if value.lower().startswith("win32support"):
+				# Strip off "WIN32SUPPORT\" and join to Win32 support location
+				win32supportdirs[directory] = os.path.join(options.win32support, value[13:]) 
+			else:
+				# Relative to current directory
+				win32supportdirs[directory] = value
+
+		else: # Use default location
+			win32supportdirs[directory] = os.path.join(options.win32support, win32supportdirs[directory])
+		
+	print "\n\nIdentified win32supportdirs are = %s\n\n" % win32supportdirs
+
+	# Check that all the specified directories exist and exit if any of them is missing.
+	for directory in win32supportdirs:
+		dir = win32supportdirs[directory]
+		if os.path.isdir(dir):
+			print "Found directory %s" % dir
+		else:
+			print "ERROR: directory %s does not exist. Cannot build installer. Exiting..." % dir
+			sys.exit(2)
+
+
 raptorversion = options.versionprefix + generateinstallerversion(options.sbshome) + options.versionpostfix
-nsiscommand = makensispath + " /DRAPTOR_LOCATION=%s /DBV_LOCATION=%s /DCYGWIN_LOCATION=%s /DMINGW_LOCATION=%s /DPYTHON_LOCATION=%s /DRAPTOR_VERSION=%s raptorinstallerscript.nsi" % (options.sbshome, 
-				win32supportdirs["bv"],
+
+print "Using Raptor version %s ..." % raptorversion
+
+if not options.noexe:
+	makensispath = unzipnsis("." + os.sep + "NSIS.zip")
+	if "win" in sys.platform.lower():
+		switch="/"
+	else:
+		switch="-"
+
+	nsiscommand = (makensispath + " " + 
+				switch + "DRAPTOR_LOCATION=%s "  + 
+				switch + "DBV_LOCATION=%s "  + 
+				switch + "DCYGWIN_LOCATION=%s "  + 
+				switch + "DMINGW_LOCATION=%s "  + 
+				switch + "DPYTHON_LOCATION=%s "  +
+				switch + "DRAPTOR_VERSION=%s " + 
+				"%s" ) % \
+			(	options.sbshome, 
+				win32supportdirs["bv"], 
 				win32supportdirs["cygwin"],
 				win32supportdirs["mingw"],
 				win32supportdirs["python"],
-				raptorversion)
-print "nsiscommand = %s" % nsiscommand
-runmakensis(nsiscommand)
-cleanup()
+				raptorversion,
+				os.path.join(options.sbshome, "util", "install-windows", "raptorinstallerscript.nsi")
+			)
+	
+	# On Linux, we need to run makensis via Bash, so that is can find all its
+	# internal libraries and header files etc. Makensis fails unless it 
+	# is executed this way on Linux.
+	if "lin" in sys.platform.lower():
+		nsiscommand = "bash -c \"%s\"" % nsiscommand
+	
+	runmakensis(nsiscommand)
+else:
+	print "Not creating .exe as requested."
 
+# Only clean NSIS installation in the temporary directory if requested
+if not options.noclean:
+	cleanup()
+else:
+	print "Not cleaning makensis in %s" % makensispath
+
+# Only create zip archive if required
+if not options.nozip:
+	filename = "sbs-" + raptorversion + ".zip"
+	writeZip(filename, options.sbshome, win32supportdirs["bv"], win32supportdirs["cygwin"], win32supportdirs["mingw"], win32supportdirs["python"])
+else:
+	print "Not creating zip archive as requested."
+
+print "Finished."
+