comparison piecrust/processing/browserify.py @ 1049:c2bfa1869f0d

bake: Optimize Browserify dependency handling.
author Ludovic Chabant <ludovic@chabant.com>
date Fri, 26 Jan 2018 18:01:15 -0800
parents 717ac3c4ee77
children a3dec0fbd9ce
comparison
equal deleted inserted replaced
1048:63be34ce6e65 1049:c2bfa1869f0d
1 import os 1 import os
2 import os.path 2 import os.path
3 import hashlib
3 import logging 4 import logging
4 import platform 5 import platform
5 import subprocess 6 import subprocess
6 from piecrust.processing.base import Processor, PRIORITY_FIRST, FORCE_BUILD 7 from piecrust.processing.base import Processor, PRIORITY_FIRST, FORCE_BUILD
7 8
13 PROCESSOR_NAME = 'browserify' 14 PROCESSOR_NAME = 'browserify'
14 15
15 def __init__(self): 16 def __init__(self):
16 super(BrowserifyProcessor, self).__init__() 17 super(BrowserifyProcessor, self).__init__()
17 self.priority = PRIORITY_FIRST 18 self.priority = PRIORITY_FIRST
18 self.is_delegating_dependency_check = False 19 self._tmp_dir = None
19 self._conf = None 20 self._conf = None
20 21
21 def initialize(self, app): 22 def initialize(self, app):
22 super(BrowserifyProcessor, self).initialize(app) 23 super(BrowserifyProcessor, self).initialize(app)
23 24
28 if self._conf is True: 29 if self._conf is True:
29 self._conf = {} 30 self._conf = {}
30 31
31 self._conf.setdefault('bin', 'browserify') 32 self._conf.setdefault('bin', 'browserify')
32 33
34 def onPipelineStart(self, ctx):
35 self._tmp_dir = ctx.tmp_dir
36
33 def matches(self, path): 37 def matches(self, path):
34 return self._conf is not None and os.path.splitext(path)[1] == '.js' 38 return self._conf is not None and os.path.splitext(path)[1] == '.js'
35 39
36 def getDependencies(self, path): 40 def getDependencies(self, path):
37 return FORCE_BUILD 41 deps_path = self._getDepListPath(path)
42 try:
43 with open(deps_path, 'r', encoding='utf8') as f:
44 deps_list = f.read()
45 except OSError:
46 logger.debug("No dependency list found for Browserify target '%s' "
47 "at '%s'. Rebuilding" % (path, deps_path))
48 return FORCE_BUILD
49
50 deps_list = [d.strip() for d in deps_list.split('\n')]
51 return filter(lambda d: d, deps_list)
38 52
39 def getOutputFilenames(self, filename): 53 def getOutputFilenames(self, filename):
40 return [filename] 54 return [filename]
41 55
42 def process(self, path, out_dir): 56 def process(self, path, out_dir):
57 # Update the dependency list file.
58 # Sadly there doesn't seem to be a way to get the list at the same
59 # time as compiling the bundle so we need to run the process twice :(
60 deps_list = self._runBrowserify([path, '--list'])
61 deps_list = deps_list.decode('utf8')
62 deps_path = self._getDepListPath(path)
63 with open(deps_path, 'w', encoding='utf8') as f:
64 f.write(deps_list)
65
66 # Actually compile the JS bundle.
43 out_path = os.path.join(out_dir, os.path.basename(path)) 67 out_path = os.path.join(out_dir, os.path.basename(path))
68 self._runBrowserify([path, '-o', out_path])
44 69
45 args = [self._conf['bin'], path, '-o', out_path] 70 return True
71
72 def _runBrowserify(self, args):
73 args = [self._conf['bin']] + args
46 cwd = self.app.root_dir 74 cwd = self.app.root_dir
47 logger.debug("Running Browserify: %s" % ' '.join(args)) 75 logger.debug("Running Browserify: %s" % ' '.join(args))
48 try: 76 try:
49 retcode = subprocess.call(args, cwd=cwd) 77 return subprocess.check_output(
78 args,
79 cwd=cwd,
80 stderr=subprocess.STDOUT)
50 except FileNotFoundError as ex: 81 except FileNotFoundError as ex:
51 logger.error("Tried running Browserify processor " 82 logger.error("Tried running Browserify with command: %s" % args)
52 "with command: %s" % args)
53 raise Exception("Error running Browserify. " 83 raise Exception("Error running Browserify. "
54 "Did you install it?") from ex 84 "Did you install it?") from ex
55 if retcode != 0: 85 except subprocess.CalledProcessError as ex:
56 raise Exception("Error occured in Browserify compiler. " 86 logger.error("Error occured while running Browserify:")
87 logger.info(ex.stdout)
88 logger.error(ex.stderr)
89 raise Exception("Error occured while running Browserify. "
57 "Please check log messages above for " 90 "Please check log messages above for "
58 "more information.") 91 "more information.")
59 return True 92
93 def _getDepListPath(self, path):
94 deps_name = "%s_%s.deps" % (
95 os.path.basename(path),
96 hashlib.md5(path.encode('utf8')).hexdigest())
97 deps_path = os.path.join(self._tmp_dir, deps_name)
98 return deps_path
99