make configuration more flexible and more readable
[mass-build.git] / kdebuildpy.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='Build KDE')
8 parser.add_argument("-c, --config",
9                     dest="config", default="config.py",
10                     help="kdebuildpy config file")
11 parser.add_argument("--reconfigure",
12                     action="store_true", dest="reconfigure",
13                     help="Force configuration to be run")
14 parser.add_argument("--phases", choices=["update", "configure", "compile"], nargs='*', metavar='PHASE',
15                     dest="phases", default=["update", "configure", "compile"],
16                     help="For each module, run the given phases in the given order. Possible phases are: update, configure, compile")
17 parser.add_argument("--resume-from", metavar='MODULE',
18                     dest="resume_from",
19                     help="Resume building from the given repository")
20 parser.add_argument("modules",  metavar='MODULE', nargs='*',
21                     help="Manually specify modules to be built")
22 args = parser.parse_args()
23
24 # load config
25 config = imp.load_source('config', args.config)
26 projects = OrderedDict() # all projects
27 workProjects = [] # projects we work on
28
29 # an entire Project
30 class Project:
31         def __init__(self, folder, module):
32                 self.folder = folder
33                 self.name = module['name']
34                 # VCS
35                 vcsName = module.get('vcs', 'kde+git')
36                 if vcsName == 'kde+git':
37                         self.vcs = vcs.KDEGit(self.sourceFolder(), module['name'], module['version'])
38                 elif vcsName == 'kde+svn':
39                         self.vcs = vcs.KDESVN(self.sourceFolder(), module['svn-path'])
40                 else:
41                         raise Exception("Unknown VCS type "+vcsName)
42                 # build system
43                 buildSystemName = module.get('build-system', 'cmake')
44                 if buildSystemName == 'cmake':
45                         self.buildSystem = build_system.CMake(self.sourceFolder(), self.buildFolder(), config)
46                 else:
47                         raise Exception("Unknown build system type "+buildSystemName)
48         
49         def sourceFolder(self):
50                 return os.path.join(self.folder, self.name)
51         
52         def buildFolder(self):
53                 return os.path.join(config.buildDir, self.sourceFolder())
54
55 # return the position of the given item in the list
56 def findInList(list, item):
57         for i in xrange(len(list)):
58                 if list[i] == item:
59                         return i
60         raise Exception("%s not found in list" % str(item))
61
62 # populate list of projects
63 def loadProjects(modules, folder=''):
64         for module in modules:
65                 if 'folder' in module: # a subpath
66                         loadProjects(module['modules'], os.path.join(folder, module['folder']))
67                 else: # a proper project
68                         if module['name'] in projects:
69                                 raise Exception("Duplicate module name "+module['name'])
70                         projects[module['name']] = Project(folder, module)
71
72 # now check what we have to do
73 loadProjects(config.modules)
74 if args.modules:
75         if args.resume_from is not None:
76                 raise Exception("Can not use --resume-from and manually specify modules")
77         for module in args.modules:
78                 if not module in projects:
79                         raise Exception("Project %s does not exist" % module)
80                 workProjects.append(projects[module])
81 elif args.resume_from is None:
82         workProjects = projects.values() # all the projects
83 else:
84         if not args.resume_from in projects:
85                 raise Exception("Project %s does not exist" % args.resume_from)
86         startWith = projects[args.resume_from]
87         startIndex = findInList(projects.values(), startWith)
88         workProjects = projects.values()[startIndex:]
89
90 # and do it!
91 for project in workProjects:
92         try:
93                 for phase in args.phases:
94                         if phase == 'update':
95                                 project.vcs.update()
96                         elif phase == 'configure':
97                                 project.buildSystem.configure(force=args.reconfigure)
98                         elif phase == 'compile':
99                                 project.buildSystem.build()
100                                 project.buildSystem.install()
101                         else:
102                                 raise Exception("Invalid phase "+phase)
103         except (subprocess.CalledProcessError, KeyboardInterrupt) as e:
104                 print >> sys.stderr
105                 print >> sys.stderr
106                 if isinstance(e, KeyboardInterrupt): # str(e) would be the empty string
107                         print >> sys.stderr, "Interruped by user while processing %s" % (project.name)
108                 else:
109                         print >> sys.stderr, "Error while processing %s: %s" % (project.name, str(e))
110                 print >> sys.stderr
111                 sys.exit(1)