lithium-sdk
Version:
### Lithium Developer Community Area
652 lines (578 loc) • 22.3 kB
JavaScript
/**
* Library methods for generating stubs
*
* @author jaker
*/
;
var expect = require('gulp-expect-file');
var extend = require('gulp-extend');
var fs = require('fs');
var http = require('http');
var merge = require('merge-stream');
var path = require('path');
var rename = require('gulp-rename');
var spawnSeries = require('spawn-series');
var template = require('gulp-template');
var inquirer = require('inquirer');
var through = require('through2').obj;
var prettyTime = require('pretty-hrtime');
var is = require('is_js');
var gulpif = require('gulp-if');
module.exports = function (gulp, gutil) {
var skinLib = require('./skin')(gulp, gutil);
function logFile() {
function decorate(color, text) {
return text ? '[' + gutil.colors[color](text) + ']' : '';
}
var stream = through(function (file, enc, callback) {
var items = [];
items.push(gutil.colors.cyan(file.path));
if (file.isDirectory()) {
items.push(decorate('magenta', 'DIR'));
} else if (file.isNull()) {
items.push(decorate('magenta', 'EMPTY'));
}
gutil.log(items.join(' '));
this.push(file);
return callback();
});
stream.resume();
return stream;
}
function validate(value, regex, allowEmpty) {
if (value === '') {
if (allowEmpty) {
return true;
} else {
return 'Please provide a valid value';
}
}
var cases = value.match(regex);
if (cases === null) {
return 'Invalid value, please try again.';
} else {
return true;
}
}
function npmLinkAndInstall(cwd, callback) {
/**
* Attempt to npm link global packages.
* This may fail because of permissions, if it fails packages
* will be installed locally using npm install
*/
spawnSeries(
[
{
command: 'npm',
args: ['link', require('../package.json').name],
options: {
cwd: cwd,
ignoreError: true,
stdio: 'inherit'
}
},
{
command: 'npm',
args: ['link', 'gulp'],
options: {
cwd: cwd,
ignoreError: true,
stdio: 'inherit'
}
},
{
command: 'npm',
args: ['install'],
options: {
cwd: cwd,
stdio: 'inherit'
}
}
],
callback,
function (child, i, cmdObj) {
gutil.log(gutil.colors.blue('Starting: ' + cmdObj.command + ' ' + cmdObj.args.join(' ')));
child.on('close', function (code) {
if (code === 0) {
gutil.log(gutil.colors.blue('Finished: ' + cmdObj.command + ' ' + cmdObj.args.join(' ')));
} else if (cmdObj.options.ignoreError) {
gutil.log(gutil.colors.red('Failed: ' + cmdObj.command + ' ' + cmdObj.args.join(' ')));
gutil.log(gutil.colors.blue('Ignoring error and continuing (Package will be installed in npm install) ..'));
}
});
}
);
}
function parseVersionPage(page) {
var start = page.lastIndexOf('<body>');
var end = page.lastIndexOf('</body>');
var body = page.substring(start + 6, end);
var versionArr = body.split(' ');
var revision;
if (versionArr.length > 2) {
revision = versionArr[2].replace(')', '');
}
return {
version: versionArr[0],
branch: versionArr[1].replace('(', ''),
revision: revision
};
}
function bowerInstall(cwd, callback) {
spawnSeries(
[
{
command: 'bower',
args: ['install'],
options: {
cwd: cwd,
stdio: 'inherit'
}
}
],
callback,
function (child, i, cmdObj) {
gutil.log(gutil.colors.blue('Starting: ' + cmdObj.command + ' ' + cmdObj.args.join(' ')));
child.on('close', function () {
gutil.log(gutil.colors.blue('Finished: ' + cmdObj.command + ' ' + cmdObj.args.join(' ')));
});
}
);
}
var templateConstraint = function(file) {
return path.basename(file.path) !== 'README.md';
};
return {
scaffold: function () {
var ops = {
serverConf: {}
};
inquirer.prompt([
{
type: 'input',
name: 'name',
message: 'What is your repository name?\nOnly lower case characters, numbers or hyphens (-) are allowed.',
validate: function (val) {
return validate(val, /^[a-z0-9\-]+$/);
}
},
{
type: 'confirm',
name: 'continue',
message: 'Do you want to continue?',
when: function (repo) {
if (fs.existsSync(path.join('.', repo.name))) {
console.log(gutil.colors.red(gutil.colors.bold(repo.name) + ' already exists in ' + process.cwd() + '.' +
'\nTo update the project please "li update" from root directory of the project.' +
'\nTo recreate the project please delete the existing project and then re-run "li create"'));
process.exit(1);
return true;
} else {
return false;
}
},
default: true
},
{
type: 'input',
name: 'serverUrl',
message: function () {
return 'What is the URL (include port if exists) to the dev/stage site that you will connect to ' +
'(beginning with "https://")?';
},
validate: function (val) {
return validate(val, /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&\/\/=]*)/);
}
},
{
type: 'input',
name: 'pluginToken',
message: function () {
return 'Do you have a plugin token (if not press enter)?';
},
validate: function (val) {
return validate(val, /^[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}$/, true);
},
default: function () {
return '';
}
}
], function (answers) {
// set up vars for server.conf.json
ops.serverConf.serverUrl = answers.serverUrl;
if (answers.pluginToken) {
ops.serverConf.pluginToken = answers.pluginToken;
}
//default studio overrides allowed
ops.serverConf.allowStudioOverrides = true;
//default strict mode false
ops.serverConf.strictMode = false;
//default dry run mode false
ops.serverConf.dryRun = false;
//default verbose false
ops.serverConf.verbose = false;
//default force false
ops.serverConf.force = false;
//default pluginPoints
ops.serverConf.pluginPoints = [];
//defaults for sass support
ops.serverConf.useResponsiveConfigsFromServer = true;
ops.serverConf.useLocalCompile = true;
//default skipTemplateValidation to false
ops.serverConf.skipTemplateValidation = false;
ops.name = answers.name;
ops.description = 'lithium-sdk project: ' + answers.name + '\nGenerated by ' + process.env.USER;
ops.version = require('../package.json').version;
// copy and process templates
var checkResponseCallback = function() {
gulp.src(path.join(__dirname, '../templates/project/**/*'))
.pipe(rename(function (path) {
if (path.basename.indexOf('_') === 0) {
path.basename = path.basename.replace('_', '');
}
}))
.pipe(gulpif(templateConstraint, template(ops)))
.pipe(rename(function (path) {
if (path.extname === '.mdt') {
path.extname = '.md';
}
}))
.pipe(gulp.dest('./' + answers.name))
.pipe(logFile())
.on('end', function () {
// once templates are finished, create server.conf.json
fs.writeFile(path.join('.', answers.name, 'server.conf.json'), JSON.stringify(ops.serverConf, null, 2),
function (error) {
if (error) {
throw error;
} else {
gutil.log(gutil.colors.cyan(path.resolve(path.join('.', answers.name, 'server.conf.json'))));
// npm link and install
npmLinkAndInstall(path.join('.', answers.name), function (code) {
if (code === 0) {
gutil.log(gutil.colors.green('Created ' + answers.name));
} else {
gutil.log(gutil.colors.red('Error while creating ' + answers.name));
}
});
}
});
});
};
answers.debugMode = gutil.env['debug'];
//Check server version before processing the templates
require('./version-check.js')(gulp, gutil).validate(answers.serverUrl, answers.pluginToken, answers, checkResponseCallback);
});
},
update: function (cb) {
var ops = {
serverConf: {}
};
try {
ops.serverConf = require(path.join(process.cwd(), 'server.conf.json'));
} catch (err) {
console.log('Your project may be corrupt.\nPlease delete try recreating the project using "li create"');
process.exit(1);
}
inquirer.prompt([
{
type: 'input',
name: 'serverUrl',
message: function () {
return 'Enter the new URL (include port if exists) to the dev/stage site that you will connect to (beginning with "http") or press enter to use existing';
},
validate: function (val) {
return validate(val, /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&\/\/=]*)/);
},
default: function () {
return ops.serverConf.serverUrl;
}
},
{
type: 'input',
name: 'pluginToken',
message: function () {
if (ops.serverConf.pluginToken) {
return 'Enter plugin token to change it or press enter to continue';
} else {
return 'Do you have a plugin token (if not press enter)?';
}
},
validate: function (val) {
return validate(val, /^[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}$/, true);
},
default: function () {
return ops.serverConf.pluginToken || '';
}
}
], function (answers) {
// set up vars for server.conf.json
ops.serverConf.serverUrl = answers.serverUrl;
if (answers.pluginToken) {
ops.serverConf.pluginToken = answers.pluginToken;
}
//defaults for sass support
ops.serverConf.useResponsiveConfigsFromServer = true;
ops.serverConf.useLocalCompile = true;
answers.name = process.cwd().split(path.normalize('/')).pop();
ops.name = answers.name;
ops.description = 'lithium-sdk project: ' + answers.name + '\nGenerated by ' + process.env.USER;
ops.version = require('../package.json').version;
// copy and process templates
var checkResponseCallback = function() {
gulp.src([path.join(__dirname, '../templates/project/**/*'),
'!' + path.join(__dirname, '../templates/project/sdk.conf.json'),
'!' + path.join(__dirname, '../templates/project/_.gitignore')])
.pipe(rename(function (path) {
if (path.basename.indexOf('_') === 0) {
path.basename = path.basename.replace('_', '');
}
}))
.pipe(gulpif(templateConstraint, template(ops)))
.pipe(rename(function (path) {
if (path.extname === '.mdt') {
path.extname = '.md';
}
}))
.pipe(gulp.dest('.'))
.pipe(logFile())
.on('end', function () {
// once templates are finished, create server.conf.json
fs.writeFile(path.join('.', 'server.conf.json'), JSON.stringify(ops.serverConf, null, 2),
function (error) {
if (error) {
cb(error);
} else {
gutil.log(gutil.colors.cyan(path.resolve('./server.conf.json')));
// npm link and install
npmLinkAndInstall('./', function (code) {
if (code === 0) {
gutil.log(gutil.colors.green('Project updated!'));
cb();
} else {
gutil.log(gutil.colors.red('Error while updating project.'));
cb(error);
}
});
}
});
});
};
require('./version-check.js')(gulp, gutil).validate(answers.serverUrl, answers.pluginToken, answers, checkResponseCallback);
// copy README files
});
},
// before we enable angular, we need to make sure they have a few things
verify: function () {
var files = ['sdk.conf.json', 'server.conf.json'];
return gulp.src(files)
.pipe(expect({ checkRealFile: true, errorOnFailure: true }, files))
.on('end', function () {
var sdkConf = require(path.join(process.cwd(), 'sdk.conf.json'));
if (!is.undefined(sdkConf.ng)) {
gutil.log(gutil.colors.red('Angularjs support is already enabled on this project.'));
process.exit(1);
}
})
.on('error', function () {
gutil.log(gutil.colors.red('File check failed.'));
process.exit(1);
});
},
enableAngular: function (cb) {
// get version
var serverUrl = require(path.join(process.cwd(), 'server.conf.json')).serverUrl;
var statusPath = '/t5/status/versionpage';
var request = http.get(serverUrl + statusPath);
var reqCallStarted = setInterval(function () {
gutil.log(gutil.colors.cyan('Waiting for response from ' + serverUrl + ' ...'));
}, 3000);
var reqCallStartTime = process.hrtime();
gutil.log(gutil.colors.cyan('Starting call to ' + serverUrl + ' ...'));
request.on('response', function (response) {
clearInterval(reqCallStarted);
if (response.statusCode === 200) {
var serverCallTime = prettyTime(process.hrtime(reqCallStartTime));
gutil.log(gutil.colors.cyan('Finished call to ' + serverUrl + ' in ' + gutil.colors.magenta(serverCallTime)));
response.setEncoding('utf8');
response.on('data', function (chunk) {
var liaBranch = parseVersionPage(chunk);
var custName = require(path.join(process.cwd(), 'package.json')).name;
gutil.log(gutil.colors.cyan('Lia version ' + gutil.colors.magenta(liaBranch.branch)));
if (liaBranch.branch.indexOf('release') > -1) {
liaBranch = 'release/' + liaBranch.version;
} else { // active branch
liaBranch = 'develop';
}
var ops = {
name: custName,
branch: liaBranch
};
// now that we have template variables, run gulp.src
merge(
// merge sdk.conf.json
gulp.src(['./sdk.conf.json',
path.join(__dirname, '../templates/project-ng/sdk.conf.json')])
.pipe(extend('sdk.conf.json'))
.pipe(gulp.dest('./'))
.pipe(logFile()),
// copy over everything else
gulp.src([path.join(__dirname, '../templates/project-ng/**/*'),
'!' + path.join(__dirname, '../templates/project-ng/sdk.conf.json')])
.pipe(template(ops))
.pipe(rename(function (path) {
path.basename = path.basename.replace('_', '');
}))
.pipe(gulp.dest('./'))
.pipe(logFile())
).on('end', function () {
bowerInstall('./', function (code) {
if (code === 0) {
gutil.log(gutil.colors.green('Finished! You may now use angular in your sdk environment.'));
cb();
} else {
gutil.log(gutil.colors.red('Bower install failed'));
cb(new Error('Bower install failed'));
}
});
});
});
} else {
gutil.log(gutil.colors.red('Call to ' + serverUrl + ' failed. Response status code: ' + response.statusCode));
cb(new Error('Call to lia failed.'));
}
});
},
server: function (opts, cb) {
var ops = {
serverConf: {}
};
var questions = [
{
type: 'input',
name: 'serverUrl',
message: function () {
return 'What is the URL (include port if exists) to the dev/stage site that you will connect to ' +
'(beginning with "https://")?';
},
validate: function (val) {
return validate(val, /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&\/\/=]*)/);
}
}
];
var noToken = gutil.env['notoken'];
if (noToken) {
var skins = skinLib.getResponsiveSkinIds();
if (skins.length < 1) {
process.exitCode = 1;
throw new Error('There are no responsive skins. You should create a skin in the res/skins folder and make its ' +
'parent a responsive skin (such as the responsive_peak skin) by setting the parent property in the ' +
'skin.properties file');
}
questions = questions.concat([
{
type: 'input',
name: 'liaVersion',
message: function() {
return 'What version of LIA are you running on your dev/stage site?';
},
default: function() {
return '16.2';
}
},
{
type: 'input',
name: 'responsiveVersion',
message: function() {
return 'What version of the core responsive feature (responsivepeak) are you using?';
},
default: function() {
return '1.7';
}
},
{
name: 'localSkinCompileSkin',
type: 'list',
message: function() {
return 'What responsive skin would you like to serve locally?'
},
choices: skins
},
{
type: 'input',
name: 'localServerPort',
message: function() {
return 'What port would you like to use to serve the compiled css for your skin from?';
},
default: function() {
return '9000';
}
}
]);
} else {
questions = questions.concat([
{
type: 'input',
name: 'pluginToken',
message: function () {
return 'Do you have a plugin token (if not press enter)?';
},
validate: function (val) {
return validate(val, /^[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}$/, true);
},
default: function () {
return '';
}
}
]);
}
inquirer.prompt(questions, function (answers) {
// set up vars for server.conf.json
ops.serverConf.serverUrl = answers.serverUrl;
if (answers.pluginToken) {
ops.serverConf.pluginToken = answers.pluginToken;
}
//default studio overrides allowed
ops.serverConf.allowStudioOverrides = true;
//default strict mode false
ops.serverConf.strictMode = false;
//default dry run mode false
ops.serverConf.dryRun = false;
//default verbose false
ops.serverConf.verbose = false;
//default force false
ops.serverConf.force = false;
//default pluginPoints
ops.serverConf.pluginPoints = [];
//defaults for sass support
ops.serverConf.useResponsiveConfigsFromServer = true;
ops.serverConf.useLocalCompile = true;
//default skipTemplateValidation to false
ops.serverConf.skipTemplateValidation = false;
// notoken options
if (noToken) {
ops.serverConf.useResponsiveConfigsFromServer = false;
ops.serverConf.localSkinCompileFeature = 'responsivepeak';
ops.serverConf.localSkinCompileVersion = 'v' + answers.responsiveVersion + 'lia' + answers.liaVersion;
ops.serverConf.localSkinCompileSkin = answers.localSkinCompileSkin;
ops.serverConf.localServerPort = parseInt(answers.localServerPort);
}
answers.name = process.cwd().split(path.normalize('/')).pop();
ops.name = answers.name;
ops.description = 'server.conf.json file for ' + answers.name + '\nGenerated by ' + process.env.USER;
//create server.conf.json
fs.writeFile(path.join('.', 'server.conf.json'), JSON.stringify(ops.serverConf, null, 2),
function (error) {
if (error) {
gutil.log(gutil.colors.red('Some error occured while creating server.conf.json file'));
cb(error);
} else {
gutil.log(gutil.colors.green("Finished creating server.conf.json file"));
gutil.log(gutil.colors.cyan(path.resolve(path.join('.', 'server.conf.json'))));
cb();
}
});
});
}
};
};