author | Giulio Cesare Solaroli <giulio.cesare@clipperz.com> | 2012-02-11 23:34:25 (UTC) |
---|---|---|
committer | Giulio Cesare Solaroli <giulio.cesare@clipperz.com> | 2012-02-11 23:34:25 (UTC) |
commit | 185949cb778dd13a566781bbfa8ef7ed344cc705 (patch) (unidiff) | |
tree | 8fc4ff8cf1efead7610e4141041dd440eb9febbd /scripts | |
parent | 17efce23d9f205f56f5ebbe8e4f4ca581ea47bcb (diff) | |
download | clipperz-185949cb778dd13a566781bbfa8ef7ed344cc705.zip clipperz-185949cb778dd13a566781bbfa8ef7ed344cc705.tar.gz clipperz-185949cb778dd13a566781bbfa8ef7ed344cc705.tar.bz2 |
Improved build scripts
Signed-off-by: Giulio Cesare Solaroli <giulio.cesare@clipperz.com>
-rw-r--r-- | scripts/builder/backendBuilder.py | 101 | ||||
-rw-r--r-- | scripts/builder/backends/phpBuilder.py (renamed from scripts/builder/phpBuilder.py) | 7 | ||||
-rw-r--r-- | scripts/builder/backends/pythonBuilder.py | 27 | ||||
-rw-r--r-- | scripts/builder/backends/scriptLanguageBuilder.py | 20 | ||||
-rw-r--r-- | scripts/builder/frontendBuilder.py | 141 | ||||
-rwxr-xr-x | scripts/builder/main.py | 85 | ||||
-rw-r--r-- | scripts/builder/pythonBuilder.py | 14 | ||||
-rw-r--r-- | scripts/builder/repository.py | 75 |
8 files changed, 304 insertions, 166 deletions
diff --git a/scripts/builder/backendBuilder.py b/scripts/builder/backendBuilder.py index 16dbe2f..5ecdda0 100644 --- a/scripts/builder/backendBuilder.py +++ b/scripts/builder/backendBuilder.py | |||
@@ -1,89 +1,118 @@ | |||
1 | #!/usr/bin/env python | 1 | #!/usr/bin/env python |
2 | # -*- coding: UTF-8 -*- | 2 | # -*- coding: UTF-8 -*- |
3 | 3 | ||
4 | import sys, os, json | 4 | import sys, os, json |
5 | import shutil | 5 | import shutil |
6 | import main | ||
7 | import hashlib | 6 | import hashlib |
8 | 7 | ||
9 | class BackendBuilder: | 8 | import main |
9 | |||
10 | #=================================================================== | ||
11 | |||
12 | |||
13 | class BackendBuilder(object): | ||
10 | 14 | ||
11 | def __init__ (self, projectTargetDir, frontends, versions, settings): | 15 | def __init__ (self, projectTargetDir, frontends, versions, settings): |
12 | self.projectTargetDir = projectTargetDir | 16 | self.projectTargetDir = projectTargetDir |
13 | self.frontends = frontends | 17 | self.frontends = frontends |
14 | self.versions = versions | 18 | self.versions = versions |
15 | self.settings = settings | 19 | self.settings = settings |
20 | |||
21 | # -------------------------------------------------------------------------- | ||
16 | 22 | ||
17 | def name (self): | 23 | def name (self): |
18 | raise NotImplementedError() | 24 | raise NotImplementedError() |
25 | |||
19 | 26 | ||
20 | def relativePath (self): | 27 | def relativePath (self): |
21 | raise NotImplementedError() | 28 | raise NotImplementedError() |
29 | |||
22 | 30 | ||
23 | def compileCode (self): | 31 | def compileCode (self): |
24 | pass | 32 | raise NotImplementedError() |
33 | |||
25 | 34 | ||
26 | def copyCompiledCodeToTargetDir (self): | 35 | def createPackage (self): |
27 | src = self.sourceFolder() | 36 | raise NotImplementedError() |
28 | dst = self.targetFolder() | 37 | |
29 | main.createFolder(os.path.dirname(dst)) | 38 | # -------------------------------------------------------------------------- |
30 | shutil.copytree(src, dst) | ||
31 | 39 | ||
32 | def sourceFolder (self): | 40 | def sourceFolder (self): |
33 | return main.projectBaseDir() + '/backend/' + self.relativePath() + '/src' | 41 | return os.path.join(main.projectBaseDir() , 'backend', self.relativePath(), 'src') |
34 | |||
35 | 42 | ||
36 | def targetFolder (self): | ||
37 | return self.projectTargetDir + self.relativePath() | ||
38 | |||
39 | def createTargetFolder (self): | ||
40 | main.createFolder(self.targetFolder()) | ||
41 | |||
42 | 43 | ||
43 | #def copyFrontendResources (self, frontend): | 44 | def tempFolder (self): |
44 | # print "copying resources for frontend: " + frontend | 45 | return os.path.join(self.projectTargetDir, '.tmp', self.relativePath()) |
45 | # print "SETTINGS: " + str(self.settings) | 46 | |
46 | 47 | ||
48 | def frontEndTempFolder (self): | ||
49 | return self.tempFolder() | ||
50 | |||
47 | 51 | ||
48 | def writeToTargetFolder (self, filename, content): | 52 | def developmentTargetFolder (self): |
49 | file = open(self.targetFolder() + '/' + filename, 'w') | 53 | return os.path.join(self.projectTargetDir, 'development', self.relativePath()) |
54 | |||
55 | def targetFolder (self): | ||
56 | return os.path.join(self.projectTargetDir, self.relativePath()) | ||
57 | |||
58 | # -------------------------------------------------------------------------- | ||
59 | |||
60 | def writeToFolder (self, folder, filename, content): | ||
61 | file = open(os.path.join(folder, filename), 'w') | ||
50 | file.write(content.encode('utf-8')) | 62 | file.write(content.encode('utf-8')) |
51 | file.close() | 63 | file.close() |
52 | 64 | ||
53 | 65 | ||
54 | def configureIndexContent (self, indexContent): | 66 | def configureIndexContent (self, indexContent, requestPathPrefix = ".."): |
55 | result = indexContent | 67 | result = indexContent |
56 | result = result.replace( '@request.path@', self.settings['request.path'] ) | 68 | result = result.replace( '@request.path@', requestPathPrefix + '/' + self.settings['request.path'] ) |
57 | result = result.replace( '@should.pay.toll@', self.settings['should.pay.toll'] ) | 69 | result = result.replace( '@should.pay.toll@', self.settings['should.pay.toll'] ) |
58 | 70 | ||
59 | return result | 71 | return result |
60 | 72 | ||
61 | 73 | ||
62 | def logChecksums (self, content, message): | 74 | def logChecksums (self, content, message): |
63 | md5Digest = hashlib.md5(content.encode('utf-8')).hexdigest() | 75 | md5Digest = hashlib.md5(content.encode('utf-8')).hexdigest() |
64 | shaDigest = hashlib.sha1(content.encode('utf-8')).hexdigest() | 76 | shaDigest = hashlib.sha1(content.encode('utf-8')).hexdigest() |
65 | sha256Digest= hashlib.sha256(content.encode('utf-8')).hexdigest() | 77 | sha256Digest= hashlib.sha256(content.encode('utf-8')).hexdigest() |
66 | print message + ": " + md5Digest + " (md5)" | 78 | print message + ": " + md5Digest + " (md5)" |
67 | print message + ": " + shaDigest + " (sha1)" | 79 | print message + ": " + shaDigest + " (sha1)" |
68 | print message + ": " + sha256Digest + " (sha256)" | 80 | print message + ": " + sha256Digest + " (sha256)" |
69 | 81 | ||
70 | 82 | ||
83 | def shouldCompileCode (self): | ||
84 | return ('debug' in self.versions) or ('install' in self.versions) | ||
85 | |||
71 | 86 | ||
72 | def run (self): | 87 | def run (self): |
73 | print self.name() + " - RUN" | 88 | print self.name() + " - RUN" |
74 | 89 | ||
75 | self.compileCode() | 90 | if self.shouldCompileCode(): |
76 | self.copyCompiledCodeToTargetDir() | 91 | self.compileCode() |
77 | 92 | ||
78 | for frontend in self.frontends: | 93 | for frontend in self.frontends: |
79 | frontendPath = frontend.module + '/' | 94 | main.createFolder(os.path.join(self.frontEndTempFolder(), frontend.module)) |
80 | if 'debug' in self.versions: | 95 | |
81 | frontend.copyResourcesToTargetFolder(self.targetFolder()) | 96 | if 'debug' in self.versions: |
82 | #self.writeToTargetFolder(frontendPath + 'index_debug.html', self.configureIndexContent(frontend.assembleDebugVersion())) | 97 | frontend.copyResourcesToFolder(self.frontEndTempFolder()) |
83 | self.writeToTargetFolder(frontendPath + 'index_debug.html', self.configureIndexContent(frontend.assemble(assemblyMode='DEBUG', versionType='DEBUG'))) | 98 | |
99 | index = self.configureIndexContent(frontend.assemble(assemblyMode='DEBUG', versionType='DEBUG')) | ||
100 | self.writeToFolder(self.frontEndTempFolder(), os.path.join(frontend.module, 'index_debug.html'), index) | ||
101 | |||
102 | if 'install' in self.versions: | ||
103 | index = self.configureIndexContent(frontend.assemble()) | ||
104 | self.writeToFolder(self.frontEndTempFolder(), os.path.join(frontend.module, 'index.html'), index) | ||
105 | |||
106 | self.logChecksums(index, "[" + self.name() + " - " + frontend.module + "] index.html checksum") | ||
84 | 107 | ||
85 | if 'install' in self.versions: | 108 | self.createPackage() |
86 | index = self.configureIndexContent(frontend.assemble()) | 109 | |
87 | self.writeToTargetFolder(frontendPath + 'index.html', index) | 110 | if 'development' in self.versions: |
88 | self.logChecksums(index, "[" + self.name() + " - " + frontend.module + "] index.html checksum") | 111 | for frontend in self.frontends: |
112 | main.createFolder(os.path.join(self.developmentTargetFolder(), frontend.module)) | ||
113 | |||
114 | index = self.configureIndexContent(frontend.assemble(assemblyMode='DEVELOPMENT', versionType='DEBUG'), self.settings['development.settings']['url']) | ||
115 | self.writeToFolder(self.developmentTargetFolder(), os.path.join(frontend.module, 'index_development.html'), index) | ||
116 | |||
89 | 117 | ||
118 | #=================================================================== | ||
diff --git a/scripts/builder/phpBuilder.py b/scripts/builder/backends/phpBuilder.py index cb4661d..c928aa0 100644 --- a/scripts/builder/phpBuilder.py +++ b/scripts/builder/backends/phpBuilder.py | |||
@@ -1,14 +1,13 @@ | |||
1 | #!/usr/bin/env python | 1 | #!/usr/bin/env python |
2 | # -*- coding: UTF-8 -*- | 2 | # -*- coding: UTF-8 -*- |
3 | 3 | ||
4 | from backendBuilder import BackendBuilder | 4 | from scriptLanguageBuilder import ScriptLanguageBuilder |
5 | 5 | ||
6 | class PhpBuilder(BackendBuilder): | 6 | class PhpBuilder(ScriptLanguageBuilder): |
7 | 7 | ||
8 | def name(self): | 8 | def name(self): |
9 | return "PHP builder" | 9 | return "PHP builder" |
10 | |||
10 | 11 | ||
11 | def relativePath(self): | 12 | def relativePath(self): |
12 | return 'php' | 13 | return 'php' |
13 | |||
14 | |||
diff --git a/scripts/builder/backends/pythonBuilder.py b/scripts/builder/backends/pythonBuilder.py new file mode 100644 index 0000000..1e44209 --- a/dev/null +++ b/scripts/builder/backends/pythonBuilder.py | |||
@@ -0,0 +1,27 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # -*- coding: UTF-8 -*- | ||
3 | |||
4 | from scriptLanguageBuilder import ScriptLanguageBuilder | ||
5 | |||
6 | class PythonBuilder(ScriptLanguageBuilder): | ||
7 | |||
8 | def name(self): | ||
9 | return "Python builder" | ||
10 | |||
11 | |||
12 | def relativePath(self): | ||
13 | return 'python' | ||
14 | |||
15 | |||
16 | def compileCode (self): | ||
17 | src = self.sourceFolder() | ||
18 | dst = self.targetFolder() | ||
19 | |||
20 | shutil.copytree(src, dst) | ||
21 | |||
22 | |||
23 | #def copyCompiledCodeToTargetDir (self): | ||
24 | # src = self.sourceFolder() | ||
25 | # dst = self.targetFolder() | ||
26 | # | ||
27 | # shutil.copytree(src, dst) | ||
diff --git a/scripts/builder/backends/scriptLanguageBuilder.py b/scripts/builder/backends/scriptLanguageBuilder.py new file mode 100644 index 0000000..7d5b31c --- a/dev/null +++ b/scripts/builder/backends/scriptLanguageBuilder.py | |||
@@ -0,0 +1,20 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # -*- coding: UTF-8 -*- | ||
3 | |||
4 | import shutil | ||
5 | from backendBuilder import BackendBuilder | ||
6 | |||
7 | class ScriptLanguageBuilder(BackendBuilder): | ||
8 | |||
9 | def compileCode (self): | ||
10 | src = self.sourceFolder() | ||
11 | dst = self.tempFolder() | ||
12 | |||
13 | shutil.copytree(src, dst) | ||
14 | |||
15 | |||
16 | def createPackage (self): | ||
17 | src = self.tempFolder() | ||
18 | dst = self.targetFolder() | ||
19 | |||
20 | shutil.copytree(src, dst) | ||
diff --git a/scripts/builder/frontendBuilder.py b/scripts/builder/frontendBuilder.py index 55054ee..dae837b 100644 --- a/scripts/builder/frontendBuilder.py +++ b/scripts/builder/frontendBuilder.py | |||
@@ -4,116 +4,83 @@ | |||
4 | import sys, os, re | 4 | import sys, os, re |
5 | import cssmin | 5 | import cssmin |
6 | import jsmin | 6 | import jsmin |
7 | import codecs | 7 | import codecs |
8 | import shutil | 8 | import shutil |
9 | import StringIO | 9 | import StringIO |
10 | import urllib | 10 | import urllib |
11 | 11 | ||
12 | #from mercurial import ui, hg | ||
13 | #from mercurial.node import hex | ||
14 | from dulwich.repo import Repo | ||
15 | |||
16 | import main | 12 | import main |
17 | 13 | ||
14 | class FrontendBuilder(object): | ||
18 | 15 | ||
19 | 16 | def __init__ (self, frontend, settings, repositoryVersion): | |
20 | class FrontendBuilder: | ||
21 | |||
22 | def __init__ (self, frontend, settings): | ||
23 | if '.' in frontend: | 17 | if '.' in frontend: |
24 | moduleComponents = frontend.split('.') | 18 | moduleComponents = frontend.split('.') |
25 | self.module = moduleComponents[0] | 19 | self.module = moduleComponents[0] |
26 | self.submodule = moduleComponents[1] | 20 | self.submodule = moduleComponents[1] |
27 | else: | 21 | else: |
28 | self.module = frontend | 22 | self.module = frontend |
29 | self.submodule = frontend | 23 | self.submodule = frontend |
30 | 24 | ||
31 | self.settings = settings | 25 | self.settings = settings |
32 | self.projectDir = main.projectBaseDir() | 26 | self.projectDir = main.projectBaseDir() |
27 | # self.repository = repository.repositoryWithPath(self.projectDir) | ||
28 | self.repositoryVersion = repositoryVersion | ||
33 | self.processedFiles = {} | 29 | self.processedFiles = {} |
34 | 30 | ||
35 | 31 | ||
36 | def mercurialRepositoryVersion (self): | ||
37 | repo = hg.repository(ui.ui(), self.projectDir) | ||
38 | context = repo['tip'] | ||
39 | result = str(context) | ||
40 | |||
41 | return result | ||
42 | |||
43 | |||
44 | def gitRepositoryVersion (self): | ||
45 | repo = Repo(self.projectDir) | ||
46 | #if repo.is_dirty(): | ||
47 | #print "WARNING: build run with dirty repository" | ||
48 | result = repo.refs['HEAD'] | ||
49 | |||
50 | return result | ||
51 | |||
52 | |||
53 | |||
54 | def repositoryVersion (self): | ||
55 | cacheKey = 'repositoryVersion' | ||
56 | if not self.processedFiles.has_key(cacheKey): | ||
57 | #result = self.mercurialRepositoryVersion() | ||
58 | result = self.gitRepositoryVersion() | ||
59 | self.processedFiles[cacheKey] = result | ||
60 | else: | ||
61 | result = self.processedFiles[cacheKey] | ||
62 | |||
63 | return result | ||
64 | |||
65 | |||
66 | #def relativePath (self): | ||
67 | #return self.module | ||
68 | # | ||
69 | |||
70 | def log (self, message): | 32 | def log (self, message): |
71 | print "frontend [" + self.module + "]: " + message | 33 | print "frontend [" + self.module + "]: " + message |
72 | 34 | ||
73 | 35 | ||
74 | def absolutePathForSourceFile (self, folder, basePath, file): | 36 | def absolutePathForSources (self): |
75 | return folder + '/frontend/' + self.module + '/' + basePath + '/' + file | 37 | return os.path.join(self.projectDir, 'frontend', self.module) |
38 | |||
39 | |||
40 | def absolutePathForSourceFile (self, basePath, file): | ||
41 | return os.path.join(self.absolutePathForSources(), basePath, file) | ||
76 | 42 | ||
77 | 43 | ||
78 | def absolutePathForTargetFile (self, folder, basePath, file): | 44 | def absolutePathForTargetFile (self, folder, basePath, file): |
79 | return folder + '/' + self.module + '/' + basePath + '/' + file | 45 | return os.path.join(folder, self.module, basePath, file) |
46 | |||
80 | 47 | ||
81 | def filterFiles (self, files): | 48 | def filterFiles (self, files): |
82 | result = [] | 49 | result = [] |
83 | 50 | ||
84 | for file in files: | 51 | for file in files: |
85 | if file.startswith('--'): | 52 | if file.startswith('--'): |
86 | pass | 53 | pass |
87 | else: | 54 | else: |
88 | result.append(file) | 55 | result.append(file) |
89 | 56 | ||
90 | return result | 57 | return result |
91 | 58 | ||
92 | 59 | ||
93 | def copyResources (self, sourceFolder, destinationFolder, fileType): | 60 | def copyResources (self, sourceFolder, destinationFolder, fileType): |
94 | for file in self.filterFiles(self.settings[fileType]): | 61 | for file in self.filterFiles(self.settings[fileType]): |
95 | src = self.absolutePathForSourceFile(sourceFolder, fileType, file) | 62 | src = self.absolutePathForSourceFile(fileType, file) |
96 | dst = self.absolutePathForTargetFile(destinationFolder, fileType, file) | 63 | dst = self.absolutePathForTargetFile(destinationFolder, fileType, file) |
97 | main.createFolder(os.path.dirname(dst)) | 64 | main.createFolder(os.path.dirname(dst)) |
98 | shutil.copy2(src, dst) | 65 | shutil.copy2(src, dst) |
99 | 66 | ||
100 | 67 | ||
101 | def copyResourcesToTargetFolder (self, targetFolder): | 68 | def copyResourcesToFolder (self, targetFolder): |
102 | self.copyResources(self.projectDir, targetFolder, 'css') | 69 | self.copyResources(self.projectDir, targetFolder, 'css') |
103 | self.copyResources(self.projectDir, targetFolder, 'js') | 70 | self.copyResources(self.projectDir, targetFolder, 'js') |
104 | 71 | ||
105 | 72 | ||
106 | def loadFilesContent (self, basePath, files): | 73 | def loadFilesContent (self, basePath, files): |
107 | result = "" | 74 | result = "" |
108 | 75 | ||
109 | for file in self.filterFiles(files): | 76 | for file in self.filterFiles(files): |
110 | try: | 77 | try: |
111 | fileHandler = codecs.open(self.absolutePathForSourceFile(self.projectDir, basePath, file), 'r', 'utf-8') | 78 | fileHandler = codecs.open(self.absolutePathForSourceFile(basePath, file), 'r', 'utf-8') |
112 | except: | 79 | except: |
113 | print "FILE: " + file | 80 | print "FILE: " + file |
114 | 81 | ||
115 | result += fileHandler.read() + '\n' | 82 | result += fileHandler.read() + '\n' |
116 | fileHandler.close() | 83 | fileHandler.close() |
117 | 84 | ||
118 | return result | 85 | return result |
119 | 86 | ||
@@ -176,63 +143,63 @@ class FrontendBuilder: | |||
176 | def compressCSS (self, css): | 143 | def compressCSS (self, css): |
177 | self.log("compressing CSS") | 144 | self.log("compressing CSS") |
178 | #return self.regexCssCompressor(css) | 145 | #return self.regexCssCompressor(css) |
179 | return self.cssminCompressor(css) | 146 | return self.cssminCompressor(css) |
180 | 147 | ||
181 | 148 | ||
182 | #========================================================================== | 149 | #========================================================================== |
183 | 150 | ||
184 | def compressJS_jsmin (self, js): | 151 | def compressJS_jsmin (self, js, description): |
185 | self.log("compressing JS code") | 152 | self.log("compressing " + description + " code") |
186 | original = StringIO.StringIO(js) | 153 | original = StringIO.StringIO(js) |
187 | output = StringIO.StringIO() | 154 | output = StringIO.StringIO() |
188 | 155 | ||
189 | jsMinifier = jsmin.JavascriptMinify() | 156 | jsMinifier = jsmin.JavascriptMinify() |
190 | jsMinifier.minify(original, output) | 157 | jsMinifier.minify(original, output) |
191 | 158 | ||
192 | result = output.getvalue() | 159 | result = output.getvalue() |
193 | 160 | ||
194 | original.close() | 161 | original.close() |
195 | output.close() | 162 | output.close() |
196 | 163 | ||
197 | return result | 164 | return result |
198 | 165 | ||
199 | def compressJS_closureCompiler (self, js): | 166 | def compressJS_closureCompiler (self, js, description): |
200 | #Googles Closure compiler | 167 | #Googles Closure compiler |
201 | #java -jar compiler.jar --js=in1.js --js=in2.js ... --js_output_file=out.js | 168 | #java -jar compiler.jar --js=in1.js --js=in2.js ... --js_output_file=out.js |
202 | 169 | ||
203 | result = js | 170 | result = js |
204 | 171 | ||
205 | return result | 172 | return result |
206 | 173 | ||
207 | 174 | ||
208 | def compressJS (self, js): | 175 | def compressJS (self, js, description): |
209 | return self.compressJS_jsmin(js) | 176 | return self.compressJS_jsmin(js, description) |
210 | #return self.compressJS_closureCompiler(js) | 177 | #return self.compressJS_closureCompiler(js, description) |
211 | 178 | ||
212 | 179 | ||
213 | #========================================================================== | 180 | #========================================================================== |
214 | 181 | ||
215 | def packBookmarklet (self, bookmakeletCode): | 182 | def packBookmarklet (self, bookmakeletCode, version): |
216 | replacers = [ | 183 | replacers = [ |
217 | ('isLoginForm', 'ilf'), | 184 | ('isLoginForm', 'ilf'), |
218 | ('findLoginForm', 'flf'), | 185 | ('findLoginForm', 'flf'), |
219 | ('findLoginForm', 'flf'), | 186 | ('findLoginForm', 'flf'), |
220 | ('formParameters', 'fp' ), | 187 | ('formParameters', 'fp' ), |
221 | ('pageParameters', 'pp' ), | 188 | ('pageParameters', 'pp' ), |
222 | ('serializeJSON', 'sj' ), | 189 | ('serializeJSON', 'sj' ), |
223 | ('reprString', 'rs' ), | 190 | ('reprString', 'rs' ), |
224 | ('logFormParameters', 'lfp'), | 191 | ('logFormParameters', 'lfp'), |
225 | ('loadClipperzBookmarklet','lcb'), | 192 | ('loadClipperzBookmarklet','lcb'), |
226 | ('loginForm', 'lf' ), | 193 | ('loginForm', 'lf' ), |
227 | ('parameters', 'p' ), | 194 | ('parameters', 'p' ), |
228 | ('inputElementValues', 'iev'), | 195 | ('inputElementValues', 'iev'), |
229 | ] | 196 | ] |
230 | result = self.compressJS(bookmakeletCode) | 197 | result = self.compressJS(bookmakeletCode, version + " bookmarklet") |
231 | 198 | ||
232 | result = re.sub('\n', ' ', result) #Fit all in a single line | 199 | result = re.sub('\n', ' ', result) #Fit all in a single line |
233 | # result = re.sub('\s+', ' ', result) #Collapse "redundant" spaces. WARNING: this could have some evil side effects on constant strings used inside to code!! | 200 | # result = re.sub('\s+', ' ', result) #Collapse "redundant" spaces. WARNING: this could have some evil side effects on constant strings used inside to code!! |
234 | # result = re.sub('\s?([,\+=\(\)\{\};])\s?', '\\1', result) | 201 | # result = re.sub('\s?([,\+=\(\)\{\};])\s?', '\\1', result) |
235 | 202 | ||
236 | for replacer in replacers: | 203 | for replacer in replacers: |
237 | result = re.sub(replacer[0], replacer[1], result) | 204 | result = re.sub(replacer[0], replacer[1], result) |
238 | 205 | ||
@@ -295,34 +262,34 @@ class FrontendBuilder: | |||
295 | 262 | ||
296 | return result | 263 | return result |
297 | 264 | ||
298 | 265 | ||
299 | 266 | ||
300 | def bookmarklet (self): | 267 | def bookmarklet (self): |
301 | cacheKey = 'bookmarklet' | 268 | cacheKey = 'bookmarklet' |
302 | if not self.processedFiles.has_key(cacheKey): | 269 | if not self.processedFiles.has_key(cacheKey): |
303 | result = 'bookmarklet="' + self.packBookmarklet(self.loadFilesContent('js', ['Bookmarklet.js'])) + '";bookmarklet_ie="' + self.packBookmarklet(self.loadFilesContent('js', ['Bookmarklet_IE.js'])) + '";' | 270 | result = 'bookmarklet="' + self.packBookmarklet(self.loadFilesContent('js', ['Bookmarklet.js']), "regular") + '";bookmarklet_ie="' + self.packBookmarklet(self.loadFilesContent('js', ['Bookmarklet_IE.js']), "IE") + '";' |
304 | self.processedFiles[cacheKey] = result | 271 | self.processedFiles[cacheKey] = result |
305 | else: | 272 | else: |
306 | result = self.processedFiles[cacheKey] | 273 | result = self.processedFiles[cacheKey] |
307 | 274 | ||
308 | return result | 275 | return result |
309 | 276 | ||
310 | 277 | ||
311 | def replaceTemplatePlaceholders (self, assemblyMode, pageTitle, copyright, css, code, version, versionType): | 278 | def replaceTemplatePlaceholders (self, pageTitle, copyright, css, code, jsLoadMode, version, versionType): |
312 | result = self.template() | 279 | result = self.template() |
313 | 280 | ||
314 | result = result.replace('@page.title@', pageTitle, 1) | 281 | result = result.replace('@page.title@', pageTitle, 1) |
315 | result = result.replace('@copyright@', copyright, 1) | 282 | result = result.replace('@copyright@', copyright, 1) |
316 | result = result.replace('@css@', css, 1) | 283 | result = result.replace('@css@', css, 1) |
317 | #result = result.replace('@bookmarklet@', bookmarklet,1) | 284 | #result = result.replace('@bookmarklet@', bookmarklet,1) |
318 | result = result.replace('@application.version@', version, 1) | 285 | result = result.replace('@application.version@', version, 1) |
319 | result = result.replace('@application.version.type@', versionType,1) | 286 | result = result.replace('@application.version.type@', versionType,1) |
320 | result = result.replace('@js_' + assemblyMode + '@', code, 1) | 287 | result = result.replace('@js_' + jsLoadMode + '@', code, 1) |
321 | 288 | ||
322 | result = re.sub('@js_[^@]+@', '', result) | 289 | result = re.sub('@js_[^@]+@', '', result) |
323 | 290 | ||
324 | return result | 291 | return result |
325 | 292 | ||
326 | 293 | ||
327 | def assembleCopyrightHeader (self): | 294 | def assembleCopyrightHeader (self): |
328 | processedFile = 'copyright' | 295 | processedFile = 'copyright' |
@@ -338,61 +305,85 @@ class FrontendBuilder: | |||
338 | 305 | ||
339 | self.processedFiles[processedFile] = result | 306 | self.processedFiles[processedFile] = result |
340 | 307 | ||
341 | return self.processedFiles[processedFile] | 308 | return self.processedFiles[processedFile] |
342 | 309 | ||
343 | 310 | ||
344 | def cssTagsForFiles (self, basePath, files): | 311 | def cssTagsForFiles (self, basePath, files): |
345 | #<link rel="stylesheet" type="text/css" href="./css/reset-min.css" /> | 312 | #<link rel="stylesheet" type="text/css" href="./css/reset-min.css" /> |
346 | return '\n'.join(map(lambda file: '<link rel="stylesheet" type="text/css" href="./' + basePath + '/' + file + '" />', files)) | 313 | return '\n'.join(map(lambda file: '<link rel="stylesheet" type="text/css" href="' + basePath + '/' + file + '" />', files)) |
347 | 314 | ||
348 | 315 | ||
349 | def cssTagForContent (self, content): | 316 | def cssTagForContent (self, content): |
350 | return '<style type="text/css">' + content + '</style>' | 317 | return '<style type="text/css">' + content + '</style>' |
351 | 318 | ||
352 | 319 | ||
353 | def scriptTagsForFiles (self, basePath, files): | 320 | def scriptTagsForFiles (self, basePath, files): |
354 | #<script type='text/javascript' src='./js/src/bookmarklet.js'></script> | 321 | #<script type='text/javascript' src='./js/src/bookmarklet.js'></script> |
355 | return '\n'.join(map(lambda file: '<script type="text/javascript" src="./' + basePath + '/' + file + '"></script>', files)) | 322 | return '\n'.join(map(lambda file: '<script type="text/javascript" src="' + basePath + '/' + file + '"></script>', files)) |
356 | 323 | ||
357 | 324 | ||
358 | def scriptTagForContent (self, content): | 325 | def scriptTagForContent (self, content): |
359 | return '<script>' + content + '</script>' | 326 | return '<script>' + content + '</script>' |
360 | 327 | ||
361 | 328 | ||
362 | def assembleVersion (self, assemblyMode, pageTitle, copyright, css, js, version, versionType): | 329 | def assembleVersion (self, pageTitle, copyright, css, js, jsLoadMode, version, versionType): |
363 | cacheKey = version + "-" + versionType | 330 | cacheKey = version + "-" + versionType |
364 | if not self.processedFiles.has_key(cacheKey): | 331 | if not self.processedFiles.has_key(cacheKey): |
365 | result = self.replaceTemplatePlaceholders(assemblyMode, pageTitle, copyright, css, js, version, versionType) | 332 | result = self.replaceTemplatePlaceholders(pageTitle, copyright, css, js, jsLoadMode, version, versionType) |
366 | self.processedFiles[cacheKey] = result | 333 | self.processedFiles[cacheKey] = result |
367 | else: | 334 | else: |
368 | result = self.processedFiles[cacheKey] | 335 | result = self.processedFiles[cacheKey] |
369 | 336 | ||
370 | #self.log("# cacheKey:\n" + result) | 337 | #self.log("# cacheKey:\n" + result) |
371 | return result | 338 | return result |
372 | 339 | ||
373 | 340 | ||
374 | def assemble (self, assemblyMode='INSTALL', versionType='LIVE'): | 341 | def assemble (self, assemblyMode='INSTALL', versionType='LIVE'): |
375 | pageTitle = "Clipperz - " + self.module | 342 | |
376 | if versionType != 'LIVE': | 343 | if versionType == 'LIVE': |
377 | pageTitle += " [" + versionType + " - " + assemblyMode +"]" | 344 | pageTitle = "Clipperz - " + self.module |
378 | 345 | else: | |
346 | pageTitle = "Clipperz - " + self.module + " [" + versionType + " - " + assemblyMode +"]" | ||
347 | |||
379 | if assemblyMode == 'INSTALL': | 348 | if assemblyMode == 'INSTALL': |
380 | css= self.cssTagForContent(self.compressCSS(self.loadFilesContent('css', self.settings['css']))) | 349 | copyright = self.assembleCopyrightHeader() |
381 | js= self.scriptTagForContent(self.bookmarklet() + '\n' + self.compressJS(self.loadFilesContent('js', self.settings['js']))) | 350 | css =self.cssTagForContent(self.compressCSS(self.loadFilesContent('css', self.settings['css']))) |
351 | js =self.scriptTagForContent( | ||
352 | self.bookmarklet() + | ||
353 | '\n' + | ||
354 | self.compressJS(self.loadFilesContent('js', self.settings['js']), "application") | ||
355 | ) | ||
356 | jsLoadMode = 'EMBEDDED' | ||
357 | |||
358 | elif assemblyMode == 'DEBUG': | ||
359 | copyright = self.assembleCopyrightHeader() | ||
360 | css =self.cssTagsForFiles('./css', self.filterFiles(self.settings['css'])) | ||
361 | js =self.scriptTagForContent(self.bookmarklet()) + \ | ||
362 | '\n' + \ | ||
363 | self.scriptTagsForFiles('./js', self.filterFiles(self.settings['js'])) | ||
364 | jsLoadMode = 'LINKED' | ||
365 | |||
366 | elif assemblyMode == 'DEVELOPMENT': | ||
367 | copyright = "" | ||
368 | css =self.cssTagsForFiles('file://' + str(os.path.join(self.absolutePathForSources(), 'css')), self.filterFiles(self.settings['css'])) | ||
369 | js =self.scriptTagForContent(self.bookmarklet()) + \ | ||
370 | '\n' + \ | ||
371 | self.scriptTagsForFiles('file://' + str(os.path.join(self.absolutePathForSources(), 'js')), self.filterFiles(self.settings['js'])) | ||
372 | jsLoadMode = 'LINKED' | ||
373 | |||
382 | else: | 374 | else: |
383 | css= self.cssTagsForFiles('css', self.filterFiles(self.settings['css'])) | 375 | raise NotImplementedError() |
384 | js= self.scriptTagForContent(self.bookmarklet()) + '\n' + self.scriptTagsForFiles('js', self.filterFiles(self.settings['js'])) | 376 | |
385 | |||
386 | return self.assembleVersion( | 377 | return self.assembleVersion( |
387 | assemblyMode= assemblyMode, | ||
388 | pageTitle = pageTitle, | 378 | pageTitle = pageTitle, |
389 | copyright = self.assembleCopyrightHeader(), | 379 | copyright = copyright, |
390 | css = css, | 380 | css = css, |
391 | js = js, | 381 | js = js, |
392 | version = self.repositoryVersion(), | 382 | jsLoadMode = jsLoadMode, |
383 | version = self.repositoryVersion, | ||
393 | versionType = versionType | 384 | versionType = versionType |
394 | ) | 385 | ) |
395 | 386 | ||
396 | 387 | ||
397 | 388 | ||
398 | 389 | ||
diff --git a/scripts/builder/main.py b/scripts/builder/main.py index 94f738f..6fce65d 100755 --- a/scripts/builder/main.py +++ b/scripts/builder/main.py | |||
@@ -1,21 +1,22 @@ | |||
1 | #!/usr/bin/env python | 1 | #!/usr/bin/env python |
2 | # -*- coding: UTF-8 -*- | 2 | # -*- coding: UTF-8 -*- |
3 | 3 | ||
4 | import sys, os, json | 4 | import sys |
5 | import os | ||
6 | import json | ||
5 | import shutil | 7 | import shutil |
6 | import pprint | 8 | import pprint |
7 | import frontendBuilder | ||
8 | import codecs | 9 | import codecs |
9 | import itertools | 10 | import itertools |
10 | |||
11 | from collections import deque | 11 | from collections import deque |
12 | from phpBuilder import PhpBuilder | 12 | |
13 | from pythonBuilder import PythonBuilder | 13 | import frontendBuilder |
14 | import repository | ||
14 | 15 | ||
15 | pp = pprint.PrettyPrinter(indent=4, depth=4) | 16 | pp = pprint.PrettyPrinter(indent=4, depth=4) |
16 | 17 | ||
17 | #-------------------------------------------------------------------- | 18 | #-------------------------------------------------------------------- |
18 | 19 | ||
19 | def scriptDir (): | 20 | def scriptDir (): |
20 | return os.path.dirname(sys.argv[0]) | 21 | return os.path.dirname(sys.argv[0]) |
21 | 22 | ||
@@ -29,26 +30,27 @@ def projectTargetDir(): | |||
29 | 30 | ||
30 | def createFolder (path): | 31 | def createFolder (path): |
31 | if not os.path.exists(path): | 32 | if not os.path.exists(path): |
32 | os.makedirs(path) | 33 | os.makedirs(path) |
33 | 34 | ||
34 | #-------------------------------------------------------------------- | 35 | #-------------------------------------------------------------------- |
35 | 36 | ||
36 | def loadSettings (component, module): | 37 | def loadSettings (component, module): |
37 | print "MODULE: " + module | 38 | # print "MODULE: " + module |
38 | 39 | ||
39 | if '.' in module: | 40 | if '.' in module: |
40 | moduleComponents = module.split('.') | 41 | moduleComponents = module.split('.') |
41 | module = moduleComponents[0] | 42 | module = moduleComponents[0] |
42 | submodule = moduleComponents[1] | 43 | submodule = moduleComponents[1] |
43 | else: | 44 | else: |
44 | submodule = module | 45 | submodule = module |
45 | 46 | ||
46 | settings = codecs.open(projectBaseDir() + '/' + component + '/' + module + '/properties/' + submodule + '.properties.json', 'r', 'utf-8') | 47 | #settings = codecs.open(projectBaseDir() + os.sep + component + os.sep + module + os.sep + 'properties' + os.sep + submodule + '.properties.json', 'r', 'utf-8') |
48 | settings = codecs.open(os.path.join(projectBaseDir(), component, module, 'properties', submodule + '.properties.json'), 'r', 'utf-8') | ||
47 | result = json.load(settings) | 49 | result = json.load(settings) |
48 | settings.close | 50 | settings.close |
49 | 51 | ||
50 | return result | 52 | return result |
51 | 53 | ||
52 | #==================================================================== | 54 | #==================================================================== |
53 | # | 55 | # |
54 | # def assembleFrontend (frontend, versions): | 56 | # def assembleFrontend (frontend, versions): |
@@ -66,81 +68,89 @@ def loadSettings (component, module): | |||
66 | # | 68 | # |
67 | # return result | 69 | # return result |
68 | # | 70 | # |
69 | #==================================================================== | 71 | #==================================================================== |
70 | 72 | ||
71 | def assembleBackend (backend, frontends, versions): | 73 | def assembleBackend (backend, frontends, versions): |
72 | settings = loadSettings('backend', backend) | 74 | settings = loadSettings('backend', backend) |
73 | 75 | ||
74 | if backend == 'php': | 76 | builderModuleName = backend + 'Builder' |
75 | backendBuilder = PhpBuilder(projectTargetDir(), frontends, versions, settings) | 77 | builderClassName = backend.capitalize() + 'Builder' |
76 | elif backend == 'python': | 78 | |
77 | backendBuilder = PythonBuilder(projectTargetDir(), frontends, versions, settings) | 79 | builderModule = __import__(builderModuleName) |
78 | #elif backend == 'java': | 80 | builderClass = getattr(builderModule, builderClassName) |
79 | #buildJavaBackend (frontends, versions, settings) | 81 | |
80 | else: | 82 | backendBuilder = builderClass(projectTargetDir(), frontends, versions, settings) |
81 | raise Exception('unrecognized backend: ' + backend) | ||
82 | |||
83 | backendBuilder.run() | 83 | backendBuilder.run() |
84 | 84 | ||
85 | #==================================================================== | 85 | #==================================================================== |
86 | 86 | ||
87 | def build (settings): | 87 | def build (settings, repository): |
88 | frontends = [] | 88 | frontends = [] |
89 | 89 | ||
90 | if repository.areTherePendingChanges(): | ||
91 | print "\nWARNING: repository has pending changes\n" | ||
92 | |||
90 | for frontend in settings['frontends']: | 93 | for frontend in settings['frontends']: |
91 | frontends.append(frontendBuilder.FrontendBuilder(frontend, loadSettings('frontend', frontend))) | 94 | frontends.append(frontendBuilder.FrontendBuilder(frontend, loadSettings('frontend', frontend), repository.version())) |
92 | 95 | ||
93 | for backend in settings['backends']: | 96 | for backend in settings['backends']: |
94 | assembleBackend(backend, frontends, settings['versions']) | 97 | assembleBackend(backend, frontends, settings['versions']) |
95 | 98 | ||
96 | #-------------------------------------------------------------------- | 99 | #-------------------------------------------------------------------- |
97 | 100 | ||
98 | def clean (): | 101 | def clean (): |
99 | print "cleaning up …" | 102 | # print "cleaning up …" |
100 | if os.path.exists(projectTargetDir()): | 103 | if os.path.exists(projectTargetDir()): |
101 | shutil.rmtree(projectTargetDir()) | 104 | shutil.rmtree(projectTargetDir()) |
102 | 105 | ||
103 | #-------------------------------------------------------------------- | 106 | #-------------------------------------------------------------------- |
104 | 107 | ||
105 | def usage (message): | 108 | def usage (message): |
106 | if message != None: | 109 | if message != None: |
107 | print "ERROR: " + message | 110 | print "ERROR: " + message |
108 | 111 | ||
109 | 112 | ||
110 | print "build.py clean" | 113 | # print "build clean" |
111 | print "build.py clean install" | 114 | # print "build clean install" |
112 | print "build.py install --ALL" | 115 | print "build install --ALL" |
113 | print "build.py install debug --ALL" | 116 | print "build install debug --ALL" |
114 | print "build.py clean install debug --ALL" | 117 | # print "build clean install debug --ALL" |
115 | print "build.ph install, debug --backends php java --frontends beta gamma" | 118 | print "build install debug --backends php python --frontends beta gamma" |
116 | print "build.ph install, debug --backends php java --frontends beta gamma gamma.mobile" | 119 | print "build install debug development --backends php python --frontends beta gamma gamma.mobile" |
117 | exit(1) | 120 | exit(1) |
118 | 121 | ||
119 | #-------------------------------------------------------------------- | 122 | #-------------------------------------------------------------------- |
120 | 123 | ||
124 | def allFrontends (): | ||
125 | return ['beta', 'gamma', 'mobile'] | ||
126 | |||
127 | def allBackends (): | ||
128 | return ['php', 'python'] | ||
129 | |||
130 | #-------------------------------------------------------------------- | ||
131 | |||
121 | def main (): | 132 | def main (): |
122 | settings = {} | 133 | settings = {} |
123 | parameters = list(itertools.islice(sys.argv, 1, None)) | 134 | parameters = list(itertools.islice(sys.argv, 1, None)) |
124 | 135 | ||
125 | shouldClean = len(filter(lambda x: x == 'clean', parameters)) > 0 | 136 | sys.path.append(os.path.join(scriptDir(), 'backends')) |
126 | if (shouldClean): | 137 | currentRepository = repository.repositoryWithPath(projectBaseDir()) |
127 | clean () | 138 | |
128 | 139 | clean() | |
129 | parameters = filter(lambda x: x != 'clean', parameters) | ||
130 | versions = list(itertools.takewhile(lambda x: not x.startswith('--'), parameters)) | 140 | versions = list(itertools.takewhile(lambda x: not x.startswith('--'), parameters)) |
131 | settings['versions'] = versions; #['debug', 'install'] | 141 | settings['versions'] = versions; #['debug', 'install', 'development'] |
132 | parameters = deque(itertools.dropwhile(lambda x: not x.startswith('--'), parameters)) | 142 | parameters = deque(itertools.dropwhile(lambda x: not x.startswith('--'), parameters)) |
133 | 143 | ||
134 | if len(parameters) > 0: | 144 | if len(parameters) > 0: |
135 | parameter = parameters.popleft() | 145 | parameter = parameters.popleft() |
136 | if parameter == "--ALL": | 146 | if parameter == "--ALL": |
137 | settings['frontends'] = ['beta', 'gamma', 'mobile'] | 147 | settings['frontends'] = allFrontends() |
138 | settings['backends'] = ['php', 'python', 'java'] | 148 | settings['backends'] = allBackends() |
139 | else: | 149 | else: |
140 | while parameter != None: | 150 | while parameter != None: |
141 | values = list(itertools.takewhile(lambda x: not x.startswith('--'), parameters)) | 151 | values = list(itertools.takewhile(lambda x: not x.startswith('--'), parameters)) |
142 | 152 | ||
143 | if parameter == "--backends": | 153 | if parameter == "--backends": |
144 | settings['backends'] = values | 154 | settings['backends'] = values |
145 | elif parameter == "--frontends": | 155 | elif parameter == "--frontends": |
146 | settings['frontends'] = values | 156 | settings['frontends'] = values |
@@ -153,14 +163,15 @@ def main (): | |||
153 | 163 | ||
154 | if (not settings.has_key('versions')): | 164 | if (not settings.has_key('versions')): |
155 | usage("missing 'versions'") | 165 | usage("missing 'versions'") |
156 | if (not settings.has_key('frontends')): | 166 | if (not settings.has_key('frontends')): |
157 | usage("missing 'frontends'") | 167 | usage("missing 'frontends'") |
158 | if (not settings.has_key('backends')): | 168 | if (not settings.has_key('backends')): |
159 | usage("missing 'backends'") | 169 | usage("missing 'backends'") |
160 | 170 | ||
161 | build (settings) | 171 | build(settings, currentRepository) |
162 | 172 | else: | |
173 | usage("Suggestions on how to call the 'build' script:") | ||
163 | 174 | ||
164 | 175 | ||
165 | if __name__ == "__main__": | 176 | if __name__ == "__main__": |
166 | main() | 177 | main() |
diff --git a/scripts/builder/pythonBuilder.py b/scripts/builder/pythonBuilder.py deleted file mode 100644 index a84598d..0000000 --- a/scripts/builder/pythonBuilder.py +++ b/dev/null | |||
@@ -1,14 +0,0 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # -*- coding: UTF-8 -*- | ||
3 | |||
4 | from backendBuilder import BackendBuilder | ||
5 | |||
6 | class PythonBuilder(BackendBuilder): | ||
7 | |||
8 | def name(self): | ||
9 | return "Python builder" | ||
10 | |||
11 | def relativePath(self): | ||
12 | return 'python' | ||
13 | |||
14 | |||
diff --git a/scripts/builder/repository.py b/scripts/builder/repository.py new file mode 100644 index 0000000..89db9a5 --- a/dev/null +++ b/scripts/builder/repository.py | |||
@@ -0,0 +1,75 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # -*- coding: UTF-8 -*- | ||
3 | |||
4 | |||
5 | def repositoryWithPath (path): | ||
6 | try: | ||
7 | from dulwich.repo import Repo | ||
8 | |||
9 | repo = Repo(path) | ||
10 | result = GitRepository(repo, path) | ||
11 | except: | ||
12 | from mercurial import ui, hg | ||
13 | |||
14 | repo = hg.repository(ui.ui(), path) | ||
15 | result = HgRepository(repo, path) | ||
16 | |||
17 | return result | ||
18 | |||
19 | |||
20 | #=================================================================== | ||
21 | |||
22 | |||
23 | class Repository(object): | ||
24 | |||
25 | def __init__ (self, repository, path): | ||
26 | self.repository = repository | ||
27 | self.path = path | ||
28 | |||
29 | |||
30 | def revision (self): | ||
31 | raise NotImplementedError() | ||
32 | |||
33 | |||
34 | def areTherePendingChanges (self): | ||
35 | raise NotImplementedError() | ||
36 | |||
37 | |||
38 | def version (self): | ||
39 | result = self.revision() | ||
40 | if self.areTherePendingChanges(): | ||
41 | result = '>>> ' + result + ' <<<' | ||
42 | |||
43 | # print "VERSION: " + result | ||
44 | return result | ||
45 | |||
46 | |||
47 | #=================================================================== | ||
48 | |||
49 | |||
50 | class GitRepository(Repository): | ||
51 | |||
52 | def revision (self): | ||
53 | return repository.refs['HEAD'] | ||
54 | |||
55 | |||
56 | def areTherePendingChanges (self): | ||
57 | return repository.is_dirty() | ||
58 | |||
59 | |||
60 | #=================================================================== | ||
61 | |||
62 | |||
63 | class HgRepository(Repository): | ||
64 | #http://mercurial.selenic.com/wiki/MercurialApi | ||
65 | |||
66 | def revision (self): | ||
67 | return 'hg:' + str(self.repository['tip']) | ||
68 | |||
69 | |||
70 | def areTherePendingChanges (self): | ||
71 | # TODO: FIXME: repository.status() does not report 'unknown(?)' files. :( | ||
72 | return not all(map(lambda fileList: len(fileList) == 0, self.repository.status())) | ||
73 | |||
74 | |||
75 | #=================================================================== | ||