Make fiel checkout function available to the git library
authorLinus Torvalds <torvalds@ppc970.osdl.org>
Mon, 6 Jun 2005 04:59:54 +0000 (21:59 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Mon, 6 Jun 2005 04:59:54 +0000 (21:59 -0700)
The merge stuff will want it soon, and we don't want to
duplicate all the work..

Makefile
cache.h
checkout-cache.c
entry.c [new file with mode: 0644]

index fff5a6a..d0f1cfa 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -40,7 +40,7 @@ install: $(PROG) $(SCRIPTS)
        $(INSTALL) $(PROG) $(SCRIPTS) $(dest)$(bin)
 
 LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o \
-        tag.o delta.o date.o index.o diff-delta.o patch-delta.o
+        tag.o delta.o date.o index.o diff-delta.o patch-delta.o entry.o
 LIB_FILE=libgit.a
 LIB_H=cache.h object.h blob.h tree.h commit.h tag.h delta.h
 
diff --git a/cache.h b/cache.h
index 481f7c7..7cb5b55 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -214,4 +214,15 @@ static inline void *xcalloc(size_t nmemb, size_t size)
        return ret;
 }
 
+struct checkout {
+       const char *base_dir;
+       int base_dir_len;
+       unsigned force:1,
+                quiet:1,
+                not_new:1,
+                refresh_cache:1;
+};
+
+extern int checkout_entry(struct cache_entry *ce, struct checkout *state);
+
 #endif /* CACHE_H */
index 9d09c39..82ddbe4 100644 (file)
  * of "-a" causing problems (not possible in the above example,
  * but get used to it in scripting!).
  */
-#include <sys/types.h>
-#include <dirent.h>
 #include "cache.h"
 
