using UnityEngine; using UnityEditor; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using Perforce.P4; using log4net; namespace P4Connect { public static class ChangeManager { private static readonly ILog log = LogManager.GetLogger(typeof(ChangeManager)); public static int DEFAULT_CHANGE = -1; static Dictionary<int, Changelist> _changes = new Dictionary<int, Changelist>(); public static void Initialize() { } /// <summary> /// This callback is working and is called whenever an Operation is completed with a list of the modifed assetPaths /// </summary> /// <param name="assetPaths">Enumeration of asset paths</param> public static void OnUpdatedFiles(IEnumerable<string> assetPaths) { // ToDo: This routine should check all pending changes to see if they contain any of the assets. log.Debug("OnUpdatedFiles " + Logger.StringEnumerationToString(assetPaths)); HashSet<string> changeContents = ChangeManager.GetHashMap(DEFAULT_CHANGE); changeContents.IntersectWith(assetPaths); foreach (var f in changeContents) { ReplaceChangeMetadata(ChangeManager.DEFAULT_CHANGE, f); } } /// <summary> /// Find an existing FileMetaData in an existing Change and Update it. /// </summary> /// <param name="changeId">Change Id of Change to update</param> /// <param name="path">AssetPath</param> static void ReplaceChangeMetadata(int changeId, string path) { PrepareChanges(); var files = _changes[changeId].Files.ToList(); int j = files.FindIndex(e => e.ToAssetPath().Equals(path)); if (j > 0) { files[j] = AssetStatusCache.GetCachedMetaData(path); } else { //Debug.Log("No Match found for " + path + " in change " + changeId); _changes[changeId].Files.Add(AssetStatusCache.GetCachedMetaData(path)); } } /// <summary> /// See if this Change has already been retrieved from server, /// If not, retrieve it. /// </summary> /// <param name="changeId">Change ID of changelist</param> /// <param name="force">optional flag to force reinitialization</param> public static void PrepareChange(int changeId, bool force = false) { if (Config.ValidConfiguration) { PrepareChanges(); if (force || !_changes[changeId].Initialized) { using (PerforceConnection con = new PerforceConnection()) { RefreshChange(con, changeId); } } } } /// <summary> /// Get a list of ChangeListsWindow /// </summary> /// <returns>List of Changelists</returns> public static IList<Changelist> Changelists { get { PrepareChanges(); return (_changes.Values.ToList()); } } /// <summary> /// Get a specific changelist by ID /// </summary> /// <param name="id"></param> /// <returns>Changelist</returns> public static Changelist GetChangelist(int id) { PrepareChanges(); if (_changes.ContainsKey(id)) { PrepareChange(id); return (_changes[id]); } Debug.Log("GetChangelist() can't find " + id.ToString()); return null; } /// <summary> /// Get a HashSet containing all paths in the selected change ID /// </summary> /// <param name="id">change ID (-1 for DefaultChange) </param> /// <returns>A hashset</returns> public static HashSet<string> GetHashMap(int id) { var change = GetChangelist(id); if (change != null) { if (! change.Files.IsNullOrEmpty()) { return change.Files.ToAssetPaths().ToHashSet(); } } return new HashSet<string>(); } /// <summary> /// Return the string associated with a change id /// </summary> /// <param name="id"></param> /// <returns>string id</returns> public static string ChangeIdToString(int id) { if (id <= DEFAULT_CHANGE) return "default"; return id.ToString(); } /// <summary> /// Get a list of all local opened files from the DEFAULT_CHANGE /// </summary> public static IEnumerable<string> LocalOpenedFiles { get { PrepareChanges(); PrepareChange(DEFAULT_CHANGE); foreach (string fname in _changes[DEFAULT_CHANGE].Files.ToAssetPaths()) { yield return fname; } } } /// <summary> /// If the ChangeListsWindow have not been initialized, do it. /// If not initialized, call "p4 changes" /// </summary> /// <returns>number of changelists</returns> public static int PrepareChanges() { // If no changes have been stored, look for some if (_changes.Count == 0 || (!_changes.ContainsKey(DEFAULT_CHANGE))) { using (PerforceConnection con = new PerforceConnection()) { RefreshChangeLists(con); } } return _changes.Count; } // Collect all the Changelists and put them in the _changes dictionary static void RefreshChangeLists(PerforceConnection p4conn) { if (Config.ValidConfiguration) { //log.DebugFormat("RefreshChangeLists {0}", all.ToString()); _changes.Clear(); // Create a placeholder for the default change Changelist dchange = new Changelist() { Description = "Default", OwnerName = Config.Username, ClientId = Config.Workspace }; dchange.initialize(p4conn.P4Connection); _changes.Add(DEFAULT_CHANGE, dchange); //// Now go get the numbered change lists //ChangesCmdOptions opts = new ChangesCmdOptions(ChangesCmdFlags.FullDescription, null, 0, ChangeListStatus.Pending, null); //IList<Changelist> allChanges = p4conn.P4Depot.GetChangelists(opts, null); //if (allChanges != null) //{ // foreach (var change in allChanges) // { // change.initialize(p4conn.P4Connection); // _changes.Add(change.Id, change); // if (all) // { // RefreshChange(p4conn, change.Id); // } // } //} } } /// <summary> /// Go to the Server and retrieve information about a specific change /// Collect all the files and shelves for a specific changelist /// </summary> /// <param name="p4Conn">Perforce Connection</param> /// <param name="changeId">Change ID </param> static void RefreshChange( PerforceConnection p4Conn, int changeId) { if (Config.ValidConfiguration) { log.DebugFormat("RefreshChange {0}", changeId); if (changeId <= DEFAULT_CHANGE) { RefreshDefaultChange(p4Conn); return; } // Get files for the specified changeId _changes[changeId].initialize(p4Conn.P4Connection); // runs "p4 change -o" to get file lists // Get shelves too P4Command cmd = new P4Command(p4Conn.P4Connection, "describe", true, "-S", changeId.ToString()); P4CommandResult results = cmd.Run(); if ((results.Success) && (results.TaggedOutput != null) && (results.TaggedOutput.Count > 0)) { _changes[changeId].FromChangeCmdTaggedOutput(results.TaggedOutput[0], true, string.Empty, false); // FIXME: the time zone is wrong. } // Verify that all the files returned are rooted in this project var filesToRemove = _changes[changeId].Files.Where(entry => entry.ClientPath != null && entry.ClientPath.Path != null && ! entry.ClientPath.Path.StartsWith(Config.ClientProjectRootMatch) == false); foreach(var itemToRemove in filesToRemove) { log.Debug("Removing file from change " + changeId.ToString() + ", not in project: " + itemToRemove.ClientPath.Path); _changes[changeId].Files.Remove(itemToRemove); } } } /// <summary> /// Force a refresh of the Default Change /// </summary> /// <param name="p4Conn"></param> static void RefreshDefaultChange(PerforceConnection p4Conn) { if (Config.ValidConfiguration) { // Use "p4 opened -c default" to get the opened files in the default changelist Options opts = new Options(); opts["-c"] = "default"; // The default change opts["-C"] = Config.Workspace; // workspace must match opts["-u"] = Config.Username; // username must match also IList<File> allOpenedFiles = p4Conn.P4Depot.GetOpenedFiles(Config.ProjectFileSpec, opts); PrepareChanges(); _changes[DEFAULT_CHANGE].Files.Clear(); // Clear out old list of files if (allOpenedFiles != null) { //AssetStatusCache.GetAssetMetaData() IEnumerable<FileSpec> fromMetas = allOpenedFiles.Cast<FileSpec>().UnversionedSpecs(); // we need to break this into bite sized chunks var fromMetasBatches = fromMetas.Split(100); foreach (var batch in fromMetasBatches) { // Go to the server to get all the metadata var files = AssetStatusCache.GetAssetMetaData(p4Conn, batch.ToAssetPaths()); // Update the Default Change with the new MetaData foreach (var file in files) { _changes[DEFAULT_CHANGE].Files.Add(AssetStatusCache.GetCachedMetaData(file)); } } } } } } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 22026 | prizkall |
Populate -o //guest/perforce_software/p4connect/... //guest/prizkall/p4connect/.... |
||
//guest/perforce_software/p4connect/main/src/P4Connect/P4Connect/P4Connect.ChangeManager.cs | |||||
#4 | 20581 | Norman Morse |
Add P4Connect.Skin Fixed issues in ChangeManager Renamed ChangeLists to ChangeListsWindow. |
||
#3 | 20275 | Norman Morse |
Update source to match 2016.2 patch 2 release Much thrashing of source during refactor. Proper caching of asset statuses, reducing fstats issued. Some bug fixes by Liz Lam Cleanup of Pending changes, rework of initialization and play/stop play transitions |
||
#2 | 16350 | Norman Morse |
Minor Code Clean Up Minor Documentation Clean Up Changed Post Processor callback to ignore directories Added option to use Server Typemap |
||
#1 | 16209 | Norman Morse | Move entire source tree into "main" branch so workshop code will act correctly. | ||
//guest/perforce_software/p4connect/src/P4Connect/P4Connect/P4Connect.ChangeManager.cs | |||||
#9 | 15244 | Norman Morse |
Better Directory support in "add" "get latest" "refresh" and other commands. Improved Project Root detection Various Bug Fixes and Clean up |
||
#8 | 14193 | Norman Morse |
GA.7 release Refactor Pending Changes Resolve Submit issues. Fixed Menu entries. Handle mismatched file and meta states. |
||
#7 | 13824 | Norman Morse |
Changes to have fstat return true client paths. Remove versions, fixes problems with "local" paths sneaking into results. |
||
#6 | 13813 | Norman Morse |
Changed Config to call CheckProjectRoot which creates ClientProjectRoot and DepotProjectRoot Filter files in changelists to include only files under the Project root. Run fstat on files in the default change to make sure we have complete metadata |
||
#5 | 13692 | Norman Morse |
Fix FileSpec corruption issue Make sure that the logged in user is verified against files in the default change. Multiple users can share the same workspace and cause lots of confusion. Also changed the code in Perforce.P4.Changelist.ToString() to create new FileSpecs instead of doing implicite casts. This should fix the exception if the source FileMetaData is incomplete some how. |
||
#4 | 12862 | Norman Morse |
Fixed problem with an empty default change list not refresshing. Fixed crash in is_ignored Removed a lot of log output |
||
#3 | 12565 | Norman Morse |
Integrated from Dev Branch Made ChangeManager into Static Class. Improved close window behavior for when connection is invalid Fixed localOpenFiles not updating on submit |
||
#2 | 12553 | Norman Morse |
integrate from internal main Build fixes for EC. Major changes to Configuration and re-initialization code. Bug fixes |
||
#1 | 12512 | Norman Morse | Integrate from Dev branch, preparing for Beta3 release | ||
//guest/norman_morse/dev/p4connect/src/P4Connect/P4Connect/P4Connect.ChangeManager.cs | |||||
#4 | 12501 | Norman Morse |
Rewrote Configuration Window. Provided buttons to read values and to save configurations. Removed P4Config settings, replaced with P4Config button and reports to Debug.Log() Removed SaveConfigurationAsset Setting, replaced with "Save as Asset" button. Made Connection Configuration read only while connected. Made dialogs disappear if they become disconnected during OnGui() Bumped Beta Value. |
||
#3 | 12480 | Norman Morse |
Fixed crash in logging. Worked on UI issues. Cleaned up some connection usage. Still looking for the problem with pending changes. |
||
#2 | 12473 | Norman Morse | More minor fixes to logging and config | ||
#1 | 12445 | Norman Morse |
Integrated log4net and nunit into P4Connect. Still need cleanup and debugging, good enough for dev tree Also added ChangeManager and ChangeLists Classes for future use with multiple changes. |