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

Various enhancements (SCP Support, bug fixes, list command) #237

Merged
merged 11 commits into from
Jun 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
node_modules
node_modules
.vscode
ftp-test
18 changes: 10 additions & 8 deletions extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,31 @@ global.STATUS_TIMEOUT = 3000;
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
function activate(context) {

var syncHelper, currentConfig;
var ftpConfig = require('./modules/ftp-config');
var getSyncHelper = function() {
var oldConfig = currentConfig;
currentConfig = ftpConfig.getSyncConfig();

if(!syncHelper)
syncHelper = require('./modules/sync-helper')();
else if(ftpConfig.connectionChanged(oldConfig))
else if(ftpConfig.connectionChanged(oldConfig))
syncHelper.disconnect();

syncHelper.useConfig(currentConfig)

return syncHelper;
}

var initCommand = vscode.commands.registerCommand('extension.ftpsyncinit', require('./modules/init-command'));
var syncCommand = vscode.commands.registerCommand('extension.ftpsyncupload', function() { require('./modules/sync-command')(true, getSyncHelper) });
var downloadCommand = vscode.commands.registerCommand('extension.ftpsyncdownload', function() { require('./modules/sync-command')(false, getSyncHelper) });
var commitCommand = vscode.commands.registerCommand('extension.ftpsynccommit', function() { require('./modules/commit-command')(getSyncHelper) });
var singleCommand = vscode.commands.registerTextEditorCommand('extension.ftpsyncsingle', function(editor) { require('./modules/sync-single-command')(editor, getSyncHelper) });
var uploadcurrentCommand = vscode.commands.registerCommand("extension.ftpsyncuploadselected", function(fileUrl) { require('./modules/uploadcurrent-command')(fileUrl, getSyncHelper) });
var downloadcurrentCommand = vscode.commands.registerCommand("extension.ftpsyncdownloadselected", function(fileUrl) { require('./modules/downloadcurrent-command')(fileUrl, getSyncHelper) });
var listcurrentCommand = vscode.commands.registerCommand("extension.ftpsynclistselected", function(fileUrl) { require('./modules/list-command')(fileUrl, getSyncHelper) });
var onSave = require('./modules/on-save');

var currentConfig = getSyncHelper().getConfig();
Expand All @@ -53,19 +54,20 @@ function activate(context) {
vscode.workspace.onDidSaveTextDocument(function(file) {
onSave(file, getSyncHelper);
});

context.subscriptions.push(initCommand);
context.subscriptions.push(syncCommand);
context.subscriptions.push(downloadCommand);
context.subscriptions.push(commitCommand);
context.subscriptions.push(singleCommand);
context.subscriptions.push(uploadcurrentCommand);
context.subscriptions.push(downloadcurrentCommand);
context.subscriptions.push(listcurrentCommand);
}

exports.activate = activate;

function deactivate() {
fsw.dispose();
}
exports.deactivate = deactivate;
exports.deactivate = deactivate;
67 changes: 40 additions & 27 deletions modules/downloadcurrent-command.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,43 @@ var ftpconfig = require("./ftp-config");
var path = require("path");
var isIgnored = require("./is-ignored");

module.exports = function(fileUrl, getFtpSync) {
if(!vscode.workspace.rootPath) {
vscode.window.showErrorMessage("Ftp-sync: Cannot init ftp-sync without opened folder");
return;
}

if(fileUrl.fsPath.indexOf(vscode.workspace.rootPath) < 0) {
vscode.window.showErrorMessage("Ftp-sync: Selected file is not a part of the workspace.");
return;
}

var config = ftpconfig.getConfig();
if(isIgnored(fileUrl.fsPath, config.allow, config.ignore)) {
vscode.window.showErrorMessage("Ftp-sync: Selected file is ignored.");
return;
}

var fileName = path.basename(fileUrl.fsPath);
var downloadStatus = vscode.window.setStatusBarMessage("Ftp-sync: Downloading " + fileName + " from FTP server...", STATUS_TIMEOUT);
getFtpSync().downloadFile(fileUrl.fsPath, vscode.workspace.rootPath, function(err) {
downloadStatus.dispose();
if(err)
vscode.window.showErrorMessage("Ftp-sync: Downloading " + fileName + " failed: " + err);
else
vscode.window.setStatusBarMessage("Ftp-sync: " + fileName + " downloaded successfully!", STATUS_TIMEOUT);
})
}
module.exports = function (fileUrl, getFtpSync) {

var filePath = fileUrl ? fileUrl.fsPath : undefined;

//We aren't getting a file, trying to take the current one
if (!filePath) {
filePath = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.document.fileName : undefined;
}

if (!filePath) {
vscode.window.showErrorMessage("Ftp-sync: No file selected");
return;
}

if (!vscode.workspace.rootPath) {
vscode.window.showErrorMessage("Ftp-sync: Cannot init ftp-sync without opened folder");
return;
}

if (filePath.indexOf(vscode.workspace.rootPath) < 0) {
vscode.window.showErrorMessage("Ftp-sync: Selected file is not a part of the workspace.");
return;
}

var config = ftpconfig.getConfig();
if (isIgnored(filePath, config.allow, config.ignore)) {
vscode.window.showErrorMessage("Ftp-sync: Selected file is ignored.");
return;
}

var fileName = path.basename(filePath);
var downloadStatus = vscode.window.setStatusBarMessage("Ftp-sync: Downloading " + fileName + " from FTP server...", STATUS_TIMEOUT);
getFtpSync().downloadFile(filePath, vscode.workspace.rootPath, function (err) {
downloadStatus.dispose();
if (err)
vscode.window.showErrorMessage("Ftp-sync: Downloading " + fileName + " failed: " + err);
else
vscode.window.setStatusBarMessage("Ftp-sync: " + fileName + " downloaded successfully!", STATUS_TIMEOUT);
})
}
146 changes: 146 additions & 0 deletions modules/list-command.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/* global STATUS_TIMEOUT */
const vscode = require('vscode');
const ftpconfig = require('./ftp-config');
const path = require('path');
const isIgnored = require('./is-ignored');
const output = require('./output');
const downloadFn = require('./downloadcurrent-command');
const uploadFn = require('./uploadcurrent-command');

module.exports = function(fileUrl, getFtpSync) {
var filePath = fileUrl ? fileUrl.fsPath : undefined;

//We aren't getting a file, trying to take the current one
if(!filePath) {
filePath = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.document.fileName : undefined;
}

if(!filePath) {
vscode.window.showErrorMessage("Ftp-sync: No file selected");
return;
}

if (!vscode.workspace.rootPath) {
vscode.window.showErrorMessage('Ftp-sync: Cannot init ftp-sync without opened folder');
return;
}

if (filePath.indexOf(vscode.workspace.rootPath) < 0) {
vscode.window.showErrorMessage('Ftp-sync: Selected file is not a part of the workspace.');
return;
}

var config = ftpconfig.getConfig();
if (isIgnored(filePath, config.allow, config.ignore)) {
vscode.window.showErrorMessage('Ftp-sync: Selected file is ignored.');
return;
}

let remotePath = getFatherPath(filePath.replace(vscode.workspace.rootPath, config.remotePath));
function listAllFiles(filesRemotePath) {
getFtpSync().ListRemoteFilesByPath(filesRemotePath, function(err, files) {
if (err) {
// console.error('err:', err);
vscode.window.showErrorMessage('Ftp-sync: Listing failed: ' + err);
} else {
vscode.window.setStatusBarMessage('Ftp-sync: Listing successfully!', STATUS_TIMEOUT);
// console.log('files:', files);
showFiles(files, filesRemotePath);
}
});
}
function deleteFn(filePath) {
getFtpSync().deleteRemoteFile(filePath).then(result => {
vscode.window.setStatusBarMessage('Ftp-sync: Delete successfully!', STATUS_TIMEOUT);
}).catch(err => {
vscode.window.showErrorMessage('Ftp-sync: Delete failed: ' + err);
})
}
listAllFiles(remotePath);
// show remotePath files
function showFiles(files, filesRemotePath) {
const pickOptions = files.map(file => ({label: getLabel(file), description: file.path, file, isDir: file.isDir}));
const pickResult = vscode.window.showQuickPick([
{
label: '../',
description: '. UP a folder',
backPath: getFatherPath(filesRemotePath)
}
].concat(pickOptions), {placeHolder: 'Select a folder or file'});

pickResult.then(function(result) {
if (!result) {
return;
}
// console.log('sel file:', result);
if (result.backPath) {
listAllFiles(result.backPath);
} else if (result.isDir) {
listAllFiles(result.file.path);
} else {
showFileActions(result.file);
}
});
}
// show Actions
function showFileActions(file) {
const pickOptions = [
{
label: '../',
description: '. UP a folder',
backPath: getFatherPath(file.path)
}, {
label: 'DownLoad',
description: 'DownLoad this file',
file,
action: 'download'
}, {
label: 'Upload',
description: 'Upload this file',
file,
action: 'upload'
}, {
label: 'Delete',
description: 'Delete this file',
file,
action: 'delete'
}
];
const pickResult = vscode.window.showQuickPick(pickOptions);

pickResult.then(function(result) {
// console.log('sel Actions:', result);
if (!result) {
return;
}
if (result.backPath) {
listAllFiles(result.backPath);
} else if (result.action === 'download') {
downloadFn(getLocalPath(result.file.path), getFtpSync);
} else if (result.action === 'upload') {
uploadFn(getLocalPath(result.file.path), getFtpSync);
} else if (result.action === 'delete') {
deleteFn(result.file.path);
}
});
}
};
function getLabel(file) {
const name = file.name && file.name.indexOf('/') === 0
? file.name.slice(1)
: file.name;
return file.isDir
? `${name}/`
: name

}
function getLocalPath(fileRemotePath) {
return {
fsPath: fileRemotePath.replace(ftpconfig.getConfig().remotePath, vscode.workspace.rootPath)
};
}
function getFatherPath(son) {
let father = son.split('/');
father = father.slice(0, father.length - 1).join('/');
return father;
}
109 changes: 109 additions & 0 deletions modules/scp-wrapper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
module.exports = function () {
var self = this;

var Mode = require('stat-mode');
var Client = require('scp2');
var path = require("path");
var client = Client;
var low = require('scp2').Client;
var config = {};
var sftp;
self.connect = function (ftpConfig) {

try {
var privateKey = ftpConfig.privateKeyPath ? require('fs').readFileSync(ftpConfig.privateKeyPath) : undefined;
} catch (err) {
process.nextTick(function () {
onErrorHandler(err);
});
return;
}

config = {
host: ftpConfig.host,
port: ftpConfig.port,
username: ftpConfig.user,
password: ftpConfig.password,
privateKey: privateKey,
passphrase: ftpConfig.passphrase,
agent: ftpConfig.agent
};

client.defaults(config);

setTimeout(function() {
client.emit('ready');
});
}

self.onready = function (callback) {
client.once('ready', callback);
}

var onErrorHandler;
self.onerror = function (callback) {
onErrorHandler = callback;
client.once('error', callback);
}

self.pasv = function (callback) {
callback();
}

self.goSftp = function (callback) {
client.sftp(function (err, sftpClient) {
if (!err && !sftp) {
sftp = sftpClient;
}
callback(err);
})
}

self.end = function () {
client.end();
}

self.onclose = function (callback) {
client.once('close', callback);
}

self.list = function (remote, callback) {
client.sftp(function (err, sftpClient) {
sftpClient.readdir(remote, function (err, result) {
if (!err) result = result.map(f => {
return {
name: f.filename,
type: new Mode(f.attrs).isDirectory() ? "d" : "f", //TODO: determine if it's a file or not
size: f.attrs.size
}
});
callback(err, result);
});
});
}

self.get = function (remote, local, callback) {
client.scp(Object.assign({}, config, { path: remote }), local, callback);
}

self.put = function (local, remote, callback) {
client.scp(local, Object.assign({}, config, { path: remote }), callback)
}

self.mkdir = function (remote, callback) {
client.mkdir(remote, callback);
}

self.delete = function (remote, callback) {
client.sftp(function (err, sftpClient) {
sftpClient.unlink(remote, callback)
});
}

self.rmdir = function (remote, callback) {
client.sftp(function (err, sftpClient) {
sftpClient.rmdir(remote, callback)
});
}

}
Loading