Skip to content

Commit 7f20e59

Browse files
wj-publish
1 parent cee6e17 commit 7f20e59

File tree

6 files changed

+273
-0
lines changed

6 files changed

+273
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,4 @@ typings/
7171
Note/oss-upload/.wj.config.js
7272
Deploy/minikube/registry/data
7373
Guides/node-start/node-v10.16.0/**
74+
Project/node-sh/test.json

Project/node-sh/bin/wj-publish.js

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#!/usr/bin/env node
2+
3+
const program = require('commander');
4+
const fs = require('fs');
5+
const path = require('path');
6+
const { promisify } = require('util');
7+
const Publish = require('../lib/publish');
8+
const packageJson = require('../package');
9+
program.version(packageJson.version, '-v, --version');
10+
11+
/*
12+
* 根据配置文件路径执行发布操作
13+
* */
14+
async function publishWithConfigFile(configPath) {
15+
16+
configPath = path.resolve(process.cwd(), configPath);
17+
const stat = await promisify(fs.stat).call(fs, configPath);
18+
if (!stat.isFile()) {
19+
throw new Error('please input valid config file path');
20+
}
21+
22+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
23+
console.log(`bengin publish ${config.host} ${config.remote}`);
24+
const pub = new Publish(config);
25+
await pub.publish();
26+
return `publish end`;
27+
}
28+
29+
async function exportExampleConfig(configPath) {
30+
const defaultConfig = {
31+
"host": "192.168.1.1",
32+
"port": 22,
33+
"username": "home",
34+
"privateKey": "/Users/xxx/Desktop/xxx/ssh/xxx",
35+
"passphrase": "xxx",
36+
"local": "/Users/xxx/Desktop/Project/xxx",
37+
"remote": "/home/xxx/",
38+
"ignore": [
39+
".idea",
40+
".git",
41+
"node_modules"
42+
],
43+
"clear": true,
44+
"cmds": [
45+
"ls -al"
46+
]
47+
};
48+
49+
const json = JSON.stringify(defaultConfig, null, 4);
50+
configPath = path.resolve(process.cwd(), configPath);
51+
fs.writeFileSync(configPath, json);
52+
}
53+
54+
program
55+
.command('<configPath>', 'publish with config file')
56+
.action(function (configPath) {
57+
publishWithConfigFile(configPath).then(console.log).catch(console.error);
58+
})
59+
.command('example <configPath>')
60+
.action(function (configPath) {
61+
exportExampleConfig(configPath).then(console.log).catch(console.error);
62+
});
63+
program.parse(process.argv);
64+

Project/node-sh/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
const Publish = require('./lib/publish');
2+
module.exports = Publish;

Project/node-sh/lib/publish.js

