重新初始化
This commit is contained in:
commit
22429c0735
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/node_modules/
|
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
12
.idea/deploy_server.iml
generated
Normal file
12
.idea/deploy_server.iml
generated
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
6
.idea/jsLibraryMappings.xml
generated
Normal file
6
.idea/jsLibraryMappings.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JavaScriptLibraryMappings">
|
||||||
|
<includedPredefinedLibrary name="Node.js Core" />
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/misc.xml
generated
Normal file
6
.idea/misc.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JavaScriptSettings">
|
||||||
|
<option name="languageLevel" value="ES6" />
|
||||||
|
</component>
|
||||||
|
</project>
|
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/deploy_server.iml" filepath="$PROJECT_DIR$/.idea/deploy_server.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
11
.idea/runConfigurations/bin_www.xml
generated
Normal file
11
.idea/runConfigurations/bin_www.xml
generated
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="bin/www" type="NodeJSConfigurationType" path-to-js-file="bin/www" working-dir="$PROJECT_DIR$">
|
||||||
|
<envs>
|
||||||
|
<env name="DEBUG" value="deploy-server:*" />
|
||||||
|
</envs>
|
||||||
|
<EXTENSION ID="com.jetbrains.nodejs.run.NodeJSStartBrowserRunConfigurationExtension">
|
||||||
|
<browser url="http://localhost:3000/" />
|
||||||
|
</EXTENSION>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
24
app.js
Normal file
24
app.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const path = require('path');
|
||||||
|
const cookieParser = require('cookie-parser');
|
||||||
|
const logger = require('morgan');
|
||||||
|
const bodyParser = require('body-parser');
|
||||||
|
|
||||||
|
const indexRouter = require('./routes/index');
|
||||||
|
const projectRouter = require('./routes/project');
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
app.use(logger('dev'));
|
||||||
|
app.use(express.json());
|
||||||
|
app.use(bodyParser.urlencoded({
|
||||||
|
extended:true
|
||||||
|
}));
|
||||||
|
app.use(express.urlencoded({ extended: false }));
|
||||||
|
app.use(cookieParser());
|
||||||
|
app.use(express.static(path.join(__dirname, 'public')));
|
||||||
|
|
||||||
|
app.use('/', indexRouter);
|
||||||
|
app.use('/project', projectRouter);
|
||||||
|
|
||||||
|
module.exports = app;
|
92
bin/www
Normal file
92
bin/www
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var app = require('../app');
|
||||||
|
var debug = require('debug')('deploy-server:server');
|
||||||
|
var http = require('http');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get port from environment and store in Express.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var port = normalizePort(process.env.PORT || '3000');
|
||||||
|
app.set('port', port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create HTTP server.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var server = http.createServer(app);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen on provided port, on all network interfaces.
|
||||||
|
*/
|
||||||
|
|
||||||
|
server.listen(port,()=>{
|
||||||
|
console.log( `server run at http://localhost:${port}/`)
|
||||||
|
});
|
||||||
|
server.on('error', onError);
|
||||||
|
server.on('listening', onListening);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize a port into a number, string, or false.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function normalizePort(val) {
|
||||||
|
var port = parseInt(val, 10);
|
||||||
|
|
||||||
|
if (isNaN(port)) {
|
||||||
|
// named pipe
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port >= 0) {
|
||||||
|
// port number
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event listener for HTTP server "error" event.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function onError(error) {
|
||||||
|
if (error.syscall !== 'listen') {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bind = typeof port === 'string'
|
||||||
|
? 'Pipe ' + port
|
||||||
|
: 'Port ' + port;
|
||||||
|
|
||||||
|
// handle specific listen errors with friendly messages
|
||||||
|
switch (error.code) {
|
||||||
|
case 'EACCES':
|
||||||
|
console.error(bind + ' requires elevated privileges');
|
||||||
|
process.exit(1);
|
||||||
|
break;
|
||||||
|
case 'EADDRINUSE':
|
||||||
|
console.error(bind + ' is already in use');
|
||||||
|
process.exit(1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event listener for HTTP server "listening" event.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function onListening() {
|
||||||
|
var addr = server.address();
|
||||||
|
var bind = typeof addr === 'string'
|
||||||
|
? 'pipe ' + addr
|
||||||
|
: 'port ' + addr.port;
|
||||||
|
debug('Listening on ' + bind);
|
||||||
|
}
|
16
exec.js
Normal file
16
exec.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
const process = require('child_process')
|
||||||
|
|
||||||
|
const workerProcess = process.spawn('sh', ['/Users/yaclty/WebstormProjects/deploy_server/routes/project/1/build.sh']);
|
||||||
|
|
||||||
|
let startTime = Date.now(); // 记录开始时间
|
||||||
|
workerProcess.stdout.on('data', function (execData) {
|
||||||
|
console.log('out:'+ execData)
|
||||||
|
});
|
||||||
|
workerProcess.stderr.on('data', function (execData) {
|
||||||
|
console.log('err', execData.toString())
|
||||||
|
});
|
||||||
|
workerProcess.on('close', function (code) {
|
||||||
|
// 计算使用时间
|
||||||
|
const useTime = Date.now() - startTime;
|
||||||
|
console.log('use time:', useTime);
|
||||||
|
});
|
17
package.json
Normal file
17
package.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "deploy-server",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"start": "node ./bin/www",
|
||||||
|
"dev": "nodemon ./bin/www"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"body-parser": "^1.19.0",
|
||||||
|
"child_process": "^1.0.2",
|
||||||
|
"cookie-parser": "~1.4.4",
|
||||||
|
"debug": "~2.6.9",
|
||||||
|
"express": "~4.16.1",
|
||||||
|
"morgan": "~1.9.1"
|
||||||
|
}
|
||||||
|
}
|
268
public/index.html
Normal file
268
public/index.html
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-cn">
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Deploy Service</title>
|
||||||
|
<link rel="stylesheet"
|
||||||
|
href="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/element-ui/2.15.7/theme-chalk/index.css">
|
||||||
|
<style>
|
||||||
|
#app {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script src="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.js"
|
||||||
|
type="application/javascript"></script>
|
||||||
|
<script src="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/element-ui/2.15.7/index.js"
|
||||||
|
type="application/javascript"></script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<h1>Deploy Service</h1>
|
||||||
|
<el-button @click="dialogVisible = true">新建</el-button>
|
||||||
|
<el-dialog :close-on-click-modal="false" title="新建部署项目" :visible.sync="dialogVisible" width="600">
|
||||||
|
<div>
|
||||||
|
<el-row>
|
||||||
|
<el-input v-model="project.name" placeholder="请输入项目名称"/>
|
||||||
|
</el-row>
|
||||||
|
<div style="margin-top:20px">
|
||||||
|
<el-input type="textarea" :autosize="{ minRows: 3, maxRows: 10}" placeholder="请输入待执行shell内容"
|
||||||
|
v-model="project.shell"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
|
<el-button type="primary" @click="handleCreate">确 定</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
<el-dialog :close-on-click-modal="false" title="项目运行日志" :visible.sync="historyVisible" width="500">
|
||||||
|
<div>
|
||||||
|
<el-table :data="currentHistories" stripe style="width: 100%;">
|
||||||
|
<el-table-column prop="time" label="创建时间"></el-table-column>
|
||||||
|
<el-table-column prop="useTime" label="执行时长" width="100">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{scope.row.useTime}} ms</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="状态" width="100">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{formatStatus(scope.row, true)}}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="lastUpdate" label="" width="100">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<a target="_blank"
|
||||||
|
:href="'./project/history?id=' + currentProject.id
|
||||||
|
+ '&time='+(scope.row.timestamp||scope.row.time)">查看记录</a>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
<el-pagination style="text-align: center;padding-top: 20px;"
|
||||||
|
:hide-on-single-page="true"
|
||||||
|
:total="currentHistory.list.length"
|
||||||
|
:page-size="currentHistory.size"
|
||||||
|
@current-change="onPageChange"
|
||||||
|
layout="prev, pager, next">
|
||||||
|
</el-pagination>
|
||||||
|
<!-- <span slot="footer" class="dialog-footer">-->
|
||||||
|
<!-- <el-button @click="dialogVisible = false">取 消</el-button>-->
|
||||||
|
<!-- <el-button type="primary" @click="handleCreate">确 定</el-button>-->
|
||||||
|
<!-- </span>-->
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog :close-on-click-modal="false" title="编辑脚本内容" :visible.sync="shellModify.visible" width="600">
|
||||||
|
<div>
|
||||||
|
<el-input type="textarea" :autosize="{ minRows: 3, maxRows: 10}" placeholder="请输入待执行shell内容"
|
||||||
|
v-model="shellModify.shell"/>
|
||||||
|
</div>
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="shellModify.visible = false">取 消</el-button>
|
||||||
|
<el-button :loading="shellModify.loading" type="primary" @click="handleModifyShell">确 定</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
<div class="data-list">
|
||||||
|
<el-table :data="projects" stripe border style="width: 100%;margin-top:20px;" size="small">
|
||||||
|
<el-table-column prop="id" label="ID" width="80"></el-table-column>
|
||||||
|
<el-table-column prop="name" label="名称"></el-table-column>
|
||||||
|
<el-table-column prop="create" label="创建时间" width="180"></el-table-column>
|
||||||
|
<el-table-column prop="lastUpdate" label="更新时间" width="220"></el-table-column>
|
||||||
|
<el-table-column label="执行状态" width="100">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{formatStatus(scope.row)}}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" width="250">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button @click="showProjectInfo(scope.row)" type="text" size="small">执行历史</el-button>
|
||||||
|
<el-button @click="execShell(scope.row)" type="text" size="small">执行</el-button>
|
||||||
|
<el-button @click="editShell(scope.row)" type="text" size="small">编辑脚本</el-button>
|
||||||
|
<el-button @click="showHook(scope.row)" type="text" size="small">Hook地址</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<div class="log-list">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
const app = new Vue({
|
||||||
|
el: '#app',
|
||||||
|
async mounted() {
|
||||||
|
let data = await this.requestData('./project/');
|
||||||
|
console.log(data);
|
||||||
|
this.projects = data
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {ProjectInfo} data
|
||||||
|
*/
|
||||||
|
formatStatus(data, isHistory = false) {
|
||||||
|
if (!isHistory && data.running) return '正在执行中';
|
||||||
|
else if ((data.lastStatus || data.status) == 'success') return '成功';
|
||||||
|
return (data.lastStatus || data.status);
|
||||||
|
},
|
||||||
|
requestData(url, data) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let option = {}
|
||||||
|
if (data) {
|
||||||
|
option = {
|
||||||
|
method: 'POST',
|
||||||
|
mode: 'cors',
|
||||||
|
credentials: 'include',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const loading = this.$loading({
|
||||||
|
lock: true,
|
||||||
|
text: '加载中',
|
||||||
|
spinner: 'el-icon-loading',
|
||||||
|
background: 'rgba(0, 0, 0, 0.7)'
|
||||||
|
});
|
||||||
|
fetch(url, option).then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
loading.close()
|
||||||
|
if (data && data.code && data.code != 0) {
|
||||||
|
this.$message.error(data.message);
|
||||||
|
reject()
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve(data)
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
loading.close()
|
||||||
|
this.$message.error('加载数据失败')
|
||||||
|
reject()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async showProjectInfo(rowData) {
|
||||||
|
this.currentProject = rowData;
|
||||||
|
let histories = await this.requestData('./project/' + rowData.id);
|
||||||
|
this.currentHistory.list = histories;
|
||||||
|
this.historyVisible = true;
|
||||||
|
},
|
||||||
|
async handleCreate() {
|
||||||
|
let projects = await this.requestData('./project/create', this.project);
|
||||||
|
this.projects = projects;
|
||||||
|
this.project = {name: '', shell: ''};
|
||||||
|
this.dialogVisible = false;
|
||||||
|
},
|
||||||
|
getExecUrl(rowData) {
|
||||||
|
return location.href.replace(new RegExp('\\/$', 'g'), '') + '/project/hook/' + rowData.id + '?param=test';
|
||||||
|
},
|
||||||
|
execShell(rowData) {
|
||||||
|
this.$confirm('此操作会执行脚本, 是否继续?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(async () => {
|
||||||
|
let data = await this.requestData(this.getExecUrl(rowData));
|
||||||
|
this.$message.info(data.message);
|
||||||
|
}).catch();
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {ProjectInfo} rowData
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async editShell(item) {
|
||||||
|
// this.$message.info('开发中...')
|
||||||
|
try {
|
||||||
|
const data = await this.requestData('./project/shell/' + item.id);
|
||||||
|
this.shellModify = {
|
||||||
|
visible: true,
|
||||||
|
loading: false,
|
||||||
|
shell: data.shell,
|
||||||
|
id: item.id
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
async handleModifyShell() {
|
||||||
|
this.shellModify.loading = true;
|
||||||
|
try {
|
||||||
|
const {id, shell} = this.shellModify
|
||||||
|
const data = await this.requestData('./project/shell/' + id, {shell});
|
||||||
|
this.$message.info('保存脚本内容成功')
|
||||||
|
this.shellModify.visible = false;
|
||||||
|
} catch (e) {
|
||||||
|
} finally {
|
||||||
|
this.shellModify.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showHook(rowData) {
|
||||||
|
this.$alert(this.getExecUrl(rowData), '请自行复制一下链接', {confirmButtonText: '关闭'});
|
||||||
|
},
|
||||||
|
onPageChange(page){
|
||||||
|
this.currentHistory.page = page;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
currentHistories() {
|
||||||
|
const {list, page, size} = this.currentHistory
|
||||||
|
const _list = [];
|
||||||
|
for (let start = 0, i = (page - 1) * size; i < list.length && start < size; i++, start++) {
|
||||||
|
_list.push(list[i]);
|
||||||
|
}
|
||||||
|
return _list;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
shellModify: {
|
||||||
|
visible: false,
|
||||||
|
shell: '',
|
||||||
|
loading: false,
|
||||||
|
id: 0,
|
||||||
|
},
|
||||||
|
dialogVisible: false,
|
||||||
|
historyVisible: false,
|
||||||
|
histories: [],
|
||||||
|
currentHistory: {
|
||||||
|
list: [],
|
||||||
|
size: 10,
|
||||||
|
page: 1
|
||||||
|
},
|
||||||
|
currentProject: {id: 0},
|
||||||
|
project: {
|
||||||
|
name: '',
|
||||||
|
shell: ''
|
||||||
|
},
|
||||||
|
projects: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
0
public/stylesheets/style.css
Normal file
0
public/stylesheets/style.css
Normal file
9
routes/index.js
Normal file
9
routes/index.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
var express = require('express');
|
||||||
|
var router = express.Router();
|
||||||
|
|
||||||
|
/* GET home page. */
|
||||||
|
router.get('/', function(req, res, next) {
|
||||||
|
res.render('index', { title: 'Projects' });
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
211
routes/project.js
Normal file
211
routes/project.js
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const process = require('child_process');
|
||||||
|
const projectsFile = path.join(__dirname, 'project')
|
||||||
|
|
||||||
|
const getDatetime = (fmt = "YYYY-mm-dd HH:MM", date) => {
|
||||||
|
date = date || new Date();
|
||||||
|
|
||||||
|
let ret;
|
||||||
|
const opt = {
|
||||||
|
"Y+": date.getFullYear().toString(), // 年
|
||||||
|
"m+": (date.getMonth() + 1).toString(), // 月
|
||||||
|
"d+": date.getDate().toString(), // 日
|
||||||
|
"H+": date.getHours().toString(), // 时
|
||||||
|
"M+": date.getMinutes().toString(), // 分
|
||||||
|
"S+": date.getSeconds().toString() // 秒
|
||||||
|
// 有其他格式化字符需求可以继续添加,必须转化成字符串
|
||||||
|
};
|
||||||
|
for (let k in opt) {
|
||||||
|
ret = new RegExp("(" + k + ")").exec(fmt);
|
||||||
|
if (ret) {
|
||||||
|
fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
return fmt;
|
||||||
|
}
|
||||||
|
router.get('/', function (req, res, next) {
|
||||||
|
const data = fs.readFileSync(projectsFile + '/index.json');
|
||||||
|
res.json(JSON.parse(data.toString()))
|
||||||
|
});
|
||||||
|
router.get('/history', (req, res, next) => {
|
||||||
|
let {id, time} = req.query;
|
||||||
|
|
||||||
|
const fileName = projectsFile + '/' + id + '/' + time + '.log';
|
||||||
|
if (!fs.existsSync(fileName)) {
|
||||||
|
res.json({code: 1, message: "日志不存在", fileName});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res.sendFile(fileName, {}, function (err) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 读取编译记录
|
||||||
|
router.get('/:id', function (req, res, next) {
|
||||||
|
const id = req.params.id;
|
||||||
|
const file = projectsFile + '/' + id + '/index.json';
|
||||||
|
|
||||||
|
if (!fs.existsSync(file)) {
|
||||||
|
res.json({code: 1, message: "项目不存在"});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const data = fs.readFileSync(file);
|
||||||
|
res.json(JSON.parse(data.toString()))
|
||||||
|
});
|
||||||
|
router.get('/shell/:id', (req, res) => {
|
||||||
|
const path = projectsFile + '/' + req.params.id + '/build.sh';
|
||||||
|
if (!fs.existsSync(path)) {
|
||||||
|
res.send({code: 1, message: '脚本文件不存在'})
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const shell = fs.readFileSync(path,{encoding:'utf-8'})
|
||||||
|
res.send({code: 0, shell})
|
||||||
|
});
|
||||||
|
router.post('/shell/:id', (req, res) => {
|
||||||
|
const path = projectsFile + '/' + req.params.id + '/build.sh';
|
||||||
|
if (!fs.existsSync(path)) {
|
||||||
|
res.send({code: 1, message: '脚本文件文件不存在'})
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const shell = req.body.shell;
|
||||||
|
fs.writeFileSync(path, shell,{encoding:"utf-8"})
|
||||||
|
res.send({code: 0})
|
||||||
|
});
|
||||||
|
|
||||||
|
const writeExecLog = (id, status, running = false) => {
|
||||||
|
const data = JSON.parse(fs.readFileSync(projectsFile + '/index.json'));
|
||||||
|
data[id - 1].lastUpdate = getDatetime('YYYY-mm-dd HH:MM:SS');
|
||||||
|
data[id - 1].lastStatus = status;
|
||||||
|
data[id - 1].running = running;
|
||||||
|
|
||||||
|
fs.writeFile(projectsFile + '/index.json', JSON.stringify(data), (err1) => {
|
||||||
|
if (err1) {
|
||||||
|
console.log('writeExecLog:write project file fail')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行
|
||||||
|
router.all('/hook/:id', function (req, res, next) {
|
||||||
|
const id = parseInt(req.params.id);
|
||||||
|
const projects = JSON.parse(fs.readFileSync(projectsFile + '/index.json',{encoding:'utf-8'}));
|
||||||
|
if (id < 1 || id > projects.length) {
|
||||||
|
res.json({code: 1, message: "项目不存在(1)"});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (projects[id - 1].running) {
|
||||||
|
res.json({code: 3, message: "当前项目脚本正在运行中"});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const file = projectsFile + '/' + id + '/build.sh';
|
||||||
|
if (!fs.existsSync(file)) {
|
||||||
|
res.json({code: 1, message: "项目不存在(2)"});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res.json({code: 0, message: "开始执行脚本,请稍后查看运行结果"});
|
||||||
|
|
||||||
|
// 历史记录
|
||||||
|
fs.readFile(projectsFile + '/' + id + '/index.json', (err, data) => {
|
||||||
|
if (err) {
|
||||||
|
console.log('read project {', id, '} history failed', err)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const histories = JSON.parse(data.toString());
|
||||||
|
const currentTime = getDatetime('YYYY-mm-dd HH:MM:SS'),timeNow = Date.now();
|
||||||
|
// 开始执行脚本
|
||||||
|
fs.open(projectsFile + '/' + id + '/' + timeNow + '.log', 'a', function (err, fd) {
|
||||||
|
if (err) { // 操作日志失败了
|
||||||
|
writeExecLog(id, 'fail');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
writeExecLog(id, null, true); // 运行中
|
||||||
|
let isFailed = -1;
|
||||||
|
const workerProcess = process.spawn('sh', [file]);
|
||||||
|
let startTime = Date.now(); // 记录开始时间
|
||||||
|
workerProcess.stdout.on('data', (execData) => {
|
||||||
|
let line = execData.toString().trim();
|
||||||
|
console.log('out:', line);
|
||||||
|
if (line == 'execute success') {
|
||||||
|
isFailed = 1;
|
||||||
|
} else if (line == 'execute fail') {
|
||||||
|
isFailed = 0;
|
||||||
|
}
|
||||||
|
fs.writeSync(fd, line); // 写入日志
|
||||||
|
});
|
||||||
|
workerProcess.stderr.on('data', (execData) => {
|
||||||
|
console.log('err:', execData.toString())
|
||||||
|
fs.writeSync(fd, execData.toString()); // 写入日志
|
||||||
|
// isFailed = true;
|
||||||
|
});
|
||||||
|
workerProcess.on('close', function (code) {
|
||||||
|
// 计算使用时间
|
||||||
|
const useTime = Date.now() - startTime;
|
||||||
|
let status = isFailed == -1 ? '未知' : (isFailed == 1 ? '成功' : '失败');
|
||||||
|
histories.push({
|
||||||
|
time: currentTime,
|
||||||
|
timestamp:timeNow,
|
||||||
|
status,
|
||||||
|
useTime
|
||||||
|
})
|
||||||
|
// 写入记录
|
||||||
|
fs.writeFileSync(projectsFile + '/' + id + '/index.json', JSON.stringify(histories));
|
||||||
|
writeExecLog(id, status)
|
||||||
|
fs.close(fd, function (err) {
|
||||||
|
if (err) {
|
||||||
|
console.log('close file error', err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
//创建项目
|
||||||
|
router.post('/create', (req, res, next) => {
|
||||||
|
const data = JSON.parse(fs.readFileSync(projectsFile + '/index.json'));
|
||||||
|
let id = data.length + 1;
|
||||||
|
|
||||||
|
let {name, shell} = req.body;
|
||||||
|
if (!name || !shell) {
|
||||||
|
res.json({code: 1, message: "参数不能为空"})
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fs.mkdirSync(projectsFile + '/' + id); // 创建项目目录
|
||||||
|
// 创建记录文件
|
||||||
|
fs.writeFile(projectsFile + '/' + id + '/index.json', '[]', function (err) {
|
||||||
|
fs.writeFile(projectsFile + '/' + id + '/build.sh', shell, (err1) => {
|
||||||
|
if (err1) {
|
||||||
|
console.log('create shell success')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (err) {
|
||||||
|
res.json({code: 2, message: "创建项目失败"})
|
||||||
|
}
|
||||||
|
data.push({
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
create: getDatetime(),
|
||||||
|
lastUpdate: null,
|
||||||
|
lastStatus: "",
|
||||||
|
running: false
|
||||||
|
})
|
||||||
|
fs.writeFile(projectsFile + '/index.json', JSON.stringify(data), (err1) => {
|
||||||
|
if (err1) {
|
||||||
|
console.log('create project fail')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
res.json(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = router;
|
1
routes/project/1/123123.log
Normal file
1
routes/project/1/123123.log
Normal file
@ -0,0 +1 @@
|
|||||||
|
12123
|
10
routes/project/1/build.sh
Normal file
10
routes/project/1/build.sh
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
for ((j=1;j<=10;j++))
|
||||||
|
do
|
||||||
|
echo "♥ $j ♥"
|
||||||
|
if (( $j < 3 ))
|
||||||
|
then
|
||||||
|
sleep 1
|
||||||
|
fi
|
||||||
|
done
|
3
routes/project/1/index.json
Normal file
3
routes/project/1/index.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[{"time":"2020-02-23 18:01:16","status":"success","useTime":2012},{"time":"2020-02-23 18:06:00","status":"success","useTime":2016,
|
||||||
|
"timestamp": 123123
|
||||||
|
}]
|
1
routes/project/index.json
Normal file
1
routes/project/index.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[{"id":1,"name":"test","create":"2020-02-23 18:00","lastUpdate":"2020-02-23 18:06:02","lastStatus":"success","running":false}]
|
9
types.d.ts
vendored
Normal file
9
types.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
declare type ProjectInfo = {
|
||||||
|
create: String
|
||||||
|
id: number
|
||||||
|
lastStatus: "success" | String
|
||||||
|
status: "success" | String
|
||||||
|
lastUpdate: String
|
||||||
|
name: String
|
||||||
|
running: boolean
|
||||||
|
}
|
444
yarn.lock
Normal file
444
yarn.lock
Normal file
@ -0,0 +1,444 @@
|
|||||||
|
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||||
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
accepts@~1.3.5:
|
||||||
|
version "1.3.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
|
||||||
|
integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
|
||||||
|
dependencies:
|
||||||
|
mime-types "~2.1.24"
|
||||||
|
negotiator "0.6.2"
|
||||||
|
|
||||||
|
array-flatten@1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
|
||||||
|
integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
|
||||||
|
|
||||||
|
basic-auth@~2.0.0:
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a"
|
||||||
|
integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==
|
||||||
|
dependencies:
|
||||||
|
safe-buffer "5.1.2"
|
||||||
|
|
||||||
|
body-parser@1.18.3:
|
||||||
|
version "1.18.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4"
|
||||||
|
integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=
|
||||||
|
dependencies:
|
||||||
|
bytes "3.0.0"
|
||||||
|
content-type "~1.0.4"
|
||||||
|
debug "2.6.9"
|
||||||
|
depd "~1.1.2"
|
||||||
|
http-errors "~1.6.3"
|
||||||
|
iconv-lite "0.4.23"
|
||||||
|
on-finished "~2.3.0"
|
||||||
|
qs "6.5.2"
|
||||||
|
raw-body "2.3.3"
|
||||||
|
type-is "~1.6.16"
|
||||||
|
|
||||||
|
body-parser@^1.19.0:
|
||||||
|
version "1.19.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
|
||||||
|
integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
|
||||||
|
dependencies:
|
||||||
|
bytes "3.1.0"
|
||||||
|
content-type "~1.0.4"
|
||||||
|
debug "2.6.9"
|
||||||
|
depd "~1.1.2"
|
||||||
|
http-errors "1.7.2"
|
||||||
|
iconv-lite "0.4.24"
|
||||||
|
on-finished "~2.3.0"
|
||||||
|
qs "6.7.0"
|
||||||
|
raw-body "2.4.0"
|
||||||
|
type-is "~1.6.17"
|
||||||
|
|
||||||
|
bytes@3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
|
||||||
|
integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
|
||||||
|
|
||||||
|
bytes@3.1.0:
|
||||||
|
version "3.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
|
||||||
|
integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
|
||||||
|
|
||||||
|
child_process@^1.0.2:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/child_process/-/child_process-1.0.2.tgz#b1f7e7fc73d25e7fd1d455adc94e143830182b5a"
|
||||||
|
integrity sha1-sffn/HPSXn/R1FWtyU4UODAYK1o=
|
||||||
|
|
||||||
|
content-disposition@0.5.2:
|
||||||
|
version "0.5.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
|
||||||
|
integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ=
|
||||||
|
|
||||||
|
content-type@~1.0.4:
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
|
||||||
|
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
|
||||||
|
|
||||||
|
cookie-parser@~1.4.4:
|
||||||
|
version "1.4.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/cookie-parser/-/cookie-parser-1.4.4.tgz#e6363de4ea98c3def9697b93421c09f30cf5d188"
|
||||||
|
integrity sha512-lo13tqF3JEtFO7FyA49CqbhaFkskRJ0u/UAiINgrIXeRCY41c88/zxtrECl8AKH3B0hj9q10+h3Kt8I7KlW4tw==
|
||||||
|
dependencies:
|
||||||
|
cookie "0.3.1"
|
||||||
|
cookie-signature "1.0.6"
|
||||||
|
|
||||||
|
cookie-signature@1.0.6:
|
||||||
|
version "1.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
|
||||||
|
integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
|
||||||
|
|
||||||
|
cookie@0.3.1:
|
||||||
|
version "0.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
|
||||||
|
integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
|
||||||
|
|
||||||
|
debug@2.6.9, debug@~2.6.9:
|
||||||
|
version "2.6.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||||
|
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
|
||||||
|
dependencies:
|
||||||
|
ms "2.0.0"
|
||||||
|
|
||||||
|
depd@~1.1.2:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
|
||||||
|
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
|
||||||
|
|
||||||
|
destroy@~1.0.4:
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
|
||||||
|
integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
|
||||||
|
|
||||||
|
ee-first@1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
||||||
|
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
|
||||||
|
|
||||||
|
encodeurl@~1.0.2:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
|
||||||
|
integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
|
||||||
|
|
||||||
|
escape-html@~1.0.3:
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
||||||
|
integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
|
||||||
|
|
||||||
|
etag@~1.8.1:
|
||||||
|
version "1.8.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
|
||||||
|
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
|
||||||
|
|
||||||
|
express@~4.16.1:
|
||||||
|
version "4.16.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e"
|
||||||
|
integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==
|
||||||
|
dependencies:
|
||||||
|
accepts "~1.3.5"
|
||||||
|
array-flatten "1.1.1"
|
||||||
|
body-parser "1.18.3"
|
||||||
|
content-disposition "0.5.2"
|
||||||
|
content-type "~1.0.4"
|
||||||
|
cookie "0.3.1"
|
||||||
|
cookie-signature "1.0.6"
|
||||||
|
debug "2.6.9"
|
||||||
|
depd "~1.1.2"
|
||||||
|
encodeurl "~1.0.2"
|
||||||
|
escape-html "~1.0.3"
|
||||||
|
etag "~1.8.1"
|
||||||
|
finalhandler "1.1.1"
|
||||||
|
fresh "0.5.2"
|
||||||
|
merge-descriptors "1.0.1"
|
||||||
|
methods "~1.1.2"
|
||||||
|
on-finished "~2.3.0"
|
||||||
|
parseurl "~1.3.2"
|
||||||
|
path-to-regexp "0.1.7"
|
||||||
|
proxy-addr "~2.0.4"
|
||||||
|
qs "6.5.2"
|
||||||
|
range-parser "~1.2.0"
|
||||||
|
safe-buffer "5.1.2"
|
||||||
|
send "0.16.2"
|
||||||
|
serve-static "1.13.2"
|
||||||
|
setprototypeof "1.1.0"
|
||||||
|
statuses "~1.4.0"
|
||||||
|
type-is "~1.6.16"
|
||||||
|
utils-merge "1.0.1"
|
||||||
|
vary "~1.1.2"
|
||||||
|
|
||||||
|
finalhandler@1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105"
|
||||||
|
integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==
|
||||||
|
dependencies:
|
||||||
|
debug "2.6.9"
|
||||||
|
encodeurl "~1.0.2"
|
||||||
|
escape-html "~1.0.3"
|
||||||
|
on-finished "~2.3.0"
|
||||||
|
parseurl "~1.3.2"
|
||||||
|
statuses "~1.4.0"
|
||||||
|
unpipe "~1.0.0"
|
||||||
|
|
||||||
|
forwarded@~0.1.2:
|
||||||
|
version "0.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
|
||||||
|
integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
|
||||||
|
|
||||||
|
fresh@0.5.2:
|
||||||
|
version "0.5.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
|
||||||
|
integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
|
||||||
|
|
||||||
|
http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3:
|
||||||
|
version "1.6.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
|
||||||
|
integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=
|
||||||
|
dependencies:
|
||||||
|
depd "~1.1.2"
|
||||||
|
inherits "2.0.3"
|
||||||
|
setprototypeof "1.1.0"
|
||||||
|
statuses ">= 1.4.0 < 2"
|
||||||
|
|
||||||
|
http-errors@1.7.2:
|
||||||
|
version "1.7.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
|
||||||
|
integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
|
||||||
|
dependencies:
|
||||||
|
depd "~1.1.2"
|
||||||
|
inherits "2.0.3"
|
||||||
|
setprototypeof "1.1.1"
|
||||||
|
statuses ">= 1.5.0 < 2"
|
||||||
|
toidentifier "1.0.0"
|
||||||
|
|
||||||
|
iconv-lite@0.4.23:
|
||||||
|
version "0.4.23"
|
||||||
|
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
|
||||||
|
integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==
|
||||||
|
dependencies:
|
||||||
|
safer-buffer ">= 2.1.2 < 3"
|
||||||
|
|
||||||
|
iconv-lite@0.4.24:
|
||||||
|
version "0.4.24"
|
||||||
|
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||||
|
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
|
||||||
|
dependencies:
|
||||||
|
safer-buffer ">= 2.1.2 < 3"
|
||||||
|
|
||||||
|
inherits@2.0.3:
|
||||||
|
version "2.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||||
|
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
||||||
|
|
||||||
|
ipaddr.js@1.9.0:
|
||||||
|
version "1.9.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65"
|
||||||
|
integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==
|
||||||
|
|
||||||
|
media-typer@0.3.0:
|
||||||
|
version "0.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||||
|
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
|
||||||
|
|
||||||
|
merge-descriptors@1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
|
||||||
|
integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
|
||||||
|
|
||||||
|
methods@~1.1.2:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
|
||||||
|
integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
|
||||||
|
|
||||||
|
mime-db@1.43.0:
|
||||||
|
version "1.43.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58"
|
||||||
|
integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==
|
||||||
|
|
||||||
|
mime-types@~2.1.24:
|
||||||
|
version "2.1.26"
|
||||||
|
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06"
|
||||||
|
integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==
|
||||||
|
dependencies:
|
||||||
|
mime-db "1.43.0"
|
||||||
|
|
||||||
|
mime@1.4.1:
|
||||||
|
version "1.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
|
||||||
|
integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==
|
||||||
|
|
||||||
|
morgan@~1.9.1:
|
||||||
|
version "1.9.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.9.1.tgz#0a8d16734a1d9afbc824b99df87e738e58e2da59"
|
||||||
|
integrity sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==
|
||||||
|
dependencies:
|
||||||
|
basic-auth "~2.0.0"
|
||||||
|
debug "2.6.9"
|
||||||
|
depd "~1.1.2"
|
||||||
|
on-finished "~2.3.0"
|
||||||
|
on-headers "~1.0.1"
|
||||||
|
|
||||||
|
ms@2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||||
|
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
|
||||||
|
|
||||||
|
negotiator@0.6.2:
|
||||||
|
version "0.6.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
|
||||||
|
integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
|
||||||
|
|
||||||
|
on-finished@~2.3.0:
|
||||||
|
version "2.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
|
||||||
|
integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
|
||||||
|
dependencies:
|
||||||
|
ee-first "1.1.1"
|
||||||
|
|
||||||
|
on-headers@~1.0.1:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
|
||||||
|
integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
|
||||||
|
|
||||||
|
parseurl@~1.3.2:
|
||||||
|
version "1.3.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
|
||||||
|
integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
|
||||||
|
|
||||||
|
path-to-regexp@0.1.7:
|
||||||
|
version "0.1.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
|
||||||
|
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
|
||||||
|
|
||||||
|
proxy-addr@~2.0.4:
|
||||||
|
version "2.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34"
|
||||||
|
integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==
|
||||||
|
dependencies:
|
||||||
|
forwarded "~0.1.2"
|
||||||
|
ipaddr.js "1.9.0"
|
||||||
|
|
||||||
|
qs@6.5.2:
|
||||||
|
version "6.5.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
||||||
|
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
|
||||||
|
|
||||||
|
qs@6.7.0:
|
||||||
|
version "6.7.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
||||||
|
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
|
||||||
|
|
||||||
|
range-parser@~1.2.0:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
|
||||||
|
integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
|
||||||
|
|
||||||
|
raw-body@2.3.3:
|
||||||
|
version "2.3.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3"
|
||||||
|
integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==
|
||||||
|
dependencies:
|
||||||
|
bytes "3.0.0"
|
||||||
|
http-errors "1.6.3"
|
||||||
|
iconv-lite "0.4.23"
|
||||||
|
unpipe "1.0.0"
|
||||||
|
|
||||||
|
raw-body@2.4.0:
|
||||||
|
version "2.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332"
|
||||||
|
integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==
|
||||||
|
dependencies:
|
||||||
|
bytes "3.1.0"
|
||||||
|
http-errors "1.7.2"
|
||||||
|
iconv-lite "0.4.24"
|
||||||
|
unpipe "1.0.0"
|
||||||
|
|
||||||
|
safe-buffer@5.1.2:
|
||||||
|
version "5.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||||
|
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||||
|
|
||||||
|
"safer-buffer@>= 2.1.2 < 3":
|
||||||
|
version "2.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||||
|
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||||
|
|
||||||
|
send@0.16.2:
|
||||||
|
version "0.16.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1"
|
||||||
|
integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==
|
||||||
|
dependencies:
|
||||||
|
debug "2.6.9"
|
||||||
|
depd "~1.1.2"
|
||||||
|
destroy "~1.0.4"
|
||||||
|
encodeurl "~1.0.2"
|
||||||
|
escape-html "~1.0.3"
|
||||||
|
etag "~1.8.1"
|
||||||
|
fresh "0.5.2"
|
||||||
|
http-errors "~1.6.2"
|
||||||
|
mime "1.4.1"
|
||||||
|
ms "2.0.0"
|
||||||
|
on-finished "~2.3.0"
|
||||||
|
range-parser "~1.2.0"
|
||||||
|
statuses "~1.4.0"
|
||||||
|
|
||||||
|
serve-static@1.13.2:
|
||||||
|
version "1.13.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1"
|
||||||
|
integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==
|
||||||
|
dependencies:
|
||||||
|
encodeurl "~1.0.2"
|
||||||
|
escape-html "~1.0.3"
|
||||||
|
parseurl "~1.3.2"
|
||||||
|
send "0.16.2"
|
||||||
|
|
||||||
|
setprototypeof@1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
|
||||||
|
integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
|
||||||
|
|
||||||
|
setprototypeof@1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
|
||||||
|
integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
|
||||||
|
|
||||||
|
"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2":
|
||||||
|
version "1.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
|
||||||
|
integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
|
||||||
|
|
||||||
|
statuses@~1.4.0:
|
||||||
|
version "1.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
|
||||||
|
integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==
|
||||||
|
|
||||||
|
toidentifier@1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
|
||||||
|
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
|
||||||
|
|
||||||
|
type-is@~1.6.16, type-is@~1.6.17:
|
||||||
|
version "1.6.18"
|
||||||
|
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
|
||||||
|
integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
|
||||||
|
dependencies:
|
||||||
|
media-typer "0.3.0"
|
||||||
|
mime-types "~2.1.24"
|
||||||
|
|
||||||
|
unpipe@1.0.0, unpipe@~1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
|
||||||
|
integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
|
||||||
|
|
||||||
|
utils-merge@1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
||||||
|
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
|
||||||
|
|
||||||
|
vary@~1.1.2:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||||
|
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
|
Loading…
x
Reference in New Issue
Block a user