From: Nguyen Thai Ngoc Duy <pclouds@gmail.com>
To: Junio C Hamano <gitster@pobox.com>
Cc: git@vger.kernel.org
Subject: Re: [PATCH 4/5] archive: do not read .gitattributes in working directory
Date: Thu, 16 Apr 2009 22:38:46 +1000 [thread overview]
Message-ID: <fcaeb9bf0904160538w4a826c57r40e9cf1c52b0b6ff@mail.gmail.com> (raw)
In-Reply-To: <fcaeb9bf0904160350m14dce828oe88bda6562d98f48@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 693 bytes --]
On Thu, Apr 16, 2009 at 8:50 PM, Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:
> I was thinking about loading .gitattributes inside write_archive_entry
> too, to avoid calling read_tree_recursive twice, but it requires
> .gitattributes to be traversed first. Won't work if there are files
> .abc, .def...
>
> If read_tree_recusive() expose its tree to read_tree_fn_t, we can then
> look ahead and load .gitattributes, but that requires changing
> read_tree_fn_t interface. I'll see if it's feasible to make a
> customized read_tree_recusive() just for archive.c
Here it is (again on top of your patch). Need to read directories
twice, but not as bad as read_tree_recursive() twice.
--
Duy
[-- Attachment #2: attr-3.patch --]
[-- Type: text/x-patch, Size: 5198 bytes --]
diff --git a/archive.c b/archive.c
index 0ce628b..8df53a8 100644
--- a/archive.c
+++ b/archive.c
@@ -97,6 +97,43 @@ struct archiver_context {
write_archive_entry_fn_t write_entry;
};
+static int read_gitattr_to_index(struct tree *tree, const char *base, int baselen, struct archiver_args *args)
+{
+ struct tree_desc desc;
+ struct name_entry entry;
+ struct cache_entry *ce;
+ unsigned int size;
+ int pathlen;
+
+ if (parse_tree(tree))
+ return -1;
+
+ init_tree_desc(&desc, tree->buffer, tree->size);
+
+ while (tree_entry(&desc, &entry)) {
+ if (S_ISDIR(entry.mode) || S_ISGITLINK(entry.mode))
+ continue;
+ if (strcmp(entry.path, GITATTRIBUTES_FILE))
+ continue;
+ pathlen = tree_entry_len(entry.path, entry.sha1);
+ baselen -= args->baselen; /* remove user prefix */
+ if (baselen)
+ baselen++; /* slash */
+ size = cache_entry_size(baselen + pathlen);
+ ce = xcalloc(1, size);
+ ce->ce_mode = create_ce_mode(entry.mode);
+ ce->ce_flags = create_ce_flags(baselen + pathlen, 0);
+ if (baselen) {
+ memcpy(ce->name, base + args->baselen, baselen-1);
+ ce->name[baselen-1] = '/';
+ }
+ memcpy(ce->name + baselen, entry.path, pathlen + 1);
+ hashcpy(ce->sha1, entry.sha1);
+ return add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_SKIP_DFCHECK);
+ }
+ return 0;
+}
+
static int write_archive_entry(const unsigned char *sha1, const char *base,
int baselen, const char *filename, unsigned mode, int stage,
void *context)
@@ -119,11 +156,25 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
strbuf_addstr(&path, filename);
path_without_prefix = path.buf + args->baselen;
- setup_archive_check(check);
- if (!git_checkattr(path_without_prefix, ARRAY_SIZE(check), check)) {
- if (ATTR_TRUE(check[0].value))
- return 0;
- convert = ATTR_TRUE(check[1].value);
+ if (S_ISDIR(mode)) {
+ /*
+ * we want to read .gitattributes before any entry is processed
+ * so every time we get a directory entry, we look ahead to see
+ * if there is .gitattributes and load it
+ *
+ * later when the directory is processed, .gitattributes is
+ * already ready in index for git_checkattr()
+ */
+ if (!args->worktree_attributes)
+ read_gitattr_to_index(lookup_tree(sha1), base, baselen, args);
+ }
+ else {
+ setup_archive_check(check);
+ if (!git_checkattr(path_without_prefix, ARRAY_SIZE(check), check)) {
+ if (ATTR_TRUE(check[0].value))
+ return 0;
+ convert = ATTR_TRUE(check[1].value);
+ }
}
if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
@@ -151,8 +202,6 @@ int write_archive_entries(struct archiver_args *args,
write_archive_entry_fn_t write_entry)
{
struct archiver_context context;
- struct unpack_trees_options opts;
- struct tree_desc t;
int err;
if (args->baselen > 0 && args->base[args->baselen - 1] == '/') {
@@ -171,19 +220,9 @@ int write_archive_entries(struct archiver_args *args,
context.args = args;
context.write_entry = write_entry;
- /*
- * Setup index and instruct attr to read index only
- */
if (!args->worktree_attributes) {
- memset(&opts, 0, sizeof(opts));
- opts.index_only = 1;
- opts.head_idx = -1;
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
- opts.fn = oneway_merge;
- init_tree_desc(&t, args->tree->buffer, args->tree->size);
- if (unpack_trees(1, &t, &opts))
- return -1;
+ /* read .gitattributes at root if any */
+ read_gitattr_to_index(args->tree, args->base, args->baselen, args);
git_attr_set_direction(GIT_ATTR_INDEX, &the_index);
}
@@ -209,13 +248,23 @@ static const struct archiver *lookup_archiver(const char *name)
}
static void parse_pathspec_arg(const char **pathspec,
- struct archiver_args *ar_args)
+ struct archiver_args *ar_args,
+ const char *prefix)
{
- ar_args->pathspec = get_pathspec(ar_args->base, pathspec);
+ struct strbuf s = STRBUF_INIT;
+ if (ar_args->base)
+ strbuf_addstr(&s, ar_args->base);
+ if (prefix)
+ strbuf_addstr(&s, prefix);
+ ar_args->pathspec = get_pathspec(s.len ? s.buf : NULL, pathspec);
+ /*
+ * s.buf must never be freed because
+ * get_pathspec does not duplicate it
+ */
}
static void parse_treeish_arg(const char **argv,
- struct archiver_args *ar_args, const char *prefix)
+ struct archiver_args *ar_args)
{
const char *name = argv[0];
const unsigned char *commit_sha1;
@@ -240,18 +289,6 @@ static void parse_treeish_arg(const char **argv,
if (tree == NULL)
die("not a tree object");
- if (prefix) {
- unsigned char tree_sha1[20];
- unsigned int mode;
- int err;
-
- err = get_tree_entry(tree->object.sha1, prefix,
- tree_sha1, &mode);
- if (err || !S_ISDIR(mode))
- die("current working directory is untracked");
-
- tree = parse_tree_indirect(tree_sha1);
- }
ar_args->tree = tree;
ar_args->commit_sha1 = commit_sha1;
ar_args->commit = commit;
@@ -360,8 +397,8 @@ int write_archive(int argc, const char **argv, const char *prefix,
if (setup_prefix && prefix == NULL)
prefix = setup_git_directory();
- parse_treeish_arg(argv, &args, prefix);
- parse_pathspec_arg(argv + 1, &args);
+ parse_treeish_arg(argv, &args);
+ parse_pathspec_arg(argv + 1, &args, prefix);
git_config(git_default_config, NULL);
next prev parent reply other threads:[~2009-04-16 12:40 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-04-16 2:28 [PATCH 0/5] archive attribute series Junio C Hamano
2009-04-16 2:28 ` [PATCH 1/5] archive tests: do not use .gitattributes in working directory Junio C Hamano
2009-04-16 2:28 ` [PATCH 2/5] attr: add GIT_ATTR_INDEX "direction" Junio C Hamano
2009-04-16 2:28 ` [PATCH 3/5] unpack-trees: do not muck with attributes when we are not checking out Junio C Hamano
2009-04-16 2:28 ` [PATCH 4/5] archive: do not read .gitattributes in working directory Junio C Hamano
2009-04-16 2:28 ` [PATCH 5/5] archive test: test new --fix-attributes feature Junio C Hamano
2009-04-17 19:53 ` René Scharfe
2009-04-16 5:17 ` [PATCH 4/5] archive: do not read .gitattributes in working directory Junio C Hamano
2009-04-16 7:06 ` Jeff King
2009-04-16 7:29 ` Jakub Narebski
2009-04-16 10:50 ` Nguyen Thai Ngoc Duy
2009-04-16 12:38 ` Nguyen Thai Ngoc Duy [this message]
2009-04-17 20:33 ` [PATCH 2/5] attr: add GIT_ATTR_INDEX "direction" René Scharfe
2009-04-17 19:51 ` [PATCH 1/5] archive tests: do not use .gitattributes in working directory René Scharfe
2009-04-17 22:17 ` [PATCH v2 " René Scharfe
2009-04-17 22:17 ` [PATCH v2 2/5] attr: add GIT_ATTR_INDEX "direction" René Scharfe
2009-04-17 22:18 ` [PATCH v2 3/5] unpack-trees: do not muck with attributes when we are not checking out René Scharfe
2009-04-17 22:18 ` [PATCH v2 4/5] archive: do not read .gitattributes in working directory René Scharfe
2009-04-17 22:18 ` [PATCH v2 5/5] archive test: attributes René Scharfe
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=fcaeb9bf0904160538w4a826c57r40e9cf1c52b0b6ff@mail.gmail.com \
--to=pclouds@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).