-static int force = 0, quiet = 0, not_new = 0, refresh_cache = 0;
-static const char *base_dir = "";
-static int base_dir_len = 0;
-
-static void create_directories(const char *path)
-{
-       int len = strlen(path);
-       char *buf = xmalloc(len + 1);
-       const char *slash = path;
-
-       while ((slash = strchr(slash+1, '/')) != NULL) {
-               len = slash - path;
-               memcpy(buf, path, len);
-               buf[len] = 0;
-               if (mkdir(buf, 0755)) {
-                       if (errno == EEXIST) {
-                               struct stat st;
-                               if (len > base_dir_len && force && !unlink(buf) && !mkdir(buf, 0755))
-                                       continue;
-                               if (!stat(buf, &st) && S_ISDIR(st.st_mode))
-                                       continue; /* ok */
-                       }
-                       die("cannot create directory at %s", buf);
-               }
-       }
-       free(buf);
-}
-
-static void remove_subtree(const char *path)
-{
-       DIR *dir = opendir(path);
-       struct dirent *de;
-       char pathbuf[PATH_MAX];
-       char *name;
-       
-       if (!dir)
-               die("cannot opendir %s", path);
-       strcpy(pathbuf, path);
-       name = pathbuf + strlen(path);
-       *name++ = '/';
-       while ((de = readdir(dir)) != NULL) {
-               struct stat st;
-               if ((de->d_name[0] == '.') &&
-                   ((de->d_name[1] == 0) ||
-                    ((de->d_name[1] == '.') && de->d_name[2] == 0)))
-                       continue;
-               strcpy(name, de->d_name);
-               if (lstat(pathbuf, &st))
-                       die("cannot lstat %s", pathbuf);
-               if (S_ISDIR(st.st_mode))
-                       remove_subtree(pathbuf);
-               else if (unlink(pathbuf))
-                       die("cannot unlink %s", pathbuf);
-       }
-       closedir(dir);
-       if (rmdir(path))
-               die("cannot rmdir %s", path);
-}
-
-static int create_file(const char *path, unsigned int mode)
-{
-       int fd;
-
-       mode = (mode & 0100) ? 0777 : 0666;
-       create_directories(path);
-       fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
-       if (fd < 0) {
-               if (errno == EISDIR && force) {
-                       remove_subtree(path);
-                       fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
-               }
-       }
-       return fd;
-}
-
-static int write_entry(struct cache_entry *ce, const char *path)
-{
-       int fd;
-       void *new;
-       unsigned long size;
-       long wrote;
-       char type[20];
-       char target[1024];
-
-       new = read_sha1_file(ce->sha1, type, &size);
-       if (!new || strcmp(type, "blob")) {
-               if (new)
-                       free(new);
-               return error("git-checkout-cache: unable to read sha1 file of %s (%s)",
-                       path, sha1_to_hex(ce->sha1));
-       }
-       switch (ntohl(ce->ce_mode) & S_IFMT) {
-       case S_IFREG:
-               fd = create_file(path, ntohl(ce->ce_mode));
-               if (fd < 0) {
-                       free(new);
-                       return error("git-checkout-cache: unable to create file %s (%s)",
-                               path, strerror(errno));
-               }
-               wrote = write(fd, new, size);
-               close(fd);
-               free(new);
-               if (wrote != size)
-                       return error("git-checkout-cache: unable to write file %s", path);
-               break;
-       case S_IFLNK:
-               memcpy(target, new, size);
-               target[size] = '\0';
-               create_directories(path);
-               if (symlink(target, path)) {
-                       free(new);
-                       return error("git-checkout-cache: unable to create symlink %s (%s)",
-                               path, strerror(errno));
-               }
-               free(new);
-               break;
-       default:
-               free(new);
-               return error("git-checkout-cache: unknown file mode for %s", path);
-       }
-
-       if (refresh_cache) {
-               struct stat st;
-               lstat(ce->name, &st);
-               fill_stat_cache_info(ce, &st);
-       }
-       return 0;
-}
-
-static int checkout_entry(struct cache_entry *ce)
-{
-       struct stat st;
-       static char path[MAXPATHLEN+1];
-       int len = base_dir_len;
-
-       memcpy(path, base_dir, len);
-       strcpy(path + len, ce->name);
-
-       if (!lstat(path, &st)) {
-               unsigned changed = ce_match_stat(ce, &st);
-               if (!changed)
-                       return 0;
-               if (!force) {
-                       if (!quiet)
-                               fprintf(stderr, "git-checkout-cache: %s already exists\n", path);
-                       return 0;
-               }
-
-               /*
-                * We unlink the old file, to get the new one with the
-                * right permissions (including umask, which is nasty
-                * to emulate by hand - much easier to let the system
-                * just do the right thing)
-                */
-               unlink(path);
-       } else if (not_new) 
-               return 0;
-       return write_entry(ce, path);
-}
+static struct checkout state = {
+       .base_dir = "",
+       .base_dir_len = 0,
+       .force = 0,
+       .quiet = 0,
+       .not_new = 0,
+       .refresh_cache = 0,
+};
 
 static int checkout_file(const char *name)
 {
        int pos = cache_name_pos(name, strlen(name));
        if (pos < 0) {
-               if (!quiet) {
+               if (!state.quiet) {
                        pos = -pos - 1;
                        fprintf(stderr,
                                "git-checkout-cache: %s is %s.\n",
@@ -211,7 +58,7 @@ static int checkout_file(const char *name)
                }
                return -1;
        }
-       return checkout_entry(active_cache[pos]);
+       return checkout_entry(active_cache[pos], &state);
 }
 
 static int checkout_all(void)
@@ -222,7 +69,7 @@ static int checkout_all(void)
                struct cache_entry *ce = active_cache[i];
                if (ce_stage(ce))
                        continue;
-               if (checkout_entry(ce) < 0)
+               if (checkout_entry(ce, &state) < 0)
                        return -1;
        }
        return 0;
@@ -250,19 +97,19 @@ int main(int argc, char **argv)
                                continue;
                        }
                        if (!strcmp(arg, "-f")) {
-                               force = 1;
+                               state.force = 1;
                                continue;
                        }
                        if (!strcmp(arg, "-q")) {
-                               quiet = 1;
+                               state.quiet = 1;
                                continue;
                        }
                        if (!strcmp(arg, "-n")) {
-                               not_new = 1;
+                               state.not_new = 1;
                                continue;
                        }
                        if (!strcmp(arg, "-u")) {
-                               refresh_cache = 1;
+                               state.refresh_cache = 1;
                                if (newfd < 0)
                                        newfd = hold_index_file_for_update
                                                (&cache_file,
@@ -272,20 +119,20 @@ int main(int argc, char **argv)
                                continue;
                        }
                        if (!memcmp(arg, "--prefix=", 9)) {
-                               base_dir = arg+9;
-                               base_dir_len = strlen(base_dir);
+                               state.base_dir = arg+9;
+                               state.base_dir_len = strlen(state.base_dir);
                                continue;
                        }
                }
