Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 42 additions & 131 deletions src/packager/packager.re
Original file line number Diff line number Diff line change
@@ -1,145 +1,56 @@
/**
* How this works?
* 1. Build a dependencies list of the current package in the correct loading order
* ocamlfind query PACKAGE_NAME -r -p-format -predicates byte
* 2. With that list of all packages. We can find cmi and cma files and building them one by one
* ocamlfind query PACKAGE_NAME -i-format -predicates byte
* ocamlfind query PACKAGE_NAME -a-format -predicates byte
* 3. There are some deduplication going on so we don't build the package twice
*/
open Utils;
let verbose = ref(false);
let output = ref(None);

let execute = execute(~verbose);

let usage = () => {
Format.eprintf("Usage: sketch [find packages] @.");
Format.eprintf(" --verbose@.");
Format.eprintf(" --output\t\t\tBuild output directory@.");
Format.eprintf(" --help\t\t\tDisplay usage@.");
exit(1);
let verbose = ref(true);
let exec = Utils.execute(~verbose);

module Ocamlfind = {
let cmas = name =>
["ocamlfind query", name, "-r -predicates byte -a-format"] |> exec;
let cmis = name =>
["ocamlfind query", name, "-r -predicates byte -i-format"] |> exec;
};

let rec scan_args = acc =>
fun
| ["--verbose", ...xs] => {
verbose := true;
scan_args(acc, xs);
}
| ["--help" | "-h", ..._] => usage()
| ["--output", outputDir, ...xs] => {
output := Some(outputDir);
scan_args(acc, xs);
}
| [x, ...xs] => scan_args([x, ...acc], xs)
| [] => List.rev(acc);
module Ocamlc = {
let archive = (aFiles, output) => {
let cma = output ++ ".cma";
["ocamlc -a", aFiles, "-o", cma] |> exec |> ignore;
cma;
};
};

let findDeps = name =>
execute([
"ocamlfind",
"query",
name,
"-r",
"-p-format",
"-predicates byte",
]);
let findCmi = name =>
execute(["ocamlfind", "query", name, "-i-format", "-predicates byte"]);
let findCma = name =>
execute(["ocamlfind", "query", name, "-a-format", "-predicates byte"]);
module Jsoo = {
let lib = name => name ++ ".sketch.lib.js";

let buildLib = (~outputDir, packageName) => {
if (verbose^) {
Printf.printf("Building library with jsoo: %s\n", packageName);
};
let safePkgName = toSafePackageName(packageName);
let funcName = "sketch__private__" ++ safePkgName;
let autoBootstrap = libName =>
["echo \"sketch_private__" ++ libName ++ "(self);\"", ">>", lib(libName)]
|> exec
|> ignore;

let cmaPath = findCma(packageName);
switch (String.trim(cmaPath)) {
| "" => print_endline("Can't find cma file for package " ++ packageName)
| _ =>
execute([
let compile = (libName, archive, cmis) =>
[
"js_of_ocaml",
"--wrap-with-fun=" ++ funcName,
"--wrap-with-fun=sketch_private__" ++ libName,
"--toplevel",
findCmi(packageName),
findCma(packageName),
cmis,
archive,
"-o",
Filename.concat(outputDir, safePkgName ++ ".lib.sketch.js"),
])
|> ignore
};
lib(libName),
]
|> exec
|> ignore;
};

module SS = Set.Make(String);
module LibMap = Map.Make(String);

/*
* These packages are for compatibility with OCaml
* But Sketch only supports OCaml > 4.06
* So this will result in not found packages
*/

let excludedPackages = SS.of_list(["uchar", "result", "bytes"]);
module Cli = {
let run = () => {
let libName = Sys.argv[1];
Printf.printf("Beginning build for \"%s\"...\n", libName);

module J = Json;
let cmas = Ocamlfind.cmas(libName);
let cmis = Ocamlfind.cmis(libName);
let bundle = Ocamlc.archive(cmas, libName);
Jsoo.compile(libName, bundle, cmis);
Jsoo.autoBootstrap(libName);

let build = (~outputDir, toplevelPkgs) => {
/* if (verbose^) {
Printf.printf("Building dependencies for: %s\n", toplevelPkg);
}; */
let libsToBuild = ref(SS.empty);
let libsWithDependencies =
toplevelPkgs
|> List.fold_left(
(map: LibMap.t(list(string)), pkg) => {
let allDeps =
findDeps(pkg)
|> String.split_on_char('\n')
|> List.filter(name => name != "")
|> List.filter(name => !SS.mem(name, excludedPackages));

let _ =
allDeps
|> List.iter(name => libsToBuild := libsToBuild^ |> SS.add(name));

map |> LibMap.add(pkg, allDeps);
},
LibMap.empty,
);

let _ = libsToBuild^ |> SS.iter(name => buildLib(~outputDir, name));
let _ =
LibMap.fold(
(topName, libs, acc) => {
let libField =
J.Object([
(topName, J.Array(libs |> List.map(name => J.String(name)))),
]);
[libField, ...acc];
},
libsWithDependencies,
[],
)
|> (list => J.Array(list))
|> (json => J.stringify(json))
|> writeFileSync(~path=Filename.concat(outputDir, "list.json"));
();
Printf.printf("📦 Done!\n");
};
};

let _ = {
let args = List.tl(Array.to_list(Sys.argv));
let args = scan_args([], args);

let outputDir =
switch (output^) {
| None => Filename.concat(Sys.getcwd(), "packages")
| Some(output) => output
};
mkdirp(outputDir);

build(~outputDir, args);
print_endline("Done !");
};
Cli.run();