Skip to content

Commit a1665c7

Browse files
authored
Support relative paths for Python/Node.js executables (#4230)
1 parent 8c296c1 commit a1665c7

2 files changed

Lines changed: 48 additions & 6 deletions

File tree

Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ internal AbstractPluginEnvironment(List<PluginMetadata> pluginMetadataList, Plug
4040
PluginSettings = pluginSettings;
4141
}
4242

43+
/// <summary>
44+
/// Resolves the configured runtime executable path to an absolute path.
45+
/// Supports both absolute paths and relative paths (relative to ProgramDirectory).
46+
/// </summary>
47+
private string ResolvedPluginsSettingsFilePath => FilesFolders.ResolveAbsolutePath(PluginsSettingsFilePath);
48+
4349
internal IEnumerable<PluginPair> Setup()
4450
{
4551
// If no plugin is using the language, return empty list
@@ -48,13 +54,16 @@ internal IEnumerable<PluginPair> Setup()
4854
return new List<PluginPair>();
4955
}
5056

51-
if (!string.IsNullOrEmpty(PluginsSettingsFilePath) && FilesFolders.FileExists(PluginsSettingsFilePath))
57+
var resolvedPath = ResolvedPluginsSettingsFilePath;
58+
if (!string.IsNullOrEmpty(resolvedPath) && FilesFolders.FileExists(resolvedPath))
5259
{
5360
// Ensure latest only if user is using Flow's environment setup.
54-
if (PluginsSettingsFilePath.StartsWith(EnvPath, StringComparison.OrdinalIgnoreCase))
55-
EnsureLatestInstalled(ExecutablePath, PluginsSettingsFilePath, EnvPath);
61+
if (resolvedPath.StartsWith(EnvPath, StringComparison.OrdinalIgnoreCase))
62+
EnsureLatestInstalled(ExecutablePath, resolvedPath, EnvPath);
5663

57-
return SetPathForPluginPairs(PluginsSettingsFilePath, Language);
64+
// Ensure the path is updated in settings in case environment was updated
65+
resolvedPath = ResolvedPluginsSettingsFilePath;
66+
return SetPathForPluginPairs(resolvedPath, Language);
5867
}
5968

6069
var noRuntimeMessage = Localize.runtimePluginInstalledChooseRuntimePrompt(Language, EnvName, Environment.NewLine);
@@ -103,9 +112,11 @@ internal IEnumerable<PluginPair> Setup()
103112
InstallEnvironment();
104113
}
105114

106-
if (FilesFolders.FileExists(PluginsSettingsFilePath))
115+
// Ensure the path is updated when user has chosen to install or select environment executable
116+
resolvedPath = ResolvedPluginsSettingsFilePath;
117+
if (FilesFolders.FileExists(resolvedPath))
107118
{
108-
return SetPathForPluginPairs(PluginsSettingsFilePath, Language);
119+
return SetPathForPluginPairs(resolvedPath, Language);
109120
}
110121
else
111122
{

Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
using System.Diagnostics;
33
using System.IO;
44
using System.Linq;
5+
using System.Reflection;
6+
57
#pragma warning disable IDE0005
68
using System.Windows;
79
#pragma warning restore IDE0005
@@ -487,5 +489,34 @@ public static void ValidateDataDirectory(string bundledDataDirectory, string dat
487489
}
488490
}
489491
}
492+
493+
/// <summary>
494+
/// Resolves a path that may be relative to an absolute path.
495+
/// If the path is already absolute, returns it as-is.
496+
/// If the path is not rooted (as determined by <see cref="Path.IsPathRooted(string)"/>), resolves it relative to ProgramDirectory.
497+
/// </summary>
498+
/// <param name="path">The path to resolve</param>
499+
/// <returns>An absolute path</returns>
500+
public static string ResolveAbsolutePath(string path)
501+
{
502+
if (string.IsNullOrEmpty(path))
503+
return path;
504+
505+
// If already absolute, return as-is
506+
if (Path.IsPathFullyQualified(path))
507+
return path;
508+
509+
// Resolve relative to ProgramDirectory, handling invalid path formats gracefully
510+
try
511+
{
512+
return Path.GetFullPath(Path.Combine(Directory.GetParent(Assembly.GetExecutingAssembly().Location).ToString(), path));
513+
}
514+
catch (Exception)
515+
{
516+
// If the path cannot be resolved (invalid characters, format, or too long),
517+
// return the original path to avoid crashing the application.
518+
return path;
519+
}
520+
}
490521
}
491522
}

0 commit comments

Comments
 (0)