appc-cli-titanium
Version:
Titanium CLI Plugin
192 lines (166 loc) • 5.13 kB
JavaScript
/**
* This code is closed source and Confidential and Proprietary to
* Appcelerator, Inc. All Rights Reserved. This code MUST not be
* modified, copied or otherwise redistributed without express
* written permission of Appcelerator. This file is licensed as
* part of the Appcelerator Platform and governed under the terms
* of the Appcelerator license agreement.
*/
var appc,
fs = require('fs-extra'),
path = require('path'),
_ = require('lodash'),
async = require('async'),
tar = require('tar');
module.exports = {
name: 'titanium-components-publish',
type: 'timodule',
execute: publish,
find: findComponent,
when: function (opts) {
var isModule = false;
[ 'android', 'iphone', 'mobileweb' ].forEach(function (platform) {
isModule |= fs.existsSync(path.join(opts.projectDir || process.cwd(), platform, 'timodule.xml'));
});
return isModule;
},
passthru: true
};
function findComponent(appc, opts, pluginExports) {
var components = [];
// search for component keywords in a directory
function search(dir) {
var pkgFile = path.join(dir, 'appc.json');
if (fs.existsSync(pkgFile)) {
try {
var pkg = JSON.parse(fs.readFileSync(pkgFile, 'utf8'));
if (!pkg.type) {
return;
}
if (/^(timodule|widget|template|theme)$/.test(pkg.type)) {
appc.log.debug('found publishable component ' + pkg.name + ' at ' + dir);
var rel = path.relative(process.cwd(), dir);
components.push({
name: pkg.type + '/' + pkg.name + '@' + pkg.version + ' '
+ appc.chalk.dim.gray('[' + (/^[/.\\]/.test(rel) ? '' : './') + rel + ']'),
value: {
name: pkg.name,
type: pkg.type,
version: pkg.version,
dir: dir,
plugin: module.exports
}
});
return;
}
} catch (e) {
appc.log.trace('Failed to parse appc.json: ' + e.message);
return;
}
return;
}
}
// search directories for publishable components
var searchDir = opts.projectDir || process.cwd();
appc.log.trace('searching for publishable components in ' + searchDir);
search(searchDir);
return components;
}
function publish(_appc, args, opts, callback) {
appc = _appc;
opts = _.clone(opts || {});
var component = opts.component,
pkgFile = path.join(component.dir, 'appc.json');
appc.log.trace('loading for publish ' + appc.chalk.yellow(pkgFile));
try {
opts.pkg = JSON.parse(fs.readFileSync(pkgFile, 'utf8'));
} catch (e) {
return callback(new Error('unable to parse appc.json\n' + e.toString()));
}
opts.publishDir = component.dir;
async.waterfall([
// feed opts into waterfall
function (cb) { return cb(null, opts); },
// package the module, via npm pack
packModule,
// sha1 the dist
sha1Dist,
// upload packaged module to registry
uploadModule
], function (err, result) {
if (opts.packFile) {
try {
fs.unlinkSync(opts.packFile);
} catch (e) {
// do nothing
}
}
return callback(err, result);
});
}
function packModule(opts, callback) {
appc.log.info('Packaging ' + opts.pkg.name);
appc.spinner.start();
opts.packFile = path.join(opts.publishDir, opts.pkg.name + '-' + opts.pkg.version + '.tgz');
const tarOpt = {
file: opts.packFile,
cwd: path.dirname(opts.publishDir),
portable: true,
gzip: true
};
tar.create(tarOpt, [ path.basename(opts.publishDir) ], function (err) {
appc.spinner.stop();
if (err) {
return callback(err);
}
return callback(null, opts);
});
}
function sha1Dist(opts, callback) {
appc.log.info('Encoding ' + opts.pkg.name);
var hash = require('crypto').createHash('sha1');
hash.setEncoding('hex');
var fd = fs.createReadStream(opts.packFile);
fd.on('end', function () {
hash.end();
opts.shasum = hash.read();
callback(null, opts);
});
fd.pipe(hash);
}
function uploadModule(opts, callback) {
appc.spinner.start();
// add the shasum to the package.json
opts.pkg._shasum = opts.shasum;
// attempt to find a suitable README and bring it in like npm publish does
var readmeNames = [ 'README.md', 'README', 'README.txt' ];
for (var c = 0; c < readmeNames.length; c++) {
var readme = path.join(opts.publishDir, readmeNames[c]);
if (fs.existsSync(readme)) {
opts.pkg.readme = fs.readFileSync(readme).toString();
opts.pkg.readmeFilename = readmeNames[c];
break;
}
}
// get the TYPE if there's one and this is a appc-cli-plugin
if (opts.pkg && opts.pkg.keywords && opts.pkg.keywords.indexOf('appc-cli-plugin') !== -1) {
var appcfn = path.join(opts.publishDir, 'appc.js');
if (fs.existsSync(appcfn)) {
try {
var m = require(appcfn); // eslint-disable-line security/detect-non-literal-require
opts.subtype = m.TYPE;
} catch (E) {
appc.log.debug('Error attempting to determine appc-cli-plugin TYPE by loading', appcfn, '. Error: ', E);
}
}
}
var appcFile = path.join(opts.publishDir, 'appc.json');
appc.publish.validateAppC(appcFile, opts.pkg, opts.session, function (err, appcJSON, saveappcJSON, savePKG) {
if (err) {
appc.spinner.stop();
return callback(err);
}
opts.appcJSON = appcJSON;
appc.publish.uploadModule(opts, callback);
});
}