--- /dev/null
+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'])
--- /dev/null
+# 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'},
+]
--- /dev/null
+#!/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)
--- /dev/null
+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