Authored by 毕凯

Merge branch 'feature/upload' into 'master'

活动压缩包上传



See merge request !16
... ... @@ -10,4 +10,6 @@ packages/
.idea/
*.log
\ No newline at end of file
*.log
/uploads
\ No newline at end of file
... ...
'use strict';
const FileModel = require('../models/file');
const _ = require('lodash');
const shelljs = require('shelljs');
const decompress = require('decompress');
const decompressUnzip = require('decompress-unzip');
const moment = require('moment');
const path = require('path');
const fs = require('fs');
const rd = require('rd');
const ws = require('../../lib/ws');
const CDNCONFIG = require('../../config/cdn_config');
const qn = require('../../lib/qiniu')(CDNCONFIG.feature); // 活动上传
const FILE_SAVE_ROOT_PATH = './uploads'; // 上传到本地服务器的根目录
const SUPER_FILE_CHECK_PASS = 'yohowebtech.superfile'; // 存在此文件,直接上传到七牛
const BROADCAST_PATH = '/upload'; // ws 键
class FileApi {
/**
* 上传到服务器的文件处理
* @param {文件} file
* @param {路径} actPath
* @param {用户} user
*/
async upload(file, actPath, user) {
let fileName = _.get(file, 'name');
let fileNameWithoutType = _.split(fileName, '.')[0];
let fileSavePath = path.join(FILE_SAVE_ROOT_PATH, fileName); // 文件保存到服务器的路径
await new Promise((resolve, reject) => {
let readable = fs.createReadStream(file.path);
let writable = fs.createWriteStream(fileSavePath);
readable.pipe(writable);
readable.on('end', result => {
resolve(result);
});
});
ws.broadcast(BROADCAST_PATH, {
state: '压缩包已经上传到服务器,开始解压...'
});
let fileDistPath = path.join(FILE_SAVE_ROOT_PATH, actPath); // 文件解压的路径
shelljs.mkdir('-p', fileDistPath);
// 解压
await decompress(path.resolve(fileSavePath), path.resolve(fileDistPath), {
plugins: [
decompressUnzip()
]
});
ws.broadcast(BROADCAST_PATH, {
state: '压缩包已经解压成功,开始校验文件...'
});
let fileList = rd.readSync(fileDistPath); // 读取待上传的文件列表
let testRes = this._testFiles(fileList); // 文件校验
if (testRes) {
ws.broadcast(BROADCAST_PATH, {
state: '校验文件通过,开始将文件上传到七牛...'
});
let fileModel = new FileModel();
let insertRes = await fileModel.insert({ // 上传记录写库
date: moment().format('YYYY-MM-DD HH:mm'),
fileName: fileName,
actPath: actPath,
username: user.username,
user_id: user._id
});
await this._uploadToQiniu(fileList, fileDistPath);
ws.broadcast(BROADCAST_PATH, {
state: '文件上传到七牛处理结束!'
});
} else {
ws.broadcast(BROADCAST_PATH, {
state: '校验文件失败,非法上传!'
});
}
return true;
}
/**
* 上传到七牛
* @param {待上传的文件列表} fileList
* @param {待上传的文件夹路径} fileDistPath
*/
async _uploadToQiniu(fileList, fileDistPath) {
_.remove(fileList, perFilePath => {
return !perFilePath || /__MACOSX/.test(perFilePath) || /.DS_Store/.test(perFilePath) || !fs.lstatSync(perFilePath).isFile();
});
let fileListPromises = _.map(fileList, filepath => {
let fileKey = path.relative(FILE_SAVE_ROOT_PATH, filepath);
return new Promise((resolve, reject) => {
qn.uploadFile(filepath, {key:fileKey}, (err, result) => {
if (err) {
ws.broadcast(BROADCAST_PATH, {
state: `${fileKey} 上传到七牛过程中出现错误`
});
reject(err);
} else {
if (result && result.url) {
ws.broadcast(BROADCAST_PATH, {
state: `${fileKey} 上传到七牛成功`
});
} else {
ws.broadcast(BROADCAST_PATH, {
state: `${fileKey} 上传到七牛失败`
});
}
resolve(result);
}
});
});
});
return Promise.all(fileListPromises);
}
/**
* 测试是否是可以上传的文件包
* @param {待上传的文件列表} fileDistPath
*/
_testFiles(fileList) {
let isSuperFile = false;
let isExistedHyperesources = false;
let isExistedHypeGenerated = false;
_.forEach(fileList, file => {
if (file.indexOf(SUPER_FILE_CHECK_PASS) > 0) {
isSuperFile = true;
return false;
}
if (/.hyperesources/.test(file)) {
isExistedHyperesources = true;
}
if (/_hype_generated_script/.test(file)) {
isExistedHypeGenerated = true;
}
if (isExistedHyperesources && isExistedHypeGenerated) {
return false;
}
});
return isSuperFile || (isExistedHyperesources && isExistedHypeGenerated);
}
/**
* 获取上传记录
*/
async getAllLogs(params) {
let page = _.parseInt(params.page);
let limit = 10;
let skip = page > 0? limit * (page - 1) : 0;
let result = await new FileModel().cfind({}).sort({
date: -1
}).skip(skip).limit(limit).exec();
_.forEach(result, perLog => {
perLog.link = _.get(CDNCONFIG, 'feature.origin') + perLog.actPath + '/index.html';
});
return result;
}
}
module.exports = FileApi;
... ...
'use strict';
const Model = require('./model');
class FileModel extends Model {
constructor() {
super('files');
}
}
module.exports = FileModel;
... ...
'use strict';
const _ = require('lodash');
const moment = require('moment');
const Router = require('koa-router');
const router = new Router();
const FileApi = require('../../ci/file');
const CDNCONFIG = require('../../../config/cdn_config');
const qn = require('../../../lib/qiniu')(CDNCONFIG.feature);
/**
* 处理列表数据
*/
const _handleListItems = items => {
_.forEach(items, perFile => {
perFile.fsizekb = (perFile.fsize / 1024).toFixed(2) + 'kb';
let dateTime = _.parseInt(perFile.putTime.toString().substring(0, 13));
perFile.putTimeFormat = moment(dateTime).format('YYYY-MM-DD HH:mm');
perFile.link = _.get(CDNCONFIG, 'feature.origin') + '/' + perFile.key;
});
return items;
};
/**
* 校验是否是允许上传的文件包
*/
const _verifyFiles = filesList => {
return true;
};
const file = {
/**
* 文件管理页面
*/
page: async(ctx) => {
await ctx.render('/action/file_page', {domain: _.get(CDNCONFIG, 'feature.origin')});
},
/**
* 列出上传记录
*/
listLogs: async(ctx) => {
let fileApi = new FileApi();
let result = await fileApi.getAllLogs({
page: ctx.query.page
});
ctx.body = {
code: 200,
message: '',
data: result
}
},
/**
* 列出包内的文件
*/
listFiles: async(ctx) => {
let params = {
prefix: ctx.query.actPath,
limit: 20
};
if (ctx.query.marker) {
params.marker = ctx.query.marker;
}
let result = await qn.listAsync(params);
let finalResult = {
items: _handleListItems(result.items)
};
if (result.marker) {
finalResult.marker = result.marker;
}
ctx.body = {
code: 200,
message: '',
data: finalResult
};
},
/**
* 上传处理
*/
upload: async(ctx, next) => {
if ('POST' !== ctx.method) return await next();
let file = _.get(ctx, 'request.body._files.file');
let user = ctx.session.user;
if (!file) {
return ctx.body = {
code: 400,
message: '没有接收到上传的文件包'
};
}
let actPath = _.get(ctx, 'request.body.actPath');
if (!actPath) {
return ctx.body = {
code: 400,
message: '请指定路径'
};
}
await new FileApi().upload(file, actPath, user);
return ctx.body = {
code: 200,
message: '处理完毕',
data: {}
};
}
}
router.get('/page', file.page);
router.get('/listlogs', file.listLogs);
router.get('/listfiles', file.listFiles);
router.post('/upload', file.upload);
module.exports = router;
... ...
... ... @@ -25,6 +25,7 @@ const profile = require('./actions/profile');
const checkcode = require('./actions/checkcode').router;
const noAuth = new Router();
const base = new Router();
const file = require('./actions/file');
module.exports = function(app) {
... ... @@ -66,6 +67,7 @@ module.exports = function(app) {
base.use('/abuse_protection', abuseProtection.routes(), degrade.allowedMethods());
base.use('/seo', seo.routes(), seo.allowedMethods());
base.use('/files', file.routes(), file.allowedMethods());
base.use('', index.routes(), index.allowedMethods());
... ...
<div class="pageheader">
<div class="media">
<div class="pageicon pull-left">
<i class="fa fa-th-list"></i>
</div>
<div class="media-body">
<ul class="breadcrumb">
<li><a href=""><i class="glyphicon glyphicon-home"></i></a></li>
<li>静态资源</li>
</ul>
<h4>活动上传</h4>
</div>
</div>
<!-- media -->
</div>
<!-- pageheader -->
<div class="contentpanel">
<div class="row">
<div class="col-sm-12">
<div class="form-horizontal">
<div class="form-group col-sm-12">
<label class="control-label col-sm-1">上传地址:</label>
<div class="col-sm-6">
<div class="input-group">
<span class="input-group-addon">{{domain}}</span>
<input id="actPath" type="text" class="form-control col-sm-10" placeholder="请输入上传地址">
<span class="input-group-addon">/index.html</span>
</div>
</div>
</div>
<div class="form-group col-sm-12">
<label class="control-label col-sm-1">上传文件:</label>
<div class="col-sm-3">
<input type="file" accept="application/x-zip-compressed" name="file" id="fileInput" class="btn btn-default btn-block">
<p class="form-control-static">注:仅支持zip格式</p>
<button id="upload" class="btn btn-primary btn-block">上传</button>
</div>
</div>
<div class="form-group col-sm-12">
<label class="control-label col-sm-1">上传日志:</label>
<div class="col-sm-8">
<div class="logs panel-body yoho-log-dark" style="height: 150px; overflow-y: scroll; color: #fff;"></div>
</div>
</div>
<div class="form-group col-sm-12">
<label class="control-label col-sm-1">上传记录:</label>
<div class="col-sm-11">
<table id="upload-list" style="word-break: break-all;" class="table table-bordered table-hover">
<tr class="title">
<th style="text-align:center;">活动地址</th>
<th style="text-align:center;">文件名称</th>
<th style="text-align:center;">上传时间</th>
<th style="text-align:center;">上传用户</th>
<th style="text-align:center;">操作</th>
</tr>
</table>
</div>
</div>
<div class="form-group col-sm-12">
<div class="col-sm-11 col-sm-offset-1" style="text-align: center;">
<a class="btn btn-primary more-list">加载更多记录</a>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
let $uploadList = $('#upload-list tbody');
let marker = '';
let page = 1;
$('#upload').on('click', function() {
var formData = new FormData();
var file = $('#fileInput').prop('files')[0];
var actPath = $('#actPath').val();
if (!$('#actPath').val()) {
$('.logs').prepend('<p>state: 请输入上传地址!</p>');
return false;
}
actPath = `/${actPath}`;
formData.append('file', file);
formData.append('actPath', actPath);
$.ajax({
type: 'POST',
url: '/files/upload',
cache: false,
data: formData,
dataType: 'json',
processData: false,
contentType: false,
success: function(result) {
if (result) {
if (result.code === 200) {
$('.logs').prepend('<p>state: 上传完成!</p>');
$('#upload-list tr[class!=title]').remove();
page = 1;
getList();
} else if (result.code === 400) {
$('.logs').prepend('<p>state: 请选择上传文件!</p>');
}
} else {
$('.logs').prepend('<p>state: 请稍后再试!</p>');
}
}
});
});
// 上传记录列表
function getList(){
$.ajax({
type: 'GET',
url: '/files/listlogs',
cache: false,
dataType: 'json',
data: {
page: page++
},
success: function(result) {
if (result && result.data && result.data.length > 0) {
let $uploadList = $('#upload-list > tbody');
result.data.forEach(function(item){
$uploadList.append(`
<tr>
<td><a href="${item.link}">${item.actPath}</a></td>
<td style="text-align:center;">${item.fileName}</td>
<td style="text-align:center;">${item.date}</td>
<td style="text-align:center;">${item.username}</td>
<td style="text-align: center;">
<a class="detail-btn btn btn-warning btn-block" data-path="${item.actPath}">展开详情</a>
<a class="get-more btn btn-success btn-block hide" data-path="${item.actPath}">加载更多</a>
</td>
</tr>
<tr class="detail-c hide">
<td colspan=5>
<table class="table table-bordered detail-table">
<tr>
<th style="text-align: center">文件路径</th>
<th style="text-align: center">文件大小</th>
<th style="text-align: center">文件格式</th>
<th style="text-align: center">上传时间</th>
</tr>
</table>
</td>
</tr>
`);
});
} else {
$('.more-list').hide();
}
}
});
};
// 上传记录详情
function getDetail(e, marker) {
let $this = $(e.currentTarget);
let path = $this.data('path');
let $uploadDetail = $this.parents('tr');
let detail = '';
$.ajax({
type: 'GET',
url: '/files/listfiles',
cache: false,
dataType: 'json',
data: {
actPath: `${path}`,
marker: marker
},
success: (result) => {
if (result && result.data &&result.data.items) {
if ($this.parents('td').find('.get-more').attr('data-marker') === result.data.marker) {
$this.parents('td').find('.get-more').remove();
return false;
}
$this.parents('td').find('.get-more').attr('data-marker', result.data.marker);
result.data.items.forEach(function(item){
detail += `<tr class="detail-list">
<td><a href="${item.link}">${item.key}</a></td>
<td style="text-align:center;">${item.fsizekb}</td>
<td style="text-align:center;">${item.mimeType}</td>
<td style="text-align:center;">${item.putTimeFormat}</td>
</tr>`;
});
$uploadDetail.next('.detail-c').find('.detail-table tbody').append(detail);
$this.parents('td').find('.get-more').removeClass('hide');
}
}
});
}
// 加载更多列表
$('.more-list').on('click', function() {
getList();
})
// 上传记录详情,插入tr
$uploadList.on('click', '.detail-btn', function(e) {
let $this = $(e.currentTarget);
let $detailC = $this.parents('tr').next('.detail-c');
let $detailList = $this.parents('tr').next('.detail-c').find('.detail-list');
if ($detailC.is(':hidden')) {
$('.detail-c').addClass('hide');
$detailC.removeClass('hide');
$('.detail-btn').text('展开详情');
$this.text('关闭详情');
if ($detailList.length <= 0) {
getDetail(e, marker);
} else if ($detailC.find('.detail-list').length > 0) {
$this.siblings('.get-more').removeClass('hide');
}
} else {
$detailC.addClass('hide');
$this.text('展开详情');
$this.siblings('.get-more').addClass('hide');
}
});
// 加载更多
$uploadList.on('click', '.get-more', function(e) {
let $this = $(e.currentTarget);
let marker = $this.data('marker');
getDetail(e, marker);
})
// 打印日志
$(() => {
var ws = io();
ws.on('connect', function() {
ws.on('/upload', function(data) {
$('.logs').prepend(`<p>state: ${data.state}</p>`);
});
});
getList();
});
</script>
... ...
... ... @@ -61,9 +61,10 @@
</li>
</ul>
</li>
<li class="parent"><a><i class="fa fa-list"></i> <span>静态资源</span>
<li class="parent"><a><i class="fa fa-list"></i> <span>静态资源</span></a>
<ul class="children">
<li><a href="/check/list">代码检查</a></li>
<li><a href="/files/page">活动上传</a></li>
</ul>
</li>
... ...
/**
* CDN 配置
*/
const CDNCONFIG = {
feature: {
origin: 'https://feature.yoho.cn',
bucket: 'yohogirlzine'
}
}
module.exports = CDNCONFIG;
\ No newline at end of file
... ...
... ... @@ -17,8 +17,17 @@ const config = {
bucket: 'yohocdn'
};
const _default = (params) => {
let finalConfig = config;
const _default = Promise.promisifyAll(qn.create(config));
if (params) {
_.assign(finalConfig, params);
}
return Promise.promisifyAll(
qn.create(finalConfig)
);
}
_default.key = function(key) {
let _conifg = _.clone(config);
... ...
... ... @@ -28,6 +28,8 @@
"bluebird": "^3.5.0",
"co": "^4.6.0",
"co-body": "^4.2.0",
"decompress": "^4.2.0",
"decompress-unzip": "^4.0.1",
"formidable": "^1.0.17",
"fs-promise": "^0.5.0",
"fstream": "^1.0.9",
... ... @@ -56,10 +58,12 @@
"node-zookeeper-client": "^0.2.2",
"nodemailer": "^3.1.8",
"npm": "^3.10.9",
"path": "^0.12.7",
"promise-mysql": "^3.0.1",
"qcloudapi-sdk": "^0.1.5",
"qn": "^1.3.0",
"qs": "^6.2.0",
"rd": "^1.1.2",
"redis": "^2.7.1",
"request-promise": "^4.1.1",
"shelljs": "^0.7.0",
... ...
... ... @@ -224,6 +224,10 @@ base64-arraybuffer@0.1.5:
version "0.1.5"
resolved "http://registry.npm.taobao.org/base64-arraybuffer/download/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
base64-js@0.0.8:
version "0.0.8"
resolved "http://npm.yoho.cn/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978"
base64id@0.1.0:
version "0.1.0"
resolved "http://registry.npm.taobao.org/base64id/download/base64id-0.1.0.tgz#02ce0fdeee0cef4f40080e1e73e834f0b1bfce3f"
... ... @@ -258,6 +262,12 @@ binary-search-tree@0.2.5:
dependencies:
underscore "~1.4.4"
bl@^1.0.0:
version "1.2.1"
resolved "http://npm.yoho.cn/bl/-/bl-1.2.1.tgz#cac328f7bee45730d404b692203fcb590e172d5e"
dependencies:
readable-stream "^2.0.5"
bl@~1.1.2:
version "1.1.2"
resolved "http://registry.npm.taobao.org/bl/download/bl-1.1.2.tgz#fdca871a99713aa00d19e3bbba41c44787a65398"
... ... @@ -338,6 +348,10 @@ buffer-concat@~0.0.1:
version "0.0.1"
resolved "http://registry.npm.taobao.org/buffer-concat/download/buffer-concat-0.0.1.tgz#43e1e3c77f3d22fb55bea6890a92d03778c4c10a"
buffer-crc32@~0.2.3:
version "0.2.13"
resolved "http://npm.yoho.cn/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
buffer-shims@^1.0.0:
version "1.0.0"
resolved "http://registry.npm.taobao.org/buffer-shims/download/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51"
... ... @@ -346,6 +360,14 @@ buffer-type@^0.0.2:
version "0.0.2"
resolved "http://registry.npm.taobao.org/buffer-type/download/buffer-type-0.0.2.tgz#8a0bbcbe786049af8b436a636b9b50525fe26ca3"
buffer@^3.0.1:
version "3.6.0"
resolved "http://npm.yoho.cn/buffer/-/buffer-3.6.0.tgz#a72c936f77b96bf52f5f7e7b467180628551defb"
dependencies:
base64-js "0.0.8"
ieee754 "^1.1.4"
isarray "^1.0.0"
builtin-modules@^1.0.0:
version "1.1.1"
resolved "http://registry.npm.taobao.org/builtin-modules/download/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
... ... @@ -525,6 +547,19 @@ commander@, commander@^2.9.0:
dependencies:
graceful-readlink ">= 1.0.0"
<<<<<<< HEAD
commander@~2.11.0:
version "2.11.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563"
commander@~2.8.1:
version "2.8.1"
resolved "http://npm.yoho.cn/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4"
dependencies:
graceful-readlink ">= 1.0.0"
=======
>>>>>>> master
component-bind@1.0.0:
version "1.0.0"
resolved "http://registry.npm.taobao.org/component-bind/download/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1"
... ... @@ -707,6 +742,54 @@ decamelize@^1.0.0:
version "1.2.0"
resolved "http://registry.npm.taobao.org/decamelize/download/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1:
version "4.1.1"
resolved "http://npm.yoho.cn/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1"
dependencies:
file-type "^5.2.0"
is-stream "^1.1.0"
tar-stream "^1.5.2"
decompress-tarbz2@^4.0.0:
version "4.1.1"
resolved "http://npm.yoho.cn/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b"
dependencies:
decompress-tar "^4.1.0"
file-type "^6.1.0"
is-stream "^1.1.0"
seek-bzip "^1.0.5"
unbzip2-stream "^1.0.9"
decompress-targz@^4.0.0:
version "4.1.1"
resolved "http://npm.yoho.cn/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee"
dependencies:
decompress-tar "^4.1.1"
file-type "^5.2.0"
is-stream "^1.1.0"
decompress-unzip@^4.0.1:
version "4.0.1"
resolved "http://npm.yoho.cn/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69"
dependencies:
file-type "^3.8.0"
get-stream "^2.2.0"
pify "^2.3.0"
yauzl "^2.4.2"
decompress@^4.2.0:
version "4.2.0"
resolved "http://npm.yoho.cn/decompress/-/decompress-4.2.0.tgz#7aedd85427e5a92dacfe55674a7c505e96d01f9d"
dependencies:
decompress-tar "^4.0.0"
decompress-tarbz2 "^4.0.0"
decompress-targz "^4.0.0"
decompress-unzip "^4.0.1"
graceful-fs "^4.1.10"
make-dir "^1.0.0"
pify "^2.3.0"
strip-dirs "^2.0.0"
deep-equal@^1.0.0, deep-equal@~1.0.0, deep-equal@~1.0.1:
version "1.0.1"
resolved "http://registry.npm.taobao.org/deep-equal/download/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
... ... @@ -807,6 +890,12 @@ ee-first@1.1.1:
version "1.1.1"
resolved "http://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
end-of-stream@^1.0.0:
version "1.4.0"
resolved "http://npm.yoho.cn/end-of-stream/-/end-of-stream-1.4.0.tgz#7a90d833efda6cfa6eac0f4949dbb0fad3a63206"
dependencies:
once "^1.4.0"
engine.io-client@1.7.2:
version "1.7.2"
resolved "http://registry.npm.taobao.org/engine.io-client/download/engine.io-client-1.7.2.tgz#12f01d3d9d676908a86339cee067ff799a585c3d"
... ... @@ -1030,6 +1119,24 @@ fast-deep-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff"
fd-slicer@~1.0.1:
version "1.0.1"
resolved "http://npm.yoho.cn/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65"
dependencies:
pend "~1.2.0"
file-type@^3.8.0:
version "3.9.0"
resolved "http://npm.yoho.cn/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9"
file-type@^5.2.0:
version "5.2.0"
resolved "http://npm.yoho.cn/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6"
file-type@^6.1.0:
version "6.2.0"
resolved "http://npm.yoho.cn/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919"
filename-regex@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
... ... @@ -1242,6 +1349,20 @@ generate-object-property@^1.1.0:
dependencies:
is-property "^1.0.0"
<<<<<<< HEAD
get-caller-file@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
get-stream@^2.2.0:
version "2.3.1"
resolved "http://npm.yoho.cn/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de"
dependencies:
object-assign "^4.0.1"
pinkie-promise "^2.0.0"
=======
>>>>>>> master
get-stream@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
... ... @@ -1313,7 +1434,7 @@ got@^6.7.1:
unzip-response "^2.0.1"
url-parse-lax "^1.0.0"
graceful-fs@^4.1.11:
graceful-fs@^4.1.10, graceful-fs@^4.1.11:
version "4.1.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
... ... @@ -1491,6 +1612,10 @@ iconv-lite@0.4.13, iconv-lite@^0.4.13:
version "0.4.13"
resolved "http://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
ieee754@^1.1.4:
version "1.1.8"
resolved "http://npm.yoho.cn/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
iferr@^0.1.5, iferr@~0.1.5:
version "0.1.5"
resolved "http://registry.npm.taobao.org/iferr/download/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501"
... ... @@ -1658,6 +1783,10 @@ is-nan@^1.2.1:
dependencies:
define-properties "^1.1.1"
is-natural-number@^4.0.1:
version "4.0.1"
resolved "http://npm.yoho.cn/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8"
is-npm@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4"
... ... @@ -1720,7 +1849,7 @@ isarray@0.0.1:
version "0.0.1"
resolved "http://registry.npm.taobao.org/isarray/download/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
isarray@1.0.0, isarray@~1.0.0:
isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
version "1.0.0"
resolved "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
... ... @@ -2634,7 +2763,7 @@ on-finished@^2.1.0:
dependencies:
ee-first "1.1.1"
once@^1.3.0, once@^1.3.3, once@~1.4.0:
once@^1.3.0, once@^1.3.3, once@^1.4.0, once@~1.4.0:
version "1.4.0"
resolved "http://registry.npm.taobao.org/once/download/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
dependencies:
... ... @@ -2774,12 +2903,34 @@ path-to-regexp@^1.1.1:
dependencies:
isarray "0.0.1"
<<<<<<< HEAD
path-type@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
dependencies:
graceful-fs "^4.1.2"
pify "^2.0.0"
pinkie-promise "^2.0.0"
path@^0.12.7:
version "0.12.7"
resolved "http://npm.yoho.cn/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f"
dependencies:
process "^0.11.1"
util "^0.10.3"
=======
>>>>>>> master
pause-stream@0.0.11, pause-stream@~0.0.11:
version "0.0.11"
resolved "http://registry.npm.taobao.org/pause-stream/download/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445"
dependencies:
through "~2.3"
pend@~1.2.0:
version "1.2.0"
resolved "http://npm.yoho.cn/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
performance-now@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
... ... @@ -2822,6 +2973,10 @@ process-nextick-args@~1.0.6:
version "1.0.7"
resolved "http://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
process@^0.11.1:
version "0.11.10"
resolved "http://npm.yoho.cn/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
promise-mysql@^3.0.1:
version "3.0.2"
resolved "https://registry.yarnpkg.com/promise-mysql/-/promise-mysql-3.0.2.tgz#356e22511c2fa5193c6a4ef187ccec8e4eab7161"
... ... @@ -2916,6 +3071,12 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.1.7:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
rd@^1.1.2:
version "1.1.2"
resolved "http://npm.yoho.cn/rd/-/rd-1.1.2.tgz#86297e2025608ee5576c1b451e6997e679ef6b1d"
dependencies:
"@types/node" "^8.0.20"
read-cmd-shim@~1.0.1:
version "1.0.1"
resolved "http://registry.npm.taobao.org/read-cmd-shim/download/read-cmd-shim-1.0.1.tgz#2d5d157786a37c055d22077c32c53f8329e91c7b"
... ... @@ -2973,7 +3134,7 @@ read@1, read@~1.0.1, read@~1.0.7:
string_decoder "~0.10.x"
util-deprecate "~1.0.1"
readable-stream@2, readable-stream@2.3.3, readable-stream@^2.0.5, readable-stream@^2.1.4:
readable-stream@2, readable-stream@2.3.3, readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.1.4:
version "2.3.3"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c"
dependencies:
... ... @@ -3276,6 +3437,12 @@ safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, s
version "5.1.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
seek-bzip@^1.0.5:
version "1.0.5"
resolved "http://npm.yoho.cn/seek-bzip/-/seek-bzip-1.0.5.tgz#cfe917cb3d274bcffac792758af53173eb1fabdc"
dependencies:
commander "~2.8.1"
semver-diff@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
... ... @@ -3577,6 +3744,21 @@ strip-ansi@^4.0.0:
dependencies:
ansi-regex "^3.0.0"
<<<<<<< HEAD
strip-bom@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
dependencies:
is-utf8 "^0.2.0"
strip-dirs@^2.0.0:
version "2.0.0"
resolved "http://npm.yoho.cn/strip-dirs/-/strip-dirs-2.0.0.tgz#610cdb2928200da0004f41dcb90fc95cd919a0b6"
dependencies:
is-natural-number "^4.0.1"
=======
>>>>>>> master
strip-eof@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
... ... @@ -3641,6 +3823,15 @@ tar-pack@^3.4.0:
tar "^2.2.1"
uid-number "^0.0.6"
tar-stream@^1.5.2:
version "1.5.4"
resolved "http://npm.yoho.cn/tar-stream/-/tar-stream-1.5.4.tgz#36549cf04ed1aee9b2a30c0143252238daf94016"
dependencies:
bl "^1.0.0"
end-of-stream "^1.0.0"
readable-stream "^2.0.0"
xtend "^4.0.0"
tar@^2.0.0, tar@^2.2.1, tar@~2.2.1:
version "2.2.1"
resolved "http://registry.npm.taobao.org/tar/download/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
... ... @@ -3678,7 +3869,7 @@ through2@^0.6.2, through2@^0.6.5:
readable-stream ">=1.0.33-1 <1.1.0-0"
xtend ">=4.0.0 <4.1.0-0"
through@2, through@~2.3, through@~2.3.1, through@~2.3.4, through@~2.3.8:
through@2, through@^2.3.6, through@~2.3, through@~2.3.1, through@~2.3.4, through@~2.3.8:
version "2.3.8"
resolved "http://registry.npm.taobao.org/through/download/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
... ... @@ -3758,6 +3949,13 @@ umask@~1.1.0:
version "1.1.0"
resolved "http://registry.npm.taobao.org/umask/download/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d"
unbzip2-stream@^1.0.9:
version "1.2.5"
resolved "http://npm.yoho.cn/unbzip2-stream/-/unbzip2-stream-1.2.5.tgz#73a033a567bbbde59654b193c44d48a7e4f43c47"
dependencies:
buffer "^3.0.1"
through "^2.3.6"
undefsafe@0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-0.0.3.tgz#ecca3a03e56b9af17385baac812ac83b994a962f"
... ... @@ -3848,6 +4046,12 @@ util-extend@^1.0.1:
version "1.0.3"
resolved "http://registry.npm.taobao.org/util-extend/download/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f"
util@^0.10.3:
version "0.10.3"
resolved "http://npm.yoho.cn/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
dependencies:
inherits "2.0.1"
utility@0.1.11:
version "0.1.11"
resolved "http://registry.npm.taobao.org/utility/download/utility-0.1.11.tgz#fde60cf9b4e4751947a0cf5d104ce29367226715"
... ... @@ -4008,6 +4212,13 @@ yargs@~3.10.0:
decamelize "^1.0.0"
window-size "0.1.0"
yauzl@^2.4.2:
version "2.8.0"
resolved "http://npm.yoho.cn/yauzl/-/yauzl-2.8.0.tgz#79450aff22b2a9c5a41ef54e02db907ccfbf9ee2"
dependencies:
buffer-crc32 "~0.2.3"
fd-slicer "~1.0.1"
yeast@0.1.2:
version "0.1.2"
resolved "http://registry.npm.taobao.org/yeast/download/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
... ...