From b99ccda839d9321cb383dc6db6a0a059a5a83a4f Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Sat, 12 Jan 2013 14:57:35 +0000 Subject: [PATCH] * ./bootstrap: - New: Complete rewrite of builCoriolis.py & merge with easyChams to provide a graphical interface. Asides to the GUI, when run in graphic mode all settings are kept from run to run. Meaning that once the initial setup is done, a user may completly forget where things are... The new tool is named for 'Coriolis & Chams Builder'. The Builder is now a module, that is split into multiples files. The old buildCoriolis.py is kept for the time beeing to ensure a smooth transition. --- bootstrap/CMakeLists.txt | 7 +- bootstrap/build.conf | 1 + bootstrap/buildCoriolis.py | 827 +-------------------------- bootstrap/builder/AboutWidget.py | 99 ++++ bootstrap/builder/Builder.py | 543 ++++++++++++++++++ bootstrap/builder/BuilderGui.py | 76 +++ bootstrap/builder/CompileWidget.py | 209 +++++++ bootstrap/builder/Configuration.py | 293 ++++++++++ bootstrap/builder/ConfigureWidget.py | 195 +++++++ bootstrap/builder/Highlighter.py | 80 +++ bootstrap/builder/OptionsWidget.py | 179 ++++++ bootstrap/builder/Project.py | 51 ++ bootstrap/builder/ProjectWidgets.py | 76 +++ bootstrap/builder/__init__.py | 64 +++ bootstrap/ccb.py | 256 +++++++++ 15 files changed, 2131 insertions(+), 825 deletions(-) create mode 100644 bootstrap/builder/AboutWidget.py create mode 100644 bootstrap/builder/Builder.py create mode 100644 bootstrap/builder/BuilderGui.py create mode 100644 bootstrap/builder/CompileWidget.py create mode 100644 bootstrap/builder/Configuration.py create mode 100644 bootstrap/builder/ConfigureWidget.py create mode 100644 bootstrap/builder/Highlighter.py create mode 100644 bootstrap/builder/OptionsWidget.py create mode 100644 bootstrap/builder/Project.py create mode 100644 bootstrap/builder/ProjectWidgets.py create mode 100644 bootstrap/builder/__init__.py create mode 100755 bootstrap/ccb.py diff --git a/bootstrap/CMakeLists.txt b/bootstrap/CMakeLists.txt index 39c19761..f690b646 100644 --- a/bootstrap/CMakeLists.txt +++ b/bootstrap/CMakeLists.txt @@ -7,6 +7,7 @@ list(INSERT CMAKE_MODULE_PATH 0 "${Bootstrap_SOURCE_DIR}/cmake_modules/") find_package(Bootstrap REQUIRED) + find_package(PythonSitePackages REQUIRED) print_cmake_module_path() setup_sysconfdir("${CMAKE_INSTALL_PREFIX}") @@ -17,8 +18,12 @@ OWNER_READ GROUP_READ WORLD_READ OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE) - install(FILES buildCoriolis.py + install(DIRECTORY builder + DESTINATION ${PYTHON_SITE_PACKAGES} ) + + install(FILES ccb.py DESTINATION bin + RENAME ccb PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE) diff --git a/bootstrap/build.conf b/bootstrap/build.conf index 82fa9fad..67749f1d 100644 --- a/bootstrap/build.conf +++ b/bootstrap/build.conf @@ -29,6 +29,7 @@ projects = [ { 'name' : 'bootstrap' , "equinox" , "solstice" , "unicorn" + , "testbench" #, "ispd" , "cumulus" , "stratus1" diff --git a/bootstrap/buildCoriolis.py b/bootstrap/buildCoriolis.py index f628cea1..c5fab940 100755 --- a/bootstrap/buildCoriolis.py +++ b/bootstrap/buildCoriolis.py @@ -1,831 +1,10 @@ #!/usr/bin/env python import sys -import re -import os import os.path -import datetime -import socket -import subprocess import optparse - - -class ErrorMessage ( Exception ): - - def __init__ ( self, code, *arguments ): - self._code = code - self._errors = [ 'Malformed call to ErrorMessage()' - , '%s' % str(arguments) ] - - text = None - if len(arguments) == 1: - if isinstance(arguments[0],Exception): text = str(arguments[0]).split('\n') - else: - self._errors = arguments[0] - elif len(arguments) > 1: - text = list(arguments) - - if text: - self._errors = [] - while len(text[0]) == 0: del text[0] - - lstrip = 0 - if text[0].startswith('[ERROR]'): lstrip = 8 - - for line in text: - if line[0:lstrip ] == ' '*lstrip or \ - line[0:lstrip-1] == '[ERROR]': - self._errors += [ line[lstrip:] ] - else: - self._errors += [ line.lstrip() ] - return - - def __str__ ( self ): - if not isinstance(self._errors,list): - return "[ERROR] %s" % self._errors - - formatted = "\n" - for i in range(len(self._errors)): - if i == 0: formatted += "[ERROR] %s" % self._errors[i] - else: formatted += " %s" % self._errors[i] - if i+1 < len(self._errors): formatted += "\n" - return formatted - - def addMessage ( self, message ): - if not isinstance(self._errors,list): - self._errors = [ self._errors ] - if isinstance(message,list): - for line in message: - self._errors += [ line ] - else: - self._errors += [ message ] - return - - def terminate ( self ): - print self - sys.exit(self._code) - - def _getCode ( self ): return self._code - - code = property(_getCode) - - - -class Project: - - def __init__ ( self, name, tools, repository ): - self._name = name - self._tools = tools - self._repository = repository - self._actives = [] - return - - def getName ( self ): return self._name - def getTools ( self ): return self._tools - def getRepository ( self ): return self._repository - def getActives ( self ): return self._actives - def hasTool ( self, tool ): return tool in self._tools - - def desactivate ( self ): - self._active = [] - return - - def activateAll ( self ): - self._actives = self._tools - return - - def activate ( self, tools ): - # Build the ordered list. - for tool in self._tools: - if (tool in tools) and not (tool in self._actives): - self._actives += [ tool ] - # Find the tools not part of the project. - rejecteds = [] - for tool in tools: - if not (tool in self._tools) and (not tool in rejecteds): - rejecteds += [ tool ] - return rejecteds - - - -class ProjectBuilder: - - def __init__ ( self ): - self._projects = [] - self._standalones = [] - self._svnTag = "x" - self._svnMethod = None - self._projectDir = 'coriolis-2.x' - self._rootDir = os.path.join ( os.environ["HOME"], self._projectDir ) - self._packageName = None - self._packageVersion = None - self._packageExcludes = [] - self._packageProject = [] - - self._quiet = False - self._buildMode = "Release" - self._rmBuild = False - self._doBuild = True - self._noCache = False - self._enableShared = "ON" - self._enableDoc = "OFF" - self._checkDatabase = "OFF" - self._checkDeterminism = "OFF" - self._verboseMakefile = "OFF" - self._libMode = "Shared" - self._makeArguments = [] - self._environment = os.environ - - self._guessOs () - self._updateSecondary () - return - - - def __setattr__ ( self, attribute, value ): - if attribute[0] == "_": - self.__dict__[attribute] = value - return - - if attribute == "svnTag": self._svnTag = value - elif attribute == "svnMethod": self._svnMethod = value - elif attribute == "projectDir": self._projectDir = value - elif attribute == "rootDir": self._rootDir = os.path.expanduser(value) - elif attribute == "packageName": self._packageName = value - elif attribute == "packageVersion": self._packageVersion = value - elif attribute == "quiet": self._quiet = value - elif attribute == "buildMode": self._buildMode = value - elif attribute == "rmBuild": self._rmBuild = value - elif attribute == "doBuild": self._doBuild = value - elif attribute == "noCache": self._noCache = value - elif attribute == "enableShared": self._enableShared = value - elif attribute == "enableDoc": self._enableDoc = value - elif attribute == "enableShared": self._enableShared = value - elif attribute == "checkDatabase": self._checkDatabase = value - elif attribute == "checkDeterminism": self._checkDeterminism = value - elif attribute == "verboseMakefile": self._verboseMakefile = value - elif attribute == "makeArguments": self._makeArguments = value.split () - elif attribute == "libMode": self._libMode = value - self._updateSecondary () - return - - - def _updateSecondary ( self ): - #self._rootDir = os.path.join ( os.environ["HOME"], self._projectDir ) - self._rpmbuildDir = os.path.join ( self._rootDir , "rpmbuild" ) - self._debbuildDir = os.path.join ( self._rootDir , "debbuild" ) - self._tmppathDir = os.path.join ( self._rpmbuildDir, "tmp" ) - self._tarballDir = os.path.join ( self._rootDir , "tarball" ) - self._archiveDir = os.path.join ( self._tarballDir , "%s-%s.%s" % (self._packageName - ,self._packageVersion - ,self._svnTag) ) - self._sourceDir = os.path.join ( self._rootDir , "src" ) - self._osDir = os.path.join ( self._rootDir - , self._osType - , "%s.%s" % (self._buildMode,self._libMode) ) - self._buildDir = os.path.join ( self._osDir, "build" ) - self._installDir = os.path.join ( self._osDir, "install" ) - - if self._enableShared == "ON": self._libMode = "Shared" - else: self._libMode = "Static" - - self._specFileIn = os.path.join ( self._sourceDir, "bootstrap", "%s.spec.in"%self._packageName ) - self._specFile = os.path.join ( self._sourceDir, "bootstrap", "%s.spec" %self._packageName ) - self._debianDir = os.path.join ( self._sourceDir, "bootstrap", "debian" ) - self._debChangelogIn = os.path.join ( self._debianDir, "changelog.in" ) - self._debChangelog = os.path.join ( self._debianDir, "changelog" ) - self._sourceTarBz2 = "%s-%s.%s.tar.bz2" % (self._packageName,self._packageVersion,self._svnTag) - self._binaryTarBz2 = "%s-binary-%s.%s-1.slsoc6.tar.bz2" % (self._packageName,self._packageVersion,self._svnTag) - self._distribPatch = os.path.join ( self._sourceDir, "bootstrap", "%s-for-distribution.patch"%self._packageName ) - return - - - def _guessOs ( self ): - self._libSuffix = None - self._osSlsoc6x_64 = re.compile (".*Linux.*el6.*x86_64.*") - self._osSlsoc6x = re.compile (".*Linux.*el6.*") - self._osSLSoC5x_64 = re.compile (".*Linux.*el5.*x86_64.*") - self._osSLSoC5x = re.compile (".*Linux.*(el5|2.6.23.13.*SoC).*") - self._osLinux_64 = re.compile (".*Linux.*x86_64.*") - self._osLinux = re.compile (".*Linux.*") - self._osFreeBSD8x_amd64 = re.compile (".*FreeBSD 8.*amd64.*") - self._osFreeBSD8x_64 = re.compile (".*FreeBSD 8.*x86_64.*") - self._osFreeBSD8x = re.compile (".*FreeBSD 8.*") - self._osDarwin = re.compile (".*Darwin.*") - - uname = subprocess.Popen ( ["uname", "-srm"], stdout=subprocess.PIPE ) - lines = uname.stdout.readlines() - - if self._osSlsoc6x_64.match(lines[0]): - self._osType = "Linux.slsoc6x_64" - self._libSuffix = "64" - elif self._osSlsoc6x .match(lines[0]): self._osType = "Linux.slsoc6x" - elif self._osSLSoC5x_64.match(lines[0]): - self._osType = "Linux.SLSoC5x_64" - self._libSuffix = "64" - elif self._osSLSoC5x .match(lines[0]): self._osType = "Linux.SLSoC5x" - elif self._osLinux_64 .match(lines[0]): - self._osType = "Linux.x86_64" - self._libSuffix = "64" - elif self._osLinux .match(lines[0]): self._osType = "Linux.i386" - elif self._osDarwin .match(lines[0]): self._osType = "Darwin" - elif self._osFreeBSD8x_amd64.match(lines[0]): - self._osType = "FreeBSD.8x.amd64" - self._libSuffix = "64" - elif self._osFreeBSD8x_64.match(lines[0]): - self._osType = "FreeBSD.8x.x86_64" - self._libSuffix = "64" - elif self._osFreeBSD8x .match(lines[0]): self._osType = "FreeBSD.8x.i386" - else: - uname = subprocess.Popen ( ["uname", "-sr"], stdout=subprocess.PIPE ) - self._osType = uname.stdout.readlines()[0][:-1] - - print "[WARNING] Unrecognized OS: \"%s\"." % lines[0][:-1] - print " (using: \"%s\")" % self._osType - - return - - - def _guessSvnTag ( self, project ): - revisionPattern = re.compile ( r"^Revision:\s*(?P\d+)" ) - projectSvnDir = os.path.join ( self._svnMethod+project.getRepository() ) - - command = [ "svn", "info", projectSvnDir ] - svnInfo = subprocess.Popen ( command, stdout=subprocess.PIPE ) - - for line in svnInfo.stdout.readlines(): - m = revisionPattern.match ( line ) - if m: - self._svnTag = m.group("revision") - print "Latest revision of project %s is %s." % (project.getName(),self._svnTag) - self._updateSecondary () - return - - print "[WARNING] Cannot guess revision for project \"%s\"." % project.getName() - print " (using: \"x\")" - return - - - def _configure ( self, fileIn, file ): - fdFileIn = open ( fileIn, "r" ) - fdFile = open ( file , "w" ) - - for line in fdFileIn.readlines(): - stable = False - substituted0 = line - - while not stable: - substituted1 = re.sub ( r"@svntag@" , self._svnTag , substituted0 ) - substituted1 = re.sub ( r"@coriolisTop@", "/opt/coriolis2", substituted1 ) - if substituted0 == substituted1: stable = True - else: substituted0 = substituted1 - - fdFile.write ( substituted0 ) - - fdFileIn.close () - fdFile.close () - return - - - def _doSpec ( self ): - self._configure ( self._specFileIn, self._specFile ) - return - - - def _doDebChangelog ( self ): - self._configure ( self._debChangelogIn, self._debChangelog ) - return - - - def _execute ( self, command, error ): - sys.stdout.flush () - sys.stderr.flush () - child = subprocess.Popen ( command, env=self._environment, stdout=None ) - (pid,status) = os.waitpid ( child.pid, 0 ) - status >>= 8 - if status != 0: - ErrorMessage( status, "%s (status:%d)."%(error,status) ).terminate() - return - - - def _enableTool ( self, tool ): - return - - - def _build ( self, tool ): - toolSourceDir = os.path.join ( self._sourceDir, tool ) - toolBuildDir = os.path.join ( self._buildDir , tool ) - # Supplied directly in the CMakeLists.txt. - #cmakeModules = os.path.join ( self._installDir, "share", "cmake", "Modules" ) - - if not os.path.isdir(toolSourceDir): - print ErrorMessage( 0, "Missing tool source directory: \"%s\" (skipped)."%toolSourceDir ) - return - - if self._rmBuild: - print "Removing tool build directory: \"%s\"." % toolBuildDir - command = [ "/bin/rm", "-rf", toolBuildDir ] - self._execute ( command, "Removing tool build directory" ) - - if not os.path.isdir(toolBuildDir): - print "Creating tool build directory: \"%s\"." % toolBuildDir - os.makedirs ( toolBuildDir ) - os.chdir ( toolBuildDir ) - - command = ["cmake", "-D", "CMAKE_BUILD_TYPE:STRING=%s" % self._buildMode - , "-D", "BUILD_SHARED_LIBS:STRING=%s" % self._enableShared - #, "-D", "CMAKE_MODULE_PATH:STRING=%s" % cmakeModules - , toolSourceDir ] - self._execute ( command, "First CMake failed" ) - - os.chdir ( toolBuildDir ) - if self._noCache: - cmakeCache = os.path.join(toolBuildDir,"CMakeCache.txt") - if os.path.isfile ( cmakeCache ): os.unlink ( cmakeCache ) - - command = ["cmake", "-D", "CMAKE_BUILD_TYPE:STRING=%s" % self._buildMode - , "-D", "BUILD_SHARED_LIBS:STRING=%s" % self._enableShared - , "-D", "BUILD_DOC:STRING=%s" % self._enableDoc - , "-D", "CHECK_DATABASE:STRING=%s" % self._checkDatabase - , "-D", "CHECK_DETERMINISM:STRING=%s" % self._checkDeterminism - , "-D", "CMAKE_VERBOSE_MAKEFILE:STRING=%s" % self._verboseMakefile - , "-D", "CMAKE_INSTALL_PREFIX:STRING=%s" % self._installDir - ] - if self._libSuffix: - command += [ "-D", "LIB_SUFFIX:STRING=%s" % self._libSuffix ] - command += [ toolSourceDir ] - self._execute ( command, "Second CMake failed" ) - - if self._doBuild: - command = [ "make" ] - #command += [ "DESTDIR=%s" % self._installDir ] - if self._enableDoc == "ON": - #if tool == "crlcore" or tool == "stratus1": - if tool == "stratus1": - command += [ "dvi", "safepdf", "html" ] - command += self._makeArguments - print "Make command:", command - sys.stdout.flush () - self._execute ( command, "Build failed" ) - return - - - def _svnStatus ( self, tool ): - toolSourceDir = os.path.join ( self._sourceDir , tool ) - if not os.path.isdir(toolSourceDir): - if not self._quiet: - print ErrorMessage( 0, "Missing tool source directory: \"%s\" (skipped)."%toolSourceDir ) - return - os.chdir ( toolSourceDir ) - - print "Checking SVN status of tool: ", tool - command = [ "svn", "status", "-u", "-q" ] - self._execute ( command, "svn status -u -q" ) - print - return - - - def _svnDiff ( self, tool ): - toolSourceDir = os.path.join ( self._sourceDir , tool ) - if not os.path.isdir(toolSourceDir): - if not self._quiet: - print ErrorMessage( 0, "Missing tool source directory: \"%s\" (skipped)."%toolSourceDir ) - return - os.chdir ( toolSourceDir ) - - print "Doing a SVN diff of tool: ", tool - command = [ "svn", "diff" ] - if self._svnTag != "x": - command += [ "--revision", self._svnTag ] - self._execute ( command, "svn diff %s" % tool ) - print - return - - - def _svnUpdate ( self, tool ): - toolSourceDir = os.path.join ( self._sourceDir , tool ) - if not os.path.isdir(toolSourceDir): - if not self._quiet: - print ErrorMessage( 0, "Missing tool source directory: \"%s\" (skipped)."%toolSourceDir) - return - os.chdir ( toolSourceDir ) - - print "Doing a SVN update of tool: ", tool - command = [ "svn", "update" ] - self._execute ( command, "svn update" ) - print - return - - - def _svnCheckout ( self, tool ): - project = self.getToolProject ( tool ) - if not project: - print ErrorMessage( 0, "Tool \"%s\" is not part of any project."%tool - ,"Cannot guess the SVN repository." ) - return - if not project.getRepository (): - print ErrorMessage( 0, "Project \"%s\" isn't associated to a repository."%project.getName() ) - return - - if not os.path.isdir(self._sourceDir): - print ErrorMessage( 0, "Source directory <%s> doesn't exists. Creating."%self._sourceDir ) - os.makedirs( self._sourceDir ) - - toolSvnTrunkDir = os.path.join ( self._svnMethod+project.getRepository(), tool, "trunk" ) - os.chdir ( self._sourceDir ) - - print "Doing a SVN checkout of tool: ", tool - command = [ "svn", "co", toolSvnTrunkDir, tool ] - if self._svnTag != "x": - command += [ "--revision", self._svnTag ] - self._execute ( command, "svn checkout %s" % tool ) - print - return - - - def _svnExport ( self, tool ): - project = self.getToolProject ( tool ) - if not project: - print ErrorMessage( 0, "Tool \"%s\" is not part of any project."%tool - , "Cannot guess the SVN repository.") - return - if not project.getRepository (): - print ErrorMessage( 0, "Project \"%s\" isn't associated to a repository."%project.getName() ) - return - - toolSvnTrunkDir = os.path.join ( self._svnMethod+project.getRepository(), tool, "trunk" ) - - if not os.path.isdir ( self._archiveDir ): - os.mkdir ( self._archiveDir ) - os.chdir ( self._archiveDir ) - - toolExportDir = os.path.join ( self._archiveDir, tool ) - if os.path.isdir ( toolExportDir ): - print "Removing tool export (tarball) directory: \"%s\"." % toolExportDir - command = [ "/bin/rm", "-r", toolExportDir ] - self._execute ( command, "Removing tool export (tarball) directory" ) - - print "Doing a SVN export of tool: ", tool - command = [ "svn", "export", toolSvnTrunkDir, toolExportDir ] - if self._svnTag != "x": - command += [ "--revision", self._svnTag ] - self._execute ( command, "svn export %s" % toolExportDir ) - print - return - - - def getProject ( self, name ): - for project in self._projects: - if project.getName() == name: - return project - return None - - - def getToolProject ( self, name ): - for project in self._projects: - if project.hasTool(name): - return project - return None - - - def register ( self, project ): - for registered in self._projects: - if registered.getName() == project.getName(): - print ErrorMessage( 0, "Project \"%s\" is already registered (ignored)." ) - return - self._projects += [ project ] - return - - - def _setEnvironment ( self, systemVariable, userVariable ): - if not self._environment.has_key(systemVariable) or self._environment[systemVariable] == "": - if not self._environment.has_key(userVariable) or self._environment[userVariable] == "" : - self._environment[ systemVariable ] = self._installDir - print "[WARNING] Neither <%s> nor <%s> environment variables are sets." \ - % (systemVariable,userVariable) - print " Setting <%s> to <%s>." % (systemVariable,self._installDir) - else: - self._environment[ systemVariable ] = self._environment[ userVariable ] - - if not self._quiet: - print "Setting <%s> to <%s>." % (systemVariable,self._environment[systemVariable]) - if self._environment.has_key(userVariable): - print "Transmitting <%s> as <%s>." % (userVariable,self._environment[userVariable]) - return - - - def _commandTemplate ( self, tools, projects, command ): - # Set or guess the various projects TOP environment variables. - for project in self._projects: - topVariable = "%s_TOP" % project.getName().upper() - topUserVariable = "%s_USER_TOP" % project.getName().upper() - self._setEnvironment ( topVariable, topUserVariable ) - - if tools: - # Checks if the requested tools are in the various projects. - self._standalones = tools - for project in self._projects: - self._standalones = project.activate ( self._standalones ) - for tool in self._standalones: - print "[WARNING] Tool \"%s\" is not part of any project." % tool - - if projects: - for projectName in projects: - project = self.getProject ( projectName ) - if not project: - ErrorMessage( 1, "No project of name \"%s\"."%projectName ).terminate() - project.activateAll() - - if not tools and not projects: - for project in self._projects: - project.activateAll () - - for project in self._projects: - for tool in project.getActives(): - print "\nProcessing tool: \"%s\"." % tool - getattr(self,command) ( tool ) - - for tool in self._standalones: - print "\nProcessing tool: \"%s\"." % tool - getattr(self,command) ( tool ) - return - - - def enable ( self, tools, projects ): - self._commandTemplate ( tools, projects, "_enableTool" ) - return - - - def enabledTools ( self ): - tools = [] - for project in self._projects: - tools += project.getActives() - return tools - - - def build ( self, tools, projects ): - self._commandTemplate ( tools, projects, "_build" ) - return - - - def svnStatus ( self, tools, projects ): - self._commandTemplate ( tools, projects, "_svnStatus" ) - return - - - def svnUpdate ( self, tools, projects ): - self._commandTemplate ( tools, projects, "_svnUpdate" ) - return - - - def svnCheckout ( self, tools, projects ): - self._commandTemplate ( tools, projects, "_svnCheckout" ) - return - - - def svnDiff ( self, tools, projects ): - self._commandTemplate ( tools, projects, "_svnDiff" ) - return - - - def svnExport ( self, tools, projects ): - self._commandTemplate ( tools, projects, "_svnExport" ) - return - - - def svnTarball ( self, tools, projects ): - if self._svnTag == "x": - self._guessSvnTag ( self.getProject(projects[0]) ) - - self._doSpec () - self._doDebChangelog () - - if os.path.isdir(self._tarballDir): - print "Removing previous tarball directory: \"%s\"." % self._tarballDir - command = [ "/bin/rm", "-rf", self._tarballDir ] - self._execute ( command, "Removing top export (tarball) directory" ) - - print "Creating tarball directory: \"%s\"." % self._tarballDir - os.makedirs ( self._tarballDir ) - self.svnExport ( tools, projects ) - - # Remove unpublisheds (yet) tools/files. - for item in self._packageExcludes: - command = [ "/bin/rm", "-rf", os.path.join(self._archiveDir,item) ] - self._execute ( command, "rm of %s failed" % item) - - # Adds files neededs only for packaging purpose. - command = [ "/bin/cp", "-r", os.path.join(self._sourceDir ,"bootstrap","Makefile.package") - , os.path.join(self._archiveDir,"Makefile") ] - self._execute ( command, "copy of %s failed" % "boostrap/Makefile.package") - - command = [ "/bin/cp", self._specFile, self._archiveDir ] - self._execute ( command, "Copying RPM spec file" ) - - command = [ "/bin/cp", "-r", self._debianDir, self._archiveDir ] - self._execute ( command, "Copying Debian/Ubuntu package control files" ) - - os.chdir ( self._archiveDir ) - #command = [ "/usr/bin/patch", "--remove-empty-files" - # , "--no-backup-if-mismatch" - # , "-p0", "-i", self._distribPatch ] - #self._execute ( command, "patch for distribution command failed" ) - - os.chdir ( self._tarballDir ) - command = [ "/bin/tar" - , "--exclude-backups" - , "--exclude-vcs" - , "-jcvf", self._sourceTarBz2, os.path.basename(self._archiveDir) ] - self._execute ( command, "tar command failed" ) - - print "Cleanup SVN export tarball archive directory: \"%s\"." % self._archiveDir - command = [ "/bin/rm", "-rf", self._archiveDir ] - self._execute ( command, "Removing archive export (tarball) directory" ) - - return - - - def userTarball ( self, tools, projects ): - self.enable( tools, projects ) - - userSourceTarBz2 = os.path.join ( self._tarballDir - , datetime.date.today().strftime('%s-%s-%%Y%%m%%d.tar.bz2'% - (self._packageName - ,self._packageVersion)) ) - - excludes = [] - for exclude in self._packageExcludes: - excludes += [ '--exclude='+exclude ] - - os.chdir ( self._sourceDir ) - command = [ "/bin/tar" - , "--exclude-backups" - , "--exclude-vcs" - , "--transform=s,^,%s/src/,"%self._projectDir ] \ - + excludes \ - + [ "-jcvf", userSourceTarBz2 ] \ - + self.enabledTools() - self._execute ( command, "tar command failed" ) - - return - - - def doRpm ( self ): - self.svnTarball ( [], self._packageProjects ) - - for rpmDir in [ "SOURCES", "SPECS", "BUILD", "tmp" - , "SRPMS", "RPMS/i386", "RPMS/i686", "RPMS/x86_64" ]: - rpmFullDir = os.path.join ( self._rpmbuildDir, rpmDir ) - if not os.path.isdir(rpmFullDir): - os.makedirs ( rpmFullDir ) - - #rpmSpecFile = os.path.join ( self._rpmbuildDir, "SPECS" , "coriolis2.spec" ) - rpmSourceFile = os.path.join ( self._rpmbuildDir, "SOURCES", self._sourceTarBz2 ) - sourceFile = os.path.join ( self._tarballDir, self._sourceTarBz2 ) - - #if os.path.isfile ( rpmSpecFile ): - # os.unlink ( rpmSpecFile ) - #os.symlink ( self._specFile, rpmSpecFile ) - - if not os.path.islink ( rpmSourceFile ): - os.symlink ( sourceFile, rpmSourceFile ) - - os.chdir ( self._rpmbuildDir ) - - command = [ "/usr/bin/rpmbuild" - , "--define", "_topdir %s" % self._rpmbuildDir - , "--define", "_tmppath %s" % self._tmppathDir - , "--define", "_enable_debug_packages 0" - , "-ta", "--with", "binarytar", rpmSourceFile ] - - self._execute ( command, "Rebuild rpm packages" ) - - return - - - def doDeb ( self ): - self.svnTarball ( [], self._packageProjects ) - - if not os.path.isdir(self._debbuildDir): - os.makedirs ( self._debbuildDir ) - - os.chdir ( self._debbuildDir ) - sourceFile = os.path.join ( self._tarballDir , self._sourceTarBz2 ) - debOrigFile = os.path.join ( self._debbuildDir, "coriolis2_1.0.%s.orig.tar.bz2" % self._svnTag ) - if not os.path.islink(debOrigFile): - os.link ( sourceFile, debOrigFile ) - - command = [ "/bin/tar", "jxf", debOrigFile ] - self._execute ( command, "Unpacking pristine sources" ) - - #command = [ "/bin/cp", "-r", self._debianDir, "." ] - #self._execute ( command, "Copying Debian/Ubuntu package control files" ) - - packageDir = os.path.join ( self._debbuildDir, "coriolis2-1.0.%s" % self._svnTag ) - os.chdir ( packageDir ) - - self._environment["CFLAGS" ] = "-O2" - self._environment["CXXFLAGS"] = "-O2" - command = [ "/usr/bin/debuild", "-us", "-uc" ] - self._execute ( command, "Rebuild Debian packages" ) - - return - - - def loadConfiguration ( self, confFile ): - moduleGlobals = globals() - - if not confFile: - print 'Making an educated guess to locate the configuration file:' - locations = [ os.path.abspath(os.path.dirname(sys.argv[0])) - , os.environ['HOME']+'/coriolis-2.x/src/bootstrap' - , os.environ['HOME']+'/coriolis/src/bootstrap' - , os.environ['HOME']+'/chams-2.x/src/bootstrap' - , os.environ['HOME']+'/chams/src/bootstrap' - , '/users/outil/coriolis/coriolis-2.x/src/bootstrap' - , self._rootDir+'/src/bootstrap' - ] - - for location in locations: - confFile = location + '/build.conf' - print ' <%s>' % confFile - - if os.path.isfile(confFile): break - if not confFile: - ErrorMessage( 1, 'Cannot locate any configuration file.' ).terminate() - else: - if not os.path.isfile(confFile): - ErrorMessage( 1, 'Missing configuration file:', '<%s>'%confFile ).terminate() - - print 'Reading configuration from:' - print ' <%s>' % options.conf - - try: - execfile( confFile, moduleGlobals ) - except Exception, e: - ErrorMessage( 1, 'An exception occured while loading the configuration file:' - , '<%s>\n' % (confFile) - , 'You should check for simple python errors in this file.' - , 'Error was:' - , '%s\n' % e ).terminate() - - if moduleGlobals.has_key('projects'): - entryNb = 0 - for entry in moduleGlobals['projects']: - entryNb += 1 - if not entry.has_key('name'): - raise ErrorMessage( 1, 'Missing project name in project entry #%d.' % entryNb ) - if not entry.has_key('tools'): - raise ErrorMessage( 1, 'Missing tools list in project entry #%d (<%s>).' \ - % (entryNb,entry['name']) ) - if not isinstance(entry['tools'],list): - raise ErrorMessage( 1, 'Tools item of project entry #%d (<%s>) is not a list.' \ - % (entryNb,entry['name']) ) - if not entry.has_key('repository'): - raise ErrorMessage( 1, 'Missing project repository in project entry #%d.' \ - % entryNb ) - - self.register( Project(entry['name'],entry['tools'],entry['repository']) ) - else: - ErrorMessage( 1, 'Configuration file is missing the \'project\' symbol.' - , '<%s>'%confFile ).terminate() - - if moduleGlobals.has_key('projectdir'): - self.projectDir = moduleGlobals['projectdir'] - - if moduleGlobals.has_key('svnconfig'): - svnconfig = moduleGlobals['svnconfig'] - if svnconfig.has_key('method'): self._svnMethod = svnconfig['method'] - - if moduleGlobals.has_key('package'): - package = moduleGlobals['package'] - if package.has_key('name' ): self.packageName = package['name'] - if package.has_key('version' ): self.packageVersion = package['version'] - if package.has_key('excludes'): - if not isinstance(package['excludes'],list): - raise ErrorMessage( 1, 'Excludes of package configuration is not a list.') - self._packageExcludes = package['excludes'] - if package.has_key('projects'): - if not isinstance(package['projects'],list): - raise ErrorMessage( 1, 'Projects to package is not a list.') - self._packageProjects = package['projects'] - return - - - def showConfiguration ( self ): - print 'BuildCoriolis Configuration:' - if self._svnMethod: - print ' SVN Method: <%s>' % self._svnMethod - else: - print ' SVN Method not defined, will not be able to checkout/commit.' - - for project in self._projects: - print ' project:%-15s repository:<%s>' % ( ('<%s>'%project.getName()), project.getRepository() ) - toolOrder = 1 - for tool in project.getTools(): - print '%s%02d:<%s>' % (' '*26,toolOrder,tool) - toolOrder += 1 - print - return +from builder import ErrorMessage +from builder.Builder import Builder if __name__ == "__main__": @@ -869,7 +48,7 @@ if __name__ == "__main__": parser.add_option ( "-u", "--check-deter", action="store_true" , dest="checkDeterminism", help="Enable Katabatic/Kite determinism checking (*very* slow)." ) ( options, args ) = parser.parse_args () - builder = ProjectBuilder () + builder = Builder () builder.loadConfiguration ( options.conf ) if options.showConf: diff --git a/bootstrap/builder/AboutWidget.py b/bootstrap/builder/AboutWidget.py new file mode 100644 index 00000000..f38a3a36 --- /dev/null +++ b/bootstrap/builder/AboutWidget.py @@ -0,0 +1,99 @@ + +# -*- mode:Python -*- +# +# This file is part of the Coriolis Software. +# Copyright (c) UPMC/LIP6 2012-2012, All Rights Reserved +# +# +-----------------------------------------------------------------+ +# | C O R I O L I S | +# | C o r i o l i s / C h a m s B u i l d e r | +# | | +# | Author : Jean-Paul Chaput | +# | E-mail : Jean-Paul.Chaput@asim.lip6.fr | +# | =============================================================== | +# | Python : "./builder/AboutWidget.py" | +# +-----------------------------------------------------------------+ + + +from PyQt4.QtCore import Qt +from PyQt4.QtGui import QPalette +from PyQt4.QtGui import QColor +from PyQt4.QtGui import QFont +from PyQt4.QtGui import QWidget +from PyQt4.QtGui import QFrame +from PyQt4.QtGui import QLabel +from PyQt4.QtGui import QVBoxLayout +from PyQt4.QtGui import QAction +from PyQt4.QtGui import QKeySequence +from PyQt4.QtGui import QApplication + + +class AboutWidget ( QWidget ): + + def __init__ ( self, parent=None ): + QWidget.__init__ ( self, parent ) + self.setFixedSize( 500, 400 ) + self.setStyleSheet( 'background-color: #ffffdd;' ) + + topLine = QFrame() + topLine.setFrameShape( QFrame.HLine ) + topLine.setLineWidth ( 2 ) + botLine = QFrame() + botLine.setFrameShape( QFrame.HLine ) + botLine.setLineWidth ( 2 ) + + title = QLabel( 'CCB' ) + title.setAlignment( Qt.AlignCenter ) + font = title.font() + font.setPointSize( 72 ) + font.setWeight ( QFont.Bold ) + title.setFont( font ) + + subTitle = QLabel( 'Coriolis & Chams Builder for the Dummies' ) + subTitle.setAlignment( Qt.AlignCenter ) + subTitle.setFont( QFont('Courier',10,QFont.Bold) ) + + authors = QLabel( 'Coriolis CAD System 1.0 . . . . . . . . ccb 1.0\n' + 'Copyright (c) 2008-2013 . . . . . . . . . . UPMC\n' + 'Authors . . . . . . . . . . . . . Damien Dupuis\n' + ' . . . . . . . . . . . . Jean-Paul Chaput\n' + 'E-Mail . . . . . . . . Jean-Paul.Chaput@lip6.fr' + ) + authors.setAlignment( Qt.AlignCenter ) + authors.setFont( QFont('Courier',10,QFont.Bold) ) + + vLayout = QVBoxLayout() + vLayout.addStretch(10) + vLayout.addWidget( topLine ) + vLayout.addWidget( title ) + vLayout.addStretch(1) + vLayout.addWidget( subTitle ) + vLayout.addWidget( authors ) + vLayout.addStretch(1) + vLayout.addWidget( botLine ) + vLayout.addStretch(10) + + frame = QFrame() + frame.setFrameShape ( QFrame.Box ) + frame.setFrameShadow( QFrame.Sunken ) + frame.setLayout ( vLayout ) + frame.setLineWidth ( 1 ) + + vLayout = QVBoxLayout() + vLayout.addWidget( frame ) + + self.setLayout( vLayout ) + + self._exitAction = QAction( '&Exit', self ) + self._exitAction.setStatusTip( 'Exit CCB (settings are saved)' ) + self._exitAction.setShortcut ( QKeySequence('CTRL+Q') ) + self._exitAction.triggered.connect( QApplication.closeAllWindows ) + self.addAction( self._exitAction ) + + self._closeAction = QAction( '&Close', self ) + self._closeAction.setStatusTip( 'Close the About Window' ) + self._closeAction.setShortcut ( QKeySequence('CTRL+A') ) + self._closeAction.triggered.connect( self.close ) + self.addAction( self._closeAction ) + + return diff --git a/bootstrap/builder/Builder.py b/bootstrap/builder/Builder.py new file mode 100644 index 00000000..bb781aba --- /dev/null +++ b/bootstrap/builder/Builder.py @@ -0,0 +1,543 @@ + +# -*- mode:Python -*- +# +# This file is part of the Coriolis Software. +# Copyright (c) UPMC/LIP6 2008-2012, All Rights Reserved +# +# +-----------------------------------------------------------------+ +# | C O R I O L I S | +# | C o r i o l i s / C h a m s B u i l d e r | +# | | +# | Author : Jean-Paul Chaput | +# | E-mail : Jean-Paul.Chaput@asim.lip6.fr | +# | =============================================================== | +# | Python : "./builder/Builder.py" | +# +-----------------------------------------------------------------+ + + +import sys +import re +import os +import os.path +import datetime +import subprocess +from . import ErrorMessage +from Project import Project +from Configuration import Configuration + + +class Builder: + + def __init__ ( self ): + self._conf = Configuration() + self._quiet = False + self._rmBuild = False + self._doBuild = True + self._noCache = False + self._enableShared = "ON" + self._enableDoc = "OFF" + self._checkDatabase = "OFF" + self._checkDeterminism = "OFF" + self._verboseMakefile = "OFF" + self._makeArguments = [] + self._environment = os.environ + return + + + def __setattr__ ( self, attribute, value ): + if attribute[0] == "_": + self.__dict__[attribute] = value + return + + if attribute in self._conf.getAllIds(): setattr( self._conf, attribute, value ) + + if attribute == "quiet": self._quiet = value + elif attribute == "rmBuild": self._rmBuild = value + elif attribute == "doBuild": self._doBuild = value + elif attribute == "noCache": self._noCache = value + elif attribute == "enableDoc": self._enableDoc = value + elif attribute == "enableShared": self._enableShared = value + elif attribute == "checkDatabase": self._checkDatabase = value + elif attribute == "checkDeterminism": self._checkDeterminism = value + elif attribute == "verboseMakefile": self._verboseMakefile = value + elif attribute == "makeArguments": self._makeArguments = value.split () + return + + + def __getattr__ ( self, attribute ): + if attribute[0] != "_": + if attribute == 'conf': return self._conf + if attribute in self._conf.getAllIds(): + return getattr( self._conf, attribute ) + + if not self.__dict__.has_key(attribute): + raise ErrorMessage( 1, 'Builder has no attribute <%s>.'%attribute ) + return self.__dict__[attribute] + + + def _guessSvnTag ( self, project ): + revisionPattern = re.compile ( r"^Revision:\s*(?P\d+)" ) + projectSvnDir = os.path.join ( self.svnMethod+project.getRepository() ) + + command = [ "svn", "info", projectSvnDir ] + svnInfo = subprocess.Popen ( command, stdout=subprocess.PIPE ) + + for line in svnInfo.stdout.readlines(): + m = revisionPattern.match ( line ) + if m: + self.svnTag = m.group("revision") + print "Latest revision of project %s is %s." % (project.getName(),self.svnTag) + return + + print "[WARNING] Cannot guess revision for project \"%s\"." % project.getName() + print " (using: \"x\")" + return + + + def _configure ( self, fileIn, file ): + fdFileIn = open ( fileIn, "r" ) + fdFile = open ( file , "w" ) + + for line in fdFileIn.readlines(): + stable = False + substituted0 = line + + while not stable: + substituted1 = re.sub ( r"@svntag@" , self.svnTag, substituted0 ) + substituted1 = re.sub ( r"@coriolisTop@", "/opt/coriolis2" , substituted1 ) + if substituted0 == substituted1: stable = True + else: substituted0 = substituted1 + + fdFile.write ( substituted0 ) + + fdFileIn.close () + fdFile.close () + return + + + def _doSpec ( self ): + self._configure ( self.specFileIn, self.specFile ) + return + + + def _doDebChangelog ( self ): + self._configure ( self.debChangelogIn, self.debChangelog ) + return + + + def _execute ( self, command, error ): + sys.stdout.flush () + sys.stderr.flush () + child = subprocess.Popen ( command, env=self._environment, stdout=None ) + (pid,status) = os.waitpid ( child.pid, 0 ) + status >>= 8 + if status != 0: + ErrorMessage( status, "%s (status:%d)."%(error,status) ).terminate() + return + + + def _enableTool ( self, tool ): + return + + + def _build ( self, tool ): + toolSourceDir = os.path.join ( self.sourceDir, tool ) + toolBuildDir = os.path.join ( self.buildDir , tool ) + # Supplied directly in the CMakeLists.txt. + #cmakeModules = os.path.join ( self.installDir, "share", "cmake", "Modules" ) + + if not os.path.isdir(toolSourceDir): + print ErrorMessage( 0, "Missing tool source directory: \"%s\" (skipped)."%toolSourceDir ) + return + + if self._rmBuild: + print "Removing tool build directory: \"%s\"." % toolBuildDir + command = [ "/bin/rm", "-rf", toolBuildDir ] + self._execute ( command, "Removing tool build directory" ) + + if not os.path.isdir(toolBuildDir): + print "Creating tool build directory: \"%s\"." % toolBuildDir + os.makedirs ( toolBuildDir ) + os.chdir ( toolBuildDir ) + + command = ["cmake", "-D", "CMAKE_BUILD_TYPE:STRING=%s" % self.buildMode + , "-D", "BUILD_SHARED_LIBS:STRING=%s" % self.enableShared + #, "-D", "CMAKE_MODULE_PATH:STRING=%s" % cmakeModules + , toolSourceDir ] + self._execute ( command, "First CMake failed" ) + + os.chdir ( toolBuildDir ) + if self._noCache: + cmakeCache = os.path.join(toolBuildDir,"CMakeCache.txt") + if os.path.isfile ( cmakeCache ): os.unlink ( cmakeCache ) + + command = ["cmake", "-D", "CMAKE_BUILD_TYPE:STRING=%s" % self.buildMode + , "-D", "BUILD_SHARED_LIBS:STRING=%s" % self.enableShared + , "-D", "BUILD_DOC:STRING=%s" % self._enableDoc + , "-D", "CHECK_DATABASE:STRING=%s" % self._checkDatabase + , "-D", "CHECK_DETERMINISM:STRING=%s" % self._checkDeterminism + , "-D", "CMAKE_VERBOSE_MAKEFILE:STRING=%s" % self._verboseMakefile + , "-D", "CMAKE_INSTALL_PREFIX:STRING=%s" % self.installDir + ] + if self.libSuffix: + command += [ "-D", "LIB_SUFFIX:STRING=%s" % self.libSuffix ] + command += [ toolSourceDir ] + self._execute ( command, "Second CMake failed" ) + + if self._doBuild: + command = [ "make" ] + #command += [ "DESTDIR=%s" % self.installDir ] + if self._enableDoc == "ON": + #if tool == "crlcore" or tool == "stratus1": + if tool == "stratus1": + command += [ "dvi", "safepdf", "html" ] + command += self._makeArguments + print "Make command:", command + sys.stdout.flush () + self._execute ( command, "Build failed" ) + return + + + def _svnStatus ( self, tool ): + toolSourceDir = os.path.join ( self.sourceDir , tool ) + if not os.path.isdir(toolSourceDir): + if not self._quiet: + print ErrorMessage( 0, "Missing tool source directory: \"%s\" (skipped)."%toolSourceDir ) + return + os.chdir ( toolSourceDir ) + + print "Checking SVN status of tool: ", tool + command = [ "svn", "status", "-u", "-q" ] + self._execute ( command, "svn status -u -q" ) + print + return + + + def _svnDiff ( self, tool ): + toolSourceDir = os.path.join ( self.sourceDir , tool ) + if not os.path.isdir(toolSourceDir): + if not self._quiet: + print ErrorMessage( 0, "Missing tool source directory: \"%s\" (skipped)."%toolSourceDir ) + return + os.chdir ( toolSourceDir ) + + print "Doing a SVN diff of tool: ", tool + command = [ "svn", "diff" ] + if self.svnTag != "x": + command += [ "--revision", self.svnTag ] + self._execute ( command, "svn diff %s" % tool ) + print + return + + + def _svnUpdate ( self, tool ): + toolSourceDir = os.path.join ( self.sourceDir , tool ) + if not os.path.isdir(toolSourceDir): + if not self._quiet: + print ErrorMessage( 0, "Missing tool source directory: \"%s\" (skipped)."%toolSourceDir) + return + os.chdir ( toolSourceDir ) + + print "Doing a SVN update of tool: ", tool + command = [ "svn", "update" ] + self._execute ( command, "svn update" ) + print + return + + + def _svnCheckout ( self, tool ): + project = self.getToolProject ( tool ) + if not project: + print ErrorMessage( 0, "Tool \"%s\" is not part of any project."%tool + ,"Cannot guess the SVN repository." ) + return + if not project.getRepository (): + print ErrorMessage( 0, "Project \"%s\" isn't associated to a repository."%project.getName() ) + return + + if not os.path.isdir(self.sourceDir): + print ErrorMessage( 0, "Source directory <%s> doesn't exists. Creating."%self.sourceDir ) + os.makedirs( self.sourceDir ) + + toolSvnTrunkDir = os.path.join ( self.svnMethod+project.getRepository(), tool, "trunk" ) + os.chdir ( self.sourceDir ) + + print "Doing a SVN checkout of tool: ", tool + command = [ "svn", "co", toolSvnTrunkDir, tool ] + if self.svnTag != "x": + command += [ "--revision", self.svnTag ] + self._execute ( command, "svn checkout %s" % tool ) + print + return + + + def _svnExport ( self, tool ): + project = self.getToolProject ( tool ) + if not project: + print ErrorMessage( 0, "Tool \"%s\" is not part of any project."%tool + , "Cannot guess the SVN repository.") + return + if not project.getRepository (): + print ErrorMessage( 0, "Project \"%s\" isn't associated to a repository."%project.getName() ) + return + + toolSvnTrunkDir = os.path.join ( self.svnMethod+project.getRepository(), tool, "trunk" ) + + if not os.path.isdir ( self.archiveDir ): + os.mkdir ( self.archiveDir ) + os.chdir ( self.archiveDir ) + + toolExportDir = os.path.join ( self.archiveDir, tool ) + if os.path.isdir ( toolExportDir ): + print "Removing tool export (tarball) directory: \"%s\"." % toolExportDir + command = [ "/bin/rm", "-r", toolExportDir ] + self._execute ( command, "Removing tool export (tarball) directory" ) + + print "Doing a SVN export of tool: ", tool + command = [ "svn", "export", toolSvnTrunkDir, toolExportDir ] + if self.svnTag != "x": + command += [ "--revision", self.svnTag ] + self._execute ( command, "svn export %s" % toolExportDir ) + print + return + + + def _setEnvironment ( self, systemVariable, userVariable ): + if not self._environment.has_key(systemVariable) or self._environment[systemVariable] == "": + if not self._environment.has_key(userVariable) or self._environment[userVariable] == "" : + self._environment[ systemVariable ] = self.installDir + print "[WARNING] Neither <%s> nor <%s> environment variables are sets." \ + % (systemVariable,userVariable) + print " Setting <%s> to <%s>." % (systemVariable,self.installDir) + else: + self._environment[ systemVariable ] = self._environment[ userVariable ] + + if not self._quiet: + print "Setting <%s> to <%s>." % (systemVariable,self._environment[systemVariable]) + if self._environment.has_key(userVariable): + print "Transmitting <%s> as <%s>." % (userVariable,self._environment[userVariable]) + return + + + def _commandTemplate ( self, tools, projects, command ): + # Set or guess the various projects TOP environment variables. + for project in self.projects: + topVariable = "%s_TOP" % project.getName().upper() + topUserVariable = "%s_USER_TOP" % project.getName().upper() + self._setEnvironment ( topVariable, topUserVariable ) + + if tools: + # Checks if the requested tools are in the various projects. + self.standalones = tools + for project in self.projects: + self.standalones = project.activate ( self.standalones ) + for tool in self.standalones: + print "[WARNING] Tool \"%s\" is not part of any project." % tool + + if projects: + for projectName in projects: + project = self.getProject ( projectName ) + if not project: + ErrorMessage( 1, "No project of name \"%s\"."%projectName ).terminate() + project.activateAll() + + if not tools and not projects: + for project in self.projects: + project.activateAll () + + for project in self.projects: + for tool in project.getActives(): + print "\nProcessing tool: \"%s\"." % tool + getattr(self,command) ( tool ) + + for tool in self.standalones: + print "\nProcessing tool: \"%s\"." % tool + getattr(self,command) ( tool ) + return + + + def enable ( self, tools, projects ): + self._commandTemplate ( tools, projects, "_enableTool" ) + return + + + def enabledTools ( self ): + tools = [] + for project in self.projects: + tools += project.getActives() + return tools + + + def build ( self, tools, projects ): + self._commandTemplate ( tools, projects, "_build" ) + return + + + def svnStatus ( self, tools, projects ): + self._commandTemplate ( tools, projects, "_svnStatus" ) + return + + + def svnUpdate ( self, tools, projects ): + self._commandTemplate ( tools, projects, "_svnUpdate" ) + return + + + def svnCheckout ( self, tools, projects ): + self._commandTemplate ( tools, projects, "_svnCheckout" ) + return + + + def svnDiff ( self, tools, projects ): + self._commandTemplate ( tools, projects, "_svnDiff" ) + return + + + def svnExport ( self, tools, projects ): + self._commandTemplate ( tools, projects, "_svnExport" ) + return + + + def svnTarball ( self, tools, projects ): + if self.svnTag == "x": + self._guessSvnTag ( self.getProject(projects[0]) ) + + self._doSpec () + self._doDebChangelog () + + if os.path.isdir(self.tarballDir): + print "Removing previous tarball directory: \"%s\"." % self.tarballDir + command = [ "/bin/rm", "-rf", self.tarballDir ] + self._execute ( command, "Removing top export (tarball) directory" ) + + print "Creating tarball directory: \"%s\"." % self.tarballDir + os.makedirs ( self.tarballDir ) + self.svnExport ( tools, projects ) + + # Remove unpublisheds (yet) tools/files. + for item in self.packageExcludes: + command = [ "/bin/rm", "-rf", os.path.join(self.archiveDir,item) ] + self._execute ( command, "rm of %s failed" % item) + + # Adds files neededs only for packaging purpose. + command = [ "/bin/cp", "-r", os.path.join(self.sourceDir ,"bootstrap","Makefile.package") + , os.path.join(self.archiveDir,"Makefile") ] + self._execute ( command, "copy of %s failed" % "boostrap/Makefile.package") + + command = [ "/bin/cp", self.specFile, self.archiveDir ] + self._execute ( command, "Copying RPM spec file" ) + + command = [ "/bin/cp", "-r", self.debianDir, self.archiveDir ] + self._execute ( command, "Copying Debian/Ubuntu package control files" ) + + os.chdir ( self.archiveDir ) + #command = [ "/usr/bin/patch", "--remove-empty-files" + # , "--no-backup-if-mismatch" + # , "-p0", "-i", self.distribPatch ] + #self._execute ( command, "patch for distribution command failed" ) + + os.chdir ( self.tarballDir ) + command = [ "/bin/tar" + , "--exclude-backups" + , "--exclude-vcs" + , "-jcvf", self.sourceTarBz2, os.path.basename(self.archiveDir) ] + self._execute ( command, "tar command failed" ) + + print "Cleanup SVN export tarball archive directory: \"%s\"." % self.archiveDir + command = [ "/bin/rm", "-rf", self.archiveDir ] + self._execute ( command, "Removing archive export (tarball) directory" ) + + return + + + def userTarball ( self, tools, projects ): + self.enable( tools, projects ) + + userSourceTarBz2 = os.path.join ( self.tarballDir + , datetime.date.today().strftime('%s-%s-%%Y%%m%%d.tar.bz2'% + (self.packageName + ,self.packageVersion)) ) + + excludes = [] + for exclude in self.packageExcludes: + excludes += [ '--exclude='+exclude ] + + os.chdir ( self.sourceDir ) + command = [ "/bin/tar" + , "--exclude-backups" + , "--exclude-vcs" + , "--transform=s,^,%s/src/,"%self.projectDir ] \ + + excludes \ + + [ "-jcvf", userSourceTarBz2 ] \ + + self.enabledTools() + self._execute ( command, "tar command failed" ) + + return + + + def doRpm ( self ): + self.svnTarball ( [], self.packageProjects ) + + for rpmDir in [ "SOURCES", "SPECS", "BUILD", "tmp" + , "SRPMS", "RPMS/i386", "RPMS/i686", "RPMS/x86_64" ]: + rpmFullDir = os.path.join ( self.rpmbuildDir, rpmDir ) + if not os.path.isdir(rpmFullDir): + os.makedirs ( rpmFullDir ) + + #rpmSpecFile = os.path.join ( self.rpmbuildDir, "SPECS" , "coriolis2.spec" ) + rpmSourceFile = os.path.join ( self.rpmbuildDir, "SOURCES", self.sourceTarBz2 ) + sourceFile = os.path.join ( self.tarballDir, self.sourceTarBz2 ) + + #if os.path.isfile ( rpmSpecFile ): + # os.unlink ( rpmSpecFile ) + #os.symlink ( self.specFile, rpmSpecFile ) + + if not os.path.islink ( rpmSourceFile ): + os.symlink ( sourceFile, rpmSourceFile ) + + os.chdir ( self.rpmbuildDir ) + + command = [ "/usr/bin/rpmbuild" + , "--define", "_topdir %s" % self.rpmbuildDir + , "--define", "_tmppath %s" % self.tmppathDir + , "--define", "_enable_debug_packages 0" + , "-ta", "--with", "binarytar", rpmSourceFile ] + + self._execute ( command, "Rebuild rpm packages" ) + + return + + + def doDeb ( self ): + self.svnTarball ( [], self.packageProjects ) + + if not os.path.isdir(self.debbuildDir): + os.makedirs ( self.debbuildDir ) + + os.chdir ( self.debbuildDir ) + sourceFile = os.path.join ( self.tarballDir , self.sourceTarBz2 ) + debOrigFile = os.path.join ( self.debbuildDir, "coriolis2_1.0.%s.orig.tar.bz2" % self.svnTag ) + if not os.path.islink(debOrigFile): + os.link ( sourceFile, debOrigFile ) + + command = [ "/bin/tar", "jxf", debOrigFile ] + self._execute ( command, "Unpacking pristine sources" ) + + #command = [ "/bin/cp", "-r", self.debianDir, "." ] + #self._execute ( command, "Copying Debian/Ubuntu package control files" ) + + packageDir = os.path.join ( self.debbuildDir, "coriolis2-1.0.%s" % self.svnTag ) + os.chdir ( packageDir ) + + self._environment["CFLAGS" ] = "-O2" + self._environment["CXXFLAGS"] = "-O2" + command = [ "/usr/bin/debuild", "-us", "-uc" ] + self._execute ( command, "Rebuild Debian packages" ) + + return + + + def loadConfiguration ( self, confFile ): self._conf.load( confFile ) + def showConfiguration ( self ): self._conf.show() + + diff --git a/bootstrap/builder/BuilderGui.py b/bootstrap/builder/BuilderGui.py new file mode 100644 index 00000000..20195bdf --- /dev/null +++ b/bootstrap/builder/BuilderGui.py @@ -0,0 +1,76 @@ + +# -*- mode:Python -*- +# +# This file is part of the Coriolis Software. +# Copyright (c) UPMC/LIP6 2012-2012, All Rights Reserved +# +# +-----------------------------------------------------------------+ +# | C O R I O L I S | +# | C o r i o l i s / C h a m s B u i l d e r | +# | | +# | Author : Damien Dupuis | +# | E-mail : Jean-Paul.Chaput@asim.lip6.fr | +# | =============================================================== | +# | Python : "./builder/BuilderGui.py" | +# +-----------------------------------------------------------------+ + + +from PyQt4.QtGui import QTabWidget +from PyQt4.QtGui import QApplication +from PyQt4.QtGui import QMainWindow +from PyQt4.QtGui import QAction +from PyQt4.QtGui import QKeySequence +from OptionsWidget import OptionsWidget +from CompileWidget import CompileWidget +from ConfigureWidget import ConfigureWidget +from AboutWidget import AboutWidget + + +class BuilderGui ( QMainWindow ): + + def __init__ ( self, confFile, parent=None ): + QMainWindow.__init__( self, parent ) + self.setWindowTitle( 'Coriolis/Chams Builder' ) + self._tabWidget = QTabWidget() + self._configureWidget = ConfigureWidget(confFile) + self._optionsWidget = OptionsWidget(self._configureWidget.conf) + self._compileWidget = CompileWidget() + self._aboutWidget = AboutWidget() + + self._tabWidget.addTab( self._optionsWidget , 'Options' ) + self._tabWidget.addTab( self._compileWidget , 'Compile' ) + self._tabWidget.addTab( self._configureWidget, 'Configure' ) + self.setCentralWidget( self._tabWidget ) + + self._compileWidget.conf = self._configureWidget + self._compileWidget.options = self._optionsWidget + + self._exitAction = QAction( '&Exit', self ) + self._exitAction.setStatusTip( 'Exit CCB (settings are saved)' ) + self._exitAction.setShortcut ( QKeySequence('CTRL+Q') ) + self._exitAction.triggered.connect( QApplication.closeAllWindows ) + + self._saveAction = QAction( '&Save Settings', self ) + self._saveAction.setStatusTip( 'Save Settings' ) + self._saveAction.setShortcut ( QKeySequence('CTRL+S') ) + self._saveAction.triggered.connect( self._configureWidget.saveSettings ) + self._saveAction.triggered.connect( self._optionsWidget.saveSettings ) + self._saveAction.triggered.connect( self._compileWidget.saveSettings ) + + self._aboutAction = QAction( '&About', self ) + self._aboutAction.setStatusTip( 'A Word About Who\'s Responsible for This Thing' ) + self._aboutAction.setShortcut ( QKeySequence('CTRL+A') ) + self._aboutAction.triggered.connect( self._aboutWidget.show ) + + fileMenu = self.menuBar().addMenu( 'File' ) + fileMenu.addAction( self._exitAction ) + fileMenu.addAction( self._saveAction ) + fileMenu.addAction( self._aboutAction ) + return + + def closeEvent ( self, event ): + self._configureWidget.saveSettings() + self._optionsWidget .saveSettings() + self._compileWidget .saveSettings() + event.accept() + return diff --git a/bootstrap/builder/CompileWidget.py b/bootstrap/builder/CompileWidget.py new file mode 100644 index 00000000..8f6b5830 --- /dev/null +++ b/bootstrap/builder/CompileWidget.py @@ -0,0 +1,209 @@ + +# -*- mode:Python -*- +# +# This file is part of the Coriolis Software. +# Copyright (c) UPMC/LIP6 2012-2012, All Rights Reserved +# +# +-----------------------------------------------------------------+ +# | C O R I O L I S | +# | C o r i o l i s / C h a m s B u i l d e r | +# | | +# | Author : Damien Dupuis | +# | E-mail : Jean-Paul.Chaput@asim.lip6.fr | +# | =============================================================== | +# | Python : "./builder/CompileWidget.py" | +# +-----------------------------------------------------------------+ + + +import re +import subprocess +from PyQt4.QtCore import Qt +from PyQt4.QtCore import pyqtSignal +from PyQt4.QtCore import QSettings +from PyQt4.QtGui import QFont +from PyQt4.QtGui import QColor +from PyQt4.QtGui import QPalette +from PyQt4.QtGui import QTextCharFormat +from PyQt4.QtGui import QWidget +from PyQt4.QtGui import QLabel +from PyQt4.QtGui import QPushButton +from PyQt4.QtGui import QCheckBox +from PyQt4.QtGui import QGroupBox +from PyQt4.QtGui import QButtonGroup +from PyQt4.QtGui import QVBoxLayout +from PyQt4.QtGui import QHBoxLayout +from PyQt4.QtGui import QGridLayout +from PyQt4.QtGui import QScrollArea +from PyQt4.QtGui import QComboBox +from PyQt4.QtGui import QLineEdit +from PyQt4.QtGui import QTextEdit +from PyQt4.QtGui import QFileDialog +from PyQt4.QtGui import QProgressBar +from PyQt4.QtGui import QApplication +from builder.Highlighter import Highlighter + + +class CompileWidget ( QWidget ): + + progress = pyqtSignal(int) + + def __init__ ( self, parent=None ): + QWidget.__init__ ( self, parent ) + self._options = None + self._conf = None + + self._go = QPushButton( 'Go' ) + self._go.setMaximumWidth( 100 ) + font = self._go.font() + font.setPointSizeF( font.pointSizeF()*2.0 ) + font.setWeight ( QFont.Bold ) + self._go.setFont( font ) + self._go.clicked.connect( self.go ) + + self._saveLog = QPushButton( 'Save' ) + saveLogLabel = QLabel( 'Log File:' ) + saveLogBrowse = QPushButton( '&Browse' ) + saveLogBrowse.clicked.connect( self.browseSaveLog ) + self._saveLogEdit = QLineEdit( '' ) + + gLayout = QGridLayout() + gLayout.addWidget( saveLogLabel , 0, 0, 1, 1, Qt.AlignRight ) + gLayout.addWidget( self._saveLogEdit, 0, 1, 1, 6 ) + gLayout.addWidget( saveLogBrowse , 0, 7, 1, 1 ) + + self._console = QTextEdit() + self._console.setLineWrapMode( QTextEdit.NoWrap ) + self._console.setMinimumSize ( 800, 400 ) + palette = self._console.palette() + palette.setColor( QPalette.Base, QColor.fromRgb(255,255,221) ) # ffffdd. + self._console.setPalette( palette ) + font = QFont( 'Bitstream Vera Sans Mono', self._console.font().pointSize() ) + self._console.setFont( font ) + self._highlighter = Highlighter( self._console.document() ) + + self._progressBar = QProgressBar() + self._progressBar.setRange ( 0, 100 ) + self._progressBar.setTextVisible( True ) + + hLayout = QHBoxLayout() + hLayout.addStretch() + hLayout.addWidget( self._go ) + hLayout.addStretch() + hLayout.addWidget( self._saveLog ) + hLayout.addStretch() + + vLayout = QVBoxLayout() + vLayout.addLayout( hLayout ) + vLayout.addLayout( gLayout ) + vLayout.addWidget( self._progressBar ) + vLayout.addWidget( self._console ) + self.setLayout( vLayout ) + + self.progress.connect( self._progressBar.setValue ) + self._saveLog.clicked.connect( self.saveLog ) + + self.readSettings() + return + + + def _setOptions ( self, options ): self._options = options + def _setConf ( self, conf ): self._conf = conf + def _getOptions ( self ): return self._options + def _getConf ( self ): return self._conf + + options = property( _getOptions, _setOptions ) + conf = property( _getConf , _setConf ) + + + def browseSaveLog ( self ): + self._saveLogEdit.setText( QFileDialog.getSaveFileName(self + ,'Select Log File Report' + ,self._saveLogEdit.text() + ,'Report Files (*.log *.txt)') ) + return + + def saveLog ( self ): + if self._saveLogEdit.text(): + fd = open( self._saveLogEdit.text(), 'w+' ) + fd.write( self._console.toPlainText() ) + fd.close() + return + + + def shellCommand ( self ): + command = [ 'buildCoriolis.py' ] + for project in self.options.projects: + for tool in project.actives: + command += [ '--tool='+tool ] + toolsCount = len(command) - 1 + + if self.conf.rootDir: command += [ '--root=%s'%self.conf.rootDir ] + + if self.options.svnUpdate: command += [ '--svn-update' ] + if self.options.svnStatus: command += [ '--svn-update' ] + if self.options.enableDoc: command += [ '--doc' ] + if self.options.noCache: command += [ '--no-cache' ] + if self.options.rmBuild: command += [ '--rm-build' ] + if self.options.verbose: command += [ '--verbose' ] + if self.options.make: + makeArguments='install '+self.options.threads + command += [ '--make=%s'%makeArguments ] + + if self.options.buildMode == 'Debug': + command += [ '--debug' ] + return toolsCount, command + + + def go ( self ): + rePercentage = re.compile(r'^\[\s*(?P\d+)%\].*') + reProcessTool = re.compile(r'^Processing tool:\s*"(?P.+)"') + + if not self.options or not self.conf: return + + toolsCount, command = self.shellCommand() + if not toolsCount: return + + self._progressBar.reset() + self._progressBar.setRange( 0, toolsCount*100 ) + + strCommand = command[0] + for arg in command[1:]: + strCommand += ' ' + arg + strCommand += '\n\n' + self._console.setFontItalic( True ) + self._console.insertPlainText( strCommand ) + self._console.setFontItalic( False ) + + toolsDone = -1 + builderProcess = subprocess.Popen( command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT ) + while True: + line = builderProcess.stdout.readline() + if line == '': break + + m = rePercentage.match( line ) + if m: + self.progress.emit( toolsDone*100+int(m.group('percent')) ) + else: + m = reProcessTool.match( line ) + if m: + toolsDone += 1 + + self._console.insertPlainText( line ) + + scrollBar = self._console.verticalScrollBar() + scrollBar.setValue( scrollBar.maximum() ) + QApplication.processEvents() + builderProcess.wait() + if builderProcess.returncode == None: + pass + return + + def readSettings ( self ): + settings = QSettings() + self._saveLogEdit.setText( settings.value('compile/saveLog').toString() ) + return + + def saveSettings ( self ): + settings = QSettings() + settings.setValue( 'compile/saveLog', self._saveLogEdit.text() ) + return diff --git a/bootstrap/builder/Configuration.py b/bootstrap/builder/Configuration.py new file mode 100644 index 00000000..32d4cc48 --- /dev/null +++ b/bootstrap/builder/Configuration.py @@ -0,0 +1,293 @@ + +# -*- mode:Python -*- +# +# This file is part of the Coriolis Software. +# Copyright (c) UPMC/LIP6 2008-2012, All Rights Reserved +# +# +-----------------------------------------------------------------+ +# | C O R I O L I S | +# | C o r i o l i s / C h a m s B u i l d e r | +# | | +# | Author : Jean-Paul Chaput | +# | E-mail : Jean-Paul.Chaput@asim.lip6.fr | +# | =============================================================== | +# | Python : "./builder/Configuration.py" | +# +-----------------------------------------------------------------+ + + +import sys +import re +import os +import os.path +import datetime +import subprocess +from . import ErrorMessage +from Project import Project + + +class Configuration ( object ): + + PrimaryNames = \ + [ 'confFile', 'projects', 'standalones' + , 'svnTag', 'svnMethod' + , 'projectDir', 'rootDir' + , 'packageName', 'packageVersion', 'packageExcludes', 'packageProject' + , 'osType', 'libSuffix', 'buildMode', 'libMode', 'enableShared' + ] + SecondaryNames = \ + [ 'rpmbuildDir' , 'debbuildDir' , 'tmppathDir' , 'tarballDir' + , 'archiveDir' , 'sourceDir' , 'osDir' , 'buildDir' + , 'installDir' , 'specFileIn' , 'specFile' + , 'debianDir' , 'debChangelogIn', 'debChangelog', 'sourceTarBz2' + , 'binaryTarBz2', 'distribPatch' + ] + + def __init__ ( self ): + self._confFile = None + self._projects = [] + self._standalones = [] + self._svnTag = "x" + self._svnMethod = None + self._projectDir = 'coriolis-2.x' + self._rootDir = os.path.join ( os.environ["HOME"], self._projectDir ) + self._packageName = None + self._packageVersion = None + self._packageExcludes = [] + self._packageProject = [] + self._enableShared = 'ON' + self._buildMode = 'Release' + + # Secondary (derived) variables. + # Setup by _updateSecondary(). + self._guessOs() + self._updateSecondary() + return + + + def __setattr__ ( self, attribute, value ): + if attribute in Configuration.SecondaryNames: + print ErrorMessage( 1, 'Attempt to write in read-only attribute <%s> in Configuration.'%attribute ) + return + + if attribute[0] == '_': + self.__dict__[attribute] = value + return + + if attribute == 'rootDir': value = os.path.expanduser(value) + elif attribute == 'enableShared' and value != 'ON': value = 'OFF' + + self.__dict__['_'+attribute] = value + self._updateSecondary() + return + + + def __getattr__ ( self, attribute ): + if attribute[0] != '_': attribute = '_'+attribute + if not self.__dict__.has_key(attribute): + raise ErrorMessage( 1, 'Configuration has no attribute <%s>.'%attribute ) + return self.__dict__[attribute] + + + def _updateSecondary ( self ): + if self._enableShared == "ON": self._libMode = "Shared" + else: self._libMode = "Static" + + #self._rootDir = os.path.join ( os.environ["HOME"], self._projectDir ) + self._rpmbuildDir = os.path.join ( self._rootDir , "rpmbuild" ) + self._debbuildDir = os.path.join ( self._rootDir , "debbuild" ) + self._tmppathDir = os.path.join ( self._rpmbuildDir, "tmp" ) + self._tarballDir = os.path.join ( self._rootDir , "tarball" ) + self._archiveDir = os.path.join ( self._tarballDir , "%s-%s.%s" % (self._packageName + ,self._packageVersion + ,self._svnTag) ) + self._sourceDir = os.path.join ( self._rootDir , "src" ) + self._osDir = os.path.join ( self._rootDir + , self._osType + , "%s.%s" % (self._buildMode,self._libMode) ) + self._buildDir = os.path.join ( self._osDir, "build" ) + self._installDir = os.path.join ( self._osDir, "install" ) + + self._specFileIn = os.path.join ( self._sourceDir, "bootstrap", "%s.spec.in"%self._packageName ) + self._specFile = os.path.join ( self._sourceDir, "bootstrap", "%s.spec" %self._packageName ) + self._debianDir = os.path.join ( self._sourceDir, "bootstrap", "debian" ) + self._debChangelogIn = os.path.join ( self._debianDir, "changelog.in" ) + self._debChangelog = os.path.join ( self._debianDir, "changelog" ) + self._sourceTarBz2 = "%s-%s.%s.tar.bz2" % (self._packageName,self._packageVersion,self._svnTag) + self._binaryTarBz2 = "%s-binary-%s.%s-1.slsoc6.tar.bz2" % (self._packageName,self._packageVersion,self._svnTag) + self._distribPatch = os.path.join ( self._sourceDir, "bootstrap", "%s-for-distribution.patch"%self._packageName ) + return + + + def _guessOs ( self ): + self._libSuffix = None + self._osSlsoc6x_64 = re.compile (".*Linux.*el6.*x86_64.*") + self._osSlsoc6x = re.compile (".*Linux.*el6.*") + self._osSLSoC5x_64 = re.compile (".*Linux.*el5.*x86_64.*") + self._osSLSoC5x = re.compile (".*Linux.*(el5|2.6.23.13.*SoC).*") + self._osLinux_64 = re.compile (".*Linux.*x86_64.*") + self._osLinux = re.compile (".*Linux.*") + self._osFreeBSD8x_amd64 = re.compile (".*FreeBSD 8.*amd64.*") + self._osFreeBSD8x_64 = re.compile (".*FreeBSD 8.*x86_64.*") + self._osFreeBSD8x = re.compile (".*FreeBSD 8.*") + self._osDarwin = re.compile (".*Darwin.*") + + uname = subprocess.Popen ( ["uname", "-srm"], stdout=subprocess.PIPE ) + lines = uname.stdout.readlines() + + if self._osSlsoc6x_64.match(lines[0]): + self._osType = "Linux.slsoc6x_64" + self._libSuffix = "64" + elif self._osSlsoc6x .match(lines[0]): self._osType = "Linux.slsoc6x" + elif self._osSLSoC5x_64.match(lines[0]): + self._osType = "Linux.SLSoC5x_64" + self._libSuffix = "64" + elif self._osSLSoC5x .match(lines[0]): self._osType = "Linux.SLSoC5x" + elif self._osLinux_64 .match(lines[0]): + self._osType = "Linux.x86_64" + self._libSuffix = "64" + elif self._osLinux .match(lines[0]): self._osType = "Linux.i386" + elif self._osDarwin .match(lines[0]): self._osType = "Darwin" + elif self._osFreeBSD8x_amd64.match(lines[0]): + self._osType = "FreeBSD.8x.amd64" + self._libSuffix = "64" + elif self._osFreeBSD8x_64.match(lines[0]): + self._osType = "FreeBSD.8x.x86_64" + self._libSuffix = "64" + elif self._osFreeBSD8x .match(lines[0]): self._osType = "FreeBSD.8x.i386" + else: + uname = subprocess.Popen ( ["uname", "-sr"], stdout=subprocess.PIPE ) + self._osType = uname.stdout.readlines()[0][:-1] + + print "[WARNING] Unrecognized OS: \"%s\"." % lines[0][:-1] + print " (using: \"%s\")" % self._osType + + return + + + def getPrimaryIds ( self ): return Configuration.PrimaryNames + def getSecondaryIds ( self ): return Configuration.SecondaryNames + def getAllIds ( self ): return Configuration.PrimaryNames + Configuration.SecondaryNames + + + def register ( self, project ): + for registered in self._projects: + if registered.getName() == project.getName(): + print ErrorMessage( 0, "Project \"%s\" is already registered (ignored)." ) + return + self._projects += [ project ] + return + + + def getProject ( self, name ): + for project in self._projects: + if project.getName() == name: + return project + return None + + + def getToolProject ( self, name ): + for project in self._projects: + if project.hasTool(name): + return project + return None + + + def load ( self, confFile ): + moduleGlobals = globals() + + if not confFile: + print 'Making an educated guess to locate the configuration file:' + locations = [ os.path.abspath(os.path.dirname(sys.argv[0])) + , os.environ['HOME']+'/coriolis-2.x/src/bootstrap' + , os.environ['HOME']+'/coriolis/src/bootstrap' + , os.environ['HOME']+'/chams-2.x/src/bootstrap' + , os.environ['HOME']+'/chams/src/bootstrap' + , '/users/outil/coriolis/coriolis-2.x/src/bootstrap' + , self._rootDir+'/src/bootstrap' + ] + + for location in locations: + self._confFile = location + '/build.conf' + print ' <%s>' % self._confFile + + if os.path.isfile(self._confFile): break + if not self._confFile: + ErrorMessage( 1, 'Cannot locate any configuration file.' ).terminate() + else: + print 'Using user-supplied configuration file:' + print ' <%s>' % confFile + + self._confFile = confFile + if not os.path.isfile(self._confFile): + ErrorMessage( 1, 'Missing configuration file:', '<%s>'%self._confFile ).terminate() + + print 'Reading configuration from:' + print ' <%s>' % self._confFile + + try: + execfile( self._confFile, moduleGlobals ) + except Exception, e: + ErrorMessage( 1, 'An exception occured while loading the configuration file:' + , '<%s>\n' % (self._confFile) + , 'You should check for simple python errors in this file.' + , 'Error was:' + , '%s\n' % e ).terminate() + + if moduleGlobals.has_key('projects'): + entryNb = 0 + for entry in moduleGlobals['projects']: + entryNb += 1 + if not entry.has_key('name'): + raise ErrorMessage( 1, 'Missing project name in project entry #%d.' % entryNb ) + if not entry.has_key('tools'): + raise ErrorMessage( 1, 'Missing tools list in project entry #%d (<%s>).' \ + % (entryNb,entry['name']) ) + if not isinstance(entry['tools'],list): + raise ErrorMessage( 1, 'Tools item of project entry #%d (<%s>) is not a list.' \ + % (entryNb,entry['name']) ) + if not entry.has_key('repository'): + raise ErrorMessage( 1, 'Missing project repository in project entry #%d.' \ + % entryNb ) + + self.register( Project(entry['name'],entry['tools'],entry['repository']) ) + else: + ErrorMessage( 1, 'Configuration file is missing the \'project\' symbol.' + , '<%s>'%self._confFile ).terminate() + + if moduleGlobals.has_key('projectdir'): + self.projectDir = moduleGlobals['projectdir'] + + if moduleGlobals.has_key('svnconfig'): + svnconfig = moduleGlobals['svnconfig'] + if svnconfig.has_key('method'): self._svnMethod = svnconfig['method'] + + if moduleGlobals.has_key('package'): + package = moduleGlobals['package'] + if package.has_key('name' ): self.packageName = package['name'] + if package.has_key('version' ): self.packageVersion = package['version'] + if package.has_key('excludes'): + if not isinstance(package['excludes'],list): + raise ErrorMessage( 1, 'Excludes of package configuration is not a list.') + self._packageExcludes = package['excludes'] + if package.has_key('projects'): + if not isinstance(package['projects'],list): + raise ErrorMessage( 1, 'Projects to package is not a list.') + self._packageProjects = package['projects'] + return + + + def show ( self ): + print 'CCB Configuration:' + if self._svnMethod: + print ' SVN Method: <%s>' % self._svnMethod + else: + print ' SVN Method not defined, will not be able to checkout/commit.' + + for project in self._projects: + print ' project:%-15s repository:<%s>' % ( ('<%s>'%project.getName()), project.getRepository() ) + toolOrder = 1 + for tool in project.getTools(): + print '%s%02d:<%s>' % (' '*26,toolOrder,tool) + toolOrder += 1 + print + return diff --git a/bootstrap/builder/ConfigureWidget.py b/bootstrap/builder/ConfigureWidget.py new file mode 100644 index 00000000..2d739f53 --- /dev/null +++ b/bootstrap/builder/ConfigureWidget.py @@ -0,0 +1,195 @@ + +# -*- mode:Python -*- +# +# This file is part of the Coriolis Software. +# Copyright (c) UPMC/LIP6 2012-2012, All Rights Reserved +# +# +-----------------------------------------------------------------+ +# | C O R I O L I S | +# | C o r i o l i s / C h a m s B u i l d e r | +# | | +# | Author : Damien Dupuis | +# | E-mail : Jean-Paul.Chaput@asim.lip6.fr | +# | =============================================================== | +# | Python : "./builder/ConfigureWidget.py" | +# +-----------------------------------------------------------------+ + + +from PyQt4.QtCore import Qt +from PyQt4.QtCore import QVariant +from PyQt4.QtCore import pyqtSignal +from PyQt4.QtCore import QSettings +from PyQt4.QtGui import QFont +from PyQt4.QtGui import QWidget +from PyQt4.QtGui import QGridLayout +from PyQt4.QtGui import QHBoxLayout +from PyQt4.QtGui import QVBoxLayout +from PyQt4.QtGui import QLabel +from PyQt4.QtGui import QPushButton +from PyQt4.QtGui import QLineEdit +from PyQt4.QtCore import QModelIndex +from PyQt4.QtCore import QAbstractTableModel +from PyQt4.QtGui import QAbstractItemView +from PyQt4.QtGui import QHeaderView +from PyQt4.QtGui import QTableView +from PyQt4.QtGui import QGroupBox +from PyQt4.QtGui import QFileDialog +from PyQt4.QtGui import QApplication +from Configuration import Configuration + + +class ConfSettingsModel ( QAbstractTableModel ): + + HeaderFont = QApplication.font() + PrimaryFont = QFont('Courier',HeaderFont.pointSize()-2,QFont.Normal) + SecondaryFont = QFont('Courier',HeaderFont.pointSize()-2,QFont.Normal) + ValueFont = QFont('Courier',HeaderFont.pointSize()-2,QFont.Bold) + + def __init__ ( self, conf, parent=None ): + ConfSettingsModel.HeaderFont.setBold( True ) + ConfSettingsModel.SecondaryFont.setItalic( True ) + + QAbstractTableModel.__init__( self, parent ) + self._conf = conf + self._ids = self._conf.getAllIds() + return + + def data ( self, index, role ): + if role == Qt.SizeHintRole: + if index.column() == 0: return 300 + else: return -1 + elif role == Qt.FontRole: + if index.column() == 0: + if index.row() >= len(self._conf.getPrimaryIds()): + return ConfSettingsModel.SecondaryFont + return ConfSettingsModel.PrimaryFont + else: + return ConfSettingsModel.ValueFont + elif role == Qt.DisplayRole: + row = index.row() + if row < self.rowCount(): + if index.column() == 0: return self._ids[row] + elif index.column() == 1: return getattr( self._conf, self._ids[row] ) + + return QVariant() + + + def headerData ( self, section, orientation, role ): + if orientation == Qt.Vertical: return QVariant() + if role == Qt.FontRole: return ConfSettingsModel.HeaderFont + if role != Qt.DisplayRole: return QVariant() + + if section == 0: return 'Setting' + elif section == 1: return 'Value' + + return QVariant('?') + + + def rowCount ( self, index=QModelIndex() ): return len(self._ids) + def columnCount ( self, index=QModelIndex() ): return 2 + + +class ConfSettingsWidget ( QWidget ): + + def __init__ ( self, conf, parent=None ): + QWidget.__init__( self, parent ) + self._rowHeight = 20 + + self._view = QTableView() + self._view.setShowGrid ( False ) + self._view.setAlternatingRowColors( True ) + self._view.setSelectionBehavior ( QAbstractItemView.SelectRows ) + #self._view.setSortingEnabled ( True ) + #self._view.installEventFilter ( self ) + + horizontalHeader = self._view.horizontalHeader () + horizontalHeader.setStretchLastSection ( True ) + horizontalHeader.setMinimumSectionSize ( 150 ) + horizontalHeader.setResizeMode ( QHeaderView.ResizeToContents ) + horizontalHeader.setDefaultSectionSize ( 150 ) + + verticalHeader = self._view.verticalHeader (); + verticalHeader.setVisible ( False ); + verticalHeader.setDefaultSectionSize ( self._rowHeight ); + + self._baseModel = ConfSettingsModel( conf ) + self._view.setModel( self._baseModel ); + self._view.horizontalHeader().setStretchLastSection( True ); + self._view.resizeColumnToContents( 0 ); + + peanoDataLayout = QGridLayout(); + peanoDataLayout.addWidget( self._view, 0, 0, 1, 1 ); + + self.setLayout ( peanoDataLayout ); + return + + +class ConfigureWidget ( QWidget ): + + def __init__ ( self, confFile, parent=None ): + QWidget.__init__ ( self, parent ) + self._confFile = confFile + self._conf = Configuration() + self._rootDir = '' + + rootDirLabel = QLabel( 'Root Directory' ) + rootDirBrowse = QPushButton( '&Browse' ) + rootDirBrowse.clicked.connect( self.browseRootDir ) + self._rootDirEdit = QLineEdit( '' ) + #self._rootDirEdit.setFixedWidth( 600 ) + + gLayout = QGridLayout() + gLayout.addWidget( rootDirLabel , 0, 0, 1, 1 ) + gLayout.addWidget( self._rootDirEdit, 0, 1, 1, 6 ) + gLayout.addWidget( rootDirBrowse , 0, 7, 1, 1 ) + groupDirs = QGroupBox( 'Directories' ) + groupDirs.setLayout( gLayout ) + + gLayout = QGridLayout() + groupConf = QGroupBox( 'Configuration' ) + groupConf.setLayout( gLayout ) + + vLayout = QVBoxLayout() + vLayout.addWidget ( groupDirs ) + vLayout.addWidget ( groupConf ) + #vLayout.addStretch() + + self.setLayout( vLayout ) + + self._rootDirEdit.textChanged.connect( self.rootDirChanged ) + + self.readSettings() + + noteLabel = QLabel( 'Those settings can be changed only by editing build.conf' ) + gLayout.addWidget( noteLabel , 0, 0, 1, 1 ) + gLayout.addWidget( ConfSettingsWidget(self._conf), 1, 0, 1, 1 ) + + + def _getRootDir ( self ): return self._rootDir + def _getConf ( self ): return self._conf + + rootDir = property( _getRootDir ) + conf = property( _getConf ) + + + def rootDirChanged ( self, rootDir ): + self._rootDir = rootDir + return + + def browseRootDir ( self ): + self._rootDirEdit.setText( QFileDialog.getExistingDirectory(self,'Select the Building Root Directory') ) + return + + def readSettings ( self ): + settings = QSettings() + self._rootDirEdit.setText( settings.value('conf/rootDir').toString() ) + if not self._confFile and settings.value('conf/confFile'): + self._confFile = str( settings.value('conf/confFile').toString() ) + self._conf.load( self._confFile ) + return + + def saveSettings ( self ): + settings = QSettings() + settings.setValue( 'conf/rootDir' , self._rootDirEdit.text() ) + settings.setValue( 'conf/confFile', self._confFile ) + return diff --git a/bootstrap/builder/Highlighter.py b/bootstrap/builder/Highlighter.py new file mode 100644 index 00000000..2ce0cb03 --- /dev/null +++ b/bootstrap/builder/Highlighter.py @@ -0,0 +1,80 @@ + +# -*- mode:Python -*- +# +# This file is part of the Coriolis Software. +# Copyright (c) UPMC/LIP6 2012-2012, All Rights Reserved +# +# +-----------------------------------------------------------------+ +# | C O R I O L I S | +# | C o r i o l i s / C h a m s B u i l d e r | +# | | +# | Author : Damien Dupuis | +# | E-mail : Jean-Paul.Chaput@asim.lip6.fr | +# | =============================================================== | +# | Python : "./builder/Highlighter.py" | +# +-----------------------------------------------------------------+ + + +import re +from PyQt4.QtCore import Qt +from PyQt4.QtGui import QFont +from PyQt4.QtGui import QColor +from PyQt4.QtGui import QTextCharFormat +from PyQt4.QtGui import QSyntaxHighlighter + + +class Highlighter ( QSyntaxHighlighter ): + + Normal = 0x0001 + Bold = 0x0002 + Italic = 0x0004 + + ttyBackground = QColor.fromRgb( 255, 255, 221 ) # #ffffdd + ttyBlack = QColor.fromRgb( 46, 52, 54 ) # #2e3436 + ttyRed = QColor.fromRgb( 204, 0, 0 ) # #cc0000 + ttyGreen = QColor.fromRgb( 78, 154, 6 ) # #4e9a06 + ttyYellow = QColor.fromRgb( 196, 160, 0 ) # #c4a000 + ttyBlue = QColor.fromRgb( 52, 101, 164 ) # #3465a4 + ttyViolet = QColor.fromRgb( 117, 80, 123 ) # #75507b + ttyCyan = QColor.fromRgb( 6, 152, 154 ) # #06989a + ttyGrey = QColor.fromRgb( 211, 215, 207 ) # #d3d7cf + ttyLightBlack = QColor.fromRgb( 85, 87, 83 ) # #555753 + ttyLightRed = QColor.fromRgb( 239, 41, 41 ) # #ef2929 + ttyLightGreen = QColor.fromRgb( 138, 226, 52 ) # #8ae234 + ttyLightYellow = QColor.fromRgb( 252, 233, 79 ) # #fce94f + ttyLightBlue = QColor.fromRgb( 114, 159, 207 ) # #729fcf + ttyLightViolet = QColor.fromRgb( 173, 127, 168 ) # #ad7fa8 + ttyLightCyan = QColor.fromRgb( 52, 226, 226 ) # #34e2e2 + ttyLightGrey = QColor.fromRgb( 238, 238, 236 ) # #eeeeec + + Rules = [ [ttyLightViolet, Bold , re.compile(r'^Scanning.*'), None] + , [ttyLightRed , Bold , re.compile(r'^Linking.*'), None] + , [ttyLightGreen , Normal , re.compile(r'^\[(?P\s*\d+)%\]\s*(?PBuilding.*)'), None] + , [ttyLightGreen , Bold , re.compile(r'^\[(?P\s*\d+)%\]\s*(?PBuilt target.*)'), None] + , [ttyLightBlue , Normal , re.compile(r'^\[(?P\s*\d+)%\]\s*(?PGenerating.*moc_.*)'), None] + , [ttyLightBlue , Bold , re.compile(r'^Generating.*'), None] + , [ttyLightCyan , Normal , re.compile(r'^Install the project.*'), None] + , [ttyCyan , Bold , re.compile(r'^-- Install.*'), None] + , [ttyCyan , Bold|Italic, re.compile(r'^-- Up-to-date.*'), None] + ] + + def __init__ ( self, parent=None ): + QSyntaxHighlighter.__init__ ( self, parent ) + for rule in Highlighter.Rules: + if not rule[3]: + rule[3] = QTextCharFormat() + rule[3].setForeground( rule[0] ) + if rule[1] & Highlighter.Normal: rule[3].setFontWeight( QFont.Normal ) + if rule[1] & Highlighter.Bold: rule[3].setFontWeight( QFont.Bold ) + if rule[1] & Highlighter.Italic: rule[3].setFontItalic( True ) + return + + def highlightBlock ( self, line ): + for rule in Highlighter.Rules: + m = rule[2].match(line) + if m: + if m.groupdict().has_key('percent'): + self.setFormat( 7, len(line), rule[3] ) + else: + self.setFormat( 0, len(line), rule[3] ) + return diff --git a/bootstrap/builder/OptionsWidget.py b/bootstrap/builder/OptionsWidget.py new file mode 100644 index 00000000..29474639 --- /dev/null +++ b/bootstrap/builder/OptionsWidget.py @@ -0,0 +1,179 @@ + +# -*- mode:Python -*- +# +# This file is part of the Coriolis Software. +# Copyright (c) UPMC/LIP6 2012-2012, All Rights Reserved +# +# +-----------------------------------------------------------------+ +# | C O R I O L I S | +# | C o r i o l i s / C h a m s B u i l d e r | +# | | +# | Author : Damien Dupuis | +# | E-mail : Jean-Paul.Chaput@asim.lip6.fr | +# | =============================================================== | +# | Python : "./builder/OptionsWidget.py" | +# +-----------------------------------------------------------------+ + + +import re +import subprocess +from PyQt4.QtCore import Qt +from PyQt4.QtCore import pyqtSignal +from PyQt4.QtCore import QSettings +from PyQt4.QtGui import QColor +from PyQt4.QtGui import QWidget +from PyQt4.QtGui import QPushButton +from PyQt4.QtGui import QCheckBox +from PyQt4.QtGui import QGroupBox +from PyQt4.QtGui import QButtonGroup +from PyQt4.QtGui import QVBoxLayout +from PyQt4.QtGui import QHBoxLayout +from PyQt4.QtGui import QGridLayout +from PyQt4.QtGui import QScrollArea +from PyQt4.QtGui import QComboBox +from builder.Project import Project +from builder.ConfigureWidget import ConfigureWidget +from builder.ProjectWidgets import ProjectWidgets + + +class OptionsWidget ( QWidget ): + + progress = pyqtSignal(int) + + def __init__ ( self, conf, parent=None ): + QWidget.__init__ ( self, parent ) + self._conf = conf + self._projects = [] + for project in self._conf.projects: + self._projects += [ ProjectWidgets(project) ] + + gLayout = QGridLayout() + for column in range(len(self._projects)): + self._projects[column].addToLayout( column, gLayout ) + toolsGroup = QGroupBox( 'Projects && Tools' ) + toolsGroup.setLayout( gLayout ) + + scrollToolsGroup = QScrollArea() + scrollToolsGroup.setMinimumHeight( 400 ) + #scrollToolsGroup.setVerticalScrollBarPolicy( Qt.ScrollBarAlwaysOn ) + scrollToolsGroup.setWidget( toolsGroup ) + + self._buildMode = QComboBox() + self._buildMode.addItems( ('Release', 'Debug') ) + self._svnUpdate = QCheckBox( 'SVN Update' ) + self._svnStatus = QCheckBox( 'SVN Status' ) + self._make = QCheckBox( 'Build' ) + self._enableDoc = QCheckBox( 'Build Documentation' ) + self._noCache = QCheckBox( 'Remove previous CMake cache' ) + self._rmBuild = QCheckBox( 'Cleanup Build Directory' ) + self._verbose = QCheckBox( 'Display Compiler Commands' ) + self._threads = QComboBox() + for j in range(16): + self._threads.addItem( '-j%d'%(j+1), j+1 ) + + self._commandGroup = QButtonGroup() + self._commandGroup.setExclusive( True ) + self._commandGroup.addButton( self._svnUpdate ) + self._commandGroup.addButton( self._svnStatus ) + self._commandGroup.addButton( self._make ) + + vLayout = QVBoxLayout() + vLayout.addWidget( self._svnUpdate ) + vLayout.addWidget( self._svnStatus ) + vLayout.addWidget( self._make ) + vLayout.addStretch() + commandGroup = QGroupBox( 'Command' ) + commandGroup.setLayout( vLayout ) + + vLayout = QVBoxLayout() + vLayout.addWidget( self._buildMode ) + vLayout.addWidget( self._enableDoc ) + vLayout.addWidget( self._noCache ) + vLayout.addWidget( self._rmBuild ) + vLayout.addStretch() + optionsGroup = QGroupBox( 'Command Options' ) + optionsGroup.setLayout( vLayout ) + + vLayout = QVBoxLayout() + vLayout.addWidget( self._threads ) + vLayout.addWidget( self._verbose ) + vLayout.addStretch() + miscGroup = QGroupBox( 'Misc. Options' ) + miscGroup.setLayout( vLayout ) + + hLayout = QHBoxLayout() + hLayout.addWidget( commandGroup ) + hLayout.addWidget( optionsGroup ) + hLayout.addWidget( miscGroup ) + commands = QWidget() + commands.setLayout( hLayout ) + + vLayout = QVBoxLayout() + vLayout.addWidget( commands ) + vLayout.addWidget( scrollToolsGroup ) + vLayout.addStretch() + self.setLayout( vLayout ) + + self.readSettings() + return + + + def _getProjects ( self ): return self._projects + def _getBuildMode ( self ): return self._buildMode.currentText() + def _getThreads ( self ): return self._threads.currentText() + def _getSvnUpdate ( self ): return self._svnUpdate.isChecked() + def _getSvnStatus ( self ): return self._svnStatus.isChecked() + def _getMake ( self ): return self._make.isChecked() + def _getEnableDoc ( self ): return self._enableDoc.isChecked() + def _getNoCache ( self ): return self._noCache.isChecked() + def _getRmBuild ( self ): return self._rmBuild.isChecked() + def _getVerbose ( self ): return self._verbose.isChecked() + + projects = property( _getProjects ) + buildMode = property( _getBuildMode ) + threads = property( _getThreads ) + svnUpdate = property( _getSvnUpdate ) + svnStatus = property( _getSvnStatus ) + make = property( _getMake ) + enableDoc = property( _getEnableDoc ) + noCache = property( _getNoCache ) + rmBuild = property( _getRmBuild ) + verbose = property( _getVerbose ) + + + def readSettings ( self ): + settings = QSettings() + self._svnUpdate.setChecked( settings.value('builder/svnUpdate').toBool() ) + self._svnStatus.setChecked( settings.value('builder/svnStatus').toBool() ) + self._make .setChecked( settings.value('builder/make' ).toBool() ) + self._enableDoc.setChecked( settings.value('builder/enableDoc').toBool() ) + self._noCache .setChecked( settings.value('builder/noCache' ).toBool() ) + self._rmBuild .setChecked( settings.value('builder/rmBuild' ).toBool() ) + self._verbose .setChecked( settings.value('builder/verbose' ).toBool() ) + + buildModeName = settings.value('builder/buildMode').toString() + index = self._buildMode.findText( buildModeName ) + if index >= 0: self._buildMode.setCurrentIndex( index ) + + threads = settings.value('builder/threads').toString() + index = self._threads.findText( threads ) + if index >= 0: self._threads.setCurrentIndex( index ) + + for project in self._projects: project.readFromSettings() + return + + + def saveSettings ( self ): + settings = QSettings() + settings.setValue('builder/svnUpdate', self._svnUpdate.isChecked() ) + settings.setValue('builder/svnStatus', self._svnStatus.isChecked() ) + settings.setValue('builder/make' , self._make .isChecked() ) + settings.setValue('builder/enableDoc', self._enableDoc.isChecked() ) + settings.setValue('builder/buildMode', self._buildMode.currentText() ) + settings.setValue('builder/noCache' , self._noCache .isChecked() ) + settings.setValue('builder/rmBuild' , self._rmBuild .isChecked() ) + settings.setValue('builder/verbose' , self._verbose .isChecked() ) + settings.setValue('builder/threads' , self._threads .currentText() ) + + for project in self._projects: project.saveToSettings() + return diff --git a/bootstrap/builder/Project.py b/bootstrap/builder/Project.py new file mode 100644 index 00000000..22bb45b4 --- /dev/null +++ b/bootstrap/builder/Project.py @@ -0,0 +1,51 @@ + +# -*- mode:Python -*- +# +# This file is part of the Coriolis Software. +# Copyright (c) UPMC/LIP6 2012-2012, All Rights Reserved +# +# +-----------------------------------------------------------------+ +# | C O R I O L I S | +# | C o r i o l i s / C h a m s B u i l d e r | +# | | +# | Author : Jean-Paul Chaput | +# | E-mail : Jean-Paul.Chaput@asim.lip6.fr | +# | =============================================================== | +# | Python : "./builder/Project.py" | +# +-----------------------------------------------------------------+ + + +class Project ( object ): + + def __init__ ( self, name, tools, repository ): + self._name = name + self._tools = tools + self._repository = repository + self._actives = [] + return + + def getName ( self ): return self._name + def getTools ( self ): return self._tools + def getRepository ( self ): return self._repository + def getActives ( self ): return self._actives + def hasTool ( self, tool ): return tool in self._tools + + def desactivate ( self ): + self._active = [] + return + + def activateAll ( self ): + self._actives = self._tools + return + + def activate ( self, tools ): + # Build the ordered list. + for tool in self._tools: + if (tool in tools) and not (tool in self._actives): + self._actives += [ tool ] + # Find the tools not part of the project. + rejecteds = [] + for tool in tools: + if not (tool in self._tools) and (not tool in rejecteds): + rejecteds += [ tool ] + return rejecteds diff --git a/bootstrap/builder/ProjectWidgets.py b/bootstrap/builder/ProjectWidgets.py new file mode 100644 index 00000000..902495c2 --- /dev/null +++ b/bootstrap/builder/ProjectWidgets.py @@ -0,0 +1,76 @@ + +# -*- mode:Python -*- +# +# This file is part of the Coriolis Software. +# Copyright (c) UPMC/LIP6 2012-2012, All Rights Reserved +# +# +-----------------------------------------------------------------+ +# | C O R I O L I S | +# | C o r i o l i s / C h a m s B u i l d e r | +# | | +# | Author : Jean-Paul Chaput | +# | E-mail : Jean-Paul.Chaput@asim.lip6.fr | +# | =============================================================== | +# | Python : "./builder/ProjectWidget.py" | +# +-----------------------------------------------------------------+ + + +from PyQt4.QtCore import Qt +from PyQt4.QtCore import QObject +from PyQt4.QtCore import QSettings +from PyQt4.QtGui import QPushButton +from PyQt4.QtGui import QCheckBox + + +class ProjectWidgets ( QObject ): + + def __init__ ( self, project ): + self._project = project + self._projectButton = QPushButton( self._project.getName() ) + self._projectButton.setStyleSheet( 'font-weight: bold;' ) + + self._toolsCheckBoxes = [] + for tool in self._project.getTools(): + self._toolsCheckBoxes += [ QCheckBox( tool ) ] + + #self._projectButton.clicked.connect( self.toggleToolsVisibility ) + return + + def _getProjectButton ( self ): return self._projectButton + def _getToolsCheckBoxes ( self ): return self._toolsCheckBoxes + + def _getActives ( self ): + actives = [] + for toolCb in self._toolsCheckBoxes: + if toolCb.isChecked(): actives += [ str(toolCb.text()) ] + return actives + + projectButton = property( _getProjectButton ) + toolsCheckBoxes = property( _getToolsCheckBoxes ) + actives = property( _getActives ) + + def addToLayout( self, column, layout ): + layout.addWidget( self._projectButton, 0, column, Qt.AlignLeft ) + for row in range(len(self._toolsCheckBoxes)): + layout.addWidget( self._toolsCheckBoxes[row], row+1, column, Qt.AlignTop ) + return + + #def toggleToolsVisibility ( self ): + # self._visibleTools = not self._visibleTools + # for toolCb in self._toolsCheckBoxes: + # toolCb.setVisible( self._visibleTools ) + # return + + def readFromSettings ( self ): + settings = QSettings() + for toolCb in self._toolsCheckBoxes: + toolId = 'tools/'+self._project.getName()+'/'+toolCb.text() + toolCb.setChecked( settings.value(toolId).toBool() ) + return + + def saveToSettings ( self ): + settings = QSettings() + for toolCb in self._toolsCheckBoxes: + toolId = 'tools/'+self._project.getName()+'/'+toolCb.text() + settings.setValue( toolId, toolCb.isChecked() ) + return diff --git a/bootstrap/builder/__init__.py b/bootstrap/builder/__init__.py new file mode 100644 index 00000000..bf225cf7 --- /dev/null +++ b/bootstrap/builder/__init__.py @@ -0,0 +1,64 @@ + +# -*- mode:Python -*- + +import sys + + +class ErrorMessage ( Exception ): + + def __init__ ( self, code, *arguments ): + self._code = code + self._errors = [ 'Malformed call to ErrorMessage()' + , '%s' % str(arguments) ] + + text = None + if len(arguments) == 1: + if isinstance(arguments[0],Exception): text = str(arguments[0]).split('\n') + else: + self._errors = arguments[0] + elif len(arguments) > 1: + text = list(arguments) + + if text: + self._errors = [] + while len(text[0]) == 0: del text[0] + + lstrip = 0 + if text[0].startswith('[ERROR]'): lstrip = 8 + + for line in text: + if line[0:lstrip ] == ' '*lstrip or \ + line[0:lstrip-1] == '[ERROR]': + self._errors += [ line[lstrip:] ] + else: + self._errors += [ line.lstrip() ] + return + + def __str__ ( self ): + if not isinstance(self._errors,list): + return "[ERROR] %s" % self._errors + + formatted = "\n" + for i in range(len(self._errors)): + if i == 0: formatted += "[ERROR] %s" % self._errors[i] + else: formatted += " %s" % self._errors[i] + if i+1 < len(self._errors): formatted += "\n" + return formatted + + def addMessage ( self, message ): + if not isinstance(self._errors,list): + self._errors = [ self._errors ] + if isinstance(message,list): + for line in message: + self._errors += [ line ] + else: + self._errors += [ message ] + return + + def terminate ( self ): + print self + sys.exit(self._code) + + def _getCode ( self ): return self._code + + code = property(_getCode) diff --git a/bootstrap/ccb.py b/bootstrap/ccb.py new file mode 100755 index 00000000..bc15ad27 --- /dev/null +++ b/bootstrap/ccb.py @@ -0,0 +1,256 @@ +#!/usr/bin/env python +# +# -*- mode:Python -*- +# +# This file is part of the Coriolis Software. +# Copyright (c) UPMC/LIP6 2008-2012, All Rights Reserved +# +# +-----------------------------------------------------------------+ +# | C O R I O L I S | +# | C o r i o l i s / C h a m s B u i l d e r | +# | | +# | Authors : Jean-Paul Chaput | +# | Damien Dupuis | +# | E-mail : Jean-Paul.Chaput@asim.lip6.fr | +# | =============================================================== | +# | Python : "./ccb.py" | +# +-----------------------------------------------------------------+ + +showTrace = True + +try: + import sys + import os.path + import optparse + import traceback + import distutils.sysconfig + import subprocess + import re +except ImportError, e: + module = str(e).split()[-1] + + print '[ERROR] The <%s> python module or symbol cannot be loaded.' % module + print ' Please check your standard Python installation, it may have problems.' + quit() + + +def safeImport ( moduleName, symbol=None ): + try: + module = __import__( moduleName, globals(), locals(), symbol ) + except ImportError, e: + print '[ERROR] The <%s> python module or symbol cannot be loaded.' % moduleName + print ' Please check the integrity of the package.' + if showTrace: traceback.print_tb(sys.exc_info()[2]) + sys.exit(1) + except Exception, e: + print '[ERROR] An exception occured while importing module <%s>. Is is a bug,' % moduleName + print ' you may want to report it...' + print ' %s' % e + if showTrace: traceback.print_tb(sys.exc_info()[2]) + sys.exit(2) + if symbol: return module.__dict__[symbol] + return module + + +def guessOs (): + libDir = 'lib' + osSlsoc6x_64 = re.compile (".*Linux.*el6.*x86_64.*") + osSlsoc6x = re.compile (".*Linux.*el6.*") + osSLSoC5x_64 = re.compile (".*Linux.*el5.*x86_64.*") + osSLSoC5x = re.compile (".*Linux.*(el5|2.6.23.13.*SoC).*") + osLinux_64 = re.compile (".*Linux.*x86_64.*") + osLinux = re.compile (".*Linux.*") + osFreeBSD8x_amd64 = re.compile (".*FreeBSD 8.*amd64.*") + osFreeBSD8x_64 = re.compile (".*FreeBSD 8.*x86_64.*") + osFreeBSD8x = re.compile (".*FreeBSD 8.*") + osDarwin = re.compile (".*Darwin.*") + + uname = subprocess.Popen ( ["uname", "-srm"], stdout=subprocess.PIPE ) + lines = uname.stdout.readlines() + + if osSlsoc6x_64.match(lines[0]): + osType = "Linux.slsoc6x_64" + libDir = "lib64" + elif osSlsoc6x .match(lines[0]): osType = "Linux.slsoc6x" + elif osSLSoC5x_64.match(lines[0]): + osType = "Linux.SLSoC5x_64" + libDir = "lib64" + elif osSLSoC5x .match(lines[0]): osType = "Linux.SLSoC5x" + elif osLinux_64.match(lines[0]): + osType = "Linux.x86_64" + libDir = "lib64" + elif osLinux .match(lines[0]): osType = "Linux.i386" + elif osDarwin.match(lines[0]): osType = "Darwin" + elif osFreeBSD8x_amd64.match(lines[0]): + osType = "FreeBSD.8x.amd64" + libDir = "lib64" + elif osFreeBSD8x_64.match(lines[0]): + osType = "FreeBSD.8x.x86_64" + libDir = "lib64" + elif osFreeBSD8x.match(lines[0]): + osType = "FreeBSD.8x.i386" + else: + uname = subprocess.Popen ( ["uname", "-sr"], stdout=subprocess.PIPE ) + osType = uname.stdout.readlines()[0][:-1] + + print "[WARNING] Unrecognized OS: \"%s\"." % lines[0][:-1] + print " (using: \"%s\")" % osType + + return osType, libDir + + +def guessPythonSitePackage (): + pathes = distutils.sysconfig.get_python_lib().split('/')[-2:] + return os.path.join( pathes[0], pathes[1] ) + + +def autoLocate (): + print 'Making an educated guess to locate myself:' + sitePackage = guessPythonSitePackage() + osType, libDir = guessOs() + + builderDir = None + locations = [ os.path.abspath(os.path.dirname(sys.argv[0])) + , os.environ['HOME']+'/coriolis-2.x/src/bootstrap' + , os.environ['HOME']+'/coriolis/src/bootstrap' + , os.environ['HOME']+'/chams-1.x/src/bootstrap' + , os.environ['HOME']+'/chams/src/bootstrap' + , '/users/outil/coriolis/coriolis-2.x/src/bootstrap' + , os.environ['HOME']+'/coriolis-2.x/'+osType+'/Release.Shared/install/'+libDir+'/'+sitePackage + , os.environ['HOME']+'/chams-1.x/'+osType+'/Release.Shared/install/'+libDir+'/'+sitePackage + , os.environ['HOME']+'/chams/'+osType+'/Release.Shared/install/'+libDir+'/'+sitePackage + , '/users/outil/coriolis/coriolis-2.x/'+osType+'/Release.Shared/install/'+libDir+'/'+sitePackage + ] + + for location in locations: + print ' <%s>' % location, + if os.path.isfile(location + '/builder/__init__.py'): + if not builderDir: + builderDir = location + print '(Found*)' + else: + print '(Found)' + else: + print '(No)' + + if not builderDir: + print '[ERROR] Failed to locate the builder modules in any of the normal pathes.' + print ' Please check your Coriolis/Bootsrap installation.' + if showTrace: traceback.print_tb(sys.exc_info()[2]) + sys.exit(1) + + sys.path.insert( 0, builderDir ) + return + + +# ------------------------------------------------------------------- +# CCB Main Part. + +autoLocate() + +parser = optparse.OptionParser () +parser.add_option ( "-g", "--gui" , action="store_true" , dest="gui" , help="Lauch the graphical interface." ) +# Build relateds. +parser.add_option ( "-c", "--conf", type="string", dest="conf" , help="Fichier de configuration." ) +parser.add_option ( "--show-conf" , action="store_true" , dest="showConf" , help="Display the Project/Tools configuration, then exit." ) +parser.add_option ( "-q", "--quiet" , action="store_true" , dest="quiet" , help="Do not print all the informative messages." ) +parser.add_option ( "-r", "--release" , action="store_true" , dest="release" , help="Build a aka optimized version." ) +parser.add_option ( "-d", "--debug" , action="store_true" , dest="debug" , help="Build a aka (-g) version." ) +parser.add_option ( "-s", "--static" , action="store_true" , dest="static" , help="Try to link statically, as much as possible." ) +parser.add_option ( "--doc" , action="store_true" , dest="doc" , help="Enable the documentation building (uses with -j1)." ) +parser.add_option ( "-v", "--verbose" , action="store_true" , dest="verboseMakefile" , help="Tells CMake to print all compilation commands." ) +parser.add_option ( "--root" , action="store" , type="string", dest="rootDir" , help="The root directory (default: <~/coriolis-2.x/>)." ) +parser.add_option ( "--no-build" , action="store_true" , dest="noBuild" , help="Do *not* build anything (by default: build)." ) +parser.add_option ( "--no-cache" , action="store_true" , dest="noCache" , help="Remove previous CMake cache before building." ) +parser.add_option ( "--rm-build" , action="store_true" , dest="rmBuild" , help="Remove previous build directoty before building." ) +parser.add_option ( "--make" , action="store" , type="string", dest="makeArguments", help="Arguments to pass to make (ex: \"-j4 install\")." ) +parser.add_option ( "--project" , action="append" , type="string", dest="projects" , help="The name of a project to build (may appears any number of time)." ) +parser.add_option ( "-t", "--tool" , action="append" , type="string", dest="tools" , help="The name of a tool to build (may appears any number of time)." ) +# SVN repository relateds. +parser.add_option ( "--svn-tag" , action="store" , type="string", dest="svnTag" , help="Explicitly select a SVN tag (for SVN related commands)." ) +parser.add_option ( "--svn-method" , action="store" , type="string", dest="svnMethod" , help="Allows to sets the svn checkout method (svn+ssh://coriolis.soc.lip6.fr)." ) +parser.add_option ( "--svn-status" , action="store_true" , dest="svnStatus" , help="Check status against the SVN repository." ) +parser.add_option ( "--svn-diff" , action="store_true" , dest="svnDiff" , help="Perform a diff against the SVN repository." ) +parser.add_option ( "--svn-update" , action="store_true" , dest="svnUpdate" , help="Update to the latest SVN version *or* the one given by svn-tag." ) +parser.add_option ( "--svn-checkout" , action="store_true" , dest="svnCheckout", help="Checkout the latest SVN version *or* the one given by svn-tag." ) +# Miscellaneous. +parser.add_option ( "--user-tarball" , action="store_true" , dest="userTarball", help="Regenerate a tarball from checked out sources (in /tarball/." ) +parser.add_option ( "--tarball" , action="store_true" , dest="tarball" , help="Regenerate a tarball (in /tarball/." ) +parser.add_option ( "--rpm" , action="store_true" , dest="doRpm" , help="Regenerate RPM packages." ) +parser.add_option ( "--deb" , action="store_true" , dest="doDeb" , help="Regenerate Debian/Ubuntu packages." ) +# Katabatic/Kite specific options. +parser.add_option ( "-D", "--check-db" , action="store_true" , dest="checkDb" , help="Enable Katabatic/Kite data-base checking (*very* slow)." ) +parser.add_option ( "-u", "--check-deter", action="store_true" , dest="checkDeterminism", help="Enable Katabatic/Kite determinism checking (*very* slow)." ) +(options, args) = parser.parse_args () + +if options.gui: + ErrorMessage = safeImport( 'builder' , 'ErrorMessage' ) + QApplication = safeImport( 'PyQt4.QtGui' , 'QApplication' ) + BuilderGui = safeImport( 'builder.BuilderGui', 'BuilderGui' ) + + try: + app = QApplication( sys.argv ) + app.setOrganizationName ( 'UPMC' ) + app.setOrganizationDomain( 'lip6.fr' ) + app.setApplicationName ( 'CoriolisBuilder' ) + gui = BuilderGui( options.conf ) + gui.show() + rcode = app.exec_() + sys.exit( rcode ) + except ErrorMessage, e: + print e + if showTrace: traceback.print_tb(sys.exc_info()[2]) + sys.exit(2) + except Exception, e: + print '[ERROR] An exception occured while running the Qt application.' + print ' %s' % e + if showTrace: traceback.print_tb(sys.exc_info()[2]) + sys.exit(2) + +else: + + ErrorMessage = safeImport( 'builder' , 'ErrorMessage' ) + Builder = safeImport( 'builder.Builder', 'Builder' ) + + try: + builder = Builder() + builder.loadConfiguration( options.conf ) + + if options.showConf: + builder.showConfiguration () + sys.exit(0) + + if options.quiet: builder.quiet = True + if options.release: builder.buildMode = "Release" + if options.debug: builder.buildMode = "Debug" + if options.static: builder.enableShared = "OFF" + if options.doc: builder.enableDoc = "ON" + if options.checkDb: builder.checkDatabase = "ON" + if options.checkDeterminism: builder.enableDeterminism = "ON" + if options.verboseMakefile: builder.verboseMakefile = "ON" + if options.rootDir: builder.rootDir = options.rootDir + if options.noBuild: builder.doBuild = False + if options.noCache: builder.noCache = True + if options.rmBuild: builder.rmBuild = True + if options.makeArguments: builder.makeArguments = options.makeArguments + if options.svnMethod: builder.svnMethod = options.svnMethod + if options.svnTag: builder.svnTag = options.svnTag + + if options.svnStatus: builder.svnStatus ( tools=options.tools, projects=options.projects ) + elif options.svnUpdate: builder.svnUpdate ( tools=options.tools, projects=options.projects ) + elif options.svnDiff: builder.svnDiff ( tools=options.tools, projects=options.projects ) + elif options.svnCheckout: builder.svnCheckout ( tools=options.tools, projects=options.projects ) + elif options.userTarball: builder.userTarball ( tools=options.tools, projects=options.projects ) + elif options.tarball: builder.svnTarball ( tools=options.tools, projects=options.projects ) + elif options.doRpm: builder.doRpm () + elif options.doDeb: builder.doDeb () + else: builder.build ( tools=options.tools, projects=options.projects ) + except ErrorMessage, e: + print e + if showTrace: traceback.print_tb(sys.exc_info()[2]) + sys.exit(e.code) + except KeyboardInterrupt, e: + print '\n[ERROR] Interrupted by user\'s request (CTRL+C)' + sys.exit(1) + +sys.exit(0)