Skip to content

Commit 4f5eb2b

Browse files
authored
Merge pull request #823 from Garulf/install-from-url
Detect URL and install using Plugin Manager
2 parents 5e57d73 + 07aebae commit 4f5eb2b

File tree

13 files changed

+294
-53
lines changed

13 files changed

+294
-53
lines changed

Flow.Launcher.Core/Plugin/PluginConfig.cs

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.IO;
@@ -45,8 +45,56 @@ public static List<PluginMetadata> Parse(string[] pluginDirectories)
4545
}
4646
}
4747
}
48-
49-
return allPluginMetadata;
48+
49+
(List<PluginMetadata> uniqueList, List<PluginMetadata> duplicateList) = GetUniqueLatestPluginMetadata(allPluginMetadata);
50+
51+
duplicateList
52+
.ForEach(
53+
x => Log.Warn("PluginConfig",
54+
string.Format("Duplicate plugin name: {0}, id: {1}, version: {2} " +
55+
"not loaded due to version not the highest of the duplicates",
56+
x.Name, x.ID, x.Version),
57+
"GetUniqueLatestPluginMetadata"));
58+
59+
return uniqueList;
60+
}
61+
62+
internal static (List<PluginMetadata>, List<PluginMetadata>) GetUniqueLatestPluginMetadata(List<PluginMetadata> allPluginMetadata)
63+
{
64+
var duplicate_list = new List<PluginMetadata>();
65+
var unique_list = new List<PluginMetadata>();
66+
67+
var duplicateGroups = allPluginMetadata.GroupBy(x => x.ID).Where(g => g.Count() > 1).Select(y => y).ToList();
68+
69+
foreach (var metadata in allPluginMetadata)
70+
{
71+
var duplicatesExist = false;
72+
foreach (var group in duplicateGroups)
73+
{
74+
if (metadata.ID == group.Key)
75+
{
76+
duplicatesExist = true;
77+
78+
// If metadata's version greater than each duplicate's version, CompareTo > 0
79+
var count = group.Where(x => metadata.Version.CompareTo(x.Version) > 0).Count();
80+
81+
// Only add if the meatadata's version is the highest of all duplicates in the group
82+
if (count == group.Count() - 1)
83+
{
84+
unique_list.Add(metadata);
85+
}
86+
else
87+
{
88+
duplicate_list.Add(metadata);
89+
}
90+
}
91+
}
92+
93+
if (!duplicatesExist)
94+
unique_list.Add(metadata);
95+
}
96+
97+
return (unique_list, duplicate_list);
5098
}
5199

52100
private static PluginMetadata GetPluginMetadata(string pluginDirectory)

Flow.Launcher.Test/PluginLoadTest.cs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
using NUnit.Framework;
2+
using Flow.Launcher.Core.Plugin;
3+
using Flow.Launcher.Plugin;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
7+
namespace Flow.Launcher.Test
8+
{
9+
[TestFixture]
10+
class PluginLoadTest
11+
{
12+
[Test]
13+
public void GivenDuplicatePluginMetadatasWhenLoadedThenShouldReturnOnlyUniqueList()
14+
{
15+
// Given
16+
var duplicateList = new List<PluginMetadata>
17+
{
18+
new PluginMetadata
19+
{
20+
ID = "CEA0TYUC6D3B4085823D60DC76F28855",
21+
Version = "1.0.0"
22+
},
23+
new PluginMetadata
24+
{
25+
ID = "CEA0TYUC6D3B4085823D60DC76F28855",
26+
Version = "1.0.1"
27+
},
28+
new PluginMetadata
29+
{
30+
ID = "CEA0TYUC6D3B4085823D60DC76F28855",
31+
Version = "1.0.2"
32+
},
33+
new PluginMetadata
34+
{
35+
ID = "CEA0TYUC6D3B4085823D60DC76F28855",
36+
Version = "1.0.0"
37+
},
38+
new PluginMetadata
39+
{
40+
ID = "CEA0TYUC6D3B4085823D60DC76F28855",
41+
Version = "1.0.0"
42+
},
43+
new PluginMetadata
44+
{
45+
ID = "ABC0TYUC6D3B7855823D60DC76F28855",
46+
Version = "1.0.0"
47+
},
48+
new PluginMetadata
49+
{
50+
ID = "ABC0TYUC6D3B7855823D60DC76F28855",
51+
Version = "1.0.0"
52+
}
53+
};
54+
55+
// When
56+
(var unique, var duplicates) = PluginConfig.GetUniqueLatestPluginMetadata(duplicateList);
57+
58+
// Then
59+
Assert.True(unique.FirstOrDefault().ID == "CEA0TYUC6D3B4085823D60DC76F28855" && unique.FirstOrDefault().Version == "1.0.2");
60+
Assert.True(unique.Count() == 1);
61+
62+
Assert.False(duplicates.Any(x => x.Version == "1.0.2" && x.ID == "CEA0TYUC6D3B4085823D60DC76F28855"));
63+
Assert.True(duplicates.Count() == 6);
64+
}
65+
66+
[Test]
67+
public void GivenDuplicatePluginMetadatasWithNoUniquePluginWhenLoadedThenShouldReturnEmptyList()
68+
{
69+
// Given
70+
var duplicateList = new List<PluginMetadata>
71+
{
72+
new PluginMetadata
73+
{
74+
ID = "CEA0TYUC6D3B7855823D60DC76F28855",
75+
Version = "1.0.0"
76+
},
77+
new PluginMetadata
78+
{
79+
ID = "CEA0TYUC6D3B7855823D60DC76F28855",
80+
Version = "1.0.0"
81+
}
82+
};
83+
84+
// When
85+
(var unique, var duplicates) = PluginConfig.GetUniqueLatestPluginMetadata(duplicateList);
86+
87+
// Then
88+
Assert.True(unique.Count() == 0);
89+
Assert.True(duplicates.Count() == 2);
90+
}
91+
}
92+
}

