SlHelpers
Repo.h
1 // SPDX-License-Identifier: GPL-2.0-only
2 
3 #pragma once
4 
5 #include <filesystem>
6 #include <optional>
7 #include <string>
8 #include <variant>
9 #include <vector>
10 
11 #include <git2.h>
12 
13 #include "../helpers/LastError.h"
14 #include "../helpers/Unique.h"
15 
16 #include "DefaultFetchCallbacks.h"
17 
18 namespace SlGit {
19 
20 class Blob;
21 class Commit;
22 class Diff;
23 class Index;
24 class Object;
25 class Reference;
26 class Remote;
27 class RevWalk;
28 class Signature;
29 class Tag;
30 class Tree;
31 class TreeBuilder;
32 class TreeEntry;
33 
45 class Repo {
46  using GitTy = git_repository;
48 public:
49  Repo() = delete;
50 
60  static std::optional<Repo> init(const std::filesystem::path &path, bool bare = false,
61  const std::string &originUrl = "") noexcept;
62 
75  static std::optional<Repo> clone(const std::filesystem::path &path, const std::string &url,
76  FetchCallbacks &fc,
77  const std::string &branch = "",
78  const unsigned int &depth = 0,
79  bool tags = true) noexcept;
91  static std::optional<Repo> clone(const std::filesystem::path &path, const std::string &url,
92  const std::string &branch = "",
93  const unsigned int &depth = 0,
94  bool tags = true) noexcept {
96  return clone(path, url, fc, branch, depth, tags);
97  }
98 
104  static std::optional<Repo> open(const std::filesystem::path &path = ".") noexcept;
105 
114  static bool update(const std::filesystem::path &path, const std::string &remote = "origin");
115 
117  bool checkout(const std::string &branch) const noexcept;
119  bool checkout(const Reference &reference) const noexcept;
121  bool checkoutTree(const Tree &tree, unsigned int strategy = GIT_CHECKOUT_SAFE) const noexcept;
130  std::optional<std::string> catFile(const std::string &branch,
131  const std::string &file) const noexcept;
132 
134  std::variant<Blob, Commit, Tag, Tree, std::monostate>
135  revparseSingle(const std::string &rev) const noexcept;
136 
138  std::optional<Blob> blobCreateFromWorkDir(const std::filesystem::path &file) const noexcept;
140  std::optional<Blob> blobCreateFromDisk(const std::filesystem::path &file) const noexcept;
142  std::optional<Blob> blobCreateFromBuffer(const std::string &buf) const noexcept;
144  std::optional<Blob> blobLookup(const git_oid &oid) const noexcept;
146  std::optional<Blob> blobLookup(const TreeEntry &tentry) const noexcept;
148  std::optional<Blob> blobRevparseSingle(const std::string &rev) const noexcept;
149 
151  std::optional<Commit> commitLookup(const git_oid &oid) const noexcept;
153  std::optional<Commit> commitCreate(const Signature &author, const Signature &committer,
154  const std::string &msg, const Tree &tree,
155  const std::vector<const Commit *> &parents = {}) const noexcept;
157  std::optional<Commit> commitCreateCheckout(const Signature &author,
158  const Signature &committer,
159  const std::string &msg, const Tree &tree,
160  unsigned int strategy = GIT_CHECKOUT_SAFE,
161  const std::vector<const Commit *> &parents = {}) const noexcept;
163  std::optional<Commit> commitHead() const noexcept;
165  std::optional<Commit> commitRevparseSingle(const std::string &rev) const noexcept;
166 
169  std::optional<Diff> diff(const Commit &commit1, const Commit &commit2,
170  const git_diff_options *opts = nullptr) const noexcept;
173  std::optional<Diff> diff(const Tree &tree1, const Tree &tree2,
174  const git_diff_options *opts = nullptr) const noexcept;
177  std::optional<Diff> diffCached(const Commit &commit, const Index &index,
178  const git_diff_options *opts = nullptr) const noexcept;
181  std::optional<Diff> diffCached(const Tree &tree, const Index &index,
182  const git_diff_options *opts = nullptr) const noexcept;
184  std::optional<Diff> diffCached(const Commit &commit,
185  const git_diff_options *opts = nullptr) const noexcept;
187  std::optional<Diff> diffCached(const Tree &tree,
188  const git_diff_options *opts = nullptr) const noexcept;
191  std::optional<Diff> diffWorkdir(const Index &index,
192  const git_diff_options *opts = nullptr) const noexcept;
194  std::optional<Diff> diffWorkdir(const Commit &commit,
195  const git_diff_options *opts = nullptr) const noexcept;
197  std::optional<Diff> diffWorkdir(const Tree &tree,
198  const git_diff_options *opts = nullptr) const noexcept;
199 
201  std::optional<Index> index() const noexcept;
202 
204  std::optional<Remote> remoteCreate(const std::string &name,
205  const std::string &url) const noexcept;
207  std::optional<Remote> remoteLookup(const std::string &name) const noexcept;
208 
210  std::optional<Reference> refLookup(const std::string &name) const noexcept;
212  std::optional<Reference> refDWIM(const std::string &name) const noexcept;
213 
215  std::optional<Reference> refCreateDirect(const std::string &name, const git_oid &oid,
216  bool force = false) const noexcept;
218  std::optional<Reference> refCreateSymbolic(const std::string &name,
219  const std::string &target,
220  bool force = false) const noexcept;
221 
223  std::optional<RevWalk> revWalkCreate() const noexcept;
224 
226  std::optional<Tag> tagCreate(const std::string &tagName, const Object &target,
227  const Signature &tagger, const std::string &message,
228  bool force = false) const noexcept;
230  std::optional<Tag> tagLookup(const git_oid &oid) const noexcept;
232  std::optional<Tag> tagLookup(const TreeEntry &tentry) const noexcept;
234  std::optional<Tag> tagRevparseSingle(const std::string &rev) const noexcept;
235 
237  std::optional<Tree> treeLookup(const git_oid &oid) const noexcept;
239  std::optional<Tree> treeLookup(const TreeEntry &tentry) const noexcept;
241  std::optional<Tree> treeRevparseSingle(const std::string &rev) const noexcept;
242 
244  std::optional<TreeBuilder> treeBuilderCreate(const Tree *source = nullptr) const noexcept;
245 
247  std::filesystem::path path() const noexcept { return git_repository_path(repo()); }
249  std::filesystem::path workDir() const noexcept { return git_repository_workdir(repo()); }
250 
252  static auto &lastError() noexcept { return m_lastError.lastError(); }
254  static auto lastClass() noexcept { return m_lastError.get<0>(); }
256  static auto lastErrno() noexcept { return m_lastError.get<1>(); }
257 
259  GitTy *repo() const noexcept { return m_repo.get(); }
261  operator GitTy *() const noexcept { return repo(); }
262 private:
263  explicit Repo(GitTy *repo) noexcept : m_repo(repo) {}
264 
265  friend class Diff;
266  friend class Index;
267  friend class PathSpec;
268  friend class Remote;
269  friend class RevWalk;
270  friend class Signature;
271  friend class Tag;
272  friend class Tree;
273  friend class TreeBuilder;
274 
275  static std::pair<std::string, int> lastGitError() noexcept;
276 
277  static int setLastError(int ret) {
278  if (ret) {
279  auto le = lastGitError();
280  m_lastError.reset().setError(std::move(le.first));
281  m_lastError.set<0>(le.second);
282  m_lastError.set<1>(ret);
283  }
284 
285  return ret;
286  }
287 
288  template<class Class, typename FunTy, typename... Args>
289  static std::optional<Class> MakeGit(const FunTy &fun, Args&&... args)
290  {
291  typename Class::GitTy *gitEntry;
292  if (setLastError(fun(&gitEntry, std::forward<Args>(args)...)))
293  return std::nullopt;
294  return Class(gitEntry);
295  }
296 
297  template<class Class, typename FunTy, typename... Args>
298  static std::optional<Class> MakeGitRepo(const Repo &repo, const FunTy &fun, Args&&... args)
299  {
300  typename Class::GitTy *gitEntry;
301  if (setLastError(fun(&gitEntry, std::forward<Args>(args)...)))
302  return std::nullopt;
303  return Class(repo, gitEntry);
304  }
305 
306  static void checkoutProgress(const char *path, size_t completed_steps, size_t total_steps,
307  void *payload);
308 
309  Holder m_repo;
310  static thread_local SlHelpers::LastErrorStr<int, int> m_lastError;
311 };
312 
313 }
static std::optional< Repo > clone(const std::filesystem::path &path, const std::string &url, FetchCallbacks &fc, const std::string &branch="", const unsigned int &depth=0, bool tags=true) noexcept
clone Clone (and open) an existing repository
Definition: Blob.h:11
static std::optional< Repo > clone(const std::filesystem::path &path, const std::string &url, const std::string &branch="", const unsigned int &depth=0, bool tags=true) noexcept
clone Clone (and open) an existing repository
Definition: Repo.h:91
std::optional< Tree > treeLookup(const git_oid &oid) const noexcept
Get a Tree corresponding to oid.
std::filesystem::path workDir() const noexcept
Get the path to sources.
Definition: Repo.h:249
std::optional< Remote > remoteCreate(const std::string &name, const std::string &url) const noexcept
Create a new Remote called name located at url.
std::optional< Blob > blobLookup(const git_oid &oid) const noexcept
Get a Blob corresponding to oid.
bool checkoutTree(const Tree &tree, unsigned int strategy=GIT_CHECKOUT_SAFE) const noexcept
Update index and files to match tree.
std::optional< Blob > blobRevparseSingle(const std::string &rev) const noexcept
Parse rev as blob.
std::tuple_element_t< idx, Tuple > & get() noexcept
Get n-th error member.
Definition: LastError.h:22
std::optional< Commit > commitRevparseSingle(const std::string &rev) const noexcept
Parse rev as commit.
std::optional< Commit > commitHead() const noexcept
Get a Commit corresponding to HEAD.
static std::optional< Repo > open(const std::filesystem::path &path=".") noexcept
Open an existing repository.
std::optional< Commit > commitLookup(const git_oid &oid) const noexcept
Get a Commit corresponding to oid.
const std::string & lastError() const &noexcept
Obtain the stored string.
Definition: LastError.h:75
std::optional< Commit > commitCreateCheckout(const Signature &author, const Signature &committer, const std::string &msg, const Tree &tree, unsigned int strategy=GIT_CHECKOUT_SAFE, const std::vector< const Commit *> &parents={}) const noexcept
Create a new Commit and move to it.
std::optional< Reference > refCreateSymbolic(const std::string &name, const std::string &target, bool force=false) const noexcept
Create a new symbolic Reference to target called name.
The most important Git class.
Definition: Repo.h:45
static bool update(const std::filesystem::path &path, const std::string &remote="origin")
Update/fetch remote remote in repository at path.
Commit is a representation of a git commit.
Definition: Commit.h:21
std::optional< Tag > tagLookup(const git_oid &oid) const noexcept
Get a Tag corresponding to oid.
std::optional< Reference > refLookup(const std::string &name) const noexcept
Get a Reference called exactly name (like refs/heads/master)
std::optional< Blob > blobCreateFromWorkDir(const std::filesystem::path &file) const noexcept
Create a new Blob from file in workdir.
Blob is a representation of a git blob.
Definition: Blob.h:16
std::optional< TreeBuilder > treeBuilderCreate(const Tree *source=nullptr) const noexcept
Create a new TreeBuilder.
std::optional< Diff > diff(const Commit &commit1, const Commit &commit2, const git_diff_options *opts=nullptr) const noexcept
Create a new Diff of commit1 and commit2.
static auto & lastError() noexcept
Return the last error string if some (from git_last_error())
Definition: Repo.h:252
static std::optional< Repo > init(const std::filesystem::path &path, bool bare=false, const std::string &originUrl="") noexcept
init Init an empty repository
Tree is a representation of a git tree.
Definition: Tree.h:27
GitTy * repo() const noexcept
Get the underlying libgit2 pointer.
Definition: Repo.h:259
std::optional< Blob > blobCreateFromBuffer(const std::string &buf) const noexcept
Create a new Blob from string buf.
std::optional< Tag > tagCreate(const std::string &tagName, const Object &target, const Signature &tagger, const std::string &message, bool force=false) const noexcept
Create a new Tag called tagName, pointing at target.
std::optional< std::string > catFile(const std::string &branch, const std::string &file) const noexcept
Cat a file in a branch.
std::optional< Reference > refDWIM(const std::string &name) const noexcept
Get a Reference called name (like master)
std::optional< Remote > remoteLookup(const std::string &name) const noexcept
Get a Remote called name.
std::optional< Commit > commitCreate(const Signature &author, const Signature &committer, const std::string &msg, const Tree &tree, const std::vector< const Commit *> &parents={}) const noexcept
Create a new Commit.
std::optional< Reference > refCreateDirect(const std::string &name, const git_oid &oid, bool force=false) const noexcept
Create a new direct Reference to oid called name.
Callbacks invoked from Repo::clone() or Remote::fetchRefspecs()
Definition: FetchCallbacks.h:17
std::optional< Tag > tagRevparseSingle(const std::string &rev) const noexcept
Parse rev as tag.
The TreeEntry represents one git tree entry.
Definition: Tree.h:107
std::optional< Index > index() const noexcept
Get repository&#39;s index.
bool checkout(const std::string &branch) const noexcept
Checkout a branch.
static auto lastClass() noexcept
Return the last error class (from git_last_error())
Definition: Repo.h:254
std::optional< Diff > diffWorkdir(const Index &index, const git_diff_options *opts=nullptr) const noexcept
Create a new Diff of an index and workdir.
Tag is a representation of a git tag.
Definition: Tag.h:23
void set(Arg &&val) noexcept
Set n-th error member.
Definition: LastError.h:34
std::optional< Diff > diffCached(const Commit &commit, const Index &index, const git_diff_options *opts=nullptr) const noexcept
Create a new Diff of a commit and index.
std::variant< Blob, Commit, Tag, Tree, std::monostate > revparseSingle(const std::string &rev) const noexcept
Parse rev as either blob, commit, tag, or tree.
Reference is a representation of a git reference.
Definition: Misc.h:18
The default FetchCallbacks implementation.
Definition: DefaultFetchCallbacks.h:15
static auto lastErrno() noexcept
Return the last error number (returned from git_* functions)
Definition: Repo.h:256
LastErrorStr & reset() noexcept
Wipe out everything.
Definition: LastError.h:55
Signature is a representation of a git signature.
Definition: Misc.h:120
void setError(T &&str) requires(std
Store a string into this error.
Definition: LastError.h:66
std::optional< RevWalk > revWalkCreate() const noexcept
Create a new RevWalk.
std::optional< Blob > blobCreateFromDisk(const std::filesystem::path &file) const noexcept
Create a new Blob from file.
std::optional< Tree > treeRevparseSingle(const std::string &rev) const noexcept
Parse rev as tree.
std::filesystem::path path() const noexcept
Get the path to .git.
Definition: Repo.h:247