Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow disabling installing dependencies on restore #518

Merged
merged 9 commits into from
Jul 29, 2023
3 changes: 1 addition & 2 deletions src/NuGetForUnity.Cli/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ public static int Main(string[] args)
Application.SetUnityProjectPath(projectPath);

// need to disable dependency installation as UnityPreImportedLibraryResolver.GetAlreadyImportedLibs is not working outside Unity.
NugetHelper.InstallDependencies = false;
NugetHelper.Restore();
NugetHelper.Restore(false);
FixRoslynAnalyzerImportSettings();
return Debug.HasError ? 1 : 0;
}
Expand Down
21 changes: 19 additions & 2 deletions src/NuGetForUnity.Tests/Assets/Tests/Editor/NuGetTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,24 @@ public void InstallStyleCopTest()
Assert.IsFalse(NugetHelper.IsInstalled(styleCopId), "The package is STILL installed: {0} {1}", styleCopId.Id, styleCopId.Version);
}

[Test]
public void InstallStyleCopWithoutDependenciesTest()
{
var styleCopPlusId = new NugetPackageIdentifier("StyleCopPlus.MSBuild", "4.7.49.5");
var styleCopId = new NugetPackageIdentifier("StyleCop.MSBuild", "4.7.49.0");

NugetHelper.InstallIdentifier(styleCopPlusId, installDependencies: false);

// StyleCopPlus depends on StyleCop, so they should both be installed
// it depends on version 4.7.49.0, so ensure it is also installed
Assert.IsTrue(NugetHelper.IsInstalled(styleCopPlusId), "The package was NOT installed: {0} {1}", styleCopPlusId.Id, styleCopPlusId.Version);
Assert.IsFalse(NugetHelper.IsInstalled(styleCopId), "The package SHOULD NOT be installed: {0} {1}", styleCopId.Id, styleCopId.Version);

// cleanup and uninstall everything
NugetHelper.UninstallAll(NugetHelper.InstalledPackages.ToList());
Assert.IsFalse(NugetHelper.IsInstalled(styleCopPlusId), "The package is STILL installed: {0} {1}", styleCopPlusId.Id, styleCopPlusId.Version);
}

[Test]
public void InstallSignalRClientTest()
{
Expand Down Expand Up @@ -604,8 +622,7 @@ public void TestPostprocessUninstall(string packageId, string packageVersion)

var assetsIndex = filepath.LastIndexOf("Assets", StringComparison.Ordinal);
filepath = filepath.Substring(assetsIndex);
NugetPackageAssetPostprocessor.OnPostprocessAllAssets(new[]{filepath},
null, null, null);
NugetPackageAssetPostprocessor.OnPostprocessAllAssets(new[] { filepath }, null, null, null);

Assert.IsFalse(NugetHelper.IsInstalled(package), "The package is STILL installed: {0} {1}", package.Id, package.Version);
}
Expand Down
62 changes: 53 additions & 9 deletions src/NuGetForUnity/Editor/NugetConfigFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ public class NugetConfigFile
/// </summary>
public const string FileName = "NuGet.config";

/// <summary>
/// Default timeout in seconds for all web requests.
/// </summary>
private const int DefaultRequestTimeout = 10;

private const string RequestTimeoutSecondsConfigKey = "RequestTimeoutSeconds";

private const string LockPackagesOnRestoreConfigKey = "LockPackagesOnRestore";

/// <summary>
/// The incomplete path that is saved. The path is expanded and made public via the property above.
/// </summary>
Expand Down Expand Up @@ -47,7 +56,7 @@ public class NugetConfigFile
public string DefaultPushSource { get; private set; }

/// <summary>
/// True to output verbose log messages to the console. False to output the normal level of messages.
/// Gets or sets a value indicating whether to output verbose log messages to the console. False to output the normal level of messages.
/// </summary>
public bool Verbose { get; set; }

