Merge branch 'backend-tv-rename'
[armadillo.git] / build.py
1 #!/usr/bin/env python2.5
2 #
3 # Armadillo File Manager
4 # Copyright (c) 2010-2011, Robert Sesek <http://www.bluestatic.org>
5 #
6 # This program is free software: you can redistribute it and/or modify it under
7 # the terms of the GNU General Public License as published by the Free Software
8 # Foundation, either version 3 of the License, or any later version.
9 #
10 import optparse
11 import os
12 import re
13 import shutil
14 import string
15 import subprocess
16 import sys
17 import time
18
19 ROOT = os.path.dirname(os.path.realpath(__file__))
20 SRC_PATH = os.path.join(ROOT, 'src')
21 PROD_PATH = os.path.join(ROOT, 'out')
22 FE_PATH = os.path.join(ROOT, 'web_frontend')
23
24 CLOSURE_SVN = 'http://closure-library.googlecode.com/svn/trunk/'
25 CLOSURE_REV = '235'
26 CLOSURE_DEST = os.path.join(ROOT, 'closure')
27 CLOSURE_COMPILER = os.path.join(ROOT, 'closure-compiler.jar')
28 CLOSURE_CALCDEPS = os.path.join(CLOSURE_DEST, 'closure', 'bin', 'calcdeps.py')
29
30 VERSION_FILE = os.path.join(FE_PATH, 'version.js.proto')
31
32 SOURCES = [
33 'config.go',
34 'paths.go',
35 'tv_rename.go',
36 'server.go',
37 'main.go'
38 ]
39 SOURCES_FE = [
40 'version.js',
41 'tv_renamer.js',
42 'path_control.js',
43 'actor.js',
44 'file.js',
45 'main.js',
46 ]
47 RESOURCES_FE = [
48 'index.html',
49 'screen.css',
50 'reset.css'
51 ]
52 RESOURCES_CLOSURE = [
53 'common.css',
54 'dialog.css',
55 'menu.css',
56 'menuitem.css',
57 'menubutton.css',
58 ]
59 PRODUCT_NAME = 'armadillo'
60
61 # The Golang version (hg id).
62 BACK_END_COMPILER_VERSION = 'a7800e20064a release/release.2010-11-10'
63
64 COMPILER = '8g'
65 LINKER = '8l'
66 O_EXTENSION = '8'
67
68 def _ObjFileName(gofile):
69 gofile = os.path.basename(gofile)
70 return os.path.join(PROD_PATH, os.path.splitext(gofile)[0] + '.' + O_EXTENSION)
71
72 def _PullDeps():
73 print '=== Pulling Dependencies ==='
74 if os.path.exists(CLOSURE_DEST):
75 handle = subprocess.Popen([ 'svn', 'info', CLOSURE_DEST ], stdout = subprocess.PIPE)
76 handle.wait()
77 for line in handle.stdout:
78 if line.startswith('Revision'):
79 if not line.startswith('Revision: ' + CLOSURE_REV):
80 subprocess.Popen([ 'svn', 'update', '-r', CLOSURE_REV, CLOSURE_DEST ]).wait()
81 else:
82 print ' Closure @ ' + CLOSURE_REV
83 else:
84 subprocess.Popen([ 'svn', 'checkout', '-r', CLOSURE_REV, CLOSURE_SVN, CLOSURE_DEST ]).wait()
85
86 def _CompileBackEnd():
87 for gofile in SOURCES:
88 gofile = os.path.join(SRC_PATH, gofile)
89 args = [ COMPILER, gofile ]
90 print ' ' + ' '.join(args)
91 handle = subprocess.Popen(args, stdout = sys.stdout, stderr = sys.stderr)
92 handle.wait()
93
94 # Link
95 objects = map(_ObjFileName, SOURCES)
96 args = [ LINKER, '-o', os.path.join(PROD_PATH, PRODUCT_NAME), 'main.8' ]
97 print ' ' + ' ' .join(args)
98 handle = subprocess.Popen(args, stdout = sys.stdout, stderr = sys.stderr)
99 handle.wait()
100
101 def _StampVersion(options):
102 print '=== Version Stamp ==='
103 if os.path.exists(VERSION_FILE):
104 gitcrement = subprocess.Popen([ 'gitcrement', 'next' ], stdout = subprocess.PIPE, cwd = ROOT)
105 gitcrement.wait()
106 build_stamp = gitcrement.stdout.read().strip()
107 time_stamp = str(int(time.time()))
108
109 fd = open(VERSION_FILE, 'a+')
110 fd.seek(0)
111 lines = fd.readlines()
112 fd.seek(0)
113 fd.truncate()
114 for line in lines:
115 line = re.sub(r'(BUILD =) ([0-9\.]+)', r'\1 ' + build_stamp, line)
116 line = re.sub(r'(STAMP =) ([0-9]+)', r'\1 ' + time_stamp, line)
117 fd.write(line)
118 fd.close()
119 print ' BUILD ' + build_stamp + ' @ ' + time_stamp
120 if options.compile_fe:
121 mfiles = subprocess.Popen([ 'git', 'ls-files', '-m' ], stdout = subprocess.PIPE, cwd = ROOT)
122 mfiles.wait()
123 versioned_stamp_file = string.replace(VERSION_FILE, '.proto', '')
124 shutil.copy(VERSION_FILE, versioned_stamp_file)
125 print ' COPY version.js.proto -> version.js'
126 if not len(mfiles.stdout.readlines()):
127 subprocess.Popen([ 'git', 'commit', '--author=Armadillo Build Script <armadillo@bluestatic.org>',
128 '-m', 'Stamp version.js @ ' + build_stamp + '.', versioned_stamp_file ], stdout = sys.stdout,
129 stderr = sys.stderr).wait()
130
131 def _CompileFrontEnd(options):
132 _PullDeps()
133
134 # Copy
135 print '=== Copying Resources ==='
136 fe_resources = os.path.join(PROD_PATH, 'fe')
137 subprocess.Popen([ 'rm', '-rf', fe_resources ]).wait()
138 os.mkdir(fe_resources)
139 for resource in RESOURCES_FE:
140 print ' COPY ' + resource
141 shutil.copy(os.path.join(FE_PATH, resource), fe_resources)
142 fd = open(os.path.join(fe_resources, 'closure.css'), 'w+')
143 fd.write('/*=== Generated Resources for Closure Library ===*/')
144 for resource in RESOURCES_CLOSURE:
145 print ' COPY closure/' + resource
146 respath = os.path.join(CLOSURE_DEST, 'closure', 'goog', 'css', resource)
147 ofd = open(respath, 'r')
148 fd.write('\n\n/*=== File: ' + respath.replace(ROOT, '/') + ' ===*/\n')
149 fd.writelines(ofd.readlines())
150 ofd.close()
151 fd.close()
152
153 # Version
154 _StampVersion(options)
155
156 # Compile JS.
157 print '=== Compiling Front End ==='
158 outfile = os.path.join(PROD_PATH, 'fe', PRODUCT_NAME + '.js')
159 fe_sources = map(lambda f: '-i' + os.path.join(FE_PATH, f), SOURCES_FE)
160 closure_sources = os.path.join(CLOSURE_DEST, 'closure', 'goog')
161 args = [ CLOSURE_CALCDEPS ]
162 args.extend(fe_sources)
163 output = "script"
164 if options.compile_fe:
165 output = "compiled"
166 args.extend([ '-p', closure_sources, '-o', output, '-c', CLOSURE_COMPILER,
167 '--output_file', outfile ])
168 print ' ' + ' '.join(args)
169 handle = subprocess.Popen(args, stdout = sys.stdout, stderr = sys.stderr)
170 handle.wait()
171
172
173 def Main():
174 parser = optparse.OptionParser()
175 parser.add_option('-c', '--closure_fe', action="store_true", dest="compile_fe",
176 help="Run the Front End inputs through the Closure Compiler")
177 parser.add_option('-b', '--back-end', action="store_true", dest="backend_only",
178 help="Compiles only the back-end")
179 parser.add_option('-f', '--front-end', action="store_true", dest="frontend_only",
180 help="Compiles only the front-end")
181 (options, args) = parser.parse_args()
182
183 print '=== Starting Build ==='
184 os.chdir(PROD_PATH)
185
186 if not options.frontend_only:
187 _CompileBackEnd()
188
189 if not options.backend_only:
190 _CompileFrontEnd(options)
191
192 if __name__ == '__main__':
193 Main()