-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Init #1
Init #1
Changes from 4 commits
df51a8f
dd749fd
6f88314
ed2016f
677b64f
2fcf35e
619b911
2ee4cd5
c8d0069
5909dec
ebc57e8
52d59b4
e1c349c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
'use strict'; | ||
|
||
module.exports = { | ||
write: true, | ||
prefix: '^', | ||
test: [ | ||
'test', | ||
'benchmark', | ||
], | ||
devdep: [ | ||
'egg-ci', | ||
'egg-bin', | ||
'autod', | ||
'eslint', | ||
'eslint-config-egg', | ||
'supertest', | ||
'power-assert', | ||
'intelli-espower-loader', | ||
'egg-view-nunjucks', | ||
], | ||
exclude: [ | ||
'./test/fixtures', | ||
], | ||
}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
test/fixtures | ||
coverage |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"extends": "eslint-config-egg" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
logs/ | ||
npm-debug.log | ||
node_modules/ | ||
coverage/ | ||
.idea/ | ||
run/ | ||
.DS_Store | ||
*.swp | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
sudo: false | ||
language: node_js | ||
node_js: | ||
- '4' | ||
- '6' | ||
install: | ||
- npm i npminstall && npminstall | ||
script: | ||
- npm run ci | ||
after_script: | ||
- npminstall codecov && codecov |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,15 @@ | ||
# Nodeinstall | ||
|
||
|
||
|
||
## QuickStart | ||
|
||
```shell | ||
$ npm install | ||
$ npm run dev | ||
$ open http://localhost:7001/news | ||
``` | ||
|
||
## Questions & Suggestions | ||
|
||
Please open an issue [here](https://github.com/eggjs/egg/issues). |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
environment: | ||
matrix: | ||
- nodejs_version: '4' | ||
- nodejs_version: '6' | ||
|
||
install: | ||
- ps: Install-Product node $env:nodejs_version | ||
- npm i npminstall && node_modules\.bin\npminstall | ||
|
||
test_script: | ||
- node --version | ||
- npm --version | ||
- npm run ci | ||
|
||
build: off |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
'use strict'; | ||
|
||
const co = require('co'); | ||
exports.install = co(require('./lib/install')); | ||
exports.installNode = co(require('./lib/install_node')); | ||
exports.installAlinode = co(require('./lib/install_alinode')); | ||
exports.installNsolid = co(require('./lib/install_nsolid')); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
'use strict'; | ||
|
||
const os = require('os'); | ||
const path = require('path'); | ||
|
||
let homedir = process.env.HOME; | ||
// for Windows HOME | ||
if (!homedir) { | ||
homedir = process.env.HOMEDRIVE + process.env.HOMEPATH; | ||
} | ||
if (!homedir) { | ||
homedir = os.tmpdir(); | ||
} | ||
|
||
const tmpdir = path.join(homedir, '.tmp'); | ||
let cachedir = process.env.NODEINSTALL_CACHE; | ||
if (!cachedir) { | ||
if (process.platform === 'win32') { | ||
cachedir = path.join(process.env.APPDATA || tmpdir, '.nodeinstall'); | ||
} else { | ||
cachedir = path.join(process.env.HOME || tmpdir, '.nodeinstall'); | ||
} | ||
} | ||
|
||
// 获取缓存策略 | ||
exports.getStrategy = function() { | ||
// http://gitlab.alibaba-inc.com/node/tnpm/issues/24 | ||
// 避免网络问题导致 tnpm install 变慢,默认在本地开发环境开启 cache 功能。 | ||
let disable = false; | ||
if (process.argv.indexOf('--production') >= 0) { | ||
disable = true; | ||
} | ||
if (process.env.NODE_ENV) { | ||
// NODE_ENV 这个环境变量存在,代表当前运行环境是服务器,关闭 cache | ||
disable = true; | ||
} | ||
|
||
let cache = cachedir; | ||
if (disable) { | ||
// 一次性缓存目录 | ||
// http://gitlab.alibaba-inc.com/node/tnpm/issues/44 | ||
// tnpm.$yyyy-MM-dd.$pid.$timestamp | ||
const now = new Date(); | ||
const yyyyMMdd = now.getFullYear() + '-' + (now.getMonth() + 1) + '-' + now.getDate(); | ||
cache = path.join(tmpdir, 'nodeinstall.' + yyyyMMdd + '.' + process.pid + '.' + Date.now()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. install-node 关闭缓存不需要这种一次性缓存目录的 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 那应该如何处理呢,直接 pipe 到 extracter? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 放到真正的临时目录? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 恩,那也要建个一次性缓存目录 |
||
} | ||
return { disable, cache }; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
'use strict'; | ||
|
||
|
||
module.exports = { | ||
nodeDistUrl: 'https://nodejs.org/dist', | ||
nodeDistUrlMirror: 'https://npm.taobao.org/mirrors/node', | ||
nodeRcDistUrl: 'https://nodejs.org/download/rc', | ||
nodeRcDistUrlMirror: 'https://npm.taobao.org/mirrors/node-rc', | ||
nodeNightlyDistUrl: 'https://nodejs.org/download/nightly', | ||
nodeNightlyDistUrlMirror: 'https://npm.taobao.org/mirrors/node-nightly', | ||
alinodeDistUrl: 'http://alinode.aliyun.com/dist/new-alinode', | ||
alinodeDistUrlMirror: 'https://npm.taobao.org/mirrors/alinode', | ||
nsolidDistUrl: 'https://nsolid-download.nodesource.com/download/nsolid-node/release', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nsolid 我也 mirrors 一下好了 https://nsolid-download.nodesource.com/download/nsolid-node/release/ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good |
||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
'use strict'; | ||
|
||
const os = require('os'); | ||
const path = require('path'); | ||
const fs = require('fs'); | ||
const bytes = require('bytes'); | ||
const urlparse = require('url').parse; | ||
const ProgressBar = require('progress'); | ||
const crypto = require('crypto'); | ||
const zlib = require('zlib'); | ||
const tar = require('tar'); | ||
const mkdirp = require('mkdirp'); | ||
const debug = require('debug')('nodeinstall'); | ||
const request = require('./request'); | ||
const cache = require('./cache'); | ||
const getLocalNodeVersion = require('./version').getLocalNodeVersion; | ||
|
||
|
||
module.exports = function* install(options) { | ||
const distUrl = options.distUrl; | ||
const version = options.version; | ||
const name = options.name; | ||
const cwd = options.cwd; | ||
|
||
debug('Start install %s@%s, options: %j', name, version, options); | ||
|
||
const nodeModulesDir = path.join(cwd, 'node_modules'); | ||
const nodeDir = path.join(nodeModulesDir, 'node'); | ||
const nodeLinkDir = path.join(nodeModulesDir, '.bin'); | ||
const nodeLink = path.join(nodeLinkDir, 'node'); | ||
const npmLink = path.join(nodeLinkDir, 'npm'); | ||
|
||
const platform = process.env.MOCK_OS_PLATFORM || os.platform(); | ||
const arch = os.arch() === 'x64' ? 'x64' : 'x86'; | ||
const shaUrl = `${distUrl}/v${version}/SHASUMS256.txt`; | ||
const tgzUrl = `${distUrl}/v${version}/${name}-v${version}-${platform}-${arch}.tar.gz`; | ||
|
||
try { | ||
// process.versions from installed node | ||
const versions = getLocalNodeVersion(cwd); | ||
if (version === versions[name]) { | ||
console.info('%s has been installed, version %s', name, version); | ||
return; | ||
} | ||
} catch (e) { | ||
if (e.name !== 'NodeNotInstalledError') { | ||
throw e; | ||
} | ||
} | ||
|
||
// use cache or not | ||
const cacheStrategy = cache.getStrategy(); | ||
debug('cacheStrategy, %j', cacheStrategy); | ||
const targetName = path.basename(urlparse(tgzUrl).pathname); | ||
const targetFile = path.join(cacheStrategy.cache, targetName); | ||
|
||
try { | ||
// download tarball if cache is disabled or cache file is not exist, | ||
// otherwise use cache | ||
if (cacheStrategy.disable || fs.existsSync(targetFile)) { | ||
yield downloadTgz(tgzUrl, shaUrl, targetFile); | ||
} | ||
|
||
// extract tarball to $cwd/node_modules | ||
yield extract(targetFile, nodeDir); | ||
} catch (err) { | ||
if (fs.existsSync(targetFile)) { | ||
fs.unlinkSync(targetFile); | ||
} | ||
throw err; | ||
} | ||
|
||
mkdirp.sync(nodeLinkDir); | ||
fs.symlinkSync(path.normalize('../node/bin/node'), nodeLink); | ||
if (!fs.existsSync(npmLink)) { | ||
fs.symlinkSync(path.normalize('../node/bin/npm'), npmLink); | ||
} | ||
const packageJsonFile = path.join(nodeDir, 'package.json'); | ||
fs.writeFileSync(packageJsonFile, JSON.stringify({ name, version }, null, 2)); | ||
}; | ||
|
||
function* downloadTgz(tgzUrl, shaUrl, targetFile) { | ||
debug('download %s to %s', tgzUrl, targetFile); | ||
const ret = yield request(tgzUrl, { | ||
timeout: 20000, | ||
streaming: true, | ||
followRedirect: true, | ||
retry: 3, | ||
}); | ||
const res = ret.res; | ||
|
||
if (res.statusCode !== 200) { | ||
const err = new Error('GET ' + tgzUrl + ' got ' + res.statusCode); | ||
err.statusCode = res.statusCode; | ||
err.headers = res.headers; | ||
throw err; | ||
} | ||
|
||
yield writeFile(res, targetFile); | ||
yield verifyChecksum(shaUrl, targetFile); | ||
} | ||
|
||
function* verifyChecksum(shaUrl, targetFile) { | ||
const ret = yield request(shaUrl); | ||
const res = ret.res; | ||
|
||
if (res.statusCode !== 200) { | ||
const err = new Error('GET ' + shaUrl + ' got ' + res.statusCode); | ||
err.statusCode = res.statusCode; | ||
throw err; | ||
} | ||
|
||
const tgzName = path.basename(targetFile); | ||
const shas = ret.data.toString(); | ||
const refSha = getShaByTgzName(shas, tgzName); | ||
const actualSha = calcSha(fs.readFileSync(targetFile)); | ||
if (refSha !== actualSha) { | ||
const err = new Error(`Checksum verification failed. Reference checksum is ${refSha.slice(0, 7)}, but the actual checksum is ${actualSha.slice(0, 7)}`); | ||
err.name = 'ChecksumError'; | ||
throw err; | ||
} | ||
debug('checksum success %s', refSha); | ||
} | ||
|
||
function extract(targetFile, nodeDir) { | ||
return new Promise((resolve, reject) => { | ||
const gunzip = zlib.createGunzip(); | ||
gunzip.on('error', reject); | ||
const extracter = tar.Extract({ path: nodeDir, strip: 1 }); | ||
extracter.on('error', reject); | ||
extracter.on('end', resolve); | ||
fs.createReadStream(targetFile).pipe(gunzip).pipe(extracter); | ||
}); | ||
} | ||
|
||
function writeFile(res, targetFile) { | ||
mkdirp.sync(path.dirname(targetFile)); | ||
return new Promise(function(resolve, reject) { | ||
const ws = fs.createWriteStream(targetFile) | ||
.on('error', reject) | ||
.on('finish', resolve); | ||
showProgress(res); | ||
res.pipe(ws); | ||
}); | ||
} | ||
|
||
function showProgress(res) { | ||
const bar = new ProgressBar('[nodeinstall] downloading [:bar] :percent :etas/:elapseds :current/:total :speed/s', { | ||
complete: '=', | ||
incomplete: ' ', | ||
width: 20, | ||
total: parseInt(res.headers['content-length'] || 1024 * 1024 * 30), | ||
}); | ||
|
||
let start = Date.now(); | ||
let size = 0; | ||
let speed = 0; | ||
res.on('data', chunk => { | ||
size += chunk.length; | ||
const use = Date.now() - start; | ||
// 每秒钟计算一次 | ||
if (use >= 1000) { | ||
speed = size / use * 1000; | ||
start = Date.now(); | ||
size = 0; | ||
} | ||
bar.tick(chunk.length, { | ||
speed: bytes(speed || size), | ||
}); | ||
}); | ||
} | ||
|
||
function getShaByTgzName(content, tarName) { | ||
let sha = ''; | ||
for (const line of content.split('\n')) { | ||
if (line.indexOf(tarName) > -1) { | ||
sha = line.split(/\s/)[0]; | ||
break; | ||
} | ||
} | ||
return sha; | ||
} | ||
|
||
function calcSha(file) { | ||
return crypto.createHash('sha256').update(file).digest('hex'); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
'use strict'; | ||
|
||
const getAlinodeVersion = require('./version').getAlinodeVersion; | ||
const install = require('./install'); | ||
const config = require('./config'); | ||
|
||
const DEFAULT_OPTIONS = { | ||
cwd: process.cwd(), | ||
version: '', | ||
distUrl: config.alinodeDistUrl, | ||
}; | ||
|
||
module.exports = function* installAlinode(options) { | ||
options = Object.assign({}, DEFAULT_OPTIONS, options, { name: 'alinode' }); | ||
options.version = yield getAlinodeVersion(options); | ||
yield install(options); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
'use strict'; | ||
|
||
const getNodeVersion = require('./version').getNodeVersion; | ||
const install = require('./install'); | ||
const config = require('./config'); | ||
|
||
const DEFAULT_OPTIONS = { | ||
cwd: process.cwd(), | ||
version: '', | ||
distUrl: config.nodeDistUrl, | ||
}; | ||
|
||
module.exports = function* installNode(options) { | ||
options = Object.assign({}, DEFAULT_OPTIONS, options, { name: 'node' }); | ||
options.version = yield getNodeVersion(options); | ||
yield install(options); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
�内网地址删除了吧
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
内网地址删除了。。