]> git.proxmox.com Git - libgit2.git/blob - src/worktree.c
worktree: introduce `struct git_worktree`
[libgit2.git] / src / worktree.c
1 /*
2 * Copyright (C) the libgit2 contributors. All rights reserved.
3 *
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
6 */
7
8 #include "git2/worktree.h"
9
10 #include "common.h"
11 #include "repository.h"
12 #include "worktree.h"
13
14 static bool is_worktree_dir(git_buf *dir)
15 {
16 return git_path_contains_file(dir, "commondir")
17 && git_path_contains_file(dir, "gitdir")
18 && git_path_contains_file(dir, "HEAD");
19 }
20
21 int git_worktree_list(git_strarray *wts, git_repository *repo)
22 {
23 git_vector worktrees = GIT_VECTOR_INIT;
24 git_buf path = GIT_BUF_INIT;
25 char *worktree;
26 unsigned i, len;
27 int error;
28
29 assert(wts && repo);
30
31 wts->count = 0;
32 wts->strings = NULL;
33
34 if ((error = git_buf_printf(&path, "%s/worktrees/", repo->commondir)) < 0)
35 goto exit;
36 if (!git_path_exists(path.ptr) || git_path_is_empty_dir(path.ptr))
37 goto exit;
38 if ((error = git_path_dirload(&worktrees, path.ptr, path.size, 0x0)) < 0)
39 goto exit;
40
41 len = path.size;
42
43 git_vector_foreach(&worktrees, i, worktree) {
44 git_buf_truncate(&path, len);
45 git_buf_puts(&path, worktree);
46
47 if (!is_worktree_dir(&path)) {
48 git_vector_remove(&worktrees, i);
49 git__free(worktree);
50 }
51 }
52
53 wts->strings = (char **)git_vector_detach(&wts->count, NULL, &worktrees);
54
55 exit:
56 git_buf_free(&path);
57
58 return error;
59 }
60
61 static char *read_link(const char *base, const char *file)
62 {
63 git_buf path = GIT_BUF_INIT, buf = GIT_BUF_INIT;
64
65 assert(base && file);
66
67 if (git_buf_joinpath(&path, base, file) < 0)
68 goto err;
69 if (git_futils_readbuffer(&buf, path.ptr) < 0)
70 goto err;
71 git_buf_free(&path);
72
73 git_buf_rtrim(&buf);
74
75 if (!git_path_is_relative(buf.ptr))
76 return git_buf_detach(&buf);
77
78 if (git_buf_sets(&path, base) < 0)
79 goto err;
80 if (git_path_apply_relative(&path, buf.ptr) < 0)
81 goto err;
82 git_buf_free(&buf);
83
84 return git_buf_detach(&path);
85
86 err:
87 git_buf_free(&buf);
88 git_buf_free(&path);
89
90 return NULL;
91 }
92
93 int git_worktree_lookup(git_worktree **out, git_repository *repo, const char *name)
94 {
95 git_buf path = GIT_BUF_INIT;
96 git_worktree *wt = NULL;
97 int error;
98
99 assert(repo && name);
100
101 *out = NULL;
102
103 if ((error = git_buf_printf(&path, "%s/worktrees/%s", repo->commondir, name)) < 0)
104 goto out;
105
106 if (!is_worktree_dir(&path)) {
107 error = -1;
108 goto out;
109 }
110
111 if ((wt = git__malloc(sizeof(struct git_repository))) == NULL) {
112 error = -1;
113 goto out;
114 }
115
116 if ((wt->name = git__strdup(name)) == NULL
117 || (wt->commondir_path = read_link(path.ptr, "commondir")) == NULL
118 || (wt->gitlink_path = read_link(path.ptr, "gitdir")) == NULL
119 || (wt->parent_path = git__strdup(git_repository_path(repo))) == NULL) {
120 error = -1;
121 goto out;
122 }
123 wt->gitdir_path = git_buf_detach(&path);
124
125 (*out) = wt;
126
127 out:
128 git_buf_free(&path);
129
130 if (error)
131 git_worktree_free(wt);
132
133 return error;
134 }
135
136 void git_worktree_free(git_worktree *wt)
137 {
138 if (!wt)
139 return;
140
141 git__free(wt->commondir_path);
142 git__free(wt->gitlink_path);
143 git__free(wt->gitdir_path);
144 git__free(wt->parent_path);
145 git__free(wt->name);
146 git__free(wt);
147 }