blob: a176af1bcc71844c2e0613c7e9811d977f55077a [file] [log] [blame]
%% -*- tab-width: 4;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ft=erlang ts=4 sw=4 et
%% Licensed under the Apache License, Version 2.0 (the "License"); you may not
%% use this file except in compliance with the License. You may obtain a copy of
%% the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
%% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
%% License for the specific language governing permissions and limitations under
%% the License.
%%
%%
%% Utility script to compile query server .js files into C arrays. Main JS and
%% Coffeescript files are treated separately. First each is bundled into a
%% single .js file. Then the file is passed to qjsc to produce the bytecode
%% array.
%%
-export([main/1]).
-mode(compile).
main(["compile"]) ->
concat_js_files("bundle_mainjs.js", "bundle_coffee.js"),
Changed1 = compile_bytecode("bundle_mainjs.js", "couchjs_mainjs_bytecode.c"),
Changed2 = compile_bytecode("bundle_coffee.js", "couchjs_coffee_bytecode.c"),
case Changed1 orelse Changed2 of
true ->
% A stupid hack. The compile step is often too quick and
% generates .o timestamps with the same 1 second timestamp
% as the .c file. During dev work, it means it will
% re-compile and re-link everything uncessarily at least
% one more time as the port compiler compares timestamps
% with the >= operator.
timer:sleep(1000),
ok;
false ->
ok
end;
main(["clean"]) ->
rm("priv/bundle_*.js"),
rm("c_src/couchjs_*_bytecode.c");
main(Arg) ->
io:format(standard_error, "Expected a 'compile' or 'clean' arg. Got:~p", [Arg]),
halt(1).
concat_js_files(JsScript, CoffeeScript) ->
Prefix = "../../share/server/",
JsFiles = [
"rewrite_fun.js",
"dreyfus.js",
"nouveau.js",
"filter.js",
"mimeparse.js",
"render.js",
"state.js",
"util.js",
"validate.js",
"views.js"
],
Main = JsFiles ++ ["dispatch-quickjs.js"],
Coffee = JsFiles ++ ["coffee-script.js", "dispatch-quickjs.js"],
concat([Prefix ++ File || File <- Main], "priv/" ++ JsScript),
concat([Prefix ++ File || File <- Coffee], "priv/" ++ CoffeeScript),
ok.
compile_bytecode(Js, CBytecode) ->
% cp_if_different/2 is used to to avoid triggering a re-compile if nothing changed
Tmp = CBytecode ++ ".tmp",
{ok, Cwd} = file:get_cwd(),
CompileCmd = Cwd ++ "/quickjs/qjsc -c -N bytecode -o c_src/" ++ Tmp ++ " priv/" ++ Js,
os:cmd(CompileCmd),
Changed = cp_if_different("c_src/" ++ Tmp, "c_src/" ++ CBytecode),
rm("c_src/" ++ Tmp),
Changed.
cp_if_different(From, To) ->
Bin = fread(From),
case filelib:is_file(To) of
true ->
case fread(To) of
Bin ->
false;
<<_/binary>> ->
ok = fwrite(To, Bin),
true
end;
false ->
ok = fwrite(To, Bin),
true
end.
concat(Sources, Target) ->
SourceBins = [fread(P) || P <- Sources],
TargetBin = iolist_to_binary(["(function () {\n"] ++ SourceBins ++ ["})();\n"]),
fwrite(Target, TargetBin).
fread(Path) ->
{ok, Bin} = file:read_file(Path),
Bin.
fwrite(Path, Bin) when is_binary(Bin) ->
ok = file:write_file(Path, Bin).
rm(Path) ->
Fun = fun(F) ->
case filelib:is_file(F) of
true -> ok = file:delete(F);
false -> ok
end
end,
lists:foreach(Fun, filelib:wildcard(Path)).