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