├── test
├── b.txt
├── a.txt
└── deploy.js
├── package.json
├── .gitignore
├── README.md
├── index.js
├── bin
└── deploy
└── upload.js
/test/b.txt:
--------------------------------------------------------------------------------
1 | fdsaaf
--------------------------------------------------------------------------------
/test/a.txt:
--------------------------------------------------------------------------------
1 | 2ddfdsfdsaa
2 |
3 | rerwfdsfs
--------------------------------------------------------------------------------
/test/deploy.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | {
3 | receiver: 'http://127.0.0.1:8999/receiver',
4 | from: '/',
5 | to: '/Users/shouding/Downloads/'
6 | }
7 | ];
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "deploy.js",
3 | "version": "0.0.4",
4 | "description": "...",
5 | "main": "index.js",
6 | "bin": {
7 | "deploy": "bin/deploy"
8 | },
9 | "scripts": {
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "keywords": [
13 | "fis-plus",
14 | "fis",
15 | "jello",
16 | "yogurt"
17 | ],
18 | "author": "fansekey",
19 | "license": "MIT",
20 | "dependencies": {
21 | "debug": ">=2.6.9",
22 | "glob": "4.0.6",
23 | "mstring": "0.1.2",
24 | "rewatch": "0.4.0"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # Compiled binary addons (http://nodejs.org/api/addons.html)
20 | build/Release
21 |
22 | # Dependency directory
23 | # Deployed apps should consider commenting this line out:
24 | # see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
25 | node_modules
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### deploy.js
2 |
3 | ### install
4 |
5 | ```
6 | npm install -g deploy.js
7 | ```
8 |
9 | ### use
10 |
11 | ➜ deploy git:(master) ✗ deploy -h
12 | ```
13 | Usage:
14 | deploy -r
15 |
16 | Options:
17 | -r, --root set root path
18 | -v, --version print the version of deploy
19 | -h, --help display this message
20 |
21 | Examples:
22 | deploy -r /home/user/dir
23 | ```
24 |
25 | - 服务端部署 receiver
26 |
27 | 参见[fex-team/receiver](https://github.com/fex-team/receiver)
28 |
29 | - 想上传部署的目录下放置配置文件 `deploy.js`
30 |
31 | :deploy.js:
32 | ```javascript
33 | module.exports = [
34 | {
35 | receiver: 'http://127.0.0.1:8999/receiver',
36 | from: '/',
37 | to: '/home/work/www'
38 | }
39 | ];
40 | ```
41 |
42 | > 具体配置可以参考FIS 2.x 的`deploy`配置方式
43 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * author: fansekey@gmail.com
3 | * create time: 2014-10-16 14:11:44
4 | */
5 |
6 | var Rewatch = require('Rewatch');
7 | var debug = require('debug')('deploy');
8 | var util = require('util');
9 | var glob = require('glob');
10 | var fs = require('fs');
11 |
12 | function Deploy(files, command, options) {
13 | var me = this;
14 | me.root = options['root'] || process.cwd();
15 | Rewatch.apply(me, arguments);
16 | me.removeAllListeners('change');
17 | me.on('change', function(o) {
18 | if (me.delay) {
19 | setTimeout(function() {
20 | me.execute(o.file);
21 | }, me.delay);
22 | } else {
23 | me.execute(o.file);
24 | }
25 | });
26 | }
27 |
28 | util.inherits(Deploy, Rewatch);
29 |
30 | Deploy.prototype.watch = function(file) {
31 | var me = this;
32 | if (~file.indexOf('*')) {
33 | glob(file, function(err, files) {
34 | files.forEach(function(file) {
35 | me.watch(file);
36 | });
37 | });
38 | } else {
39 | // fs.watch is not reliable
40 | // https://github.com/joyent/node/issues/3172
41 | fs.watchFile(file, {interval: me.interval}, function() {
42 | me.emit('change', {
43 | file: file
44 | });
45 | });
46 | }
47 | };
48 |
49 | Deploy.prototype.execute = function (file) {
50 | var me = this;
51 | var now = new Date();
52 | var spawn = require('child_process').spawn;
53 |
54 | var commands = me._command.split(/\s+/);
55 | if (!me._time || now - me._time > me.interval) {
56 | me._time = now;
57 | if (me._child && me.signal) {
58 | me._child.kill(me.singal);
59 | }
60 |
61 | me._child = spawn(commands[0], commands.slice(1), {
62 | cwd: me.root,
63 | change_file: file
64 | });
65 | me._child.stdout.pipe(process.stdout);
66 | me._child.stderr.pipe(process.stderr);
67 | }
68 | }
69 |
70 |
71 |
72 | module.exports = Deploy;
73 |
--------------------------------------------------------------------------------
/bin/deploy:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | function parseArgv() {
4 | var argv = process.argv;
5 | var opts = {};
6 | for (var i = 0, len = argv.length; i < len; i+=2) {
7 | var cur = argv[i];
8 |
9 | if (cur == '-h' || cur == '--help') {
10 | opts['help'] = true;
11 | }
12 |
13 | if (cur == '-v' || cur == '--version') {
14 | opts['version'] = true;
15 | }
16 |
17 | if (cur == '-r' || cur == '--root') {
18 | var path = require('path');
19 | opts['root'] = path.resolve(argv[i+1]);
20 | }
21 | }
22 | return opts;
23 | }
24 |
25 | function printVersion() {
26 | console.log(require('../package.json').version);
27 | process.exit();
28 | }
29 |
30 | function printHelp() {
31 | var mstring = require('mstring');
32 | console.log(mstring(function () {
33 | /***
34 | Usage:
35 | deploy -r
36 |
37 | Options:
38 | -r, --root set root path
39 | -v, --version print the version of deploy
40 | -h, --help display this message
41 |
42 | Examples:
43 | deploy -r /home/user/dir
44 | ***/
45 | }));
46 | process.exit();
47 | }
48 |
49 | (function main() {
50 | var opts = parseArgv();
51 | if (opts['help']) {
52 | printHelp();
53 | }
54 |
55 | if (opts['version']) {
56 | printVersion();
57 | }
58 |
59 | if (!opts['root']) {
60 | printHelp();
61 | }
62 |
63 | var spawn = require('child_process').spawn;
64 | var god = spawn('node', [__dirname + '/../upload.js'], {
65 | cwd: opts['root']
66 | });
67 | var str = '';
68 | god.stdout.on('data', function (c) {
69 | str += c.toString();
70 | });
71 | god.stdout.on('end', function () {
72 | console.log(str);
73 | var Deploy = require('..');
74 | var w = new Deploy(
75 | ['**'],
76 | 'node ' + __dirname + '/../upload.js',
77 | opts
78 | );
79 | });
80 | god.stderr.pipe(process.stderr);
81 | })();
82 |
--------------------------------------------------------------------------------
/upload.js:
--------------------------------------------------------------------------------
1 | /**
2 | * author: fansekey@gmail.com
3 | */
4 |
5 | 'use strict';
6 |
7 | var path = require('path');
8 | var fs = require('fs');
9 | var glob = require('glob');
10 | var Url = require('url');
11 |
12 | function now(){
13 | var d = new Date(), str;
14 | str = [
15 | d.getHours(),
16 | d.getMinutes(),
17 | d.getSeconds()
18 | ].join(':').replace(/\b\d\b/g, '0$&');
19 | return str;
20 | };
21 |
22 |
23 | function parseUrl(url, opt){
24 | opt = opt || {};
25 | url = Url.parse(url);
26 | var ssl = url.protocol === 'https:';
27 | opt.host = opt.host
28 | || opt.hostname
29 | || ((ssl || url.protocol === 'http:') ? url.hostname : 'localhost');
30 | opt.port = opt.port || (url.port || (ssl ? 443 : 80));
31 | opt.path = opt.path || (url.pathname + (url.search ? url.search : ''));
32 | opt.method = opt.method || 'GET';
33 | opt.agent = opt.agent || false;
34 | return opt;
35 | }
36 |
37 | function map(obj, callback, merge){
38 | var index = 0;
39 | for(var key in obj){
40 | if(obj.hasOwnProperty(key)){
41 | if(merge){
42 | callback[key] = obj[key];
43 | } else if(callback(key, obj[key], index++)) {
44 | break;
45 | }
46 | }
47 | }
48 | }
49 |
50 | function upload(url, opt, data, content, subpath, callback){
51 | if(typeof content === 'string'){
52 | content = new Buffer(content, 'utf8');
53 | } else if(!(content instanceof Buffer)){
54 | throw new Error('unable to upload content [' + (typeof content) + ']');
55 | }
56 | data = data || {};
57 | var endl = '\r\n';
58 | var boundary = '-----np' + Math.random();
59 | var collect = [];
60 | map(data, function(key, value){
61 | collect.push('--' + boundary + endl);
62 | collect.push('Content-Disposition: form-data; name="' + key + '"' + endl);
63 | collect.push(endl);
64 | collect.push(value + endl);
65 | });
66 | collect.push('--' + boundary + endl);
67 | collect.push('Content-Disposition: form-data; name="file"; filename="' + subpath + '"' + endl);
68 | collect.push(endl);
69 | collect.push(content);
70 | collect.push('--' + boundary + '--' + endl);
71 |
72 | var length = 0;
73 | collect.forEach(function(ele){
74 | length += ele.length;
75 | });
76 |
77 | opt = opt || {};
78 | opt.method = opt.method || 'POST';
79 | opt.headers = {
80 | 'Content-Type': 'multipart/form-data; boundary=' + boundary,
81 | 'Content-Length': length
82 | };
83 | opt = parseUrl(url, opt);
84 | var http = opt.protocol === 'https:' ? require('https') : require('http');
85 | var req = http.request(opt, function(res){
86 | var status = res.statusCode;
87 | var body = '';
88 | res
89 | .on('data', function(chunk){
90 | body += chunk;
91 | })
92 | .on('end', function(){
93 | if(status >= 200 && status < 300 || status === 304){
94 | callback(null, body);
95 | } else {
96 | callback(status);
97 | }
98 | })
99 | .on('error', function(err){
100 | callback(err.message || err);
101 | });
102 | });
103 | collect.forEach(function(d){
104 | req.write(d);
105 | if(d instanceof Buffer){
106 | req.write(endl);
107 | }
108 | });
109 | req.end();
110 | }
111 |
112 | (function main() {
113 | var root = process.cwd();
114 |
115 | var config = path.join(root, 'deploy.js');
116 | var opts = require(config);
117 |
118 | for (var i = 0, len = opts.length; i < len; i++) {
119 | var node = opts[i];
120 | var dir = path.join(root, node.from);
121 | glob(dir + '**', function (err, files) {
122 | if (err) {
123 | throw err;
124 | }
125 | for (var k = 0, ll = files.length; k < ll; k++) {
126 | var file = files[k];
127 | var subpath = '/' + file.replace(dir, '');
128 | var stat = fs.statSync(file);
129 | if (!stat.isFile()) {
130 | continue;
131 | }
132 | (function (file, subpath) {
133 | fs.readFile(file, function (err, content) {
134 | if (err) {
135 | throw err;
136 | }
137 | var to = path.join(node.to, subpath);
138 | upload(
139 | node['receiver'],
140 | {},
141 | {
142 | to: to
143 | },
144 | content,
145 | subpath,
146 | function (err, body) {
147 | if (err) {
148 | throw new Error(err);
149 | }
150 | console.log('[', now(), '] upload file ', file, ' > ', to, 'success');
151 | }
152 | );
153 | });
154 | })(file, subpath);
155 | }
156 | });
157 | }
158 | })();
159 |
--------------------------------------------------------------------------------