├── .editorconfig
├── .github
└── FUNDING.yml
├── .gitignore
├── Directory.Build.props
├── Directory.Build.targets
├── Directory.Packages.props
├── GitExtensions.PluginManager.sln
├── GitExtensions.settings
├── LICENSE.md
├── README.md
├── appveyor.yml
├── assets
└── screenshot-search.png
├── data
└── NuGetFeed
│ ├── CustomPackage.5.0.0.nupkg
│ ├── GitExtensions.Extensibility.0.1.0.nupkg
│ ├── GitExtensions.Extensibility.0.2.0.nupkg
│ ├── PluginA.1.0.0.nupkg
│ ├── PluginA.1.1.0.nupkg
│ ├── PluginB.1.0.0.nupkg
│ ├── PluginB.2.0.0.nupkg
│ └── PluginC.1.0.0.nupkg
├── src
├── GitExtensions.PluginManager
│ ├── ArgsFix.cs
│ ├── GitExtensions.PluginManager.csproj
│ ├── GitExtensions.PluginManager.csproj.user
│ ├── GitExtensions.PluginManager.nuspec
│ ├── Plugin.cs
│ ├── PluginSettings.cs
│ ├── Project.Publish.targets
│ ├── Properties
│ │ ├── Resources.Designer.cs
│ │ ├── Resources.resx
│ │ └── launchSettings.json
│ └── Resources
│ │ └── box-search-result.png
├── PackageManager.Cli
│ ├── AllPackageSourceSelector.cs
│ ├── Args.cs
│ ├── PackageManager.Cli.csproj
│ ├── Program.cs
│ ├── SelfUpdateService.IApplication.cs
│ └── SelfUpdateService.IArgs.cs
├── PackageManager.NuGet
│ ├── Logging
│ │ └── NuGetLogger.cs
│ ├── Models
│ │ ├── InvalidPackageSourceImplementationException.cs
│ │ ├── NuGetInstalledPackage.cs
│ │ ├── NuGetPackage.cs
│ │ ├── NuGetPackageContent.AnyFrameworkFilter.cs
│ │ ├── NuGetPackageContent.IFrameworkFilter.cs
│ │ ├── NuGetPackageContent.cs
│ │ ├── NuGetPackageIdentity.cs
│ │ ├── NuGetPackageSource.cs
│ │ ├── NuGetPackageSourceBuilder.cs
│ │ ├── NuGetPackageSourceCollection.cs
│ │ └── NuGetPackageVersionComparer.cs
│ ├── PackageManager.NuGet.csproj
│ └── Services
│ │ ├── EmptyNuGetSearchTermTransformer.cs
│ │ ├── INuGetPackageFilter.cs
│ │ ├── INuGetSearchTermTransformer.cs
│ │ ├── NuGetInstallService.cs
│ │ ├── NuGetPackageContentService.cs
│ │ ├── NuGetPackageFilterResult.cs
│ │ ├── NuGetPackageVersionService.cs
│ │ ├── NuGetSearchService.cs
│ │ ├── NuGetSearchTerm.cs
│ │ ├── NuGetSourceRepositoryFactory.cs
│ │ └── OkNuGetPackageFilter.cs
├── PackageManager.UI
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── Args.Partial.cs
│ ├── Args.cs
│ ├── Exceptions
│ │ ├── MessageExceptionHandler.cs
│ │ ├── NuGetFatalProtocolExceptionHandler.cs
│ │ ├── PackageInstallExceptionHandler.cs
│ │ ├── RestartAsAdministratorCancelledExceptionHandler.cs
│ │ ├── ShutdownExceptionHandler.cs
│ │ └── UnauthorizedExceptionHandler.cs
│ ├── Logging
│ │ └── Serialization
│ │ │ └── MemoryLogSerializer.cs
│ ├── Models
│ │ ├── NuGetFrameworkFilter.cs
│ │ └── SelfPackage.cs
│ ├── PackageManager.UI.csproj
│ ├── Program.cs
│ ├── Properties
│ │ ├── Resources.Designer.cs
│ │ ├── Resources.resx
│ │ ├── Settings.Designer.cs
│ │ ├── Settings.settings
│ │ └── VersionInfo.cs
│ ├── Services
│ │ ├── DependencyNuGetPackageFilter.cs
│ │ ├── Navigator.cs
│ │ ├── ProcessService.IApplication.cs
│ │ ├── ProcessService.ProcessKillContext.cs
│ │ ├── ProcessService.cs
│ │ ├── RestartAsAdministratorCancelledException.cs
│ │ ├── SelfUpdateService.IApplication.cs
│ │ ├── SelfUpdateService.IArgs.cs
│ │ ├── SelfUpdateService.cs
│ │ └── TagsNuGetSearchTermTransformer.cs
│ └── Views
│ │ ├── Assets
│ │ ├── baseline_add_black_18dp.png
│ │ ├── baseline_arrow_downward_black_18dp.png
│ │ ├── baseline_arrow_upward_black_18dp.png
│ │ ├── baseline_chevron_left_black_18dp.png
│ │ ├── baseline_chevron_right_black_18dp.png
│ │ ├── baseline_clear_black_18dp.png
│ │ ├── baseline_done_black_18dp.png
│ │ ├── baseline_edit_black_18dp.png
│ │ ├── baseline_refresh_black_18dp.png
│ │ ├── baseline_search_black_18dp.png
│ │ ├── box-search-result.ico
│ │ ├── box-search-result.png
│ │ ├── default-package-icon.png
│ │ └── settings.png
│ │ ├── Browser.xaml
│ │ ├── Browser.xaml.cs
│ │ ├── Controls
│ │ ├── Button.cs
│ │ ├── CompatibilityLabel.cs
│ │ └── TabControl.cs
│ │ ├── Converters
│ │ ├── BoolConverter.cs
│ │ ├── CuttingConverter.cs
│ │ ├── DropNewLineConverter.cs
│ │ ├── FirstNotNullMultiConverter.cs
│ │ ├── FormatConverter.cs
│ │ ├── NullConverter.cs
│ │ ├── NullValueConverter.cs
│ │ ├── SelfPackageConverter.cs
│ │ └── ValidUrlToTrueConverter.cs
│ │ ├── DesignData
│ │ ├── MockInstallService.cs
│ │ ├── MockInstalledPackage.cs
│ │ ├── MockPackage.cs
│ │ ├── MockPackageSource.cs
│ │ ├── MockPackageSourceBuilder.cs
│ │ ├── MockPackageSourceCollection.cs
│ │ ├── MockPackageSourceProvider.cs
│ │ ├── MockSearchService.cs
│ │ ├── MockSelfUpdateService.cs
│ │ └── ViewModelLocator.cs
│ │ ├── IAutoFocus.cs
│ │ ├── Installed.xaml
│ │ ├── Installed.xaml.cs
│ │ ├── Loading.xaml
│ │ ├── Loading.xaml.cs
│ │ ├── LogWindow.xaml
│ │ ├── LogWindow.xaml.cs
│ │ ├── MainWindow.xaml
│ │ ├── MainWindow.xaml.cs
│ │ ├── PackageDetail.xaml
│ │ ├── PackageDetail.xaml.cs
│ │ ├── PackageName.xaml
│ │ ├── PackageName.xaml.cs
│ │ ├── PackageSourceWindow.xaml
│ │ ├── PackageSourceWindow.xaml.cs
│ │ ├── Updates.xaml
│ │ └── Updates.xaml.cs
└── PackageManager
│ ├── Models
│ ├── IInstalledPackage.cs
│ ├── IPackage.cs
│ ├── IPackageContent.cs
│ ├── IPackageIdentity.cs
│ ├── IPackageSource.cs
│ ├── IPackageSourceBuilder.cs
│ ├── IPackageSourceCollection.cs
│ ├── IPackageSourceProvider.cs
│ ├── PackageFileExtractionException.cs
│ ├── PackageFileRemovalException.cs
│ └── PackageIdentityExtensions.cs
│ ├── PackageManager.csproj
│ ├── Services
│ ├── IInstallService.cs
│ ├── ISearchService.cs
│ ├── ISelfUpdateService.cs
│ ├── SearchOptions.cs
│ └── SelfPackageConfiguration.cs
│ └── ViewModels
│ ├── BrowserViewModel.cs
│ ├── Commands
│ ├── CancelCommand.cs
│ ├── InstallCommand.cs
│ ├── MoveCommand.cs
│ ├── RefreshInstalledCommand.cs
│ ├── RefreshUpdatesCommand.cs
│ ├── ReinstallCommand.cs
│ ├── RemoveSourceCommand.cs
│ ├── SaveSourceCommand.cs
│ ├── SearchCommand.cs
│ ├── UninstallAllCommand.IViewModel.cs
│ ├── UninstallAllCommand.cs
│ ├── UninstallCommand.cs
│ ├── UpdateAllCommand.IViewModel.cs
│ ├── UpdateAllCommand.cs
│ └── UpdateCommand.cs
│ ├── IPackageOptions.cs
│ ├── IPackageSourceSelector.cs
│ ├── InstalledViewModel.cs
│ ├── MainViewModel.cs
│ ├── PackageSourceSelectorViewModel.cs
│ ├── PackageSourceViewModel.cs
│ ├── PackageUpdateViewModel.cs
│ ├── PackageViewModel.cs
│ ├── PagingViewModel.cs
│ └── UpdatesViewModel.cs
└── test
├── Directory.Build.props
├── Directory.Build.targets
├── PackageManager.NuGet.Tests
├── Models
│ ├── TestPackageContent.cs
│ └── TestPackageSourceCollection.cs
├── PackageManager.NuGet.Tests.csproj
└── Services
│ ├── InstallService.cs
│ ├── SearchService.cs
│ ├── TestInstallService.cs
│ └── TestPackageSearchService.cs
└── PackageManager.Tests
├── Arguments
└── TestArgs.cs
├── PackageManager.Tests.csproj
└── ViewModels
└── Commands
├── CallCounter.cs
├── InstallService.cs
├── InstalledPackage.cs
├── Package.cs
├── PackageOptions.cs
├── SelfUpdateService.cs
├── TestCommands.cs
├── UninstallAllCommandViewModel.cs
└── UpdateAllCommandViewModel.cs
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | open_collective: gitextensions
4 | custom: https://github.com/gitextensions/gitextensions/wiki
5 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0-windows
5 | latest
6 | $(NoWarn);1573;1591;1712
7 | true
8 | true
9 | win-x86
10 |
11 |
12 |
13 | Git Extensions
14 | Git Extensions
15 | https://github.com/gitextensions/gitextensions.pluginmanager
16 | latest
17 | 0.0.0
18 | 0.0.0.1
19 | 0.0.0.1
20 | 0.0.0.1
21 | 0.0.0.1
22 |
23 |
24 |
25 |
26 | $([MSBuild]::NormalizeDirectory('$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), 'appveyor.yml'))'))
27 |
28 | $([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'artifacts', '$(Configuration)'))
29 | $([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'obj'))
30 | $([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'bin'))
31 | $([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'TestResults'))
32 | $([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'tmp'))
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/Directory.Packages.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | true
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Git Extensions
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GitExtensions.PluginManager
2 | NuGet based plugin manager for Git Extensions
3 |
4 | 
5 |
6 | Repository with some example plugins - https://www.myget.org/F/neptuo-gitextensions/api/v2.
7 | Nightly builds of PluginManager available at Appveyor - https://ci.appveyor.com/nuget/gitextensions-pluginmanager.
8 |
9 | ### Appveyor
10 |
11 | [](https://ci.appveyor.com/project/gitextensions/gitextensions-pluginmanager)
12 |
13 | ### Browsing for packages
14 | PluginManager integrated into Git Extensions filters packages with dependency on `GitExtensions.Extensibility`. This package is right now a kind of meta package and it is used to mark nuget packages intended as Git Extensions plugins.
15 |
16 | We are heading to use the official nuget.org feed to distribute plugin packages, but there is a bug (#67) which prevents us from using it.
17 | Right now it is recommended to use https://www.myget.org/F/neptuo-gitextensions/api/v2.
18 |
19 | ### Command line arguments
20 | PluginManager is designed to be a reusable tool to manage plugins distributed as nuget packages. This repository contains an integration package for Git Extensins.
21 | As a standalone application, PluginManager supports these command line arguments:
22 |
23 | - `--path` (required) - A root path to a directory where to install packages.
24 | - `--selfpackageid` (optional) - A package id to indicate which package should be treated as a package for self update.
25 | - `--dependencies` (optional) - A comma separated list of package ids and versions that are required in package to be compatible (Eg. `GitExtensions.Extensibility-v3.0,TestA,TestB-v1`).
26 | - `--monikers` (optional) - A comma separated list of .NET framework monikers to filter package content during extraction (Eg. `net461,netstandard2.0`).
27 | - `--processnamestokillbeforechange` - A comma separated list of process names to be killed before any changes being processed (it is used to kill all instances on Git Extensions before installing/uninstalling dlls, that might be locked).
28 |
29 | ### Icons
30 |
31 | Some icons by Yusuke [Kamiyamane](http://p.yusukekamiyamane.com).
32 | Some other by [Material Design](https://material.io/tools/icons).
33 |
--------------------------------------------------------------------------------
/assets/screenshot-search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/assets/screenshot-search.png
--------------------------------------------------------------------------------
/data/NuGetFeed/CustomPackage.5.0.0.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/data/NuGetFeed/CustomPackage.5.0.0.nupkg
--------------------------------------------------------------------------------
/data/NuGetFeed/GitExtensions.Extensibility.0.1.0.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/data/NuGetFeed/GitExtensions.Extensibility.0.1.0.nupkg
--------------------------------------------------------------------------------
/data/NuGetFeed/GitExtensions.Extensibility.0.2.0.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/data/NuGetFeed/GitExtensions.Extensibility.0.2.0.nupkg
--------------------------------------------------------------------------------
/data/NuGetFeed/PluginA.1.0.0.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/data/NuGetFeed/PluginA.1.0.0.nupkg
--------------------------------------------------------------------------------
/data/NuGetFeed/PluginA.1.1.0.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/data/NuGetFeed/PluginA.1.1.0.nupkg
--------------------------------------------------------------------------------
/data/NuGetFeed/PluginB.1.0.0.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/data/NuGetFeed/PluginB.1.0.0.nupkg
--------------------------------------------------------------------------------
/data/NuGetFeed/PluginB.2.0.0.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/data/NuGetFeed/PluginB.2.0.0.nupkg
--------------------------------------------------------------------------------
/data/NuGetFeed/PluginC.1.0.0.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/data/NuGetFeed/PluginC.1.0.0.nupkg
--------------------------------------------------------------------------------
/src/GitExtensions.PluginManager/ArgsFix.cs:
--------------------------------------------------------------------------------
1 | namespace Neptuo
2 | {
3 | public interface ICloneable
4 | {
5 | T Clone();
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/GitExtensions.PluginManager/GitExtensions.PluginManager.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | true
6 | true
7 | NuGet-based Plugin Manager for Git Extensions
8 | GitExtensions
9 | https://github.com/gitextensions/gitextensions.pluginmanager
10 | OnOutputUpdated
11 | $(MSBuildThisFileDirectory)$(MSBuildProjectName).nuspec
12 | 1701;1702;NU5100;NU5101;NU5103;NU5128
13 | false
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | $(GitExtensionsPath)\GitExtensions.Extensibility.dll
29 |
30 |
31 | $(GitExtensionsPath)\GitUIPluginInterfaces.dll
32 |
33 |
34 |
35 |
36 |
38 |
39 |
40 |
41 |
42 | True
43 | True
44 | Resources.resx
45 |
46 |
47 | ResXFileCodeGenerator
48 | Resources.Designer.cs
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/src/GitExtensions.PluginManager/GitExtensions.PluginManager.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 | ..\..\..\gitextensions.shared
4 | latest
5 | AppVeyor
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/GitExtensions.PluginManager/GitExtensions.PluginManager.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $id$
5 | $version$
6 | $author$
7 | $description$
8 | $projectUrl$
9 | $tags$
10 | LICENSE.md
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/GitExtensions.PluginManager/PluginSettings.cs:
--------------------------------------------------------------------------------
1 | using GitExtensions.Extensibility.Settings;
2 | using System;
3 | using System.Collections;
4 | using System.Collections.Generic;
5 |
6 | namespace GitExtensions.PluginManager
7 | {
8 | internal class PluginSettings : IEnumerable
9 | {
10 | ///
11 | /// Gets a property holding if asking to close git extensions is required.
12 | ///
13 | public static BoolSetting CloseInstancesProperty { get; } = new BoolSetting("CloseInstances", "Close all instances of Git Extensions before starting Plugin Manager", false);
14 |
15 | private readonly SettingsSource source;
16 |
17 | ///
18 | /// Gets current value of .
19 | ///
20 | public bool CloseInstances => source.GetBool(CloseInstancesProperty.Name, CloseInstancesProperty.DefaultValue);
21 |
22 | public PluginSettings(SettingsSource source)
23 | {
24 | this.source = source ?? throw new ArgumentNullException(nameof(source));
25 | }
26 |
27 | #region IEnumerable
28 |
29 | private static readonly List properties;
30 |
31 | public static bool HasProperties => properties.Count > 0;
32 |
33 | static PluginSettings()
34 | {
35 | properties = new List(1)
36 | {
37 | CloseInstancesProperty
38 | };
39 | }
40 |
41 | public IEnumerator GetEnumerator()
42 | => properties.GetEnumerator();
43 |
44 | IEnumerator IEnumerable.GetEnumerator()
45 | => GetEnumerator();
46 |
47 | #endregion
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/GitExtensions.PluginManager/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace GitExtensions.PluginManager.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GitExtensions.PluginManager.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// Looks up a localized resource of type System.Drawing.Bitmap.
65 | ///
66 | internal static System.Drawing.Bitmap Icon {
67 | get {
68 | object obj = ResourceManager.GetObject("Icon", resourceCulture);
69 | return ((System.Drawing.Bitmap)(obj));
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/GitExtensions.PluginManager/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "GitExtensions.PluginManager": {
4 | "commandName": "Executable",
5 | "executablePath": "$(GitExtensionsExecutablePath)"
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/src/GitExtensions.PluginManager/Resources/box-search-result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/src/GitExtensions.PluginManager/Resources/box-search-result.png
--------------------------------------------------------------------------------
/src/PackageManager.Cli/AllPackageSourceSelector.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using PackageManager.Models;
3 | using PackageManager.ViewModels;
4 | using System.Collections.Generic;
5 |
6 | namespace PackageManager
7 | {
8 | public class AllPackageSourceSelector : IPackageSourceSelector
9 | {
10 | private readonly IPackageSourceProvider service;
11 |
12 | public IEnumerable Sources => service.All;
13 |
14 | public AllPackageSourceSelector(IPackageSourceProvider service)
15 | {
16 | Ensure.NotNull(service, "service");
17 | this.service = service;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/PackageManager.Cli/PackageManager.Cli.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | PackageManager
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/PackageManager.Cli/SelfUpdateService.IApplication.cs:
--------------------------------------------------------------------------------
1 | namespace PackageManager.Services
2 | {
3 | internal partial class SelfUpdateService
4 | {
5 | public interface IApplication
6 | {
7 | IArgs Args { get; }
8 | void Shutdown();
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/PackageManager.Cli/SelfUpdateService.IArgs.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 |
3 | namespace PackageManager.Services
4 | {
5 | internal partial class SelfUpdateService
6 | {
7 | public interface IArgs : ICloneable
8 | {
9 | string Path { get; }
10 |
11 | bool IsSelfUpdate { get; set; }
12 | string SelfOriginalPath { get; set; }
13 | string SelfUpdateVersion { get; set; }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/PackageManager.NuGet/Logging/NuGetLogger.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Logging;
3 | using NuGet.Common;
4 | using System.Threading.Tasks;
5 | using LogLevel = Neptuo.Logging.LogLevel;
6 | using NuGetLogLevel = NuGet.Common.LogLevel;
7 |
8 | namespace PackageManager.Logging
9 | {
10 | public class NuGetLogger : ILogger
11 | {
12 | private readonly ILog log;
13 |
14 | public NuGetLogger(ILog log)
15 | {
16 | Ensure.NotNull(log, "log");
17 | this.log = log;
18 | }
19 |
20 | private LogLevel MapLevel(NuGetLogLevel level)
21 | {
22 | switch (level)
23 | {
24 | case NuGetLogLevel.Debug:
25 | return LogLevel.Debug;
26 | case NuGetLogLevel.Verbose:
27 | return LogLevel.Debug;
28 | case NuGetLogLevel.Information:
29 | return LogLevel.Info;
30 | case NuGetLogLevel.Minimal:
31 | return LogLevel.Info;
32 | case NuGetLogLevel.Warning:
33 | return LogLevel.Warning;
34 | case NuGetLogLevel.Error:
35 | return LogLevel.Error;
36 | default:
37 | throw Ensure.Exception.NotSupported(level);
38 | }
39 | }
40 |
41 | public void Log(NuGetLogLevel level, string data)
42 | {
43 | log.Log(MapLevel(level), data);
44 | }
45 |
46 | public void Log(ILogMessage message)
47 | {
48 | log.Log(MapLevel(message.Level), message.Message);
49 | }
50 |
51 | public Task LogAsync(NuGetLogLevel level, string data)
52 | {
53 | Log(level, data);
54 | return Task.CompletedTask;
55 | }
56 |
57 | public Task LogAsync(ILogMessage message)
58 | {
59 | Log(message);
60 | return Task.CompletedTask;
61 | }
62 |
63 | public void LogDebug(string data) => Log(NuGetLogLevel.Debug, data);
64 | public void LogError(string data) => Log(NuGetLogLevel.Error, data);
65 | public void LogInformation(string data) => Log(NuGetLogLevel.Information, data);
66 | public void LogInformationSummary(string data) => Log(NuGetLogLevel.Information, data);
67 | public void LogMinimal(string data) => Log(NuGetLogLevel.Minimal, data);
68 | public void LogVerbose(string data) => Log(NuGetLogLevel.Verbose, data);
69 | public void LogWarning(string data) => Log(NuGetLogLevel.Warning, data);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/PackageManager.NuGet/Models/InvalidPackageSourceImplementationException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace PackageManager.Models
4 | {
5 | ///
6 | /// Raised when passed implementation of to not compatible with ,
7 | ///
8 | public class InvalidPackageSourceImplementationException : Exception
9 | {
10 | ///
11 | /// Creates a new empty instance.
12 | ///
13 | public InvalidPackageSourceImplementationException()
14 | { }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/PackageManager.NuGet/Models/NuGetInstalledPackage.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 |
3 | namespace PackageManager.Models
4 | {
5 | public class NuGetInstalledPackage : IInstalledPackage
6 | {
7 | public IPackage Definition { get; }
8 | public bool IsCompatible { get; }
9 |
10 | public NuGetInstalledPackage(IPackage definition, bool isCompatible)
11 | {
12 | Ensure.NotNull(definition, "definition");
13 | Definition = definition;
14 | IsCompatible = isCompatible;
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/PackageManager.NuGet/Models/NuGetPackage.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using NuGet.Protocol.Core.Types;
3 | using PackageManager.Services;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 |
9 | namespace PackageManager.Models
10 | {
11 | public class NuGetPackage : NuGetPackageIdentity, IPackage
12 | {
13 | private readonly IPackageSearchMetadata source;
14 | private readonly SourceRepository repository;
15 | private readonly NuGetPackageContentService contentService;
16 | private readonly NuGetPackageVersionService versionService;
17 |
18 | public string Description => source.Description;
19 |
20 | public string Authors => source.Authors;
21 | public DateTime? Published => source.Published?.DateTime;
22 | public string Tags => source.Tags;
23 |
24 | public Uri IconUrl => source.IconUrl;
25 | public Uri ProjectUrl => source.ProjectUrl;
26 | public Uri LicenseUrl => source.LicenseUrl;
27 |
28 | public NuGetPackage(IPackageSearchMetadata source, SourceRepository repository, NuGetPackageContentService contentService, NuGetPackageVersionService versionService)
29 | : base(source?.Identity)
30 | {
31 | Ensure.NotNull(source, "source");
32 | Ensure.NotNull(repository, "repository");
33 | Ensure.NotNull(contentService, "contentService");
34 | Ensure.NotNull(versionService, "versionService");
35 | this.source = source;
36 | this.repository = repository;
37 | this.contentService = contentService;
38 | this.versionService = versionService;
39 | }
40 |
41 | public async Task GetContentAsync(CancellationToken cancellationToken)
42 | => await contentService.DownloadAsync(repository, source, cancellationToken);
43 |
44 | public async Task> GetVersionsAsync(bool isPrereleaseIncluded, CancellationToken cancellationToken)
45 | => await versionService.GetListAsync(int.MaxValue, source, repository, isPrereleaseIncluded: isPrereleaseIncluded, cancellationToken: cancellationToken);
46 |
47 | public bool Equals(IPackage other)
48 | => Equals((IPackageIdentity)other);
49 |
50 | public override bool Equals(object obj)
51 | {
52 | if (obj is IPackage other)
53 | return Equals(other);
54 |
55 | return false;
56 | }
57 |
58 | public override int GetHashCode()
59 | {
60 | int hash = 17 * 2;
61 | hash += 5 * Id.GetHashCode();
62 | hash += 5 * Version.GetHashCode();
63 | return hash;
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/PackageManager.NuGet/Models/NuGetPackageContent.AnyFrameworkFilter.cs:
--------------------------------------------------------------------------------
1 | using NuGet.Packaging;
2 |
3 | namespace PackageManager.Models
4 | {
5 | partial class NuGetPackageContent
6 | {
7 | public class AnyFrameworkFilter : IFrameworkFilter
8 | {
9 | public bool IsPassed(FrameworkSpecificGroup group)
10 | => group.TargetFramework.IsAny;
11 |
12 | private static AnyFrameworkFilter instance;
13 | private static object instanceLock = new object();
14 |
15 | public static AnyFrameworkFilter Instance
16 | {
17 | get
18 | {
19 | if (instance == null)
20 | {
21 | lock (instanceLock)
22 | {
23 | if (instance == null)
24 | instance = new AnyFrameworkFilter();
25 | }
26 | }
27 |
28 | return instance;
29 | }
30 | }
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/PackageManager.NuGet/Models/NuGetPackageContent.IFrameworkFilter.cs:
--------------------------------------------------------------------------------
1 | using NuGet.Packaging;
2 |
3 | namespace PackageManager.Models
4 | {
5 | partial class NuGetPackageContent
6 | {
7 | public interface IFrameworkFilter
8 | {
9 | bool IsPassed(FrameworkSpecificGroup group);
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/PackageManager.NuGet/Models/NuGetPackageIdentity.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using NuGet.Packaging.Core;
3 | using System;
4 |
5 | namespace PackageManager.Models
6 | {
7 | public class NuGetPackageIdentity : IPackageIdentity
8 | {
9 | private readonly PackageIdentity identity;
10 |
11 | public string Id => identity.Id;
12 | public string Version => identity.Version.ToFullString();
13 |
14 | public NuGetPackageIdentity(PackageIdentity identity)
15 | {
16 | Ensure.NotNull(identity, "identity");
17 | this.identity = identity;
18 | }
19 |
20 | public bool Equals(IPackageIdentity other)
21 | {
22 | if (other == null)
23 | return false;
24 |
25 | return string.Equals(Id, other.Id, StringComparison.CurrentCultureIgnoreCase) && string.Equals(Version, other.Version, StringComparison.CurrentCultureIgnoreCase);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/PackageManager.NuGet/Models/NuGetPackageSource.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using NuGet.Configuration;
3 | using System;
4 |
5 | namespace PackageManager.Models
6 | {
7 | public class NuGetPackageSource : IPackageSource
8 | {
9 | internal PackageSource Original { get; }
10 |
11 | public string Name => Original.Name;
12 | public Uri Uri => Original.SourceUri;
13 |
14 | public NuGetPackageSource(PackageSource source)
15 | {
16 | Ensure.NotNull(source, "source");
17 | Original = source;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/PackageManager.NuGet/Models/NuGetPackageSourceBuilder.cs:
--------------------------------------------------------------------------------
1 | using NuGet.Configuration;
2 | using System;
3 |
4 | namespace PackageManager.Models
5 | {
6 | public class NuGetPackageSourceBuilder : IPackageSourceBuilder
7 | {
8 | private readonly NuGetPackageSourceCollection service;
9 | private readonly NuGetPackageSource edit;
10 |
11 | private string name;
12 | private Uri uri;
13 |
14 | internal NuGetPackageSourceBuilder(NuGetPackageSourceCollection service)
15 | {
16 | this.service = service;
17 | }
18 |
19 | internal NuGetPackageSourceBuilder(NuGetPackageSourceCollection service, NuGetPackageSource edit)
20 | {
21 | this.service = service;
22 | this.edit = edit;
23 | this.name = edit.Name;
24 | this.uri = edit.Uri;
25 | }
26 |
27 | public IPackageSourceBuilder Name(string name)
28 | {
29 | this.name = name;
30 | return this;
31 | }
32 |
33 | public IPackageSourceBuilder Uri(Uri uri)
34 | {
35 | this.uri = uri;
36 | return this;
37 | }
38 |
39 | public IPackageSource Save()
40 | {
41 | if (edit == null)
42 | {
43 | var source = new NuGetPackageSource(new PackageSource(uri.ToString(), name));
44 | service.Sources.Add(source);
45 | service.SavePackageSources();
46 | return source;
47 | }
48 | else if(edit.Name == name)
49 | {
50 | edit.Original.Source = uri.ToString();
51 | service.SavePackageSources();
52 | return edit;
53 | }
54 | else
55 | {
56 | int index = service.Sources.IndexOf(edit);
57 | service.Sources.Remove(edit);
58 |
59 | var source = new NuGetPackageSource(new PackageSource(uri.ToString(), name));
60 | service.Sources.Insert(index, source);
61 | service.SavePackageSources();
62 | return source;
63 | }
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/PackageManager.NuGet/Models/NuGetPackageVersionComparer.cs:
--------------------------------------------------------------------------------
1 | using NuGet.Versioning;
2 | using System.Collections.Generic;
3 |
4 | namespace PackageManager.Models
5 | {
6 | public class NuGetPackageVersionComparer : IComparer
7 | {
8 | public static readonly NuGetPackageVersionComparer Instance = new NuGetPackageVersionComparer();
9 |
10 | public int Compare(IPackageIdentity x, IPackageIdentity y)
11 | {
12 | NuGetVersion xVersion = new NuGetVersion(x.Version);
13 | NuGetVersion yVersion = new NuGetVersion(y.Version);
14 | return xVersion.CompareTo(yVersion);
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/PackageManager.NuGet/PackageManager.NuGet.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | PackageManager
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/PackageManager.NuGet/Services/EmptyNuGetSearchTermTransformer.cs:
--------------------------------------------------------------------------------
1 | namespace PackageManager.Services
2 | {
3 | public class EmptyNuGetSearchTermTransformer : INuGetSearchTermTransformer
4 | {
5 | public void Transform(NuGetSearchTerm searchTerm)
6 | {
7 | }
8 |
9 | public readonly static EmptyNuGetSearchTermTransformer Instance = new EmptyNuGetSearchTermTransformer();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/PackageManager.NuGet/Services/INuGetPackageFilter.cs:
--------------------------------------------------------------------------------
1 | using NuGet.Protocol.Core.Types;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 |
5 | namespace PackageManager.Services
6 | {
7 | public interface INuGetPackageFilter
8 | {
9 | Task FilterAsync(SourceRepository repository, IPackageSearchMetadata package, CancellationToken cancellationToken);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/PackageManager.NuGet/Services/INuGetSearchTermTransformer.cs:
--------------------------------------------------------------------------------
1 | namespace PackageManager.Services
2 | {
3 | public interface INuGetSearchTermTransformer
4 | {
5 | void Transform(NuGetSearchTerm searchTerm);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/PackageManager.NuGet/Services/NuGetPackageContentService.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Logging;
3 | using NuGet.Common;
4 | using NuGet.Packaging;
5 | using NuGet.Protocol.Core.Types;
6 | using PackageManager.Logging;
7 | using PackageManager.Models;
8 | using System;
9 | using System.IO;
10 | using System.Threading;
11 | using System.Threading.Tasks;
12 |
13 | namespace PackageManager.Services
14 | {
15 | public class NuGetPackageContentService
16 | {
17 | private readonly ILog log;
18 | private readonly ILogger nuGetLog;
19 | private readonly NuGetPackageContent.IFrameworkFilter frameworkFilter;
20 |
21 | public NuGetPackageContentService(ILog log, NuGetPackageContent.IFrameworkFilter frameworkFilter = null)
22 | {
23 | Ensure.NotNull(log, "log");
24 | this.log = log.Factory.Scope("Package");
25 | this.nuGetLog = new NuGetLogger(this.log);
26 | this.frameworkFilter = frameworkFilter;
27 | }
28 |
29 | public async Task DownloadAsync(SourceRepository repository, IPackageSearchMetadata package, CancellationToken cancellationToken)
30 | {
31 | Ensure.NotNull(repository, "repository");
32 | Ensure.NotNull(package, "package");
33 |
34 | DownloadResource download = await repository.GetResourceAsync();
35 | if (download == null)
36 | throw Ensure.Exception.InvalidOperation($"Unnable to resolve '{nameof(DownloadResource)}'.");
37 |
38 | using (var sourceCacheContext = new SourceCacheContext())
39 | {
40 | var context = new PackageDownloadContext(sourceCacheContext, Path.GetTempPath(), true);
41 | var result = await download.GetDownloadResourceResultAsync(package.Identity, context, string.Empty, nuGetLog, cancellationToken);
42 | if (result.Status == DownloadResourceResultStatus.Cancelled)
43 | throw new OperationCanceledException();
44 | else if (result.Status == DownloadResourceResultStatus.NotFound)
45 | throw Ensure.Exception.InvalidOperation($"Package '{package.Identity.Id}-v{package.Identity.Version}' not found");
46 |
47 | return new NuGetPackageContent(new PackageArchiveReader(result.PackageStream), log, frameworkFilter);
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/PackageManager.NuGet/Services/NuGetPackageFilterResult.cs:
--------------------------------------------------------------------------------
1 | namespace PackageManager.Services
2 | {
3 | public enum NuGetPackageFilterResult
4 | {
5 | Ok,
6 | NotCompatible,
7 | NotCompatibleVersion
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/PackageManager.NuGet/Services/NuGetSourceRepositoryFactory.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Activators;
3 | using NuGet.Protocol.Core.Types;
4 | using PackageManager.Models;
5 |
6 | namespace PackageManager.Services
7 | {
8 | public class NuGetSourceRepositoryFactory : IFactory
9 | {
10 | public SourceRepository Create(IPackageSource packageSource)
11 | {
12 | Ensure.NotNull(packageSource, "packageSource");
13 |
14 | if (packageSource is NuGetPackageSource nuget)
15 | return Repository.CreateSource(Repository.Provider.GetCoreV3(), nuget.Original);
16 |
17 | return Repository.CreateSource(Repository.Provider.GetCoreV3(), packageSource.Uri.ToString());
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/PackageManager.NuGet/Services/OkNuGetPackageFilter.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 | using NuGet.Protocol.Core.Types;
4 |
5 | namespace PackageManager.Services
6 | {
7 | public class OkNuGetPackageFilter : INuGetPackageFilter
8 | {
9 | public Task FilterAsync(SourceRepository repository, IPackageSearchMetadata package, CancellationToken cancellationToken)
10 | => Task.FromResult(NuGetPackageFilterResult.Ok);
11 |
12 | public readonly static OkNuGetPackageFilter Instance = new OkNuGetPackageFilter();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Args.Partial.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using PackageManager.Services;
3 |
4 | namespace PackageManager
5 | {
6 | partial class Args : SelfUpdateService.IArgs, ICloneable
7 | {
8 | SelfUpdateService.IArgs ICloneable.Clone()
9 | => Clone();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Exceptions/MessageExceptionHandler.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Exceptions.Handlers;
3 | using PackageManager.Services;
4 | using System;
5 | using System.Text;
6 |
7 | namespace PackageManager.Exceptions
8 | {
9 | internal class MessageExceptionHandler : IExceptionHandler>
10 | {
11 | private readonly Navigator navigator;
12 |
13 | public MessageExceptionHandler(Navigator navigator)
14 | {
15 | Ensure.NotNull(navigator, "navigator");
16 | this.navigator = navigator;
17 | }
18 |
19 | public void Handle(IExceptionHandlerContext context)
20 | {
21 | StringBuilder message = new StringBuilder();
22 |
23 | string exceptionMessage = context.Exception.ToString();
24 | if (exceptionMessage.Length > 800)
25 | exceptionMessage = exceptionMessage.Substring(0, 800);
26 |
27 | message.AppendLine(exceptionMessage);
28 |
29 | bool result = navigator.Confirm("Unhandled exception - Do you want to kill the aplication?", message.ToString(), Navigator.MessageType.Error);
30 | if (!result)
31 | context.IsHandled = true;
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Exceptions/NuGetFatalProtocolExceptionHandler.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Exceptions.Handlers;
3 | using NuGet.Protocol.Core.Types;
4 | using PackageManager.Services;
5 | using System.Net;
6 | using System.Net.Http;
7 |
8 | namespace PackageManager.Exceptions
9 | {
10 | internal class NuGetFatalProtocolExceptionHandler : IExceptionHandler>
11 | {
12 | private readonly Navigator navigator;
13 |
14 | public NuGetFatalProtocolExceptionHandler(Navigator navigator)
15 | {
16 | Ensure.NotNull(navigator, "navigator");
17 | this.navigator = navigator;
18 | }
19 |
20 | void IExceptionHandler>.Handle(IExceptionHandlerContext context)
21 | {
22 | if (context.Exception.InnerException is HttpRequestException && context.Exception.InnerException.InnerException is WebException webException)
23 | {
24 | navigator.Notify("Communcation Error", GetMessage(webException), Navigator.MessageType.Error);
25 | context.IsHandled = true;
26 | }
27 | }
28 |
29 | private string GetMessage(WebException exception)
30 | {
31 | switch (exception.Status)
32 | {
33 | case WebExceptionStatus.NameResolutionFailure:
34 | return "Error resolving the host name.";
35 | case WebExceptionStatus.ConnectFailure:
36 | return "Error opening the connection to the server.";
37 | case WebExceptionStatus.ReceiveFailure:
38 | return "Error receiving data over the connection.";
39 | case WebExceptionStatus.RequestCanceled:
40 | return "Request has been canceled.";
41 | case WebExceptionStatus.ConnectionClosed:
42 | return "The connection has been unexpectedly closed.";
43 | case WebExceptionStatus.Timeout:
44 | return "The connection has timed out.";
45 | case WebExceptionStatus.ProxyNameResolutionFailure:
46 | return "Error resolving proxy name.";
47 | case WebExceptionStatus.Success:
48 | case WebExceptionStatus.SendFailure:
49 | case WebExceptionStatus.PipelineFailure:
50 | case WebExceptionStatus.ProtocolError:
51 | case WebExceptionStatus.TrustFailure:
52 | case WebExceptionStatus.SecureChannelFailure:
53 | case WebExceptionStatus.ServerProtocolViolation:
54 | case WebExceptionStatus.KeepAliveFailure:
55 | case WebExceptionStatus.Pending:
56 | case WebExceptionStatus.UnknownError:
57 | case WebExceptionStatus.MessageLengthLimitExceeded:
58 | case WebExceptionStatus.CacheEntryNotFound:
59 | case WebExceptionStatus.RequestProhibitedByCachePolicy:
60 | case WebExceptionStatus.RequestProhibitedByProxy:
61 | default:
62 | return "An unknown error has occured while communicating over the wire.";
63 | }
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Exceptions/PackageInstallExceptionHandler.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Exceptions.Handlers;
3 | using PackageManager.Models;
4 | using PackageManager.Services;
5 |
6 | namespace PackageManager.Exceptions
7 | {
8 | internal class PackageInstallExceptionHandler :
9 | IExceptionHandler>,
10 | IExceptionHandler>
11 | {
12 | private readonly Navigator navigator;
13 |
14 | public PackageInstallExceptionHandler(Navigator navigator)
15 | {
16 | Ensure.NotNull(navigator, "navigator");
17 | this.navigator = navigator;
18 | }
19 |
20 | void IExceptionHandler>.Handle(IExceptionHandlerContext context)
21 | {
22 | navigator.Notify("Package Install Error", $"Error extracting file to '{context.Exception.FilePath}'", Navigator.MessageType.Error);
23 | context.IsHandled = true;
24 | }
25 |
26 | void IExceptionHandler>.Handle(IExceptionHandlerContext context)
27 | {
28 | navigator.Notify("Package Removal Error", $"Error deleting file '{context.Exception.FilePath}'", Navigator.MessageType.Error);
29 | context.IsHandled = true;
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Exceptions/RestartAsAdministratorCancelledExceptionHandler.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Exceptions.Handlers;
3 | using PackageManager.Services;
4 |
5 | namespace PackageManager.Exceptions
6 | {
7 | public class RestartAsAdministratorCancelledExceptionHandler : IExceptionHandler>
8 | {
9 | private readonly Navigator navigator;
10 | private readonly App application;
11 |
12 | internal RestartAsAdministratorCancelledExceptionHandler(Navigator navigator, App application)
13 | {
14 | Ensure.NotNull(navigator, "navigator");
15 | Ensure.NotNull(application, "application");
16 | this.navigator = navigator;
17 | this.application = application;
18 | }
19 |
20 | public void Handle(IExceptionHandlerContext context)
21 | {
22 | context.IsHandled = true;
23 |
24 | navigator.Notify("Unauthorized", "The operation requires elevated privilege which has not been given.", Navigator.MessageType.Error);
25 | application.Shutdown();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Exceptions/ShutdownExceptionHandler.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Exceptions.Handlers;
3 | using System;
4 |
5 | namespace PackageManager.Exceptions
6 | {
7 | internal class ShutdownExceptionHandler : IExceptionHandler
8 | {
9 | private readonly App application;
10 |
11 | public ShutdownExceptionHandler(App application)
12 | {
13 | Ensure.NotNull(application, "application");
14 | this.application = application;
15 | }
16 |
17 | void IExceptionHandler.Handle(Exception exception) => application.Shutdown();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Exceptions/UnauthorizedExceptionHandler.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Exceptions.Handlers;
3 | using NuGet.Configuration;
4 | using NuGet.Packaging;
5 | using PackageManager.Services;
6 | using System;
7 |
8 | namespace PackageManager.Exceptions
9 | {
10 | internal class UnauthorizedExceptionHandler :
11 | IExceptionHandler>,
12 | IExceptionHandler>,
13 | IExceptionHandler>
14 | {
15 | private readonly ProcessService processService;
16 |
17 | public UnauthorizedExceptionHandler(ProcessService processService)
18 | {
19 | Ensure.NotNull(processService, "processService");
20 | this.processService = processService;
21 | }
22 |
23 | private void HandleInternal(IExceptionHandlerContext context)
24 | where T : Exception
25 | {
26 | processService.RestartAsAdministrator();
27 | context.IsHandled = true;
28 | }
29 |
30 | void IExceptionHandler>.Handle(IExceptionHandlerContext context) => HandleInternal(context);
31 | void IExceptionHandler>.Handle(IExceptionHandlerContext context) => HandleInternal(context);
32 | void IExceptionHandler>.Handle(IExceptionHandlerContext context) => HandleInternal(context);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Logging/Serialization/MemoryLogSerializer.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using Neptuo;
3 | using Neptuo.Logging;
4 | using Neptuo.Logging.Serialization;
5 | using Neptuo.Logging.Serialization.Formatters;
6 |
7 | namespace PackageManager.Logging.Serialization
8 | {
9 | public class MemoryLogSerializer : ILogSerializer
10 | {
11 | private readonly StringBuilder content = new StringBuilder();
12 | private readonly ILogFormatter formatter;
13 |
14 | public MemoryLogSerializer(ILogFormatter formatter)
15 | {
16 | Ensure.NotNull(formatter, "formatter");
17 | this.formatter = formatter;
18 | }
19 |
20 | public string GetContent()
21 | => content.ToString();
22 |
23 | public void Clear()
24 | => content.Clear();
25 |
26 | public void Append(string scopeName, LogLevel level, object model)
27 | => content.AppendLine(formatter.Format(scopeName, level, model));
28 |
29 | public bool IsEnabled(string scopeName, LogLevel level)
30 | => true;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Models/NuGetFrameworkFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using NuGet.Frameworks;
5 | using NuGet.Packaging;
6 |
7 | namespace PackageManager.Models
8 | {
9 | internal class NuGetFrameworkFilter : NuGetPackageContent.IFrameworkFilter
10 | {
11 | private readonly IReadOnlyCollection collection;
12 |
13 | public NuGetFrameworkFilter(IReadOnlyCollection collection)
14 | => this.collection = collection;
15 |
16 | public bool IsPassed(FrameworkSpecificGroup group)
17 | => collection.Contains(group.TargetFramework);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Models/SelfPackage.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using System;
3 |
4 | namespace PackageManager.Models
5 | {
6 | internal class SelfPackage : IPackageIdentity
7 | {
8 | public string Id { get; }
9 | public string Version { get; }
10 |
11 | public SelfPackage(string id)
12 | {
13 | Ensure.NotNull(id, "id");
14 | Id = id;
15 | Version = VersionInfo.Version;
16 |
17 | int indexOfPlus = Version.IndexOf('+');
18 | if (indexOfPlus > 0)
19 | Version = Version.Substring(0, indexOfPlus);
20 | }
21 |
22 | public bool Equals(IPackageIdentity other)
23 | {
24 | if (other == null)
25 | return false;
26 |
27 | return string.Equals(Id, other.Id, StringComparison.CurrentCultureIgnoreCase) && string.Equals(Version, other.Version, StringComparison.CurrentCultureIgnoreCase);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/PackageManager.UI.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WinExe
5 | true
6 | PackageManager
7 | PackageManager.UI
8 | Views\Assets\box-search-result.ico
9 | PackageManager.Program
10 |
11 | true
12 | false
13 | $(PackageManagerUIRuntimeIdentifier)
14 | true
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | True
34 | True
35 | Resources.resx
36 |
37 |
38 | True
39 | True
40 | Settings.settings
41 |
42 |
43 |
44 |
45 |
46 | ResXFileCodeGenerator
47 | Resources.Designer.cs
48 |
49 |
50 |
51 |
52 |
53 | SettingsSingleFileGenerator
54 | Settings.Designer.cs
55 |
56 |
57 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Runtime.InteropServices;
6 |
7 | namespace PackageManager
8 | {
9 | public static class Program
10 | {
11 | private const string ApplicationKey = "5CFB158B-8346-4588-926D-99006A5195B6";
12 | private const int RestoreWindowCommandCode = 0x09;
13 |
14 | [DllImport("user32.dll")]
15 | [return: MarshalAs(UnmanagedType.Bool)]
16 | private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
17 |
18 | [DllImport("user32.dll")]
19 | private static extern IntPtr SetForegroundWindow(IntPtr hWnd);
20 |
21 | [STAThread]
22 | public static void Main()
23 | {
24 | using var mutex = new Mutex(false, ApplicationKey, out bool createdNew);
25 |
26 | if (createdNew)
27 | {
28 | var application = new App();
29 |
30 | application.InitializeComponent();
31 | application.Run();
32 | }
33 | else
34 | {
35 | var currentProcess = Process.GetCurrentProcess();
36 | var mainProcess = Process.GetProcesses()
37 | .Where(x => x.Id != currentProcess.Id)
38 | .FirstOrDefault(x => x.ProcessName == currentProcess.ProcessName);
39 |
40 | if (mainProcess != null)
41 | {
42 | ShowWindow(mainProcess.MainWindowHandle, RestoreWindowCommandCode);
43 | SetForegroundWindow(mainProcess.MainWindowHandle);
44 | }
45 | }
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace PackageManager.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PackageManager.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace PackageManager.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Properties/VersionInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | namespace PackageManager
4 | {
5 | public static class VersionInfo
6 | {
7 | public static string Version => typeof(VersionInfo).Assembly.GetCustomAttribute().InformationalVersion;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Services/ProcessService.IApplication.cs:
--------------------------------------------------------------------------------
1 | namespace PackageManager.Services
2 | {
3 | partial class ProcessService
4 | {
5 | public interface IApplication
6 | {
7 | object Args { get; }
8 |
9 | void Shutdown();
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Services/ProcessService.ProcessKillContext.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Diagnostics;
5 | using System.Linq;
6 |
7 | namespace PackageManager.Services
8 | {
9 | partial class ProcessService
10 | {
11 | internal class ProcessKillContext
12 | {
13 | private readonly IReadOnlyCollection targets;
14 |
15 | public ProcessKillContext(IReadOnlyCollection names)
16 | {
17 | Ensure.NotNull(names, "names");
18 | ProcessNames = names;
19 | targets = names.SelectMany(name => Process.GetProcessesByName(name)).ToList();
20 | }
21 |
22 | public IReadOnlyCollection ProcessNames { get; }
23 |
24 | public int ProcessCount { get => targets.Count; }
25 |
26 | public bool IsExecutable => targets.Count > 0;
27 |
28 | public void Execute()
29 | {
30 | foreach (Process process in targets)
31 | {
32 | try
33 | {
34 | process.Kill();
35 | }
36 | catch (Win32Exception)
37 | {
38 | continue;
39 | }
40 | }
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Services/ProcessService.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Diagnostics;
5 |
6 | namespace PackageManager.Services
7 | {
8 | internal partial class ProcessService
9 | {
10 | private const int ErrorCancelled = 1223;
11 |
12 | private readonly IApplication application;
13 | private readonly IReadOnlyCollection toKillNames;
14 |
15 | public ProcessService(IApplication application, IReadOnlyCollection toKillNames)
16 | {
17 | Ensure.NotNull(application, "application");
18 | Ensure.NotNull(toKillNames, "toKillNames");
19 | this.application = application;
20 | this.toKillNames = toKillNames;
21 | }
22 |
23 | public void RestartAsAdministrator()
24 | {
25 | Process current = Process.GetCurrentProcess();
26 | ProcessStartInfo processStart = new ProcessStartInfo(
27 | current.MainModule.FileName,
28 | application.Args.ToString()
29 | );
30 |
31 | processStart.Verb = "runas";
32 |
33 | try
34 | {
35 | Process.Start(processStart);
36 | }
37 | catch (Win32Exception e) when (e.NativeErrorCode == ErrorCancelled)
38 | {
39 | throw new RestartAsAdministratorCancelledException(e);
40 | }
41 |
42 | application.Shutdown();
43 | }
44 |
45 | public void Run(string filePath, string arguments)
46 | {
47 | ProcessStartInfo processStart = new ProcessStartInfo(
48 | filePath,
49 | arguments
50 | );
51 |
52 | Process.Start(processStart);
53 | }
54 |
55 | public ProcessKillContext PrepareContextForProcessesKillBeforeChange()
56 | => new ProcessKillContext(toKillNames);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Services/RestartAsAdministratorCancelledException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace PackageManager.Services
4 | {
5 | ///
6 | /// An exception raised when attempt to restart the application as administrator was cancelled by the user.
7 | ///
8 | public class RestartAsAdministratorCancelledException : Exception
9 | {
10 | ///
11 | /// Creates new instance with the exception.
12 | ///
13 | /// The inner cause of the exceptional state.
14 | public RestartAsAdministratorCancelledException(Exception inner)
15 | : base("Attempt to restart the application as administrator was cancelled by the user.", inner)
16 | { }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Services/SelfUpdateService.IApplication.cs:
--------------------------------------------------------------------------------
1 | namespace PackageManager.Services
2 | {
3 | partial class SelfUpdateService
4 | {
5 | public interface IApplication
6 | {
7 | IArgs Args { get; }
8 | void Shutdown();
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Services/SelfUpdateService.IArgs.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 |
3 | namespace PackageManager.Services
4 | {
5 | partial class SelfUpdateService
6 | {
7 | public interface IArgs : ICloneable
8 | {
9 | string Path { get; }
10 |
11 | bool IsSelfUpdate { get; set; }
12 | string SelfOriginalPath { get; set; }
13 | string SelfUpdateVersion { get; set; }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Services/SelfUpdateService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using System.Linq;
5 | using Neptuo;
6 | using PackageManager.Models;
7 |
8 | namespace PackageManager.Services
9 | {
10 | internal partial class SelfUpdateService : ISelfUpdateService
11 | {
12 | private readonly IApplication application;
13 | private readonly ProcessService processes;
14 |
15 | public SelfUpdateService(IApplication application, ProcessService processes)
16 | {
17 | Ensure.NotNull(application, "application");
18 | Ensure.NotNull(processes, "processes");
19 | this.application = application;
20 | this.processes = processes;
21 | }
22 |
23 | public string CurrentFileName => Path.GetFileName(GetCurrentApplicationPath());
24 |
25 | private static string GetCurrentApplicationPath() => Process.GetCurrentProcess().MainModule!.FileName!;
26 |
27 | public bool IsSelfUpdate => application.Args.IsSelfUpdate;
28 |
29 | public void Update(IPackage latest)
30 | {
31 | string current = GetCurrentApplicationPath();
32 | string temp = CopySelfToTemp(current);
33 | IArgs arguments = CreateArguments(current, latest);
34 | RerunFromTemp(temp, arguments);
35 | }
36 |
37 | private string CopySelfToTemp(string current)
38 | {
39 | string tempDirectory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString().Replace("-", string.Empty));
40 | string temp = Path.Combine(tempDirectory, CurrentFileName);
41 | if (!Directory.Exists(tempDirectory))
42 | Directory.CreateDirectory(tempDirectory);
43 |
44 | File.Copy(current, temp, true);
45 | return temp;
46 | }
47 |
48 | private void RerunFromTemp(string temp, IArgs arguments)
49 | {
50 | processes.Run(temp, arguments.ToString());
51 | application.Shutdown();
52 | }
53 |
54 | private IArgs CreateArguments(string current, IPackageIdentity package)
55 | {
56 | IArgs args = application.Args.Clone();
57 |
58 | args.IsSelfUpdate = true;
59 | args.SelfOriginalPath = current;
60 | args.SelfUpdateVersion = package.Version;
61 |
62 | return args;
63 | }
64 |
65 | public void RunNewInstance(IPackage package)
66 | {
67 | string target = null;
68 | if (application.Args.SelfOriginalPath != null)
69 | {
70 | target = application.Args.SelfOriginalPath;
71 | }
72 | else
73 | {
74 | target = Directory
75 | .EnumerateFiles(application.Args.Path, CurrentFileName, SearchOption.AllDirectories)
76 | .FirstOrDefault();
77 | }
78 |
79 | if (target != null)
80 | {
81 | IArgs args = application.Args.Clone();
82 |
83 | args.IsSelfUpdate = false;
84 | args.SelfUpdateVersion = null;
85 |
86 | string arguments = args.ToString();
87 | processes.Run(target, arguments);
88 | }
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Services/TagsNuGetSearchTermTransformer.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 |
3 | namespace PackageManager.Services
4 | {
5 | public class TagsNuGetSearchTermTransformer : INuGetSearchTermTransformer
6 | {
7 | private readonly string tags;
8 |
9 | public TagsNuGetSearchTermTransformer(string tags)
10 | {
11 | Ensure.NotNull(tags, "tags");
12 | this.tags = tags;
13 | }
14 |
15 | public void Transform(NuGetSearchTerm searchTerm)
16 | {
17 | if (!string.IsNullOrEmpty(tags))
18 | searchTerm.Tags.Add(tags);
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Assets/baseline_add_black_18dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/src/PackageManager.UI/Views/Assets/baseline_add_black_18dp.png
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Assets/baseline_arrow_downward_black_18dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/src/PackageManager.UI/Views/Assets/baseline_arrow_downward_black_18dp.png
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Assets/baseline_arrow_upward_black_18dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/src/PackageManager.UI/Views/Assets/baseline_arrow_upward_black_18dp.png
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Assets/baseline_chevron_left_black_18dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/src/PackageManager.UI/Views/Assets/baseline_chevron_left_black_18dp.png
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Assets/baseline_chevron_right_black_18dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/src/PackageManager.UI/Views/Assets/baseline_chevron_right_black_18dp.png
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Assets/baseline_clear_black_18dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/src/PackageManager.UI/Views/Assets/baseline_clear_black_18dp.png
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Assets/baseline_done_black_18dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/src/PackageManager.UI/Views/Assets/baseline_done_black_18dp.png
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Assets/baseline_edit_black_18dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/src/PackageManager.UI/Views/Assets/baseline_edit_black_18dp.png
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Assets/baseline_refresh_black_18dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/src/PackageManager.UI/Views/Assets/baseline_refresh_black_18dp.png
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Assets/baseline_search_black_18dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/src/PackageManager.UI/Views/Assets/baseline_search_black_18dp.png
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Assets/box-search-result.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/src/PackageManager.UI/Views/Assets/box-search-result.ico
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Assets/box-search-result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/src/PackageManager.UI/Views/Assets/box-search-result.png
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Assets/default-package-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/src/PackageManager.UI/Views/Assets/default-package-icon.png
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Assets/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitextensions/gitextensions.pluginmanager/daaf7af3ab2a895afc5dab4e494c585455a39924/src/PackageManager.UI/Views/Assets/settings.png
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Controls/CompatibilityLabel.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 | using System.Windows.Media;
4 |
5 | namespace PackageManager.Views.Controls
6 | {
7 | public class CompatibilityLabel : ContentControl
8 | {
9 | public bool IsCompatible
10 | {
11 | get => (bool)GetValue(IsCompatibleProperty);
12 | set => SetValue(IsCompatibleProperty, value);
13 | }
14 |
15 | public static readonly DependencyProperty IsCompatibleProperty = DependencyProperty.Register(
16 | "IsCompatible",
17 | typeof(bool),
18 | typeof(CompatibilityLabel),
19 | new PropertyMetadata(true, OnIsCompatibleChanged)
20 | );
21 |
22 | private static void OnIsCompatibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
23 | {
24 | CompatibilityLabel view = (CompatibilityLabel)d;
25 | view.UpdateVisibility();
26 | }
27 |
28 | public CompatibilityLabel()
29 | {
30 | CreateContent();
31 | UpdateVisibility();
32 | }
33 |
34 | private void CreateContent()
35 | {
36 | Content = new TextBlock()
37 | {
38 | Text = " (Not compatible)",
39 | ToolTip = "Installed version is not compatible with current a version of the application.",
40 | Foreground = new SolidColorBrush(Colors.Red)
41 | };
42 | }
43 |
44 | private void UpdateVisibility()
45 | => Visibility = IsCompatible ? Visibility.Collapsed : Visibility.Visible;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Controls/TabControl.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 | using System.Windows.Controls.Primitives;
4 |
5 | namespace PackageManager.Views.Controls
6 | {
7 | public class TabControl
8 | {
9 | public static int GetLastSelectedIndex(DependencyObject obj)
10 | => (int)obj.GetValue(LastSelectedIndexProperty);
11 |
12 | public static void SetLastSelectedIndex(DependencyObject obj, int value)
13 | => obj.SetValue(LastSelectedIndexProperty, value);
14 |
15 | public static readonly DependencyProperty LastSelectedIndexProperty = DependencyProperty.RegisterAttached(
16 | "LastSelectedIndex",
17 | typeof(int),
18 | typeof(TabControl),
19 | new PropertyMetadata(-1)
20 | );
21 |
22 |
23 | public static bool GetIsAutoFocus(DependencyObject obj)
24 | => (bool)obj.GetValue(IsAutoFocusProperty);
25 |
26 | public static void SetIsAutoFocus(DependencyObject obj, bool value)
27 | => obj.SetValue(IsAutoFocusProperty, value);
28 |
29 | public static readonly DependencyProperty IsAutoFocusProperty = DependencyProperty.RegisterAttached(
30 | "IsAutoFocus",
31 | typeof(bool),
32 | typeof(TabControl),
33 | new PropertyMetadata(false, OnIsAutoFocusChanged)
34 | );
35 |
36 | private static void OnIsAutoFocusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
37 | {
38 | Selector view = (Selector)d;
39 | bool isAutoFocus = (bool)e.NewValue;
40 | if (isAutoFocus)
41 | {
42 | view.SelectionChanged += OnSelectionChanged;
43 | TabSelected(view, view.SelectedIndex);
44 | }
45 | else
46 | {
47 | view.SelectionChanged -= OnSelectionChanged;
48 | }
49 | }
50 |
51 |
52 | private static void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
53 | {
54 | Selector view = (Selector)sender;
55 | TabSelected(view, view.SelectedIndex);
56 | }
57 |
58 | private static void TabSelected(Selector sender, int index)
59 | {
60 | if (GetLastSelectedIndex(sender) == index)
61 | return;
62 |
63 | SetLastSelectedIndex(sender, index);
64 |
65 | ContentControl item = (ContentControl)sender.Items[index];
66 | UIElement element = (UIElement)item.Content;
67 |
68 | if (element is IAutoFocus autoFocus)
69 | autoFocus.Focus();
70 | else
71 | element.Focus();
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Converters/BoolConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Globalization;
4 | using System.Windows.Data;
5 |
6 | namespace PackageManager.Views.Converters
7 | {
8 | public class BoolConverter : IValueConverter
9 | {
10 | [DefaultValue(true)]
11 | public bool Test { get; set; } = true;
12 | public object TrueValue { get; set; }
13 | public object FalseValue { get; set; }
14 |
15 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
16 | {
17 | bool? boolValue = value as bool?;
18 | if (boolValue == null)
19 | boolValue = false;
20 |
21 | object result = null;
22 | if (Test == boolValue.Value)
23 | result = TrueValue;
24 | else
25 | result = FalseValue;
26 |
27 | if (targetType != null && result != null)
28 | {
29 | Type resultType = result.GetType();
30 | TypeConverter converter = TypeDescriptor.GetConverter(targetType);
31 | if (converter != null && converter.CanConvertFrom(resultType))
32 | result = converter.ConvertFrom(null, CultureInfo.InvariantCulture, result);
33 | }
34 |
35 | return result;
36 | }
37 |
38 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
39 | {
40 | throw new NotImplementedException();
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Converters/CuttingConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Windows.Data;
4 |
5 | namespace PackageManager.Views.Converters
6 | {
7 | public class CuttingConverter : IValueConverter
8 | {
9 | public int EdgeValue { get; set; }
10 |
11 | public object LowerValue { get; set; }
12 | public object EqualValue { get; set; }
13 | public object GreaterValue { get; set; }
14 |
15 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
16 | {
17 | int intValue = (int)value;
18 | if (intValue > EdgeValue)
19 | return GreaterValue;
20 | else if (intValue < EdgeValue)
21 | return LowerValue;
22 | else
23 | return EqualValue;
24 | }
25 |
26 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
27 | {
28 | throw new NotImplementedException();
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Converters/DropNewLineConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Windows.Data;
4 |
5 | namespace PackageManager.Views.Converters
6 | {
7 | public class DropNewLineConverter : IValueConverter
8 | {
9 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
10 | {
11 | string target = value?.ToString();
12 | if (string.IsNullOrEmpty(target))
13 | return target;
14 |
15 | target = target.Replace(Environment.NewLine, string.Empty);
16 | target = target.Replace("\n", string.Empty);
17 | return target;
18 | }
19 |
20 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
21 | {
22 | throw new NotImplementedException();
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Converters/FirstNotNullMultiConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Windows;
4 | using System.Windows.Data;
5 |
6 | namespace PackageManager.Views.Converters
7 | {
8 | public class FirstNotNullMultiConverter : IMultiValueConverter
9 | {
10 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
11 | {
12 | for (int i = 0; i < values.Length; i++)
13 | {
14 | if (values[i] != null && values[i] != DependencyProperty.UnsetValue)
15 | return values[i];
16 | }
17 |
18 | return null;
19 | }
20 |
21 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
22 | {
23 | throw new NotImplementedException();
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Converters/FormatConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Windows.Data;
4 |
5 | namespace PackageManager.Views.Converters
6 | {
7 | public class FormatConverter : IValueConverter
8 | {
9 | public string Format { get; set; }
10 |
11 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
12 | {
13 | IFormattable formattable = value as IFormattable;
14 | if (formattable != null)
15 | return formattable.ToString(Format, culture);
16 |
17 | return value;
18 | }
19 |
20 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
21 | {
22 | throw new NotImplementedException();
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Converters/NullConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Windows.Data;
4 |
5 | namespace PackageManager.Views.Converters
6 | {
7 | public class NullConverter : IValueConverter
8 | {
9 | public object TrueValue { get; set; }
10 | public object FalseValue { get; set; }
11 |
12 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
13 | {
14 | if (value == null)
15 | return TrueValue;
16 |
17 | if (value is string)
18 | {
19 | string stringValue = value as string;
20 | if (stringValue == string.Empty)
21 | return TrueValue;
22 | }
23 |
24 | return FalseValue;
25 | }
26 |
27 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
28 | {
29 | throw new NotImplementedException();
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Converters/NullValueConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Windows.Data;
4 |
5 | namespace PackageManager.Views.Converters
6 | {
7 | public class NullValueConverter : IValueConverter
8 | {
9 | public object DefaultValue { get; set; }
10 |
11 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
12 | {
13 | if (value == null)
14 | return DefaultValue;
15 |
16 | return value;
17 | }
18 |
19 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
20 | {
21 | throw new NotImplementedException();
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Converters/SelfPackageConverter.cs:
--------------------------------------------------------------------------------
1 | using PackageManager.Models;
2 | using PackageManager.Services;
3 | using System;
4 | using System.Globalization;
5 | using System.Windows.Data;
6 |
7 | namespace PackageManager.Views.Converters
8 | {
9 | public class SelfPackageConverter : IValueConverter
10 | {
11 | public static SelfPackageConfiguration Configuration { get; set; }
12 |
13 | public object TrueValue { get; set; }
14 | public object FalseValue { get; set; }
15 |
16 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
17 | {
18 | if (IsSelfPackage(value))
19 | return TrueValue;
20 |
21 | return FalseValue;
22 | }
23 |
24 | private static bool IsSelfPackage(object value)
25 | {
26 | if (Configuration == null)
27 | return false;
28 |
29 | string packageId = value as string;
30 | if (packageId == null)
31 | {
32 | var package = value as IPackageIdentity;
33 | if (package == null)
34 | return false;
35 |
36 | packageId = package.Id;
37 | }
38 |
39 | return Configuration.Equals(packageId);
40 | }
41 |
42 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
43 | {
44 | throw new NotImplementedException();
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Converters/ValidUrlToTrueConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Windows.Data;
4 |
5 | namespace PackageManager.Views.Converters
6 | {
7 | public class ValidUrlToTrueConverter : IValueConverter
8 | {
9 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
10 | {
11 | string url = (string)value;
12 | return Uri.TryCreate(url, UriKind.Absolute, out Uri uri);
13 | }
14 |
15 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
16 | {
17 | throw new NotImplementedException();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/DesignData/MockInstallService.cs:
--------------------------------------------------------------------------------
1 | using PackageManager.Models;
2 | using PackageManager.Services;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 |
8 | namespace PackageManager.Views.DesignData
9 | {
10 | internal class MockInstallService : IInstallService
11 | {
12 | public string Path => @"C:\Temp";
13 | public IPackageIdentity Installed { get; set; }
14 |
15 | public bool IsInstalled(string packageId)
16 | => false;
17 |
18 | public bool IsInstalled(IPackageIdentity package)
19 | => string.Equals(Installed?.Id, package?.Id, StringComparison.CurrentCultureIgnoreCase) && string.Equals(Installed?.Version, package?.Version, StringComparison.CurrentCultureIgnoreCase);
20 |
21 | public void Install(IPackageIdentity package)
22 | { }
23 |
24 | public void Uninstall(IPackageIdentity package)
25 | { }
26 |
27 | public Task> GetInstalledAsync(IEnumerable packageSources, CancellationToken cancellationToken)
28 | {
29 | return Task.FromResult>(
30 | new List()
31 | {
32 | ViewModelLocator.IncompatiblePackage,
33 | ViewModelLocator.CompatiblePackage
34 | }
35 | );
36 | }
37 |
38 | public Task FindInstalledAsync(string packageId, CancellationToken cancellationToken)
39 | {
40 | return null;
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/DesignData/MockInstalledPackage.cs:
--------------------------------------------------------------------------------
1 | using PackageManager.Models;
2 |
3 | namespace PackageManager.Views.DesignData
4 | {
5 | internal class MockInstalledPackage : IInstalledPackage
6 | {
7 | public IPackage Definition { get; }
8 | public bool IsCompatible { get; }
9 |
10 | public MockInstalledPackage(IPackage definition, bool isCompatible)
11 | {
12 | Definition = definition;
13 | IsCompatible = isCompatible;
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/DesignData/MockPackage.cs:
--------------------------------------------------------------------------------
1 | using PackageManager.Models;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace PackageManager.Views.DesignData
8 | {
9 | internal class MockPackage : IPackage
10 | {
11 | public string Id { get; set; }
12 | public string Version { get; set; }
13 | public string Description { get; set; }
14 |
15 | public string Authors { get; set; }
16 | public DateTime? Published { get; set; }
17 | public string Tags { get; set; }
18 |
19 | public Uri IconUrl { get; set; }
20 | public Uri ProjectUrl { get; set; }
21 | public Uri LicenseUrl { get; set; }
22 |
23 | public bool Equals(IPackageIdentity other)
24 | {
25 | if (other == null)
26 | return false;
27 |
28 | return string.Equals(Id, other.Id, StringComparison.CurrentCultureIgnoreCase) && string.Equals(Version, other.Version, StringComparison.CurrentCultureIgnoreCase);
29 | }
30 |
31 | public bool Equals(IPackage other)
32 | => Equals((IPackageIdentity)other);
33 |
34 | public Task GetContentAsync(CancellationToken cancellationToken)
35 | {
36 | throw new NotImplementedException();
37 | }
38 |
39 | public Task> GetVersionsAsync(bool isPrereleaseIncluded, CancellationToken cancellationToken)
40 | {
41 | throw new NotImplementedException();
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/DesignData/MockPackageSource.cs:
--------------------------------------------------------------------------------
1 | using PackageManager.Models;
2 | using System;
3 |
4 | namespace PackageManager.Views.DesignData
5 | {
6 | public class MockPackageSource : IPackageSource
7 | {
8 | public string Name { get; }
9 | public Uri Uri { get; }
10 |
11 | public MockPackageSource(string name, Uri uri)
12 | {
13 | Name = name;
14 | Uri = uri;
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/DesignData/MockPackageSourceBuilder.cs:
--------------------------------------------------------------------------------
1 | using PackageManager.Models;
2 | using System;
3 |
4 | namespace PackageManager.Views.DesignData
5 | {
6 | public class MockPackageSourceBuilder : IPackageSourceBuilder
7 | {
8 | private readonly MockPackageSourceCollection service;
9 | private string name;
10 | private Uri uri;
11 |
12 | public MockPackageSourceBuilder(MockPackageSourceCollection service)
13 | {
14 | this.service = service;
15 | }
16 |
17 | public IPackageSourceBuilder Name(string name)
18 | {
19 | this.name = name;
20 | return this;
21 | }
22 |
23 | public IPackageSourceBuilder Uri(Uri uri)
24 | {
25 | this.uri = uri;
26 | return this;
27 | }
28 |
29 | public IPackageSource Save()
30 | {
31 | var source = new MockPackageSource(name, uri);
32 | service.all.Add(source);
33 | service.RaiseChanged();
34 | return source;
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/DesignData/MockPackageSourceCollection.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using PackageManager.Models;
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | namespace PackageManager.Views.DesignData
7 | {
8 | public class MockPackageSourceCollection : IPackageSourceCollection
9 | {
10 | internal readonly List all = new List();
11 | private IPackageSource primary;
12 |
13 | public IPackageSource Primary => primary;
14 | public IReadOnlyCollection All => all;
15 |
16 | public event Action Changed;
17 |
18 | internal void RaiseChanged() => Changed?.Invoke();
19 |
20 | public IPackageSource Add(string name, Uri uri)
21 | {
22 | var source = new MockPackageSource(name, uri);
23 | all.Add(source);
24 | RaiseChanged();
25 | return source;
26 | }
27 |
28 | public IPackageSourceBuilder Add()
29 | => new MockPackageSourceBuilder(this);
30 |
31 | public IPackageSourceBuilder Edit(IPackageSource source)
32 | => new MockPackageSourceBuilder(this);
33 |
34 | public void MarkAsPrimary(IPackageSource source)
35 | {
36 | primary = source;
37 | RaiseChanged();
38 | }
39 |
40 | public void Remove(IPackageSource source)
41 | {
42 | all.Remove((MockPackageSource)source);
43 | RaiseChanged();
44 | }
45 |
46 | public int MoveUp(IPackageSource source)
47 | => throw Ensure.Exception.NotSupported();
48 |
49 | public int MoveDown(IPackageSource source)
50 | => throw Ensure.Exception.NotSupported();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/DesignData/MockPackageSourceProvider.cs:
--------------------------------------------------------------------------------
1 | using PackageManager.Models;
2 | using PackageManager.ViewModels;
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | namespace PackageManager.Views.DesignData
7 | {
8 | public class MockPackageSourceProvider : IPackageSourceSelector
9 | {
10 | public IEnumerable Sources => new List(1) { new MockPackageSource("NuGet.org", new Uri("https://api.nuget.org/v3/index.json", UriKind.Absolute)) };
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/DesignData/MockSearchService.cs:
--------------------------------------------------------------------------------
1 | using PackageManager.Models;
2 | using PackageManager.Services;
3 | using System.Collections.Generic;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace PackageManager.Views.DesignData
8 | {
9 | internal class MockSearchService : ISearchService
10 | {
11 | public Task> SearchAsync(IEnumerable packageSources, string searchText, SearchOptions options = default, CancellationToken cancellationToken = default)
12 | {
13 | return Task.FromResult>(new List()
14 | {
15 | ViewModelLocator.Package
16 | });
17 | }
18 |
19 | public Task FindLatestVersionAsync(IEnumerable packageSources, IPackage package, bool isPrereleaseIncluded, CancellationToken cancellationToken = default)
20 | {
21 | return Task.FromResult(ViewModelLocator.Package);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/DesignData/MockSelfUpdateService.cs:
--------------------------------------------------------------------------------
1 | using PackageManager.Models;
2 | using PackageManager.Services;
3 |
4 | namespace PackageManager.Views.DesignData
5 | {
6 | public class MockSelfUpdateService : ISelfUpdateService
7 | {
8 | public bool IsSelfUpdate { get; set; }
9 |
10 | public void RunNewInstance(IPackage package)
11 | { }
12 |
13 | public void Update(IPackage latest)
14 | { }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/IAutoFocus.cs:
--------------------------------------------------------------------------------
1 | namespace PackageManager.Views
2 | {
3 | public interface IAutoFocus
4 | {
5 | void Focus();
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Installed.xaml.cs:
--------------------------------------------------------------------------------
1 | using PackageManager.Models;
2 | using PackageManager.ViewModels;
3 | using System.Windows;
4 | using System.Windows.Controls;
5 |
6 | namespace PackageManager.Views
7 | {
8 | public partial class Installed : UserControl, IAutoFocus
9 | {
10 | public InstalledViewModel ViewModel
11 | {
12 | get { return (InstalledViewModel)GetValue(ViewModelProperty); }
13 | set { SetValue(ViewModelProperty, value); }
14 | }
15 |
16 | public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(
17 | "ViewModel",
18 | typeof(InstalledViewModel),
19 | typeof(Installed),
20 | new PropertyMetadata(null, OnViewModelChanged)
21 | );
22 |
23 | private static void OnViewModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
24 | {
25 | Installed view = (Installed)d;
26 | view.OnViewModelChanged((InstalledViewModel)e.OldValue, (InstalledViewModel)e.NewValue);
27 | }
28 |
29 |
30 | internal IInstalledPackage SelectedPackage
31 | {
32 | get { return (IInstalledPackage)GetValue(SelectedPackageProperty); }
33 | set { SetValue(SelectedPackageProperty, value); }
34 | }
35 |
36 | internal static readonly DependencyProperty SelectedPackageProperty = DependencyProperty.Register(
37 | "SelectedPackage",
38 | typeof(IInstalledPackage),
39 | typeof(Installed),
40 | new PropertyMetadata(null)
41 | );
42 |
43 | public Installed()
44 | {
45 | InitializeComponent();
46 | }
47 |
48 | private void OnViewModelChanged(InstalledViewModel oldValue, InstalledViewModel newValue)
49 | {
50 | if (oldValue != null)
51 | oldValue.Uninstall.Completed += OnRefresh;
52 |
53 | MainPanel.DataContext = newValue;
54 |
55 | if (newValue != null)
56 | newValue.Uninstall.Completed += OnRefresh;
57 | }
58 |
59 | private void OnRefresh()
60 | => ViewModel.Refresh.Execute();
61 |
62 | void IAutoFocus.Focus()
63 | {
64 | ViewModel.Refresh.Execute();
65 | lvwPackages.Focus();
66 | }
67 |
68 | private void lvwPackages_SelectionChanged(object sender, SelectionChangedEventArgs e)
69 | {
70 | ViewModel.Uninstall.RaiseCanExecuteChanged();
71 | ViewModel.Reinstall.RaiseCanExecuteChanged();
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Loading.xaml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Loading.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 | using System.Windows.Input;
4 |
5 | namespace PackageManager.Views
6 | {
7 | public partial class Loading : UserControl
8 | {
9 | public ICommand CancelCommand
10 | {
11 | get { return (ICommand)GetValue(CancelCommandProperty); }
12 | set { SetValue(CancelCommandProperty, value); }
13 | }
14 |
15 | public static readonly DependencyProperty CancelCommandProperty = DependencyProperty.Register(
16 | "CancelCommand",
17 | typeof(ICommand),
18 | typeof(Loading),
19 | new PropertyMetadata(null, OnCancelCommandChanged)
20 | );
21 |
22 | private static void OnCancelCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
23 | {
24 | Loading view = (Loading)d;
25 | view.btnCancel.Command = (ICommand)e.NewValue;
26 | }
27 |
28 | public Loading()
29 | {
30 | InitializeComponent();
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/LogWindow.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/LogWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using PackageManager.Logging.Serialization;
3 | using System.Threading.Tasks;
4 | using System.Windows;
5 |
6 | namespace PackageManager.Views
7 | {
8 | public partial class LogWindow : Window
9 | {
10 | private readonly MemoryLogSerializer log;
11 |
12 | public LogWindow(MemoryLogSerializer log)
13 | {
14 | Ensure.NotNull(log, "log");
15 | this.log = log;
16 |
17 | InitializeComponent();
18 | RefreshContent();
19 | }
20 |
21 | private async void RefreshContent()
22 | {
23 | TextContent.Text = log.GetContent();
24 | if (string.IsNullOrEmpty(TextContent.Text))
25 | TextContent.Text = "No entries.";
26 |
27 | await Task.Delay(50);
28 | TextContent.ScrollToEnd();
29 | }
30 |
31 | private void Clear_Click(object sender, RoutedEventArgs e)
32 | {
33 | log.Clear();
34 | RefreshContent();
35 | }
36 |
37 | private void GoToBottom_Click(object sender, RoutedEventArgs e)
38 | => TextContent.ScrollToEnd();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using PackageManager.Services;
3 | using PackageManager.ViewModels;
4 | using System.Threading.Tasks;
5 | using System.Windows;
6 |
7 | namespace PackageManager.Views
8 | {
9 | public partial class MainWindow : Window
10 | {
11 | private readonly ProcessService processes;
12 | private readonly Navigator navigator;
13 |
14 | public MainViewModel ViewModel
15 | => (MainViewModel)DataContext;
16 |
17 | internal MainWindow(MainViewModel viewModel, ProcessService processes, Navigator navigator)
18 | {
19 | Ensure.NotNull(viewModel, "viewModel");
20 | Ensure.NotNull(processes, "processes");
21 | Ensure.NotNull(navigator, "navigator");
22 | DataContext = viewModel;
23 | this.processes = processes;
24 | this.navigator = navigator;
25 | InitializeViewModel();
26 |
27 | InitializeComponent();
28 | }
29 |
30 | private void InitializeViewModel()
31 | {
32 | ViewModel.Browser.Install.Executing += OnBeforeChange;
33 | ViewModel.Installed.Uninstall.Executing += OnBeforeChange;
34 | ViewModel.Updates.Update.Executing += OnBeforeChange;
35 | }
36 |
37 | private Task OnBeforeChange()
38 | {
39 | var context = processes.PrepareContextForProcessesKillBeforeChange();
40 | if (context.IsExecutable)
41 | {
42 | var processNames = string.Join(" and ", context.ProcessNames);
43 | if (context.ProcessCount > 1 || context.ProcessNames.Count > 1)
44 | processNames = $"all instances of {processNames}";
45 |
46 | bool result = navigator.Confirm(
47 | "Plugin Manager",
48 | $"Plugin Manager will be writing to files that are currently in use.\r\n\r\nDo you want to stop {processNames}?"
49 | );
50 |
51 | if (result)
52 | context.Execute();
53 | }
54 |
55 | return Task.FromResult(true);
56 | }
57 |
58 | public void SelectUpdatesTab()
59 | => Tabs.SelectedIndex = 2;
60 |
61 | private void PackageSourceSettings_Click(object sender, RoutedEventArgs e)
62 | => navigator.OpenPackageSources();
63 |
64 | private void ShowLog_Click(object sender, RoutedEventArgs e)
65 | => navigator.OpenLog();
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/PackageDetail.xaml.cs:
--------------------------------------------------------------------------------
1 | using PackageManager.Models;
2 | using System.Diagnostics;
3 | using System.Windows;
4 | using System.Windows.Controls;
5 | using System.Windows.Navigation;
6 |
7 | namespace PackageManager.Views
8 | {
9 | public partial class PackageDetail : UserControl
10 | {
11 | public IPackage Model
12 | {
13 | get { return (IPackage)GetValue(ViewModelProperty); }
14 | set { SetValue(ViewModelProperty, value); }
15 | }
16 |
17 | public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(
18 | "Model",
19 | typeof(IPackage),
20 | typeof(PackageDetail),
21 | new PropertyMetadata(null, OnModelChanged)
22 | );
23 |
24 | private static void OnModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
25 | {
26 | PackageDetail view = (PackageDetail)d;
27 | view.DataContext = view.Model;
28 | }
29 |
30 | public PackageDetail()
31 | {
32 | InitializeComponent();
33 | }
34 |
35 | private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
36 | {
37 | Process.Start(new ProcessStartInfo()
38 | {
39 | FileName = e.Uri.AbsoluteUri,
40 | UseShellExecute = true
41 | });
42 | e.Handled = true;
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/PackageName.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/PackageName.xaml.cs:
--------------------------------------------------------------------------------
1 | using PackageManager.Models;
2 | using System.Windows;
3 | using System.Windows.Controls;
4 |
5 | namespace PackageManager.Views
6 | {
7 | public partial class PackageName : UserControl
8 | {
9 | public IPackage Model
10 | {
11 | get { return (IPackage)GetValue(ViewModelProperty); }
12 | set { SetValue(ViewModelProperty, value); }
13 | }
14 |
15 | public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(
16 | "Model",
17 | typeof(IPackage),
18 | typeof(PackageName),
19 | new PropertyMetadata(null, OnModelChanged)
20 | );
21 |
22 | private static void OnModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
23 | {
24 | PackageName view = (PackageName)d;
25 | view.DataContext = view.Model;
26 | }
27 |
28 | public PackageName()
29 | {
30 | InitializeComponent();
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/PackageSourceWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using PackageManager.ViewModels;
3 | using System.Windows;
4 | using System.Windows.Controls;
5 |
6 | namespace PackageManager.Views
7 | {
8 | public partial class PackageSourceWindow : Window
9 | {
10 | public PackageSourceViewModel ViewModel => (PackageSourceViewModel)DataContext;
11 |
12 | internal PackageSourceWindow(PackageSourceViewModel viewModel)
13 | {
14 | Ensure.NotNull(viewModel, "viewModel");
15 | DataContext = viewModel;
16 |
17 | InitializeComponent();
18 | }
19 |
20 | private void lvwSources_SelectionChanged(object sender, SelectionChangedEventArgs e)
21 | {
22 | ViewModel.Edit.RaiseCanExecuteChanged();
23 | ViewModel.Remove.RaiseCanExecuteChanged();
24 | ViewModel.MoveUp.RaiseCanExecuteChanged();
25 | ViewModel.MoveDown.RaiseCanExecuteChanged();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/PackageManager.UI/Views/Updates.xaml.cs:
--------------------------------------------------------------------------------
1 | using PackageManager.ViewModels;
2 | using System.Windows;
3 | using System.Windows.Controls;
4 |
5 | namespace PackageManager.Views
6 | {
7 | public partial class Updates : UserControl, IAutoFocus
8 | {
9 | public UpdatesViewModel ViewModel
10 | {
11 | get { return (UpdatesViewModel)GetValue(ViewModelProperty); }
12 | set { SetValue(ViewModelProperty, value); }
13 | }
14 |
15 | public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(
16 | "ViewModel",
17 | typeof(UpdatesViewModel),
18 | typeof(Updates),
19 | new PropertyMetadata(null, OnViewModelChanged)
20 | );
21 |
22 | private static void OnViewModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
23 | {
24 | Updates view = (Updates)d;
25 | view.OnViewModelChanged((UpdatesViewModel)e.OldValue, (UpdatesViewModel)e.NewValue);
26 | }
27 |
28 |
29 | internal PackageUpdateViewModel SelectedPackage
30 | {
31 | get { return (PackageUpdateViewModel)GetValue(SelectedPackageProperty); }
32 | set { SetValue(SelectedPackageProperty, value); }
33 | }
34 |
35 | internal static readonly DependencyProperty SelectedPackageProperty = DependencyProperty.Register(
36 | "SelectedPackage",
37 | typeof(PackageUpdateViewModel),
38 | typeof(Updates),
39 | new PropertyMetadata(null)
40 | );
41 |
42 |
43 | public Updates()
44 | {
45 | InitializeComponent();
46 | }
47 |
48 | private void OnViewModelChanged(UpdatesViewModel oldValue, UpdatesViewModel newValue)
49 | {
50 | if (oldValue != null)
51 | oldValue.Update.Completed += OnRefresh;
52 |
53 | MainPanel.DataContext = newValue;
54 |
55 | if (newValue != null)
56 | newValue.Update.Completed += OnRefresh;
57 | }
58 |
59 | private void OnRefresh()
60 | => ViewModel.Refresh.Execute();
61 |
62 | async void IAutoFocus.Focus()
63 | {
64 | lvwPackages.Focus();
65 | await ViewModel.Refresh.ExecuteAsync();
66 | }
67 |
68 | private void lvwPackages_SelectionChanged(object sender, SelectionChangedEventArgs e)
69 | {
70 | ViewModel.Update.RaiseCanExecuteChanged();
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/PackageManager/Models/IInstalledPackage.cs:
--------------------------------------------------------------------------------
1 | namespace PackageManager.Models
2 | {
3 | ///
4 | /// A model of installed package.
5 | ///
6 | public interface IInstalledPackage
7 | {
8 | ///
9 | /// Gets a package definition.
10 | ///
11 | IPackage Definition { get; }
12 |
13 | ///
14 | /// Gets true when package is compatible with current application version; false otherwise.
15 | ///
16 | bool IsCompatible { get; }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/PackageManager/Models/IPackage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 |
6 | namespace PackageManager.Models
7 | {
8 | ///
9 | /// A package.
10 | ///
11 | public interface IPackage : IPackageIdentity, IEquatable
12 | {
13 | ///
14 | /// Gets a package description.
15 | ///
16 | string Description { get; }
17 |
18 |
19 | ///
20 | /// Gets package authors.
21 | ///
22 | string Authors { get; }
23 |
24 | ///
25 | /// Gets a date of publish.
26 | ///
27 | DateTime? Published { get; }
28 |
29 | ///
30 | /// Gets defined tags.
31 | ///
32 | string Tags { get; }
33 |
34 |
35 | ///
36 | /// Gets a path to the package icon.
37 | ///
38 | Uri IconUrl { get; }
39 |
40 | ///
41 | /// Gets an URL to the package project.
42 | ///
43 | Uri ProjectUrl { get; }
44 |
45 | ///
46 | /// Gets an URL to the package license text.
47 | ///
48 | Uri LicenseUrl { get; }
49 |
50 |
51 | ///
52 | /// Gets a content of the package.
53 | ///
54 | /// A cancellation token.
55 | /// A continuation task returning a content of the package.
56 | Task GetContentAsync(CancellationToken cancellationToken);
57 |
58 | ///
59 | /// Gets an enumeration of all available package versions.
60 | ///
61 | /// Whehter to include pre-release versions.
62 | /// A cancellation token.
63 | /// A continutaion task returning an enumeration of all available package versions.
64 | Task> GetVersionsAsync(bool isPrereleaseIncluded, CancellationToken cancellationToken);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/PackageManager/Models/IPackageContent.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace PackageManager.Models
5 | {
6 | ///
7 | /// A package content.
8 | ///
9 | public interface IPackageContent
10 | {
11 | ///
12 | /// Extracts all content from package to the .
13 | ///
14 | /// A path to extract content to.
15 | /// A cancellation token.
16 | /// A continuation task.
17 | Task ExtractToAsync(string path, CancellationToken cancellationToken);
18 |
19 | ///
20 | /// Removes all package content from the .
21 | ///
22 | /// A path to remove content from.
23 | /// A cancellation token.
24 | /// A continuation task.
25 | Task RemoveFromAsync(string path, CancellationToken cancellationToken);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/PackageManager/Models/IPackageIdentity.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace PackageManager.Models
4 | {
5 | ///
6 | /// A package identification (unique name and version).
7 | ///
8 | public interface IPackageIdentity : IEquatable
9 | {
10 | ///
11 | /// Gets an unique package identifier.
12 | ///
13 | string Id { get; }
14 |
15 | ///
16 | /// Gets a package version.
17 | ///
18 | string Version { get; }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/PackageManager/Models/IPackageSource.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace PackageManager.Models
4 | {
5 | ///
6 | /// A package source endpoint.
7 | ///
8 | public interface IPackageSource
9 | {
10 | ///
11 | /// Gets a user defined name of package source.
12 | ///
13 | string Name { get; }
14 |
15 | ///
16 | /// Gets a URI of package source.
17 | ///
18 | Uri Uri { get; }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/PackageManager/Models/IPackageSourceBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace PackageManager.Models
4 | {
5 | ///
6 | /// A package source definition builder.
7 | ///
8 | public interface IPackageSourceBuilder
9 | {
10 | ///
11 | /// Sets a name of the source.
12 | ///
13 | /// A name of the source.
14 | /// Self (for fluency).
15 | IPackageSourceBuilder Name(string name);
16 |
17 | ///
18 | /// Sets an URI of the source.
19 | ///
20 | /// An URI of the source.
21 | /// Self (for fluency).
22 | IPackageSourceBuilder Uri(Uri uri);
23 |
24 | ///
25 | /// Saves changes or creates a new source.
26 | ///
27 | /// Updated or created source.
28 | IPackageSource Save();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/PackageManager/Models/IPackageSourceCollection.cs:
--------------------------------------------------------------------------------
1 | namespace PackageManager.Models
2 | {
3 | ///
4 | /// A mutable collection of defined package sources.
5 | ///
6 | public interface IPackageSourceCollection : IPackageSourceProvider
7 | {
8 | ///
9 | /// Sets as primary.
10 | /// If is null, removed any definition of primary source.
11 | ///
12 | /// A source to set as primary or null to clear this setting.
13 | void MarkAsPrimary(IPackageSource source);
14 |
15 | ///
16 | /// REturns a builder for creating a new source.
17 | ///
18 | IPackageSourceBuilder Add();
19 |
20 | ///
21 | /// Returns builder for editing package source.
22 | ///
23 | /// A source to edit.
24 | /// Builder for editing package source.
25 | IPackageSourceBuilder Edit(IPackageSource source);
26 |
27 | ///
28 | /// Removes from the collection.
29 | ///
30 | /// A source to remove.
31 | void Remove(IPackageSource source);
32 |
33 | ///
34 | /// Moves by one up.
35 | ///
36 | /// A source to move up.
37 | /// A new index.
38 | int MoveUp(IPackageSource source);
39 |
40 | ///
41 | /// Moves by one down.
42 | ///
43 | /// A source to move down.
44 | /// A new index.
45 | int MoveDown(IPackageSource source);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/PackageManager/Models/IPackageSourceProvider.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace PackageManager.Models
5 | {
6 | ///
7 | /// A provider of package sources.
8 | /// A single primary could be selected or if not all defined should be used.
9 | ///
10 | public interface IPackageSourceProvider
11 | {
12 | ///
13 | /// Gets a primary source.
14 | /// Can returns null - if it does, should be used.
15 | ///
16 | IPackageSource Primary { get; }
17 |
18 | ///
19 | /// Gets a collection of all defined sources.
20 | ///
21 | IReadOnlyCollection All { get; }
22 |
23 | ///
24 | /// An event raised when state of this provider has changed.
25 | ///
26 | event Action Changed;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/PackageManager/Models/PackageFileExtractionException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace PackageManager.Models
4 | {
5 | ///
6 | /// An exception raised when there was an extracting file from package content.
7 | ///
8 | public class PackageFileExtractionException : Exception
9 | {
10 | ///
11 | /// Gets a real file path where extraction problem occured.
12 | ///
13 | public string FilePath { get; }
14 |
15 | ///
16 | /// Creates a new instance where caused the problem and exception.
17 | ///
18 | /// A real file path where extraction problem occured.
19 | /// An inner cause of the exceptional state.
20 | public PackageFileExtractionException(string filePath, Exception inner)
21 | : base($"Error deleting file from '{filePath}'.", inner)
22 | {
23 | FilePath = filePath;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/PackageManager/Models/PackageFileRemovalException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace PackageManager.Models
4 | {
5 | ///
6 | /// An exception raised when there was an removing file from installed package.
7 | ///
8 | public class PackageFileRemovalException : Exception
9 | {
10 | ///
11 | /// Gets a real file path where removal problem occured.
12 | ///
13 | public string FilePath { get; }
14 |
15 | ///
16 | /// Creates a new instance where caused the problem and exception.
17 | ///
18 | /// A real file path where removal problem occured.
19 | /// An inner cause of the exceptional state.
20 | public PackageFileRemovalException(string filePath, Exception inner)
21 | : base($"Error extracting file to '{filePath}'.", inner)
22 | {
23 | FilePath = filePath;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/PackageManager/Models/PackageIdentityExtensions.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 |
3 | namespace PackageManager.Models
4 | {
5 | public static class PackageIdentityExtensions
6 | {
7 | ///
8 | /// Gets package identity in form "{id}-v{version}" for .
9 | ///
10 | /// A package to identity for.
11 | /// A package identity string.
12 | public static string ToIdentityString(this IPackageIdentity package)
13 | {
14 | Ensure.NotNull(package, "package");
15 | return $"{package.Id}-v{package.Version}";
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/PackageManager/PackageManager.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/PackageManager/Services/IInstallService.cs:
--------------------------------------------------------------------------------
1 | using PackageManager.Models;
2 | using System.Collections.Generic;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 |
6 | namespace PackageManager.Services
7 | {
8 | public interface IInstallService
9 | {
10 | string Path { get; }
11 |
12 | bool IsInstalled(string packageId);
13 | bool IsInstalled(IPackageIdentity package);
14 |
15 | void Install(IPackageIdentity package);
16 | void Uninstall(IPackageIdentity package);
17 |
18 | Task> GetInstalledAsync(IEnumerable packageSources, CancellationToken cancellationToken);
19 | Task FindInstalledAsync(string packageId, CancellationToken cancellationToken);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/PackageManager/Services/ISearchService.cs:
--------------------------------------------------------------------------------
1 | using PackageManager.Models;
2 | using System.Collections.Generic;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 |
6 | namespace PackageManager.Services
7 | {
8 | public interface ISearchService
9 | {
10 | Task> SearchAsync(IEnumerable packageSources, string searchText, SearchOptions options = default, CancellationToken cancellationToken = default);
11 |
12 | Task FindLatestVersionAsync(IEnumerable packageSources, IPackage package, bool isPrereleaseIncluded = false, CancellationToken cancellationToken = default);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/PackageManager/Services/ISelfUpdateService.cs:
--------------------------------------------------------------------------------
1 | using PackageManager.Models;
2 |
3 | namespace PackageManager.Services
4 | {
5 | public interface ISelfUpdateService
6 | {
7 | bool IsSelfUpdate { get; }
8 |
9 | void Update(IPackage latest);
10 |
11 | void RunNewInstance(IPackage package);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/PackageManager/Services/SearchOptions.cs:
--------------------------------------------------------------------------------
1 | namespace PackageManager.Services
2 | {
3 | public class SearchOptions
4 | {
5 | public static class Default
6 | {
7 | public const int PageSize = 10;
8 | }
9 |
10 | public int PageIndex { get; set; }
11 | public int PageSize { get; set; }
12 | public bool IsPrereleaseIncluded { get; set; }
13 |
14 | public SearchOptions()
15 | { }
16 |
17 | public SearchOptions(int pageIndex)
18 | {
19 | PageIndex = pageIndex;
20 | PageSize = Default.PageSize;
21 | }
22 |
23 | public SearchOptions(int pageIndex, int pageSize)
24 | {
25 | PageIndex = pageIndex;
26 | PageSize = pageSize;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/PackageManager/Services/SelfPackageConfiguration.cs:
--------------------------------------------------------------------------------
1 | using PackageManager.Models;
2 | using System;
3 |
4 | namespace PackageManager.Services
5 | {
6 | public class SelfPackageConfiguration : IEquatable
7 | {
8 | public string PackageId { get; }
9 |
10 | public SelfPackageConfiguration(string packageId)
11 | {
12 | PackageId = packageId;
13 | }
14 |
15 | public bool Equals(IPackageIdentity packageIdentity)
16 | {
17 | if (packageIdentity == null)
18 | return false;
19 |
20 | return Equals(packageIdentity.Id);
21 | }
22 |
23 | public bool Equals(string packageId)
24 | {
25 | if (PackageId == null || packageId == null)
26 | return false;
27 |
28 | return PackageId == packageId;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/BrowserViewModel.cs:
--------------------------------------------------------------------------------
1 | using Neptuo.Observables;
2 | using Neptuo.Observables.Collections;
3 | using PackageManager.Services;
4 | using PackageManager.ViewModels.Commands;
5 |
6 | namespace PackageManager.ViewModels
7 | {
8 | public class BrowserViewModel : ObservableModel, IPackageOptions
9 | {
10 | private string searchText;
11 | public string SearchText
12 | {
13 | get { return searchText; }
14 | set
15 | {
16 | if (searchText != value)
17 | {
18 | searchText = value;
19 | RaisePropertyChanged();
20 | }
21 | }
22 | }
23 |
24 | private bool isPrereleaseIncluded;
25 | public bool IsPrereleaseIncluded
26 | {
27 | get { return isPrereleaseIncluded; }
28 | set
29 | {
30 | if (isPrereleaseIncluded != value)
31 | {
32 | isPrereleaseIncluded = value;
33 | RaisePropertyChanged();
34 | }
35 | }
36 | }
37 |
38 | public PagingViewModel Paging { get; }
39 | public ObservableCollection Packages { get; }
40 | public SearchCommand Search { get; }
41 | public InstallCommand Install { get; }
42 |
43 | public BrowserViewModel(IPackageSourceSelector packageSource, ISearchService search, IInstallService install)
44 | {
45 | Packages = new ObservableCollection();
46 | Search = new SearchCommand(this, packageSource, search);
47 | Paging = new PagingViewModel(Search);
48 | Install = new InstallCommand(install);
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/Commands/CancelCommand.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Observables.Commands;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 |
7 | namespace PackageManager.ViewModels.Commands
8 | {
9 | ///
10 | /// A command that cancels a command implementing .
11 | ///
12 | public class CancelCommand : Command
13 | {
14 | private readonly IEnumerable commands;
15 |
16 | ///
17 | /// Creates a new instance that can cancel .
18 | ///
19 | /// An enumeration of commands that can be cancelled by this object.
20 | public CancelCommand(params ICancellableCommand[] commands)
21 | : this((IEnumerable)commands)
22 | { }
23 |
24 | ///
25 | /// Creates a new instance that can cancel .
26 | ///
27 | /// An enumeration of commands that can be cancelled by this object.
28 | public CancelCommand(IEnumerable commands)
29 | {
30 | Ensure.NotNull(commands, "commands");
31 | this.commands = commands;
32 |
33 | foreach (ICancellableCommand command in commands)
34 | command.CanExecuteChanged += OnCanExecuteChanged;
35 | }
36 |
37 | private void OnCanExecuteChanged(object sender, EventArgs e)
38 | => RaiseCanExecuteChanged();
39 |
40 | public override bool CanExecute()
41 | => commands.Any(c => c.IsRunning);
42 |
43 | public override void Execute()
44 | {
45 | foreach (ICancellableCommand command in commands)
46 | {
47 | if (command.IsRunning)
48 | command.Cancel();
49 | }
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/Commands/InstallCommand.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Observables.Commands;
3 | using PackageManager.Models;
4 | using PackageManager.Services;
5 | using System;
6 | using System.IO;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 |
10 | namespace PackageManager.ViewModels.Commands
11 | {
12 | public class InstallCommand : AsyncCommand
13 | {
14 | private readonly IInstallService service;
15 |
16 | public event Func> Executing;
17 | public event Action Completed;
18 |
19 | public InstallCommand(IInstallService service)
20 | {
21 | Ensure.NotNull(service, "service");
22 | this.service = service;
23 | }
24 |
25 | protected override bool CanExecuteOverride(IPackage package)
26 | => package != null && !service.IsInstalled(package.Id);
27 |
28 | protected override async Task ExecuteAsync(IPackage package, CancellationToken cancellationToken)
29 | {
30 | bool execute = true;
31 |
32 | if (Executing != null)
33 | execute = await Executing();
34 |
35 | if (execute)
36 | {
37 | IPackageContent packageContent = await package.GetContentAsync(cancellationToken);
38 | string pluginPath = Path.Combine(service.Path, package.Id);
39 | Directory.CreateDirectory(pluginPath);
40 | await packageContent.ExtractToAsync(pluginPath, cancellationToken);
41 |
42 | service.Install(package);
43 | }
44 |
45 | Completed?.Invoke();
46 | }
47 |
48 | public new void RaiseCanExecuteChanged()
49 | => base.RaiseCanExecuteChanged();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/Commands/MoveCommand.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Observables.Collections;
3 | using Neptuo.Observables.Commands;
4 | using System;
5 | using System.Collections.Specialized;
6 |
7 | namespace PackageManager.ViewModels.Commands
8 | {
9 | public class MoveCommand : Command, IDisposable
10 | {
11 | private readonly ObservableCollection sources;
12 | private readonly Func execute;
13 | private readonly Func canExecute;
14 |
15 | public MoveCommand(ObservableCollection sources, Func execute, Func canExecute)
16 | {
17 | Ensure.NotNull(sources, "sources");
18 | Ensure.NotNull(execute, "execute");
19 | Ensure.NotNull(canExecute, "canExecute");
20 | this.sources = sources;
21 | this.execute = execute;
22 | this.canExecute = canExecute;
23 |
24 | sources.CollectionChanged += OnSourcesChanged;
25 | }
26 |
27 | private void OnSourcesChanged(object sender, NotifyCollectionChangedEventArgs e)
28 | => RaiseCanExecuteChanged();
29 |
30 | public override bool CanExecute(T item)
31 | => item != null && canExecute(item);
32 |
33 | public override void Execute(T item)
34 | {
35 | if (CanExecute(item))
36 | {
37 | int oldIndex = sources.IndexOf(item);
38 | int newIndex = execute(item);
39 | sources.Move(oldIndex, newIndex);
40 | }
41 | }
42 |
43 | public new void RaiseCanExecuteChanged()
44 | => base.RaiseCanExecuteChanged();
45 |
46 | public void Dispose()
47 | => sources.CollectionChanged -= OnSourcesChanged;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/Commands/RefreshInstalledCommand.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Observables.Commands;
3 | using PackageManager.Services;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace PackageManager.ViewModels.Commands
8 | {
9 | public class RefreshInstalledCommand : AsyncCommand
10 | {
11 | private readonly InstalledViewModel viewModel;
12 | private readonly IInstallService service;
13 | private readonly IPackageSourceSelector packageSource;
14 |
15 | public RefreshInstalledCommand(InstalledViewModel viewModel, IPackageSourceSelector packageSource, IInstallService service)
16 | {
17 | Ensure.NotNull(viewModel, "viewModel");
18 | Ensure.NotNull(packageSource, "packageSource");
19 | Ensure.NotNull(service, "service");
20 | this.viewModel = viewModel;
21 | this.packageSource = packageSource;
22 | this.service = service;
23 | }
24 |
25 | protected override bool CanExecuteOverride()
26 | => true;
27 |
28 | protected override async Task ExecuteAsync(CancellationToken cancellationToken)
29 | {
30 | viewModel.Packages.Clear();
31 | viewModel.Packages.AddRange(await service.GetInstalledAsync(packageSource.Sources, cancellationToken));
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/Commands/RefreshUpdatesCommand.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Observables.Commands;
3 | using PackageManager.Models;
4 | using PackageManager.Services;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 |
10 | namespace PackageManager.ViewModels.Commands
11 | {
12 | public class RefreshUpdatesCommand : AsyncCommand
13 | {
14 | private readonly UpdatesViewModel viewModel;
15 | private readonly IPackageSourceSelector packageSource;
16 | private readonly IInstallService installService;
17 | private readonly ISearchService searchService;
18 | private readonly SelfPackageConfiguration selfPackageConfiguration;
19 | private readonly IComparer packageVersionComparer;
20 |
21 | public event Action Completed;
22 |
23 | public RefreshUpdatesCommand(UpdatesViewModel viewModel, IPackageSourceSelector packageSource, IInstallService installService, ISearchService searchService, SelfPackageConfiguration selfPackageConfiguration, IComparer packageVersionComparer)
24 | {
25 | Ensure.NotNull(viewModel, "viewModel");
26 | Ensure.NotNull(packageSource, "packageSource");
27 | Ensure.NotNull(installService, "installService");
28 | Ensure.NotNull(searchService, "searchService");
29 | Ensure.NotNull(selfPackageConfiguration, "selfPackageConfiguration");
30 | Ensure.NotNull(packageVersionComparer, "packageVersionComparer");
31 | this.viewModel = viewModel;
32 | this.packageSource = packageSource;
33 | this.installService = installService;
34 | this.searchService = searchService;
35 | this.selfPackageConfiguration = selfPackageConfiguration;
36 | this.packageVersionComparer = packageVersionComparer;
37 | }
38 |
39 | protected override bool CanExecuteOverride()
40 | => true;
41 |
42 | protected override async Task ExecuteAsync(CancellationToken cancellationToken)
43 | {
44 | viewModel.Packages.Clear();
45 |
46 | foreach (IInstalledPackage current in await installService.GetInstalledAsync(packageSource.Sources, cancellationToken))
47 | {
48 | IPackage latest = await searchService.FindLatestVersionAsync(packageSource.Sources, current.Definition, viewModel.IsPrereleaseIncluded, cancellationToken);
49 |
50 | if (latest != null && packageVersionComparer.Compare(latest, current.Definition) > 0)
51 | {
52 | viewModel.Packages.Add(new PackageUpdateViewModel(
53 | current.Definition,
54 | latest,
55 | viewModel,
56 | selfPackageConfiguration.Equals(current.Definition)
57 | ));
58 | }
59 | }
60 |
61 | Completed?.Invoke();
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/Commands/ReinstallCommand.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Observables.Commands;
3 | using PackageManager.Models;
4 | using PackageManager.Services;
5 | using System.IO;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 |
9 | namespace PackageManager.ViewModels.Commands
10 | {
11 | public class ReinstallCommand : AsyncCommand
12 | {
13 | private readonly IInstallService service;
14 | private readonly SelfPackageConfiguration selfPackageConfiguration;
15 |
16 | public ReinstallCommand(IInstallService service, SelfPackageConfiguration selfPackageConfiguration)
17 | {
18 | Ensure.NotNull(service, "service");
19 | Ensure.NotNull(selfPackageConfiguration, "selfPackageConfiguration");
20 | this.service = service;
21 | this.selfPackageConfiguration = selfPackageConfiguration;
22 | }
23 |
24 | protected override bool CanExecuteOverride(IPackage package)
25 | => package != null && service.IsInstalled(package) && !selfPackageConfiguration.Equals(package);
26 |
27 | protected override async Task ExecuteAsync(IPackage package, CancellationToken cancellationToken)
28 | {
29 | IPackageContent packageContent = await package.GetContentAsync(cancellationToken);
30 | string pluginPath = Path.Combine(service.Path, package.Id);
31 | await packageContent.RemoveFromAsync(pluginPath, cancellationToken);
32 | await packageContent.ExtractToAsync(pluginPath, cancellationToken);
33 | }
34 |
35 | public new void RaiseCanExecuteChanged()
36 | => base.RaiseCanExecuteChanged();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/Commands/RemoveSourceCommand.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Observables.Commands;
3 | using PackageManager.Models;
4 | using System.Collections.Generic;
5 |
6 | namespace PackageManager.ViewModels.Commands
7 | {
8 | public class RemoveSourceCommand : Command
9 | {
10 | private readonly ICollection sources;
11 | private readonly IPackageSourceCollection service;
12 |
13 | public RemoveSourceCommand(ICollection sources, IPackageSourceCollection service)
14 | {
15 | Ensure.NotNull(sources, "sources");
16 | Ensure.NotNull(service, "service");
17 | this.sources = sources;
18 | this.service = service;
19 | }
20 |
21 | public override bool CanExecute(IPackageSource source)
22 | => source != null;
23 |
24 | public override void Execute(IPackageSource source)
25 | {
26 | if (CanExecute(source))
27 | {
28 | sources.Remove(source);
29 | service.Remove(source);
30 | }
31 | }
32 |
33 | public new void RaiseCanExecuteChanged()
34 | => base.RaiseCanExecuteChanged();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/Commands/SearchCommand.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Observables.Commands;
3 | using PackageManager.Models;
4 | using PackageManager.Services;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 |
11 | namespace PackageManager.ViewModels.Commands
12 | {
13 | public class SearchCommand : AsyncCommand
14 | {
15 | private readonly BrowserViewModel viewModel;
16 | private readonly IPackageSourceSelector packageSource;
17 | private readonly ISearchService search;
18 |
19 | private string lastSearchText;
20 |
21 | public event Action Completed;
22 |
23 | public SearchCommand(BrowserViewModel viewModel, IPackageSourceSelector packageSource, ISearchService search)
24 | {
25 | Ensure.NotNull(viewModel, "viewModel");
26 | Ensure.NotNull(packageSource, "packageSource");
27 | Ensure.NotNull(search, "search");
28 | this.viewModel = viewModel;
29 | this.packageSource = packageSource;
30 | this.search = search;
31 | }
32 |
33 | protected override bool CanExecuteOverride()
34 | => true;
35 |
36 | protected override async Task ExecuteAsync(CancellationToken cancellationToken)
37 | {
38 | if (lastSearchText != viewModel.SearchText)
39 | {
40 | lastSearchText = viewModel.SearchText;
41 | viewModel.Paging.CurrentIndex = 0;
42 | }
43 |
44 | (List packages, int pageSize) = await Task.Run(() => SearchAsync(cancellationToken));
45 | if (packages.Count > 0 || viewModel.Paging.CurrentIndex == 0)
46 | {
47 | viewModel.Packages.Clear();
48 |
49 | foreach (IPackage package in packages)
50 | viewModel.Packages.Add(new PackageViewModel(package, viewModel));
51 |
52 | viewModel.Paging.IsNextAvailable = viewModel.Packages.Count == pageSize;
53 | }
54 | else
55 | {
56 | viewModel.Paging.CurrentIndex--;
57 | viewModel.Paging.IsNextAvailable = false;
58 | }
59 |
60 | Completed?.Invoke();
61 | }
62 |
63 | private async Task<(List packages, int pageSize)> SearchAsync(CancellationToken cancellationToken)
64 | {
65 | SearchOptions options = new SearchOptions(viewModel.Paging.CurrentIndex);
66 | options.IsPrereleaseIncluded = viewModel.IsPrereleaseIncluded;
67 | IEnumerable packages = await search.SearchAsync(packageSource.Sources, viewModel.SearchText, options, cancellationToken);
68 | return (packages.ToList(), options.PageSize);
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/Commands/UninstallAllCommand.IViewModel.cs:
--------------------------------------------------------------------------------
1 | using Neptuo.Observables.Collections;
2 | using PackageManager.Models;
3 |
4 | namespace PackageManager.ViewModels.Commands
5 | {
6 | partial class UninstallAllCommand
7 | {
8 | public interface IViewModel
9 | {
10 | ObservableCollection Packages { get; }
11 | UninstallCommand Uninstall { get; }
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/Commands/UninstallAllCommand.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Observables.Commands;
3 | using PackageManager.Models;
4 | using System.Collections.Specialized;
5 | using System.Linq;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 |
9 | namespace PackageManager.ViewModels.Commands
10 | {
11 | public partial class UninstallAllCommand : AsyncCommand
12 | {
13 | private readonly IViewModel viewModel;
14 |
15 | public UninstallAllCommand(IViewModel viewModel)
16 | {
17 | Ensure.NotNull(viewModel, "viewModel");
18 | this.viewModel = viewModel;
19 |
20 | viewModel.Packages.CollectionChanged += OnPackagesChanged;
21 | }
22 |
23 | private void OnPackagesChanged(object sender, NotifyCollectionChangedEventArgs e)
24 | => RaiseCanExecuteChanged();
25 |
26 | protected override bool CanExecuteOverride()
27 | => viewModel.Packages.Count > 0;
28 |
29 | protected async override Task ExecuteAsync(CancellationToken cancellationToken)
30 | {
31 | foreach (IInstalledPackage package in viewModel.Packages.ToList())
32 | {
33 | if (viewModel.Uninstall.CanExecute(package.Definition))
34 | await viewModel.Uninstall.ExecuteAsync(package.Definition);
35 | }
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/Commands/UninstallCommand.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Observables.Commands;
3 | using PackageManager.Models;
4 | using PackageManager.Services;
5 | using System;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 |
11 | namespace PackageManager.ViewModels.Commands
12 | {
13 | public class UninstallCommand : AsyncCommand
14 | {
15 | private readonly IInstallService service;
16 | private readonly SelfPackageConfiguration selfPackageConfiguration;
17 |
18 | public event Func> Executing;
19 | public event Action Completed;
20 |
21 | public UninstallCommand(IInstallService service, SelfPackageConfiguration selfPackageConfiguration)
22 | {
23 | Ensure.NotNull(service, "service");
24 | Ensure.NotNull(selfPackageConfiguration, "selfPackageConfiguration");
25 | this.service = service;
26 | this.selfPackageConfiguration = selfPackageConfiguration;
27 | }
28 |
29 | protected override bool CanExecuteOverride(IPackage package)
30 | => package != null && service.IsInstalled(package) && !selfPackageConfiguration.Equals(package.Id);
31 |
32 | protected override async Task ExecuteAsync(IPackage package, CancellationToken cancellationToken)
33 | {
34 | bool execute = true;
35 |
36 | if (Executing != null)
37 | execute = await Executing();
38 |
39 | if (execute)
40 | {
41 | IPackageContent packageContent = await package.GetContentAsync(cancellationToken);
42 | string pluginPath = Path.Combine(service.Path, package.Id);
43 | await packageContent.RemoveFromAsync(pluginPath, cancellationToken);
44 |
45 | // do not delete the plugin directory if it still contains files (e.g. data files)
46 | if (Directory.Exists(pluginPath) && !Directory.EnumerateFileSystemEntries(pluginPath).Any())
47 | {
48 | Directory.Delete(pluginPath);
49 | }
50 |
51 | cancellationToken.ThrowIfCancellationRequested();
52 |
53 | service.Uninstall(package);
54 | }
55 |
56 | Completed?.Invoke();
57 | }
58 |
59 | public new void RaiseCanExecuteChanged()
60 | => base.RaiseCanExecuteChanged();
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/Commands/UpdateAllCommand.IViewModel.cs:
--------------------------------------------------------------------------------
1 | using Neptuo.Observables.Collections;
2 |
3 | namespace PackageManager.ViewModels.Commands
4 | {
5 | partial class UpdateAllCommand
6 | {
7 | public interface IViewModel
8 | {
9 | ObservableCollection Packages { get; }
10 | UpdateCommand Update { get; }
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/Commands/UpdateAllCommand.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Observables.Commands;
3 | using System.Collections.Specialized;
4 | using System.Linq;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 |
8 | namespace PackageManager.ViewModels.Commands
9 | {
10 | public partial class UpdateAllCommand : AsyncCommand
11 | {
12 | private readonly IViewModel viewModel;
13 |
14 | public UpdateAllCommand(IViewModel viewModel)
15 | {
16 | Ensure.NotNull(viewModel, "viewModel");
17 | this.viewModel = viewModel;
18 |
19 | viewModel.Packages.CollectionChanged += OnPackagesChanged;
20 | }
21 |
22 | private void OnPackagesChanged(object sender, NotifyCollectionChangedEventArgs e)
23 | => RaiseCanExecuteChanged();
24 |
25 | protected override bool CanExecuteOverride()
26 | => viewModel.Packages.Count > 0;
27 |
28 | protected async override Task ExecuteAsync(CancellationToken cancellationToken)
29 | {
30 | PackageUpdateViewModel selfUpdate = null;
31 |
32 | foreach (PackageUpdateViewModel package in viewModel.Packages.ToList())
33 | {
34 | if (package.IsSelf)
35 | selfUpdate = package;
36 | else
37 | await UpdateAsync(package);
38 | }
39 |
40 | if (selfUpdate != null)
41 | await UpdateAsync(selfUpdate);
42 | }
43 |
44 | private async Task UpdateAsync(PackageUpdateViewModel package)
45 | {
46 | if (viewModel.Update.CanExecute(package))
47 | await viewModel.Update.ExecuteAsync(package);
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/Commands/UpdateCommand.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Observables.Commands;
3 | using PackageManager.Models;
4 | using PackageManager.Services;
5 | using System;
6 | using System.IO;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 |
10 | namespace PackageManager.ViewModels.Commands
11 | {
12 | public class UpdateCommand : AsyncCommand
13 | {
14 | private readonly IInstallService install;
15 | private readonly ISelfUpdateService selfUpdate;
16 |
17 | public event Func> Executing;
18 | public event Action Completed;
19 |
20 | public UpdateCommand(IInstallService installService, ISelfUpdateService selfUpdate)
21 | {
22 | Ensure.NotNull(installService, "service");
23 | Ensure.NotNull(selfUpdate, "selfUpdate");
24 | this.install = installService;
25 | this.selfUpdate = selfUpdate;
26 | }
27 |
28 | protected override bool CanExecuteOverride(PackageUpdateViewModel package)
29 | => package != null && install.IsInstalled(package.Current.Model) && package.Target != null;
30 |
31 | protected override async Task ExecuteAsync(PackageUpdateViewModel package, CancellationToken cancellationToken)
32 | {
33 | bool execute = true;
34 |
35 | if (Executing != null)
36 | execute = await Executing();
37 |
38 | if (execute)
39 | {
40 | if (package.IsSelf && !selfUpdate.IsSelfUpdate)
41 | {
42 | selfUpdate.Update(package.Target);
43 | return;
44 | }
45 |
46 | IPackageContent packageContent = await package.Current.Model.GetContentAsync(cancellationToken);
47 | string pluginPath = Path.Combine(install.Path, package.Current.Id);
48 | await packageContent.RemoveFromAsync(pluginPath, cancellationToken);
49 | install.Uninstall(package.Current.Model);
50 |
51 | packageContent = await package.Target.GetContentAsync(cancellationToken);
52 | await packageContent.ExtractToAsync(pluginPath, cancellationToken);
53 | install.Install(package.Target);
54 |
55 | if (package.IsSelf)
56 | selfUpdate.RunNewInstance(package.Target);
57 | }
58 |
59 | Completed?.Invoke();
60 | }
61 |
62 | public new void RaiseCanExecuteChanged()
63 | => base.RaiseCanExecuteChanged();
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/IPackageOptions.cs:
--------------------------------------------------------------------------------
1 | namespace PackageManager.ViewModels
2 | {
3 | public interface IPackageOptions
4 | {
5 | bool IsPrereleaseIncluded { get; }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/IPackageSourceSelector.cs:
--------------------------------------------------------------------------------
1 | using PackageManager.Models;
2 | using System.Collections.Generic;
3 |
4 | namespace PackageManager.ViewModels
5 | {
6 | ///
7 | /// A provider of current package sources.
8 | ///
9 | public interface IPackageSourceSelector
10 | {
11 | ///
12 | /// Gets an enumeration of current package sources.
13 | ///
14 | IEnumerable Sources { get; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/InstalledViewModel.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Observables;
3 | using Neptuo.Observables.Collections;
4 | using PackageManager.Models;
5 | using PackageManager.Services;
6 | using PackageManager.ViewModels.Commands;
7 |
8 | namespace PackageManager.ViewModels
9 | {
10 | public class InstalledViewModel : ObservableModel, UninstallAllCommand.IViewModel
11 | {
12 | private readonly IInstallService service;
13 |
14 | public ObservableCollection Packages { get; }
15 | public RefreshInstalledCommand Refresh { get; }
16 | public ReinstallCommand Reinstall { get; }
17 | public UninstallCommand Uninstall { get; }
18 | public UninstallAllCommand UninstallAll { get; }
19 |
20 | public InstalledViewModel(IPackageSourceSelector packageSource, IInstallService service, SelfPackageConfiguration selfPackageConfiguration)
21 | {
22 | Ensure.NotNull(service, "service");
23 | this.service = service;
24 |
25 | Packages = new ObservableCollection();
26 | Refresh = new RefreshInstalledCommand(this, packageSource, service);
27 | Reinstall = new ReinstallCommand(service, selfPackageConfiguration);
28 | Uninstall = new UninstallCommand(service, selfPackageConfiguration);
29 | UninstallAll = new UninstallAllCommand(this);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/MainViewModel.cs:
--------------------------------------------------------------------------------
1 | using Neptuo.Observables;
2 | using PackageManager.Models;
3 | using PackageManager.Services;
4 | using PackageManager.ViewModels.Commands;
5 | using System;
6 | using System.Collections.Generic;
7 |
8 | namespace PackageManager.ViewModels
9 | {
10 | public class MainViewModel : ObservableModel, IDisposable
11 | {
12 | public PackageSourceSelectorViewModel SourceSelector { get; }
13 |
14 | public BrowserViewModel Browser { get; }
15 | public InstalledViewModel Installed { get; }
16 | public UpdatesViewModel Updates { get; }
17 |
18 | public CancelCommand Cancel { get; }
19 |
20 | private bool isLoading;
21 | public bool IsLoading
22 | {
23 | get { return isLoading; }
24 | set
25 | {
26 | if (isLoading != value)
27 | {
28 | isLoading = value;
29 | RaisePropertyChanged();
30 | }
31 | }
32 | }
33 |
34 | public MainViewModel(IPackageSourceCollection sources, ISearchService search, IInstallService install, SelfPackageConfiguration selfPackageConfiguration, ISelfUpdateService selfUpdate, IComparer packageVersionComparer)
35 | {
36 | SourceSelector = new PackageSourceSelectorViewModel(sources);
37 |
38 | Browser = new BrowserViewModel(SourceSelector, search, install);
39 | Installed = new InstalledViewModel(SourceSelector, install, selfPackageConfiguration);
40 | Updates = new UpdatesViewModel(SourceSelector, install, search, selfPackageConfiguration, selfUpdate, packageVersionComparer);
41 |
42 | Cancel = new CancelCommand(
43 | Browser.Search,
44 | Browser.Install,
45 | Installed.Uninstall,
46 | Installed.UninstallAll,
47 | Installed.Reinstall,
48 | Installed.Refresh,
49 | Updates.Update,
50 | Updates.UpdateAll,
51 | Updates.Refresh
52 | );
53 | Cancel.CanExecuteChanged += OnCancelCanExecuteChanged;
54 |
55 | Installed.Uninstall.Completed += OnInstalledChanged;
56 | Updates.Update.Completed += OnInstalledChanged;
57 | }
58 |
59 | private void OnCancelCanExecuteChanged(object sender, EventArgs e)
60 | => IsLoading = Cancel.CanExecute();
61 |
62 | private void OnInstalledChanged()
63 | => Browser.Packages.Clear();
64 |
65 | public void Dispose()
66 | {
67 | SourceSelector.Dispose();
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/PackageSourceViewModel.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Observables;
3 | using Neptuo.Observables.Collections;
4 | using Neptuo.Observables.Commands;
5 | using PackageManager.Models;
6 | using PackageManager.ViewModels.Commands;
7 | using MoveCommand = PackageManager.ViewModels.Commands.MoveCommand;
8 |
9 | namespace PackageManager.ViewModels
10 | {
11 | public class PackageSourceViewModel : ObservableModel
12 | {
13 | private readonly IPackageSourceCollection service;
14 |
15 | public ObservableCollection Sources { get; }
16 | public Command Add { get; }
17 | public DelegateCommand Edit { get; }
18 | public RemoveSourceCommand Remove { get; }
19 |
20 | public MoveCommand MoveUp { get; }
21 | public MoveCommand MoveDown { get; }
22 |
23 | public SaveSourceCommand Save { get; }
24 | public Command Cancel { get; }
25 |
26 | private bool isEditActive;
27 | public bool IsEditActive
28 | {
29 | get { return isEditActive; }
30 | set
31 | {
32 | if (isEditActive != value)
33 | {
34 | isEditActive = value;
35 | RaisePropertyChanged();
36 | }
37 | }
38 | }
39 |
40 | public PackageSourceViewModel(IPackageSourceCollection service)
41 | {
42 | Ensure.NotNull(service, "service");
43 | this.service = service;
44 |
45 | Sources = new ObservableCollection(service.All);
46 |
47 | Add = new DelegateCommand(OnAdd);
48 | Edit = new DelegateCommand(OnEdit, CanEdit);
49 | Remove = new RemoveSourceCommand(Sources, service);
50 |
51 | MoveUp = new MoveCommand(Sources, source => service.MoveUp(source), source => Sources.IndexOf(source) > 0);
52 | MoveDown = new MoveCommand(Sources, source => service.MoveDown(source), source => Sources.IndexOf(source) < Sources.Count - 1);
53 |
54 | Save = new SaveSourceCommand(Sources, service);
55 | Save.Executed += () => IsEditActive = false;
56 | Cancel = new DelegateCommand(() => IsEditActive = false);
57 | }
58 |
59 | private void OnAdd()
60 | {
61 | Save.New();
62 | IsEditActive = true;
63 | }
64 |
65 | private bool CanEdit(IPackageSource source)
66 | => source != null;
67 |
68 | private void OnEdit(IPackageSource source)
69 | {
70 | if (CanEdit(source))
71 | {
72 | Save.Edit(source);
73 | IsEditActive = true;
74 | }
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/PackageUpdateViewModel.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Observables;
3 | using PackageManager.Models;
4 |
5 | namespace PackageManager.ViewModels
6 | {
7 | public class PackageUpdateViewModel : ObservableModel
8 | {
9 | public PackageViewModel Current { get; }
10 | public bool IsSelf { get; }
11 |
12 | private IPackage target;
13 | public IPackage Target
14 | {
15 | get { return target; }
16 | set
17 | {
18 | if (target != value)
19 | {
20 | target = value;
21 | RaisePropertyChanged();
22 | }
23 | }
24 | }
25 |
26 | public PackageUpdateViewModel(IPackage current, IPackage latest, IPackageOptions packageOptions, bool isSelf)
27 | {
28 | Ensure.NotNull(current, "current");
29 | Ensure.NotNull(latest, "latest");
30 | Current = new PackageViewModel(current, packageOptions);
31 | Target = latest;
32 | IsSelf = isSelf;
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/PackageViewModel.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Observables;
3 | using Neptuo.Observables.Collections;
4 | using Neptuo.Observables.Commands;
5 | using PackageManager.Models;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 |
11 | namespace PackageManager.ViewModels
12 | {
13 | public class PackageViewModel : ObservableModel
14 | {
15 | private readonly IPackage model;
16 | private readonly IPackageOptions packageOptions;
17 |
18 | // TODO: Remove...
19 | public IPackage Model => model;
20 |
21 | public string Id => model.Id;
22 | public string Version => model.Version;
23 | public string Description => model.Description;
24 | public string Authors => model.Authors;
25 | public DateTime? Published => model.Published;
26 |
27 | public string Tags => model.Tags;
28 | public Uri IconUrl => model.IconUrl;
29 | public Uri ProjectUrl => model.ProjectUrl;
30 | public Uri LicenseUrl => model.LicenseUrl;
31 |
32 | public ObservableCollection Versions { get; } = new ObservableCollection();
33 |
34 | public Command LoadVersions { get; }
35 |
36 | private bool areVersionsLoaded;
37 | public bool AreVersionsLoaded
38 | {
39 | get { return areVersionsLoaded; }
40 | set
41 | {
42 | if (areVersionsLoaded != value)
43 | {
44 | areVersionsLoaded = value;
45 | RaisePropertyChanged();
46 | }
47 | }
48 | }
49 |
50 | public PackageViewModel(IPackage model, IPackageOptions packageOptions)
51 | {
52 | Ensure.NotNull(model, "model");
53 | Ensure.NotNull(packageOptions, "packageOptions");
54 | this.model = model;
55 | this.packageOptions = packageOptions;
56 | LoadVersions = new AsyncDelegateCommand(OnLoadVersionsAsync, CanLoadVersions);
57 | }
58 |
59 | private async Task OnLoadVersionsAsync(CancellationToken cancellationToken)
60 | {
61 | Versions.Clear();
62 |
63 | IEnumerable versions = await model.GetVersionsAsync(packageOptions.IsPrereleaseIncluded, cancellationToken);
64 | foreach (IPackage version in versions)
65 | Versions.Add(new PackageViewModel(version, packageOptions));
66 |
67 | AreVersionsLoaded = true;
68 | }
69 |
70 | private bool CanLoadVersions()
71 | => !AreVersionsLoaded;
72 |
73 | public override bool Equals(object obj)
74 | {
75 | PackageViewModel other = obj as PackageViewModel;
76 | if (other == null)
77 | return false;
78 |
79 | return string.Equals(Id, other.Id, StringComparison.CurrentCultureIgnoreCase) && string.Equals(Version, other.Version, StringComparison.CurrentCultureIgnoreCase);
80 | }
81 |
82 | public override int GetHashCode()
83 | {
84 | int hash = 13 * 2;
85 | hash += 7 * Model.GetHashCode();
86 | return hash;
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/PagingViewModel.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Observables;
3 | using Neptuo.Observables.Commands;
4 |
5 | namespace PackageManager.ViewModels
6 | {
7 | public class PagingViewModel : ObservableModel
8 | {
9 | private readonly Command searchCommand;
10 | private readonly DelegateCommand prev;
11 | private readonly DelegateCommand next;
12 |
13 | private int currentIndex;
14 | public int CurrentIndex
15 | {
16 | get { return currentIndex; }
17 | set
18 | {
19 | Ensure.PositiveOrZero(value, "CurrentIndex");
20 | if (currentIndex != value)
21 | {
22 | currentIndex = value;
23 | RaisePropertyChanged();
24 | RaisePropertyChanged(nameof(CurrentNumber));
25 |
26 | RaisePropertyChanged(nameof(IsPrevAvailable));
27 | prev.RaiseCanExecuteChanged();
28 | }
29 | }
30 | }
31 |
32 | public int CurrentNumber
33 | => CurrentIndex + 1;
34 |
35 | public bool IsPrevAvailable
36 | => CurrentIndex > 0;
37 |
38 | private bool isNextAvailable;
39 | public bool IsNextAvailable
40 | {
41 | get { return isNextAvailable; }
42 | set
43 | {
44 | if (isNextAvailable != value)
45 | {
46 | isNextAvailable = value;
47 | RaisePropertyChanged();
48 | next.RaiseCanExecuteChanged();
49 | }
50 | }
51 | }
52 |
53 | public Command Prev => prev;
54 | public Command Next => next;
55 |
56 | public PagingViewModel(Command searchCommand)
57 | {
58 | Ensure.NotNull(searchCommand, "searchCommand");
59 | this.searchCommand = searchCommand;
60 |
61 | next = new DelegateCommand(OnNext, () => IsNextAvailable);
62 | prev = new DelegateCommand(OnPrev, () => IsPrevAvailable);
63 | }
64 |
65 | private void OnNext()
66 | {
67 | CurrentIndex++;
68 | searchCommand.Execute();
69 | }
70 |
71 | private void OnPrev()
72 | {
73 | CurrentIndex--;
74 | searchCommand.Execute();
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/PackageManager/ViewModels/UpdatesViewModel.cs:
--------------------------------------------------------------------------------
1 | using Neptuo;
2 | using Neptuo.Observables;
3 | using Neptuo.Observables.Collections;
4 | using PackageManager.Models;
5 | using PackageManager.Services;
6 | using PackageManager.ViewModels.Commands;
7 | using System.Collections.Generic;
8 |
9 | namespace PackageManager.ViewModels
10 | {
11 | public class UpdatesViewModel : ObservableModel, UpdateAllCommand.IViewModel, IPackageOptions
12 | {
13 | private bool isPrereleaseIncluded;
14 | public bool IsPrereleaseIncluded
15 | {
16 | get { return isPrereleaseIncluded; }
17 | set
18 | {
19 | if (isPrereleaseIncluded != value)
20 | {
21 | isPrereleaseIncluded = value;
22 | RaisePropertyChanged();
23 | }
24 | }
25 | }
26 |
27 | public ObservableCollection Packages { get; }
28 | public RefreshUpdatesCommand Refresh { get; }
29 | public UpdateCommand Update { get; }
30 | public UpdateAllCommand UpdateAll { get; }
31 |
32 | public UpdatesViewModel(IPackageSourceSelector packageSource, IInstallService installService, ISearchService searchService, SelfPackageConfiguration selfPackageConfiguration, ISelfUpdateService selfUpdate, IComparer packageVersionComparer)
33 | {
34 | Ensure.NotNull(installService, "service");
35 | Ensure.NotNull(searchService, "searchService");
36 |
37 | Packages = new ObservableCollection();
38 | Refresh = new RefreshUpdatesCommand(this, packageSource, installService, searchService, selfPackageConfiguration, packageVersionComparer);
39 | Update = new UpdateCommand(installService, selfUpdate);
40 | UpdateAll = new UpdateAllCommand(this);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/test/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | false
6 | PackageManager
7 |
8 |
9 |
10 | false
11 | true
12 |
13 |
14 |
15 | false
16 | true
17 |
18 |
19 |
20 | false
21 | true
22 |
23 |
24 |
25 | false
26 | true
27 |
28 |
29 |
--------------------------------------------------------------------------------
/test/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | trx
6 | $(ArtifactsTestResultsDir)
7 |
8 |
9 |
10 | $(PlatformTarget)
11 | x64
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/test/PackageManager.NuGet.Tests/Models/TestPackageContent.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using PackageManager.Services;
3 | using System;
4 | using System.IO;
5 | using System.Linq;
6 |
7 | namespace PackageManager.Models
8 | {
9 | [TestClass]
10 | public class TestPackageContent
11 | {
12 | public const string ConfigFilePath = "PackageSource_Content.config";
13 | public static string ExtractPath => Path.Combine(Environment.CurrentDirectory, "UserPlugins");
14 |
15 | private ISearchService search;
16 | private IPackageSourceCollection sources;
17 | private IPackage package;
18 |
19 | [TestInitialize]
20 | public void Initialize()
21 | {
22 | (search, sources) = SearchService.Create(ConfigFilePath);
23 | package = search.SearchAsync(sources.All, "PluginA").Result.FirstOrDefault();
24 | Assert.IsNotNull(package);
25 |
26 | if (!Directory.Exists(ExtractPath))
27 | Directory.CreateDirectory(ExtractPath);
28 | }
29 |
30 | [TestMethod]
31 | public void ExtractToAsync()
32 | {
33 | IPackageContent packageContent = package.GetContentAsync(default).Result;
34 | packageContent.ExtractToAsync(ExtractPath, default).Wait();
35 |
36 | Assert.IsTrue(File.Exists(Path.Combine(ExtractPath, "PluginA-2.txt")));
37 | }
38 |
39 | [TestMethod]
40 | public void RemoveFromAsync()
41 | {
42 | ExtractToAsync();
43 |
44 | IPackageContent packageContent = package.GetContentAsync(default).Result;
45 | packageContent.RemoveFromAsync(ExtractPath, default).Wait();
46 |
47 | Assert.IsFalse(File.Exists(Path.Combine(ExtractPath, "PluginA-2.txt")));
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/test/PackageManager.NuGet.Tests/PackageManager.NuGet.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/test/PackageManager.NuGet.Tests/Services/InstallService.cs:
--------------------------------------------------------------------------------
1 | using Neptuo.Logging;
2 | using NuGet.Frameworks;
3 | using PackageManager.Models;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.IO;
7 |
8 | namespace PackageManager.Services
9 | {
10 | public class InstallService
11 | {
12 | private static void EnsureConfigDeleted(string configFilePath)
13 | {
14 | string path = Path.Combine(Environment.CurrentDirectory, configFilePath);
15 |
16 | if (File.Exists(path))
17 | File.Delete(path);
18 | }
19 |
20 | public static IInstallService Create(string extractPath)
21 | {
22 | var frameworks = new List() { NuGetFramework.AnyFramework };
23 |
24 | var frameworkFilter = new NuGetFrameworkFilter(frameworks);
25 | var packageFilter = new DependencyNuGetPackageFilter(
26 | new DefaultLog(),
27 | new List()
28 | {
29 | new Args.Dependency("GitExtensions.Extensibility", null)
30 | },
31 | frameworks
32 | );
33 | var install = new NuGetInstallService(
34 | new NuGetSourceRepositoryFactory(),
35 | new DefaultLog(),
36 | extractPath,
37 | new NuGetPackageContentService(new DefaultLog()),
38 | new NuGetPackageVersionService(
39 | new NuGetPackageContentService(new DefaultLog()),
40 | new DefaultLog(),
41 | packageFilter,
42 | frameworkFilter
43 | ),
44 | packageFilter,
45 | frameworkFilter
46 | );
47 |
48 | return install;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/test/PackageManager.NuGet.Tests/Services/SearchService.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using Neptuo.Logging;
3 | using NuGet.Configuration;
4 | using NuGet.Frameworks;
5 | using PackageManager.Models;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.IO;
9 | using System.Linq;
10 |
11 | namespace PackageManager.Services
12 | {
13 | public class SearchService
14 | {
15 | private static void EnsureConfigDeleted(string configFilePath)
16 | {
17 | string path = Path.Combine(Environment.CurrentDirectory, configFilePath);
18 |
19 | if (File.Exists(path))
20 | File.Delete(path);
21 | }
22 |
23 | public static (ISearchService search, IPackageSourceCollection sources) Create(string configFilePath)
24 | {
25 | var frameworks = new List() { NuGetFramework.AnyFramework };
26 |
27 | var frameworkFilter = new NuGetFrameworkFilter(frameworks);
28 | var packageFilter = new DependencyNuGetPackageFilter(
29 | new DefaultLog(),
30 | new List()
31 | {
32 | new Args.Dependency("GitExtensions.Extensibility", null)
33 | },
34 | frameworks
35 | );
36 | var search = new NuGetSearchService(
37 | new NuGetSourceRepositoryFactory(),
38 | new DefaultLog(),
39 | new NuGetPackageContentService(new DefaultLog()),
40 | new NuGetPackageVersionService(
41 | new NuGetPackageContentService(new DefaultLog()),
42 | new DefaultLog(),
43 | packageFilter,
44 | frameworkFilter
45 | ),
46 | new DependencyNuGetPackageFilter(
47 | new DefaultLog(),
48 | new List() { new Args.Dependency("GitExtensions.Extensibility", "0.2.0") },
49 | frameworks
50 | )
51 | );
52 |
53 | EnsureConfigDeleted(configFilePath);
54 | var sources = new NuGetPackageSourceCollection(
55 | new PackageSourceProvider(new Settings(Environment.CurrentDirectory, configFilePath))
56 | );
57 |
58 | sources.Remove(sources.All.First());
59 | sources.Add().Name("Local").Uri(new Uri(Path.Combine(Environment.CurrentDirectory, @"..\..\..\..\..\data\NuGetFeed"), UriKind.Absolute)).Save();
60 |
61 | Assert.IsTrue(Directory.Exists(sources.All.First().Uri.AbsolutePath));
62 |
63 | return (search, sources);
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/test/PackageManager.NuGet.Tests/Services/TestInstallService.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using NuGet.Frameworks;
3 | using NuGet.Packaging;
4 | using NuGet.Versioning;
5 | using PackageManager.ViewModels.Commands;
6 | using System;
7 | using System.IO;
8 | using System.Linq;
9 |
10 | namespace PackageManager.Services
11 | {
12 | [TestClass]
13 | public class TestInstallService
14 | {
15 | public static string ExtractPath => Path.Combine(Environment.CurrentDirectory, "Plugins");
16 | public static string ExtractFilePath => Path.Combine(ExtractPath, "packages.config");
17 |
18 | private IInstallService install;
19 | private Package package = new Package(ExtractPath, "PluginA", "2.0.0");
20 |
21 | private void Reader(Action handler)
22 | {
23 | using (Stream fileContent = new FileStream(ExtractFilePath, FileMode.Open))
24 | {
25 | PackagesConfigReader reader = new PackagesConfigReader(fileContent);
26 | handler(reader);
27 | }
28 | }
29 |
30 | private void Writer(Action handler)
31 | {
32 | using (PackagesConfigWriter writer = new PackagesConfigWriter(ExtractFilePath, !File.Exists(ExtractFilePath)))
33 | {
34 | handler(writer);
35 | }
36 | }
37 |
38 | [TestInitialize]
39 | public void Initialize()
40 | {
41 | install = InstallService.Create(ExtractPath);
42 |
43 | if (File.Exists(ExtractFilePath))
44 | File.Delete(ExtractFilePath);
45 | }
46 |
47 | [TestMethod]
48 | public void Install()
49 | {
50 | install.Install(package.Object);
51 |
52 | Reader(reader =>
53 | {
54 | Assert.IsTrue(reader.GetPackages().Any(p => string.Equals(p.PackageIdentity.Id, package.Object.Id, StringComparison.CurrentCultureIgnoreCase) && string.Equals(p.PackageIdentity.Version.ToFullString(), package.Object.Version, StringComparison.CurrentCultureIgnoreCase)));
55 | });
56 | }
57 |
58 | [TestMethod]
59 | public void UnInstall()
60 | {
61 | Writer(writer => writer.AddPackageEntry("PluginA", new NuGetVersion("2.0.0"), NuGetFramework.AnyFramework));
62 |
63 | install.Uninstall(package.Object);
64 |
65 | Reader(reader =>
66 | {
67 | Assert.IsFalse(reader.GetPackages().Any(p => string.Equals(p.PackageIdentity.Id, package.Object.Id, StringComparison.CurrentCultureIgnoreCase) && string.Equals(p.PackageIdentity.Version.ToFullString(), package.Object.Version, StringComparison.CurrentCultureIgnoreCase)));
68 | });
69 | }
70 |
71 | [TestMethod]
72 | public void IsInstalled()
73 | {
74 | Assert.IsFalse(install.IsInstalled(package.Object));
75 |
76 | Writer(writer => writer.AddPackageEntry("PluginA", new NuGetVersion("2.0.0"), NuGetFramework.AnyFramework));
77 |
78 | Assert.IsTrue(install.IsInstalled(package.Object));
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/test/PackageManager.NuGet.Tests/Services/TestPackageSearchService.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using PackageManager.Models;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 |
6 | namespace PackageManager.Services
7 | {
8 | [TestClass]
9 | public class TestPackageSearchService
10 | {
11 | public const string ConfigFilePath = "PackageSource_Search.config";
12 |
13 | private ISearchService search;
14 | private IPackageSourceCollection sources;
15 |
16 | [TestInitialize]
17 | public void Initialize()
18 | {
19 | (search, sources) = SearchService.Create(ConfigFilePath);
20 | }
21 |
22 | [TestMethod]
23 | public void SearchAsync_Success()
24 | {
25 | List packages = search.SearchAsync(sources.All, "Plugin").Result.ToList();
26 | Assert.AreEqual(2, packages.Count);
27 | Assert.AreEqual("PluginA", packages[0].Id);
28 | Assert.AreEqual("PluginB", packages[1].Id);
29 | }
30 |
31 | [TestMethod]
32 | public void SearchAsync_Nothing()
33 | {
34 | List packages = search.SearchAsync(sources.All, "CustomPackage").Result.ToList();
35 | Assert.AreEqual(0, packages.Count);
36 | }
37 |
38 | [TestMethod]
39 | public void FindLatestVersionAsync()
40 | {
41 | IPackage package = search.FindLatestVersionAsync(sources.All, search.SearchAsync(sources.All, "PluginA").Result.First()).Result;
42 | Assert.IsNotNull(package);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/test/PackageManager.Tests/Arguments/TestArgs.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 |
6 | namespace PackageManager
7 | {
8 | [TestClass]
9 | public class TestArgs
10 | {
11 | private Args SerializeAndDeserialize(Args args)
12 | {
13 | string raw = args.ToString();
14 | string[] parts = raw.Split(' ');
15 | parts = parts.Select(p => p.Trim('"')).ToArray();
16 |
17 | return new Args(parts);
18 | }
19 |
20 | private void TestAndCompare(Func handler)
21 | {
22 | string path = @"C:\Temp";
23 | string moniker1 = "A";
24 | string moniker2 = "B";
25 | var dependency1 = new Args.Dependency("A", "v1.0.0");
26 | var dependency2 = new Args.Dependency("B", "v2.0.0");
27 | string selfPackageId = "C";
28 | string processToKill1 = "D.exe";
29 | string processToKill2 = "E.exe";
30 | string selfOriginalPath = @"C:\F.exe";
31 | bool isSelfUpdate = true;
32 | string selfUpdateVersion = "1.0.0";
33 |
34 | var args = new Args();
35 | args.Path = path;
36 | args.Monikers = new List() { moniker1, moniker2 };
37 | args.Dependencies = new List() { dependency1, dependency2 };
38 | args.SelfPackageId = selfPackageId;
39 | args.ProcessNamesToKillBeforeChange = new List() { processToKill1, processToKill2 };
40 | args.SelfOriginalPath = selfOriginalPath;
41 | args.IsSelfUpdate = isSelfUpdate;
42 | args.SelfUpdateVersion = selfUpdateVersion;
43 |
44 | args = handler(args);
45 | Assert.AreEqual(path, args.Path);
46 |
47 | Assert.AreEqual(2, args.Monikers.Count);
48 | Assert.AreEqual(moniker1, args.Monikers.First());
49 | Assert.AreEqual(moniker2, args.Monikers.Last());
50 |
51 | Assert.AreEqual(2, args.Dependencies.Count);
52 | Assert.AreEqual(dependency1, args.Dependencies.First());
53 | Assert.AreEqual(dependency2, args.Dependencies.Last());
54 |
55 | Assert.AreEqual(selfPackageId, args.SelfPackageId);
56 |
57 | Assert.AreEqual(2, args.ProcessNamesToKillBeforeChange.Count);
58 | Assert.AreEqual(processToKill1, args.ProcessNamesToKillBeforeChange.First());
59 | Assert.AreEqual(processToKill2, args.ProcessNamesToKillBeforeChange.Last());
60 |
61 | Assert.AreEqual(selfOriginalPath, args.SelfOriginalPath);
62 | Assert.AreEqual(isSelfUpdate, args.IsSelfUpdate);
63 | Assert.AreEqual(selfUpdateVersion, args.SelfUpdateVersion);
64 | }
65 |
66 | [TestMethod]
67 | public void All() => TestAndCompare(SerializeAndDeserialize);
68 |
69 | [TestMethod]
70 | public void Clone() => TestAndCompare(args => args.Clone());
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/test/PackageManager.Tests/PackageManager.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/test/PackageManager.Tests/ViewModels/Commands/CallCounter.cs:
--------------------------------------------------------------------------------
1 | namespace PackageManager.ViewModels.Commands
2 | {
3 | public class CallCounter
4 | {
5 | public int Count { get; private set; }
6 | public void Increment() => Count++;
7 |
8 | public static implicit operator bool(CallCounter counter) => (counter?.Count ?? 0) > 0;
9 | public static implicit operator int(CallCounter counter) => counter?.Count ?? 0;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/test/PackageManager.Tests/ViewModels/Commands/InstallService.cs:
--------------------------------------------------------------------------------
1 | using Moq;
2 | using PackageManager.Models;
3 | using PackageManager.Services;
4 | using System.Collections.Generic;
5 |
6 | namespace PackageManager.ViewModels.Commands
7 | {
8 | public class InstallService
9 | {
10 | public IInstallService Object { get; }
11 | public CallCounter InstallCalled { get; } = new CallCounter();
12 | public CallCounter UninstallCalled { get; } = new CallCounter();
13 | public CallCounter IsInstalledCalled { get; } = new CallCounter();
14 |
15 | public List InstallPackages { get; } = new List();
16 | public List UninstallPackages { get; } = new List();
17 | public List IsInstalledPackages { get; } = new List();
18 |
19 | public InstallService(string extractPath, Package installPackage = null, Package uninstallPackage = null, Package isInstalledPackage = null)
20 | {
21 | Mock mock = new Mock();
22 |
23 | mock
24 | .Setup(i => i.Install(It.Is(p => p == InstallPackages[InstallCalled])))
25 | .Callback(() => InstallCalled.Increment());
26 |
27 | mock
28 | .Setup(i => i.Uninstall(It.Is(p => p == UninstallPackages[UninstallCalled])))
29 | .Callback(() => UninstallCalled.Increment());
30 |
31 | mock
32 | .Setup(i => i.IsInstalled(It.Is(p => p == IsInstalledPackages[IsInstalledCalled])))
33 | .Callback(() => IsInstalledCalled.Increment())
34 | .Returns(true);
35 |
36 | mock
37 | .Setup(i => i.Path)
38 | .Returns(() => extractPath);
39 |
40 | if (installPackage != null)
41 | InstallPackages.Add(installPackage.Object);
42 |
43 | if (uninstallPackage != null)
44 | UninstallPackages.Add(uninstallPackage.Object);
45 |
46 | if (isInstalledPackage != null)
47 | IsInstalledPackages.Add(isInstalledPackage.Object);
48 |
49 | Object = mock.Object;
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/test/PackageManager.Tests/ViewModels/Commands/InstalledPackage.cs:
--------------------------------------------------------------------------------
1 | using Moq;
2 | using PackageManager.Models;
3 |
4 | namespace PackageManager.ViewModels.Commands
5 | {
6 | public class InstalledPackage
7 | {
8 | public IInstalledPackage Object { get; }
9 |
10 | public InstalledPackage(IPackage definition, bool isCompatible = true)
11 | {
12 | Mock mock = new Mock();
13 | mock
14 | .SetupGet(p => p.Definition)
15 | .Returns(definition);
16 |
17 | mock
18 | .SetupGet(p => p.IsCompatible)
19 | .Returns(isCompatible);
20 |
21 | Object = mock.Object;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/test/PackageManager.Tests/ViewModels/Commands/Package.cs:
--------------------------------------------------------------------------------
1 | using Moq;
2 | using PackageManager.Models;
3 | using System.IO;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace PackageManager.ViewModels.Commands
8 | {
9 | public class Package
10 | {
11 | public CallCounter GetContentCalled { get; } = new CallCounter();
12 | public CallCounter ExtractToAsyncCalled { get; } = new CallCounter();
13 | public CallCounter RemoveFromAsyncCalled { get; } = new CallCounter();
14 | public IPackage Object { get; }
15 |
16 | public Package(string extractPath, string id, string version = null)
17 | {
18 | Mock contentMock = new Mock();
19 | contentMock
20 | .Setup(pc => pc.ExtractToAsync(It.Is(s => s == Path.Combine(extractPath, id)), It.IsAny()))
21 | .Callback(() => ExtractToAsyncCalled.Increment())
22 | .Returns(() => Task.CompletedTask);
23 |
24 | contentMock
25 | .Setup(pc => pc.RemoveFromAsync(It.Is(s => s == Path.Combine(extractPath, id)), It.IsAny()))
26 | .Callback(() => RemoveFromAsyncCalled.Increment())
27 | .Returns(() => Task.CompletedTask);
28 |
29 | Mock mock = new Mock();
30 | mock
31 | .Setup(p => p.GetContentAsync(It.IsAny()))
32 | .Callback(() => GetContentCalled.Increment())
33 | .Returns(() => Task.FromResult(contentMock.Object));
34 |
35 | mock
36 | .SetupGet(p => p.Id)
37 | .Returns(id);
38 |
39 | if (version != null)
40 | {
41 | mock
42 | .SetupGet(p => p.Version)
43 | .Returns(version);
44 | }
45 |
46 | Object = mock.Object;
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/test/PackageManager.Tests/ViewModels/Commands/PackageOptions.cs:
--------------------------------------------------------------------------------
1 | using Moq;
2 |
3 | namespace PackageManager.ViewModels.Commands
4 | {
5 | public class PackageOptions
6 | {
7 | public IPackageOptions Object { get; }
8 |
9 | public PackageOptions()
10 | {
11 | Mock mock = new Mock();
12 | mock
13 | .Setup(p => p.IsPrereleaseIncluded)
14 | .Returns(() => false);
15 |
16 | Object = mock.Object;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/test/PackageManager.Tests/ViewModels/Commands/SelfUpdateService.cs:
--------------------------------------------------------------------------------
1 | using Moq;
2 | using PackageManager.Models;
3 | using PackageManager.Services;
4 | using System.Collections.Generic;
5 |
6 | namespace PackageManager.ViewModels.Commands
7 | {
8 | public class SelfUpdateService
9 | {
10 | public ISelfUpdateService Object { get; }
11 | public CallCounter IsSelfUpdateCalled { get; } = new CallCounter();
12 | public CallCounter UpdateCalled { get; } = new CallCounter();
13 | public CallCounter RunNewInstanceCalled { get; } = new CallCounter();
14 |
15 | public List UpdatePackages { get; } = new List();
16 |
17 | public SelfUpdateService(bool isSelfUpdate, Package updatePackage)
18 | {
19 | Mock mock = new Mock();
20 |
21 | mock
22 | .SetupGet(s => s.IsSelfUpdate)
23 | .Callback(() => IsSelfUpdateCalled.Increment())
24 | .Returns(isSelfUpdate);
25 |
26 | mock
27 | .Setup(s => s.Update(It.Is(p => p == UpdatePackages[UpdateCalled])))
28 | .Callback(() => UpdateCalled.Increment());
29 |
30 | mock
31 | .Setup(s => s.RunNewInstance(It.Is(p => p == UpdatePackages[RunNewInstanceCalled])))
32 | .Callback(() => RunNewInstanceCalled.Increment());
33 |
34 | if (updatePackage != null)
35 | UpdatePackages.Add(updatePackage.Object);
36 |
37 | Object = mock.Object;
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/test/PackageManager.Tests/ViewModels/Commands/UninstallAllCommandViewModel.cs:
--------------------------------------------------------------------------------
1 | using Moq;
2 | using Neptuo.Observables.Collections;
3 | using PackageManager.Models;
4 | using System.Collections.Generic;
5 |
6 | namespace PackageManager.ViewModels.Commands
7 | {
8 | public class UninstallAllCommandViewModel
9 | {
10 | public CallCounter CommandCalled { get; } = new CallCounter();
11 | public CallCounter PackagesCalled { get; } = new CallCounter();
12 |
13 | public UninstallAllCommand.IViewModel Object { get; }
14 |
15 | public UninstallAllCommandViewModel(UninstallCommand command, ICollection packages)
16 | {
17 | Mock mock = new Mock();
18 | mock
19 | .SetupGet(vm => vm.Uninstall)
20 | .Callback(() => CommandCalled.Increment())
21 | .Returns(command);
22 |
23 | mock
24 | .SetupGet(vm => vm.Packages)
25 | .Callback(() => PackagesCalled.Increment())
26 | .Returns(new ObservableCollection(packages));
27 |
28 | Object = mock.Object;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/test/PackageManager.Tests/ViewModels/Commands/UpdateAllCommandViewModel.cs:
--------------------------------------------------------------------------------
1 | using Moq;
2 | using Neptuo.Observables.Collections;
3 | using System.Collections.Generic;
4 |
5 | namespace PackageManager.ViewModels.Commands
6 | {
7 | public class UpdateAllCommandViewModel
8 | {
9 | public CallCounter CommandCalled { get; } = new CallCounter();
10 | public CallCounter PackagesCalled { get; } = new CallCounter();
11 |
12 | public UpdateAllCommand.IViewModel Object { get; }
13 |
14 | public UpdateAllCommandViewModel(UpdateCommand command, ICollection packages)
15 | {
16 | Mock mock = new Mock();
17 | mock
18 | .SetupGet(vm => vm.Update)
19 | .Callback(() => CommandCalled.Increment())
20 | .Returns(command);
21 |
22 | mock
23 | .SetupGet(vm => vm.Packages)
24 | .Callback(() => PackagesCalled.Increment())
25 | .Returns(new ObservableCollection(packages));
26 |
27 | Object = mock.Object;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------