Adding auto sync support (#41)
* Adding auto sync support * Updated delete and push to support login * Fixes based on feedback.
This commit is contained in:
Родитель
c539ead5cf
Коммит
e7a9226ea3
|
@ -73,6 +73,7 @@ This extension requires:
|
||||||
- [Terraform](https://www.terraform.io/downloads.html)
|
- [Terraform](https://www.terraform.io/downloads.html)
|
||||||
- [Docker](http://www.docker.io) if you are running the execute test feature locally.
|
- [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.
|
- [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.
|
- 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
|
## Supported Environments
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
"Other"
|
"Other"
|
||||||
],
|
],
|
||||||
"activationEvents": [
|
"activationEvents": [
|
||||||
|
"workspaceContains:**/*.tf",
|
||||||
"onCommand:vscode-terraform-azure.init",
|
"onCommand:vscode-terraform-azure.init",
|
||||||
"onCommand:vscode-terraform-azure.plan",
|
"onCommand:vscode-terraform-azure.plan",
|
||||||
"onCommand:vscode-terraform-azure.apply",
|
"onCommand:vscode-terraform-azure.apply",
|
||||||
|
@ -41,6 +42,11 @@
|
||||||
"default": "**/*.{tf,txt,yml,tfvars,rb}",
|
"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}"
|
"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": {
|
"tf-azure.test-container": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "microsoft/terraform-test",
|
"default": "microsoft/terraform-test",
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { BaseShell } from "./baseShell";
|
||||||
import { openCloudConsole, OSes } from "./cloudConsole";
|
import { openCloudConsole, OSes } from "./cloudConsole";
|
||||||
import { delay } from "./cloudConsoleLauncher";
|
import { delay } from "./cloudConsoleLauncher";
|
||||||
import { aciConfig, Constants, exportContainerCmd, exportTestScript } from "./Constants";
|
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";
|
import { CSTerminal } from "./utilities";
|
||||||
|
|
||||||
|
@ -32,57 +32,38 @@ export class CloudShell extends BaseShell {
|
||||||
TerminalType.CloudShell,
|
TerminalType.CloudShell,
|
||||||
Constants.TerraformTerminalName);
|
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");
|
this.outputChannel.appendLine("Attempting to upload files to CloudShell");
|
||||||
const RETRY_INTERVAL = 500;
|
const RETRY_INTERVAL = 500;
|
||||||
const RETRY_TIMES = 30;
|
const RETRY_TIMES = 30;
|
||||||
|
|
||||||
// Checking if the terminal has been created
|
// Checking if the terminal has been created and user is logged in.
|
||||||
if (( this.csTerm.terminal != null) && (this.csTerm.storageAccountKey != null)) {
|
await this.checkInitTerm();
|
||||||
for (let i = 0; i < RETRY_TIMES; i++ ) {
|
|
||||||
if (this.csTerm.ws.readyState !== ws.OPEN ) {
|
for (let i = 0; i < RETRY_TIMES; i++) {
|
||||||
// wait for valid ws connection
|
if (this.csTerm.ws.readyState !== ws.OPEN) {
|
||||||
await delay (RETRY_INTERVAL);
|
// wait for valid ws connection
|
||||||
} else {
|
await delay(RETRY_INTERVAL);
|
||||||
for (const file of files.map( (a) => a.fsPath)) {
|
} else {
|
||||||
try {
|
for (const file of files.map((a) => a.fsPath)) {
|
||||||
if (await fsExtra.pathExists(file)) {
|
try {
|
||||||
this.outputChannel.appendLine(`Uploading file ${file} to cloud shell`);
|
if (await fsExtra.pathExists(file)) {
|
||||||
await azFilePush(this.csTerm.storageAccountName,
|
this.outputChannel.appendLine(`Uploading file ${file} to cloud shell`);
|
||||||
this.csTerm.storageAccountKey,
|
await azFilePush(this.csTerm.storageAccountName,
|
||||||
this.csTerm.fileShareName, file);
|
this.csTerm.storageAccountKey,
|
||||||
}
|
this.csTerm.fileShareName, file);
|
||||||
} catch (err) {
|
|
||||||
this.outputChannel.appendLine(err);
|
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
this.outputChannel.appendLine(err);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (syncAllFiles) {
|
||||||
vscode.window.showInformationMessage(
|
vscode.window.showInformationMessage(
|
||||||
"Uploaded all the text files in the current workspace to CloudShell");
|
"Synced all matched files in the current workspace to CloudShell");
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
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[]) {
|
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) {
|
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 {
|
protected stop(interval: NodeJS.Timer): void {
|
||||||
clearInterval(interval);
|
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 the module and reference it with the alias vscode in your code below
|
||||||
import * as vscode from "vscode";
|
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 { AzureServiceClient, BaseResource } from "ms-rest-azure";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
|
@ -20,6 +20,9 @@ import { isDotInstalled } from "./utils/dotUtils";
|
||||||
let cs: CloudShell;
|
let cs: CloudShell;
|
||||||
let is: IntegratedShell;
|
let is: IntegratedShell;
|
||||||
let outputChannel: vscode.OutputChannel;
|
let outputChannel: vscode.OutputChannel;
|
||||||
|
let fileWatcher: vscode.FileSystemWatcher;
|
||||||
|
let isFirstPush = true;
|
||||||
|
let _disposable: Disposable;
|
||||||
|
|
||||||
function getShell(): BaseShell {
|
function getShell(): BaseShell {
|
||||||
let activeShell = null;
|
let activeShell = null;
|
||||||
|
@ -35,6 +38,7 @@ function getShell(): BaseShell {
|
||||||
function init(): void {
|
function init(): void {
|
||||||
cs = new CloudShell(outputChannel);
|
cs = new CloudShell(outputChannel);
|
||||||
is = new IntegratedShell(outputChannel);
|
is = new IntegratedShell(outputChannel);
|
||||||
|
initFileWatcher();
|
||||||
outputChannel.show();
|
outputChannel.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,18 +52,13 @@ export function activate(ctx: vscode.ExtensionContext) {
|
||||||
|
|
||||||
outputChannel.appendLine("Loading extension");
|
outputChannel.appendLine("Loading extension");
|
||||||
|
|
||||||
const fileWatcher = vscode.workspace.createFileSystemWatcher(filesGlobSetting());
|
ctx.subscriptions.push(vscode.workspace.onDidChangeConfiguration((e) => {
|
||||||
|
if (e.affectsConfiguration("tf-azure.files")) {
|
||||||
// TODO: Implement filewatcher handlers and config to automatically sync changes in workspace to cloudshell.
|
// dispose of current file watcher and re-init
|
||||||
fileWatcher.onDidDelete((deletedUri) => {
|
fileWatcher.dispose();
|
||||||
outputChannel.appendLine("Deleted: " + deletedUri.path);
|
initFileWatcher();
|
||||||
});
|
}
|
||||||
fileWatcher.onDidCreate((createdUri) => {
|
}));
|
||||||
outputChannel.appendLine("Created: " + createdUri.path);
|
|
||||||
});
|
|
||||||
fileWatcher.onDidChange((changedUri) => {
|
|
||||||
outputChannel.appendLine("Changed: " + changedUri.path);
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.subscriptions.push(vscode.commands.registerCommand("vscode-terraform-azure.init", () => {
|
ctx.subscriptions.push(vscode.commands.registerCommand("vscode-terraform-azure.init", () => {
|
||||||
getShell().runTerraformCmd("terraform init", Constants.clouddrive);
|
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
|
// Create a function that will sync the files to Cloudshell
|
||||||
if (terminalSetToCloudshell()) {
|
if (terminalSetToCloudshell()) {
|
||||||
vscode.workspace.findFiles(filesGlobSetting()).then((tfFiles) => {
|
vscode.workspace.findFiles(filesGlobSetting()).then((tfFiles) => {
|
||||||
cs.pushFiles(tfFiles);
|
cs.pushFiles(tfFiles, true);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
vscode.window.showErrorMessage("Push function only available when using cloudshell.")
|
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;
|
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) {
|
export async function TFLogin(api: AzureAccount) {
|
||||||
outputChannel.appendLine("Attempting - TFLogin");
|
outputChannel.appendLine("Attempting - TFLogin");
|
||||||
if (!(await api.waitForLogin())) {
|
if (!(await api.waitForLogin())) {
|
||||||
|
@ -129,3 +132,47 @@ export async function TFLogin(api: AzureAccount) {
|
||||||
}
|
}
|
||||||
outputChannel.appendLine("Succeeded - TFLogin");
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче