<commit_before>#!/usr/bin/env node

/*
 * Copyright 2013, All Rights Reserved.
 *
 * Code licensed under the BSD License:
 * https://github.com/node-gh/gh/blob/master/LICENSE.md
 *
 * @author Eduardo Lundgren <eduardolundgren@gmail.com>
 */

// -- Requires -------------------------------------------------------------------------------------

var async = require('async'),
    base = require('../lib/base'),
    fs = require('fs'),
    git = require('../lib/git'),
    logger = require('../lib/logger'),
    nopt = require('nopt'),
    path = require('path'),
    Help = require('../lib/cmds/help').Impl,
    User = require('../lib/cmds/user').Impl,
    command,
    commandDir,
    commandFiles,
    commandPath,
    cooked,
    iterative,
    operations,
    options,
    parsed,
    remain;

// -- Env ------------------------------------------------------------------------------------------

process.env.GH_PATH = path.join(__dirname, '../');

// -- Init -----------------------------------------------------------------------------------------

operations = [];
parsed = nopt(process.argv);
remain = parsed.argv.remain;
cooked = parsed.argv.cooked;

if (!remain.length ||
    (cooked.indexOf('-h') >= 0) ||
    (cooked.indexOf('--help') >= 0)) {

    new Help().run();
    process.exit(0);
}

commandDir = path.join(__dirname, '..', 'lib', 'cmds');
commandPath = path.join(commandDir, remain[0] + '.js');

// -- Find command ---------------------------------------------------------------------------------

if (fs.existsSync(commandPath)) {
    command = require(commandPath).Impl;
}
else {
    commandFiles = base.find(commandDir, /\.js$/i);
    commandFiles.every(function(file) {
        commandPath = path.join(commandDir, file);
        command = require(commandPath).Impl;

        if (command.DETAILS.alias === remain[0]) {
            return false;
        }

        command = null;
        return true;
    });
}

// If command was not found, check if it is registered as a plugin.
if (!command) {
    command = base.getPlugin(remain[0]).Impl;

    if (command) {
        // If plugin command exists, register the executed plugin name on
        // process.env.PLUGIN. This may simplify core plugin infrastructure.
        process.env.PLUGIN = remain[0];
    }
}

// -- Utils ----------------------------------------------------------------------------------------

function expandAlias(options) {
    var alias = base.config.alias;

    if (alias) {
        options.user = alias[options.user] || options.user;
        options.fwd = alias[options.fwd] || options.fwd;
        options.submit = alias[options.submit] || options.submit;
    }
}

function hasCommandInOptions(commands, options) {
    var found = false;

    if (commands) {
        commands.every(function(c) {
            if (options[c] !== undefined) {
                found = true;
                return false;
            }
            return true;
        });
    }

    return found;
}

function invokePayload(options, command, cooked, remain) {
    var payload;

    if (command.DETAILS.payload && !hasCommandInOptions(command.DETAILS.commands, options)) {
        payload = remain.concat();
        payload.shift();
        command.DETAILS.payload(payload, options);
    }
}

// -- Run command ----------------------------------------------------------------------------------

if (command) {
    options = nopt(
        command.DETAILS.options,
        command.DETAILS.shorthands, process.argv, 2);

    iterative = command.DETAILS.iterative;

    cooked = options.argv.cooked;
    remain = options.argv.remain;

    options.number = options.number || [remain[1]];
    options.remote = options.remote || base.config.default_remote;

    operations.push(User.login);

    operations.push(function(callback) {
        git.getUser(options.remote, callback);
    });

    operations.push(function(callback) {
        git.getRepo(options.remote, callback);
    });

    operations.push(git.getCurrentBranch);
    operations.push(base.checkVersion);

    async.series(operations, function(err, results) {
        var iterativeValues;

        options.loggedUser = base.getUser();
        options.remoteUser = results[1];

        if (!options.user) {
            if (options.repo || options.all) {
                options.user = options.loggedUser;
            }
            else {
                options.user = options.remoteUser || options.loggedUser;
            }
        }

        options.repo = options.repo || results[2];
        options.currentBranch = options.currentBranch || results[3];

        expandAlias(options);

        // Try to retrieve iterative values from iterative option key,
        // e.g. option['number'] === [1,2,3]. If iterative option key is not
        // present, assume [undefined] in order to initialize the loop.
        iterativeValues = options[iterative] || [undefined];

        iterativeValues.forEach(function(value) {
            options = base.clone(options);

            // Value can be undefined when the command doesn't have a iterative
            // option.
            options[iterative] = value;

            invokePayload(options, command, cooked, remain);

            new command(options).run();
        });
    });
}
else {
    logger.error('Command not found');
}
<commit_msg>Cannot read property "Impl" of undefined error - Fix #202<commit_after>#!/usr/bin/env node

/*
 * Copyright 2013, All Rights Reserved.
 *
 * Code licensed under the BSD License:
 * https://github.com/node-gh/gh/blob/master/LICENSE.md
 *
 * @author Eduardo Lundgren <eduardolundgren@gmail.com>
 */

// -- Requires -------------------------------------------------------------------------------------

var async = require('async'),
    base = require('../lib/base'),
    fs = require('fs'),
    git = require('../lib/git'),
    logger = require('../lib/logger'),
    nopt = require('nopt'),
    path = require('path'),
    Help = require('../lib/cmds/help').Impl,
    User = require('../lib/cmds/user').Impl,
    command,
    commandDir,
    commandFiles,
    commandPath,
    cooked,
    iterative,
    operations,
    options,
    parsed,
    plugin,
    remain;

// -- Env ------------------------------------------------------------------------------------------

process.env.GH_PATH = path.join(__dirname, '../');

// -- Init -----------------------------------------------------------------------------------------

operations = [];
parsed = nopt(process.argv);
remain = parsed.argv.remain;
cooked = parsed.argv.cooked;

if (!remain.length ||
    (cooked.indexOf('-h') >= 0) ||
    (cooked.indexOf('--help') >= 0)) {

    new Help().run();
    process.exit(0);
}

commandDir = path.join(__dirname, '..', 'lib', 'cmds');
commandPath = path.join(commandDir, remain[0] + '.js');

// -- Find command ---------------------------------------------------------------------------------

if (fs.existsSync(commandPath)) {
    command = require(commandPath).Impl;
}
else {
    commandFiles = base.find(commandDir, /\.js$/i);
    commandFiles.every(function(file) {
        commandPath = path.join(commandDir, file);
        command = require(commandPath).Impl;

        if (command.DETAILS.alias === remain[0]) {
            return false;
        }

        command = null;
        return true;
    });
}

// If command was not found, check if it is registered as a plugin.
if (!command) {
    plugin = base.getPlugin(remain[0]);

    if (plugin) {
        command = plugin.Impl;

        // If plugin command exists, register the executed plugin name on
        // process.env.PLUGIN. This may simplify core plugin infrastructure.
        process.env.PLUGIN = remain[0];
    }
}

// -- Utils ----------------------------------------------------------------------------------------

function expandAlias(options) {
    var alias = base.config.alias;

    if (alias) {
        options.user = alias[options.user] || options.user;
        options.fwd = alias[options.fwd] || options.fwd;
        options.submit = alias[options.submit] || options.submit;
    }
}

function hasCommandInOptions(commands, options) {
    var found = false;

    if (commands) {
        commands.every(function(c) {
            if (options[c] !== undefined) {
                found = true;
                return false;
            }
            return true;
        });
    }

    return found;
}

function invokePayload(options, command, cooked, remain) {
    var payload;

    if (command.DETAILS.payload && !hasCommandInOptions(command.DETAILS.commands, options)) {
        payload = remain.concat();
        payload.shift();
        command.DETAILS.payload(payload, options);
    }
}

// -- Run command ----------------------------------------------------------------------------------

if (command) {
    options = nopt(
        command.DETAILS.options,
        command.DETAILS.shorthands, process.argv, 2);

    iterative = command.DETAILS.iterative;

    cooked = options.argv.cooked;
    remain = options.argv.remain;

    options.number = options.number || [remain[1]];
    options.remote = options.remote || base.config.default_remote;

    operations.push(User.login);

    operations.push(function(callback) {
        git.getUser(options.remote, callback);
    });

    operations.push(function(callback) {
        git.getRepo(options.remote, callback);
    });

    operations.push(git.getCurrentBranch);
    operations.push(base.checkVersion);

    async.series(operations, function(err, results) {
        var iterativeValues;

        options.loggedUser = base.getUser();
        options.remoteUser = results[1];

        if (!options.user) {
            if (options.repo || options.all) {
                options.user = options.loggedUser;
            }
            else {
                options.user = options.remoteUser || options.loggedUser;
            }
        }

        options.repo = options.repo || results[2];
        options.currentBranch = options.currentBranch || results[3];

        expandAlias(options);

        // Try to retrieve iterative values from iterative option key,
        // e.g. option['number'] === [1,2,3]. If iterative option key is not
        // present, assume [undefined] in order to initialize the loop.
        iterativeValues = options[iterative] || [undefined];

        iterativeValues.forEach(function(value) {
            options = base.clone(options);

            // Value can be undefined when the command doesn't have a iterative
            // option.
            options[iterative] = value;

            invokePayload(options, command, cooked, remain);

            new command(options).run();
        });
    });
}
else {
    logger.error('Command not found');
}
<|endoftext|>


<commit_before>var inherit = require('inherit');

var Provider = inherit({
	__constructor : function() {
		this.prov_type = [];
	},
	ready : false,
});

module.exports.MediaProvider = inherit(Provider, {
	__constructor : function(id) {
		this.__base();
		this.prov_type.push('media');
	},
},
{
	id: new Error("Please set an ID for the provider"),
	search : function() {
		return new Error("Please override this function");
	},
});

module.exports.MetadataProvider = inherit(Provider, {
	__constructor : function(id) {
		this.__base();
		this.prov_type.push('metadata');
	},
},
{
	id: new Error("Please set an ID for the provider"),
	setMetadata : function() {
		return new Error("Please override this function");
	},
});<commit_msg>keeping it DRY<commit_after>var inherit = require('inherit');

var Provider = inherit({
	__constructor : function() {
		this.prov_type = [];
	},
	ready : false,
},
{
	id: new Error("Please set an ID for the provider"),
});

module.exports.MediaProvider = inherit(Provider, {
	__constructor : function(id) {
		this.__base();
		this.prov_type.push('media');
	},
},
{
	search : function() {
		return new Error("Please override this function");
	},
});

module.exports.MetadataProvider = inherit(Provider, {
	__constructor : function(id) {
		this.__base();
		this.prov_type.push('metadata');
	},
},
{
	setMetadata : function() {
		return new Error("Please override this function");
	},
});<|endoftext|>


<commit_before>import AbstractNode from "./abstract-node"
import Context from "../context"
import {default as DocParser, DocNode} from "../doc-parser"
import * as PHPError from "../php-error"
import * as PHPType from "../php-type"

