Skip to content

Conversation

@Jack251970
Copy link
Member

Flow Launcher required absolute paths for Python and Node.js executables, breaking portability when the application is moved. Embedded runtimes within the portable directory structure were not supported.

CHANGES

  • ResolveAbsolutePath(): Resolves relative paths to absolute at runtime, based on ProgramDirectory
  • Path resolution integrated at file existence checks and plugin instantiation

Usage

Users can now configure:

Python Path: .\runtimes\python\pythonw.exe
Node.js Path: .\runtimes\nodejs\node.exe

Paths are stored as-entered (relative or absolute), resolved to absolute only at execution. File picker selections within ProgramDirectory are automatically stored as relative paths.

Enables truly portable setups with embedded runtimes that survive directory moves, USB installations, and restricted environments.

Resolve #4228

Copilot AI and others added 10 commits January 24, 2026 07:43
Co-authored-by: Jack251970 <53996452+Jack251970@users.noreply.github.com>
Co-authored-by: Jack251970 <53996452+Jack251970@users.noreply.github.com>
…portability

Co-authored-by: Jack251970 <53996452+Jack251970@users.noreply.github.com>
Removed logic that converted selected Python and Node executable
paths to relative if within the program directory. Now, the
selected file paths are stored as absolute paths without
conversion. This simplifies path handling and improves clarity.
Removed the PathResolutionTest.cs file, which contained unit tests for the Constant class's path resolution methods. These tests covered absolute, relative, UNC, null, and empty path scenarios, as well as round-trip conversions.
Move ResolveAbsolutePath and ConvertToRelativePathIfPossible from Constant to DataLocation for better organization. Update all references accordingly; implementations remain unchanged. This improves code clarity around file path management.
Eliminated the unnecessary using statement for Flow.Launcher.Infrastructure in AbstractPluginEnvironment.cs, as its types or members are no longer referenced in this file. This helps clean up the code and avoid redundant dependencies.
Removed logic that converted absolute paths to relative paths within the ProgramDirectory. Now, plugin settings file paths are always stored as absolute paths. Deleted the ConvertToRelativePathIfPossible method and updated usages accordingly.
Copilot AI review requested due to automatic review settings January 24, 2026 08:09
@github-actions github-actions bot added this to the 2.1.0 milestone Jan 24, 2026
@gitstream-cm
Copy link

gitstream-cm bot commented Jan 24, 2026

🥷 Code experts: no user but you matched threshold 10

Jack251970 has most 👩‍💻 activity in the files.
Jack251970 has most 🧠 knowledge in the files.

See details

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

Activity based on git-commit:

Jack251970
JAN
DEC
NOV
OCT
SEP 17 additions & 28 deletions
AUG

Knowledge based on git-blame:
Jack251970: 100%

Flow.Launcher.Infrastructure/UserSettings/DataLocation.cs

Activity based on git-commit:

Jack251970
JAN
DEC
NOV
OCT
SEP 29 additions & 27 deletions
AUG

Knowledge based on git-blame:
Jack251970: 100%

✨ Comment /gs review for LinearB AI review. Learn how to automate it here.

@gitstream-cm
Copy link

gitstream-cm bot commented Jan 24, 2026

Be a legend 🏆 by adding a before and after screenshot of the changes you made, especially if they are around UI/UX.

@coderabbitai coderabbitai bot added the enhancement New feature or request label Jan 24, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 24, 2026

📝 Walkthrough

Walkthrough

This pull request adds support for relative paths in Flow Launcher's portable version. It introduces a new utility method ResolveAbsolutePath in DataLocation that resolves paths relative to the program directory, and refactors AbstractPluginEnvironment to use this method when determining the plugins settings file path.

Changes

Cohort / File(s) Summary
Path Resolution Utility
Flow.Launcher.Infrastructure/UserSettings/DataLocation.cs
Added public ResolveAbsolutePath(string path) method that converts relative paths to absolute paths (rooted from Constant.ProgramDirectory), handles null/empty inputs, and passes through already-rooted paths unchanged
Plugin Environment Path Resolution
Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs
Introduced private property ResolvedPluginsSettingsFilePath that leverages the new utility method; refactored four instances where PluginsSettingsFilePath was used to employ the resolved path instead, ensuring consistent absolute path handling throughout the class

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested labels