+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
const { promisify } = require('util');
2+
const fs = require('fs');
3+
const path = require('path');
4+
const Client = require('ssh2').Client;
5+
6+
7+
class Publish {
8+
constructor(config) {
9+
/*
10+
* ip
11+
* port
12+
* username
13+
* privateKey
14+
* passphrase
15+
*
16+
* local: ''
17+
* remote: ''
18+
* ignore: []
19+
* clear: true/false
20+
* cmds: []
21+
* */
22+
this.config = Object.assign({}, config);
23+
this.connection = undefined;
24+
this.sftp = undefined;
25+
this.config.ignore = (this.config.ignore || []).map(p => {
26+
if (path.isAbsolute(p)) {
27+
return path.normalize(p)
28+
}
29+
return path.resolve(this.config.local, p);
30+
});
31+
this.config.privateKey = fs.readFileSync(this.config.privateKey, 'utf-8');
32+
}
33+
34+
async getConnection() {
35+
if (this.connection) return this.connection;
36+
const con = new Client();
37+
return new Promise((resolve, reject) => {
38+
con.on('ready', ()=> {
39+
this.connection = con;
40+
return resolve(con);
41+
});
42+
con.on('error', (error) => {
43+
console.log(`getConnection error`);
44+
console.log(error);
45+
return reject(error);
46+
});
47+
con.connect({
48+
host: '39.105.35.151',
49+
port: 22,
50+
username: 'root',
51+
privateKey: fs.readFileSync('/Users/wangjun/Desktop/important/ssh/wj_server'),
52+
passphrase: 'xinshang2011'
53+
});
54+
});
55+
}
56+
57+
async getSftp() {
58+
59+
if (!this.connection) await this.getConnection();
60+
if (this.sftp) return this.sftp;
61+
this.sftp = await promisify(this.connection.sftp).call(this.connection);
62+
}
63+
64+
async ensureRemoteDir(dirPath) {
65+
await this.getConnection();
66+
await this.getSftp();
67+
return new Promise((resolve, reject) => {
68+
this.sftp.exists(dirPath, (exists) => {
69+
if (exists) return resolve();
70+
this.execCmd(`mkdir -p ${dirPath}`).then(resolve).catch(reject);
71+
});
72+
});
73+
}
74+
75+
async uploadFile(from, dest) {
76+
if (this.ignorePath(from)) return ;
77+
await this.getSftp();
78+
console.log(`upload ${from} to ${dest}`);
79+
const data = await promisify(fs.readFile).call(fs, from);
80+
await promisify(this.sftp.writeFile).call(this.sftp, dest, data);
81+
}
82+
83+
async uploadDir(from, dest) {
84+
if (this.ignorePath(from)) return;
85+
await this.ensureRemoteDir(dest);
86+
const files = await promisify(fs.readdir).call(fs, from);
87+
88+
for (let i=0; i<files.length; i++) {
89+
const file = files[i];
90+
const stat = await promisify(fs.stat).call(fs, path.resolve(from, file));
91+
if (stat.isDirectory()) {
92+
await this.uploadDir(path.resolve(from, file), path.resolve(dest, file))
93+
} else if (stat.isFile()) {
94+
await this.uploadFile(path.resolve(from, file), path.resolve(dest, file));
95+
}
96+
}
97+
98+
// await Promise.all(files.map(async file => {
99+
// const stat = await promisify(fs.stat).call(fs, path.resolve(from, file));
100+
// if (stat.isDirectory()) {
101+
// await this.uploadDir(path.resolve(from, file), path.resolve(dest, file))
102+
// } else if (stat.isFile()) {
103+
// await this.uploadFile(path.resolve(from, file), path.resolve(dest, file));
104+
// }
105+
// }));
106+
}
107+
108+
async execCmd(cmd) {
109+
await this.getConnection();
110+
const stream = await promisify(this.connection.exec).call(this.connection, cmd);
111+
return new Promise((resolve, reject) => {
112+
let data = '';
113+
let err = '';
114+
stream.on('data', chunk => {
115+
data += chunk;
116+
}).stderr.on('data', chunk => {
117+
err += chunk;
118+
}).on('close', () => {
119+
if (err) console.error(`execCmd error ${cmd}`);
120+
if (err) return reject(err);
121+
return resolve(data);
122+
});
123+
});
124+
}
125+
126+
ignorePath(checkPath) {
127+
return this.config.ignore.includes(path.normalize(checkPath))
128+
}
129+
130+
async execCmds() {
131+
const { cmds } = this.config;
132+
if (!cmds || cmds.length <= 0) return ;
133+
let ret = [];
134+
for (let i = 0; i < cmds.length; i++) {
135+
ret.push(await this.execCmd(cmds[i]));
136+
}
137+
return ret;
138+
}
139+
140+
async publish() {
141+
try {
142+
if (this.config.clear) await this.execCmd(`rm -rf ${this.config.remote} && echo clear success`);
143+
const stat = await promisify(fs.stat).call(fs, this.config.local);
144+
if (stat.isDirectory()) {
145+
await this.uploadDir(this.config.local, this.config.remote);
146+
} else if (stat.isFile()) {
147+
await this.uploadFile(this.config.local, this.config.remote);
148+
} else {
149+
throw new Error('unsupported upload type')
150+
}
151+
const res = await this.execCmds();
152+
res.forEach(m => console.log(m));
153+
this.destroy();
154+
} catch (e) {
155+
console.log(e);
156+
this.destroy();
157+
throw e;
158+
}
159+
160+
};
161+
162+
destroy() {
163+
if (this.connection && typeof this.connection.end === 'function') this.connection.end();
164+
this.connection = undefined;
165+
if (this.sftp) this.sftp = undefined;
166+
}
167+
}
168+
169+
170+
module.exports = Publish;

Project/node-sh/package.json

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "publish",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"bin": {
7+
"wj-publish": "bin/wj-publish.js"
8+
},
9+
"scripts": {
10+
"test": "mocha",
11+
"cov": "nyc npm run test"
12+
},
13+
"author": "wang-jun-coder",
14+
"license": "ISC",
15+
"dependencies": {
16+
"commander": "^3.0.1",
17+
"nyc": "^14.1.1",
18+
"ssh2": "^0.8.5"
19+
},
20+
"devDependencies": {
21+
"chai": "^4.2.0",
22+
"mocha": "^6.2.0"
23+
}
24+
}
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const { expect } = require('chai');
2+
const Publish = require('../lib/publish');
3+
describe('publish test', function () {
4+
5+
it('should publish success', async function () {
6+
this.timeout(100 *1000);
7+
8+
const config = require('../test.json');
9+
const pub = new Publish(config);
10+
await pub.publish();
11+
});
12+
});

0 commit comments

Comments
 (0)