aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJohannes Zellner <johannes@nebulon.de>2015-06-27 17:07:42 +0200
committerJohannes Zellner <johannes@nebulon.de>2015-06-27 17:07:42 +0200
commit8c3ae0719e1f7d266ee04d86e7e1c3756745d372 (patch)
treeb5c2c0e9d7d339490c3c8384dcffe264ae67e7de
parent08b2ad7f716b3323ab8c168eb8a00a47fda03d66 (diff)
downloadSurfer-8c3ae0719e1f7d266ee04d86e7e1c3756745d372.tar.gz
Surfer-8c3ae0719e1f7d266ee04d86e7e1c3756745d372.tar.zst
Surfer-8c3ae0719e1f7d266ee04d86e7e1c3756745d372.zip
Support recursive put
-rwxr-xr-xapp.js3
-rw-r--r--cli/actions.js96
-rw-r--r--cli/config.js62
-rwxr-xr-xcli/surfer.js39
-rw-r--r--package.json10
-rw-r--r--src/actions.js34
-rw-r--r--src/files.js27
-rwxr-xr-xsurfer.js25
8 files changed, 224 insertions, 72 deletions
diff --git a/app.js b/app.js
index 196473f..6960764 100755
--- a/app.js
+++ b/app.js
@@ -4,11 +4,12 @@
4 4
5var express = require('express'), 5var express = require('express'),
6 morgan = require('morgan'), 6 morgan = require('morgan'),
7 path = require('path'),
7 compression = require('compression'), 8 compression = require('compression'),
8 bodyParser = require('body-parser'), 9 bodyParser = require('body-parser'),
9 lastMile = require('connect-lastmile'), 10 lastMile = require('connect-lastmile'),
10 multipart = require('./src/multipart'), 11 multipart = require('./src/multipart'),
11 files = require('./src/files.js'); 12 files = require('./src/files.js')(path.resolve(__dirname, 'files'));
12 13
13var app = express(); 14var app = express();
14var router = new express.Router(); 15var router = new express.Router();
diff --git a/cli/actions.js b/cli/actions.js
new file mode 100644
index 0000000..592d809
--- /dev/null
+++ b/cli/actions.js
@@ -0,0 +1,96 @@
1'use strict';
2
3exports.login = login;
4exports.put = put;
5exports.get = get;
6exports.del = del;
7
8var superagent = require('superagent'),
9 config = require('./config'),
10 async = require('async'),
11 fs = require('fs'),
12 path = require('path');
13
14require('colors');
15
16var API = '/api/files/';
17
18function checkConfig() {
19 if (!config.server()) {
20 console.log('You have run "login" first');
21 process.exit(1);
22 }
23}
24
25function collectFiles(filesOrFolders) {
26 var tmp = [];
27
28 filesOrFolders.forEach(function (filePath) {
29 var stat = fs.statSync(filePath);
30
31 if (stat.isFile()) {
32 tmp.push(filePath);
33 } else if (stat.isDirectory()) {
34 var files = fs.readdirSync(filePath).map(function (file) { return path.join(filePath, file); });
35 tmp = tmp.concat(collectFiles(files));
36 } else {
37 console.log('Skipping %s', filePath.cyan);
38 }
39 });
40
41 return tmp;
42}
43
44function login(server) {
45 console.log('Using server', server);
46 config.set('server', server);
47}
48
49function put(filePath, otherFilePaths) {
50 checkConfig();
51
52 var files = collectFiles([ filePath ].concat(otherFilePaths));
53
54 async.eachSeries(files, function (file, callback) {
55 var relativeFilePath = path.resolve(file).slice(process.cwd().length + 1);
56
57 console.log('Uploading file %s', relativeFilePath.cyan);
58
59 superagent.put(config.server() + API + relativeFilePath).attach('file', file).end(callback);
60 }, function (error) {
61 if (error) {
62 console.log('Failed to put file.', error);
63 process.exit(1);
64 }
65
66 console.log('Done');
67 });
68}
69
70function get(filePath) {
71 checkConfig();
72
73 var relativeFilePath = path.resolve(filePath).slice(process.cwd().length + 1);
74 superagent.get(config.server() + API + relativeFilePath).end(function (error, result) {
75 if (error) return console.log('Failed', result ? result.body : error);
76
77 if (result.body && result.body.entries) {
78 console.log('Files:');
79 result.body.entries.forEach(function (entry) {
80 console.log('\t %s', entry);
81 });
82 } else {
83 console.log(result.text);
84 }
85 });
86}
87
88function del(filePath) {
89 checkConfig();
90
91 var relativeFilePath = path.resolve(filePath).slice(process.cwd().length + 1);
92 superagent.del(config.server() + API + relativeFilePath).end(function (error, result) {
93 if (error) return console.log('Failed', result ? result.body : error);
94 console.log('Success', result.body);
95 });
96}
diff --git a/cli/config.js b/cli/config.js
new file mode 100644
index 0000000..a3708b8
--- /dev/null
+++ b/cli/config.js
@@ -0,0 +1,62 @@
1/* jshint node:true */
2
3'use strict';
4
5var fs = require('fs'),
6 path = require('path'),
7 safe = require('safetydance'),
8 _ = require('underscore');
9
10exports = module.exports = {
11 clear: clear,
12 set: set,
13 get: get,
14 unset: unset,
15 has: has,
16
17 // convenience
18 server: function () { return get('server'); }
19};
20
21var HOME = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
22var CONFIG_FILE_PATH = path.join(HOME, '.surfer.json');
23
24var gConfig = (function () {
25 return safe.JSON.parse(safe.fs.readFileSync(CONFIG_FILE_PATH)) || {};
26})();
27
28function save() {
29 fs.writeFileSync(CONFIG_FILE_PATH, JSON.stringify(gConfig, null, 4));
30}
31
32function clear() {
33 safe.fs.unlinkSync(CONFIG_FILE_PATH);
34}
35
36function set(key, value) {
37 if (typeof key === 'object') {
38 _.extend(gConfig, key);
39 } else {
40 safe.set(gConfig, key, value);
41 }
42 save();
43}
44
45function get(key) {
46 return safe.query(gConfig, key);
47}
48
49function unset(key /*, .... */) {
50 for (var i = 0; i < arguments.length; i++) {
51 gConfig = safe.unset(gConfig, arguments[i]);
52 }
53
54 save();
55}
56
57function has(key /*, ... */) {
58 for (var i = 0; i < arguments.length; i++) {
59 if (!(arguments[i] in gConfig)) return false;
60 }
61 return true;
62}
diff --git a/cli/surfer.js b/cli/surfer.js
new file mode 100755
index 0000000..d906d62
--- /dev/null
+++ b/cli/surfer.js
@@ -0,0 +1,39 @@
1#!/usr/bin/env node
2
3'use strict';
4
5var program = require('commander'),
6 actions = require('./actions');
7
8// Allow self signed certs!
9process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
10
11program.version('0.1.0');
12
13program.command('login')
14 .description('Login to server')
15 .action(actions.login);
16
17program.command('put <file> [files...]')
18 .description('Put a file')
19 .action(actions.put);
20
21program.command('get')
22 .description('Get a file or directory')
23 .action(actions.get);
24
25program.command('del')
26 .description('Delete a file')
27 .action(actions.del);
28
29program.parse(process.argv);
30
31if (!process.argv.slice(2).length) {
32 program.outputHelp();
33} else { // https://github.com/tj/commander.js/issues/338
34 var knownCommand = program.commands.some(function (command) { return command._name === process.argv[2]; });
35 if (!knownCommand) {
36 console.error('Unknown command: ' + process.argv[2]);
37 process.exit(1);
38 }
39}
diff --git a/package.json b/package.json
index e5eb25d..5e97c28 100644
--- a/package.json
+++ b/package.json
@@ -10,20 +10,28 @@
10 "file", 10 "file",
11 "server" 11 "server"
12 ], 12 ],
13 "bin": {
14 "surfer": "./cli/surfer.js"
15 },
13 "author": "Johannes Zellner <johannes@nebulon.de>", 16 "author": "Johannes Zellner <johannes@nebulon.de>",
14 "license": "MIT", 17 "license": "MIT",
15 "dependencies": { 18 "dependencies": {
19 "async": "^1.2.1",
16 "body-parser": "^1.13.1", 20 "body-parser": "^1.13.1",
21 "colors": "^1.1.2",
17 "commander": "^2.8.1", 22 "commander": "^2.8.1",
18 "compression": "^1.5.0", 23 "compression": "^1.5.0",
19 "connect-lastmile": "0.0.10", 24 "connect-lastmile": "0.0.10",
20 "connect-timeout": "^1.6.2", 25 "connect-timeout": "^1.6.2",
26 "debug": "^2.2.0",
21 "ejs": "^2.3.1", 27 "ejs": "^2.3.1",
22 "express": "^4.12.4", 28 "express": "^4.12.4",
23 "mkdirp": "^0.5.1", 29 "mkdirp": "^0.5.1",
24 "morgan": "^1.6.0", 30 "morgan": "^1.6.0",
25 "multiparty": "^4.1.2", 31 "multiparty": "^4.1.2",
26 "rimraf": "^2.4.0", 32 "rimraf": "^2.4.0",
27 "superagent": "^1.2.0" 33 "safetydance": "0.0.16",
34 "superagent": "^1.2.0",
35 "underscore": "^1.8.3"
28 } 36 }
29} 37}
diff --git a/src/actions.js b/src/actions.js
deleted file mode 100644
index 33e47aa..0000000
--- a/src/actions.js
+++ /dev/null
@@ -1,34 +0,0 @@
1'use strict';
2
3exports.put = put;
4exports.get = get;
5exports.del = del;
6
7var superagent = require('superagent'),
8 path = require('path');
9
10var server = 'http://localhost:3000/api/files/';
11
12function put(filePath) {
13 var relativeFilePath = path.resolve(filePath).slice(process.cwd().length + 1);
14 superagent.put(server + relativeFilePath).attach('file', filePath).end(function (error, result) {
15 if (error) return console.log('Failed', result ? result.body : error);
16 console.log('Success', result.body);
17 });
18}
19
20function get(filePath) {
21 var relativeFilePath = path.resolve(filePath).slice(process.cwd().length + 1);
22 superagent.get(server + relativeFilePath).end(function (error, result) {
23 if (error) return console.log('Failed', result ? result.body : error);
24 console.log('Success', result.body);
25 });
26}
27
28function del(filePath) {
29 var relativeFilePath = path.resolve(filePath).slice(process.cwd().length + 1);
30 superagent.del(server + relativeFilePath).end(function (error, result) {
31 if (error) return console.log('Failed', result ? result.body : error);
32 console.log('Success', result.body);
33 });
34}
diff --git a/src/files.js b/src/files.js
index 3812d21..48f91a8 100644
--- a/src/files.js
+++ b/src/files.js
@@ -4,17 +4,22 @@ var fs = require('fs'),
4 path = require('path'), 4 path = require('path'),
5 ejs = require('ejs'), 5 ejs = require('ejs'),
6 rimraf = require('rimraf'), 6 rimraf = require('rimraf'),
7 debug = require('debug')('files'),
7 mkdirp = require('mkdirp'), 8 mkdirp = require('mkdirp'),
8 HttpError = require('connect-lastmile').HttpError, 9 HttpError = require('connect-lastmile').HttpError,
9 HttpSuccess = require('connect-lastmile').HttpSuccess; 10 HttpSuccess = require('connect-lastmile').HttpSuccess;
10 11
11exports = module.exports = { 12var gBasePath;
12 get: get, 13
13 put: put, 14exports = module.exports = function (basePath) {
14 del: del 15 gBasePath = basePath;
15};
16 16
17var FILE_BASE = path.resolve(__dirname, '../files'); 17 return {
18 get: get,
19 put: put,
20 del: del
21 };
22};
18 23
19// http://stackoverflow.com/questions/11293857/fastest-way-to-copy-file-in-node-js 24// http://stackoverflow.com/questions/11293857/fastest-way-to-copy-file-in-node-js
20function copyFile(source, target, cb) { 25function copyFile(source, target, cb) {
@@ -54,9 +59,9 @@ function render(view, options) {
54} 59}
55 60
56function getAbsolutePath(filePath) { 61function getAbsolutePath(filePath) {
57 var absoluteFilePath = path.resolve(FILE_BASE, filePath); 62 var absoluteFilePath = path.resolve(gBasePath, filePath);
58 63
59 if (absoluteFilePath.indexOf(FILE_BASE) !== 0) return null; 64 if (absoluteFilePath.indexOf(gBasePath) !== 0) return null;
60 return absoluteFilePath; 65 return absoluteFilePath;
61} 66}
62 67
@@ -68,7 +73,7 @@ function get(req, res, next) {
68 fs.stat(absoluteFilePath, function (error, result) { 73 fs.stat(absoluteFilePath, function (error, result) {
69 if (error) return next(new HttpError(404, error)); 74 if (error) return next(new HttpError(404, error));
70 75
71 console.log('get', absoluteFilePath); 76 debug('get', absoluteFilePath);
72 77
73 if (result.isFile()) return res.sendfile(absoluteFilePath); 78 if (result.isFile()) return res.sendfile(absoluteFilePath);
74 if (result.isDirectory()) return res.status(200).send({ entries: fs.readdirSync(absoluteFilePath) }); 79 if (result.isDirectory()) return res.status(200).send({ entries: fs.readdirSync(absoluteFilePath) });
@@ -88,7 +93,7 @@ function put(req, res, next) {
88 fs.stat(absoluteFilePath, function (error, result) { 93 fs.stat(absoluteFilePath, function (error, result) {
89 if (error && error.code !== 'ENOENT') return next(new HttpError(500, error)); 94 if (error && error.code !== 'ENOENT') return next(new HttpError(500, error));
90 95
91 console.log('put', absoluteFilePath, req.files.file); 96 debug('put', absoluteFilePath, req.files.file);
92 97
93 if (result && result.isDirectory()) return next(new HttpError(409, 'cannot put on directories')); 98 if (result && result.isDirectory()) return next(new HttpError(409, 'cannot put on directories'));
94 if (!result || result.isFile()) { 99 if (!result || result.isFile()) {
@@ -106,7 +111,7 @@ function del(req, res, next) {
106 var filePath = req.params[0]; 111 var filePath = req.params[0];
107 var absoluteFilePath = getAbsolutePath(filePath); 112 var absoluteFilePath = getAbsolutePath(filePath);
108 if (!absoluteFilePath) return next(new HttpError(404, 'Not found')); 113 if (!absoluteFilePath) return next(new HttpError(404, 'Not found'));
109 if (absoluteFilePath.slice(FILE_BASE.length) === '') return next(new HttpError(403, 'Forbidden')); 114 if (absoluteFilePath.slice(gBasePath.length) === '') return next(new HttpError(403, 'Forbidden'));
110 115
111 fs.stat(absoluteFilePath, function (error, result) { 116 fs.stat(absoluteFilePath, function (error, result) {
112 if (error) return next(new HttpError(404, error)); 117 if (error) return next(new HttpError(404, error));
diff --git a/surfer.js b/surfer.js
deleted file mode 100755
index 703fc59..0000000
--- a/surfer.js
+++ /dev/null
@@ -1,25 +0,0 @@
1#!/usr/bin/env node
2
3'use strict';
4
5var program = require('commander'),
6 actions = require('./src/actions');
7
8// Allow self signed certs!
9process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
10
11program.version('0.1.0');
12
13program.command('put')
14 .description('Put a file')
15 .action(actions.put);
16
17program.command('get')
18 .description('Get a file or directory')
19 .action(actions.get);
20
21program.command('del')
22 .description('Delete a file')
23 .action(actions.del);
24
25program.parse(process.argv);