export default class Doc extends AbstractNode {
    /** @type {boolean} */
    get isDoc() {
        return this.node.isDoc
    }
    /** @type {string[]} */
    get lines() {
        return this.node.lines
    }
    /**
     * Given a type union filled with unqualified names, returns the same with
     * qualified names.
     *
     * @param {PHPType.Union} u
     * @param {Context} context
     * @param {Doc} doc
     * @returns {PHPType.Union}
     */
    resolveAllDocNames(u, context, doc) {
        let n = PHPType.Union.empty
        u.types.map(t => {
            if(t instanceof PHPType.AssociativeArray) {
                return new PHPType.AssociativeArray(
                    this.resolveAllDocNames(t.memberType, context, doc)
                )
            } else if(t instanceof PHPType.IndexedArray) {
                return new PHPType.IndexedArray(
                    this.resolveAllDocNames(t.memberType, context, doc)
                )
            } else if(t instanceof PHPType.Simple) {
                return new PHPType.Simple(
                    this.resolveDocName(t.typeName, context, doc),
                    t.values,
                    t.polyValue
                )
            } else if(t instanceof PHPType.Function) {
                let cbp = {}
                Object.keys(t.callbackPositions).forEach(k => {
                    cbp[k] = this.resolveAllDocNames(t.callbackPositions[k], context, doc)
                })
                return new PHPType.Function(
                    t.argTypes.map(
                        atype => this.resolveAllDocNames(atype, context, doc)
                    ),
                    this.resolveAllDocNames(t.returnType, context, doc),
                    t.passByReferencePositions,
                    cbp
                )
            } else if(t instanceof PHPType.Mixed) {
                // Do nothing
                return t
            } else {
                throw new Error(`Don't know how to resolve doc names in type ${t}`)
            }
        }).forEach(
            t => n.addType(t)
        )
        return n
    }
    /**
     * @param {string} t
     * @param {Context} context
     * @param {Doc} doc
     * @returns {string}
     */
    resolveDocName(t, context, doc) {
        try {
            if(t.match(/^\\/)) {
                return t
            } else if(PHPType.Core.types.hasOwnProperty(t)) {
                return context.resolveName(PHPType.Core.types[t].toString())
            } else {
                return(
                    context.fileContext.resolveAliasName(t) ||
                    context.resolveName(t, "uqn")
                )
            }
        } catch(e) {
            if(e instanceof PHPType.WrongType) {
                this.throw(new PHPError.BadCoreType(e.message), context, doc.loc)
                return context.resolveName(e.realName)
            } else {
                throw e
            }
        }
    }
    /**
     * @type {DocNode[]}
     */
    get structure() {
        if(!this._structure) {
            this._structure = new DocParser(this.lines).top.children
        }
        return this._structure
    }
}
export {DocTypeNode} from "../doc-parser"<commit_msg>Retain the correct object<commit_after>import AbstractNode from "./abstract-node"
import Context from "../context"
import {default as DocParser, DocNode} from "../doc-parser"
import * as PHPError from "../php-error"
import * as PHPType from "../php-type"

export default class Doc extends AbstractNode {
    /** @type {boolean} */
    get isDoc() {
        return this.node.isDoc
    }
    /** @type {string[]} */
    get lines() {
        return this.node.lines
    }
    /**
     * Given a type union filled with unqualified names, returns the same with
     * qualified names.
     *
     * @param {PHPType.Union} u
     * @param {Context} context
     * @param {Doc} doc
     * @returns {PHPType.Union}
     */
    resolveAllDocNames(u, context, doc) {
        let n = PHPType.Union.empty
        u.types.map(t => {
            if(t instanceof PHPType.AssociativeArray) {
                return new PHPType.AssociativeArray(
                    this.resolveAllDocNames(t.memberType, context, doc)
                )
            } else if(t instanceof PHPType.IndexedArray) {
                return new PHPType.IndexedArray(
                    this.resolveAllDocNames(t.memberType, context, doc)
                )
            } else if(t instanceof PHPType.Simple) {
                return new PHPType.Simple(
                    this.resolveDocName(t.typeName, context, doc),
                    t.values,
                    t.polyValue
                )
            } else if(t instanceof PHPType.Function) {
                let cbp = {}
                Object.keys(t.callbackPositions).forEach(k => {
                    cbp[k] = this.resolveAllDocNames(t.callbackPositions[k], context, doc)
                })
                return new PHPType.Function(
                    t.argTypes.map(
                        atype => this.resolveAllDocNames(atype, context, doc)
                    ),
                    this.resolveAllDocNames(t.returnType, context, doc),
                    t.passByReferencePositions,
                    cbp
                )
            } else if(t instanceof PHPType.Mixed) {
                // Do nothing
                return t
            } else {
                throw new Error(`Don't know how to resolve doc names in type ${t}`)
            }
        }).forEach(
            t => n = n.addType(t)
        )
        return n
    }
    /**
     * @param {string} t
     * @param {Context} context
     * @param {Doc} doc
     * @returns {string}
     */
    resolveDocName(t, context, doc) {
        try {
            if(t.match(/^\\/)) {
                return t
            } else if(PHPType.Core.types.hasOwnProperty(t)) {
                return context.resolveName(PHPType.Core.types[t].toString())
            } else {
                return(
                    context.fileContext.resolveAliasName(t) ||
                    context.resolveName(t, "uqn")
                )
            }
        } catch(e) {
            if(e instanceof PHPType.WrongType) {
                this.throw(new PHPError.BadCoreType(e.message), context, doc.loc)
                return context.resolveName(e.realName)
            } else {
                throw e
            }
        }
    }
    /**
     * @type {DocNode[]}
     */
    get structure() {
        if(!this._structure) {
            this._structure = new DocParser(this.lines).top.children
        }
        return this._structure
    }
}
export {DocTypeNode} from "../doc-parser"<|endoftext|>


<commit_before>'use strict';

var url = require('url');
var _ = require('lodash');
var coroutine = require('bluebird').coroutine;
var Chalk = require('chalk');
var Cli = require('structured-cli');
var ConfigFile = require('../lib/config');

module.exports = Cli.createCommand('mv', {
    description: 'Move a named webtask',
    plugins: [
        require('./_plugins/profile'),
    ],
    options: {
        'target-container': {
            description: 'Target container',
            type: 'string',
            dest: 'targetContainer'
        },
        'target-profile': {
            description: 'Target profile',
            type: 'string',
            dest: 'targetProfile'
        },
    },
    params: {
        'source': {
            description: 'Source webtask name',
            type: 'string',
            required: true,
        },
        'target': {
            description: 'Target webtask name',
            type: 'string',
            required: false,
        },
    },
    handler: handleWebtaskMove,
});

function handleWebtaskMove(args) {
    var options = _(args).pick(['targetContainer', 'targetProfile']).omitBy(_.isNull).value();
    var targetName = args.target || args.source;

    return moveWebtask(args.profile, args.source, {
        profile: options.targetProfile,
        container: options.targetContainer,
        name: targetName
    }).then(function() {
        console.log(Chalk.green('Moved webtask: %s'), Chalk.bold(targetName));
    });
}

function moveWebtask(profile, name, target) {
    var sourceWebtask;

    if (equal({
            name: name,
            container: profile.container,
            profile: profile.name
        }, target)) {
        throw Cli.error.invalid('Webtasks are identical. Use a different target name, container or profile.');
    }

    return profile.getWebtask({
            name: name
        })
        .catch(function(err) {
            if (err.statusCode === 404) {
                throw Cli.error.notFound('No such webtask: ' + Chalk.bold(name));
            }
            throw err;
        })
        .then(function(webtask) {
            sourceWebtask = webtask;
            return webtask.inspect({
                decrypt: true,
                fetch_code: true
            });
        })
        .then(function(data) {
            return copy(sourceWebtask, data, target);
        })
        .then(function() {
            return sourceWebtask.remove();
        });
}

function equal(sourceParams, targetParams) {
    return _.isEqual(sourceParams, {
        name: targetParams.name,
        container: targetParams.container || sourceParams.container,
        profile: targetParams.profile || sourceParams.profile
    });
}

function copy(webtask, data, target) {
    if (!data.jtn) {
        throw Cli.error.cancelled('Not a named webtask.');
    }

    var claims = cloneWebtaskData(data);
    claims.jtn = target.name || claims.jtn;
    claims.ten = target.container || claims.ten;

    var pendingCreate;
    if (target.profile) {
        pendingCreate = loadProfile(target.profile)
            .then(function(profile) {
                target.profile = profile;
                claims.ten = target.container || profile.container || claims.ten;
                return target.profile.createRaw(claims);
            });
    } else {
        target.profile = webtask.sandbox;
        pendingCreate = target.profile.createRaw(claims);
    }

    return pendingCreate
        .then(function() {
            target.name = claims.jtn;
            return moveCronJob(webtask.sandbox, data.jtn, target, {
                verify: webtask.token
            });
        })
        .then(function() {
            return copyStorage(webtask, target);
        })
        .catch(function(err) {
            throw Cli.error.cancelled('Failed to create webtask. ' + err);
        });
}

function loadProfile(name) {
    var config = new ConfigFile();

    return config.getProfile(name);
}

function moveCronJob(profile, name, target, options) {
    return coroutine(function*() {
        var job;

        try {
            job = yield profile.getCronJob({
                name: name
            });
        } catch (err) {
            if (err.statusCode === 404) {
                return;
            }
            throw err;
        }

        let webtask = yield profile.getWebtask({
            name: target.name,
            container: target.container
        });

        if (job.token !== _.get(options, 'verify')) {
            console.log(Chalk.yellow('Warning: ') + 'failed to verify the cron job token (no match).');
        }

        yield target.profile.createCronJob({
            name: target.name,
            container: target.container,
            token: webtask.token,
            schedule: job.schedule
        });

        yield profile.removeCronJob({
            name: name
        });
    })();
}

function copyStorage(webtask, target) {
    return coroutine(function*() {
        let targetWebtask = yield target.profile.getWebtask({
            name: target.name,
            container: target.container
        });
        let data = yield exportStorage(webtask);

        // TODO: import data
        console.log('copyStorage: webtask=%j, targetWebtask=%j, data=%j', webtask, targetWebtask, data);
    })();
}

function exportStorage(webtask) {
    var exportCode = `module.exports = function(ctx, done) {
            ctx.storage.get(function(err, data) {
                if (err) { return done(err); } done(null, data || {});
            });
        }`;

    return ephemeralRun(webtask, exportCode)
        .then(function(res) {
            return JSON.parse(_.get(res, 'text', '{}'));
        });
}

function cloneWebtaskData(data) {
    var clone = _(_.clone(data)).omit(['jti', 'iat', 'ca']).value();
    if (url.parse(data.url).protocol === 'webtask:') {
        delete clone.url;
    } else {
        delete clone.code;
    }

    return clone;
}

function ephemeralRun(webtask, code) {
    return coroutine(function*() {
        let data = yield webtask.inspect({
            decrypt: true,
            fetch_code: true
        });
        let claims = cloneWebtaskData(data);

        claims.code = code;
        delete claims.url;

        try {
            yield webtask.sandbox.createRaw(claims);
            return yield webtask.run();
        } finally {
            yield webtask.sandbox.createRaw(cloneWebtaskData(data));
        }
    })();
}<commit_msg>mv: import storage<commit_after>'use strict';

var url = require('url');
var _ = require('lodash');
var coroutine = require('bluebird').coroutine;
var Chalk = require('chalk');
var Cli = require('structured-cli');
var ConfigFile = require('../lib/config');

module.exports = Cli.createCommand('mv', {
    description: 'Move a named webtask',
    plugins: [
        require('./_plugins/profile'),
    ],
    options: {
        'target-container': {
            description: 'Target container',
            type: 'string',
            dest: 'targetContainer'
        },
        'target-profile': {
            description: 'Target profile',
            type: 'string',
            dest: 'targetProfile'
        },
    },
    params: {
        'source': {
            description: 'Source webtask name',
            type: 'string',
            required: true,
        },
        'target': {
            description: 'Target webtask name',
            type: 'string',
            required: false,
        },
    },
    handler: handleWebtaskMove,
});

