From fa8cd548f6c11d71cf9dbd91a5c6c1495837222b Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Thu, 5 Dec 2024 14:18:13 +0600 Subject: [PATCH 01/44] Add `.`, `./lib`, `./plugin` directories to path for Python plugins --- Flow.Launcher.Core/Plugin/PythonPlugin.cs | 52 ++++++++++++++++++--- Flow.Launcher.Core/Plugin/PythonPluginV2.cs | 31 +++++++++++- 2 files changed, 75 insertions(+), 8 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PythonPlugin.cs b/Flow.Launcher.Core/Plugin/PythonPlugin.cs index 536e69b3d..36160b920 100644 --- a/Flow.Launcher.Core/Plugin/PythonPlugin.cs +++ b/Flow.Launcher.Core/Plugin/PythonPlugin.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; using System.IO; using System.Text.Json; using System.Threading; @@ -29,10 +30,6 @@ namespace Flow.Launcher.Core.Plugin _startInfo.EnvironmentVariables["FLOW_VERSION"] = Constant.Version; _startInfo.EnvironmentVariables["FLOW_PROGRAM_DIRECTORY"] = Constant.ProgramDirectory; _startInfo.EnvironmentVariables["FLOW_APPLICATION_DIRECTORY"] = Constant.ApplicationDirectory; - - - //Add -B flag to tell python don't write .py[co] files. Because .pyc contains location infos which will prevent python portable - _startInfo.ArgumentList.Add("-B"); } protected override Task RequestAsync(JsonRPCRequestModel request, CancellationToken token = default) @@ -50,10 +47,51 @@ namespace Flow.Launcher.Core.Plugin // TODO: Async Action return Execute(_startInfo); } + public override async Task InitAsync(PluginInitContext context) { - _startInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath); - _startInfo.ArgumentList.Add(""); + // Run .py files via `-c ` + if (context.CurrentPluginMetadata.ExecuteFilePath.EndsWith(".py", StringComparison.OrdinalIgnoreCase)) + { + var rootDirectory = context.CurrentPluginMetadata.PluginDirectory; + var libDirectory = Path.Combine(rootDirectory, "lib"); + var pluginDirectory = Path.Combine(rootDirectory, "plugin"); + + // This makes it easier for plugin authors to import their own modules. + // They won't have to add `.`, `./lib`, or `./plugin` to their sys.path manually. + // Instead of running the .py file directly, we pass the code we want to run as a CLI argument. + // This code sets sys.path for the plugin author and then runs the .py file via runpy. + _startInfo.ArgumentList.Add("-c"); + _startInfo.ArgumentList.Add( + $""" + import sys + sys.path.append(r'{rootDirectory}') + sys.path.append(r'{libDirectory}') + sys.path.append(r'{pluginDirectory}') + + import runpy + runpy.run_path(r'{context.CurrentPluginMetadata.ExecuteFilePath}', None, '__main__') + """ + ); + // Plugins always expect the JSON data to be in the third argument + // (we're always setting it as _startInfo.ArgumentList[2] = ...). + _startInfo.ArgumentList.Add(""); + // Because plugins always expect the JSON data to be in the third argument, and specifying -c + // takes up two arguments, we have to move `-B` to the end. + _startInfo.ArgumentList.Add("-B"); + } + // Run .pyz files as is + else + { + // -B flag is needed to tell python not to write .py[co] files. + // Because .pyc contains location infos which will prevent python portable + _startInfo.ArgumentList.Add("-B"); + _startInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath); + // Plugins always expect the JSON data to be in the third argument + // (we're always setting it as _startInfo.ArgumentList[2] = ...). + _startInfo.ArgumentList.Add(""); + } + await base.InitAsync(context); _startInfo.WorkingDirectory = context.CurrentPluginMetadata.PluginDirectory; } diff --git a/Flow.Launcher.Core/Plugin/PythonPluginV2.cs b/Flow.Launcher.Core/Plugin/PythonPluginV2.cs index 5c36e0eea..224653ba1 100644 --- a/Flow.Launcher.Core/Plugin/PythonPluginV2.cs +++ b/Flow.Launcher.Core/Plugin/PythonPluginV2.cs @@ -33,7 +33,36 @@ namespace Flow.Launcher.Core.Plugin public override async Task InitAsync(PluginInitContext context) { - StartInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath); + // Run .py files via `-c ` + if (context.CurrentPluginMetadata.ExecuteFilePath.EndsWith(".py", StringComparison.OrdinalIgnoreCase)) + { + var rootDirectory = context.CurrentPluginMetadata.PluginDirectory; + var libDirectory = Path.Combine(rootDirectory, "lib"); + var pluginDirectory = Path.Combine(rootDirectory, "plugin"); + var filePath = context.CurrentPluginMetadata.ExecuteFilePath; + + // This makes it easier for plugin authors to import their own modules. + // They won't have to add `.`, `./lib`, or `./plugin` to their sys.path manually. + // Instead of running the .py file directly, we pass the code we want to run as a CLI argument. + // This code sets sys.path for the plugin author and then runs the .py file via runpy. + StartInfo.ArgumentList.Add("-c"); + StartInfo.ArgumentList.Add( + $""" + import sys + sys.path.append(r'{rootDirectory}') + sys.path.append(r'{libDirectory}') + sys.path.append(r'{pluginDirectory}') + + import runpy + runpy.run_path(r'{filePath}', None, '__main__') + """ + ); + } + // Run .pyz files as is + else + { + StartInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath); + } await base.InitAsync(context); } From d5dd7b44a41322ebdd9e4e97a25e62e653775688 Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Thu, 5 Dec 2024 17:37:54 +0600 Subject: [PATCH 02/44] Use PYTHONDONTWRITEBYTECODE instead of -B flag when running Python plugins --- Flow.Launcher.Core/Plugin/PythonPlugin.cs | 11 ++++++----- Flow.Launcher.Core/Plugin/PythonPluginV2.cs | 4 +--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PythonPlugin.cs b/Flow.Launcher.Core/Plugin/PythonPlugin.cs index 36160b920..7b670742a 100644 --- a/Flow.Launcher.Core/Plugin/PythonPlugin.cs +++ b/Flow.Launcher.Core/Plugin/PythonPlugin.cs @@ -26,6 +26,9 @@ namespace Flow.Launcher.Core.Plugin var path = Path.Combine(Constant.ProgramDirectory, JsonRPC); _startInfo.EnvironmentVariables["PYTHONPATH"] = path; + // Prevent Python from writing .py[co] files. + // Because .pyc contains location infos which will prevent python portable. + _startInfo.EnvironmentVariables["PYTHONDONTWRITEBYTECODE"] = "1"; _startInfo.EnvironmentVariables["FLOW_VERSION"] = Constant.Version; _startInfo.EnvironmentVariables["FLOW_PROGRAM_DIRECTORY"] = Constant.ProgramDirectory; @@ -76,15 +79,13 @@ namespace Flow.Launcher.Core.Plugin // Plugins always expect the JSON data to be in the third argument // (we're always setting it as _startInfo.ArgumentList[2] = ...). _startInfo.ArgumentList.Add(""); - // Because plugins always expect the JSON data to be in the third argument, and specifying -c - // takes up two arguments, we have to move `-B` to the end. - _startInfo.ArgumentList.Add("-B"); } // Run .pyz files as is else { - // -B flag is needed to tell python not to write .py[co] files. - // Because .pyc contains location infos which will prevent python portable + // No need for -B flag because we're using PYTHONDONTWRITEBYTECODE env variable now, + // but the plugins still expect data to be sent as the third argument, so we're keeping + // the flag here, even though it's not necessary anymore. _startInfo.ArgumentList.Add("-B"); _startInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath); // Plugins always expect the JSON data to be in the third argument diff --git a/Flow.Launcher.Core/Plugin/PythonPluginV2.cs b/Flow.Launcher.Core/Plugin/PythonPluginV2.cs index 224653ba1..03ac0e661 100644 --- a/Flow.Launcher.Core/Plugin/PythonPluginV2.cs +++ b/Flow.Launcher.Core/Plugin/PythonPluginV2.cs @@ -26,9 +26,7 @@ namespace Flow.Launcher.Core.Plugin var path = Path.Combine(Constant.ProgramDirectory, JsonRpc); StartInfo.EnvironmentVariables["PYTHONPATH"] = path; - - //Add -B flag to tell python don't write .py[co] files. Because .pyc contains location infos which will prevent python portable - StartInfo.ArgumentList.Add("-B"); + StartInfo.EnvironmentVariables["PYTHONDONTWRITEBYTECODE"] = "1"; } public override async Task InitAsync(PluginInitContext context) From 37058f765185341a08007d4c713d944e25303b79 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 4 Jan 2025 21:55:44 +0800 Subject: [PATCH 03/44] Improve code quality. --- .../Flow.Launcher.Plugin.PluginsManager/Main.cs | 2 +- .../PluginsManager.cs | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs index bec84f484..156135f81 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs @@ -51,7 +51,7 @@ namespace Flow.Launcher.Plugin.PluginsManager return query.FirstSearch.ToLower() switch { //search could be url, no need ToLower() when passed in - Settings.InstallCommand => await pluginManager.RequestInstallOrUpdate(query.SecondToEndSearch, token, query.IsReQuery), + Settings.InstallCommand => await pluginManager.RequestInstallOrUpdateAsync(query.SecondToEndSearch, token, query.IsReQuery), Settings.UninstallCommand => pluginManager.RequestUninstall(query.SecondToEndSearch), Settings.UpdateCommand => await pluginManager.RequestUpdateAsync(query.SecondToEndSearch, token, query.IsReQuery), _ => pluginManager.GetDefaultHotKeys().Where(hotkey => diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 305d248d3..b1b1a7502 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -324,7 +324,7 @@ namespace Flow.Launcher.Plugin.PluginsManager string.Format( Context.API.GetTranslation("plugin_pluginsmanager_install_error_subtitle"), x.Name)); - }, TaskContinuationOptions.OnlyOnFaulted); + }, token, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default); return true; }, @@ -337,7 +337,7 @@ namespace Flow.Launcher.Plugin.PluginsManager }); // Update all result - if (resultsForUpdate.Count() > 1) + if (resultsForUpdate.Count > 1) { var updateAllResult = new Result { @@ -351,13 +351,13 @@ namespace Flow.Launcher.Plugin.PluginsManager { message = string.Format( Context.API.GetTranslation("plugin_pluginsmanager_update_all_prompt"), - resultsForUpdate.Count(), Environment.NewLine); + resultsForUpdate.Count, Environment.NewLine); } else { message = string.Format( Context.API.GetTranslation("plugin_pluginsmanager_update_all_prompt_no_restart"), - resultsForUpdate.Count()); + resultsForUpdate.Count); } if (Context.API.ShowMsgBox(message, @@ -401,7 +401,7 @@ namespace Flow.Launcher.Plugin.PluginsManager Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_update_title"), string.Format( Context.API.GetTranslation("plugin_pluginsmanager_update_all_success_restart"), - resultsForUpdate.Count())); + resultsForUpdate.Count)); Context.API.RestartApp(); } else @@ -409,7 +409,7 @@ namespace Flow.Launcher.Plugin.PluginsManager Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_update_title"), string.Format( Context.API.GetTranslation("plugin_pluginsmanager_update_all_success_no_restart"), - resultsForUpdate.Count())); + resultsForUpdate.Count)); } return true; @@ -545,7 +545,7 @@ namespace Flow.Launcher.Plugin.PluginsManager Context.API.GetAllPlugins().Any(x => x.Metadata.Website.StartsWith(constructedUrlPart)); } - internal async ValueTask> RequestInstallOrUpdate(string search, CancellationToken token, + internal async ValueTask> RequestInstallOrUpdateAsync(string search, CancellationToken token, bool usePrimaryUrlOnly = false) { await PluginsManifest.UpdateManifestAsync(token, usePrimaryUrlOnly); From 562b233c157f2d11bc00f744f2772223037c4eb4 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 4 Jan 2025 23:11:13 +0800 Subject: [PATCH 04/44] Add progress box support for downloading plugin --- Flow.Launcher.Core/ProgressBoxEx.xaml | 106 ++++++++++++++++++ Flow.Launcher.Core/ProgressBoxEx.xaml.cs | 76 +++++++++++++ .../PluginsManager.cs | 59 +++++++++- 3 files changed, 239 insertions(+), 2 deletions(-) create mode 100644 Flow.Launcher.Core/ProgressBoxEx.xaml create mode 100644 Flow.Launcher.Core/ProgressBoxEx.xaml.cs diff --git a/Flow.Launcher.Core/ProgressBoxEx.xaml b/Flow.Launcher.Core/ProgressBoxEx.xaml new file mode 100644 index 000000000..4cce82221 --- /dev/null +++ b/Flow.Launcher.Core/ProgressBoxEx.xaml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +