TOTVSTEC/cloudbridge-cli

View on GitHub
src/utils/package.js

Summary

Maintainability
C
1 day
Test Coverage
'use strict';

var utils = cb_require('utils/utils'),
    path = require('path'),
    fs = require('fs'),
    shelljs = require('shelljs'),
    Q = require('q'),
    semver = require('semver'),
    request = require('request');

const CLOUDBRIDGE_HOME = path.join(process.env.HOME || process.env.USERPROFILE || process.env.HOMEPATH, '.cloudbridge');

class Package {

    constructor(name, group, version) {
        if (typeof name === 'object') {
            var options = name;

            this.name = options.name;
            this.group = options.group || 'totvstec';
            this.version = options.version || 'master';
        }
        else {
            if (name.indexOf('/') !== -1) {
                let parts = name.split('/');

                group = parts[0];
                name = parts[1];
            }

            this.name = name;
            this.group = group || 'totvstec';
            this.version = version || 'master';
        }

        if (typeof this.version !== 'string')
            this.version = 'master';

        if (Package.data === undefined) {
            Package.loadData();
        }

        this.version = semver.valid(this.version.replace(/[\^~]/g, '')) || 'master';
    }

    latest() {
        var deferred = Q.defer(),
            etag = this.getEtag(),
            url = 'https://api.github.com/repos/' + this.group + '/' + this.name + '/tags',
            _this = this,
            options = {
                url: url,
                json: true,
                headers: {
                    'User-Agent': 'https://github.com/TOTVSTEC/cloudbridge-cli'
                }
            };

        if (etag)
            options.headers['If-None-Match'] = etag;

        request.get(options, function(err, res, data) {
            if (err) {
                deferred.reject(err);
                return;
            }

            _this.saveEtag(res.headers.etag);

            if (res.statusCode === 304) {
                _this.version = _this.getVersion();

                deferred.resolve(_this.version);
            }
            else {
                try {
                    if (data[0] === undefined) {
                        /*
                        console.error('Error: The request to "' + url + '" returned:');
                        console.error(JSON.stringify(data));

                        console.log('x-ratelimit-limit:     ' + res.headers['x-ratelimit-limit']);
                        console.log('x-ratelimit-remaining: ' + res.headers['x-ratelimit-remaining']);
                        console.log('x-ratelimit-reset:     ' + new Date(Number(res.headers['x-ratelimit-reset']) * 1000));
                        */

                        _this.version = _this.readLatestVersionFromGitCli();
                    }
                    else {
                        _this.version = data[0].name.replace(/^[\^~v=\s]+/ig, '');
                    }

                    _this.saveVersion();

                    deferred.resolve(_this.version);
                }
                catch (e) {
                    deferred.reject(e);
                }
            }
        });

        return deferred.promise;
    }

    readLatestVersionFromGitCli() {
        let cmd = 'git ls-remote --tags --refs https://github.com/' + this.group + '/' + this.name + '.git',
            result = shelljs.exec(cmd, { silent: true });

        if (result.code !== 0) {
            throw new Error(result.stderr);
        }

        let output = result.stdout.replace(/^.+refs\/tags\/v?/igm, '').trim(),
            versions = output.split(/\s/igm).sort(semver.rcompare);

        return versions[0];
    }

    getEtag() {
        var data = Package.data,
            id = this.group + '/' + this.name;

        if (data[id]) {
            return data[id].etag || "";
        }

        return "";
    }

    getVersion() {
        var data = Package.data,
            id = this.group + '/' + this.name;

        if (data[id]) {
            return data[id].version || "master";
        }

        return "master";
    }

    saveEtag(etag) {
        if (typeof etag !== 'string')
            return;

        var id = this.group + '/' + this.name;

        Package.data[id] = Package.data[id] || {};

        if (Package.data[id].etag !== etag) {
            Package.data[id].etag = etag;
            Package.saveData();
        }
    }

    saveVersion() {
        var id = this.group + '/' + this.name;

        Package.data[id] = Package.data[id] || {};

        if (Package.data[id].version !== this.version) {
            Package.data[id].version = this.version;
            Package.saveData();
        }
    }

    static loadData() {
        var file = path.join(CLOUDBRIDGE_HOME, 'packages.json');

        if (fs.existsSync(file)) {
            Package.data = JSON.parse(fs.readFileSync(file));
        }
        else {
            Package.data = {};
        }
    }

    static saveData() {
        var file = path.join(CLOUDBRIDGE_HOME, 'packages.json'),
            dataString = JSON.stringify(Package.data, null, 2);

        fs.writeFileSync(file, dataString);
    }

    fetch() {
        var _this = this,
            homeDir = process.env.HOME || process.env.USERPROFILE || process.env.HOMEPATH,
            packageDir = path.join(homeDir, '.cloudbridge', 'packages', this.group, this.name),
            url = 'https://github.com/' + this.group + '/' + this.name + '/archive/';

        this.version = this.version.replace(/[\^~]/g, '');

        var outputDir = path.join(packageDir, this.version);

        if (semver.valid(this.version)) {
            url += 'v';
        }
        else {
            this.version = 'master';
        }

        url += this.version + '.zip';

        _this.src = outputDir;

        if (shelljs.test('-d', outputDir)) {
            return Q.fcall(function() {
                return outputDir;
            });
        }

        shelljs.mkdir('-p', packageDir);

        return utils.fetchArchive(packageDir, url, false)
            .then(function() {
                var contentDir = path.join(packageDir, _this.name + '-' + _this.version);

                shelljs.mv(contentDir, outputDir);

                return outputDir;
            });
    }

    install(targetPath, projectData) {
        return this.execute('install', targetPath, projectData);
    }

    restore(targetPath, projectData) {
        return this.execute('restore', targetPath, projectData);
    }

    update(targetPath, projectData) {
        return this.execute('update', targetPath, projectData);
    }

    remove(targetPath, projectData) {
        return this.execute('remove', targetPath, projectData);
    }

    execute(action, targetPath, projectData) {
        var task = null,
            moduleName = path.join(this.src, action);

        try {
            task = require(moduleName);
        }
        catch (error) {
            return Q.reject(error);
        }

        if (task !== null) {
            if (task instanceof Function) {
                task = new task(cli, targetPath, projectData);

                return task.run();
            }
            else {
                return task.run(cli, targetPath, projectData);
            }
        }
    }

}

module.exports = Package;