Skip to content

Commit 77dd146

Browse files
committed
added zip support with encryption and tty support
1 parent cd4fcf3 commit 77dd146

File tree

7 files changed

+244
-23
lines changed

7 files changed

+244
-23
lines changed

package-lock.json

Lines changed: 112 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
"description": "Easy backup script for webspaces",
55
"main": "index.js",
66
"scripts": {
7-
"prestart": "tsc",
8-
"start": "cp src/config.json dist/config.json && node dist/environments/app.dev.js",
7+
"prestart": "tsc && cp src/config.json dist/config.json",
8+
"start": "node dist/environments/app.dev.js",
99
"test": "node test.js",
1010
"build": "sh ./build.sh"
1111
},
@@ -29,8 +29,10 @@
2929
"del": "^5.1.0",
3030
"fs-extra": "^8.1.0",
3131
"moment": "^2.24.0",
32+
"node-7z": "^2.0.3",
3233
"os-locale": "^4.0.0",
3334
"pkg": "^4.4.0",
35+
"rimraf": "^3.0.0",
3436
"rxjs": "^6.5.3"
3537
},
3638
"devDependencies": {

src/app-settings.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ export interface Configuration {
4545
},
4646
'backup': {
4747
'root': string,
48-
'downloadPath': string
48+
'downloadPath': string,
49+
'zip': {
50+
'enabled': boolean,
51+
'password': string
52+
}
53+
},
54+
'console': {
55+
'tty': boolean
4956
}
5057
}

src/obj/ConsoleOutput.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,54 @@
1+
import * as readline from 'readline';
2+
import * as process from 'process';
3+
14
export class ConsoleOutput {
5+
private static lastWasLive = false;
6+
27
public static log(message: string) {
8+
if(this.lastWasLive){
9+
console.log("");
10+
this.lastWasLive = false;
11+
}
312
console.log(`${message}`);
413
}
514

615
public static error(message: string) {
16+
if(this.lastWasLive){
17+
console.log("");
18+
this.lastWasLive = false;
19+
}
720
console.log(`\x1b[31m${message}\x1b[0m`);
821
}
922

1023
public static info(message: string) {
24+
if(this.lastWasLive){
25+
console.log("");
26+
this.lastWasLive = false;
27+
}
1128
console.log(`\x1b[34m${message}\x1b[0m`);
1229
}
1330

1431
public static success(message: string) {
32+
if(this.lastWasLive){
33+
console.log("");
34+
this.lastWasLive = false;
35+
}
1536
console.log(`\x1b[32m${message}\x1b[0m`);
1637
}
1738

1839
public static warning(message: string) {
40+
if(this.lastWasLive){
41+
console.log("");
42+
this.lastWasLive = false;
43+
}
1944
console.log(`\x1b[33m${message}\x1b[0m`);
2045
}
46+
47+
public static logLive = (message: string) => {
48+
// @ts-ignore
49+
readline.clearLine(process.stdout, 0);
50+
readline.cursorTo(process.stdout, 0, null);
51+
process.stdout.write(message);
52+
ConsoleOutput.lastWasLive = true;
53+
}
2154
}

src/obj/backup-manager.ts

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import * as path from 'path';
2+
import * as Path from 'path';
23
import * as fs from 'fs';
34
import * as osLocale from 'os-locale';
45
import {FtpManager} from './ftp-manager';
56
import {AppSettings} from '../app-settings';
67
import {ConsoleOutput} from './ConsoleOutput';
8+
import * as Zipper from 'node-7z'
9+
import * as rimraf from 'rimraf';
710
import moment = require('moment');
811

