git-p4: additional testing of --changes-block-size
[gitweb.git] / sha1_name.c
index 6d10f052b5050c64de5589733c2a8600e2ddb3dc..e57513e61032fb851a669255c30d8417f66c81f9 100644 (file)
@@ -6,6 +6,7 @@
 #include "tree-walk.h"
 #include "refs.h"
 #include "remote.h"
+#include "dir.h"
 
 static int get_sha1_oneline(const char *, unsigned char *, struct commit_list *);
 
@@ -415,12 +416,12 @@ static int ambiguous_path(const char *path, int len)
        return slash;
 }
 
-static inline int upstream_mark(const char *string, int len)
+static inline int at_mark(const char *string, int len,
+                         const char **suffix, int nr)
 {
-       const char *suffix[] = { "@{upstream}", "@{u}" };
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(suffix); i++) {
+       for (i = 0; i < nr; i++) {
                int suffix_len = strlen(suffix[i]);
                if (suffix_len <= len
                    && !memcmp(string, suffix[i], suffix_len))
@@ -429,6 +430,18 @@ static inline int upstream_mark(const char *string, int len)
        return 0;
 }
 
+static inline int upstream_mark(const char *string, int len)
+{
+       const char *suffix[] = { "@{upstream}", "@{u}" };
+       return at_mark(string, len, suffix, ARRAY_SIZE(suffix));
+}
+
+static inline int push_mark(const char *string, int len)
+{
+       const char *suffix[] = { "@{push}" };
+       return at_mark(string, len, suffix, ARRAY_SIZE(suffix));
+}
+
 static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags);
 static int interpret_nth_prior_checkout(const char *name, int namelen, struct strbuf *buf);
 
@@ -476,7 +489,8 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
                                        nth_prior = 1;
                                        continue;
                                }
