2 import vcs, build_system, imp
3 import argparse, os, sys, subprocess
4 from collections import OrderedDict
8 def __init__(self, folder, config):
10 self.name = config['name']
12 vcsName = config['vcs']
14 self.vcs = vcs.Git(self.sourceFolder(), config['url'], config['version'])
15 elif vcsName == 'svn':
16 self.vcs = vcs.SVN(self.sourceFolder(), config['url'], config.get('versionName'))
18 raise Exception("Unknown VCS type "+vcsName)
20 if config.get('buildDeb', False):
21 self.buildSystem = build_system.AutoDebuild(self.sourceFolder(), self.buildFolder(), config, self.vcs)
23 buildSystemName = config['buildSystem']
24 if buildSystemName == 'cmake':
25 self.buildSystem = build_system.CMake(self.sourceFolder(), self.buildFolder(), config)
27 raise Exception("Unknown build system type "+buildSystemName)
29 def sourceFolder(self):
30 return os.path.join(self.folder, self.name)
32 def buildFolder(self):
33 return os.path.join(config['buildDir'], self.sourceFolder())
35 # read command-line arguments
36 parser = argparse.ArgumentParser(description='Update and build a bunch of stuff')
37 parser.add_argument("-c, --config",
38 dest="config", default="mass-build.conf",
39 help="mass-build config file")
40 parser.add_argument("--reconfigure",
41 action="store_true", dest="reconfigure",
42 help="Force configuration to be run")
43 parser.add_argument("--reset-source",
44 action="store_true", dest="reset_source",
45 help="Reset sourcecode to the given version (removes local changes!)")
46 parser.add_argument("--no-update",
47 action="store_false", dest="update",
48 help="Do not update projects before compilation")
49 parser.add_argument("--resume-from", metavar='PROJECT',
51 help="Resume building from the given project")
52 parser.add_argument("projects", metavar='PROJECT', nargs='*',
53 help="Manually specify projects or folders to be built (project names take precedence)")
54 args = parser.parse_args()
56 if args.reset_source and not args.update:
57 raise Exception("When no update is performed, no reset to the given version can be done either")
60 config = imp.load_source('config', args.config).__dict__
61 os.remove(args.config+'c') # remove compiled python file
62 allProjects = OrderedDict() # all projects
63 allFolders = {} # all folders
64 workProjects = [] # projects we work on
66 # return the position of the given item in the list
67 def findInList(list, item):
68 for i in xrange(len(list)):
71 raise Exception("%s not found in list" % str(item))
73 # copy all items which don't exist below, except for those in the exclude list
74 def inherit(subConfig, superConfig, exclude = ('name', 'projects')):
75 for name in superConfig.keys():
76 if (not name in subConfig) and (not name in exclude):
77 subConfig[name] = superConfig[name]
79 # populate list of projects, return list of projects in that folder
80 def loadProjects(config, folder=''):
82 for projectConfig in config['projects']:
83 assert 'name' in projectConfig # everything must have a name
84 inherit(projectConfig, config)
85 if 'projects' in projectConfig: # a subpath
86 folderProjects += loadProjects(projectConfig, os.path.join(folder, projectConfig['name']))
87 else: # a proper project
88 if projectConfig['name'] in allProjects:
89 raise Exception("Duplicate project name "+projectConfig['name'])
90 project = Project(folder, projectConfig)
91 allProjects[projectConfig['name']] = project
92 folderProjects.append(project)
93 # store projects of this folder
94 if folder in allFolders:
95 raise Exception("Duplicate folder name "+folder)
96 allFolders[folder] = folderProjects
99 # now check what we have to do
102 if args.resume_from is not None:
103 raise Exception("Can not use --resume-from and manually specify projects")
104 for name in args.projects:
105 if name in allProjects:
106 workProjects.append(allProjects[name])
107 elif name in allFolders:
108 workProjects += allFolders[name]
110 raise Exception("Project or folder%s does not exist" % name)
111 elif args.resume_from is None:
112 workProjects = projects.values() # all the projects
114 if not args.resume_from in allProjects:
115 raise Exception("Project %s does not exist" % args.resume_from)
116 startWith = allProjects[args.resume_from]
117 startIndex = findInList(allProjects.values(), startWith)
118 workProjects = allProjects.values()[startIndex:]
121 for project in workProjects:
124 print "Updating project",project.sourceFolder()
125 project.vcs.update(forceVersion=args.reset_source)
126 print "Building project",project.sourceFolder()
127 project.buildSystem.build(reconfigure=args.reconfigure)
129 except (subprocess.CalledProcessError, KeyboardInterrupt) as e: # for some exceptions, a stackrace is usually pointless
132 if isinstance(e, KeyboardInterrupt): # str(e) would be the empty string
133 print >> sys.stderr, "Interruped by user while processing %s" % (project.name)
135 print >> sys.stderr, "Error while processing %s: %s" % (project.name, str(e))