From f5cfd50537397f98896e0ce0fe0c62f8ef121106 Mon Sep 17 00:00:00 2001 From: shmyga Date: Tue, 3 Apr 2018 15:13:25 +0300 Subject: [PATCH] added tasks --- .gitignore | 3 + haxetool/adobe_air.js | 255 ++++++++++++++++++++++++++++++++ haxetool/exec.js | 30 ++++ haxetool/flashplayer.js | 171 ++++++++++++++++++++++ haxetool/haxe.js | 312 ++++++++++++++++++++++++++++++++++++++++ haxetool/neko.js | 35 +++++ haxetool/sdk.js | 113 +++++++++++++++ index.js | 7 + package.json | 14 ++ 9 files changed, 940 insertions(+) create mode 100644 .gitignore create mode 100755 haxetool/adobe_air.js create mode 100755 haxetool/exec.js create mode 100755 haxetool/flashplayer.js create mode 100755 haxetool/haxe.js create mode 100644 haxetool/neko.js create mode 100755 haxetool/sdk.js create mode 100644 index.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c08ef50 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/.idea +/node_modules +package-lock.json \ No newline at end of file diff --git a/haxetool/adobe_air.js b/haxetool/adobe_air.js new file mode 100755 index 0000000..8212be3 --- /dev/null +++ b/haxetool/adobe_air.js @@ -0,0 +1,255 @@ +const fs = require('fs'); +const tmp = require('tmp-file'); +const exec = require('./exec'); +const gulp = require('gulp'); +const through = require('through2'); +//const mark = require('gulp-mark'); +//const replace = require('gulp-replace-task'); +const Sdk = require('./sdk'); + + +// ToDo: remove gutil +class AdobeAir extends Sdk { + + get adtBin() { + return `${this.path}/bin/adt.bat`; + } + + get adlBin() { + return `${this.path}/bin/adl.exe`; + } + + static buildAdtArgs(params, descriptor, keystore, files, output) { + //const quote = (value) => `"${value}"`; + const quote = (value) => value; // ToDo: + const command = ['-package']; + const target = params.target || 'native'; + if (target !== 'native') command.push('-target', target); //ToDo: adobe bleat' (target param position in native and apk-captive-runtime targets) + if (params.useLegacyAOT) { + command.push('-useLegacyAOT', 'yes'); + } + if (params.profile) { + command.push('-provisioning-profile', quote(params.profile)); + } + if (keystore) { + command.push('-storetype', 'PKCS12'); + command.push('-keystore', keystore.path); + command.push('-storepass', keystore.storepass); + } + if (params.target === 'native') { + command.push('-tsa', 'http://sha256timestamp.ws.symantec.com/sha256/timestamp'); + command.push('-target', target); + } + command.push(quote(output), quote(descriptor.path)); + if (params.extdir) { + command.push('-extdir', quote(params.extdir)); + } + if (params.content) { + for (let k in params.content) if (params.content.hasOwnProperty(k)) { + command.push('-C', quote(k), quote(params.content[k])); + } + } + for (let file of files) { + command.push('-C', quote(file.base), quote(file.path.split(file.base)[1])); + } + return command; + }; + + constructor(version) { + super(AdobeAir.ID, version || AdobeAir.VERSION); + } + + get prepared() { + return fs.existsSync(`${this.path}/air-sdk-description.xml`); + } + + get link() { + return `http://airdownload.adobe.com/air/win/download/${this.version}/AIRSDK_Compiler.zip`; + } + + adt(path, args) { + return exec(path, [this.adtBin].concat(args).join(' ')); + } + + adl(path, args) { + return exec(path, [this.adlBin].concat(args).join(' ')); + } + + pack(params) { + const files = []; + let descriptor = null; + let keystore = null; + let stream = null; + + const bufferContents = (file, enc, callback) => { + // ToDo: check file not stream + switch (file.mark) { + case 'descriptor': + descriptor = file; + break; + case 'keystore': + keystore = file; + break; + default: + files.push(file); + } + callback(); + }; + + const endStream = (callback) => { + gutil.log(this.tag, col.cyan('adt', 'build', params.target), '=>', col.magenta(params.outputFile)); + if (!descriptor) { + stream.emit('error', new gutil.PluginError({plugin: this.name, message: 'descriptor is not defined'})); + callback(); + return; + } + const tmpFile = tmp.generateFile(); + const command = AdobeAir.buildAdtArgs(params, descriptor, keystore, files, tmpFile.path); + this.adt('.', command) + .then(() => { + stream.push(new gutil.File({ + path: params.outputFile, + contents: fs.createReadStream(tmpFile.path) + })); + callback(); + }) + .catch((error) => { + stream.emit('error', new gutil.PluginError({plugin: this.name, message: error})); + callback(); + }); + }; + + return stream = through.obj(bufferContents, endStream); + } + + install() { + let stream = null; + const bufferContents = (file, enc, callback) => { + gutil.log(this.tag, col.cyan('adt', 'install'), col.magenta(file.name)); + const command = ['-installApp', '-platform', 'android', '-package', file.path]; + this.adt('.', command) + .then(() => { + stream.push(file); + callback(); + }) + .catch((error) => { + stream.emit('error', new gutil.PluginError({plugin: this.name, message: error})); + callback(); + }); + }; + return stream = through.obj(bufferContents); + } + + launch(appid) { + let stream = null; + const bufferContents = (file, enc, callback) => { + gutil.log(this.tag, col.cyan('adt', 'launch'), col.magenta(appid)); + const command = ['-launchApp', '-platform', 'android', '-appid', appid]; + this.adt('.', command) + .then(() => { + stream.push(file); + callback(); + }) + .catch((error) => { + stream.emit('error', new gutil.PluginError({plugin: this.name, message: error})); + callback(); + }); + }; + return stream = through.obj(bufferContents); + } + + test(params) { + let root = null; + let descriptor = null; + let stream = null; + + const bufferContents = (file, enc, callback) => { + // ToDo: check file not stream + switch (file.mark) { + case 'descriptor': + descriptor = file; + break; + default: + root = file; + } + callback(); + }; + + const endStream = (callback) => { + gutil.log(this.tag, col.cyan('adl')); + //const command = AdobeAir.buildAdtArgs(params, files, tmpFile.path); + const command = []; + if (params.profile) command.push('-profile', params.profile); + if (params.extdir) command.push('-extdir', params.extdir); + if (!descriptor) { + stream.emit('error', new gutil.PluginError({plugin: this.name, message: 'descriptor is not defined'})); + callback(); + return; + } + command.push(descriptor.path); + command.push(root.path); + if (params.args) { + command.push('--'); + for (let key of Object.keys(params.args)) { + const value = params.args[key]; + if (value === true) { + command.push(`-${key}`); + } else if (value) { + command.push(`-${key}`, `${value}`); + } + } + } + this.adl('.', command) + .then(() => { + stream.emit('end'); + callback(); + }) + .catch((error) => { + stream.emit('error', new gutil.PluginError({plugin: this.name, message: error})); + callback(); + }); + + //callback(); + stream.push(root); + }; + + return stream = through.obj(bufferContents, endStream); + } + + static descriptor(template, values) { + const tmpFile = tmp.generateFile(); + const patterns = []; + for (let k in values) if (values.hasOwnProperty(k)) { + patterns.push({match: k, replacement: values[k]}); + } + return gulp.src(template) + .pipe(replace({patterns: patterns})) + .pipe(mark.set('descriptor')) + .pipe(gulp.dest(tmpFile.path)); + } + + static keystore(keystore, storepass) { + return gulp.src(keystore).pipe(through.obj((file, enc, callback) => { + file.mark = 'keystore'; + file.storepass = storepass; + callback(null, file); + })); + } + + static pack(params) { + return new AdobeAir().pack(params); + } + + static test(params) { + return new AdobeAir().test(params); + } +} + +AdobeAir.ID = 'adobe-air'; + +AdobeAir.VERSION_26 = '26.0'; +AdobeAir.VERSION_25 = '25.0'; +AdobeAir.VERSION_24 = '24.0'; +AdobeAir.VERSION = AdobeAir.VERSION_26; + +module.exports = AdobeAir; \ No newline at end of file diff --git a/haxetool/exec.js b/haxetool/exec.js new file mode 100755 index 0000000..26ad50f --- /dev/null +++ b/haxetool/exec.js @@ -0,0 +1,30 @@ +const child_process = require('child_process'); +const async = require('async'); +const colors = require('ansi-colors'); +const log = require('fancy-log'); + +const TAG = colors.green('[exec]'); + +const queue = async.queue((task, done) => { + //log(TAG, colors.magenta(task.command)); + //process.chdir(task.dir); + child_process.exec(task.command, {cwd: task.dir, maxBuffer: 1024 * 5000}, (err, stdout, stderr) => { + if (err) { + task.failure(stderr || stdout || err); + } else { + task.success({stdout: stdout, stderr: stderr}); + } + done(); + }); +}); + +module.exports = (dir, command) => { + return new Promise((success, failure) => { + queue.push({ + dir: dir, + command: command, + success: success, + failure: failure, + }); + }); +}; \ No newline at end of file diff --git a/haxetool/flashplayer.js b/haxetool/flashplayer.js new file mode 100755 index 0000000..940e823 --- /dev/null +++ b/haxetool/flashplayer.js @@ -0,0 +1,171 @@ +const path = require('path'); +const fs = require('fs'); +const fse = require('fs-extra'); +const os = require('os'); +const through = require('through2'); +const gulp = require('gulp'); +const Sdk = require('./sdk'); +const exec = require('./exec'); +const PluginError = require('plugin-error'); +const colors = require('ansi-colors'); +const log = require('fancy-log'); + + +class FlashPlayer extends Sdk { + + constructor(version) { + super(FlashPlayer.ID, version || FlashPlayer.VERSION); + } + + playerPath(debug) { + const v = this.version.split('.'); + const dir = `${v[0]}_${v[1]}_r${v[2]}_${v[3]}`; + return `${this.path}/${dir}${debug ? '_debug': ''}`; + } + + prepare() { + let p = super.prepare(); + if (!this.prepared && os.type() === 'Linux') { + p = p.then(() => { + let arch = null; + if (os.arch() === 'ia32') { arch = 'i386'} + if (os.arch() === 'x64') { arch = 'x86_64'} + + const extract = (debug) => { + const v = this.version.split('.'); + const playerPath = this.playerPath(debug); + // ToDo: fix + const archive = `${playerPath}/flashplayer${v[0]}_${v[1]}r${v[2]}_${v[3]}_linux_sa${debug ? '_debug' : ''}.${arch}.tar.gz`; + return gulp.src(archive) + .pipe(gunzip()).pipe(untar()) + .pipe(gulp.dest(playerPath)); + }; + + return new Promise((success, fail) => { + extract().on('end', () => { + extract(true).on('end', success).on('error', fail) + }).on('error', fail); + }) + }) + } + return p; + } + + get prepared() { + try { + return fs.existsSync(`${this.flashPlayerBin()}`); + } catch (e) { + return false; + } + } + + get link() { + return `https://fpdownload.macromedia.com/pub/flashplayer/installers/archive/fp_${this.version}_archive.zip`; + } + + flashPlayerBin(debug) { + if (os.type() === 'Windows_NT') { + const v = this.version.split('.'); + const playerName = `flashplayer${v[0]}_${v[1]}r${v[2]}_${v[3]}_win_sa${debug ? '_debug' : ''}.exe`; + return `${this.playerPath(debug)}/${playerName}`; + } else if (os.type() === 'Linux') { + const binPath = `${this.playerPath(debug)}/${debug ? 'flashplayerdebugger': 'flashplayer'}`; + fs.chmodSync(binPath, 0o755); + return binPath; + } else { + throw `Unsupported os '${os.type()}'`; + } + } + + static get flashPlayerDir() { + if (os.type() === 'Windows_NT') { + return `${process.env.APPDATA}/Macromedia/Flash Player`; + } else if (os.type() === 'Linux') { + return `${os.homedir()}/.macromedia/Flash_Player`; + } + } + + static get log() { + return `${this.flashPlayerDir}/Logs/flashlog.txt`; + } + + static enableLog() { + const filename = `${os.homedir()}/mm.cfg`; + const value = 'TraceOutputFileEnable=1'; + if (fs.exists(filename)) { + const data = fs.readFileSync(filename); + if (data.indexOf(value) === -1) { + fs.appendFileSync(filename, `${value}\n`); + } + } else { + fs.writeFileSync(filename, `${value}\n`); + } + } + + static trust(value) { + const filename = `${this.flashPlayerDir}/#Security/FlashPlayerTrust/gulp.cfg`; + if (fs.exists(filename)) { + const data = fs.readFileSync(filename); + if (data.indexOf(value) === -1) { + fs.appendFileSync(filename, `${value}\n`); + } + } else { + if (!fs.exists(path.dirname(filename))) { + fse.ensureDirSync(path.dirname(filename)); + } + fs.writeFileSync(filename, `${value}\n`); + } + } + + run(debug) { + let stream = null; + const bufferContents = (file, enc, callback) => { + log(this.tag, colors.cyan("run"), colors.magenta(file.path)); + FlashPlayer.trust(file.path); + FlashPlayer.enableLog(); + exec('.', [this.flashPlayerBin(debug), file.path].join(' ')).then(() => { + stream.emit('end'); + callback(); + }).catch((error) => { + stream.emit('error', new PluginError({plugin: this.tag, message: error})); + callback(); + }); + //stream.push(file); + // ToDo: watch when file is exists + // or create log file in FlashPlayer.enableLog()? + /*stream.push(new Vinyl({ + path: FlashPlayer.log + }));*/ + stream.push(file); + }; + + return stream = through.obj(bufferContents); + } +} + +FlashPlayer.ID = "flashplayer"; + +FlashPlayer.VERSION_11_2_202_644 = '11.2.202.644'; +FlashPlayer.VERSION_11 = FlashPlayer.VERSION_11_2_202_644; + +FlashPlayer.VERSION_24_0_0_186 = '24.0.0.186'; +FlashPlayer.VERSION_24_0_0_194 = '24.0.0.194'; +FlashPlayer.VERSION_24_0_0_221 = '24.0.0.221'; +FlashPlayer.VERSION_24 = FlashPlayer.VERSION_24_0_0_221; + +FlashPlayer.VERSION_25_0_0_127 = '25.0.0.127'; +FlashPlayer.VERSION_25_0_0_148 = '25.0.0.148'; +FlashPlayer.VERSION_25_0_0_163 = '25.0.0.163'; +FlashPlayer.VERSION_25_0_0_117 = '25.0.0.171'; +FlashPlayer.VERSION_25 = FlashPlayer.VERSION_25_0_0_117; + +FlashPlayer.VERSION_26_0_0_131 = '26.0.0.131'; +FlashPlayer.VERSION_26 = FlashPlayer.VERSION_26_0_0_131; + +if (os.type() === 'Linux' && os.arch() === 'ia32') { //Linux i386 + FlashPlayer.VERSION = FlashPlayer.VERSION_11; +} else { + FlashPlayer.VERSION = FlashPlayer.VERSION_26; +} + +module.exports = FlashPlayer; \ No newline at end of file diff --git a/haxetool/haxe.js b/haxetool/haxe.js new file mode 100755 index 0000000..36de769 --- /dev/null +++ b/haxetool/haxe.js @@ -0,0 +1,312 @@ +const os = require('os'); +const fs = require('fs'); +const path = require('path'); +const tmp = require('tmp-file'); +const exec = require('./exec'); +const through = require('through2'); +const Sdk = require('./sdk'); +const dateformat = require('dateformat'); +const Vinyl = require('vinyl'); +const PluginError = require('plugin-error'); +const colors = require('ansi-colors'); +const log = require('fancy-log'); +const vfs = require('vinyl-fs'); +const rmdir = require('rmdir'); + + +class Haxe extends Sdk { + + getBin(name) { + if (Sdk.System.isWindows) { + return `${this.binPath}/${name}.exe`; + } else if (Sdk.System.isLinux) { + const binPath = `${this.binPath}/${name}`; + fs.chmodSync(binPath, 0o755); + return binPath; + } + return `` + } + + get binPath() { + return `${this.path}`; + } + + get haxeBin() { + return this.getBin('haxe'); + } + + get haxelibBin() { + return this.getBin('haxelib'); + } + + constructor(version) { + super(Haxe.ID, version || Haxe.VERSION); + } + + get prepared() { + try { + return fs.existsSync(this.haxeBin); + } catch (e) { + return false; + } + } + + activate() { + process.env.HAXE_VERSION = this.version; + process.env.HAXE_STD_PATH = `${this.binPath}/std`; + process.env.HAXE_HOME = this.binPath; + process.env.PATH = `${process.env.PATH}:${this.binPath}`; + } + + prepare() { + return super.prepare().then(() => this.activate()); + } + + get link() { + if (Sdk.System.isWindows) { + return `https://github.com/HaxeFoundation/haxe/releases/download/${this.version}/haxe-${this.version}-win.zip`; + } else if (Sdk.System.isLinux) { + let arch = Sdk.System.archInt; + return `https://github.com/HaxeFoundation/haxe/releases/download/${this.version}/haxe-${this.version}-linux${arch}.tar.gz`; + } + } + + haxe(args) { + return exec('.', [this.haxeBin].concat(args).join(' ')); + } + + haxelib(args) { + const haxelibBin = this.haxelibBin; + //return exec(this.binPath, [path.basename(haxelibBin)].concat(args).join(' ')); + return exec('.', [haxelibBin].concat(args).join(' ')); + } + + install(packages) { + let promise = this.haxelib(['setup', `${this.path}/lib`]); + const next = (args) => () => { + log(this.tag, colors.cyan('haxelib', 'install'), colors.magenta(args[1])); + return this.haxelib(args); + }; + + if (!Array.isArray(packages)) { + packages = Object.entries(packages).map(([k, v]) => ({name: k, version: v})); + } + + for (let pack of packages) { + const args = []; + let version = null; + if (typeof pack === 'string') { + args.push('install', pack); + } else if (typeof pack === 'object') { + version = pack.version; + if (version.substr(0, 3) === 'git') { + pack.git = version; + version = null; + } + if (pack.git) { + args.push('git', pack.name, pack.git); + if (pack.branch) args.push(pack.branch); + } else { + args.push('install', pack.name); + if (version) args.push(version); + } + args.push('--always'); + } + let path = `${this.path}/lib/${args[1]}`; + if (version) { + path += `/${version.replace(/\./g, ',')}`; + } else if (pack.git) { + path += '/git'; + } + if (!fs.existsSync(path)) { + promise = promise.then(next(args)); + } + } + return promise; + } + + upgrade() { + let promise = this.haxelib(['setup', `${this.path}/lib`]); + promise = promise.then(() => this.haxelib(['upgrade', '--always'])); + return promise; + } + + /** + * + * @param params + * @returns {*} + * + * { + * command: 'build', + * platform: 'flash', + * version: '1.0.0', + * build: '1999.12.12 00:00', + * values: {}, + * outputFile: 'out.swf', + * } + */ + openfl(params) { + params = Object.assign({ + build: dateformat(new Date(), 'yyyy-mm-dd HH:MM:ss'), + macro: [], + debug: false, + }, params); + + const files = []; + let stream = null; + + const bufferContents = (file, enc, callback) => { + // ToDo: check file not stream + files.push(file); + callback(); + }; + + const endStream = (callback) => { + log(this.tag, colors.cyan(`openfl ${params.command} ${params.platform}`)); + const args = ['-cwd', files[0].path, 'run', 'openfl', params.command, params.platform]; + if (params.values) for (let key of Object.keys(params.values)) { + const value = params.values[key]; + if (value === true) { + args.push(`-D${key}`); + } else if (value) { + args.push(`-D${key}="${value}"`); + } + } + const buildDir = path.join(os.tmpdir(), 'build'); + args.push(`--app-path=${buildDir}`); + if (params.outputFile) { + args.push(`--app-file=${params.outputFile}`); + } + if (params.version) args.push(`--meta-version=${params.version}`); + //if (params.build) args.push(`--haxedef=BUILD="${params.build}"`); + args.push(`--haxeflag="--macro CompilationOption.set('build','${params.build}')"`); + let debug = null; + if (params.debug) { + debug = { + host: 'localhost', + port: 6000 + Math.floor(Math.random() * 1000), + }; + args.push(`--haxeflag="--macro CompilationOption.set('debug.address','${debug.host}')"`); + args.push(`--haxeflag="--macro CompilationOption.set('debug.port','${debug.port}')"`); + args.push('-debug'); + } + //console.log('haxelib', args.join(' ')); + const target = `${buildDir}/${params.platform}/bin`; + rmdir(target); + this.haxelib(args).then(() => { + vfs.src(`${target}/**/*`).pipe(through.obj((file, enc, cb) => { + file.debug = debug; + stream.push(file); + cb(); + }, (cb) => { + callback(); + cb(); + })); + //callback(); + }).catch((error) => { + stream.emit('error', new PluginError({plugin: this.name, message: error})); + callback(); + }); + }; + + return stream = through.obj(bufferContents, endStream); + } + + /** + * + * @param params + * + * { + * platform: 'neko', + * version: '1.0.0', + * build: '1999.12.12 00:00', + * values: {}, + * lib: [], + * src: [], + * main: 'Main.hx', + * outputFile: 'out.n', + * debug: true, + * } + */ + build(params) { + params = Object.assign({ + build: dateformat(new Date(), 'yyyy-mm-dd HH:MM:ss'), + macro: [], + debug: false, + }, params); + + const files = []; + let stream = null; + + const bufferContents = (file, enc, callback) => { + // ToDo: check file not stream + files.push(file); + callback(); + }; + + const endStream = (callback) => { + log(this.tag, colors.cyan("haxe", params.platform), '=>', colors.magenta(params.outputFile)); + const args = []; + args.push('-main', params.main); + for (const lib of params.lib) { + args.push('-lib', lib); + } + for (const cp of params.cp) { + args.push('-cp', cp); + } + for (const macro of params.macro) { + args.push('--macro', `"${macro}"`); + } + if (params.values) for (let key of Object.keys(params.values)) { + const value = params.values[key]; + if (value === true) { + args.push(`-D ${key}`); + } else if (value) { + args.push(`-D ${key}="${value}"`); + } + } + const tmpFile = tmp.generateFile(); + const dir = path.dirname(tmpFile.path); + const name = path.basename(tmpFile.path); + args.push(`-${params.platform}`, tmpFile.path); + args.push(`--macro "CompilationOption.set('build','${params.build}')"`); + let debug = null; + if (params.debug) { + debug = { + host: 'localhost', + port: 6000 + Math.floor(Math.random() * 1000), + }; + args.push(`--macro "CompilationOption.set('debug.address','${debug.host}')"`); + args.push(`--macro "CompilationOption.set('debug.port','${debug.port}')"`); + args.push('-debug'); + } + //console.log('haxe', args.join(' ')); + this.haxe(args).then(() => { + const out = new Vinyl({ + path: params.outputFile, + //contents: fs.createReadStream(tmpFile.path), + contents: fs.readFileSync(tmpFile.path), + }); + out.debug = debug; + stream.push(out); + callback(); + }).catch((error) => { + stream.emit('error', new PluginError({plugin: this.name, message: error})); + callback(); + }); + }; + + return stream = through.obj(bufferContents, endStream); + } +} + +Haxe.ID = 'haxe'; + +Haxe.VERSION_3_4_0 = '3.4.0'; +Haxe.VERSION_3_4_2 = '3.4.2'; +Haxe.VERSION_3_4_3 = '3.4.3'; +Haxe.VERSION_3_4_7 = '3.4.7'; +Haxe.VERSION_3 = Haxe.VERSION_3_4_7; +Haxe.VERSION = Haxe.VERSION_3; + +module.exports = Haxe; \ No newline at end of file diff --git a/haxetool/neko.js b/haxetool/neko.js new file mode 100644 index 0000000..5ff1e42 --- /dev/null +++ b/haxetool/neko.js @@ -0,0 +1,35 @@ +const exec = require('./exec'); +const through = require('through2'); +const PluginError = require('plugin-error'); +const colors = require('ansi-colors'); +const log = require('fancy-log'); + +class Neko { + + constructor() { + this.tag = 'Neko'; + } + + run(...args) { + let stream = null; + const bufferContents = (file, enc, callback) => { + log(this.tag, colors.cyan("run"), colors.magenta(file.path)); + + exec('.', ['neko', file.path].concat(args).join(' ')) + .then(() => { + stream.emit('end'); + callback(); + }) + .catch((error) => { + stream.emit('error', new PluginError({plugin: this.tag, message: error})); + callback(); + }); + + stream.push(file); + }; + + return stream = through.obj(bufferContents); + } +} + +module.exports = Neko; \ No newline at end of file diff --git a/haxetool/sdk.js b/haxetool/sdk.js new file mode 100755 index 0000000..efc28b5 --- /dev/null +++ b/haxetool/sdk.js @@ -0,0 +1,113 @@ +const os = require('os'); +const fs = require('fs'); +const ps = require('promise-streams'); +const got = require('got'); +const unzip = require('unzip-stream'); +const tar = require('tar'); +const ProgressBar = require('progress'); +const colors = require('ansi-colors'); +const log = require('fancy-log'); +const mkdirp = require('mkdirp'); + + +class System { + + static get isWindows() { + return os.type() === 'Windows_NT'; + } + + static get isLinux() { + return os.type() === 'Linux'; + } + + static get archInt() { + if (os.arch() === 'ia32') return 32; + if (os.arch() === 'x64') return 64; + } + + static get isArch32() { + return this.archInt === 32; + } + + static get isArch64() { + return this.archInt === 64; + } +} + + +class Sdk { + static set dir(value) { + Sdk._dir = value + } + + static get dir() { + return Sdk._dir || `${os.homedir()}/sdk`; + } + + static path(name, version) { + return `${this.dir}/${name}/${version}`; + } + + constructor(name, version) { + this.name = name; + this.tag = colors.green(`[${name}]`); + this.version = version; + this.path = Sdk.path(name, version); + } + + get intVersion() { + const vArr = this.version.split('\.').reverse(); + let m = 1; + let r = 0; + for (let v of vArr) { + r += parseInt(v) * m; + m *= 10; + } + return r; + } + + get prepared() { + throw "Not implemented"; + } + + get link() { + throw "Not implemented"; + } + + prepare() { + log(this.tag, `version: ${colors.magenta(this.version)}`); + + if (this.prepared) { + return Promise.resolve(); + } else { + mkdirp(this.path); + const bar = new ProgressBar(`${this.tag} [:bar] :percent :etas`, {width: 40, total: 1000, clear: true}); + let stream = got.stream(this.link); + stream = stream.on('downloadProgress', (p) => bar.update(p.percent)); + if (this.link.endsWith('.zip')) { + const sep = '/'; + stream = stream.pipe(unzip.Parse()).on('entry', (entry) => { + const filePath = entry.path.split(sep).slice(1).join(sep); + if (filePath.length > 0) { + if (entry.type === 'Directory') { + mkdirp(this.path + sep + filePath); + } else if (entry.type === 'File') { + entry.pipe(fs.createWriteStream(this.path + sep + filePath)); + } + } else { + entry.autodrain(); + } + }); + } else if (this.link.endsWith('tar.gz')) { + stream = stream.pipe(tar.x({C: this.path, strip: 1})); + } else { + stream = stream.pipe(fs.createWriteStream(this.path)); + } + return ps.wait(stream); + } + } +} + +Sdk.System = System; + +module.exports = Sdk; diff --git a/index.js b/index.js new file mode 100644 index 0000000..526c489 --- /dev/null +++ b/index.js @@ -0,0 +1,7 @@ +module.exports = { + Sdk: require('./haxetool/sdk'), + Haxe: require('./haxetool/haxe'), + FlashPlayer: require('./haxetool/flashplayer'), + Neko: require('./haxetool/neko'), + AdobeAir: require('./haxetool/adobe_air'), +}; \ No newline at end of file diff --git a/package.json b/package.json index 2832784..56ddc06 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,20 @@ "version": "0.0.1", "description": "Haxe tool for gulp", "main": "index.js", + "dependencies": { + "async": "^2.6.0", + "dateformat": "^3.0.3", + "fs-extra": "^5.0.0", + "got": "^8.3.0", + "gulp": "github:gulpjs/gulp#4.0", + "plugin-error": "^1.0.1", + "progress": "^2.0.0", + "promise-streams": "^2.1.1", + "rmdir": "^1.2.0", + "tar": "^4.4.1", + "tmp-file": "^2.0.1", + "unzip-stream": "^0.3.0" + }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" },