enhancement

Suggested reviewers

  • VictoriousRaptor
🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Support relative paths for Python/Node.js executables' directly and accurately describes the main change in the changeset.
Description check ✅ Passed The description clearly relates to the changeset, explaining the problem, the implemented solution with ResolveAbsolutePath(), and practical usage examples.
Linked Issues check ✅ Passed The PR successfully implements all coding requirements from issue #4228: relative path support via ResolveAbsolutePath(), integration into plugin instantiation and file checks, and portable embedded runtime capability.
Out of Scope Changes check ✅ Passed All changes are directly scoped to supporting relative paths: ResolveAbsolutePath() utility method and integration into AbstractPluginEnvironment's path handling.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Jack251970 Jack251970 enabled auto-merge January 24, 2026 08:12
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds support for relative paths in Python and Node.js executable configuration, enabling truly portable Flow Launcher setups. The changes allow users to configure runtime paths relative to the application directory (e.g., .\runtimes\python\pythonw.exe), which are resolved to absolute paths at runtime.

Changes:

  • Added ResolveAbsolutePath() method to handle relative-to-absolute path resolution
  • Integrated path resolution into plugin environment setup and file existence checks
  • Paths are stored as-entered (relative or absolute) and resolved only at execution time

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
Flow.Launcher.Infrastructure/UserSettings/DataLocation.cs Adds ResolveAbsolutePath() method to resolve relative paths based on ProgramDirectory
Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs Integrates path resolution into plugin setup, using resolved paths for file checks and plugin instantiation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +62 to +63
// Resolve relative to ProgramDirectory
return Path.GetFullPath(Path.Combine(Constant.ProgramDirectory, path));
Copy link

Copilot AI Jan 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ResolveAbsolutePath method doesn't handle exceptions that can be thrown by Path.GetFullPath, such as ArgumentException for invalid path characters, NotSupportedException for invalid path formats, or PathTooLongException. If a user configures an invalid relative path, this could crash the application during plugin initialization. Consider adding try-catch error handling to gracefully handle invalid paths, either by logging an error and returning the original path, or by providing a meaningful error message to the user.

Suggested change
// Resolve relative to ProgramDirectory
return Path.GetFullPath(Path.Combine(Constant.ProgramDirectory, path));
// Resolve relative to ProgramDirectory, handling invalid path formats gracefully
try
{
return Path.GetFullPath(Path.Combine(Constant.ProgramDirectory, path));
}
catch (Exception ex) when (ex is ArgumentException ||
ex is NotSupportedException ||
ex is PathTooLongException)
{
// If the path cannot be resolved (invalid characters, format, or too long),
// return the original path to avoid crashing the application.
return path;
}

Copilot uses AI. Check for mistakes.
Comment on lines +53 to +64
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(Constant.ProgramDirectory, path));
}
Copy link

Copilot AI Jan 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new ResolveAbsolutePath method lacks comprehensive test coverage. Given that this is a critical feature for portability and involves path resolution logic with edge cases (relative paths starting with ".", paths without drives, UNC paths, etc.), it should have unit tests to verify correct behavior across different scenarios. Consider adding tests in Flow.Launcher.Test to verify: 1) absolute paths are returned unchanged, 2) relative paths like ".\runtime\python.exe" resolve correctly, 3) paths without leading "." also resolve correctly, and 4) edge cases like null/empty strings are handled properly.

Copilot uses AI. Check for mistakes.
/// <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.
Copy link

Copilot AI Jan 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation comment states the method handles paths that "start with . or doesn't contain a drive", but the implementation only checks if the path is rooted using Path.IsPathRooted. This check returns false for relative paths (including those starting with ".") but may have unexpected behavior with UNC paths or paths on Unix-like systems. Consider clarifying the documentation to match the actual implementation, which relies on Path.IsPathRooted for the determination.

Suggested change
/// If the path is relative (starts with . or doesn't contain a drive), resolves it relative to ProgramDirectory.
/// If the path is not rooted (as determined by <see cref="Path.IsPathRooted(string)"/>), resolves it relative to ProgramDirectory.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for Relative Path for Portable Version

2 participants