diff --git a/lib/NuGet-Chocolatey/src/Core/IPackageManager.cs b/lib/NuGet-Chocolatey/src/Core/IPackageManager.cs
index 9abb140258..4430b10e68 100644
--- a/lib/NuGet-Chocolatey/src/Core/IPackageManager.cs
+++ b/lib/NuGet-Chocolatey/src/Core/IPackageManager.cs
@@ -1,7 +1,38 @@
using System;
+using System.Runtime.Versioning;
namespace NuGet
{
+ public enum WalkerType
+ {
+ install,
+ update,
+ uninstall
+ }
+
+ ///
+ /// Parameters for specific walker initialization.
+ ///
+ public class WalkerInfo
+ {
+ public WalkerType type;
+
+ // for install
+ public bool ignoreDependencies;
+ public bool ignoreWalkInfo = false;
+ public FrameworkName targetFramework = null;
+
+ // for update
+ public bool updateDependencies;
+
+ // for install & update
+ public bool allowPrereleaseVersions;
+
+ // for uninstall
+ public bool forceRemove;
+ public bool removeDependencies;
+ }
+
public interface IPackageManager
{
///
@@ -35,6 +66,7 @@ public interface IPackageManager
event EventHandler PackageUninstalled;
event EventHandler PackageUninstalling;
+ IPackage FindLocalPackage(string packageId, SemanticVersion version);
void InstallPackage(IPackage package, bool ignoreDependencies, bool allowPrereleaseVersions);
void InstallPackage(IPackage package, bool ignoreDependencies, bool allowPrereleaseVersions, bool ignoreWalkInfo);
void InstallPackage(string packageId, SemanticVersion version, bool ignoreDependencies, bool allowPrereleaseVersions);
@@ -43,5 +75,12 @@ public interface IPackageManager
void UpdatePackage(string packageId, IVersionSpec versionSpec, bool updateDependencies, bool allowPrereleaseVersions);
void UninstallPackage(IPackage package, bool forceRemove, bool removeDependencies);
void UninstallPackage(string packageId, SemanticVersion version, bool forceRemove, bool removeDependencies);
+
+ ///
+ /// Creates package dependency walker
+ ///
+ /// walker parameters
+ /// walker
+ IPackageOperationResolver GetWalker( WalkerInfo walkerInfo );
}
}
diff --git a/lib/NuGet-Chocolatey/src/Core/PackageManager.cs b/lib/NuGet-Chocolatey/src/Core/PackageManager.cs
index 6cc20f76a6..ac51aaf39e 100644
--- a/lib/NuGet-Chocolatey/src/Core/PackageManager.cs
+++ b/lib/NuGet-Chocolatey/src/Core/PackageManager.cs
@@ -140,22 +140,14 @@ protected void InstallPackage(
bool allowPrereleaseVersions,
bool ignoreWalkInfo = false)
{
- if (WhatIf)
- {
- // This prevents InstallWalker from downloading the packages
- ignoreWalkInfo = true;
- }
+ var installerWalker = GetWalker( new WalkerInfo {
+ type = WalkerType.install,
+ ignoreDependencies = ignoreDependencies,
+ allowPrereleaseVersions = allowPrereleaseVersions,
+ ignoreWalkInfo = ignoreWalkInfo,
+ targetFramework = targetFramework
+ } );
- var installerWalker = new InstallWalker(
- LocalRepository, SourceRepository,
- targetFramework, Logger,
- ignoreDependencies, allowPrereleaseVersions,
- DependencyVersion)
- {
- DisableWalkInfo = ignoreWalkInfo,
- CheckDowngrade = CheckDowngrade,
- SkipPackageTargetCheck = SkipPackageTargetCheck
- };
Execute(package, installerWalker);
}
@@ -176,7 +168,7 @@ private void Execute(IPackage package, IPackageOperationResolver resolver)
}
}
- protected void Execute(PackageOperation operation)
+ public void Execute(PackageOperation operation)
{
bool packageExists = LocalRepository.Exists(operation.Package);
@@ -293,7 +285,7 @@ public void UninstallPackage(string packageId, SemanticVersion version, bool for
UninstallPackage(packageId, version: version, forceRemove: forceRemove, removeDependencies: false);
}
- public virtual void UninstallPackage(string packageId, SemanticVersion version, bool forceRemove, bool removeDependencies)
+ public IPackage FindLocalPackage(string packageId, SemanticVersion version)
{
if (String.IsNullOrEmpty(packageId))
{
@@ -309,7 +301,13 @@ public virtual void UninstallPackage(string packageId, SemanticVersion version,
NuGetResources.UnknownPackage, packageId));
}
- UninstallPackage(package, forceRemove, removeDependencies);
+ return package;
+ }
+
+ public virtual void UninstallPackage(string packageId, SemanticVersion version, bool forceRemove, bool removeDependencies)
+ {
+
+ UninstallPackage(FindLocalPackage(packageId, version), forceRemove, removeDependencies);
}
public void UninstallPackage(IPackage package)
@@ -324,15 +322,11 @@ public void UninstallPackage(IPackage package, bool forceRemove)
public virtual void UninstallPackage(IPackage package, bool forceRemove, bool removeDependencies)
{
- Execute(package, new UninstallWalker(LocalRepository,
- new DependentsWalker(LocalRepository, targetFramework: null),
- targetFramework: null,
- logger: Logger,
- removeDependencies: removeDependencies,
- forceRemove: forceRemove)
- {
- DisableWalkInfo = WhatIf
- });
+ Execute(package, GetWalker( new WalkerInfo() {
+ type = WalkerType.uninstall,
+ forceRemove = forceRemove,
+ removeDependencies = removeDependencies
+ }) );
}
protected virtual void ExecuteUninstall(IPackage package)
@@ -473,16 +467,74 @@ internal void UpdatePackage(string packageId, Func resolvePackage, boo
public void UpdatePackage(IPackage newPackage, bool updateDependencies, bool allowPrereleaseVersions)
{
- Execute(newPackage, new UpdateWalker(LocalRepository,
- SourceRepository,
- new DependentsWalker(LocalRepository, targetFramework: null),
- NullConstraintProvider.Instance,
- targetFramework: null,
- logger: Logger,
- updateDependencies: updateDependencies,
- allowPrereleaseVersions: allowPrereleaseVersions));
+ var upgradeWalker = GetWalker( new WalkerInfo() {
+ type = WalkerType.update,
+ updateDependencies = updateDependencies,
+ allowPrereleaseVersions = allowPrereleaseVersions
+ });
+
+ Execute(newPackage, upgradeWalker);
+ }
+
+ public IPackageOperationResolver GetWalker( WalkerInfo walkinfo )
+ {
+ switch (walkinfo.type)
+ {
+ case WalkerType.install:
+ {
+ if (WhatIf)
+ {
+ // This prevents InstallWalker from downloading the packages
+ walkinfo.ignoreWalkInfo = true;
+ }
+
+ var installerWalker = new InstallWalker(
+ LocalRepository, SourceRepository,
+ walkinfo.targetFramework, Logger,
+ walkinfo.ignoreDependencies, walkinfo.allowPrereleaseVersions,
+ DependencyVersion)
+ {
+ DisableWalkInfo = walkinfo.ignoreWalkInfo,
+ CheckDowngrade = CheckDowngrade,
+ SkipPackageTargetCheck = SkipPackageTargetCheck
+ };
+
+ return installerWalker;
+ }
+
+ case WalkerType.update:
+ {
+ return new UpdateWalker(LocalRepository,
+ SourceRepository,
+ new DependentsWalker(LocalRepository, targetFramework: null),
+ NullConstraintProvider.Instance,
+ targetFramework: null,
+ logger: Logger,
+ updateDependencies: walkinfo.updateDependencies,
+ allowPrereleaseVersions: walkinfo.allowPrereleaseVersions);
+ }
+
+ case WalkerType.uninstall:
+ {
+ var uninstallWalker = new UninstallWalker(LocalRepository,
+ new DependentsWalker(LocalRepository, targetFramework: null),
+ targetFramework: null,
+ logger: Logger,
+ removeDependencies: walkinfo.removeDependencies,
+ forceRemove: walkinfo.forceRemove)
+ {
+ DisableWalkInfo = WhatIf
+ };
+
+ return uninstallWalker;
+ }
+ }
+
+ return null;
}
public bool CheckDowngrade { get; set; }
}
-}
\ No newline at end of file
+
+}
+
diff --git a/lib/NuGet-Chocolatey/src/Core/Packages/PackageTags.cs b/lib/NuGet-Chocolatey/src/Core/Packages/PackageTags.cs
index 4c7f7d25de..0a5c17a0cc 100644
--- a/lib/NuGet-Chocolatey/src/Core/Packages/PackageTags.cs
+++ b/lib/NuGet-Chocolatey/src/Core/Packages/PackageTags.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
@@ -40,6 +41,48 @@ public static string GetKey(this IPackage pack, string key)
return value;
}
+ ///
+ /// Gets all key value pairs from package
+ ///
+ /// package to query
+ /// Dictionary of items
+ public static Dictionary GetKeyValuePairs(this IPackage pack, Func matcher = null)
+ {
+ Dictionary d = new Dictionary();
+
+ if (matcher == null)
+ {
+ matcher = (key) => { return true; };
+ }
+
+ if (pack.TagsExtra != null)
+ {
+ foreach (var tag in pack.TagsExtra)
+ {
+ if (matcher(tag.Key))
+ {
+ d[tag.Key] = tag.Value;
+ }
+ }
+ }
+ else
+ {
+ var lines = pack.Tags.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
+
+ var keyValuePairs = lines.
+ Select(x => reSplitEqual.Match(x)).
+ Where(m => m.Success && matcher(m.Groups[1].Value)).
+ Select(m => (m.Groups[1].Value, Uri.UnescapeDataString(m.Groups[2].Value)));
+
+ foreach (var kvPair in keyValuePairs)
+ {
+ d[kvPair.Item1] = kvPair.Item2;
+ }
+ }
+
+ return d;
+ }
+
public static string GetInstallLocation(this IPackage pack)
{
return GetKey(pack, "InstallLocation");
diff --git a/lib/NuGet-Chocolatey/src/Core/Repositories/LocalPackageRepository.cs b/lib/NuGet-Chocolatey/src/Core/Repositories/LocalPackageRepository.cs
index cb8bf2d779..2fa68352b8 100644
--- a/lib/NuGet-Chocolatey/src/Core/Repositories/LocalPackageRepository.cs
+++ b/lib/NuGet-Chocolatey/src/Core/Repositories/LocalPackageRepository.cs
@@ -74,6 +74,45 @@ protected IFileSystem FileSystem
private set;
}
+ ///
+ /// When packageIdToFilesystem is in use - this must be non-null
+ ///
+ public Func GetPackageInstallPath;
+
+ ///
+ /// Package id to it's file system.
+ ///
+ public Dictionary PackageIdToFilesystem = new Dictionary();
+
+
+ ///
+ /// Gets current file system for specific package id
+ ///
+ /// package id
+ /// file system
+ public IFileSystem GetFS(string packageId)
+ {
+ IFileSystem fs;
+
+ if (GetPackageInstallPath != null && packageId != null)
+ {
+ if (!PackageIdToFilesystem.ContainsKey(packageId))
+ {
+ string dir = GetPackageInstallPath(packageId);
+ PackageIdToFilesystem[packageId] = new PhysicalFileSystem(dir);
+ }
+
+ fs = PackageIdToFilesystem[packageId];
+ }
+ else
+ {
+ fs = FileSystem;
+ }
+
+ return fs;
+ }
+
+
public override IQueryable GetPackages()
{
return GetPackages(OpenPackage).AsQueryable();
@@ -170,8 +209,8 @@ public virtual IEnumerable GetPackageLookupPaths(string packageId, Seman
var packageFileName = PathResolver.GetPackageFileName(packageId, version);
var manifestFileName = Path.ChangeExtension(packageFileName, Constants.ManifestExtension);
var filesMatchingFullName = Enumerable.Concat(
- GetPackageFiles(packageFileName),
- GetPackageFiles(manifestFileName));
+ GetPackageFiles(packageId,packageFileName),
+ GetPackageFiles(packageId, manifestFileName));
if (version != null && version.Version.Revision < 1)
{
@@ -190,15 +229,15 @@ public virtual IEnumerable GetPackageLookupPaths(string packageId, Seman
// Partial names would result is gathering package with matching major and minor but different build and revision.
// Attempt to match the version in the path to the version we're interested in.
- var partialNameMatches = GetPackageFiles(partialName).Where(path => FileNameMatchesPattern(packageId, version, path));
- var partialManifestNameMatches = GetPackageFiles(partialManifestName).Where(
+ var partialNameMatches = GetPackageFiles(packageId, partialName).Where(path => FileNameMatchesPattern(packageId, version, path));
+ var partialManifestNameMatches = GetPackageFiles(packageId, partialManifestName).Where(
path => FileNameMatchesPattern(packageId, version, path));
return Enumerable.Concat(filesMatchingFullName, partialNameMatches).Concat(partialManifestNameMatches);
}
return filesMatchingFullName;
}
- internal IPackage FindPackage(Func openPackage, string packageId, SemanticVersion version)
+ internal IPackage FindPackage(Func openPackage, string packageId, SemanticVersion version)
{
var lookupPackageName = new PackageName(packageId, version);
string packagePath;
@@ -208,19 +247,19 @@ internal IPackage FindPackage(Func openPackage, string package
FileSystem.FileExists(packagePath))
{
// When depending on the cached path, verify the file exists on disk.
- return GetPackage(openPackage, packagePath);
+ return GetPackage(packageId, openPackage, packagePath);
}
// Lookup files which start with the name "." and attempt to match it with all possible version string combinations (e.g. 1.2.0, 1.2.0.0)
// before opening the package. To avoid creating file name strings, we attempt to specifically match everything after the last path separator
// which would be the file name and extension.
return (from path in GetPackageLookupPaths(packageId, version)
- let package = GetPackage(openPackage, path)
+ let package = GetPackage(packageId, openPackage, path)
where lookupPackageName.Equals(new PackageName(package.Id, package.Version))
select package).FirstOrDefault();
}
- internal IEnumerable FindPackagesById(Func openPackage, string packageId)
+ internal IEnumerable FindPackagesById(Func openPackage, string packageId)
{
Debug.Assert(!String.IsNullOrEmpty(packageId), "The caller has to ensure packageId is never null.");
@@ -231,18 +270,18 @@ internal IEnumerable FindPackagesById(Func openPacka
GetPackages(
openPackage,
packageId,
- GetPackageFiles(packageId + "*" + Constants.PackageExtension)));
+ GetPackageFiles(packageId, packageId + "*" + Constants.PackageExtension)));
// then, get packages through nuspec files
packages.AddRange(
GetPackages(
openPackage,
packageId,
- GetPackageFiles(packageId + "*" + Constants.ManifestExtension)));
+ GetPackageFiles(packageId, packageId + "*" + Constants.ManifestExtension)));
return packages;
}
- internal IEnumerable GetPackages(Func openPackage,
+ internal IEnumerable GetPackages(Func openPackage,
string packageId,
IEnumerable packagePaths)
{
@@ -251,7 +290,7 @@ internal IEnumerable GetPackages(Func openPackage,
IPackage package = null;
try
{
- package = GetPackage(openPackage, path);
+ package = GetPackage(packageId, openPackage, path);
}
catch (InvalidOperationException)
{
@@ -277,14 +316,14 @@ internal IEnumerable GetPackages(Func openPackage,
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
Justification = "We want to suppress all errors opening a package")]
- internal IEnumerable GetPackages(Func openPackage)
+ internal IEnumerable GetPackages(Func openPackage)
{
- return GetPackageFiles()
+ return GetPackageFiles(null)
.Select(path =>
{
try
{
- return GetPackage(openPackage, path);
+ return GetPackage(null, openPackage, path);
}
catch
{
@@ -294,10 +333,11 @@ internal IEnumerable GetPackages(Func openPackage)
.Where(p => p != null);
}
- private IPackage GetPackage(Func openPackage, string path)
+ private IPackage GetPackage(string packageId, Func openPackage, string path)
{
PackageCacheEntry cacheEntry;
- DateTimeOffset lastModified = FileSystem.GetLastModified(path);
+ var fs = GetFS(packageId);
+ DateTimeOffset lastModified = fs.GetLastModified(path);
// If we never cached this file or we did and it's current last modified time is newer
// create a new entry
if (!_packageCache.TryGetValue(path, out cacheEntry) ||
@@ -307,7 +347,7 @@ private IPackage GetPackage(Func openPackage, string path)
string packagePath = path;
// Create the package
- IPackage package = openPackage(packagePath);
+ IPackage package = openPackage(packageId, packagePath);
// create a cache entry with the last modified time
cacheEntry = new PackageCacheEntry(package, lastModified);
@@ -323,34 +363,38 @@ private IPackage GetPackage(Func openPackage, string path)
return cacheEntry.Package;
}
- internal IEnumerable GetPackageFiles(string filter = null)
+ internal IEnumerable GetPackageFiles(string packageId, string filter = null)
{
filter = filter ?? "*" + Constants.PackageExtension;
Debug.Assert(
filter.EndsWith(Constants.PackageExtension, StringComparison.OrdinalIgnoreCase) ||
filter.EndsWith(Constants.ManifestExtension, StringComparison.OrdinalIgnoreCase));
+ var fs = GetFS(packageId);
+
// Check for package files one level deep. We use this at package install time
// to determine the set of installed packages. Installed packages are copied to
// {id}.{version}\{packagefile}.{extension}.
- foreach (var dir in FileSystem.GetDirectories(String.Empty))
+ foreach (var dir in fs.GetDirectories(String.Empty))
{
- foreach (var path in FileSystem.GetFiles(dir, filter))
+ foreach (var path in fs.GetFiles(dir, filter))
{
yield return path;
}
}
// Check top level directory
- foreach (var path in FileSystem.GetFiles(String.Empty, filter))
+ foreach (var path in fs.GetFiles(String.Empty, filter))
{
yield return path;
}
}
- internal virtual IPackage OpenPackage(string path)
+ internal virtual IPackage OpenPackage(string packageId, string path)
{
- if (!FileSystem.FileExists(path))
+ var fs = GetFS(packageId);
+
+ if (!fs.FileExists(path))
{
return null;
}
@@ -360,7 +404,7 @@ internal virtual IPackage OpenPackage(string path)
OptimizedZipPackage package;
try
{
- package = new OptimizedZipPackage(FileSystem, path);
+ package = new OptimizedZipPackage(fs, path);
}
catch (FileFormatException ex)
{
@@ -368,15 +412,15 @@ internal virtual IPackage OpenPackage(string path)
}
// Set the last modified date on the package
- package.Published = FileSystem.GetLastModified(path);
+ package.Published = fs.GetLastModified(path);
return package;
}
else if (Path.GetExtension(path) == Constants.ManifestExtension)
{
- if (FileSystem.FileExists(path))
+ if (fs.FileExists(path))
{
- return new UnzippedPackage(FileSystem, Path.GetFileNameWithoutExtension(path));
+ return new UnzippedPackage(fs, Path.GetFileNameWithoutExtension(path));
}
}
diff --git a/lib/NuGet-Chocolatey/src/Core/Repositories/MachineCache.cs b/lib/NuGet-Chocolatey/src/Core/Repositories/MachineCache.cs
index 0c8132d217..535493c2fa 100644
--- a/lib/NuGet-Chocolatey/src/Core/Repositories/MachineCache.cs
+++ b/lib/NuGet-Chocolatey/src/Core/Repositories/MachineCache.cs
@@ -65,7 +65,7 @@ internal static MachineCache CreateDefault(Func getCachePath)
public override void AddPackage(IPackage package)
{
// If we exceed the package count then clear the cache.
- var files = GetPackageFiles().ToList();
+ var files = GetPackageFiles(package.Id).ToList();
if (files.Count >= MaxPackages)
{
// It's expensive to hit the file system to get the last accessed date for files
@@ -144,7 +144,7 @@ public bool InvokeOnPackage(string packageId, SemanticVersion version, Action files)
diff --git a/lib/NuGet-Chocolatey/src/Core/Repositories/SharedPackageRepository.cs b/lib/NuGet-Chocolatey/src/Core/Repositories/SharedPackageRepository.cs
index 050868c104..0e1675902c 100644
--- a/lib/NuGet-Chocolatey/src/Core/Repositories/SharedPackageRepository.cs
+++ b/lib/NuGet-Chocolatey/src/Core/Repositories/SharedPackageRepository.cs
@@ -202,9 +202,11 @@ protected virtual IPackageRepository CreateRepository(string path)
return new PackageReferenceRepository(absolutePath, sourceRepository: this);
}
- internal override IPackage OpenPackage(string path)
+ internal override IPackage OpenPackage(string packageId, string path)
{
- if (!FileSystem.FileExists(path))
+ var fs = GetFS(packageId);
+
+ if (!fs.FileExists(path))
{
return null;
}
@@ -214,7 +216,7 @@ internal override IPackage OpenPackage(string path)
{
try
{
- return new SharedOptimizedZipPackage(FileSystem, path);
+ return new SharedOptimizedZipPackage(fs, path);
}
catch (FileFormatException ex)
{
diff --git a/nuspec/chocolatey/choco/choco.nuspec b/nuspec/chocolatey/choco/choco.nuspec
index f677f7d87b..2b769728f2 100644
--- a/nuspec/chocolatey/choco/choco.nuspec
+++ b/nuspec/chocolatey/choco/choco.nuspec
@@ -18,7 +18,9 @@
https://github.com/chocolatey/choco/issues-->
nuget apt-get machine repository chocolatey
-
+
+
+
Chocolatey is the package manager for Windows (like apt-get but for Windows)
@@ -67,7 +69,7 @@ In that mess there is a link to the [PowerShell Chocolatey module reference](htt
See all - https://docs.chocolatey.org/en-us/choco/release-notes
-
+
diff --git a/src/chocolatey.tests.integration/context/dependencies/reghasdependency/1.0.0/reghasdependency.nuspec b/src/chocolatey.tests.integration/context/dependencies/reghasdependency/1.0.0/reghasdependency.nuspec
new file mode 100644
index 0000000000..db6d6a8b90
--- /dev/null
+++ b/src/chocolatey.tests.integration/context/dependencies/reghasdependency/1.0.0/reghasdependency.nuspec
@@ -0,0 +1,23 @@
+
+
+
+ reghasdependency
+ 1.0.0
+ reghasdependency
+ Publisher
+ false
+ test package
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/chocolatey.tests.integration/context/dependencies/reghasdependency/1.0.0/tools/chocolateyinstall.ps1 b/src/chocolatey.tests.integration/context/dependencies/reghasdependency/1.0.0/tools/chocolateyinstall.ps1
new file mode 100644
index 0000000000..d64eb8f47b
--- /dev/null
+++ b/src/chocolatey.tests.integration/context/dependencies/reghasdependency/1.0.0/tools/chocolateyinstall.ps1
@@ -0,0 +1 @@
+Write-Output "$env:PackageName $env:PackageVersion Installed"
\ No newline at end of file
diff --git a/src/chocolatey.tests.integration/context/dependencies/reghasdependency/1.0.0/tools/chocolateyuninstall.ps1 b/src/chocolatey.tests.integration/context/dependencies/reghasdependency/1.0.0/tools/chocolateyuninstall.ps1
new file mode 100644
index 0000000000..9ead91ffa3
--- /dev/null
+++ b/src/chocolatey.tests.integration/context/dependencies/reghasdependency/1.0.0/tools/chocolateyuninstall.ps1
@@ -0,0 +1 @@
+Write-Output "$env:PackageName $env:PackageVersion Uninstalled"
\ No newline at end of file
diff --git a/src/chocolatey.tests2/ChocoTestContext.cs b/src/chocolatey.tests2/ChocoTestContext.cs
index 95403c29d6..479cd10d73 100644
--- a/src/chocolatey.tests2/ChocoTestContext.cs
+++ b/src/chocolatey.tests2/ChocoTestContext.cs
@@ -15,6 +15,7 @@ public enum ChocoTestContext
installupdate,
installupdate2,
installpackage3,
+ install_regpackage_with_dependencies,
isdependency,
isdependency_hasdependency,
isdependency_hasdependency_sxs,
@@ -36,6 +37,8 @@ public enum ChocoTestContext
packages_for_dependency_testing9,
packages_for_dependency_testing10,
packages_for_dependency_testing11,
+
+ packages_for_reg_dependency_testing,
packages_for_upgrade_testing,
upgrade_testing_context,
uninstall_testing_context,
@@ -68,5 +71,8 @@ public enum ChocoTestContext
pack_upgradepackage_1_1_0,
pack_upgradepackage_1_1_1_beta,
pack_upgradepackage_1_1_1_beta2,
+
+ pack_reghasdependency_1_0_0
};
}
+
diff --git a/src/chocolatey.tests2/LogTesting.cs b/src/chocolatey.tests2/LogTesting.cs
index a687e33ec4..0b21f8c9d6 100644
--- a/src/chocolatey.tests2/LogTesting.cs
+++ b/src/chocolatey.tests2/LogTesting.cs
@@ -29,6 +29,7 @@ public class LogTesting
protected IChocolateyPackageService Service;
public const string installpackage2_id = "installpackage2";
+ public const string reghasdependency_id = "reghasdependency";
public LogTesting()
{
@@ -658,6 +659,14 @@ bool PrepareTestContext(ChocoTestContext testcontext, ChocolateyConfiguration _c
);
break;
+ case ChocoTestContext.packages_for_reg_dependency_testing:
+ PrepareMultiPackageFolder(
+ ChocoTestContext.pack_reghasdependency_1_0_0,
+ ChocoTestContext.pack_isdependency_1_0_0,
+ ChocoTestContext.pack_isexactversiondependency_1_1_0
+ );
+ break;
+
case ChocoTestContext.packages_for_upgrade_testing:
PrepareMultiPackageFolder(
ChocoTestContext.pack_badpackage_1_0,
@@ -714,6 +723,22 @@ bool PrepareTestContext(ChocoTestContext testcontext, ChocolateyConfiguration _c
}
break;
+ case ChocoTestContext.install_regpackage_with_dependencies:
+ {
+ const string packageId = LogTesting.reghasdependency_id;
+
+ using (var tester = new TestRegistry())
+ {
+ tester.DeleteInstallEntries(packageId);
+
+ Install(packageId, "1.0.0", ChocoTestContext.packages_for_reg_dependency_testing);
+
+ tester.LogInstallEntries(true, packageId);
+ tester.DeleteInstallEntries(packageId);
+ }
+ }
+ break;
+
case ChocoTestContext.installpackage3:
{
Install("installpackage3", "1.0.0", ChocoTestContext.pack_installpackage3_1_0_0, true);
diff --git a/src/chocolatey.tests2/LogTesting/PrepareTestFolder_install_regpackage_with_dependencies.txt b/src/chocolatey.tests2/LogTesting/PrepareTestFolder_install_regpackage_with_dependencies.txt
new file mode 100644
index 0000000000..23e1d750b4
--- /dev/null
+++ b/src/chocolatey.tests2/LogTesting/PrepareTestFolder_install_regpackage_with_dependencies.txt
@@ -0,0 +1,79 @@
+Installing the following packages:
+reghasdependency
+By installing you accept licenses for the packages.
+[NuGet] Attempting to resolve dependency 'isdependency (≥ 1.0.0)'.
+[NuGet] Attempting to resolve dependency 'isexactversiondependency (= 1.1.0)'.
+[NuGet] Installing 'isdependency 1.0.0'.
+[NuGet] Successfully installed 'isdependency 1.0.0'.
+
+isdependency v1.0.0
+isdependency package files install completed. Performing other installation steps.
+isdependency 1.0.0 Installed
+ The install of isdependency was successful.
+ Software install location not explicitly set, could be in package or
+ default install location if installer.
+[NuGet] Installing 'isexactversiondependency 1.1.0'.
+[NuGet] Successfully installed 'isexactversiondependency 1.1.0'.
+
+isexactversiondependency v1.1.0
+isexactversiondependency package files install completed. Performing other installation steps.
+isexactversiondependency 1.1.0 Installed
+ The install of isexactversiondependency was successful.
+ Software install location not explicitly set, could be in package or
+ default install location if installer.
+[NuGet] Installing 'reghasdependency 1.0.0'.
+[NuGet] Successfully installed 'reghasdependency 1.0.0'.
+
+reghasdependency v1.0.0
+reghasdependency package files install completed. Performing other installation steps.
+reghasdependency 1.0.0 Installed
+ The install of reghasdependency was successful.
+ Software install location not explicitly set, could be in package or
+ default install location if installer.
+
+Chocolatey installed 3/3 packages.
+ See the log for details (logs\chocolatey.log).
+=> install result for isdependency/1.0.0: succeeded
+=> install result for isexactversiondependency/1.1.0: succeeded
+=> install result for reghasdependency/1.0.0: succeeded
+=> added new files:
+custominstalldir\lib\isexactversiondependency\.install_info\.arguments
+custominstalldir\lib\isexactversiondependency\.install_info\.files
+custominstalldir\lib\isexactversiondependency\isexactversiondependency.nupkg
+ version: 1.1.0.0
+custominstalldir\lib\isexactversiondependency\isexactversiondependency.nuspec
+custominstalldir\lib\isexactversiondependency\tools\chocolateyinstall.ps1
+custominstalldir\lib\isexactversiondependency\tools\chocolateyuninstall.ps1
+custominstalldir\plugins\isdependency\.install_info\.arguments
+custominstalldir\plugins\isdependency\.install_info\.files
+custominstalldir\plugins\isdependency\isdependency.nupkg
+ version: 1.0.0.0
+custominstalldir\plugins\isdependency\isdependency.nuspec
+custominstalldir\plugins\isdependency\tools\chocolateyinstall.ps1
+custominstalldir\plugins\isdependency\tools\chocolateyuninstall.ps1
+custominstalldir\reghasdependency\.install_info\.arguments
+custominstalldir\reghasdependency\.install_info\.files
+custominstalldir\reghasdependency\reghasdependency.nupkg
+ version: 1.0.0.0
+custominstalldir\reghasdependency\reghasdependency.nuspec
+custominstalldir\reghasdependency\tools\chocolateyinstall.ps1
+custominstalldir\reghasdependency\tools\chocolateyuninstall.ps1
+
+- after operation reghasdependency registry:
+ Hive: LocalMachine
+ KeyPath: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\reghasdependency
+ PackageId: reghasdependency
+ IsPinned: False
+ DisplayName: reghasdependency
+ InstallLocation: custominstalldir\reghasdependency
+ UninstallString: uninstall string: to do
+ HasQuietUninstall: False
+ Publisher: Publisher
+ DisplayVersion: 1.0.0
+ Version: 1.0.0
+ NoRemove: False
+ NoModify: True
+ NoRepair: True
+ EstimatedSize: 3
+
+shared context ends
diff --git a/src/chocolatey.tests2/TestRegistry.cs b/src/chocolatey.tests2/TestRegistry.cs
index 22e5d7f715..382fafc0e1 100644
--- a/src/chocolatey.tests2/TestRegistry.cs
+++ b/src/chocolatey.tests2/TestRegistry.cs
@@ -74,14 +74,17 @@ public void AddInstallEntry(RegistryApplicationKey appKey)
registryService.set_key_values(appKey, propNames.ToArray());
}
- public void AddInstallPackage2Entry()
+ public void AddInstallPackage2Entry(
+ string packageId = "installpackage2",
+ string installdirectory = "custominstalldir",
+ string version = "1.0.0" )
{
AddInstallEntry(
new RegistryApplicationKey()
{
- PackageId = "installpackage2",
- Version = "1.0.0",
- InstallLocation = Path.Combine(InstallContext.Instance.RootLocation, "custominstalldir", "installpackage2"),
+ PackageId = packageId,
+ Version = version,
+ InstallLocation = Path.Combine(InstallContext.Instance.RootLocation, installdirectory, packageId),
Tags = "test"
}
);
diff --git a/src/chocolatey.tests2/commands/TestInstallCommand.cs b/src/chocolatey.tests2/commands/TestInstallCommand.cs
index 85345a0067..6746e60885 100644
--- a/src/chocolatey.tests2/commands/TestInstallCommand.cs
+++ b/src/chocolatey.tests2/commands/TestInstallCommand.cs
@@ -478,6 +478,26 @@ public void when_installing_regpackage_on_already_installed()
}
}
+ [LogTest]
+ public void when_installing_regpackage_with_dependencies_on_empty()
+ {
+ string packageId = reghasdependency_id;
+
+ using (var tester = new TestRegistry())
+ {
+ tester.DeleteInstallEntries(packageId);
+ tester.LogInstallEntries(false, packageId);
+
+ InstallOnEmpty((conf) =>
+ {
+ conf.PackageNames = conf.Input = packageId;
+ }, ChocoTestContext.packages_for_reg_dependency_testing);
+
+ tester.LogInstallEntries(true, packageId);
+ tester.DeleteInstallEntries(packageId);
+ }
+ }
+
}
}
diff --git a/src/chocolatey.tests2/commands/TestInstallCommand/when_installing_regpackage_with_dependencies_on_empty.txt b/src/chocolatey.tests2/commands/TestInstallCommand/when_installing_regpackage_with_dependencies_on_empty.txt
new file mode 100644
index 0000000000..4ad95df5f3
--- /dev/null
+++ b/src/chocolatey.tests2/commands/TestInstallCommand/when_installing_regpackage_with_dependencies_on_empty.txt
@@ -0,0 +1,81 @@
+
+- before operation reghasdependency - not installed
+Installing the following packages:
+reghasdependency
+By installing you accept licenses for the packages.
+[NuGet] Attempting to resolve dependency 'isdependency (≥ 1.0.0)'.
+[NuGet] Attempting to resolve dependency 'isexactversiondependency (= 1.1.0)'.
+[NuGet] Installing 'isdependency 1.0.0'.
+[NuGet] Successfully installed 'isdependency 1.0.0'.
+
+isdependency v1.0.0
+isdependency package files install completed. Performing other installation steps.
+isdependency 1.0.0 Installed
+ The install of isdependency was successful.
+ Software install location not explicitly set, could be in package or
+ default install location if installer.
+[NuGet] Installing 'isexactversiondependency 1.1.0'.
+[NuGet] Successfully installed 'isexactversiondependency 1.1.0'.
+
+isexactversiondependency v1.1.0
+isexactversiondependency package files install completed. Performing other installation steps.
+isexactversiondependency 1.1.0 Installed
+ The install of isexactversiondependency was successful.
+ Software install location not explicitly set, could be in package or
+ default install location if installer.
+[NuGet] Installing 'reghasdependency 1.0.0'.
+[NuGet] Successfully installed 'reghasdependency 1.0.0'.
+
+reghasdependency v1.0.0
+reghasdependency package files install completed. Performing other installation steps.
+reghasdependency 1.0.0 Installed
+ The install of reghasdependency was successful.
+ Software install location not explicitly set, could be in package or
+ default install location if installer.
+
+Chocolatey installed 3/3 packages.
+ See the log for details (logs\chocolatey.log).
+=> install result for isdependency/1.0.0: succeeded
+=> install result for isexactversiondependency/1.1.0: succeeded
+=> install result for reghasdependency/1.0.0: succeeded
+=> added new files:
+custominstalldir\lib\isexactversiondependency\.install_info\.arguments
+custominstalldir\lib\isexactversiondependency\.install_info\.files
+custominstalldir\lib\isexactversiondependency\isexactversiondependency.nupkg
+ version: 1.1.0.0
+custominstalldir\lib\isexactversiondependency\isexactversiondependency.nuspec
+custominstalldir\lib\isexactversiondependency\tools\chocolateyinstall.ps1
+custominstalldir\lib\isexactversiondependency\tools\chocolateyuninstall.ps1
+custominstalldir\plugins\isdependency\.install_info\.arguments
+custominstalldir\plugins\isdependency\.install_info\.files
+custominstalldir\plugins\isdependency\isdependency.nupkg
+ version: 1.0.0.0
+custominstalldir\plugins\isdependency\isdependency.nuspec
+custominstalldir\plugins\isdependency\tools\chocolateyinstall.ps1
+custominstalldir\plugins\isdependency\tools\chocolateyuninstall.ps1
+custominstalldir\reghasdependency\.install_info\.arguments
+custominstalldir\reghasdependency\.install_info\.files
+custominstalldir\reghasdependency\reghasdependency.nupkg
+ version: 1.0.0.0
+custominstalldir\reghasdependency\reghasdependency.nuspec
+custominstalldir\reghasdependency\tools\chocolateyinstall.ps1
+custominstalldir\reghasdependency\tools\chocolateyuninstall.ps1
+
+- after operation reghasdependency registry:
+ Hive: LocalMachine
+ KeyPath: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\reghasdependency
+ PackageId: reghasdependency
+ IsPinned: False
+ DisplayName: reghasdependency
+ InstallLocation: custominstalldir\reghasdependency
+ UninstallString: uninstall string: to do
+ HasQuietUninstall: False
+ Publisher: Publisher
+ DisplayVersion: 1.0.0
+ Version: 1.0.0
+ NoRemove: False
+ NoModify: True
+ NoRepair: True
+ EstimatedSize: 3
+
+end of test
diff --git a/src/chocolatey.tests2/commands/TestUninstallCommand.cs b/src/chocolatey.tests2/commands/TestUninstallCommand.cs
index f99ae73529..9633d49111 100644
--- a/src/chocolatey.tests2/commands/TestUninstallCommand.cs
+++ b/src/chocolatey.tests2/commands/TestUninstallCommand.cs
@@ -216,6 +216,29 @@ public void when_uninstalling_registry_package()
}
+ [LogTest]
+ public void when_uninstalling_regpackage_with_dependencies()
+ {
+ string packageId = reghasdependency_id;
+
+ using (var tester = new TestRegistry(false))
+ {
+ TestUninstall((conf) =>
+ {
+ conf.PackageNames = conf.Input = packageId;
+ conf.ForceDependencies = true;
+
+ tester.Lock();
+ tester.AddInstallPackage2Entry(packageId);
+ tester.LogInstallEntries(false, packageId);
+
+ }, ChocoTestContext.install_regpackage_with_dependencies);
+
+ tester.LogInstallEntries(true, packageId);
+ tester.DeleteInstallEntries(packageId);
+ }
+ }
+
}
}
diff --git a/src/chocolatey.tests2/commands/TestUninstallCommand/when_uninstalling_regpackage_with_dependencies.txt b/src/chocolatey.tests2/commands/TestUninstallCommand/when_uninstalling_regpackage_with_dependencies.txt
new file mode 100644
index 0000000000..a225dc6a35
--- /dev/null
+++ b/src/chocolatey.tests2/commands/TestUninstallCommand/when_uninstalling_regpackage_with_dependencies.txt
@@ -0,0 +1,71 @@
+
+- before operation reghasdependency registry:
+ Hive: LocalMachine
+ KeyPath: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\reghasdependency
+ PackageId: reghasdependency
+ IsPinned: False
+ DisplayName: reghasdependency
+ InstallLocation: custominstalldir\reghasdependency
+ UninstallString: none
+ HasQuietUninstall: False
+ Publisher: TestRegistry
+ DisplayVersion: 1.0.0
+ Version: 1.0.0
+ NoRemove: False
+ NoModify: False
+ NoRepair: False
+ EstimatedSize: 0
+ Tags: test
+
+Uninstalling the following packages:
+reghasdependency
+[NuGet] Uninstalling 'reghasdependency 1.0.0'.
+
+reghasdependency v1.0.0
+reghasdependency 1.0.0 Uninstalled
+ Skipping auto uninstaller - No registry snapshot.
+[NuGet] Successfully uninstalled 'reghasdependency 1.0.0'.
+ reghasdependency has been successfully uninstalled.
+[NuGet] Uninstalling 'isexactversiondependency 1.1.0'.
+
+isexactversiondependency v1.1.0
+isexactversiondependency 1.1.0 Uninstalled
+ Skipping auto uninstaller - No registry snapshot.
+[NuGet] Successfully uninstalled 'isexactversiondependency 1.1.0'.
+ isexactversiondependency has been successfully uninstalled.
+[NuGet] Uninstalling 'isdependency 1.0.0'.
+
+isdependency v1.0.0
+isdependency 1.0.0 Uninstalled
+ Skipping auto uninstaller - No registry snapshot.
+[NuGet] Successfully uninstalled 'isdependency 1.0.0'.
+ isdependency has been successfully uninstalled.
+
+Chocolatey uninstalled 3/3 packages.
+ See the log for details (logs\chocolatey.log).
+=> uninstall result for isdependency/1.0.0: succeeded
+=> uninstall result for isexactversiondependency/1.1.0: succeeded
+=> uninstall result for reghasdependency/1.0.0: succeeded
+=> folder was not updated
+=> removed files:
+custominstalldir\lib\isexactversiondependency\.install_info\.arguments
+custominstalldir\lib\isexactversiondependency\.install_info\.files
+custominstalldir\lib\isexactversiondependency\isexactversiondependency.nupkg
+custominstalldir\lib\isexactversiondependency\isexactversiondependency.nuspec
+custominstalldir\lib\isexactversiondependency\tools\chocolateyinstall.ps1
+custominstalldir\lib\isexactversiondependency\tools\chocolateyuninstall.ps1
+custominstalldir\plugins\isdependency\.install_info\.arguments
+custominstalldir\plugins\isdependency\.install_info\.files
+custominstalldir\plugins\isdependency\isdependency.nupkg
+custominstalldir\plugins\isdependency\isdependency.nuspec
+custominstalldir\plugins\isdependency\tools\chocolateyinstall.ps1
+custominstalldir\plugins\isdependency\tools\chocolateyuninstall.ps1
+custominstalldir\reghasdependency\.install_info\.arguments
+custominstalldir\reghasdependency\.install_info\.files
+custominstalldir\reghasdependency\reghasdependency.nupkg
+custominstalldir\reghasdependency\reghasdependency.nuspec
+custominstalldir\reghasdependency\tools\chocolateyinstall.ps1
+custominstalldir\reghasdependency\tools\chocolateyuninstall.ps1
+
+- after operation reghasdependency - not installed
+end of test
diff --git a/src/chocolatey.tests2/commands/TestUpgradeCommand.cs b/src/chocolatey.tests2/commands/TestUpgradeCommand.cs
index 39ddb7df4f..915f364325 100644
--- a/src/chocolatey.tests2/commands/TestUpgradeCommand.cs
+++ b/src/chocolatey.tests2/commands/TestUpgradeCommand.cs
@@ -588,28 +588,28 @@ public void when_upgrading_all_packages_with_except()
[LogTest]
public void when_upgrading_regpackage()
{
+ string packageId = installpackage2_id;
+
using (var tester = new TestRegistry(false))
{
TestUpgrade(
(conf) =>
{
- conf.PackageNames = conf.Input = installpackage2_id;
+ conf.PackageNames = conf.Input = packageId;
tester.Lock();
- tester.AddInstallPackage2Entry();
- tester.LogInstallEntries(false, installpackage2_id);
+ tester.AddInstallPackage2Entry(packageId);
+ tester.LogInstallEntries(false, packageId);
},
ChocoTestContext.installupdate2,
ChocoTestContext.pack_installpackage2_2_3_0
);
- tester.LogInstallEntries(true, installpackage2_id);
- tester.DeleteInstallEntries(installpackage2_id);
+ tester.LogInstallEntries(true, packageId);
+ tester.DeleteInstallEntries(packageId);
}
}
-
-
}
}
diff --git a/src/chocolatey.tests2/infrastructure.app/services/NugetServiceSpecs.cs b/src/chocolatey.tests2/infrastructure.app/services/NugetServiceSpecs.cs
index 26c52ec9ee..cbe5c72113 100644
--- a/src/chocolatey.tests2/infrastructure.app/services/NugetServiceSpecs.cs
+++ b/src/chocolatey.tests2/infrastructure.app/services/NugetServiceSpecs.cs
@@ -3,6 +3,7 @@
using chocolatey.infrastructure.app.domain;
using chocolatey.infrastructure.app.services;
using chocolatey.infrastructure.filesystem;
+using chocolatey.infrastructure.logging;
using logtesting;
using Moq;
using NuGet;
@@ -133,5 +134,66 @@ public void TestBackupRemove()
service.pack_noop(config);
}
}
+
+ ///
+ /// Makes dummy package with specific tags
+ ///
+ /// tags to add to package
+ /// new package
+ RegistryPackage NewPack(string packageId, params string[] tags)
+ {
+ var p = new RegistryPackage() { Id = packageId };
+
+ p.Tags = "";
+ p.TagsExtra = new List();
+ for (int i = 0; i < tags.Length; i += 2)
+ {
+ p.TagsExtra.Add(new NuGet.Authoring.Tag() { Key = tags[i], Value = tags[i + 1] });
+ }
+
+ return p;
+ }
+
+ [LogTest]
+ public void InstallFolderSelection()
+ {
+ var main = NewPack("mainp",
+ "InstallLocation", "%RootLocation%\\installdir",
+
+ // Parent package may define general installation directory
+ "AddonsInstallFolder", "addons",
+
+ // Parent package may define multiple child install locations
+ "*.plugin_InstallFolder", "plugins",
+
+ // Parent package may define child install location
+ "forth.plugin_InstallFolder", "forthplugin_special"
+ );
+
+ List packages = new List();
+ packages.Add(main);
+ packages.Add(NewPack("childp1"));
+ packages.Add(NewPack("childp2"));
+ packages.Add(NewPack("first.plugin"));
+ packages.Add(NewPack("second.plugin"));
+ packages.Add(
+ NewPack("third.plugin",
+ // plugin can override it's install location
+ "InstallLocation", "%RootLocation%\\thirdplugin_special"
+ )
+ );
+ packages.Add(NewPack("forth.plugin"));
+
+ // does not end with '.plugin' must not match.
+ packages.Add(NewPack("fifth.plugin2"));
+
+ foreach (var p in packages)
+ {
+ var dir = NugetService.GetInstallDirectory(main, p);
+ string id2 = "'" + p.Id + "'";
+ LogService.console.Info(InstallContext.NormalizeMessage($"Package {id2,-15} - install dir: '{dir}'"));
+ }
+ }
+
}
}
diff --git a/src/chocolatey.tests2/infrastructure.app/services/NugetServiceSpecs/InstallFolderSelection.txt b/src/chocolatey.tests2/infrastructure.app/services/NugetServiceSpecs/InstallFolderSelection.txt
new file mode 100644
index 0000000000..71b40e1152
--- /dev/null
+++ b/src/chocolatey.tests2/infrastructure.app/services/NugetServiceSpecs/InstallFolderSelection.txt
@@ -0,0 +1,9 @@
+Package 'mainp' - install dir: 'installdir'
+Package 'childp1' - install dir: 'installdir\addons'
+Package 'childp2' - install dir: 'installdir\addons'
+Package 'first.plugin' - install dir: 'installdir\plugins'
+Package 'second.plugin' - install dir: 'installdir\plugins'
+Package 'third.plugin' - install dir: 'thirdplugin_special'
+Package 'forth.plugin' - install dir: 'installdir\forthplugin_special'
+Package 'fifth.plugin2' - install dir: 'installdir\addons'
+end of test
diff --git a/src/chocolatey/infrastructure.app/nuget/ChocolateyNugetLogger.cs b/src/chocolatey/infrastructure.app/nuget/ChocolateyNugetLogger.cs
index 14fbbaa27c..eeb39fce5f 100644
--- a/src/chocolatey/infrastructure.app/nuget/ChocolateyNugetLogger.cs
+++ b/src/chocolatey/infrastructure.app/nuget/ChocolateyNugetLogger.cs
@@ -28,27 +28,29 @@ public FileConflictResolution ResolveFileConflict(string message)
return FileConflictResolution.OverwriteAll;
}
+ public const string NuGet = "[NuGet] ";
+
public void Log(MessageLevel level, string message, params object[] args)
{
switch (level)
{
case MessageLevel.Debug:
- this.Log().Debug("[NuGet] " + message, args);
+ this.Log().Debug(NuGet + message, args);
break;
case MessageLevel.Info:
- this.Log().Info("[NuGet] " + message, args);
+ this.Log().Info(NuGet + message, args);
break;
case MessageLevel.Warning:
- this.Log().Warn("[NuGet] " + message, args);
+ this.Log().Warn(NuGet + message, args);
break;
case MessageLevel.Error:
- this.Log().Error("[NuGet] " + message, args);
+ this.Log().Error(NuGet + message, args);
break;
case MessageLevel.Fatal:
- this.Log().Fatal("[NuGet] " + message, args);
+ this.Log().Fatal(NuGet + message, args);
break;
case MessageLevel.Verbose:
- this.Log().Info(ChocolateyLoggers.Verbose, "[NuGet] " + message, args);
+ this.Log().Info(ChocolateyLoggers.Verbose, NuGet + message, args);
break;
}
}
diff --git a/src/chocolatey/infrastructure.app/nuget/PackageManagerEx.cs b/src/chocolatey/infrastructure.app/nuget/PackageManagerEx.cs
index f53e70668b..6a7e418469 100644
--- a/src/chocolatey/infrastructure.app/nuget/PackageManagerEx.cs
+++ b/src/chocolatey/infrastructure.app/nuget/PackageManagerEx.cs
@@ -25,7 +25,7 @@ public PackageManagerEx(
///
/// Finds locally installed package - either in local repostory or via registry
///
- public IPackage FindLocalPackage(string packageName)
+ public IPackage FindAnyLocalPackage(string packageName)
{
IPackage package = LocalRepository.FindPackage(packageName);
if (package != null)
diff --git a/src/chocolatey/infrastructure.app/services/NugetService.cs b/src/chocolatey/infrastructure.app/services/NugetService.cs
index a49c77eec8..1380ea2b1a 100644
--- a/src/chocolatey/infrastructure.app/services/NugetService.cs
+++ b/src/chocolatey/infrastructure.app/services/NugetService.cs
@@ -493,7 +493,7 @@ public virtual ConcurrentDictionary install_run(Chocolate
config = originalConfig.deep_copy();
//todo: get smarter about realizing multiple versions have been installed before and allowing that
- IPackage installedPackage = packageManager.FindLocalPackage(packageName);
+ IPackage installedPackage = packageManager.FindAnyLocalPackage(packageName);
if (installedPackage != null && (version == null || version == installedPackage.Version) && !config.Force)
{
@@ -536,7 +536,7 @@ Version was specified as '{0}'. It is possible that version
@"
Please see https://chocolatey.org/docs/troubleshooting for more
assistance.");
-
+
if (ApplicationParameters.runningUnitTesting)
{
logMessage = $"{packageName} not installed. The package was not found with the source(s) listed.";
@@ -548,36 +548,7 @@ Version was specified as '{0}'. It is possible that version
continue;
}
- // Figure out installation directory.
- string targetDir = availablePackage.GetInstallLocation();
- if (string.IsNullOrEmpty(targetDir))
- {
- targetDir = InstallContext.Instance.PackagesLocation;
- }else
- {
- // properties use "$propertykey$", use '%' to avoid conflicts
- targetDir = Regex.Replace(targetDir, "%(.*?)%", (m) =>
- {
- Environment.SpecialFolder e;
- string propKey = m.Groups[1].Value;
-
- // Using "%ProgramFiles%\yourcompany" can set install directory to program files
- if (Enum.TryParse(propKey, out e))
- {
- return Environment.GetFolderPath(e);
- }
-
- // Using "%RootLocation%\plugins" can set install directory to plugins folder.
- var prop = typeof(InstallContext).GetProperty(propKey, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
- if (prop != null && prop.PropertyType == typeof(string))
- {
- return (string)prop.GetValue(InstallContext.Instance);
- }
-
- return m.Value;
- });
- }
- packageManager.FileSystem.Root = targetDir;
+ packageManager.FileSystem.Root = GetInstallDirectory(availablePackage, availablePackage);
if (installedPackage != null && (installedPackage.Version == availablePackage.Version) && config.Force)
{
@@ -605,39 +576,296 @@ Version was specified as '{0}'. It is possible that version
}
}
- try
+ var installWalker = new WalkerInfo
{
- using (packageManager.SourceRepository.StartOperation(
- RepositoryOperationNames.Install,
- packageName,
- version == null ? null : version.ToString()))
+ type = WalkerType.install,
+ ignoreDependencies = config.IgnoreDependencies,
+ allowPrereleaseVersions = config.Prerelease
+ };
+
+ SetPathResolver(packageManager, availablePackage, availablePackage);
+ DoOperation(installWalker, packageName, version, availablePackage, packageManager, packageInstalls, continueAction);
+ }
+
+ OptimizedZipPackage.NuGetScratchFileSystem.DeleteDirectory(null, true);
+ return packageInstalls;
+ }
+
+ ///
+ /// Gets package installation directory.
+ ///
+ /// Generally 'InstallLocation' tag determines where specific package gets installed - it also determines where
+ /// dependent packages will be installed as well.
+ ///
+ /// 'AddonsInstallFolder' determines into which folder all application addons (=dependencies)
+ /// will be installed (from 'InstallLocation' folder).
+ ///
+ /// Additionally '{selector}_InstallFolder' can enforce specific package location.
+ /// where selection can be just 'package id' or text + asterisk for multiple package id selection.
+ /// You can use '*plugin' to select 'firstplugin' & 'secondplugin' packages.
+ ///
+ /// Main package to be installed (which has dependencies)
+ /// Child package (who's install directory is determined by mainpackage)
+ /// sub package id as a string if subpackage is not given
+ public static string GetInstallDirectory(IPackage mainPackage, IPackage subpackage, string subpackageId = null)
+ {
+ // Figure out installation directory.
+ string targetDir = subpackage?.GetInstallLocation();
+
+ if (subpackage != null)
+ {
+ subpackageId = subpackage.Id;
+ }
+
+ if (subpackage == null && mainPackage.Id == subpackageId)
+ {
+ subpackage = mainPackage;
+ }
+
+ if (string.IsNullOrEmpty(targetDir) && mainPackage != subpackage)
+ {
+ targetDir = mainPackage.GetInstallLocation();
+
+ string addonsDirectory = mainPackage.GetKey($"{subpackageId}_InstallFolder");
+ const string installFolderSuffix = "_InstallFolder";
+
+ if (string.IsNullOrEmpty(addonsDirectory))
+ {
+ var keyValuePairs = mainPackage.GetKeyValuePairs(x => x.EndsWith(installFolderSuffix));
+
+ foreach (var kvpair in keyValuePairs)
{
- packageManager.InstallPackage(availablePackage, ignoreDependencies: config.IgnoreDependencies, allowPrereleaseVersions: config.Prerelease);
- //packageManager.InstallPackage(packageName, version, configuration.IgnoreDependencies, configuration.Prerelease);
- remove_nuget_cache_for_package(availablePackage);
+ string key = kvpair.Key;
+ key = key.Substring(0, key.Length - installFolderSuffix.Length);
+ bool takeEntry = false;
+
+ if (!key.Contains("*"))
+ {
+ takeEntry = key == subpackageId;
+ }
+ else
+ {
+ takeEntry = Regex.IsMatch(subpackageId, "^" + Regex.Escape(key).Replace("\\*", ".*") + "$");
+ }
+
+ if(takeEntry)
+ {
+ addonsDirectory = kvpair.Value;
+ break;
+ }
}
}
- catch (Exception ex)
+
+ if (string.IsNullOrEmpty(addonsDirectory))
+ {
+ addonsDirectory = mainPackage.GetKey("AddonsInstallFolder");
+ }
+
+ if (!string.IsNullOrEmpty(addonsDirectory))
{
- var message = ex.Message;
- var webException = ex as System.Net.WebException;
- if (webException != null)
+ targetDir = Path.Combine(targetDir, addonsDirectory);
+ }
+ }
+
+ if (string.IsNullOrEmpty(targetDir))
+ {
+ targetDir = InstallContext.Instance.PackagesLocation;
+ }
+ else
+ {
+ // properties use "$propertykey$", use '%' to avoid conflicts
+ targetDir = Regex.Replace(targetDir, "%(.*?)%", (m) =>
+ {
+ Environment.SpecialFolder e;
+ string propKey = m.Groups[1].Value;
+
+ // Using "%ProgramFiles%\yourcompany" can set install directory to program files
+ if (Enum.TryParse(propKey, out e))
{
- var response = webException.Response as HttpWebResponse;
- if (response != null && !string.IsNullOrWhiteSpace(response.StatusDescription)) message += " {0}".format_with(response.StatusDescription);
+ return Environment.GetFolderPath(e);
}
- var logMessage = "{0} not installed. An error occurred during installation:{1} {2}".format_with(packageName, Environment.NewLine, message);
- this.Log().Error(ChocolateyLoggers.Important, logMessage);
- var errorResult = packageInstalls.GetOrAdd(packageName, new PackageResult(packageName, version.to_string(), null));
- errorResult.Messages.Add(new ResultMessage(ResultType.Error, logMessage));
- if (errorResult.ExitCode == 0) errorResult.ExitCode = 1;
- if (continueAction != null) continueAction.Invoke(errorResult);
+ // Using "%RootLocation%\plugins" can set install directory to plugins folder.
+ var prop = typeof(InstallContext).GetProperty(propKey, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
+ if (prop != null && prop.PropertyType == typeof(string))
+ {
+ return (string)prop.GetValue(InstallContext.Instance);
+ }
+
+ return m.Value;
+ });
+ }
+
+ return targetDir;
+ }
+
+ ///
+ /// Set package path resolver - to either one folder when we know which package we will install and into which folder,
+ /// or resolving to multiple paths, when there are multiple packages in questions and they are installed into different folders.
+ ///
+ /// mainPackage which controls subpackages
+ /// currently installed main package
+ /// update package
+ void SetPathResolver(PackageManagerEx packageManager, IPackage mainPackage, IPackage updateSubPackage, IPackage mainInstalledPackage = null)
+ {
+ bool setMultiPathResolver = updateSubPackage != null &&
+ mainInstalledPackage != null &&
+ mainInstalledPackage.Id == updateSubPackage.Id;
+
+ var packageRepo = (ChocolateyLocalPackageRepository)packageManager.LocalRepository;
+
+ packageRepo.PackageIdToFilesystem.Clear();
+
+ string mainPackageDir;
+ bool mainPackageIsRegistryPackage;
+
+ if (mainInstalledPackage != null && mainInstalledPackage is RegistryPackage regp)
+ {
+ // Installation can be seen from registry only
+ mainPackageDir = Path.GetDirectoryName(regp.GetPackageLocation());
+ mainPackageIsRegistryPackage = true;
+ }
+ else
+ {
+ // Normal installation
+ mainPackageDir = GetInstallDirectory(mainPackage, updateSubPackage ?? mainPackage);
+ mainPackageIsRegistryPackage = false;
+ }
+
+ if (!setMultiPathResolver)
+ {
+ packageManager.FileSystem.Root = mainPackageDir;
+ packageRepo.GetPackageInstallPath = null;
+ }
+ else
+ {
+ // Multiple packages, each is installed into it's own independent folder.
+ packageManager.FileSystem.Root = mainPackageDir;
+
+ IPackage trueMainPackage = mainPackage;
+ if (mainPackageIsRegistryPackage)
+ {
+ // We need to get same Tags as in meta-data, registry does not keep this information currently.
+ trueMainPackage = packageManager.LocalRepository.FindPackagesById(mainPackage.Id).FirstOrDefault();
}
+ trueMainPackage ??= mainPackage;
+
+ packageRepo.GetPackageInstallPath = (packageId) =>
+ {
+ if (packageId == mainPackage.Id)
+ {
+ return mainPackageDir;
+ }
+
+ return GetInstallDirectory(trueMainPackage, null, packageId);
+ };
}
+ }
- OptimizedZipPackage.NuGetScratchFileSystem.DeleteDirectory(null, true);
- return packageInstalls;
+ ///
+ /// Performs specific nuget operation (install / uninstall / update)
+ ///
+ /// available package
+ /// operation to perform
+ /// action executed before main nuget package operation
+ /// action executed after main nuget package operation
+ void DoOperation(
+ WalkerInfo walkerInfo, string packageName, SemanticVersion packageVersion, IPackage package,
+ PackageManagerEx packageManager, ConcurrentDictionary packageResults,
+ Action continueAction,
+ Action beforeOp = null,
+ Action afterOp = null
+ )
+ {
+ string packageVersionStr = packageVersion?.ToString();
+
+ try
+ {
+ using (packageManager.SourceRepository.StartOperation(walkerInfo.type.ToString(), packageName, packageVersionStr) )
+ {
+ if (beforeOp != null)
+ {
+ beforeOp();
+ }
+
+ if (walkerInfo.type == WalkerType.uninstall)
+ {
+ // package could be Registy package, need to find right one which is installed
+ package = packageManager.FindLocalPackage(package.Id.to_lower(), packageVersion);
+ }
+
+ var walker = packageManager.GetWalker(walkerInfo);
+ var operations = walker.ResolveOperations(package);
+
+ if (operations.Any())
+ {
+ foreach (PackageOperation operation in operations)
+ {
+ SetPathResolver(packageManager, package, operation.Package);
+ packageManager.Execute(operation);
+ }
+ }
+ else
+ {
+ if (walkerInfo.type != WalkerType.uninstall)
+ {
+ packageManager.Logger.Log(MessageLevel.Verbose, $"'{package.GetFullName()}' already installed.");
+ }
+ }
+
+ SetPathResolver(packageManager, package, null);
+
+ if (afterOp != null)
+ {
+ afterOp();
+ }
+
+ remove_nuget_cache_for_package(package);
+ }
+ }
+ catch (Exception ex)
+ {
+ var message = ex.Message;
+ var webException = ex as WebException;
+ if (webException != null)
+ {
+ var response = webException.Response as HttpWebResponse;
+ if (response != null && !string.IsNullOrWhiteSpace(response.StatusDescription)) message += " {0}".format_with(response.StatusDescription);
+ }
+
+ string logMessage;
+ string reportPackageName;
+ PackageResult reportPackageResult;
+
+ switch (walkerInfo.type)
+ {
+ default:
+ case WalkerType.install:
+ logMessage = "not installed. An error occurred during installation";
+ reportPackageName = packageName.to_lower();
+ reportPackageResult = new PackageResult(packageName, packageVersionStr.to_string(), null);
+ break;
+ case WalkerType.update:
+ logMessage = "not upgraded. An error occurred during installation";
+ reportPackageName = packageName.to_lower();
+ reportPackageResult = new PackageResult(packageName, packageVersionStr.to_string(), null);
+ break;
+ case WalkerType.uninstall: logMessage = "not uninstalled. An error occurred during uninstall";
+ reportPackageName = packageName.to_lower() + "." + packageVersion.to_string();
+ reportPackageResult = new PackageResult(package, _fileSystem.combine_paths(ApplicationParameters.PackagesLocation, package.Id));
+ break;
+ }
+
+ logMessage = $"{packageName} {logMessage}:\n {message}";
+ logMessage = InstallContext.NormalizeMessage(logMessage);
+ this.Log().Error(ChocolateyLoggers.Important, logMessage);
+
+ var result = packageResults.GetOrAdd(reportPackageName, reportPackageResult);
+ result.Messages.Add(new ResultMessage(ResultType.Error, logMessage));
+
+ if (result.ExitCode == 0) result.ExitCode = 1;
+ if (continueAction != null) continueAction.Invoke(result);
+ }
}
public virtual void remove_rollback_directory_if_exists(string packageName)
@@ -708,7 +936,7 @@ public virtual ConcurrentDictionary upgrade_run(Chocolate
// reset config each time through
config = originalConfig.deep_copy();
- IPackage installedPackage = packageManager.FindLocalPackage(packageName);
+ IPackage installedPackage = packageManager.FindAnyLocalPackage(packageName);
if (installedPackage == null)
{
@@ -902,64 +1130,49 @@ public virtual ConcurrentDictionary upgrade_run(Chocolate
if (performAction)
{
- if (installedPackage is RegistryPackage regp)
+ WalkerInfo walker = new WalkerInfo()
+ {
+ ignoreDependencies = config.IgnoreDependencies,
+ allowPrereleaseVersions = config.Prerelease,
+ updateDependencies = !config.IgnoreDependencies,
+ };
+
+ if (config.Force && (installedPackage.Version == availablePackage.Version))
{
- packageManager.FileSystem.Root = Path.GetDirectoryName(regp.GetPackageLocation());
+ walker.type = WalkerType.install;
+ }
+ else
+ {
+ walker.type = WalkerType.update;
}
- try
+ Action beforeOp = () =>
{
- using (packageManager.SourceRepository.StartOperation(
- RepositoryOperationNames.Update,
- packageName,
- version == null ? null : version.ToString()))
+ if (beforeUpgradeAction != null)
{
- if (beforeUpgradeAction != null)
- {
- var currentPackageResult = new PackageResult(installedPackage, get_install_directory(config, installedPackage));
- beforeUpgradeAction(currentPackageResult);
- }
-
- remove_rollback_directory_if_exists(packageName);
- ensure_package_files_have_compatible_attributes(config, installedPackage, pkgInfo);
- rename_legacy_package_version(config, installedPackage, pkgInfo);
- backup_existing_version(config, installedPackage, pkgInfo);
- remove_shim_directors(config, installedPackage, pkgInfo);
- if (config.Force && (installedPackage.Version == availablePackage.Version))
- {
- FaultTolerance.try_catch_with_logging_exception(
- () =>
- {
- _fileSystem.delete_directory_if_exists(_fileSystem.combine_paths(ApplicationParameters.PackagesLocation, installedPackage.Id), recursive: true);
- remove_cache_for_package(config, installedPackage);
- },
- "Error during force upgrade");
- packageManager.InstallPackage(availablePackage, config.IgnoreDependencies, config.Prerelease);
- }
- else
- {
- packageManager.UpdatePackage(availablePackage, updateDependencies: !config.IgnoreDependencies, allowPrereleaseVersions: config.Prerelease);
- }
- remove_nuget_cache_for_package(availablePackage);
+ var currentPackageResult = new PackageResult(installedPackage, get_install_directory(config, installedPackage));
+ beforeUpgradeAction(currentPackageResult);
}
- }
- catch (Exception ex)
- {
- var message = ex.Message;
- var webException = ex as System.Net.WebException;
- if (webException != null)
+
+ remove_rollback_directory_if_exists(packageName);
+ ensure_package_files_have_compatible_attributes(config, installedPackage, pkgInfo);
+ rename_legacy_package_version(config, installedPackage, pkgInfo);
+ backup_existing_version(config, installedPackage, pkgInfo);
+ remove_shim_directors(config, installedPackage, pkgInfo);
+ if (config.Force && (installedPackage.Version == availablePackage.Version))
{
- var response = webException.Response as HttpWebResponse;
- if (response != null && !string.IsNullOrWhiteSpace(response.StatusDescription)) message += " {0}".format_with(response.StatusDescription);
+ FaultTolerance.try_catch_with_logging_exception(
+ () =>
+ {
+ _fileSystem.delete_directory_if_exists(_fileSystem.combine_paths(ApplicationParameters.PackagesLocation, installedPackage.Id), recursive: true);
+ remove_cache_for_package(config, installedPackage);
+ },
+ "Error during force upgrade");
}
+ };
- var logMessage = "{0} not upgraded. An error occurred during installation:{1} {2}".format_with(packageName, Environment.NewLine, message);
- logMessage = InstallContext.NormalizeMessage(logMessage);
- this.Log().Error(ChocolateyLoggers.Important, logMessage);
- packageResult.Messages.Add(new ResultMessage(ResultType.Error, logMessage));
- if (packageResult.ExitCode == 0) packageResult.ExitCode = 1;
- if (continueAction != null) continueAction.Invoke(packageResult);
- }
+ SetPathResolver(packageManager, availablePackage, availablePackage, installedPackage);
+ DoOperation(walker, packageName, version, availablePackage, packageManager, packageInstalls, continueAction, beforeOp);
}
}
}
@@ -984,7 +1197,7 @@ public virtual ConcurrentDictionary get_outdated(Chocolat
// reset config each time through
config = originalConfig.deep_copy();
- var installedPackage = packageManager.FindLocalPackage(packageName);
+ var installedPackage = packageManager.FindAnyLocalPackage(packageName);
var pkgInfo = _packageInfoService.get_package_information(installedPackage);
bool isPinned = pkgInfo.IsPinned;
@@ -1384,7 +1597,7 @@ public virtual ConcurrentDictionary uninstall_run(Chocola
}
// is this the latest version, have you passed --sxs, or is this a side-by-side install? This is the only way you get through to the continue action.
- var latestVersion = packageManager.FindLocalPackage(e.Package.Id);
+ var latestVersion = packageManager.FindAnyLocalPackage(e.Package.Id);
var pkgInfo = _packageInfoService.get_package_information(e.Package);
if (latestVersion.Version == pkg.Version || config.AllowMultipleVersions || (pkgInfo != null && pkgInfo.IsSideBySide))
{
@@ -1548,50 +1761,48 @@ public virtual ConcurrentDictionary uninstall_run(Chocola
if (performAction)
{
- if (packageVersion is RegistryPackage regp)
- {
- string packagesLocation = Path.GetDirectoryName(regp.GetPackageLocation());
- packageManager.FileSystem.Root = packagesLocation;
- }
-
- try
+ Action beforeOp = () =>
{
- using (packageManager.SourceRepository.StartOperation(
- RepositoryOperationNames.Install,
- packageVersion.Id, packageVersion.Version.to_string())
- )
+ if (beforeUninstallAction != null)
{
- if (beforeUninstallAction != null)
- {
- // guessing this is not added so that it doesn't fail the action if an error is recorded?
- //var currentPackageResult = packageUninstalls.GetOrAdd(packageName, new PackageResult(packageVersion, get_install_directory(config, packageVersion)));
- var currentPackageResult = new PackageResult(packageVersion, get_install_directory(config, packageVersion));
- beforeUninstallAction(currentPackageResult);
- }
- ensure_package_files_have_compatible_attributes(config, packageVersion, pkgInfo);
- rename_legacy_package_version(config, packageVersion, pkgInfo);
- remove_rollback_directory_if_exists(packageName);
- backup_existing_version(config, packageVersion, pkgInfo);
- packageManager.UninstallPackage(packageVersion.Id.to_lower(), forceRemove: config.Force, removeDependencies: config.ForceDependencies, version: packageVersion.Version);
- ensure_nupkg_is_removed(packageVersion, pkgInfo);
- remove_installation_files(packageVersion, pkgInfo);
- remove_cache_for_package(config, packageVersion);
+ // guessing this is not added so that it doesn't fail the action if an error is recorded?
+ //var currentPackageResult = packageUninstalls.GetOrAdd(packageName, new PackageResult(packageVersion, get_install_directory(config, packageVersion)));
+ var currentPackageResult = new PackageResult(packageVersion, get_install_directory(config, packageVersion));
+ beforeUninstallAction(currentPackageResult);
}
- }
- catch (Exception ex)
+ ensure_package_files_have_compatible_attributes(config, packageVersion, pkgInfo);
+ rename_legacy_package_version(config, packageVersion, pkgInfo);
+ remove_rollback_directory_if_exists(packageName);
+ backup_existing_version(config, packageVersion, pkgInfo);
+ };
+
+ Action afterOp = () =>
+ {
+ ensure_nupkg_is_removed(packageVersion, pkgInfo);
+ remove_installation_files(packageVersion, pkgInfo);
+ };
+
+ var walker = new WalkerInfo
+ {
+ type = WalkerType.uninstall,
+ forceRemove = config.Force,
+ removeDependencies = config.ForceDependencies
+ };
+
+ Action continueUninstallAction = (r) =>
{
- var logMessage = "{0} not uninstalled. An error occurred during uninstall:{1} {2}".format_with(packageName, Environment.NewLine, ex.Message);
- logMessage = InstallContext.NormalizeMessage(logMessage);
- this.Log().Error(ChocolateyLoggers.Important, logMessage);
- var result = packageUninstalls.GetOrAdd(packageVersion.Id.to_lower() + "." + packageVersion.Version.to_string(), new PackageResult(packageVersion, _fileSystem.combine_paths(ApplicationParameters.PackagesLocation, packageVersion.Id)));
- result.Messages.Add(new ResultMessage(ResultType.Error, logMessage));
- if (result.ExitCode == 0) result.ExitCode = 1;
if (config.Features.StopOnFirstPackageFailure)
{
throw new ApplicationException("Stopping further execution as {0} has failed uninstallation".format_with(packageVersion.Id.to_lower()));
}
+ };
+
+ SetPathResolver(packageManager, packageVersion, packageVersion, packageVersion);
+ DoOperation(walker, packageName, packageVersion.Version, packageVersion, packageManager, packageUninstalls,
// do not call continueAction - will result in multiple passes
- }
+ continueUninstallAction,
+ beforeOp, afterOp);
+
}
else
{