ionic
Version:
A tool for creating and developing Ionic Framework mobile apps.
340 lines (269 loc) • 9.2 kB
JavaScript
var fs = require('fs'),
os = require('os'),
request = require('request'),
path = require('path'),
unzip = require('unzip'),
argv = require('optimist').argv,
prompt = require('prompt'),
colors = require('colors'),
exec = require('child_process').exec,
Q = require('q'),
Task = require('./task').Task,
IonicStats = require('./stats').IonicStats;
var IonicTask = function() {};
IonicTask.prototype = new Task();
IonicTask.prototype.run = function(ionic) {
var self = this;
self.local = {};
self.versionData = {};
self.usesBower = false;
if (!fs.existsSync( path.resolve('www') )) {
return ionic.fail('"www" directory cannot be found. Make sure the working directory is at the top level of an Ionic project.', 'lib');
}
this.loadVersionData();
if(argv._.length > 1 && (argv._[1].toLowerCase() == 'update' || argv._[1].toLowerCase() == 'up')) {
this.updateLibVersion();
} else {
// just version info
this.printLibVersions();
}
};
IonicTask.prototype.loadVersionData = function() {
this.versionFilePath = path.resolve('www/lib/ionic/version.json');
if( !fs.existsSync(this.versionFilePath) ) {
this.versionFilePath = path.resolve('www/lib/ionic/bower.json');
this.usesBower = fs.existsSync(this.versionFilePath);
}
try {
this.local = require(this.versionFilePath);
} catch(e) {
console.log('Unable to load ionic lib version information'.bold.error);
}
};
IonicTask.prototype.printLibVersions = function() {
var self = this;
console.log('Local Ionic version: '.bold.green + this.local.version + ' (' + this.versionFilePath + ')');
this.getVersionData('latest').then(function(){
console.log('Latest Ionic version: '.bold.green + self.versionData.version_number + ' (released ' + self.versionData.release_date + ')');
if(self.local.version != self.versionData.version_number) {
console.log(' * Local version is out of date'.yellow );
} else {
console.log(' * Local version up to date'.green );
}
});
};
IonicTask.prototype.getVersionData = function(version) {
var q = Q.defer();
var self = this;
var url = 'http://code.ionicframework.com';
if(version == 'latest') {
url += '/latest.json';
} else {
url += '/' + version + '/version.json';
}
var proxy = process.env.PROXY || process.env.http_proxy || null;
request({ url: url, proxy: proxy }, function(err, res, body) {
try {
if(err || !res || !body) {
console.log('Unable to receive version data');
q.reject();
return;
}
if(res.statusCode == 404) {
console.log( ('Invalid version: ' + version).bold.red );
q.reject();
return;
}
if(res.statusCode >= 400) {
console.log('Unable to load version data');
q.reject();
return;
}
self.versionData = JSON.parse(body);
self.versionData.version_number = self.versionData.version_number || self.versionData.version;
self.versionData.version_codename = self.versionData.version_codename || self.versionData.codename;
self.versionData.release_date = self.versionData.release_date || self.versionData.date;
q.resolve();
} catch(e) {
console.log('Error loading '.bold.error + version.bold + ' version information'.bold.error );
q.reject();
}
});
return q.promise;
};
IonicTask.prototype.updateLibVersion = function() {
var self = this;
if(self.usesBower) {
var bowerCmd = exec('bower update ionic');
bowerCmd.stdout.on('data', function (data) {
process.stdout.write(data);
});
bowerCmd.stderr.on('data', function (data) {
if(data) {
process.stderr.write(data.toString().error.bold);
}
});
return;
}
prompt.message = '';
prompt.delimiter = '';
prompt.start();
var libPath = path.resolve('www/lib/ionic/');
console.log('Are you sure you want to replace '.green.bold + libPath.bold + ' with an updated version of Ionic?'.green.bold);
var promptProperties = {
areYouSure: {
name: 'areYouSure',
description: '(yes/no):'.yellow.bold,
required: true
}
};
prompt.get({properties: promptProperties}, function (err, promptResult) {
if(err) {
return console.log(err);
}
var areYouSure = promptResult.areYouSure.toLowerCase().trim();
if(areYouSure == 'yes' || areYouSure == 'y') {
self.getLatest();
}
});
};
IonicTask.prototype.getLatest = function() {
var self = this;
var dirPath = path.resolve('www/lib/');
if(!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath);
}
dirPath = path.resolve('www/lib/ionic/');
if(!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath);
}
var version = argv.version || argv.v;
if(version === true || !version) {
version = 'latest';
}
this.getVersionData(version).then(function(){
if(version == 'latest') {
console.log('Latest version: '.bold.green + self.versionData.version_number + ' (released ' + self.versionData.release_date + ')');
} else {
console.log('Version: '.bold.green + self.versionData.version_number + ' (released ' + self.versionData.release_date + ')');
}
self.downloadZip(self.versionData.version_number);
});
};
IonicTask.prototype.downloadZip = function(version) {
var self = this;
var archivePath = 'https://github.com/driftyco/ionic-bower/archive/v' + version + '.zip';
self.tmpExtractPath = path.resolve('www/lib/.ionic');
self.tmpZipPath = path.join(self.tmpExtractPath, 'ionic.zip');
if( !fs.existsSync(self.tmpExtractPath) ) {
fs.mkdirSync(self.tmpExtractPath);
}
console.log('Downloading: '.green.bold + archivePath);
var proxy = process.env.PROXY || null;
request({ url: archivePath, rejectUnauthorized: false, encoding: null, proxy: proxy }, function(err, res, body) {
if(err) {
console.log(err);
return;
}
if(res.statusCode == 404 || res.statusCode == 406) {
console.log( ('Invalid version: ' + version).bold.red );
return;
}
if(res.statusCode >= 400) {
console.log('Unable to download zip (' + res.statusCode + ')');
return;
}
try {
fs.writeFileSync(self.tmpZipPath, body);
self.updateFiles();
} catch(e) {
console.error(e);
}
}).on('response', function(res){
var ProgressBar = require('progress');
var bar = new ProgressBar('[:bar] :percent :etas', {
complete: '=',
incomplete: ' ',
width: 30,
total: parseInt(res.headers['content-length'], 10)
});
res.on('data', function (chunk) {
try {
bar.tick(chunk.length);
} catch(e){}
});
}).on('error', function(err) {
try {
fs.unlink(self.tmpZipPath);
} catch(e) {
console.error(e);
}
console.error(err);
});
};
IonicTask.prototype.updateFiles = function(version) {
var self = this;
var ionicLibDir = path.resolve('www/lib/ionic');
try {
var readStream = fs.createReadStream(self.tmpZipPath);
readStream.on('error', function(err) {
console.log( ('updateFiles readStream: ' + err).error );
});
var writeStream = unzip.Extract({ path: self.tmpExtractPath });
writeStream.on('close', function() {
try {
rm('-rf', self.tmpZipPath)
} catch(e){}
try {
var dir = fs.readdirSync(self.tmpExtractPath);
var copyFrom;
for(var x=0; x<dir.length; x++) {
if( dir[x].indexOf('ionic') === 0 ) {
copyFrom = path.join(self.tmpExtractPath, dir[x], '*');
}
}
if(!copyFrom) {
console.log('updateFiles, invalid zip');
return;
}
cp('-Rf', copyFrom, ionicLibDir);
try {
rm('-rf', self.tmpExtractPath)
} catch(e){}
try {
rm('-rf', path.join(ionicLibDir, 'README.md'));
} catch(e){}
try {
rm('-rf', path.join(ionicLibDir, 'bower.json'));
} catch(e){}
console.log('Ionic version updated to: '.bold.green + self.versionData.version_number.bold );
IonicStats.t();
self.writeVersionData();
var ionicBower = require('./bower').IonicBower;
ionicBower.setIonicVersion(self.versionData.version_number);
} catch(e){
console.log('updateFiles Error: ' + e);
}
});
writeStream.on('error', function(err) {
console.log( ('updateFiles writeStream: ' + err).error );
});
readStream.pipe(writeStream);
} catch(e) {
console.log('updateFiles Error: ' + e);
}
};
IonicTask.prototype.writeVersionData = function() {
try {
var versionData = {
"version": this.versionData.version_number || this.versionData.version,
"codename": this.versionData.version_codename || this.versionData.codename,
"date": this.versionData.release_date || this.versionData.date
};
fs.writeFileSync( path.resolve('www/lib/ionic/version.json'),
JSON.stringify(versionData, null, 2) );
} catch(e) {
console.log( ('Error writing version data: ' + e).error.bold );
}
};
exports.IonicTask = IonicTask;