Skip to content

Commit

Permalink
feat: deterministic package installation
Browse files Browse the repository at this point in the history
Record the commit hash of the auto-installed package in `packages-lock.git.json`
  • Loading branch information
mob-sakai committed Aug 28, 2020
1 parent 09612ca commit 5485ff9
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ private static void UninstallUnusedPackages()
{
needToCheck = true;
Log("Uninstall the unused package '{0}@{1}'", p.name, p.version);
PackageMeta.GitUnlock(p);
FileUtil.DeleteFileOrDirectory(p.repository);
}
}
Expand All @@ -106,6 +107,7 @@ private static void StartResolve()
var needToCheck = true;

Log("Start dependency resolution.");
PackageMeta.LoadGitLock();
AssetDatabase.StartAssetEditing();
while (needToCheck)
{
Expand Down Expand Up @@ -186,16 +188,18 @@ private static void StartResolve()
DirUtils.Delete(installPath);
DirUtils.Create(installPath);
DirUtils.Move(pkgPath, installPath, p => p != ".git");
AssetDatabase.ImportAsset(installPath, ImportAssetOptions.ForceUpdate | ImportAssetOptions.ForceSynchronousImport | ImportAssetOptions.ImportRecursive);

Log("A package '{0}@{1}' has been installed.", package.name, package.version);
needToRefresh = true;
AssetDatabase.ImportAsset(installPath, ImportAssetOptions.ForceUpdate | ImportAssetOptions.ForceSynchronousImport | ImportAssetOptions.ImportRecursive);
PackageMeta.GitLock(package);
}

EditorUtility.ClearProgressBar();
}

AssetDatabase.StopAssetEditing();
PackageMeta.SaveGitLock();

Log("Dependency resolution complete. refresh = {0}", needToRefresh);
if (needToRefresh)
Expand Down
29 changes: 26 additions & 3 deletions Packages/com.coffee.git-dependency-resolver/Editor/GitUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Coffee.GitDependencyResolver
{
//TODO: It's better to implement it in javascript.
internal static class GitUtils
{
private static readonly StringBuilder s_sbError = new StringBuilder();
Expand All @@ -16,11 +17,32 @@ internal static class GitUtils
public static bool ClonePackage(PackageMeta package, string clonePath)
{
Directory.CreateDirectory(clonePath);
var args = string.Format("clone --depth=1 --branch {0} --single-branch {1} {2}", package.rev, package.url, clonePath);
return ExecuteGitCommand(args);

ExecuteGitCommand("init", dir: clonePath);
ExecuteGitCommand("remote add origin " + package.repository, dir: clonePath);
if (!string.IsNullOrEmpty(package.path))
{
ExecuteGitCommand("config core.sparsecheckout true", dir: clonePath);
File.WriteAllText(Path.Combine(clonePath, ".git/info/sparse-checkout"), package.path);
}

var revision = !string.IsNullOrEmpty(package.hash)
? package.hash
: !string.IsNullOrEmpty(package.revision)
? package.revision
: "HEAD";

return
ExecuteGitCommand("fetch --depth 1 origin " + revision, dir: clonePath)
&& ExecuteGitCommand("reset --hard FETCH_HEAD", dir: clonePath)
&& ExecuteGitCommand("rev-parse HEAD", (success, output) =>
{
if (!success) return;
package.hash = output.Trim();
}, dir: clonePath);
}

static bool ExecuteGitCommand(string args, GitCommandCallback callback = null, bool waitForExit = true)
static bool ExecuteGitCommand(string args, GitCommandCallback callback = null, bool waitForExit = true, string dir = ".")
{
var startInfo = new System.Diagnostics.ProcessStartInfo
{
Expand All @@ -30,6 +52,7 @@ static bool ExecuteGitCommand(string args, GitCommandCallback callback = null, b
RedirectStandardError = true,
RedirectStandardOutput = true,
UseShellExecute = false,
WorkingDirectory = dir,
};

var launchProcess = System.Diagnostics.Process.Start(startInfo);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,47 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEngine;

namespace Coffee.GitDependencyResolver
{
[Serializable]
internal class GitLock
{
public List<Entry> dependencies = new List<Entry>();

[Serializable]
internal struct Entry
{
public string name;
public string hash;
public string url;

public Entry(PackageMeta package)
{
name = package.name;
hash = package.hash;
url = package.url;
}

public bool IsValid(PackageMeta package)
{
return name == package.name && url == package.url;
}
}
}

internal class PackageMeta
{
#if NETSTANDARD
const RegexOptions k_RegOption = RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture;
#else
const RegexOptions k_RegOption = RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.ExplicitCapture;
#endif
private const string k_GitLockFile = "Packages/packages-lock.git.json";

private static readonly Regex s_PackageUrlReg =
new Regex(
@"^(git\+)?" +
Expand All @@ -26,20 +56,26 @@ internal class PackageMeta
@"(git@|git://|http://|https://|ssh://)",
k_RegOption);

private static readonly GitLock s_GitLock = new GitLock();

public string name { get; private set; }
internal SemVersion version { get; private set; }
public string revision { get; private set; }
public string repository { get; private set; }
public string path { get; private set; }
public PackageMeta[] dependencies { get; private set; }
public PackageMeta[] gitDependencies { get; private set; }
public string hash { get; set; }
public string url { get; set; }

private PackageMeta()
{
name = "";
repository = "";
revision = "";
path = "";
hash = "";
url = "";
version = new SemVersion(0);
dependencies = new PackageMeta [0];
gitDependencies = new PackageMeta [0];
Expand Down Expand Up @@ -126,6 +162,8 @@ public static PackageMeta FromNameAndUrl(string name, string url)

package.repository = m.Groups["repository"].Value;
package.revision = m.Groups["revision"].Value;
package.url = url;
package.hash = s_GitLock.dependencies.FirstOrDefault(x => x.IsValid(package)).hash ?? "";

// Get version from revision/branch/tag
package.SetVersion(package.revision);
Expand Down Expand Up @@ -182,7 +220,39 @@ public string GetDirectoryName()

public override string ToString()
{
return string.Format("{0}@{1} ({2}) [{3}]", name, version, revision, path);
return string.Format("{0}@{1} ({2}) [{3}] <{4}>", name, version, revision, path, url);
}

public static void LoadGitLock()
{
var text = File.Exists(k_GitLockFile)
? File.ReadAllText(k_GitLockFile)
: "{}";

JsonUtility.FromJsonOverwrite(text, s_GitLock);
}

public static void GitLock(PackageMeta package)
{
s_GitLock.dependencies.RemoveAll(e => e.name == package.name);
s_GitLock.dependencies.Add(new GitLock.Entry(package));
}

public static void GitUnlock(PackageMeta package)
{
s_GitLock.dependencies.RemoveAll(e => e.name == package.name);
}

public static void SaveGitLock()
{
var text = File.Exists(k_GitLockFile)
? File.ReadAllText(k_GitLockFile)
: "{}";

var text2 = JsonUtility.ToJson(s_GitLock, true);
if (text == text2) return;

File.WriteAllText(k_GitLockFile, text2);
}
}
}
9 changes: 9 additions & 0 deletions Packages/packages-lock.git.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"dependencies": [
{
"name": "com.coffee.ugd.math",
"hash": "46720ffb837eb050452d5e78503ddd08cfe8ff5c",
"url": "https://github.com/mob-sakai/UnityGitDependencyTest.git?path=Packages/math"
}
]
}

0 comments on commit 5485ff9

Please sign in to comment.