Flow.Launcher.Test/Plugins/PluginInitTest.cs

Lines changed: 0 additions & 17 deletions
This file was deleted.

Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@
44

55
<!--Dialogues-->
66
<system:String x:Key="plugin_pluginsmanager_downloading_plugin">Downloading plugin</system:String>
7-
<system:String x:Key="plugin_pluginsmanager_please_wait">Please wait...</system:String>
87
<system:String x:Key="plugin_pluginsmanager_download_success">Successfully downloaded</system:String>
8+
<system:String x:Key="plugin_pluginsmanager_download_error">Error: Unable to download the plugin</system:String>
99
<system:String x:Key="plugin_pluginsmanager_uninstall_prompt">{0} by {1} {2}{3}Would you like to uninstall this plugin? After the uninstallation Flow will automatically restart.</system:String>
1010
<system:String x:Key="plugin_pluginsmanager_install_prompt">{0} by {1} {2}{3}Would you like to install this plugin? After the installation Flow will automatically restart.</system:String>
1111
<system:String x:Key="plugin_pluginsmanager_install_title">Plugin Install</system:String>
12+
<system:String x:Key="plugin_pluginsmanager_install_from_web">Download and install {0}</system:String>
1213
<system:String x:Key="plugin_pluginsmanager_uninstall_title">Plugin Uninstall</system:String>
13-
<system:String x:Key="plugin_pluginsmanager_install_errormetadatafile">Install failed: unable to find the plugin.json metadata file from the new plugin</system:String>
14+
<system:String x:Key="plugin_pluginsmanager_install_success_restart">Plugin successfully installed. Restarting Flow, please wait...</system:String>
15+
<system:String x:Key="plugin_pluginsmanager_install_errormetadatafile">Unable to find the plugin.json metadata file from the extracted zip file.</system:String>
16+
<system:String x:Key="plugin_pluginsmanager_install_error_duplicate">Error: A plugin which has the same or greater version with {0} already exists.</system:String>
1417
<system:String x:Key="plugin_pluginsmanager_install_error_title">Error installing plugin</system:String>
1518
<system:String x:Key="plugin_pluginsmanager_install_error_subtitle">Error occured while trying to install {0}</system:String>
1619
<system:String x:Key="plugin_pluginsmanager_update_noresult_title">No update available</system:String>
@@ -21,12 +24,15 @@
2124
<system:String x:Key="plugin_pluginsmanager_update_alreadyexists">This plugin is already installed</system:String>
2225
<system:String x:Key="plugin_pluginsmanager_update_failed_title">Plugin Manifest Download Failed</system:String>
2326
<system:String x:Key="plugin_pluginsmanager_update_failed_subtitle">Please check if you can connect to github.com. This error means you may not be able to install or update plugins.</system:String>
24-
27+
<system:String x:Key="plugin_pluginsmanager_install_unknown_source_warning_title">Installing from an unknown source</system:String>
28+
<system:String x:Key="plugin_pluginsmanager_install_unknown_source_warning">You are installing this plugin from an unknown source and it may contain potential risks!{0}{0}Please ensure you understand where this plugin is from and that it is safe.{0}{0}Would you like to continue still?{0}{0}(You can switch off this warning via settings)</system:String>
29+
2530
<!--Controls-->
2631

2732
<!--Plugin Infos-->
2833
<system:String x:Key="plugin_pluginsmanager_plugin_name">Plugins Manager</system:String>
2934
<system:String x:Key="plugin_pluginsmanager_plugin_description">Management of installing, uninstalling or updating Flow Launcher plugins</system:String>
35+
<system:String x:Key="plugin_pluginsmanager_unknown_author">Unknown Author</system:String>
3036

