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

Connection Session Files #188

Merged
merged 11 commits into from May 18, 2019
Next

fsprovider: Session file

  • Loading branch information...
mtxr committed Apr 16, 2019
commit d98426484dc124198bd5e6adbe10d50ed4933278
@@ -8,8 +8,9 @@ import { getSelectedText, quickPick, readInput } from '@sqltools/core/utils/vsco
import { SidebarConnection, SidebarTableOrView, ConnectionExplorer } from '@sqltools/plugins/connection-manager/explorer';
import ResultsWebview from '@sqltools/plugins/connection-manager/screens/results';
import SettingsWebview from '@sqltools/plugins/connection-manager/screens/settings';
import { commands, QuickPickItem, ExtensionContext, StatusBarAlignment, StatusBarItem, window, workspace, ConfigurationTarget } from 'vscode';
import { commands, QuickPickItem, ExtensionContext, StatusBarAlignment, StatusBarItem, window, workspace, ConfigurationTarget, Uri, ViewColumn, TextEditor } from 'vscode';
import { ConnectionDataUpdatedRequest, ConnectRequest, DisconnectRequest, GetConnectionDataRequest, GetConnectionPasswordRequest, GetConnectionsRequest, RefreshAllRequest, RunCommandRequest } from './contracts';
import SQLToolsFSProvider from './provider';

export default class ConnectionManagerPlugin implements SQLTools.ExtensionPlugin {
public client: SQLTools.LanguageClientInterface;
@@ -20,6 +21,7 @@ export default class ConnectionManagerPlugin implements SQLTools.ExtensionPlugin
private errorHandler: SQLTools.ExtensionInterface['errorHandler'];
private explorer: ConnectionExplorer;

private fsProvider: SQLToolsFSProvider;
public handler_connectionDataUpdated: RequestHandler<typeof ConnectionDataUpdatedRequest> = (data) => this.explorer.setTreeData(data);

// extension commands
@@ -83,13 +85,27 @@ export default class ConnectionManagerPlugin implements SQLTools.ExtensionPlugin
}, (e) => this.errorHandler('Error closing connection', e));
}

private async openConnectionFile(conn: ConnectionInterface) {
if (!conn) return;
await this.fsProvider.getConnFile(conn.name);
const doc = await workspace.openTextDocument(Uri.parse(`${EXT_NAME.toLowerCase()}:/${conn.name} Session.sql`).with({ query: getConnectionId(conn) }));
await window.showTextDocument(doc, ViewColumn.Active);
}

private ext_selectConnection = async (connIdOrNode?: SidebarConnection | string) => {
if (connIdOrNode) {
const conn = connIdOrNode instanceof SidebarConnection ? connIdOrNode.conn : this.explorer.getById(connIdOrNode);
let conn = connIdOrNode instanceof SidebarConnection ? connIdOrNode.conn : this.explorer.getById(connIdOrNode);

return this._setConnection(conn as ConnectionInterface).catch(e => this.errorHandler('Error opening connection', e));
conn = await this._setConnection(conn as ConnectionInterface).catch(e => this.errorHandler('Error opening connection', e));
await this.openConnectionFile(conn)
return conn;
}
try {
const conn = await this._connect(true);
await this.openConnectionFile(conn)
} catch (error) {
this.errorHandler('Error selecting connection', error);
}
this._connect(true).catch(e => this.errorHandler('Error selecting connection', e));
}

private ext_executeQuery = async (query?: string, connName?: string) => {
@@ -344,12 +360,20 @@ export default class ConnectionManagerPlugin implements SQLTools.ExtensionPlugin
return <ConnectionInterface[]>(config.workspaceValue || config.defaultValue);
}

private changeTextEditorHandler = async (editor: TextEditor) => {
if (!editor || !editor.document || editor.document.uri.scheme !== EXT_NAME.toLowerCase()) return;

const connId = editor.document.uri.query;
await this.ext_selectConnection(connId);
}

