Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions Assets/Plugins/CandyCoded.GitStatus/Scripts/CustomEditor/Git.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using UnityEngine;

namespace CandyCoded.GitStatus
{
Expand All @@ -15,8 +16,12 @@ public static class Git

#if UNITY_EDITOR_WIN
private static string GitPath => @"C:\Program Files\Git\bin\git.exe";

private static string GitLFSPath => @"C:\Program Files\Git LFS\git-lfs.exe";
#else
private static string GitPath => "/usr/local/bin/git";

private static string GitLFSPath => "/usr/local/bin/git-lfs";
#endif

private static string RepoPath => $"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}";
Expand Down Expand Up @@ -110,13 +115,68 @@ public static async Task DiscardChanges(string path)

}

public static async Task ForceUnlockFile(string path)
{

var process =
await GenerateProcessAsync(GitLFSPath,
$@"unlock ""{path.Replace(RepoPath, "")}"" --force");

process?.WaitForExit();

}

public static async Task Init()
{

await GenerateProcessAsync(GitPath, "init");

}

public static async Task<string[]> LockedFiles()
{

var process = await GenerateProcessAsync(GitLFSPath, "locks --json");

process?.WaitForExit();

var locked = new List<string>();

var locks = JsonUtility.FromJson<Locks>($@"{{""locks"":{process?.StandardOutput.ReadToEnd()}}}").locks;

if (locks != null)
{

for (var i = 0; i < locks.Length; i += 1)
{

locked.Add(locks[i].path);

}

}

return locked.ToArray();

}

public static async Task LockFile(string path)
{

var process = await GenerateProcessAsync(GitLFSPath,
$@"lock ""{path.Replace(RepoPath, "")}""");

if (process?.StandardError.ReadLine() is string line && line.StartsWith("Lock failed: missing protocol"))
{

throw new Exception("Locking requires git repo has been pushed to a remote.");

}

process?.WaitForExit();

}

public static async Task<string> Status()
{

Expand All @@ -133,6 +193,16 @@ public static async Task<string> Status()

}

public static async Task UnlockFile(string path)
{

var process = await GenerateProcessAsync(GitLFSPath,
$@"unlock ""{path.Replace(RepoPath, "")}""");

process?.WaitForExit();

}

public static async Task<string[]> UntrackedFiles()
{

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,31 @@ public static Texture2D Untracked

}

private static Texture2D _locked;

public static Texture2D Locked
{

get
{
if (_locked != null)
{

return _locked;

}

_locked = new Texture2D(SIZE, SIZE);

_locked.LoadImage(Convert.FromBase64String(
"iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAyVBMVEUtQZU6TJtte7WapMy6wdzZ3Ovq7PT19vr8/P0/UZ6GksLQ1ef9/f7///9BU5+psdP6+/ybpMz29/qAjL7x8vcxRZers9Q/Up7O0+ZSYqfo6vPn6vNAUp7n6fI0R5jS1ui4vtvb3u2cpc1qeLRWZqmPmcb5+fyiq9BIWaKvt9dEVqGrs9X3+Pt3hLpQYaZVZanp6/TCx+BUZKhMXaRserWkrdHj5fDx8/g8T5yMl8V/i749T52mrtLJzuPHzOKHksJjcrDv8PdNXqVWCyDhAAABVUlEQVR4AezS1YFbMQAEwDXjHp+Z8ZljZuy/qHxJZpaCmhoGfy/DMAzDMAzDsNkdTpfb4/W4XU6H3YZfy+cPBLkrGPD78Mu8vL7x2NvrC34J2/sHT/t4t0G/zy+e9/UJzb5DvCz0DZ3CEV4TCUOfaIzXxaPQJZHkLZIJ6JFK8zbpFLTIcF82ly+8fL8U8rks92WgQ5G7SmULW1a5xF1FqJfwcEelin3VCnd4ElCuxq16A8cadW7VoFrTSynWwimtH5S8TSjWpuTp4LSOh1IbanUpBXs4pxek1IVS75T6OK9PyQGlBhSGI5w3GlIYQCWL0hiXjClZUGhCwTvFJVMvhQkUmlGY47I5hRkUWlDw47IlhYWegytcttKzcE1hg8s2FNZQgAr8bHeOBQAAAAAG+VtPY0cRJCAgICAgICAgICAgICAgICAgICAgICAgICAgMA8AAAAQnY7wX9sqolIAAAAASUVORK5CYII="
));

return _locked;
}

}

}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#if UNITY_EDITOR
using System;
using System.IO;
using System.Linq;
using UnityEditor;

namespace CandyCoded.GitStatus
Expand All @@ -13,10 +14,17 @@ public static class GitMenuItems

private const int PRIORITY = 5000;

private static string GetSelectedPath()
private static string GetSelectedAbsolutePath()
{

return Path.Combine(Environment.CurrentDirectory, AssetDatabase.GetAssetPath(Selection.activeObject));
return Path.Combine(Environment.CurrentDirectory, GetSelectedRelativePath());

}

private static string GetSelectedRelativePath()
{

return AssetDatabase.GetAssetPath(Selection.activeObject);

}