function handleWebtaskMove(args) {
    var options = _(args).pick(['targetContainer', 'targetProfile']).omitBy(_.isNull).value();
    var targetName = args.target || args.source;

    return moveWebtask(args.profile, args.source, {
        profile: options.targetProfile,
        container: options.targetContainer,
        name: targetName
    }).then(function() {
        console.log(Chalk.green('Moved webtask: %s'), Chalk.bold(targetName));
    });
}

function moveWebtask(profile, name, target) {
    var sourceWebtask;

    if (equal({
            name: name,
            container: profile.container,
            profile: profile.name
        }, target)) {
        throw Cli.error.invalid('Webtasks are identical. Use a different target name, container or profile.');
    }

    return profile.getWebtask({
            name: name
        })
        .catch(function(err) {
            if (err.statusCode === 404) {
                throw Cli.error.notFound('No such webtask: ' + Chalk.bold(name));
            }
            throw err;
        })
        .then(function(webtask) {
            sourceWebtask = webtask;
            return webtask.inspect({
                decrypt: true,
                fetch_code: true
            });
        })
        .then(function(data) {
            return copy(sourceWebtask, data, target);
        })
        .then(function() {
            return sourceWebtask.remove();
        });
}

function equal(sourceParams, targetParams) {
    return _.isEqual(sourceParams, {
        name: targetParams.name,
        container: targetParams.container || sourceParams.container,
        profile: targetParams.profile || sourceParams.profile
    });
}

function copy(webtask, data, target) {
    if (!data.jtn) {
        throw Cli.error.cancelled('Not a named webtask.');
    }

    var claims = cloneWebtaskData(data);
    claims.jtn = target.name || claims.jtn;
    claims.ten = target.container || claims.ten;

    var pendingCreate;
    if (target.profile) {
        pendingCreate = loadProfile(target.profile)
            .then(function(profile) {
                target.profile = profile;
                claims.ten = target.container || profile.container || claims.ten;
                return target.profile.createRaw(claims);
            });
    } else {
        target.profile = webtask.sandbox;
        pendingCreate = target.profile.createRaw(claims);
    }

    return pendingCreate
        .then(function() {
            target.name = claims.jtn;
            return moveCronJob(webtask.sandbox, data.jtn, target, {
                verify: webtask.token
            });
        })
        .then(function() {
            return copyStorage(webtask, target);
        })
        .catch(function(err) {
            throw Cli.error.cancelled('Failed to create webtask. ' + err);
        });
}

function loadProfile(name) {
    var config = new ConfigFile();

    return config.getProfile(name);
}

function moveCronJob(profile, name, target, options) {
    return coroutine(function*() {
        var job;

        try {
            job = yield profile.getCronJob({
                name: name
            });
        } catch (err) {
            if (err.statusCode === 404) {
                return;
            }
            throw err;
        }

        let webtask = yield profile.getWebtask({
            name: target.name,
            container: target.container
        });

        if (job.token !== _.get(options, 'verify')) {
            console.log(Chalk.yellow('Warning: ') + 'failed to verify the cron job token (no match).');
        }

        yield target.profile.createCronJob({
            name: target.name,
            container: target.container,
            token: webtask.token,
            schedule: job.schedule
        });

        yield profile.removeCronJob({
            name: name
        });
    })();
}

function copyStorage(webtask, target) {
    return coroutine(function*() {
        let targetWebtask = yield target.profile.getWebtask({
            name: target.name,
            container: target.container
        });
        let data = yield exportStorage(webtask);
        yield importStorage(targetWebtask, data);
    })();
}

function exportStorage(webtask) {
    var code = `module.exports = function(ctx, done) {
        ctx.storage.get(function(err, data) {
            if (err) { return done(err); } done(null, data || {});
        });
    }`;

    return ephemeralRun(webtask, code)
        .then(function(res) {
            return JSON.parse(_.get(res, 'text', '{}'));
        });
}

function importStorage(webtask, data) {
    var code = `module.exports = function(ctx, done) {
        ctx.storage.get(function(err, data) {
            if (err) { return done(err); }
            if (!ctx.data.import) { return done(); }
            ctx.storage.set(JSON.parse(ctx.data.import), { force: 1 }, function(err) {
                if (err) { return done(err); } done();
            });
        });
    }`;

    return ephemeralRun(webtask, code, data)
        .then(function(res) {
            return JSON.parse(_.get(res, 'text', '{}'));
        });
}

function cloneWebtaskData(data) {
    var clone = _(_.clone(data)).omit(['jti', 'iat', 'ca']).value();
    if (url.parse(data.url).protocol === 'webtask:') {
        delete clone.url;
    } else {
        delete clone.code;
    }

    return clone;
}

function ephemeralRun(webtask, code, query) {
    return coroutine(function*() {
        let data = yield webtask.inspect({
            decrypt: true,
            fetch_code: true
        });
        let claims = cloneWebtaskData(data);

        claims.code = code;
        delete claims.url;

        try {
            yield webtask.sandbox.createRaw(claims);
            return yield webtask.run({
                query: query
            });
        } finally {
            yield webtask.sandbox.createRaw(cloneWebtaskData(data));
        }
    })();
}<|endoftext|>


<commit_before>'use strict';

const url = require('url');
const _ = require('lodash');
const coroutine = require('bluebird').coroutine;
const debug = require('debug')('wt-cli:mv');
const request = require('superagent');
const Sandbox = require('sandboxjs');
const chalk = require('chalk');
const Cli = require('structured-cli');
const ConfigFile = require('../lib/config');

module.exports = Cli.createCommand('mv', {
    description: 'Move a named webtask',
    plugins: [
        require('./_plugins/profile')
    ],
    options: {
        'target-container': {
            description: 'Target container',
            type: 'string',
            dest: 'targetContainer'
        },
        'target-url': {
            description: 'Target url',
            type: 'string',
            dest: 'targetUrl'
        },
        'target-token': {
            description: 'Target token',
            type: 'string',
            dest: 'targetToken'
        },
        'target-profile': {
            description: 'Target profile',
            type: 'string',
            dest: 'targetProfile'
        },
        'no-delete': {
            description: 'Do not delete the source',
            type: 'boolean',
            dest: 'noDelete'
        }
    },
    params: {
        'source-webtask': {
            description: 'Source webtask name',
            type: 'string',
            required: false,
            dest: 'source'
        },
        'target-webtask': {
            description: 'Target webtask name',
            type: 'string',
            required: false,
            dest: 'target'
        },
    },
    handler: handleWebtaskMove,
});

function handleWebtaskMove(args) {
    return coroutine(function*() {
        let options = _(args).pick([
            'targetContainer',
            'targetUrl',
            'targetToken',
            'targetProfile'
        ]).omitBy(_.isNull).value();

        if (!args.source && !args.target && _.isEmpty(options)) {
            throw Cli.error.invalid('wt mv: error: too few arguments; specify a target.');
        }

        let targetList = [];

        if (args.source) {
            targetList.push(args.source);
        }

        if (targetList.length === 0) {
            let webtaskList = yield args.profile.listWebtasks({all: true});
            if (!webtaskList) return;
            for (const webtask of webtaskList) {
                targetList.push(webtask.claims.jtn);
            }
        }

        let targetName = args.target || args.source;

        debug('handleWebtaskMove: targetName=%j, targetList=%j', targetName, targetList);

        for (const name of targetList) {
            let target = {
                profile: options.targetProfile,
                url: options.targetUrl,
                token: options.targetToken,
                container: options.targetContainer,
                name: targetName || name
            };
            yield moveWebtask(args.profile, name, target, {noDelete: args.noDelete});
            console.log(chalk.green('Moved webtask: %s'), chalk.bold(name));
        }

    })();
}

function moveWebtask(profile, name, target, options) {
    debug('moveWebtask: profile=%j, name=%s, target=%j', _.omit(profile, 'token'), name, target);

    let sourceWebtask;
    let sourceParams = {
        name: name,
        container: profile.container,
        profile: profile.name,
        url: profile.url,
        token: profile.url
    };

    if (equal(sourceParams, target)) {
        throw Cli.error.invalid('Webtasks are identical. Use a different target name, container or profile.');
    }

    return profile.getWebtask({name: name})
        .catch(function (err) {
            if (err.statusCode === 404) {
                throw Cli.error.notFound('No such webtask: ' + chalk.bold(name));
            }
            throw err;
        })
        .then(function (webtask) {
            sourceWebtask = webtask;
            return webtask.inspect({
                decrypt: true,
                fetch_code: true
            });
        })
        .then(function (data) {
            return copy(sourceWebtask, data, target, options);
        })
        .then(function () {
            if (options.noDelete) return;
            debug('remove: webtask=%j', sourceWebtask);
            return sourceWebtask.remove();
        });
}

function equal(sourceParams, targetParams) {
    return _.isEqual(sourceParams, {
        name: targetParams.name,
        container: targetParams.container || sourceParams.container,
        profile: targetParams.profile || sourceParams.profile,
        url: targetParams.url || sourceParams.url,
        token: targetParams.token || sourceParams.token
    });
}

function copy(webtask, data, target, options) {
    debug('copy: webtask=%j, data=%j, target=%j', _.omit(webtask, 'token'), data, target);
    if (!data.jtn) throw Cli.error.cancelled('Not a named webtask.');

    return coroutine(function*() {
        target.profile = loadProfile(target.profile, target.url, target.token) || webtask.sandbox;
        target.container = target.container || target.profile.container;
        debug('copy: target.profile=%j', target.profile);

        let claims = cloneWebtaskData(data);
        claims.jtn = target.name || claims.jtn;
        claims.ten = target.container || claims.ten;

        try {
            yield target.profile.createRaw(claims);
            yield moveCronJob(webtask.sandbox, data.jtn, target, _.merge({verify: webtask.token}, options));
            yield copyStorage(webtask, target);
        } catch (err) {
            throw Cli.error.cancelled('Failed to create webtask. ' + err);
        }
    })();
}

function loadProfile(name, url, token) {
    debug('loadProfile: name=%s, url=%j, token=%j', name, url, token);

    let profile;
    let config;

    if (name) {
        config = new ConfigFile();
        profile = config.getProfile(name);
    }

    if (url || token) {
        profile = profile || {};
        profile = Sandbox.init({
            url: url || profile.url,
            container: profile.container || 'default',
            token: token || profile.token
        });
    }

    debug('loadProfile: profile=%j', profile);

    return profile;
}

function moveCronJob(profile, name, target, options) {
    debug('moveCronJob: profile=%j, name=%s, target=%j, options=%j', _.omit(profile, 'token'), name, target, options);

    return coroutine(function*() {
        let job;

        try {
            job = yield profile.getCronJob({name: name});
        } catch (err) {
            if (err.statusCode === 404) return;
            throw err;
        }

        let webtask = yield target.profile.getWebtask({name: target.name, container: target.container});

        if (_.get(options, 'verify') && job.token !== options.verify) {
            console.log(chalk.bold('* Warning: failed to verify the cron job token (no match).'));
        }

        yield target.profile.createCronJob({
            name: target.name,
            container: target.container,
            token: webtask.token,
            schedule: job.schedule,
            state: job.state
        });

        if (!options.noDelete) yield profile.removeCronJob({name: name});
    })();
}

function copyStorage(webtask, target) {
    debug('copyStorage: webtask=%j, target=%j', _.omit(webtask, 'token'), target);

    return coroutine(function*() {
        let body = yield exportStorage(webtask);
        let data = _.get(body, 'data');
        if (!_.isEmpty(data)) {
            yield importStorage(target, {data});
        }
    })();
}