public register(extension: SQLTools.ExtensionInterface) {
if (this.client) return; // do not register twice
this.client = extension.client;
this.context = extension.context;
this.errorHandler = extension.errorHandler;
this.explorer = new ConnectionExplorer(extension);
this.fsProvider = new SQLToolsFSProvider(this.context);

this.client.onRequest(ConnectionDataUpdatedRequest, this.handler_connectionDataUpdated);

@@ -361,6 +385,8 @@ export default class ConnectionManagerPlugin implements SQLTools.ExtensionPlugin
workspace.onDidCloseTextDocument(this.ext_refreshAll),
workspace.onDidOpenTextDocument(this.ext_refreshAll),
this.explorer.onConnectionDidChange(() => this.ext_refreshAll()),
workspace.registerFileSystemProvider(EXT_NAME.toLowerCase(), this.fsProvider, { isCaseSensitive: true }),
window.onDidChangeActiveTextEditor(this.changeTextEditorHandler),
);

// register extension commands
@@ -0,0 +1,80 @@
import {
FileSystemProvider,
ExtensionContext,
EventEmitter,
FileChangeEvent,
Disposable,
Uri,
FileStat,
FileType,
} from 'vscode';
import { promises as fs } from 'fs';
import path from 'path';
import rimraf from 'rimraf';
import { EXT_NAME } from '@sqltools/core/constants';

export default class SQLToolsFSProvider implements FileSystemProvider {
onDidChangeFileEmitter = new EventEmitter<FileChangeEvent[]>();
onDidChangeFile = this.onDidChangeFileEmitter.event;
watch(uri: Uri, options: { recursive: boolean; excludes: string[]; }): Disposable {
throw new Error('Method not implemented.');
}
async stat(uri: Uri): Promise<FileStat> {
return fs.stat(await this.getConnFile(uri.fsPath)).then(stat => ({
...stat,
mtime: +stat.mtime,
ctime: +stat.ctime,
type: FileType.File
}));
}
async readDirectory(uri: Uri): Promise<[string, FileType][]> {
throw new Error('Method not implemented.');
}
async createDirectory(uri: Uri): Promise<void> {
throw new Error('Method not implemented.');
}
async readFile(uri: Uri): Promise<Uint8Array> {
return fs.readFile(await this.getConnFile(uri.fsPath));
}
async writeFile(uri: Uri, content: Uint8Array): Promise<void> {
return fs.writeFile(await this.getConnFile(uri.fsPath), content);
}
async delete(uri: Uri) {
let p = uri.scheme === EXT_NAME.toLowerCase() ? await this.getConnFile(uri.fsPath) : uri.fsPath;
await new Promise((resolve,reject) => rimraf(p, { disableGlob: true }, (err) => err ? reject(err) : resolve()));
}
async rename(oldUri: Uri, newUri: Uri) {
const [ oldPath, newPath ] = await Promise.all([
this.getConnFile(oldUri.fsPath),
this.getConnFile(newUri.fsPath),
]);
return fs.rename(oldPath, newPath);
}

private connFileCacheDir: string;

public async getConnFile(connName: string) {
const dir = await this.getOrCreateCacheDir();
const connFile = path.join(dir, `${connName} Session.sql`);
await fs.appendFile(connFile, Buffer.from(''));
return connFile;
}

public clearCache() {
return this.delete(Uri.file(this.connFileCacheDir));
}
private async getOrCreateCacheDir() {
try {
await fs.stat(this.connFileCacheDir)
} catch (error) {
await fs.mkdir(this.connFileCacheDir, { recursive: true })
.catch(async () => {
this.connFileCacheDir = await fs.mkdtemp('sqltoolsConns');
});
}
return this.connFileCacheDir;
}
constructor(private context: ExtensionContext) {
this.connFileCacheDir = this.context.asAbsolutePath('./connFileCaches');
}
}
@@ -14,7 +14,8 @@
"@sqltools/language-server": "*",
"@sqltools/ui": "*",
"csv-stringify": "^5.3.0",
"lodash": "^4.17.11"
"lodash": "^4.17.11",
"rimraf": "^2.6.3"
},
"scripts": {
"test": "(cd ../.. && cross-env TESTS_PATH_FILTER=packages/plugins yarn test)",
@@ -23,6 +24,7 @@
"devDependencies": {
"@types/jest": "^24.0.11",
"@types/lodash": "^4.14.123",
"@types/rimraf": "^2.0.2",
"cross-env": "^5.2.0",
"jest": "^24.5.0",
"jest-cli": "^24.5.0",
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.