Simplify build file

This commit is contained in:
be5invis 2020-11-27 01:44:43 -08:00
parent 794cdb2f6c
commit 3a3a4ff633

View file

@ -52,26 +52,9 @@ const Version = oracle(`oracle:version`, async target => {
return package_json.version; return package_json.version;
}); });
const HasTtx = oracle(`oracle:has-ttx`, async () => { ///////////////////////////////////////////////////////////
try { ////// Plans //////
const cmd = await which(TTX); ///////////////////////////////////////////////////////////
return !!cmd;
} catch (e) {
return false;
}
});
async function tryParseToml(str) {
try {
return JSON.parse(JSON.stringify(toml.parse(fs.readFileSync(str, "utf-8"))));
} catch (e) {
throw new Error(
`Failed to parse configuration file ${str}.\n` +
`Please validate whether there's syntax error.\n` +
`${e}`
);
}
}
const RawPlans = computed(`metadata:raw-plans`, async target => { const RawPlans = computed(`metadata:raw-plans`, async target => {
await target.need(sfu(BUILD_PLANS), ofu(PRIVATE_BUILD_PLANS)); await target.need(sfu(BUILD_PLANS), ofu(PRIVATE_BUILD_PLANS));
@ -86,30 +69,17 @@ const RawPlans = computed(`metadata:raw-plans`, async target => {
} }
return bp; return bp;
}); });
const OptimizeWithTtx = computed("metadata:optimize-with-ttx", async target => { async function tryParseToml(str) {
const [hasTtx, rp] = await target.need(HasTtx, RawPlans); try {
return hasTtx && !!rp.buildOptions.optimizeWithTtx; return JSON.parse(JSON.stringify(toml.parse(fs.readFileSync(str, "utf-8"))));
}); } catch (e) {
const OptimizeWithFilter = computed("metadata:optimize-with-filter", async target => { throw new Error(
const [rp] = await target.need(RawPlans); `Failed to parse configuration file ${str}.\n` +
return rp.buildOptions.optimizeWithFilter; `Please validate whether there's syntax error.\n` +
}); `${e}`
const RawCollectPlans = computed("metadata:raw-collect-plans", async target => { );
const [rp] = await target.need(RawPlans);
return rp.collectPlans;
});
const CollectConfig = computed("metadata:collect-config", async target => {
const [rp] = await target.need(RawPlans);
return rp.collectConfig;
});
const ExportPlans = computed("metadata:export-plans", async target => {
const [rp] = await target.need(RawCollectPlans);
let result = {};
for (const collection in rp) {
for (const s of rp[collection].from) result[s] = s;
} }
return result; }
});
const BuildPlans = computed("metadata:build-plans", async target => { const BuildPlans = computed("metadata:build-plans", async target => {
const [rp] = await target.need(RawPlans); const [rp] = await target.need(RawPlans);
@ -255,17 +225,110 @@ function whyBuildPlanIsnNotThere(gid) {
return ""; return "";
} }
///////////////////////////////////////////////////////////
////// Font Building //////
///////////////////////////////////////////////////////////
const BuildRawTtf = file.make(
(gr, fn) => `${BUILD}/ttf/${gr}/${fn}.raw.ttf`,
async (target, output, gr, fn) => {
const [fi] = await target.need(FontInfoOf(fn), Version);
const charmap = output.dir + "/" + fn + ".charmap";
await target.need(Scripts, Parameters, de`${output.dir}`);
await node("font-src/index", { o: output.full, oCharMap: charmap, ...fi });
}
);
const BuildTTF = file.make(
(gr, fn) => `${BUILD}/ttf/${gr}/${fn}.ttf`,
async (target, output, gr, fn) => {
await target.need(de`${output.dir}`);
await target.needed(FontInfoOf(fn), Version, Scripts, Parameters);
const [rawTtf] = await target.order(BuildRawTtf(gr, fn));
await mv(rawTtf.full, output.full);
}
);
const BuildCM = file.make(
(gr, f) => `${BUILD}/ttf/${gr}/${f}.charmap`,
async (target, output, gr, f) => {
await target.need(BuildTTF(gr, f));
}
);
///////////////////////////////////////////////////////////
////// Font Distribution //////
///////////////////////////////////////////////////////////
// Group-level
const GroupContents = task.group("contents", async (target, gr) => {
await target.need(GroupFonts(gr), DistWebFontCSS(gr));
return gr;
});
// Webfont CSS
const DistWebFontCSS = file.make(
gid => `${DIST}/${gid}/${gid}.css`,
async (target, out, gid) => {
// Note: this target does NOT depend on the font files.
const [gr, ts] = await target.need(BuildPlanOf(gid), GroupFontsOf(gid), de(out.dir));
const hs = await target.need(...ts.map(FontInfoOf));
await node("utility/make-webfont-css.js", out.full, gr.family, hs, webfontFormats);
}
);
// Content files
const GroupTTFs = task.group("ttf", async (target, gid) => {
const [ts] = await target.need(GroupFontsOf(gid));
await target.need(ts.map(tn => DistHintedTTF(gid, tn)));
});
const GroupUnhintedTTFs = task.group("ttf-unhinted", async (target, gid) => {
const [ts] = await target.need(GroupFontsOf(gid));
await target.need(ts.map(tn => DistUnhintedTTF(gid, tn)));
});
const GroupWoff2s = task.group("woff2", async (target, gid) => {
const [ts] = await target.need(GroupFontsOf(gid));
await target.need(ts.map(tn => DistWoff2(gid, tn)));
});
const GroupFonts = task.group("fonts", async (target, gid) => {
await target.need(GroupTTFs(gid), GroupUnhintedTTFs(gid), GroupWoff2s(gid));
});
// Per group file
const DistUnhintedTTF = file.make(
(gr, fn) => `${DIST}/${gr}/ttf-unhinted/${fn}.ttf`,
async (target, path, gr, f) => {
const [from] = await target.need(BuildTTF(gr, f), de`${path.dir}`);
await cp(from.full, path.full);
}
);
const DistHintedTTF = file.make(
(gr, fn) => `${DIST}/${gr}/ttf/${fn}.ttf`,
async (target, path, gr, f) => {
const [{ hintParams }] = await target.need(FontInfoOf(f));
const [from] = await target.need(BuildTTF(gr, f), de`${path.dir}`);
await run("ttfautohint", hintParams, from.full, path.full);
}
);
const DistWoff2 = file.make(
(gr, fn) => `${DIST}/${gr}/woff2/${fn}.woff2`,
async (target, path, group, f) => {
const [from] = await target.need(DistHintedTTF(group, f), de`${path.dir}`);
await node(`utility/ttf-to-woff2.js`, from.full, path.full);
}
);
///////////////////////////////////////////////////////////
////// Font Collection Plans //////
///////////////////////////////////////////////////////////
const CollectPlans = computed(`metadata:collect-plans`, async target => { const CollectPlans = computed(`metadata:collect-plans`, async target => {
const [rawCollectPlans, suffixMapping, collectConfig] = await target.need( const [rawPlans, suffixMapping] = await target.need(RawPlans, StandardSuffixes);
RawCollectPlans,
StandardSuffixes,
CollectConfig
);
return await getCollectPlans( return await getCollectPlans(
target, target,
rawCollectPlans, rawPlans.collectPlans,
suffixMapping, suffixMapping,
collectConfig, rawPlans.collectConfig,
fnStandardTtc fnStandardTtc
); );
}); });
@ -332,140 +395,43 @@ function fnStandardTtc(collectConfig, prefix, w, wd, s) {
} }
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
////// Font Building ////// ////// Font Collection //////
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
const BuildRawTtf = file.make( const SpecificSuperTtc = task.group(`super-ttc`, async (target, cgr) => {
(gr, fn) => `${BUILD}/ttf/${gr}/${fn}.raw.ttf`, await target.need(CollectedSuperTtcFile(cgr));
async (target, output, gr, fn) => {
const [fi] = await target.need(FontInfoOf(fn), Version);
const charmap = output.dir + "/" + fn + ".charmap";
await target.need(Scripts, Parameters, de`${output.dir}`);
await node("font-src/index", { o: output.full, oCharMap: charmap, ...fi });
}
);
const BuildTTF = file.make(
(gr, fn) => `${BUILD}/ttf/${gr}/${fn}.ttf`,
async (target, output, gr, fn) => {
const [useFilter, useTtx] = await target.need(
OptimizeWithFilter,
OptimizeWithTtx,
de`${output.dir}`
);
await target.needed(FontInfoOf(fn), Version, Scripts, Parameters);
const [rawTtf] = await target.order(BuildRawTtf(gr, fn));
if (useFilter) {
const filterArgs = useFilter.split(/ +/g);
await run(filterArgs, rawTtf.full, output.full);
await rm(rawTtf.full);
} else if (useTtx) {
const ttxPath = `${output.dir}/${output.name}.temp.ttx`;
await run(TTX, "-q", ["-o", ttxPath], rawTtf.full);
await rm(rawTtf.full);
await run(TTX, "-q", ["-o", output.full], ttxPath);
await rm(ttxPath);
} else {
await mv(rawTtf.full, output.full);
}
}
);
const BuildCM = file.make(
(gr, f) => `${BUILD}/ttf/${gr}/${f}.charmap`,
async (target, output, gr, f) => {
await target.need(BuildTTF(gr, f));
}
);
///////////////////////////////////////////////////////////
////// Font Distribution //////
///////////////////////////////////////////////////////////
// Per group file
const DistUnhintedTTF = file.make(
(gr, fn) => `${DIST}/${gr}/ttf-unhinted/${fn}.ttf`,
async (target, path, gr, f) => {
const [from] = await target.need(BuildTTF(gr, f), de`${path.dir}`);
await cp(from.full, path.full);
}
);
const DistHintedTTF = file.make(
(gr, fn) => `${DIST}/${gr}/ttf/${fn}.ttf`,
async (target, path, gr, f) => {
const [{ hintParams }] = await target.need(FontInfoOf(f));
const [from] = await target.need(BuildTTF(gr, f), de`${path.dir}`);
await run("ttfautohint", hintParams, from.full, path.full);
}
);
const DistWoff = file.make(
(gr, fn) => `${DIST}/${gr}/woff/${fn}.woff`,
async (target, path, group, f) => {
const [from] = await target.need(DistHintedTTF(group, f), de`${path.dir}`);
await node(`utility/ttf-to-woff.js`, from.full, path.full);
}
);
const DistWoff2 = file.make(
(gr, fn) => `${DIST}/${gr}/woff2/${fn}.woff2`,
async (target, path, group, f) => {
const [from] = await target.need(DistHintedTTF(group, f), de`${path.dir}`);
await node(`utility/ttf-to-woff2.js`, from.full, path.full);
}
);
// Group-level
const GroupTTFs = task.group("ttf", async (target, gid) => {
const [ts] = await target.need(GroupFontsOf(gid));
await target.need(ts.map(tn => DistHintedTTF(gid, tn)));
}); });
const GroupUnhintedTTFs = task.group("ttf-unhinted", async (target, gid) => { const CollectedSuperTtcFile = file.make(
const [ts] = await target.need(GroupFontsOf(gid)); cgr => `${DIST_SUPER_TTC}/${cgr}.ttc`,
await target.need(ts.map(tn => DistUnhintedTTF(gid, tn))); async (target, out, cgr) => {
}); const [cp] = await target.need(CollectPlans, de(out.dir));
const GroupWoff2s = task.group("woff2", async (target, gid) => { const parts = Array.from(new Set(cp.ttcContents[cgr]));
const [ts] = await target.need(GroupFontsOf(gid)); const [inputs] = await target.need(parts.map(pt => CollectedTtcFile(cgr, pt)));
await target.need(ts.map(tn => DistWoff2(gid, tn)));
});
const GroupFonts = task.group("fonts", async (target, gid) => {
await target.need(GroupTTFs(gid), GroupUnhintedTTFs(gid), GroupWoff2s(gid));
});
// Webfont CSS
const DistWebFontCSS = file.make(
gid => `${DIST}/${gid}/${gid}.css`,
async (target, out, gid) => {
// Note: this target does NOT depend on the font files.
const [gr, ts] = await target.need(BuildPlanOf(gid), GroupFontsOf(gid), de(out.dir));
const hs = await target.need(...ts.map(FontInfoOf));
await node("utility/make-webfont-css.js", out.full, gr.family, hs, webfontFormats);
}
);
const GroupContents = task.group("contents", async (target, gr) => {
await target.need(GroupFonts(gr), DistWebFontCSS(gr));
return gr;
});
// TTC
const ExportTtcFile = file.make(
(gr, f) => `${BUILD}/ttc-collect/${gr}/ttc/${f}.ttc`,
async (target, out, gr, f) => {
const [cp] = await target.need(CollectPlans, de`${out.dir}`);
const parts = Array.from(new Set(cp.ttcComposition[f]));
const [inputs] = await target.need(parts.map(pt => glyfTtc(gr, pt)));
await buildCompositeTtc(out, inputs); await buildCompositeTtc(out, inputs);
} }
); );
const glyfTtc = file.make( const CollectedTtcFile = file.make(
(gr, f) => `${BUILD}/glyf-ttc/${gr}/${f}.ttc`, (cgr, f) => `${BUILD}/ttc-collect/${cgr}/ttc/${f}.ttc`,
async (target, out, gr, f) => {
const [cp] = await target.need(CollectPlans, de`${out.dir}`);
const parts = Array.from(new Set(cp.ttcComposition[f]));
const [inputs] = await target.need(parts.map(pt => GlyfTtc(gr, pt)));
await buildCompositeTtc(out, inputs);
}
);
const GlyfTtc = file.make(
(cgr, f) => `${BUILD}/glyf-ttc/${cgr}/${f}.ttc`,
async (target, out, gr, f) => { async (target, out, gr, f) => {
const [cp] = await target.need(CollectPlans); const [cp] = await target.need(CollectPlans);
const parts = cp.glyfTtcComposition[f]; const parts = cp.glyfTtcComposition[f];
await buildGlyfTtc(target, parts, out); await buildGlyphSharingTtc(target, parts, out);
} }
); );
async function buildCompositeTtc(out, inputs) {
async function buildGlyfTtc(target, parts, out) { const inputPaths = inputs.map(f => f.full);
await run(TTCIZE, ["-o", out.full], inputPaths);
}
async function buildGlyphSharingTtc(target, parts, out) {
await target.need(de`${out.dir}`); await target.need(de`${out.dir}`);
const [ttfInputs] = await target.need(parts.map(part => BuildTTF(part.dir, part.file))); const [ttfInputs] = await target.need(parts.map(part => BuildTTF(part.dir, part.file)));
const tmpTtc = `${out.dir}/${out.name}.unhinted.ttc`; const tmpTtc = `${out.dir}/${out.name}.unhinted.ttc`;
@ -474,63 +440,22 @@ async function buildGlyfTtc(target, parts, out) {
await run("ttfautohint", tmpTtc, out.full); await run("ttfautohint", tmpTtc, out.full);
await rm(tmpTtc); await rm(tmpTtc);
} }
async function buildCompositeTtc(out, inputs) {
const inputPaths = inputs.map(f => f.full);
await run(TTCIZE, ["-o", out.full], inputPaths);
}
const ExportSuperTtc = file.make(
gr => `${DIST_SUPER_TTC}/${gr}.ttc`,
async (target, out, gr) => {
const [cp] = await target.need(CollectPlans, de(out.dir));
const parts = Array.from(new Set(cp.ttcContents[gr]));
const [inputs] = await target.need(parts.map(pt => ExportTtcFile(gr, pt)));
await buildCompositeTtc(out, inputs);
}
);
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
////// Archives ////// ////// Archives //////
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
// Collection Archives // Collection Archives
const CollectionArchiveFile = file.make( const TtcArchiveFile = file.make(
(gr, version) => `${ARCHIVE_DIR}/pkg-${gr}-${version}.zip`, (cgr, version) => `${ARCHIVE_DIR}/ttc-${cgr}-${version}.zip`,
async (target, out, gr) => { async (target, out, cgr) => {
const [collectPlans] = await target.need(CollectPlans, de`${out.dir}`); const [collectPlans] = await target.need(CollectPlans, de`${out.dir}`);
const sourceGroups = collectPlans.groupDecomposition[gr]; const ttcFiles = Array.from(new Set(collectPlans.ttcContents[cgr]));
const ttcFiles = Array.from(new Set(collectPlans.ttcContents[gr])); await target.need(ttcFiles.map(pt => CollectedTtcFile(cgr, pt)));
await target.need(sourceGroups.map(g => GroupContents(g)));
await target.need(ttcFiles.map(pt => ExportTtcFile(gr, pt)));
// Packaging // Packaging
await rm(out.full); await rm(out.full);
for (const g of sourceGroups) { await cd(`${BUILD}/ttc-collect/${cgr}/ttc`).run(
await cd(`${DIST}/${g}`).run(
["7z", "a"],
["-tzip", "-r", "-mx=9"],
`../../${out.full}`,
`./`
);
}
await cd(`${BUILD}/ttc-collect/${gr}`).run(
["7z", "a"],
["-tzip", "-r", "-mx=9"],
`../../../${out.full}`,
`./`
);
}
);
const TtcOnlyCollectionArchiveFile = file.make(
(gr, version) => `${ARCHIVE_DIR}/ttc-${gr}-${version}.zip`,
async (target, out, gr) => {
const [collectPlans] = await target.need(CollectPlans, de`${out.dir}`);
const ttcFiles = Array.from(new Set(collectPlans.ttcContents[gr]));
await target.need(ttcFiles.map(pt => ExportTtcFile(gr, pt)));
// Packaging
await rm(out.full);
await cd(`${BUILD}/ttc-collect/${gr}/ttc`).run(
["7z", "a"], ["7z", "a"],
["-tzip", "-r", "-mx=9"], ["-tzip", "-r", "-mx=9"],
`../../../../${out.full}`, `../../../../${out.full}`,
@ -538,53 +463,37 @@ const TtcOnlyCollectionArchiveFile = file.make(
); );
} }
); );
const CollectionArchive = task.group(`collection-archive`, async (target, cid) => {
const [version] = await target.need(Version);
await target.need(CollectionArchiveFile(cid, version));
});
const TtcOnlyCollectionArchive = task.group(`ttc-only-collection-archive`, async (target, cid) => {
const [version] = await target.need(Version);
await target.need(TtcOnlyCollectionArchiveFile(cid, version));
});
// Single-group Archives // Single-group Archives
const GroupTtfArchiveFile = file.make(
(gr, version) => `${ARCHIVE_DIR}/ttf-${gr}-${version}.zip`,
async (target, out, gr) => {
await target.need(de`${out.dir}`);
await target.need(GroupContents(gr));
await CreateGroupArchiveFile(`${DIST}/${gr}/ttf`, out, "*.ttf");
}
);
const GroupTtfUnhintedArchiveFile = file.make(
(gr, version) => `${ARCHIVE_DIR}/ttf-unhinted-${gr}-${version}.zip`,
async (target, out, gr) => {
await target.need(de`${out.dir}`);
await target.need(GroupContents(gr));
await CreateGroupArchiveFile(`${DIST}/${gr}/ttf-unhinted`, out, "*.ttf");
}
);
const GroupWebArchiveFile = file.make(
(gr, version) => `${ARCHIVE_DIR}/webfont-${gr}-${version}.zip`,
async (target, out, gr) => {
await target.need(de`${out.dir}`);
await target.need(GroupContents(gr));
await CreateGroupArchiveFile(`${DIST}/${gr}`, out, "*.css", "ttf", "woff2");
}
);
async function CreateGroupArchiveFile(dir, out, ...files) { async function CreateGroupArchiveFile(dir, out, ...files) {
const relOut = Path.relative(dir, out.full); const relOut = Path.relative(dir, out.full);
await rm(out.full); await rm(out.full);
await cd(dir).run(["7z", "a"], ["-tzip", "-r", "-mx=9"], relOut, ...files); await cd(dir).run(["7z", "a"], ["-tzip", "-r", "-mx=9"], relOut, ...files);
} }
const GroupTtfArchiveFile = file.make(
(gid, version) => `${ARCHIVE_DIR}/ttf-${gid}-${version}.zip`,
async (target, out, gid) => {
const [exportPlans] = await target.need(ExportPlans, de`${out.dir}`);
await target.need(GroupContents(exportPlans[gid]));
await CreateGroupArchiveFile(`${DIST}/${exportPlans[gid]}/ttf`, out, "*.ttf");
}
);
const GroupTtfUnhintedArchiveFile = file.make(
(gid, version) => `${ARCHIVE_DIR}/ttf-unhinted-${gid}-${version}.zip`,
async (target, out, gid) => {
const [exportPlans] = await target.need(ExportPlans, de`${out.dir}`);
await target.need(GroupContents(exportPlans[gid]));
await CreateGroupArchiveFile(`${DIST}/${exportPlans[gid]}/ttf-unhinted`, out, "*.ttf");
}
);
const GroupWebArchiveFile = file.make(
(gid, version) => `${ARCHIVE_DIR}/webfont-${gid}-${version}.zip`,
async (target, out, gid) => {
const [exportPlans] = await target.need(ExportPlans, de`${out.dir}`);
await target.need(GroupContents(exportPlans[gid]));
await CreateGroupArchiveFile(`${DIST}/${exportPlans[gid]}`, out, "*.css", "ttf", "woff2");
}
);
const GroupArchive = task.group(`archive`, async (target, gid) => {
const [version] = await target.need(Version);
await target.need(
GroupTtfArchiveFile(gid, version),
GroupTtfUnhintedArchiveFile(gid, version),
GroupWebArchiveFile(gid, version)
);
});
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
////// Root Tasks ////// ////// Root Tasks //////
@ -750,25 +659,6 @@ const SampleImages = task(`sample-images`, async target => {
); );
}); });
const AllTtfArchives = task(`all:ttf`, async target => {
const [exportPlans] = await target.need(ExportPlans);
await target.need(Object.keys(exportPlans).map(GroupArchive));
});
const CollectionArchives = task(`all:pkg`, async target => {
const [collectPlans] = await target.need(CollectPlans);
await target.need(Object.keys(collectPlans.groupDecomposition).map(CollectionArchive));
});
const AllTtcArchives = task(`all:ttc`, async target => {
const [collectPlans] = await target.need(CollectPlans);
await target.need(Object.keys(collectPlans.groupDecomposition).map(TtcOnlyCollectionArchive));
});
const SpecificSuperTtc = task.group(`super-ttc`, async (target, gr) => {
await target.need(ExportSuperTtc(gr));
});
const ReleaseNotes = task(`release:release-note`, async t => { const ReleaseNotes = task(`release:release-note`, async t => {
const [version] = await t.need(Version); const [version] = await t.need(Version);
await t.need(ReleaseNotesFile(version)); await t.need(ReleaseNotesFile(version));
@ -827,7 +717,19 @@ phony(`clean`, async () => {
build.deleteJournal(); build.deleteJournal();
}); });
phony(`release`, async target => { phony(`release`, async target => {
await target.need(AllTtfArchives, /* CollectionArchives, */ AllTtcArchives); const [version, collectPlans] = await target.need(Version, CollectPlans);
let goals = [];
for (const [cgr, subGroups] of Object.entries(collectPlans.groupDecomposition)) {
goals.push(TtcArchiveFile(cgr, version));
for (const gr of subGroups) {
goals.push(
GroupTtfArchiveFile(gr, version),
GroupTtfUnhintedArchiveFile(gr, version),
GroupWebArchiveFile(gr, version)
);
}
}
await target.need(goals);
await target.need(SampleImages, Pages, ReleaseNotes, ChangeLog); await target.need(SampleImages, Pages, ReleaseNotes, ChangeLog);
}); });