Skip to content

Commit 60a67b5

Browse files
author
Andrey Fedoseev
committed
Change BaseCompiler API:
- `compile_file` does not rely on `compile_source` - `compile_file` returns the relative path to compiled file rather than compiled code - remove `write_output` method - remove `postprocess` method. Compilers post-process the compiled code in `compile_file` Refactor `utils.convert_urls`: now it accepts full path to compiled file and updates the file in place
1 parent aa128c4 commit 60a67b5

File tree

13 files changed

+176
-150
lines changed

13 files changed

+176
-150
lines changed

static_precompiler/compilers/babel.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import os
2+
13
from static_precompiler import exceptions, utils
24

35
from . import base
@@ -19,7 +21,27 @@ def __init__(self, executable="babel", modules=None):
1921
super(Babel, self).__init__()
2022

2123
def compile_file(self, source_path):
22-
return self.compile_source(self.get_source(source_path))
24+
args = [
25+
self.executable
26+
]
27+
28+
if self.modules is not None:
29+
args.extend(["--modules", self.modules])
30+
31+
full_output_path = self.get_full_output_path(source_path)
32+
33+
full_output_dirname = os.path.dirname(full_output_path)
34+
if not os.path.exists(full_output_dirname):
35+
os.makedirs(full_output_dirname)
36+
37+
args.extend(["-o", full_output_path])
38+
args.append(self.get_full_source_path(source_path))
39+
40+
out, errors = utils.run_command(args)
41+
if errors:
42+
raise exceptions.StaticCompilationError(errors)
43+
44+
return self.get_output_path(source_path)
2345