function exportStorage(webtask) {
    debug('exportStorage: webtask=%j', _.omit(webtask, 'token'));

    return coroutine(function*() {
        let url = `${webtask.sandbox.url}/api/webtask/${webtask.claims.ten}/${webtask.claims.jtn}/data`;
        let res = yield request.get(url).set('Authorization', `Bearer ${webtask.sandbox.token}`);

        debug('exportStorage: res.body=%j', res.body);

        return res.body;
    })();
}

function importStorage(webtask, data) {
    debug('importStorage: webtask=%j, data=%j', _.omit(webtask, 'token'), data);

    return coroutine(function*() {
        let url = `${webtask.profile.url}/api/webtask/${webtask.container}/${webtask.name}/data`;
        let res = yield request.put(url)
            .set('Authorization', `Bearer ${webtask.profile.token}`)
            .send(data);

        debug('importStorage: res.body=%j', res.body);

        return res.body;
    })();
}

function cloneWebtaskData(data) {
    let clone = _(_.clone(data)).omit(['jti', 'iat', 'ca', 'webtask_url']).value();
    if (url.parse(data.url).protocol === 'webtask:') {
        delete clone.url;
    } else {
        delete clone.code;
    }

    return clone;
}
<commit_msg>mv: positional parameters name<commit_after>'use strict';

const url = require('url');
const _ = require('lodash');
const coroutine = require('bluebird').coroutine;
const debug = require('debug')('wt-cli:mv');
const request = require('superagent');
const Sandbox = require('sandboxjs');
const chalk = require('chalk');
const Cli = require('structured-cli');
const ConfigFile = require('../lib/config');

module.exports = Cli.createCommand('mv', {
    description: 'Move a named webtask',
    plugins: [
        require('./_plugins/profile')
    ],
    options: {
        'target-container': {
            description: 'Target container',
            type: 'string',
            dest: 'targetContainer'
        },
        'target-url': {
            description: 'Target url',
            type: 'string',
            dest: 'targetUrl'
        },
        'target-token': {
            description: 'Target token',
            type: 'string',
            dest: 'targetToken'
        },
        'target-profile': {
            description: 'Target profile',
            type: 'string',
            dest: 'targetProfile'
        },
        'no-delete': {
            description: 'Do not delete the source',
            type: 'boolean',
            dest: 'noDelete'
        }
    },
    params: {
        'source': {
            description: 'Source webtask name',
            type: 'string',
            required: false
        },
        'target': {
            description: 'Target webtask name',
            type: 'string',
            required: false
        },
    },
    handler: handleWebtaskMove,
});

function handleWebtaskMove(args) {
    return coroutine(function*() {
        let options = _(args).pick([
            'targetContainer',
            'targetUrl',
            'targetToken',
            'targetProfile'
        ]).omitBy(_.isNull).value();

        if (!args.source && !args.target && _.isEmpty(options)) {
            throw Cli.error.invalid('wt mv: error: too few arguments; specify a target.');
        }

        let targetList = [];

        if (args.source) {
            targetList.push(args.source);
        }

        if (targetList.length === 0) {
            let webtaskList = yield args.profile.listWebtasks({all: true});
            if (!webtaskList) return;
            for (const webtask of webtaskList) {
                targetList.push(webtask.claims.jtn);
            }
        }

        let targetName = args.target || args.source;

        debug('handleWebtaskMove: targetName=%j, targetList=%j', targetName, targetList);

        for (const name of targetList) {
            let target = {
                profile: options.targetProfile,
                url: options.targetUrl,
                token: options.targetToken,
                container: options.targetContainer,
                name: targetName || name
            };
            yield moveWebtask(args.profile, name, target, {noDelete: args.noDelete});
            console.log(chalk.green('Moved webtask: %s'), chalk.bold(name));
        }

    })();
}

function moveWebtask(profile, name, target, options) {
    debug('moveWebtask: profile=%j, name=%s, target=%j', _.omit(profile, 'token'), name, target);

    let sourceWebtask;
    let sourceParams = {
        name: name,
        container: profile.container,
        profile: profile.name,
        url: profile.url,
        token: profile.url
    };

    if (equal(sourceParams, target)) {
        throw Cli.error.invalid('Webtasks are identical. Use a different target name, container or profile.');
    }

    return profile.getWebtask({name: name})
        .catch(function (err) {
            if (err.statusCode === 404) {
                throw Cli.error.notFound('No such webtask: ' + chalk.bold(name));
            }
            throw err;
        })
        .then(function (webtask) {
            sourceWebtask = webtask;
            return webtask.inspect({
                decrypt: true,
                fetch_code: true
            });
        })
        .then(function (data) {
            return copy(sourceWebtask, data, target, options);
        })
        .then(function () {
            if (options.noDelete) return;
            debug('remove: webtask=%j', sourceWebtask);
            return sourceWebtask.remove();
        });
}

function equal(sourceParams, targetParams) {
    return _.isEqual(sourceParams, {
        name: targetParams.name,
        container: targetParams.container || sourceParams.container,
        profile: targetParams.profile || sourceParams.profile,
        url: targetParams.url || sourceParams.url,
        token: targetParams.token || sourceParams.token
    });
}

function copy(webtask, data, target, options) {
    debug('copy: webtask=%j, data=%j, target=%j', _.omit(webtask, 'token'), data, target);
    if (!data.jtn) throw Cli.error.cancelled('Not a named webtask.');

    return coroutine(function*() {
        target.profile = loadProfile(target.profile, target.url, target.token) || webtask.sandbox;
        target.container = target.container || target.profile.container;
        debug('copy: target.profile=%j', target.profile);

        let claims = cloneWebtaskData(data);
        claims.jtn = target.name || claims.jtn;
        claims.ten = target.container || claims.ten;

        try {
            yield target.profile.createRaw(claims);
            yield moveCronJob(webtask.sandbox, data.jtn, target, _.merge({verify: webtask.token}, options));
            yield copyStorage(webtask, target);
        } catch (err) {
            throw Cli.error.cancelled('Failed to create webtask. ' + err);
        }
    })();
}

function loadProfile(name, url, token) {
    debug('loadProfile: name=%s, url=%j, token=%j', name, url, token);

    let profile;
    let config;

    if (name) {
        config = new ConfigFile();
        profile = config.getProfile(name);
    }

    if (url || token) {
        profile = profile || {};
        profile = Sandbox.init({
            url: url || profile.url,
            container: profile.container || 'default',
            token: token || profile.token
        });
    }

    debug('loadProfile: profile=%j', profile);

    return profile;
}

function moveCronJob(profile, name, target, options) {
    debug('moveCronJob: profile=%j, name=%s, target=%j, options=%j', _.omit(profile, 'token'), name, target, options);

    return coroutine(function*() {
        let job;

        try {
            job = yield profile.getCronJob({name: name});
        } catch (err) {
            if (err.statusCode === 404) return;
            throw err;
        }

        let webtask = yield target.profile.getWebtask({name: target.name, container: target.container});

        if (_.get(options, 'verify') && job.token !== options.verify) {
            console.log(chalk.bold('* Warning: failed to verify the cron job token (no match).'));
        }

        yield target.profile.createCronJob({
            name: target.name,
            container: target.container,
            token: webtask.token,
            schedule: job.schedule,
            state: job.state
        });

        if (!options.noDelete) yield profile.removeCronJob({name: name});
    })();
}

function copyStorage(webtask, target) {
    debug('copyStorage: webtask=%j, target=%j', _.omit(webtask, 'token'), target);

    return coroutine(function*() {
        let body = yield exportStorage(webtask);
        let data = _.get(body, 'data');
        if (!_.isEmpty(data)) {
            yield importStorage(target, {data});
        }
    })();
}

function exportStorage(webtask) {
    debug('exportStorage: webtask=%j', _.omit(webtask, 'token'));

    return coroutine(function*() {
        let url = `${webtask.sandbox.url}/api/webtask/${webtask.claims.ten}/${webtask.claims.jtn}/data`;
        let res = yield request.get(url).set('Authorization', `Bearer ${webtask.sandbox.token}`);

        debug('exportStorage: res.body=%j', res.body);

        return res.body;
    })();
}

function importStorage(webtask, data) {
    debug('importStorage: webtask=%j, data=%j', _.omit(webtask, 'token'), data);

    return coroutine(function*() {
        let url = `${webtask.profile.url}/api/webtask/${webtask.container}/${webtask.name}/data`;
        let res = yield request.put(url)
            .set('Authorization', `Bearer ${webtask.profile.token}`)
            .send(data);

        debug('importStorage: res.body=%j', res.body);

        return res.body;
    })();
}