Expand All @@ -62,11 +71,22 @@ public class NugetConfigFile
/// </summary>
public bool ReadOnlyPackageFiles { get; set; }

/// <summary>
/// Gets or sets the timeout in seconds used for all web requests to NuGet sources.
/// </summary>
public int RequestTimeoutSeconds { get; set; } = DefaultRequestTimeout;

/// <summary>
/// Gets or sets a value indicating whether the installed packages should be fixed, so only the packages that are configure inside the
/// 'package.config' are installed without installing the dependencies of them.
/// </summary>
public bool LockPackagesOnRestore { get; set; }

/// <summary>
/// Saves this NuGet.config file to disk.
/// </summary>
/// <param name="filepath">The file-path to where this NuGet.config will be saved.</param>
public void Save(string filepath)
/// <param name="filePath">The file-path to where this NuGet.config will be saved.</param>
public void Save(string filePath)
{
var configFile = new XDocument();

Expand Down Expand Up @@ -157,6 +177,22 @@ public void Save(string filepath)
config.Add(addElement);
}

if (RequestTimeoutSeconds != DefaultRequestTimeout)
{
addElement = new XElement("add");
addElement.Add(new XAttribute("key", RequestTimeoutSecondsConfigKey));
addElement.Add(new XAttribute("value", RequestTimeoutSeconds));
config.Add(addElement);
}

if (LockPackagesOnRestore)
{
addElement = new XElement("add");
addElement.Add(new XAttribute("key", LockPackagesOnRestoreConfigKey));
addElement.Add(new XAttribute("value", LockPackagesOnRestore.ToString().ToLower()));
config.Add(addElement);
}

var configuration = new XElement("configuration");
configuration.Add(packageSources);
configuration.Add(disabledPackageSources);
Expand All @@ -166,21 +202,21 @@ public void Save(string filepath)

configFile.Add(configuration);

var fileExists = File.Exists(filepath);
var fileExists = File.Exists(filePath);

// remove the read only flag on the file, if there is one.
if (fileExists)
{
var attributes = File.GetAttributes(filepath);
var attributes = File.GetAttributes(filePath);

if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
{
attributes &= ~FileAttributes.ReadOnly;
File.SetAttributes(filepath, attributes);
File.SetAttributes(filePath, attributes);
}
}

configFile.Save(filepath);
configFile.Save(filePath);
}

/// <summary>
Expand Down Expand Up @@ -304,16 +340,24 @@ public static NugetConfigFile Load(string filePath)
{
configFile.ReadOnlyPackageFiles = bool.Parse(value);
}
else if (string.Equals(key, RequestTimeoutSecondsConfigKey, StringComparison.OrdinalIgnoreCase))
{
configFile.RequestTimeoutSeconds = int.Parse(value);
}
else if (string.Equals(key, LockPackagesOnRestoreConfigKey, StringComparison.OrdinalIgnoreCase))
{
configFile.LockPackagesOnRestore = bool.Parse(value);
}
}
}

return configFile;
}

/// <summary>
/// Creates a NuGet.config file with the default settings at the given full filepath.
/// Creates a NuGet.config file with the default settings at the given full file-path.
/// </summary>
/// <param name="filePath">The full filepath where to create the NuGet.config file.</param>
/// <param name="filePath">The full file-path where to create the NuGet.config file.</param>
/// <returns>The loaded <see cref="NugetConfigFile" /> loaded off of the newly created default file.</returns>
public static NugetConfigFile CreateDefaultFile(string filePath)
{
Expand Down
72 changes: 34 additions & 38 deletions src/NuGetForUnity/Editor/NugetHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,6 @@ static NugetHelper()
Directory.CreateDirectory(PackOutputDirectory);
}

