Skip to content

Commit

Permalink
Packages install path can again be edited from preferences window (#619)
Browse files Browse the repository at this point in the history
* Packages install path can again be edited from preferences window

* Improved handling of invalid folder selection

* Made a Packages path fixed

* Fixed moving packages out of Assets

* Fixed Asset Refreshing when moving packages outside of Assets

* Improved asset refresh after moving to Packages folder

* Renamed Placement to PackageInstallLocation and core reformat

* run autoformatter

* rename configuration parameter from 'Platcement' to 'packageInstallLocation'

---------

Co-authored-by: JoC0de <[email protected]>
  • Loading branch information
igor84 and JoC0de authored Apr 1, 2024
1 parent b93741e commit 4b67af9
Show file tree
Hide file tree
Showing 11 changed files with 354 additions and 53 deletions.
39 changes: 35 additions & 4 deletions src/NuGetForUnity/Editor/Configuration/ConfigurationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,16 @@ public static class ConfigurationManager

static ConfigurationManager()
{
NugetConfigFileDirectoryPath = UnityPathHelper.AbsoluteAssetsPath;
NugetConfigFilePath = Path.Combine(NugetConfigFileDirectoryPath, NugetConfigFile.FileName);
NugetConfigFilePath = Path.Combine(UnityPathHelper.AbsoluteUnityPackagesNugetPath, NugetConfigFile.FileName);
if (File.Exists(NugetConfigFilePath))
{
NugetConfigFileDirectoryPath = UnityPathHelper.AbsoluteUnityPackagesNugetPath;
}
else
{
NugetConfigFilePath = Path.Combine(UnityPathHelper.AbsoluteAssetsPath, NugetConfigFile.FileName);
NugetConfigFileDirectoryPath = UnityPathHelper.AbsoluteAssetsPath;
}
}

/// <summary>
Expand All @@ -45,7 +53,7 @@ static ConfigurationManager()
/// <see cref="NugetConfigFile" />.
/// </remarks>
[NotNull]
public static string NugetConfigFilePath { get; }
public static string NugetConfigFilePath { get; private set; }

/// <summary>
/// Gets the loaded NuGet.config file that holds the settings for NuGet.
Expand All @@ -69,7 +77,7 @@ public static NugetConfigFile NugetConfigFile
/// Gets the path to the directory containing the NuGet.config file.
/// </summary>
[NotNull]
internal static string NugetConfigFileDirectoryPath { get; }
internal static string NugetConfigFileDirectoryPath { get; private set; }

/// <summary>
/// Gets a value indicating whether verbose logging is enabled.
Expand Down Expand Up @@ -207,5 +215,28 @@ public static INugetPackage GetSpecificPackage([NotNull] INugetPackageIdentifier
{
return ActivePackageSource.GetSpecificPackage(nugetPackageIdentifier);
}

/// <summary>
/// Moves the Nuget.config under newPlacement and updated local properties to point to it.
/// </summary>
/// <param name="newInstallLocation">New placement for configs.</param>
internal static void MoveConfig(PackageInstallLocation newInstallLocation)
{
NugetConfigFile.ChangeInstallLocation(newInstallLocation);
var newConfigsPath = newInstallLocation == PackageInstallLocation.InPackagesFolder ?
UnityPathHelper.AbsoluteUnityPackagesNugetPath :
UnityPathHelper.AbsoluteAssetsPath;
var newConfigFilePath = Path.Combine(newConfigsPath, NugetConfigFile.FileName);

File.Move(NugetConfigFilePath, newConfigFilePath);
var configMeta = NugetConfigFilePath + ".meta";
if (File.Exists(configMeta))
{
File.Move(configMeta, newConfigFilePath + ".meta");
}

NugetConfigFilePath = newConfigFilePath;
NugetConfigFileDirectoryPath = newConfigsPath;
}
}
}
113 changes: 92 additions & 21 deletions src/NuGetForUnity/Editor/Configuration/NugetConfigFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,17 @@ public class NugetConfigFile

