mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Add relative path resolution support for Python and Node.js executables
Co-authored-by: Jack251970 <53996452+Jack251970@users.noreply.github.com>
This commit is contained in:
parent
438bb8a2fc
commit
d61ec1828f
3 changed files with 139 additions and 6 deletions
|
|
@ -4,6 +4,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
|
|
@ -40,6 +41,12 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
PluginSettings = pluginSettings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the configured executable path to an absolute path.
|
||||
/// Supports both absolute paths and relative paths (relative to ProgramDirectory).
|
||||
/// </summary>
|
||||
private string ResolvedPluginsSettingsFilePath => Constant.ResolveAbsolutePath(PluginsSettingsFilePath);
|
||||
|
||||
internal IEnumerable<PluginPair> Setup()
|
||||
{
|
||||
// If no plugin is using the language, return empty list
|
||||
|
|
@ -48,13 +55,14 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
return new List<PluginPair>();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(PluginsSettingsFilePath) && FilesFolders.FileExists(PluginsSettingsFilePath))
|
||||
var resolvedPath = ResolvedPluginsSettingsFilePath;
|
||||
if (!string.IsNullOrEmpty(resolvedPath) && FilesFolders.FileExists(resolvedPath))
|
||||
{
|
||||
// Ensure latest only if user is using Flow's environment setup.
|
||||
if (PluginsSettingsFilePath.StartsWith(EnvPath, StringComparison.OrdinalIgnoreCase))
|
||||
EnsureLatestInstalled(ExecutablePath, PluginsSettingsFilePath, EnvPath);
|
||||
if (resolvedPath.StartsWith(EnvPath, StringComparison.OrdinalIgnoreCase))
|
||||
EnsureLatestInstalled(ExecutablePath, resolvedPath, EnvPath);
|
||||
|
||||
return SetPathForPluginPairs(PluginsSettingsFilePath, Language);
|
||||
return SetPathForPluginPairs(resolvedPath, Language);
|
||||
}
|
||||
|
||||
var noRuntimeMessage = Localize.runtimePluginInstalledChooseRuntimePrompt(Language, EnvName, Environment.NewLine);
|
||||
|
|
@ -103,9 +111,10 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
InstallEnvironment();
|
||||
}
|
||||
|
||||
if (FilesFolders.FileExists(PluginsSettingsFilePath))
|
||||
resolvedPath = ResolvedPluginsSettingsFilePath;
|
||||
if (FilesFolders.FileExists(resolvedPath))
|
||||
{
|
||||
return SetPathForPluginPairs(PluginsSettingsFilePath, Language);
|
||||
return SetPathForPluginPairs(resolvedPath, Language);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -56,5 +56,25 @@ namespace Flow.Launcher.Infrastructure
|
|||
public const string Docs = "https://flowlauncher.com/docs";
|
||||
|
||||
public const string SystemLanguageCode = "system";
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a path that may be relative to an absolute path.
|
||||
/// If the path is already absolute, returns it as-is.
|
||||
/// If the path is relative (starts with . or doesn't contain a drive), resolves it relative to ProgramDirectory.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to resolve</param>
|
||||
/// <returns>An absolute path</returns>
|
||||
public static string ResolveAbsolutePath(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return path;
|
||||
|
||||
// If already absolute, return as-is
|
||||
if (Path.IsPathRooted(path))
|
||||
return path;
|
||||
|
||||
// Resolve relative to ProgramDirectory
|
||||
return Path.GetFullPath(Path.Combine(ProgramDirectory, path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
104
Flow.Launcher.Test/PathResolutionTest.cs
Normal file
104
Flow.Launcher.Test/PathResolutionTest.cs
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using Xunit;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
|
||||
namespace Flow.Launcher.Test
|
||||
{
|
||||
public class PathResolutionTest
|
||||
{
|
||||
[Fact]
|
||||
public void ResolveAbsolutePath_WithAbsolutePath_ReturnsOriginalPath()
|
||||
{
|
||||
// Arrange
|
||||
var absolutePath = @"C:\Program Files\Python\python.exe";
|
||||
|
||||
// Act
|
||||
var result = Constant.ResolveAbsolutePath(absolutePath);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(absolutePath, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResolveAbsolutePath_WithRelativePath_ResolvesToProgramDirectory()
|
||||
{
|
||||
// Arrange
|
||||
var relativePath = @".\runtimes\python\pythonw.exe";
|
||||
|
||||
// Act
|
||||
var result = Constant.ResolveAbsolutePath(relativePath);
|
||||
|
||||
// Assert
|
||||
Assert.True(Path.IsPathRooted(result), "Result should be an absolute path");
|
||||
Assert.Contains(Constant.ProgramDirectory, result);
|
||||
Assert.EndsWith(@"runtimes\python\pythonw.exe", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResolveAbsolutePath_WithDotDotPath_ResolvesCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var relativePath = @"..\runtimes\node\node.exe";
|
||||
|
||||
// Act
|
||||
var result = Constant.ResolveAbsolutePath(relativePath);
|
||||
|
||||
// Assert
|
||||
Assert.True(Path.IsPathRooted(result), "Result should be an absolute path");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResolveAbsolutePath_WithNullPath_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
string nullPath = null;
|
||||
|
||||
// Act
|
||||
var result = Constant.ResolveAbsolutePath(nullPath);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResolveAbsolutePath_WithEmptyPath_ReturnsEmpty()
|
||||
{
|
||||
// Arrange
|
||||
var emptyPath = string.Empty;
|
||||
|
||||
// Act
|
||||
var result = Constant.ResolveAbsolutePath(emptyPath);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(string.Empty, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResolveAbsolutePath_WithForwardSlashes_ResolvesCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var relativePath = @"./runtimes/python/pythonw.exe";
|
||||
|
||||
// Act
|
||||
var result = Constant.ResolveAbsolutePath(relativePath);
|
||||
|
||||
// Assert
|
||||
Assert.True(Path.IsPathRooted(result), "Result should be an absolute path");
|
||||
Assert.Contains(Constant.ProgramDirectory, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResolveAbsolutePath_WithUNCPath_ReturnsOriginalPath()
|
||||
{
|
||||
// Arrange
|
||||
var uncPath = @"\\server\share\python\pythonw.exe";
|
||||
|
||||
// Act
|
||||
var result = Constant.ResolveAbsolutePath(uncPath);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(uncPath, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue