]> git.ipfire.org Git - thirdparty/git.git/commitdiff
ref-filter: modify the 'lstrip=<N>' option to work with negative '<N>'
authorKarthik Nayak <karthik.188@gmail.com>
Tue, 10 Jan 2017 08:49:48 +0000 (14:19 +0530)
committerJunio C Hamano <gitster@pobox.com>
Tue, 31 Jan 2017 20:38:59 +0000 (12:38 -0800)
Currently the 'lstrip=<N>' option only takes a positive value '<N>'
and strips '<N>' slash-separated path components from the left. Modify
the 'lstrip' option to also take a negative number '<N>' which would
strip from the left as necessary and _leave_ behind only 'N'
slash-separated path components from the right-most end.

For e.g. %(refname:lstrip=-1) would make 'foo/goo/abc' into 'abc'.

Add documentation and tests for the same.

Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/git-for-each-ref.txt
ref-filter.c
t/t6300-for-each-ref.sh

index 04ffc35524288eb251576e9db4df41157e75eb87..8e4d16d7a3fa17756dea54ea93de83e9b6e53be8 100644 (file)
@@ -97,8 +97,14 @@ refname::
        The option core.warnAmbiguousRefs is used to select the strict
        abbreviation mode. If `lstrip=<N>` is appended, strips `<N>`
        slash-separated path components from the front of the refname
-       (e.g., `%(refname:lstrip=2)` turns `refs/tags/foo` into `foo`.
-       `<N>` must be a positive integer.
+       (e.g. `%(refname:lstrip=2)` turns `refs/tags/foo` into `foo`.
+       If `<N>` is a negative number, strip as many path components as
+       necessary from the left to leave `-<N>` path components
+       (e.g. `%(refname:lstrip=-2)` turns
+       `refs/tags/foo` into `tags/foo`). When the ref does not have
+       enough components, the result becomes an empty string if
+       stripping with positive <N>, or it becomes the full refname if
+       stripping with negative <N>.  Neither is an error.
 
 objecttype::
        The type of the object (`blob`, `tree`, `commit`, `tag`).
index 4fd6ef186cc430b34be9f15335e5af72e67bbc1c..2840ca18e3f1c81b14bf5bc5db08d3efa913a89e 100644 (file)
@@ -34,7 +34,7 @@ struct if_then_else {
 
 struct refname_atom {
        enum { R_NORMAL, R_SHORT, R_LSTRIP } option;
-       unsigned int lstrip;
+       int lstrip;
 };
 
 /*
@@ -93,8 +93,8 @@ static void refname_atom_parser_internal(struct refname_atom *atom,
                atom->option = R_SHORT;
        else if (skip_prefix(arg, "lstrip=", &arg)) {
                atom->option = R_LSTRIP;
-               if (strtoul_ui(arg, 10, &atom->lstrip) || atom->lstrip <= 0)
-                       die(_("positive value expected refname:lstrip=%s"), arg);
+               if (strtol_i(arg, 10, &atom->lstrip))
+                       die(_("Integer value expected refname:lstrip=%s"), arg);
        } else
                die(_("unrecognized %%(%s) argument: %s"), name, arg);
 }
@@ -1091,12 +1091,28 @@ static inline char *copy_advance(char *dst, const char *src)
        return dst;
 }
 
-static const char *lstrip_ref_components(const char *refname, unsigned int len)
+static const char *lstrip_ref_components(const char *refname, int len)
 {
        long remaining = len;
        const char *start = refname;
 
-       while (remaining) {
+       if (len < 0) {
+               int i;
+               const char *p = refname;
+
+               /* Find total no of '/' separated path-components */
+               for (i = 0; p[i]; p[i] == '/' ? i++ : *p++)
+                       ;
+               /*
+                * The number of components we need to strip is now
+                * the total minus the components to be left (Plus one
+                * because we count the number of '/', but the number
+                * of components is one more than the no of '/').
+                */
+               remaining = i + len + 1;
+       }
+
+       while (remaining > 0) {
                switch (*start++) {
                case '\0':
                        return "";
@@ -1105,6 +1121,7 @@ static const char *lstrip_ref_components(const char *refname, unsigned int len)
                        break;
                }
        }
+
        return start;
 }
 
index d3d1a97db9709c29b829cf64df4fa6cce04ed6fe..203cfaa156a409925b450a9be55488e91dbcca80 100755 (executable)
@@ -53,12 +53,16 @@ test_atom head refname refs/heads/master
 test_atom head refname:short master
 test_atom head refname:lstrip=1 heads/master
 test_atom head refname:lstrip=2 master
+test_atom head refname:lstrip=-1 master
+test_atom head refname:lstrip=-2 heads/master
 test_atom head upstream refs/remotes/origin/master
 test_atom head upstream:short origin/master
 test_atom head upstream:lstrip=2 origin/master
+test_atom head upstream:lstrip=-2 origin/master
 test_atom head push refs/remotes/myfork/master
 test_atom head push:short myfork/master
 test_atom head push:lstrip=1 remotes/myfork/master
+test_atom head push:lstrip=-1 master
 test_atom head objecttype commit
 test_atom head objectsize 171
 test_atom head objectname $(git rev-parse refs/heads/master)
@@ -141,12 +145,6 @@ test_expect_success 'Check invalid atoms names are errors' '
        test_must_fail git for-each-ref --format="%(INVALID)" refs/heads
 '
 
-test_expect_success 'arguments to :lstrip must be positive integers' '
-       test_must_fail git for-each-ref --format="%(refname:lstrip=0)" &&
-       test_must_fail git for-each-ref --format="%(refname:lstrip=-1)" &&
-       test_must_fail git for-each-ref --format="%(refname:lstrip=foo)"
-'
-
 test_expect_success 'Check format specifiers are ignored in naming date atoms' '
        git for-each-ref --format="%(authordate)" refs/heads &&
        git for-each-ref --format="%(authordate:default) %(authordate)" refs/heads &&
@@ -624,10 +622,12 @@ test_expect_success 'Verify usage of %(symref:short) atom' '
 
 cat >expected <<EOF
 master
+heads/master
 EOF
 
 test_expect_success 'Verify usage of %(symref:lstrip) atom' '
        git for-each-ref --format="%(symref:lstrip=2)" refs/heads/sym > actual &&
+       git for-each-ref --format="%(symref:lstrip=-2)" refs/heads/sym >> actual &&
        test_cmp expected actual
 '