fix(launch): reject option-like and missing paths, resolve them absolute and drop the folder-missing page

This commit is contained in:
yyc12345 committed 2026-10-04 16:17:05 +08:00
1 parent 157f597eed
commit e3265e3c89
9 files changed
+91 -94

No files matched your search

-6
View File
@@ -265,12 +265,6 @@
<data name="Error_Argument_Usage" xml:space="preserve">
<value>Usage: ykanban &lt;path&gt;</value>
</data>
<data name="Error_DirectoryMissing_Title" xml:space="preserve">
<value>Folder not found</value>
</data>
<data name="Error_DirectoryMissing_Message" xml:space="preserve">
<value>The folder does not exist: {0}</value>
</data>
<data name="Error_NotInitialized_Title" xml:space="preserve">
<value>No workspace here</value>
</data>
@@ -265,12 +265,6 @@
<data name="Error_Argument_Usage" xml:space="preserve">
<value>用法:ykanban &lt;路径&gt;</value>
</data>
<data name="Error_DirectoryMissing_Title" xml:space="preserve">
<value>目录不存在</value>
</data>
<data name="Error_DirectoryMissing_Message" xml:space="preserve">
<value>目录不存在:{0}</value>
</data>
<data name="Error_NotInitialized_Title" xml:space="preserve">
<value>尚未初始化</value>
</data>
+25 -10
View File
@@ -4,9 +4,11 @@ namespace YKanBan.Launching;
/// <summary>
/// Parses raw command-line arguments. The only accepted form is a single,
/// non-blank workspace path (<c>ykanban &lt;path&gt;</c>); zero arguments,
/// more than one argument, or a blank argument is rejected as an argument
/// error. The path itself is not checked for existence here.
/// non-blank, existing workspace folder (<c>ykanban &lt;path&gt;</c>); zero
/// arguments, more than one argument, a blank argument, an argument starting
/// with <c>-</c> (any option form, <c>--help</c> included), a malformed path or
/// a path that is not an existing folder is rejected as an argument error. A
/// relative path is resolved against the process's current directory.
/// </summary>
public static class LaunchArguments {
/// <summary>
@@ -14,15 +16,28 @@ public static class LaunchArguments {
/// <c>ykanban &lt;path&gt;</c> contract.
/// </summary>
/// <param name="arguments">The raw arguments, excluding the executable name.</param>
/// <param name="folderPath">The parsed workspace path on success, otherwise <see langword="null"/>.</param>
/// <returns><see langword="true"/> when exactly one non-blank path was supplied.</returns>
/// <param name="folderPath">The absolute, existing workspace folder on success, otherwise <see langword="null"/>.</param>
/// <returns><see langword="true"/> when exactly one usable path was supplied.</returns>
public static bool TryParse(IReadOnlyList<string> arguments, [NotNullWhen(true)] out string? folderPath) {
if (arguments.Count == 1 && !string.IsNullOrWhiteSpace(arguments[0])) {
folderPath = arguments[0];
return true;
folderPath = null;
if (arguments.Count != 1 || string.IsNullOrWhiteSpace(arguments[0]) || arguments[0].StartsWith('-')) {
return false;
}
folderPath = null;
return false;
string fullPath;
try {
fullPath = Path.GetFullPath(arguments[0]);
} catch (Exception exception) when (exception is ArgumentException or NotSupportedException or PathTooLongException) {
// A path the OS cannot even represent is a bad argument, not a missing folder.
return false;
}
// Existence is checked here so every caller gets an already validated folder.
if (!Directory.Exists(fullPath)) {
return false;
}
folderPath = fullPath;
return true;
}
}
@@ -1,29 +0,0 @@
using System.Globalization;
namespace YKanBan.ViewModels.ErrorPages;
/// <summary>
/// The full-window page shown when the folder passed on the command line does
/// not exist. It has no operations.
/// </summary>
public sealed class DirectoryMissingPageViewModel : ViewModelBase {
/// <summary>
/// Initializes the page for a missing folder.
/// </summary>
/// <param name="folderPath">The folder path that does not exist.</param>
public DirectoryMissingPageViewModel(string folderPath) {
FolderPath = folderPath;
Message = string.Format(
Resources.Culture ?? CultureInfo.CurrentCulture, Resources.Error_DirectoryMissing_Message, folderPath);
}
/// <summary>
/// Gets the folder path that does not exist.
/// </summary>
public string FolderPath { get; }
/// <summary>
/// Gets the localized explanatory message.
/// </summary>
public string Message { get; }
}
@@ -69,11 +69,6 @@ public sealed partial class MainWindowViewModel : ViewModelBase {
return;
}
if (!Directory.Exists(folderPath)) {
Content = new DirectoryMissingPageViewModel(folderPath);
return;
}
try {
OpenWorkspace(folderPath);
} catch (WorkspaceNotInitializedException) {
@@ -1,18 +0,0 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:YKanBan.ViewModels.ErrorPages"
xmlns:lang="using:YKanBan"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="640"
x:Class="YKanBan.Views.ErrorPages.DirectoryMissingPageView"
x:DataType="vm:DirectoryMissingPageViewModel">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="12"
MaxWidth="560" Margin="32">
<TextBlock Text="{x:Static lang:Resources.Error_DirectoryMissing_Title}"
FontSize="20" FontWeight="SemiBold" HorizontalAlignment="Center"/>
<TextBlock Text="{Binding Message}"
TextWrapping="Wrap" HorizontalAlignment="Center" TextAlignment="Center"/>
</StackPanel>
</UserControl>
@@ -1,9 +0,0 @@
using Avalonia.Controls;
namespace YKanBan.Views.ErrorPages;
public partial class DirectoryMissingPageView : UserControl {
public DirectoryMissingPageView() {
InitializeComponent();
}
}