const gulp = require('gulp'); const path = require('path'); const os = require('os'); const fs = require('fs'); const fse = require('fs-extra'); //const concat = require('gulp-concat'); //const uglify = require('gulp-uglify'); //const babel = require('gulp-babel'); //const template = require('gulp-template'); const Haxe = require('./haxe'); const FlashPlayer = require('./flashplayer'); const Debug = require('./debug'); const webserver = require('gulp-webserver'); const run = require('../run/index'); const tail = require('./tail'); const deb = require('gulp-debian'); const {BuildSystem, Platform, Config} = require('./core'); const vfs = require('vinyl-fs'); const rename = require('gulp-rename'); const template = require('lodash.template'); const mkdirp = require('mkdirp'); const streamToPromise = (stream) => { return new Promise((resolve, reject) => { stream.on("end", resolve); stream.on("error", reject); }); }; /** * */ class Target { constructor() { this.target = 'target'; } targetPath(name, platform) { return path.resolve(this.target, name, platform); } } /** * */ class Builder extends Target { constructor(buildSystem) { super(); this.buildSystem = buildSystem; } prepare() { return Promise.resolve(); } call(debug) { throw 'Not Implemented'; } static register(buildSystem, builder) { Builder.factory[buildSystem] = builder; } static new(buildSystem) { return new Builder.factory[buildSystem](buildSystem); } } Builder.factory = {}; /** * */ class HaxeBuilder extends Builder { constructor(buildSystem) { super(buildSystem); this.haxe = new Haxe(); } prepare() { return this.haxe.prepare(); } call(platform, config, debug) { const target = this.targetPath(config.name, platform); switch (this.buildSystem) { case BuildSystem.OPENFL: return this.haxe.openfl('build', platform, config, debug) .then(result => streamToPromise(result.pipe(vfs.dest(target)))); case BuildSystem.HAXE: return this.haxe.build(platform, config, debug) .then(result => streamToPromise(result.pipe(vfs.dest(target)))); } } } Builder.register(BuildSystem.HAXE, HaxeBuilder); Builder.register(BuildSystem.OPENFL, HaxeBuilder); /** * */ class Packer extends Target { constructor(platform) { super(); this.platform = platform; } prepare() { return Promise.resolve(); } call(config) { throw 'Not Implemented'; } static register(platform, packer) { Packer.factory[platform] = packer; } static new(platform) { return new Packer.factory[platform](); } } Packer.factory = {}; /** * */ class FlashPacker extends Packer { constructor() { super(Platform.FLASH); } call(config) { const target = this.targetPath(config.name, this.platform); const indexTemplate = template(fs.readFileSync(path.resolve(__dirname, '..', 'template/flash/index.html'))); const index = indexTemplate(config); fs.writeFileSync(path.resolve(target, 'index.html'), index); fs.copyFileSync(path.resolve(__dirname, '..', 'template/flash/swf.js'), path.resolve(target, 'swf.js')); return Promise.resolve(); } } Packer.register(Platform.FLASH, FlashPacker); /** * */ class LinuxPacker extends Packer { constructor() { super(Platform.LINUX); } call(config) { const target = this.targetPath(config.name, this.platform); const buildDir = path.join(os.tmpdir(), 'build', config.name, 'debian'); const desktopTemplate = template(fs.readFileSync(path.resolve(__dirname, '..', 'template/linux/app.desktop'))); const desktop = desktopTemplate(config); mkdirp.sync(`${buildDir}/usr/share/applications`); fs.writeFileSync(`${buildDir}/usr/share/applications/${config.meta.filename}.desktop`, desktop); fse.copySync(`${target}`, `${buildDir}/usr/share/${config.meta.filename}/`); return gulp.src(`${buildDir}/*`) .pipe(deb({ package: config.meta.filename, version: config.meta.version, section: 'base', priority: 'optional', architecture: 'all', maintainer: config.meta.author, description: config.meta.title, changelog: [], postinst: [ 'if [ "$1" = "configure" ] && [ -x "`which update-menus 2>/dev/null`" ] ; then\n' + ' update-menus\n' + 'fi' ], _target: '/', _out: path.join(target, '..', 'debian'), _clean: true, _verbose: false })); } } Packer.register(Platform.LINUX, LinuxPacker); /** * */ class Runner extends Target { constructor(platform, name) { super(); this.platform = platform; this.name = name; } prepare() { return Promise.resolve(); } call(debug) { throw 'Not Implemented'; } targetPath() { return super.targetPath(this.name, this.platform); } log(stream) { stream .pipe(tail(new Debug().log)) .pipe(rename('out.log')) .pipe(gulp.dest(this.targetPath())); } static register(platform, builder) { Runner.factory[platform] = builder; } static new(platform, name) { return new Runner.factory[platform](platform, name); } } Runner.factory = {}; /** * */ class FlashRunner extends Runner { constructor(platform, name) { super(platform, name); this.player = new FlashPlayer(); } prepare() { return this.player.prepare(); } call(debug) { const target = this.targetPath(); const filename = path.resolve(target, this.name+'.swf'); const player = this.player.flashPlayerBin(debug); FlashPlayer.trust(filename); fs.writeFileSync(FlashPlayer.log, ''); const result = gulp.src(filename).pipe(run(player + " <%=file.basename%>", {cwd: target})); return this.log(gulp.src(FlashPlayer.log)); } } Runner.register(Platform.FLASH, FlashRunner); /** * */ class Html5Runner extends Runner { call(debug) { return gulp.src(this.targetPath()) .pipe(webserver({ host: 'localhost', port: 3000, open: true, fallback: 'index.html' })); } } Runner.register(Platform.HTML5, Html5Runner); /** * */ class LinuxRunner extends Runner { call(debug) { const target = this.targetPath(); const filename = path.resolve(target, this.name); const result = gulp.src(filename).pipe(run("./<%=file.basename%>", {cwd: target})); return this.log(result); } } Runner.register(Platform.LINUX, LinuxRunner); /** * */ class NekoRunner extends Runner { call(debug) { const target = this.targetPath(); const filename = path.resolve(target, this.name+'.n'); const result = gulp.src(filename).pipe(run("neko <%=file.path%>", {cwd: target})); return this.log(result); } } Runner.register(Platform.NEKO, NekoRunner); /** * */ class Project { constructor(buildSystem, platforms, config) { this.buildSystem = buildSystem; this.platforms = platforms; this.config = config; } build(platform) { const builder = Builder.new(this.buildSystem); const config = this.config; return [ function prepare() { return builder.prepare() }, function build() { return builder.call(platform, config) }, ]; } run(platform) { const builder = Builder.new(this.buildSystem); const runner = Runner.new(platform, this.config.name); const config = this.config; const debug = new Debug(); return [ function prepare() { return builder.prepare() }, function build() { return builder.call(platform, config, debug) }, function prepare() { return runner.prepare() }, function run() { return runner.call(debug) }, ]; } pack(platform) { const config = this.config; const packer = Packer.new(platform); return [ function prepare() { return packer.prepare() }, function pack() { return packer.call(config) }, ]; } bind(module, external_gulp /* ToDo: spike */) { const _gulp = (external_gulp || gulp); for (const platform of this.platforms) { module.exports[`${this.config.name}:${platform}:build`] = _gulp.series(this.build(platform)); module.exports[`${this.config.name}:${platform}:run`] = _gulp.series(this.run(platform)); if (Packer.factory[platform]) { module.exports[`${this.config.name}:${platform}:pack`] = _gulp.series(this.pack(platform, _gulp)); } } return this; } } Project.BuildSystem = BuildSystem; Project.Platform = Platform; Project.Config = Config; Project.Builder = Builder; Project.Runner = Runner; module.exports = Project;