nyx_server
Version:
Node内容发布
293 lines (261 loc) • 11.2 kB
JavaScript
/* global process */
/**
* 项目发布命令,该命令将项目信息注册到数据库
*/
var projectFn = require("../core/Project");
var Project = require("../core/ProjectLoader").Project;
var build = require("./build");
var cdn = require("./cdn");
var gencid = require("./gencid");
var config = require("../config/default-config");
var cmd = require("../core/utils/cmd");
var path = require("path");
var log4js = require("log4js");
var log = log4js.getLogger("Publish");
var Promise = require("bluebird");
var fs = Promise.promisifyAll(require("fs"));
var glob = require("glob");
var buildUtil = require("./lib/build/utils");
var Optimist = require('../optimist/optimist');
var help = require('../optimist/help');
var optimist = new Optimist();
optimist
.info('项目版本发布')
.usage('nyx publish [--version v]')
.define("version").type("string", "number").describe('项目版本号').require(true)
.define("message").type("string").describe('描述信息').require(true);
var argv = optimist.getArgv();
var Publish = function(){};
Publish.prototype.execute = function(){
var argvAnalysis = optimist.analysis;
if (argvAnalysis.options.hasOwnProperty('help') || argvAnalysis.shortKeys.hasOwnProperty('h')) {
help.detailed(optimist);
process.exit(1);
}
var version = argv.version; //发布的版本号
var message = argv.message; //描述信息
if(!version || !message){
help.detailed(optimist);
process.exit(1);
}
var project = new Project(process.cwd());
//1、替换碎片id, 创建碎片实例(配置)数据
return gencid.execute1(project).then(function(){
return build.execute1("*"); //2、build
}).then(function(){
return adjustProjectVersion(version);
}).then(function(){
return adjustVersion(version); //3、修改版本号,重新计算文件名称,修改文件依赖
}).then(function(){
return cdn.execute1("*"); //上传cdn
}).then(function(){
return commitLocalFile(message); //提交本地
}).then(function(){
return commitLocalVersion(version);
}).then(function(){
return commitRemote().catch(function(err){
deleteLocalTag(version);
throw err;
});
}).then(function(){
log.info("publish处理完成");
return true;
}).catch(function(err){
log.error(err);
});
};
function deleteLocalTag(version){
return cmd('git', ['tag', "-d" , version]);
}
/**
* 创建本地版本
* @param version 版本
*/
function commitLocalVersion(version){
return cmd("git" , ["tag"]).then(function(data){
var tags = data[0].match(/.*[\r|\n]/g);
if(!tags) return;
for(var i=0; i<tags.length; i++){
var tag = tags[i].replace(/[\r|\n]/g ,"");
if(tag == version){
throw new Error("版本"+version+"已经存在");
}
}
return true;
}).then(function(){
return cmd('git', ['tag', version]);
});
}
function commitLocalFile(message){
return cmd("git" , ["add" , "." ,"-A"]).then(function(){
return cmd('git', ['commit', '-a' , '--m' , '"'+message+'"']).then(
function(data){
return []; //提交成功
},
function(data){
//提交失败。
var stdout = data.stdout;
if(stdout.match(/\s*nothing\s*to\s*commit\s*/ig)){
//git commit当没有数据可以提交是返回的code==1
//这里需要处理没有数据提交的情况,如果是没有数据提交则返回正常。
return [];
}
throw new Error(data);
},
function(data){
//回显通知
return [];
}
);
});
}
function commitRemote(){
return cmd('git' , ['status']).then(function(result){
var regx = /\s*On\s*branch\s*(\S*)\s*.*[\r|n]*/i;
var matchs = regx.exec(result);
if(typeof matchs != 'undefined' && matchs.length && matchs.length>0){
console.log('push to branch '+matchs[1]);
return cmd('git', ['push', '--tag' , '--progress' , 'origin' , matchs[1]]);
}
console.log('waring : no find branch , use default set . please confirm.');
return cmd('git', ['push', '--tag' , '--progress' , 'origin']);
});
}
function adjustProjectVersion(version){
var packageFile = path.join(process.cwd() , "package.json");
var packageInfo = require(packageFile);
packageInfo.version = version;
return new Promise(function(resolve , reject){
fs.writeFile(packageFile , JSON.stringify(packageInfo) , function(err){
if(err){
reject(err);
}else{
resolve(true);
}
});
});
}
var versionString = "@version@";
var versionPattern = new RegExp(versionString);
function adjustVersion(version){
var project = new Project(process.cwd());
var allpromise = [];
var p= projectFn.loadTemplates(project).map(function(template){
var basePath = template.basePath;
return _adjustVersion(basePath , version);
});
allpromise.push(p);
p= projectFn.loadChips(project).map(function(chip){
var basePath = chip.basePath;
return _adjustVersion(basePath , version);
});
allpromise.push(p);
return Promise.all(allpromise);
}
/**
* 修改所有js文件中的@version@为真实的版本号
*/
function _adjustVersion(basePath , version){
return new Promise(function(resolve , reject){
var patterns = path.join(basePath , config.DIST_DIR , "**/!(*.min).js");
glob(patterns , function(err , files){
var p =Promise.map(files , function(file){
log.info("adjustVersion file :" + file);
return new Promise(function(resolve , reject){
fs.readFile(file , "utf-8" ,function(err , data){
var haschange = false;
data = data.replace(/(@version@)/ , function(match , oldversion , offset , input){
haschange = true;
return version;
});
if(haschange){
var ret = {filePath : file , content : data};
resolve(ret);
}else{
resolve(null);
}
});
});
}).filter(function(result){
return result != null;
}).map(function(result){
var content = result.content;
var oldFilePath = result.filePath;
var suffix = buildUtil.md5Suffix(content,"md5","hex");
var extname = path.extname(oldFilePath);
var baseName = path.basename(oldFilePath , extname);
var oldMinFilePath = path.dirname(oldFilePath)+'/'+ baseName+".min"+extname;
var appPromise = [];
appPromise.push(fs.unlinkAsync(oldFilePath).then(function(err){
if(err){log.error("unlinkAsync "+err);}
}));
appPromise.push(fs.unlinkAsync(oldMinFilePath).then(function(err){
if(err){log.error("unlinkAsync "+err);}
}));
baseName = buildUtil.getWithoutMd5Suffix(baseName); //去除文件MD5后缀
var fileNamePrefix = path.dirname(oldFilePath)+'/'+ baseName+'_'+suffix;
//处理压缩文件
var compressContent = buildUtil.compressContent(content);
var newCompressedFileName = fileNamePrefix+'.min'+extname; //压缩的文件名
var newFileName = fileNamePrefix+extname; //未压缩的文件名
appPromise.push(fs.writeFileAsync(newFileName , content).then(function(err){
if(err){log.error("writeFileAsync ,"+err);}
}));
appPromise.push(fs.writeFileAsync(newCompressedFileName , compressContent).then(function(err){
if(err){log.error("writeFileAsync ,"+err);}
}));
return Promise.all(appPromise).then(function(){
return {"originMinFile" : oldMinFilePath , 'newMinFile':newCompressedFileName};
});
}).map(function(compareMinFiles){
//console.log(compareMinFiles);
//替换模板中引用的地址
var oldBasename = path.basename(compareMinFiles.originMinFile);
var newBasename = path.basename(compareMinFiles.newMinFile);
//console.log(oldBasename , newBasename);
return new Promise(function(resolve ,reject){
glob(path.join(basePath , config.DIST_DIR , "**/*.ejs") , function(err , files){
var allpromise = [];
files.forEach(function(file){
allpromise.push(fs.readFileAsync(file , "utf-8").then(function(content){
content = content.replace(oldBasename , newBasename);
fs.writeFileAsync(file , content).then(function(err){
return true;
});
}));
});
resolve(Promise.all(allpromise));
});
});
});
resolve(p);
});
});
}
function getProjectInfo(){
var packagePath = path.join(process.cwd() , "package.json");
return new Promise(function(resolve , reject){
fs.exists(packagePath , function(exists){
if(!exists){
resolve(null);
}else{
fs.readFile(packagePath , "utf-8" , function(err , data){
if(err){
log.error(err);
resolve(null);
}else{
var v = JSON.parse(data);
resolve(v);
}
});
}
});
});
}
Publish.prototype.showhelp = function(){
help.detailed(optimist);
};
Publish.prototype.optimist = function() {
return optimist;
};
module.exports = new Publish();