syncodemayo 1.0.9 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +81 -0
- package/README.md +91 -25
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +66 -0
- package/dist/cli.js.map +1 -0
- package/dist/env.d.ts +1 -0
- package/dist/env.js +17 -0
- package/dist/env.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/Args.d.ts +21 -0
- package/dist/lib/Args.js +99 -0
- package/dist/lib/Args.js.map +1 -0
- package/{lib → dist/lib}/Cli.d.ts +1 -1
- package/dist/lib/Cli.js +104 -0
- package/dist/lib/Cli.js.map +1 -0
- package/{lib → dist/lib}/Client.d.ts +4 -4
- package/dist/lib/Client.js +73 -0
- package/dist/lib/Client.js.map +1 -0
- package/dist/lib/Config.d.ts +48 -0
- package/dist/lib/Config.js +92 -0
- package/dist/lib/Config.js.map +1 -0
- package/dist/lib/ConfigSchema.d.ts +3 -0
- package/dist/lib/ConfigSchema.js +132 -0
- package/dist/lib/ConfigSchema.js.map +1 -0
- package/dist/lib/Connection.d.ts +41 -0
- package/dist/lib/Connection.js +176 -0
- package/dist/lib/Connection.js.map +1 -0
- package/dist/lib/Filelist.d.ts +42 -0
- package/dist/lib/Filelist.js +156 -0
- package/dist/lib/Filelist.js.map +1 -0
- package/{lib → dist/lib}/Log.d.ts +1 -1
- package/{lib → dist/lib}/Log.js +9 -16
- package/dist/lib/Log.js.map +1 -0
- package/dist/lib/Prompt.d.ts +15 -0
- package/dist/lib/Prompt.js +31 -0
- package/dist/lib/Prompt.js.map +1 -0
- package/dist/lib/RemoteConnection.d.ts +37 -0
- package/dist/lib/RemoteConnection.js +2 -0
- package/dist/lib/RemoteConnection.js.map +1 -0
- package/dist/lib/Sync.d.ts +18 -0
- package/dist/lib/Sync.js +127 -0
- package/dist/lib/Sync.js.map +1 -0
- package/dist/lib/TargetServer.d.ts +31 -0
- package/dist/lib/TargetServer.js +76 -0
- package/dist/lib/TargetServer.js.map +1 -0
- package/dist/lib/index.d.ts +8 -0
- package/dist/lib/index.js +9 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/vendor/strip-json-comments.d.ts +23 -0
- package/dist/vendor/strip-json-comments.js +126 -0
- package/dist/vendor/strip-json-comments.js.map +1 -0
- package/package.json +24 -26
- package/.npmignore +0 -9
- package/cli.d.ts +0 -0
- package/cli.js +0 -102
- package/index.d.ts +0 -1
- package/index.js +0 -7
- package/lib/Cli.js +0 -130
- package/lib/Client.js +0 -85
- package/lib/Config.d.ts +0 -32
- package/lib/Config.js +0 -114
- package/lib/ConfigSchema.d.ts +0 -7
- package/lib/ConfigSchema.js +0 -65
- package/lib/Connection.d.ts +0 -14
- package/lib/Connection.js +0 -112
- package/lib/Filelist.d.ts +0 -11
- package/lib/Filelist.js +0 -59
- package/lib/Sync.d.ts +0 -18
- package/lib/Sync.js +0 -140
- package/lib/TargetServer.d.ts +0 -22
- package/lib/TargetServer.js +0 -74
- package/lib/index.d.ts +0 -7
- package/lib/index.js +0 -13
- package/missing-types.d.ts +0 -14
- package/tsconfig.json +0 -48
- package/yarn.lock +0 -975
package/lib/Client.js
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
const Log = require("./Log");
|
|
12
|
-
const path_1 = require("path");
|
|
13
|
-
const Config_1 = require("./Config");
|
|
14
|
-
const TargetServer_1 = require("./TargetServer");
|
|
15
|
-
const ConfigSchema_1 = require("./ConfigSchema");
|
|
16
|
-
const Filelist_1 = require("./Filelist");
|
|
17
|
-
class Client {
|
|
18
|
-
constructor(preferredPath) {
|
|
19
|
-
this.hasConfig = null;
|
|
20
|
-
this.DEFAULT_CONFIG = "syncodemayo.json";
|
|
21
|
-
this._path = preferredPath;
|
|
22
|
-
this.whenReady = new Promise((resolve) => {
|
|
23
|
-
Config_1.loadConfigFile(preferredPath)
|
|
24
|
-
.then((config) => {
|
|
25
|
-
this.config = config;
|
|
26
|
-
this._path = this.config._path;
|
|
27
|
-
this.hasConfig = true;
|
|
28
|
-
resolve(this);
|
|
29
|
-
})
|
|
30
|
-
.catch((err) => {
|
|
31
|
-
if (err.message.indexOf('Schema Error'))
|
|
32
|
-
this.loadError = err;
|
|
33
|
-
if (err.message.indexOf('JSON'))
|
|
34
|
-
this.parseError = err;
|
|
35
|
-
this.hasConfig = false;
|
|
36
|
-
resolve(this);
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
get hasError() {
|
|
41
|
-
return !!this.loadError || !!this.parseError;
|
|
42
|
-
}
|
|
43
|
-
setVerbosity(level) {
|
|
44
|
-
Log.setLogLevel(level);
|
|
45
|
-
}
|
|
46
|
-
createConfig(preferredPath) {
|
|
47
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
48
|
-
const path = path_1.resolve(preferredPath || this._path || this.DEFAULT_CONFIG);
|
|
49
|
-
const alreadyExists = yield Filelist_1.localFileExists(path);
|
|
50
|
-
if (alreadyExists) {
|
|
51
|
-
throw new Error("Config already exists at " + path);
|
|
52
|
-
}
|
|
53
|
-
Filelist_1.writeLocalFile(path, JSON.stringify(ConfigSchema_1.DefaultConfig, null, 2));
|
|
54
|
-
return true;
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
getTargetNames() {
|
|
58
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
59
|
-
if (this.hasConfig === null)
|
|
60
|
-
throw new Error("Config not loaded yet.");
|
|
61
|
-
if (this.hasConfig === false) {
|
|
62
|
-
if (this.hasError) {
|
|
63
|
-
const error = this.loadError || this.parseError;
|
|
64
|
-
throw error;
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
throw new Error("This directory has no SyncoDeMayo config.");
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
return Object.keys(this.config.targets).filter(name => this.config.targets[name].enabled);
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
getTargetConfig(name) {
|
|
74
|
-
return Config_1.resolveTarget(this.config, name);
|
|
75
|
-
}
|
|
76
|
-
getTargetServer(name) {
|
|
77
|
-
return TargetServer_1.TargetServer.create(this.config, name);
|
|
78
|
-
}
|
|
79
|
-
static create(configPath) {
|
|
80
|
-
const client = new Client(configPath);
|
|
81
|
-
return client.whenReady;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
exports.Client = Client;
|
|
85
|
-
//# sourceMappingURL=Client.js.map
|
package/lib/Config.d.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
export interface IConfig {
|
|
2
|
-
local: ILocalConfig;
|
|
3
|
-
targets: {
|
|
4
|
-
[name: string]: ITargetConfig;
|
|
5
|
-
};
|
|
6
|
-
_path?: string;
|
|
7
|
-
}
|
|
8
|
-
export interface ILocalConfig {
|
|
9
|
-
path: string;
|
|
10
|
-
files: string;
|
|
11
|
-
exclude: string[];
|
|
12
|
-
defaultTarget: string;
|
|
13
|
-
deleteRemoteFiles: boolean;
|
|
14
|
-
}
|
|
15
|
-
export interface ITargetConfig {
|
|
16
|
-
host: string;
|
|
17
|
-
user: string;
|
|
18
|
-
pass?: string;
|
|
19
|
-
path: string;
|
|
20
|
-
port: number;
|
|
21
|
-
cache: string;
|
|
22
|
-
prompt?: boolean | string;
|
|
23
|
-
_name: string;
|
|
24
|
-
enabled?: boolean;
|
|
25
|
-
type?: string;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Sending nulll as the preferred path will result in scan for the config
|
|
29
|
-
*/
|
|
30
|
-
export declare function loadConfigFile(preferredPath?: string): Promise<IConfig>;
|
|
31
|
-
export declare function resolvePassword(targetConfig: ITargetConfig): string;
|
|
32
|
-
export declare function resolveTarget(config: IConfig, name: string | ITargetConfig | undefined): ITargetConfig;
|
package/lib/Config.js
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
const path_1 = require("path");
|
|
12
|
-
const ConfigSchema_1 = require("./ConfigSchema");
|
|
13
|
-
const Filelist_1 = require("./Filelist");
|
|
14
|
-
const stripJsonComments = require("strip-json-comments");
|
|
15
|
-
function evalConfigFromFile(pathname) {
|
|
16
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
17
|
-
if (typeof pathname !== 'string')
|
|
18
|
-
throw new Error(`Path must be a string. Got a ${typeof pathname}`);
|
|
19
|
-
const fullpath = path_1.resolve("./" + pathname);
|
|
20
|
-
if (!Filelist_1.localFileExists(fullpath))
|
|
21
|
-
throw new Error("SKIP");
|
|
22
|
-
const source = yield Filelist_1.readLocalFile(fullpath, false);
|
|
23
|
-
const data = JSON.parse(stripJsonComments(source));
|
|
24
|
-
// const data = require(fullpath) as IConfig
|
|
25
|
-
if (typeof data === 'object')
|
|
26
|
-
data._path = fullpath;
|
|
27
|
-
return data;
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Sending nulll as the preferred path will result in scan for the config
|
|
32
|
-
*/
|
|
33
|
-
function loadConfigFile(preferredPath) {
|
|
34
|
-
const loadingPromise = new Promise((resolve, reject) => {
|
|
35
|
-
const potentialConfigs = (!!preferredPath)
|
|
36
|
-
? [preferredPath]
|
|
37
|
-
: [
|
|
38
|
-
'syncodemayo.json',
|
|
39
|
-
'.syncodemayo.json',
|
|
40
|
-
'syncodemayo.js',
|
|
41
|
-
'.syncodemayo.js',
|
|
42
|
-
'.syncodemayo',
|
|
43
|
-
'sync-config.json',
|
|
44
|
-
'sync-config.js',
|
|
45
|
-
'.sync-config',
|
|
46
|
-
];
|
|
47
|
-
const tryLoading = (path) => {
|
|
48
|
-
if (!!path) {
|
|
49
|
-
evalConfigFromFile(path)
|
|
50
|
-
.then(resolve)
|
|
51
|
-
.catch(err => {
|
|
52
|
-
if (err.message === "SKIP")
|
|
53
|
-
tryLoading(potentialConfigs.shift());
|
|
54
|
-
else
|
|
55
|
-
reject(err);
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
reject(new Error("Local config not found."));
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
// Kick off config loading...
|
|
63
|
-
tryLoading(potentialConfigs.shift());
|
|
64
|
-
});
|
|
65
|
-
return loadingPromise
|
|
66
|
-
.then(ConfigSchema_1.validateConfig)
|
|
67
|
-
.then(massageConfigData);
|
|
68
|
-
}
|
|
69
|
-
exports.loadConfigFile = loadConfigFile;
|
|
70
|
-
function massageConfigData(config) {
|
|
71
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
72
|
-
config.local.files = config.local.files || '**/**';
|
|
73
|
-
config.local.exclude = config.local.exclude || [];
|
|
74
|
-
config.local.defaultTarget = config.local.defaultTarget || "staging";
|
|
75
|
-
config.local.deleteRemoteFiles = config.local.deleteRemoteFiles === true;
|
|
76
|
-
Object.keys(config.targets).forEach(name => {
|
|
77
|
-
const target = config.targets[name];
|
|
78
|
-
target._name = name;
|
|
79
|
-
target.port = target.port || 21;
|
|
80
|
-
target.cache = target.cache || ".synco-filelist";
|
|
81
|
-
target.enabled = target.enabled !== false;
|
|
82
|
-
target.type = target.type || 'ftp'; // Will support more eventually
|
|
83
|
-
if (typeof target.prompt === 'undefined')
|
|
84
|
-
target.prompt = true;
|
|
85
|
-
});
|
|
86
|
-
return config;
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
function resolvePassword(targetConfig) {
|
|
90
|
-
const password = targetConfig.pass || process.env[`${targetConfig._name.toUpperCase()}_PWD`];
|
|
91
|
-
if (typeof password === 'undefined') {
|
|
92
|
-
throw new Error("Cannot find password for target: " + targetConfig._name);
|
|
93
|
-
}
|
|
94
|
-
return password;
|
|
95
|
-
}
|
|
96
|
-
exports.resolvePassword = resolvePassword;
|
|
97
|
-
function resolveTarget(config, name) {
|
|
98
|
-
if (typeof name === 'undefined')
|
|
99
|
-
name = config.local.defaultTarget;
|
|
100
|
-
if (typeof name === 'object')
|
|
101
|
-
return name;
|
|
102
|
-
const lookingFor = name;
|
|
103
|
-
const targetName = Object.keys(config.targets).find(namedTarget => (lookingFor.toUpperCase() === config.targets[namedTarget]._name.toUpperCase()));
|
|
104
|
-
if (!targetName) {
|
|
105
|
-
throw new Error("Target '" + name + "' not found.");
|
|
106
|
-
}
|
|
107
|
-
const target = config.targets[targetName];
|
|
108
|
-
if (!target.enabled) {
|
|
109
|
-
throw new Error("Target '" + name + "' not enabled.");
|
|
110
|
-
}
|
|
111
|
-
return target;
|
|
112
|
-
}
|
|
113
|
-
exports.resolveTarget = resolveTarget;
|
|
114
|
-
//# sourceMappingURL=Config.js.map
|
package/lib/ConfigSchema.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { IConfig } from './Config';
|
|
2
|
-
import * as joi from 'joi';
|
|
3
|
-
export declare const localSchema: joi.ObjectSchema;
|
|
4
|
-
export declare const targetSchema: joi.ObjectSchema;
|
|
5
|
-
export declare const configSchema: joi.ObjectSchema;
|
|
6
|
-
export declare function validateConfig(config: IConfig): Promise<IConfig>;
|
|
7
|
-
export declare const DefaultConfig: any;
|
package/lib/ConfigSchema.js
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
const joi = require("joi");
|
|
12
|
-
exports.localSchema = joi.object({
|
|
13
|
-
path: joi.string().required(),
|
|
14
|
-
files: joi.string(),
|
|
15
|
-
exclude: joi.array().items(joi.string()),
|
|
16
|
-
defaultTarget: joi.string(),
|
|
17
|
-
deleteRemoteFiles: joi.bool(),
|
|
18
|
-
});
|
|
19
|
-
exports.targetSchema = joi.object({
|
|
20
|
-
host: joi.string().required(),
|
|
21
|
-
user: joi.string().required(),
|
|
22
|
-
path: joi.string().required(),
|
|
23
|
-
pass: joi.string(),
|
|
24
|
-
port: joi.number(),
|
|
25
|
-
cache: joi.string(),
|
|
26
|
-
prompt: joi.alternatives([joi.bool(), joi.string()]),
|
|
27
|
-
enabled: joi.bool(),
|
|
28
|
-
// For future use...
|
|
29
|
-
type: joi.string(),
|
|
30
|
-
});
|
|
31
|
-
exports.configSchema = joi.object({
|
|
32
|
-
local: exports.localSchema.required(),
|
|
33
|
-
targets: joi.object().pattern(/.*/, exports.targetSchema).required()
|
|
34
|
-
}).unknown(true);
|
|
35
|
-
function validateConfig(config) {
|
|
36
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
-
const result = exports.configSchema.validate(config);
|
|
38
|
-
if (!!result.error)
|
|
39
|
-
throw new Error("Config Schema Error: " + result.error.message);
|
|
40
|
-
return config;
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
exports.validateConfig = validateConfig;
|
|
44
|
-
exports.DefaultConfig = {
|
|
45
|
-
local: {
|
|
46
|
-
path: "public",
|
|
47
|
-
files: "**/**",
|
|
48
|
-
exclude: ["**/*.map", "**/.DS_Store", "**/.git*"],
|
|
49
|
-
defaultTarget: "staging"
|
|
50
|
-
},
|
|
51
|
-
targets: {
|
|
52
|
-
staging: {
|
|
53
|
-
path: "Example/www/stage",
|
|
54
|
-
host: "www.example.com",
|
|
55
|
-
user: "USERNAME"
|
|
56
|
-
},
|
|
57
|
-
production: {
|
|
58
|
-
path: "Example/www",
|
|
59
|
-
host: "www.example.com",
|
|
60
|
-
user: "USERNAME",
|
|
61
|
-
prompt: "This will upload to PRODUCTION! Are you sure?"
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
//# sourceMappingURL=ConfigSchema.js.map
|
package/lib/Connection.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { ITargetConfig } from './Config';
|
|
2
|
-
export declare class Connection {
|
|
3
|
-
private _ftpConn;
|
|
4
|
-
constructor(host: string, port: number, user: string, pass: string);
|
|
5
|
-
getRemoteFile(filename: string): Promise<string>;
|
|
6
|
-
remoteDirectoryExists(pathname: string): Promise<boolean>;
|
|
7
|
-
remoteFileExists(remotePath: string): Promise<boolean>;
|
|
8
|
-
putBuffer(buff: any, remotePath: string): Promise<boolean>;
|
|
9
|
-
putContent(content: string, remotePath: string): Promise<boolean>;
|
|
10
|
-
putFile(filename: string, remotePath: string): Promise<string>;
|
|
11
|
-
deleteRemoteFile(remotePath: string): Promise<boolean>;
|
|
12
|
-
close(): void;
|
|
13
|
-
static create(target: ITargetConfig): Connection;
|
|
14
|
-
}
|
package/lib/Connection.js
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
const JsFtp = require("jsftp");
|
|
12
|
-
const JsFtpMkDirP = require("jsftp-mkdirp");
|
|
13
|
-
const Log = require("./Log");
|
|
14
|
-
const Config_1 = require("./Config");
|
|
15
|
-
const Filelist_1 = require("./Filelist");
|
|
16
|
-
const Ftp = JsFtpMkDirP(JsFtp);
|
|
17
|
-
/*
|
|
18
|
-
TODO: Extract FTP from the connection to allow other connection types.. File/SFTP/S3/whatever
|
|
19
|
-
*/
|
|
20
|
-
// interface IRemoteConnection {
|
|
21
|
-
// get(filepath): Promise<string>
|
|
22
|
-
// put(filepath): Promise<boolean>
|
|
23
|
-
// }
|
|
24
|
-
class Connection {
|
|
25
|
-
constructor(host, port, user, pass) {
|
|
26
|
-
// log("Connecting to FTP:", { host, port, user, pass: `(${pass.length} chars)` })
|
|
27
|
-
this._ftpConn = new Ftp({ host, port, user, pass });
|
|
28
|
-
process.on('beforeExit', () => {
|
|
29
|
-
this.close(); // Ensure all connections are close when the app exits
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
getRemoteFile(filename) {
|
|
33
|
-
return new Promise((resolve, reject) => {
|
|
34
|
-
let content = "";
|
|
35
|
-
Log.log(" <-", filename);
|
|
36
|
-
this._ftpConn.get(filename, function (err, socket) {
|
|
37
|
-
if (err != null) {
|
|
38
|
-
return reject(err);
|
|
39
|
-
}
|
|
40
|
-
socket.on("data", (d) => content += d.toString());
|
|
41
|
-
socket.on('error', (err) => {
|
|
42
|
-
Log.urgent("Retrieval error.", err);
|
|
43
|
-
reject(err);
|
|
44
|
-
});
|
|
45
|
-
socket.on("close", (connErr) => {
|
|
46
|
-
if (connErr)
|
|
47
|
-
reject(connErr);
|
|
48
|
-
else
|
|
49
|
-
resolve(content);
|
|
50
|
-
});
|
|
51
|
-
socket.resume();
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
remoteDirectoryExists(pathname) {
|
|
56
|
-
return new Promise((resolve, reject) => {
|
|
57
|
-
this._ftpConn.mkdirp(pathname, (err) => resolve(!err));
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
remoteFileExists(remotePath) {
|
|
61
|
-
return new Promise((resolve, reject) => {
|
|
62
|
-
this._ftpConn.raw.size(remotePath, (err, size) => resolve(!err));
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
putBuffer(buff, remotePath) {
|
|
66
|
-
return new Promise((resolve, reject) => {
|
|
67
|
-
Log.log(" ->", remotePath);
|
|
68
|
-
this._ftpConn.put(buff, remotePath, (err) => {
|
|
69
|
-
if (err)
|
|
70
|
-
reject(err);
|
|
71
|
-
else
|
|
72
|
-
resolve(true);
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
putContent(content, remotePath) {
|
|
77
|
-
return this.putBuffer(new Buffer(content), remotePath);
|
|
78
|
-
}
|
|
79
|
-
putFile(filename, remotePath) {
|
|
80
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
81
|
-
const buffer = yield Filelist_1.readLocalFile(filename, true);
|
|
82
|
-
yield this.putBuffer(buffer, remotePath);
|
|
83
|
-
return remotePath;
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
deleteRemoteFile(remotePath) {
|
|
87
|
-
return new Promise((resolve, reject) => {
|
|
88
|
-
Log.log(" x", remotePath);
|
|
89
|
-
this._ftpConn.raw('dele', remotePath, function (err, data) {
|
|
90
|
-
if (err)
|
|
91
|
-
Log.log("Error removing", remotePath, err.message);
|
|
92
|
-
if (err)
|
|
93
|
-
resolve(false);
|
|
94
|
-
else
|
|
95
|
-
resolve(true);
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
close() {
|
|
100
|
-
const conn = this._ftpConn;
|
|
101
|
-
conn && conn.raw && conn.raw.quit && conn.raw.quit((err, data) => {
|
|
102
|
-
if (err != null)
|
|
103
|
-
Log.urgent(err);
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
static create(target) {
|
|
107
|
-
const pass = Config_1.resolvePassword(target);
|
|
108
|
-
return new Connection(target.host, target.port, target.user, pass);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
exports.Connection = Connection;
|
|
112
|
-
//# sourceMappingURL=Connection.js.map
|
package/lib/Filelist.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
import { ILocalConfig, ITargetConfig } from './Config';
|
|
3
|
-
import { Connection } from './Connection';
|
|
4
|
-
export interface IFilelist {
|
|
5
|
-
[filename: string]: number;
|
|
6
|
-
}
|
|
7
|
-
export declare function localFileExists(path: string): Promise<boolean>;
|
|
8
|
-
export declare function readLocalFile(path: string, asBuffer?: boolean): Promise<string | Buffer>;
|
|
9
|
-
export declare function writeLocalFile(path: string, content: string): Promise<any>;
|
|
10
|
-
export declare function getRemoteFilelist(target: ITargetConfig, conn: Connection): Promise<IFilelist>;
|
|
11
|
-
export declare function buildLocalFilelist(config: ILocalConfig): Promise<IFilelist>;
|
package/lib/Filelist.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
const glob = require("glob");
|
|
12
|
-
const minimatch = require("minimatch");
|
|
13
|
-
const crc = require("crc");
|
|
14
|
-
const fs = require("fs");
|
|
15
|
-
const Log = require("./Log");
|
|
16
|
-
function localFileExists(path) {
|
|
17
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
18
|
-
return fs.existsSync(path);
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
exports.localFileExists = localFileExists;
|
|
22
|
-
function readLocalFile(path, asBuffer = false) {
|
|
23
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
24
|
-
const buff = fs.readFileSync(path);
|
|
25
|
-
return asBuffer ? buff : buff.toString();
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
exports.readLocalFile = readLocalFile;
|
|
29
|
-
function writeLocalFile(path, content) {
|
|
30
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
31
|
-
return fs.writeFileSync(path, content);
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
exports.writeLocalFile = writeLocalFile;
|
|
35
|
-
function getRemoteFilelist(target, conn) {
|
|
36
|
-
const path = `${target.path}/${target.cache}`;
|
|
37
|
-
return conn.getRemoteFile(path)
|
|
38
|
-
.then(JSON.parse)
|
|
39
|
-
.catch((err) => {
|
|
40
|
-
Log.info("Missing or error parsing remote file list.", err);
|
|
41
|
-
Log.log("\n Run sync:init to setup SyncoDeMayo on the server.\n");
|
|
42
|
-
process.exit(1);
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
exports.getRemoteFilelist = getRemoteFilelist;
|
|
46
|
-
function buildLocalFilelist(config) {
|
|
47
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
48
|
-
// Create the CRCs...
|
|
49
|
-
const excludeDirectories = (path) => !fs.statSync(path).isDirectory();
|
|
50
|
-
const excludeBlacklistedFiles = (path) => !config.exclude.some(pattern => minimatch(path, pattern, { dot: true }));
|
|
51
|
-
return glob
|
|
52
|
-
.sync(`${config.path}/${config.files}`)
|
|
53
|
-
.filter(excludeDirectories)
|
|
54
|
-
.filter(excludeBlacklistedFiles)
|
|
55
|
-
.reduce((hash, filepath) => (hash[filepath] = crc.crc32(fs.readFileSync(filepath)), hash), {});
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
exports.buildLocalFilelist = buildLocalFilelist;
|
|
59
|
-
//# sourceMappingURL=Filelist.js.map
|
package/lib/Sync.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { IConfig, ITargetConfig } from './Config';
|
|
2
|
-
import { Connection } from './Connection';
|
|
3
|
-
export interface IChangeset {
|
|
4
|
-
added: string[];
|
|
5
|
-
changed: string[];
|
|
6
|
-
removed: string[];
|
|
7
|
-
}
|
|
8
|
-
export declare class Sync {
|
|
9
|
-
private _conn;
|
|
10
|
-
private _config;
|
|
11
|
-
private _target;
|
|
12
|
-
constructor(conn: Connection, config: IConfig, target: string | ITargetConfig);
|
|
13
|
-
run(isDryRun?: boolean, forceConfirmation?: boolean): Promise<IChangeset | null>;
|
|
14
|
-
private _confirmUpload(target, fileCount);
|
|
15
|
-
private _getFilelists(local, target, conn);
|
|
16
|
-
private _buildChangeset(localFiles, remoteFiles);
|
|
17
|
-
static create(conn: Connection, config: IConfig, target: string | ITargetConfig): Sync;
|
|
18
|
-
}
|
package/lib/Sync.js
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
const path = require("path");
|
|
12
|
-
const yesno = require("yesno");
|
|
13
|
-
const Log = require("./Log");
|
|
14
|
-
const Config_1 = require("./Config");
|
|
15
|
-
const Filelist_1 = require("./Filelist");
|
|
16
|
-
class Sync {
|
|
17
|
-
constructor(conn, config, target) {
|
|
18
|
-
this._conn = conn;
|
|
19
|
-
this._config = config;
|
|
20
|
-
this._target = Config_1.resolveTarget(config, target);
|
|
21
|
-
}
|
|
22
|
-
run(isDryRun = false, forceConfirmation = false) {
|
|
23
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
24
|
-
const { localFiles, remoteFiles } = yield this._getFilelists(this._config.local, this._target, this._conn);
|
|
25
|
-
const changeset = this._buildChangeset(localFiles, remoteFiles);
|
|
26
|
-
const filesToUpload = [...changeset.added, ...changeset.changed];
|
|
27
|
-
if (isDryRun || (filesToUpload.length === 0 && changeset.removed.length === 0)) {
|
|
28
|
-
return changeset;
|
|
29
|
-
}
|
|
30
|
-
const _verifiedDirs = new Map();
|
|
31
|
-
const verifyDirExists = (remoteDir) => __awaiter(this, void 0, void 0, function* () {
|
|
32
|
-
if (!_verifiedDirs.has(remoteDir)) {
|
|
33
|
-
const isVerified = yield this._conn.remoteDirectoryExists(remoteDir);
|
|
34
|
-
_verifiedDirs.set(remoteDir, isVerified);
|
|
35
|
-
}
|
|
36
|
-
return true;
|
|
37
|
-
});
|
|
38
|
-
Log.info("\n%s files to upload...", filesToUpload.length);
|
|
39
|
-
Log.info("%s files to remove...\n", changeset.removed.length);
|
|
40
|
-
const confirmed = forceConfirmation === true
|
|
41
|
-
? true
|
|
42
|
-
: yield this._confirmUpload(this._target, filesToUpload.length);
|
|
43
|
-
if (!confirmed) {
|
|
44
|
-
Log.info("Canceled upload.");
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
Log.log("Uploading %s files...", filesToUpload.length);
|
|
48
|
-
let sequentialUploader = Promise.resolve(true);
|
|
49
|
-
filesToUpload.forEach((filePath) => {
|
|
50
|
-
sequentialUploader = sequentialUploader.then(() => __awaiter(this, void 0, void 0, function* () {
|
|
51
|
-
const remotePath = `${this._target.path}${filePath.replace(this._config.local.path, '')}`;
|
|
52
|
-
const remoteDir = path.dirname(remotePath);
|
|
53
|
-
const localPath = path.resolve(filePath);
|
|
54
|
-
yield verifyDirExists(remoteDir);
|
|
55
|
-
yield this._conn.putFile(localPath, remotePath);
|
|
56
|
-
return true;
|
|
57
|
-
}));
|
|
58
|
-
});
|
|
59
|
-
if (this._config.local.deleteRemoteFiles && changeset.removed.length > 0) {
|
|
60
|
-
changeset.removed.forEach((filePath) => {
|
|
61
|
-
sequentialUploader = sequentialUploader.then(() => __awaiter(this, void 0, void 0, function* () {
|
|
62
|
-
const remotePath = `${this._target.path}${filePath.replace(this._config.local.path, '')}`;
|
|
63
|
-
const didDelete = yield this._conn.deleteRemoteFile(remotePath);
|
|
64
|
-
if (!didDelete)
|
|
65
|
-
Log.urgent(" -> Error deleting file");
|
|
66
|
-
return true;
|
|
67
|
-
}));
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
yield sequentialUploader;
|
|
71
|
-
// await Promise.all(
|
|
72
|
-
// filesToUpload.map(async (filePath: string) => {
|
|
73
|
-
// const remotePath = `${this._target.path}${filePath.replace(this._config.local.path, '')}`
|
|
74
|
-
// const remoteDir = path.dirname(remotePath)
|
|
75
|
-
// await verifyDirExists(remoteDir)
|
|
76
|
-
// await this._conn.putFile(filePath, remotePath)
|
|
77
|
-
// return filePath
|
|
78
|
-
// })
|
|
79
|
-
// )
|
|
80
|
-
const remoteCachePath = `${this._target.path}/${this._target.cache}`;
|
|
81
|
-
yield verifyDirExists(path.dirname(remoteCachePath));
|
|
82
|
-
yield this._conn.putContent(JSON.stringify(localFiles, null, 2), remoteCachePath);
|
|
83
|
-
return changeset;
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
_confirmUpload(target, fileCount) {
|
|
87
|
-
// If no prompt is specified, auto-confirm upload!
|
|
88
|
-
return new Promise(resolve => {
|
|
89
|
-
if (!target.prompt)
|
|
90
|
-
return resolve(true);
|
|
91
|
-
const message = typeof target.prompt === 'string'
|
|
92
|
-
? target.prompt
|
|
93
|
-
: "Confirm upload?";
|
|
94
|
-
yesno.ask(`${message} - (Yes will upload)`, null, resolve);
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
_getFilelists(local, target, conn) {
|
|
98
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
99
|
-
// Load/build Filesets in parralel.
|
|
100
|
-
const remoteFilesLoader = Filelist_1.getRemoteFilelist(target, conn);
|
|
101
|
-
const localFilesBuilder = Filelist_1.buildLocalFilelist(local);
|
|
102
|
-
return {
|
|
103
|
-
localFiles: yield localFilesBuilder,
|
|
104
|
-
remoteFiles: yield remoteFilesLoader
|
|
105
|
-
};
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
_buildChangeset(localFiles, remoteFiles) {
|
|
109
|
-
const changeset = {
|
|
110
|
-
added: [],
|
|
111
|
-
removed: [],
|
|
112
|
-
changed: []
|
|
113
|
-
};
|
|
114
|
-
// Build list of files that need to be uploaded...
|
|
115
|
-
Object.keys(localFiles).forEach((localFilename) => {
|
|
116
|
-
const localHash = localFiles[localFilename];
|
|
117
|
-
const remoteHash = remoteFiles[localFilename];
|
|
118
|
-
// Local hash not in remote cache
|
|
119
|
-
if (!(localFilename in remoteFiles)) {
|
|
120
|
-
changeset.added.push(localFilename);
|
|
121
|
-
}
|
|
122
|
-
else if (remoteHash != localHash) {
|
|
123
|
-
changeset.changed.push(localFilename);
|
|
124
|
-
}
|
|
125
|
-
// Local hash and remote hash are equal!
|
|
126
|
-
});
|
|
127
|
-
// Build list of files to be removed from the server...
|
|
128
|
-
Object.keys(remoteFiles).forEach((remoteFilename) => {
|
|
129
|
-
if (!(remoteFilename in localFiles)) {
|
|
130
|
-
changeset.removed.push(remoteFilename);
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
return changeset;
|
|
134
|
-
}
|
|
135
|
-
static create(conn, config, target) {
|
|
136
|
-
return new Sync(conn, config, target);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
exports.Sync = Sync;
|
|
140
|
-
//# sourceMappingURL=Sync.js.map
|