private const string SupportsPackageIdSearchFilterAttributeName = "supportsPackageIdSearchFilter";

/// <summary>
/// The incomplete path that is saved. The path is expanded and made public via the property above.
/// </summary>
[CanBeNull]
private string savedRepositoryPath;
[NotNull]
private readonly string unityPackagesNugetInstallPath = Path.Combine(UnityPathHelper.AbsoluteUnityPackagesNugetPath, "InstalledPackages");

[NotNull]
private string configuredRepositoryPath = "Packages";

[NotNull]
private string packagesConfigDirectoryPath = Application.dataPath;

[NotNull]
private string repositoryPath = Path.GetFullPath(Path.Combine(Application.dataPath, "Packages"));

/// <summary>
/// Gets the list of package sources that are defined in the NuGet.config file.
Expand All @@ -87,7 +93,35 @@ public class NugetConfigFile
/// Gets the absolute path where packages are to be installed.
/// </summary>
[NotNull]
public string RepositoryPath { get; private set; } = Path.GetFullPath(Path.Combine(Application.dataPath, "Packages"));
public string RepositoryPath
{
get => InstallLocation == PackageInstallLocation.InPackagesFolder ? unityPackagesNugetInstallPath : repositoryPath;

private set => repositoryPath = value;
}

/// <summary>
/// Gets or sets the incomplete path that is saved. The path is expanded and made public via the property above.
/// </summary>
[NotNull]
public string ConfiguredRepositoryPath
{
get => configuredRepositoryPath;

set
{
configuredRepositoryPath = value;

var expandedPath = Environment.ExpandEnvironmentVariables(value);

if (!Path.IsPathRooted(expandedPath))
{
expandedPath = Path.Combine(Application.dataPath, expandedPath);
}

RepositoryPath = Path.GetFullPath(expandedPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
}
}

/// <summary>
/// Gets the default package source to push NuGet packages to.
Expand Down Expand Up @@ -121,7 +155,15 @@ public class NugetConfigFile
/// Gets or sets absolute path to directory containing packages.config file.
/// </summary>
[NotNull]
public string PackagesConfigDirectoryPath { get; set; } = Application.dataPath;
public string PackagesConfigDirectoryPath
{
get =>
InstallLocation == PackageInstallLocation.InPackagesFolder ?
UnityPathHelper.AbsoluteUnityPackagesNugetPath :
packagesConfigDirectoryPath;

set => packagesConfigDirectoryPath = value;
}

/// <summary>
/// Gets the relative path to directory containing packages.config file. The path is relative to the folder containing the 'NuGet.config' file.
Expand All @@ -144,6 +186,11 @@ public string RelativePackagesConfigDirectoryPath
/// </summary>
public int RequestTimeoutSeconds { get; set; } = DefaultRequestTimeout;

/// <summary>
/// Gets the value that tells the system how to determine where the packages are to be installed and configurations are to be stored.
/// </summary>
internal PackageInstallLocation InstallLocation { get; private set; }

/// <summary>
/// Gets the list of enabled plugins.
/// </summary>
Expand Down Expand Up @@ -297,18 +344,13 @@ public static NugetConfigFile Load([NotNull] string filePath)
var key = add.Attribute("key")?.Value;
var value = add.Attribute("value")?.Value ?? throw new InvalidOperationException($"config misses 'value' attribute. Element:\n{add}");

if (string.Equals(key, "repositoryPath", StringComparison.OrdinalIgnoreCase))
if (string.Equals(key, "packageInstallLocation", StringComparison.OrdinalIgnoreCase))
{
configFile.savedRepositoryPath = value;
configFile.RepositoryPath = Environment.ExpandEnvironmentVariables(value);

if (!Path.IsPathRooted(configFile.RepositoryPath))
{
configFile.RepositoryPath = Path.Combine(Application.dataPath, configFile.RepositoryPath);
}

configFile.RepositoryPath = Path.GetFullPath(
configFile.RepositoryPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
configFile.InstallLocation = (PackageInstallLocation)Enum.Parse(typeof(PackageInstallLocation), value);
}
else if (string.Equals(key, "repositoryPath", StringComparison.OrdinalIgnoreCase))
{
configFile.ConfiguredRepositoryPath = value;
}
else if (string.Equals(key, "DefaultPushSource", StringComparison.OrdinalIgnoreCase))
{
Expand Down Expand Up @@ -362,6 +404,7 @@ public static NugetConfigFile CreateDefaultFile([NotNull] string filePath)
<add key=""All"" value=""(Aggregate source)"" />
</activePackageSource>
<config>
<add key=""packageInstallLocation"" value=""CustomWithinAssets"" />
<add key=""repositoryPath"" value=""./Packages"" />
<add key=""PackagesConfigDirectoryPath"" value=""."" />
<add key=""slimRestore"" value=""true"" />
Expand Down Expand Up @@ -454,18 +497,23 @@ public void Save([NotNull] string filePath)

var config = new XElement("config");

if (!string.IsNullOrEmpty(savedRepositoryPath))
addElement = new XElement("add");
addElement.Add(new XAttribute("key", "packageInstallLocation"));
addElement.Add(new XAttribute("value", InstallLocation.ToString()));
config.Add(addElement);

if (!string.IsNullOrEmpty(ConfiguredRepositoryPath))
{
// save the un-expanded repository path
addElement = new XElement("add");
addElement.Add(new XAttribute("key", "repositoryPath"));
addElement.Add(new XAttribute("value", savedRepositoryPath));
addElement.Add(new XAttribute("value", ConfiguredRepositoryPath));
config.Add(addElement);
}

addElement = new XElement("add");
addElement.Add(new XAttribute("key", PackagesConfigDirectoryPathConfigKey));
addElement.Add(new XAttribute("value", RelativePackagesConfigDirectoryPath));
addElement.Add(new XAttribute("value", PathHelper.GetRelativePath(Application.dataPath, packagesConfigDirectoryPath)));
config.Add(addElement);

// save the default push source
Expand Down Expand Up @@ -553,5 +601,28 @@ public void Save([NotNull] string filePath)

configFile.Save(filePath);
}

/// <summary>
/// Changes the package install location config and also moves the packages.config to the new location.
/// </summary>
/// <param name="newInstallLocation">New install location to set.</param>
internal void ChangeInstallLocation(PackageInstallLocation newInstallLocation)
{
if (newInstallLocation == InstallLocation)
{
return;
}

var oldPackagesConfigPath = PackagesConfigFilePath;
InstallLocation = newInstallLocation;
UnityPathHelper.EnsurePackageInstallDirectoryIsSetup();
var newConfigPath = PackagesConfigFilePath;
File.Move(oldPackagesConfigPath, newConfigPath);
var configMeta = oldPackagesConfigPath + ".meta";
if (File.Exists(configMeta))
{
File.Move(configMeta, newConfigPath + ".meta");
}
}
}
}
22 changes: 22 additions & 0 deletions src/NuGetForUnity/Editor/Configuration/PackageInstallLocation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace NugetForUnity.Configuration
{
/// <summary>
/// Tells the system how to determine where the packages are to be installed and configurations are to be stored.
/// </summary>
internal enum PackageInstallLocation
{
/// <summary>
/// This option will place Nuget.config into the Assets folder and will allow the user to
/// specify custom location within Assets folder for packages.config and package installation
/// folder.
/// </summary>
CustomWithinAssets,

/// <summary>
/// This options will place the Nuget.config and packages.config under Packages/nuget-packages
/// and will install the packages under Packages/nuget-packages/InstalledPackages.
/// </summary>
/// .
InPackagesFolder,
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion src/NuGetForUnity/Editor/Configuration/PackagesConfigFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,9 @@ internal static void Move([NotNull] string newPath)
var nugetConfig = ConfigurationManager.NugetConfigFile;
var oldFilePath = nugetConfig.PackagesConfigFilePath;
var oldPath = nugetConfig.PackagesConfigDirectoryPath;
nugetConfig.PackagesConfigDirectoryPath = newPath;

// We need to make sure saved path is using forward slashes so it works on all systems
nugetConfig.PackagesConfigDirectoryPath = newPath.Replace("\\", "/");
var newFilePath = Path.GetFullPath(Path.Combine(newPath, FileName));
try
{
Expand Down
42 changes: 41 additions & 1 deletion src/NuGetForUnity/Editor/Helper/UnityPathHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.IO;
using JetBrains.Annotations;
using NugetForUnity.Configuration;
using UnityEngine;

#region No ReShaper
Expand All @@ -28,8 +29,15 @@ static UnityPathHelper()
{
AbsoluteAssetsPath = Path.GetFullPath(Application.dataPath);
AbsoluteProjectPath = Path.GetDirectoryName(AbsoluteAssetsPath) ?? throw new InvalidOperationException("Can't detect project root.");
AbsoluteUnityPackagesNugetPath = Path.GetFullPath(Path.Combine(AbsoluteAssetsPath, "../Packages/nuget-packages"));
}

/// <summary>
/// Gets the absolute path to 'project root'/Packages/nuget-packages.
/// </summary>
[NotNull]
internal static string AbsoluteUnityPackagesNugetPath { get; }

/// <summary>
/// Gets the absolute path to the Unity-Project 'Assets' directory.
/// </summary>
Expand All @@ -53,10 +61,42 @@ internal static bool IsPathInAssets([NotNull] string path)
return !Path.IsPathRooted(assetsRelativePath) && !assetsRelativePath.StartsWith("..", StringComparison.Ordinal);
}

/// <summary>
/// Checks if given relative path is a valid for packages installations.
/// </summary>
/// <param name="path">Relative path to check.</param>
/// <returns>True if path is within Assets folder or Packages subfolder, false otherwise.</returns>
internal static bool IsValidInstallPath([NotNull] string path)
{
return !Path.IsPathRooted(path) && !path.StartsWith("..", StringComparison.Ordinal);
}

/// <summary>
/// Ensures that the package install directory exists and in case it is under Unity's
/// Packages folder that it contains a dummy package.json file so that Unity can see it.
/// </summary>
internal static void EnsurePackageInstallDirectoryIsSetup()
{
Directory.CreateDirectory(ConfigurationManager.NugetConfigFile.RepositoryPath);

if (ConfigurationManager.NugetConfigFile.InstallLocation == PackageInstallLocation.CustomWithinAssets)
{
return;
}

var jsonPath = Path.Combine(AbsoluteUnityPackagesNugetPath, "package.json");
if (!File.Exists(jsonPath))
{
File.WriteAllText(
jsonPath,
@"{ ""name"": ""nuget-packages"",""version"": ""1.0.0"",""displayName"": ""NuGetPackages"", ""description"": ""NuGetPackages"", ""dependencies"": {}}");
}
}

/// <summary>
/// Returns the path relative to Assets directory, or <c>"."</c> if it is the Assets directory.
/// </summary>
/// <param name="path">The path of witch we calculate the relative path of.</param>
/// <param name="path">The path of which we calculate the relative path of.</param>
/// <returns>The path relative to Assets directory, or <c>"."</c> if it is the Assets directory.</returns>
[NotNull]
private static string GetAssetsRelativePath([NotNull] string path)
Expand Down
2 changes: 1 addition & 1 deletion src/NuGetForUnity/Editor/NugetPackageInstaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ private static bool Install([NotNull] INugetPackage package, bool refreshAssets,

if (File.Exists(cachedPackagePath))
{
var baseDirectory = Path.Combine(ConfigurationManager.NugetConfigFile.RepositoryPath, $"{package.Id}.{package.Version}");
var baseDirectory = package.GetPackageInstallPath();

// unzip the package
using (var zip = ZipFile.OpenRead(cachedPackagePath))
Expand Down
Loading

0 comments on commit 4b67af9

Please sign in to comment.