Guillermo Rauch
9 years ago
commit
f2693e19d7
42 changed files with 1164 additions and 0 deletions
@ -0,0 +1,11 @@ |
|||
{ |
|||
"extends": "standard", |
|||
"parser": "babel-eslint", |
|||
"rules": { |
|||
"yoda": 0, |
|||
"semi": [2, "always"], |
|||
"no-extra-semi": 2, |
|||
"semi-spacing": [2, { "before": false, "after": true }], |
|||
"no-shadow": [2, {"builtinGlobals": true, "hoist": "functions"}] |
|||
} |
|||
} |
@ -0,0 +1 @@ |
|||
node_modules |
@ -0,0 +1,43 @@ |
|||
# now |
|||
|
|||
The fastest way to deploy a Node.JS service. |
|||
|
|||
## How it works |
|||
|
|||
In any directory with a `package.json`, run: |
|||
|
|||
```bash |
|||
$ now |
|||
> https://some-code-nd23n2.now.sh |
|||
``` |
|||
|
|||
every time you run it, you get a new URL (unless nothing's changed). |
|||
|
|||
### Conventions |
|||
|
|||
- Only files that would be included in `npm publish` are synchronized. |
|||
- `package.json` `files`, `.npmignore`, `.gitignore` supported |
|||
- `package.json` must contain a `start` task inside `scripts`. |
|||
If a `now` script is defined, that's used instead. |
|||
- Your HTTP server is expected to run in port `3000`. |
|||
|
|||
## Installing |
|||
|
|||
```bash |
|||
$ npm install -g now |
|||
> Enter your email: rauchg@gmail.com. |
|||
> We sent an email. Click to log in. |
|||
``` |
|||
|
|||
## Features |
|||
|
|||
- No reliance on Git. |
|||
- File de-duping. |
|||
- Respects NPM conventions. |
|||
|
|||
## Options |
|||
|
|||
``` |
|||
-d Debug mode. Lists all files to be uploaded. |
|||
-f Force. Creates a new URL even if nothing has changed. |
|||
``` |
@ -0,0 +1,45 @@ |
|||
#!/usr/bin/env node |
|||
import program from 'commander'; |
|||
import { resolve } from 'path'; |
|||
import { copy } from 'copy-paste'; |
|||
import now from '../lib'; |
|||
import ms from 'ms'; |
|||
|
|||
program |
|||
.option('-d, --debug', 'Debug mode [off]', false) |
|||
.option('-C, --no-clipboard', 'Do not attempt to copy URL to clipboard') |
|||
.parse(process.argv); |
|||
|
|||
let path = program.args[program.args.length - 1]; |
|||
|
|||
if (path) { |
|||
if ('/' !== path[0]) { |
|||
path = resolve(process.cwd(), path); |
|||
} |
|||
} else { |
|||
path = process.cwd(); |
|||
} |
|||
|
|||
const debug = !!program.debug; |
|||
const clipboard = !program.noClipboard; |
|||
const start = Date.now(); |
|||
|
|||
console.log(`> Deploying ${path}`); |
|||
|
|||
now(path, { debug }).then((url) => { |
|||
const elapsed = ms(new Date() - start); |
|||
if (clipboard) { |
|||
copy(url, (err) => { |
|||
console.log(`> ${url} ${!err ? '(copied to clipboard)' : ''} [${elapsed}]`); |
|||
}); |
|||
} else { |
|||
console.log(`> ${url} [${elapsed}]`); |
|||
} |
|||
}, (err) => { |
|||
error(err.message); |
|||
process.exit(1); |
|||
}); |
|||
|
|||
function error (err) { |
|||
console.error(`> \u001b[31mError!\u001b[39m ${err}.`); |
|||
} |
@ -0,0 +1,56 @@ |
|||
#!/usr/bin/env node |
|||
'use strict'; |
|||
|
|||
var _commander = require('commander'); |
|||
|
|||
var _commander2 = _interopRequireDefault(_commander); |
|||
|
|||
var _path = require('path'); |
|||
|
|||
var _copyPaste = require('copy-paste'); |
|||
|
|||
var _lib = require('../lib'); |
|||
|
|||
var _lib2 = _interopRequireDefault(_lib); |
|||
|
|||
var _ms = require('ms'); |
|||
|
|||
var _ms2 = _interopRequireDefault(_ms); |
|||
|
|||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } |
|||
|
|||
_commander2.default.option('-d, --debug', 'Debug mode [off]', false).option('-C, --no-clipboard', 'Do not attempt to copy URL to clipboard').parse(process.argv); |
|||
|
|||
var path = _commander2.default.args[_commander2.default.args.length - 1]; |
|||
|
|||
if (path) { |
|||
if ('/' !== path[0]) { |
|||
path = (0, _path.resolve)(process.cwd(), path); |
|||
} |
|||
} else { |
|||
path = process.cwd(); |
|||
} |
|||
|
|||
var debug = !!_commander2.default.debug; |
|||
var clipboard = !_commander2.default.noClipboard; |
|||
var start = Date.now(); |
|||
|
|||
console.log('> Deploying ' + path); |
|||
|
|||
(0, _lib2.default)(path, { debug: debug }).then(function (url) { |
|||
var elapsed = (0, _ms2.default)(new Date() - start); |
|||
if (clipboard) { |
|||
(0, _copyPaste.copy)(url, function (err) { |
|||
console.log('> ' + url + ' ' + (!err ? '(copied to clipboard)' : '') + ' [' + elapsed + ']'); |
|||
}); |
|||
} else { |
|||
console.log('> ' + url + ' [' + elapsed + ']'); |
|||
} |
|||
}, function (err) { |
|||
error(err.message); |
|||
process.exit(1); |
|||
}); |
|||
|
|||
function error(err) { |
|||
console.error('> \u001b[31mError!\u001b[39m ' + err + '.'); |
|||
} |
@ -0,0 +1,347 @@ |
|||
'use strict'; |
|||
|
|||
Object.defineProperty(exports, "__esModule", { |
|||
value: true |
|||
}); |
|||
|
|||
var _promise = require('babel-runtime/core-js/promise'); |
|||
|
|||
var _promise2 = _interopRequireDefault(_promise); |
|||
|
|||
var _regenerator = require('babel-runtime/regenerator'); |
|||
|
|||
var _regenerator2 = _interopRequireDefault(_regenerator); |
|||
|
|||
var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); |
|||
|
|||
var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); |
|||
|
|||
var _fsPromise = require('fs-promise'); |
|||
|
|||
var _fsPromise2 = _interopRequireDefault(_fsPromise); |
|||
|
|||
var _path = require('path'); |
|||
|
|||
var _arrFlatten = require('arr-flatten'); |
|||
|
|||
var _arrFlatten2 = _interopRequireDefault(_arrFlatten); |
|||
|
|||
var _arrayUnique = require('array-unique'); |
|||
|
|||
var _arrayUnique2 = _interopRequireDefault(_arrayUnique); |
|||
|
|||
var _minimatch = require('minimatch'); |
|||
|
|||
var _minimatch2 = _interopRequireDefault(_minimatch); |
|||
|
|||
var _ignored = require('./ignored'); |
|||
|
|||
var _ignored2 = _interopRequireDefault(_ignored); |
|||
|
|||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } |
|||
|
|||
/** |
|||
* Returns a list of files in the given |
|||
* directory that are subject to be |
|||
* synchronized. |
|||
* |
|||
* @param {String} full path to directory |
|||
* @return {Array} comprehensive list of paths to sync |
|||
*/ |
|||
|
|||
exports.default = function () { |
|||
var ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee(path) { |
|||
var pkgData, pkg, search, found, npmIgnore, gitIgnore, ignored; |
|||
return _regenerator2.default.wrap(function _callee$(_context) { |
|||
while (1) { |
|||
switch (_context.prev = _context.next) { |
|||
case 0: |
|||
_context.next = 2; |
|||
return (0, _fsPromise.readFile)((0, _path.resolve)(path, 'package.json'), 'utf8'); |
|||
|
|||
case 2: |
|||
pkgData = _context.sent; |
|||
pkg = JSON.parse(pkgData); |
|||
search = (pkg.files || ['.']).concat('package.json'); |
|||
|
|||
if (pkg.main) search = search.concat(pkg.main); |
|||
search = search.map(function (file) { |
|||
return asAbsolute(file, path); |
|||
}); |
|||
|
|||
_context.next = 9; |
|||
return explode(search); |
|||
|
|||
case 9: |
|||
_context.t0 = _context.sent; |
|||
found = (0, _arrayUnique2.default)(_context.t0); |
|||
_context.next = 13; |
|||
return maybeRead((0, _path.resolve)(path, '.npmignore')); |
|||
|
|||
case 13: |
|||
npmIgnore = _context.sent; |
|||
|
|||
if (!npmIgnore) { |
|||
_context.next = 18; |
|||
break; |
|||
} |
|||
|
|||
_context.t1 = ''; |
|||
_context.next = 21; |
|||
break; |
|||
|
|||
case 18: |
|||
_context.next = 20; |
|||
return maybeRead((0, _path.resolve)(path, '.gitignore')); |
|||
|
|||
case 20: |
|||
_context.t1 = _context.sent; |
|||
|
|||
case 21: |
|||
gitIgnore = _context.t1; |
|||
ignored = (0, _arrayUnique2.default)(_ignored2.default.concat(gitIgnore.split('\n').filter(invalidFilter)).concat(npmIgnore.split('\n').filter(invalidFilter))).map(function (file) { |
|||
return (0, _path.resolve)(path, file); |
|||
}); |
|||
return _context.abrupt('return', found.filter(ignoredFilter(ignored))); |
|||
|
|||
case 24: |
|||
case 'end': |
|||
return _context.stop(); |
|||
} |
|||
} |
|||
}, _callee, this); |
|||
})); |
|||
return function getFiles(_x) { |
|||
return ref.apply(this, arguments); |
|||
}; |
|||
}(); |
|||
|
|||
/** |
|||
* Returns a filter function that |
|||
* excludes ignored files in the path. |
|||
* |
|||
* @param {String} path |
|||
* @return {Function} filter fn |
|||
*/ |
|||
|
|||
var ignoredFilter = function ignoredFilter(ignored) { |
|||
return function (file) { |
|||
return !ignored.some(function (test) { |
|||
return (0, _minimatch2.default)(file, test); |
|||
}); |
|||
}; |
|||
}; |
|||
|
|||
/** |
|||
* Returns a filter function that |
|||
* excludes invalid rules for .*ignore files |
|||
* |
|||
* @param {String} path |
|||
* @return {Function} filter fn |
|||
*/ |
|||
|
|||
var invalidFilter = function invalidFilter(path) { |
|||
return !( |
|||
/* commments */ |
|||
'#' === path[0] || |
|||
|
|||
/* empty lines or newlines */ |
|||
!path.trim().length); |
|||
}; |
|||
|
|||
/** |
|||
* Transform relative paths into absolutes, |
|||
* and maintains absolutes as such. |
|||
* |
|||
* @param {String} maybe relative path |
|||
* @param {String} parent full path |
|||
*/ |
|||
|
|||
var asAbsolute = function asAbsolute(path, parent) { |
|||
if ('/' === path[0]) return path; |
|||
return (0, _path.resolve)(parent, path); |
|||
}; |
|||
|
|||
/** |
|||
* Explodes directories into a full list of files. |
|||
* Eg: |
|||
* in: ['/a.js', '/b'] |
|||
* out: ['/a.js', '/b/c.js', '/b/d.js'] |
|||
* |
|||
* @param {Array} of {String}s representing paths |
|||
* @return {Array} of {String}s of full paths |
|||
*/ |
|||
|
|||
var explode = function () { |
|||
var ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee5(paths) { |
|||
var _this2 = this; |
|||
|
|||
var many, list; |
|||
return _regenerator2.default.wrap(function _callee5$(_context5) { |
|||
while (1) { |
|||
switch (_context5.prev = _context5.next) { |
|||
case 0: |
|||
many = function () { |
|||
var ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee3(all) { |
|||
return _regenerator2.default.wrap(function _callee3$(_context3) { |
|||
while (1) { |
|||
switch (_context3.prev = _context3.next) { |
|||
case 0: |
|||
_context3.next = 2; |
|||
return _promise2.default.all(all.map(function () { |
|||
var ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee2(file) { |
|||
return _regenerator2.default.wrap(function _callee2$(_context2) { |
|||
while (1) { |
|||
switch (_context2.prev = _context2.next) { |
|||
case 0: |
|||
_context2.next = 2; |
|||
return list(file); |
|||
|
|||
case 2: |
|||
return _context2.abrupt('return', _context2.sent); |
|||
|
|||
case 3: |
|||
case 'end': |
|||
return _context2.stop(); |
|||
} |
|||
} |
|||
}, _callee2, _this2); |
|||
})), |
|||
_this = _this2; |
|||
return function (_x4) { |
|||
return ref.apply(_this, arguments); |
|||
}; |
|||
}())); |
|||
|
|||
case 2: |
|||
return _context3.abrupt('return', _context3.sent); |
|||
|
|||
case 3: |
|||
case 'end': |
|||
return _context3.stop(); |
|||
} |
|||
} |
|||
}, _callee3, _this2); |
|||
})), |
|||
_this = _this2; |
|||
return function many(_x3) { |
|||
return ref.apply(_this, arguments); |
|||
}; |
|||
}(); |
|||
|
|||
list = function () { |
|||
var ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee4(file) { |
|||
var path, stat, all; |
|||
return _regenerator2.default.wrap(function _callee4$(_context4) { |
|||
while (1) { |
|||
switch (_context4.prev = _context4.next) { |
|||
case 0: |
|||
path = file; |
|||
stat = undefined; |
|||
_context4.prev = 2; |
|||
_context4.next = 5; |
|||
return _fsPromise2.default.stat(path); |
|||
|
|||
case 5: |
|||
stat = _context4.sent; |
|||
_context4.next = 14; |
|||
break; |
|||
|
|||
case 8: |
|||
_context4.prev = 8; |
|||
_context4.t0 = _context4['catch'](2); |
|||
|
|||
// in case the file comes from `files` or `main`
|
|||
// and it wasn't specified with `.js` by the user
|
|||
path = file + '.js'; |
|||
_context4.next = 13; |
|||
return _fsPromise2.default.stat(path); |
|||
|
|||
case 13: |
|||
stat = _context4.sent; |
|||
|
|||
case 14: |
|||
if (!stat.isDirectory()) { |
|||
_context4.next = 21; |
|||
break; |
|||
} |
|||
|
|||
_context4.next = 17; |
|||
return _fsPromise2.default.readdir(file); |
|||
|
|||
case 17: |
|||
all = _context4.sent; |
|||
return _context4.abrupt('return', many(all.map(function (subdir) { |
|||
return asAbsolute(subdir, file); |
|||
}))); |
|||
|
|||
case 21: |
|||
return _context4.abrupt('return', path); |
|||
|
|||
case 22: |
|||
case 'end': |
|||
return _context4.stop(); |
|||
} |
|||
} |
|||
}, _callee4, _this2, [[2, 8]]); |
|||
})), |
|||
_this = _this2; |
|||
return function list(_x5) { |
|||
return ref.apply(_this, arguments); |
|||
}; |
|||
}(); |
|||
|
|||
_context5.next = 4; |
|||
return many(paths); |
|||
|
|||
case 4: |
|||
_context5.t0 = _context5.sent; |
|||
return _context5.abrupt('return', (0, _arrFlatten2.default)(_context5.t0)); |
|||
|
|||
case 6: |
|||
case 'end': |
|||
return _context5.stop(); |
|||
} |
|||
} |
|||
}, _callee5, this); |
|||
})); |
|||
return function explode(_x2) { |
|||
return ref.apply(this, arguments); |
|||
}; |
|||
}(); |
|||
|
|||
/** |
|||
* Returns the contents of a file if it exists. |
|||
* |
|||
* @return {String} results or `''` |
|||
*/ |
|||
|
|||
var maybeRead = function () { |
|||
var ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee6(path) { |
|||
return _regenerator2.default.wrap(function _callee6$(_context6) { |
|||
while (1) { |
|||
switch (_context6.prev = _context6.next) { |
|||
case 0: |
|||
_context6.prev = 0; |
|||
_context6.next = 3; |
|||
return _fsPromise2.default.readFile(path, 'utf8'); |
|||
|
|||
case 3: |
|||
return _context6.abrupt('return', _context6.sent); |
|||
|
|||
case 6: |
|||
_context6.prev = 6; |
|||
_context6.t0 = _context6['catch'](0); |
|||
return _context6.abrupt('return', ''); |
|||
|
|||
case 9: |
|||
case 'end': |
|||
return _context6.stop(); |
|||
} |
|||
} |
|||
}, _callee6, this, [[0, 6]]); |
|||
})); |
|||
return function maybeRead(_x6) { |
|||
return ref.apply(this, arguments); |
|||
}; |
|||
}(); |
@ -0,0 +1,100 @@ |
|||
'use strict'; |
|||
|
|||
Object.defineProperty(exports, "__esModule", { |
|||
value: true |
|||
}); |
|||
|
|||
var _map = require('babel-runtime/core-js/map'); |
|||
|
|||
var _map2 = _interopRequireDefault(_map); |
|||
|
|||
var _regenerator = require('babel-runtime/regenerator'); |
|||
|
|||
var _regenerator2 = _interopRequireDefault(_regenerator); |
|||
|
|||
var _promise = require('babel-runtime/core-js/promise'); |
|||
|
|||
var _promise2 = _interopRequireDefault(_promise); |
|||
|
|||
var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); |
|||
|
|||
var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); |
|||
|
|||
var _fsPromise = require('fs-promise'); |
|||
|
|||
var _fsPromise2 = _interopRequireDefault(_fsPromise); |
|||
|
|||
var _crypto = require('crypto'); |
|||
|
|||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } |
|||
|
|||
/** |
|||
* Computes hashes for the contents of each file given. |
|||
* |
|||
* @param {Array} of {String} full paths |
|||
* @return {Map} |
|||
*/ |
|||
|
|||
exports.default = function () { |
|||
var ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee2(files) { |
|||
var _this2 = this; |
|||
|
|||
var entries; |
|||
return _regenerator2.default.wrap(function _callee2$(_context2) { |
|||
while (1) { |
|||
switch (_context2.prev = _context2.next) { |
|||
case 0: |
|||
_context2.next = 2; |
|||
return _promise2.default.all(files.map(function () { |
|||
var ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee(file) { |
|||
var data; |
|||
return _regenerator2.default.wrap(function _callee$(_context) { |
|||
while (1) { |
|||
switch (_context.prev = _context.next) { |
|||
case 0: |
|||
_context.next = 2; |
|||
return _fsPromise2.default.readFile(file); |
|||
|
|||
case 2: |
|||
data = _context.sent; |
|||
return _context.abrupt('return', [file, hash(data)]); |
|||
|
|||
case 4: |
|||
case 'end': |
|||
return _context.stop(); |
|||
} |
|||
} |
|||
}, _callee, _this2); |
|||
})), |
|||
_this = _this2; |
|||
return function (_x2) { |
|||
return ref.apply(_this, arguments); |
|||
}; |
|||
}())); |
|||
|
|||
case 2: |
|||
entries = _context2.sent; |
|||
return _context2.abrupt('return', new _map2.default(entries)); |
|||
|
|||
case 4: |
|||
case 'end': |
|||
return _context2.stop(); |
|||
} |
|||
} |
|||
}, _callee2, this); |
|||
})); |
|||
return function hashes(_x) { |
|||
return ref.apply(this, arguments); |
|||
}; |
|||
}(); |
|||
|
|||
/** |
|||
* Computes a hash for the given buf. |
|||
* |
|||
* @param {Buffer} file data |
|||
* @return {String} hex digest |
|||
*/ |
|||
|
|||
function hash(buf) { |
|||
return (0, _crypto.createHash)('sha1').update(buf).digest('hex'); |
|||
} |
@ -0,0 +1,6 @@ |
|||
'use strict'; |
|||
|
|||
Object.defineProperty(exports, "__esModule", { |
|||
value: true |
|||
}); |
|||
exports.default = ['._*', '.hg', '.git', '.svn', '.npmrc', '.*.swp', '.DS_Store', '.wafpickle-*', '.lock-wscript', 'npm-debug.log', 'config.gypi', 'node_modules', 'CVS', 'README', 'README.*', 'CHANGELOG', 'History.md', 'LICENSE', 'Readme', 'Readme.*', 'test', 'tests']; |
@ -0,0 +1,88 @@ |
|||
'use strict'; |
|||
|
|||
Object.defineProperty(exports, "__esModule", { |
|||
value: true |
|||
}); |
|||
|
|||
var _regenerator = require('babel-runtime/regenerator'); |
|||
|
|||
var _regenerator2 = _interopRequireDefault(_regenerator); |
|||
|
|||
var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); |
|||
|
|||
var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); |
|||
|
|||
var _fsPromise = require('fs-promise'); |
|||
|
|||
var _fsPromise2 = _interopRequireDefault(_fsPromise); |
|||
|
|||
var _getFiles = require('./get-files'); |
|||
|
|||
var _getFiles2 = _interopRequireDefault(_getFiles); |
|||
|
|||
var _hash = require('./hash'); |
|||
|
|||
var _hash2 = _interopRequireDefault(_hash); |
|||
|
|||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } |
|||
|
|||
exports.default = function () { |
|||
var ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee(path, _ref) { |
|||
var debug = _ref.debug; |
|||
var files, hashes; |
|||
return _regenerator2.default.wrap(function _callee$(_context) { |
|||
while (1) { |
|||
switch (_context.prev = _context.next) { |
|||
case 0: |
|||
_context.prev = 0; |
|||
_context.next = 3; |
|||
return _fsPromise2.default.stat(path); |
|||
|
|||
case 3: |
|||
_context.next = 8; |
|||
break; |
|||
|
|||
case 5: |
|||
_context.prev = 5; |
|||
_context.t0 = _context['catch'](0); |
|||
throw new Error('Could not read directory ' + path + '.'); |
|||
|
|||
case 8: |
|||
|
|||
if (debug) console.time('> [debug] Getting files'); |
|||
_context.next = 11; |
|||
return (0, _getFiles2.default)(path); |
|||
|
|||
case 11: |
|||
files = _context.sent; |
|||
|
|||
if (debug) console.timeEnd('> [debug] Getting files'); |
|||
|
|||
if (debug) console.time('> [debug] Computing hashes'); |
|||
_context.next = 16; |
|||
return (0, _hash2.default)(files); |
|||
|
|||
case 16: |
|||
hashes = _context.sent; |
|||
|
|||
if (debug) console.timeEnd('> [debug] Computing hashes'); |
|||
|
|||
if (debug) { |
|||
hashes.forEach(function (val, key) { |
|||
console.log('> [debug] Found "' + key + '" [' + val + ']'); |
|||
}); |
|||
} |
|||
|
|||
return _context.abrupt('return', 'https://test.now.run'); |
|||
|
|||
case 20: |
|||
case 'end': |
|||
return _context.stop(); |
|||
} |
|||
} |
|||
}, _callee, this, [[0, 5]]); |
|||
})); |
|||
return function now(_x, _x2) { |
|||
return ref.apply(this, arguments); |
|||
}; |
|||
}(); |
@ -0,0 +1,22 @@ |
|||
'use strict'; |
|||
|
|||
var _getFiles = require('./get-files'); |
|||
|
|||
var _getFiles2 = _interopRequireDefault(_getFiles); |
|||
|
|||
var _path = require('path'); |
|||
|
|||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } |
|||
|
|||
(0, _getFiles2.default)((0, _path.resolve)('../mng-test/files-in-package')).then(function (files) { |
|||
console.log(files); |
|||
|
|||
(0, _getFiles2.default)((0, _path.resolve)('../mng-test/files-in-package-ignore')).then(function (files2) { |
|||
console.log('ignored: '); |
|||
console.log(files2); |
|||
}).catch(function (err) { |
|||
console.log(err.stack); |
|||
}); |
|||
}).catch(function (err) { |
|||
console.log(err.stack); |
|||
}); |
@ -0,0 +1,57 @@ |
|||
const gulp = require('gulp'); |
|||
const del = require('del'); |
|||
const ext = require('gulp-ext'); |
|||
const babel = require('gulp-babel'); |
|||
const eslint = require('gulp-eslint'); |
|||
const help = require('gulp-task-listing'); |
|||
|
|||
gulp.task('help', help); |
|||
|
|||
gulp.task('compile', [ |
|||
'compile-lib', |
|||
'compile-bin' |
|||
]); |
|||
|
|||
gulp.task('compile-lib', function () { |
|||
return gulp.src('lib/**/*.js') |
|||
.pipe(babel({ |
|||
presets: ['es2015'], |
|||
plugins: [ |
|||
'syntax-async-functions', |
|||
'transform-async-to-generator', |
|||
'transform-runtime' |
|||
] |
|||
})) |
|||
.pipe(gulp.dest('build/lib')); |
|||
}); |
|||
|
|||
gulp.task('compile-bin', function () { |
|||
return gulp.src('bin/*') |
|||
.pipe(babel({ |
|||
presets: ['es2015'], |
|||
plugins: [ |
|||
'syntax-async-functions', |
|||
'transform-async-to-generator', |
|||
'transform-runtime' |
|||
] |
|||
})) |
|||
.pipe(ext.crop()) |
|||
.pipe(gulp.dest('build/bin')); |
|||
}); |
|||
|
|||
gulp.task('lint', function () { |
|||
return gulp.src([ |
|||
'gulpfile.js', |
|||
'lib/**/*.js', |
|||
'bin/*' |
|||
]) |
|||
.pipe(eslint()) |
|||
.pipe(eslint.format()) |
|||
.pipe(eslint.failAfterError()); |
|||
}); |
|||
|
|||
gulp.task('clean', function () { |
|||
return del(['build']); |
|||
}); |
|||
|
|||
gulp.task('default', ['lint', 'compile']); |
@ -0,0 +1,138 @@ |
|||
import fs, { readFile as read } from 'fs-promise'; |
|||
import { resolve } from 'path'; |
|||
import flatten from 'arr-flatten'; |
|||
import unique from 'array-unique'; |
|||
import minimatch from 'minimatch'; |
|||
import IGNORED from './ignored'; |
|||
|
|||
/** |
|||
* Returns a list of files in the given |
|||
* directory that are subject to be |
|||
* synchronized. |
|||
* |
|||
* @param {String} full path to directory |
|||
* @return {Array} comprehensive list of paths to sync |
|||
*/ |
|||
|
|||
export default async function getFiles (path) { |
|||
const pkgData = await read(resolve(path, 'package.json'), 'utf8'); |
|||
const pkg = JSON.parse(pkgData); |
|||
|
|||
let search = (pkg.files || ['.']).concat('package.json'); |
|||
if (pkg.main) search = search.concat(pkg.main); |
|||
search = search.map((file) => asAbsolute(file, path)); |
|||
|
|||
const found = unique((await explode(search))); |
|||
|
|||
const npmIgnore = await maybeRead(resolve(path, '.npmignore')); |
|||
const gitIgnore = npmIgnore |
|||
? '' |
|||
: (await maybeRead(resolve(path, '.gitignore'))); |
|||
|
|||
const ignored = unique(IGNORED |
|||
.concat(gitIgnore.split('\n').filter(invalidFilter)) |
|||
.concat(npmIgnore.split('\n').filter(invalidFilter))) |
|||
.map(file => resolve(path, file)); |
|||
|
|||
return found.filter(ignoredFilter(ignored)); |
|||
} |
|||
|
|||
/** |
|||
* Returns a filter function that |
|||
* excludes ignored files in the path. |
|||
* |
|||
* @param {String} path |
|||
* @return {Function} filter fn |
|||
*/ |
|||
|
|||
const ignoredFilter = (ignored) => (file) => { |
|||
return !ignored.some((test) => { |
|||
return minimatch(file, test); |
|||
}); |
|||
}; |
|||
|
|||
/** |
|||
* Returns a filter function that |
|||
* excludes invalid rules for .*ignore files |
|||
* |
|||
* @param {String} path |
|||
* @return {Function} filter fn |
|||
*/ |
|||
|
|||
const invalidFilter = (path) => { |
|||
return !( |
|||
/* commments */ |
|||
'#' === path[0] || |
|||
|
|||
/* empty lines or newlines */ |
|||
!path.trim().length |
|||
); |
|||
}; |
|||
|
|||
/** |
|||
* Transform relative paths into absolutes, |
|||
* and maintains absolutes as such. |
|||
* |
|||
* @param {String} maybe relative path |
|||
* @param {String} parent full path |
|||
*/ |
|||
|
|||
const asAbsolute = function (path, parent) { |
|||
if ('/' === path[0]) return path; |
|||
return resolve(parent, path); |
|||
}; |
|||
|
|||
/** |
|||
* Explodes directories into a full list of files. |
|||
* Eg: |
|||
* in: ['/a.js', '/b'] |
|||
* out: ['/a.js', '/b/c.js', '/b/d.js'] |
|||
* |
|||
* @param {Array} of {String}s representing paths |
|||
* @return {Array} of {String}s of full paths |
|||
*/ |
|||
|
|||
const explode = async function (paths) { |
|||
const many = async (all) => { |
|||
return await Promise.all(all.map(async (file) => { |
|||
return await list(file); |
|||
})); |
|||
}; |
|||
|
|||
const list = async (file) => { |
|||
let path = file; |
|||
let stat; |
|||
|
|||
try { |
|||
stat = await fs.stat(path); |
|||
} catch (e) { |
|||
// in case the file comes from `files` or `main`
|
|||
// and it wasn't specified with `.js` by the user
|
|||
path = file + '.js'; |
|||
stat = await fs.stat(path); |
|||
} |
|||
|
|||
if (stat.isDirectory()) { |
|||
const all = await fs.readdir(file); |
|||
return many(all.map(subdir => asAbsolute(subdir, file))); |
|||
} else { |
|||
return path; |
|||
} |
|||
}; |
|||
|
|||
return flatten((await many(paths))); |
|||
}; |
|||
|
|||
/** |
|||
* Returns the contents of a file if it exists. |
|||
* |
|||
* @return {String} results or `''` |
|||
*/ |
|||
|
|||
const maybeRead = async function (path) { |
|||
try { |
|||
return (await fs.readFile(path, 'utf8')); |
|||
} catch (e) { |
|||
return ''; |
|||
} |
|||
}; |
@ -0,0 +1,30 @@ |
|||
import fs from 'fs-promise'; |
|||
import { createHash } from 'crypto'; |
|||
|
|||
/** |
|||
* Computes hashes for the contents of each file given. |
|||
* |
|||
* @param {Array} of {String} full paths |
|||
* @return {Map} |
|||
*/ |
|||
|
|||
export default async function hashes (files) { |
|||
const entries = await Promise.all(files.map(async (file) => { |
|||
const data = await fs.readFile(file); |
|||
return [file, hash(data)]; |
|||
})); |
|||
return new Map(entries); |
|||
} |
|||
|
|||
/** |
|||
* Computes a hash for the given buf. |
|||
* |
|||
* @param {Buffer} file data |
|||
* @return {String} hex digest |
|||
*/ |
|||
|
|||
function hash (buf) { |
|||
return createHash('sha1') |
|||
.update(buf) |
|||
.digest('hex'); |
|||
} |
@ -0,0 +1,24 @@ |
|||
export default [ |
|||
'._*', |
|||
'.hg', |
|||
'.git', |
|||
'.svn', |
|||
'.npmrc', |
|||
'.*.swp', |
|||
'.DS_Store', |
|||
'.wafpickle-*', |
|||
'.lock-wscript', |
|||
'npm-debug.log', |
|||
'config.gypi', |
|||
'node_modules', |
|||
'CVS', |
|||
'README', |
|||
'README.*', |
|||
'CHANGELOG', |
|||
'History.md', |
|||
'LICENSE', |
|||
'Readme', |
|||
'Readme.*', |
|||
'test', |
|||
'tests' |
|||
]; |
@ -0,0 +1,27 @@ |
|||
import fs from 'fs-promise'; |
|||
import getFiles from './get-files'; |
|||
import hash from './hash'; |
|||
|
|||
export default async function now (path, { debug }) { |
|||
try { |
|||
await fs.stat(path); |
|||
} catch (err) { |
|||
throw new Error(`Could not read directory ${path}.`); |
|||
} |
|||
|
|||
if (debug) console.time('> [debug] Getting files'); |
|||
const files = await getFiles(path); |
|||
if (debug) console.timeEnd('> [debug] Getting files'); |
|||
|
|||
if (debug) console.time('> [debug] Computing hashes'); |
|||
const hashes = await hash(files); |
|||
if (debug) console.timeEnd('> [debug] Computing hashes'); |
|||
|
|||
if (debug) { |
|||
hashes.forEach((val, key) => { |
|||
console.log(`> [debug] Found "${key}" [${val}]`); |
|||
}); |
|||
} |
|||
|
|||
return 'https://test.now.run'; |
|||
} |
@ -0,0 +1,20 @@ |
|||
import getFiles from './get-files'; |
|||
import { resolve } from 'path'; |
|||
|
|||
getFiles(resolve('../mng-test/files-in-package')) |
|||
.then(files => { |
|||
console.log(files); |
|||
|
|||
getFiles(resolve('../mng-test/files-in-package-ignore')) |
|||
.then(files2 => { |
|||
console.log('ignored: '); |
|||
console.log(files2); |
|||
}) |
|||
.catch(err => { |
|||
console.log(err.stack); |
|||
}); |
|||
}) |
|||
.catch(err => { |
|||
console.log(err.stack); |
|||
}); |
|||
|
@ -0,0 +1,63 @@ |
|||
{ |
|||
"name": "now", |
|||
"private": true, |
|||
"version": "0.0.1", |
|||
"description": "", |
|||
"main": "./build/lib/index", |
|||
"files": [ |
|||
"build/lib", |
|||
"build/bin" |
|||
], |
|||
"bin": { |
|||
"now": "./build/bin/now" |
|||
}, |
|||
"dependencies": { |
|||
"arr-flatten": "1.0.1", |
|||
"array-unique": "0.2.1", |
|||
"commander": "2.9.0", |
|||
"copy-paste": "1.1.4", |
|||
"fs-promise": "0.4.1", |
|||
"http2": "3.3.2", |
|||
"ms": "0.7.1" |
|||
}, |
|||
"devDependencies": { |
|||
"alpha-sort": "1.0.2", |
|||
"ava": "0.12.0", |
|||
"babel-eslint": "4.1.8", |
|||
"babel-plugin-syntax-async-functions": "6.3.13", |
|||
"babel-plugin-transform-async-to-generator": "6.4.6", |
|||
"babel-preset-es2015": "6.3.13", |
|||
"babel-register": "6.5.2", |
|||
"del": "2.2.0", |
|||
"eslint-config-standard": "4.4.0", |
|||
"eslint-plugin-standard": "1.3.1", |
|||
"gulp": "3.9.0", |
|||
"gulp-babel": "6.1.2", |
|||
"gulp-eslint": "1.1.1", |
|||
"gulp-ext": "1.0.0", |
|||
"gulp-task-listing": "1.0.1" |
|||
}, |
|||
"scripts": { |
|||
"gulp": "gulp", |
|||
"test": "ava" |
|||
}, |
|||
"babel": { |
|||
"presets": [ |
|||
"es2015" |
|||
], |
|||
"plugins": [ |
|||
"transform-runtime", |
|||
"syntax-async-functions", |
|||
"transform-async-to-generator" |
|||
] |
|||
}, |
|||
"ava": { |
|||
"failFast": true, |
|||
"files": [ |
|||
"test/*.js" |
|||
], |
|||
"require": [ |
|||
"babel-register" |
|||
] |
|||
} |
|||
} |
@ -0,0 +1,2 @@ |
|||
should-be-excluded.js |
|||
./build/a/should-be-excluded.js |
@ -0,0 +1,5 @@ |
|||
{ |
|||
"files": [ |
|||
"build" |
|||
] |
|||
} |
@ -0,0 +1,5 @@ |
|||
{ |
|||
"files": [ |
|||
"build" |
|||
] |
|||
} |
After Width: | Height: | Size: 167 KiB |
@ -0,0 +1 @@ |
|||
woot |
@ -0,0 +1,6 @@ |
|||
{ |
|||
"name": "hashes", |
|||
"version": "0.0.1", |
|||
"description": "", |
|||
"dependencies": {} |
|||
} |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"name": "simple-with-main", |
|||
"version": "0.0.1", |
|||
"description": "", |
|||
"main": "./index.js", |
|||
"files": ["build/a.js"], |
|||
"dependencies": {} |
|||
} |
@ -0,0 +1,3 @@ |
|||
{ |
|||
"name": "simple" |
|||
} |
@ -0,0 +1,56 @@ |
|||
import test from 'ava'; |
|||
import { join, resolve } from 'path'; |
|||
import getFiles from '../lib/get-files'; |
|||
import hash from '../lib/hash'; |
|||
import { asc as alpha } from 'alpha-sort'; |
|||
|
|||
const prefix = join(__dirname, '_fixtures') + '/'; |
|||
const base = (path) => path.replace(prefix, ''); |
|||
const fixture = (name) => resolve(`./_fixtures/${name}`); |
|||
|
|||
test('`files` + README', async t => { |
|||
let files = await getFiles(fixture('files-in-package')); |
|||
t.same(files.length, 3); |
|||
files = files.sort(alpha); |
|||
t.same(base(files[0]), 'files-in-package/build/a/b/c/d.js'); |
|||
t.same(base(files[1]), 'files-in-package/build/a/e.js'); |
|||
t.same(base(files[2]), 'files-in-package/package.json'); |
|||
}); |
|||
|
|||
test('`files` + README + `.*.swp` + `.npmignore`', async t => { |
|||
let files = await getFiles(fixture('files-in-package-ignore')); |
|||
t.same(files.length, 3); |
|||
files = files.sort(alpha); |
|||
t.same(base(files[0]), 'files-in-package-ignore/build/a/b/c/d.js'); |
|||
t.same(base(files[1]), 'files-in-package-ignore/build/a/e.js'); |
|||
t.same(base(files[2]), 'files-in-package-ignore/package.json'); |
|||
}); |
|||
|
|||
test('simple', async t => { |
|||
let files = await getFiles(fixture('simple')); |
|||
t.same(files.length, 5); |
|||
files = files.sort(alpha); |
|||
t.same(base(files[0]), 'simple/bin/test'); |
|||
t.same(base(files[1]), 'simple/index.js'); |
|||
t.same(base(files[2]), 'simple/lib/woot'); |
|||
t.same(base(files[3]), 'simple/lib/woot.jsx'); |
|||
t.same(base(files[4]), 'simple/package.json'); |
|||
}); |
|||
|
|||
test('simple with main', async t => { |
|||
let files = await getFiles(fixture('simple-main')); |
|||
t.same(files.length, 3); |
|||
files = files.sort(alpha); |
|||
t.same(base(files[0]), 'simple-main/build/a.js'); |
|||
t.same(base(files[1]), 'simple-main/index.js'); |
|||
t.same(base(files[2]), 'simple-main/package.json'); |
|||
}); |
|||
|
|||
test('hashes', async t => { |
|||
const files = await getFiles(fixture('hashes')); |
|||
const hashes = await hash(files); |
|||
t.same(hashes.size, 3); |
|||
t.same(hashes.get(prefix + 'hashes/dei.png'), '277c55a2042910b9fe706ad00859e008c1b7d172'); |
|||
t.same(hashes.get(prefix + 'hashes/index.js'), '56c00d0466fc6bdd41b13dac5fc920cc30a63b45'); |
|||
t.same(hashes.get(prefix + 'hashes/package.json'), '706214f42ae940a01d2aa60c5e32408f4d2127dd'); |
|||
}); |
Loading…
Reference in new issue