-                               if (!upstream_mark(str + at, len - at)) {
+                               if (!upstream_mark(str + at, len - at) &&
+                                   !push_mark(str + at, len - at)) {
                                        reflog_len = (len-1) - (at+2);
                                        len = at;
                                }
@@ -831,11 +845,11 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned l
 /* Remember to update object flag allocation in object.h */
 #define ONELINE_SEEN (1u<<20)
 
-static int handle_one_ref(const char *path,
-               const unsigned char *sha1, int flag, void *cb_data)
+static int handle_one_ref(const char *path, const struct object_id *oid,
+                         int flag, void *cb_data)
 {
        struct commit_list **list = cb_data;
-       struct object *object = parse_object(sha1);
+       struct object *object = parse_object(oid->hash);
        if (!object)
                return 0;
        if (object->type == OBJ_TAG) {
@@ -1055,46 +1069,36 @@ static void set_shortened_ref(struct strbuf *buf, const char *ref)
        free(s);
 }
 
-static const char *get_upstream_branch(const char *branch_buf, int len)
-{
-       char *branch = xstrndup(branch_buf, len);
-       struct branch *upstream = branch_get(*branch ? branch : NULL);
-
-       /*
-        * Upstream can be NULL only if branch refers to HEAD and HEAD
-        * points to something different than a branch.
-        */
-       if (!upstream)
-               die(_("HEAD does not point to a branch"));
-       if (!upstream->merge || !upstream->merge[0]->dst) {
-               if (!ref_exists(upstream->refname))
-                       die(_("No such branch: '%s'"), branch);
-               if (!upstream->merge) {
-                       die(_("No upstream configured for branch '%s'"),
-                               upstream->name);
-               }
-               die(
-                       _("Upstream branch '%s' not stored as a remote-tracking branch"),
-                       upstream->merge[0]->src);
-       }
-       free(branch);
-
-       return upstream->merge[0]->dst;
-}
-
-static int interpret_upstream_mark(const char *name, int namelen,
-                                  int at, struct strbuf *buf)
+static int interpret_branch_mark(const char *name, int namelen,
+                                int at, struct strbuf *buf,
+                                int (*get_mark)(const char *, int),
+                                const char *(*get_data)(struct branch *,
+                                                        struct strbuf *))
 {
        int len;
+       struct branch *branch;
+       struct strbuf err = STRBUF_INIT;
+       const char *value;
 
-       len = upstream_mark(name + at, namelen - at);
+       len = get_mark(name + at, namelen - at);
        if (!len)
                return -1;
 
        if (memchr(name, ':', at))
                return -1;
 
-       set_shortened_ref(buf, get_upstream_branch(name, at));
+       if (at) {
+               char *name_str = xmemdupz(name, at);
+               branch = branch_get(name_str);
+               free(name_str);
+       } else
+               branch = branch_get(NULL);
+
+       value = get_data(branch, &err);
+       if (!value)
+               die("%s", err.buf);
+
+       set_shortened_ref(buf, value);
        return len + at;
 }
 
@@ -1145,7 +1149,13 @@ int interpret_branch_name(const char *name, int namelen, struct strbuf *buf)
                if (len > 0)
                        return reinterpret(name, namelen, len, buf);
 
-               len = interpret_upstream_mark(name, namelen, at - name, buf);
+               len = interpret_branch_mark(name, namelen, at - name, buf,
+                                           upstream_mark, branch_get_upstream);
+               if (len > 0)
+                       return len;
+
+               len = interpret_branch_mark(name, namelen, at - name, buf,
+                                           push_mark, branch_get_push);
                if (len > 0)
                        return len;
        }
@@ -1237,14 +1247,13 @@ static void diagnose_invalid_sha1_path(const char *prefix,
                                       const char *object_name,
                                       int object_name_len)
 {
-       struct stat st;
        unsigned char sha1[20];
        unsigned mode;
 
        if (!prefix)
                prefix = "";
 
-       if (!lstat(filename, &st))
+       if (file_exists(filename))
                die("Path '%s' exists on disk, but not in '%.*s'.",
                    filename, object_name_len, object_name);
        if (errno == ENOENT || errno == ENOTDIR) {
@@ -1271,7 +1280,6 @@ static void diagnose_invalid_index_path(int stage,
                                        const char *prefix,
                                        const char *filename)
 {
-       struct stat st;
        const struct cache_entry *ce;
        int pos;
        unsigned namelen = strlen(filename);
@@ -1314,7 +1322,7 @@ static void diagnose_invalid_index_path(int stage,
                            ce_stage(ce), filename);
        }
 
-       if (!lstat(filename, &st))
+       if (file_exists(filename))
                die("Path '%s' exists on disk, but not in the index.", filename);
        if (errno == ENOENT || errno == ENOTDIR)
                die("Path '%s' does not exist (neither on disk nor in the index).",
@@ -1371,6 +1379,7 @@ static int get_sha1_with_context_1(const char *name,
                int pos;
                if (!only_to_die && namelen > 2 && name[1] == '/') {
                        struct commit_list *list = NULL;
+
                        for_each_ref(handle_one_ref, &list);
                        commit_list_sort_by_date(&list);
                        return get_sha1_oneline(name + 2, sha1, list);
@@ -1434,11 +1443,19 @@ static int get_sha1_with_context_1(const char *name,
                        new_filename = resolve_relative_path(filename);
                        if (new_filename)
                                filename = new_filename;
-                       ret = get_tree_entry(tree_sha1, filename, sha1, &oc->mode);
-                       if (ret && only_to_die) {
-                               diagnose_invalid_sha1_path(prefix, filename,
-                                                          tree_sha1,
-                                                          name, len);
+                       if (flags & GET_SHA1_FOLLOW_SYMLINKS) {
+                               ret = get_tree_entry_follow_symlinks(tree_sha1,
+                                       filename, sha1, &oc->symlink_path,
+                                       &oc->mode);
+                       } else {
+                               ret = get_tree_entry(tree_sha1, filename,
+                                                    sha1, &oc->mode);
+                               if (ret && only_to_die) {
+                                       diagnose_invalid_sha1_path(prefix,
+                                                                  filename,
+                                                                  tree_sha1,
+                                                                  name, len);
+                               }
                        }
                        hashcpy(oc->tree, tree_sha1);
                        strlcpy(oc->path, filename, sizeof(oc->path));
@@ -1469,5 +1486,7 @@ void maybe_die_on_misspelt_object_name(const char *name, const char *prefix)
 
 int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc)
 {
+       if (flags & GET_SHA1_FOLLOW_SYMLINKS && flags & GET_SHA1_ONLY_TO_DIE)
+               die("BUG: incompatible flags for get_sha1_with_context");
        return get_sha1_with_context_1(str, flags, NULL, sha1, orc);
 }