Commits

Greg Ward committed 58d50c9

svn: fix incorrect implementation of %r (at least for svn 1.4 .. 1.6)

It was reporting what "svn info" reports as "Revision", which is
typically the HEAD revision for the whole repo. But if the current
directory (branch) was last modified in an older revision, that's not
what you want. You want the "Last Changed Rev" from "svn info", which
seems to be stored a few lines later in .svn/entries.

Also refactored and cleaned up a bunch.

  • Participants
  • Parent commits 6147607

Comments (0)

Files changed (2)

     return isdir(".svn");
 }
 
+static int
+svn_read_custom(FILE *fp, char line[], int size, int line_num, result_t *result)
+{
+    // Caller has already read line 1. Read lines 2..5, discarding 2..4.
+    while (line_num <= 5) {
+        if (fgets(line, size, fp) == NULL) {
+            debug(".svn/entries: early EOF (line %d empty)", line_num);
+            return 0;
+        }
+        line_num++;
+    }
+
+    // Line 5 is the URL for the working dir, now in 'line'. Should
+    // use this to get the branch name (not implemented yet).
+
+    // Lines 6 .. 10 are also uninteresting.
+    while (line_num <= 11) {
+        if (fgets(line, size, fp) == NULL) {
+            debug(".svn/entries: early EOF (line %d empty)", line_num);
+            return 0;
+        }
+        line_num++;
+    }
+
+    // Line 11 is the revision number we care about, now in 'line'.
+    chop_newline(line);
+    result->revision = strdup(line);
+    debug("read svn revision from .svn/entries: '%s'", line);
+    return 1;
+}
+
+static int
+svn_read_xml(FILE *fp, char line[], int size, int line_num, result_t *result)
+{
+    char rev[100];
+    char *marker = "revision=";
+    char *p = NULL;
+    while (fgets(line, size, fp)) {
+        if ((p = strstr(line, marker)) != NULL) {
+            break;
+        }
+    }
+    if (p == NULL) {
+        debug("no 'revision=' line found in .svn/entries");
+        return 0;
+    }
+    if (sscanf(p, " %*[^\"]\"%[0-9]\"", rev) == 1) {
+        result_set_revision(result, rev, -1);
+        debug("read svn revision from .svn/entries: '%s'", rev);
+    }
+    return 1;
+}
+
 static result_t*
 svn_get_info(vccontext_t *context)
 {
     result_t *result = init_result();
     FILE *fp = NULL;
-    char buf[1024];
-
-    if (!read_first_line(".svn/entries", buf, 1024)) {
-        debug("failed to read from .svn/entries: not an svn working copy");
-        goto err;
-    }
 
     fp = fopen(".svn/entries", "r");
     if (!fp) {
         goto err;
     }
     char line[1024];
+    int line_num = 1;                   // the line we're about to read
 
-    // Check the version
-    if (fgets(line, sizeof(line), fp)) {
-        if(isdigit(line[0])) {
-            // Custom file format (working copy created by svn >= 1.4)
+    if (fgets(line, sizeof(line), fp) == NULL) {
+        debug(".svn/entries: empty file");
+        goto err;
+    }
+    line_num++;
 
-            // Read and discard line 2 (name), 3 (entries kind)
-            if (fgets(line, sizeof(line), fp) == NULL ||
-                fgets(line, sizeof(line), fp) == NULL) {
-                debug("early EOF reading .svn/entries");
-                goto err;
-            }
-
-            // Get the revision number
-            if (fgets(line, sizeof(line), fp)) {
-                chop_newline(line);
-                result->revision = strdup(line);
-                debug("read a svn revision from .svn/entries: '%s'", line);
-            }
-            else {
-                debug("early EOF: expected revision number");
-                goto err;
-            }
-        }
-        else {
-            // XML file format (working copy created by svn < 1.4)
-            char rev[100];
-            char *marker = "revision=";
-            char *p = NULL;
-            while (fgets(line, sizeof(line), fp))
-                if ((p = strstr(line, marker)) != NULL)
-                    break;
-            if (p == NULL) {
-                debug("no 'revision=' line found in .svn/entries");
-                goto err;
-            }
-            if (sscanf(p, " %*[^\"]\"%[0-9]\"", rev) == 1) {
-                result_set_revision(result, rev, -1);
-                debug("read svn revision from .svn/entries: '%s'", rev);
-            }
-        }
+    // First line of the file tells us what the format is.
+    int ok;
+    if(isdigit(line[0])) {
+        // Custom file format (working copy created by svn >= 1.4)
+        ok = svn_read_custom(fp, line, sizeof(line), line_num, result);
     }
-    fclose(fp);
-    return result;
+    else {
+        // XML file format (working copy created by svn < 1.4)
+        ok = svn_read_xml(fp, line, sizeof(line), line_num, result);
+    }
+    if (ok) {
+        fclose(fp);
+        return result;
+    }
 
  err:
     free(result);

File tests/test-svn

     assert_vcprompt "vc name" "svn" "%n"
     # %b isn't implemented: when that is fixed, this will break!
     assert_vcprompt "no branch name on trunk" "" "%b"
+    assert_vcprompt "rev num on trunk" "2" "%r"
 
     svn -q switch $repourl/branches/stable
     assert_vcprompt "no branch name on branch" "" "%b"
+    assert_vcprompt "rev num on branch" "4" "%r"
 }
 
 check_svn