diff --git a/.travis.yml b/.travis.yml index 6a78f713..5ebba1ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,12 +4,12 @@ sudo: false language: node_js cache: npm -node_js: 8 +node_js: 10 install: - pip install --user -r requirements.txt - npm install - - 'if [[ "$TRAVIS_BRANCH" = stable ]]; then npm install kaitai-struct-compiler@latest && npm install kaitai-struct@latest && python vendor_build.py; fi' + - 'if [[ "$TRAVIS_BRANCH" = stable ]]; then npm install kaitai-struct-compiler@latest && npm install kaitai-struct@latest && node vendor_build.js; fi' script: - '[ "$TRAVIS_BRANCH" = stable ] && export GA_ID=UA-76299550-2 || export GA_ID=UA-76299550-3' diff --git a/README.md b/README.md index 53774cfc..993d03eb 100644 --- a/README.md +++ b/README.md @@ -21,14 +21,14 @@ Online editor / visualizer for Kaitai Struct .ksy files - Clone stable release: `git clone https://github.com/kaitai-io/ide-kaitai-io.github.io` or - Devel release: `git clone https://github.com/kaitai-io/ide-devel-kaitai-io.github.io` -- Serve on a webserver (ex. `python -mSimpleHTTPServer` or `python serve.py`) +- Serve on a webserver (ex. `python -mSimpleHTTPServer` or `node serve.js`) - Go to [http://127.0.0.1:8000/](http://127.0.0.1:8000/) ## compile and run locally - `git clone --recursive https://github.com/kaitai-io/kaitai_struct_webide` - `npm install` -- `python serve.py --compile` +- `node serve.js --compile` - Go to [http://127.0.0.1:8000/](http://127.0.0.1:8000/) ## screenshots diff --git a/build b/build index e401136f..d7f5d63d 100755 --- a/build +++ b/build @@ -5,7 +5,7 @@ TSC=node_modules/.bin/tsc mkdir -p "$OUT_DIR/js" -./genKaitaiFsFiles.py "$OUT_DIR" +node ./genKaitaiFsFiles.js "$OUT_DIR" "$TSC" --outDir $OUT_DIR/js/ --noEmitOnError if [ -f "tsconfig.worker.json" ]; then @@ -29,4 +29,4 @@ cp -r src/ui/Components/*.html "$OUT_DIR/src/ui/Components" mkdir -p "$OUT_DIR/src/ui/Parts" cp -r src/ui/Parts/*.html "$OUT_DIR/src/ui/Parts" -./build.py "$OUT_DIR" \ No newline at end of file +node ./build.js "$OUT_DIR" diff --git a/build.js b/build.js new file mode 100644 index 00000000..f866a39f --- /dev/null +++ b/build.js @@ -0,0 +1,86 @@ +const { readFileSync, writeFileSync } = require("fs"); +const { exec } = require("child_process"); + +const { GA_ID, SENTRY_DSN, SENTRY_ENV } = process.env; + +const GA_TEMPLATE = GA_ID ? ` + + + +` : ""; + +const SENTRY_TEMPLATE = SENTRY_DSN && SENTRY_ENV ? ` + + +` : ""; + +const outDir = process.argv.length > 2 ? process.argv[2] : "out"; + +function fileAction(fn, action) { + writeFileSync(fn, action(readFileSync(fn, { encoding: "utf-8" }))); +} + +function appendAfter(str, afterStr, appendStr) { + const i = str.indexOf(afterStr) + afterStr.length; + return str.slice(0, i) + appendStr + str.slice(i); +} + +function fetchGitCommitInfo() { + return new Promise((resolve, reject) => + exec("git log -1 --format=%H,%ct", (err, stdout) => { + if (err) { + reject(err); + } else { + const [commitId, commitTs] = stdout.trim().split(","); + const commitDate = new Date(Number(commitTs)*1000); + resolve({ commitId, commitDate }); + } + }) + ); +} + +function formatCommitDate(d) { + return String(d.getUTCFullYear()).padStart(2, '0') + '-' + + String(d.getUTCMonth() + 1).padStart(2, '0') + '-' + + String(d.getUTCDate()).padStart(2, '0') + ' ' + + String(d.getUTCHours()).padStart(2, '0') + ':' + + String(d.getUTCMinutes()).padStart(2, '0') + ':' + + String(d.getUTCSeconds()).padStart(2, '0'); +} + +async function main() { + const { commitId, commitDate } = await fetchGitCommitInfo(); + const scriptAppend = + SENTRY_TEMPLATE.replace("{{SENTRY_RELEASE}}", commitId) + GA_TEMPLATE; + if (scriptAppend) { + fileAction(outDir + "/index.html", html => + appendAfter(html, "", scriptAppend) + ); + } + fileAction(outDir + "/js/v1/app.js", html => + html + .replace( + 'kaitaiIde.commitId = "";', + `kaitaiIde.commitId = "${commitId}";` + ) + .replace( + 'kaitaiIde.commitDate = "";', + `kaitaiIde.commitDate = "${formatCommitDate(commitDate)}";` + ) + ); +} + +main().catch(err => console.error(err)); diff --git a/build.py b/build.py deleted file mode 100755 index bd860451..00000000 --- a/build.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python2 -import os -import sys -import subprocess -import datetime - -GA_TEMPLATE = ''' - - - -''' - -SENTRY_TEMPLATE = ''' - - -''' - -outDir = sys.argv[1] if len(sys.argv) > 1 else 'out' - -def fileAction(fn, action): - with open(fn, 'rt') as f: content = f.read() - newContent = action(content) - with open(fn, 'wt') as f: f.write(newContent) - -def envVarFill(template, envVarNames, allReq = True): - result = template.rstrip() - - for name in envVarNames: - value = os.environ.get(name) - if allReq and not value: - return "" - result = result.replace("{{%s}}" % name, value) - - return result - -def appendAfter(str, afterStr, appendStr): - i = str.index(afterStr) + len(afterStr) - return str[0:i] + appendStr + str[i:] - -gitInfo = subprocess.check_output(['git log -1 --format=%H,%ct'], shell=True).strip().split(',') -commitId = gitInfo[0] -commitTs = int(gitInfo[1]) -commitDate = datetime.datetime.fromtimestamp(commitTs).strftime('%Y-%m-%d %H:%M:%S') - -scriptAppend = envVarFill(SENTRY_TEMPLATE, ['SENTRY_DSN', 'SENTRY_ENV']).replace("{{SENTRY_RELEASE}}", commitId) + envVarFill(GA_TEMPLATE, ['GA_ID']) -if scriptAppend: - fileAction(outDir + '/index.html', lambda html: appendAfter(html, '', scriptAppend)) - -fileAction(outDir + '/js/v1/app.js', lambda html: html - .replace('kaitaiIde.commitId = "";', 'kaitaiIde.commitId = "%s";' % (commitId)) - .replace('kaitaiIde.commitDate = "";', 'kaitaiIde.commitDate = "%s";' % (commitDate))) \ No newline at end of file diff --git a/genKaitaiFsFiles.js b/genKaitaiFsFiles.js new file mode 100644 index 00000000..e3ae4aec --- /dev/null +++ b/genKaitaiFsFiles.js @@ -0,0 +1,39 @@ +const { readdirSync, statSync, writeFileSync, mkdirSync } = require("fs"); +const { join } = require("path"); + +function recursiveFind(dir, pattern, results = []) { + const files = readdirSync(dir, "utf-8") + .map(fn => join(dir, fn)) + .map(fn => ({ stat: statSync(fn), fn })); + results.push.apply( + results, + files + .filter(s => s.stat.isFile()) + .map(s => s.fn) + .filter(fn => pattern.test(fn)) + ); + files + .filter(s => s.stat.isDirectory()) + .forEach(s => recursiveFind(s.fn, pattern, results)); + return results; +} + +function generate(outDir) { + const files = + recursiveFind("formats/", /\.ksy$/) + .concat(recursiveFind("samples/", /.+/)) + .map(path => path.replace(/\\/g,'/')); + files.sort(); + + const js = `var kaitaiFsFiles = ${JSON.stringify(files, null, 4)};`; + + mkdirSync(outDir + "js", { recursive: true }); + writeFileSync(outDir + "js/kaitaiFsFiles.js", js); +} + +function main() { + const outDir = process.argv.length > 2 ? process.argv[2] + "/" : ""; + generate(outDir); +} + +main(); diff --git a/genKaitaiFsFiles.py b/genKaitaiFsFiles.py deleted file mode 100755 index 0a348766..00000000 --- a/genKaitaiFsFiles.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python - -import os -import glob -import fnmatch -import sys - -def recursive_glob(treeroot, pattern): - results = [] - for base, dirs, files in os.walk(treeroot): - goodfiles = fnmatch.filter(files, pattern) - results.extend(os.path.join(base, f) for f in goodfiles) - return results - -def generate(outDir): - files = (recursive_glob('formats/', '*.ksy') + recursive_glob('samples/', '*')) - files.sort() - lines = [" '" + x.replace('\\','/') + "'," for x in files] - js = 'var kaitaiFsFiles = [\n' + '\n'.join(lines) + '\n];'; - - if not os.path.isdir(outDir + 'js'): - os.mkdir(outDir + 'js') - - with open(outDir + 'js/kaitaiFsFiles.js', 'wt') as f: - f.write(js) - -if __name__ == "__main__": - outDir = sys.argv[1] + '/' if len(sys.argv) > 1 else '' - generate(outDir) -#print js diff --git a/package-lock.json b/package-lock.json index ce897482..88b34178 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3,6 +3,16 @@ "requires": true, "lockfileVersion": 1, "dependencies": { + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, "ace-builds": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.2.8.tgz", @@ -38,6 +48,12 @@ "sprintf-js": "1.0.3" } }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + }, "ast-types": { "version": "0.8.15", "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.15.tgz", @@ -78,6 +94,24 @@ "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.25.tgz", "integrity": "sha1-HeRan1dUKsIBIcaC+NZCIgo06CM=" }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } + }, "bootstrap": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz", @@ -102,6 +136,12 @@ "concat-map": "0.0.1" } }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true + }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", @@ -132,6 +172,33 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, "core-js": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", @@ -147,6 +214,45 @@ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.0.0.tgz", "integrity": "sha1-J0Pjq7XD/CRi5SfcpEXgTp9N7hc=" }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "diff": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", + "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", + "dev": true + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, "es3ify": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/es3ify/-/es3ify-0.1.4.tgz", @@ -164,6 +270,12 @@ } } }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -186,6 +298,50 @@ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dev": true, + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, "falafel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/falafel/-/falafel-1.2.0.tgz", @@ -197,6 +353,21 @@ "object-keys": "1.0.11" } }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, "font-awesome": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", @@ -207,6 +378,18 @@ "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -249,6 +432,28 @@ "ansi-regex": "2.1.1" } }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, "immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", @@ -277,6 +482,12 @@ "through2": "0.6.5" } }, + "ipaddr.js": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", + "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==", + "dev": true + }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", @@ -337,6 +548,45 @@ "lie": "3.0.2" } }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "dev": true + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "dev": true, + "requires": { + "mime-db": "1.40.0" + } + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -345,11 +595,32 @@ "brace-expansion": "1.1.8" } }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "dev": true + }, "object-keys": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=" }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -363,6 +634,12 @@ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==" }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -374,11 +651,51 @@ "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", "dev": true }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + }, "private": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/private/-/private-0.1.7.tgz", "integrity": "sha1-aM5eih7woju1cMwoU3tTMqumPvE=" }, + "proxy-addr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", + "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", + "dev": true, + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.0" + } + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, "readable-stream": { "version": "1.0.34", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", @@ -437,12 +754,71 @@ "path-parse": "1.0.5" } }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, "semver": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", "dev": true }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, "smooth-scrollbar": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/smooth-scrollbar/-/smooth-scrollbar-7.4.1.tgz", @@ -464,6 +840,12 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", @@ -508,6 +890,12 @@ "xtend": "4.0.1" } }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true + }, "tslib": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.7.1.tgz", @@ -549,12 +937,28 @@ } } }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, "typescript": { "version": "2.9.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==", "dev": true }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, "unreachable-branch-transform": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/unreachable-branch-transform/-/unreachable-branch-transform-0.3.0.tgz", @@ -565,6 +969,18 @@ "through2": "0.6.5" } }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, "vue": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/vue/-/vue-2.4.4.tgz", diff --git a/package.json b/package.json index cda42980..8a7aec59 100644 --- a/package.json +++ b/package.json @@ -28,12 +28,13 @@ "yamljs": "^0.3.0" }, "devDependencies": { + "express": "^4.17.1", "tslint": "^5.7.0", "typescript": "^2.9.2" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "install": "pip install -r requirements.txt; python vendor_build.py" + "install": "node vendor_build.js" }, "repository": { "type": "git", diff --git a/practice/chall1/geninput.js b/practice/chall1/geninput.js new file mode 100644 index 00000000..0431d81d --- /dev/null +++ b/practice/chall1/geninput.js @@ -0,0 +1,12 @@ +const { writeFileSync } = require("fs"); +let i = 0; +const buf = Buffer.alloc(0x3a); +i = buf.writeUInt8(42, i); +i = buf.writeInt16LE(-1337, i); +i = buf.writeFloatLE(3.33, i); +// TODO: Switch to writeBigInt64BE, available in Node v12.0.0: +// i = buf.writeBigInt64BE(1n, i); +i = buf.writeInt32BE(0, i); +i = buf.writeInt32BE(1, i); +i = buf.write("★★★ Congratulations! ★★★\0EOFEOF", i, "utf-8"); +writeFileSync("input.bin", buf); diff --git a/practice/chall1/geninput.py b/practice/chall1/geninput.py deleted file mode 100644 index ddb303ca..00000000 --- a/practice/chall1/geninput.py +++ /dev/null @@ -1,4 +0,0 @@ -# coding=utf-8 -import struct - -open('input.bin', 'wb').write(struct.pack('Q', 1) + '★★★ Congratulations! ★★★\0EOFEOF') \ No newline at end of file diff --git a/serve.js b/serve.js new file mode 100644 index 00000000..3d7591c3 --- /dev/null +++ b/serve.js @@ -0,0 +1,91 @@ +const { readdirSync, statSync } = require("fs"); +const { join } = require("path"); +const express = require("express"); +const ts = require("typescript"); + +const port = 8000; +const watchPattern = /(\.html$)|(^js\/)|(^css\/)$/; +const ignorePattern = /node_modules/; +const tsFormatHost = { + getCanonicalFileName: path => path, + getCurrentDirectory: ts.sys.getCurrentDirectory, + getNewLine: () => ts.sys.newLine +}; + +const app = express(); + +function reportDiagnostic(diagnostic) { + console.error( + `Error ${diagnostic.code}:`, + ts.flattenDiagnosticMessageText( + diagnostic.messageText, + tsFormatHost.getNewLine() + ) + ); +} + +function reportWatchStatusChanged(diagnostic) { + console.info(ts.formatDiagnostic(diagnostic, tsFormatHost).trimRight()); +} + +function startWatcher() { + console.log("Starting typescript compiler..."); + const configPath = ts.findConfigFile( + "./", + ts.sys.fileExists, + "tsconfig.json" + ); + if (!configPath) { + throw new Error("Could not find a valid 'tsconfig.json'."); + } + const createProgram = ts.createEmitAndSemanticDiagnosticsBuilderProgram; + const host = ts.createWatchCompilerHost( + configPath, + {}, + ts.sys, + createProgram, + reportDiagnostic, + reportWatchStatusChanged + ); + return ts.createWatchProgram(host); +} + +function findLatestChange(dir = ".", latestChange = 0) { + const fns = readdirSync(dir, "utf-8"); + for (const fn of fns) { + const path = join(dir, fn); + const stats = statSync(path); + if (stats.isDirectory() && !ignorePattern.test(path)) { + latestChange = findLatestChange(path, latestChange); + } else if (stats.isFile() && watchPattern.test(path)) { + if (stats.mtimeMs > latestChange) { + latestChange = stats.mtimeMs; + } + } + } + return latestChange; +} + +app.get("/onchange", (req, res, next) => { + const initialChange = findLatestChange(); + const checkChange = () => { + if (findLatestChange() > initialChange) { + res.send({ changed: true }); + return; + } + setTimeout(checkChange, 500); + }; + checkChange(); +}); + +app.use(express.static(".")); + +function main() { + if (process.argv.includes("--compile")) { + startWatcher(); + } + + app.listen(port, () => console.log(`Listening on ${port}.`)); +} + +main(); diff --git a/serve.py b/serve.py deleted file mode 100755 index 85e77db9..00000000 --- a/serve.py +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/env python - -import SimpleHTTPServer -import json -import fnmatch -import os -import sys -import threading -import time -import subprocess -import re -from SocketServer import ThreadingMixIn -from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler - -PORT = 8000 -watchDirs = ['*.html', 'js/*', 'css/*', 'src/*.html'] -compileCmd = r'node node_modules/typescript/bin/tsc -w' - -def recursive_glob(treeroot, pattern): - if treeroot == '.': - walkResult = [('.', None, os.listdir('.'),)] - else: - walkResult = list(os.walk(treeroot)) - - results = [] - for base, dirs, files in walkResult: - goodfiles = fnmatch.filter(files, pattern) - results.extend(os.path.join(base, f) for f in goodfiles) - return results - -def getFiles(dirs): - return [fn for pattern in dirs for fn in recursive_glob(*(os.path.join('./', pattern).rsplit('/', 1)))] - -def getLastChange(dirs): - files = [{'fn': fn, 'modTime': os.path.getmtime(fn)} for fn in getFiles(dirs)] - files = sorted(files, key=lambda x: x['modTime'], reverse=True) - return files[0] if len(files) > 0 else None - -class MyHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): - def resp(self, statusCode, result): - self.send_response(statusCode) - self.end_headers() - self.wfile.write(json.dumps(result)) - - def close_request(self): - print "Close" - - def do_GET(self): - if self.path == '/onchange': - lastChange = getLastChange(watchDirs) - while True: - time.sleep(0.5) - currChange = getLastChange(watchDirs) - if currChange and lastChange and currChange['modTime'] <> lastChange['modTime'] and not 'config.js' in currChange['fn']: - self.resp(200, { 'changed': True }) - break - lastChange = currChange - else: - return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self) - - def do_POST(self): - if self.path == '/check': - try: - input = json.loads(self.rfile.read(int(self.headers.getheader('content-length')))) - challName = input['chall'] - if not re.match('^[a-zA-Z0-9_]+$', challName): - self.resp(400, {'status': 'error', 'error': 'badChallName'}); - return - - with open('user.ksy', 'wt') as f: f.write(input['yaml']) - checkRes = json.loads(subprocess.check_output('node checker.js user.ksy practice\%s\input.bin practice\%s\check.json' % (challName, challName))); - - self.resp(200, {'status': 'ok', 'check_res': checkRes}); - except Exception as e: - print e - self.resp(400, {'status': 'exception'}); - else: - return SimpleHTTPServer.SimpleHTTPRequestHandler.do_POST(self) - - extensions_map = { - '.manifest': 'text/cache-manifest', - '.html': 'text/html', - '.png': 'image/png', - '.jpg': 'image/jpg', - '.svg': 'image/svg+xml', - '.css': 'text/css', - '.js': 'application/javascript', - '.json': 'application/json', - '.xml': 'application/xml', - '': 'application/octet-stream', # Default - } - -if '--compile' in sys.argv: - print "Starting typescript compiler..." - compileProcess = subprocess.Popen(compileCmd, shell=True) - -sys.dont_write_bytecode = True -import genKaitaiFsFiles -genKaitaiFsFiles.generate('') - -print "Please use 127.0.0.1:%d on Windows (using localhost makes 1sec delay)" % PORT - -class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): - daemon_threads = True - """Handle requests in a separate thread.""" - -print "Press Ctrl+C to exit." - -try: - ThreadedHTTPServer(("", PORT), MyHandler).serve_forever() -except KeyboardInterrupt: - pass - -if compileProcess: - print "Waiting for compiler to stop..." - compileProcess.wait() diff --git a/vendor_build.js b/vendor_build.js new file mode 100644 index 00000000..2c3d515f --- /dev/null +++ b/vendor_build.js @@ -0,0 +1,59 @@ +const YAML = require("yamljs"); +const { copyFileSync, readdirSync, statSync, mkdirSync } = require("fs"); +const { join, basename, dirname } = require("path"); +const firstBy = require("thenby"); + +function isDirectory(file) { + return statSync(file).isDirectory(); +} + +function copyOverwrite(src, dst) { + if (isDirectory(src)) { + readdirSync(src).forEach(file => + copyOverwrite(join(src, file), join(dst, file)) + ); + } else { + let dstFile, dstDir; + if (dst.endsWith("/")) { + dstDir = dst; + dstFile = join(dst, basename(src)); + } else { + dstDir = dirname(dst); + dstFile = dst; + } + console.log(" copying", src, "to", dstFile); + mkdirSync(dstDir, { recursive: true }); + copyFileSync(src, dstFile); + } +} + +function main() { + const vendor = YAML.load("vendor.yaml"); + const sortedLibs = Object.entries(vendor["libs"]).sort( + firstBy(([, lib]) => lib["priority"]) + ); + for (const [libName, lib] of sortedLibs) { + if (!lib["npmDir"] || !lib["files"]) { + continue; + } + console.log("Processing:", libName); + const distDir = `./lib/_npm/${lib["distDir"] || lib["npmDir"]}/`; + for (let file of lib["files"]) { + const allFilesInDir = file.endsWith("/*"); + if (allFilesInDir) { + file = file.replace("/*", ""); + } + + srcPattern = `./node_modules/${lib["npmDir"]}/${file}`; + if (isDirectory(srcPattern) && !allFilesInDir) { + copyOverwrite(srcPattern, join(distDir, file)); + } else { + copyOverwrite(srcPattern, distDir); + } + } + } + + require("./vendor_license"); +} + +main(); diff --git a/vendor_build.py b/vendor_build.py deleted file mode 100755 index 8e0b05d8..00000000 --- a/vendor_build.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python2 - -import ruamel.yaml as yaml -import glob -import shutil -import os - -def mkdir_recursive(path): - sub_path = os.path.dirname(path) - if not os.path.exists(sub_path): - mkdir_recursive(sub_path) - if not os.path.exists(path): - os.mkdir(path) - -def recursive_overwrite(src, dest): - #print ' recursive_overwrite %s, %s' % (src, dest) - - isDir = os.path.isdir(src) - destDir = dest if isDir else os.path.dirname(dest) - - if not os.path.exists(destDir): - os.makedirs(destDir) - - if isDir: - for f in os.listdir(src): - #print ' f: %s' % f - recursive_overwrite(os.path.join(src, f), os.path.join(destDir, f)) - else: - print ' copying %s to %s' % (src, destDir) - shutil.copy(src, destDir) - -with open('vendor.yaml','rt') as f: vendor = yaml.safe_load(f.read()) - -sortedLibs = sorted(vendor['libs'].iteritems(), key=lambda (k,v): v.get('priority')) -for (libName, lib) in sortedLibs: - if 'npmDir' in lib and 'files' in lib: - print 'Processing: %s' % libName - distDir = './lib/_npm/%s/' % (lib['distDir'] if 'distDir' in lib else lib['npmDir']) - for file in lib['files']: - allFilesInDir = file.endswith('/*') - if allFilesInDir: - file = file.replace('/*', '') - - srcPattern = './node_modules/%s/%s' % (lib['npmDir'], file) - if os.path.isdir(srcPattern) and not allFilesInDir: - recursive_overwrite(srcPattern, distDir + file + '/') - else: - recursive_overwrite(srcPattern, distDir) - -#print 'Processing lib_src...' -#recursive_overwrite('lib_src', 'lib') - -import vendor_license diff --git a/vendor_license.js b/vendor_license.js new file mode 100644 index 00000000..42b1c96b --- /dev/null +++ b/vendor_license.js @@ -0,0 +1,68 @@ +const YAML = require("yamljs"); +const { readdirSync, readFileSync, writeFileSync, statSync } = require("fs"); +const { join, basename } = require("path"); +const firstBy = require("thenby"); + +function isLicenseFilename(name) { + const fn = basename(name); + return fn.startsWith("LICENSE") || fn.startsWith("license"); +} + +function findLicenses(dst) { + return readdirSync(dst) + .map(file => join(dst, file)) + .filter(isLicenseFilename); +} + +function main() { + const vendor = YAML.load("vendor.yaml"); + let licResult = ""; + let wikiResult = "# 3rd-party libraries\n\n"; + const sortedLibs = Object.entries(vendor["libs"]).sort( + firstBy(([libName]) => libName) + ); + for (const [libName, lib] of sortedLibs) { + console.log("Processing", libName); + const distDir = `lib/${lib["npmDir"] ? "_npm/" : ""}${lib["distDir"] || lib["npmDir"]}/`; + const licFns = findLicenses(distDir); + + if (licFns.length != 1) { + console.log(`License not found: ${distDir}:`, licFns); + continue; + } + + licResult += "=".repeat(80) + "\n"; + licResult += " ".repeat(((80 - libName.length) / 2) | 0) + libName + "\n"; + licResult += "\n"; + licResult += `License name: ${lib["licenseName"]}\n`; + licResult += ` License URL: ${lib["licenseUrl"]}\n`; + licResult += ` License applies to files under the folder ${distDir}\n`; + licResult += "\n"; + + wikiResult += `## ${libName}\n`; + + if (lib["website"]) { + licResult += `Website: ${lib["website"]}\n`; + wikiResult += `Website: ${lib["website"]}\n\n`; + } + + if (lib["source"]) { + licResult += `Source: ${lib["source"]}\n`; + wikiResult += `Source: ${lib["source"]}\n\n`; + } + + wikiResult += `License: ${lib["licenseName"]} (${lib["licenseUrl"]})\n\n`; + + licResult += "=".repeat(80) + "\n"; + licResult += + readFileSync(licFns[0], { encoding: "utf-8" }) + .trim() + .replace(/\r\n/g, "\n") + "\n"; + licResult += "=".repeat(80) + "\n\n"; + } + + writeFileSync("LICENSE-3RD-PARTY.txt", licResult.trim()); + writeFileSync("docs/wiki/3rd-party-libraries.md", wikiResult.trim()); +} + +main(); diff --git a/vendor_license.py b/vendor_license.py deleted file mode 100755 index 042c2700..00000000 --- a/vendor_license.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python - -import os -import glob -import ruamel.yaml as yaml - -with open('vendor.yaml') as f: libs = yaml.safe_load(f)['libs'] - -licResult = '' -wikiResult = '# 3rd-party libraries\n\n' -for libName in sorted(libs): - print "Processing %s" % libName - lib = libs[libName] - distDir = ('_npm/' if 'npmDir' in lib else '') + (lib['distDir'] if 'distDir' in lib else lib['npmDir']) - licFns = [] - for filePattern in ['LICENSE*', 'license*']: - licFns = licFns + glob.glob('./lib/%s/%s' % (distDir, filePattern)) - licFns = list(set(licFns)) - - if len(licFns) != 1: - print "License not found: %s: %r" % (distDir, licFns) - continue - - licResult += '='*80 + '\n' - licResult += ' '*((80 - len(libName)) / 2) + libName + '\n' - licResult += '\n' - licResult += 'License name: %s\n' % lib['licenseName'] - licResult += ' License URL: %s\n' % lib['licenseUrl'] - licResult += ' License applies to files under the folder lib/%s/\n' % distDir - licResult += '\n' - - wikiResult += '## %s\n' % libName - - if 'website' in lib: - licResult += 'Website: %s\n' % lib['website'] - wikiResult += 'Website: %s\n\n' % lib['website'] - - if 'source' in lib: - licResult += 'Source: %s\n' % lib['source'] - wikiResult += 'Source: %s\n\n' % lib['source'] - - wikiResult += 'License: %s (%s)\n\n' % (lib['licenseName'], lib['licenseUrl']) - - licResult += '='*80 + '\n' - with open(licFns[0],'rb') as f: licResult += f.read().strip().replace('\r\n', '\n') + '\n' - licResult += '='*80 + '\n\n' - -open('LICENSE-3RD-PARTY.txt', 'wb').write(licResult.strip()) -open('docs/wiki/3rd-party-libraries.md', 'wb').write(wikiResult.strip())