11e519966e783aafea3ae3c357f8153d4e9ff604
[mass-build.git] / mass_build.py
1 #!/usr/bin/python
2 import vcs, build_system, imp
3 import argparse, os, sys, subprocess
4 from collections import OrderedDict
5
6 # read command-line arguments
7 parser = argparse.ArgumentParser(description='Update and build a bunch of stuff')
8 parser.add_argument("-c, --config",
9                     dest="config", default="mass-build.conf",
10                     help="mass-build config file")
11 parser.add_argument("--reconfigure",
12                     action="store_true", dest="reconfigure",
13                     help="Force configuration to be run")
14 parser.add_argument("--reset-source",
15                     action="store_true", dest="reset_source",
16                     help="Reset sourcecode to the given version (removes local changes!)")
17 parser.add_argument("--no-update",
18                     action="store_false", dest="update",
19                     help="Do not update modules before compilation")
20 parser.add_argument("--resume-from", metavar='MODULE',
21                     dest="resume_from",
22                     help="Resume building from the given repository")
23 parser.add_argument("modules",  metavar='MODULE', nargs='*',
24                     help="Manually specify modules to be built")
25 args = parser.parse_args()
26 # sanitize
27 if args.reset_source and not args.update:
28         raise Exception("When no update is performed, no reset to the given version can be done either")
29
30 # load config
31 config = imp.load_source('config', args.config).__dict__
32 os.remove(args.config+'c') # remove compiled python file
33 projects = OrderedDict() # all projects
34 workProjects = [] # projects we work on
35
36 # an entire Project
37 class Project:
38         def __init__(self, config, folder, module):
39                 self.folder = folder
40                 self.name = module['name']
41                 # VCS
42                 vcsName = module['vcs']
43                 if vcsName == 'git':
44                         self.vcs = vcs.Git(self.sourceFolder(), module['url'], module['version'])
45                 elif vcsName == 'svn':
46                         self.vcs = vcs.SVN(self.sourceFolder(), module['url'], module.get('versionName'))
47                 else:
48                         raise Exception("Unknown VCS type "+vcsName)
49                 # build system
50                 if config.get('buildDeb', False):
51                         self.buildSystem = build_system.AutoDebuild(self.sourceFolder(), self.buildFolder(), module, self.vcs, config)
52                 else:
53                         buildSystemName = module['buildSystem']
54                         if buildSystemName == 'cmake':
55                                 self.buildSystem = build_system.CMake(self.sourceFolder(), self.buildFolder(), module, config)
56                         else:
57                                 raise Exception("Unknown build system type "+buildSystemName)
58         
59         def sourceFolder(self):
60                 return os.path.join(self.folder, self.name)
61         
62         def buildFolder(self):
63                 return os.path.join(config['buildDir'], self.sourceFolder())
64
65 # return the position of the given item in the list
66 def findInList(list, item):
67         for i in xrange(len(list)):
68                 if list[i] == item:
69                         return i
70         raise Exception("%s not found in list" % str(item))
71
72 # populate list of projects
73 def loadProjects(config, modules, folder=''):
74         for module in modules:
75                 if 'folder' in module: # a subpath
76                         loadProjects(config, module['modules'], os.path.join(folder, module['folder']))
77                 else: # a proper project
78                         if module['name'] in projects:
79                                 raise Exception("Duplicate module name "+module['name'])
80                         projects[module['name']] = Project(config, folder, module)
81
82 # now check what we have to do
83 loadProjects(config, config['modules'])
84 if args.modules:
85         if args.resume_from is not None:
86                 raise Exception("Can not use --resume-from and manually specify modules")
87         for module in args.modules:
88                 if not module in projects:
89                         raise Exception("Project %s does not exist" % module)
90                 workProjects.append(projects[module])
91 elif args.resume_from is None:
92         workProjects = projects.values() # all the projects
93 else:
94         if not args.resume_from in projects:
95                 raise Exception("Project %s does not exist" % args.resume_from)
96         startWith = projects[args.resume_from]
97         startIndex = findInList(projects.values(), startWith)
98         workProjects = projects.values()[startIndex:]
99
100 # and do it!
101 for project in workProjects:
102         try:
103                 if args.update:
104                         print "Updating module",project.sourceFolder()
105                         project.vcs.update(forceVersion=args.reset_source)
106                 print "Building module",project.sourceFolder()
107                 project.buildSystem.build(reconfigure=args.reconfigure)
108                 print
109         except (subprocess.CalledProcessError, KeyboardInterrupt) as e: # for some exceptions, a stackrace is usually pointless
110                 print >> sys.stderr
111                 print >> sys.stderr
112                 if isinstance(e, KeyboardInterrupt): # str(e) would be the empty string
113                         print >> sys.stderr, "Interruped by user while processing %s" % (project.name)
114                 else:
115                         print >> sys.stderr, "Error while processing %s: %s" % (project.name, str(e))
116                 print >> sys.stderr
117                 sys.exit(1)