AcUtils
A high performance abstraction layer for AccuRev
AcWorkspaces.cs
Go to the documentation of this file.
1 
16 using System;
17 using System.Collections.Generic;
18 using System.Diagnostics;
19 using System.Linq;
20 using System.Threading.Tasks;
21 using System.Xml.Linq;
22 
23 namespace AcUtils
24 {
25  #region enums
26 
27  public enum WsType {
34  Standard = 1,
37  RefTree = 3,
40  Exclusive = 9,
43  Anchor = 17
44  };
45 
49  public enum WsEOL {
52  Platform = 0,
55  Unix = 1,
58  Windows = 2
59  };
61  #endregion
62 
71  [Serializable]
72  [DebuggerDisplay("{Name} ({ID}), {Host}, {Location} ULevel-Target [{UpdateLevel}:{TargetLevel}]")]
73  public sealed class AcWorkspace : IFormattable, IEquatable<AcWorkspace>, IComparable<AcWorkspace>, IComparable
74  {
75  #region class variables
76  private string _name; // workspace name
77  private int _id; // workspace ID number
78  private string _location; // workspace location; the path on the machine where the workspace is located
79  private string _storage; // location on the host (storage) where the elements physically reside
80  private string _host; // machine name (host) where the elements physically reside
81  private bool _hidden; // true if the workspace has been removed (hidden), false if it is active
82  private AcDepot _depot; // depot the workspace is located in
83  private int _targetLevel; // how up-to-date the workspace should be
84  private int _updateLevel; // how up-to-date the workspace actually is
85  private DateTime? _fileModTime; // time of the oldest non-member file in the workspace with modified status, otherwise time the update command was issued
86  private WsType _type; // 1 (standard workspace), 3 (reference tree), 9 (exclusive-file locking), 17 (anchor-required)
87  private WsEOL _eol; // 0 (platform-appropriate), 1 (Unix/Linux style:NL), 2 (Windows style: CR-LF)
88  private AcPrincipal _principal = new AcPrincipal(); // principal who owns the workspace
89  #endregion
90 
94  internal AcWorkspace() { }
95 
96  #region Equality comparison
97 
99  public bool Equals(AcWorkspace other)
106  {
107  if (ReferenceEquals(other, null)) return false;
108  if (ReferenceEquals(this, other)) return true;
109  var left = Tuple.Create(ID, Depot);
110  var right = Tuple.Create(other.ID, other.Depot);
111  return left.Equals(right);
112  }
113 
118  public override bool Equals(object other)
119  {
120  if (ReferenceEquals(other, null)) return false;
121  if (ReferenceEquals(this, other)) return true;
122  if (GetType() != other.GetType()) return false;
123  return Equals(other as AcWorkspace);
124  }
125 
130  public override int GetHashCode()
131  {
132  var hash = Tuple.Create(ID, Depot);
133  return hash.GetHashCode();
134  }
136  #endregion
137 
138  #region Order comparison
139 
141 
147  public int CompareTo(AcWorkspace other)
148  {
149  int result;
150  if (AcWorkspace.ReferenceEquals(this, other))
151  result = 0;
152  else
153  {
154  result = Depot.CompareTo(other.Depot);
155  if (result == 0)
156  result = Name.CompareTo(other.Name);
157  }
158 
159  return result;
160  }
161 
168  int IComparable.CompareTo(object other)
169  {
170  if (!(other is AcWorkspace))
171  throw new ArgumentException("Argument is not an AcWorkspace", "other");
172  AcWorkspace o = (AcWorkspace)other;
173  return this.CompareTo(o);
174  }
176  #endregion
177 
181  public string Name
182  {
183  get { return _name ?? String.Empty; }
184  internal set { _name = value; }
185  }
186 
190  public bool Hidden
191  {
192  get { return _hidden; }
193  internal set { _hidden = value; }
194  }
195 
201 
221  public string Location
222  {
223  get { return _location ?? String.Empty; }
224  internal set { _location = value; }
225  }
226 
230 
231  public string Storage
232  {
233  get { return _storage ?? String.Empty; }
234  internal set { _storage = value; }
235  }
236 
240 
241  public string Host
242  {
243  get { return _host ?? String.Empty; }
244  internal set { _host = value; }
245  }
246 
250  public int ID
251  {
252  get { return _id; }
253  internal set { _id = value; }
254  }
255 
259  public AcDepot Depot
260  {
261  get { return _depot; }
262  internal set { _depot = value; }
263  }
264 
273  public int TargetLevel
274  {
275  get { return _targetLevel; }
276  internal set { _targetLevel = value; }
277  }
278 
289  public int UpdateLevel
290  {
291  get { return _updateLevel; }
292  internal set { _updateLevel = value; }
293  }
294 
301  public DateTime? FileModTime
302  {
303  get { return _fileModTime; }
304  internal set { _fileModTime = value; }
305  }
306 
310  public WsType Type
311  {
312  get { return _type; }
313  internal set { _type = value; }
314  }
315 
319  public WsEOL EOL
320  {
321  get { return _eol; }
322  internal set { _eol = value; }
323  }
324 
328  public AcPrincipal Principal
329  {
330  get { return _principal; }
331  internal set { _principal = value; }
332  }
333 
339  {
340  AcStream basis = _depot.getBasis(_id);
341  return basis;
342  }
343 
344  #region ToString
345  public string ToString(string format, IFormatProvider provider)
369  {
370  if (provider != null)
371  {
372  ICustomFormatter fmt = provider.GetFormat(this.GetType()) as ICustomFormatter;
373  if (fmt != null)
374  return fmt.Format(format, this, provider);
375  }
376 
377  if (String.IsNullOrEmpty(format))
378  format = "G";
379 
380  switch (format.ToUpperInvariant())
381  {
382  case "G": // name of the workspace, e.g. MARS_DEV3_barnyrd
383  return Name; // general format should be short since it can be called by anything
384  case "LV": // long version (verbose)
385  return $"{Name} ({ID}) {{{Type}}}{Environment.NewLine}" +
386  $@"Location: ""{Location}"", Storage: ""{Storage}""{Environment.NewLine}" +
387  $"Host: {Host}, ULevel-Target [{UpdateLevel}:{TargetLevel}]{((TargetLevel != UpdateLevel) ? " (incomplete)" : String.Empty)}{Environment.NewLine}" +
388  $"Depot: {Depot}, EOL: {EOL}, Hidden: {Hidden}{Environment.NewLine}";
389  case "I": // workspace ID number
390  return ID.ToString();
391  case "L": // workspace location
392  return Location;
393  case "S": // location on the host (storage) where the elements physically reside
394  return Storage;
395  case "M": // machine name (host) where the elements physically reside
396  return Host;
397  case "H": // True if workspace is hidden, False otherwise
398  return Hidden.ToString();
399  case "D": // depot name
400  return Depot.ToString();
401  case "TL": // how up-to-date the workspace should be
402  return TargetLevel.ToString();
403  case "UL": // how up-to-date the workspace actually is
404  return UpdateLevel.ToString();
405  case "U": // time of the oldest non-member file in the workspace with modified status, otherwise time the update command was issued
406  return FileModTime.ToString();
407  case "T": // type of workspace: standard, exclusive-file locking, anchor-required, or reference tree
408  return Type.ToString();
409  case "E": // end-of-line character in use by the workspace: platform-appropriate, Unix/Linux style, or Windows style
410  return EOL.ToString();
411  case "PI": // ID number of the AccuRev principal who owns the workspace
412  return Principal.ID.ToString();
413  case "PN": // principal name of the workspace owner
414  return Principal.Name;
415  default:
416  throw new FormatException($"The {format} format string is not supported.");
417  }
418  }
419 
420  // Calls ToString(string, IFormatProvider) version with a null IFormatProvider argument.
421  public string ToString(string format)
422  {
423  return ToString(format, null);
424  }
425 
426  // Calls ToString(string, IFormatProvider) version with the general format and a null IFormatProvider argument.
427  public override string ToString()
428  {
429  return ToString("G", null);
430  }
431  #endregion ToString
432  }
433 
437  [Serializable]
438  public sealed class AcWorkspaces : List<AcWorkspace>
439  {
440  #region class variables
441  private AcDepots _depots;
442  private bool _allWSpaces;
443  private bool _includeHidden;
444  private bool _includeRefTrees;
445  [NonSerialized] private readonly object _locker = new object();
446  #endregion
447 
448  #region object construction:
449 
451 
484  public AcWorkspaces(AcDepots depots, bool allWSpaces, bool includeHidden, bool includeRefTrees = false)
485  {
486  _depots = depots;
487  _allWSpaces = allWSpaces;
488  _includeHidden = includeHidden;
489  _includeRefTrees = includeRefTrees;
490  }
491 
498 
499  public async Task<bool> initAsync(AcDepot depot = null)
500  {
501  Task<AcResult> ws = getWorkspacesXMLAsync();
502  if (_includeRefTrees)
503  {
504  // run both in parallel
505  Task<AcResult> rt = getReferenceTreesXMLAsync();
506  AcResult[] arr = await Task.WhenAll(ws, rt).ConfigureAwait(false);
507  bool ret = (arr != null && arr.All(n => n != null && n.RetVal == 0)); // true if both were successful
508  if (!ret) return false;
509  foreach (AcResult r in arr)
510  {
511  if (!storeWSpaces(r, depot))
512  return false;
513  }
514  }
515  else
516  {
517  AcResult r = await ws.ConfigureAwait(false);
518  if (r != null && r.RetVal == 0)
519  {
520  if (!storeWSpaces(r, depot))
521  return false;
522  }
523  else
524  return false;
525  }
526 
527  return true;
528  }
530  #endregion
531 
537 
538 
542  private async Task<AcResult> getWorkspacesXMLAsync()
543  {
544  AcResult result = null;
545  try
546  {
547  string cmd = null;
548  // for all below, -v option adds the Loc (location) to output
549  if (_allWSpaces && _includeHidden)
550  // All workspaces, not just those that belong to the principal. Include deactivated workspaces.
551  cmd = "show -fvix -a wspaces"; // -a is the only option available for show wspaces
552  else if (_allWSpaces && !_includeHidden)
553  // All workspaces, not just those that belong to the principal. Do not include deactivated workspaces.
554  cmd = "show -fvx -a wspaces";
555  else if (!_allWSpaces && _includeHidden)
556  // Only those workspaces that belong to the principal. Include deactivated workspaces.
557  cmd = "show -fvix wspaces";
558  else if (!_allWSpaces && !_includeHidden)
559  // Only those workspaces that belong to the principal. Do not include deactivated workspaces.
560  cmd = "show -fvx wspaces";
561  result = await AcCommand.runAsync(cmd).ConfigureAwait(false);
562  }
563 
564  catch (AcUtilsException ecx)
565  {
566  AcDebug.Log($"AcUtilsException caught and logged in AcWorkspaces.getWorkspacesXMLAsync{Environment.NewLine}{ecx.Message}");
567  }
568 
569  catch (Exception ecx)
570  {
571  AcDebug.Log($"Exception caught and logged in AcWorkspaces.getWorkspacesXMLAsync{Environment.NewLine}{ecx.Message}");
572  }
573 
574  return result;
575  }
576 
582 
583 
587  private async Task<AcResult> getReferenceTreesXMLAsync()
588  {
589  AcResult result = null;
590  try
591  {
592  // -fvix: display all reference trees including deactivated ones
593  // -fvx: display only active reference trees
594  result = await AcCommand.runAsync($"show {(_includeHidden ? "-fvix" : "-fvx")} refs").ConfigureAwait(false);
595  }
596 
597  catch (AcUtilsException ecx)
598  {
599  AcDebug.Log($"AcUtilsException caught and logged in AcWorkspaces.getReferenceTreesXMLAsync{Environment.NewLine}{ecx.Message}");
600  }
601 
602  catch (Exception ecx)
603  {
604  AcDebug.Log($"Exception caught and logged in AcWorkspaces.getReferenceTreesXMLAsync{Environment.NewLine}{ecx.Message}");
605  }
606 
607  return result;
608  }
609 
619  private bool storeWSpaces(AcResult result, AcDepot depot = null)
620  {
621  bool ret = false; // assume failure
622  try
623  {
624  // filter out workspace/ref trees not in the user's default list
625  XElement xml = XElement.Parse(result.CmdResult);
626  IEnumerable<XElement> filter;
627  if (depot != null)
628  filter = from w in xml.Elements("Element")
629  join AcDepot d in _depots on
630  (string)w.Attribute("depot") equals d.Name
631  where (string)w.Attribute("depot") == depot.Name
632  select w;
633  else
634  filter = from w in xml.Elements("Element")
635  join AcDepot d in _depots on
636  (string)w.Attribute("depot") equals d.Name
637  select w;
638 
639  foreach (XElement e in filter)
640  {
641  AcWorkspace ws = new AcWorkspace();
642  ws.Name = (string)e.Attribute("Name");
643  ws.Hidden = (e.Attribute("hidden") != null); // attribute hidden exists only when true
644  ws.Location = (string)e.Attribute("Loc");
645  ws.Storage = (string)e.Attribute("Storage");
646  ws.Host = (string)e.Attribute("Host");
647  ws.ID = (int)e.Attribute("Stream");
648  string temp = (string)e.Attribute("depot");
649  ws.Depot = _depots.getDepot(temp);
650  ws.TargetLevel = (int)e.Attribute("Target_trans");
651  ws.UpdateLevel = (int)e.Attribute("Trans");
652  ws.FileModTime = e.acxTime("fileModTime");
653  int type = (int)e.Attribute("Type");
654  ws.Type = (WsType)type;
655  int eol = (int)e.Attribute("EOL");
656  ws.EOL = (WsEOL)eol;
657  ws.Principal.ID = (int)e.Attribute("user_id");
658  ws.Principal.Name = (string)e.Attribute("user_name");
659  lock (_locker) { Add(ws); }
660  }
661 
662  ret = true; // operation succeeded
663  }
664 
665  catch (Exception ecx)
666  {
667  AcDebug.Log($"Exception caught and logged in AcWorkspaces.storeWSpaces{Environment.NewLine}{ecx.Message}");
668  }
669 
670  return ret;
671  }
672 
678  public AcDepot getDepot(string name)
679  {
680  AcWorkspace wspace = this.SingleOrDefault(n => n.Name == name);
681  return (wspace != null) ? wspace.Depot : null;
682  }
683 
691  {
692  return this.SingleOrDefault(n => n.ID == ID && n.Depot.Equals(depot));
693  }
694 
700  public AcWorkspace getWorkspace(string name)
701  {
702  return this.SingleOrDefault(n => n.Name == name);
703  }
704  }
705 }
int ID
AccuRev principal ID number for the user or group.
Definition: AcPrincipal.cs:145
bool Equals(AcWorkspace other)
IEquatable implementation to determine the equality of instances of type AcWorkspace. Uses the workspace ID number and depot to compare instances.
int ID
Workspace ID number. The same number as AcStream.ID when the stream object is a workspace.
AccuRev program return value and command result.
Definition: AcCommand.cs:29
async Task< AcResult > getReferenceTreesXMLAsync()
Get the list of reference trees in XML and optionally include those that are inactive as per AcWorksp...
WsType Type
Type of workspace: standard, exclusive-file locking, anchor-required, or reference tree...
int CompareTo(AcWorkspace other)
Generic IComparable implementation (default) for comparing AcWorkspace objects to sort by depot name ...
int UpdateLevel
Current update level of the workspace. Also known as the workspace transaction level or x-action...
AcPrincipal Principal
AccuRev principal who owns the workspace.
async Task< AcResult > getWorkspacesXMLAsync()
Get the list of workspaces in XML for all or the current user and optionally include inactive workspa...
WsType
Workspace type the user created. These numeric values are passed by AccuRev and converted to our enum...
Definition: AcWorkspaces.cs:31
string Location
Here Loc is the workspace location; the path on the machine where the workspace is located...
async Task< bool > initAsync(AcDepot depot=null)
Populate this container with AcWorkspace objects as per constructor parameters.
Contains the AccuRev principal attributes name, ID and status (active or inactive) for users and grou...
Definition: AcPrincipal.cs:52
bool Hidden
True if the workspace has been removed (hidden), False if it is active.
AcWorkspace getWorkspace(string name)
Get the AcWorkspace object for workspace name.
string Host
Machine name where the elements physically reside.
A depot object that defines the attributes of an AccuRev depot.
Definition: AcDepots.cs:49
AcDepot Depot
Depot the workspace is located in.
string ToString(string format, IFormatProvider provider)
The ToString implementation.
A container of AcWorkspace objects that define AccuRev workspaces in the repository.
AcDepot getDepot(string name)
Get the AcDepot object that workspace name is located in.
A stream object that defines the attributes of an AccuRev stream. AcStream objects are instantiated d...
Definition: AcStreams.cs:74
string CmdResult
The command result (usually XML) emitted by AccuRev.
Definition: AcCommand.cs:70
int RetVal
The AccuRev program return value for the command, otherwise minus one (-1) on error.
Definition: AcCommand.cs:61
static void Log(string message, bool formatting=true)
Write the message text to STDOUT, to weekly log files located in %LOCALAPPDATA%\AcTools\Logs, and to trigger.log in the AccuRev server's ..storage\site_slice\logs folder in the case of triggers.
Definition: AcDebug.cs:378
AcWorkspace getWorkspace(AcDepot depot, int ID)
Get the AcWorkspace object in depot with workspace ID number.
string Name
Depot name.
Definition: AcDepots.cs:251
override int GetHashCode()
Override appropriate for type AcWorkspace.
int TargetLevel
Current target level of the workspace. Also known as the target transaction level or target x-action...
WsEOL EOL
End-of-line character in use by the workspace: platform-appropriate, Unix/Linux style, or Windows style.
string Name
AccuRev principal name for the user or group.
Definition: AcPrincipal.cs:154
Exception thrown when an AccuRev command fails. The AccuRev program return value is zero (0) on succe...
AcStream getBasis(string name)
Get the basis (parent) stream for stream name.
Definition: AcDepots.cs:318
AccuRev command processing.
Definition: AcCommand.cs:138
static async Task< AcResult > runAsync(string command, ICmdValidate validator=null)
Run the AccuRev command asynchronously with non-blocking I/O.
Definition: AcCommand.cs:184
int CompareTo(AcDepot other)
Generic IComparable implementation (default) for comparing AcDepot objects to sort by depot name...
Definition: AcDepots.cs:211
Use to log and display error and general purpose text messages, and to save the XML param data sent b...
Definition: AcDebug.cs:100
string Name
Name of the workspace, e.g. MARS_DEV3_barnyrd
A container of AcDepot objects that define AccuRev depots in the repository.
Definition: AcDepots.cs:622
AcStream getBasis()
Get the basis (parent) stream for this workspace.
string ToString(string format, IFormatProvider provider)
The ToString implementation.
Definition: AcDepots.cs:573
DateTime FileModTime
This property value is used in AccuRev's update algorithm while processing the update command...
string Storage
Location on the Host where the elements physically reside.
A workspace object that defines the attributes of an AccuRev workspace. AcWorkspace objects are insta...
Definition: AcWorkspaces.cs:73
bool storeWSpaces(AcResult result, AcDepot depot=null)
Convert AcResult.CmdResult XML from result into AcWorkspace objects and add them to our container...
WsEOL
End-of-line character used by the workspace. These numeric values are passed by AccuRev and converted...
Definition: AcWorkspaces.cs:49
override bool Equals(object other)
Overridden to determine equality.
AcWorkspaces(AcDepots depots, bool allWSpaces, bool includeHidden, bool includeRefTrees=false)
A container of AcWorkspace objects that define AccuRev workspaces in the repository.
AcWorkspace()
Constructor used during AcWorkspaces list construction. It is called internally and not by user code...
Definition: AcWorkspaces.cs:94