Code

Merge branch 'jc/unseekable-bundle'
authorJunio C Hamano <gitster@pobox.com>
Fri, 21 Oct 2011 23:04:32 +0000 (16:04 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 21 Oct 2011 23:04:32 +0000 (16:04 -0700)
* jc/unseekable-bundle:
  bundle: add parse_bundle_header() helper function
  bundle: allowing to read from an unseekable fd

Conflicts:
transport.c

1  2 
bundle.c
bundle.h
transport.c

diff --combined bundle.c
index f82baae3bd2736cd0abca6b2412e3c4fd363b1e6,105b005366ab2bbc349defff3572a7722e6c1ddf..08020bc3a258e055a8f5f6974217cf482edc3ee3
+++ b/bundle.c
@@@ -23,50 -23,102 +23,102 @@@ static void add_to_ref_list(const unsig
        list->nr++;
  }
  
- /* returns an fd */
int read_bundle_header(const char *path, struct bundle_header *header)
+ /* Eventually this should go to strbuf.[ch] */
static int strbuf_readline_fd(struct strbuf *sb, int fd)
  {
-       char buffer[1024];
-       int fd;
-       long fpos;
-       FILE *ffd = fopen(path, "rb");
+       strbuf_reset(sb);
  
-       if (!ffd)
-               return error("could not open '%s'", path);
-       if (!fgets(buffer, sizeof(buffer), ffd) ||
-                       strcmp(buffer, bundle_signature)) {
-               fclose(ffd);
-               return error("'%s' does not look like a v2 bundle file", path);
+       while (1) {
+               char ch;
+               ssize_t len = xread(fd, &ch, 1);
+               if (len < 0)
+                       return -1;
+               strbuf_addch(sb, ch);
+               if (ch == '\n')
+                       break;
        }
-       while (fgets(buffer, sizeof(buffer), ffd)
-                       && buffer[0] != '\n') {
-               int is_prereq = buffer[0] == '-';
-               int offset = is_prereq ? 1 : 0;
-               int len = strlen(buffer);
+       return 0;
+ }
+ static int parse_bundle_header(int fd, struct bundle_header *header,
+                              const char *report_path)
+ {
+       struct strbuf buf = STRBUF_INIT;
+       int status = 0;
+       /* The bundle header begins with the signature */
+       if (strbuf_readline_fd(&buf, fd) ||
+           strcmp(buf.buf, bundle_signature)) {
+               if (report_path)
+                       error("'%s' does not look like a v2 bundle file",
+                             report_path);
+               status = -1;
+               goto abort;
+       }
+       /* The bundle header ends with an empty line */
+       while (!strbuf_readline_fd(&buf, fd) &&
+              buf.len && buf.buf[0] != '\n') {
                unsigned char sha1[20];
-               struct ref_list *list = is_prereq ? &header->prerequisites
-                       : &header->references;
-               char delim;
-               if (len && buffer[len - 1] == '\n')
-                       buffer[len - 1] = '\0';
-               if (get_sha1_hex(buffer + offset, sha1)) {
-                       warning("unrecognized header: %s", buffer);
-                       continue;
+               int is_prereq = 0;
+               if (*buf.buf == '-') {
+                       is_prereq = 1;
+                       strbuf_remove(&buf, 0, 1);
                }
-               delim = buffer[40 + offset];
-               if (!isspace(delim) && (delim != '\0' || !is_prereq))
-                       die ("invalid header: %s", buffer);
-               add_to_ref_list(sha1, isspace(delim) ?
-                               buffer + 41 + offset : "", list);
+               strbuf_rtrim(&buf);
+               /*
+                * Tip lines have object name, SP, and refname.
+                * Prerequisites have object name that is optionally
+                * followed by SP and subject line.
+                */
+               if (get_sha1_hex(buf.buf, sha1) ||
+                   (40 <= buf.len && !isspace(buf.buf[40])) ||
+                   (!is_prereq && buf.len <= 40)) {
+                       if (report_path)
+                               error("unrecognized header: %s%s (%d)",
+                                     (is_prereq ? "-" : ""), buf.buf, (int)buf.len);
+                       status = -1;
+                       break;
+               } else {
+                       if (is_prereq)
+                               add_to_ref_list(sha1, "", &header->prerequisites);
+                       else
+                               add_to_ref_list(sha1, buf.buf + 41, &header->references);
+               }
+       }
+  abort:
+       if (status) {
+               close(fd);
+               fd = -1;
        }
-       fpos = ftell(ffd);
-       fclose(ffd);
-       fd = open(path, O_RDONLY);
+       strbuf_release(&buf);
+       return fd;
+ }
+ int read_bundle_header(const char *path, struct bundle_header *header)
+ {
+       int fd = open(path, O_RDONLY);
        if (fd < 0)
                return error("could not open '%s'", path);
-       lseek(fd, fpos, SEEK_SET);
-       return fd;
+       return parse_bundle_header(fd, header, path);
+ }
+ int is_bundle(const char *path, int quiet)
+ {
+       struct bundle_header header;
+       int fd = open(path, O_RDONLY);
+       if (fd < 0)
+               return 0;
+       memset(&header, 0, sizeof(header));
+       fd = parse_bundle_header(fd, &header, quiet ? NULL : path);
+       if (fd >= 0)
+               close(fd);
+       return (fd >= 0);
  }
  
  static int list_refs(struct ref_list *r, int argc, const char **argv)
@@@ -122,8 -174,11 +174,8 @@@ int verify_bundle(struct bundle_header 
        req_nr = revs.pending.nr;
        setup_revisions(2, argv, &revs, NULL);
  
 -      memset(&refs, 0, sizeof(struct object_array));
 -      for (i = 0; i < revs.pending.nr; i++) {
 -              struct object_array_entry *e = revs.pending.objects + i;
 -              add_object_array(e->item, e->name, &refs);
 -      }
 +      refs = revs.pending;
 +      revs.leak_pending = 1;
  
        if (prepare_revision_walk(&revs))
                die("revision walk setup failed");
                                refs.objects[i].name);
                }
  
 -      for (i = 0; i < refs.nr; i++)
 -              clear_commit_marks((struct commit *)refs.objects[i].item, -1);
 +      clear_commit_marks_for_object_array(&refs, ALL_REV_FLAGS);
 +      free(refs.objects);
  
        if (verbose) {
                struct ref_list *r;
@@@ -377,15 -432,12 +429,15 @@@ int create_bundle(struct bundle_header 
        return 0;
  }
  
 -int unbundle(struct bundle_header *header, int bundle_fd)
 +int unbundle(struct bundle_header *header, int bundle_fd, int flags)
  {
        const char *argv_index_pack[] = {"index-pack",
 -              "--fix-thin", "--stdin", NULL};
 +                                       "--fix-thin", "--stdin", NULL, NULL};
        struct child_process ip;
  
 +      if (flags & BUNDLE_VERBOSE)
 +              argv_index_pack[3] = "-v";
 +
        if (verify_bundle(header, 0))
                return -1;
        memset(&ip, 0, sizeof(ip));
diff --combined bundle.h
index c5a22c8d10c7bf5e27536a3b84033b77f3542445,c6228e2102c4fe6958d4086061df1f556451cdb9..1584e4d821440d525f10515d6a07c6506b732fec
+++ b/bundle.h
@@@ -14,12 -14,12 +14,13 @@@ struct bundle_header 
        struct ref_list references;
  };
  
+ int is_bundle(const char *path, int quiet);
  int read_bundle_header(const char *path, struct bundle_header *header);
  int create_bundle(struct bundle_header *header, const char *path,
                int argc, const char **argv);
  int verify_bundle(struct bundle_header *header, int verbose);
 -int unbundle(struct bundle_header *header, int bundle_fd);
 +#define BUNDLE_VERBOSE 1
 +int unbundle(struct bundle_header *header, int bundle_fd, int flags);
  int list_bundle_refs(struct bundle_header *header,
                int argc, const char **argv);
  
diff --combined transport.c
index 57138d908a5749d378af441e8d3cfe8150b27271,84d6480ce65cf4bc45a344d6e9986696cbd8498f..4ff21ad28d89c6a4fc39628d358662bc7790ffde
@@@ -10,7 -10,6 +10,7 @@@
  #include "refs.h"
  #include "branch.h"
  #include "url.h"
 +#include "submodule.h"
  
  /* rsync support */
  
@@@ -432,8 -431,7 +432,8 @@@ static int fetch_refs_from_bundle(struc
                               int nr_heads, struct ref **to_fetch)
  {
        struct bundle_transport_data *data = transport->data;
 -      return unbundle(&data->header, data->fd);
 +      return unbundle(&data->header, data->fd,
 +                      transport->progress ? BUNDLE_VERBOSE : 0);
  }
  
  static int close_bundle(struct transport *transport)
@@@ -755,10 -753,18 +755,10 @@@ void transport_verify_remote_names(int 
                        continue;
  
                remote = remote ? (remote + 1) : local;
 -              switch (check_ref_format(remote)) {
 -              case 0: /* ok */
 -              case CHECK_REF_FORMAT_ONELEVEL:
 -                      /* ok but a single level -- that is fine for
 -                       * a match pattern.
 -                       */
 -              case CHECK_REF_FORMAT_WILDCARD:
 -                      /* ok but ends with a pattern-match character */
 -                      continue;
 -              }
 -              die("remote part of refspec is not a valid name in %s",
 -                  heads[i]);
 +              if (check_refname_format(remote,
 +                              REFNAME_ALLOW_ONELEVEL|REFNAME_REFSPEC_PATTERN))
 +                      die("remote part of refspec is not a valid name in %s",
 +                              heads[i]);
        }
  }
  
@@@ -859,28 -865,6 +859,6 @@@ static int is_local(const char *url
                has_dos_drive_prefix(url);
  }
  
- static int is_gitfile(const char *url)
- {
-       struct stat st;
-       char buf[9];
-       int fd, len;
-       if (stat(url, &st))
-               return 0;
-       if (!S_ISREG(st.st_mode))
-               return 0;
-       if (st.st_size < 10 || st.st_size > 9 + PATH_MAX)
-               return 0;
-       fd = open(url, O_RDONLY);
-       if (fd < 0)
-               die_errno("Error opening '%s'", url);
-       len = read_in_full(fd, buf, sizeof(buf));
-       close(fd);
-       if (len != sizeof(buf))
-               die("Error reading %s", url);
-       return !prefixcmp(buf, "gitdir: ");
- }
  static int is_file(const char *url)
  {
        struct stat buf;
@@@ -929,7 -913,7 +907,7 @@@ struct transport *transport_get(struct 
                ret->fetch = fetch_objs_via_rsync;
                ret->push = rsync_transport_push;
                ret->smart_options = NULL;
-       } else if (is_local(url) && is_file(url) && !is_gitfile(url)) {
+       } else if (is_local(url) && is_file(url) && is_bundle(url, 1)) {
                struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
                ret->data = data;
                ret->get_refs_list = get_refs_from_bundle;
@@@ -1057,14 -1041,6 +1035,14 @@@ int transport_push(struct transport *tr
                        flags & TRANSPORT_PUSH_MIRROR,
                        flags & TRANSPORT_PUSH_FORCE);
  
 +              if ((flags & TRANSPORT_RECURSE_SUBMODULES_CHECK) && !is_bare_repository()) {
 +                      struct ref *ref = remote_refs;
 +                      for (; ref; ref = ref->next)
 +                              if (!is_null_sha1(ref->new_sha1) &&
 +                                  check_submodule_needs_pushing(ref->new_sha1,transport->remote->name))
 +                                      die("There are unpushed submodules, aborting.");
 +              }
 +
                push_ret = transport->push_refs(transport, remote_refs, flags);
                err = push_had_errors(remote_refs);
                ret = push_ret | err;