* Adding auto sync support

* Updated delete and push to support login

* Fixes based on feedback.
This commit is contained in:
Richard Guthrie 2018-01-23 17:13:24 -08:00 коммит произвёл Sheng Chen
Родитель c539ead5cf
Коммит e7a9226ea3
4 изменённых файлов: 149 добавлений и 106 удалений

Просмотреть файл

@ -73,6 +73,7 @@ This extension requires:
- [Terraform](https://www.terraform.io/downloads.html)
- [Docker](http://www.docker.io) if you are running the execute test feature locally.
- [GraphViz dot](http://www.graphviz.org) if you are using the visualize feature.
- NOTE: On Windows after installing the graphViz msi/zip, you will most likely need to add your PATH env variable `(Ex. c:\Program Files(x86)\GraphViz2.38\bin)` in order to use dot from the command line.
## Supported Environments

Просмотреть файл

@ -16,6 +16,7 @@
"Other"
],
"activationEvents": [
"workspaceContains:**/*.tf",
"onCommand:vscode-terraform-azure.init",
"onCommand:vscode-terraform-azure.plan",
"onCommand:vscode-terraform-azure.apply",
@ -41,6 +42,11 @@
"default": "**/*.{tf,txt,yml,tfvars,rb}",
"description": "Indicates the files that should be synchronized to Azure cloudshell using the glob pattern string, for example: **/*.{tf,txt,yml,tfvars,rb}"
},
"tf-azure.syncEnabled": {
"type": "boolean",
"default": true,
"description": "When terminal is set to `cloudshell`, indicates whether changes to files that match tf-azure.files setting glob pattern should automatically sync to cloudshell."
},
"tf-azure.test-container": {
"type": "string",
"default": "microsoft/terraform-test",

Просмотреть файл

@ -4,7 +4,7 @@ import { BaseShell } from "./baseShell";
import { openCloudConsole, OSes } from "./cloudConsole";
import { delay } from "./cloudConsoleLauncher";
import { aciConfig, Constants, exportContainerCmd, exportTestScript } from "./Constants";
import { azFilePush, escapeFile, TerminalType, TFTerminal } from "./shared";
import { azFileDelete, azFilePush, escapeFile, TerminalType, TFTerminal } from "./shared";
import { CSTerminal } from "./utilities";
@ -32,57 +32,38 @@ export class CloudShell extends BaseShell {
TerminalType.CloudShell,
Constants.TerraformTerminalName);
public async pushFiles(files: vscode.Uri[]) {
public async pushFiles(files: vscode.Uri[], syncAllFiles: boolean) {
this.outputChannel.appendLine("Attempting to upload files to CloudShell");
const RETRY_INTERVAL = 500;
const RETRY_TIMES = 30;
// Checking if the terminal has been created
if (( this.csTerm.terminal != null) && (this.csTerm.storageAccountKey != null)) {
for (let i = 0; i < RETRY_TIMES; i++ ) {
if (this.csTerm.ws.readyState !== ws.OPEN ) {
// wait for valid ws connection
await delay (RETRY_INTERVAL);
} else {
for (const file of files.map( (a) => a.fsPath)) {
try {
if (await fsExtra.pathExists(file)) {
this.outputChannel.appendLine(`Uploading file ${file} to cloud shell`);
await azFilePush(this.csTerm.storageAccountName,
this.csTerm.storageAccountKey,
this.csTerm.fileShareName, file);
}
} catch (err) {
this.outputChannel.appendLine(err);
// Checking if the terminal has been created and user is logged in.
await this.checkInitTerm();
for (let i = 0; i < RETRY_TIMES; i++) {
if (this.csTerm.ws.readyState !== ws.OPEN) {
// wait for valid ws connection
await delay(RETRY_INTERVAL);
} else {
for (const file of files.map((a) => a.fsPath)) {
try {
if (await fsExtra.pathExists(file)) {
this.outputChannel.appendLine(`Uploading file ${file} to cloud shell`);
await azFilePush(this.csTerm.storageAccountName,
this.csTerm.storageAccountKey,
this.csTerm.fileShareName, file);
}
} catch (err) {
this.outputChannel.appendLine(err);
}
}
if (syncAllFiles) {
vscode.window.showInformationMessage(
"Uploaded all the text files in the current workspace to CloudShell");
break;
"Synced all matched files in the current workspace to CloudShell");
}
break;
}
} else {
const message = "Do you want to open CloudShell?";
const ok: MessageItem = { title : "Yes" };
const cancel: MessageItem = { title : "No", isCloseAffordance: true };
vscode.window.showWarningMessage(message, ok, cancel).then( (response) => {
if ( response === ok ) {
this.startCloudShell().then((terminal) => {
this.csTerm.terminal = terminal[0];
this.csTerm.ws = terminal[1];
this.csTerm.storageAccountName = terminal[2];
this.csTerm.storageAccountKey = terminal[3];
this.csTerm.fileShareName = terminal[4];
this.csTerm.ResourceGroup = terminal[5];
this.outputChannel.appendLine(`Obtained cloudshell terminal, retrying push files.\n`);
this.pushFiles(files);
return;
});
} else {
console.log("Push to cloud shell cancelled by user.");
}
});
// TODO THIS LINE SEEMS UNNECESSARY console.log("Cloudshell terminal not opened when trying to transfer files");
}
}
@ -91,7 +72,29 @@ export class CloudShell extends BaseShell {
}
public async deleteFiles(files: vscode.Uri[]) {
return;
const RETRY_INTERVAL = 500;
const RETRY_TIMES = 3;
// Checking if the terminal has been created and user is logged in.
await this.checkInitTerm();
for (let i = 0; i < RETRY_TIMES; i++) {
if (this.csTerm.ws.readyState !== ws.OPEN) {
// wait for valid ws connection
await delay(RETRY_INTERVAL);
} else {
for (const file of files.map((a) => a.fsPath)) {
try {
this.outputChannel.appendLine(`Deleting file ${file} from cloud shell`);
await azFileDelete(this.csTerm.storageAccountName,
this.csTerm.storageAccountKey,
this.csTerm.fileShareName, file);
} catch (err) {
this.outputChannel.appendLine(err);
}
}
}
}
}
protected runTerraformInternal(TFCommand: string, WorkDir: string) {
@ -286,56 +289,42 @@ export class CloudShell extends BaseShell {
}
protected async uploadTFFiles(TFFiles) {
console.log("Uploading files to CloudShell");
const RETRY_INTERVAL = 500;
const RETRY_TIMES = 30;
// Checking if the terminal has been created
if ( (this.csTerm.terminal != null) && (this.csTerm.storageAccountKey != null) ) {
for (let i = 0; i < RETRY_TIMES; i++ ) {
if (this.csTerm.ws.readyState !== ws.OPEN ) {
await delay (RETRY_INTERVAL);
} else {
for (const file of TFFiles.map( (a) => a.fsPath)) {
try {
if (fsExtra.existsSync(file)) {
console.log(`Uploading file ${file} to cloud shell`);
azFilePush(this.csTerm.storageAccountName, this.csTerm.storageAccountKey, this.csTerm.fileShareName, file);
}
} catch (err) {
console.log(err);
}
}
vscode.window.showInformationMessage("Uploaded all the text files in the current workspace to CloudShell");
break;
}
}
} else {
const message = "Do you want to open CloudShell?";
const ok: MessageItem = { title : "Yes" };
const cancel: MessageItem = { title : "No", isCloseAffordance: true };
vscode.window.showWarningMessage(message, ok, cancel).then( (response) => {
if ( response === ok ) {
this.startCloudShell().then((terminal) => {
this.csTerm.terminal = terminal[0];
this.csTerm.ws = terminal[1];
this.csTerm.storageAccountName = terminal[2];
this.csTerm.storageAccountKey = terminal[3];
this.csTerm.fileShareName = terminal[4];
this.csTerm.ResourceGroup = terminal[5];
console.log(`Obtained terminal and fileshare data\n`);
this.uploadTFFiles(TFFiles);
return;
});
}
});
console.log("Terminal not opened when trying to transfer files");
}
}
protected stop(interval: NodeJS.Timer): void {
clearInterval(interval);
}
private async delayWrap(ms: number) {
await delay(500);
}
private checkInitTerm(): Promise<void> {
return new Promise<void> ((resolve, reject) => {
if ((this.csTerm.terminal !== null) && (this.csTerm.storageAccountKey !== undefined)) {
resolve();
} else {
const message = "Do you want to open CloudShell?";
const ok: MessageItem = { title: "Yes" };
const cancel: MessageItem = { title: "No", isCloseAffordance: true };
vscode.window.showWarningMessage(message, ok, cancel).then((response) => {
if (response === ok) {
this.startCloudShell().then((terminal) => {
this.csTerm.terminal = terminal[0];
this.csTerm.ws = terminal[1];
this.csTerm.storageAccountName = terminal[2];
this.csTerm.storageAccountKey = terminal[3];
this.csTerm.fileShareName = terminal[4];
this.csTerm.ResourceGroup = terminal[5];
this.outputChannel.appendLine(`Obtained cloudshell terminal, retrying push files.\n`);
this.delayWrap(500);
resolve();
}).catch((error) => {
reject(error);
});
} else {
console.log("Push to cloud shell cancelled by user.");
}
});
}
});
}
}

Просмотреть файл

@ -3,7 +3,7 @@
// Import the module and reference it with the alias vscode in your code below
import * as vscode from "vscode";
import { commands, Disposable, extensions, GlobPattern, window } from "vscode";
import { commands, Disposable, extensions, GlobPattern, MessageItem, window } from "vscode";
import { AzureServiceClient, BaseResource } from "ms-rest-azure";
import { join } from "path";
@ -20,6 +20,9 @@ import { isDotInstalled } from "./utils/dotUtils";
let cs: CloudShell;
let is: IntegratedShell;
let outputChannel: vscode.OutputChannel;
let fileWatcher: vscode.FileSystemWatcher;
let isFirstPush = true;
let _disposable: Disposable;
function getShell(): BaseShell {
let activeShell = null;
@ -35,6 +38,7 @@ function getShell(): BaseShell {
function init(): void {
cs = new CloudShell(outputChannel);
is = new IntegratedShell(outputChannel);
initFileWatcher();
outputChannel.show();
}
@ -48,18 +52,13 @@ export function activate(ctx: vscode.ExtensionContext) {
outputChannel.appendLine("Loading extension");
const fileWatcher = vscode.workspace.createFileSystemWatcher(filesGlobSetting());
// TODO: Implement filewatcher handlers and config to automatically sync changes in workspace to cloudshell.
fileWatcher.onDidDelete((deletedUri) => {
outputChannel.appendLine("Deleted: " + deletedUri.path);
});
fileWatcher.onDidCreate((createdUri) => {
outputChannel.appendLine("Created: " + createdUri.path);
});
fileWatcher.onDidChange((changedUri) => {
outputChannel.appendLine("Changed: " + changedUri.path);
});
ctx.subscriptions.push(vscode.workspace.onDidChangeConfiguration((e) => {
if (e.affectsConfiguration("tf-azure.files")) {
// dispose of current file watcher and re-init
fileWatcher.dispose();
initFileWatcher();
}
}));
ctx.subscriptions.push(vscode.commands.registerCommand("vscode-terraform-azure.init", () => {
getShell().runTerraformCmd("terraform init", Constants.clouddrive);
@ -106,7 +105,7 @@ export function activate(ctx: vscode.ExtensionContext) {
// Create a function that will sync the files to Cloudshell
if (terminalSetToCloudshell()) {
vscode.workspace.findFiles(filesGlobSetting()).then((tfFiles) => {
cs.pushFiles(tfFiles);
cs.pushFiles(tfFiles, true);
});
} else {
vscode.window.showErrorMessage("Push function only available when using cloudshell.")
@ -122,6 +121,10 @@ export function filesGlobSetting(): GlobPattern {
return vscode.workspace.getConfiguration("tf-azure").get("files") as GlobPattern;
}
export function workspaceSyncEnabled(): boolean {
return vscode.workspace.getConfiguration("tf-azure").get("syncEnabled") as boolean;
}
export async function TFLogin(api: AzureAccount) {
outputChannel.appendLine("Attempting - TFLogin");
if (!(await api.waitForLogin())) {
@ -129,3 +132,47 @@ export async function TFLogin(api: AzureAccount) {
}
outputChannel.appendLine("Succeeded - TFLogin");
}
function initFileWatcher(): void {
// TODO: Implement filewatcher handlers and config to automatically sync changes in workspace to cloudshell.
const subscriptions: Disposable[] = [];
fileWatcher = vscode.workspace.createFileSystemWatcher(filesGlobSetting());
// enable file watcher to detect file changes.
fileWatcher.onDidDelete((deletedUri) => {
if (terminalSetToCloudshell() && workspaceSyncEnabled()) {
cs.deleteFiles([deletedUri]);
}
}, this, subscriptions);
fileWatcher.onDidCreate((createdUri) => {
pushHelper(createdUri);
}, this, subscriptions);
fileWatcher.onDidChange((changedUri) => {
pushHelper(changedUri);
}, this, subscriptions);
this._disposable = Disposable.from(...subscriptions);
}
function pushHelper(uri: vscode.Uri) {
if (terminalSetToCloudshell() && workspaceSyncEnabled()) {
if (isFirstPush) {
// do initial sync of workspace before enabling file watcher.
vscode.workspace.findFiles(filesGlobSetting()).then((tfFiles) => {
cs.pushFiles(tfFiles, false);
});
isFirstPush = false;
return;
}
cs.pushFiles([uri], false);
}
}
export function deactivate(): void {
this._disposable.dispose();
if (fileWatcher) {
fileWatcher.dispose();
}
}