/// <summary> /// Locks a set of files in git. /// </summary> /// <param name="paths"></param> /// <returns></returns> public bool GitLockFile(string[] paths) { if (!GitHelper.LFSEnabled) { return(false); } var cmdstring = new StringBuilder(); foreach (var path in paths) { cmdstring.Append('"' + path + '"'); } /* * GitHelper.RunGitCommand("track -- " + cmdstring, * proc => * { * if (!proc.WaitForExit(5000)) * { * return true; * } * return false; * } * );*/ bool hasError = GitHelper.RunGitCommand("lfs lock -- " + cmdstring, proc => { try { while (!proc.HasExited) { if (paths.Length > 1) { if (EditorUtility.DisplayCancelableProgressBar("Version Control", "Locking files " + (cmdstring.ToString()) + "...", 0)) { proc.Kill(); return(true); } } else { if (EditorUtility.DisplayCancelableProgressBar("Version Control", "Locking file " + Path.GetFileName(paths[0]) + "...", 0)) { proc.Kill(); return(true); } } Thread.Sleep(16); } } finally { EditorUtility.ClearProgressBar(); } return(false); }, result => { Debug.Log("[LFS Lock] " + result); if (!result.Contains("Locked")) { // Failed for some reason and didn't go to std::error, search for updated locks. RefreshGitLocks(); } else { foreach (var path in paths) { var locked = new LockedFile(); locked.Path = GitHelper.GitToUnityPath(path); locked.User = GitHelper.Username; LockedFiles.Add(path.Trim(), locked); } } }, error => { Debug.Log("Failed to lock " + cmdstring); Debug.LogError(error); return(true); }); EditorApplication.RepaintProjectWindow(); UpdateLockedFiles(); return(!hasError); }
public override bool IsFileLocked(string path) { return(LockedFiles.ContainsKey(path)); }
public override void Initialize() { if (!GitHelper.VCSEnabled) { return; } if (!FindGitRoot()) { Debug.LogError("[VCS] Unable to find .git folder, git support disabled"); return; } Thread m_asyncthread = new Thread(() => { while (true) { try { if (!GitHelper.VCSEnabled) { break; } if (inPlayMode) { Thread.Sleep(100); continue; } UpdateModifiedFilesAsync(); var newLockFiles = new Dictionary <string, LockedFile>(); if (GitHelper.LFSEnabled) { // Update locks GitHelper.RunGitCommand("lfs locks", proc => { if (!proc.WaitForExit(5000)) { return(true); } return(false); }, result => { try { var parts = result.Split('\t'); var path = GitHelper.GitToUnityPath(parts[0]); var user = parts[1]; var locked = new LockedFile(); locked.Path = path; locked.User = user; newLockFiles.Add(path.Trim(), locked); } catch (System.Exception ex) { Debug.LogError("[VCS Async] " + ex); } }, error => { Debug.LogError("[VCS]" + error); return(true); } ); lock (_actionQueueLock) { var cnt = LockedFiles.Count; string hashStr = ""; foreach (var v in LockedFiles) { hashStr += v.Key + ": " + v.Value.User.GetHashCode(); } int hash = hashStr.GetHashCode(); _toRunOnMainThread.Enqueue(() => { // Locked files if (cnt == LockedFiles.Count) { var newHashStr = ""; foreach (var v in LockedFiles) { newHashStr += v.Key + ": " + v.Value.User.GetHashCode(); } int newhash = newHashStr.GetHashCode(); // Let's make sure that the super lazy hashes match if (newhash == hash) { foreach (var v in LockedFiles) { if (v.Value.FileLock != null) { v.Value.FileLock.Dispose(); } } LockedFiles.Clear(); _lockedFiles = newLockFiles; foreach (var v in LockedFiles) { if (v.Value.User != GitHelper.Username && GitHelper.PreventEditsOnRemoteLock) { if (File.Exists(v.Value.Path)) { try { v.Value.FileLock = new FileStream(v.Value.Path, FileMode.Open, FileAccess.Read, FileShare.Read); } catch (System.Exception ex) { Debug.LogError("Failed to create file lock for " + v.Key + ": " + ex); } } } } } } UpdateLockedFiles(); }); } } Thread.Sleep(10000); } catch (ThreadAbortException ex) { throw ex; } catch (System.Exception ex) { Debug.LogError("[VCS Async] " + ex); } } }); m_asyncthread.Name = "Git Async Thread"; m_asyncthread.Start(); // Preserves locked files for play mode, etc AssemblyReloadEvents.beforeAssemblyReload += () => { foreach (var v in LockedFiles) { if (v.Value.FileLock != null) { v.Value.FileLock.Dispose(); } } m_asyncthread.Abort(); UpdateLockedFiles(); }; UnityEditor.SceneManagement.EditorSceneManager.sceneSaved += (scn) => { if (GitHelper.SceneAutoLock) { if (string.IsNullOrEmpty(scn.path)) { return; } if (!IsFileLockedByLocalUser(scn.path)) { GitLockFile(new string[] { scn.path }); } } }; EditorApplication.playModeStateChanged += (s) => { if (s == PlayModeStateChange.ExitingEditMode) { UpdateLockedFiles(); } }; EditorApplication.projectWindowItemOnGUI += (string guid, Rect rect) => { var path = AssetDatabase.GUIDToAssetPath(guid); var iconRect = rect; var oldBack = GUI.backgroundColor; GUI.backgroundColor = new Color(0, 0, 0, 0); if (ModifiedPaths.Contains(path)) { GUI.Box(iconRect, VCSHelper.ModifiedItemIcon); } if (IsFileLockedByLocalUser(path)) { GUI.Box(iconRect, new GUIContent(VCSHelper.LocalLockIcon, "Locked by " + LockedFiles[path].User + " (local user)")); } else if (IsFileLocked(path)) { GUI.Box(iconRect, new GUIContent(VCSHelper.RemoteLockIcon, "Locked by " + LockedFiles[path].User)); } GUI.backgroundColor = oldBack; }; if (VCSPrefs.HasInitializedKeys && !GitHelper.Configured) { if (EditorUtility.DisplayDialog("Version Control", "You have not yet set up your GitHub username and you will not be able to lock files. Would you like to open the configuration window?", "Yes", "No")) { VCSConfigWindow.OpenWindow(); } } else { LoadLockedFilesFromVCSPrefs(); RefreshGitLockTypes(); } }
public void RefreshGitLocks() { if (GitHelper.AutoUpdateSubmodules) { try { var startinfo = new ProcessStartInfo(); startinfo.FileName = "git"; startinfo.RedirectStandardOutput = true; startinfo.RedirectStandardError = true; startinfo.UseShellExecute = false; startinfo.CreateNoWindow = true; startinfo.Arguments = "submodule update --init --recursive"; var proc = Process.Start(startinfo); string line = "Downloading..."; while (!proc.HasExited) { while (!proc.StandardError.EndOfStream && (line = proc.StandardError.ReadLine()) != null) { Debug.LogError(line); } while (!proc.StandardOutput.EndOfStream && (line = proc.StandardOutput.ReadLine()) != null) { Debug.Log(line); } EditorUtility.DisplayProgressBar("Downloading submodules...", line, 0); Thread.Sleep(30); } Debug.Log("Submodules completed"); } finally { EditorUtility.ClearProgressBar(); } AssetDatabase.Refresh(); } GitHelper.RunGitCommand("lfs", proc => { // If it doesn't work in 10 seconds there's something wrong proc.WaitForExit(10000); return(false); }, result => { }, error => { if (error.Contains("'lfs' is ")) { EditorUtility.DisplayDialog("Version Control", "Error: Git LFS is not installed. File locking will not work. Please install Git LFS.", "Okay"); GitHelper.LFSEnabled = false; } return(true); }); if (!GitHelper.LFSEnabled) { return; } foreach (var v in LockedFiles) { if (v.Value.FileLock != null) { v.Value.FileLock.Dispose(); } } LockedFiles.Clear(); if (GitHelper.LFSEnabled) { GitHelper.RunGitCommand("lfs locks", proc => { try { while (!proc.HasExited) { if (EditorUtility.DisplayCancelableProgressBar("Version Control", "Refreshing LFS locks...", 0)) { proc.Kill(); return(true); } Thread.Sleep(16); } } finally { EditorUtility.ClearProgressBar(); } return(false); }, result => { var parts = result.Split('\t'); var path = GitHelper.GitToUnityPath(parts[0]); Debug.Log("Locking path " + path + "(from " + parts[0] + ")"); var user = parts[1]; var locked = new LockedFile(); locked.Path = path; locked.User = user; if (user != GitHelper.Username && GitHelper.PreventEditsOnRemoteLock) { if (File.Exists(path)) { try { locked.FileLock = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); } catch (System.Exception ex) { Debug.LogError("Failed to create file lock for " + path + ": " + ex); } } } LockedFiles.Add(path.Trim(), locked); }, error => { Debug.LogError(error); return(true); } ); } UpdateLockedFiles(); EditorApplication.RepaintProjectWindow(); }
public bool GitUnlockFile(string[] paths) { if (!GitHelper.LFSEnabled) { return(false); } var cmdstring = new StringBuilder(); foreach (var path in paths) { cmdstring.Append('"' + path + '"'); } bool hasError = GitHelper.RunGitCommand("lfs unlock -- " + cmdstring.ToString(), proc => { try { while (!proc.HasExited) { if (paths.Length > 1) { if (EditorUtility.DisplayCancelableProgressBar("Version Control", "Unlocking files " + (cmdstring.ToString()) + "...", 0)) { proc.Kill(); return(true); } } else { if (EditorUtility.DisplayCancelableProgressBar("Version Control", "Unlocking file " + Path.GetFileName(paths[0]) + "...", 0)) { proc.Kill(); return(true); } } Thread.Sleep(16); } } finally { EditorUtility.ClearProgressBar(); } return(false); }, result => { Debug.Log("[LFS Unlock] " + result); if (!result.Contains("Unlocked")) { // Failed for some reason and didn't go to std::error, search for updated locks. RefreshGitLocks(); } else { foreach (var path in paths) { LockedFiles.Remove(path.Trim()); } } }, error => { EditorUtility.DisplayDialog("Version Control", "Error while unlocking file: " + error, "Okay"); // If it's erroring because it's already locked with local changes, ignore. // Otherwise, someone else locked the file before we did so everything is confused if (!error.Contains("uncommitted")) { RefreshGitLocks(); } return(true); } ); EditorApplication.RepaintProjectWindow(); UpdateLockedFiles(); return(!hasError); }
public void RefreshGitLocks() { foreach (var v in LockedFiles) { if (v.Value.FileLock != null) { v.Value.FileLock.Close(); } } LockedFiles.Clear(); GitHelper.RunGitCommand("lfs locks", proc => { try { while (!proc.HasExited) { if (EditorUtility.DisplayCancelableProgressBar("Version Control", "Refreshing LFS locks...", 0)) { proc.Kill(); return(true); } Thread.Sleep(16); } } finally { EditorUtility.ClearProgressBar(); } return(false); }, result => { var parts = result.Split('\t'); var path = parts[0]; var user = parts[1]; var locked = new LockedFile(); locked.Path = path; locked.User = user; if (user != GitHelper.Username && GitHelper.PreventEditsOnRemoteLock) { try { locked.FileLock = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read); } catch (System.Exception ex) { Debug.LogError("Failed to create file lock for " + path + ": " + ex); } } LockedFiles.Add(path.Trim(), locked); }, error => { Debug.LogError(error); return(true); } ); UpdateLockedFiles(); EditorApplication.RepaintProjectWindow(); }