tests: introduce test_ln_s_add
[gitweb.git] / convert.c
index 33373b3ac0ebeaeb39167b006a9e11494b5e837a..2a2e46c2012de3af673b9d8d8647ec894f07b65a 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -153,36 +153,13 @@ static void check_safe_crlf(const char *path, enum crlf_action crlf_action,
 
 static int has_cr_in_index(const char *path)
 {
-       int pos, len;
        unsigned long sz;
-       enum object_type type;
        void *data;
        int has_cr;
-       struct index_state *istate = &the_index;
 
-       len = strlen(path);
-       pos = index_name_pos(istate, path, len);
-       if (pos < 0) {
-               /*
-                * We might be in the middle of a merge, in which
-                * case we would read stage #2 (ours).
-                */
-               int i;
-               for (i = -pos - 1;
-                    (pos < 0 && i < istate->cache_nr &&
-                     !strcmp(istate->cache[i]->name, path));
-                    i++)
-                       if (ce_stage(istate->cache[i]) == 2)
-                               pos = i;
-       }
-       if (pos < 0)
-               return 0;
-       data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
-       if (!data || type != OBJ_BLOB) {
-               free(data);
+       data = read_blob_data_from_cache(path, &sz);
+       if (!data)
                return 0;
-       }
-
        has_cr = memchr(data, '\r', sz) != NULL;
        free(data);
        return has_cr;
@@ -196,9 +173,17 @@ static int crlf_to_git(const char *path, const char *src, size_t len,
        char *dst;
 
        if (crlf_action == CRLF_BINARY ||
-           (crlf_action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE) || !len)
+           (crlf_action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE) ||
+           (src && !len))
                return 0;
 
+       /*
+        * If we are doing a dry-run and have no source buffer, there is
+        * nothing to analyze; we must assume we would convert.
+        */
+       if (!buf && !src)
+               return 1;
+
        gather_stats(src, len, &stats);
 
        if (crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS) {
@@ -232,6 +217,13 @@ static int crlf_to_git(const char *path, const char *src, size_t len,
        if (!stats.cr)
                return 0;
 
+       /*
+        * At this point all of our source analysis is done, and we are sure we
+        * would convert. If we are in dry-run mode, we can give an answer.
+        */
+       if (!buf)
+               return 1;
+
        /* only grow if not in place */
        if (strbuf_avail(buf) + buf->len < len)
                strbuf_grow(buf, len - buf->len);
@@ -396,6 +388,9 @@ static int apply_filter(const char *path, const char *src, size_t len,
        if (!cmd)
                return 0;
 
+       if (!dst)
+               return 1;
+
        memset(&async, 0, sizeof(async));
        async.proc = filter_buffer;
        async.data = &params;
@@ -434,11 +429,12 @@ static struct convert_driver {
        struct convert_driver *next;
        const char *smudge;
        const char *clean;
+       int required;
 } *user_convert, **user_convert_tail;
 
 static int read_convert_config(const char *var, const char *value, void *cb)
 {
-       const char *ep, *name;
+       const char *key, *name;
        int namelen;
        struct convert_driver *drv;
 
@@ -446,10 +442,8 @@ static int read_convert_config(const char *var, const char *value, void *cb)
         * External conversion drivers are configured using
         * "filter.<name>.variable".
         */
-       if (prefixcmp(var, "filter.") || (ep = strrchr(var, '.')) == var + 6)
+       if (parse_config_key(var, "filter", &name, &namelen, &key) < 0 || !name)
                return 0;
-       name = var + 7;
-       namelen = ep - name;
        for (drv = user_convert; drv; drv = drv->next)
                if (!strncmp(drv->name, name, namelen) && !drv->name[namelen])
                        break;
@@ -460,8 +454,6 @@ static int read_convert_config(const char *var, const char *value, void *cb)
                user_convert_tail = &(drv->next);
        }
 
-       ep++;
-
        /*
         * filter.<name>.smudge and filter.<name>.clean specifies
         * the command line:
@@ -471,12 +463,17 @@ static int read_convert_config(const char *var, const char *value, void *cb)
         * The command-line will not be interpolated in any way.
         */
 
-       if (!strcmp("smudge", ep))
+       if (!strcmp("smudge", key))
                return git_config_string(&drv->smudge, var, value);
 
-       if (!strcmp("clean", ep))
+       if (!strcmp("clean", key))
                return git_config_string(&drv->clean, var, value);
 
+       if (!strcmp("required", key)) {
+               drv->required = git_config_bool(var, value);
+               return 0;
+       }
+
        return 0;
 }
 
@@ -527,9 +524,12 @@ static int ident_to_git(const char *path, const char *src, size_t len,
 {
        char *dst, *dollar;
 
-       if (!ident || !count_ident(src, len))
+       if (!ident || (src && !count_ident(src, len)))
                return 0;
 
+       if (!buf)
+               return 1;
+
        /* only grow if not in place */
        if (strbuf_avail(buf) + buf->len < len)
                strbuf_grow(buf, len - buf->len);
@@ -752,20 +752,26 @@ int convert_to_git(const char *path, const char *src, size_t len,
 {
        int ret = 0;
        const char *filter = NULL;
+       int required = 0;
        struct conv_attrs ca;
 
        convert_attrs(&ca, path);
-       if (ca.drv)
+       if (ca.drv) {
                filter = ca.drv->clean;
+               required = ca.drv->required;
+       }
 
        ret |= apply_filter(path, src, len, dst, filter);
-       if (ret) {
+       if (!ret && required)
+               die("%s: clean filter '%s' failed", path, ca.drv->name);
+
+       if (ret && dst) {
                src = dst->buf;
                len = dst->len;
        }
        ca.crlf_action = input_crlf_action(ca.crlf_action, ca.eol_attr);
        ret |= crlf_to_git(path, src, len, dst, ca.crlf_action, checksafe);
-       if (ret) {
+       if (ret && dst) {
                src = dst->buf;
                len = dst->len;
        }
@@ -776,13 +782,16 @@ static int convert_to_working_tree_internal(const char *path, const char *src,
                                            size_t len, struct strbuf *dst,
                                            int normalizing)
 {
-       int ret = 0;
+       int ret = 0, ret_filter = 0;
        const char *filter = NULL;
+       int required = 0;
        struct conv_attrs ca;
 
        convert_attrs(&ca, path);
-       if (ca.drv)
+       if (ca.drv) {
                filter = ca.drv->smudge;
+               required = ca.drv->required;
+       }
 
        ret |= ident_to_worktree(path, src, len, dst, ca.ident);
        if (ret) {
@@ -801,7 +810,12 @@ static int convert_to_working_tree_internal(const char *path, const char *src,
                        len = dst->len;
                }
        }
-       return ret | apply_filter(path, src, len, dst, filter);
+
+       ret_filter = apply_filter(path, src, len, dst, filter);
+       if (!ret_filter && required)
+               die("%s: smudge filter %s failed", path, ca.drv->name);
+
+       return ret | ret_filter;
 }
 
 int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst)