commit - 8fd174549d6af728ab316c727a527717d9fec756
commit + 86c3caaf12dbc42db6a36284eddfbbb5d243dc8f
blob - 63ff8ec7e3a9660476e5885e90590b8b63bc52bc
blob + 128e60e57bcaaebc470eebccc4ddd8948f7044d4
--- include/got_error.h
+++ include/got_error.h
#define GOT_ERR_BAD_DELTA 21
#define GOT_ERR_COMPRESSION 22
#define GOT_ERR_BAD_OBJ_ID_STR 23
+#define GOT_ERR_WORKTREE_EXISTS 26
static const struct got_error {
int code;
{ GOT_ERR_BAD_DELTA, "bad delta" },
{ GOT_ERR_COMPRESSION, "compression failed" },
{ GOT_ERR_BAD_OBJ_ID_STR,"bad object id string" },
+ { GOT_ERR_WORKTREE_EXISTS,"worktree already exists" },
};
const struct got_error * got_error(int code);
blob - e3f715f2cb0eed090fe9c7e42d360a3a6a75b4c2
blob + 9c30c84496b4423c3a5d3cb3282db636b246c4d3
--- include/got_refs.h
+++ include/got_refs.h
struct got_reference *got_ref_dup(struct got_reference *);
const struct got_error *got_ref_resolve(struct got_object_id **,
struct got_repository *, struct got_reference *);
+char *got_ref_to_str(struct got_reference *);
blob - 3ca9626ba044cf3a00cb587c9d36e9c37ee0f39e
blob + 96f1b71b451b24b056f5bb16b7cf978bfc6dc5e1
--- include/got_repository.h
+++ include/got_repository.h
const struct got_error *got_repo_open(struct got_repository**, const char *);
void got_repo_close(struct got_repository*);
+char *got_repo_get_path(struct got_repository *);
char *got_repo_get_path_git_dir(struct got_repository *);
char *got_repo_get_path_objects(struct got_repository *);
char *got_repo_get_path_objects_pack(struct got_repository *);
blob - /dev/null
blob + efcffc833f19d3b45d8b089c5ce124a3e89c9fd8 (mode 644)
--- /dev/null
+++ include/got_worktree.h
+/*
+ * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+struct got_worktree;
+
+const struct got_error *got_worktree_init(const char *, struct got_reference *,
+ struct got_repository *);
+const struct got_error *got_worktree_open(struct got_worktree **, const char *);
+void got_worktree_close(struct got_worktree *);
+char *got_worktree_get_repo_path(struct got_worktree *);
+struct got_reference *got_worktree_get_head(struct got_worktree *);
+const struct got_error *got_worktree_set_head(struct got_worktree *,
+ struct got_reference *, struct got_repository *);
+const struct got_error *got_worktree_checkout_files(struct got_worktree *,
+ struct got_repository *);
blob - 3bca95b3c18a88dff7ba4f0da9738a1e898be44b
blob + 977e6fa24ee0d199aed7f2654832d0b74fc28e31
--- lib/got_path_priv.h
+++ lib/got_path_priv.h
/* Utilities for dealing with filesystem paths. */
+#define GOT_DEFAULT_FILE_MODE (S_IRUSR|S_IWUSR | S_IRGRP | S_IROTH)
+#define GOT_DEFAULT_DIR_MODE (S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH)
+
/* Determine whether a path is an absolute path. */
int got_path_is_absolute(const char *);
blob - /dev/null
blob + 97fb6c888a7d319c81a0c1bc3f9c8158bed69ada (mode 644)
--- /dev/null
+++ lib/got_worktree_priv.h
+/*
+ * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+struct got_worktree {
+ char *path_worktree_root;
+ char *path_repo;
+};
+
+#define GOT_WORKTREE_GOT_DIR ".got"
+#define GOT_WORKTREE_FILE_INDEX "fileindex"
+#define GOT_WORKTREE_REPOSITORY "repository"
blob - 718cf6189afb20d006aa4347bc2035355ab67e9c
blob + fe5dfd7dd99058d3effb1cd88e52dc14a2767ebb
--- lib/refs.c
+++ lib/refs.c
return got_error(GOT_ERR_NO_MEM);
memcpy((*id)->sha1, ref->ref.ref.sha1, SHA1_DIGEST_LENGTH);
return NULL;
+}
+
+char *
+got_ref_to_str(struct got_reference *ref)
+{
+ char *str;
+ if (ref->flags & GOT_REF_IS_SYMBOLIC) {
+ if (asprintf(&str, "ref: %s", ref->ref.symref.ref) == -1)
+ return NULL;
+ } else {
+ str = calloc(1, SHA1_DIGEST_STRING_LENGTH);
+ if (str == NULL)
+ return NULL;
+ str = got_sha1_digest_to_str(ref->ref.ref.sha1, str,
+ SHA1_DIGEST_STRING_LENGTH);
+ }
+
+ return str;
}
blob - 9037504a410bed587331d101a6cb0a65968e356a
blob + ac7b356c73e492aea73ce81178afb0ddd399972d
--- lib/repository.c
+++ lib/repository.c
#define GOT_OBJECTS_PACK_DIR "objects/pack"
char *
+got_repo_get_path(struct got_repository *repo)
+{
+ return strdup(repo->path);
+}
+
+char *
got_repo_get_path_git_dir(struct got_repository *repo)
{
char *path_git;
blob - /dev/null
blob + 0a8cb93ba6e69957b761f1acb9c87b4aeb315c61 (mode 644)
--- /dev/null
+++ lib/worktree.c
+/*
+ * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/stat.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "got_error.h"
+#include "got_repository.h"
+#include "got_refs.h"
+#include "got_worktree.h"
+
+#include "got_worktree_priv.h"
+#include "got_path_priv.h"
+
+const struct got_error *
+got_worktree_init(const char *path, struct got_reference *head_ref,
+ struct got_repository *repo)
+{
+ const struct got_error *err = NULL;
+ char *abspath = NULL;
+ char *normpath = NULL;
+ char *gotpath = NULL;
+ char *indexpath = NULL;
+ char *headpath = NULL;
+ char *repopath = NULL;
+ char *refstr = NULL;
+ char *path_repos = NULL;
+ char buf[4];
+ ssize_t n;
+ int fd;
+
+ if (got_path_is_absolute(path)) {
+ abspath = strdup(path);
+ if (abspath == NULL)
+ return got_error(GOT_ERR_NO_MEM);
+ } else {
+ abspath = got_path_get_absolute(path);
+ if (abspath == NULL)
+ return got_error(GOT_ERR_BAD_PATH);
+ }
+
+ /* Create top-level directory (may already exist). */
+ normpath = got_path_normalize(abspath);
+ if (normpath == NULL) {
+ err = got_error(GOT_ERR_BAD_PATH);
+ goto done;
+ }
+ if (mkdir(normpath, GOT_DEFAULT_DIR_MODE) == -1 && errno != EEXIST) {
+ err = got_error_from_errno();
+ goto done;
+ }
+
+ /* Create .got directory (may already exist). */
+ if (asprintf(&gotpath, "%s/%s", normpath, GOT_WORKTREE_GOT_DIR) == -1) {
+ err = got_error(GOT_ERR_NO_MEM);
+ goto done;
+ }
+ if (mkdir(gotpath, GOT_DEFAULT_DIR_MODE) == -1 && errno != EEXIST) {
+ err = got_error_from_errno();
+ goto done;
+ }
+
+ /* Create an empty file index. */
+ if (asprintf(&indexpath, "%s/%s", gotpath, GOT_WORKTREE_FILE_INDEX)
+ == -1) {
+ err = got_error(GOT_ERR_NO_MEM);
+ goto done;
+ }
+ fd = open(indexpath, O_RDWR | O_CREAT | O_EXCL | O_EXLOCK | O_NOFOLLOW,
+ GOT_DEFAULT_FILE_MODE);
+ if (fd == -1) {
+ err = got_error_from_errno();
+ goto done;
+ }
+ n = read(fd, buf, sizeof(buf));
+ if (n != 0) {
+ err = (n == -1 ? got_error_from_errno() :
+ got_error(GOT_ERR_WORKTREE_EXISTS));
+ close(fd);
+ goto done;
+ }
+ if (close(fd) == -1) {
+ err = got_error_from_errno();
+ goto done;
+ }
+
+ /* Write the HEAD reference. */
+ refstr = got_ref_to_str(head_ref);
+ if (refstr == NULL) {
+ err = got_error(GOT_ERR_NO_MEM);
+ goto done;
+ }
+ if (asprintf(&headpath, "%s/%s", gotpath, GOT_REF_HEAD) == -1) {
+ err = got_error(GOT_ERR_NO_MEM);
+ goto done;
+ }
+ fd = open(headpath, O_RDWR | O_CREAT | O_EXCL | O_EXLOCK | O_NOFOLLOW,
+ GOT_DEFAULT_FILE_MODE);
+ if (fd == -1) {
+ err = got_error_from_errno();
+ goto done;
+ }
+ n = read(fd, buf, sizeof(buf));
+ if (n != 0) {
+ err = (n == -1 ? got_error_from_errno() :
+ got_error(GOT_ERR_WORKTREE_EXISTS));
+ close(fd);
+ goto done;
+ }
+ n = write(fd, refstr, strlen(refstr));
+ if (n != strlen(refstr)) {
+ err = got_error_from_errno();
+ close(fd);
+ goto done;
+ }
+ n = write(fd, "\n", 1);
+ if (n != 1) {
+ err = got_error_from_errno();
+ close(fd);
+ goto done;
+ }
+ if (close(fd) == -1) {
+ err = got_error_from_errno();
+ goto done;
+ }
+
+ /* Store path to repository. */
+ if (asprintf(&repopath, "%s/%s", gotpath, GOT_WORKTREE_REPOSITORY) == -1) {
+ err = got_error(GOT_ERR_NO_MEM);
+ goto done;
+ }
+ fd = open(repopath, O_RDWR | O_CREAT | O_EXCL | O_EXLOCK | O_NOFOLLOW,
+ GOT_DEFAULT_FILE_MODE);
+ if (fd == -1) {
+ err = got_error_from_errno();
+ goto done;
+ }
+ n = read(fd, buf, sizeof(buf));
+ if (n != 0) {
+ err = (n == -1 ? got_error_from_errno() :
+ got_error(GOT_ERR_WORKTREE_EXISTS));
+ close(fd);
+ goto done;
+ }
+ path_repos = got_repo_get_path(repo);
+ if (path_repos == NULL) {
+ err = got_error(GOT_ERR_NO_MEM);
+ goto done;
+ }
+ n = write(fd, path_repos, strlen(path_repos));
+ if (n != strlen(path_repos)) {
+ err = got_error_from_errno();
+ close(fd);
+ goto done;
+ }
+ n = write(fd, "\n", 1);
+ if (n != 1) {
+ err = got_error_from_errno();
+ close(fd);
+ goto done;
+ }
+ if (close(fd) == -1) {
+ err = got_error_from_errno();
+ goto done;
+ }
+
+done:
+ free(abspath);
+ free(normpath);
+ free(gotpath);
+ free(indexpath);
+ free(headpath);
+ free(repopath);
+ free(refstr);
+ free(path_repos);
+ return err;
+}
+
+const struct got_error *
+got_worktree_open(struct got_worktree **worktree, const char *path)
+{
+ return NULL;
+}
+
+void
+got_worktree_close(struct got_worktree *worktree)
+{
+}
+
+char *
+got_worktree_get_repo_path(struct got_worktree *worktree)
+{
+ return strdup(worktree->path_repo);
+}
+
+struct got_reference *
+got_worktree_get_head(struct got_worktree *worktree)
+{
+ return NULL;
+}
+
+const struct got_error *
+got_worktree_set_head(struct got_worktree *worktree, struct got_reference *head,
+ struct got_repository *repo)
+{
+ return NULL;
+}
+
+const struct got_error *
+got_worktree_checkout_files(struct got_worktree *worktree,
+ struct got_repository *repo)
+{
+ return NULL;
+}
blob - /dev/null
blob + e10b20fba2f9e06be8895d91675f8fc91f3ff522 (mode 644)
--- /dev/null
+++ regress/worktree/Makefile
+.PATH:${.CURDIR}/../../lib
+
+PROG = worktree_test
+SRCS = worktree.c repository.c object.c path.c error.c refs.c sha1.c pack.c \
+ delta.c zb.c worktree_test.c
+
+CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib
+LDADD = -lutil -lz
+DEBUG = -O0 -g
+CFLAGS += -Werror
+
+NOMAN = yes
+
+.include <bsd.regress.mk>
blob - /dev/null
blob + 252f9c9aa2f1eac333b88865699f7a17ad70aae3 (mode 644)
--- /dev/null
+++ regress/worktree/worktree_test.c
+/*
+ * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/limits.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "got_error.h"
+#include "got_object.h"
+#include "got_refs.h"
+#include "got_repository.h"
+#include "got_worktree.h"
+
+#include "got_worktree_priv.h"
+
+#define GOT_REPO_PATH "../../../"
+
+static int verbose;
+
+void
+test_printf(char *fmt, ...)
+{
+ va_list ap;
+
+ if (!verbose)
+ return;
+
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+}
+
+static int
+check_meta_file_exists(const char *worktree_path, const char *name)
+{
+ FILE *f;
+ char *path;
+
+ if (asprintf(&path, "%s/%s/%s", worktree_path, GOT_WORKTREE_GOT_DIR,
+ name) == -1)
+ return 0;
+ f = fopen(path, "r");
+ if (f == NULL)
+ return 0;
+ fclose(f);
+ return 1;
+}
+
+static int
+worktree_init(const char *repo_path)
+{
+ const struct got_error *err;
+ struct got_repository *repo = NULL;
+ struct got_reference *head_ref = NULL;
+ char worktree_path[PATH_MAX];
+ int ok = 0;
+
+ err = got_repo_open(&repo, repo_path);
+ if (err != NULL || repo == NULL)
+ goto done;
+ err = got_ref_open(&head_ref, repo, GOT_REF_HEAD);
+ if (err != NULL || head_ref == NULL)
+ goto done;
+
+ strlcpy(worktree_path, "worktree-XXXXXX", sizeof(worktree_path));
+ if (mkdtemp(worktree_path) == NULL)
+ goto done;
+
+ err = got_worktree_init(worktree_path, head_ref, repo);
+ if (err != NULL)
+ goto done;
+
+ /* Ensure required files were created. */
+ if (!check_meta_file_exists(worktree_path, GOT_REF_HEAD))
+ goto done;
+ if (!check_meta_file_exists(worktree_path, GOT_WORKTREE_FILE_INDEX))
+ goto done;
+ if (!check_meta_file_exists(worktree_path, GOT_WORKTREE_REPOSITORY))
+ goto done;
+ ok = 1;
+done:
+ if (head_ref)
+ got_ref_close(head_ref);
+ if (repo)
+ got_repo_close(repo);
+ return ok;
+}
+
+#define RUN_TEST(expr, name) \
+ { test_ok = (expr); \
+ printf("test %s %s\n", (name), test_ok ? "ok" : "failed"); \
+ failure = (failure || !test_ok); }
+
+
+void
+usage(void)
+{
+ fprintf(stderr, "usage: worktree_test [-v] [REPO_PATH]\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+ int test_ok = 0, failure = 0;
+ const char *repo_path;
+ int ch;
+ int vflag = 0;
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ usage();
+ return 1;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ repo_path = GOT_REPO_PATH;
+ else if (argc == 1)
+ repo_path = argv[0];
+ else {
+ usage();
+ return 1;
+ }
+
+ RUN_TEST(worktree_init(repo_path), "init");
+
+ return failure ? 1 : 0;
+}