1 # mass-build - Easily Build Software Involving a Large Amount of Source Repositories
2 # Copyright (C) 2012-2013 Ralf Jung <post@ralfj.de>
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 import os, shutil, subprocess, multiprocessing
20 '''A build system must have a "build" method with parameters "reconfigure" and "waitAfterConfig".'''
22 # Compile, build, and install cmake projects:
24 def __init__(self, sourceFolder, buildFolder, config):
25 self.sourceFolder = os.path.abspath(sourceFolder)
26 self.buildFolder = os.path.abspath(buildFolder)
29 def setEnv(self, name, val):
30 '''Set the given environment variable, return old value'''
31 oldVal = os.getenv(name)
35 def prependDirToEnv(self, name, dir, default):
36 '''Prepends the given directory to the environment variable. If the variable is empty, dir isprepended to the default.
37 Returns the old value.'''
38 oldVal = os.getenv(name)
39 oldPaths = default if oldVal is None else oldVal
40 os.putenv(name, dir+':'+oldPaths)
43 def restoreEnv(self, name, oldVal):
44 '''Restore environment variable to previous value'''
48 os.putenv(name, oldVal)
50 def build(self, reconfigure, waitAfterConfig):
51 # Make sure we have a build directory
52 if not os.path.exists(self.buildFolder): os.makedirs(self.buildFolder)
53 os.chdir(self.buildFolder)
54 # In case of reconfiguration, delete cache file if it exists
55 cacheFile = 'CMakeCache.txt'
56 if os.path.exists(cacheFile) and reconfigure: os.remove(cacheFile)
57 # Run cmake, in the proper environment, then restore old environment
58 oldPKGConfigPath = self.setEnv('PKG_CONFIG_PATH', os.path.join(self.config['installDir'], 'lib', 'pkgconfig'))
59 oldCMakePrefixPath = self.setEnv('CMAKE_PREFIX_PATH', self.config['installDir'])
60 oldXDGDataDirs = self.prependDirToEnv('XDG_DATA_DIRS', os.path.join(self.config['installDir'], 'share'), '/usr/share')
61 oldXDGConfigDirs = self.prependDirToEnv('XDG_CONFIG_DIRS', os.path.join(self.config['installDir'], 'etc', 'xdg'), '/etc/xdg')
62 subprocess.check_call(['cmake', self.sourceFolder, '-DCMAKE_BUILD_TYPE='+self.config['buildType'],
63 '-DCMAKE_INSTALL_PREFIX='+self.config['installDir']]+self.config.get('cmakeParameters', []))
64 self.restoreEnv('PKG_CONFIG_PATH', oldPKGConfigPath)
65 self.restoreEnv('CMAKE_PREFIX_PATH', oldCMakePrefixPath)
66 self.restoreEnv('XDG_DATA_DIRS', oldXDGDataDirs)
67 self.restoreEnv('XDG_CONFIG_DIRS', oldXDGConfigDirs)
68 # if asked to do so, wait
70 input('Configuration done. Hit "Enter" to build the project. ')
72 jobs = multiprocessing.cpu_count()+1
73 subprocess.check_call(self.config.get('buildCmdPrefix', []) + ['make', '-j'+str(jobs)])
75 subprocess.check_call(self.config.get('installCmdPrefix', []) + ['make', 'install', '-j'+str((jobs+1)//2)]) # jobs/2, rounded up
77 # if auto-debuild is available, provide a wrapper for it
81 def __init__(self, sourceFolder, buildFolder, config, vcs):
82 self.sourceFolder = os.path.abspath(sourceFolder)
83 self.buildFolder = os.path.abspath(buildFolder)
84 self.debFolder = os.path.abspath(config['debDir'])
88 def build(self, reconfigure, waitAfterConfig): # reconfigure is ignored (we always do a reconfiguration)
90 versionName = self.config['versionName'] if 'versionName' in self.config else self.vcs.version()
91 if versionName is None:
92 raise Exception("VCS did not provide us with a proper version number, please provide one manually")
93 # create auto-debuild configuration
95 'sourceName': self.config['name'],
96 'buildSystem': self.config['buildSystem'],
97 'debDir': self.debFolder,
98 'buildDir': self.buildFolder,
99 'name': self.config['debName'],
100 'email': self.config['debEMail'],
101 'version': versionName + self.config.get('versionSuffix', ''),
102 'waitAfterConfig': waitAfterConfig,
104 # copy some more optional configuration
105 for option in ('epoch', 'dbgPackage', 'section', 'withPython2', 'withSIP', 'binarySkipFiles', 'binaryInstallFiles',
106 'buildDepends', 'binaryDepends', 'binaryShims', 'binaryRecommends', 'binaryProvides', 'binaryConflicts', 'binaryBreaks',
107 'binaryReplaces', 'binaryBreaksReplaces',
108 'alternatives', 'cmakeParameters', 'automakeParameters'):
109 if option in self.config:
110 autoDebuildConfig[option] = self.config[option]
111 # create Debian files
112 os.chdir(self.sourceFolder)
113 if os.path.isdir('debian'): # clean previous build attempts
114 shutil.rmtree('debian')
115 files = auto_debuild.createDebianFiles(autoDebuildConfig)
117 auto_debuild.buildDebianPackage(autoDebuildConfig)
119 if self.config.get('debInstall', True):
120 subprocess.check_call(['sudo', 'dpkg', '--install'] + files)
123 #print "auto_debuild not found, disabling auto-debuild system"