From b82c0cdbd36ccfbdff73f65616f30f7d22f9083b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 12 Jun 2012 21:52:04 +0200 Subject: [PATCH 1/1] Initial project import --- build_system.py | 37 +++++++++++++++++ config.py.sample | 31 ++++++++++++++ kdebuildpy.py | 104 +++++++++++++++++++++++++++++++++++++++++++++++ vcs.py | 62 ++++++++++++++++++++++++++++ 4 files changed, 234 insertions(+) create mode 100644 build_system.py create mode 100644 config.py.sample create mode 100755 kdebuildpy.py create mode 100644 vcs.py diff --git a/build_system.py b/build_system.py new file mode 100644 index 0000000..5035e68 --- /dev/null +++ b/build_system.py @@ -0,0 +1,37 @@ +import os, subprocess + +'''A build system has three methods: "configure" (with optionak "force" parameter), "build" and "install"''' + +# Compile, build, and install cmake projects: +class CMake: + def __init__(self, sourceFolder, buildFolder, config): + self.sourceFolder = os.path.abspath(sourceFolder) + self.buildFolder = os.path.abspath(buildFolder) + self.installDir = config.installDir + self.buildType = config.buildType + self.jobs = config.jobs + self.buildCmdPrefix = config.buildCmdPrefix + self.installCmdPrefix = config.installCmdPrefix + + def configure(self, force=False): + print "Configuring",self.folder + if not os.path.exists(self.buildFolder): os.makedirs(self.buildFolder) + os.chdir(self.buildFolder) + # check if we actually need to work + cacheFile = 'CMakeCache.txt' + if os.path.exists(cacheFile) and os.path.exists('Makefile') and not force: return + # yes we do! make sure we start clean, and then go ahead + if os.path.exists(cacheFile): os.remove(cacheFile) + os.putenv('PKG_CONFIG_PATH', os.path.join(self.installDir, 'lib', 'pkgconfig')) # I found no way to do this within cmake + subprocess.check_call(['cmake', self.sourceFolder, '-DCMAKE_BUILD_TYPE='+self.buildType, '-DCMAKE_INSTALL_PREFIX='+self.installDir]) + os.unsetenv('PKG_CONFIG_PATH') + + def build(self): + print "Building",self.folder + os.chdir(self.buildFolder) + subprocess.check_call(self.buildCmdPrefix + ['make', '-j'+str(self.jobs)]) + + def install(self): + print "Installing",self.folder + os.chdir(self.buildFolder) + subprocess.check_call(self.installCmdPrefix + ['make', 'install']) diff --git a/config.py.sample b/config.py.sample new file mode 100644 index 0000000..3aa886c --- /dev/null +++ b/config.py.sample @@ -0,0 +1,31 @@ +# global configuration +installDir = '/opt/kde' +buildDir = 'build' +buildType = 'Debug' +jobs = 2 +buildCmdPrefix = ['nice'] +installCmdPrefix = [] +# the modules we are interested in +KDEBranch = 'KDE/4.8' +modules = [ + # KDE core +# {'type': 'kde+svn', 'in-folder': 'kde', 'name': 'oxygen-icons', 'svn-path': 'tags/KDE/4.8.2/oxygen-icons'}, + {'type': 'kde+git', 'in-folder': 'kde', 'name': 'kdelibs', 'version': 'origin/'+KDEBranch}, + {'type': 'kde+git', 'in-folder': 'kde', 'name': 'kactivities', 'version': 'origin/'+KDEBranch}, + {'type': 'kde+git', 'in-folder': 'kde', 'name': 'kdepimlibs', 'version': 'origin/'+KDEBranch}, + {'type': 'kde+git', 'in-folder': 'kde', 'name': 'kde-runtime', 'version': 'origin/'+KDEBranch}, + {'type': 'kde+git', 'in-folder': 'kde', 'name': 'kde-workspace', 'version': 'origin/'+KDEBranch}, + {'type': 'kde+git', 'in-folder': 'kde', 'name': 'kde-baseapps', 'version': 'origin/'+KDEBranch}, +# {'type': 'kde+git', 'in-folder': 'kde', 'name': 'kdepim-runtime', 'version': 'origin/'+KDEBranch}, + # KDE applications +# {'type': 'kde+svn', 'in-folder': 'kde', 'name': 'kde-wallpapers', 'svn-path': 'branches/'+KDEBranch+'/kde-wallpapers'}, + {'type': 'kde+svn', 'in-folder': 'kde', 'name': 'kdenetwork', 'svn-path': 'branches/'+KDEBranch+'/kdenetwork'}, + {'type': 'kde+git', 'in-folder': 'kde', 'name': 'konsole', 'version': 'origin/'+KDEBranch}, + {'type': 'kde+git', 'in-folder': 'kde', 'name': 'kate', 'version': 'origin/'+KDEBranch}, + {'type': 'kde+git', 'in-folder': 'kde', 'name': 'kwallet', 'version': 'origin/'+KDEBranch}, + # Extragear applications, addons +# {'type': 'kde+git', 'in-folder': 'extragear', 'name': 'polkit-kde-agent-1', 'version': 'v0.99.0'}, + {'type': 'kde+git', 'in-folder': 'extragear', 'name': 'networkmanagement', 'version': 'v0.9.0.1'}, +# {'type': 'kde+git', 'in-folder': 'extragear', 'name': 'kdevplatform', 'version': 'v1.2.3'}, +# {'type': 'kde+git', 'in-folder': 'extragear', 'name': 'kdevelop', 'version': 'v4.2.3'}, +] diff --git a/kdebuildpy.py b/kdebuildpy.py new file mode 100755 index 0000000..720c96b --- /dev/null +++ b/kdebuildpy.py @@ -0,0 +1,104 @@ +#!/usr/bin/python +import vcs, build_system, imp +import argparse, os, sys, subprocess +from collections import OrderedDict + +# read command-line arguments +parser = argparse.ArgumentParser(description='Build KDE') +parser.add_argument("-c, --config", + dest="config", default="config.py", + help="kdebuildpy config file") +parser.add_argument("--reconfigure", + action="store_true", dest="reconfigure", + help="Force configuration to be run") +parser.add_argument("--phases", choices=["update", "configure", "compile"], nargs='*', metavar='PHASE', + dest="phases", default=["update", "configure", "compile"], + help="For each module, run the given phases in the given order. Possible phases are: update, configure, compile") +parser.add_argument("--resume-from", metavar='MODULE', + dest="resume_from", + help="Resume building from the given repository") +parser.add_argument("modules", metavar='MODULE', nargs='*', + help="Manually specify modules to be built") +args = parser.parse_args() + +# load config +config = imp.load_source('config', args.config) + +# template for a KDE project: combine git/svn with cmake +def sourceFolder(module): + return os.path.join(module['in-folder'], module['name']) +def buildFolder(module): + return os.path.join(config.buildDir, sourceFolder(module)) + +class KDEGitProject(vcs.Git, build_system.CMake): + def __init__(self, module): + vcs.Git.__init__(self, sourceFolder(module),'kde:'+module['name'], module['version']) + build_system.CMake.__init__(self, sourceFolder(module), buildFolder(module), config) + self.name = module['name'] + +class KDESVNProject(vcs.SVN, build_system.CMake): + def __init__(self, module): + vcs.SVN.__init__(self, sourceFolder(module), 'svn://svn.kde.org/home/kde/'+module['svn-path']) + build_system.CMake.__init__(self, sourceFolder(module), buildFolder(module), config) + self.name = module['name'] + +moduleTypes = { + 'kde+git': KDEGitProject, + 'kde+svn': KDESVNProject +} + +# return the position of the given item in the list +def findInList(list, item): + for i in xrange(len(list)): + if list[i] == item: + return i + raise Exception("%s not found in list" % str(item)) + +# collect list of projects (separate run, since the actual compilation will change the working directory!) +projects = OrderedDict() +for module in config.modules: + if module['name'] in projects: + raise Exception("Duplicate module name "+module['name']) + if not module['type'] in moduleTypes: + raise Exception("Invalid module type "+module['type']) + projects[module['name']] = moduleTypes[module['type']](module) # create module of proper type + +# now check what we have to do +workProjects = [] +if args.modules: + if args.resume_from is not None: + raise Exception("Can not use --resume-from and manually specify modules") + for module in args.modules: + if not module in projects: + raise Exception("Project %s does not exist" % module) + workProjects.append(projects[module]) +elif args.resume_from is None: workProjects = projects.values() # all the projects +else: + if not args.resume_from in projects: + raise Exception("Project %s does not exist" % args.resume_from) + startWith = projects[args.resume_from] + startIndex = findInList(projects.values(), startWith) + workProjects = projects.values()[startIndex:] + +# and do it! +for project in workProjects: + try: + for phase in args.phases: + if phase == 'update': + project.update() + elif phase == 'configure': + project.configure(force=args.reconfigure) + elif phase == 'compile': + project.build() + project.install() + else: + raise Exception("Invalid phase "+phase) + except (subprocess.CalledProcessError, KeyboardInterrupt) as e: + print >> sys.stderr + print >> sys.stderr + if isinstance(e, KeyboardInterrupt): # str(e) would be the empty string + print >> sys.stderr, "Interruped by user while processing %s" % (project.name) + else: + print >> sys.stderr, "Error while processing %s: %s" % (project.name, str(e)) + print >> sys.stderr + sys.exit(1) diff --git a/vcs.py b/vcs.py new file mode 100644 index 0000000..994f03b --- /dev/null +++ b/vcs.py @@ -0,0 +1,62 @@ +import os, git, subprocess + +'''A VCS must have an "update" method with an optional "force" parameter.''' + +# Fetch updates from git +class Git: + def __init__(self, folder, url, commit): + self.folder = os.path.abspath(folder) + self.url = url + self.commit = commit + + class _ProgressPrinter(git.remote.RemoteProgress): + def update(self, op_code, cur_count, max_count=None, message=''): + print self._cur_line+(" "*30)+"\r", + + def update(self): + print "Updating",self.folder + isBranch = (self.commit.startswith('origin/')) + if isBranch: + branchname = self.commit[len('origin/'):] + else: + branchname = "tag" + # get us a git repository, and the "origin" remote + if os.path.exists(self.folder): + # load existing repo + repo = git.Repo(self.folder) + origin = repo.remotes.origin + else: + # create a new one + os.makedirs(self.folder) + repo = git.Repo.init(self.folder) + origin = repo.create_remote('origin', self.url) + origin.fetch(progress=Git._ProgressPrinter()) # download new data + print " "*80+"\r", # clean the line we are in + # create/find correct branch + if branchname in repo.heads: + branch = repo.heads[branchname] + else: + branch = repo.create_head(branchname, self.commit) + if isBranch: + branch.set_tracking_branch(origin.refs[branchname]) + # update it to the latest remote commit + branch.checkout() + repo.git.rebase(self.commit) + print "...done", + if repo.head.reference.commit != repo.refs[self.commit].commit: + print "(keeping local patches around)", + print + +# Fetch updates via SVN +class SVN: + def __init__(self, folder, svnPath): + self.folder = os.path.abspath(folder) + self.svnPath = svnPath + + def update(self): + print "Updating",self.folder + if os.path.exists(self.folder): + os.chdir(self.folder) # go into repository + subprocess.check_call(['svn', 'switch', self.svnPath]) # and update to the URL we got + else: + subprocess.check_call(['svn', 'co', self.svnPath, self.folder])# just download it -- 2.30.2