Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

basic modules sharing system

  • Loading branch information...
commit 3e1da4c53da15fe2bb7932b46008e11d5ece9b6a 1 parent d0198a9
@Shogun147 authored
Showing with 542 additions and 63 deletions.
  1. +534 −53 bin/katana
  2. +6 −8 modules.json
  3. +2 −2 package.json
View
587 bin/katana
@@ -4,74 +4,555 @@ var mod_root = require('path').normalize(__dirname + '/../');
var root = process.cwd() + '/';
var eol = require('os').platform() == 'win32' ? '\r\n' : '\n';
-var version = require(mod_root + 'package.json').version;
+var info = require(mod_root +'package.json');
-var Path = require('path');
-var Fs = require('fs');
-var mkdir = require('mkdirp');
-var copy = require('../lib/utils').copy_dir;
+var Path = require('path');
+var Fs = require('fs');
+var spawn = require('child_process').spawn;
+
+var Async = require('async');
+var request = require('request');
+var mkdir = require('mkdirp');
+var colors = require('colors');
+var copy = require('../lib/utils').copy;
+var rand_str = require('../lib/utils').rand_str;
+var load = require('../lib/utils').load;
+var remove = require('../lib/utils').remove;
+var check = require('../lib/utils').validator;
+
+var zlib = require('zlib');
+var tar = require('tar');
+var gzip = zlib.createUnzip();
+
+var semver = require('semver');
+
+var modules = require(mod_root +'modules.json');
var App = require('commander');
-App.version('0.1.0');
+App.version(info.version);
+
+var Err = function(message) {
+ console.log('\n', message);
+
+ process.exit();
+}
-var create = App.command('create [path]')
-.description('Create default application structure and base configuration')
+App.command('create [path]')
+.description('create katana application')
.action(function(path) {
- path = path ? Path.resolve(root, path) + '/' : root;
+ path = path ? Path.resolve(root, path) +'/' : root;
App.confirm('Create application at: '+ path +' ? [Yes|No]: ', function(ok) {
- if (ok) {
- if (!Fs.existsSync(path)) {
- mkdir.sync(path, 0755);
- }
-
- copy(mod_root + 'template', path, function(error) {
- console.log(error ? error : 'Done!');
-
- var empty_paths = [path + 'application/config/production', path + 'application/models',
- path + 'public/images', path + 'public/scripts', path + 'public/styles',
- path + 'modules', path + 'temp'];
-
- empty_paths.forEach(function(p) {
- if (!Fs.existsSync(p)) {
- mkdir.sync(p, 0777);
- }
- });
-
- var pack = {
- name: 'application-name',
- version: '0.0.1',
- private: true,
- dependencies: {
- katana: version,
- joose: '*'
- }
- };
-
- Fs.writeFileSync(path + 'package.json', JSON.stringify(pack));
-
- process.stdin.destroy();
- });
- } else {
- process.stdin.destroy();
+ if (!ok) { process.exit(); }
+
+ Async.series([
+ function(callback) {
+ mkdir(path, 0755, function(error) {
+ callback(error);
+ });
+ },
+ function(callback) {
+ Fs.readdir(mod_root +'template', function(error, items) {
+ if (error) { return callback(error); }
+
+ var pending = items.length;
+
+ if (!pending) { return callback(); }
+
+ items.forEach(function(item) {
+ copy(mod_root +'template/'+ item, path + item, function(error) {
+ if (error) { console.log(error); }
+
+ if (!--pending) {
+ callback();
+ }
+ });
+ });
+ });
+ },
+ function(callback) {
+ var paths = [
+ path + 'application/config/production',
+ path + 'application/models',
+ path + 'public/images',
+ path + 'public/scripts',
+ path + 'public/styles',
+ path + 'modules',
+ path + 'temp'
+ ];
+
+ Async.forEach(paths, function(path, cb) {
+ mkdir(path, 0777, function(error) {
+ if (error) { console.log('Warning:'.magenta, 'could not create directory:', path); }
+
+ cb();
+ })
+ }, function(error) {
+ callback(error);
+ });
+ },
+ function(callback) {
+ var pack = {
+ name: 'katana-app',
+ version: '0.0.1',
+ private: true,
+ dependencies: {
+ katana: info.version,
+ joose: '*'
+ },
+ katana: {
+ modules: {}
+ }
+ };
+
+ Fs.writeFile(path +'package.json', JSON.stringify(pack, null, 2), function(error) {
+ if (error) { console.log('Warning:'.magenta, ' could not write package.json file!'); }
+
+ callback();
+ });
+ }
+ ], function(error, results) {
+ if (error) { return Err(error); }
+
+ console.log('App created! Run "npm install" under app root to install dependencies.');
+
+ process.exit();
+ })
+ });
+});
+
+App.command('modules')
+.description('list all available modules')
+.action(function() {
+ var pack;
+ var total = 0;
+
+ try {
+ pack = require(root +'package.json').katana;
+ } catch(error) {}
+
+ for (var name in modules) {
+ total++;
+
+ var module = modules[name];
+
+ console.log('\n#'+ total, name, '-', module.description);
+ console.log(' author:', module.author.name, '<'+ module.author.email +'>');
+ console.log(' tags:', module.tags.length ? module.tags.join(' ') : 'no tags, download master branch');
+
+ if (pack !== undefined) {
+ var installed = pack.modules[name] !== undefined;
+ var enabled = pack.modules[name]!==undefined && pack.modules[name].enabled===true;
+
+ console.log(' installed:', installed ? 'true'.green : 'false'.yellow, ' enabled:', enabled ? 'true'.green : 'false'.yellow);
+ }
+ }
+
+ if (!total) {
+ console.log('There are no modules available.');
+ }
+});
+
+App.command('modules-update')
+.description('update modules list and info')
+.action(function() {
+ var url = 'https://raw.github.com/Shogun147/Katana/master/modules.json';
+
+ request(url).on('response', function(response) {
+ if (response.statusCode !== 200 && response.statusCode !== 304) {
+ return Err('Error: url not found or error while downloading it.');
}
+ }).pipe(Fs.createWriteStream(mod_root + 'modules.json')).on('error', function(error) {
+ Err(error);
+ }).on('error', function(error) {
+ Err(error);
+ }).on('end', function() {
+ console.log('Done! Run "katana modules" to view updated modules list.');
+
+ process.exit();
});
});
-App.command('install <module>')
-.description('Install Katana application module')
-.action(function(module) {
- var version = 'last';
+App.command('modules-search <contain>')
+.description('search modules')
+.action(function(contain) {
+ var pack;
+ var total = 0;
+
+ try {
+ pack = require(root +'package.json').katana;
+ } catch(error) {}
+
+ for (var name in modules) {
+ var module = modules[name];
- var has_version = module.match(/^([\-\_a-z]+)\@([\.0-9]+)$/i);
-
- if (has_version) {
- module = has_version[1];
- version = has_version[2];
+ var regexp = new RegExp(contain, 'ig');
+
+ if (regexp.test(module.name) || regexp.test(module.description)) {
+ total++;
+
+ console.log('#'+ total, name, '-', module.description);
+ console.log(' author:', module.author.name, '<'+ module.author.email +'>');
+ console.log(' tags:', module.tags.length ? module.tags.join(' ') : 'no tags, download master branch');
+
+ if (pack !== undefined) {
+ var installed = pack.modules[name] !== undefined;
+ var enabled = pack.modules[name]!==undefined && pack.modules[name].enabled===true;
+
+ console.log(' installed:', installed ? 'true'.green : 'false'.yellow, ' enabled:', enabled ? 'true'.green : 'false'.yellow);
+ }
+ }
}
- console.log('Downloading module '+ module +' '+ version);
+ if (!total) {
+ console.log(' There are no modules that match your search request.');
+ }
});
+// name@version - installs from modules.json registry, optional version
+// name username:name@version - install from github username and repo-name, optional version
+// name url - install as name from url
+
+App.command('modules-install <name> [url]')
+.description('install or reinstall application module')
+.action(function(name, url) {
+ var ProgressBar = require('progress');
+ var Bar;
+
+ var username, version;
+
+ if ((!check(url, 'isUrl') || !url) && name.indexOf('@') !== -1) {
+ name = name.split('@');
+
+ version = name[1];
+ name = name[0];
+
+ if (!semver.valid(version)) {
+ return Err('Error:'.red, ' invalid version!');
+ }
+ }
+
+ if (url && !check(url, 'isUrl')) {
+ if (url.indexOf(':') === -1) {
+ return Err('Error:'.red, ' invalid url or github username:repository!');
+ }
+
+ var repository = url.split(':');
+
+ username = repository[0];
+ repository = repository[1];
+
+ if (!repository) {
+ return Err('Error: invalid repository name!');
+ }
+
+ if (repository.indexOf('@') !== -1) {
+ version = repository.split('@')[1];
+ repository = repository.split('@')[0];
+
+ if (!semver.valid(version)) {
+ return Err('Error: invalid version!');
+ }
+ }
+
+ url = 'https://github.com/'+ username +'/'+ repository +'/tarball/'+ (version ? 'v'+version : 'master');
+ }
+
+ check_installed(name, function(ok, exists) {
+ if(!ok) { return process.exit(); }
+
+ if (!username && !url && !modules[name]) {
+ return Err('Error: Module ['+ name +'] not found!')
+ }
+
+ if (!username && !url) {
+ var module = modules[name];
+
+ if (version && module.tags.indexOf(version) === -1) {
+ return Err('Error: there\'s no '+ version +' version for module ['+ name +']');
+ }
+
+ if (!version && module.tags.length) {
+ version = module.tags.pop();
+ }
+
+ url = module.url ? module.url + (version ? 'v'+version : 'master') : 'https://github.com/'+ module.github.username +'/'+ module.github.repository +'/tarball/'+ (version ? 'v'+version : 'master');
+ }
+
+ console.log(' name: ', name);
+ console.log(' version: ', version);
+ console.log('username: ', username);
+ console.log(' url: ', url);
+
+ mkdir(root + 'temp/modules/'+ name, 0777, function(error) {
+ if (error) { return Err('Error: could not create temporary directory.\n'+ error); }
+
+ request({ url: url })
+ .on('response', function(response) {
+ if (response.statusCode !== 200 && response.statusCode !== 304) {
+ this.abort();
+
+ return Err('Error: module not found! Server responded with status code: '+ response.statusCode);
+ }
+
+ if (response.headers['content-type'] !== 'application/x-gzip') {
+ this.abort();
+
+ return Err('Error: the server should respond with content-type application/x-gzip, '+ response.headers['content-type'] +' given.');
+ }
+
+ var length = parseInt(response.headers['content-length'], 10);
+
+ Bar = new ProgressBar('\n downloading [:bar] :percent :etas', {
+ complete: '=',
+ incomplete: ' ',
+ width: 40,
+ total: length
+ });
+ }).on('data', function(chunk) {
+ if (this._aborted) { return; }
+
+ Bar.tick(chunk.length);
+ }).pipe(zlib.createUnzip()).on('error', function(error) {
+ Err('Error: \n'+ error);
+ }).pipe(tar.Extract({ path: root +'temp/modules/'+ name })).on('error', function(error) {
+ Err('Error: \n'+ error);
+ }).on('end', function() {
+ Fs.readdir(root +'temp/modules/'+ name, function(error, items) {
+ if (error || !items.length) { return Err('Error: '+ (error ? '\n'+error : 'module extracting failed!')); }
+
+ var tmp = items[0];
+
+ Fs.readdir(root +'temp/modules/'+ name +'/'+ tmp, function(error, items) {
+ var pending = items.length;
+
+ Async.series([
+ function(callback) {
+ if (pending === 1) {
+ var item = items[0];
+
+ copy(root +'temp/modules/'+ name +'/'+ tmp +'/'+ item, root +'modules/'+ item, function(error) {
+ callback(error);
+ });
+ } else {
+ Fs.mkdir(root +'modules/'+ name, 0777, function(error) {
+ if (error) { return callback(error); }
+
+ items.forEach(function(item) {
+ copy(root +'temp/modules/'+ name +'/'+ tmp +'/'+ item, root +'modules/'+ name +'/'+ item, function(error) {
+ if (error) { console.log(error); }
+
+ if (!--pending) {
+ remove(root +'temp/modules/'+ name, function(error) {
+ if (error) { console.log('Warning:'.magento, 'could not remove temporary directory.'); }
+
+ callback();
+ });
+ }
+ });
+ });
+ });
+ }
+ },
+ function(callback) {
+ Fs.readdir(root +'modules/'+ name +'/hooks', function(error, hooks) {
+ if (error) { return callback(); }
+
+ var pending = hooks.length;
+
+ if (!pending) { return callback(); }
+
+ hooks.forEach(function(hook) {
+ Fs.chmod(root +'modules/'+ name +'/hooks/'+ hook, '+x', function(error) {
+ if (error) { console.log('Warning:'.magento, 'could not make hook "'+ hook +'" executable.'); }
+
+ if (!--pending) {
+ callback();
+ }
+ });
+ });
+ });
+ },
+ function(callback) {
+ run_hook('install', name, function(error) {
+ if (error) { console.log('Error while running install hook:\n', error); }
+
+ callback();
+ });
+ }
+ ], function(error) {
+ if (error) {
+ return Err(error);
+ }
+
+ var pack = require(root +'package.json');
+
+ var v;
+
+ try {
+ var v = require(root +'modules/'+ name +'/package.json').version;
+ } catch(error) {}
+
+ pack.katana.modules[name] = {
+ version: v || version || null,
+ enabled: false
+ }
+
+ Fs.writeFile(root +'package.json', JSON.stringify(pack, null, 2), function(error) {
+ console.log('\nModule "'+ name +'" now installed! Run "katana modules-enabled '+ name +'" to enable it.');
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+});
+
+function check_installed(name, callback) {
+ Fs.exists(root +'modules/'+ name, function(exists) {
+ if (!exists) {
+ return callback(true, false);
+ }
+
+ App.confirm('Module '+ name +' already installed, did you want to continue and rewrite old one? [Yes|No] ', function(ok) {
+ remove(root +'modules/'+ name, function(error) {
+ if (error) {
+ return Err('Error:'.red, 'could not remove existing module directory!');
+ }
+
+ callback(ok, true);
+ });
+ });
+ });
+}
+
+App.command('modules-enable <name>')
+.description('enable module')
+.action(function(module) {
+ run_hook('enable', module, function(error) {
+ if (error) { return Err(error); }
+
+ var pack = require(root +'package.json');
+
+ pack.katana.modules[module].enabled = true;
+
+ Fs.writeFile(root +'package.json', JSON.stringify(pack, null, 2), function(error) {
+ if (error) { return Err(error); }
+
+ console.log('Done! Module "'+ module +'" now', 'enabled'.green, '!');
+ });
+ });
+});
+
+App.command('modules-disable <name>')
+.description('disable module')
+.action(function(module) {
+ run_hook('disable', module, function(error) {
+ if (error) { return Err(error); }
+
+ var pack = require(root +'package.json');
+
+ pack.katana.modules[module].enabled = false;
+
+ Fs.writeFile(root +'package.json', JSON.stringify(pack, null, 2), function(error) {
+ if (error) { return Err(error); }
+
+ console.log('Done! Module "'+ module +'" now', 'disabled'.yellow, '!');
+ });
+ });
+});
+
+App.command('modules-uninstall <name>')
+.description('remove module')
+.action(function(module) {
+ run_hook('uninstall', module, function(error) {
+ if (error) { return Err(error); }
+
+ remove(root +'modules/'+ module, function(error) {
+ if (error) { return Err(error); }
+
+ var pack = require(root +'package.json');
+
+ delete pack.katana.modules[module];
+
+ Fs.writeFile(root +'package.json', JSON.stringify(pack, null, 2), function(error) {
+ if (error) { return Err(error); }
+
+ console.log('Done! Module "'+ module +'"', 'removed'.red, '!');
+ });
+ })
+ });
+});
+
+var run_hook = function(name, module, callback) {
+ Fs.exists(root +'modules/'+ module +'/hooks/'+ name +'.js', function(exists) {
+ if (!exists) { return callback(); }
+
+ var hook = spawn(root +'modules/'+ module +'/hooks/'+ name +'.js', [], {
+ cwd: root,
+ stdio: 'inherit'
+ });
+
+ hook.on('exit', function(code) {
+ if (code) {
+ return callback('Something goes wrong. Hook exited with code: '+ code);
+ }
+
+ callback();
+ });
+
+ try {
+ ['SIGTERM', 'SIGINT', 'SIGHUP', 'SIGQUIT'].forEach(function(signal) {
+ process.on(signal, function() {
+ if (hook) {
+ hook.kill(signal);
+ }
+
+ process.exit();
+ });
+ });
+ } catch(e) {
+ // callback(e);
+ }
+ });
+}
+
App.parse(process.argv);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
View
14 modules.json
@@ -8,13 +8,11 @@
"url": "https://github.com/Shogun147"
},
- "tags": {
- "0.1.0": {
- "url": "https://github.com/Shogun147/Katana-auth/tarball/v0.1.0",
- "dependencies": {
- "mailer": "0.1.0"
- }
- }
- }
+ "github": {
+ "username": "Shogun147",
+ "repository": "Katana-auth"
+ },
+
+ "tags": ["0.1.0"]
}
}
View
4 package.json
@@ -23,9 +23,9 @@
},
"dependencies": {
- "mkdirp": "*", "async": "*", "joose": "*", "formidable": "*",
+ "mkdirp": "*", "async": "*", "joose": "*", "formidable": "*", "semver": "*",
"ejs": "*", "jinsoku": "*", "crypto": "*", "validator": "*", "underscore": "*", "qs": "*",
- "commander": "*", "node-static": "*", "winston": "*"
+ "commander": "*", "node-static": "*", "winston": "*", "request": "*", "colors": "*", "tar": "*"
},
"devDependencies": {
},
Please sign in to comment.
Something went wrong with that request. Please try again.