Skip to content

Commit

Permalink
Refactor fileModel and memFs to receive state
Browse files Browse the repository at this point in the history
Signed-off-by: Radoslaw Szwajkowski <[email protected]>
  • Loading branch information
rszwajko committed Nov 21, 2024
1 parent 9a46955 commit 8178a44
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 58 deletions.
1 change: 1 addition & 0 deletions shared/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export interface LocalChange {
modifiedUri: Uri;
originalUri: Uri;
diff: string;
state: "pending" | "applied" | "discarded";
}

export interface ResolutionMessage {
Expand Down
14 changes: 7 additions & 7 deletions vscode/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,23 +336,23 @@ const commandsMap: (state: ExtensionState) => {
// Update the user settings
await config.update("labelSelector", modifiedLabelSelector, ConfigurationTarget.Workspace);
},
"konveyor.loadRuleSets": (ruleSets: RuleSet[]): void => loadRuleSets(state, ruleSets),
"konveyor.loadRuleSets": async (ruleSets: RuleSet[]) => loadRuleSets(state, ruleSets),
"konveyor.cleanRuleSets": () => cleanRuleSets(state),
"konveyor.loadStaticResults": loadStaticResults,
"konveyor.loadResultsFromDataFolder": loadResultsFromDataFolder,
"konveyor.loadSolution": async (solution: GetSolutionResult) => loadSolution(state, solution),
"konveyor.applyAll": () => applyAll(state),
"konveyor.applyFile": (item: FileItem | Uri) => applyFile(item, state),
"konveyor.copyDiff": (item: FileItem | Uri) => copyDiff(item, state),
"konveyor.applyAll": async () => applyAll(state),
"konveyor.applyFile": async (item: FileItem | Uri) => applyFile(item, state),
"konveyor.copyDiff": async (item: FileItem | Uri) => copyDiff(item, state),
"konveyor.copyPath": copyPath,
"konveyor.diffView.viewFix": viewFix,
"konveyor.discardAll": () => discardAll(state),
"konveyor.discardFile": (item: FileItem | Uri) => discardFile(item, state),
"konveyor.discardAll": async () => discardAll(state),
"konveyor.discardFile": async (item: FileItem | Uri) => discardFile(item, state),
"konveyor.showResolutionPanel": () => {
const resolutionProvider = state.webviewProviders?.get("resolution");
resolutionProvider?.showWebviewPanel();
},
"konveyor.reloadLastResolutions": () => reloadLastResolutions(state),
"konveyor.reloadLastResolutions": async () => reloadLastResolutions(state),
"konveyor.diffView.applyBlock": applyBlock,
"konveyor.diffView.applyBlockInline": applyBlock,
"konveyor.diffView.applySelection": applyBlock,
Expand Down
30 changes: 14 additions & 16 deletions vscode/src/data/loadResults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@ import { processIncidents } from "./analyzerResults";
import { ExtensionState } from "src/extensionState";
import { writeDataFile } from "./storage";
import { toLocalChanges, writeSolutionsToMemFs } from "./virtualStorage";
import { Location, Position, window } from "vscode";
import { window } from "vscode";
import {
KONVEYOR_SCHEME,
RULE_SET_DATA_FILE_PREFIX,
SOLUTION_DATA_FILE_PREFIX,
} from "../utilities";
import { Immutable } from "immer";

export const loadRuleSets = (state: ExtensionState, ruleSets: RuleSet[]): void => {
writeDataFile(ruleSets, RULE_SET_DATA_FILE_PREFIX);
export const loadRuleSets = async (state: ExtensionState, ruleSets: RuleSet[]) => {
await writeDataFile(ruleSets, RULE_SET_DATA_FILE_PREFIX);
state.diagnosticCollection.set(processIncidents(ruleSets));
state.mutateData((draft) => {
draft.ruleSets = ruleSets;
Expand All @@ -26,24 +25,23 @@ export const cleanRuleSets = (state: ExtensionState) => {
};

export const loadSolution = async (state: ExtensionState, solution: GetSolutionResult) => {
writeDataFile(solution, SOLUTION_DATA_FILE_PREFIX);
const localChanges = toLocalChanges(solution);
doLoadSolution(state, localChanges);
state.mutateData((draft) => {
draft.localChanges = localChanges;
});
await writeDataFile(solution, SOLUTION_DATA_FILE_PREFIX);
await doLoadSolution(state, toLocalChanges(solution));
};

export const reloadLastResolutions = async (state: ExtensionState) => {
doLoadSolution(state, state.data.localChanges);
await doLoadSolution(
state,
state.data.localChanges.map((it) => ({ ...it, state: "pending" })),
);

window.showInformationMessage(`Loaded last available resolutions`);
};

const doLoadSolution = async (state: ExtensionState, localChanges: Immutable<LocalChange[]>) => {
const doLoadSolution = async (state: ExtensionState, localChanges: LocalChange[]) => {
state.memFs.removeAll(KONVEYOR_SCHEME);
await writeSolutionsToMemFs(localChanges, state);
const locations = localChanges.map(
({ originalUri: uri }) => new Location(uri, new Position(0, 0)),
);
state.fileModel.updateLocations(locations);
state.mutateData((draft) => {
draft.localChanges = localChanges;
});
};
3 changes: 2 additions & 1 deletion vscode/src/data/virtualStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ import path from "path";
import { KONVEYOR_SCHEME, fromRelativeToKonveyor } from "../utilities";
import { Immutable } from "immer";

export const toLocalChanges = (solution: GetSolutionResult) =>
export const toLocalChanges = (solution: GetSolutionResult): LocalChange[] =>
solution.changes.map(({ modified, original, diff }) => ({
modifiedUri: fromRelativeToKonveyor(modified),
originalUri: Uri.from({
scheme: "file",
path: path.join(workspace.workspaceFolders?.[0].uri.fsPath ?? "", original),
}),
diff,
state: "pending",
}));

export const writeSolutionsToMemFs = async (
Expand Down
37 changes: 35 additions & 2 deletions vscode/src/diffView/register.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import * as vscode from "vscode";
import { KonveyorTreeDataProvider } from "./fileModel";
import { Navigation } from "./navigation";
import { ExtensionState } from "src/extensionState";
import { ExtensionData, ExtensionState } from "src/extensionState";
import { KONVEYOR_READ_ONLY_SCHEME, KONVEYOR_SCHEME } from "../utilities";
import KonveyorReadOnlyProvider from "../data/readOnlyStorage";
import { Immutable } from "immer";
import { LocalChange } from "@editor-extensions/shared";

export function registerDiffView({
extensionContext: context,
memFs,
fileModel: model,
}: ExtensionState): void {
}: ExtensionState): (data: Immutable<ExtensionData>) => void {
context.subscriptions.push(
vscode.workspace.registerFileSystemProvider(KONVEYOR_SCHEME, memFs, {
isCaseSensitive: true,
Expand Down Expand Up @@ -39,4 +41,35 @@ export function registerDiffView({
readOnlyProvider,
),
);

const lastLocalChanges: LocalChange[] = [];
return async (data: Immutable<ExtensionData>) => {
const locations = data.localChanges
.filter((change) => change.state === "pending")
.map(({ originalUri: uri }) => new vscode.Location(uri, new vscode.Position(0, 0)));
model.updateLocations(locations);

const hasChanged = (it: unknown, index: number) => lastLocalChanges[index] !== it;
const copyFromTo = (change: LocalChange) =>
change.state === "discarded"
? [change.originalUri, change.modifiedUri]
: [change.modifiedUri, change.originalUri];

await Promise.all(
data.localChanges
.map((change, index): [LocalChange, number] => [change, index])
.filter(([change, index]) => hasChanged(change, index))
.filter(([{ state }]) => state === "applied" || state === "discarded")
.map(([change, index]): [LocalChange, number, vscode.Uri[]] => [
change,
index,
copyFromTo(change),
])
.map(([change, index, [fromUri, toUri]]) =>
vscode.workspace.fs.copy(fromUri, toUri, { overwrite: true }).then(() => {
lastLocalChanges[index] = change;
}),
),
);
};
}
73 changes: 42 additions & 31 deletions vscode/src/diffView/solutionCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,26 @@ import * as vscode from "vscode";
import { ExtensionState } from "src/extensionState";
import { fromRelativeToKonveyor, KONVEYOR_READ_ONLY_SCHEME } from "../utilities";
import { FileItem, toUri } from "./fileModel";
import { LocalChange } from "@editor-extensions/shared";
import { Immutable } from "immer";

export const applyAll = async (state: ExtensionState) => {
const localChanges = state.data.localChanges;
await Promise.all(
localChanges.map(({ originalUri, modifiedUri }) =>
vscode.workspace.fs.copy(modifiedUri, originalUri, { overwrite: true }),
),
);
const sidebarProvider = state.webviewProviders?.get("sidebar");
sidebarProvider?.webview?.postMessage({
type: "solutionConfirmation",
data: { confirmed: true, solution: null },

state.mutateData((draft) => {
draft.localChanges = localChanges.map((it) => ({ ...it, state: "applied" }));
});
//TODO: need to keep solutions view and analysis view in sync based on these actions

vscode.window.showInformationMessage(`All resolutions applied successfully`);
state.fileModel.updateLocations([]);
};

export const discardAll = async (state: ExtensionState) => {
const localChanges = state.data.localChanges;
await Promise.all(
localChanges.map(({ originalUri, modifiedUri }) =>
vscode.workspace.fs.copy(originalUri, modifiedUri, { overwrite: true }),
),
);
state.fileModel.updateLocations([]);

state.mutateData((draft) => {
draft.localChanges = localChanges.map((it) => ({ ...it, state: "discarded" }));
});

vscode.window.showInformationMessage(`Discarded all resolutions`);
};

Expand Down Expand Up @@ -64,15 +58,12 @@ export const viewFixInDiffEditor = async (uri: vscode.Uri, preserveFocus: boolea
);

export const applyFile = async (item: FileItem | vscode.Uri | unknown, state: ExtensionState) => {
const originalUri = toUri(item);
if (!originalUri) {
vscode.window.showErrorMessage("Failed to apply changes");
console.error("Failed to apply changes", item, originalUri);
return;
const index = getChangeIndex(item, "Failed to apply changes", state.data.localChanges);
if (index > -1) {
state.mutateData((draft) => {
draft.localChanges[index].state = "applied";
});
}
const modifiedUri = fromRelativeToKonveyor(vscode.workspace.asRelativePath(originalUri));
await vscode.workspace.fs.copy(modifiedUri, originalUri, { overwrite: true });
state.fileModel.markedAsApplied(originalUri);
};

interface ApplyBlockArgs {
Expand Down Expand Up @@ -102,13 +93,33 @@ export const applyBlock = async ({ originalUri, originalWithModifiedChanges }: A
};

export const discardFile = async (item: FileItem | vscode.Uri | unknown, state: ExtensionState) => {
const index = getChangeIndex(item, "Failed to discard changes", state.data.localChanges);
if (index > -1) {
state.mutateData((draft) => {
draft.localChanges[index].state = "discarded";
});
}
};

const getChangeIndex = (
item: FileItem | vscode.Uri | unknown,
errorMsg: string,
localChanges: Immutable<LocalChange[]>,
) => {
const originalUri = toUri(item);
if (!originalUri) {
vscode.window.showErrorMessage("Failed to discard changes");
console.error("Failed to discard changes", item, originalUri);
return;
vscode.window.showErrorMessage(`${errorMsg}(unknown URI)`);
console.error(`${errorMsg}(unknown URI)`, item, originalUri);
return -1;
}
const index = localChanges.findIndex(
(it) => it.originalUri.toString() === originalUri.toString(),
);

if (index < 0) {
vscode.window.showErrorMessage(`${errorMsg}(unknown index)`);
console.error(`${errorMsg}(unknown index)`, item, originalUri);
return -1;
}
const modifiedUri = fromRelativeToKonveyor(vscode.workspace.asRelativePath(originalUri));
await vscode.workspace.fs.copy(originalUri, modifiedUri, { overwrite: true });
state.fileModel.markedAsApplied(originalUri);
return index;
};
2 changes: 1 addition & 1 deletion vscode/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class VsCodeExtension {
try {
this.checkWorkspace();
this.registerWebviewProvider(context);
registerDiffView(this.state);
this.onDidChangeData(registerDiffView(this.state));
this.registerCommands();
this.registerLanguageProviders(context);
vscode.commands.executeCommand("konveyor.loadResultsFromDataFolder");
Expand Down

0 comments on commit 8178a44

Please sign in to comment.