-               if (base_dir_len) {
+               if (state.base_dir_len) {
                        /* when --prefix is specified we do not
                         * want to update cache.
                         */
-                       if (refresh_cache) {
+                       if (state.refresh_cache) {
                                close(newfd); newfd = -1;
                                rollback_index_file(&cache_file);
                        }
-                       refresh_cache = 0;
+                       state.refresh_cache = 0;
                }
                checkout_file(arg);
        }
diff --git a/entry.c b/entry.c
new file mode 100644 (file)
index 0000000..d7824c4
--- /dev/null
+++ b/entry.c
@@ -0,0 +1,160 @@
+#include <sys/types.h>
+#include <dirent.h>
+#include "cache.h"
+
+static void create_directories(const char *path, struct checkout *state)
+{
+       int len = strlen(path);
+       char *buf = xmalloc(len + 1);
+       const char *slash = path;
+
+       while ((slash = strchr(slash+1, '/')) != NULL) {
+               len = slash - path;
+               memcpy(buf, path, len);
+               buf[len] = 0;
+               if (mkdir(buf, 0755)) {
+                       if (errno == EEXIST) {
+                               struct stat st;
+                               if (len > state->base_dir_len && state->force && !unlink(buf) && !mkdir(buf, 0755))
+                                       continue;
+                               if (!stat(buf, &st) && S_ISDIR(st.st_mode))
+                                       continue; /* ok */
+                       }
+                       die("cannot create directory at %s", buf);
+               }
+       }
+       free(buf);
+}
+
+static void remove_subtree(const char *path)
+{
+       DIR *dir = opendir(path);
+       struct dirent *de;
+       char pathbuf[PATH_MAX];
+       char *name;
+       
+       if (!dir)
+               die("cannot opendir %s", path);
+       strcpy(pathbuf, path);
+       name = pathbuf + strlen(path);
+       *name++ = '/';
+       while ((de = readdir(dir)) != NULL) {
+               struct stat st;
+               if ((de->d_name[0] == '.') &&
+                   ((de->d_name[1] == 0) ||
+                    ((de->d_name[1] == '.') && de->d_name[2] == 0)))
+                       continue;
+               strcpy(name, de->d_name);
+               if (lstat(pathbuf, &st))
+                       die("cannot lstat %s", pathbuf);
+               if (S_ISDIR(st.st_mode))
+                       remove_subtree(pathbuf);
+               else if (unlink(pathbuf))
+                       die("cannot unlink %s", pathbuf);
+       }
+       closedir(dir);
+       if (rmdir(path))
+               die("cannot rmdir %s", path);
+}
+
+static int create_file(const char *path, unsigned int mode, int force)
+{
+       int fd;
+
+       mode = (mode & 0100) ? 0777 : 0666;
+       fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
+       if (fd < 0) {
+               if (errno == EISDIR && force) {
+                       remove_subtree(path);
+                       fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
+               }
+       }
+       return fd;
+}
+
+static int write_entry(struct cache_entry *ce, const char *path, struct checkout *state)
+{
+       int fd;
+       void *new;
+       unsigned long size;
+       long wrote;
+       char type[20];
+       char target[1024];
+
+       new = read_sha1_file(ce->sha1, type, &size);
+       if (!new || strcmp(type, "blob")) {
+               if (new)
+                       free(new);
+               return error("git-checkout-cache: unable to read sha1 file of %s (%s)",
+                       path, sha1_to_hex(ce->sha1));
+       }
+       switch (ntohl(ce->ce_mode) & S_IFMT) {
+       case S_IFREG:
+               fd = create_file(path, ntohl(ce->ce_mode), state->force);
+               if (fd < 0) {
+                       free(new);
+                       return error("git-checkout-cache: unable to create file %s (%s)",
+                               path, strerror(errno));
+               }
+               wrote = write(fd, new, size);
+               close(fd);
+               free(new);
+               if (wrote != size)
+                       return error("git-checkout-cache: unable to write file %s", path);
+               break;
+       case S_IFLNK:
+               memcpy(target, new, size);
+               target[size] = '\0';
+               if (symlink(target, path)) {
+                       free(new);
+                       return error("git-checkout-cache: unable to create symlink %s (%s)",
+                               path, strerror(errno));
+               }
+               free(new);
+               break;
+       default:
+               free(new);
+               return error("git-checkout-cache: unknown file mode for %s", path);
+       }
+
+       if (state->update) {
+               struct stat st;
+               lstat(ce->name, &st);
+               fill_stat_cache_info(ce, &st);
+       }
+       return 0;
+}
+
+int checkout_entry(struct cache_entry *ce, struct checkout *state)
+{
+       struct stat st;
+       static char path[MAXPATHLEN+1];
+       int len = state->base_dir_len;
+
+       memcpy(path, state->base_dir, len);
+       strcpy(path + len, ce->name);
+
+       if (!lstat(path, &st)) {
+               unsigned changed = ce_match_stat(ce, &st);
+               if (!changed)
+                       return 0;
+               if (!state->force) {
+                       if (!state->quiet)
+                               fprintf(stderr, "git-checkout-cache: %s already exists\n", path);
+                       return 0;
+               }
+
+               /*
+                * We unlink the old file, to get the new one with the
+                * right permissions (including umask, which is nasty
+                * to emulate by hand - much easier to let the system
+                * just do the right thing)
+                */
+               unlink(path);
+       } else if (state->not_new) 
+               return 0;
+       create_directories(path, state);
+       return write_entry(ce, path, state);
+}
+
+