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 configuration to auto copy file remotely #138

Merged
merged 6 commits into from
Jul 19, 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
30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@
- [Usage](#usage)
- [Auto completion](#auto-completion)
- [Code Snippets](#code-snippets)
- [Syntax highlighting](#syntax-highlighting)
- [Run Ansible playbook](#run-ansible-playbook)
- [Run Playbook in Docker](#run-playbook-in-docker)
- [Run Playbook in Local Ansible](#run-playbook-in-local-ansible)
- [Run Playbook in Cloud Shell](#run-playbook-in-cloud-shell)
- [Run Playbook Remotely via ssh](#run-playbook-remotely-via-ssh)
- [Auto File Copy on saving](#files-copy-to-remote-on-saving)
- [Configuration](#configuration)
- [Feedback and Questions](#feedback-and-questions)
- [License](#license)
Expand All @@ -26,7 +28,7 @@

- Auto completion. Auto completion Ansible directives, modules and plugins from Ansible doc, Auto completion for variables. Disable auto completion by setting `ansible.autocompletion` to `false`.
- Code snippets. Press `Ctrl + Space`, Ansible playbook code snippets will show up.
- Syntax highlighting.
- Syntax highlighting. Enable syntax highlighting by setting `files.associations` in `settings.json`.
- Code navigation by Symbols, press `Ctrl + Shift + O`.
- Hover over module names, to show module documentation. Disable hovering over by setting `ansible.hover` to `false`.
- Run playbook from Docker.
Expand All @@ -49,8 +51,17 @@
Press `Ctrl + Space` in playbook yml file, you'll see Ansible modules code snippets. Then press `tab` to move inside snippet parameters.
![auto completion and code snippets](./images/authoring.gif)

### Syntax highlighting
Enable syntax highlighting by add `files.associations` configuration in `settings.json`, to associate your paths with `ansible`.
```
"files.associations": {
"C:\\mypath\\ansible-playbooks\\*.yml": "ansible",
"**/*.yaml": "ansible"
},
```

### Run Ansible playbook
4 methods are supported to run Ansible playbook:
4 methods are supported to run Ansible playbook, with custom options configured in `ansible.customOptions`:
- [Docker](#run-playbook-in-docker).
- [Local Ansible installation](#run-playbook-in-local-ansible).
- [Cloud Shell](#run-playbook-in-cloud-shell).
Expand Down Expand Up @@ -100,6 +111,19 @@ Press `Ctrl + Space` in playbook yml file, you'll see Ansible modules code snipp
]
```

#### Files copy to remote on saving
1. Configure file copying to remote host on saving as below in `settings.json`. `sourcePath` will be copied to remote `server` as `targetPath` when configuration added/updated. `copyOnSave` will copy local files saved to remote host.
```
"ansible.fileCopyConfig": [
{
"server": "remote-host-name",
"sourcePath": "local file/folder to copy from, eg. e:\\testfolder\\ansibleplaybooks",
"targetPath": "remote file/folder to copy to, eg. /home/user/ansibleplaybooks",
"copyOnSave": true
}
]
```

## Configuration
This extension provides below configurations in settings.json.

Expand All @@ -110,6 +134,8 @@ This extension provides below configurations in settings.json.
|`ansible.autocompletion` | `true` | Enable/Disable ansible autocompletion(including code snippets) functionality. To enable ansible autocompletion only in specific yaml files, set `ansible.autocompletion = false`, then add `# ansible-configured` header in first line of yaml file.|
|`ansible.credentialsFile` |`$HOME/.vscode/ansible-credentials.yml` |Specify ansible credentials file path, used when run playbook in Docker/Local Ansible. |
|`ansible.termininalInitCommand`|Default is `docker run` command for Docker, and `ansible-playbook` for local ansible.| Specify customized terminal init command when run playbook in Docker/Local Ansible. |
|`ansible.reuseSSHTerminal`|`true`| Enable/Disable SSH terminal resuing. |
|`ansible.customOptions`| null | Customize run playbook options. eg. `-i xxxx -vvv`.|


## Feedback and Questions
Expand Down
27 changes: 21 additions & 6 deletions package-lock.json

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

15 changes: 8 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"displayName": "Ansible",
"description": "VSCode extension for Ansible",
"license": "SEE LICENSE IN LICENSE.md",
"version": "0.2.6",
"version": "0.3.0",
"publisher": "vscoss",
"icon": "images/logo.png",
"engines": {
Expand Down Expand Up @@ -169,15 +169,15 @@
"default": true,
"description": "Enable/Disable resuing SSH terminal session"
},
"ansible.runPlaybookOptions": {
"ansible.customOptions": {
"type": "string",
"default": "",
"description": "Custom options to run ansible playbook. eg. -i inventoryfile -vvv"
},
"ansible.copyWorkspace": {
"type": "boolean",
"default": false,
"description": "Enable/Disable copying whole workspace to remote SSH host"
"ansible.fileCopyConfig": {
"type": "array",
"default": "",
"description": "Config file copying to remote host, including weather copy file on save. E.g. [ { \"server\": \"host\", \"sourcePath\":\"/mypath/\", \"targetPath\": \"/destpath/\", \"copyOnSave\", \"true\" }]"
}
}
}
Expand All @@ -200,6 +200,7 @@
},
"dependencies": {
"adal-node": "0.1.22",
"async": "^2.6.1",
"azure-arm-resource": "^3.0.0-preview",
"azure-storage": "^2.8.2",
"fs-extra": "^4.0.2",
Expand All @@ -222,4 +223,4 @@
"ws": "^3.3.2",
"yamljs": "^0.3.0"
}
}
}
2 changes: 1 addition & 1 deletion server/src/services/yamlHover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export class YAMLHover {
let currentDoc = matchOffsetToDocument(offset, jsonDoc);


if (currentDoc === null || currentDoc === undefined) {
if (!currentDoc) {
return this.promise.resolve(void 0);
}

Expand Down
2 changes: 1 addition & 1 deletion src/SSHLauncher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ async function connectTerminal(host: string, port: string, user: string, passwor
port: port,
username: user,
password: password,
privateKey: (keyfile === null || keyfile === undefined) ? keyfile : fs.readFileSync(keyfile),
privateKey: keyfile ? fs.readFileSync(keyfile) : keyfile,
passphrase: passphrase,
keepaliveInternal: 4000
});
Expand Down
4 changes: 1 addition & 3 deletions src/baseRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ export abstract class BaseRunner {
})
} else {
if (this.validatePlaybook(playbook)) {
this._outputChannel.appendLine('Validated playbook ' + playbook);
this._outputChannel.show();
return this.runPlaybookInternal(playbook);
}
}
Expand All @@ -68,7 +66,7 @@ export abstract class BaseRunner {

protected getRunPlaybookCmd(playbook: string): string {
let cmd = ['ansible-playbook'];
let customOption = utilities.getCodeConfiguration<string>('ansible', 'runPlaybookOptions');
let customOption = utilities.getCodeConfiguration<string>('ansible', 'customOptions');

if (customOption) {
cmd.push(customOption);
Expand Down
2 changes: 1 addition & 1 deletion src/cloudShellRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export class CloudShellRunner extends BaseRunner {
return;
}

if (this.terminal === null || this.terminal === undefined) {
if (!this.terminal) {

this._outputChannel.append('\nConnecting to Cloud Shell.');
this._outputChannel.show();
Expand Down
12 changes: 12 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { LocalAnsibleRunner } from './localAnsibleRunner';
import { SSHRunner } from './sshRunner';
import { DeploymentTemplate } from './deploymentTemplate';
import { FolderSyncer } from './folderSyncer';
import { FileSyncer } from './fileSyncer';

const documentSelector = [
{ language: 'yaml', scheme: 'file' },
Expand All @@ -40,6 +41,7 @@ export function activate(context: vscode.ExtensionContext) {
var sshRunner = new SSHRunner(outputChannel);
var deploymentTemplate = new DeploymentTemplate();
var folderSyncer = new FolderSyncer(outputChannel);
var fileSyncer = new FileSyncer(outputChannel);

context.subscriptions.push(vscode.commands.registerCommand('vscode-ansible.playbook-in-docker', (playbook) => {
dockerRunner.runPlaybook(playbook ? playbook.fsPath : null);
Expand All @@ -63,10 +65,20 @@ export function activate(context: vscode.ExtensionContext) {
folderSyncer.syncFolder(srcFolder, targetFolder, null, true);
}));

context.subscriptions.push(vscode.workspace.onDidChangeConfiguration((configChange) => {
if (configChange.affectsConfiguration("ansible.fileCopyConfig")) {
let config = vscode.workspace.getConfiguration('ansible').get('fileCopyConfig');
fileSyncer.onConfigurationChange(config);
}
}));

context.subscriptions.push(vscode.window.onDidCloseTerminal((closedTerminal: vscode.Terminal) => {
TerminalExecutor.onDidCloseTerminal(closedTerminal);
}));

context.subscriptions.push(vscode.workspace.onDidSaveTextDocument(listener => {
fileSyncer.copyFiles(null, listener.fileName);
}));

// start language client
var serverModule = path.join(context.extensionPath, 'out', 'server', 'server.js');
Expand Down
127 changes: 127 additions & 0 deletions src/fileSyncer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
'use strict';

import * as vscode from 'vscode';
import * as utilities from './utilities';
import * as fs from 'fs-extra';
import * as path from 'path';
import { SSHServer, FileCopyConfigs, FileCopyConfig } from './interfaces';
import * as sshHelper from './sshRunner';
import * as async from 'async';
import { StatusBarAlignment } from 'vscode';

const browseThePC = 'Browse the PC..';

export enum TargetType {
cloudshell = 'cloudshell',
remotehost = 'remotehost'
}


export class FileSyncer {
protected _statusBar: vscode.StatusBarItem;
protected _outputChannel: vscode.OutputChannel;
protected _configuration: FileCopyConfigs;
protected _hosts: { key: string, string };

constructor(outputChannel: vscode.OutputChannel) {
this._outputChannel = outputChannel;
this._configuration = utilities.getCodeConfiguration('ansible', 'copyFileOnSave');
this._statusBar = vscode.window.createStatusBarItem(StatusBarAlignment.Right, 100);
}

public onConfigurationChange(config: any): void {
// check if changed
let updatedConfig = this.getChangedConfiguration(this._configuration, config);

this.copyFiles(updatedConfig);

this._configuration = config;
}

protected getChangedConfiguration(oldConfig: FileCopyConfigs, newConfig: FileCopyConfigs) {
let result = [];

if (!oldConfig || oldConfig.length === 0) {
return newConfig;
}

if (!newConfig) {
return result;
}

for (let newc of newConfig) {
let exists = false;
for (let old of oldConfig) {
if (newc.server === old.server && newc.sourcePath === old.sourcePath && newc.targetPath === old.targetPath) {
exists = true;
break;
}
}

if (!exists) {
result.push(newc);
}
}

return result;
}

public copyFiles(configuration: FileCopyConfigs, fileName: string = null) {
let servers = utilities.getSSHConfig();

if (!configuration) {
if (!this._configuration) {
return;
}
configuration = this._configuration;
}

for (let item of configuration) {
// get server
let server = this.getServer(servers, item.server);

if (!server) {
this._statusBar.text = "Invalid host " + item.server;
this._statusBar.show();
}

let source = item.sourcePath;
let target = item.targetPath;
if (fileName != null) {
// check if file under configured source path
if (utilities.isSubPath(fileName, item.sourcePath)) {
source = fileName;
target = path.join(item.targetPath, path.relative(item.sourcePath, fileName));
} else {
return;
}
}

this._statusBar.text = "Copying " + source + " to " + item.server;
this._statusBar.show();

utilities.copyFilesRemote(source, target, server)
.then(() => {
this._statusBar.text = "Copied " + source + " to " + item.server;
this._statusBar.show();
})
.catch((err) => {
this._statusBar.text = "Failed to copy " + source + " to " + item.server;
this._statusBar.show();
this._outputChannel.appendLine('\nFailed to copy ' + source + ' to ' + item.server + ': ' + err);
this._outputChannel.show();
throw err;
});
}
}


public getServer(servers: SSHServer[], serverName: string): SSHServer {
for (let s of servers) {
if (s.host === serverName) {
return s;
}
}
return null;
}
}
1 change: 0 additions & 1 deletion src/folderSyncer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ export class FolderSyncer {

protected _outputChannel: vscode.OutputChannel;


constructor(outputChannel: vscode.OutputChannel) {
this._outputChannel = outputChannel;
}
Expand Down
Loading