AcUtils
A high performance abstraction layer for AccuRev
AcLocks.cs
Go to the documentation of this file.
1 
16 using System;
17 using System.Collections.Generic;
18 using System.Linq;
19 using System.Threading.Tasks;
20 using System.Xml.Linq;
21 
22 namespace AcUtils
23 {
24  #region enums
25 
26  public enum LockKind {
33  from,
36  to,
39  all
40  };
41 
43  public enum PrinType
47  {
50  group,
53  user,
56  none
57  };
59 
61  public enum OnlyExcept {
67  Only,
70  Except
71  };
73  #endregion
74 
82  [Serializable]
83  public sealed class AcLock : IFormattable, IEquatable<AcLock>, IComparable<AcLock>, IComparable
84  {
85  #region class variables
86  // Kind and Name are the only ones that always exist in the XML.
87  // Others exist only if there are values for them.
88  private LockKind _kind;
89  private string _name;
90  private PrinType _type;
91  private string _exceptFor;
92  private string _onlyFor;
93  private string _comment;
94  #endregion
95 
99  internal AcLock() {}
100 
101  #region Equality comparison
102 
104  public bool Equals(AcLock other)
111  {
112  if (ReferenceEquals(other, null)) return false;
113  if (ReferenceEquals(this, other)) return true;
114  // [stream], [from|to|all]
115  var left = Tuple.Create(Name, Kind);
116  var right = Tuple.Create(other.Name, other.Kind);
117  return left.Equals(right);
118  }
119 
124  public override bool Equals(object other)
125  {
126  if (ReferenceEquals(other, null)) return false;
127  if (ReferenceEquals(this, other)) return true;
128  if (GetType() != other.GetType()) return false;
129  return Equals(other as AcLock);
130  }
131 
136  public override int GetHashCode()
137  {
138  var hash = Tuple.Create(Name, Kind);
139  return hash.GetHashCode();
140  }
142  #endregion
143 
144  #region Order comparison
145 
147 
154  public int CompareTo(AcLock other)
155  {
156  int result;
157  if (AcLock.ReferenceEquals(this, other))
158  result = 0;
159  else
160  {
161  result = (-1 * Kind.CompareTo(other.Kind)); // descending
162  if (result == 0)
163  result = String.Compare(Name, other.Name);
164  }
165 
166  return result;
167  }
168 
175  int IComparable.CompareTo(object other)
176  {
177  if (!(other is AcLock))
178  throw new ArgumentException("Argument is not an AcLock", "other");
179  AcLock o = (AcLock)other;
180  return this.CompareTo(o);
181  }
183  #endregion
184 
188  public LockKind Kind
189  {
190  get { return _kind; }
191  internal set { _kind = value; }
192  }
193 
197  public string Name
198  {
199  get { return _name ?? String.Empty; }
200  internal set { _name = value; }
201  }
202 
206  public PrinType Type
207  {
208  get { return _type; }
209  internal set { _type = value; }
210  }
211 
215  public string ExceptFor
216  {
217  get { return _exceptFor ?? String.Empty; }
218  internal set { _exceptFor = value; }
219  }
220 
224  public string OnlyFor
225  {
226  get { return _onlyFor ?? String.Empty; }
227  internal set { _onlyFor = value; }
228  }
229 
233  public string Comment
234  {
235  get { return _comment ?? String.Empty; }
236  internal set { _comment = value; }
237  }
238 
239  #region ToString
240  public string ToString(string format, IFormatProvider provider)
256  {
257  if (provider != null)
258  {
259  ICustomFormatter fmt = provider.GetFormat(this.GetType()) as ICustomFormatter;
260  if (fmt != null)
261  return fmt.Format(format, this, provider);
262  }
263 
264  if (String.IsNullOrEmpty(format))
265  format = "G";
266 
267  switch (format.ToUpperInvariant())
268  {
269  case "G": // long version and default when not using a format specifier
270  {
271  string kind = $"{((Kind == LockKind.all) ? "promotions to and from" : "promotions " + Kind)}";
272  string howfor = String.Format("{0}",
273  (Kind == LockKind.all) || (String.IsNullOrEmpty(ExceptFor) && String.IsNullOrEmpty(OnlyFor)) ?
274  "for all" : !String.IsNullOrEmpty(ExceptFor) ?
275  ("except for " + Type + " " + ExceptFor) : ("for " + Type + " " + OnlyFor + " only"));
276  return $"Lock {kind} {Name} {howfor}. {Comment}";
277  }
278  case "K": // kind of AccuRev lock: from, to, or all
279  return Kind.ToString();
280  case "N": // name of stream the lock applies to
281  return Name;
282  case "T": // whether lock is for a user or group
283  return Type.ToString();
284  case "E": // lock applies to all except this principal
285  return ExceptFor;
286  case "O": // lock applies only to this principal
287  return OnlyFor;
288  case "C": // comment given to the lock
289  return Comment;
290  default:
291  throw new FormatException($"The {format} format string is not supported.");
292  }
293  }
294 
295  // Calls ToString(string, IFormatProvider) version with a null IFormatProvider argument.
296  public string ToString(string format)
297  {
298  return ToString(format, null);
299  }
300 
301  // Calls ToString(string, IFormatProvider) version with the general format and a null IFormatProvider argument.
302  public override string ToString()
303  {
304  return ToString("G", null);
305  }
306  #endregion ToString
307  }
308 
313  [Serializable]
314  public sealed class AcLocks : List<AcLock>
315  {
316  #region class variables
317  [NonSerialized] private readonly object _locker = new object();
318  #endregion
319 
320  #region object construction:
321 
323 
359  public AcLocks() { }
360 
370 
372  public async Task<bool> initAsync(AcDepot depot = null)
373  {
374  bool ret = false; // assume failure
375  try
376  {
377  AcResult r = await AcCommand.runAsync("show -fx locks").ConfigureAwait(false);
378  if (r != null && r.RetVal == 0)
379  {
380  XElement xml = XElement.Parse(r.CmdResult);
381  IEnumerable<XElement> query = null;
382  if (depot == null)
383  query = from e in xml.Elements("Element")
384  select e;
385  else
386  query = from e in xml.Elements("Element")
387  join AcStream s in depot.Streams on (string)e.Attribute("Name") equals s.Name
388  select e;
389  ret = initList(query);
390  }
391  }
392 
393  catch (AcUtilsException ecx)
394  {
395  AcDebug.Log($"AcUtilsException caught and logged in AcLocks.initAsync(AcDepot){Environment.NewLine}{ecx.Message}");
396  }
397 
398  catch (Exception ecx)
399  {
400  AcDebug.Log($"Exception caught and logged in AcLocks.initAsync(AcDepot){Environment.NewLine}{ecx.Message}");
401  }
402 
403  return ret;
404  }
405 
415 
417  public async Task<bool> initAsync(DepotsCollection depots)
418  {
419  AcDepots dlist = new AcDepots();
420  if (!(await dlist.initAsync(depots).ConfigureAwait(false))) return false;
421 
422  bool ret = false; // assume failure
423  try
424  {
425  AcResult r = await AcCommand.runAsync("show -fx locks").ConfigureAwait(false);
426  if (r != null && r.RetVal == 0)
427  {
428  bool result = true;
429  XElement xml = XElement.Parse(r.CmdResult);
430  for (int ii = 0; ii < dlist.Count && result; ii++)
431  {
432  AcDepot depot = dlist[ii];
433  IEnumerable<XElement> query = from e in xml.Elements("Element")
434  join AcStream s in depot.Streams on (string)e.Attribute("Name") equals s.Name
435  select e;
436  result = initList(query);
437  }
438 
439  ret = result;
440  }
441  }
442 
443  catch (AcUtilsException ecx)
444  {
445  AcDebug.Log($"AcUtilsException caught and logged in AcLocks.initAsync(DepotsCollection){Environment.NewLine}{ecx.Message}");
446  }
447 
448  catch (Exception ecx)
449  {
450  AcDebug.Log($"Exception caught and logged in AcLocks.initAsync(DepotsCollection){Environment.NewLine}{ecx.Message}");
451  }
452 
453  return ret;
454  }
455 
465 
467  public async Task<bool> initAsync(StreamsCollection streams)
468  {
469  bool ret = false; // assume failure
470  try
471  {
472  AcResult r = await AcCommand.runAsync("show -fx locks").ConfigureAwait(false);
473  if (r != null && r.RetVal == 0)
474  {
475  XElement xml = XElement.Parse(r.CmdResult);
476  IEnumerable<XElement> query = from e in xml.Elements("Element")
477  where streams.OfType<StreamElement>().Any(se => se.Stream == (string)e.Attribute("Name"))
478  select e;
479  ret = initList(query);
480  }
481  }
482 
483  catch (AcUtilsException ecx)
484  {
485  AcDebug.Log($"AcUtilsException caught and logged in AcLocks.initAsync(StreamsCollection){Environment.NewLine}{ecx.Message}");
486  }
487 
488  catch (Exception ecx)
489  {
490  AcDebug.Log($"Exception caught and logged in AcLocks.initAsync(StreamsCollection){Environment.NewLine}{ecx.Message}");
491  }
492 
493  return ret;
494  }
496  #endregion
497 
505 
507  private bool initList(IEnumerable<XElement> query)
508  {
509  bool ret = false; // assume failure
510  try
511  {
512  foreach (XElement e in query)
513  {
514  AcLock lk = new AcLock();
515  // Kind and Name are the only ones that always exist in the XML
516  // others exist only if there are values for them
517  string kind = (string)e.Attribute("kind");
518  lk.Kind = (LockKind)Enum.Parse(typeof(LockKind), kind);
519  lk.Name = (string)e.Attribute("Name");
520  string type = (string)e.Attribute("userType") ?? String.Empty;
521  lk.Type = String.IsNullOrEmpty(type) ? PrinType.none :
522  (PrinType)Enum.Parse(typeof(PrinType), type);
523  lk.ExceptFor = (string)e.Attribute("exceptFor") ?? String.Empty;
524  lk.OnlyFor = (string)e.Attribute("onlyFor") ?? String.Empty;
525  lk.Comment = (string)e.Attribute("comment") ?? String.Empty;
526  lock (_locker) { Add(lk); }
527  }
528 
529  ret = true; // operation succeeded
530  }
531 
532  catch (Exception ecx)
533  {
534  AcDebug.Log($"Exception caught and logged in AcLocks.initList{Environment.NewLine}{ecx.Message}");
535  }
536 
537  return ret;
538  }
539 
545  public bool hasLock(string stream)
546  {
547  AcLock lk = this.FirstOrDefault(n => n.Name == stream);
548  return (lk != null);
549  }
550 
562 
564  public async Task<bool> lockAsync(string stream, string comment, LockKind kind = LockKind.all, AcPrincipal prncpl = null, OnlyExcept onlyexcept = OnlyExcept.Except)
565  {
566  bool ret = false; // assume failure
567  try
568  {
569  string cmd = null;
570  if (kind == LockKind.from)
571  if (prncpl != null)
572  cmd = $@"lock -c ""{comment}"" -kf {((onlyexcept == OnlyExcept.Except) ? "-e" : "-o")} ""{prncpl}"" ""{stream}""";
573  else
574  cmd = $@"lock -c ""{comment}"" -kf ""{stream}"""; // lock 'from' for all
575  else if (kind == LockKind.to)
576  if (prncpl != null)
577  cmd = $@"lock -c ""{comment}"" -kt {((onlyexcept == OnlyExcept.Except) ? "-e" : "-o")} ""{prncpl}"" ""{stream}""";
578  else
579  cmd = $@"lock -c ""{comment}"" -kt ""{stream}"""; // lock 'to' for all
580  else if (kind == LockKind.all)
581  cmd = $@"lock -c ""{comment}"" ""{stream}"""; // lock 'to and from' for all
582 
583  AcResult r = await AcCommand.runAsync(cmd).ConfigureAwait(false);
584  ret = (r != null && r.RetVal == 0);
585  }
586 
587  catch (AcUtilsException ecx)
588  {
589  AcDebug.Log($"AcUtilsException in AcLocks.lockAsync caught and logged.{Environment.NewLine}{ecx.Message}");
590  }
591 
592  return ret;
593  }
594 
603 
604  public async Task<bool> unlockAsync(string stream, LockKind kind = LockKind.all)
605  {
606  bool ret = false; // assume failure
607  try
608  {
609  string cmd = null;
610  if (kind == LockKind.from)
611  cmd = $@"unlock -kf ""{stream}""";
612  else if (kind == LockKind.to)
613  cmd = $@"unlock -kt ""{stream}""";
614  else if (kind == LockKind.all)
615  cmd = $@"unlock ""{stream}""";
616 
617  AcResult r = await AcCommand.runAsync(cmd).ConfigureAwait(false);
618  ret = (r != null && r.RetVal == 0);
619  }
620 
621  catch (AcUtilsException ecx)
622  {
623  AcDebug.Log($"AcUtilsException in AcLocks.unlockAsync caught and logged.{Environment.NewLine}{ecx.Message}");
624  }
625 
626  return ret;
627  }
628  }
629 }
PrinType Type
Whether the lock is for a user or group.
Definition: AcLocks.cs:207
OnlyExcept
Lock applies to the principal only or to all except the principal.
Definition: AcLocks.cs:64
AccuRev program return value and command result.
Definition: AcCommand.cs:29
A container of AcLock objects that define the AccuRev locks that prevent certain users from making ch...
Definition: AcLocks.cs:314
override bool Equals(object other)
Overridden to determine equality.
Definition: AcLocks.cs:124
string OnlyFor
Lock applies only to this principal.
Definition: AcLocks.cs:225
bool initList(IEnumerable< XElement > query)
Helper function that populates this container with AcLock objects as per query sent by an initAsync m...
Definition: AcLocks.cs:507
The list of AccuRev depots from .exe.config.
async Task< bool > initAsync(StreamsCollection streams)
Populate this container with AcLock objects on streams.
Definition: AcLocks.cs:467
A lock object that defines the attributes of an AccuRev lock: The stream name the lock is on and mann...
Definition: AcLocks.cs:83
AcLock()
Constructor used during AcLocks list construction. It is called internally and not by user code...
Definition: AcLocks.cs:99
IEnumerable< AcStream > Streams
The list of streams in this depot.
Definition: AcDepots.cs:287
AcLocks()
A container of AcLock objects that define the AccuRev locks that prevent certain users from making ch...
Definition: AcLocks.cs:359
async Task< bool > unlockAsync(string stream, LockKind kind=LockKind.all)
Remove lock kind on stream.
Definition: AcLocks.cs:604
async Task< bool > initAsync(DepotsCollection depotsCol=null, IProgress< int > progress=null)
Populate this container with AcDepot objects as per constructor parameters.
Definition: AcDepots.cs:714
Contains the AccuRev principal attributes name, ID and status (active or inactive) for users and grou...
Definition: AcPrincipal.cs:52
A depot object that defines the attributes of an AccuRev depot.
Definition: AcDepots.cs:49
async Task< bool > initAsync(AcDepot depot=null)
Populate this container with AcLock objects on streams in depot or all AcLock objects in the reposito...
Definition: AcLocks.cs:372
async Task< bool > lockAsync(string stream, string comment, LockKind kind=LockKind.all, AcPrincipal prncpl=null, OnlyExcept onlyexcept=OnlyExcept.Except)
Put a lock on stream as per lock kind.
Definition: AcLocks.cs:564
async Task< bool > initAsync(DepotsCollection depots)
Populate this container with AcLock objects on streams in depots.
Definition: AcLocks.cs:417
PrinType
Whether the lock is for a user or a group.
Definition: AcLocks.cs:46
A stream object that defines the attributes of an AccuRev stream. AcStream objects are instantiated d...
Definition: AcStreams.cs:74
override int GetHashCode()
Override appropriate for type AcLock.
Definition: AcLocks.cs:136
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
LockKind Kind
Kind of AccuRev lock: from, to, or all.
Definition: AcLocks.cs:189
Exception thrown when an AccuRev command fails. The AccuRev program return value is zero (0) on succe...
AccuRev command processing.
Definition: AcCommand.cs:138
An AccuRev stream from the Streams section in .exe.config.
static async Task< AcResult > runAsync(string command, ICmdValidate validator=null)
Run the AccuRev command asynchronously with non-blocking I/O.
Definition: AcCommand.cs:184
Use to log and display error and general purpose text messages, and to save the XML param data sent b...
Definition: AcDebug.cs:100
bool hasLock(string stream)
Determine if stream has a lock on it.
Definition: AcLocks.cs:545
A container of AcDepot objects that define AccuRev depots in the repository.
Definition: AcDepots.cs:622
LockKind
The kind of AccuRev lock.
Definition: AcLocks.cs:30
string ExceptFor
Lock applies to all except this principal.
Definition: AcLocks.cs:216
bool Equals(AcLock other)
IEquatable implementation to determine the equality of instances of type AcLock. Uses stream name the...
Definition: AcLocks.cs:110
string ToString(string format, IFormatProvider provider)
The ToString implementation.
Definition: AcLocks.cs:255
string Name
Name of stream the lock applies to.
Definition: AcLocks.cs:198
The list of AccuRev streams from .exe.config.
int CompareTo(AcLock other)
Generic IComparable implementation (default) for comparing AcLock objects to sort by LockKind (descen...
Definition: AcLocks.cs:154
string Comment
Comment given to the lock.
Definition: AcLocks.cs:234