From a23470ca74cb90771fb9704a4ac0403c00789fa6 Mon Sep 17 00:00:00 2001 From: marcello Date: Thu, 8 Nov 2018 08:10:34 +0000 Subject: [PATCH] existing transport support --- src/abap/AbapObject.ts | 64 +++++++++++++++++++++++++++++++----------- src/adt/AdtServer.ts | 21 +++++++++++++- src/fs/AbapNode.ts | 6 +--- src/fs/FsProvider.ts | 9 ++---- 4 files changed, 71 insertions(+), 29 deletions(-) diff --git a/src/abap/AbapObject.ts b/src/abap/AbapObject.ts index 7d4d144..79d879a 100644 --- a/src/abap/AbapObject.ts +++ b/src/abap/AbapObject.ts @@ -31,6 +31,11 @@ export interface AbapMetaData { masterLanguage?: string masterSystem?: string } +export enum TransportStatus { + UNKNOWN, + REQUIRED, + LOCAL +} interface MainProgram { "adtcore:uri": string "adtcore:type": string @@ -43,6 +48,8 @@ export class AbapObject { readonly techName: string readonly path: string readonly expandable: boolean + lockId?: string + transport: TransportStatus | string = TransportStatus.UNKNOWN metaData?: AbapMetaData protected sapguiOnly: boolean @@ -117,15 +124,8 @@ export class AbapObject { ) } - async setContents( - connection: AdtConnection, - contents: Uint8Array - ): Promise { - if (!this.isLeaf()) throw FileSystemError.FileIsADirectory(this.vsName()) - if (this.sapguiOnly) - throw FileSystemError.FileNotFound( - `${this.name} can only be edited in SAPGUI` - ) + async lock(connection: AdtConnection) { + this.checkWritable() let contentUri = this.getContentsUri(connection) const response = await connection.request( @@ -134,17 +134,49 @@ export class AbapObject { { headers: { "X-sap-adt-sessiontype": "stateful" } } ) const lockRecord = await parsetoPromise(adtLockParser)(response.body) - const lock = encodeURIComponent(lockRecord.LOCK_HANDLE) - + this.lockId = lockRecord.LOCK_HANDLE + this.transport = + lockRecord.CORRNR || + (lockRecord.IS_LOCAL ? TransportStatus.LOCAL : TransportStatus.REQUIRED) + } + async unlock(connection: AdtConnection) { + this.checkWritable() + if (!this.lockId) return + let contentUri = this.getContentsUri(connection) await connection.request( - contentUri.with({ query: `lockHandle=${lock}` }), - "PUT", - { body: contents } + contentUri.with({ + query: `_action=UNLOCK&lockHandle=${encodeURIComponent(this.lockId)}` + }), + "POST" ) + } + + protected checkWritable() { + if (!this.isLeaf()) throw FileSystemError.FileIsADirectory(this.vsName()) + if (this.sapguiOnly) + throw FileSystemError.FileNotFound( + `${this.name} can only be edited in SAPGUI` + ) + } + + async setContents( + connection: AdtConnection, + contents: Uint8Array + ): Promise { + this.checkWritable() + let contentUri = this.getContentsUri(connection) + + const trselection = + typeof this.transport === "string" ? `&corrNr=${this.transport}` : "" await connection.request( - contentUri.with({ query: `_action=UNLOCK&lockHandle=${lock}` }), - "POST" + contentUri.with({ + query: `lockHandle=${encodeURIComponent( + this.lockId || "" + )}${trselection}` + }), + "PUT", + { body: contents } ) } diff --git a/src/adt/AdtServer.ts b/src/adt/AdtServer.ts index 9f45fb9..c4fb777 100644 --- a/src/adt/AdtServer.ts +++ b/src/adt/AdtServer.ts @@ -2,7 +2,7 @@ import { AdtConnection } from "./AdtConnection" import { Uri, FileSystemError, FileType, window, commands } from "vscode" import { MetaFolder } from "../fs/MetaFolder" import { AbapObjectNode, AbapNode, isAbap } from "../fs/AbapNode" -import { AbapObject } from "../abap/AbapObject" +import { AbapObject, TransportStatus } from "../abap/AbapObject" import { getRemoteList } from "../config" export const ADTBASEURL = "/sap/bc/adt/repository/nodestructure" @@ -49,6 +49,25 @@ export class AdtServer { new AbapObjectNode(new AbapObject("DEVC/K", "", ADTBASEURL, "X")) ) } + + async saveFile(file: AbapNode, content: Uint8Array): Promise { + if (file.isFolder()) throw FileSystemError.FileIsADirectory() + if (!isAbap(file)) + throw FileSystemError.NoPermissions("Can only save source code") + + const conn = await this.connectionP + await file.abapObject.lock(conn) + if (file.abapObject.transport === TransportStatus.REQUIRED) + throw new Error("transport selection not supported(yet)") + + await file.abapObject.setContents(conn, content) + + await file.abapObject.unlock(conn) + await file.stat(conn) + //might have a race condition with user changing editor... + commands.executeCommand("setContext", "abapfs:objectInactive", true) + } + findNode(uri: Uri): AbapNode { const parts = uriParts(uri) return parts.reduce((current: any, name) => { diff --git a/src/fs/AbapNode.ts b/src/fs/AbapNode.ts index 71f301d..4aab13e 100644 --- a/src/fs/AbapNode.ts +++ b/src/fs/AbapNode.ts @@ -122,11 +122,7 @@ export class AbapObjectNode implements FileStat, Iterable<[string, AbapNode]> { return Promise.reject(e) } } - public save(connection: AdtConnection, contents: Uint8Array) { - if (this.isFolder()) throw FileSystemError.FileIsADirectory() - //returning a promise will allow the exceptions to propagate - return this.abapObject.setContents(connection, contents) - } + public refresh(connection: AdtConnection): Promise { return this.abapObject.getChildren(connection).then(objects => { refreshObjects(this, objects) diff --git a/src/fs/FsProvider.ts b/src/fs/FsProvider.ts index ae4708d..71fad67 100644 --- a/src/fs/FsProvider.ts +++ b/src/fs/FsProvider.ts @@ -1,6 +1,6 @@ import * as vscode from "vscode" import { fromUri } from "../adt/AdtServer" -import { FileSystemError, commands } from "vscode" +import { FileSystemError } from "vscode" export class FsProvider implements vscode.FileSystemProvider { private _eventEmitter = new vscode.EventEmitter() @@ -58,12 +58,7 @@ export class FsProvider implements vscode.FileSystemProvider { "Not a real filesystem, file creation is not supported" ) if (!file) throw FileSystemError.FileNotFound(uri) - const connection = await server.connectionP - await file.save(connection, content) - //not active anymore... update the status. By the book we should check if it's set by this object first... - //TODO: move this logic somewhere else... - await this.stat(uri) - commands.executeCommand("setContext", "abapfs:objectInactive", true) + return server.saveFile(file, content) } delete( uri: vscode.Uri,