/// <summary>
/// Gets or sets a value indicating whether when installing a NuGet package we also install its dependencies.
/// This is required by the NuGetForUnity.Cli as the CLI only installs packages listed explicitly inside
/// the <see cref="PackagesConfigFile" /> because dependency resolution wouldn't work seamlessly
/// as it can't detect libraries imported by Unity <see cref="UnityPreImportedLibraryResolver" />.
/// </summary>
internal static bool InstallDependencies { get; set; } = true;

/// <summary>
/// The loaded NuGet.config file that holds the settings for NuGet.
/// </summary>
Expand All @@ -131,14 +123,6 @@ public static PackagesConfigFile PackagesConfigFile
}
}

/// <summary>
/// Invalidates the currently loaded 'packages.config' so it is reloaded when it is accessed the next time.
/// </summary>
internal static void ReloadPackagesConfig()
{
packagesConfigFile = null;
}

/// <summary>
/// Gets the packages that are actually installed in the project.
/// </summary>
Expand All @@ -160,6 +144,14 @@ private static Dictionary<string, NugetPackage> InstalledPackagesDictionary
}
}

/// <summary>
/// Invalidates the currently loaded 'packages.config' so it is reloaded when it is accessed the next time.
/// </summary>
internal static void ReloadPackagesConfig()
{
packagesConfigFile = null;
}

/// <summary>
/// Loads the NuGet.config file.
/// </summary>
Expand Down Expand Up @@ -905,13 +897,13 @@ void AddPackageToInstalled(NugetPackage package)
{
// set root packages as manually installed if none are marked as such
foreach (var rootPackage in GetInstalledRootPackages())
{
PackagesConfigFile.SetManuallyInstalledFlag(rootPackage);
}

PackagesConfigFile.Save(PackagesConfigFilePath);
{
PackagesConfigFile.SetManuallyInstalledFlag(rootPackage);
}

PackagesConfigFile.Save(PackagesConfigFilePath);
}
}

