Diffstat (limited to 'scripts/builder/frontendBuilder.py') (more/less context) (ignore whitespace changes)
-rw-r--r-- | scripts/builder/frontendBuilder.py | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/scripts/builder/frontendBuilder.py b/scripts/builder/frontendBuilder.py index dae837b..1f0f92f 100644 --- a/scripts/builder/frontendBuilder.py +++ b/scripts/builder/frontendBuilder.py | |||
@@ -43,97 +43,98 @@ class FrontendBuilder(object): | |||
43 | 43 | ||
44 | def absolutePathForTargetFile (self, folder, basePath, file): | 44 | def absolutePathForTargetFile (self, folder, basePath, file): |
45 | return os.path.join(folder, self.module, basePath, file) | 45 | return os.path.join(folder, self.module, basePath, file) |
46 | 46 | ||
47 | 47 | ||
48 | def filterFiles (self, files): | 48 | def filterFiles (self, files): |
49 | result = [] | 49 | result = [] |
50 | 50 | ||
51 | for file in files: | 51 | for file in files: |
52 | if file.startswith('--'): | 52 | if file.startswith('--'): |
53 | pass | 53 | pass |
54 | else: | 54 | else: |
55 | result.append(file) | 55 | result.append(file) |
56 | 56 | ||
57 | return result | 57 | return result |
58 | 58 | ||
59 | 59 | ||
60 | def copyResources (self, sourceFolder, destinationFolder, fileType): | 60 | def copyResources (self, sourceFolder, destinationFolder, fileType): |
61 | for file in self.filterFiles(self.settings[fileType]): | 61 | for file in self.filterFiles(self.settings[fileType]): |
62 | src = self.absolutePathForSourceFile(fileType, file) | 62 | src = self.absolutePathForSourceFile(fileType, file) |
63 | dst = self.absolutePathForTargetFile(destinationFolder, fileType, file) | 63 | dst = self.absolutePathForTargetFile(destinationFolder, fileType, file) |
64 | main.createFolder(os.path.dirname(dst)) | 64 | main.createFolder(os.path.dirname(dst)) |
65 | shutil.copy2(src, dst) | 65 | shutil.copy2(src, dst) |
66 | 66 | ||
67 | 67 | ||
68 | def copyResourcesToFolder (self, targetFolder): | 68 | def copyResourcesToFolder (self, targetFolder): |
69 | self.copyResources(self.projectDir, targetFolder, 'css') | 69 | self.copyResources(self.projectDir, targetFolder, 'css') |
70 | self.copyResources(self.projectDir, targetFolder, 'js') | 70 | self.copyResources(self.projectDir, targetFolder, 'js') |
71 | 71 | ||
72 | 72 | ||
73 | def loadFilesContent (self, basePath, files): | 73 | def loadFilesContent (self, basePath, files): |
74 | result = "" | 74 | result = "" |
75 | 75 | ||
76 | for file in self.filterFiles(files): | 76 | for file in self.filterFiles(files): |
77 | try: | 77 | try: |
78 | fileHandler = codecs.open(self.absolutePathForSourceFile(basePath, file), 'r', 'utf-8') | 78 | fileHandler = codecs.open(self.absolutePathForSourceFile(basePath, file), 'r', 'utf-8') |
79 | except: | 79 | except: |
80 | print "FILE: " + file | 80 | print "FILE: " + file |
81 | 81 | ||
82 | result += fileHandler.read() + '\n' | 82 | result += fileHandler.read() + '\n' |
83 | fileHandler.close() | 83 | fileHandler.close() |
84 | 84 | ||
85 | return result | 85 | return result |
86 | 86 | ||
87 | 87 | ||
88 | def template (self): | 88 | def template (self): |
89 | processedFile = 'html_template' | 89 | processedFile = 'html_template' |
90 | if not self.processedFiles.has_key(processedFile): | 90 | if not self.processedFiles.has_key(processedFile): |
91 | self.processedFiles[processedFile] = self.loadFilesContent('html', ['index_template.html']) | 91 | #self.processedFiles[processedFile] = self.loadFilesContent('html', ['index_template.html']) |
92 | self.processedFiles[processedFile] = self.loadFilesContent('html', [self.settings['html.template']]) | ||
92 | 93 | ||
93 | return self.processedFiles[processedFile] | 94 | return self.processedFiles[processedFile] |
94 | 95 | ||
95 | 96 | ||
96 | def cssminCompressor (self, css): | 97 | def cssminCompressor (self, css): |
97 | # package found here: | 98 | # package found here: |
98 | # - http://stackoverflow.com/questions/222581/python-script-for-minifying-css/2396777#2396777 | 99 | # - http://stackoverflow.com/questions/222581/python-script-for-minifying-css/2396777#2396777 |
99 | # actual downloaded version: http://pypi.python.org/pypi/cssmin/0.1.4 | 100 | # actual downloaded version: http://pypi.python.org/pypi/cssmin/0.1.4 |
100 | return cssmin.cssmin(css) | 101 | return cssmin.cssmin(css) |
101 | 102 | ||
102 | 103 | ||
103 | def regexCssCompressor (self, css): | 104 | def regexCssCompressor (self, css): |
104 | # http://stackoverflow.com/questions/222581/python-script-for-minifying-css/223689#223689 | 105 | # http://stackoverflow.com/questions/222581/python-script-for-minifying-css/223689#223689 |
105 | 106 | ||
106 | # remove comments - this will break a lot of hacks :-P | 107 | # remove comments - this will break a lot of hacks :-P |
107 | css = re.sub( r'\s*/\*\s*\*/', "$$HACK1$$", css ) # preserve IE<6 comment hack | 108 | css = re.sub( r'\s*/\*\s*\*/', "$$HACK1$$", css ) # preserve IE<6 comment hack |
108 | css = re.sub( r'/\*[\s\S]*?\*/', "", css ) | 109 | css = re.sub( r'/\*[\s\S]*?\*/', "", css ) |
109 | css = css.replace( "$$HACK1$$", '/**/' ) # preserve IE<6 comment hack | 110 | css = css.replace( "$$HACK1$$", '/**/' ) # preserve IE<6 comment hack |
110 | 111 | ||
111 | # url() doesn't need quotes | 112 | # url() doesn't need quotes |
112 | css = re.sub( r'url\((["\'])([^)]*)\1\)', r'url(\2)', css ) | 113 | css = re.sub( r'url\((["\'])([^)]*)\1\)', r'url(\2)', css ) |
113 | 114 | ||
114 | # spaces may be safely collapsed as generated content will collapse them anyway | 115 | # spaces may be safely collapsed as generated content will collapse them anyway |
115 | css = re.sub( r'\s+', ' ', css ) | 116 | css = re.sub( r'\s+', ' ', css ) |
116 | 117 | ||
117 | # shorten collapsable colors: #aabbcc to #abc | 118 | # shorten collapsable colors: #aabbcc to #abc |
118 | css = re.sub( r'#([0-9a-f])\1([0-9a-f])\2([0-9a-f])\3(\s|;)', r'#\1\2\3\4', css ) | 119 | css = re.sub( r'#([0-9a-f])\1([0-9a-f])\2([0-9a-f])\3(\s|;)', r'#\1\2\3\4', css ) |
119 | 120 | ||
120 | # fragment values can loose zeros | 121 | # fragment values can loose zeros |
121 | css = re.sub( r':\s*0(\.\d+([cm]m|e[mx]|in|p[ctx]))\s*;', r':\1;', css ) | 122 | css = re.sub( r':\s*0(\.\d+([cm]m|e[mx]|in|p[ctx]))\s*;', r':\1;', css ) |
122 | 123 | ||
123 | for rule in re.findall( r'([^{]+){([^}]*)}', css ): | 124 | for rule in re.findall( r'([^{]+){([^}]*)}', css ): |
124 | 125 | ||
125 | # we don't need spaces around operators | 126 | # we don't need spaces around operators |
126 | selectors = [re.sub( r'(?<=[\[\(>+=])\s+|\s+(?=[=~^$*|>+\]\)])', r'', selector.strip() ) for selector in rule[0].split( ',' )] | 127 | selectors = [re.sub( r'(?<=[\[\(>+=])\s+|\s+(?=[=~^$*|>+\]\)])', r'', selector.strip() ) for selector in rule[0].split( ',' )] |
127 | 128 | ||
128 | # order is important, but we still want to discard repetitions | 129 | # order is important, but we still want to discard repetitions |
129 | properties = {} | 130 | properties = {} |
130 | porder = [] | 131 | porder = [] |
131 | for prop in re.findall( '(.*?):(.*?)(;|$)', rule[1] ): | 132 | for prop in re.findall( '(.*?):(.*?)(;|$)', rule[1] ): |
132 | key = prop[0].strip().lower() | 133 | key = prop[0].strip().lower() |
133 | if key not in porder: porder.append( key ) | 134 | if key not in porder: porder.append( key ) |
134 | properties[ key ] = prop[1].strip() | 135 | properties[ key ] = prop[1].strip() |
135 | 136 | ||
136 | # output rule if it contains any declarations | 137 | # output rule if it contains any declarations |
137 | if properties: | 138 | if properties: |
138 | print "%s{%s}" % ( ','.join( selectors ), ''.join(['%s:%s;' % (key, properties[key]) for key in porder])[:-1] ) | 139 | print "%s{%s}" % ( ','.join( selectors ), ''.join(['%s:%s;' % (key, properties[key]) for key in porder])[:-1] ) |
139 | 140 | ||
@@ -274,97 +275,97 @@ class FrontendBuilder(object): | |||
274 | 275 | ||
275 | return result | 276 | return result |
276 | 277 | ||
277 | 278 | ||
278 | def replaceTemplatePlaceholders (self, pageTitle, copyright, css, code, jsLoadMode, version, versionType): | 279 | def replaceTemplatePlaceholders (self, pageTitle, copyright, css, code, jsLoadMode, version, versionType): |
279 | result = self.template() | 280 | result = self.template() |
280 | 281 | ||
281 | result = result.replace('@page.title@', pageTitle, 1) | 282 | result = result.replace('@page.title@', pageTitle, 1) |
282 | result = result.replace('@copyright@', copyright, 1) | 283 | result = result.replace('@copyright@', copyright, 1) |
283 | result = result.replace('@css@', css, 1) | 284 | result = result.replace('@css@', css, 1) |
284 | #result = result.replace('@bookmarklet@', bookmarklet,1) | 285 | #result = result.replace('@bookmarklet@', bookmarklet,1) |
285 | result = result.replace('@application.version@', version, 1) | 286 | result = result.replace('@application.version@', version, 1) |
286 | result = result.replace('@application.version.type@', versionType,1) | 287 | result = result.replace('@application.version.type@', versionType,1) |
287 | result = result.replace('@js_' + jsLoadMode + '@', code, 1) | 288 | result = result.replace('@js_' + jsLoadMode + '@', code, 1) |
288 | 289 | ||
289 | result = re.sub('@js_[^@]+@', '', result) | 290 | result = re.sub('@js_[^@]+@', '', result) |
290 | 291 | ||
291 | return result | 292 | return result |
292 | 293 | ||
293 | 294 | ||
294 | def assembleCopyrightHeader (self): | 295 | def assembleCopyrightHeader (self): |
295 | processedFile = 'copyright' | 296 | processedFile = 'copyright' |
296 | if not self.processedFiles.has_key(processedFile): | 297 | if not self.processedFiles.has_key(processedFile): |
297 | #self.log("assembling copyright header") | 298 | #self.log("assembling copyright header") |
298 | copyrightValues = self.settings['copyright.values'] | 299 | copyrightValues = self.settings['copyright.values'] |
299 | license = self.loadFilesContent('../../properties', ['license.txt']) | 300 | license = self.loadFilesContent('../../properties', ['license.txt']) |
300 | result = self.loadFilesContent('properties', ['creditsAndCopyrights.txt']) | 301 | result = self.loadFilesContent('properties', ['creditsAndCopyrights.txt']) |
301 | 302 | ||
302 | result = re.sub('@clipperz.license@', license, result) | 303 | result = re.sub('@clipperz.license@', license, result) |
303 | for key in copyrightValues: | 304 | for key in copyrightValues: |
304 | result = re.sub('@'+key+'@', copyrightValues[key], result) | 305 | result = re.sub('@'+key+'@', copyrightValues[key], result) |
305 | 306 | ||
306 | self.processedFiles[processedFile] = result | 307 | self.processedFiles[processedFile] = result |
307 | 308 | ||
308 | return self.processedFiles[processedFile] | 309 | return self.processedFiles[processedFile] |
309 | 310 | ||
310 | 311 | ||
311 | def cssTagsForFiles (self, basePath, files): | 312 | def cssTagsForFiles (self, basePath, files): |
312 | #<link rel="stylesheet" type="text/css" href="./css/reset-min.css" /> | 313 | #<link rel="stylesheet" type="text/css" href="./css/reset-min.css" /> |
313 | return '\n'.join(map(lambda file: '<link rel="stylesheet" type="text/css" href="' + basePath + '/' + file + '" />', files)) | 314 | return '\n'.join(map(lambda file: '<link rel="stylesheet" type="text/css" href="' + basePath + '/' + file + '" />', files)) |
314 | 315 | ||
315 | 316 | ||
316 | def cssTagForContent (self, content): | 317 | def cssTagForContent (self, content): |
317 | return '<style type="text/css">' + content + '</style>' | 318 | return '<style type="text/css">' + content + '</style>' |
318 | 319 | ||
319 | 320 | ||
320 | def scriptTagsForFiles (self, basePath, files): | 321 | def scriptTagsForFiles (self, basePath, files): |
321 | #<script type='text/javascript' src='./js/src/bookmarklet.js'></script> | 322 | #<script type='text/javascript' src='./js/src/bookmarklet.js'></script> |
322 | return '\n'.join(map(lambda file: '<script type="text/javascript" src="' + basePath + '/' + file + '"></script>', files)) | 323 | return '\n'.join(map(lambda file: '<script type="text/javascript" src="' + basePath + '/' + file + '" charset="utf-8"></script>', files)) |
323 | 324 | ||
324 | 325 | ||
325 | def scriptTagForContent (self, content): | 326 | def scriptTagForContent (self, content): |
326 | return '<script>' + content + '</script>' | 327 | return '<script>' + content + '</script>' |
327 | 328 | ||
328 | 329 | ||
329 | def assembleVersion (self, pageTitle, copyright, css, js, jsLoadMode, version, versionType): | 330 | def assembleVersion (self, pageTitle, copyright, css, js, jsLoadMode, version, versionType): |
330 | cacheKey = version + "-" + versionType | 331 | cacheKey = version + "-" + versionType |
331 | if not self.processedFiles.has_key(cacheKey): | 332 | if not self.processedFiles.has_key(cacheKey): |
332 | result = self.replaceTemplatePlaceholders(pageTitle, copyright, css, js, jsLoadMode, version, versionType) | 333 | result = self.replaceTemplatePlaceholders(pageTitle, copyright, css, js, jsLoadMode, version, versionType) |
333 | self.processedFiles[cacheKey] = result | 334 | self.processedFiles[cacheKey] = result |
334 | else: | 335 | else: |
335 | result = self.processedFiles[cacheKey] | 336 | result = self.processedFiles[cacheKey] |
336 | 337 | ||
337 | #self.log("# cacheKey:\n" + result) | 338 | #self.log("# cacheKey:\n" + result) |
338 | return result | 339 | return result |
339 | 340 | ||
340 | 341 | ||
341 | def assemble (self, assemblyMode='INSTALL', versionType='LIVE'): | 342 | def assemble (self, assemblyMode='INSTALL', versionType='LIVE'): |
342 | 343 | ||
343 | if versionType == 'LIVE': | 344 | if versionType == 'LIVE': |
344 | pageTitle = "Clipperz - " + self.module | 345 | pageTitle = "Clipperz - " + self.module |
345 | else: | 346 | else: |
346 | pageTitle = "Clipperz - " + self.module + " [" + versionType + " - " + assemblyMode +"]" | 347 | pageTitle = "Clipperz - " + self.module + " [" + versionType + " - " + assemblyMode +"]" |
347 | 348 | ||
348 | if assemblyMode == 'INSTALL': | 349 | if assemblyMode == 'INSTALL': |
349 | copyright = self.assembleCopyrightHeader() | 350 | copyright = self.assembleCopyrightHeader() |
350 | css =self.cssTagForContent(self.compressCSS(self.loadFilesContent('css', self.settings['css']))) | 351 | css =self.cssTagForContent(self.compressCSS(self.loadFilesContent('css', self.settings['css']))) |
351 | js =self.scriptTagForContent( | 352 | js =self.scriptTagForContent( |
352 | self.bookmarklet() + | 353 | self.bookmarklet() + |
353 | '\n' + | 354 | '\n' + |
354 | self.compressJS(self.loadFilesContent('js', self.settings['js']), "application") | 355 | self.compressJS(self.loadFilesContent('js', self.settings['js']), "application") |
355 | ) | 356 | ) |
356 | jsLoadMode = 'EMBEDDED' | 357 | jsLoadMode = 'EMBEDDED' |
357 | 358 | ||
358 | elif assemblyMode == 'DEBUG': | 359 | elif assemblyMode == 'DEBUG': |
359 | copyright = self.assembleCopyrightHeader() | 360 | copyright = self.assembleCopyrightHeader() |
360 | css =self.cssTagsForFiles('./css', self.filterFiles(self.settings['css'])) | 361 | css =self.cssTagsForFiles('./css', self.filterFiles(self.settings['css'])) |
361 | js =self.scriptTagForContent(self.bookmarklet()) + \ | 362 | js =self.scriptTagForContent(self.bookmarklet()) + \ |
362 | '\n' + \ | 363 | '\n' + \ |
363 | self.scriptTagsForFiles('./js', self.filterFiles(self.settings['js'])) | 364 | self.scriptTagsForFiles('./js', self.filterFiles(self.settings['js'])) |
364 | jsLoadMode = 'LINKED' | 365 | jsLoadMode = 'LINKED' |
365 | 366 | ||
366 | elif assemblyMode == 'DEVELOPMENT': | 367 | elif assemblyMode == 'DEVELOPMENT': |
367 | copyright = "" | 368 | copyright = "" |
368 | css =self.cssTagsForFiles('file://' + str(os.path.join(self.absolutePathForSources(), 'css')), self.filterFiles(self.settings['css'])) | 369 | css =self.cssTagsForFiles('file://' + str(os.path.join(self.absolutePathForSources(), 'css')), self.filterFiles(self.settings['css'])) |
369 | js =self.scriptTagForContent(self.bookmarklet()) + \ | 370 | js =self.scriptTagForContent(self.bookmarklet()) + \ |
370 | '\n' + \ | 371 | '\n' + \ |