Updated package list to match new versions / new packages.
[beastbuild.git] / beastbuild.py
1 import utils;
2 import hashlib;
3 import os;
4 import urlparse;
5 import subprocess;
6 import sys;
7
8 from buildutils import file_md5_hash, prepend_path, platform_is_win32, platform_is_unix, call_log_file
9 from package import Config
10 from Path import Path
11
12 class Options:
13   def __init__ (self):
14     self.no_deps = False
15     self.download_only = False
16     self.packages = []
17
18   def parse (self, argv):
19     for i in argv:
20       if i == '--no-deps':
21         self.no_deps = True
22       elif i == '--download-only':
23         self.download_only = True
24       else:
25         options.packages += [ i ]
26
27
28 options = Options()
29 options.parse (sys.argv[1:])
30
31 if options.no_deps:
32   print "(dependencies will not be built)"
33
34 config = Config()
35
36 #######
37 # need generic environment builder
38 # for now, set things manually
39 if platform_is_win32():
40   prepend_path (config.PREFIX.join (Path ("mingw/bin")))
41   prepend_path (config.PREFIX.join (Path ("msys/bin")))
42
43 prepend_path (config.PREFIX.join (Path ("bin")))
44
45 def perform_operation (package, operation, function, hash):
46   stamp_file_name = config.BEASTBUILD.join (Path ("stamps/" + package.full_name() + "_" +
47                                                   hash + "_" + operation)).native()
48   try:
49     open (stamp_file_name, "r")
50     skip = True
51   except IOError:
52     skip = False
53   if skip:
54     print "***** " + operation + " complete already."
55   else:
56     print "***** " + operation + ":"
57     log_file_name = config.BEASTBUILD.join (Path ("logs/" + package.full_name() + "_" + operation + ".log")).unix()
58     call_log_file (log_file_name)
59     function()
60     sys.stdout.flush()
61     done_file = open (stamp_file_name, "w")
62     done_file.write (operation + " stamp")
63     done_file.close()
64
65 pkg2file = dict()
66 shortpkg2pkg = dict()
67 pkg2package = dict()
68
69 if platform_is_win32():
70   DIR_SEP = '\\'
71 else:
72   DIR_SEP = '/'
73
74 def import_all (path):
75   if os.path.isdir (path):
76     if not path.endswith (DIR_SEP + "attic"):
77       for entry in os.listdir (path):
78         import_all (os.path.join (path, entry))
79   elif os.path.isfile (path):
80     if path.endswith (".py") and not path.endswith ("__.py"):
81       name = path[:-3].replace (DIR_SEP, ".")
82       __import__ (name)
83       pkg_module = sys.modules[name]
84       try:
85         full_name = pkg_module.package().full_name()
86       except:
87         utils.die ("%s needs to implement a package() method" % path)
88       pkg2file[full_name] = path
89       pkg2package[full_name] = pkg_module.package()
90       short_name = os.path.basename (path[:-3])
91       shortpkg2pkg[short_name] = full_name
92
93 if platform_is_win32():
94   essential_pkgs = [ 'binutils', 'gcccore', 'gccgxx', 'mingwrtdev', 'mingwrtdll', 'w32apidev',
95                      'msyscore', 'msyscrypt', 'cvs', 'vim', 'ssh', 'wget', 'slashx', 'ccache',
96                      'nsis', 'nsis_untgz' ]
97 else:
98   essential_pkgs = [ 'slashx' ]
99
100 import_all ("packages")
101
102 def dependency_order (package_list, complete=None):
103   if complete is None:
104     complete = set()
105   build_list = []
106   for package_full_name in package_list:
107     package = pkg2package [package_full_name]
108     for i in package.depends():
109       try:
110         ip = shortpkg2pkg [i]
111       except:
112         utils.die ("can not find package %s which is a dependancy of %s" % (i, package_full_name))
113       build_list += dependency_order ([ip], complete)
114     if package_full_name not in complete:
115       build_list += [package_full_name]
116       complete.add (package_full_name)
117   return build_list
118
119 build_pkgs = map (lambda short_name: shortpkg2pkg [short_name], essential_pkgs + options.packages)
120 if not options.no_deps:
121   build_pkgs = dependency_order (build_pkgs)
122 build_pkgs = map (lambda full_name: pkg2package [full_name], build_pkgs)
123
124 def source_hash (full_name):
125   os.chdir (config.BEASTBUILD.native())
126   md5 = hashlib.md5()
127   # hash all packages .py files that p depends on (including p)
128   hash_pkgs = []
129   # include essential packages in the list
130   for pkg in essential_pkgs:
131     hash_pkgs += [shortpkg2pkg [pkg]]
132   hash_pkgs += [full_name]
133   hash_pkgs = dependency_order (hash_pkgs)
134   dep_files = 0
135   for package in hash_pkgs:
136     md5.update (package)
137     md5.update (file_md5_hash (pkg2file[package]))
138     dep_files += 1
139   # hash all .py files that are part of the build system
140   for i in [ 'Path.py', 'beastbuild.py', 'buildutils.py', 'config.py', 'package.py', 'utils.py']:
141     md5.update (file_md5_hash (i))
142     dep_files += 1
143   print "***** hash-depends on %d python files" % dep_files
144   return md5.hexdigest()
145
146 for package in build_pkgs:
147   print "***** " + package.full_name() 
148   hash = source_hash (package.full_name())
149   perform_operation (package, "download", package.download, hash)
150   if not options.download_only:
151     perform_operation (package, "extract", package.extract, hash)
152     perform_operation (package, "patch", package.patch, hash)
153     perform_operation (package, "configure", package.configure, hash)
154     perform_operation (package, "compile", package.compile, hash)
155     perform_operation (package, "dist_image", package.dist_image, hash)
156     perform_operation (package, "install", package.install, hash)
157   package.setup_env()
158
159 # vim:set sw=2 sts=2: