1
0
Fork 0

Fixed issues in runjs

This commit is contained in:
Michaël Lemaire 2018-04-04 23:57:28 +02:00
parent 5f0732b39b
commit 4838c74236
6 changed files with 145 additions and 114 deletions

View file

@ -103,8 +103,6 @@ Common UI
Technical Technical
--------- ---------
* Fix "npm test" returning 0 even on failure
* Fix "npm start" stopping when there is an error in initial build
* Pack sounds * Pack sounds
* Add toggles for shaders, automatically disable them if too slow, and initially disable them on mobile * Add toggles for shaders, automatically disable them if too slow, and initially disable them on mobile

View file

@ -10,5 +10,5 @@ fi
vdir="./.venv" vdir="./.venv"
test -x "${vdir}/bin/nodeenv" || ( virtualenv -p python3 "${vdir}" && "${vdir}/bin/pip" install --upgrade nodeenv ) test -x "${vdir}/bin/nodeenv" || ( virtualenv -p python3 "${vdir}" && "${vdir}/bin/pip" install --upgrade nodeenv )
test -e "${vdir}/node/bin/activate" || "${vdir}/bin/nodeenv" --node=9.3.0 --force "${vdir}/node" test -e "${vdir}/node/bin/activate" || "${vdir}/bin/nodeenv" --node=9.11.1 --force "${vdir}/node"
source "${vdir}/node/bin/activate" source "${vdir}/node/bin/activate"

View file

@ -5,7 +5,7 @@
"main": "out/build.js", "main": "out/build.js",
"scripts": { "scripts": {
"build": "run build", "build": "run build",
"test": "run test", "test": "run ci",
"start": "run continuous", "start": "run continuous",
"codecov": "remap-istanbul -i out/coverage/coverage.json -o out/coverage/mapped.json -t json && codecov -f out/coverage/mapped.json", "codecov": "remap-istanbul -i out/coverage/coverage.json -o out/coverage/mapped.json -t json && codecov -f out/coverage/mapped.json",
"deploy": "run deploy" "deploy": "run deploy"
@ -41,4 +41,4 @@
"parse": "^1.11.0", "parse": "^1.11.0",
"phaser": "2.6.2" "phaser": "2.6.2"
} }
} }

View file

