diff --git a/write-tree.c b/write-tree.c
index 19b6ee5ea3bf17b81a22c0f76ae5da85998552d3..a5069921a0f01e872c5e7c62f836cd0b4441e551 100644 (file)
--- a/write-tree.c
+++ b/write-tree.c
* Copyright (C) Linus Torvalds, 2005
*/
#include "cache.h"
+#include "tree.h"
+#include "cache-tree.h"
-static int check_valid_sha1(unsigned char *sha1)
-{
- char *filename = sha1_file_name(sha1);
- int ret;
-
- /* If we were anal, we'd check that the sha1 of the contents actually matches */
- ret = access(filename, R_OK);
- if (ret)
- perror(filename);
- return ret;
-}
-
-static int write_tree(struct cache_entry **cachep, int maxentries, const char *base, int baselen, unsigned char *returnsha1)
-{
- unsigned char subdir_sha1[20];
- unsigned long size, offset;
- char *buffer;
- int nr;
-
- /* Guess at some random initial size */
- size = 8192;
- buffer = xmalloc(size);
- offset = 0;
-
- nr = 0;
- do {
- struct cache_entry *ce = cachep[nr];
- const char *pathname = ce->name, *filename, *dirname;
- int pathlen = ce_namelen(ce), entrylen;
- unsigned char *sha1;
- unsigned int mode;
-
- /* Did we hit the end of the directory? Return how many we wrote */
- if (baselen >= pathlen || memcmp(base, pathname, baselen))
- break;
-
- sha1 = ce->sha1;
- mode = ntohl(ce->ce_mode);
-
- /* Do we have _further_ subdirectories? */
- filename = pathname + baselen;
- dirname = strchr(filename, '/');
- if (dirname) {
- int subdir_written;
-
- subdir_written = write_tree(cachep + nr, maxentries - nr, pathname, dirname-pathname+1, subdir_sha1);
- nr += subdir_written;
+static int missing_ok = 0;
- /* Now we need to write out the directory entry into this tree.. */
- mode = S_IFDIR;
- pathlen = dirname - pathname;
+static const char write_tree_usage[] = "git-write-tree [--missing-ok]";
- /* ..but the directory entry doesn't count towards the total count */
- nr--;
- sha1 = subdir_sha1;
- }
-
- if (check_valid_sha1(sha1) < 0)
- exit(1);
-
- entrylen = pathlen - baselen;
- if (offset + entrylen + 100 > size) {
- size = alloc_nr(offset + entrylen + 100);
- buffer = xrealloc(buffer, size);
- }
- offset += sprintf(buffer + offset, "%o %.*s", mode, entrylen, filename);
- buffer[offset++] = 0;
- memcpy(buffer + offset, sha1, 20);
- offset += 20;
- nr++;
- } while (nr < maxentries);
-
- write_sha1_file(buffer, offset, "tree", returnsha1);
- free(buffer);
- return nr;
-}
+static struct cache_file cache_file;
int main(int argc, char **argv)
{
- int i, funny;
- int entries = read_cache();
- unsigned char sha1[20];
+ int entries, was_valid, newfd;
- if (entries <= 0)
- die("write-tree: no cache contents to write");
+ setup_git_directory();
- /* Verify that the tree is merged */
- funny = 0;
- for (i = 0; i < entries; i++) {
- struct cache_entry *ce = active_cache[i];
- if (ntohs(ce->ce_flags) & ~CE_NAMEMASK) {
- if (10 < ++funny) {
- fprintf(stderr, "...\n");
- break;
- }
- fprintf(stderr, "%s: unmerged (%s)\n", ce->name, sha1_to_hex(ce->sha1));
- }
+ newfd = hold_index_file_for_update(&cache_file, get_index_file());
+ entries = read_cache();
+ if (argc == 2) {
+ if (!strcmp(argv[1], "--missing-ok"))
+ missing_ok = 1;
+ else
+ die(write_tree_usage);
}
- if (funny)
- die("write-tree: not able to write tree");
-
- /* Also verify that the cache does not have path and path/file
- * at the same time. At this point we know the cache has only
- * stage 0 entries.
- */
- funny = 0;
- for (i = 0; i < entries - 1; i++) {
- /* path/file always comes after path because of the way
- * the cache is sorted. Also path can appear only once,
- * which means conflicting one would immediately follow.
- */
- const char *this_name = active_cache[i]->name;
- const char *next_name = active_cache[i+1]->name;
- int this_len = strlen(this_name);
- if (this_len < strlen(next_name) &&
- strncmp(this_name, next_name, this_len) == 0 &&
- next_name[this_len] == '/') {
- if (10 < ++funny) {
- fprintf(stderr, "...\n");
- break;
- }
- fprintf(stderr, "You have both %s and %s\n",
- this_name, next_name);
+
+ if (argc > 2)
+ die("too many options");
+
+ if (entries < 0)
+ die("git-write-tree: error reading cache");
+
+ if (!active_cache_tree)
+ active_cache_tree = cache_tree();
+
+ was_valid = cache_tree_fully_valid(active_cache_tree);
+ if (!was_valid) {
+ if (cache_tree_update(active_cache_tree,
+ active_cache, active_nr,
+ missing_ok) < 0)
+ die("git-write-tree: error building trees");
+ if (0 <= newfd) {
+ if (!write_cache(newfd, active_cache, active_nr))
+ commit_index_file(&cache_file);
}
+ /* Not being able to write is fine -- we are only interested
+ * in updating the cache-tree part, and if the next caller
+ * ends up using the old index with unupdated cache-tree part
+ * it misses the work we did here, but that is just a
+ * performance penalty and not a big deal.
+ */
}
- if (funny)
- die("write-tree: not able to write tree");
-
- /* Ok, write it out */
- if (write_tree(active_cache, entries, "", 0, sha1) != entries)
- die("write-tree: internal error");
- printf("%s\n", sha1_to_hex(sha1));
+ printf("%s\n", sha1_to_hex(active_cache_tree->sha1));
return 0;
}