From 37ea303d40fe1168d04f0abeeff7b93839c2abb0 Mon Sep 17 00:00:00 2001 From: Jan Dolejsi Date: Sat, 27 Jul 2024 19:35:15 +0200 Subject: [PATCH] import planner url, upgade from preview, v2.28.1 --- package-lock.json | 4 +- package.json | 6 +-- src/configuration/PlannersConfiguration.ts | 48 ++++++++++++++++++--- src/session/SessionRepository.ts | 5 ++- src/session/SessionSourceControl.ts | 34 +++++++++++---- src/test/suite/PlannerConfiguration.test.ts | 24 +++++++++++ 6 files changed, 98 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index c0b0bc7..95a4822 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pddl", - "version": "2.28.0", + "version": "2.28.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "pddl", - "version": "2.28.0", + "version": "2.28.1", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 5bbd418..03ec282 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Planning Domain Description Language support", "author": "Jan Dolejsi", "license": "MIT", - "version": "2.28.0", + "version": "2.28.1", "publisher": "jan-dolejsi", "engines": { "vscode": "^1.69.0", @@ -675,7 +675,7 @@ "markdownDescription": "The PDDL Extension can work with multiple **PDDL Planners**. It has a notion of planner _kind_. The _kind_s are defined by the PDDL Extension, or by other extensions injecting in their _Planner Providers_. For more information, see [Configuring the PDDL planner](https://github.com/jan-dolejsi/vscode-pddl/wiki/Configuring-the-PDDL-planner) wiki page.", "default": [ { - "kind": "PLANNING_AS_A_SERVICE_PREVIEW", + "kind": "PLANNING_AS_A_SERVICE", "url": "https://solver.planning.domains:5001/package", "title": "Planning as a service (solver.planning.domains)", "canConfigure": false @@ -697,7 +697,7 @@ "COMMAND", "SERVICE_SYNC", "SERVICE_ASYNC", - "PLANNING_AS_A_SERVICE_PREVIEW" + "PLANNING_AS_A_SERVICE" ] }, "title": { diff --git a/src/configuration/PlannersConfiguration.ts b/src/configuration/PlannersConfiguration.ts index 5187d71..ac5f61b 100644 --- a/src/configuration/PlannersConfiguration.ts +++ b/src/configuration/PlannersConfiguration.ts @@ -9,7 +9,11 @@ import * as path from 'path'; import { parseTree, findNodeAtLocation } from 'jsonc-parser'; import { window, commands, workspace, ConfigurationTarget, QuickPickItem, ExtensionContext, StatusBarItem, StatusBarAlignment, Uri, Range, WorkspaceFolder, TextDocument, ViewColumn, env } from 'vscode'; import { PddlWorkspace, planner } from 'pddl-workspace'; -import { CommandPlannerProvider, SolveServicePlannerProvider, RequestServicePlannerProvider, ExecutablePlannerProvider, Popf, JavaPlannerProvider, Lpg, Pddl4jProvider, PlanningAsAServiceProvider, PlanutilsServerProvider, PythonPlannerProvider, NodeJsPlannerProvider, SchedulingServiceProvider } from './plannerConfigurations'; +import { + CommandPlannerProvider, SolveServicePlannerProvider, RequestServicePlannerProvider, ExecutablePlannerProvider, + Popf, JavaPlannerProvider, Lpg, Pddl4jProvider, PlanningAsAServiceProvider, PlanutilsServerProvider, + PythonPlannerProvider, NodeJsPlannerProvider, SchedulingServiceProvider, PreviewPlanningAsAServiceProvider +} from './plannerConfigurations'; import { CONF_PDDL, PDDL_PLANNER, EXECUTABLE_OR_SERVICE, EXECUTABLE_OPTIONS } from './configuration'; import { instrumentOperationAsVsCodeCommand } from 'vscode-extension-telemetry-wrapper'; import { showError, jsonNodeToRange, isHttp } from '../utils'; @@ -136,6 +140,11 @@ export class PlannersConfiguration { } async migrateLegacyConfiguration(workspaceFolder?: WorkspaceFolder): Promise { + await this.migrateLegacySelectedPlannerConfiguration(workspaceFolder); + await this.migrateLegacyPaaSPreviews(workspaceFolder); + } + + async migrateLegacySelectedPlannerConfiguration(workspaceFolder?: WorkspaceFolder): Promise { const config = workspace.getConfiguration(PDDL_PLANNER, workspaceFolder); const legacyPlannerInspect = config.inspect(EXECUTABLE_OR_SERVICE); const legacySyntaxInspect = config.inspect(EXECUTABLE_OPTIONS); @@ -158,11 +167,7 @@ export class PlannersConfiguration { async migrateLegacyConfigurationInTarget(legacyPlanner: string, legacySyntax: string | undefined, scope: PlannerConfigurationScope, workspaceFolder?: WorkspaceFolder): Promise { const config = workspace.getConfiguration(PDDL_PLANNER, workspaceFolder); - const migratedPlanner = isHttp(legacyPlanner) - ? legacyPlanner.endsWith('/solve') - ? new SolveServicePlannerProvider([]).createPlannerConfiguration(legacyPlanner) - : new RequestServicePlannerProvider([]).createPlannerConfiguration(legacyPlanner) - : new CommandPlannerProvider().createPlannerConfiguration(legacyPlanner, legacySyntax); + const migratedPlanner = this.migrateLegacyPlannerConfigurationInTarget(legacyPlanner, legacySyntax); const target = this.toConfigurationTarget(scope); @@ -173,6 +178,35 @@ export class PlannersConfiguration { console.log(`Migrated ${legacyPlanner} to ${newPlannerConfig.scope.toString()}:${newPlannerConfig.configuration.title}`); } + private migrateLegacyPlannerConfigurationInTarget(legacyPlanner: string, legacySyntax: string | undefined): planner.PlannerConfiguration { + if (isHttp(legacyPlanner)) { + if (legacyPlanner.endsWith('/solve')) { + return new SolveServicePlannerProvider([]).createPlannerConfiguration(legacyPlanner); + } else if (legacyPlanner.endsWith('/package')) { + return new PlanningAsAServiceProvider([]).createPlannerConfiguration(legacyPlanner); + } else { + return new RequestServicePlannerProvider([]).createPlannerConfiguration(legacyPlanner); + } + } else { + return new CommandPlannerProvider().createPlannerConfiguration(legacyPlanner, legacySyntax); + } + } + + async migrateLegacyPaaSPreviews(workspaceFolder: WorkspaceFolder | undefined): Promise { + const planners = this.getPlanners(workspaceFolder); + const previewKind = new PreviewPlanningAsAServiceProvider([]).kind.kind; + const awaitables = planners + .filter(p => p.configuration.kind === previewKind) + .map(async p => await this.migrateLegacyPaaSPreview(p)); + Promise.all(awaitables); + } + + private async migrateLegacyPaaSPreview(config: ScopedPlannerConfiguration): Promise { + config.configuration.kind = planner.WellKnownPlannerKind.PLANNING_AS_A_SERVICE.kind; + await this.savePlannerConfiguration(config.index, config.scope, config.configuration, this.toWorkspaceFolder(config)); + console.log(`Migrated '${config.configuration.title}' to ${config.configuration.kind}`); + } + refreshStatusBar(): void { if (!this.plannerSelector) { return; @@ -411,7 +445,7 @@ export class PlannersConfiguration { for (const scope of PlannersConfiguration.SCOPES) { // todo: get the planners for all scopes, then filter const planners = this.getPlannersPerScope(scope, workingFolder); - if (!Array.isArray(planners)) { console.error(`Planners configuration for scope ${scope} is invalid: ${planners}`); continue; } + if (!Array.isArray(planners)) { console.error(`Planners configuration for scope ${scope} is invalid: `, planners); continue; } const indexFound = planners.findIndex(p => p.title === selectedPlannerTitle); if (indexFound > -1) { return this.toScopedConfiguration(planners[indexFound], indexFound, scope, workingFolder); diff --git a/src/session/SessionRepository.ts b/src/session/SessionRepository.ts index 5bf1464..7412f3d 100644 --- a/src/session/SessionRepository.ts +++ b/src/session/SessionRepository.ts @@ -241,7 +241,8 @@ export async function duplicateSession(session: SessionContent): Promise } const SAVE_TABS_PLUGIN_NAME = "save-tabs"; -const SOLVER_PLUGIN_NAME = "solver"; +export const SOLVER_PLUGIN_NAME = "solver"; +export const PLANNING_AS_A_SERVICE_PLUGIN_NAME = "planning-as-a-service-plugin"; /** * Fetches session from the planning.domains server. @@ -283,7 +284,7 @@ async function getRawSession(sessionConfiguration: SessionConfiguration): Promis if (pluginsMatch = SESSION_PLUGINS_PATTERN.exec(sessionContent)) { const rawPlugins = JSON.parse(pluginsMatch[1]); - [SAVE_TABS_PLUGIN_NAME, SOLVER_PLUGIN_NAME].forEach(pluginName => { + [SAVE_TABS_PLUGIN_NAME, SOLVER_PLUGIN_NAME, PLANNING_AS_A_SERVICE_PLUGIN_NAME].forEach(pluginName => { if (rawPlugins.hasOwnProperty(pluginName)) { plugins.set(pluginName, toRawSessionPlugin(pluginName, rawPlugins[pluginName])); } diff --git a/src/session/SessionSourceControl.ts b/src/session/SessionSourceControl.ts index 58fbb93..15cd33e 100644 --- a/src/session/SessionSourceControl.ts +++ b/src/session/SessionSourceControl.ts @@ -4,12 +4,14 @@ * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; -import { SessionRepository, getSession, SessionContent, uploadSession, duplicateSession, checkSession } from './SessionRepository'; +import { SessionRepository, getSession, SessionContent, uploadSession, duplicateSession, checkSession, PLANNING_AS_A_SERVICE_PLUGIN_NAME, SOLVER_PLUGIN_NAME } from './SessionRepository'; import * as path from 'path'; import { toFuzzyRelativeTime } from '../utils'; import { SessionConfiguration, saveConfiguration, SessionMode, toSessionConfiguration, CONFIGURATION_FILE } from './SessionConfiguration'; -import { PDDL_PLANNER, EXECUTABLE_OR_SERVICE } from '../configuration/configuration'; +import { CONF_PDDL } from '../configuration/configuration'; import { exists } from '../util/workspaceFs'; +import { CONF_PLANNERS, CONF_SELECTED_PLANNER } from '../configuration/PlannersConfiguration'; +import { PlanningAsAServiceProvider, SolveServicePlannerProvider } from '../configuration/plannerConfigurations'; /** * Command for cloning a session to the local storage. @@ -273,18 +275,32 @@ export class SessionSourceControl implements vscode.Disposable { return await saveConfiguration(this.workspaceFolder.uri, this.session); } - private static readonly SOLVER_PLUGIN = "solver"; - /** Saves setting of eligible session plugins to workspace configuration. */ async saveWorkspaceSettings(): Promise { - if (this.session.plugins.has(SessionSourceControl.SOLVER_PLUGIN)) { - const solver = this.session.plugins.get(SessionSourceControl.SOLVER_PLUGIN); + if (this.session.plugins.has(PLANNING_AS_A_SERVICE_PLUGIN_NAME)) { + const solver = this.session.plugins.get(PLANNING_AS_A_SERVICE_PLUGIN_NAME); + if (solver?.url !== "/plugins/featured/paas/plugin.js") { return; } + + const solverUrl = solver.settings["PASURL"] + '/package'; + const configuration = new PlanningAsAServiceProvider([]).createPlannerConfiguration(solverUrl); + configuration.title += ' - from session'; + + await vscode.workspace.getConfiguration(CONF_PDDL, this.workspaceFolder.uri) + .update(CONF_PLANNERS, [configuration], vscode.ConfigurationTarget.WorkspaceFolder); + await vscode.workspace.getConfiguration(CONF_PDDL, this.workspaceFolder.uri) + .update(CONF_SELECTED_PLANNER, configuration.title, vscode.ConfigurationTarget.WorkspaceFolder); + } else if (this.session.plugins.has(SOLVER_PLUGIN_NAME)) { + const solver = this.session.plugins.get(SOLVER_PLUGIN_NAME); if (solver?.url !== "/plugins/solver.js") { return; } - const solverUrl = solver.settings["url"]; + const solverUrl = solver.settings["url"] + "/solve"; + const configuration = new SolveServicePlannerProvider([]).createPlannerConfiguration(solverUrl); + configuration.title += ' - from obsolete session'; - // todo: this configuration is upgraded right away; move to the new planner configuration pattern - await vscode.workspace.getConfiguration(PDDL_PLANNER, this.workspaceFolder.uri).update(EXECUTABLE_OR_SERVICE, solverUrl + "/solve", vscode.ConfigurationTarget.WorkspaceFolder); + await vscode.workspace.getConfiguration(CONF_PDDL, this.workspaceFolder.uri) + .update(CONF_PLANNERS, [configuration], vscode.ConfigurationTarget.WorkspaceFolder); + await vscode.workspace.getConfiguration(CONF_PDDL, this.workspaceFolder.uri) + .update(CONF_SELECTED_PLANNER, configuration.title, vscode.ConfigurationTarget.WorkspaceFolder); } } diff --git a/src/test/suite/PlannerConfiguration.test.ts b/src/test/suite/PlannerConfiguration.test.ts index 8c44911..5b9f31c 100644 --- a/src/test/suite/PlannerConfiguration.test.ts +++ b/src/test/suite/PlannerConfiguration.test.ts @@ -13,6 +13,7 @@ import { plannersConfiguration, codePddlWorkspaceForTests } from '../../extensio import { PlannerConfigurationScope, CONF_PLANNERS, CONF_SELECTED_PLANNER } from '../../configuration/PlannersConfiguration'; import { PDDL_PLANNER, EXECUTABLE_OR_SERVICE, EXECUTABLE_OPTIONS, CONF_PDDL } from '../../configuration/configuration'; import { fail } from 'assert'; +import { PreviewPlanningAsAServiceProvider } from '../../configuration/plannerConfigurations'; suite('Planner configuration test', () => { @@ -327,4 +328,27 @@ suite('Planner configuration test', () => { expect(migratedPlanner.url).to.equal(executable); expect(migratedPlanner.title).to.equal(executable); }); + + + test('Migrates deprecated planning-as-a-service configuration', async () => { + const executable = 'https://solver.planning.domains/solve'; + + // GIVEN + const legacyProvider = new PreviewPlanningAsAServiceProvider([]); + const legacyConfiguration = legacyProvider.createPlannerConfiguration('https://mock-as-a-service/'); + await plannersConfiguration.addPlannerConfiguration(PlannerConfigurationScope.User, legacyConfiguration); + await workspace.getConfiguration(PDDL_PLANNER).update(EXECUTABLE_OR_SERVICE, executable, ConfigurationTarget.Global); + + const previewConfigsBefore = plannersConfiguration.getPlanners().filter(p => p.configuration.kind === legacyProvider.kind.kind); + + expect(previewConfigsBefore, 'preview configs before').to.have.length.greaterThanOrEqual(1); + + // WHEN + await plannersConfiguration.migrateLegacyConfiguration(); + + // THEN + const previewConfigsAfter = plannersConfiguration.getPlanners().filter(p => p.configuration.kind === legacyProvider.kind.kind); + expect(previewConfigsAfter, 'preview configs after').to.have.length(previewConfigsBefore.length); + }); + });