@ -14,6 +14,8 @@ String.prototype.rsplit = function (sep, maxsplit) {
return maxsplit ? [split.slice(0, -maxsplit).join(sep)].concat(split.slice(-maxsplit)) : split; return maxsplit ? [split.slice(0, -maxsplit).join(sep)].concat(split.slice(-maxsplit)) : split;
} }
let forever = () => new Promise(() => null);
/** /**
* Promise-compatible version of glob * Promise-compatible version of glob
*/ */
@ -26,141 +28,139 @@ function list(pattern) {
/** /**
* Asynchronous execution of shell commands * Asynchronous execution of shell commands
*/ */
function exec(command) { async function exec(command) {
return run(command, { async: true }); await run(command, { async: true });
} }
/** /**
* Build app from typescript sources * Build app from typescript sources
*/ */
function ts(dist = false) { async function ts(dist = false) {
console.log("Building app..."); console.log("Building app...");
return exec(`tsc -p ${dist ? "./tsconfig.dist.json" : "."}`); await exec(`tsc -p ${dist ? "./tsconfig.dist.json" : "."}`);
} }
/** /**
* Start watching for typescript changes * Start watching for typescript changes
*/ */
function watch_ts() { async function watch_ts() {
watch(["./src/**/*.ts", "package.json"], () => ts()); watch(["./src/**/*.ts", "package.json"], () => ts());
await forever();
} }
/** /**
* Build an atlas of images for a given stage * Build an atlas of images for a given stage
*/ */
function atlas(stage) { async function atlas(stage) {
shell.rm('-f', `out/assets/atlas${stage}-*`); shell.rm('-f', `out/assets/atlas${stage}-*`);
return list(`data/stage${stage}/image/**/*.{png,jpg}`).then(files => {
let opts = { let files = await list(`data/stage${stage}/image/**/*.{png,jpg}`);
name: `out/assets/atlas${stage}`,
fullpath: true, let opts = {
width: 2048, name: `out/assets/atlas${stage}`,
height: 2048, fullpath: true,
square: true, width: 2048,
powerOfTwo: true, height: 2048,
padding: 2 square: true,
}; powerOfTwo: true,
return new Promise(resolve => gfPacker(files, opts, resolve)); padding: 2
}).then(() => { };
return list(`out/assets/atlas${stage}-*.json`); await new Promise(resolve => gfPacker(files, opts, resolve));
}).then(outfiles => { let outfiles = await list(`out/assets/atlas${stage}-*.json`);
return Promise.resolve(outfiles.map(file => path.basename(file).replace('.json', ''))) return outfiles.map(file => path.basename(file).replace('.json', ''));
});
} }
/** /**
* Build a single data pack * Build a single data pack
*/ */
function pack(stage) { async function pack(stage) {
console.log(`Building pack ${stage}...`); console.log(`Building pack ${stage}...`);
let getKey = x => x.replace(/\//g, "-").replace(/\.[a-z0-9]+$/, ''); let getKey = x => x.replace(/\//g, "-").replace(/\.[a-z0-9]+$/, '');
return atlas(stage).then(files => { let files = await atlas(stage)
return Promise.resolve(files.map(file => { let items = files.map(file => {
let fname = path.basename(file); let fname = path.basename(file);
return { return {
type: "atlasJSONHash", type: "atlasJSONHash",
key: fname, key: fname,
atlasURL: `assets/${fname}.json?t=${Date.now()}`, atlasURL: `assets/${fname}.json?t=${Date.now()}`,
textureURL: `assets/${fname}.png`, textureURL: `assets/${fname}.png`,
atlasData: null atlasData: null
} }
}));
}).then(items => {
return list(`data/stage${stage}/sound/**/*.{mp3,wav}`).then(files => {
return Promise.resolve(items.concat(files.map(file => {
const [name, ext] = file.rsplit('.');
const key = getKey(name.replace(`data/stage${stage}/sound/`, ''));
shell.cp(file, `out/assets/${key}.${ext}`);
return {
type: "audio",
key: key,
urls: [`assets/${key}.${ext}?t=${Date.now()}`],
autoDecode: (ext == 'mp3')
};
})));
});
}).then(items => {
return list(`data/stage${stage}/shader/**/*.glsl`).then(files => {
return Promise.resolve(items.concat(files.map(file => {
const [name, ext] = file.rsplit('.');
const key = getKey(name.replace(`data/stage${stage}/shader/`, ''));
shell.cp(file, `out/assets/${key}.${ext}`);
return {
type: "shader",
key: key,
url: `assets/${key}.${ext}?t=${Date.now()}`
};
})));
});
}).then(items => {
let packdata = {};
packdata[`stage${stage}`] = items;
return new Promise(resolve => fs.writeFile(`out/assets/pack${stage}.json`, JSON.stringify(packdata), 'utf8', resolve));
}); });
files = await list(`data/stage${stage}/sound/**/*.{mp3,wav}`);
items = items.concat(files.map(file => {
const [name, ext] = file.rsplit('.');
const key = getKey(name.replace(`data/stage${stage}/sound/`, ''));
shell.cp(file, `out/assets/${key}.${ext}`);
return {
type: "audio",
key: key,
urls: [`assets/${key}.${ext}?t=${Date.now()}`],
autoDecode: (ext == 'mp3')
};
}));
files = await list(`data/stage${stage}/shader/**/*.glsl`);
items = items.concat(files.map(file => {
const [name, ext] = file.rsplit('.');
const key = getKey(name.replace(`data/stage${stage}/shader/`, ''));
shell.cp(file, `out/assets/${key}.${ext}`);
return {
type: "shader",
key: key,
url: `assets/${key}.${ext}?t=${Date.now()}`
};
}));
let packdata = {};
packdata[`stage${stage}`] = items;
await new Promise(resolve => fs.writeFile(`out/assets/pack${stage}.json`, JSON.stringify(packdata), 'utf8', resolve));
} }
/** /**
* Build data packs * Build data packs
*/ */
function data() { async function data() {
shell.mkdir("-p", "out/assets"); shell.mkdir("-p", "out/assets");
return Promise.all([1, 2, 3].map(stage => pack(stage))); await Promise.all([1, 2, 3].map(stage => pack(stage)));
} }
/** /**
* Start watch for data changes * Start watch for data changes
*/ */
function watch_data() { async function watch_data() {
watch(["./data/**/*.*"], () => data()); watch(["./data/**/*.*"], () => data());
await forever();
} }
/** /**
* Copy the vendors from node_modules to dist directory * Copy the vendors from node_modules to dist directory
*/ */
function vendors() { async function vendors() {
console.log("Copying vendors..."); console.log("Copying vendors...");
shell.rm('-rf', 'out/vendor'); shell.rm('-rf', 'out/vendor');
shell.mkdir('-p', 'out/vendor'); shell.mkdir('-p', 'out/vendor');
shell.cp('-R', 'node_modules/phaser/build', 'out/vendor/phaser'); shell.cp('-R', 'node_modules/phaser/build', 'out/vendor/phaser');
shell.cp('-R', 'node_modules/parse/dist', 'out/vendor/parse'); shell.cp('-R', 'node_modules/parse/dist', 'out/vendor/parse');
shell.cp('-R', 'node_modules/jasmine-core/lib/jasmine-core', 'out/vendor/jasmine'); shell.cp('-R', 'node_modules/jasmine-core/lib/jasmine-core', 'out/vendor/jasmine');
return Promise.resolve();
} }
/** /**
* Start watching for vendors changes * Start watching for vendors changes
*/ */
function watch_vendors() { async function watch_vendors() {
watch(['package.json'], () => vendors()); watch(['package.json'], () => vendors());
await forever();
} }
/** /**
* Trigger a single build * Trigger a single build
*/ */
function build(dist = false) { async function build(dist = false) {
return Promise.all([ await Promise.all([
ts(dist), ts(dist),
data(), data(),
vendors() vendors()
@ -170,35 +170,47 @@ function build(dist = false) {
/** /**
* Optimize the build for production * Optimize the build for production
*/ */
function optimize() { async function optimize() {
// TODO do not overwrite dev build // TODO do not overwrite dev build
return exec("uglifyjs out/build.dist.js --source-map --output out/build.js"); await exec("uglifyjs out/build.dist.js --source-map --output out/build.js");
} }
/** /**
* Deploy to production * Deploy to production
*/ */
function deploy(task) { async function deploy(task) {
return build(true).then(optimize).then(() => { await build(true);
return exec("rsync -avz --delete ./out/ hosting.thunderk.net:/srv/website/spacetac/") await optimize();
}); await exec("rsync -avz --delete ./out/ hosting.thunderk.net:/srv/website/spacetac/");
} }
/** /**
* Run tests in karma, using freshly built app * Run tests in karma
*/ */
function test(task) { async function karma() {
return Promise.all([ts(), vendors()]).then(() => { await exec("karma start spec/support/karma.conf.js");
return exec("karma start spec/support/karma.conf.js"); }
}).then(() => {
return exec("remap-istanbul -i out/coverage/coverage.json -o out/coverage -t html"); /**
}); * Run tests in karma (suppose is already built)
*/
async function test(task) {
await karma();
}
/**
* Run tests in karma, using freshly built app (for continuous integration)
*/
async function ci(task) {
await Promise.all([ts(), vendors()]);
await karma();
await exec("remap-istanbul -i out/coverage/coverage.json -o out/coverage -t html");
} }
/** /**
* Serve the app for dev purpose * Serve the app for dev purpose
*/ */
function serve() { async function serve() {
liveServer.start({ liveServer.start({
host: '127.0.0.1', host: '127.0.0.1',
port: 8012, port: 8012,
@ -206,31 +218,52 @@ function serve() {
ignore: 'coverage', ignore: 'coverage',
wait: 500 wait: 500
}); });
return new Promise(() => null); await new Promise(() => null);
} }
/** /**
* Continuous development server * Continuous development server
*/ */
function continuous() { async function continuous() {
return build().then(() => Promise.all([ try {
await build();
} catch (err) {
console.error(err);
}
await Promise.all([
serve(), serve(),
watch_ts(), watch_ts(),
watch_data(), watch_data(),
watch_vendors() watch_vendors()
])); ]);
}
/**
* Wrapper around an async execution function, to make it a runjs command
*/
function command(func) {
return async function () {
try {
await func();
} catch (err) {
console.error(err);
process.exit(1);
}
}
} }
module.exports = { module.exports = {
ts, ts: command(ts),
watch_ts, watch_ts: command(watch_ts),
data, data: command(data),
watch_data, watch_data: command(watch_data),
vendors, vendors: command(vendors),
watch_vendors, watch_vendors: command(watch_vendors),
build, build: command(build),
test, test: command(test),
deploy, deploy: command(deploy),
serve, serve: command(serve),
continuous continuous: command(continuous),
ci: command(ci)
} }

View file

@ -24,25 +24,25 @@ module TK.SpaceTac.Specs {
intruder_count: 0, intruder_count: 0,
intruder_effects: [new ValueEffect("hull", -1)] intruder_effects: [new ValueEffect("hull", -1)]
}); });
check.equals(action.getEffectsDescription(), "Watch a 120km area (power usage 2):\n• hull -1 for all incoming ships"); check.equals(action.getEffectsDescription(), "Watch a 120km area (power usage 2):\n• hull -1 on all incoming ships");
action = new VigilanceAction("Reactive Fire", { power: 2, radius: 120 }, { action = new VigilanceAction("Reactive Fire", { power: 2, radius: 120 }, {
intruder_count: 1, intruder_count: 1,
intruder_effects: [new ValueEffect("hull", -1)] intruder_effects: [new ValueEffect("hull", -1)]
}); });
check.equals(action.getEffectsDescription(), "Watch a 120km area (power usage 2):\n• hull -1 for the first incoming ship"); check.equals(action.getEffectsDescription(), "Watch a 120km area (power usage 2):\n• hull -1 on the first incoming ship");
action = new VigilanceAction("Reactive Fire", { power: 2, radius: 120 }, { action = new VigilanceAction("Reactive Fire", { power: 2, radius: 120 }, {
intruder_count: 3, intruder_count: 3,
intruder_effects: [new ValueEffect("hull", -1)] intruder_effects: [new ValueEffect("hull", -1)]
}); });
check.equals(action.getEffectsDescription(), "Watch a 120km area (power usage 2):\n• hull -1 for the first 3 incoming ships"); check.equals(action.getEffectsDescription(), "Watch a 120km area (power usage 2):\n• hull -1 on the first 3 incoming ships");
action = new VigilanceAction("Reactive Fire", { power: 2, radius: 120, filter: ActionTargettingFilter.ALLIES }, { action = new VigilanceAction("Reactive Fire", { power: 2, radius: 120, filter: ActionTargettingFilter.ALLIES }, {
intruder_count: 3, intruder_count: 3,
intruder_effects: [new ValueEffect("hull", -1)] intruder_effects: [new ValueEffect("hull", -1)]
}); });
check.equals(action.getEffectsDescription(), "Watch a 120km area (power usage 2):\n• hull -1 for the first 3 incoming team members"); check.equals(action.getEffectsDescription(), "Watch a 120km area (power usage 2):\n• hull -1 on the first 3 incoming team members");
}); });
test.case("handles the vigilance effect to know who to target", check => { test.case("handles the vigilance effect to know who to target", check => {

View file

@ -49,11 +49,11 @@ module TK.SpaceTac {
let suffix: string; let suffix: string;
if (this.intruder_count == 0) { if (this.intruder_count == 0) {
suffix = `for all incoming ${BaseAction.getFilterDesc(this.filter)}`; suffix = `on all incoming ${BaseAction.getFilterDesc(this.filter)}`;
} else if (this.intruder_count == 1) { } else if (this.intruder_count == 1) {
suffix = `for the first incoming ${BaseAction.getFilterDesc(this.filter, false)}`; suffix = `on the first incoming ${BaseAction.getFilterDesc(this.filter, false)}`;
} else { } else {
suffix = `for the first ${this.intruder_count} incoming ${BaseAction.getFilterDesc(this.filter)}`; suffix = `on the first ${this.intruder_count} incoming ${BaseAction.getFilterDesc(this.filter)}`;
} }
let effects = this.intruder_effects.map(effect => { let effects = this.intruder_effects.map(effect => {