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

Packages install path can again be edited from preferences window #619

Merged
merged 9 commits into from
Apr 1, 2024
45 changes: 28 additions & 17 deletions src/NuGetForUnity/Editor/Configuration/NugetConfigFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,8 @@ 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 string relativeRepositoryPath = "Packages";

/// <summary>
/// Gets the list of package sources that are defined in the NuGet.config file.
Expand All @@ -89,6 +86,29 @@ public class NugetConfigFile
[NotNull]
public string RepositoryPath { get; private set; } = Path.GetFullPath(Path.Combine(Application.dataPath, "Packages"));

/// <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 RelativeRepositoryPath
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public string RelativeRepositoryPath
internal string ConfiguredRepositoryPath

The important part is that this ist the path that is stored inside the NuGet.config, it can be absolute / relative / contain environment variables. Eventually there is a even better name.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the original name "savedRepositoryPath" is not so bad.

{
get => relativeRepositoryPath;

set
{
relativeRepositoryPath = value;

var repositoryPath = Environment.ExpandEnvironmentVariables(value);

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

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

/// <summary>
/// Gets the default package source to push NuGet packages to.
/// </summary>
Expand Down Expand Up @@ -299,16 +319,7 @@ public static NugetConfigFile Load([NotNull] string filePath)

if (string.Equals(key, "repositoryPath", 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.RelativeRepositoryPath = value;
}
else if (string.Equals(key, "DefaultPushSource", StringComparison.OrdinalIgnoreCase))
{
Expand Down Expand Up @@ -454,12 +465,12 @@ public void Save([NotNull] string filePath)

var config = new XElement("config");

if (!string.IsNullOrEmpty(savedRepositoryPath))
if (!string.IsNullOrEmpty(RelativeRepositoryPath))
{
// 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", RelativeRepositoryPath));
config.Add(addElement);
}

Expand Down
4 changes: 3 additions & 1 deletion src/NuGetForUnity/Editor/Configuration/PackagesConfigFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,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
40 changes: 40 additions & 0 deletions 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 Down Expand Up @@ -53,6 +54,45 @@ 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)
{
if (!Path.IsPathRooted(path) && !path.StartsWith("..", StringComparison.Ordinal))
{
return true;
}

return path.Length > "../Packages/".Length && path.StartsWith("../Packages/", StringComparison.OrdinalIgnoreCase);
}

/// <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 EnsurePackageInstallDirIsSetup()
JoC0de marked this conversation as resolved.
Show resolved Hide resolved
{
var relativePath = ConfigurationManager.NugetConfigFile.RelativeRepositoryPath;

Directory.CreateDirectory(ConfigurationManager.NugetConfigFile.RepositoryPath);

if (relativePath.Length <= "../Packages/".Length || !relativePath.StartsWith("../Packages/", StringComparison.Ordinal))
{
return;
}

var jsonPath = Path.Combine(ConfigurationManager.NugetConfigFile.RepositoryPath, "package.json");
if (!File.Exists(jsonPath))
{
File.WriteAllText(
jsonPath,
@"{ ""name"": ""com.dummy.nugetpackages"",""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>
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 @@ -159,7 +159,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
61 changes: 56 additions & 5 deletions src/NuGetForUnity/Editor/PackageContentManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using JetBrains.Annotations;
using NugetForUnity.Configuration;
using NugetForUnity.Helper;
Expand All @@ -21,7 +22,7 @@ internal static class PackageContentManager
/// <param name="package">The package to remove all its content of.</param>
internal static void DeletePackageContentPackage([NotNull] INugetPackageIdentifier package)
{
var packageInstallDirectory = GetPackageInstallDirectory(package);
var packageInstallDirectory = package.GetPackageInstallPath();
FileSystemHelper.DeleteDirectory(packageInstallDirectory, true);

var metaFile = $"{packageInstallDirectory}.meta";
Expand All @@ -38,7 +39,7 @@ internal static void DeletePackageContentPackage([NotNull] INugetPackageIdentifi
/// <param name="package">The NugetPackage to clean.</param>
internal static void CleanInstallationDirectory([NotNull] INugetPackageIdentifier package)
{
var packageInstallDirectory = GetPackageInstallDirectory(package);
var packageInstallDirectory = package.GetPackageInstallPath();

NugetLogger.LogVerbose("Cleaning {0}", packageInstallDirectory);

Expand Down Expand Up @@ -289,10 +290,60 @@ internal static void ExtractPackageEntry([NotNull] ZipArchiveEntry entry, [NotNu
}
}

[NotNull]
private static string GetPackageInstallDirectory([NotNull] INugetPackageIdentifier package)
/// <summary>
/// Moves already installed packages from the old to a new path.
/// </summary>
/// <param name="oldPath">Old package installation absolute path.</param>
/// <param name="newPath">New package installation absolute path.</param>
internal static void MoveInstalledPackages(string oldPath, string newPath)
{
return Path.Combine(ConfigurationManager.NugetConfigFile.RepositoryPath, $"{package.Id}.{package.Version}");
if (!Directory.Exists(oldPath))
{
return;
}

Directory.CreateDirectory(newPath);

// We only move the package folders because users might have other things in that folder
foreach (var package in InstalledPackagesManager.InstalledPackages)
{
var packageFolderName = $"{package.Id}.{package.Version}";
var oldPackagePath = Path.Combine(oldPath, packageFolderName);
var newPackagePath = Path.Combine(newPath, packageFolderName);
if (Directory.Exists(oldPackagePath))
{
Directory.Move(oldPackagePath, newPackagePath);
var oldMetaPath = $"{oldPackagePath}.meta";
if (File.Exists(oldMetaPath))
{
File.Move(oldMetaPath, $"{newPackagePath}.meta");
}
}
}

var oldPackageJsonPath = Path.Combine(oldPath, "package.json");
if (File.Exists(oldPackageJsonPath))
{
File.Delete(oldPackageJsonPath);
var oldPackageJsonMetaPath = $"{oldPackageJsonPath}.meta";
if (File.Exists(oldPackageJsonMetaPath))
{
File.Delete(oldPackageJsonMetaPath);
}
}

if (Directory.EnumerateFileSystemEntries(oldPath).Any())
{
return;
}

// If there is nothing left in the oldPath we remove the whole directory
Directory.Delete(oldPath);
var metaPath = oldPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + ".meta";
if (File.Exists(metaPath))
{
File.Delete(metaPath);
}
}

[NotNull]
Expand Down
2 changes: 2 additions & 0 deletions src/NuGetForUnity/Editor/PackageRestorer.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Diagnostics;
using NugetForUnity.Helper;
using UnityEditor;
using Debug = UnityEngine.Debug;

Expand All @@ -16,6 +17,7 @@ public static class PackageRestorer
/// <param name="slimRestore">True if we want to skip installing dependencies and checking if the lib is imported in Unity.</param>
public static void Restore(bool slimRestore)
{
UnityPathHelper.EnsurePackageInstallDirIsSetup();
InstalledPackagesManager.UpdateInstalledPackages();

var stopwatch = Stopwatch.StartNew();
Expand Down
48 changes: 48 additions & 0 deletions src/NuGetForUnity/Editor/Ui/NugetPreferences.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
Expand Down Expand Up @@ -108,6 +109,7 @@ public override void OnGUI([CanBeNull] string searchContext)

var preferencesChangedThisFrame = false;
var sourcePathChangedThisFrame = false;
var needsAssetRefresh = false;

var biggestLabelSize = EditorStyles.label.CalcSize(new GUIContent("Request Timeout in seconds")).x;
EditorGUIUtility.labelWidth = biggestLabelSize;
Expand Down Expand Up @@ -149,6 +151,46 @@ public override void OnGUI([CanBeNull] string searchContext)
ConfigurationManager.NugetConfigFile.SlimRestore = slimRestore;
}

using (new EditorGUILayout.HorizontalScope())
{
var repositoryPath = ConfigurationManager.NugetConfigFile.RepositoryPath;

GUILayout.Label(
new GUIContent("Packages Install path:", $"Absolute path: {repositoryPath}"),
GUILayout.Width(EditorGUIUtility.labelWidth));
GUILayout.Label(ConfigurationManager.NugetConfigFile.RelativeRepositoryPath);

if (GUILayout.Button("Browse", GUILayout.Width(100)))
{
var newPath = EditorUtility.OpenFolderPanel("Select folder where packages will be installed", repositoryPath, string.Empty);
if (!string.IsNullOrEmpty(newPath))
{
var newRelativePath = PathHelper.GetRelativePath(Application.dataPath, newPath);

// We need to make sure saved path is using forward slashes so it works on all systems
newRelativePath = newRelativePath.Replace('\\', '/');

if (string.Equals(newRelativePath, "../Packages", StringComparison.OrdinalIgnoreCase))
{
EditorUtility.DisplayDialog("Error", "You must create and select a subfolder since Packages folder can't be used directly.", "OK");
}
else if (newPath != repositoryPath && UnityPathHelper.IsValidInstallPath(newRelativePath))
{
PackageContentManager.MoveInstalledPackages(repositoryPath, newPath);
ConfigurationManager.NugetConfigFile.RelativeRepositoryPath = newRelativePath;
UnityPathHelper.EnsurePackageInstallDirIsSetup();
preferencesChangedThisFrame = true;
needsAssetRefresh = true;
}
else if (newPath != repositoryPath)
{
Debug.LogError(
$"Packages install path {newPath} {newRelativePath} is not valid. It must be somewhere under Assets or Packages folder.");
}
}
}
}

using (new EditorGUILayout.HorizontalScope())
{
var packagesConfigPath = ConfigurationManager.NugetConfigFile.PackagesConfigDirectoryPath;
Expand All @@ -169,6 +211,7 @@ public override void OnGUI([CanBeNull] string searchContext)

PackagesConfigFile.Move(newPath);
preferencesChangedThisFrame = true;
needsAssetRefresh = true;
}
}
}
Expand Down Expand Up @@ -489,6 +532,11 @@ public override void OnGUI([CanBeNull] string searchContext)
// e.g. the 'url' can be changed to a V3 nuget API url so we need to create a V3 package source.
ConfigurationManager.LoadNugetConfigFile();
}

if (needsAssetRefresh)
{
AssetDatabase.Refresh();
}
}

private sealed class NugetPlugin
Expand Down
1 change: 1 addition & 0 deletions src/NuGetForUnity/Editor/Ui/NugetWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,7 @@ private void OnEnable()
name = "NuGetForUnity";
titleContent = new GUIContent("NuGet For Unity");
Refresh(false);
UnityPathHelper.EnsurePackageInstallDirIsSetup();
}

private void ClearViewCache()
Expand Down
Loading