Matching SVK revision numbers to the SVN revision number

time to read 7 min | 1259 words

I am using SVK as a way to learn Distributed SCM, and it has been fine so far, except for one big issue. I am trying to apply SVN patches against SVK repositories. Actually, I setup SVK so I work against a local mirror, so the workflow is exactly the same, but the revision numbers are different. Trying to apply a patch just doesn't work because of that.

You can go into the patch and edit the root revision, so it is not hard to make this work, except...

SVK doesn't give me any mapping between the local revision and the source revisions (maybe it does, and someone will tell me). This means that in order to find the right version I have to do some annoying digging.

Here is a small program to solve the problem. Usage: svkrev [repository path] [source revision to look for]

Example:

C:\Users\Administrator>svkrev //mirror/nhcontrib 195
exec: svk log --xml //mirror/nhcontrib
exec: svk propget svm:headrev //mirror/nhcontrib --revprop -r 10298
exec: svk propget svm:headrev //mirror/nhcontrib --revprop -r 10260
:=349
exec: svk propget svm:headrev //mirror/nhcontrib --revprop -r 10092
:=195
Found: 10092

By the way, can you find the huge perf boost here?

class Program
{
    static void Main(string[] args)
    {
        string path = args[0]; // "//mirror/nhcontrib"
        var revisionToSearchFor = int.Parse(args[1]); // 195
        string logAsXml = ExecuteProcessAndReturnOutput("log --xml "+ path);
        var doc = new XmlDocument();
        doc.LoadXml(logAsXml);
        var list = new ArrayList();
        foreach (var node in doc.SelectNodes("/log/logentry/@revision"))
        {
            list.Add(node);
        }
        for (int i = 0; i < list.Count;i++ )
        {
            XmlNode node = (XmlNode)list[i];
            int revision = int.Parse(node.Value);
            string output = ExecuteProcessAndReturnOutput("propget svm:headrev " + path + " --revprop -r " + revision);
            if (string.IsNullOrEmpty(output.Trim()) == false)
            {
                var currentRevision = int.Parse(output.Split(':')[1].Trim());
                Console.WriteLine(":=" + currentRevision);
                if (currentRevision == revisionToSearchFor)
                {
                    Console.WriteLine("Found: " + revision);
                    return;
                }
                i += (currentRevision - revisionToSearchFor -1);
            }
        }
    }

    public static string ExecuteProcessAndReturnOutput(string args)
    {
        var output = new StringBuilder();
        string err = null;
        var psi = new ProcessStartInfo
                      {
                          FileName = @"c:\Program Files\svk\svk.bat",
                          Arguments = args,
                          RedirectStandardOutput = true,
                          RedirectStandardError = true,
                          CreateNoWindow = true,
                          UseShellExecute = false
                      };
        Console.WriteLine("exec: svk "+ args);
        Process svk = Process.Start(psi);
        ThreadPool.QueueUserWorkItem(delegate
        {
            err = svk.StandardError.ReadToEnd();
        });
        ThreadPool.QueueUserWorkItem(delegate
        {
            string line;
            while ((line = svk.StandardOutput.ReadLine()) != null)
            {
                Debug.WriteLine(line);
                output.AppendLine(line);
            }
        });
        svk.WaitForExit();
        if (string.IsNullOrEmpty(err) == false)
            throw new InvalidOperationException(err);
        svk.WaitForExit();
        Thread.Sleep(500);
        return output.ToString();
    }
}