Expand All @@ -28,7 +36,7 @@ private static async void DiscardChanges()
try
{

await Git.DiscardChanges(GetSelectedPath());
await Git.DiscardChanges(GetSelectedAbsolutePath());

}
catch (Exception error)
Expand All @@ -45,7 +53,8 @@ private static async void DiscardChanges()
private static bool ValidateDiscardChanges()
{

return Selection.activeObject && File.Exists(GetSelectedPath());
return Selection.activeObject && File.Exists(GetSelectedAbsolutePath()) &&
GitStatus.changedFiles.Contains(GetSelectedRelativePath());

}

Expand All @@ -63,7 +72,7 @@ private static async void DiscardAllChanges()
try
{

await Git.DiscardChanges(GetSelectedPath());
await Git.DiscardChanges(GetSelectedAbsolutePath());

}
catch (Exception error)
Expand All @@ -82,7 +91,84 @@ private static async void DiscardAllChanges()
private static bool ValidateDiscardAllChanges()
{

return Selection.activeObject && Directory.Exists(GetSelectedPath());
return Selection.activeObject && Directory.Exists(GetSelectedAbsolutePath());

}

[MenuItem("Git/Lock File", true, PRIORITY)]
[MenuItem("Assets/Lock File", true, PRIORITY)]
private static bool ValidateLockFile()
{

return Selection.activeObject && File.Exists(GetSelectedAbsolutePath()) &&
!GitStatus.lockedFiles.Contains(GetSelectedRelativePath());

}

[MenuItem("Git/Lock File", false, PRIORITY)]
[MenuItem("Assets/Lock File", false, PRIORITY)]
private static async void LockFile()
{

try
{

await Git.LockFile(GetSelectedAbsolutePath());

}
catch (Exception error)
{

EditorUtility.DisplayDialog("Error", error.Message, "Ok");

}

}

[MenuItem("Git/Unlock File", true, PRIORITY)]
[MenuItem("Assets/Unlock File", true, PRIORITY)]
private static bool ValidateUnlockFile()
{

return Selection.activeObject && File.Exists(GetSelectedAbsolutePath()) &&
GitStatus.lockedFiles.Contains(GetSelectedRelativePath());

}

[MenuItem("Git/Unlock File", false, PRIORITY)]
[MenuItem("Assets/Unlock File", false, PRIORITY)]
private static async void UnlockFile()
{

await Git.UnlockFile(GetSelectedAbsolutePath());

}

[MenuItem("Git/Force Unlock File", true, PRIORITY)]
[MenuItem("Assets/Force Unlock File", true, PRIORITY)]
private static bool ValidateForceUnlockFile()
{

return Selection.activeObject && File.Exists(GetSelectedAbsolutePath()) &&
GitStatus.lockedFiles.Contains(GetSelectedRelativePath());

}

[MenuItem("Git/Force Unlock File", false, PRIORITY)]
[MenuItem("Assets/Force Unlock File", false, PRIORITY)]
private static async void ForceUnlockFile()
{

if (EditorUtility.DisplayDialog(
"Force unlock file",
$"Are you sure you want to force unlock {Selection.activeObject.name}?",
"Yes",
"Cancel"))
{

await Git.ForceUnlockFile(GetSelectedAbsolutePath());

}

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public static class GitStatus

public static string[] changedFiles = { };

public static string[] lockedFiles = { };

public static string[] untrackedFiles = { };

public static DateTime lastUpdated = DateTime.Now;
Expand Down Expand Up @@ -66,6 +68,7 @@ public static async void UpdateAsync()
branch = await Git.Branch();
branches = await Git.Branches();
changedFiles = await Git.ChangedFiles();
lockedFiles = await Git.LockedFiles();
untrackedFiles = await Git.UntrackedFiles();

lastUpdated = DateTime.Now;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ private void OnGUI()

GUILayout.Label($"Number of Changes: {GitStatus.changedFiles?.Length}");
GUILayout.Label($"Untracked Files: {GitStatus.untrackedFiles?.Length}");
GUILayout.Label($"Locked Files: {GitStatus.lockedFiles?.Length}");
GUILayout.Label($"Last Updated: {GitStatus.lastUpdated}");

if (GUILayout.Button("Refresh"))
Expand Down
39 changes: 39 additions & 0 deletions Assets/Plugins/CandyCoded.GitStatus/Scripts/CustomEditor/Locks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) Scott Doxey. All Rights Reserved. Licensed under the MIT License. See LICENSE in the project root for license information.

#if UNITY_EDITOR
using System;

namespace CandyCoded.GitStatus
{

public struct Locks
{

public Lock[] locks;

}

[Serializable]
public struct Lock
{

[Serializable]
public struct Owner
{

public string name;

}

public long id;

public string path;

public Owner owner;

public string locked_at;

}

}
#endif

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

Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ private static void ProjectWindowItemOnGui(string guid, Rect selectionRect)
GUI.DrawTexture(rect, GitIcons.Untracked, ScaleMode.ScaleToFit);

}
else if (GitStatus.lockedFiles.Contains(path))
{

GUI.DrawTexture(rect, GitIcons.Locked, ScaleMode.ScaleToFit);

}

}

Expand Down