3137
<!--Context menu items-->
3238
<system:String x:Key="plugin_pluginsmanager_plugin_contextmenu_openwebsite_title">Open website</system:String>
@@ -36,6 +42,8 @@
3642
<system:String x:Key="plugin_pluginsmanager_plugin_contextmenu_newissue_title">Suggest an enhancement or submit an issue</system:String>
3743
<system:String x:Key="plugin_pluginsmanager_plugin_contextmenu_newissue_subtitle">Suggest an enhancement or submit an issue to the plugin developer</system:String>
3844
<system:String x:Key="plugin_pluginsmanager_plugin_contextmenu_pluginsmanifest_title">Go to Flow's plugins repository</system:String>
39-
<system:String x:Key="plugin_pluginsmanager_plugin_contextmenu_pluginsmanifest_subtitle">Visit the PluginsManifest repository to see comunity-made plugin submissions</system:String>
40-
45+
<system:String x:Key="plugin_pluginsmanager_plugin_contextmenu_pluginsmanifest_subtitle">Visit the PluginsManifest repository to see community-made plugin submissions</system:String>
46+
47+
<!--Settings menu items-->
48+
<system:String x:Key="plugin_pluginsmanager_plugin_settings_unknown_source">Install from unknown source warning</system:String>
4149
</ResourceDictionary>

Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/sk.xaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
<!--Dialogues-->
66
<system:String x:Key="plugin_pluginsmanager_downloading_plugin">Sťahovanie pluginu</system:String>
7-
<system:String x:Key="plugin_pluginsmanager_please_wait">Čakajte, prosím…</system:String>
87
<system:String x:Key="plugin_pluginsmanager_download_success">Úspešne stiahnuté</system:String>
98
<system:String x:Key="plugin_pluginsmanager_uninstall_prompt">{0} od {1} {2}{3}Chcete odinštalovať tento plugin? Po odinštalovaní sa Flow automaticky reštartuje.</system:String>
109
<system:String x:Key="plugin_pluginsmanager_install_prompt">{0} by {1} {2}{3}Chcete nainštalovať tento plugin? Po nainštalovaní sa Flow automaticky reštartuje.</system:String>

Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-cn.xaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
<!--Dialogues-->
66
<system:String x:Key="plugin_pluginsmanager_downloading_plugin">下载插件</system:String>
7-
<system:String x:Key="plugin_pluginsmanager_please_wait">请稍等...</system:String>
87
<system:String x:Key="plugin_pluginsmanager_download_success">下载完成</system:String>
98
<system:String x:Key="plugin_pluginsmanager_uninstall_prompt">{0} by {1} {2}{3} 您要卸载此插件吗? 卸载后,Flow Launcher 将自动重启。</system:String>
109
<system:String x:Key="plugin_pluginsmanager_install_prompt">{0} by {1} {2}{3} 您要安装此插件吗? 安装后,Flow Launcher 将自动重启</system:String>

Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public List<Result> LoadContextMenus(Result selectedResult)
5555

5656
public async Task<List<Result>> QueryAsync(Query query, CancellationToken token)
5757
{
58-
var search = query.Search.ToLower();
58+
var search = query.Search;
5959

6060
if (string.IsNullOrWhiteSpace(search))
6161
return pluginManager.GetDefaultHotKeys();
@@ -70,9 +70,13 @@ public async Task<List<Result>> QueryAsync(Query query, CancellationToken token)
7070

7171
return search switch
7272
{
73-
var s when s.StartsWith(Settings.HotKeyInstall) => await pluginManager.RequestInstallOrUpdate(s, token),
74-
var s when s.StartsWith(Settings.HotkeyUninstall) => pluginManager.RequestUninstall(s),
75-
var s when s.StartsWith(Settings.HotkeyUpdate) => await pluginManager.RequestUpdate(s, token),
73+
//search could be url, no need ToLower() when passed in
74+
var s when s.StartsWith(Settings.HotKeyInstall, StringComparison.OrdinalIgnoreCase)
75+
=> await pluginManager.RequestInstallOrUpdate(search, token),
76+
var s when s.StartsWith(Settings.HotkeyUninstall, StringComparison.OrdinalIgnoreCase)
77+
=> pluginManager.RequestUninstall(search),
78+
var s when s.StartsWith(Settings.HotkeyUpdate, StringComparison.OrdinalIgnoreCase)
79+
=> await pluginManager.RequestUpdate(search, token),
7680
_ => pluginManager.GetDefaultHotKeys().Where(hotkey =>
7781
{
7882
hotkey.Score = StringMatcher.FuzzySearch(search, hotkey.Title).Score;

0 commit comments

Comments
 (0)