function cloneWebtaskData(data) {
    let clone = _(_.clone(data)).omit(['jti', 'iat', 'ca', 'webtask_url']).value();
    if (url.parse(data.url).protocol === 'webtask:') {
        delete clone.url;
    } else {
        delete clone.code;
    }

    return clone;
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

var parser = require('nomnom')()
  .script('nt')
  .colors()

parser
  .nocommand()
  .callback(function() {
    parser.print(parser.getUsage());
  })

parser
  .command('make')
  .help('Make a torrent')
  .callback(function() {
    process.nextTick(make);
  })
  .option('announceList', {
      abbr: 'a'
    , full: 'announce'
    , list: true
    , required: true
    , metavar: 'URL'
    , help: 'Announce URL. At least one is required'
    })
  .option('comment', {
      abbr: 'c'
    , metavar: 'STR'
    , help: 'Add a comment to the metainfo'})
  .option('name', {
      abbr: 'n'
    , metavar: 'STR'
    , help: 'Name of torrent'
    })
  .option('pieceLength', {
      abbr: 'l'
    , full: 'piece-length'
    , metavar: 'INT'
    , help: 'Set piece to 2^n bytes. Default: 256KB'
    })
  .option('private', {
      abbr: 'p'
    , flag: true
    , help: 'Make this a private torrent'
    })
  .option('source', {
      abbr: 's'
    , metavar: 'STR'
    , help: 'Add source to metainfo'
    })
  .option('output', {
      abbr: 'o'
    , metavar: 'PATH'
    , help: 'Where to write the output file'
    })
  .option('maxFiles', {
      abbr: 'f'
    , full: 'max-files'
    , metavar: 'INT'
    , help: 'Max simultaneous files to open'
    })
  .option('dir', {
      abbr: 'd'
    , metavar: 'PATH'
    , default: process.cwd()
    , help: 'Torrent root directory. Default: cwd'
    })
  .option('files', {
      position: 1
    , required: true
    , list: true
    , help: 'List of files to add to torrent'
    })

parser
  .command('edit')
  .help('Read a torrent, edit its metainfo variables, and write it. ' +
        'Can\'t change its files')
  .callback(function() {
    process.nextTick(edit);
  })
  .option('announceList', {
      abbr: 'a'
    , full: 'announce'
    , list: true
    , metavar: 'URL'
    , help: 'Announce URL'
    })
  .option('comment', {
      abbr: 'c'
    , metavar: 'STR'
    , help: 'Add a comment to the metainfo'})
  .option('name', {
      abbr: 'n'
    , metavar: 'STR'
    , help: 'Name of torrent. Can only be changed in multi file mode.'
    })
  .option('private', {
      abbr: 'p'
    , flag: true
    , help: 'Toggle this torrent\'s private mode'
    })
  .option('source', {
      abbr: 's'
    , metavar: 'STR'
    , help: 'Add source to metainfo'
    })
  .option('output', {
      abbr: 'o'
    , metavar: 'PATH'
    , help: 'Where to write the output file. Default: original torrent'
    })
  .option('file', {
      position: 1
    , required: true
    , help: 'Torrent file to edit'
    })

parser
  .command('infohash')
  .help('Return info hash from torrent')
  .callback(function() {
    process.nextTick(infohash);
  })
  .option('file', {
      position: 1
    , required: true
    , help: 'Torrent file'
    })

parser
  .command('hashcheck')
  .help('Hash checks torrent file. If no directory is given, will use cwd')
  .callback(function() {
    process.nextTick(hashcheck);
  })
  .option('maxFiles', {
      abbr: 'f'
    , full: 'max-files'
    , metavar: 'INT'
    , help: 'Max simultaneous files to open'
    })
  .option('dir', {
      abbr: 'd'
    , metavar: 'PATH'
    , default: process.cwd()
    , help: 'Directory to hash check. Default: cwd'
    })
  .option('file', {
      position: 1
    , required: true
    , help: 'Torrent file to hash check'
    })

var options = parser.parse()
  , fs      = require('fs')
  , path    = require('path')
  , colors  = require('colors')
  , ss      = require('streamspeed')
  , nt      = require('..')
  , util    = require('./util')

function make() {
  var announce = util.getAnnounce(options);
  if (!announce) {
    util.logerr('Must provide at least one announce URL');
  }

  var output =
    options.output || options.name || options.files[0];
  if (path.extname(output) !== '.torrent') output += '.torrent';

  var tmpOutput = output + '.tmp';
  var hasher = nt.makeWrite(tmpOutput, announce, options.dir,
                            options.files, options)
    , infohash

  nt.readStream(hasher, function(err, torrent) {
    if (err) util.logerr(err);
    infohash = torrent.infoHash();
  });

  console.time('Time taken');

  hasher.on('error', util.logerr);
  hasher.on('progress', function(percent, speed, avg) {
    util.progress(percent, ss.toHuman(avg, 's'));
  });

  // something so node doesn't exit
  var iid = setInterval(function() {}, 500000);

  hasher.on('end', function() {
    clearInterval(iid);
    fs.rename(tmpOutput, output, function(err) {
      if (err) util.logerr(err);
      console.log('\nFinished writing torrent at', output.bold);
      console.log('Info hash:', infohash.bold);
      console.timeEnd('Time taken');
    });
  });

  // clean up on forced exit
  process.on('SIGINT', function() {
    clearInterval(iid);
    fs.unlink(tmpOutput, function(err) {
      if (err) util.logerr(err);
      process.stdout.write('\n');
      process.exit(1);
    });
  });

  process.on('SIGTSTP', function() {
    hasher.toggle();
  });
}

function edit() {
  options.announce = util.getAnnounce(options);
  var output = options.output || options.file;
  if (path.extname(output) !== '.torrent') output += '.torrent';
  var tmpOutput = output + '.tmp';

  nt.read(options.file, function(err, torrent) {
    if (err) util.logerr(err);

    // edit torrent object
    var metadata = torrent.metadata;

    if (options.announce) {
      metadata.announce = options.announce;
    }

    if (options.announceList) {
      metadata.announceList = options.announceList;
    }

    if (options.comment) {
      metadata.comment = options.comment;
    }

    if (options.name && metadata.info.files.length) {
      metadata.info.name = options.name;
    }

    if (options.private) {
      if (metadata.info.private) {
        delete metadata.info.private;
      } else {
        metadata.info.private = 1;
      }
    }

    if (options.source) {
      metadata.info.source = options.source;
    }

    // write new torrent file
    var ws = torrent.createWriteStream(tmpOutput)

    ws.on('error', util.logerr);
    ws.on('close', function() {
      fs.rename(tmpOutput, output, function(err) {
        if (err) util.logerr(err);

        console.log('File written to', output.bold);
      });
    });

  });
}

function infohash() {
  nt.readFile(options.file, function(err, torrent) {
    if (err) util.logerr(err);

    console.log(torrent.infoHash());
  });
}

function hashcheck() {
  nt.readFile(options.file, function(err, torrent) {
    if (err) util.logerr(err);

    var hasher = torrent.hashCheck(options.dir, options);
    console.time('Time taken');

    hasher.on('error', util.logerr);

    var color, avg = 0;
    hasher.on('progress', function(percent, speed, a) {
      avg = a;
    });

    hasher.on('match', function(i, hash, percent) {
      util.progress(percent, ss.toHuman(avg, 's'), color);
    });

    // change progress bar color to read on match error
    hasher.on('matcherror', function() {
      color = 'red';
    });

    // something so node doesn't exit
    var iid = setInterval(function() {}, 500000);

    hasher.on('end', function() {
      clearInterval(iid);
      console.log('\nFinished hash checking torrent');
      console.timeEnd('Time taken');
    });

    process.on('SIGINT', function() {
      clearInterval(iid);
      process.stdout.write('\n');
      process.exit(1);
    });

    process.on('SIGTSTP', function() {
      hasher.toggle();
    });
  });
}
<commit_msg>adding a number of command line commands<commit_after>#!/usr/bin/env node

var parser = require('nomnom')()
  .script('nt')
  .colors()

parser
  .nocommand()
  .callback(function() {
    parser.print(parser.getUsage());
  })

parser
  .command('make')
  .help('Make a torrent')
  .callback(function() {
    process.nextTick(make);
  })
  .option('announceList', {
      abbr: 'a'
    , full: 'announce'
    , list: true
    , required: true
    , metavar: 'URL'
    , help: 'Announce URL. At least one is required'
    })
  .option('comment', {
      abbr: 'c'
    , metavar: 'STR'
    , help: 'Add a comment to the metainfo'})
  .option('name', {
      abbr: 'n'
    , metavar: 'STR'
    , help: 'Name of torrent'
    })
  .option('pieceLength', {
      abbr: 'l'
    , full: 'piece-length'
    , metavar: 'INT'
    , help: 'Set piece to 2^n bytes. Default: 256KB'
    })
  .option('private', {
      abbr: 'p'
    , flag: true
    , help: 'Make this a private torrent'
    })
  .option('source', {
      abbr: 's'
    , metavar: 'STR'
    , help: 'Add source to metainfo'
    })
  .option('output', {
      abbr: 'o'
    , metavar: 'PATH'
    , help: 'Where to write the output file'
    })
  .option('maxFiles', {
      abbr: 'f'
    , full: 'max-files'
    , metavar: 'INT'
    , help: 'Max simultaneous files to open'
    })
  .option('dir', {
      abbr: 'd'
    , metavar: 'PATH'
    , default: process.cwd()
    , help: 'Torrent root directory. Default: cwd'
    })
  .option('files', {
      position: 1
    , required: true
    , list: true
    , help: 'List of files to add to torrent'
    })

parser
  .command('edit')
  .help('Read a torrent, edit its metainfo variables, and write it. ' +
        'Can\'t change its files')
  .callback(function() {
    process.nextTick(edit);
  })
  .option('announceList', {
      abbr: 'a'
    , full: 'announce'
    , list: true
    , metavar: 'URL'
    , help: 'Announce URL'
    })
  .option('comment', {
      abbr: 'c'
    , metavar: 'STR'
    , help: 'Add a comment to the metainfo'})
  .option('name', {
      abbr: 'n'
    , metavar: 'STR'
    , help: 'Name of torrent. Can only be changed in multi file mode.'
    })
  .option('private', {
      abbr: 'p'
    , flag: true
    , help: 'Toggle this torrent\'s private mode'
    })
  .option('source', {
      abbr: 's'
    , metavar: 'STR'
    , help: 'Add source to metainfo'
    })
  .option('output', {
      abbr: 'o'
    , metavar: 'PATH'
    , help: 'Where to write the output file. Default: original torrent'
    })
  .option('file', {
      position: 1
    , required: true
    , help: 'Torrent file to edit'
    })

parser
  .command('infohash')
  .help('Return info hash from torrent')
  .callback(function() {
    process.nextTick(infohash);
  })
  .option('file', {
      position: 1
    , required: true
    , help: 'Torrent file'
    })

parser
  .command('pieces')
  .help('Return piece hashes from torrent')
  .callback(function() {
    process.nextTick(pieces);
  })
  .option('file', {
      position: 1
    , required: true
    , help: 'Torrent file'
    })

parser
  .command('name')
  .help('Return name from torrent')
  .callback(function() {
    process.nextTick(name);
  })
  .option('file', {
      position: 1
    , required: true
    , help: 'Torrent file'
    })

parser
  .command('announce')
  .help('Return announce url from torrent')
  .callback(function() {
    process.nextTick(announce);
  })
  .option('file', {
      position: 1
    , required: true
    , help: 'Torrent file'
    })

parser
  .command('announcelist')
  .help('Return announce-list urls from torrent')
  .callback(function() {
    process.nextTick(announcelist);
  })
  .option('file', {
      position: 1
    , required: true
    , help: 'Torrent file'
    })

parser
  .command('files')
  .help('Return file paths and lengths from torrent')
  .callback(function() {
    process.nextTick(files);
  })
  .option('file', {
      position: 1
    , required: true
    , help: 'Torrent file'
    })

parser
  .command('urllist')
  .help('Return web seed urls from torrent')
  .callback(function() {
    process.nextTick(urllist);
  })
  .option('file', {
      position: 1
    , required: true
    , help: 'Torrent file'
    })

parser
  .command('hashcheck')
  .help('Hash checks torrent file. If no directory is given, will use cwd')
  .callback(function() {
    process.nextTick(hashcheck);
  })
  .option('maxFiles', {
      abbr: 'f'
    , full: 'max-files'
    , metavar: 'INT'
    , help: 'Max simultaneous files to open'
    })
  .option('dir', {
      abbr: 'd'
    , metavar: 'PATH'
    , default: process.cwd()
    , help: 'Directory to hash check. Default: cwd'
    })
  .option('file', {
      position: 1
    , required: true
    , help: 'Torrent file to hash check'
    })

var options = parser.parse()
  , fs      = require('fs')
  , path    = require('path')
  , colors  = require('colors')
  , ss      = require('streamspeed')
  , nt      = require('..')
  , util    = require('./util')

function make() {
  var announce = util.getAnnounce(options);
  if (!announce) {
    util.logerr('Must provide at least one announce URL');
  }

  var output =
    options.output || options.name || options.files[0];
  if (path.extname(output) !== '.torrent') output += '.torrent';

  var tmpOutput = output + '.tmp';
  var hasher = nt.makeWrite(tmpOutput, announce, options.dir,
                            options.files, options)
    , infohash

  nt.readStream(hasher, function(err, torrent) {
    if (err) util.logerr(err);
    infohash = torrent.infoHash();
  });

  console.time('Time taken');

  hasher.on('error', util.logerr);
  hasher.on('progress', function(percent, speed, avg) {
    util.progress(percent, ss.toHuman(avg, 's'));
  });

  // something so node doesn't exit
  var iid = setInterval(function() {}, 500000);

  hasher.on('end', function() {
    clearInterval(iid);
    fs.rename(tmpOutput, output, function(err) {
      if (err) util.logerr(err);
      console.log('\nFinished writing torrent at', output.bold);
      console.log('Info hash:', infohash.bold);
      console.timeEnd('Time taken');
    });
  });

  // clean up on forced exit
  process.on('SIGINT', function() {
    clearInterval(iid);
    fs.unlink(tmpOutput, function(err) {
      if (err) util.logerr(err);
      process.stdout.write('\n');
      process.exit(1);
    });
  });

  process.on('SIGTSTP', function() {
    hasher.toggle();
  });
}

function edit() {
  options.announce = util.getAnnounce(options);
  var output = options.output || options.file;
  if (path.extname(output) !== '.torrent') output += '.torrent';
  var tmpOutput = output + '.tmp';

  nt.read(options.file, function(err, torrent) {
    if (err) util.logerr(err);

    // edit torrent object
    var metadata = torrent.metadata;

    if (options.announce) {
      metadata.announce = options.announce;
    }

    if (options.announceList) {
      metadata.announceList = options.announceList;
    }

    if (options.comment) {
      metadata.comment = options.comment;
    }

    if (options.name && metadata.info.files.length) {
      metadata.info.name = options.name;
    }

    if (options.private) {
      if (metadata.info.private) {
        delete metadata.info.private;
      } else {
        metadata.info.private = 1;
      }
    }

    if (options.source) {
      metadata.info.source = options.source;
    }

    // write new torrent file
    var ws = torrent.createWriteStream(tmpOutput)

    ws.on('error', util.logerr);
    ws.on('close', function() {
      fs.rename(tmpOutput, output, function(err) {
        if (err) util.logerr(err);

        console.log('File written to', output.bold);
      });
    });

  });
}

function infohash() {
  nt.readFile(options.file, function(err, torrent) {
    if (err) util.logerr(err);

    console.log(torrent.infoHash());
  });
}

function pieces() {
  nt.readFile(options.file, function(err, torrent) {
    if (err) util.logerr(err);
    var piece = 20;
    var len = torrent.metadata.info.pieces.length / piece;
    for (var i = 0; i < len; i++)
      console.log(torrent.metadata.info.pieces.toString('hex', i * piece, (i + 1) * piece));
  });
}

function name() {
  nt.readFile(options.file, function(err, torrent) {
    if (err) util.logerr(err);
    console.log(torrent.metadata.info.name);
  });
}

function announce() {
  nt.readFile(options.file, function(err, torrent) {
    if (err) util.logerr(err);
    console.log(torrent.metadata.announce);
  });
}

function announcelist() {
  nt.readFile(options.file, function(err, torrent) {
    if (err) util.logerr(err);
    if (torrent.metadata.hasOwnProperty('announce-list'))
      console.log(torrent.metadata['announce-list']);
  });
}

function files() {
  nt.readFile(options.file, function(err, torrent) {
    if (err) util.logerr(err);
    var info = torrent.metadata.info;
    for(var i = 0; info.hasOwnProperty('files') &&  i < info.files.length; i++)
      console.log(info.files[i].path, info.files[i].length);
  });
}

function urllist() {
  nt.readFile(options.file, function(err, torrent) {
    if (err) util.logerr(err);
    for(var i = 0; torrent.metadata.hasOwnProperty('url-list') &&  i < torrent.metadata['url-list'].length; i++)
      console.log(torrent.metadata['url-list'][i]);
  });
}

function hashcheck() {
  nt.readFile(options.file, function(err, torrent) {
    if (err) util.logerr(err);

    var hasher = torrent.hashCheck(options.dir, options);
    console.time('Time taken');

    hasher.on('error', util.logerr);

    var color, avg = 0;
    hasher.on('progress', function(percent, speed, a) {
      avg = a;
    });

    hasher.on('match', function(i, hash, percent) {
      util.progress(percent, ss.toHuman(avg, 's'), color);
    });

    // change progress bar color to read on match error
    hasher.on('matcherror', function() {
      color = 'red';
    });

    // something so node doesn't exit
    var iid = setInterval(function() {}, 500000);

    hasher.on('end', function() {
      clearInterval(iid);
      console.log('\nFinished hash checking torrent');
      console.timeEnd('Time taken');
    });

    process.on('SIGINT', function() {
      clearInterval(iid);
      process.stdout.write('\n');
      process.exit(1);
    });

    process.on('SIGTSTP', function() {
      hasher.toggle();
    });
  });
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

var inquirer = require('inquirer');
var program = require('commander');
var Promise = require("bluebird");
var fs = Promise.promisifyAll(require('fs-extra'));;
var chalk = require('chalk');
var figlet = require('figlet');
var iconv = require('iconv-lite');
var ora = require('ora');
var fsp = require('fs-promise');
var exec = require('promise-exec');
var path = require('path');

var Mustache = require('../lib/mustache');
var checkVersion = require('../lib/check-version');
var shelljs = require('shelljs/global');
var rootPath = __dirname.replace(/(tg-cli\/bin)|(tg-cli\/lib)/, 'tg-cli\/');
var nowPath = process.cwd();
//config file
var configFile = path.resolve(__dirname, '../tg_config.json');
var templatePath = path.resolve(__dirname, '../template\/') +'/' ;
//lib

var installConfig = require('../lib/installConfig.js');
var package = require(path.resolve(__dirname, '../package.json'));

//temp
var configTemp = {};
var dt = new Date();
var installGulp = false;
var npmSource = 'npm';

function printHelp() {
	console.log('  Examples:');
  console.log('');
  console.log('    交互式创建项目：')
  console.log('    tg');
  console.log('');
  console.log('    快捷方式创建项目：')
  console.log('    tg -g cf -d a20170406newbie');
  console.log('');
}

program.version(package.version)
  .usage('[options]')
  .option('-g --game <game>', '指定游戏域名前缀，例如"cf"、"dnf"、"lol"等', /^[a-z0-9][a-z0-9\-]*[a-z0-9]+$/)
  .option('-d --dir <dir>', '指定需求目录名，格式为"a+日期+名称"，例如"a20170601test"', /^a\d{8}[a-z]+$/);

program.on('--help', printHelp);
program.parse(process.argv);
if(program.game || program.dir ) {
	if(!program.game) {
		console.log("必须指定游戏域名前缀。\n");
		printHelp();
		process.exit(1);
	}

	if(!program.dir) {
		console.log("必须指定需求目录名称。\n");
		printHelp();
		process.exit(1);
	}
	assignConfig({ gameName: program.game, appName: program.dir}, true);
} else {
	//检查版本
	checkVersion(function () {
		configTemp['time'] = dt.getFullYear() + '-' + (dt.getMonth() + 1) + '-' + dt.getDate();

		console.log(
		  chalk.green(
			  figlet.textSync("TG CLI")
		));
		inquirer.prompt(installConfig.type).then(function(args) {
			assignConfig(args)
			//name
			nameInit();
		});
	});
}

//专题名
function nameInit() {
	inquirer.prompt(installConfig.nameInit).then(function(args) {
		assignConfig(args);
		//作者名
		authorInit()
	})
};
//作者名
function authorInit() {
	inquirer.prompt(installConfig.author).then(function(args) {
		assignConfig(args);
		//游戏名
		if(args.author.toLowerCase() == 'cp') {
			configTemp['designAuthor'] = 'cp';
			//游戏名
			gameName()
		} else {
			//设计师名
			designAuthorInit();
		}

	})
};
//设计师
function designAuthorInit() {
	inquirer.prompt(installConfig.designAuthor).then(function(args) {
		assignConfig(args);
		//游戏名
		gameName()
	})
};
//游戏名
function gameName() {
	inquirer.prompt(installConfig.gameName).then(function(args) {
		assignConfig(args);
		//模块集成
		moduleLoad()
	})
};
//IEG模块集成
function moduleLoad() {
	inquirer.prompt(installConfig.moduleLoad).then(function(args) {
		assignConfig(args, true);
	})
};
//gulp环境
function gulp() {
	inquirer.prompt(installConfig.gulp).then(function(args) {
		assignConfig(args);
	})
};

function assignConfig(args, last) {
	configTemp = Object.assign(configTemp, args);
	if(last) {
		createrFn();
	}
}

function createrFn() {
	//强制小写
	if(!configTemp.gameName == undefined){
		configTemp.gameName = configTemp.gameName.toLocaleLowerCase();
	}
    configTemp.appName = configTemp.appName.toLocaleLowerCase();
	//创建文件夹
	var d = '';
	if(configTemp.appType == '移动专题') {
		var type = 'act';
		var terminal = 'm';
		if(configTemp.gameName && fs.existsSync(templatePath + type + '/' + terminal + configTemp.gameName + '/')) {
			var path = type + '/' + terminal + configTemp.gameName;
			console.log('正在生成' + configTemp.gameName + '的单独模板...');
			//生成模板
			createTemplate(path, type, terminal)
		} else {
			var path = type + '/' + terminal + '/common';
			//console.log('无' + configTemp.gameName + '的单独模板');
			console.log('   正在生成通用模板...');
			//生成模板
			createTemplate(path, type, terminal)
		}
	} else if(configTemp.appType == 'PC专题') {
		var type = 'act';
		var terminal = 'pc';
		var path = '';
		console.log(templatePath + type + '/' + terminal  + '/'+ configTemp.gameName + '/')
		if(configTemp.gameName && fs.existsSync(templatePath + type + '/' + terminal + configTemp.gameName + '/')) {
			var path = type + '/' + terminal + configTemp.gameName;
			console.log('   正在生成' + configTemp.gameName + '的单独模板...');
			//生成模板
			createTemplate(path, type, terminal)
		} else {
			var path = type + '/' + terminal + '/common';
			//console.log('无' + configTemp.gameName + '的单独模板');
			console.log('   正在生成通用模板...');
			//生成模板
			createTemplate(path, type, terminal)
		}
	}else if(configTemp.appType == '视频H5') {
		var type = 'act';
		var terminal = 'h5video';
		var path = '';
		if(configTemp.gameName && fs.existsSync(templatePath + type + '/' + terminal + '/' + configTemp.gameName + '/')) {
			var path = type + '/' + terminal + configTemp.gameName;
			console.log('   正在生成' + configTemp.gameName + '的单独模板...');
			//生成模板
			createTemplate(path, type, terminal)
		} else {
			var path = type + '/' + terminal + '/common';
			//console.log('无' + configTemp.gameName + '的单独模板');
			console.log('   正在生成通用模板...');
			//生成模板
			createTemplate(path, type, terminal)
		}
	}
}
//公用模块
function addMoudle(type, terminal) {
	//jsLib
	var jsLib = fs.readFileSync(templatePath + '/module/' + terminal + '/jslib.htm')
	configTemp['jsLib'] = iconv.decode(jsLib, 'gbk');
	if(configTemp.module == undefined) return
	//milo
	if(configTemp.module.length > 0) {
		var milo = fs.readFileSync(templatePath + '/module/' + terminal + '/milo.htm');
		configTemp['milo'] = iconv.decode(milo, 'gbk');
	}

	//通用登录
	if(configTemp.module.indexOf('IEG通用登录') >= 0) {
		var login = fs.readFileSync(templatePath + '/module/' + terminal + '/login.htm');
		configTemp['login'] = iconv.decode(login, 'gbk');
	}
	//弹窗
	if(configTemp.module.indexOf('浮层') >= 0) {
		var pop = fs.readFileSync(templatePath + '/module/' + terminal + '/pop.htm');
		configTemp['pop'] = iconv.decode(pop, 'gbk');
	}

	//视频
	if(configTemp.module.indexOf('视频') >= 0) {
		var player = fs.readFileSync(templatePath + '/module/common/player.htm')
		configTemp['player'] = iconv.decode(player, 'gbk');
	}
	//选项卡
	if(configTemp.module.indexOf('选项卡') >= 0) {
		var tab = fs.readFileSync(templatePath + '/module/' + terminal + '/tab.htm')
		configTemp['tab'] = iconv.decode(tab, 'gbk');
	}
	//轮播图
	if(configTemp.module.indexOf('轮播图') >= 0) {
		var scroll = fs.readFileSync(templatePath + '/module/' + terminal + '/scroll.htm')
		configTemp['scroll'] = iconv.decode(scroll, 'gbk');
	}
	//抽奖
	if(configTemp.module.indexOf('抽奖') >= 0) {
		var lottery = fs.readFileSync(templatePath + '/module/' + terminal + '/lottery.htm')
		configTemp['lottery'] = iconv.decode(lottery, 'gbk');
	}
}
//SEO
function  seoInfo(){
	 var m = JSON.parse(fs.readFileSync(templatePath + '/gameinfo.js').toString()).list;
    m.forEach(function (value) {
        if(value.domain == configTemp.gameName){
            configTemp['keywords'] =value.keywords;
            configTemp['description'] = value.description;
            configTemp['gamecn'] = value.gameName;
            configTemp['domain'] = value.domain;
            configTemp['imagePath'] =(value.imagePath == '' || typeof value.imagePath == 'undefined' )? value.domain: value.imagePath;
        }
	})

}
//创建模板
function createTemplate(path, type, terminal) {

	var tg_config = JSON.stringify(configTemp);
	//通用模块集成
	if(terminal == 'h5video'){
		addMoudle(type, 'm')
	}else{
		addMoudle(type, terminal)
	}

    //SEO
    seoInfo();
	//作者
	if(configTemp.author != undefined){
		if(configTemp['author'].toLowerCase() == 'cp') {
			configTemp['author'] = 'cp'
			configTemp['team'] = 'cp'
		}else{
			configTemp['team'] = 'Tgideas'
		};
	}
    tg_config =  JSON.stringify(configTemp)
	fs.readFile(templatePath + path + '/index.htm', function(err, buffer) {
		if(err) throw err;
		var str = iconv.decode(buffer, 'gbk');
		var M = Mustache.render(str, configTemp);
		var spinner = ora('   正在生成...').start();
		//复制模板目录
		fsp.copy(templatePath + path + '/', nowPath + '/' + configTemp.appName + '/')
		.then(function(){
			//生成首页
			return fsp.ensureDir(nowPath + '/' + configTemp.appName + '')
		}).then(function(){
			//写入文件
			return fsp.writeFile(nowPath + '/' + configTemp.appName + '/index.htm', iconv.encode(M, 'gbk'));
		}).then(function(){
			//生成配置文件
			return fsp.writeFile(nowPath + '/' + configTemp.appName + '/tg_config.json', tg_config)
		}).then(function(){
			//生成gulp配置&目录主要配置完成
			return 	fsp.copy(templatePath + '/gulp', nowPath + '/' + configTemp.appName + '/')
		}).then(function(){
			spinner.stop();
			console.log('')
			ora(chalk.green('目录生成成功！')).succeed();
			//初始化gulp
			if(installGulp) {
				console.log('')
				var spinnerInstall = ora('安装依赖').start();
				console.log('')
				//安装依赖
				exec(npmSource + ' install', {
					cwd: nowPath + '/' + configTemp.appName + ''
				}).then(function(){
					console.log('')
					spinnerInstall.stop();
 					ora(chalk.green('相关依赖安装成功！')).succeed();
					exec(npmSource + ' install -g gulp', {
						cwd: nowPath + '/' + configTemp.appName + ''
					})
				}).then(function(){
                    console.log('')
                    ora(chalk.green('gulp安装成功！')).succeed();
                    console.log('')
                    console.log(chalk.gray('   您的文件路径：') + nowPath + '/' + configTemp.appName + '/');
                    console.log('')
                    console.log('   使用gulp：');
                    console.log('');
					console.log('      ' + chalk.green('cd  ') + configTemp.appName);
					console.log('      ' + chalk.green('gulp'));
					console.log('');
                    console.log(chalk.gray('  请愉快的coding吧:)'));
				}).catch(function(err) {
		            console.error(err);
		        });
		    //默认不初始化gulp
			}else{
				console.log('');
				console.log(chalk.gray('   您的文件路径：') + nowPath + '/' + configTemp.appName + '\\');
				console.log('');
				console.log(chalk.gray('   接下来，请执行：'));
				console.log('');
				console.log('      ' + chalk.green('cd ') + configTemp.appName);
				console.log('      ' + chalk.green(npmSource + ' install'));
				console.log('      ' + chalk.green(npmSource + ' run dev'));
				console.log('');
				console.log(chalk.gray('   请愉快地coding吧:)'));
			}
		}).catch(function(err) {
            console.error(err);
        });
	})
};
<commit_msg>1.0.5<commit_after>#!/usr/bin/env node

var inquirer = require('inquirer');
var program = require('commander');
var Promise = require("bluebird");
var fs = Promise.promisifyAll(require('fs-extra'));;
var chalk = require('chalk');
var figlet = require('figlet');
var iconv = require('iconv-lite');
var ora = require('ora');
var fsp = require('fs-promise');
var exec = require('promise-exec');
var path = require('path');

var Mustache = require('../lib/mustache');
var checkVersion = require('../lib/check-version');
var shelljs = require('shelljs/global');
var rootPath = __dirname.replace(/(tg-cli\/bin)|(tg-cli\/lib)/, 'tg-cli\/');
var nowPath = process.cwd();
//config file
var configFile = path.resolve(__dirname, '../tg_config.json');
var templatePath = path.resolve(__dirname, '../template\/') +'/' ;
//lib

var installConfig = require('../lib/installConfig.js');
var package = require(path.resolve(__dirname, '../package.json'));

//temp
var configTemp = {};
var dt = new Date();
var installGulp = false;
var npmSource = 'npm';

function printHelp() {
	console.log('  Examples:');
  console.log('');
  console.log('    交互式创建项目：')
  console.log('    tg');
  console.log('');
  console.log('    快捷方式创建项目：')
  console.log('    tg -g cf -d a20170406newbie');
  console.log('');
}

program.version(package.version)
  .usage('[options]')
  .option('-g --game <game>', '指定游戏域名前缀，例如"cf"、"dnf"、"lol"等', /^[a-z0-9][a-z0-9\-]*[a-z0-9]+$/)
  .option('-d --dir <dir>', '指定需求目录名，格式为"a+日期+名称"，例如"a20170601test"', /^a\d{8}[a-z]+$/);

program.on('--help', printHelp);
program.parse(process.argv);
if(program.game || program.dir ) {
	if(!program.game) {
		console.log("必须指定游戏域名前缀。\n");
		printHelp();
		process.exit(1);
	}

	if(!program.dir) {
		console.log("必须指定需求目录名称。\n");
		printHelp();
		process.exit(1);
	}
	assignConfig({ gameName: program.game, appName: program.dir}, true);
} else {
	//检查版本
	checkVersion(function () {
		configTemp['time'] = dt.getFullYear() + '-' + (dt.getMonth() + 1) + '-' + dt.getDate();

		console.log(
		  chalk.green(
			  figlet.textSync("TG CLI")
		));
		inquirer.prompt(installConfig.type).then(function(args) {
			assignConfig(args)
			//name
			nameInit();
		});
	});
}

//专题名
function nameInit() {
	inquirer.prompt(installConfig.nameInit).then(function(args) {
		assignConfig(args);
		//作者名
		authorInit()
	})
};
//作者名
function authorInit() {
	inquirer.prompt(installConfig.author).then(function(args) {
		assignConfig(args);
		//游戏名
		if(args.author.toLowerCase() == 'cp') {
			configTemp['designAuthor'] = 'cp';
			//游戏名
			gameName()
		} else {
			//设计师名
			designAuthorInit();
		}

	})
};
//设计师
function designAuthorInit() {
	inquirer.prompt(installConfig.designAuthor).then(function(args) {
		assignConfig(args);
		//游戏名
		gameName()
	})
};
//游戏名
function gameName() {
	inquirer.prompt(installConfig.gameName).then(function(args) {
		assignConfig(args);
		//模块集成
		moduleLoad()
	})
};
//IEG模块集成
function moduleLoad() {
	inquirer.prompt(installConfig.moduleLoad).then(function(args) {
		assignConfig(args, true);
	})
};
//gulp环境
function gulp() {
	inquirer.prompt(installConfig.gulp).then(function(args) {
		assignConfig(args);
	})
};

function assignConfig(args, last) {
	configTemp = Object.assign(configTemp, args);
	if(last) {
		createrFn();
	}
}

function createrFn() {
	//强制小写
	if(!configTemp.gameName == undefined){
		configTemp.gameName = configTemp.gameName.toLocaleLowerCase();
	}
    configTemp.appName = configTemp.appName.toLocaleLowerCase();
	//创建文件夹
	var d = '';
	if(configTemp.appType == '移动专题') {
		var type = 'act';
		var terminal = 'm';
		if(configTemp.gameName && fs.existsSync(templatePath + type + '/' + terminal + configTemp.gameName + '/')) {
			var path = type + '/' + terminal + configTemp.gameName;
			console.log('正在生成' + configTemp.gameName + '的单独模板...');
			//生成模板
			createTemplate(path, type, terminal)
		} else {
			var path = type + '/' + terminal + '/common';
			//console.log('无' + configTemp.gameName + '的单独模板');
			console.log('   正在生成通用模板...');
			//生成模板
			createTemplate(path, type, terminal)
		}
	} else if(configTemp.appType == 'PC专题') {
		var type = 'act';
		var terminal = 'pc';
		var path = '';
		console.log(templatePath + type + '/' + terminal  + '/'+ configTemp.gameName + '/')
		if(configTemp.gameName && fs.existsSync(templatePath + type + '/' + terminal + configTemp.gameName + '/')) {
			var path = type + '/' + terminal + configTemp.gameName;
			console.log('   正在生成' + configTemp.gameName + '的单独模板...');
			//生成模板
			createTemplate(path, type, terminal)
		} else {
			var path = type + '/' + terminal + '/common';
			//console.log('无' + configTemp.gameName + '的单独模板');
			console.log('   正在生成通用模板...');
			//生成模板
			createTemplate(path, type, terminal)
		}
	}else if(configTemp.appType == '视频H5') {
		var type = 'act';
		var terminal = 'h5video';
		var path = '';
		if(configTemp.gameName && fs.existsSync(templatePath + type + '/' + terminal + '/' + configTemp.gameName + '/')) {
			var path = type + '/' + terminal + configTemp.gameName;
			console.log('   正在生成' + configTemp.gameName + '的单独模板...');
			//生成模板
			createTemplate(path, type, terminal)
		} else {
			var path = type + '/' + terminal + '/common';
			//console.log('无' + configTemp.gameName + '的单独模板');
			console.log('   正在生成通用模板...');
			//生成模板
			createTemplate(path, type, terminal)
		}
	}
}
//公用模块
function addMoudle(type, terminal) {
	//jsLib
	var jsLib = fs.readFileSync(templatePath + '/module/' + terminal + '/jslib.htm')
	configTemp['jsLib'] = iconv.decode(jsLib, 'gbk');
	if(configTemp.module == undefined) return
	//milo
	if(configTemp.module.length > 0) {
		var milo = fs.readFileSync(templatePath + '/module/' + terminal + '/milo.htm');
		configTemp['milo'] = iconv.decode(milo, 'gbk');
	}

	//通用登录
	if(configTemp.module.indexOf('IEG通用登录') >= 0) {
		var login = fs.readFileSync(templatePath + '/module/' + terminal + '/login.htm');
		configTemp['login'] = iconv.decode(login, 'gbk');
	}
	//弹窗
	if(configTemp.module.indexOf('浮层') >= 0) {
		var pop = fs.readFileSync(templatePath + '/module/' + terminal + '/pop.htm');
		configTemp['pop'] = iconv.decode(pop, 'gbk');
	}

	//视频
	if(configTemp.module.indexOf('视频') >= 0) {
		var player = fs.readFileSync(templatePath + '/module/common/player.htm')
		configTemp['player'] = iconv.decode(player, 'gbk');
	}
	//选项卡
	if(configTemp.module.indexOf('选项卡') >= 0) {
		var tab = fs.readFileSync(templatePath + '/module/' + terminal + '/tab.htm')
		configTemp['tab'] = iconv.decode(tab, 'gbk');
	}
	//轮播图
	if(configTemp.module.indexOf('轮播图') >= 0) {
		var scroll = fs.readFileSync(templatePath + '/module/' + terminal + '/scroll.htm')
		configTemp['scroll'] = iconv.decode(scroll, 'gbk');
	}
	//抽奖
	if(configTemp.module.indexOf('抽奖') >= 0) {
		var lottery = fs.readFileSync(templatePath + '/module/' + terminal + '/lottery.htm')
		configTemp['lottery'] = iconv.decode(lottery, 'gbk');
	}
}
//SEO
function  seoInfo(){
	 var m = JSON.parse(fs.readFileSync(templatePath + '/gameinfo.js').toString()).list;
    m.forEach(function (value) {
        if(value.domain == configTemp.gameName){
            configTemp['keywords'] =value.keywords;
            configTemp['description'] = value.description;
            configTemp['gamecn'] = value.gameName;
            configTemp['domain'] = value.domain;
            configTemp['imagePath'] =(value.imagePath == '' || typeof value.imagePath == 'undefined' )? value.domain: value.imagePath;
        }
	})
}
//创建模板
function createTemplate(path, type, terminal) {

	var tg_config = JSON.stringify(configTemp);
	//通用模块集成
	if(terminal == 'h5video'){
		addMoudle(type, 'm')
	}else{
		addMoudle(type, terminal)
	}

    //SEO
    seoInfo();
	//作者
	if(configTemp.author != undefined){
		if(configTemp['author'].toLowerCase() == 'cp') {
			configTemp['author'] = 'cp'
			configTemp['team'] = 'cp'
		}else{
			configTemp['team'] = 'Tgideas'
		};
	}
    tg_config =  JSON.stringify(configTemp)
	fs.readFile(templatePath + path + '/index.htm', function(err, buffer) {
		if(err) throw err;
		var str = iconv.decode(buffer, 'gbk');
		var M = Mustache.render(str, configTemp);
		var spinner = ora('   正在生成...').start();
		//复制模板目录
		fsp.copy(templatePath + path + '/', nowPath + '/' + configTemp.appName + '/')
		.then(function(){
			//生成首页
			return fsp.ensureDir(nowPath + '/' + configTemp.appName + '')
		}).then(function(){
			//写入文件
			return fsp.writeFile(nowPath + '/' + configTemp.appName + '/index.htm', iconv.encode(M, 'gbk'));
		}).then(function(){
			//生成配置文件
			return fsp.writeFile(nowPath + '/' + configTemp.appName + '/tg_config.json', tg_config)
		}).then(function(){
			//生成gulp配置&目录主要配置完成
			return 	fsp.copy(templatePath + '/gulp', nowPath + '/' + configTemp.appName + '/')
		}).then(function(){
			spinner.stop();
			console.log('')
			ora(chalk.green('目录生成成功！')).succeed();
			//初始化gulp
			if(installGulp) {
				console.log('')
				var spinnerInstall = ora('安装依赖').start();
				console.log('')
				//安装依赖
				exec(npmSource + ' install', {
					cwd: nowPath + '/' + configTemp.appName + ''
				}).then(function(){
					console.log('')
					spinnerInstall.stop();
 					ora(chalk.green('相关依赖安装成功！')).succeed();
					exec(npmSource + ' install -g gulp', {
						cwd: nowPath + '/' + configTemp.appName + ''
					})
				}).then(function(){
                    console.log('')
                    ora(chalk.green('gulp安装成功！')).succeed();
                    console.log('')
                    console.log(chalk.gray('   您的文件路径：') + nowPath + '/' + configTemp.appName + '/');
                    console.log('')
                    console.log('   使用gulp：');
                    console.log('');
					console.log('      ' + chalk.green('cd  ') + configTemp.appName);
					console.log('      ' + chalk.green('gulp'));
					console.log('');
                    console.log(chalk.gray('  请愉快的coding吧:)'));
				}).catch(function(err) {
		            console.error(err);
		        });
		    //默认不初始化gulp
			}else{
				console.log('');
				console.log(chalk.gray('   您的文件路径：') + nowPath + '/' + configTemp.appName + '\\');
				console.log('');
				console.log(chalk.gray('   接下来，请执行：'));
				console.log('');
				console.log('      ' + chalk.green('cd ') + configTemp.appName);
				console.log('      ' + chalk.green(npmSource + ' install'));
				console.log('      ' + chalk.green(npmSource + ' run dev'));
				console.log('');
				console.log(chalk.gray('   请愉快地coding吧:)'));
			}
		}).catch(function(err) {
            console.error(err);
        });
	})
};
<|endoftext|>


<commit_before>(function () {
  'use strict';

  angular
    .module('dabou.account')
    .controller('CharacterController', CharacterController);

  CharacterController.$inject = ['characterService', 'authService', 'toastr', '$state', 'globalData', '$timeout', '_'];

  /**
   * @ngdoc controller
   * @name dabou.account.controller:CharacterController
   * @description
   *
   */
  function CharacterController(characterService, authService, toastr, $state, globalData, $timeout, _) {
    var vm = this,
        user = globalData.userData.user,
        _csrf = globalData.tokenData._csrf;

    // PUBLIC PROPERTIES
    vm.characters = [];
    vm.state = $state.current.name;
    vm.loading = true;

    // PUBLIC FUNCTIONS
    vm.createCharacter = createCharacter;
    vm.updateCharacter = updateCharacter;

    // init
    activate();

    // PRIVATE FUNCTIONS
    function activate() {
      getAccount();
    }

    function createCharacter(viewCharacter) {
      var key = vm.characters.indexOf(viewCharacter),
          character = {
            name: viewCharacter.name,
            realm: viewCharacter.realm,
            region: 'us',
            race: viewCharacter.race,
            gender: viewCharacter.gender,
            thumbnail: viewCharacter.thumbnail,
            _csrf: _csrf
          };

      characterService.createCharacter(character)
        .then(function (data) {
          toastr.success(data.success);
          vm.characters.splice(key, 1);
          vm.characters.unshift(viewCharacter);
          vm.characters[0].preferred = true;
          vm.noCharacter = false;
      });
    }

    function getAccount() {
      characterService.getAccount()
        .then(function(data) {
        if (data.status == 404) {
          vm.noBnet = true;
          vm.loading = false;
        } else {
          var characters = data.characters;
          getCharacter(user.id, characters);
          _.each(characters, function (value, key) {
            vm.characters.push(data.characters[key]);
            data.characters[key].preferred = false;
          });
          vm.noBnet = false;
          vm.loading = false;
        }
      });
    }

    function getCharacter(userId, characters) {
      characterService.getCharacter(user.id)
        .then(function(data) {
        if (data.status == 404) {
          vm.noCharacter = true;
        } else {
          vm.noCharacter = false;
          _.each(characters, function (value, key) {
            if (characters[key].name == data.name && characters[key].realm == data.realm ) {
              vm.characters.splice(key, 1);
              vm.characters.unshift(characters[key]);
              characters[key].preferred = true;
            }
          });
        }
      });
    }

    function updateCharacter(viewCharacter) {
      var key = vm.characters.indexOf(viewCharacter),
          character = {
            name: viewCharacter.name,
            realm: viewCharacter.realm,
            region: 'us',
            race: viewCharacter.race,
            gender: viewCharacter.gender,
            thumbnail: viewCharacter.thumbnail,
            _csrf: _csrf
          };

      authService.authenticated().then(function (data) {
        characterService.updateCharacter(data.user.character, character)
          .then(function (data) {
            toastr.success(data.success);
            vm.characters.splice(key, 1);
            vm.characters.unshift(viewCharacter);
            vm.characters[0].preferred = true;
            vm.characters[1].preferred = false;
        });
      });
    }
  }
})();
<commit_msg>Started rewriting character controller.<commit_after>(function () {
  'use strict';

  angular
    .module('dabou.account')
    .controller('CharacterController', CharacterController);

  CharacterController.$inject = ['characterService', 'authService', 'toastr', '$state', 'globalData', '$timeout', '_'];

  /**
   * @ngdoc controller
   * @name dabou.account.controller:CharacterController
   * @description
   *
   */
  function CharacterController(characterService, authService, toastr, $state, globalData, $timeout, _) {
    var vm = this,
        user = globalData.userData.user,
        _csrf = globalData.tokenData._csrf;

    // PUBLIC PROPERTIES
    vm.characters = [];
    vm.state = $state.current.name;
    vm.loading = true;

    // PUBLIC FUNCTIONS
    vm.createCharacter = createCharacter;
    vm.updateCharacter = updateCharacter;

    // init
    activate();

    // PRIVATE FUNCTIONS
    function activate() {
      getAccount();
    }

    function createCharacter(viewCharacter) {
      var key = vm.characters.indexOf(viewCharacter),
          character = {
            name: viewCharacter.name,
            realm: viewCharacter.realm,
            region: 'us',
            race: viewCharacter.race,
            gender: viewCharacter.gender,
            thumbnail: viewCharacter.thumbnail,
            _csrf: _csrf
          };

      characterService.createCharacter(character)
        .then(function (data) {
          toastr.success(data.success);
          vm.characters.splice(key, 1);
          vm.characters.unshift(viewCharacter);
          vm.characters[0].preferred = true;
          vm.noCharacter = false;
      });
    }

    function getAccount() {
      characterService.getAccount()
        .then(function(data) {
        if (data.status == 404) {
          vm.noBnet = true;
          vm.loading = false;
        } else if (data.status == 500) {
          toastr.error('Battle.net isn\'t responding');
        } else {
          var account = data.characters;

          characterService.getCharacter(user.id)
            .then(function(data) {
               if (data.status == 404) {
                vm.noCharacter = true;
              } else {
                vm.noCharacter = false;
              }

              var characters = _.map(account, function (character) {
                if (character.name == data.name && character.realm == data.realm) {
                  return _.extend({}, character, {preferred: true});
                } else {
                  return _.extend({}, character, {preferred: false});
                }
              });

              _.each(characters, function (value, key) {
                  var preferredKey = _.indexOf(characters, (_.find(characters, {preferred: true})));

                  if (key == preferredKey) {
                    vm.characters.splice(key, 1);
                    vm.characters.unshift(characters[key]);
                  } else {
                    vm.characters.push(characters[key]);
                  }
              });

              vm.noBnet = false;
              vm.loading = false;
            });
        }
      });
    }

    function getCharacter(userId, characters) {
      characterService.getCharacter(user.id)
        .then(function(data) {
        if (data.status == 404) {
          vm.noCharacter = true;
        } else {
          vm.noCharacter = false;

          _.each(characters, function (value, key) {
            if (characters[key].name == data.name && characters[key].realm == data.realm ) {
              vm.characters.splice(key, 1);
              vm.characters.unshift(characters[key]);
              characters[key].preferred = true;
            }
          });
        }
      });
    }

    function updateCharacter(viewCharacter) {
      var key = vm.characters.indexOf(viewCharacter),
          character = {
            name: viewCharacter.name,
            realm: viewCharacter.realm,
            region: 'us',
            race: viewCharacter.race,
            gender: viewCharacter.gender,
            thumbnail: viewCharacter.thumbnail,
            _csrf: _csrf
          };

      authService.authenticated().then(function (data) {
        characterService.updateCharacter(data.user.character, character)
          .then(function (data) {
            toastr.success(data.success);
            vm.characters.splice(key, 1);
            vm.characters.unshift(viewCharacter);
            vm.characters[0].preferred = true;
            vm.characters[1].preferred = false;
        });
      });
    }
  }
})();
<|endoftext|>