912
export class BackupManager {
@@ -29,30 +32,32 @@ export class BackupManager {
2932

3033
public doBackup() {
3134
let errors = '';
32-
if (fs.existsSync(path.join(AppSettings.appPath, 'errors.log'))) {
33-
fs.unlinkSync(path.join(AppSettings.appPath, 'errors.log'));
35+
let name = AppSettings.settings.backup.root.substring(0, AppSettings.settings.backup.root.lastIndexOf('/'));
36+
name = name.substring(name.lastIndexOf('/') + 1);
37+
const downloadPath = (AppSettings.settings.backup.downloadPath === '') ? AppSettings.appPath : AppSettings.settings.backup.downloadPath;
38+
const timeString = moment().format('YYYY-MM-DD_H-mm') + '_';
39+
const targetPath = path.join(downloadPath, timeString + name);
40+
41+
if (fs.existsSync(path.join(downloadPath, `${timeString}${name}_errors.log`))) {
42+
fs.unlinkSync(path.join(downloadPath, `${timeString}${name}_errors.log`));
3443
}
35-
if (fs.existsSync(path.join(AppSettings.appPath, 'statistics.txt'))) {
36-
fs.unlinkSync(path.join(AppSettings.appPath, 'statistics.txt'));
44+
if (fs.existsSync(path.join(downloadPath, `${timeString}${name}_statistics.txt`))) {
45+
fs.unlinkSync(path.join(downloadPath, `${timeString}${name}_statistics.txt`));
3746
}
3847
const subscr = this.ftpManager.error.subscribe((message: string) => {
3948
ConsoleOutput.error(`${moment().format('L LTS')}: ${message}`);
4049
const line = `${moment().format('L LTS')}:\t${message}\n`;
4150
errors += line;
42-
fs.appendFile(path.join(AppSettings.appPath, 'errors.log'), line, {
51+
fs.appendFile(path.join(downloadPath, `${timeString}${name}_errors.log`), line, {
4352
encoding: 'utf8'
4453
}, () => {
4554
});
4655
});
4756

48-
let name = AppSettings.settings.backup.root.substring(0, AppSettings.settings.backup.root.lastIndexOf('/'));
49-
name = name.substring(name.lastIndexOf('/') + 1);
50-
const downloadPath = (AppSettings.settings.backup.downloadPath === '') ? AppSettings.appPath : AppSettings.settings.backup.downloadPath;
51-
5257
ConsoleOutput.info(`Remote path: ${AppSettings.settings.backup.root}\nDownload path: ${downloadPath}\n`);
5358

5459
this.ftpManager.statistics.started = Date.now();
55-
this.ftpManager.downloadFolder(AppSettings.settings.backup.root, downloadPath).then(() => {
60+
this.ftpManager.downloadFolder(AppSettings.settings.backup.root, targetPath).then(() => {
5661
this.ftpManager.statistics.ended = Date.now();
5762
this.ftpManager.statistics.duration = (this.ftpManager.statistics.ended - this.ftpManager.statistics.started) / 1000 / 60;
5863

@@ -67,17 +72,58 @@ Files: ${this.ftpManager.statistics.files}
6772
Errors: ${errors.split('\n').length - 1}`;
6873

6974
ConsoleOutput.log('\n' + statistics);
70-
fs.writeFileSync(path.join(AppSettings.appPath, 'statistics.txt'), statistics, {
75+
fs.writeFileSync(path.join(downloadPath, `${timeString}${name}_statistics.txt`), statistics, {
7176
encoding: 'utf-8'
7277
});
7378
if (errors !== '') {
7479
ConsoleOutput.error(`There are errors. Please read the errors.log file for further information.`);
7580
}
7681
subscr.unsubscribe();
7782
this.ftpManager.close();
83+
84+
if (AppSettings.settings.backup.zip.enabled) {
85+
console.log(`\nZip folder...`);
86+
this.createZipFile(downloadPath, timeString + name, this.ftpManager.statistics.files,
87+
AppSettings.settings.backup.zip.password).then((result) => {
88+
ConsoleOutput.success('Zip file created!');
89+
rimraf(targetPath, () => {
90+
console.log('done');
91+
});
92+
}).catch((error) => {
93+
ConsoleOutput.error(error);
94+
});
95+
}
7896
}).catch((error) => {
7997
ConsoleOutput.error(error);
8098
this.ftpManager.close();
8199
});
82100
}
101+
102+
/** create zip file for extension */
103+
async createZipFile(path: string, name: string, numOfFiles: number, password: string) {
104+
return new Promise<boolean>((resolve, reject) => {
105+
const localPath = Path.join(path, name, '*');
106+
let numOfZipped = 0;
107+
let lastFile = '';
108+
Zipper.add(Path.join(path, name) + `.zip`, localPath, {
109+
recursive: true,
110+
password
111+
}).on('end', () => {
112+
resolve(true);
113+
}).on('error', (e) => {
114+
reject(e);
115+
}).on('data', (data) => {
116+
if (lastFile !== data.file) {
117+
numOfZipped++;
118+
}
119+
lastFile = data.file;
120+
const percent = Math.min(100, ((numOfZipped / numOfFiles) * 100)).toFixed(2);
121+
if (AppSettings.settings.console.tty) {
122+
ConsoleOutput.logLive(`Zipping...${percent}%`)
123+
} else {
124+
ConsoleOutput.log(`Zipping...${percent}%`);
125+
}
126+
});
127+
});
128+
}
83129
}

0 commit comments

Comments
 (0)