aboutsummaryrefslogtreecommitdiff
path: root/bdep/git.hxx
blob: 30baf6909ac8de2e55ae8c69d74cbdf242ca274a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
// file      : bdep/git.hxx -*- C++ -*-
// license   : MIT; see accompanying LICENSE file

#ifndef BDEP_GIT_HXX
#define BDEP_GIT_HXX

#include <libbutl/git.hxx>

#include <bdep/types.hxx>
#include <bdep/utility.hxx>
#include <bdep/common-options.hxx>

namespace bdep
{
  using butl::git_repository;

  // All functions that start git process take the minimum supported git
  // version as an argument.
  //
  // They also take the system flag (only considered on Windows) that if true
  // causes these functions to prefer the system git program (determined via
  // PATH) over the bundled one (the bundled git is still used as a fallback).
  // Normally, the caller should use the system git when operating on behalf
  // of the user (commits, pushes, etc), so that the user interacts with the
  // git program they expect. For the query requests (git repository status,
  // etc) the bundled git should be used instead to avoid compatibility issues
  // (e.g., symlink handling, etc; but when querying for potentially global
  // configuration values such as author, system git should be used). Note
  // that on POSIX the system git is used for everything.
  //
  // Start git process.
  //
  template <typename I, typename O, typename E, typename... A>
  process
  start_git (const semantic_version&,
             bool system,
             I&& in, O&& out, E&& err,
             A&&... args);

  template <typename I, typename O, typename E, typename... A>
  process
  start_git (const semantic_version&,
             bool system,
             const dir_path& repo,
             I&& in, O&& out, E&& err,
             A&&... args);

  template <typename I, typename O, typename E, typename... A>
  inline process
  start_git (const semantic_version& min_ver,
             bool system,
             dir_path& repo,
             I&& in, O&& out, E&& err,
             A&&... args)
  {
    return start_git (min_ver,
                      system,
                      const_cast<const dir_path&> (repo),
                      forward<I> (in), forward<O> (out), forward<E> (err),
                      forward<A> (args)...);
  }

  // Wait for git process to terminate.
  //
  void
  finish_git (process& pr, bool io_read = false);

  // Run git process.
  //
  // Pass NULL as the repository argument if the git command is not
  // repository-specific (e.g., init).
  //
  template <typename... A>
  void
  run_git (const semantic_version&,
           bool system,
           bool progress,
           const dir_path* repo,
           A&&... args);

  template <typename... A>
  inline void
  run_git (const semantic_version& min_ver,
           bool system,
           const dir_path* repo,
           A&&... args)
  {
    run_git (min_ver,
             system,
             true /* progress */,
             repo,
             forward<A> (args)...);
  }

  template <typename... A>
  inline void
  run_git (const semantic_version& min_ver,
           bool system,
           bool progress,
           const dir_path& repo,
           A&&... args)
  {
    run_git (min_ver,
             system,
             progress,
             &repo,
             forward<A> (args)...);
  }

  template <typename... A>
  inline void
  run_git (const semantic_version& min_ver,
           bool system,
           const dir_path& repo,
           A&&... args)
  {
    run_git (min_ver,
             system,
             true /* progress */,
             repo,
             forward<A> (args)...);
  }

  // Return the first line of the git output. If ignore_error is true, then
  // suppress stderr, ignore (normal) error exit status, and return nullopt.
  //
  template <typename... A>
  optional<string>
  git_line (const semantic_version&,
            bool system,
            bool ignore_error,
            A&&... args);

  template <typename... A>
  optional<string>
  git_line (const semantic_version&,
            bool system,
            const dir_path& repo,
            bool ignore_error,
            A&&... args);

  // Similar to the above but takes the already started git process with a
  // redirected output pipe.
  //
  optional<string>
  git_line (process&&, fdpipe&&, bool ignore_error, char delim = '\n');

  // Similar to git_line() functions but return the complete git output.
  //
  template <typename... A>
  optional<string>
  git_string (const semantic_version&,
              bool system,
              bool ignore_error,
              A&&... args);

  template <typename... A>
  optional<string>
  git_string (const semantic_version&,
              bool system,
              const dir_path& repo,
              bool ignore_error,
              A&&... args);

  optional<string>
  git_string (process&&, fdpipe&&, bool ignore_error);

  // Try to derive a remote HTTPS repository URL from the optionally specified
  // custom git config value falling back to remote.origin.build2Url and then
  // remote.origin.url. Issue diagnostics (including a suggestion to use
  // option opt, if specified) and fail if unable to.
  //
  url
  git_remote_url (const dir_path& repo,
                  const char* opt = nullptr,
                  const char* what = "remote repository URL",
                  const char* cfg = nullptr);

  // Repository status.
  //
  struct git_repository_status
  {
    string commit;   // Current commit or empty if initial.
    string branch;   // Local branch or empty if detached.
    string upstream; // Upstream in <remote>/<branch> form or empty if not set.

    // Note that unmerged and untracked entries are considered as unstaged.
    //
    bool staged   = false; // Repository has staged changes.
    bool unstaged = false; // Repository has unstaged changes.

    // Note that we can be both ahead and behind.
    //
    bool ahead  = false; // Local branch is ahead of upstream.
    bool behind = false; // Local branch is behind of upstream.
  };

  // Note: requires git 2.11.0 or higher.
  //
  git_repository_status
  git_status (const dir_path& repo);

  // Run the git push command.
  //
  template <typename... A>
  void
  git_push (const common_options&, const dir_path& repo, A&&... args);

  // Return true if git is at least of the specified minimum supported
  // version.
  //
  bool
  git_try_check_version (const semantic_version&, bool system);
}

#include <bdep/git.ixx>
#include <bdep/git.txx>

#endif // BDEP_GIT_HXX