stopwatch.Stop();
LogVerbose("Getting installed packages took {0} ms", stopwatch.ElapsedMilliseconds);
Expand Down Expand Up @@ -1163,7 +1155,11 @@ private static void CopyStream(Stream input, Stream output)
/// <param name="package">The identifier of the package to install.</param>
/// <param name="refreshAssets">True to refresh the Unity asset database. False to ignore the changes (temporarily).</param>
JoC0de marked this conversation as resolved.
Show resolved Hide resolved
/// <param name="isUpdate">True to indicate we're calling method as result of Update and don't want to go through IsAlreadyImportedInEngine</param>
internal static bool InstallIdentifier(NugetPackageIdentifier package, bool refreshAssets = true, bool isUpdate = false)
/// <param name="installDependencies">True to also install all dependencies of the <paramref name="package" />.</param>
internal static bool InstallIdentifier(NugetPackageIdentifier package,
bool refreshAssets = true,
bool isUpdate = false,
bool installDependencies = true)
{
if (!isUpdate && IsAlreadyImportedInEngine(package, false))
{
Expand All @@ -1173,14 +1169,14 @@ internal static bool InstallIdentifier(NugetPackageIdentifier package, bool refr

var foundPackage = GetSpecificPackage(package);

if (foundPackage != null)
if (foundPackage == null)
{
foundPackage.IsManuallyInstalled = package.IsManuallyInstalled;
return Install(foundPackage, refreshAssets, isUpdate);
Debug.LogErrorFormat("Could not find {0} {1} or greater.", package.Id, package.Version);
return false;
}

Debug.LogErrorFormat("Could not find {0} {1} or greater.", package.Id, package.Version);
return false;
foundPackage.IsManuallyInstalled = package.IsManuallyInstalled;
return Install(foundPackage, refreshAssets, isUpdate, installDependencies);
}

/// <summary>
Expand All @@ -1204,8 +1200,9 @@ public static void LogVerbose(string format, params object[] args)
/// </summary>
/// <param name="package">The package to install.</param>
/// <param name="refreshAssets">True to refresh the Unity asset database. False to ignore the changes (temporarily).</param>
/// <param name="isUpdate">True to indicate we're calling method as result of Update and don't want to go through IsAlreadyImportedInEngine</param>
public static bool Install(NugetPackage package, bool refreshAssets = true, bool isUpdate = false)
/// <param name="isUpdate">True to indicate we're calling method as result of Update and don't want to go through IsAlreadyImportedInEngine.</param>
/// <param name="installDependencies">True to also install all dependencies of the <paramref name="package" />.</param>
public static bool Install(NugetPackage package, bool refreshAssets = true, bool isUpdate = false, bool installDependencies = true)
{
if (!isUpdate && IsAlreadyImportedInEngine(package, false))
{
Expand Down Expand Up @@ -1238,6 +1235,7 @@ public static bool Install(NugetPackage package, bool refreshAssets = true, bool
package.Version);
return Update(installedPackage, package, false);
}

LogVerbose(
"{0} {1} is installed. {2} or greater is needed, so using installed version.",
installedPackage.Id,
Expand Down Expand Up @@ -1266,7 +1264,7 @@ public static bool Install(NugetPackage package, bool refreshAssets = true, bool
0.1f);
}

if (InstallDependencies)
if (installDependencies)
{
// install all dependencies for target framework
var frameworkGroup = GetNullableBestDependencyFrameworkGroupForCurrentSettings(package);
Expand All @@ -1285,7 +1283,7 @@ public static bool Install(NugetPackage package, bool refreshAssets = true, bool
foreach (var dependency in frameworkGroup.Dependencies)
{
LogVerbose("Installing Dependency: {0} {1}", dependency.Id, dependency.Version);
var installed = InstallIdentifier(dependency);
var installed = InstallIdentifier(dependency, refreshAssets, installDependencies);
if (!installed)
{
throw new Exception(string.Format("Failed to install dependency: {0} {1}.", dependency.Id, dependency.Version));
Expand Down Expand Up @@ -1424,6 +1422,7 @@ private static void WarnIfDotNetAuthenticationIssue(Exception e)
/// Get the specified URL from the web. Throws exceptions if the request fails.
/// </summary>
/// <param name="url">URL that will be loaded.</param>
/// <param name="userName">UserName that will be passed in the Authorization header or the request. If null, authorization is omitted.</param>
/// <param name="password">Password that will be passed in the Authorization header or the request. If null, authorization is omitted.</param>
/// <param name="timeOut">Timeout in milliseconds or null to use the default timeout values of HttpWebRequest.</param>
/// <returns>Stream containing the result.</returns>
Expand All @@ -1437,11 +1436,7 @@ public static Stream RequestUrl(string url, string userName, string password, in
var getRequest = (HttpWebRequest)WebRequest.Create(url);
#pragma warning restore SYSLIB0014 // Type or member is obsolete
getRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.None;
if (timeOut.HasValue)
{
getRequest.Timeout = timeOut.Value;
getRequest.ReadWriteTimeout = timeOut.Value;
}
getRequest.Timeout = timeOut ?? NugetConfigFile.RequestTimeoutSeconds * 1000;

if (string.IsNullOrEmpty(password))
{
Expand Down Expand Up @@ -1471,7 +1466,8 @@ public static Stream RequestUrl(string url, string userName, string password, in
/// <summary>
/// Restores all packages defined in packages.config.
/// </summary>
public static void Restore()
/// <param name="installDependencies">True to also install all dependencies of the packages listed in the <see cref="PackagesConfigFile" />.</param>
public static void Restore(bool installDependencies = true)
{
UpdateInstalledPackages();

Expand All @@ -1498,7 +1494,7 @@ public static void Restore()
string.Format("Restoring {0} {1}", package.Id, package.Version),
currentProgress);
LogVerbose("---Restoring {0} {1}", package.Id, package.Version);
InstallIdentifier(package);
InstallIdentifier(package, installDependencies: installDependencies);
somethingChanged = true;
}

Expand Down
Loading
Loading