comparison piecrust/processing/less.py @ 498:35d4c172e5a6

less: Fix issues with the map file on Windows. See the comment in the code for more information. Also, only wrap the opening of the map file in a try/except clause, since we want to catch the situation where the map file is missing only.
author Ludovic Chabant <ludovic@chabant.com>
date Thu, 23 Jul 2015 23:02:07 -0700
parents c4b3a7fd2f87
children 4850f8c21b6e
comparison
equal deleted inserted replaced
497:4505a1443358 498:35d4c172e5a6
31 def getDependencies(self, path): 31 def getDependencies(self, path):
32 map_path = self._getMapPath(path) 32 map_path = self._getMapPath(path)
33 try: 33 try:
34 with open(map_path, 'r') as f: 34 with open(map_path, 'r') as f:
35 dep_map = json.load(f) 35 dep_map = json.load(f)
36 36 except OSError:
37 # Check the version, since the `sources` list has changed
38 # meanings over time.
39 if dep_map.get('version') != 3:
40 logger.warning("Unknown LESS map version. Force rebuilding.")
41 return FORCE_BUILD
42
43 # Get the sources, but make all paths absolute.
44 sources = dep_map.get('sources')
45 path_dir = os.path.dirname(path)
46
47 def _makeAbs(p):
48 return os.path.join(path_dir, p)
49 deps = list(map(_makeAbs, sources))
50 return [map_path] + deps
51 except IOError:
52 # Map file not found... rebuild. 37 # Map file not found... rebuild.
53 logger.debug("No map file found for LESS file '%s' at '%s'. " 38 logger.debug("No map file found for LESS file '%s' at '%s'. "
54 "Rebuilding" % (path, map_path)) 39 "Rebuilding" % (path, map_path))
55 return FORCE_BUILD 40 return FORCE_BUILD
56 41
42 # Check the version, since the `sources` list has changed
43 # meanings over time.
44 if dep_map.get('version') != 3:
45 logger.warning("Unknown LESS map version. Force rebuilding.")
46 return FORCE_BUILD
47
48 # Get the sources, but make all paths absolute.
49 sources = dep_map.get('sources')
50 path_dir = os.path.dirname(path)
51
52 def _makeAbs(p):
53 return os.path.join(path_dir, p)
54 deps = list(map(_makeAbs, sources))
55 return [map_path] + deps
56
57 def _doProcess(self, in_path, out_path): 57 def _doProcess(self, in_path, out_path):
58 self._ensureInitialized() 58 self._ensureInitialized()
59 59
60 map_path = self._getMapPath(in_path) 60 map_path = self._getMapPath(in_path)
61 map_url = '/' + os.path.relpath(map_path, self.app.root_dir) 61 map_url = '/' + os.path.relpath(
62 map_path, self.app.root_dir).replace('\\', '/')
63
64 # On Windows, it looks like LESSC is confused with paths when the
65 # map file is not to be created in the same directory as the input
66 # file (it ends up writing invalid dependencies in the map file, with
67 # a mix of relative and absolute paths stuck together).
68 # So create it there and move it afterwards... :(
69 temp_map_path = os.path.join(
70 os.path.dirname(in_path),
71 os.path.basename(map_path))
72
62 args = [self._conf['bin'], 73 args = [self._conf['bin'],
63 '--source-map=%s' % map_path, 74 '--source-map=%s' % temp_map_path,
64 '--source-map-url=%s' % map_url] 75 '--source-map-url=%s' % map_url]
65 args += self._conf['options'] 76 args += self._conf['options']
66 args.append(in_path) 77 args.append(in_path)
67 args.append(out_path) 78 args.append(out_path)
68 logger.debug("Processing LESS file: %s" % args) 79 logger.debug("Processing LESS file: %s" % args)
82 "Did you install it?") from ex 93 "Did you install it?") from ex
83 if proc.returncode != 0: 94 if proc.returncode != 0:
84 raise ExternalProcessException( 95 raise ExternalProcessException(
85 stderr_data.decode(sys.stderr.encoding)) 96 stderr_data.decode(sys.stderr.encoding))
86 97
98 logger.debug("Moving map file: %s -> %s" % (temp_map_path, map_path))
99 if os.path.exists(map_path):
100 os.remove(map_path)
101 os.rename(temp_map_path, map_path)
102
87 return True 103 return True
88 104
89 def _ensureInitialized(self): 105 def _ensureInitialized(self):
90 if self._conf is not None: 106 if self._conf is not None:
91 return 107 return