2446
def compile_source(self, source):
2547
args = [

static_precompiler/compilers/base.py

Lines changed: 6 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -164,24 +164,6 @@ def get_source(self, source_path):
164164
with open(self.get_full_source_path(source_path)) as source:
165165
return source.read()
166166

167-
def write_output(self, output, source_path):
168-
""" Write the compiled output to a file.
169-
170-
:param output: compiled code
171-
:type output: str
172-
:param source_path: relative path to a source file
173-
:type source_path: str
174-
175-
"""
176-
output_path = self.get_full_output_path(source_path)
177-
output_dir = os.path.dirname(output_path)
178-
if not os.path.exists(output_dir):
179-
os.makedirs(output_dir)
180-
181-
compiled_file = open(output_path, "w+")
182-
compiled_file.write(output)
183-
compiled_file.close()
184-
185167
def compile(self, source_path, from_management=False):
186168
""" Compile the given source path and return relative path to the compiled file.
187169
Raise ValueError is the source file type is not supported.
@@ -198,18 +180,19 @@ def compile(self, source_path, from_management=False):
198180
raise ValueError("'{0}' file type is not supported by '{1}'".format(
199181
source_path, self.__class__.__name__
200182
))
183+
184+
compliled_path = self.get_output_path(source_path)
185+
201186
if self.should_compile(source_path, from_management=from_management):
202187

203-
compiled = self.compile_file(source_path)
204-
compiled = self.postprocess(compiled, source_path)
205-
self.write_output(compiled, source_path)
188+
compliled_path = self.compile_file(source_path)
206189

207190
if self.supports_dependencies:
208191
self.update_dependencies(source_path, self.find_dependencies(source_path))
209192

210193
logging.info("Compiled: '{0}'".format(source_path))
211194

212-
return self.get_output_path(source_path)
195+
return compliled_path
213196

214197
def compile_lazy(self, source_path):
215198
""" Return a lazy object which, when translated to string, compiles the specified source path and returns
@@ -226,7 +209,7 @@ def compile_lazy(self, source_path):
226209
compile_lazy = functional.lazy(compile_lazy, six.text_type)
227210

228211
def compile_file(self, source_path):
229-
""" Compile the source file. Return the compiled code.
212+
""" Compile the source file. Return the relative path to compiled file.
230213
May raise a StaticCompilationError if something goes wrong with compilation.
231214
232215
:param source_path: path to the source file
@@ -247,18 +230,6 @@ def compile_source(self, source):
247230
"""
248231
raise NotImplementedError
249232

250-
# noinspection PyMethodMayBeStatic,PyUnusedLocal
251-
def postprocess(self, compiled, source_path):
252-
""" Post-process the compiled code.
253-
254-
:param compiled: compiled code
255-
:type compiled: str
256-
:param source_path: relative path to a source file
257-
:type source_path: str
258-
:returns: str
259-
"""
260-
return compiled
261-
262233
def find_dependencies(self, source_path):
263234
""" Find the dependencies for the given source file.
264235

static_precompiler/compilers/coffeescript.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import os
2+
13
from static_precompiler import exceptions, settings, utils
24

35
from . import base
@@ -18,7 +20,16 @@ def __init__(self, executable=settings.COFFEESCRIPT_EXECUTABLE):
1820
super(CoffeeScript, self).__init__()
1921

2022
def compile_file(self, source_path):
21-
return self.compile_source(self.get_source(source_path))
23+
args = [
24+
self.executable,
25+
"-c",
26+
"-o", os.path.dirname(self.get_full_output_path(source_path)),
27+
self.get_full_source_path(source_path),
28+
]
29+
out, errors = utils.run_command(args)
30+
if errors:
31+
raise exceptions.StaticCompilationError(errors)
32+
return self.get_output_path(source_path)
2233

2334
def compile_source(self, source):
2435
args = [

static_precompiler/compilers/less.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,22 @@ def should_compile(self, source_path, from_management=False):
3333

3434
def compile_file(self, source_path):
3535
full_source_path = self.get_full_source_path(source_path)
36+
full_output_path = self.get_full_output_path(source_path)
3637
args = [
3738
self.executable,
38-
full_source_path,
39+
self.get_full_source_path(source_path),
40+
full_output_path,
3941
]
4042
# `cwd` is a directory containing `source_path`.
4143
# Ex: source_path = '1/2/3', full_source_path = '/abc/1/2/3' -> cwd = '/abc'
4244
cwd = os.path.normpath(os.path.join(full_source_path, *([".."] * len(source_path.split("/")))))
43-
out, errors = utils.run_command(args, None, cwd=cwd)
45+
out, errors = utils.run_command(args, cwd=cwd)
4446
if errors:
4547
raise exceptions.StaticCompilationError(errors)
4648

47-
return out
49+
utils.convert_urls(full_output_path, source_path)
50+
51+
return self.get_output_path(source_path)
4852

4953
def compile_source(self, source):
5054
args = [
@@ -59,9 +63,6 @@ def compile_source(self, source):
5963

6064
return out
6165

62-
def postprocess(self, compiled, source_path):
63-
return utils.convert_urls(compiled, source_path)
64-
6566
def find_imports(self, source):
6667
""" Find the imported files in the source code.
6768

static_precompiler/compilers/scss.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,23 +35,37 @@ def should_compile(self, source_path, from_management=False):
3535

3636
def compile_file(self, source_path):
3737
full_source_path = self.get_full_source_path(source_path)
38+
full_output_path = self.get_full_output_path(source_path)
3839
args = [
3940
self.executable,
40-
full_source_path,
41+
"--sourcemap=none",
4142
]
4243

4344
if self.is_compass_enabled:
4445
args.append("--compass")
4546

47+
args.extend([
48+
self.get_full_source_path(source_path),
49+
full_output_path,
50+
])
51+
52+
full_output_dirname = os.path.dirname(full_output_path)
53+
if not os.path.exists(full_output_dirname):
54+
os.makedirs(full_output_dirname)
55+
4656
# `cwd` is a directory containing `source_path`.
4757
# Ex: source_path = '1/2/3', full_source_path = '/abc/1/2/3' -> cwd = '/abc'
4858
cwd = os.path.normpath(os.path.join(full_source_path, *([".."] * len(source_path.split("/")))))
4959
out, errors = utils.run_command(args, None, cwd=cwd)
5060

5161
if errors:
62+
if os.path.exists(full_output_path):
63+
os.remove(full_output_path)
5264
raise exceptions.StaticCompilationError(errors)
5365

54-
return out
66+
utils.convert_urls(full_output_path, source_path)
67+
68+
return self.get_output_path(source_path)
5569

5670
def compile_source(self, source):
5771
args = [
@@ -70,9 +84,6 @@ def compile_source(self, source):
7084

7185
return out
7286

73-
def postprocess(self, compiled, source_path):
74-
return utils.convert_urls(compiled, source_path)
75-
7687
# noinspection PyMethodMayBeStatic
7788
def parse_import_string(self, import_string):
7889
""" Extract import items from import string.

static_precompiler/compilers/stylus.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,17 @@ def compile_source(self, source):
3737

3838
def compile_file(self, source_path):
3939
full_source_path = self.get_full_source_path(source_path)
40+
full_output_path = self.get_full_output_path(source_path)
4041
args = [
4142
self.executable,
42-
"-p",
4343
full_source_path,
44+
"-o", os.path.dirname(full_output_path),
4445
]
4546

47+
full_output_dirname = os.path.dirname(full_output_path)
48+
if not os.path.exists(full_output_dirname):
49+
os.makedirs(full_output_dirname)
50+
4651
# `cwd` is a directory containing `source_path`.
4752
# Ex: source_path = '1/2/3', full_source_path = '/abc/1/2/3' -> cwd = '/abc'
4853
cwd = os.path.normpath(os.path.join(full_source_path, *([".."] * len(source_path.split("/")))))
@@ -51,10 +56,9 @@ def compile_file(self, source_path):
5156
if errors:
5257
raise exceptions.StaticCompilationError(errors)
5358

54-
return out
59+
utils.convert_urls(full_output_path, source_path)
5560

56-
def postprocess(self, compiled, source_path):
57-
return utils.convert_urls(compiled, source_path)
61+
return self.get_output_path(source_path)
5862

5963
def find_imports(self, source):
6064
""" Find the imported files in the source code.

static_precompiler/tests/test_babel.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,29 @@
11
# coding: utf-8
2+
import os
3+
24
import pytest
35

46
from static_precompiler import compilers, exceptions
57

68
from .test_coffeescript import clean_javascript
79

810

9-
def test_compile_file():
11+
def test_compile_file(monkeypatch, tmpdir):
12+
monkeypatch.setattr("static_precompiler.settings.ROOT", tmpdir.strpath)
13+
1014
compiler = compilers.Babel()
1115

12-
assert (
13-
clean_javascript(compiler.compile_file("scripts/test.es6")) ==
14-
""""use strict";\nconsole.log("Hello, World!");"""
15-
)
16+
assert compiler.compile_file("scripts/test.es6") == "COMPILED/scripts/test.js"
17+
18+
full_output_path = compiler.get_full_output_path("scripts/test.es6")
19+
20+
assert os.path.exists(full_output_path)
21+
22+
with open(full_output_path) as compiled:
23+
assert compiled.read() == """"use strict";
24+
25+
console.log("Hello, World!");
26+
"""
1627

1728

1829
def test_compile_source():

static_precompiler/tests/test_base_compiler.py

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -142,38 +142,16 @@ def test_get_source():
142142
assert compiler.get_source("scripts/test.coffee") == 'console.log "Hello, World!"'
143143

144144

145-
def test_write_output(monkeypatch, tmpdir):
146-
compiler = compilers.BaseCompiler()
147-
148-
output_path = os.path.join(tmpdir.dirname, "dummy.js")
149-
assert os.path.exists(output_path) is False
150-
151-
monkeypatch.setattr(compiler, "get_full_output_path", lambda x: output_path)
152-
153-
compiler.write_output("compiled", "dummy.coffee")
154-
assert os.path.exists(output_path) is True
155-
156-
with open(output_path) as output:
157-
assert output.read() == "compiled"
158-
159-
160145
def test_compile_source():
161146
compiler = compilers.BaseCompiler()
162147
with pytest.raises(NotImplementedError):
163148
compiler.compile_source("source")
164149

165150

166-
def test_postprocess():
167-
compiler = compilers.BaseCompiler()
168-
assert compiler.postprocess("compiled", "dummy.coffee") == "compiled"
169-
170-
171151
def test_compile(monkeypatch):
172152
compiler = compilers.BaseCompiler()
173153

174-
monkeypatch.setattr(compiler, "compile_file", pretend.call_recorder(lambda *args: "compiled"))
175-
monkeypatch.setattr(compiler, "write_output", pretend.call_recorder(lambda *args: None))
176-
monkeypatch.setattr(compiler, "postprocess", pretend.call_recorder(lambda compiled, source_path: compiled))
154+
monkeypatch.setattr(compiler, "compile_file", pretend.call_recorder(lambda *args: "dummy.js"))
177155
monkeypatch.setattr(compiler, "update_dependencies", pretend.call_recorder(lambda *args: None))
178156
monkeypatch.setattr(compiler, "find_dependencies", pretend.call_recorder(lambda *args: ["A", "B"]))
179157
monkeypatch.setattr(compiler, "get_output_path", lambda *args: "dummy.js")
@@ -185,31 +163,19 @@ def test_compile(monkeypatch):
185163

186164
# noinspection PyUnresolvedReferences
187165
assert compiler.compile_file.calls == []
188-
# noinspection PyUnresolvedReferences
189-
assert compiler.write_output.calls == []
190-
# noinspection PyUnresolvedReferences
191-
assert compiler.postprocess.calls == []
192166

193167
monkeypatch.setattr(compiler, "is_supported", lambda *args: True)
194168
monkeypatch.setattr(compiler, "should_compile", lambda *args, **kwargs: False)
195169

196170
assert compiler.compile("dummy.coffee") == "dummy.js"
197171
# noinspection PyUnresolvedReferences
198172
assert compiler.compile_file.calls == []
199-
# noinspection PyUnresolvedReferences
200-
assert compiler.write_output.calls == []
201-
# noinspection PyUnresolvedReferences
202-
assert compiler.postprocess.calls == []
203173

204174
monkeypatch.setattr(compiler, "should_compile", lambda *args, **kwargs: True)
205175
assert compiler.compile("dummy.coffee") == "dummy.js"
206176

207177
# noinspection PyUnresolvedReferences
208178
assert compiler.compile_file.calls == [pretend.call("dummy.coffee")]
209-
# noinspection PyUnresolvedReferences
210-
assert compiler.write_output.calls == [pretend.call("compiled", "dummy.coffee")]
211-
# noinspection PyUnresolvedReferences
212-
assert compiler.postprocess.calls == [pretend.call("compiled", "dummy.coffee")]
213179

214180
# noinspection PyUnresolvedReferences
215181
assert compiler.update_dependencies.calls == []

static_precompiler/tests/test_coffeescript.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# coding: utf-8
2+
import os
3+
24
import pytest
35

46
from static_precompiler import compilers, exceptions
@@ -11,13 +13,15 @@ def clean_javascript(js):
1113
)
1214

1315

14-
def test_compile_file():
16+
def test_compile_file(monkeypatch, tmpdir):
17+
monkeypatch.setattr("static_precompiler.settings.ROOT", tmpdir.strpath)
18+
1519
compiler = compilers.CoffeeScript()
1620

17-
assert (
18-
clean_javascript(compiler.compile_file("scripts/test.coffee")) ==
19-
"""(function() {\n console.log("Hello, World!");\n}).call(this);"""
20-
)
21+
assert clean_javascript(compiler.compile_file("scripts/test.coffee")) == "COMPILED/scripts/test.js"
22+
assert os.path.exists(compiler.get_full_output_path("scripts/test.coffee"))
23+
with open(compiler.get_full_output_path("scripts/test.coffee")) as compiled:
24+
assert clean_javascript(compiled.read()) == """(function() {\n console.log("Hello, World!");\n}).call(this);"""
2125

2226

2327
def test_compile_source():

0 commit comments

Comments
 (0)