From 2f5c2bcd8c236b4f198eec32a01e108beaab98c5 Mon Sep 17 00:00:00 2001 From: Wang Lun Date: Sun, 24 Jul 2022 03:38:06 +0900 Subject: [PATCH 01/16] fixed local recursive packages don't show --- src/FolderContext.ts | 8 +++- src/SwiftPackage.ts | 7 +++- src/ui/PackageDependencyProvider.ts | 58 +++++++---------------------- 3 files changed, 27 insertions(+), 46 deletions(-) diff --git a/src/FolderContext.ts b/src/FolderContext.ts index f1caa430a..ec8fdfd32 100644 --- a/src/FolderContext.ts +++ b/src/FolderContext.ts @@ -16,7 +16,7 @@ import * as vscode from "vscode"; import * as path from "path"; import { LinuxMain } from "./LinuxMain"; import { PackageWatcher } from "./PackageWatcher"; -import { SwiftPackage } from "./SwiftPackage"; +import { SwiftPackage, WorkspaceStateDependency } from "./SwiftPackage"; import { TestExplorer } from "./TestExplorer/TestExplorer"; import { WorkspaceContext, FolderEvent } from "./WorkspaceContext"; import { BackgroundCompilation } from "./BackgroundCompilation"; @@ -155,6 +155,12 @@ export class FolderContext implements vscode.Disposable { ); } + /** Get list of all packages */ + async getAllPackages(): Promise { + const workspaceState = await this.swiftPackage.loadWorkspaceState(); + return workspaceState?.object.dependencies ?? []; + } + static uriName(uri: vscode.Uri): string { return path.basename(uri.fsPath); } diff --git a/src/SwiftPackage.ts b/src/SwiftPackage.ts index 8ad820312..8e977638a 100644 --- a/src/SwiftPackage.ts +++ b/src/SwiftPackage.ts @@ -117,9 +117,14 @@ export interface WorkspaceState { version: number; } +export interface CheckoutState { + revision: string; + version: string; +} + export interface WorkspaceStateDependency { packageRef: { identity: string; kind: string; location: string; name: string }; - state: { name: string; path?: string }; + state: { name: string; path?: string; checkoutState?: CheckoutState }; } export interface PackagePlugin { diff --git a/src/ui/PackageDependencyProvider.ts b/src/ui/PackageDependencyProvider.ts index 707c43335..599c7718c 100644 --- a/src/ui/PackageDependencyProvider.ts +++ b/src/ui/PackageDependencyProvider.ts @@ -150,10 +150,7 @@ export class PackageDependenciesProvider implements vscode.TreeDataProvider !dependency.requirement && dependency.url) - .map( - dependency => - new PackageNode(dependency.identity, dependency.url!, "local", "local") - ); - } else { - // since Swift 5.6 local dependencies have `type` `fileSystem` - return folderContext.swiftPackage.dependencies - .filter(dependency => dependency.type === "fileSystem" && dependency.path) - .map( - dependency => - new PackageNode(dependency.identity, dependency.path!, "local", "local") - ); - } - } - - /** - * Returns a {@link PackageNode} for every remote dependency. - */ - private getRemoteDependencies(folderContext: FolderContext): PackageNode[] { - return ( - folderContext.swiftPackage.resolved?.pins.map( - pin => - new PackageNode( - pin.identity, - pin.location, - pin.state.version ?? pin.state.branch ?? pin.state.revision.substring(0, 7), - "remote" - ) - ) ?? [] - ); + private async getAllDependencies(folderContext: FolderContext): Promise { + return (await folderContext.getAllPackages()).map(dependency => { + const version = + dependency.packageRef.kind === "fileSystem" + ? "local" + : dependency.state.checkoutState?.version ?? "loading"; + return new PackageNode( + dependency.packageRef.identity, + dependency.packageRef.location!, + version, + dependency.packageRef.kind === "filesystem" ? "local" : "remote" + ); + }); } /** From 79313fac433c1f66f86eb01138f14f5074b73c8c Mon Sep 17 00:00:00 2001 From: Wang Lun Date: Sun, 24 Jul 2022 22:26:50 +0900 Subject: [PATCH 02/16] added identifier and fixed name/version in list --- src/FolderContext.ts | 3 ++- src/SwiftPackage.ts | 4 +++- src/ui/PackageDependencyProvider.ts | 10 ++++++---- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/FolderContext.ts b/src/FolderContext.ts index ec8fdfd32..6f669daca 100644 --- a/src/FolderContext.ts +++ b/src/FolderContext.ts @@ -150,7 +150,7 @@ export class FolderContext implements vscode.Disposable { return item.state.name === "edited" && item.state.path; }) .map(item => { - return { name: item.packageRef.identity, folder: item.state.path! }; + return { identity: item.packageRef.identity, name: item.packageRef.identity, folder: item.state.path! }; }) ?? [] ); } @@ -167,6 +167,7 @@ export class FolderContext implements vscode.Disposable { } export interface EditedPackage { + identity: string; name: string; folder: string; } diff --git a/src/SwiftPackage.ts b/src/SwiftPackage.ts index 8e977638a..ed87bbeca 100644 --- a/src/SwiftPackage.ts +++ b/src/SwiftPackage.ts @@ -117,9 +117,11 @@ export interface WorkspaceState { version: number; } +/** branch + revision || revision + version */ export interface CheckoutState { + branch: string | null; revision: string; - version: string; + version: string | null; } export interface WorkspaceStateDependency { diff --git a/src/ui/PackageDependencyProvider.ts b/src/ui/PackageDependencyProvider.ts index 599c7718c..54cf43491 100644 --- a/src/ui/PackageDependencyProvider.ts +++ b/src/ui/PackageDependencyProvider.ts @@ -21,7 +21,6 @@ import { WorkspaceContext } from "../WorkspaceContext"; import { FolderEvent } from "../WorkspaceContext"; import { FolderContext } from "../FolderContext"; import contextKeys from "../contextKeys"; -import { Version } from "../utilities/version"; /** * References: @@ -39,6 +38,7 @@ import { Version } from "../utilities/version"; */ export class PackageNode { constructor( + public identity: string, public name: string, public path: string, public version: string, @@ -184,12 +184,14 @@ export class PackageDependenciesProvider implements vscode.TreeDataProvider { return (await folderContext.getEditedPackages()).map( - item => new PackageNode(item.name, item.folder, "local", "editing") + item => new PackageNode(item.identity, item.name, item.folder, "local", "editing") ); } From e635ee8e10f579df0d2e74d559d884550e15f0c2 Mon Sep 17 00:00:00 2001 From: Wang Lun Date: Mon, 25 Jul 2022 01:44:14 +0900 Subject: [PATCH 03/16] fixed editing packages shows well --- src/SwiftPackage.ts | 1 + src/ui/PackageDependencyProvider.ts | 45 ++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/SwiftPackage.ts b/src/SwiftPackage.ts index ed87bbeca..23adc814b 100644 --- a/src/SwiftPackage.ts +++ b/src/SwiftPackage.ts @@ -127,6 +127,7 @@ export interface CheckoutState { export interface WorkspaceStateDependency { packageRef: { identity: string; kind: string; location: string; name: string }; state: { name: string; path?: string; checkoutState?: CheckoutState }; + subpath: string; } export interface PackagePlugin { diff --git a/src/ui/PackageDependencyProvider.ts b/src/ui/PackageDependencyProvider.ts index 54cf43491..8cd9f3ebd 100644 --- a/src/ui/PackageDependencyProvider.ts +++ b/src/ui/PackageDependencyProvider.ts @@ -42,7 +42,8 @@ export class PackageNode { public name: string, public path: string, public version: string, - public type: "local" | "remote" | "editing" + public type: "local" | "remote" | "editing", + public packagePath: string = "" ) {} toTreeItem(): vscode.TreeItem { @@ -164,15 +165,9 @@ export class PackageDependenciesProvider implements vscode.TreeDataProvider Date: Mon, 25 Jul 2022 02:13:31 +0900 Subject: [PATCH 04/16] fixed editing package path issue --- src/ui/PackageDependencyProvider.ts | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/ui/PackageDependencyProvider.ts b/src/ui/PackageDependencyProvider.ts index 8cd9f3ebd..ead77c8cb 100644 --- a/src/ui/PackageDependencyProvider.ts +++ b/src/ui/PackageDependencyProvider.ts @@ -152,17 +152,7 @@ export class PackageDependenciesProvider implements vscode.TreeDataProvider item.name === child.name); - if (!editedVersion) { - uneditedChildren.push(child); - } - } - return [...uneditedChildren, ...editedChildren].sort((first, second) => - first.name.localeCompare(second.name) - ); + return children; } if (element instanceof PackageNode) { @@ -192,11 +182,10 @@ export class PackageDependenciesProvider implements vscode.TreeDataProvider Date: Mon, 25 Jul 2022 02:47:15 +0900 Subject: [PATCH 05/16] clean up and enable menu for `swift package edit` --- src/FolderContext.ts | 14 -------------- src/ui/PackageDependencyProvider.ts | 18 +++--------------- 2 files changed, 3 insertions(+), 29 deletions(-) diff --git a/src/FolderContext.ts b/src/FolderContext.ts index 6f669daca..f2447b462 100644 --- a/src/FolderContext.ts +++ b/src/FolderContext.ts @@ -141,20 +141,6 @@ export class FolderContext implements vscode.Disposable { this.testExplorer = new TestExplorer(this); } - /** Get list of edited packages */ - async getEditedPackages(): Promise { - const workspaceState = await this.swiftPackage.loadWorkspaceState(); - return ( - workspaceState?.object.dependencies - .filter(item => { - return item.state.name === "edited" && item.state.path; - }) - .map(item => { - return { identity: item.packageRef.identity, name: item.packageRef.identity, folder: item.state.path! }; - }) ?? [] - ); - } - /** Get list of all packages */ async getAllPackages(): Promise { const workspaceState = await this.swiftPackage.loadWorkspaceState(); diff --git a/src/ui/PackageDependencyProvider.ts b/src/ui/PackageDependencyProvider.ts index ead77c8cb..33b426915 100644 --- a/src/ui/PackageDependencyProvider.ts +++ b/src/ui/PackageDependencyProvider.ts @@ -182,10 +182,9 @@ export class PackageDependenciesProvider implements vscode.TreeDataProvider { - return (await folderContext.getEditedPackages()).map( - item => new PackageNode(item.identity, item.name, item.folder, "local", "editing") - ); - } - /** * Returns a {@link FileNode} for every file or subdirectory * in the given directory. From f4ac5c5160a9ec8cfe1eab8b9738d4356301961a Mon Sep 17 00:00:00 2001 From: Wang Lun Date: Mon, 25 Jul 2022 05:45:18 +0900 Subject: [PATCH 06/16] clean up --- src/ui/PackageDependencyProvider.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/ui/PackageDependencyProvider.ts b/src/ui/PackageDependencyProvider.ts index 33b426915..64a650918 100644 --- a/src/ui/PackageDependencyProvider.ts +++ b/src/ui/PackageDependencyProvider.ts @@ -16,7 +16,7 @@ import * as vscode from "vscode"; import * as fs from "fs/promises"; import * as path from "path"; import configuration from "../configuration"; -import { getRepositoryName, buildDirectoryFromWorkspacePath } from "../utilities/utilities"; +import { buildDirectoryFromWorkspacePath } from "../utilities/utilities"; import { WorkspaceContext } from "../WorkspaceContext"; import { FolderEvent } from "../WorkspaceContext"; import { FolderContext } from "../FolderContext"; @@ -42,8 +42,7 @@ export class PackageNode { public name: string, public path: string, public version: string, - public type: "local" | "remote" | "editing", - public packagePath: string = "" + public type: "local" | "remote" | "editing" ) {} toTreeItem(): vscode.TreeItem { @@ -157,7 +156,7 @@ export class PackageDependenciesProvider implements vscode.TreeDataProvider Date: Mon, 25 Jul 2022 05:48:19 +0900 Subject: [PATCH 07/16] rename getAllPackages --- src/FolderContext.ts | 2 +- src/ui/PackageDependencyProvider.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FolderContext.ts b/src/FolderContext.ts index f2447b462..2077022e5 100644 --- a/src/FolderContext.ts +++ b/src/FolderContext.ts @@ -142,7 +142,7 @@ export class FolderContext implements vscode.Disposable { } /** Get list of all packages */ - async getAllPackages(): Promise { + async getWorkspaceDependencies(): Promise { const workspaceState = await this.swiftPackage.loadWorkspaceState(); return workspaceState?.object.dependencies ?? []; } diff --git a/src/ui/PackageDependencyProvider.ts b/src/ui/PackageDependencyProvider.ts index 64a650918..0dd062286 100644 --- a/src/ui/PackageDependencyProvider.ts +++ b/src/ui/PackageDependencyProvider.ts @@ -164,7 +164,7 @@ export class PackageDependenciesProvider implements vscode.TreeDataProvider { - return (await folderContext.getAllPackages()).map(dependency => { + return (await folderContext.getWorkspaceDependencies()).map(dependency => { const version = dependency.packageRef.kind === "fileSystem" ? "local" From 74b012f5eb484a92e5e16572816b0b7207eba78f Mon Sep 17 00:00:00 2001 From: Wang Lun Date: Mon, 25 Jul 2022 14:22:18 +0900 Subject: [PATCH 08/16] change the way of loading workspaceDependencies --- src/FolderContext.ts | 3 +-- src/SwiftPackage.ts | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/FolderContext.ts b/src/FolderContext.ts index 2077022e5..7cd3f47f5 100644 --- a/src/FolderContext.ts +++ b/src/FolderContext.ts @@ -143,8 +143,7 @@ export class FolderContext implements vscode.Disposable { /** Get list of all packages */ async getWorkspaceDependencies(): Promise { - const workspaceState = await this.swiftPackage.loadWorkspaceState(); - return workspaceState?.object.dependencies ?? []; + return this.swiftPackage.workspaceDependencies; } static uriName(uri: vscode.Uri): string { diff --git a/src/SwiftPackage.ts b/src/SwiftPackage.ts index 23adc814b..606d139c0 100644 --- a/src/SwiftPackage.ts +++ b/src/SwiftPackage.ts @@ -165,7 +165,8 @@ export class SwiftPackage implements PackageContents { readonly folder: vscode.Uri, private contents: SwiftPackageState, public resolved: PackageResolved | undefined, - public plugins: PackagePlugin[] + public plugins: PackagePlugin[], + public workspaceState: WorkspaceState | undefined ) {} /** @@ -177,7 +178,8 @@ export class SwiftPackage implements PackageContents { const contents = await SwiftPackage.loadPackage(folder); const resolved = await SwiftPackage.loadPackageResolved(folder); const plugins = await SwiftPackage.loadPlugins(folder); - return new SwiftPackage(folder, contents, resolved, plugins); + const workspaceState = await SwiftPackage.loadWorkspaceState(folder); + return new SwiftPackage(folder, contents, resolved, plugins, workspaceState); } /** @@ -261,10 +263,11 @@ export class SwiftPackage implements PackageContents { * Load workspace-state.json file for swift package * @returns Workspace state */ - public async loadWorkspaceState(): Promise { + static async loadWorkspaceState(folder: vscode.Uri): Promise { try { const uri = vscode.Uri.joinPath( - vscode.Uri.file(buildDirectoryFromWorkspacePath(this.folder.fsPath, true)), + vscode.Uri.file( + buildDirectoryFromWorkspacePath(folder.fsPath, true)), "workspace-state.json" ); const contents = await fs.readFile(uri.fsPath, "utf8"); @@ -278,6 +281,7 @@ export class SwiftPackage implements PackageContents { /** Reload swift package */ public async reload() { this.contents = await SwiftPackage.loadPackage(this.folder); + this.workspaceState = await SwiftPackage.loadWorkspaceState(this.folder); } /** Reload Package.resolved file */ @@ -319,6 +323,10 @@ export class SwiftPackage implements PackageContents { return (this.contents as PackageContents)?.dependencies ?? []; } + get workspaceDependencies(): WorkspaceStateDependency[] { + return this.workspaceState?.object.dependencies ?? []; + } + /** array of targets in Swift Package */ get targets(): Target[] { return (this.contents as PackageContents)?.targets ?? []; From 856b72bf4ac72d7582872a828c2e3aab5a89d1c9 Mon Sep 17 00:00:00 2001 From: Wang Lun Date: Mon, 25 Jul 2022 21:59:18 +0900 Subject: [PATCH 09/16] fixed dependency issues --- package.json | 10 +++++++--- src/FolderContext.ts | 5 +++++ src/PackageWatcher.ts | 29 +++++++++++++++++++++++++++++ src/SwiftPackage.ts | 8 +++++--- src/WorkspaceContext.ts | 2 ++ src/commands.ts | 6 +++--- src/ui/PackageDependencyProvider.ts | 22 ++++++++++------------ 7 files changed, 61 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index e523706ec..6e9845a17 100644 --- a/package.json +++ b/package.json @@ -296,13 +296,17 @@ "command": "swift.useLocalDependency", "when": "view == packageDependencies && viewItem == remote" }, + { + "command": "swift.editDependency", + "when": "view == packageDependencies && viewItem == remote" + }, { "command": "swift.uneditDependency", - "when": "view == packageDependencies && viewItem == editing" + "when": "view == packageDependencies && viewItem == edited" }, { "command": "swift.openInWorkspace", - "when": "view == packageDependencies && viewItem == editing" + "when": "view == packageDependencies && viewItem == edited" }, { "command": "swift.openInWorkspace", @@ -433,4 +437,4 @@ "plist": "^3.0.5", "vscode-languageclient": "^8.0.0" } -} +} \ No newline at end of file diff --git a/src/FolderContext.ts b/src/FolderContext.ts index 7cd3f47f5..ced12662c 100644 --- a/src/FolderContext.ts +++ b/src/FolderContext.ts @@ -123,6 +123,11 @@ export class FolderContext implements vscode.Disposable { await this.swiftPackage.reloadPackageResolved(); } + /** reload dependencies for workspace */ + async reloadDependencies() { + await this.swiftPackage.reloadDependencies(); + } + /** * Fire an event to all folder observers * @param event event type diff --git a/src/PackageWatcher.ts b/src/PackageWatcher.ts index f7cea0cc8..6309ae9ac 100644 --- a/src/PackageWatcher.ts +++ b/src/PackageWatcher.ts @@ -14,6 +14,7 @@ import * as vscode from "vscode"; import { FolderContext } from "./FolderContext"; +import { buildDirectoryFromWorkspacePath } from "./utilities/utilities"; import { FolderEvent, WorkspaceContext } from "./WorkspaceContext"; /** @@ -25,6 +26,7 @@ import { FolderEvent, WorkspaceContext } from "./WorkspaceContext"; export class PackageWatcher { private packageFileWatcher?: vscode.FileSystemWatcher; private resolvedFileWatcher?: vscode.FileSystemWatcher; + private workspaceStateFileWatcher?: vscode.FileSystemWatcher; constructor(private folderContext: FolderContext, private workspaceContext: WorkspaceContext) {} @@ -35,6 +37,7 @@ export class PackageWatcher { install() { this.packageFileWatcher = this.createPackageFileWatcher(); this.resolvedFileWatcher = this.createResolvedFileWatcher(); + this.workspaceStateFileWatcher = this.createWorkspaceStateFileWatcher(); } /** @@ -44,6 +47,7 @@ export class PackageWatcher { dispose() { this.packageFileWatcher?.dispose(); this.resolvedFileWatcher?.dispose(); + this.workspaceStateFileWatcher?.dispose(); } private createPackageFileWatcher(): vscode.FileSystemWatcher { @@ -66,6 +70,20 @@ export class PackageWatcher { return watcher; } + private createWorkspaceStateFileWatcher(): vscode.FileSystemWatcher { + const uri = vscode.Uri.file( + buildDirectoryFromWorkspacePath(this.folderContext.folder.fsPath, true) + ); + + const watcher = vscode.workspace.createFileSystemWatcher( + new vscode.RelativePattern(uri, "workspace-state.json") + ); + watcher.onDidCreate(async () => await this.handleWorkspaceStateChange()); + watcher.onDidChange(async () => await this.handleWorkspaceStateChange()); + watcher.onDidDelete(async () => await this.handleWorkspaceStateChange()); + return watcher; + } + /** * Handles a create or change event for **Package.swift**. * @@ -88,4 +106,15 @@ export class PackageWatcher { await this.folderContext.reloadPackageResolved(); this.workspaceContext.fireEvent(this.folderContext, FolderEvent.resolvedUpdated); } + + /** + * Handles a create or change event for **workspace-state.json**. + * + * This will resolve any changes in the workspace-state.json + */ + private async handleWorkspaceStateChange() { + // load dependency info from workspace-state.json + await this.folderContext.reloadDependencies(); + this.workspaceContext.fireEvent(this.folderContext, FolderEvent.workspaceStateUpdated); + } } diff --git a/src/SwiftPackage.ts b/src/SwiftPackage.ts index 606d139c0..3654f7e22 100644 --- a/src/SwiftPackage.ts +++ b/src/SwiftPackage.ts @@ -266,8 +266,7 @@ export class SwiftPackage implements PackageContents { static async loadWorkspaceState(folder: vscode.Uri): Promise { try { const uri = vscode.Uri.joinPath( - vscode.Uri.file( - buildDirectoryFromWorkspacePath(folder.fsPath, true)), + vscode.Uri.file(buildDirectoryFromWorkspacePath(folder.fsPath, true)), "workspace-state.json" ); const contents = await fs.readFile(uri.fsPath, "utf8"); @@ -281,7 +280,6 @@ export class SwiftPackage implements PackageContents { /** Reload swift package */ public async reload() { this.contents = await SwiftPackage.loadPackage(this.folder); - this.workspaceState = await SwiftPackage.loadWorkspaceState(this.folder); } /** Reload Package.resolved file */ @@ -289,6 +287,10 @@ export class SwiftPackage implements PackageContents { this.resolved = await SwiftPackage.loadPackageResolved(this.folder); } + public async reloadDependencies() { + this.workspaceState = await SwiftPackage.loadWorkspaceState(this.folder); + } + /** Return if has valid contents */ public get isValid(): boolean { return isPackage(this.contents); diff --git a/src/WorkspaceContext.ts b/src/WorkspaceContext.ts index 11d67f9a9..4b9c3719f 100644 --- a/src/WorkspaceContext.ts +++ b/src/WorkspaceContext.ts @@ -491,6 +491,8 @@ export enum FolderEvent { packageUpdated = "packageUpdated", // Package.resolved has been updated resolvedUpdated = "resolvedUpdated", + // workspace-state.json has been updated + workspaceStateUpdated = "workspaceStateUpdated", } /** Workspace Folder observer function */ diff --git a/src/commands.ts b/src/commands.ts index cb9425f2c..4c2e9d978 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -455,17 +455,17 @@ export function register(ctx: WorkspaceContext) { vscode.commands.registerCommand("swift.openPackage", () => openPackage(ctx)), vscode.commands.registerCommand("swift.useLocalDependency", item => { if (item instanceof PackageNode) { - useLocalDependency(item.name, ctx); + useLocalDependency(item.identity, ctx); } }), vscode.commands.registerCommand("swift.editDependency", item => { if (item instanceof PackageNode) { - editDependency(item.name, ctx); + editDependency(item.identity, ctx); } }), vscode.commands.registerCommand("swift.uneditDependency", item => { if (item instanceof PackageNode) { - uneditDependency(item.name, ctx); + uneditDependency(item.identity, ctx); } }), vscode.commands.registerCommand("swift.openInWorkspace", item => { diff --git a/src/ui/PackageDependencyProvider.ts b/src/ui/PackageDependencyProvider.ts index 0dd062286..fd8ebedcc 100644 --- a/src/ui/PackageDependencyProvider.ts +++ b/src/ui/PackageDependencyProvider.ts @@ -42,7 +42,7 @@ export class PackageNode { public name: string, public path: string, public version: string, - public type: "local" | "remote" | "editing" + public type: "local" | "remote" | "edited" ) {} toTreeItem(): vscode.TreeItem { @@ -50,9 +50,7 @@ export class PackageNode { item.id = this.path; item.description = this.version; item.iconPath = - this.type === "editing" - ? new vscode.ThemeIcon("edit") - : new vscode.ThemeIcon("archive"); + this.type === "edited" ? new vscode.ThemeIcon("edit") : new vscode.ThemeIcon("archive"); item.contextValue = this.type; return item; } @@ -127,12 +125,13 @@ export class PackageDependenciesProvider implements vscode.TreeDataProvider Date: Mon, 25 Jul 2022 23:27:06 +0900 Subject: [PATCH 10/16] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6e9845a17..de488f989 100644 --- a/package.json +++ b/package.json @@ -437,4 +437,4 @@ "plist": "^3.0.5", "vscode-languageclient": "^8.0.0" } -} \ No newline at end of file +} From ce97c15d1321c96c31ddac83bd6f0400335309a0 Mon Sep 17 00:00:00 2001 From: Wang Lun Date: Tue, 26 Jul 2022 21:28:31 +0900 Subject: [PATCH 11/16] don't cache dependencies --- src/FolderContext.ts | 8 ++------ src/PackageWatcher.ts | 2 -- src/SwiftPackage.ts | 14 ++------------ src/ui/PackageDependencyProvider.ts | 9 ++------- 4 files changed, 6 insertions(+), 27 deletions(-) diff --git a/src/FolderContext.ts b/src/FolderContext.ts index ced12662c..f0504cbac 100644 --- a/src/FolderContext.ts +++ b/src/FolderContext.ts @@ -123,11 +123,6 @@ export class FolderContext implements vscode.Disposable { await this.swiftPackage.reloadPackageResolved(); } - /** reload dependencies for workspace */ - async reloadDependencies() { - await this.swiftPackage.reloadDependencies(); - } - /** * Fire an event to all folder observers * @param event event type @@ -148,7 +143,8 @@ export class FolderContext implements vscode.Disposable { /** Get list of all packages */ async getWorkspaceDependencies(): Promise { - return this.swiftPackage.workspaceDependencies; + const workspaceState = await SwiftPackage.loadWorkspaceState(this.folder); + return workspaceState?.object?.dependencies ?? []; } static uriName(uri: vscode.Uri): string { diff --git a/src/PackageWatcher.ts b/src/PackageWatcher.ts index 6309ae9ac..d7c6f799c 100644 --- a/src/PackageWatcher.ts +++ b/src/PackageWatcher.ts @@ -113,8 +113,6 @@ export class PackageWatcher { * This will resolve any changes in the workspace-state.json */ private async handleWorkspaceStateChange() { - // load dependency info from workspace-state.json - await this.folderContext.reloadDependencies(); this.workspaceContext.fireEvent(this.folderContext, FolderEvent.workspaceStateUpdated); } } diff --git a/src/SwiftPackage.ts b/src/SwiftPackage.ts index 3654f7e22..80d243d6a 100644 --- a/src/SwiftPackage.ts +++ b/src/SwiftPackage.ts @@ -165,8 +165,7 @@ export class SwiftPackage implements PackageContents { readonly folder: vscode.Uri, private contents: SwiftPackageState, public resolved: PackageResolved | undefined, - public plugins: PackagePlugin[], - public workspaceState: WorkspaceState | undefined + public plugins: PackagePlugin[] ) {} /** @@ -178,8 +177,7 @@ export class SwiftPackage implements PackageContents { const contents = await SwiftPackage.loadPackage(folder); const resolved = await SwiftPackage.loadPackageResolved(folder); const plugins = await SwiftPackage.loadPlugins(folder); - const workspaceState = await SwiftPackage.loadWorkspaceState(folder); - return new SwiftPackage(folder, contents, resolved, plugins, workspaceState); + return new SwiftPackage(folder, contents, resolved, plugins); } /** @@ -287,10 +285,6 @@ export class SwiftPackage implements PackageContents { this.resolved = await SwiftPackage.loadPackageResolved(this.folder); } - public async reloadDependencies() { - this.workspaceState = await SwiftPackage.loadWorkspaceState(this.folder); - } - /** Return if has valid contents */ public get isValid(): boolean { return isPackage(this.contents); @@ -325,10 +319,6 @@ export class SwiftPackage implements PackageContents { return (this.contents as PackageContents)?.dependencies ?? []; } - get workspaceDependencies(): WorkspaceStateDependency[] { - return this.workspaceState?.object.dependencies ?? []; - } - /** array of targets in Swift Package */ get targets(): Target[] { return (this.contents as PackageContents)?.targets ?? []; diff --git a/src/ui/PackageDependencyProvider.ts b/src/ui/PackageDependencyProvider.ts index dc773cc40..ba8202b5c 100644 --- a/src/ui/PackageDependencyProvider.ts +++ b/src/ui/PackageDependencyProvider.ts @@ -152,13 +152,8 @@ export class PackageDependenciesProvider implements vscode.TreeDataProvider { From 58f0bb601340025862f5bd08c62c6256d5f584ec Mon Sep 17 00:00:00 2001 From: Wang Lun Date: Tue, 26 Jul 2022 21:47:31 +0900 Subject: [PATCH 12/16] revert some code --- src/FolderContext.ts | 20 ++++++++- src/SwiftPackage.ts | 4 +- src/ui/PackageDependencyProvider.ts | 67 +++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 3 deletions(-) diff --git a/src/FolderContext.ts b/src/FolderContext.ts index f0504cbac..d57b75d2e 100644 --- a/src/FolderContext.ts +++ b/src/FolderContext.ts @@ -141,9 +141,27 @@ export class FolderContext implements vscode.Disposable { this.testExplorer = new TestExplorer(this); } + /** Get list of edited packages */ + async getEditedPackages(): Promise { + const workspaceState = await this.swiftPackage.loadWorkspaceState(); + return ( + workspaceState?.object.dependencies + .filter(item => { + return item.state.name === "edited" && item.state.path; + }) + .map(item => { + return { + identity: item.packageRef.identity, + name: item.packageRef.name, + folder: item.state.path!, + }; + }) ?? [] + ); + } + /** Get list of all packages */ async getWorkspaceDependencies(): Promise { - const workspaceState = await SwiftPackage.loadWorkspaceState(this.folder); + const workspaceState = await this.swiftPackage.loadWorkspaceState(); return workspaceState?.object?.dependencies ?? []; } diff --git a/src/SwiftPackage.ts b/src/SwiftPackage.ts index 80d243d6a..ab0e07515 100644 --- a/src/SwiftPackage.ts +++ b/src/SwiftPackage.ts @@ -261,10 +261,10 @@ export class SwiftPackage implements PackageContents { * Load workspace-state.json file for swift package * @returns Workspace state */ - static async loadWorkspaceState(folder: vscode.Uri): Promise { + async loadWorkspaceState(): Promise { try { const uri = vscode.Uri.joinPath( - vscode.Uri.file(buildDirectoryFromWorkspacePath(folder.fsPath, true)), + vscode.Uri.file(buildDirectoryFromWorkspacePath(this.folder.fsPath, true)), "workspace-state.json" ); const contents = await fs.readFile(uri.fsPath, "utf8"); diff --git a/src/ui/PackageDependencyProvider.ts b/src/ui/PackageDependencyProvider.ts index ba8202b5c..df1983958 100644 --- a/src/ui/PackageDependencyProvider.ts +++ b/src/ui/PackageDependencyProvider.ts @@ -21,6 +21,7 @@ import { WorkspaceContext } from "../WorkspaceContext"; import { FolderEvent } from "../WorkspaceContext"; import { FolderContext } from "../FolderContext"; import contextKeys from "../contextKeys"; +import { Version } from "../utilities/version"; /** * References: @@ -198,6 +199,72 @@ export class PackageDependenciesProvider implements vscode.TreeDataProvider !dependency.requirement && dependency.url) + .map( + dependency => + new PackageNode( + dependency.identity, + dependency.identity, + dependency.url!, + "local", + "local" + ) + ); + } else { + // since Swift 5.6 local dependencies have `type` `fileSystem` + return folderContext.swiftPackage.dependencies + .filter(dependency => dependency.type === "fileSystem" && dependency.path) + .map( + dependency => + new PackageNode( + dependency.identity, + dependency.identity, + dependency.path!, + "local", + "local" + ) + ); + } + } + + /** + * Returns a {@link PackageNode} for every remote dependency. + */ + private getRemoteDependencies(folderContext: FolderContext): PackageNode[] { + return ( + folderContext.swiftPackage.resolved?.pins.map( + pin => + new PackageNode( + pin.identity, + pin.identity, + pin.location, + pin.state.version ?? pin.state.branch ?? pin.state.revision.substring(0, 7), + "remote" + ) + ) ?? [] + ); + } + + /** + * Return list of package dependencies in edit mode + * @param folderContext Folder to get edited dependencies for + * @returns Array of packages + */ + private async getEditedDependencies(folderContext: FolderContext): Promise { + return (await folderContext.getEditedPackages()).map( + item => new PackageNode(item.name, item.name, item.folder, "local", "edited") + ); + } + /** * Returns a {@link FileNode} for every file or subdirectory * in the given directory. From 1060f1734d2f7a78491a820c2f39914e3ddef39d Mon Sep 17 00:00:00 2001 From: Wang Lun Date: Tue, 26 Jul 2022 21:53:01 +0900 Subject: [PATCH 13/16] revert EditedPackage --- src/FolderContext.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/FolderContext.ts b/src/FolderContext.ts index d57b75d2e..684ce5577 100644 --- a/src/FolderContext.ts +++ b/src/FolderContext.ts @@ -151,8 +151,7 @@ export class FolderContext implements vscode.Disposable { }) .map(item => { return { - identity: item.packageRef.identity, - name: item.packageRef.name, + name: item.packageRef.identity, folder: item.state.path!, }; }) ?? [] @@ -171,7 +170,6 @@ export class FolderContext implements vscode.Disposable { } export interface EditedPackage { - identity: string; name: string; folder: string; } From 603bbb1ebf5e0c9e3d799cefafe06bd65b5d4cfc Mon Sep 17 00:00:00 2001 From: Wang Lun Date: Thu, 28 Jul 2022 20:43:57 +0900 Subject: [PATCH 14/16] update customTask, fixed watcher --- package-lock.json | 62 +++++++++++++++++ package.json | 2 + src/FolderContext.ts | 4 ++ src/PackageWatcher.ts | 46 ++++--------- src/SwiftPackage.ts | 72 +++++++++++++++++++- src/SwiftTaskProvider.ts | 101 +++++++++++++++++++++++++++- src/WorkspaceContext.ts | 7 +- src/commands.ts | 24 ++++--- src/extension.ts | 1 + src/ui/PackageDependencyProvider.ts | 16 +++-- 10 files changed, 284 insertions(+), 51 deletions(-) diff --git a/package-lock.json b/package-lock.json index 482a06700..da8da405d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,10 +9,12 @@ "version": "0.7.0", "dependencies": { "@types/plist": "^3.0.2", + "checksum": "^1.0.0", "plist": "^3.0.5", "vscode-languageclient": "^8.0.0" }, "devDependencies": { + "@types/checksum": "^0.1.33", "@types/glob": "^7.1.4", "@types/mocha": "^9.0.0", "@types/node": "14.x", @@ -126,6 +128,12 @@ "node": ">= 6" } }, + "node_modules/@types/checksum": { + "version": "0.1.33", + "resolved": "https://registry.npmjs.org/@types/checksum/-/checksum-0.1.33.tgz", + "integrity": "sha512-fe6ZaTTh2Qk6J68EOKGz992sw6Y+sGK86skRTT4tz9Wxby6owinOXzHE73wBOw/ln7ty4rTbxjHx0RwjIM1LKw==", + "dev": true + }, "node_modules/@types/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", @@ -720,6 +728,17 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/checksum": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/checksum/-/checksum-1.0.0.tgz", + "integrity": "sha512-68bHejnM/sBQhjXcXd2mFusICnqAwikZ9RVMURIacWh7moNjgOdHKimS6yk30Np/PwfR00dceY4b1GwWanu5cg==", + "dependencies": { + "optimist": "~0.3.5" + }, + "bin": { + "checksum": "bin/checksum-cli.js" + } + }, "node_modules/cheerio": { "version": "1.0.0-rc.10", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", @@ -2684,6 +2703,14 @@ "wrappy": "1" } }, + "node_modules/optimist": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", + "integrity": "sha512-TCx0dXQzVtSCg2OgY/bO9hjM9cV4XYx09TVK+s3+FhkjT6LovsLe+pPMzpWf+6yXK/hUizs2gUoTw3jHM0VaTQ==", + "dependencies": { + "wordwrap": "~0.0.2" + } + }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -3740,6 +3767,14 @@ "node": ">=0.10.0" } }, + "node_modules/wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/workerpool": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", @@ -3953,6 +3988,12 @@ "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", "dev": true }, + "@types/checksum": { + "version": "0.1.33", + "resolved": "https://registry.npmjs.org/@types/checksum/-/checksum-0.1.33.tgz", + "integrity": "sha512-fe6ZaTTh2Qk6J68EOKGz992sw6Y+sGK86skRTT4tz9Wxby6owinOXzHE73wBOw/ln7ty4rTbxjHx0RwjIM1LKw==", + "dev": true + }, "@types/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", @@ -4366,6 +4407,14 @@ "supports-color": "^7.1.0" } }, + "checksum": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/checksum/-/checksum-1.0.0.tgz", + "integrity": "sha512-68bHejnM/sBQhjXcXd2mFusICnqAwikZ9RVMURIacWh7moNjgOdHKimS6yk30Np/PwfR00dceY4b1GwWanu5cg==", + "requires": { + "optimist": "~0.3.5" + } + }, "cheerio": { "version": "1.0.0-rc.10", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", @@ -5815,6 +5864,14 @@ "wrappy": "1" } }, + "optimist": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", + "integrity": "sha512-TCx0dXQzVtSCg2OgY/bO9hjM9cV4XYx09TVK+s3+FhkjT6LovsLe+pPMzpWf+6yXK/hUizs2gUoTw3jHM0VaTQ==", + "requires": { + "wordwrap": "~0.0.2" + } + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -6608,6 +6665,11 @@ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==" + }, "workerpool": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", diff --git a/package.json b/package.json index de488f989..912feb394 100644 --- a/package.json +++ b/package.json @@ -416,6 +416,7 @@ "dev-package": "vsce package -o swift-lang-development.vsix" }, "devDependencies": { + "@types/checksum": "^0.1.33", "@types/glob": "^7.1.4", "@types/mocha": "^9.0.0", "@types/node": "14.x", @@ -434,6 +435,7 @@ }, "dependencies": { "@types/plist": "^3.0.2", + "checksum": "^1.0.0", "plist": "^3.0.5", "vscode-languageclient": "^8.0.0" } diff --git a/src/FolderContext.ts b/src/FolderContext.ts index 684ce5577..95b78a2cb 100644 --- a/src/FolderContext.ts +++ b/src/FolderContext.ts @@ -123,6 +123,10 @@ export class FolderContext implements vscode.Disposable { await this.swiftPackage.reloadPackageResolved(); } + get resolvedContent(): string | undefined { + return this.resolvedContent; + } + /** * Fire an event to all folder observers * @param event event type diff --git a/src/PackageWatcher.ts b/src/PackageWatcher.ts index d7c6f799c..9e4a09f0a 100644 --- a/src/PackageWatcher.ts +++ b/src/PackageWatcher.ts @@ -14,7 +14,6 @@ import * as vscode from "vscode"; import { FolderContext } from "./FolderContext"; -import { buildDirectoryFromWorkspacePath } from "./utilities/utilities"; import { FolderEvent, WorkspaceContext } from "./WorkspaceContext"; /** @@ -26,7 +25,6 @@ import { FolderEvent, WorkspaceContext } from "./WorkspaceContext"; export class PackageWatcher { private packageFileWatcher?: vscode.FileSystemWatcher; private resolvedFileWatcher?: vscode.FileSystemWatcher; - private workspaceStateFileWatcher?: vscode.FileSystemWatcher; constructor(private folderContext: FolderContext, private workspaceContext: WorkspaceContext) {} @@ -37,7 +35,6 @@ export class PackageWatcher { install() { this.packageFileWatcher = this.createPackageFileWatcher(); this.resolvedFileWatcher = this.createResolvedFileWatcher(); - this.workspaceStateFileWatcher = this.createWorkspaceStateFileWatcher(); } /** @@ -47,7 +44,6 @@ export class PackageWatcher { dispose() { this.packageFileWatcher?.dispose(); this.resolvedFileWatcher?.dispose(); - this.workspaceStateFileWatcher?.dispose(); } private createPackageFileWatcher(): vscode.FileSystemWatcher { @@ -64,23 +60,9 @@ export class PackageWatcher { const watcher = vscode.workspace.createFileSystemWatcher( new vscode.RelativePattern(this.folderContext.folder, "Package.resolved") ); - watcher.onDidCreate(async () => await this.handlePackageResolvedChange()); - watcher.onDidChange(async () => await this.handlePackageResolvedChange()); - watcher.onDidDelete(async () => await this.handlePackageResolvedChange()); - return watcher; - } - - private createWorkspaceStateFileWatcher(): vscode.FileSystemWatcher { - const uri = vscode.Uri.file( - buildDirectoryFromWorkspacePath(this.folderContext.folder.fsPath, true) - ); - - const watcher = vscode.workspace.createFileSystemWatcher( - new vscode.RelativePattern(uri, "workspace-state.json") - ); - watcher.onDidCreate(async () => await this.handleWorkspaceStateChange()); - watcher.onDidChange(async () => await this.handleWorkspaceStateChange()); - watcher.onDidDelete(async () => await this.handleWorkspaceStateChange()); + // watcher.onDidCreate(async () => await this.handlePackageResolvedChange()); + watcher.onDidChange(async () => await this.handlePackageResolvedChange("change")); + watcher.onDidDelete(async () => await this.handlePackageResolvedChange("delete")); return watcher; } @@ -102,17 +84,17 @@ export class PackageWatcher { * * This will resolve any changes in the Package.resolved. */ - private async handlePackageResolvedChange() { - await this.folderContext.reloadPackageResolved(); - this.workspaceContext.fireEvent(this.folderContext, FolderEvent.resolvedUpdated); - } + private async handlePackageResolvedChange(action: "change" | "delete") { + // if Package.resolved is modified, we need to resolve the dependencies + // after resolving is done, it will MODIFY the Package.resolved again + // BUT, the file content is not actually changed + // we don't want to resolve the dependencies again + const hasChanges = await this.folderContext.swiftPackage.packageResovledHasChanged(action); + if (!hasChanges) { + return; + } - /** - * Handles a create or change event for **workspace-state.json**. - * - * This will resolve any changes in the workspace-state.json - */ - private async handleWorkspaceStateChange() { - this.workspaceContext.fireEvent(this.folderContext, FolderEvent.workspaceStateUpdated); + await this.folderContext.swiftPackage.reloadPackageResolved(); + this.workspaceContext.fireEvent(this.folderContext, FolderEvent.resolvedUpdated); } } diff --git a/src/SwiftPackage.ts b/src/SwiftPackage.ts index ab0e07515..db1797e2f 100644 --- a/src/SwiftPackage.ts +++ b/src/SwiftPackage.ts @@ -19,6 +19,7 @@ import { execSwift, getErrorDescription, } from "./utilities/utilities"; +import checksum = require("checksum"); /** Swift Package Manager contents */ export interface PackageContents { @@ -165,7 +166,9 @@ export class SwiftPackage implements PackageContents { readonly folder: vscode.Uri, private contents: SwiftPackageState, public resolved: PackageResolved | undefined, - public plugins: PackagePlugin[] + public plugins: PackagePlugin[], + public resolvedContent: string | undefined, + public dependencySet: Set ) {} /** @@ -177,7 +180,8 @@ export class SwiftPackage implements PackageContents { const contents = await SwiftPackage.loadPackage(folder); const resolved = await SwiftPackage.loadPackageResolved(folder); const plugins = await SwiftPackage.loadPlugins(folder); - return new SwiftPackage(folder, contents, resolved, plugins); + const resolvedContent = await SwiftPackage.loadPackageResolvedFile(folder); + return new SwiftPackage(folder, contents, resolved, plugins, resolvedContent, new Set()); } /** @@ -213,10 +217,22 @@ export class SwiftPackage implements PackageContents { } } - static async loadPackageResolved(folder: vscode.Uri): Promise { + static async loadPackageResolvedFile(folder: vscode.Uri): Promise { try { const uri = vscode.Uri.joinPath(folder, "Package.resolved"); const contents = await fs.readFile(uri.fsPath, "utf8"); + return contents; + } catch { + return undefined; + } + } + + static async loadPackageResolved(folder: vscode.Uri): Promise { + try { + const contents = await SwiftPackage.loadPackageResolvedFile(folder); + if (contents === undefined) { + return undefined; + } const json = JSON.parse(contents); const version = <{ version: number }>json; if (version.version === 1) { @@ -257,6 +273,34 @@ export class SwiftPackage implements PackageContents { } } + async packageResovledHasChanged(action: any): Promise { + console.log(action); + const resolvedContent = await SwiftPackage.loadPackageResolvedFile(this.folder); + + console.log(resolvedContent); + console.log(this.resolvedContent); + + if (resolvedContent === undefined) { + return false; + } + // deletion --> creation --> modification + // r undefined exists exists + // pr exists undefined exists + + if (this.resolvedContent === undefined) { + return true; + } + + const oldChecksum = checksum(resolvedContent); + const newChecksum = checksum(this.resolvedContent); + + if (oldChecksum !== newChecksum) { + return true; + } + + return false; + } + /** * Load workspace-state.json file for swift package * @returns Workspace state @@ -275,6 +319,27 @@ export class SwiftPackage implements PackageContents { } } + /** + * Run `swift package describe` and return results + * @param folder folder package is in + * @returns results of `swift package describe` + */ + async resolveDependencyGraph(): Promise> { + return this.dependencySet; + } + + updateDependencySetWithStdout(stdout: string): void { + const lines = stdout + .split("\n") + .filter(item => item !== "") + .map(item => item.trim()); + this.updateDependencySet(new Set(lines ?? [])); + } + + updateDependencySet(dependencySet: Set): void { + this.dependencySet = dependencySet; + } + /** Reload swift package */ public async reload() { this.contents = await SwiftPackage.loadPackage(this.folder); @@ -282,6 +347,7 @@ export class SwiftPackage implements PackageContents { /** Reload Package.resolved file */ public async reloadPackageResolved() { + this.resolvedContent = await SwiftPackage.loadPackageResolvedFile(this.folder); this.resolved = await SwiftPackage.loadPackageResolved(this.folder); } diff --git a/src/SwiftTaskProvider.ts b/src/SwiftTaskProvider.ts index 4f90d35c2..19a6d103b 100644 --- a/src/SwiftTaskProvider.ts +++ b/src/SwiftTaskProvider.ts @@ -18,7 +18,12 @@ import { WorkspaceContext } from "./WorkspaceContext"; import { FolderContext } from "./FolderContext"; import { Product } from "./SwiftPackage"; import configuration from "./configuration"; -import { getSwiftExecutable, swiftRuntimeEnv, withSwiftSDKFlags } from "./utilities/utilities"; +import { + execSwift, + getSwiftExecutable, + swiftRuntimeEnv, + withSwiftSDKFlags, +} from "./utilities/utilities"; import { Version } from "./utilities/version"; /** @@ -212,6 +217,7 @@ export function createSwiftTask(args: string[], name: string, config: TaskConfig }), config?.problemMatcher ); + // This doesn't include any quotes added by VS Code. // See also: https://github.com/microsoft/vscode/issues/137895 @@ -227,6 +233,66 @@ export function createSwiftTask(args: string[], name: string, config: TaskConfig return task; } +interface SwiftOutput { + (stdout: string, stderr: string): void; +} + +/** + * Helper function to create a {@link vscode.Task Task} with the given parameters. + */ +export function createSwiftTask2( + args: string[], + name: string, + config: TaskConfig, + output: SwiftOutput +): vscode.Task { + args = withSwiftSDKFlags(args); + + // Add relative path current working directory + const cwd = config.cwd.fsPath; + const fullCwd = config.cwd.fsPath; + + /* Currently there seems to be a bug in vscode where kicking off two tasks + with the same definition but different scopes messes with the task + completion code. When that is resolved we will go back to the code below + where we only store the relative cwd instead of the full cwd + + const scopeWorkspaceFolder = config.scope as vscode.WorkspaceFolder; + if (scopeWorkspaceFolder.uri.fsPath) { + cwd = path.relative(scopeWorkspaceFolder.uri.fsPath, config.cwd.fsPath); + } else { + cwd = config.cwd.fsPath; + }*/ + + const task = new vscode.Task( + { type: "swift", args: args, cwd: cwd }, + config?.scope ?? vscode.TaskScope.Workspace, + name, + "swift", + new vscode.CustomExecution(async (): Promise => { + // When the task is executed, this callback will run. Here, we setup for running the task. + const { stdout, stderr } = await execSwift(args, { + cwd: fullCwd, + }); + + output(stdout, stderr); + return new CustomSwiftTaskTerminal("1"); + }), + config?.problemMatcher + ); + + let prefix: string; + if (config?.prefix) { + prefix = `(${config.prefix}) `; + } else { + prefix = ""; + } + task.detail = `${prefix}swift ${args.join(" ")}`; + task.group = config?.group; + task.presentationOptions = config?.presentationOptions ?? {}; + return task; +} + /** * A {@link vscode.TaskProvider TaskProvider} for tasks that match the definition * in **package.json**: `{ type: 'swift'; args: string[], cwd: string? }`. @@ -304,3 +370,36 @@ export class SwiftTaskProvider implements vscode.TaskProvider { return newTask; } } + +class CustomSwiftTaskTerminal implements vscode.Pseudoterminal { + private writeEmitter = new vscode.EventEmitter(); + onDidWrite: vscode.Event = this.writeEmitter.event; + private closeEmitter = new vscode.EventEmitter(); + onDidClose?: vscode.Event = this.closeEmitter.event; + + constructor(private workspaceRoot: string) {} + + open(initialDimensions: vscode.TerminalDimensions | undefined): void { + // At this point we can start using the + // print initialDimensions to set the size of the terminal. + console.log(initialDimensions); + this.resolveDependencyGraph(); + } + + close(): void { + // The terminal has been closed. Shutdown the build. + } + + private async resolveDependencyGraph(): Promise { + return new Promise(resolve => { + this.writeEmitter.fire("Starting build...\r\n"); + + // Since we don't actually build anything in this example set a timeout instead. + setTimeout(() => { + this.writeEmitter.fire("Build complete.\r\n\r\n"); + this.closeEmitter.fire(0); + resolve(); + }, 1000); + }); + } +} diff --git a/src/WorkspaceContext.ts b/src/WorkspaceContext.ts index 4b9c3719f..e54052682 100644 --- a/src/WorkspaceContext.ts +++ b/src/WorkspaceContext.ts @@ -131,9 +131,12 @@ export class WorkspaceContext implements vscode.Disposable { this.updateContextKeys(folder); break; case FolderEvent.resolvedUpdated: + break; + case FolderEvent.resolveDone: if (folder === this.currentFolder) { this.updateContextKeys(folder); } + break; } }); this.subscriptions = [ @@ -491,8 +494,8 @@ export enum FolderEvent { packageUpdated = "packageUpdated", // Package.resolved has been updated resolvedUpdated = "resolvedUpdated", - // workspace-state.json has been updated - workspaceStateUpdated = "workspaceStateUpdated", + // `swift package resolve` is done + resolveDone = "resolveDone", } /** Workspace Folder observer function */ diff --git a/src/commands.ts b/src/commands.ts index 4c2e9d978..6618ac15c 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -16,7 +16,7 @@ import * as vscode from "vscode"; import * as fs from "fs/promises"; import * as path from "path"; import { FolderEvent, WorkspaceContext } from "./WorkspaceContext"; -import { createSwiftTask, SwiftTaskProvider } from "./SwiftTaskProvider"; +import { createSwiftTask, createSwiftTask2, SwiftTaskProvider } from "./SwiftTaskProvider"; import { FolderContext } from "./FolderContext"; import { PackageNode } from "./ui/PackageDependencyProvider"; import { execSwift } from "./utilities/utilities"; @@ -50,12 +50,19 @@ export async function resolveFolderDependencies( folderContext: FolderContext, checkAlreadyRunning?: boolean ) { - const task = createSwiftTask(["package", "resolve"], SwiftTaskProvider.resolvePackageName, { - cwd: folderContext.folder, - scope: folderContext.workspaceFolder, - prefix: folderContext.name, - presentationOptions: { reveal: vscode.TaskRevealKind.Silent }, - }); + const task = createSwiftTask2( + ["package", "show-dependencies", "--format", "flatlist"], + SwiftTaskProvider.resolvePackageName, + { + cwd: folderContext.folder, + scope: folderContext.workspaceFolder, + prefix: folderContext.name, + presentationOptions: { reveal: vscode.TaskRevealKind.Silent }, + }, + (stdout: string) => { + folderContext.swiftPackage.updateDependencySetWithStdout(stdout); + } + ); await executeTaskWithUI( task, @@ -436,8 +443,9 @@ function updateAfterError(result: boolean, folderContext: FolderContext) { // send Package.resolved updated event to trigger display of package dependencies // view if (triggerResolvedUpdatedEvent && !folderContext.hasResolveErrors) { - folderContext.fireEvent(FolderEvent.resolvedUpdated); + // TODO } + folderContext.fireEvent(FolderEvent.resolveDone); } /** diff --git a/src/extension.ts b/src/extension.ts index abdb51366..54f8670e3 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -100,6 +100,7 @@ export async function activate(context: vscode.ExtensionContext): Promise { if (folder.swiftPackage.foundPackage) { await commands.resolveFolderDependencies(folder, true); } + break; } }); diff --git a/src/ui/PackageDependencyProvider.ts b/src/ui/PackageDependencyProvider.ts index df1983958..a07dd0442 100644 --- a/src/ui/PackageDependencyProvider.ts +++ b/src/ui/PackageDependencyProvider.ts @@ -123,11 +123,9 @@ export class PackageDependenciesProvider implements vscode.TreeDataProvider + showingDependencies.has(dependency.identity) + ); } // Read the contents of a package. return this.getNodesInDirectory(element.path); } + private async getShowingDependencies(folderContext: FolderContext): Promise> { + return await folderContext.swiftPackage.resolveDependencyGraph(); + } + private async getAllDependencies(folderContext: FolderContext): Promise { return (await folderContext.getWorkspaceDependencies()).map(dependency => { const version = From 803567de43a18be1b72972d46c1f7faf3e2688c8 Mon Sep 17 00:00:00 2001 From: Wang Lun Date: Fri, 29 Jul 2022 11:20:00 +0900 Subject: [PATCH 15/16] resolve dependency graph with recursive swift package describe --- package.json | 1 - src/FolderContext.ts | 5 +- src/PackageWatcher.ts | 46 ++++--- src/SwiftPackage.ts | 187 +++++++++++++++++++--------- src/WorkspaceContext.ts | 6 +- src/commands.ts | 20 +-- src/ui/PackageDependencyProvider.ts | 54 ++------ 7 files changed, 182 insertions(+), 137 deletions(-) diff --git a/package.json b/package.json index 912feb394..3cf5407c4 100644 --- a/package.json +++ b/package.json @@ -416,7 +416,6 @@ "dev-package": "vsce package -o swift-lang-development.vsix" }, "devDependencies": { - "@types/checksum": "^0.1.33", "@types/glob": "^7.1.4", "@types/mocha": "^9.0.0", "@types/node": "14.x", diff --git a/src/FolderContext.ts b/src/FolderContext.ts index 95b78a2cb..dd403b1e6 100644 --- a/src/FolderContext.ts +++ b/src/FolderContext.ts @@ -163,9 +163,8 @@ export class FolderContext implements vscode.Disposable { } /** Get list of all packages */ - async getWorkspaceDependencies(): Promise { - const workspaceState = await this.swiftPackage.loadWorkspaceState(); - return workspaceState?.object?.dependencies ?? []; + async resolveDependencyGraph(): Promise { + return await this.swiftPackage.resolveDependencyGraph(); } static uriName(uri: vscode.Uri): string { diff --git a/src/PackageWatcher.ts b/src/PackageWatcher.ts index 9e4a09f0a..d7c6f799c 100644 --- a/src/PackageWatcher.ts +++ b/src/PackageWatcher.ts @@ -14,6 +14,7 @@ import * as vscode from "vscode"; import { FolderContext } from "./FolderContext"; +import { buildDirectoryFromWorkspacePath } from "./utilities/utilities"; import { FolderEvent, WorkspaceContext } from "./WorkspaceContext"; /** @@ -25,6 +26,7 @@ import { FolderEvent, WorkspaceContext } from "./WorkspaceContext"; export class PackageWatcher { private packageFileWatcher?: vscode.FileSystemWatcher; private resolvedFileWatcher?: vscode.FileSystemWatcher; + private workspaceStateFileWatcher?: vscode.FileSystemWatcher; constructor(private folderContext: FolderContext, private workspaceContext: WorkspaceContext) {} @@ -35,6 +37,7 @@ export class PackageWatcher { install() { this.packageFileWatcher = this.createPackageFileWatcher(); this.resolvedFileWatcher = this.createResolvedFileWatcher(); + this.workspaceStateFileWatcher = this.createWorkspaceStateFileWatcher(); } /** @@ -44,6 +47,7 @@ export class PackageWatcher { dispose() { this.packageFileWatcher?.dispose(); this.resolvedFileWatcher?.dispose(); + this.workspaceStateFileWatcher?.dispose(); } private createPackageFileWatcher(): vscode.FileSystemWatcher { @@ -60,9 +64,23 @@ export class PackageWatcher { const watcher = vscode.workspace.createFileSystemWatcher( new vscode.RelativePattern(this.folderContext.folder, "Package.resolved") ); - // watcher.onDidCreate(async () => await this.handlePackageResolvedChange()); - watcher.onDidChange(async () => await this.handlePackageResolvedChange("change")); - watcher.onDidDelete(async () => await this.handlePackageResolvedChange("delete")); + watcher.onDidCreate(async () => await this.handlePackageResolvedChange()); + watcher.onDidChange(async () => await this.handlePackageResolvedChange()); + watcher.onDidDelete(async () => await this.handlePackageResolvedChange()); + return watcher; + } + + private createWorkspaceStateFileWatcher(): vscode.FileSystemWatcher { + const uri = vscode.Uri.file( + buildDirectoryFromWorkspacePath(this.folderContext.folder.fsPath, true) + ); + + const watcher = vscode.workspace.createFileSystemWatcher( + new vscode.RelativePattern(uri, "workspace-state.json") + ); + watcher.onDidCreate(async () => await this.handleWorkspaceStateChange()); + watcher.onDidChange(async () => await this.handleWorkspaceStateChange()); + watcher.onDidDelete(async () => await this.handleWorkspaceStateChange()); return watcher; } @@ -84,17 +102,17 @@ export class PackageWatcher { * * This will resolve any changes in the Package.resolved. */ - private async handlePackageResolvedChange(action: "change" | "delete") { - // if Package.resolved is modified, we need to resolve the dependencies - // after resolving is done, it will MODIFY the Package.resolved again - // BUT, the file content is not actually changed - // we don't want to resolve the dependencies again - const hasChanges = await this.folderContext.swiftPackage.packageResovledHasChanged(action); - if (!hasChanges) { - return; - } - - await this.folderContext.swiftPackage.reloadPackageResolved(); + private async handlePackageResolvedChange() { + await this.folderContext.reloadPackageResolved(); this.workspaceContext.fireEvent(this.folderContext, FolderEvent.resolvedUpdated); } + + /** + * Handles a create or change event for **workspace-state.json**. + * + * This will resolve any changes in the workspace-state.json + */ + private async handleWorkspaceStateChange() { + this.workspaceContext.fireEvent(this.folderContext, FolderEvent.workspaceStateUpdated); + } } diff --git a/src/SwiftPackage.ts b/src/SwiftPackage.ts index db1797e2f..b64c25531 100644 --- a/src/SwiftPackage.ts +++ b/src/SwiftPackage.ts @@ -14,12 +14,12 @@ import * as vscode from "vscode"; import * as fs from "fs/promises"; +import * as path from "path"; import { buildDirectoryFromWorkspacePath, execSwift, getErrorDescription, } from "./utilities/utilities"; -import checksum = require("checksum"); /** Swift Package Manager contents */ export interface PackageContents { @@ -152,6 +152,61 @@ function isError(state: SwiftPackageState): state is Error { return state instanceof Error; } +/** + * Get version of WorkspaceStateDependency for displaying in the tree + * @param dependency + * @return real version | edited | local + */ +export function dependencyVersion(dependency: WorkspaceStateDependency): string { + return dependency.packageRef.kind === "fileSystem" + ? "local" + : dependency.state.checkoutState?.version ?? + dependency.state.checkoutState?.branch ?? + "edited"; +} + +/** + * Get type of WorkspaceStateDependency for displaying in the tree: real version | edited | local + * @param dependency + * @return "local" | "remote" | "edited" + */ +export function dependencyType( + dependency: WorkspaceStateDependency +): "local" | "remote" | "edited" { + return dependency.state.name === "edited" + ? "edited" + : dependency.packageRef.kind === "fileSystem" + ? "local" + : "remote"; +} + +/** + * Get type of WorkspaceStateDependency for displaying in the tree: real version | edited | local + * `edited`: dependency.state.path ?? workspacePath + Packages/ + dependency.subpath + * `local`: dependency.packageRef.location + * `remote`: buildDirectory + checkouts + dependency.packageRef.location + * @param dependency + * @return the package path based on the type + */ +export function dependencyPackagePath( + dependency: WorkspaceStateDependency, + workspaceFolder: string +): string { + const type = dependencyType(dependency); + let packagePath = ""; + if (type === "edited") { + packagePath = + dependency.state.path ?? path.join(workspaceFolder, "Packages", dependency.subpath); + } else if (type === "local") { + packagePath = dependency.state.path ?? dependency.packageRef.location; + } else { + // remote + const buildDirectory = buildDirectoryFromWorkspacePath(workspaceFolder, true); + packagePath = path.join(buildDirectory, "checkouts", dependency.subpath); + } + return packagePath; +} + /** * Class holding Swift Package Manager Package */ @@ -166,9 +221,7 @@ export class SwiftPackage implements PackageContents { readonly folder: vscode.Uri, private contents: SwiftPackageState, public resolved: PackageResolved | undefined, - public plugins: PackagePlugin[], - public resolvedContent: string | undefined, - public dependencySet: Set + public plugins: PackagePlugin[] ) {} /** @@ -180,8 +233,7 @@ export class SwiftPackage implements PackageContents { const contents = await SwiftPackage.loadPackage(folder); const resolved = await SwiftPackage.loadPackageResolved(folder); const plugins = await SwiftPackage.loadPlugins(folder); - const resolvedContent = await SwiftPackage.loadPackageResolvedFile(folder); - return new SwiftPackage(folder, contents, resolved, plugins, resolvedContent, new Set()); + return new SwiftPackage(folder, contents, resolved, plugins); } /** @@ -217,19 +269,10 @@ export class SwiftPackage implements PackageContents { } } - static async loadPackageResolvedFile(folder: vscode.Uri): Promise { + static async loadPackageResolved(folder: vscode.Uri): Promise { try { const uri = vscode.Uri.joinPath(folder, "Package.resolved"); const contents = await fs.readFile(uri.fsPath, "utf8"); - return contents; - } catch { - return undefined; - } - } - - static async loadPackageResolved(folder: vscode.Uri): Promise { - try { - const contents = await SwiftPackage.loadPackageResolvedFile(folder); if (contents === undefined) { return undefined; } @@ -273,34 +316,6 @@ export class SwiftPackage implements PackageContents { } } - async packageResovledHasChanged(action: any): Promise { - console.log(action); - const resolvedContent = await SwiftPackage.loadPackageResolvedFile(this.folder); - - console.log(resolvedContent); - console.log(this.resolvedContent); - - if (resolvedContent === undefined) { - return false; - } - // deletion --> creation --> modification - // r undefined exists exists - // pr exists undefined exists - - if (this.resolvedContent === undefined) { - return true; - } - - const oldChecksum = checksum(resolvedContent); - const newChecksum = checksum(this.resolvedContent); - - if (oldChecksum !== newChecksum) { - return true; - } - - return false; - } - /** * Load workspace-state.json file for swift package * @returns Workspace state @@ -320,24 +335,79 @@ export class SwiftPackage implements PackageContents { } /** - * Run `swift package describe` and return results - * @param folder folder package is in - * @returns results of `swift package describe` + * tranverse the dependency tree + * in each node, call `swift package describe` to get the child dependencies and do it recursively + * @returns all dependencies in flat list */ - async resolveDependencyGraph(): Promise> { - return this.dependencySet; - } + async resolveDependencyGraph(): Promise { + const workspaceState = await this.loadWorkspaceState(); + const workspaceStateDependencies = workspaceState?.object.dependencies ?? []; + + if (workspaceStateDependencies.length === 0) { + return []; + } - updateDependencySetWithStdout(stdout: string): void { - const lines = stdout - .split("\n") - .filter(item => item !== "") - .map(item => item.trim()); - this.updateDependencySet(new Set(lines ?? [])); + const contents = this.contents as PackageContents; + console.log("== resolve graph begin"); + const showingDependencies = new Set(); + await this.getChildDependencies(contents, workspaceStateDependencies, showingDependencies); + + console.log("== resolve graph done"); + + // filter workspaceStateDependencies that in showingDependencies + return workspaceStateDependencies.filter(dependency => + showingDependencies.has(dependency.packageRef.identity) + ); + + // this can filter out dependencies that are not in the workspace state + // filter workspaceStateDependencies that not in showingDependencies + //const unusedPackages = workspaceStateDependencies.filter( + // dependency => !showingDependencies.has(dependency.packageRef.identity) + //); } - updateDependencySet(dependencySet: Set): void { - this.dependencySet = dependencySet; + /** + * tranverse the dependency tree + * @param dependency current node + * @param workspaceStateDependencies all dependencies in workspace-state.json + * @param showingDependencies result of dependencies that are showing in the tree + * @returns + */ + private async getChildDependencies( + dependency: PackageContents, + workspaceStateDependencies: WorkspaceStateDependency[], + showingDependencies: Set + ) { + for (let i = 0; i < dependency.dependencies.length; i++) { + const childDependency = dependency.dependencies[i]; + if (showingDependencies.has(childDependency.identity)) { + return; + } + showingDependencies.add(childDependency.identity); + const workspaceStateDependency = workspaceStateDependencies.find( + workspaceStateDependency => + workspaceStateDependency.packageRef.identity === childDependency.identity + ); + if (workspaceStateDependency) { + showingDependencies.add(workspaceStateDependency.packageRef.identity); + } + + if (workspaceStateDependency === undefined) { + return; + } + + const packagePath = dependencyPackagePath(workspaceStateDependency, this.folder.fsPath); + + const childDependencyContents = (await SwiftPackage.loadPackage( + vscode.Uri.file(packagePath) + )) as PackageContents; + + await this.getChildDependencies( + childDependencyContents, + workspaceStateDependencies, + showingDependencies + ); + } } /** Reload swift package */ @@ -347,7 +417,6 @@ export class SwiftPackage implements PackageContents { /** Reload Package.resolved file */ public async reloadPackageResolved() { - this.resolvedContent = await SwiftPackage.loadPackageResolvedFile(this.folder); this.resolved = await SwiftPackage.loadPackageResolved(this.folder); } diff --git a/src/WorkspaceContext.ts b/src/WorkspaceContext.ts index e54052682..eac7473e9 100644 --- a/src/WorkspaceContext.ts +++ b/src/WorkspaceContext.ts @@ -132,7 +132,7 @@ export class WorkspaceContext implements vscode.Disposable { break; case FolderEvent.resolvedUpdated: break; - case FolderEvent.resolveDone: + case FolderEvent.workspaceStateUpdated: if (folder === this.currentFolder) { this.updateContextKeys(folder); } @@ -494,8 +494,8 @@ export enum FolderEvent { packageUpdated = "packageUpdated", // Package.resolved has been updated resolvedUpdated = "resolvedUpdated", - // `swift package resolve` is done - resolveDone = "resolveDone", + // `workspace-state.json` is updated, update dependency tree only by this event + workspaceStateUpdated = "workspaceStateUpdated", } /** Workspace Folder observer function */ diff --git a/src/commands.ts b/src/commands.ts index 6618ac15c..5d8084948 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -50,19 +50,12 @@ export async function resolveFolderDependencies( folderContext: FolderContext, checkAlreadyRunning?: boolean ) { - const task = createSwiftTask2( - ["package", "show-dependencies", "--format", "flatlist"], - SwiftTaskProvider.resolvePackageName, - { - cwd: folderContext.folder, - scope: folderContext.workspaceFolder, - prefix: folderContext.name, - presentationOptions: { reveal: vscode.TaskRevealKind.Silent }, - }, - (stdout: string) => { - folderContext.swiftPackage.updateDependencySetWithStdout(stdout); - } - ); + const task = createSwiftTask(["package", "resolve"], SwiftTaskProvider.resolvePackageName, { + cwd: folderContext.folder, + scope: folderContext.workspaceFolder, + prefix: folderContext.name, + presentationOptions: { reveal: vscode.TaskRevealKind.Silent }, + }); await executeTaskWithUI( task, @@ -445,7 +438,6 @@ function updateAfterError(result: boolean, folderContext: FolderContext) { if (triggerResolvedUpdatedEvent && !folderContext.hasResolveErrors) { // TODO } - folderContext.fireEvent(FolderEvent.resolveDone); } /** diff --git a/src/ui/PackageDependencyProvider.ts b/src/ui/PackageDependencyProvider.ts index a07dd0442..28da078dc 100644 --- a/src/ui/PackageDependencyProvider.ts +++ b/src/ui/PackageDependencyProvider.ts @@ -16,12 +16,12 @@ import * as vscode from "vscode"; import * as fs from "fs/promises"; import * as path from "path"; import configuration from "../configuration"; -import { buildDirectoryFromWorkspacePath } from "../utilities/utilities"; import { WorkspaceContext } from "../WorkspaceContext"; import { FolderEvent } from "../WorkspaceContext"; import { FolderContext } from "../FolderContext"; import contextKeys from "../contextKeys"; import { Version } from "../utilities/version"; +import { dependencyVersion, dependencyType, dependencyPackagePath } from "../SwiftPackage"; /** * References: @@ -123,12 +123,13 @@ export class PackageDependenciesProvider implements vscode.TreeDataProvider - showingDependencies.has(dependency.identity) - ); + return await this.getDependencyGraph(folderContext); } // Read the contents of a package. return this.getNodesInDirectory(element.path); } - private async getShowingDependencies(folderContext: FolderContext): Promise> { - return await folderContext.swiftPackage.resolveDependencyGraph(); - } - - private async getAllDependencies(folderContext: FolderContext): Promise { - return (await folderContext.getWorkspaceDependencies()).map(dependency => { - const version = - dependency.packageRef.kind === "fileSystem" - ? "local" - : dependency.state.checkoutState?.version ?? - dependency.state.checkoutState?.branch ?? - "edited"; - - const type = - dependency.state.name === "edited" - ? "edited" - : dependency.packageRef.kind === "fileSystem" - ? "local" - : "remote"; - - let packagePath = ""; - if (type === "edited") { - packagePath = - dependency.state.path ?? - path.join(folderContext.folder.fsPath, "Packages", dependency.subpath); - } else if (type === "local") { - packagePath = dependency.state.path ?? dependency.packageRef.location; - } else { - // remote - const buildDirectory = buildDirectoryFromWorkspacePath( - folderContext.folder.fsPath, - true - ); - packagePath = path.join(buildDirectory, "checkouts", dependency.subpath); - } + private async getDependencyGraph(folderContext: FolderContext): Promise { + const graph = await folderContext.resolveDependencyGraph(); + return graph.map(dependency => { + const version = dependencyVersion(dependency); + const type = dependencyType(dependency); + const packagePath = dependencyPackagePath(dependency, folderContext.folder.fsPath); return new PackageNode( dependency.packageRef.identity, From 8b72eeff9fba5eb634dce54127074f669a30d3bc Mon Sep 17 00:00:00 2001 From: Wang Lun Date: Fri, 29 Jul 2022 11:41:37 +0900 Subject: [PATCH 16/16] revert unnecessary changes --- package-lock.json | 62 ----------------- package.json | 2 +- src/FolderContext.ts | 6 +- src/SwiftPackage.ts | 14 +--- src/SwiftTaskProvider.ts | 101 +--------------------------- src/commands.ts | 7 +- src/extension.ts | 1 - src/ui/PackageDependencyProvider.ts | 8 ++- 8 files changed, 13 insertions(+), 188 deletions(-) diff --git a/package-lock.json b/package-lock.json index da8da405d..482a06700 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,12 +9,10 @@ "version": "0.7.0", "dependencies": { "@types/plist": "^3.0.2", - "checksum": "^1.0.0", "plist": "^3.0.5", "vscode-languageclient": "^8.0.0" }, "devDependencies": { - "@types/checksum": "^0.1.33", "@types/glob": "^7.1.4", "@types/mocha": "^9.0.0", "@types/node": "14.x", @@ -128,12 +126,6 @@ "node": ">= 6" } }, - "node_modules/@types/checksum": { - "version": "0.1.33", - "resolved": "https://registry.npmjs.org/@types/checksum/-/checksum-0.1.33.tgz", - "integrity": "sha512-fe6ZaTTh2Qk6J68EOKGz992sw6Y+sGK86skRTT4tz9Wxby6owinOXzHE73wBOw/ln7ty4rTbxjHx0RwjIM1LKw==", - "dev": true - }, "node_modules/@types/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", @@ -728,17 +720,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/checksum": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/checksum/-/checksum-1.0.0.tgz", - "integrity": "sha512-68bHejnM/sBQhjXcXd2mFusICnqAwikZ9RVMURIacWh7moNjgOdHKimS6yk30Np/PwfR00dceY4b1GwWanu5cg==", - "dependencies": { - "optimist": "~0.3.5" - }, - "bin": { - "checksum": "bin/checksum-cli.js" - } - }, "node_modules/cheerio": { "version": "1.0.0-rc.10", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", @@ -2703,14 +2684,6 @@ "wrappy": "1" } }, - "node_modules/optimist": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", - "integrity": "sha512-TCx0dXQzVtSCg2OgY/bO9hjM9cV4XYx09TVK+s3+FhkjT6LovsLe+pPMzpWf+6yXK/hUizs2gUoTw3jHM0VaTQ==", - "dependencies": { - "wordwrap": "~0.0.2" - } - }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -3767,14 +3740,6 @@ "node": ">=0.10.0" } }, - "node_modules/wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/workerpool": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", @@ -3988,12 +3953,6 @@ "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", "dev": true }, - "@types/checksum": { - "version": "0.1.33", - "resolved": "https://registry.npmjs.org/@types/checksum/-/checksum-0.1.33.tgz", - "integrity": "sha512-fe6ZaTTh2Qk6J68EOKGz992sw6Y+sGK86skRTT4tz9Wxby6owinOXzHE73wBOw/ln7ty4rTbxjHx0RwjIM1LKw==", - "dev": true - }, "@types/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", @@ -4407,14 +4366,6 @@ "supports-color": "^7.1.0" } }, - "checksum": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/checksum/-/checksum-1.0.0.tgz", - "integrity": "sha512-68bHejnM/sBQhjXcXd2mFusICnqAwikZ9RVMURIacWh7moNjgOdHKimS6yk30Np/PwfR00dceY4b1GwWanu5cg==", - "requires": { - "optimist": "~0.3.5" - } - }, "cheerio": { "version": "1.0.0-rc.10", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", @@ -5864,14 +5815,6 @@ "wrappy": "1" } }, - "optimist": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", - "integrity": "sha512-TCx0dXQzVtSCg2OgY/bO9hjM9cV4XYx09TVK+s3+FhkjT6LovsLe+pPMzpWf+6yXK/hUizs2gUoTw3jHM0VaTQ==", - "requires": { - "wordwrap": "~0.0.2" - } - }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -6665,11 +6608,6 @@ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==" - }, "workerpool": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", diff --git a/package.json b/package.json index 3cf5407c4..50340e2d8 100644 --- a/package.json +++ b/package.json @@ -434,8 +434,8 @@ }, "dependencies": { "@types/plist": "^3.0.2", - "checksum": "^1.0.0", "plist": "^3.0.5", "vscode-languageclient": "^8.0.0" } } + diff --git a/src/FolderContext.ts b/src/FolderContext.ts index dd403b1e6..2b6f4a91e 100644 --- a/src/FolderContext.ts +++ b/src/FolderContext.ts @@ -123,10 +123,6 @@ export class FolderContext implements vscode.Disposable { await this.swiftPackage.reloadPackageResolved(); } - get resolvedContent(): string | undefined { - return this.resolvedContent; - } - /** * Fire an event to all folder observers * @param event event type @@ -162,7 +158,7 @@ export class FolderContext implements vscode.Disposable { ); } - /** Get list of all packages */ + /** Get list in-use packages */ async resolveDependencyGraph(): Promise { return await this.swiftPackage.resolveDependencyGraph(); } diff --git a/src/SwiftPackage.ts b/src/SwiftPackage.ts index b64c25531..777f2b932 100644 --- a/src/SwiftPackage.ts +++ b/src/SwiftPackage.ts @@ -273,9 +273,6 @@ export class SwiftPackage implements PackageContents { try { const uri = vscode.Uri.joinPath(folder, "Package.resolved"); const contents = await fs.readFile(uri.fsPath, "utf8"); - if (contents === undefined) { - return undefined; - } const json = JSON.parse(contents); const version = <{ version: number }>json; if (version.version === 1) { @@ -320,7 +317,7 @@ export class SwiftPackage implements PackageContents { * Load workspace-state.json file for swift package * @returns Workspace state */ - async loadWorkspaceState(): Promise { + public async loadWorkspaceState(): Promise { try { const uri = vscode.Uri.joinPath( vscode.Uri.file(buildDirectoryFromWorkspacePath(this.folder.fsPath, true)), @@ -348,22 +345,13 @@ export class SwiftPackage implements PackageContents { } const contents = this.contents as PackageContents; - console.log("== resolve graph begin"); const showingDependencies = new Set(); await this.getChildDependencies(contents, workspaceStateDependencies, showingDependencies); - console.log("== resolve graph done"); - // filter workspaceStateDependencies that in showingDependencies return workspaceStateDependencies.filter(dependency => showingDependencies.has(dependency.packageRef.identity) ); - - // this can filter out dependencies that are not in the workspace state - // filter workspaceStateDependencies that not in showingDependencies - //const unusedPackages = workspaceStateDependencies.filter( - // dependency => !showingDependencies.has(dependency.packageRef.identity) - //); } /** diff --git a/src/SwiftTaskProvider.ts b/src/SwiftTaskProvider.ts index 19a6d103b..4f90d35c2 100644 --- a/src/SwiftTaskProvider.ts +++ b/src/SwiftTaskProvider.ts @@ -18,12 +18,7 @@ import { WorkspaceContext } from "./WorkspaceContext"; import { FolderContext } from "./FolderContext"; import { Product } from "./SwiftPackage"; import configuration from "./configuration"; -import { - execSwift, - getSwiftExecutable, - swiftRuntimeEnv, - withSwiftSDKFlags, -} from "./utilities/utilities"; +import { getSwiftExecutable, swiftRuntimeEnv, withSwiftSDKFlags } from "./utilities/utilities"; import { Version } from "./utilities/version"; /** @@ -217,7 +212,6 @@ export function createSwiftTask(args: string[], name: string, config: TaskConfig }), config?.problemMatcher ); - // This doesn't include any quotes added by VS Code. // See also: https://github.com/microsoft/vscode/issues/137895 @@ -233,66 +227,6 @@ export function createSwiftTask(args: string[], name: string, config: TaskConfig return task; } -interface SwiftOutput { - (stdout: string, stderr: string): void; -} - -/** - * Helper function to create a {@link vscode.Task Task} with the given parameters. - */ -export function createSwiftTask2( - args: string[], - name: string, - config: TaskConfig, - output: SwiftOutput -): vscode.Task { - args = withSwiftSDKFlags(args); - - // Add relative path current working directory - const cwd = config.cwd.fsPath; - const fullCwd = config.cwd.fsPath; - - /* Currently there seems to be a bug in vscode where kicking off two tasks - with the same definition but different scopes messes with the task - completion code. When that is resolved we will go back to the code below - where we only store the relative cwd instead of the full cwd - - const scopeWorkspaceFolder = config.scope as vscode.WorkspaceFolder; - if (scopeWorkspaceFolder.uri.fsPath) { - cwd = path.relative(scopeWorkspaceFolder.uri.fsPath, config.cwd.fsPath); - } else { - cwd = config.cwd.fsPath; - }*/ - - const task = new vscode.Task( - { type: "swift", args: args, cwd: cwd }, - config?.scope ?? vscode.TaskScope.Workspace, - name, - "swift", - new vscode.CustomExecution(async (): Promise => { - // When the task is executed, this callback will run. Here, we setup for running the task. - const { stdout, stderr } = await execSwift(args, { - cwd: fullCwd, - }); - - output(stdout, stderr); - return new CustomSwiftTaskTerminal("1"); - }), - config?.problemMatcher - ); - - let prefix: string; - if (config?.prefix) { - prefix = `(${config.prefix}) `; - } else { - prefix = ""; - } - task.detail = `${prefix}swift ${args.join(" ")}`; - task.group = config?.group; - task.presentationOptions = config?.presentationOptions ?? {}; - return task; -} - /** * A {@link vscode.TaskProvider TaskProvider} for tasks that match the definition * in **package.json**: `{ type: 'swift'; args: string[], cwd: string? }`. @@ -370,36 +304,3 @@ export class SwiftTaskProvider implements vscode.TaskProvider { return newTask; } } - -class CustomSwiftTaskTerminal implements vscode.Pseudoterminal { - private writeEmitter = new vscode.EventEmitter(); - onDidWrite: vscode.Event = this.writeEmitter.event; - private closeEmitter = new vscode.EventEmitter(); - onDidClose?: vscode.Event = this.closeEmitter.event; - - constructor(private workspaceRoot: string) {} - - open(initialDimensions: vscode.TerminalDimensions | undefined): void { - // At this point we can start using the - // print initialDimensions to set the size of the terminal. - console.log(initialDimensions); - this.resolveDependencyGraph(); - } - - close(): void { - // The terminal has been closed. Shutdown the build. - } - - private async resolveDependencyGraph(): Promise { - return new Promise(resolve => { - this.writeEmitter.fire("Starting build...\r\n"); - - // Since we don't actually build anything in this example set a timeout instead. - setTimeout(() => { - this.writeEmitter.fire("Build complete.\r\n\r\n"); - this.closeEmitter.fire(0); - resolve(); - }, 1000); - }); - } -} diff --git a/src/commands.ts b/src/commands.ts index 5d8084948..aea2a80e1 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -16,7 +16,7 @@ import * as vscode from "vscode"; import * as fs from "fs/promises"; import * as path from "path"; import { FolderEvent, WorkspaceContext } from "./WorkspaceContext"; -import { createSwiftTask, createSwiftTask2, SwiftTaskProvider } from "./SwiftTaskProvider"; +import { createSwiftTask, SwiftTaskProvider } from "./SwiftTaskProvider"; import { FolderContext } from "./FolderContext"; import { PackageNode } from "./ui/PackageDependencyProvider"; import { execSwift } from "./utilities/utilities"; @@ -432,11 +432,12 @@ function updateAfterError(result: boolean, folderContext: FolderContext) { const triggerResolvedUpdatedEvent = folderContext.hasResolveErrors; // set has resolve errors flag folderContext.hasResolveErrors = !result; + // if previous folder state was with resolve errors, and now it is without then - // send Package.resolved updated event to trigger display of package dependencies + // send workspace-state.json updated event to trigger display of package dependencies // view if (triggerResolvedUpdatedEvent && !folderContext.hasResolveErrors) { - // TODO + folderContext.fireEvent(FolderEvent.workspaceStateUpdated); } } diff --git a/src/extension.ts b/src/extension.ts index 54f8670e3..abdb51366 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -100,7 +100,6 @@ export async function activate(context: vscode.ExtensionContext): Promise { if (folder.swiftPackage.foundPackage) { await commands.resolveFolderDependencies(folder, true); } - break; } }); diff --git a/src/ui/PackageDependencyProvider.ts b/src/ui/PackageDependencyProvider.ts index 28da078dc..7ee18a51e 100644 --- a/src/ui/PackageDependencyProvider.ts +++ b/src/ui/PackageDependencyProvider.ts @@ -129,9 +129,11 @@ export class PackageDependenciesProvider implements vscode.TreeDataProvider