Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add possibility to ignore files e.g. .htaccess or files that need to stay #155

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ playground
notes.md
.env
dist
.idea/workspace.xml
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ const config = {
"node_modules/**/.*",
".git/**",
],
// Preserve files that should be kept/ignored on remote directory
preserve: [".htaccess"],
// delete ALL existing files at destination before uploading, if true
deleteRemote: false,
// Passive mode is forced (EPSV command is not sent)
Expand Down
13 changes: 7 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
"server": "node test/server.js"
},
"dependencies": {
"bluebird": "^3.7.2",
"minimatch": "9.0.0",
"promise-ftp": "^1.3.5",
"read": "^2.1.0",
Expand Down Expand Up @@ -48,9 +47,13 @@
{
"name": "keyle",
"url": "https://github.com/keyle"
},
{
"name": "cyrdam",
"url": "https://github.com/cyrdam"
}
],
"prettier": {
"tabWidth": 4
}
}
}
13 changes: 6 additions & 7 deletions src/ftp-deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
const upath = require("upath");
const util = require("util");
const events = require("events");
const Promise = require("bluebird");
const fs = require("fs");

var PromiseFtp = require("promise-ftp");
Expand Down Expand Up @@ -32,7 +31,7 @@ const FtpDeployer = function () {

this.makeAllAndUpload = function (remoteDir, filemap) {
let keys = Object.keys(filemap);
return Promise.mapSeries(keys, (key) => {
return lib.mapSeries(keys, (key) => {
// console.log("Processing", key, filemap[key]);
return this.makeAndUpload(remoteDir, key, filemap[key]);
});
Expand All @@ -51,7 +50,7 @@ const FtpDeployer = function () {
let newDirectory = upath.join(config.remoteRoot, relDir);
return this.makeDir(newDirectory, true).then(() => {
// console.log("newDirectory", newDirectory);
return Promise.mapSeries(fnames, (fname) => {
return lib.mapSeries(fnames, (fname) => {
let tmpFileName = upath.join(config.localRoot, relDir, fname);
let tmp = fs.readFileSync(tmpFileName);
this.eventObject["filename"] = upath.join(relDir, fname);
Expand Down Expand Up @@ -83,8 +82,8 @@ const FtpDeployer = function () {
// so instead provide one ourselfs
if (config.sftp) {
this.connectionStatus = "disconnected";
this.ftp.on("end", this.handleDisconnect);
this.ftp.on("close", this.handleDisconnect);
this.ftp.once("end", this.handleDisconnect);
this.ftp.once("close", this.handleDisconnect);
}

return this.ftp
Expand Down Expand Up @@ -147,8 +146,8 @@ const FtpDeployer = function () {
// Returns config
this.deleteRemote = (config) => {
if (config.deleteRemote) {
return lib
.deleteDir(this.ftp, config.remoteRoot)
const preserve = config.preserve?.length ? config.preserve.map(p => config.remoteRoot + p) : [];
return lib.deleteDir(this.ftp, config.remoteRoot, preserve)
.then(() => {
this.emit("log", "Deleted directory: " + config.remoteRoot);
return config;
Expand Down
203 changes: 203 additions & 0 deletions src/ftp-deploy.js.bak
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
"use strict";

const upath = require("upath");
const util = require("util");
const events = require("events");
const Promise = require("bluebird");
const fs = require("fs");

var PromiseFtp = require("promise-ftp");
var PromiseSftp = require("ssh2-sftp-client");
const lib = require("./lib");

/* interim structure
{
'/': ['test-inside-root.txt'],
'folderA': ['test-inside-a.txt'],
'folderA/folderB': ['test-inside-b.txt'],
'folderA/folderB/emptyC': [],
'folderA/folderB/emptyC/folderD': ['test-inside-d-1.txt', 'test-inside-d-2.txt']
}
*/

const FtpDeployer = function () {
// The constructor for the super class.
events.EventEmitter.call(this);
this.ftp = null;
this.eventObject = {
totalFilesCount: 0,
transferredFileCount: 0,
filename: "",
};

this.makeAllAndUpload = function (remoteDir, filemap) {
let keys = Object.keys(filemap);
return Promise.mapSeries(keys, (key) => {
// console.log("Processing", key, filemap[key]);
return this.makeAndUpload(remoteDir, key, filemap[key]);
});
};

this.makeDir = function (newDirectory) {
if (newDirectory === "/") {
return Promise.resolve("unused");
} else {
return this.ftp.mkdir(newDirectory, true);
}
};
// Creates a remote directory and uploads all of the files in it
// Resolves a confirmation message on success
this.makeAndUpload = (config, relDir, fnames) => {
let newDirectory = upath.join(config.remoteRoot, relDir);
return this.makeDir(newDirectory, true).then(() => {
// console.log("newDirectory", newDirectory);
return Promise.mapSeries(fnames, (fname) => {
let tmpFileName = upath.join(config.localRoot, relDir, fname);
let tmp = fs.readFileSync(tmpFileName);
this.eventObject["filename"] = upath.join(relDir, fname);

this.emit("uploading", this.eventObject);

return this.ftp
.put(tmp, upath.join(config.remoteRoot, relDir, fname))
.then(() => {
this.eventObject.transferredFileCount++;
this.emit("uploaded", this.eventObject);
return Promise.resolve("uploaded " + tmpFileName);
})
.catch((err) => {
this.eventObject["error"] = err;
this.emit("upload-error", this.eventObject);
// if continue on error....
return Promise.reject(err);
});
});
});
};

// connects to the server, Resolves the config on success
this.connect = (config) => {
this.ftp = config.sftp ? new PromiseSftp() : new PromiseFtp();

// sftp client does not provide a connection status
// so instead provide one ourselfs
if (config.sftp) {
this.connectionStatus = "disconnected";
this.ftp.once("end", this.handleDisconnect);
this.ftp.once("close", this.handleDisconnect);
}

return this.ftp
.connect(config)
.then((serverMessage) => {
this.emit("log", "Connected to: " + config.host);
this.emit("log", "Connected: Server message: " + serverMessage);

// sftp does not provide a connection status
// so instead provide one ourself
if (config.sftp) {
this.connectionStatus = "connected";
}

return config;
})
.catch((err) => {
return Promise.reject({
code: err.code,
message: "connect: " + err.message,
});
});
};

this.getConnectionStatus = () => {
// only ftp client provides connection status
// sftp client connection status is handled using events
return typeof this.ftp.getConnectionStatus === "function"
? this.ftp.getConnectionStatus()
: this.connectionStatus;
};

this.handleDisconnect = () => {
this.connectionStatus = "disconnected";
};

// creates list of all files to upload and starts upload process
this.checkLocalAndUpload = (config) => {
try {
let filemap = lib.parseLocal(
config.include,
config.exclude,
config.localRoot,
"/"
);
// console.log(filemap);
this.emit(
"log",
"Files found to upload: " + JSON.stringify(filemap)
);
this.eventObject["totalFilesCount"] = lib.countFiles(filemap);

return this.makeAllAndUpload(config, filemap);
} catch (e) {
return Promise.reject(e);
}
};

// Deletes remote directory if requested by config
// Returns config
this.deleteRemote = (config) => {
if (config.deleteRemote) {
const preserve = config.preserve?.length ? config.preserve.map(p => config.remoteRoot + p) : [];
return lib
<<<<<<< HEAD
.deleteDir(this.ftp, config.remoteRoot, config.preserve)
=======
.deleteDir(this.ftp, config.remoteRoot, preserve)
>>>>>>> b921f362763aa7ae4243fddc464d189d4230ddd8
.then(() => {
this.emit("log", "Deleted directory: " + config.remoteRoot);
return config;
})
.catch((err) => {
this.emit(
"log",
"Deleting failed, trying to continue: " +
JSON.stringify(err)
);
return Promise.resolve(config);
});
}
return Promise.resolve(config);
};

this.deploy = function (config, cb) {
return lib
.checkIncludes(config)
.then(lib.getPassword)
.then(this.connect)
.then(this.deleteRemote)
.then(this.checkLocalAndUpload)
.then((res) => {
this.ftp.end();
if (typeof cb == "function") {
cb(null, res);
} else {
return Promise.resolve(res);
}
})
.catch((err) => {
console.log("Err", err.message);
if (this.ftp && this.getConnectionStatus() != "disconnected")
this.ftp.end();
if (typeof cb == "function") {
cb(err, null);
} else {
return Promise.reject(err);
}
});
};
};

util.inherits(FtpDeployer, events.EventEmitter);

module.exports = FtpDeployer;
1 change: 1 addition & 0 deletions src/ftp-deploy.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const config = {
localRoot: path.join(__dirname, "../test/local"),
remoteRoot: "/ftp",
exclude: [],
preserve: [".htaccess"],
include: ["folderA/**/*", "test-inside-root.txt"],
debugMode: true,
};
Expand Down
Loading