public static string GetPropertyValue(FilePath svnExecutableFilePath, AbsolutePath path, string propertyName, ILogger logger)
        {
            logger.LogDebug($"Getting value of SVN property {propertyName} for {path}...");

            var arguments = $@"propget {propertyName} ""{path}"" --xml";

            var outputCollector = SvnCommandServicesProvider.Run(svnExecutableFilePath, arguments);

            // Parse output.
            var svnOutput = outputCollector.GetOutputText();

            var document = XDocument.Parse(svnOutput);

            var properties = document.Element("properties");

            if (!properties.Elements().Any())
            {
                throw new Exception($"SVN automation failure.\nReceived:\n{svnOutput}");
            }

            var expectedPath = PathUtilities.EnsureNonWindowsDirectorySeparator(path.Value); // Path value is converted to a non-Windows path.

            var property = properties.Elements("target").Where(x => x.Attribute("path").Value == expectedPath).Single().Element("property");

            if (property.Attribute("name").Value != propertyName)
            {
                throw new Exception($"SVN automation failure.\nReceived:\n{svnOutput}");
            }

            var output = property.Value;

            logger.LogInformation($"Got value of SVN property {propertyName} for {path}.");

            return(output);
        }
        public static void Delete(FilePath svnExecutableFilePath, AbsolutePath path, ILogger logger, bool force = false)
        {
            logger.LogDebug($"SVN deleting path {path}...");

            var arguments = $@"delete ""{path}""";

            if (force)
            {
                arguments = arguments.Append(" --force");
            }

            var outputCollector = SvnCommandServicesProvider.Run(svnExecutableFilePath, arguments);

            bool success        = false;
            var  expectedOutput = $"D         {path}";

            using (var reader = outputCollector.GetOutputReader())
            {
                while (!reader.ReadLineIsEnd(out var line))
                {
                    if (expectedOutput == line)
                    {
                        success = true;
                        break;
                    }
                }
            }

            if (!success)
            {
                throw new Exception($"SVN automation failure.\nReceived:\n{outputCollector.GetOutputText()}");
            }

            logger.LogInformation($"SVN deleted path {path}.");
        }
        public static string[] ListProperties(FilePath svnExecutableFilePath, AbsolutePath path, ILogger logger)
        {
            logger.LogDebug($"Listing SVN properties of {path}...");

            var arguments = $@"proplist ""{path}"" --xml";

            var outputCollector = SvnCommandServicesProvider.Run(svnExecutableFilePath, arguments);

            var svnOutput = outputCollector.GetOutputText();
            var document  = XDocument.Parse(svnOutput);

            var properties = document.Element("properties");

            if (!properties.Elements().Any())
            {
                return(Array.Empty <string>());
            }

            var expectedPath = path.Value; // This method does not convert paths to non-Windows.

            var target = properties.Elements("target").Where(x => x.Attribute("path").Value == expectedPath).Single();

            var output = target.Elements("property").Attributes("name").Select(x => x.Value).ToArray();

            logger.LogInformation($"Listed SVN properties of {path}.");

            return(output);
        }
        public static int Update(FilePath svnExecutableFilePath, AbsolutePath path, ILogger logger)
        {
            var nonDirectoryIndicatedPath = PathUtilities.EnsurePathIsNotDirectoryIndicated(path.Value).AsAbsolutePath();

            logger.LogDebug($"SVN updating {path}...");                 // Use the specified path.

            var arguments = $@"update ""{nonDirectoryIndicatedPath}"""; // Use the non-directory indicated path.

            var outputCollector = SvnCommandServicesProvider.Run(svnExecutableFilePath, arguments);

            var lines = new List <string>();

            using (var reader = outputCollector.GetOutputReader())
            {
                while (!reader.ReadLineIsEnd(out var line))
                {
                    lines.Add(line);
                }
            }

            var lastLine        = lines.Last();
            var trimmedLastLine = lastLine.TrimEnd('.');
            var tokens          = trimmedLastLine.Split(' ');
            var revisionNumber  = tokens[tokens.Length - 1];

            var revision = Int32.Parse(revisionNumber);

            logger.LogInformation($"SVN updated {path}.\nRevision: {revision}");

            return(revision);
        }
        public static string RunGetText(FilePath svnExecutableFilePath, IArgumentsBuilder argumentsBuilder, bool throwIfAnyError = true)
        {
            var outputCollector = SvnCommandServicesProvider.Run(svnExecutableFilePath, argumentsBuilder, throwIfAnyError);

            var text = outputCollector.GetOutputText();

            return(text);
        }
        public static ProcessOutputCollector Run(FilePath svnExecutableFilePath, IArgumentsBuilder argumentsBuilder, bool throwIfAnyError = true)
        {
            var arguments = argumentsBuilder.Build();

            var outputCollector = SvnCommandServicesProvider.Run(svnExecutableFilePath, arguments, throwIfAnyError);

            return(outputCollector);
        }
        public static string GetStatusXmlText(FilePath svnExecutableFilePath, AbsolutePath path, ILogger logger)
        {
            logger.LogDebug($"Getting SVN status XML text for path {path}...");

            var arguments = $@"status ""{path}"" -v --xml";

            var outputCollector = SvnCommandServicesProvider.Run(svnExecutableFilePath, arguments);

            logger.LogInformation($"Got SVN status XML text of path {path}.");

            var output = outputCollector.GetOutputText();

            return(output);
        }
        private static SvnStringPathStatus StatusRobust_Internal(this SvnCommand svnCommand, AbsolutePath absolutePath)
        {
            var arguments = SvnCommandServicesProvider.GetStatusVerboseForInstanceOnly(absolutePath)
                            .AddXml(); // Get XML.

            var outputCollector = SvnCommandServicesProvider.Run(svnCommand.SvnExecutableFilePath, arguments, false);

            if (outputCollector.AnyError)
            {
                var errorText = outputCollector.GetErrorText().Trim();

                var notWorkingCopyText = $"svn: warning: W155007: '{absolutePath}' is not a working copy";
                if (errorText == notWorkingCopyText)
                {
                    var output = new SvnStringPathStatus {
                        Path = absolutePath.Value, ItemStatus = ItemStatus.NotWorkingCopy
                    };
                    return(output);
                }

                var notFoundText = $"svn: warning: W155010: The node '{absolutePath}' was not found.";
                if (errorText == notFoundText)
                {
                    var output = new SvnStringPathStatus {
                        Path = absolutePath.Value, ItemStatus = ItemStatus.NotFound
                    };
                    return(output);
                }

                throw new Exception($"Unknown SVN error:\n{errorText}");
            }

            var xmlText = outputCollector.GetOutputText();

            using (var stream = StreamHelper.FromString(xmlText))
            {
                var xmlStatusType = XmlStreamSerializer.Deserialize <StatusType>(stream, SvnXml.DefaultNamespace);

                var statuses = SvnCommandServicesProvider.GetStatuses(xmlStatusType);

                var status = statuses.Count() < 1
                    ? new SvnStringPathStatus {
                    Path = absolutePath.Value, ItemStatus = ItemStatus.None
                }
                    : statuses.Single() // Should be only 1.
                ;

                return(status);
            }
        }
        public static CheckoutResult Checkout(this SvnCommand svnCommand, string repositoryUrl, string localDirectoryPath)
        {
            svnCommand.Logger.LogDebug($"SVN checkout of '{repositoryUrl}' to '{localDirectoryPath}'...");

            // Need to ensure the local directory path is NOT directory indicated (does NOT end with a directory separator).
            var correctedLocalDirectoryPath = PathUtilities.EnsureFilePathNotDirectoryIndicated(localDirectoryPath);

            var arguments = SvnCommandServicesProvider.GetCheckoutArguments(repositoryUrl, correctedLocalDirectoryPath);

            var commandOutput = SvnCommandServicesProvider.Run(svnCommand.SvnExecutableFilePath, arguments);

            var lines = commandOutput.GetOutputLines().ToList();

            var lastLine            = lines.Last();
            var lastLineTokens      = lastLine.Split(' ');
            var revisionNumberToken = lastLineTokens.Last().TrimEnd('.');
            var revisionNumber      = Int32.Parse(revisionNumberToken);

            var entryUpdateLines = lines.ExceptLast();
            var statuses         = new List <EntryUpdateStatus>();

            foreach (var line in entryUpdateLines)
            {
                var lineTokens = line.Split(new[] { " " }, 2, StringSplitOptions.RemoveEmptyEntries);

                var statusToken  = lineTokens[0];
                var relativePath = lineTokens[1];

                var updateStatus = statusToken.ToUpdateStatus();

                var status = new EntryUpdateStatus
                {
                    UpdateStatus = updateStatus,
                    RelativePath = relativePath,
                };
                statuses.Add(status);
            }

            var result = new CheckoutResult
            {
                RevisionNumber = revisionNumber,
                Statuses       = statuses.ToArray(),
            };

            svnCommand.Logger.LogInformation($"SVN checkout of '{repositoryUrl}' to '{localDirectoryPath}' complete.");

            return(result);
        }
        public static string GetStatusXmlText2(FilePath svnExecutableFilePath, AbsolutePath path, ILogger logger)
        {
            logger.LogDebug($"Getting SVN status XML text for path {path}...");

            var arguments = SvnCommandServicesProvider.GetStatusVerboseForInstanceOnly(path)
                            .AddFlagFull("xml")
                            .Build();

            var outputCollector = SvnCommandServicesProvider.Run(svnExecutableFilePath, arguments);

            logger.LogInformation($"Got SVN status XML text of path {path}.");

            var output = outputCollector.GetOutputText();

            return(output);
        }
        public static Version GetVersion(FilePath svnExecutableFilePath, ILogger logger)
        {
            logger.LogDebug("Getting svn version...");

            var arguments = "--version --quiet";

            var outputCollector = SvnCommandServicesProvider.Run(svnExecutableFilePath, arguments);

            var line = outputCollector.GetOutputText();

            var versionString = line;

            var version = Version.Parse(versionString);

            logger.LogInformation("Got svn version.");

            return(version);
        }
        public static void Add(FilePath svnExecutableFilePath, AbsolutePath path, ILogger logger)
        {
            logger.LogDebug($"Adding changes for {path}...");

            var arguments = $@"add ""{path}""";

            var outputCollector = SvnCommandServicesProvider.Run(svnExecutableFilePath, arguments);

            var svnOutput = outputCollector.GetOutputText();

            var expectedOutput = $"A         {path}\r\n";

            if (svnOutput != expectedOutput)
            {
                throw new Exception($"SVN automation failure.\nReceived:\n{svnOutput}");
            }

            logger.LogInformation($"Added changes for {path}.");
        }
        /// <summary>
        /// Deletes an SVN property from a path.
        /// Operation is idempotent.
        /// </summary>
        public static void DeleteProperty(FilePath svnExecutableFilePath, AbsolutePath path, string propertyName, ILogger logger)
        {
            logger.LogDebug($"Deleting SVN property '{propertyName}' of {path}...");

            var arguments = $@"propdel {propertyName} ""{path}""";

            var outputCollector = SvnCommandServicesProvider.Run(svnExecutableFilePath, arguments);

            var line = outputCollector.GetOutputTextTrimmed();

            var expectedLine1 = $"property '{propertyName}' deleted from '{path}'.";
            var expectedLine2 = $"Attempting to delete nonexistent property '{propertyName}' on '{path}'";

            if (expectedLine1 != line && expectedLine2 != line)
            {
                throw new Exception($"SVN automation failure.\nReceived:\n{line}");
            }

            logger.LogInformation($"Deleted SVN property '{propertyName} of {path}.");
        }
        public static void Revert(FilePath svnExecutableFilePath, AbsolutePath path, ILogger logger)
        {
            logger.LogDebug($"SVN reverting {path}...");

            var arguments = $@"revert ""{path}""";

            var outputCollector = SvnCommandServicesProvider.Run(svnExecutableFilePath, arguments);

            // Check for success.
            var line = outputCollector.GetOutputTextTrimmed();

            var expectedLine = $"Reverted '{path}'";

            if (expectedLine != line)
            {
                throw new Exception($"SVN automation failure.\nReceived:\n{outputCollector.GetOutputText()}");
            }

            logger.LogInformation($"SVN reverted {path}.");
        }
        public static void SetPropertyValue(FilePath svnExecutableFilePath, AbsolutePath path, string propertyName, string ignoreValue, ILogger logger)
        {
            logger.LogDebug($"Setting value of SVN property {propertyName} for {path}...");

            var arguments = $@"propset {propertyName} {ignoreValue} ""{path}""";

            var outputCollector = SvnCommandServicesProvider.Run(svnExecutableFilePath, arguments);

            // Test for success.
            var line = outputCollector.GetOutputTextTrimmed();

            var expectedLine = $"property '{propertyName}' set on '{path}'";

            if (expectedLine != line)
            {
                throw new Exception($"SVN automation failure.\nExpected output:\n{expectedLine}\nReceived:\n{line}");
            }

            logger.LogInformation($"Set value of SVN property {propertyName} for {path}.");
        }
        /// <summary>
        /// Commits changes to the specified path and returns the revision number.
        /// For directory paths, to commit only changes to the directory (for example, changes to SVN properties of the directory) and not changes within the directory, set the include all changes within path input to false.
        /// </summary>
        public static int Commit(FilePath svnExecutableFilePath, AbsolutePath path, string message, ILogger logger, bool includeAllChangesWithinPath = true)
        {
            logger.LogDebug($"Committing changes for {path}...");

            var arguments = $@"commit ""{path}"" --message ""{message}""";

            // For directory paths, you can commit ONLY the directory (and not changes within the directory) using the empty depth option.
            if (!includeAllChangesWithinPath)
            {
                arguments.Append(" --depth empty");
            }

            var outputCollector = SvnCommandServicesProvider.Run(svnExecutableFilePath, arguments);

            var lines = outputCollector.GetOutputLines().ToArray();

            if (lines.Length < 1)
            {
                return(-1);
            }

            var lastLine        = lines.Last();
            var trimmedLastLine = lastLine.TrimEnd('.');

            var tokens = trimmedLastLine.Split(' ');

            if (tokens[0] != "Committed" || tokens[1] != "revision")
            {
                throw new Exception($"SVN automation failure.\nReceived:\n{lastLine}");
            }

            var revisionString = tokens[2];

            var revision = Int32.Parse(revisionString);

            logger.LogInformation($"Committed changes for {path}.");

            return(revision);
        }
        /// <summary>
        /// Allows direct access to run command.
        /// </summary>
        public static ProcessOutputCollector Run(this SvnCommand svnCommand, string arguments, bool throwIfAnyError = true)
        {
            var output = SvnCommandServicesProvider.Run(svnCommand.SvnExecutableFilePath, arguments, throwIfAnyError);

            return(output);
        }