/// <summary>
        /// Get the list of depot names in sorted order.
        /// </summary>
        /// <returns>The list of depot names on success, otherwise \e null on error.</returns>
        /*! \show_ <tt>show -fx depots</tt> */
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c show command failure.</exception>
        public static async Task <List <string> > getDepotNameListAsync()
        {
            List <string> depots = null;
            AcResult      result = null;

            try { result = await AcCommand.runAsync("show -fx depots").ConfigureAwait(false); }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcQuery.getDepotNameListAsync{Environment.NewLine}{ecx.Message}");
            }

            if (result != null && result.RetVal == 0) // if command succeeded
            {
                XElement xml = XElement.Parse(result.CmdResult);
                IEnumerable <XElement> query = from e in xml.Elements("Element")
                                               select e;
                int num = query.Count();
                depots = new List <string>(num);
                foreach (XElement n in query)
                {
                    depots.Add((string)n.Attribute("Name"));
                }

                depots.Sort();
            }

            return(depots);
        }
        /// <summary>
        /// Get user preferences retrieved by way of the \c getpref command.
        /// </summary>
        /// <returns>The full path to a temp file with the XML results from the \e getpref command, otherwise \e null on error.
        /// The caller is responsible for deleting the file.</returns>
        /*! \getpref_  \c getpref */

        /*! \accunote_ When using the AccuRev GUI client, changes in <em>User Preferences</em> do not always persist.
         *  As a workaround, use [setpref](https://www.microfocus.com/documentation/accurev/72/WebHelp/wwhelp/wwhimpl/js/html/wwhelp.htm#href=AccuRev_User_CLI/cli_ref_setpref.html):
         * -# Exit the AccuRev client.
         * -# Put the setting\(s\) needed in a file named <tt>set_pref.xml</tt>
         * -# Open a command window and cd to the folder where the file is located.
         * -# Run the command <tt>accurev setpref -l set_pref.xml</tt> \(-l switch is a lowercase L\)
         * -# Run the AccuRev client and verify the setting\(s\).
         * \verbatim
         * <AcRequest>
         * <USE_IGNORE_ELEMS_OPTIMIZATION>true</USE_IGNORE_ELEMS_OPTIMIZATION>
         * ...
         * </AcRequest>
         * \endverbatim */
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c getpref command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>
        private static async Task <string> getPreferencesAsync()
        {
            // Putting the XML into a file as opposed to using it directly avoids exceptions thrown
            // due to illegal characters. Needs further investigation.
            string tempFile = null;

            try
            {
                AcResult r = await AcCommand.runAsync("getpref").ConfigureAwait(false);

                if (r != null && r.RetVal == 0) // if command succeeded
                {
                    tempFile = Path.GetTempFileName();
                    using (StreamWriter writer = new StreamWriter(tempFile))
                    {
                        writer.Write(r.CmdResult);
                    }
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcPreferences.getPreferencesAsync{Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx) // IOException, DirectoryNotFoundException, PathTooLongException, SecurityException... others
            {
                AcDebug.Log($"Exception caught and logged in AcPreferences.getPreferencesAsync{Environment.NewLine}{ecx.Message}");
            }

            return(tempFile);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Populate this container with AcLock objects on \e streams.
        /// </summary>
        /// <param name="streams">Limit the list of locks to those on \e streams only. Stream names in \e streams
        /// must match their respective AccuRev stream name exactly.</param>
        /// <returns>\e true if initialization succeeded, \e false otherwise.</returns>
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c show command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>
        /*! \sa [AcLocks constructor](@ref AcUtils#AcLocks#AcLocks), initAsync(AcDepot), initAsync(DepotsCollection) */
        /*! \show_ <tt>show -fx locks</tt> */
        public async Task <bool> initAsync(StreamsCollection streams)
        {
            bool ret = false; // assume failure

            try
            {
                AcResult r = await AcCommand.runAsync("show -fx locks").ConfigureAwait(false);

                if (r != null && r.RetVal == 0)
                {
                    XElement xml = XElement.Parse(r.CmdResult);
                    IEnumerable <XElement> query = from e in xml.Elements("Element")
                                                   where streams.OfType <StreamElement>().Any(se => se.Stream == (string)e.Attribute("Name"))
                                                   select e;
                    ret = initList(query);
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcLocks.initAsync(StreamsCollection){Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcLocks.initAsync(StreamsCollection){Environment.NewLine}{ecx.Message}");
            }

            return(ret);
        }
        /// <summary>
        /// Get the total number of workspaces in the repository including those that are hidden.
        /// </summary>
        /// <returns>Total number of workspaces or <em>minus one (-1)</em> on error.</returns>
        /*! \show_ <tt>show -fix -a wspaces</tt> */
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c show command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>
        public static async Task <int> getTotalWorkspaceCountAsync()
        {
            int count = -1; // assume failure

            try
            {
                AcResult r = await AcCommand.runAsync("show -fix -a wspaces").ConfigureAwait(false);

                if (r != null && r.RetVal == 0)
                {
                    XElement t = XElement.Parse(r.CmdResult);
                    count = t.Elements("Element").Count();
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcQuery.getTotalWorkspaceCountAsync{Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcQuery.getTotalWorkspaceCountAsync{Environment.NewLine}{ecx.Message}");
            }

            return(count);
        }
        /// <summary>
        /// Get the number of dynamic streams in the repository that have a default group.
        /// </summary>
        /// <returns>Number of dynamic streams with a default group or <em>minus one (-1)</em> on error.</returns>
        /*! \show_ <tt>show -fx -d streams</tt> */
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c show command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>
        public static async Task <int> getDynStreamsCountAsync()
        {
            int count = -1; // assume failure

            try
            {
                AcResult r = await AcCommand.runAsync("show -fx -d streams").ConfigureAwait(false);

                if (r != null && r.RetVal == 0)
                {
                    XElement s = XElement.Parse(r.CmdResult);
                    count = (from d in s.Elements("stream") where d.Attribute("isDynamic").Value == "true" select d).Count();
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcQuery.getDynStreamsCountAsync{Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcQuery.getDynStreamsCountAsync{Environment.NewLine}{ecx.Message}");
            }

            return(count);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Populate this container with AcStream objects as per constructor parameters.
        /// AcStream objects are instantiated during AcDepot and AcDepots construction.
        /// This function is called internally and not by user code.
        /// </summary>
        /// <param name="depot">The depot for which streams will be created.</param>
        /// <param name="listfile">List file <tt>\%APPDATA\%\\AcTools\\<prog_name\>\\<depot_name\>.streams</tt> for the
        /// <a href="https://www.microfocus.com/documentation/accurev/72/WebHelp/wwhelp/wwhimpl/js/html/wwhelp.htm#href=AccuRev_User_CLI/cli_ref_show.html">show -l <list-file> streams</a>
        /// command if found, otherwise \e null.<br>
        /// Example: <tt>"C:\Users\barnyrd\AppData\Roaming\AcTools\FooApp\NEPTUNE.streams"</tt>.</param>
        /// <returns>\e true if initialization succeeded, \e false otherwise.</returns>
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c show command failure.</exception>
        /// <exception cref="Exception">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on failure
        /// to handle a range of exceptions.</exception>
        /*! \sa [AcStreams constructor](@ref AcUtils#AcStreams#AcStreams) */
        /*! \show_ <tt>show \<-fxig|-fxg\> -p \<depot\> [-l listfile] streams</tt> */

        /*! \accunote_ The following XML attributes from <tt>show -fx -p \<depot\> streams</tt> may exist depending on the version of AccuRev in use.
         * They are used internally by AccuRev and are not intended for customer usage. Micro Focus incident #3132463.
         * - \e eventStream: Efficient way to determine if the server process needs to fire the event trigger processing.
         * - \e eventStreamHWM: Used by GitCentric to track the high watermark for synchronization.
         * - \e hasProperties: Efficient way for the GUI to determine if the property icon is displayed in the StreamBrowser. */
        internal async Task <bool> initAsync(AcDepot depot, string listfile = null)
        {
            bool ret = false; // assume failure

            try
            {
                AcResult result = await AcCommand.runAsync($@"show {(_includeHidden ? "-fxig" : "-fxg")} -p ""{depot}""" +
                                                           $@"{((listfile == null) ? String.Empty : "-l " + "" + listfile + "")} streams")
                                  .ConfigureAwait(false);

                if (result != null && result.RetVal == 0)
                {
                    XElement xml = XElement.Parse(result.CmdResult);
                    IEnumerable <XElement> filter = null;
                    if (_dynamicOnly)
                    {
                        filter = from s in xml.Elements("stream")
                                 where (bool)s.Attribute("isDynamic") == true select s;
                    }
                    else
                    {
                        filter = from s in xml.Elements("stream") select s;
                    }

                    foreach (XElement e in filter)
                    {
                        AcStream stream = new AcStream();
                        stream.Name      = (string)e.Attribute("name");
                        stream.ID        = (int)e.Attribute("streamNumber");
                        stream.BasisName = (string)e.Attribute("basis") ?? String.Empty;
                        stream.BasisID   = (int?)e.Attribute("basisStreamNumber") ?? -1;
                        stream.Depot     = depot;
                        stream.IsDynamic = (bool)e.Attribute("isDynamic");
                        string type = (string)e.Attribute("type");
                        stream.Type = (StreamType)Enum.Parse(typeof(StreamType), type);
                        // attribute "time" only exists for snapshot streams (creation date) or when a dynamic stream has a time basis
                        stream.Time      = e.acxTime("time"); // time basis
                        stream.StartTime = (DateTime)e.acxTime("startTime");
                        // hidden attribute exists only if the stream is hidden
                        stream.Hidden          = (e.Attribute("hidden") != null);
                        stream.HasDefaultGroup = (bool)e.Attribute("hasDefaultGroup");
                        lock (_locker) { Add(stream); }
                    }

                    ret = true; // operation succeeded
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcStreams.initAsync{Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcStreams.initAsync{Environment.NewLine}{ecx.Message}");
            }

            return(ret);
        }
        /// <summary>
        /// Get the depot-relative path for the element in \e stream with \e EID.
        /// Also returns the element's parent folder EID (folder where the element resides).
        /// </summary>
        /// <param name="stream">Name of the stream where the element resides.</param>
        /// <param name="EID">The element ID of the element on which to query.</param>
        /// <returns>An tuple initialized as <em>{depot-relative path, parent EID}</em> on success, otherwise \e null.</returns>
        /*! \name_ <tt>name -v \<stream\> -fx -e \<EID\></tt> */
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c name command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>

        /*! \code
         * accurev name -v MARS_MAINT2 -fx -e 13763
         * <?xml version="1.0" encoding="utf-8"?>
         * <AcResponse
         *  Command="name"
         *  TaskId="51498">
         * <element
         *    location="\.\scripts\build.xml"
         *    parent_id="12269"/>
         * </AcResponse>
         * \endcode */
        /*! \accunote_ For the \c name, \c anc and \c cat commands, the validity of the results is guaranteed only if the commands are issued outside a workspace, or in a workspace whose
         *   backing stream is in the same depot for both workspace and the <tt>-v \<ver_spec\></tt> option used. If issued from a workspace that has a different backing stream than
         *   the <tt>-v \<ver_spec\></tt>, provided both workspace and ver_spec share the same depot, the command results can be deemed valid. However, if issued from a workspace whose
         *   backing stream is in a different depot than the <tt>-v \<ver_spec\></tt>, the command results are invalid. Applications should set the default directory to a non-workspace
         *   location prior to issuing these commands. AccuRev defects 18080, 21469, 1097778. */
        public static async Task <Tuple <string, int> > getElementNameAsync(string stream, int EID)
        {
            Tuple <string, int> ret = null; // depot-relative path, parent folder EID

            try
            {
                AcResult r = await AcCommand.runAsync($@"name -v ""{stream}"" -fx -e {EID}").ConfigureAwait(false);

                if (r != null && r.RetVal == 0)
                {
                    XElement xml       = XElement.Parse(r.CmdResult);
                    string   location  = (string)xml.Element("element").Attribute("location");
                    int      parent_id = (int)xml.Element("element").Attribute("parent_id");
                    ret = Tuple.Create(location, parent_id);
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcQuery.getElementNameAsync{Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcQuery.getElementNameAsync{Environment.NewLine}{ecx.Message}");
            }

            return(ret);
        }
        /// <summary>
        /// Use to retrieve the contents of a text file under version control.
        /// </summary>
        /// <remarks>
        /// Puts the content of the specified file in a temporary file. The caller is responsible for deleting the file.
        /// </remarks>
        /// <param name="eid">The file's element ID.</param>
        /// <param name="depot">The depot.</param>
        /// <param name="ver_spec">The version specification in the numeric or text format, e.g. \c 32/1 or \c PG_MAINT1_barnyrd\4.</param>
        /// <returns>A string initialized to the name of the temporary file with the contents from the
        /// AccuRev <tt>cat -v \<ver_spec\> -p \<depot\> -e \<eid\></tt> command on success, otherwise \e null on error.
        /// </returns>
        /*! \cat_ <tt>cat -v \<ver_spec\> -p \<depot\> -e \<eid\></tt> */
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c cat command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>
        /*! \accunote_ The CLI \c cat command fails on Windows for ptext files larger than 62,733 bytes. Fixed in 6.0. AccuRev defect 28177. */

        /*! \accunote_ For the \c name, \c anc and \c cat commands, the validity of the results is guaranteed only if the commands are issued outside a workspace, or in a workspace whose
         *   backing stream is in the same depot for both workspace and the <tt>-v \<ver_spec\></tt> option used. If issued from a workspace that has a different backing stream than
         *   the <tt>-v \<ver_spec\></tt>, provided both workspace and ver_spec share the same depot, the command results can be deemed valid. However, if issued from a workspace whose
         *   backing stream is in a different depot than the <tt>-v \<ver_spec\></tt>, the command results are invalid. Applications should set the default directory to a non-workspace
         *   location prior to issuing these commands. AccuRev defects 18080, 21469, 1097778. */
        public static async Task <string> getCatFileAsync(int eid, AcDepot depot, string ver_spec)
        {
            string tmpFile = null;

            try
            {
                AcResult r = await AcCommand.runAsync($@"cat -v ""{ver_spec}"" -p ""{depot}"" -e {eid}")
                             .ConfigureAwait(false);

                if (r != null && r.RetVal == 0)
                {
                    tmpFile = Path.GetTempFileName();
                    using (StreamWriter streamWriter = new StreamWriter(tmpFile))
                    {
                        streamWriter.Write(r.CmdResult);
                    }
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcQuery.getCatFileAsync{Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx) // IOException, DirectoryNotFoundException, PathTooLongException, SecurityException... others
            {
                AcDebug.Log($"Exception caught and logged in AcQuery.getCatFileAsync{Environment.NewLine}{ecx.Message}");
            }

            return(tmpFile);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Remove \c lock \e kind on \e stream.
        /// </summary>
        /// <param name="stream">Name of stream or workspace to unlock.</param>
        /// <param name="kind">Type of lock to remove: \e to, \e from, or \e all.</param>
        /// <returns>\e true if \e stream was unlocked successfully, \e false otherwise.</returns>
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c unlock command failure.</exception>
        /*! \unlock_ <tt>unlock [-kf | -kt] \<stream\></tt> */
        public async Task <bool> unlockAsync(string stream, LockKind kind = LockKind.all)
        {
            bool ret = false; // assume failure

            try
            {
                string cmd = null;
                if (kind == LockKind.from)
                {
                    cmd = $@"unlock -kf ""{stream}""";
                }
                else if (kind == LockKind.to)
                {
                    cmd = $@"unlock -kt ""{stream}""";
                }
                else if (kind == LockKind.all)
                {
                    cmd = $@"unlock ""{stream}""";
                }

                AcResult r = await AcCommand.runAsync(cmd).ConfigureAwait(false);

                ret = (r != null && r.RetVal == 0);
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException in AcLocks.unlockAsync caught and logged.{Environment.NewLine}{ecx.Message}");
            }

            return(ret);
        }
        /// <summary>
        /// Populate this container with AcProperty objects for all streams in \e depot or just \e stream in \e depot.
        /// Optionally include hidden (removed) streams.
        /// </summary>
        /// <param name="depot">The depot to query for properties.</param>
        /// <param name="stream">The stream for a specific stream only, otherwise \e null for all streams in \e depot.</param>
        /// <param name="includeHidden">\e true to include properties for hidden (removed) streams, \e false otherwise.</param>
        /// <returns>\e true if initialization succeeded, \e false otherwise.</returns>
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging) in
        /// <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c getproperty command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>
        /*! \sa [AcProperties constructor](@ref AcUtils#AcProperties#AcProperties), initAsync(string, bool) */
        /*! \getproperty_ <tt>getproperty \<-fx | -fix\> \<-s \<stream\> | -ks -p \<depot\>\></tt> */
        public async Task <bool> initAsync(AcDepot depot, AcStream stream = null, bool includeHidden = false)
        {
            bool ret = false; // assume failure

            try
            {
                string cmd = null;
                if (stream != null && includeHidden)
                {
                    cmd = $@"getproperty -fix -s ""{stream}""";
                }
                else if (stream != null && !includeHidden)
                {
                    cmd = $@"getproperty -fx -s ""{stream}""";
                }
                else if (includeHidden) // request is for all streams in depot including those that are hidden
                {
                    cmd = $@"getproperty -fix -ks -p ""{depot}""";
                }
                else  // request is for all streams except those that are hidden
                {
                    cmd = $@"getproperty -fx -ks -p ""{depot}""";
                }

                AcResult r = await AcCommand.runAsync(cmd).ConfigureAwait(false);

                if (r != null && r.RetVal == 0)
                {
                    XElement xml = XElement.Parse(r.CmdResult);
                    foreach (XElement e in xml.Elements("property"))
                    {
                        AcProperty property = new AcProperty();
                        string     kind     = (string)e.Attribute("kind");
                        property.Kind      = (PropKind)Enum.Parse(typeof(PropKind), kind);
                        property.Depot     = depot;
                        property.ID        = (int)e.Attribute("streamNumber");
                        property.Name      = (string)e.Attribute("streamName");
                        property.PropName  = (string)e.Attribute("propertyName");
                        property.PropValue = (string)e;
                        lock (_locker) { Add(property); }
                    }

                    ret = true; // operation succeeded
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcProperties.initAsync(AcDepot, AcStream, bool){Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcProperties.initAsync(AcDepot, AcStream, bool){Environment.NewLine}{ecx.Message}");
            }

            return(ret);
        }
        /// <summary>
        /// Convert AcResult.CmdResult XML from \e result into AcWorkspace objects and add them to our container.
        /// Filters out workspace/ref trees that are not in the user's default list of depots they can view based on ACL permissions.
        /// </summary>
        /// <param name="result">Previously initialized AcResult object from AcWorkspaces.getWorkspacesXMLAsync and AcWorkspaces.getReferenceTreesXMLAsync.</param>
        /// <param name="depot">Specify a depot to limit the query to workspaces and ref trees in \e depot only, not the users default list of depots.</param>
        /// <returns>\e true if object initialization succeeded, \e false otherwise.</returns>
        /// <exception cref="Exception">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on failure to handle a range of exceptions.</exception>
        private bool storeWSpaces(AcResult result, AcDepot depot = null)
        {
            bool ret = false; // assume failure

            try
            {
                // filter out workspace/ref trees not in the user's default list
                XElement xml = XElement.Parse(result.CmdResult);
                IEnumerable <XElement> filter;
                if (depot != null)
                {
                    filter = from w in xml.Elements("Element")
                             join AcDepot d in _depots on
                                 (string) w.Attribute("depot") equals d.Name
                                 where (string)w.Attribute("depot") == depot.Name
                             select w;
                }
                else
                {
                    filter = from w in xml.Elements("Element")
                             join AcDepot d in _depots on
                                 (string) w.Attribute("depot") equals d.Name
                             select w;
                }

                foreach (XElement e in filter)
                {
                    AcWorkspace ws = new AcWorkspace();
                    ws.Name     = (string)e.Attribute("Name");
                    ws.Hidden   = (e.Attribute("hidden") != null); // attribute hidden exists only when true
                    ws.Location = (string)e.Attribute("Loc");
                    ws.Storage  = (string)e.Attribute("Storage");
                    ws.Host     = (string)e.Attribute("Host");
                    ws.ID       = (int)e.Attribute("Stream");
                    string temp = (string)e.Attribute("depot");
                    ws.Depot       = _depots.getDepot(temp);
                    ws.TargetLevel = (int)e.Attribute("Target_trans");
                    ws.UpdateLevel = (int)e.Attribute("Trans");
                    ws.FileModTime = e.acxTime("fileModTime");
                    int type = (int)e.Attribute("Type");
                    ws.Type = (WsType)type;
                    int eol = (int)e.Attribute("EOL");
                    ws.EOL            = (WsEOL)eol;
                    ws.Principal.ID   = (int)e.Attribute("user_id");
                    ws.Principal.Name = (string)e.Attribute("user_name");
                    lock (_locker) { Add(ws); }
                }

                ret = true; // operation succeeded
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcWorkspaces.storeWSpaces{Environment.NewLine}{ecx.Message}");
            }

            return(ret);
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Populate this container with AcUser objects as per [constructor parameters](@ref AcUtils#AcUsers#AcUsers).
        /// </summary>
        /// <param name="progress">Optionally report progress back to the caller.</param>
        /// <returns>\e true if list initialization succeeded, \e false otherwise.</returns>
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging) in
        /// <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c show command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>
        /*! \show_ <tt>show \<-fx | -fix\> users</tt> */
        public async Task <bool> initAsync(IProgress <int> progress = null)
        {
            bool ret = false; // assume failure

            try
            {
                AcResult r = await AcCommand.runAsync($"show {(_includeDeactivated ? "-fix" : "-fx")} users")
                             .ConfigureAwait(false);

                if (r != null && r.RetVal == 0) // if command succeeded
                {
                    XElement xml = XElement.Parse(r.CmdResult);
                    IEnumerable <XElement>   query = from element in xml.Elements("Element") select element;
                    List <Task <bool> >      tasks = new List <Task <bool> >(query.Count());
                    Func <Task <bool>, bool> cf    = t =>
                    {
                        bool res = t.Result;
                        if (res && progress != null)
                        {
                            progress.Report(Interlocked.Increment(ref _counter));
                        }
                        return(res);
                    };

                    foreach (XElement e in query)
                    {
                        string name = (string)e.Attribute("Name");
                        int    id   = (int)e.Attribute("Number");
                        // XML attribute isActive exists only if the user is inactive, otherwise it isn't there
                        PrinStatus status = (e.Attribute("isActive") == null) ? PrinStatus.Active : PrinStatus.Inactive;
                        AcUser     user   = new AcUser(id, name, status);
                        lock (_locker) { Add(user); }
                        Task <bool> t = initUserPropsAsync(user).ContinueWith(cf);
                        tasks.Add(t);
                    }

                    bool[] arr = await Task.WhenAll(tasks).ConfigureAwait(false);

                    ret = (arr != null && arr.All(n => n == true));
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcUsers.initAsync{Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcUsers.initAsync{Environment.NewLine}{ecx.Message}");
            }

            return(ret);
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Initialize this AcDepot object with data from AccuRev as per constructor parameter's depot \e name or \e ID number.
        /// </summary>
        /// <returns>\e true if initialization succeeded, \e false otherwise.</returns>
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c show command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>
        /*! \sa AcDepot(string, bool, bool), AcDepot(int, bool, bool), [AcDepots constructor](@ref AcUtils#AcDepots#AcDepots) */
        /*! \show_ <tt>show -fx depots</tt> */
        public async Task <bool> initAsync()
        {
            bool ret = false; // assume failure

            try
            {
                AcResult r = await AcCommand.runAsync("show -fx depots").ConfigureAwait(false);

                if (r != null && r.RetVal == 0)
                {
                    XElement xml = XElement.Parse(r.CmdResult);
                    IEnumerable <XElement> filter = null;
                    if (_id > 0)
                    {
                        filter = from element in xml.Elements("Element")
                                 where (int)element.Attribute("Number") == _id
                                 select element;
                    }
                    else
                    {
                        filter = from element in xml.Elements("Element")
                                 where (string)element.Attribute("Name") == _name
                                 select element;
                    }

                    XElement e = filter.SingleOrDefault();
                    if (e != null)
                    {
                        ID               = (int)e.Attribute("Number");
                        Name             = (string)e.Attribute("Name");
                        Slice            = (int)e.Attribute("Slice");
                        ExclusiveLocking = (bool)e.Attribute("exclusiveLocking");
                        string temp = (string)e.Attribute("case");
                        Case     = (CaseSensitivity)Enum.Parse(typeof(CaseSensitivity), temp);
                        _streams = new AcStreams(_dynamicOnly, _includeHidden);
                        ret      = await _streams.initAsync(this, listFile()).ConfigureAwait(false);
                    }
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcDepot.initAsync{Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcDepot.initAsync{Environment.NewLine}{ecx.Message}");
            }

            return(ret);
        }
        /// <summary>
        /// Determines if the current user is logged into AccuRev and, if so, retrieves their principal name.
        /// </summary>
        /// <remarks>Implemented by extracting the user's principal name or string <b>\"(not logged in)\"</b> from the \c info command results.</remarks>
        /// <returns>A string initialized to the name of the principal logged into AccuRev or \e null if not logged in.</returns>
        /*! \info_ \c info */

        /*! \accunote_ To support GUIs logging into replicas, get host and port from \c info command
         *  (instead of from XML \<serverInfo\> results, which are not correct for replica)
         *  to use in titlebar, preferences.xml, and MQTT messages. 35934/17776122 (35921/17776020) */
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c info command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>

        /*! \note The user must have <tt>AccuRev\\bin</tt> in their \e Path environment variable to run
         *   AccuRev commands issued by the AcUtils library. Since this method is often the first function called
         *   by a client application (in this case \c info), a failure here usually means this entry is missing.*/
        public static async Task <string> getPrincipalAsync()
        {
            string prncpl = null;

            try
            {
                AcResult r = await AcCommand.runAsync("info").ConfigureAwait(false);

                if (r != null && r.RetVal == 0)
                {
                    using (StringReader reader = new StringReader(r.CmdResult))
                    {
                        bool?  login = null; // don't know yet
                        string line;
                        char[] sep = new char[] { ':' };
                        while ((line = reader.ReadLine()) != null && login == null)
                        {
                            string[] arr = line.Split(sep); // "Principal:      barnyrd"
                            if (arr.Length == 2)
                            {
                                if (String.Equals(arr[0], "Principal"))
                                {
                                    string temp = arr[1].Replace("\t", "");
                                    if (String.Equals(temp, "(not logged in)"))
                                    {
                                        login = false;
                                    }
                                    else
                                    {
                                        prncpl = temp; // AccuRev principal name
                                        login  = true;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcQuery.getPrincipalAsync{Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcQuery.getPrincipalAsync{Environment.NewLine}{ecx.Message}");
            }

            return(prncpl); // principal name or null if not logged in
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Get the depot's stream and workspace (optional) hierarchy relationship data from AccuRev.
        /// This method is called internally and not by user code.
        /// </summary>
        /// <param name="includeWSpaces">\e true to include workspaces in the list.</param>
        /// <returns>Fully initialized [MultiValueDictionary](https://www.nuget.org/packages/Microsoft.Experimental.Collections)
        /// object for the depot with [parent(key),children(values)] basis/stream ID's if no exception was thrown
        /// and the operation succeeded, otherwise \e null on error.</returns>
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c show command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>

        /*! \pre Using \e includeWSpaces to include workspaces in the list requires that all stream types be specified at AcDepot
         *   object creation as per the \e dynamicOnly=false (default) constructor parameter. */
        /*! \show_ <tt>show -p \<depot\> [-fix | -fx] -s 1 -r streams</tt> */

        /*! \attention This method requires that you deploy
         *  <a href="https://www.nuget.org/packages/Microsoft.Experimental.Collections">Microsoft.Experimental.Collections.dll</a> with your application. */
        private async Task <MultiValueDictionary <int, int> > getHierarchyAsync(bool includeWSpaces = false)
        {
            MultiValueDictionary <int, int> hierarchy = null;

            try
            {
                AcResult r = await AcCommand.runAsync($@"show -p ""{this}"" {(_includeHidden ? " -fix" : " -fx")} -s 1 -r streams")
                             .ConfigureAwait(false);

                if (r != null && r.RetVal == 0) // if command succeeded
                {
                    XElement xml = XElement.Parse(r.CmdResult);
                    IEnumerable <XElement> filter;
                    if (includeWSpaces)
                    {
                        filter = from s in xml.Elements("stream")
                                 select s;
                    }
                    else
                    {
                        filter = from s in xml.Elements("stream")
                                 where (string)s.Attribute("type") != "workspace" // all except workspaces
                                 select s;
                    }

                    int capacity = filter.Count();
                    hierarchy = new MultiValueDictionary <int, int>(capacity);
                    foreach (XElement e in filter)
                    {
                        // XML attribute basisStreamNumber does not exist in the case of root streams
                        int parent = (int?)e.Attribute("basisStreamNumber") ?? -1;
                        int child  = (int)e.Attribute("streamNumber");
                        hierarchy.Add(parent, child);
                    }
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcDepot.getHierarchyAsync{Environment.NewLine}{ecx.Message}");
                hierarchy = null;
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcDepot.getHierarchyAsync{Environment.NewLine}{ecx.Message}");
                hierarchy = null;
            }

            return(hierarchy);
        }
        /// <summary>
        /// Retrieves the AccuRev program major, minor and patch version numbers.
        /// </summary>
        /// <returns>An array initialized as <em>int[]={major, minor, patch}</em> on success, otherwise \e null on error.</returns>
        /*! \xml_ <tt>xml -l \<xmlfile\></tt> */
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c xml command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>

        /*! \code
         * <?xml version="1.0" encoding="utf-8"?>
         * <serverInfo>
         * <serverVersion
         *    major="5"
         *    minor="6"
         *    patch="0"/>
         * <serverHostPort>machine_name_omitted:5050</serverHostPort>
         * </serverInfo>
         * \endcode */
        public static async Task <int[]> getAccuRevVersionAsync()
        {
            int[]  arr      = null; // major, minor, patch
            string tempFile = null;

            try
            {
                tempFile = Path.GetTempFileName(); // the AccuRev xml command requires a file as its argument
                using (StreamWriter streamWriter = new StreamWriter(tempFile))
                {
                    streamWriter.Write(@"<serverInfo/>"); // set up the query
                }

                AcResult r = await AcCommand.runAsync($@"xml -l ""{tempFile}""").ConfigureAwait(false);

                if (r != null && r.RetVal == 0)
                {
                    using (StringReader reader = new StringReader(r.CmdResult))
                    {
                        XElement doc   = XElement.Load(reader);
                        XElement sv    = doc.Element("serverVersion");
                        int      major = (int)sv.Attribute("major");
                        int      minor = (int)sv.Attribute("minor");
                        int      patch = (int)sv.Attribute("patch");
                        arr = new int[] { major, minor, patch };
                    }
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcQuery.getAccuRevVersionAsync{Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcQuery.getAccuRevVersionAsync{Environment.NewLine}{ecx.Message}");
            }

            finally
            {
                if (tempFile != null)
                {
                    File.Delete(tempFile);
                }
            }

            return(arr);
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Populate this container with AcLock objects on streams in \e depots.
        /// </summary>
        /// <param name="depots">Limit the list of locks to those on streams in \e depots only. Depot names in \e depots
        /// must match their respective AccuRev depot name exactly.</param>
        /// <returns>\e true if initialization succeeded, \e false otherwise.</returns>
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c show command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>
        /*! \sa [AcLocks constructor](@ref AcUtils#AcLocks#AcLocks), initAsync(AcDepot), initAsync(StreamsCollection) */
        /*! \show_ <tt>show -fx locks</tt> */
        public async Task <bool> initAsync(DepotsCollection depots)
        {
            AcDepots dlist = new AcDepots();

            if (!(await dlist.initAsync(depots).ConfigureAwait(false)))
            {
                return(false);
            }

            bool ret = false; // assume failure

            try
            {
                AcResult r = await AcCommand.runAsync("show -fx locks").ConfigureAwait(false);

                if (r != null && r.RetVal == 0)
                {
                    bool     result = true;
                    XElement xml    = XElement.Parse(r.CmdResult);
                    for (int ii = 0; ii < dlist.Count && result; ii++)
                    {
                        AcDepot depot = dlist[ii];
                        IEnumerable <XElement> query = from e in xml.Elements("Element")
                                                       join AcStream s in depot.Streams on(string) e.Attribute("Name") equals s.Name
                                                       select e;

                        result = initList(query);
                    }

                    ret = result;
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcLocks.initAsync(DepotsCollection){Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcLocks.initAsync(DepotsCollection){Environment.NewLine}{ecx.Message}");
            }

            return(ret);
        }
Ejemplo n.º 18
0
        /// <summary>
        /// Put a \c lock on \e stream as per lock \e kind.
        /// </summary>
        /// <param name="stream">Name of stream or workspace to lock.</param>
        /// <param name="comment">Comment to be used for the lock.</param>
        /// <param name="kind">Type of lock to apply: \e to, \e from, or \e all.</param>
        /// <param name="prncpl">AccuRev principal name of user or group in the case of \e to or \e from lock.</param>
        /// <param name="onlyexcept">Apply \c lock to \e prncpl only or to all except \e prncpl.</param>
        /// <returns>\e true if operation succeeded, \e false otherwise.</returns>
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c lock command failure.</exception>
        /*! \lock_ <tt>lock -c \<comment\> [-kf [-e|-o prncpl] | -kt [-e|-o prncpl]] \<stream\></tt> */
        /*! \accunote_ The CLI \c lock command can be used on a workspace stream but the same cannot be done using the AccuRev GUI client. AccuRev defect 23850. */
        public async Task <bool> lockAsync(string stream, string comment, LockKind kind = LockKind.all, AcPrincipal prncpl = null, OnlyExcept onlyexcept = OnlyExcept.Except)
        {
            bool ret = false; // assume failure

            try
            {
                string cmd = null;
                if (kind == LockKind.from)
                {
                    if (prncpl != null)
                    {
                        cmd = $@"lock -c ""{comment}"" -kf {((onlyexcept == OnlyExcept.Except) ? "-e" : "-o")} ""{prncpl}"" ""{stream}""";
                    }
                    else
                    {
                        cmd = $@"lock -c ""{comment}"" -kf ""{stream}""";  // lock 'from' for all
                    }
                }
                else if (kind == LockKind.to)
                {
                    if (prncpl != null)
                    {
                        cmd = $@"lock -c ""{comment}"" -kt {((onlyexcept == OnlyExcept.Except) ? "-e" : "-o")} ""{prncpl}"" ""{stream}""";
                    }
                    else
                    {
                        cmd = $@"lock -c ""{comment}"" -kt ""{stream}"""; // lock 'to' for all
                    }
                }
                else if (kind == LockKind.all)
                {
                    cmd = $@"lock -c ""{comment}"" ""{stream}"""; // lock 'to and from' for all
                }
                AcResult r = await AcCommand.runAsync(cmd).ConfigureAwait(false);

                ret = (r != null && r.RetVal == 0);
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException in AcLocks.lockAsync caught and logged.{Environment.NewLine}{ecx.Message}");
            }

            return(ret);
        }
        //@}
        #endregion

        /// <summary>
        /// Get the list of workspaces in XML for all or the current user and optionally include
        /// inactive workspaces as per [AcWorkspaces constructor](@ref AcUtils#AcWorkspaces#AcWorkspaces) \e includeHidden parameter.
        /// </summary>
        /// <returns>AcResult initialized with the \c show command results, otherwise \e null on error.</returns>
        /*! \show_ <tt>show \<-fvx | -fvix\> \<-a | \> wspaces</tt> */
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on <tt>show wspaces</tt> command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>
        /*! \sa AcWorkspaces.getReferenceTreesXMLAsync */
        private async Task <AcResult> getWorkspacesXMLAsync()
        {
            AcResult result = null;

            try
            {
                string cmd = null;
                // for all below, -v option adds the Loc (location) to output
                if (_allWSpaces && _includeHidden)
                {
                    // All workspaces, not just those that belong to the principal. Include deactivated workspaces.
                    cmd = "show -fvix -a wspaces"; // -a is the only option available for show wspaces
                }
                else if (_allWSpaces && !_includeHidden)
                {
                    // All workspaces, not just those that belong to the principal. Do not include deactivated workspaces.
                    cmd = "show -fvx -a wspaces";
                }
                else if (!_allWSpaces && _includeHidden)
                {
                    // Only those workspaces that belong to the principal. Include deactivated workspaces.
                    cmd = "show -fvix wspaces";
                }
                else if (!_allWSpaces && !_includeHidden)
                {
                    // Only those workspaces that belong to the principal. Do not include deactivated workspaces.
                    cmd = "show -fvx wspaces";
                }
                result = await AcCommand.runAsync(cmd).ConfigureAwait(false);
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcWorkspaces.getWorkspacesXMLAsync{Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcWorkspaces.getWorkspacesXMLAsync{Environment.NewLine}{ecx.Message}");
            }

            return(result);
        }
Ejemplo n.º 20
0
        /// <summary>
        /// Populate this container with AcSession objects, the currently active login sessions.
        /// </summary>
        /// <returns>\e true if no failure occurred and list was initialized successfully, \e false otherwise.</returns>
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging) in
        /// <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c show command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>
        /*! \show_ <tt>show -fx sessions</tt> */
        public async Task <bool> initAsync()
        {
            bool ret = false; // assume failure

            try
            {
                AcResult r = await AcCommand.runAsync("show -fx sessions").ConfigureAwait(false);

                if (r != null && r.RetVal == 0)
                {
                    XElement xml = XElement.Parse(r.CmdResult);
                    foreach (XElement e in xml.Elements("Element"))
                    {
                        AcSession session = new AcSession();
                        session.Name = (string)e.Attribute("Username");
                        session.Host = (string)e.Attribute("Host");
                        string temp = (string)e.Attribute("Duration");
                        if (!String.Equals(temp, "(timed out)"))
                        {
                            double duration = double.Parse(temp);
                            session.Duration = TimeSpan.FromMinutes(duration);
                        }

                        lock (_locker) { Add(session); }
                    }

                    ret = true; // operation succeeded
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcSessions.initAsync{Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcSessions.initAsync{Environment.NewLine}{ecx.Message}");
            }

            return(ret);
        }
        /// <summary>
        /// Populate this container with AcWorkspace objects as per constructor parameters.
        /// </summary>
        /// <remarks>The resultant list includes only workspaces from depots the user has [permission to access](@ref AcUtils#AcPermissions#AcPermissions).</remarks>
        /// <param name="depot">Specify a depot to limit the query to workspaces in \e depot only, not all depots in the repository.</param>
        /// <returns>\e true if initialization succeeded, \e false otherwise.</returns>
        /*! \sa [AcWorkspaces constructor](@ref AcUtils#AcWorkspaces#AcWorkspaces) */
        public async Task <bool> initAsync(AcDepot depot = null)
        {
            Task <AcResult> ws = getWorkspacesXMLAsync();

            if (_includeRefTrees)
            {
                // run both in parallel
                Task <AcResult> rt  = getReferenceTreesXMLAsync();
                AcResult[]      arr = await Task.WhenAll(ws, rt).ConfigureAwait(false);

                bool ret = (arr != null && arr.All(n => n != null && n.RetVal == 0)); // true if both were successful
                if (!ret)
                {
                    return(false);
                }
                foreach (AcResult r in arr)
                {
                    if (!storeWSpaces(r, depot))
                    {
                        return(false);
                    }
                }
            }
            else
            {
                AcResult r = await ws.ConfigureAwait(false);

                if (r != null && r.RetVal == 0)
                {
                    if (!storeWSpaces(r, depot))
                    {
                        return(false);
                    }
                }
                else
                {
                    return(false);
                }
            }

            return(true);
        }
        /// <summary>
        /// Populate this container with AcRule objects for \e stream as per
        /// [constructor parameter](@ref AcUtils#AcRules#AcRules) \e explicitOnly.
        /// </summary>
        /// <param name="stream">The stream to query for rules.</param>
        /// <returns>\e true if no failure occurred and list was initialized successfully, \e false otherwise.</returns>
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging) in
        /// <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c lsrules command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>
        /*! \lsrules_ <tt>lsrules -s \<stream\> [-d] -fx</tt>  */

        /*! \code
         *  <!-- accurev lsrules -s "PG_DEV1" -fx -->
         *  <AcResponse
         *    Command="lscomp"
         *    TaskId="54394">
         *    <element
         *      kind="incl"
         *      elemType="dir"
         *      dir="yes" // Not used as its redundant. We use ElementType.Dir instead.
         *      location="\.\Iconic"
         *      setInStream="PG_DEV1"
         *      xlinkToStream="IC_DEV1"
         *      options="1"/> // Obsolete. Was used for compatibility of rules in version 4.5.3 and earlier. Will always be a value of 1.
         *    <element
         *      kind="incl"
         *      elemType="dir"
         *      dir="yes"
         *      location="\.\"
         *      setInStream="PlayGround"
         *      options="1"/>
         *  </AcResponse>
         *  \endcode */
        public async Task <bool> initAsync(AcStream stream)
        {
            bool ret = false; // assume failure

            try
            {
                AcResult r = await AcCommand.runAsync($@"lsrules -s ""{stream}"" {(_explicitOnly ? "-d" : String.Empty)} -fx")
                             .ConfigureAwait(false);

                if (r != null && r.RetVal == 0)
                {
                    XElement xml = XElement.Parse(r.CmdResult);
                    foreach (XElement e in xml.Elements("element"))
                    {
                        AcRule rule = new AcRule();
                        string kind = (string)e.Attribute("kind");
                        rule.Kind = (RuleKind)Enum.Parse(typeof(RuleKind), kind);
                        string type = (string)e.Attribute("elemType");
                        rule.Type          = (ElementType)Enum.Parse(typeof(ElementType), type);
                        rule.Location      = (string)e.Attribute("location");
                        rule.SetInStream   = (string)e.Attribute("setInStream");
                        rule.XlinkToStream = (string)e.Attribute("xlinkToStream") ?? String.Empty;
                        lock (_locker) { Add(rule); }
                    }

                    ret = true; // operation succeeded
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcRules.initAsync(AcStream){Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcRules.initAsync(AcStream){Environment.NewLine}{ecx.Message}");
            }

            return(ret);
        }
Ejemplo n.º 23
0
        /// <summary>
        /// Populate this container with AcPermission objects.
        /// </summary>
        /// <param name="name">Optional depot or stream name as per
        /// [constructor parameter](@ref AcUtils#AcPermissions#AcPermissions) \e kind, otherwise all.</param>
        /// <returns>\e true if no failure occurred and list was initialized successfully, \e false otherwise.</returns>
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c lsacl command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>
        /*! \sa [AcPermissions constructor](@ref AcUtils#AcPermissions#AcPermissions) */
        /*! \lsacl_ <tt>lsacl -fx {stream|depot} \<name\></tt> */
        public async Task <bool> initAsync(string name = null)
        {
            bool ret = false; // assume failure

            try
            {
                AcResult r = await AcCommand.runAsync($@"lsacl -fx {_kind} ""{name}""").ConfigureAwait(false);

                if (r != null && r.RetVal == 0)
                {
                    XElement xml = XElement.Parse(r.CmdResult);
                    foreach (XElement e in xml.Elements("Element"))
                    {
                        AcPermission perm = new AcPermission(_kind);
                        perm.Name      = (string)e.Attribute("Name");
                        perm.AppliesTo = (string)e.Attribute("Group");
                        string type = (string)e.Attribute("Type");
                        perm.Type = (PermType)Enum.Parse(typeof(PermType), type);
                        string rights = (string)e.Attribute("Rights");
                        perm.Rights      = (PermRights)Enum.Parse(typeof(PermRights), rights);
                        perm.Inheritable = (bool)e.Attribute("Inheritable");
                        lock (_locker) { Add(perm); }
                    }

                    ret = true; // operation succeeded
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcPermissions.initAsync{Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcPermissions.initAsync{Environment.NewLine}{ecx.Message}");
            }

            return(ret);
        }
        //@}
        #endregion

        /// <summary>
        /// Optionally called during [list construction](@ref AcUtils#AcGroups#AcGroups) to initialize the
        /// [list of principals](@ref AcPrincipal#Members) (users and groups) that are direct (explicit) members of \e group.
        /// This method is called internally and not by user code.
        /// </summary>
        /// <remarks>Membership lists for inactive groups are empty (not initialized). An inactive group's membership list will
        /// reappear when the group is reactivated.</remarks>
        /// <param name="group">Name of AccuRev group.</param>
        /// <returns>\e true if no exception was thrown and operation succeeded, \e false otherwise.</returns>
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c show command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>
        /*! \sa [AcUser.initGroupsListAsync](@ref AcUtils#AcUser#initGroupsListAsync) */
        /*! \show_ <tt>show -fx -g \<group\> members</tt> */

        /*! \accunote_ Unlike the \c show command used here, its <tt>show -fx -u \<user\> groups</tt> counterpart
         *   does include memberships resulting from indirect (implicit) membership. */
        private async Task <bool> initMembersListAsync(string group)
        {
            bool ret = false; // assume failure

            try
            {
                AcResult r = await AcCommand.runAsync($@"show -fx -g ""{group}"" members").ConfigureAwait(false);

                if (r != null && r.RetVal == 0) // if command succeeded
                {
                    SortedSet <string> members = new SortedSet <string>();
                    XElement           xml     = XElement.Parse(r.CmdResult);
                    foreach (XElement e in xml.Elements("Element"))
                    {
                        string name = (string)e.Attribute("User");
                        members.Add(name);
                    }

                    lock (_locker)
                    {
                        AcPrincipal prncpl = getPrincipal(group);
                        prncpl.Members = members;
                    }

                    ret = true; // operation succeeded
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcGroups.initMembersListAsync{Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcGroups.initMembersListAsync{Environment.NewLine}{ecx.Message}");
            }

            return(ret);
        }
        /// <summary>
        /// For the real version specified in the argument list, get the real stream/version
        /// for the version in the specified version's workspace backing stream.
        /// </summary>
        /// <remarks>\c diff used here with the \c -i option, not to run a diff but to get the EID's only.</remarks>
        /// <param name="realverspec">Real version specification in text format,
        /// for example <tt>PG_MAINT1_barnyrd\4</tt> (numeric format won't work).</param>
        /// <param name="depot">The depot.</param>
        /// <param name="depotrelpath">Depot relative path, for example <tt>\\\\\.\\Bin\\foo.java</tt></param>
        /// <returns>An array initialized as <em>int[]={realStreamNumber, realVersionNumber}</em> if available, otherwise \e null.</returns>

        /*! \diff_ The \c diff command returns <em>zero (0)</em> for no differences found,
         *  <em>one (1)</em> for differences found, or <em>two (2)</em> on \c diff program error.<br>
         *  <tt>diff -fx -v \<realverspec\> -b -i -p \<depot\> \<depotrelpath\></tt> */
        /*! > -v -b Compare the specified version (X) with the version in X's stream's backing stream. (Use -v -V instead if comparing elements of type text that are active in a time-based stream.) */
        /*! > -i Information only: Report the IDs of the two versions, but don't actually compare them. This option is valid only in a command that uses a -v/-V combination or a -v/-b combination. If an element appears only in the workspace stream, not in the workspace's backing stream, this option does not list it. */
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c diff command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>
        public static async Task <int[]> getBackedVersionAsync(string realverspec, AcDepot depot, string depotrelpath)
        {
            int[] arr = null; // {realStreamNumber, realVersionNumber}
            try
            {
                AcResult r = await AcCommand.runAsync($@"diff -fx -v ""{realverspec}"" -b -i -p ""{depot}"" ""{depotrelpath}""")
                             .ConfigureAwait(false);

                if (r != null && r.RetVal < 2)
                {
                    XElement xml     = XElement.Parse(r.CmdResult);
                    XElement stream2 = xml.Descendants().Where(n => n.Name == "Stream2").SingleOrDefault();
                    if (stream2 != null)
                    {
                        XAttribute version = stream2.Attributes("Version").SingleOrDefault();
                        if (version != null)
                        {
                            string   temp              = (string)version;
                            string[] a                 = temp.Split('/');
                            int      realStreamNumber  = Int32.Parse(a[0], NumberStyles.Integer);
                            int      realVersionNumber = Int32.Parse(a[1], NumberStyles.Integer);
                            arr = new int[] { realStreamNumber, realVersionNumber };
                        }
                    }
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcQuery.getBackedVersionAsync{Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcQuery.getBackedVersionAsync{Environment.NewLine}{ecx.Message}");
            }

            return(arr);
        }
Ejemplo n.º 26
0
        /// <summary>
        /// Populate this container with AcLock objects on streams in \e depot or all AcLock objects in the repository.
        /// </summary>
        /// <param name="depot">Limit the list of locks to those on \e depot only, otherwise
        /// \e null for all locks in the repository.</param>
        /// <returns>\e true if initialization succeeded, \e false otherwise.</returns>
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c show command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>
        /*! \sa [AcLocks constructor](@ref AcUtils#AcLocks#AcLocks), initAsync(DepotsCollection), initAsync(StreamsCollection) */
        /*! \show_ <tt>show -fx locks</tt> */
        public async Task <bool> initAsync(AcDepot depot = null)
        {
            bool ret = false; // assume failure

            try
            {
                AcResult r = await AcCommand.runAsync("show -fx locks").ConfigureAwait(false);

                if (r != null && r.RetVal == 0)
                {
                    XElement xml = XElement.Parse(r.CmdResult);
                    IEnumerable <XElement> query = null;
                    if (depot == null)
                    {
                        query = from e in xml.Elements("Element")
                                select e;
                    }
                    else
                    {
                        query = from e in xml.Elements("Element")
                                join AcStream s in depot.Streams on(string) e.Attribute("Name") equals s.Name
                                select e;
                    }
                    ret = initList(query);
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcLocks.initAsync(AcDepot){Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcLocks.initAsync(AcDepot){Environment.NewLine}{ecx.Message}");
            }

            return(ret);
        }
        /// <summary>
        /// Get the list of reference trees in XML and optionally include those that are inactive
        /// as per [AcWorkspaces constructor](@ref AcUtils#AcWorkspaces#AcWorkspaces) \e includeHidden parameter.
        /// </summary>
        /// <returns>AcResult initialized with the \c show command results, or \e null on error.</returns>
        /*! \show_ <tt>show \<-fvx | -fvix\> refs</tt> */
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on <tt>show refs</tt> command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>
        /*! \sa AcWorkspaces.getWorkspacesXMLAsync */
        private async Task <AcResult> getReferenceTreesXMLAsync()
        {
            AcResult result = null;

            try
            {
                // -fvix: display all reference trees including deactivated ones
                // -fvx: display only active reference trees
                result = await AcCommand.runAsync($"show {(_includeHidden ? "-fvix" : "-fvx")} refs").ConfigureAwait(false);
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcWorkspaces.getReferenceTreesXMLAsync{Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcWorkspaces.getReferenceTreesXMLAsync{Environment.NewLine}{ecx.Message}");
            }

            return(result);
        }
Ejemplo n.º 28
0
        /// <summary>
        /// Optionally called during [list construction](@ref AcUtils#AcUsers#AcUsers) to initialize the list of groups
        /// this user is a member of by way of direct or indirect (implicit) membership, e.g. Mary is implicitly a member
        /// of groupA because she's a member of groupB which is a member of groupA. This method is called internally
        /// and not by user code.
        /// </summary>
        /// <remarks>Membership lists for inactive users are initialized too when
        /// [constructor parameter](@ref AcUtils#AcUsers#AcUsers) \e includeDeactivated is \e true.</remarks>
        /// <returns>\e true if no exception was thrown and operation succeeded, \e false otherwise.</returns>
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c show command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>
        /*! \sa [AcGroups.initMembersListAsync](@ref AcUtils#AcGroups#initMembersListAsync) */
        /*! \show_ <tt>show -fx -u \<user\> groups</tt> */

        /*! \accunote_ Unlike the \c show command used here, its <tt>show -fx -g \<group\> members</tt> counterpart
         *   does not include memberships resulting from indirect (implicit) membership. */
        internal async Task <bool> initGroupsListAsync()
        {
            bool ret = false; // assume failure

            try
            {
                // works for inactive users too
                AcResult r = await AcCommand.runAsync($@"show -fx -u ""{Principal.Name}"" groups")
                             .ConfigureAwait(false);

                if (r != null && r.RetVal == 0) // if command succeeded
                {
                    SortedSet <string> members = new SortedSet <string>();
                    XElement           xml     = XElement.Parse(r.CmdResult);
                    foreach (XElement e in xml.Elements("Element"))
                    {
                        string name = (string)e.Attribute("Name");
                        members.Add(name);
                    }

                    Principal.Members = members;
                    ret = true; // operation succeeded
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcUser.initGroupsListAsync{Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcUser.initGroupsListAsync{Environment.NewLine}{ecx.Message}");
            }

            return(ret);
        }
Ejemplo n.º 29
0
        /// <summary>
        /// Populate this container with AcDepot objects as per [constructor parameters](@ref AcUtils#AcDepots#AcDepots).
        /// </summary>
        /// <param name="depotsCol">List of depots to create, otherwise \e null for all depots.</param>
        /// <param name="progress">Optionally report progress back to the caller.</param>
        /// <returns>\e true if initialization succeeded, \e false otherwise.</returns>
        /// <exception cref="AcUtilsException">caught and [logged](@ref AcUtils#AcDebug#initAcLogging) in
        /// <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on \c show command failure.</exception>
        /// <exception cref="Exception">caught and logged in same on failure to handle a range of exceptions.</exception>

        /*! \code
         *  DepotsSection ds = ConfigurationManager.GetSection("Depots") as DepotsSection;
         *  DepotsCollection _dcol = ds.Depots; // list of depots from FooApp.exe.config
         *  ...
         *  private async Task<bool> initComboBoxDepotsAsync()
         *  {
         *      bool ret = false; // assume failure
         *      try
         *      {
         *          toolStripStatusLabel.Text = "Initializing...";
         *          toolStripProgressBar.Visible = true;
         *          toolStripProgressBar.Maximum = _dcol.Count;
         *          Progress<int> progress = new Progress<int>(i => toolStripProgressBar.Value = i);
         *
         *          AcDepots depots = new AcDepots(dynamicOnly: true);
         *          if (await depots.initAsync(_dcol, progress)) // if initialization succeeds
         *          {
         *              foreach (AcDepot depot in depots)
         *                  toolStripComboBoxDepot.Items.Add(depot); // a ToolStripComboBox control
         *              ret = true; // operation succeeded
         *          }
         *          else
         *          {
         *              AcDebug.Log("Failure in FooApp.initComboBoxDepotsAsync");
         *              MessageBox.Show($"Depots list initialization failed. See log file:{Environment.NewLine}{AcDebug.getLogFile()}",
         *                  "FooApp", MessageBoxButtons.OK, MessageBoxIcon.Hand);
         *          }
         *      }
         *
         *      catch (Exception ecx)
         *      {
         *          AcDebug.Log($"Exception caught and logged in FooApp.initComboBoxDepotsAsync{Environment.NewLine}{ecx.Message}");
         *      }
         *
         *      finally
         *      {
         *          toolStripStatusLabel.Text = "Ready";
         *          toolStripProgressBar.Visible = false;
         *      }
         *
         *      return ret;
         *  }
         *  \endcode */
        /*! \sa [AcDepots constructor](@ref AcUtils#AcDepots#AcDepots), DepotsCollection, AcGroups.initAsync */
        /*! \show_ <tt>show -fx depots</tt> */

        /*! \accunote_ The XML attribute \e locWidth from <tt>show -fx depots</tt> is obsolete.
         *  It's an AccuRev 4.x artifact and should be removed. RPI defect 1112042, SupportLine AR3325. */
        public async Task <bool> initAsync(DepotsCollection depotsCol = null, IProgress <int> progress = null)
        {
            bool ret = false; // assume failure

            try
            {
                AcResult r = await AcCommand.runAsync("show -fx depots").ConfigureAwait(false);

                if (r != null && r.RetVal == 0)
                {
                    XElement xml = XElement.Parse(r.CmdResult);
                    IEnumerable <XElement> query = null;
                    if (depotsCol == null)
                    {
                        query = from e in xml.Elements("Element") select e;
                    }
                    else
                    {
                        query = from e in xml.Elements("Element")
                                where depotsCol.OfType <DepotElement>().Any(de => de.Depot == (string)e.Attribute("Name"))
                                select e;
                    }

                    int num = query.Count();
                    List <Task <bool> >      tasks = new List <Task <bool> >(num);
                    Func <Task <bool>, bool> cf    = t =>
                    {
                        bool res = t.Result;
                        if (res && progress != null)
                        {
                            progress.Report(Interlocked.Increment(ref _counter));
                        }
                        return(res);
                    };

                    foreach (XElement e in query)
                    {
                        AcDepot depot = new AcDepot(_dynamicOnly, _includeHidden);
                        depot.ID               = (int)e.Attribute("Number");
                        depot.Name             = (string)e.Attribute("Name");
                        depot.Slice            = (int)e.Attribute("Slice");
                        depot.ExclusiveLocking = (bool)e.Attribute("exclusiveLocking");
                        string temp = (string)e.Attribute("case");
                        depot.Case     = (CaseSensitivity)Enum.Parse(typeof(CaseSensitivity), temp);
                        depot._streams = new AcStreams(_dynamicOnly, _includeHidden);
                        lock (_locker) { Add(depot); }
                        Task <bool> t = depot._streams.initAsync(depot, depot.listFile()).ContinueWith(cf);
                        tasks.Add(t);
                    }

                    bool[] arr = await Task.WhenAll(tasks).ConfigureAwait(false);

                    ret = (arr != null && arr.All(n => n == true)); // true if all succeeded
                }
            }

            catch (AcUtilsException ecx)
            {
                AcDebug.Log($"AcUtilsException caught and logged in AcDepots.initAsync{Environment.NewLine}{ecx.Message}");
            }

            catch (Exception ecx)
            {
                AcDebug.Log($"Exception caught and logged in AcDepots.initAsync{Environment.NewLine}{ecx.Message}");
            }

            return(ret);
        }
        /// <summary>Run the AccuRev \e command synchronously (blocks) on the current thread.</summary>
        /// <param name="command">The AccuRev command to run, e.g. <tt>hist -fx -p AcTools -t 453</tt></param>
        /// <param name="validator">Use to change the [default logic](@ref AcUtils#CmdValidate#isValid) for determining
        /// if an AcUtilsException should be thrown based on AccuRev's program return value for \e command.</param>
        /// <returns>On success an AcResult object with AcResult.RetVal set to the AccuRev program return value and the command
        /// result (usually XML) in AcResult.CmdResult. Otherwise, AcResult.RetVal is <em>minus one (-1)</em> (default) on error.
        /// </returns>
        /// <exception cref="AcUtilsException">thrown on AccuRev program invocation failure or <tt>merge/diff</tt>
        /// program error (return value <em>two (2)</em>).</exception>
        /// <exception cref="Win32Exception">caught and [logged](@ref AcUtils#AcDebug#initAcLogging)
        /// in <tt>\%LOCALAPPDATA\%\\AcTools\\Logs\\<prog_name\>-YYYY-MM-DD.log</tt> on error spawning the AccuRev process that runs the command.</exception>
        /// <exception cref="InvalidOperationException">caught and logged in same on failure to handle a range of exceptions.</exception>
        /*! \attention Do not use this function for the <tt>ismember</tt> command. Instead, use AcGroups#isMember. */
        public static AcResult run(string command, ICmdValidate validator = null)
        {
            AcResult      result = new AcResult();
            StringBuilder error  = new StringBuilder(512);

            try
            {
                using (Process process = new Process())
                {
                    process.StartInfo.FileName               = "accurev";
                    process.StartInfo.Arguments              = command;
                    process.StartInfo.UseShellExecute        = false;
                    process.StartInfo.CreateNoWindow         = true;
                    process.StartInfo.RedirectStandardInput  = true; // fix for AccuRev defect 29059
                    process.StartInfo.RedirectStandardOutput = true;
                    process.StartInfo.RedirectStandardError  = true;
                    process.StartInfo.StandardOutputEncoding = Encoding.UTF8;
                    process.StartInfo.StandardErrorEncoding  = Encoding.UTF8;
                    process.ErrorDataReceived += (sender, e) =>
                    {
                        error.AppendLine(e.Data);
                    };
                    StringBuilder output = new StringBuilder();
                    output.Capacity             = 4096;
                    process.OutputDataReceived += (sender, e) =>
                    {
                        output.AppendLine(e.Data);
                    };
                    process.Start();
                    process.BeginErrorReadLine();
                    process.BeginOutputReadLine();
                    process.WaitForExit(); // blocks here. recommended to ensure output buffer has been flushed
                    if (process.HasExited)
                    {
                        string err = error.ToString().Trim();
                        if (!String.IsNullOrEmpty(err) &&
                            !(String.Equals("You are not in a directory associated with a workspace", err)))
                        {
                            AcDebug.Log(err, false);
                        }

                        ICmdValidate validate = validator ?? new CmdValidate();
                        if (validate.isValid(command, process.ExitCode))
                        {
                            result.RetVal    = process.ExitCode;
                            result.CmdResult = output.ToString();
                        }
                        else
                        {
                            throw new AcUtilsException($"AccuRev program return: {process.ExitCode}{Environment.NewLine}accurev {command}"); // let calling method handle
                        }
                    }
                }
            }

            catch (Win32Exception ecx)
            {
                string msg = String.Format(@"Win32Exception caught and logged in AcCommand.run{0}{1}{0}""accurev {2}""{0}errorcode: {3}{0}native errorcode: {4}{0}{5}{0}{6}{0}{7}{0}{8}",
                                           Environment.NewLine, ecx.Message, command, ecx.ErrorCode.ToString(), ecx.NativeErrorCode.ToString(), ecx.StackTrace, ecx.Source, ecx.GetBaseException().Message, error.ToString());
                AcDebug.Log(msg);
            }

            catch (InvalidOperationException ecx)
            {
                string msg = String.Format(@"InvalidOperationException caught and logged in AcCommand.run{0}{1}{0}""accurev {2}""{0}{3}",
                                           Environment.NewLine, ecx.Message, command, error.ToString());
                AcDebug.Log(msg);
            }

            return(result);
        }