rdavila-rugged 0.24.0b13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +619 -0
- data/ext/rugged/extconf.rb +105 -0
- data/ext/rugged/rugged.c +527 -0
- data/ext/rugged/rugged.h +185 -0
- data/ext/rugged/rugged_backend.c +34 -0
- data/ext/rugged/rugged_blame.c +292 -0
- data/ext/rugged/rugged_blob.c +638 -0
- data/ext/rugged/rugged_branch.c +195 -0
- data/ext/rugged/rugged_branch_collection.c +408 -0
- data/ext/rugged/rugged_commit.c +691 -0
- data/ext/rugged/rugged_config.c +404 -0
- data/ext/rugged/rugged_cred.c +148 -0
- data/ext/rugged/rugged_diff.c +686 -0
- data/ext/rugged/rugged_diff_delta.c +105 -0
- data/ext/rugged/rugged_diff_hunk.c +103 -0
- data/ext/rugged/rugged_diff_line.c +83 -0
- data/ext/rugged/rugged_index.c +1255 -0
- data/ext/rugged/rugged_note.c +376 -0
- data/ext/rugged/rugged_object.c +383 -0
- data/ext/rugged/rugged_patch.c +245 -0
- data/ext/rugged/rugged_reference.c +396 -0
- data/ext/rugged/rugged_reference_collection.c +446 -0
- data/ext/rugged/rugged_remote.c +691 -0
- data/ext/rugged/rugged_remote_collection.c +457 -0
- data/ext/rugged/rugged_repo.c +2669 -0
- data/ext/rugged/rugged_revwalk.c +495 -0
- data/ext/rugged/rugged_settings.c +155 -0
- data/ext/rugged/rugged_signature.c +106 -0
- data/ext/rugged/rugged_submodule.c +852 -0
- data/ext/rugged/rugged_submodule_collection.c +384 -0
- data/ext/rugged/rugged_tag.c +251 -0
- data/ext/rugged/rugged_tag_collection.c +347 -0
- data/ext/rugged/rugged_tree.c +919 -0
- data/lib/rugged.rb +23 -0
- data/lib/rugged/attributes.rb +41 -0
- data/lib/rugged/blob.rb +28 -0
- data/lib/rugged/branch.rb +19 -0
- data/lib/rugged/commit.rb +54 -0
- data/lib/rugged/console.rb +9 -0
- data/lib/rugged/credentials.rb +43 -0
- data/lib/rugged/diff.rb +20 -0
- data/lib/rugged/diff/delta.rb +53 -0
- data/lib/rugged/diff/hunk.rb +18 -0
- data/lib/rugged/diff/line.rb +47 -0
- data/lib/rugged/index.rb +13 -0
- data/lib/rugged/object.rb +7 -0
- data/lib/rugged/patch.rb +36 -0
- data/lib/rugged/reference.rb +7 -0
- data/lib/rugged/remote.rb +4 -0
- data/lib/rugged/repository.rb +227 -0
- data/lib/rugged/submodule_collection.rb +48 -0
- data/lib/rugged/tag.rb +50 -0
- data/lib/rugged/tree.rb +38 -0
- data/lib/rugged/version.rb +3 -0
- data/lib/rugged/walker.rb +5 -0
- metadata +146 -0
@@ -0,0 +1,2669 @@
|
|
1
|
+
/*
|
2
|
+
* The MIT License
|
3
|
+
*
|
4
|
+
* Copyright (c) 2014 GitHub, Inc
|
5
|
+
*
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
* of this software and associated documentation files (the "Software"), to deal
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
11
|
+
* furnished to do so, subject to the following conditions:
|
12
|
+
*
|
13
|
+
* The above copyright notice and this permission notice shall be included in
|
14
|
+
* all copies or substantial portions of the Software.
|
15
|
+
*
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
+
* THE SOFTWARE.
|
23
|
+
*/
|
24
|
+
|
25
|
+
#include "rugged.h"
|
26
|
+
#include <git2/sys/repository.h>
|
27
|
+
#include <git2/sys/odb_backend.h>
|
28
|
+
#include <git2/sys/refdb_backend.h>
|
29
|
+
#include <git2/refs.h>
|
30
|
+
|
31
|
+
extern VALUE rb_mRugged;
|
32
|
+
extern VALUE rb_eRuggedError;
|
33
|
+
extern VALUE rb_cRuggedIndex;
|
34
|
+
extern VALUE rb_cRuggedConfig;
|
35
|
+
extern VALUE rb_cRuggedBackend;
|
36
|
+
extern VALUE rb_cRuggedRemote;
|
37
|
+
extern VALUE rb_cRuggedCommit;
|
38
|
+
extern VALUE rb_cRuggedTag;
|
39
|
+
extern VALUE rb_cRuggedTree;
|
40
|
+
extern VALUE rb_cRuggedReference;
|
41
|
+
extern VALUE rb_cRuggedBackend;
|
42
|
+
|
43
|
+
extern VALUE rb_cRuggedCredPlaintext;
|
44
|
+
extern VALUE rb_cRuggedCredSshKey;
|
45
|
+
extern VALUE rb_cRuggedCredDefault;
|
46
|
+
|
47
|
+
VALUE rb_cRuggedRepo;
|
48
|
+
VALUE rb_cRuggedOdbObject;
|
49
|
+
|
50
|
+
static ID id_call;
|
51
|
+
|
52
|
+
/*
|
53
|
+
* call-seq:
|
54
|
+
* odb_obj.oid -> hex_oid
|
55
|
+
*
|
56
|
+
* Return the Object ID (a 40 character SHA1 hash) for this raw
|
57
|
+
* object.
|
58
|
+
*
|
59
|
+
* odb_obj.oid #=> "d8786bfc97485e8d7b19b21fb88c8ef1f199fc3f"
|
60
|
+
*/
|
61
|
+
static VALUE rb_git_odbobj_oid(VALUE self)
|
62
|
+
{
|
63
|
+
git_odb_object *obj;
|
64
|
+
Data_Get_Struct(self, git_odb_object, obj);
|
65
|
+
return rugged_create_oid(git_odb_object_id(obj));
|
66
|
+
}
|
67
|
+
|
68
|
+
/*
|
69
|
+
* call-seq:
|
70
|
+
* odb_obj.data -> buffer
|
71
|
+
*
|
72
|
+
* Return an ASCII buffer with the raw bytes that form the Git object.
|
73
|
+
*
|
74
|
+
* odb_obj.data #=> "tree 87ebee8367f9cc5ac04858b3bd5610ca74f04df9\n"
|
75
|
+
* #=> "parent 68d041ee999cb07c6496fbdd4f384095de6ca9e1\n"
|
76
|
+
* #=> "author Vicent Martí <tanoku@gmail.com> 1326863045 -0800\n"
|
77
|
+
* #=> ...
|
78
|
+
*/
|
79
|
+
static VALUE rb_git_odbobj_data(VALUE self)
|
80
|
+
{
|
81
|
+
git_odb_object *obj;
|
82
|
+
Data_Get_Struct(self, git_odb_object, obj);
|
83
|
+
return rb_str_new(git_odb_object_data(obj), git_odb_object_size(obj));
|
84
|
+
}
|
85
|
+
|
86
|
+
/*
|
87
|
+
* call-seq:
|
88
|
+
* odb_obj.size -> size
|
89
|
+
*
|
90
|
+
* Return the size in bytes of the Git object after decompression. This is
|
91
|
+
* also the size of the +obj.data+ buffer.
|
92
|
+
*
|
93
|
+
* odb_obj.size #=> 231
|
94
|
+
*/
|
95
|
+
static VALUE rb_git_odbobj_size(VALUE self)
|
96
|
+
{
|
97
|
+
git_odb_object *obj;
|
98
|
+
Data_Get_Struct(self, git_odb_object, obj);
|
99
|
+
return INT2FIX(git_odb_object_size(obj));
|
100
|
+
}
|
101
|
+
|
102
|
+
/*
|
103
|
+
* call-seq:
|
104
|
+
* odb_obj.type -> Symbol
|
105
|
+
*
|
106
|
+
* Return a Ruby symbol representing the basic Git type of this object.
|
107
|
+
* Possible values are +:tree+, +:blob+, +:commit+ and +:tag+.
|
108
|
+
*
|
109
|
+
* odb_obj.type #=> :tag
|
110
|
+
*/
|
111
|
+
static VALUE rb_git_odbobj_type(VALUE self)
|
112
|
+
{
|
113
|
+
git_odb_object *obj;
|
114
|
+
Data_Get_Struct(self, git_odb_object, obj);
|
115
|
+
return rugged_otype_new(git_odb_object_type(obj));
|
116
|
+
}
|
117
|
+
|
118
|
+
void rb_git__odbobj_free(void *obj)
|
119
|
+
{
|
120
|
+
git_odb_object_free((git_odb_object *)obj);
|
121
|
+
}
|
122
|
+
|
123
|
+
VALUE rugged_raw_read(git_repository *repo, const git_oid *oid)
|
124
|
+
{
|
125
|
+
git_odb *odb;
|
126
|
+
git_odb_object *obj;
|
127
|
+
|
128
|
+
int error;
|
129
|
+
|
130
|
+
error = git_repository_odb(&odb, repo);
|
131
|
+
rugged_exception_check(error);
|
132
|
+
|
133
|
+
error = git_odb_read(&obj, odb, oid);
|
134
|
+
git_odb_free(odb);
|
135
|
+
rugged_exception_check(error);
|
136
|
+
|
137
|
+
return Data_Wrap_Struct(rb_cRuggedOdbObject, NULL, rb_git__odbobj_free, obj);
|
138
|
+
}
|
139
|
+
|
140
|
+
void rb_git_repo__free(git_repository *repo)
|
141
|
+
{
|
142
|
+
git_repository_free(repo);
|
143
|
+
}
|
144
|
+
|
145
|
+
VALUE rugged_repo_new(VALUE klass, git_repository *repo)
|
146
|
+
{
|
147
|
+
VALUE rb_repo = Data_Wrap_Struct(klass, NULL, &rb_git_repo__free, repo);
|
148
|
+
|
149
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
150
|
+
/* TODO: set this properly */
|
151
|
+
rb_iv_set(rb_repo, "@encoding",
|
152
|
+
rb_enc_from_encoding(rb_filesystem_encoding()));
|
153
|
+
#endif
|
154
|
+
|
155
|
+
rb_iv_set(rb_repo, "@config", Qnil);
|
156
|
+
rb_iv_set(rb_repo, "@index", Qnil);
|
157
|
+
|
158
|
+
return rb_repo;
|
159
|
+
}
|
160
|
+
|
161
|
+
static void load_alternates(git_repository *repo, VALUE rb_alternates)
|
162
|
+
{
|
163
|
+
git_odb *odb = NULL;
|
164
|
+
int i, error;
|
165
|
+
|
166
|
+
if (NIL_P(rb_alternates))
|
167
|
+
return;
|
168
|
+
|
169
|
+
Check_Type(rb_alternates, T_ARRAY);
|
170
|
+
|
171
|
+
if (RARRAY_LEN(rb_alternates) == 0)
|
172
|
+
return;
|
173
|
+
|
174
|
+
for (i = 0; i < RARRAY_LEN(rb_alternates); ++i)
|
175
|
+
Check_Type(rb_ary_entry(rb_alternates, i), T_STRING);
|
176
|
+
|
177
|
+
error = git_repository_odb(&odb, repo);
|
178
|
+
rugged_exception_check(error);
|
179
|
+
|
180
|
+
for (i = 0; !error && i < RARRAY_LEN(rb_alternates); ++i) {
|
181
|
+
VALUE alt = rb_ary_entry(rb_alternates, i);
|
182
|
+
error = git_odb_add_disk_alternate(odb, StringValueCStr(alt));
|
183
|
+
}
|
184
|
+
|
185
|
+
git_odb_free(odb);
|
186
|
+
rugged_exception_check(error);
|
187
|
+
}
|
188
|
+
|
189
|
+
static void rugged_repo_new_with_backend(git_repository **repo, VALUE rb_path, VALUE rb_backend)
|
190
|
+
{
|
191
|
+
char *path;
|
192
|
+
|
193
|
+
git_odb *odb = NULL;
|
194
|
+
git_odb_backend *odb_backend = NULL;
|
195
|
+
git_refdb *refdb = NULL;
|
196
|
+
git_refdb_backend *refdb_backend = NULL;
|
197
|
+
git_reference *head = NULL;
|
198
|
+
rugged_backend *backend;
|
199
|
+
|
200
|
+
int error = 0;
|
201
|
+
|
202
|
+
Check_Type(rb_path, T_STRING);
|
203
|
+
path = StringValueCStr(rb_path);
|
204
|
+
|
205
|
+
if (rb_obj_is_kind_of(rb_backend, rb_cRuggedBackend) == Qfalse) {
|
206
|
+
rb_raise(rb_eRuggedError, "Backend must be an instance of Rugged::Backend");
|
207
|
+
}
|
208
|
+
|
209
|
+
Data_Get_Struct(rb_backend, rugged_backend, backend);
|
210
|
+
|
211
|
+
error = git_odb_new(&odb);
|
212
|
+
if (error) goto cleanup;
|
213
|
+
|
214
|
+
error = backend->odb_backend(&odb_backend, backend, path);
|
215
|
+
if (error) goto cleanup;
|
216
|
+
|
217
|
+
error = git_odb_add_backend(odb, odb_backend, 1);
|
218
|
+
if (error) {
|
219
|
+
assert(odb_backend->free);
|
220
|
+
odb_backend->free(odb_backend);
|
221
|
+
goto cleanup;
|
222
|
+
}
|
223
|
+
|
224
|
+
error = git_repository_wrap_odb(repo, odb);
|
225
|
+
if (error) goto cleanup;
|
226
|
+
|
227
|
+
error = git_refdb_new(&refdb, *repo);
|
228
|
+
if (error) goto cleanup;
|
229
|
+
|
230
|
+
error = backend->refdb_backend(&refdb_backend, backend, path);
|
231
|
+
if (error) {
|
232
|
+
assert(refdb_backend->free);
|
233
|
+
refdb_backend->free(refdb_backend);
|
234
|
+
goto cleanup;
|
235
|
+
}
|
236
|
+
|
237
|
+
error = git_refdb_set_backend(refdb, refdb_backend);
|
238
|
+
if (error) goto cleanup;
|
239
|
+
|
240
|
+
git_repository_set_refdb(*repo, refdb);
|
241
|
+
|
242
|
+
error = git_reference_lookup(&head, *repo, "HEAD");
|
243
|
+
|
244
|
+
if (error == GIT_ENOTFOUND) {
|
245
|
+
giterr_clear();
|
246
|
+
error = git_reference_symbolic_create(&head, *repo, "HEAD", "refs/heads/master", 0, NULL);
|
247
|
+
}
|
248
|
+
|
249
|
+
if (!error) {
|
250
|
+
git_reference_free(head);
|
251
|
+
return;
|
252
|
+
}
|
253
|
+
|
254
|
+
cleanup:
|
255
|
+
git_repository_free(*repo);
|
256
|
+
git_odb_free(odb);
|
257
|
+
git_refdb_free(refdb);
|
258
|
+
|
259
|
+
rugged_exception_check(error);
|
260
|
+
}
|
261
|
+
|
262
|
+
/*
|
263
|
+
* call-seq:
|
264
|
+
* Repository.bare(path[, alternates]) -> repository OR
|
265
|
+
* Repository.bare(path[, options]) -> repository
|
266
|
+
*
|
267
|
+
* Open a bare Git repository at +path+ and return a +Repository+
|
268
|
+
* object representing it.
|
269
|
+
*
|
270
|
+
* This is faster than Rugged::Repository.new, as it won't attempt to perform
|
271
|
+
* any +.git+ directory discovery, won't try to load the config options to
|
272
|
+
* determine whether the repository is bare and won't try to load the workdir.
|
273
|
+
*
|
274
|
+
* Optionally, you can pass a list of alternate object folders or an options Hash.
|
275
|
+
*
|
276
|
+
* Rugged::Repository.bare(path, ['./other/repo/.git/objects'])
|
277
|
+
* Rugged::Repository.bare(path, opts)
|
278
|
+
*
|
279
|
+
* The following options can be passed in the +options+ Hash:
|
280
|
+
*
|
281
|
+
* :backend ::
|
282
|
+
* A Rugged::Backend instance
|
283
|
+
* :alternates ::
|
284
|
+
* A list of alternate object folders.
|
285
|
+
* Rugged::Repository.bare(path, :alternates => ['./other/repo/.git/objects'])
|
286
|
+
*/
|
287
|
+
static VALUE rb_git_repo_open_bare(int argc, VALUE *argv, VALUE klass)
|
288
|
+
{
|
289
|
+
git_repository *repo = NULL;
|
290
|
+
int error = 0;
|
291
|
+
VALUE rb_path, rb_options, rb_alternates = 0;
|
292
|
+
|
293
|
+
rb_scan_args(argc, argv, "11", &rb_path, &rb_options);
|
294
|
+
|
295
|
+
if (!NIL_P(rb_options) && TYPE(rb_options) == T_ARRAY)
|
296
|
+
rb_alternates = rb_options;
|
297
|
+
|
298
|
+
if (!NIL_P(rb_options) && TYPE(rb_options) == T_HASH) {
|
299
|
+
/* Check for `:backend` */
|
300
|
+
VALUE rb_backend = rb_hash_aref(rb_options, CSTR2SYM("backend"));
|
301
|
+
|
302
|
+
if (!NIL_P(rb_backend)) {
|
303
|
+
rugged_repo_new_with_backend(&repo, rb_path, rb_backend);
|
304
|
+
}
|
305
|
+
|
306
|
+
/* Check for `:alternates` */
|
307
|
+
rb_alternates = rb_hash_aref(rb_options, CSTR2SYM("alternates"));
|
308
|
+
}
|
309
|
+
|
310
|
+
if (!repo) {
|
311
|
+
Check_Type(rb_path, T_STRING);
|
312
|
+
|
313
|
+
error = git_repository_open_bare(&repo, StringValueCStr(rb_path));
|
314
|
+
rugged_exception_check(error);
|
315
|
+
}
|
316
|
+
|
317
|
+
if (rb_alternates) {
|
318
|
+
load_alternates(repo, rb_alternates);
|
319
|
+
}
|
320
|
+
|
321
|
+
return rugged_repo_new(klass, repo);
|
322
|
+
}
|
323
|
+
|
324
|
+
/*
|
325
|
+
* call-seq:
|
326
|
+
* Repository.new(path, options = {}) -> repository
|
327
|
+
*
|
328
|
+
* Open a Git repository in the given +path+ and return a +Repository+ object
|
329
|
+
* representing it. An exception will be thrown if +path+ doesn't point to a
|
330
|
+
* valid repository. If you need to create a repository from scratch, use
|
331
|
+
* Rugged::Repository.init_at instead.
|
332
|
+
*
|
333
|
+
* The +path+ must point to either the actual folder (+.git+) of a Git repository,
|
334
|
+
* or to the directorly that contains the +.git+ folder.
|
335
|
+
*
|
336
|
+
* See also Rugged::Repository.discover and Rugged::Repository.bare.
|
337
|
+
*
|
338
|
+
* The following options can be passed in the +options+ Hash:
|
339
|
+
*
|
340
|
+
* :alternates ::
|
341
|
+
* A list of alternate object folders.
|
342
|
+
*
|
343
|
+
* Examples:
|
344
|
+
*
|
345
|
+
* Rugged::Repository.new('test/.git') #=> #<Rugged::Repository:0x108849488>
|
346
|
+
* Rugged::Repository.new(path, :alternates => ['./other/repo/.git/objects'])
|
347
|
+
*/
|
348
|
+
static VALUE rb_git_repo_new(int argc, VALUE *argv, VALUE klass)
|
349
|
+
{
|
350
|
+
git_repository *repo;
|
351
|
+
int error = 0;
|
352
|
+
VALUE rb_path, rb_options;
|
353
|
+
|
354
|
+
rb_scan_args(argc, argv, "10:", &rb_path, &rb_options);
|
355
|
+
Check_Type(rb_path, T_STRING);
|
356
|
+
|
357
|
+
error = git_repository_open(&repo, StringValueCStr(rb_path));
|
358
|
+
rugged_exception_check(error);
|
359
|
+
|
360
|
+
if (!NIL_P(rb_options)) {
|
361
|
+
/* Check for `:alternates` */
|
362
|
+
load_alternates(repo, rb_hash_aref(rb_options, CSTR2SYM("alternates")));
|
363
|
+
}
|
364
|
+
|
365
|
+
return rugged_repo_new(klass, repo);
|
366
|
+
}
|
367
|
+
|
368
|
+
/*
|
369
|
+
* call-seq:
|
370
|
+
* Repository.init_at(path, is_bare = false, opts = {}) -> repository
|
371
|
+
*
|
372
|
+
* Initialize a Git repository in +path+. This implies creating all the
|
373
|
+
* necessary files on the FS, or re-initializing an already existing
|
374
|
+
* repository if the files have already been created.
|
375
|
+
*
|
376
|
+
* The +is_bare+ (optional, defaults to false) attribute specifies whether
|
377
|
+
* the Repository should be created on disk as bare or not.
|
378
|
+
* Bare repositories have no working directory and are created in the root
|
379
|
+
* of +path+. Non-bare repositories are created in a +.git+ folder and
|
380
|
+
* use +path+ as working directory.
|
381
|
+
*
|
382
|
+
* The following options can be passed in the +options+ Hash:
|
383
|
+
*
|
384
|
+
* :backend ::
|
385
|
+
* A Rugged::Backend instance
|
386
|
+
*
|
387
|
+
*
|
388
|
+
* Rugged::Repository.init_at('repository', :bare) #=> #<Rugged::Repository:0x108849488>
|
389
|
+
*/
|
390
|
+
static VALUE rb_git_repo_init_at(int argc, VALUE *argv, VALUE klass)
|
391
|
+
{
|
392
|
+
git_repository *repo = NULL;
|
393
|
+
VALUE rb_path, rb_is_bare, rb_options;
|
394
|
+
int error;
|
395
|
+
|
396
|
+
rb_scan_args(argc, argv, "11:", &rb_path, &rb_is_bare, &rb_options);
|
397
|
+
Check_Type(rb_path, T_STRING);
|
398
|
+
|
399
|
+
if (!NIL_P(rb_options)) {
|
400
|
+
/* Check for `:backend` */
|
401
|
+
VALUE rb_backend = rb_hash_aref(rb_options, CSTR2SYM("backend"));
|
402
|
+
|
403
|
+
if (rb_backend && !NIL_P(rb_backend)) {
|
404
|
+
rugged_repo_new_with_backend(&repo, rb_path, rb_backend);
|
405
|
+
}
|
406
|
+
}
|
407
|
+
|
408
|
+
if(!repo) {
|
409
|
+
error = git_repository_init(&repo, StringValueCStr(rb_path), RTEST(rb_is_bare));
|
410
|
+
rugged_exception_check(error);
|
411
|
+
}
|
412
|
+
|
413
|
+
return rugged_repo_new(klass, repo);
|
414
|
+
}
|
415
|
+
|
416
|
+
static void parse_clone_options(git_clone_options *ret, VALUE rb_options, struct rugged_remote_cb_payload *remote_payload)
|
417
|
+
{
|
418
|
+
VALUE val;
|
419
|
+
|
420
|
+
if (NIL_P(rb_options))
|
421
|
+
return;
|
422
|
+
|
423
|
+
val = rb_hash_aref(rb_options, CSTR2SYM("bare"));
|
424
|
+
if (RTEST(val))
|
425
|
+
ret->bare = 1;
|
426
|
+
|
427
|
+
val = rb_hash_aref(rb_options, CSTR2SYM("checkout_branch"));
|
428
|
+
if (!NIL_P(val)) {
|
429
|
+
Check_Type(val, T_STRING);
|
430
|
+
ret->checkout_branch = StringValueCStr(val);
|
431
|
+
}
|
432
|
+
|
433
|
+
rugged_remote_init_callbacks_and_payload_from_options(rb_options, &ret->fetch_opts.callbacks, remote_payload);
|
434
|
+
}
|
435
|
+
|
436
|
+
/*
|
437
|
+
* call-seq:
|
438
|
+
* Repository.clone_at(url, local_path[, options]) -> repository
|
439
|
+
*
|
440
|
+
* Clone a repository from +url+ to +local_path+.
|
441
|
+
*
|
442
|
+
* The following options can be passed in the +options+ Hash:
|
443
|
+
*
|
444
|
+
* :bare ::
|
445
|
+
* If +true+, the clone will be created as a bare repository.
|
446
|
+
* Defaults to +false+.
|
447
|
+
*
|
448
|
+
* :checkout_branch ::
|
449
|
+
* The name of a branch to checkout. Defaults to the remote's +HEAD+.
|
450
|
+
*
|
451
|
+
* :remote ::
|
452
|
+
* The name to give to the "origin" remote. Defaults to <tt>"origin"</tt>.
|
453
|
+
*
|
454
|
+
* :ignore_cert_errors ::
|
455
|
+
* If set to +true+, errors while validating the remote's host certificate will be ignored.
|
456
|
+
*
|
457
|
+
* :credentials ::
|
458
|
+
* The credentials to use for the clone operation. Can be either an instance of one
|
459
|
+
* of the Rugged::Credentials types, or a proc returning one of the former.
|
460
|
+
* The proc will be called with the +url+, the +username+ from the url (if applicable) and
|
461
|
+
* a list of applicable credential types.
|
462
|
+
*
|
463
|
+
* :progress ::
|
464
|
+
* A callback that will be executed with the textual progress received from the remote.
|
465
|
+
* This is the text send over the progress side-band (ie. the "counting objects" output).
|
466
|
+
*
|
467
|
+
* :transfer_progress ::
|
468
|
+
* A callback that will be executed to report clone progress information. It will be passed
|
469
|
+
* the amount of +total_objects+, +indexed_objects+, +received_objects+, +local_objects+,
|
470
|
+
* +total_deltas+, +indexed_deltas+, and +received_bytes+.
|
471
|
+
*
|
472
|
+
* :update_tips ::
|
473
|
+
* A callback that will be executed each time a reference was updated locally. It will be
|
474
|
+
* passed the +refname+, +old_oid+ and +new_oid+.
|
475
|
+
*
|
476
|
+
* Example:
|
477
|
+
*
|
478
|
+
* Repository.clone_at("https://github.com/libgit2/rugged.git", "./some/dir", {
|
479
|
+
* transfer_progress: lambda { |total_objects, indexed_objects, received_objects, local_objects, total_deltas, indexed_deltas, received_bytes|
|
480
|
+
* # ...
|
481
|
+
* }
|
482
|
+
* })
|
483
|
+
*/
|
484
|
+
static VALUE rb_git_repo_clone_at(int argc, VALUE *argv, VALUE klass)
|
485
|
+
{
|
486
|
+
VALUE url, local_path, rb_options_hash;
|
487
|
+
git_clone_options options = GIT_CLONE_OPTIONS_INIT;
|
488
|
+
struct rugged_remote_cb_payload remote_payload = { Qnil, Qnil, Qnil, Qnil, 0 };
|
489
|
+
git_repository *repo;
|
490
|
+
int error;
|
491
|
+
|
492
|
+
rb_scan_args(argc, argv, "21", &url, &local_path, &rb_options_hash);
|
493
|
+
Check_Type(url, T_STRING);
|
494
|
+
Check_Type(local_path, T_STRING);
|
495
|
+
|
496
|
+
parse_clone_options(&options, rb_options_hash, &remote_payload);
|
497
|
+
|
498
|
+
error = git_clone(&repo, StringValueCStr(url), StringValueCStr(local_path), &options);
|
499
|
+
|
500
|
+
if (RTEST(remote_payload.exception))
|
501
|
+
rb_jump_tag(remote_payload.exception);
|
502
|
+
rugged_exception_check(error);
|
503
|
+
|
504
|
+
return rugged_repo_new(klass, repo);
|
505
|
+
}
|
506
|
+
|
507
|
+
#define RB_GIT_REPO_OWNED_GET(_klass, _object) \
|
508
|
+
VALUE rb_data = rb_iv_get(self, "@" #_object); \
|
509
|
+
if (NIL_P(rb_data)) { \
|
510
|
+
git_repository *repo; \
|
511
|
+
git_##_object *data; \
|
512
|
+
int error; \
|
513
|
+
Data_Get_Struct(self, git_repository, repo); \
|
514
|
+
error = git_repository_##_object(&data, repo); \
|
515
|
+
rugged_exception_check(error); \
|
516
|
+
rb_data = rugged_##_object##_new(_klass, self, data); \
|
517
|
+
rb_iv_set(self, "@" #_object, rb_data); \
|
518
|
+
} \
|
519
|
+
return rb_data; \
|
520
|
+
|
521
|
+
#define RB_GIT_REPO_OWNED_SET(_klass, _object) \
|
522
|
+
VALUE rb_old_data; \
|
523
|
+
git_repository *repo; \
|
524
|
+
git_##_object *data; \
|
525
|
+
if (!rb_obj_is_kind_of(rb_data, _klass))\
|
526
|
+
rb_raise(rb_eTypeError, \
|
527
|
+
"The given object is not a Rugged::" #_object); \
|
528
|
+
if (!NIL_P(rugged_owner(rb_data))) \
|
529
|
+
rb_raise(rb_eRuntimeError, \
|
530
|
+
"The given object is already owned by another repository"); \
|
531
|
+
Data_Get_Struct(self, git_repository, repo); \
|
532
|
+
Data_Get_Struct(rb_data, git_##_object, data); \
|
533
|
+
git_repository_set_##_object(repo, data); \
|
534
|
+
rb_old_data = rb_iv_get(self, "@" #_object); \
|
535
|
+
if (!NIL_P(rb_old_data)) rugged_set_owner(rb_old_data, Qnil); \
|
536
|
+
rugged_set_owner(rb_data, self); \
|
537
|
+
rb_iv_set(self, "@" #_object, rb_data); \
|
538
|
+
return Qnil; \
|
539
|
+
|
540
|
+
|
541
|
+
/*
|
542
|
+
* call-seq:
|
543
|
+
* repo.index = idx
|
544
|
+
*
|
545
|
+
* Set the index for this +Repository+. +idx+ must be a instance of
|
546
|
+
* Rugged::Index. This index will be used internally by all
|
547
|
+
* operations that use the Git index on +repo+.
|
548
|
+
*
|
549
|
+
* Note that it's not necessary to set the +index+ for any repository;
|
550
|
+
* by default repositories are loaded with the index file that can be
|
551
|
+
* located on the +.git+ folder in the filesystem.
|
552
|
+
*/
|
553
|
+
static VALUE rb_git_repo_set_index(VALUE self, VALUE rb_data)
|
554
|
+
{
|
555
|
+
RB_GIT_REPO_OWNED_SET(rb_cRuggedIndex, index);
|
556
|
+
}
|
557
|
+
|
558
|
+
/*
|
559
|
+
* call-seq:
|
560
|
+
* repo.index -> idx
|
561
|
+
*
|
562
|
+
* Return the default index for this repository.
|
563
|
+
*/
|
564
|
+
static VALUE rb_git_repo_get_index(VALUE self)
|
565
|
+
{
|
566
|
+
RB_GIT_REPO_OWNED_GET(rb_cRuggedIndex, index);
|
567
|
+
}
|
568
|
+
|
569
|
+
/*
|
570
|
+
* call-seq:
|
571
|
+
* repo.config = cfg
|
572
|
+
*
|
573
|
+
* Set the configuration file for this +Repository+. +cfg+ must be a instance of
|
574
|
+
* Rugged::Config. This config file will be used internally by all
|
575
|
+
* operations that need to lookup configuration settings on +repo+.
|
576
|
+
*
|
577
|
+
* Note that it's not necessary to set the +config+ for any repository;
|
578
|
+
* by default repositories are loaded with their relevant config files
|
579
|
+
* on the filesystem, and the corresponding global and system files if
|
580
|
+
* they can be found.
|
581
|
+
*/
|
582
|
+
static VALUE rb_git_repo_set_config(VALUE self, VALUE rb_data)
|
583
|
+
{
|
584
|
+
RB_GIT_REPO_OWNED_SET(rb_cRuggedConfig, config);
|
585
|
+
}
|
586
|
+
|
587
|
+
/*
|
588
|
+
* call-seq:
|
589
|
+
* repo.config -> cfg
|
590
|
+
*
|
591
|
+
* Return a Rugged::Config object representing this repository's config.
|
592
|
+
*/
|
593
|
+
static VALUE rb_git_repo_get_config(VALUE self)
|
594
|
+
{
|
595
|
+
RB_GIT_REPO_OWNED_GET(rb_cRuggedConfig, config);
|
596
|
+
}
|
597
|
+
|
598
|
+
/*
|
599
|
+
* call-seq:
|
600
|
+
* repo.ident = ident
|
601
|
+
*
|
602
|
+
* Set the identity to be used for writing reflogs.
|
603
|
+
*
|
604
|
+
* +ident+ can be either +nil+ or a Hash containing +name+ and/or +email+ entries.
|
605
|
+
*/
|
606
|
+
static VALUE rb_git_repo_set_ident(VALUE self, VALUE rb_ident) {
|
607
|
+
VALUE rb_val;
|
608
|
+
|
609
|
+
git_repository *repo;
|
610
|
+
const char *name = NULL, *email = NULL;
|
611
|
+
|
612
|
+
Data_Get_Struct(self, git_repository, repo);
|
613
|
+
|
614
|
+
if (!NIL_P(rb_ident)) {
|
615
|
+
Check_Type(rb_ident, T_HASH);
|
616
|
+
|
617
|
+
if (!NIL_P(rb_val = rb_hash_aref(rb_ident, CSTR2SYM("name")))) {
|
618
|
+
Check_Type(rb_val, T_STRING);
|
619
|
+
name = StringValueCStr(rb_val);
|
620
|
+
}
|
621
|
+
|
622
|
+
if (!NIL_P(rb_val = rb_hash_aref(rb_ident, CSTR2SYM("email")))) {
|
623
|
+
Check_Type(rb_val, T_STRING);
|
624
|
+
email = StringValueCStr(rb_val);
|
625
|
+
}
|
626
|
+
}
|
627
|
+
|
628
|
+
rugged_exception_check(
|
629
|
+
git_repository_set_ident(repo, name, email)
|
630
|
+
);
|
631
|
+
|
632
|
+
return Qnil;
|
633
|
+
}
|
634
|
+
|
635
|
+
/*
|
636
|
+
* call-seq:
|
637
|
+
* repo.ident -> ident
|
638
|
+
*
|
639
|
+
* Return a Hash containing the identity that is used to write reflogs.
|
640
|
+
*
|
641
|
+
* +ident+ is a Hash containing +name+ and/or +email+ entries, or `nil`.
|
642
|
+
*/
|
643
|
+
static VALUE rb_git_repo_get_ident(VALUE self)
|
644
|
+
{
|
645
|
+
VALUE rb_ident = rb_hash_new();
|
646
|
+
|
647
|
+
git_repository *repo;
|
648
|
+
const char *name = NULL, *email = NULL;
|
649
|
+
|
650
|
+
Data_Get_Struct(self, git_repository, repo);
|
651
|
+
|
652
|
+
rugged_exception_check(
|
653
|
+
git_repository_ident(&name, &email, repo)
|
654
|
+
);
|
655
|
+
|
656
|
+
if (name) {
|
657
|
+
rb_hash_aset(rb_ident, CSTR2SYM("name"), rb_str_new_utf8(name));
|
658
|
+
}
|
659
|
+
|
660
|
+
if (email) {
|
661
|
+
rb_hash_aset(rb_ident, CSTR2SYM("email"), rb_str_new_utf8(email));
|
662
|
+
}
|
663
|
+
|
664
|
+
return rb_ident;
|
665
|
+
}
|
666
|
+
|
667
|
+
/*
|
668
|
+
* call-seq:
|
669
|
+
* repo.merge_base(oid1, oid2, ...)
|
670
|
+
* repo.merge_base(ref1, ref2, ...)
|
671
|
+
* repo.merge_base(commit1, commit2, ...)
|
672
|
+
*
|
673
|
+
* Find a merge base, given two or more commits or oids.
|
674
|
+
* Returns nil if a merge base is not found.
|
675
|
+
*/
|
676
|
+
static VALUE rb_git_repo_merge_base(VALUE self, VALUE rb_args)
|
677
|
+
{
|
678
|
+
int error = GIT_OK, i;
|
679
|
+
git_repository *repo;
|
680
|
+
git_oid base, *input_array = xmalloc(sizeof(git_oid) * RARRAY_LEN(rb_args));
|
681
|
+
int len = (int)RARRAY_LEN(rb_args);
|
682
|
+
|
683
|
+
if (len < 2)
|
684
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 2+)", len);
|
685
|
+
|
686
|
+
Data_Get_Struct(self, git_repository, repo);
|
687
|
+
|
688
|
+
for (i = 0; !error && i < len; ++i) {
|
689
|
+
error = rugged_oid_get(&input_array[i], repo, rb_ary_entry(rb_args, i));
|
690
|
+
}
|
691
|
+
|
692
|
+
if (error) {
|
693
|
+
xfree(input_array);
|
694
|
+
rugged_exception_check(error);
|
695
|
+
}
|
696
|
+
|
697
|
+
error = git_merge_base_many(&base, repo, len, input_array);
|
698
|
+
xfree(input_array);
|
699
|
+
|
700
|
+
if (error == GIT_ENOTFOUND)
|
701
|
+
return Qnil;
|
702
|
+
|
703
|
+
rugged_exception_check(error);
|
704
|
+
|
705
|
+
return rugged_create_oid(&base);
|
706
|
+
}
|
707
|
+
|
708
|
+
/*
|
709
|
+
* call-seq:
|
710
|
+
* repo.merge_bases(oid1, oid2, ...) -> Array
|
711
|
+
* repo.merge_bases(ref1, ref2, ...) -> Array
|
712
|
+
* repo.merge_bases(commit1, commit2, ...) -> Array
|
713
|
+
*
|
714
|
+
* Find all merge bases, given two or more commits or oids.
|
715
|
+
* Returns an empty array if no merge bases are found.
|
716
|
+
*/
|
717
|
+
static VALUE rb_git_repo_merge_bases(VALUE self, VALUE rb_args)
|
718
|
+
{
|
719
|
+
int error = GIT_OK;
|
720
|
+
size_t i, len = (size_t)RARRAY_LEN(rb_args);
|
721
|
+
git_repository *repo;
|
722
|
+
git_oidarray bases = {NULL, 0};
|
723
|
+
git_oid *input_array;
|
724
|
+
|
725
|
+
VALUE rb_bases;
|
726
|
+
|
727
|
+
if (len < 2)
|
728
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%ld for 2+)", RARRAY_LEN(rb_args));
|
729
|
+
|
730
|
+
Data_Get_Struct(self, git_repository, repo);
|
731
|
+
|
732
|
+
input_array = xmalloc(sizeof(git_oid) * len);
|
733
|
+
|
734
|
+
for (i = 0; !error && i < len; ++i) {
|
735
|
+
error = rugged_oid_get(&input_array[i], repo, rb_ary_entry(rb_args, i));
|
736
|
+
}
|
737
|
+
|
738
|
+
if (error) {
|
739
|
+
xfree(input_array);
|
740
|
+
rugged_exception_check(error);
|
741
|
+
}
|
742
|
+
|
743
|
+
error = git_merge_bases_many(&bases, repo, len, input_array);
|
744
|
+
xfree(input_array);
|
745
|
+
|
746
|
+
if (error != GIT_ENOTFOUND)
|
747
|
+
rugged_exception_check(error);
|
748
|
+
|
749
|
+
rb_bases = rb_ary_new2(bases.count);
|
750
|
+
|
751
|
+
for (i = 0; i < bases.count; ++i) {
|
752
|
+
rb_ary_push(rb_bases, rugged_create_oid(&bases.ids[i]));
|
753
|
+
}
|
754
|
+
|
755
|
+
git_oidarray_free(&bases);
|
756
|
+
|
757
|
+
return rb_bases;
|
758
|
+
}
|
759
|
+
|
760
|
+
/*
|
761
|
+
* call-seq:
|
762
|
+
* repo.merge_analysis(their_commit) -> Array
|
763
|
+
*
|
764
|
+
* Analyzes the given commit and determines the opportunities for merging
|
765
|
+
* it into the repository's HEAD. Returns an Array containing a combination
|
766
|
+
* of the following symbols:
|
767
|
+
*
|
768
|
+
* :normal ::
|
769
|
+
* A "normal" merge is possible, both HEAD and the given commit have
|
770
|
+
* diverged from their common ancestor. The divergent commits must be
|
771
|
+
* merged.
|
772
|
+
*
|
773
|
+
* :up_to_date ::
|
774
|
+
* The given commit is reachable from HEAD, meaning HEAD is up-to-date
|
775
|
+
* and no merge needs to be performed.
|
776
|
+
*
|
777
|
+
* :fastforward ::
|
778
|
+
* The given commit is a fast-forward from HEAD and no merge needs to be
|
779
|
+
* performed. HEAD can simply be set to the given commit.
|
780
|
+
*
|
781
|
+
* :unborn ::
|
782
|
+
* The HEAD of the current repository is "unborn" and does not point to
|
783
|
+
* a valid commit. No merge can be performed, but the caller may wish
|
784
|
+
* to simply set HEAD to the given commit.
|
785
|
+
*/
|
786
|
+
static VALUE rb_git_repo_merge_analysis(int argc, VALUE *argv, VALUE self)
|
787
|
+
{
|
788
|
+
int error;
|
789
|
+
git_repository *repo;
|
790
|
+
git_commit *their_commit;
|
791
|
+
git_annotated_commit *annotated_commit;
|
792
|
+
git_merge_analysis_t analysis;
|
793
|
+
git_merge_preference_t preference;
|
794
|
+
VALUE rb_their_commit, result;
|
795
|
+
|
796
|
+
rb_scan_args(argc, argv, "10", &rb_their_commit);
|
797
|
+
|
798
|
+
Data_Get_Struct(self, git_repository, repo);
|
799
|
+
|
800
|
+
if (TYPE(rb_their_commit) == T_STRING) {
|
801
|
+
rb_their_commit = rugged_object_rev_parse(self, rb_their_commit, 1);
|
802
|
+
}
|
803
|
+
|
804
|
+
if (!rb_obj_is_kind_of(rb_their_commit, rb_cRuggedCommit)) {
|
805
|
+
rb_raise(rb_eArgError, "Expected a Rugged::Commit.");
|
806
|
+
}
|
807
|
+
|
808
|
+
Data_Get_Struct(rb_their_commit, git_commit, their_commit);
|
809
|
+
|
810
|
+
error = git_annotated_commit_lookup(&annotated_commit, repo, git_commit_id(their_commit));
|
811
|
+
rugged_exception_check(error);
|
812
|
+
|
813
|
+
error = git_merge_analysis(&analysis, &preference, repo,
|
814
|
+
/* hack as we currently only do one commit */
|
815
|
+
(const git_annotated_commit **) &annotated_commit, 1);
|
816
|
+
git_annotated_commit_free(annotated_commit);
|
817
|
+
rugged_exception_check(error);
|
818
|
+
|
819
|
+
result = rb_ary_new();
|
820
|
+
if (analysis & GIT_MERGE_ANALYSIS_NORMAL)
|
821
|
+
rb_ary_push(result, CSTR2SYM("normal"));
|
822
|
+
if (analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE)
|
823
|
+
rb_ary_push(result, CSTR2SYM("up_to_date"));
|
824
|
+
if (analysis & GIT_MERGE_ANALYSIS_FASTFORWARD)
|
825
|
+
rb_ary_push(result, CSTR2SYM("fastforward"));
|
826
|
+
if (analysis & GIT_MERGE_ANALYSIS_UNBORN)
|
827
|
+
rb_ary_push(result, CSTR2SYM("unborn"));
|
828
|
+
|
829
|
+
return result;
|
830
|
+
}
|
831
|
+
|
832
|
+
/*
|
833
|
+
* call-seq:
|
834
|
+
* repo.revert_commit(revert_commit, our_commit, options = {}) -> index
|
835
|
+
*
|
836
|
+
* Reverts the given commit against the given "our" commit, producing an
|
837
|
+
* index that reflects the result of the revert.
|
838
|
+
*/
|
839
|
+
static VALUE rb_git_repo_revert_commit(int argc, VALUE *argv, VALUE self)
|
840
|
+
{
|
841
|
+
VALUE rb_revert_commit, rb_our_commit, rb_options;
|
842
|
+
git_commit *revert_commit, *our_commit;
|
843
|
+
git_index *index;
|
844
|
+
git_repository *repo;
|
845
|
+
git_merge_options opts = GIT_MERGE_OPTIONS_INIT;
|
846
|
+
unsigned int mainline = 0;
|
847
|
+
int error;
|
848
|
+
|
849
|
+
rb_scan_args(argc, argv, "20:", &rb_revert_commit, &rb_our_commit, &rb_options);
|
850
|
+
|
851
|
+
if (TYPE(rb_revert_commit) == T_STRING)
|
852
|
+
rb_revert_commit = rugged_object_rev_parse(self, rb_revert_commit, 1);
|
853
|
+
|
854
|
+
if (TYPE(rb_our_commit) == T_STRING)
|
855
|
+
rb_our_commit = rugged_object_rev_parse(self, rb_our_commit, 1);
|
856
|
+
|
857
|
+
if (!rb_obj_is_kind_of(rb_revert_commit, rb_cRuggedCommit) ||
|
858
|
+
!rb_obj_is_kind_of(rb_our_commit, rb_cRuggedCommit)) {
|
859
|
+
rb_raise(rb_eArgError, "Expected a Rugged::Commit.");
|
860
|
+
}
|
861
|
+
|
862
|
+
if (!NIL_P(rb_options)) {
|
863
|
+
VALUE rb_mainline;
|
864
|
+
|
865
|
+
Check_Type(rb_options, T_HASH);
|
866
|
+
rugged_parse_merge_options(&opts, rb_options);
|
867
|
+
|
868
|
+
rb_mainline = rb_hash_aref(rb_options, CSTR2SYM("mainline"));
|
869
|
+
if (!NIL_P(rb_mainline)) {
|
870
|
+
Check_Type(rb_mainline, T_FIXNUM);
|
871
|
+
mainline = FIX2UINT(rb_mainline);
|
872
|
+
}
|
873
|
+
}
|
874
|
+
|
875
|
+
Data_Get_Struct(self, git_repository, repo);
|
876
|
+
Data_Get_Struct(rb_revert_commit, git_commit, revert_commit);
|
877
|
+
Data_Get_Struct(rb_our_commit, git_commit, our_commit);
|
878
|
+
|
879
|
+
error = git_revert_commit(&index, repo, revert_commit, our_commit, mainline, &opts);
|
880
|
+
if (error == GIT_EMERGECONFLICT)
|
881
|
+
return Qnil;
|
882
|
+
|
883
|
+
rugged_exception_check(error);
|
884
|
+
|
885
|
+
return rugged_index_new(rb_cRuggedIndex, self, index);
|
886
|
+
}
|
887
|
+
|
888
|
+
/*
|
889
|
+
* call-seq:
|
890
|
+
* repo.merge_commits(our_commit, their_commit, options = {}) -> index
|
891
|
+
*
|
892
|
+
* Merges the two given commits, returning a Rugged::Index that reflects
|
893
|
+
* the result of the merge.
|
894
|
+
*
|
895
|
+
* +our_commit+ and +their_commit+ can either be Rugged::Commit objects,
|
896
|
+
* or OIDs resolving to the former.
|
897
|
+
*/
|
898
|
+
static VALUE rb_git_repo_merge_commits(int argc, VALUE *argv, VALUE self)
|
899
|
+
{
|
900
|
+
VALUE rb_our_commit, rb_their_commit, rb_options;
|
901
|
+
git_commit *our_commit, *their_commit;
|
902
|
+
git_index *index;
|
903
|
+
git_repository *repo;
|
904
|
+
git_merge_options opts = GIT_MERGE_OPTIONS_INIT;
|
905
|
+
int error;
|
906
|
+
|
907
|
+
rb_scan_args(argc, argv, "20:", &rb_our_commit, &rb_their_commit, &rb_options);
|
908
|
+
|
909
|
+
if (TYPE(rb_our_commit) == T_STRING) {
|
910
|
+
rb_our_commit = rugged_object_rev_parse(self, rb_our_commit, 1);
|
911
|
+
}
|
912
|
+
|
913
|
+
if (!rb_obj_is_kind_of(rb_our_commit, rb_cRuggedCommit)) {
|
914
|
+
rb_raise(rb_eArgError, "Expected a Rugged::Commit.");
|
915
|
+
}
|
916
|
+
|
917
|
+
if (TYPE(rb_their_commit) == T_STRING) {
|
918
|
+
rb_their_commit = rugged_object_rev_parse(self, rb_their_commit, 1);
|
919
|
+
}
|
920
|
+
|
921
|
+
if (!rb_obj_is_kind_of(rb_their_commit, rb_cRuggedCommit)) {
|
922
|
+
rb_raise(rb_eArgError, "Expected a Rugged::Commit.");
|
923
|
+
}
|
924
|
+
|
925
|
+
if (!NIL_P(rb_options)) {
|
926
|
+
Check_Type(rb_options, T_HASH);
|
927
|
+
rugged_parse_merge_options(&opts, rb_options);
|
928
|
+
}
|
929
|
+
|
930
|
+
Data_Get_Struct(self, git_repository, repo);
|
931
|
+
Data_Get_Struct(rb_our_commit, git_commit, our_commit);
|
932
|
+
Data_Get_Struct(rb_their_commit, git_commit, their_commit);
|
933
|
+
|
934
|
+
error = git_merge_commits(&index, repo, our_commit, their_commit, &opts);
|
935
|
+
if (error == GIT_EMERGECONFLICT)
|
936
|
+
return Qnil;
|
937
|
+
|
938
|
+
rugged_exception_check(error);
|
939
|
+
|
940
|
+
return rugged_index_new(rb_cRuggedIndex, self, index);
|
941
|
+
}
|
942
|
+
|
943
|
+
/*
|
944
|
+
* call-seq:
|
945
|
+
* repo.include?(oid) -> true or false
|
946
|
+
* repo.exists?(oid) -> true or false
|
947
|
+
*
|
948
|
+
* Return whether an object with the given SHA1 OID (represented as
|
949
|
+
* a hex string of at least 7 characters) exists in the repository.
|
950
|
+
*
|
951
|
+
* repo.include?("d8786bfc97485e8d7b19b21fb88c8ef1f199fc3f") #=> true
|
952
|
+
* repo.include?("d8786bfc") #=> true
|
953
|
+
*/
|
954
|
+
static VALUE rb_git_repo_exists(VALUE self, VALUE hex)
|
955
|
+
{
|
956
|
+
git_repository *repo;
|
957
|
+
git_odb *odb;
|
958
|
+
git_oid oid;
|
959
|
+
int error;
|
960
|
+
|
961
|
+
Data_Get_Struct(self, git_repository, repo);
|
962
|
+
Check_Type(hex, T_STRING);
|
963
|
+
|
964
|
+
error = git_oid_fromstrn(&oid, RSTRING_PTR(hex), RSTRING_LEN(hex));
|
965
|
+
rugged_exception_check(error);
|
966
|
+
|
967
|
+
error = git_repository_odb(&odb, repo);
|
968
|
+
rugged_exception_check(error);
|
969
|
+
|
970
|
+
error = git_odb_exists_prefix(NULL, odb, &oid, RSTRING_LEN(hex));
|
971
|
+
git_odb_free(odb);
|
972
|
+
|
973
|
+
if (error == 0 || error == GIT_EAMBIGUOUS)
|
974
|
+
return Qtrue;
|
975
|
+
|
976
|
+
return Qfalse;
|
977
|
+
}
|
978
|
+
|
979
|
+
/*
|
980
|
+
* call-seq:
|
981
|
+
* repo.read(oid) -> str
|
982
|
+
*
|
983
|
+
* Read and return the raw data of the object identified by the given +oid+.
|
984
|
+
*/
|
985
|
+
static VALUE rb_git_repo_read(VALUE self, VALUE hex)
|
986
|
+
{
|
987
|
+
git_repository *repo;
|
988
|
+
git_oid oid;
|
989
|
+
int error;
|
990
|
+
|
991
|
+
Data_Get_Struct(self, git_repository, repo);
|
992
|
+
Check_Type(hex, T_STRING);
|
993
|
+
|
994
|
+
error = git_oid_fromstr(&oid, StringValueCStr(hex));
|
995
|
+
rugged_exception_check(error);
|
996
|
+
|
997
|
+
return rugged_raw_read(repo, &oid);
|
998
|
+
}
|
999
|
+
|
1000
|
+
/*
|
1001
|
+
* call-seq:
|
1002
|
+
* repo.read_header(oid) -> hash
|
1003
|
+
*
|
1004
|
+
* Read and return the header information in +repo+'s ODB
|
1005
|
+
* for the object identified by the given +oid+.
|
1006
|
+
*
|
1007
|
+
* Returns a Hash object with the following key/value pairs:
|
1008
|
+
*
|
1009
|
+
* :type ::
|
1010
|
+
* A Symbol denoting the object's type. Possible values are:
|
1011
|
+
* +:tree+, +:blob+, +:commit+ or +:tag+.
|
1012
|
+
* :len ::
|
1013
|
+
* A Number representing the object's length, in bytes.
|
1014
|
+
*/
|
1015
|
+
static VALUE rb_git_repo_read_header(VALUE self, VALUE hex)
|
1016
|
+
{
|
1017
|
+
git_repository *repo;
|
1018
|
+
git_oid oid;
|
1019
|
+
git_odb *odb;
|
1020
|
+
git_otype type;
|
1021
|
+
size_t len;
|
1022
|
+
VALUE rb_hash;
|
1023
|
+
int error;
|
1024
|
+
|
1025
|
+
Data_Get_Struct(self, git_repository, repo);
|
1026
|
+
Check_Type(hex, T_STRING);
|
1027
|
+
|
1028
|
+
error = git_oid_fromstr(&oid, StringValueCStr(hex));
|
1029
|
+
rugged_exception_check(error);
|
1030
|
+
|
1031
|
+
error = git_repository_odb(&odb, repo);
|
1032
|
+
rugged_exception_check(error);
|
1033
|
+
|
1034
|
+
error = git_odb_read_header(&len, &type, odb, &oid);
|
1035
|
+
git_odb_free(odb);
|
1036
|
+
rugged_exception_check(error);
|
1037
|
+
|
1038
|
+
rb_hash = rb_hash_new();
|
1039
|
+
rb_hash_aset(rb_hash, CSTR2SYM("type"), CSTR2SYM(git_object_type2string(type)));
|
1040
|
+
rb_hash_aset(rb_hash, CSTR2SYM("len"), INT2FIX(len));
|
1041
|
+
|
1042
|
+
return rb_hash;
|
1043
|
+
}
|
1044
|
+
|
1045
|
+
/**
|
1046
|
+
* call-seq:
|
1047
|
+
* repo.expand_oids([oid..], object_type = :any) -> hash
|
1048
|
+
*
|
1049
|
+
* Expand a list of short oids to their full value, assuming they exist
|
1050
|
+
* in the repository. If `object_type` is passed, OIDs are expected to be
|
1051
|
+
* of the given type.
|
1052
|
+
*
|
1053
|
+
* Returns a hash of `{ short_oid => full_oid }` for the short OIDs which
|
1054
|
+
* exist in the repository and match the expected object type. Missing OIDs
|
1055
|
+
* will not appear in the resulting hash.
|
1056
|
+
*/
|
1057
|
+
static VALUE rb_git_repo_expand_oids(int argc, VALUE *argv, VALUE self)
|
1058
|
+
{
|
1059
|
+
VALUE rb_result, rb_oids, rb_expected_type;
|
1060
|
+
|
1061
|
+
git_otype expected_type = GIT_OBJ_ANY;
|
1062
|
+
|
1063
|
+
git_repository *repo;
|
1064
|
+
git_oid oid;
|
1065
|
+
git_odb *odb;
|
1066
|
+
int i, error;
|
1067
|
+
|
1068
|
+
Data_Get_Struct(self, git_repository, repo);
|
1069
|
+
|
1070
|
+
rb_scan_args(argc, argv, "11", &rb_oids, &rb_expected_type);
|
1071
|
+
|
1072
|
+
Check_Type(rb_oids, T_ARRAY);
|
1073
|
+
expected_type = rugged_otype_get(rb_expected_type);
|
1074
|
+
|
1075
|
+
error = git_repository_odb(&odb, repo);
|
1076
|
+
rugged_exception_check(error);
|
1077
|
+
|
1078
|
+
rb_result = rb_hash_new();
|
1079
|
+
|
1080
|
+
for (i = 0; i < RARRAY_LEN(rb_oids); ++i) {
|
1081
|
+
VALUE hex_oid = rb_ary_entry(rb_oids, i);
|
1082
|
+
git_oid found_oid;
|
1083
|
+
|
1084
|
+
if (TYPE(hex_oid) != T_STRING) {
|
1085
|
+
git_odb_free(odb);
|
1086
|
+
rb_raise(rb_eTypeError, "Expected a SHA1 OID");
|
1087
|
+
}
|
1088
|
+
|
1089
|
+
error = git_oid_fromstrn(&oid, RSTRING_PTR(hex_oid), RSTRING_LEN(hex_oid));
|
1090
|
+
if (error < 0) {
|
1091
|
+
git_odb_free(odb);
|
1092
|
+
rugged_exception_check(error);
|
1093
|
+
}
|
1094
|
+
|
1095
|
+
error = git_odb_exists_prefix(&found_oid, odb, &oid, RSTRING_LEN(hex_oid));
|
1096
|
+
|
1097
|
+
if (!error) {
|
1098
|
+
if (expected_type != GIT_OBJ_ANY) {
|
1099
|
+
size_t found_size;
|
1100
|
+
git_otype found_type;
|
1101
|
+
|
1102
|
+
if (git_odb_read_header(&found_size, &found_type, odb, &found_oid) < 0)
|
1103
|
+
continue;
|
1104
|
+
|
1105
|
+
if (found_type != expected_type)
|
1106
|
+
continue;
|
1107
|
+
}
|
1108
|
+
|
1109
|
+
rb_hash_aset(rb_result, hex_oid, rugged_create_oid(&found_oid));
|
1110
|
+
}
|
1111
|
+
}
|
1112
|
+
|
1113
|
+
git_odb_free(odb);
|
1114
|
+
return rb_result;
|
1115
|
+
}
|
1116
|
+
|
1117
|
+
/*
|
1118
|
+
* call-seq:
|
1119
|
+
* repo.descendant_of?(commit, ancestor) -> true or false
|
1120
|
+
*
|
1121
|
+
* +commit+ and +ancestor+ must be String commit OIDs or instances of Rugged::Commit.
|
1122
|
+
*
|
1123
|
+
* Returns true if +commit+ is a descendant of +ancestor+, or false if not.
|
1124
|
+
*/
|
1125
|
+
static VALUE rb_git_repo_descendant_of(VALUE self, VALUE rb_commit, VALUE rb_ancestor)
|
1126
|
+
{
|
1127
|
+
int result;
|
1128
|
+
int error;
|
1129
|
+
git_repository *repo;
|
1130
|
+
git_oid commit, ancestor;
|
1131
|
+
|
1132
|
+
Data_Get_Struct(self, git_repository, repo);
|
1133
|
+
|
1134
|
+
error = rugged_oid_get(&commit, repo, rb_commit);
|
1135
|
+
rugged_exception_check(error);
|
1136
|
+
|
1137
|
+
error = rugged_oid_get(&ancestor, repo, rb_ancestor);
|
1138
|
+
rugged_exception_check(error);
|
1139
|
+
|
1140
|
+
result = git_graph_descendant_of(repo, &commit, &ancestor);
|
1141
|
+
rugged_exception_check(result);
|
1142
|
+
|
1143
|
+
return result ? Qtrue : Qfalse;
|
1144
|
+
}
|
1145
|
+
|
1146
|
+
/*
|
1147
|
+
* call-seq:
|
1148
|
+
* Repository.hash_data(str, type) -> oid
|
1149
|
+
*
|
1150
|
+
* Hash the contents of +str+ as raw bytes (ignoring any encoding
|
1151
|
+
* information) and adding the relevant header corresponding to +type+,
|
1152
|
+
* and return a hex string representing the result from the hash.
|
1153
|
+
*
|
1154
|
+
* Repository.hash_data('hello world', :commit) #=> "de5ba987198bcf2518885f0fc1350e5172cded78"
|
1155
|
+
*
|
1156
|
+
* Repository.hash_data('hello_world', :tag) #=> "9d09060c850defbc7711d08b57def0d14e742f4e"
|
1157
|
+
*/
|
1158
|
+
static VALUE rb_git_repo_hash(VALUE self, VALUE rb_buffer, VALUE rb_type)
|
1159
|
+
{
|
1160
|
+
int error;
|
1161
|
+
git_oid oid;
|
1162
|
+
|
1163
|
+
Check_Type(rb_buffer, T_STRING);
|
1164
|
+
|
1165
|
+
error = git_odb_hash(&oid,
|
1166
|
+
RSTRING_PTR(rb_buffer),
|
1167
|
+
RSTRING_LEN(rb_buffer),
|
1168
|
+
rugged_otype_get(rb_type)
|
1169
|
+
);
|
1170
|
+
rugged_exception_check(error);
|
1171
|
+
|
1172
|
+
return rugged_create_oid(&oid);
|
1173
|
+
}
|
1174
|
+
|
1175
|
+
/*
|
1176
|
+
* call-seq:
|
1177
|
+
* Repository.hash_file(path, type) -> oid
|
1178
|
+
*
|
1179
|
+
* Hash the contents of the file pointed at by +path+, assuming
|
1180
|
+
* that it'd be stored in the ODB with the given +type+, and return
|
1181
|
+
* a hex string representing the SHA1 OID resulting from the hash.
|
1182
|
+
*
|
1183
|
+
* Repository.hash_file('foo.txt', :commit) #=> "de5ba987198bcf2518885f0fc1350e5172cded78"
|
1184
|
+
*
|
1185
|
+
* Repository.hash_file('foo.txt', :tag) #=> "9d09060c850defbc7711d08b57def0d14e742f4e"
|
1186
|
+
*/
|
1187
|
+
static VALUE rb_git_repo_hashfile(VALUE self, VALUE rb_path, VALUE rb_type)
|
1188
|
+
{
|
1189
|
+
int error;
|
1190
|
+
git_oid oid;
|
1191
|
+
|
1192
|
+
Check_Type(rb_path, T_STRING);
|
1193
|
+
|
1194
|
+
error = git_odb_hashfile(&oid,
|
1195
|
+
StringValueCStr(rb_path),
|
1196
|
+
rugged_otype_get(rb_type)
|
1197
|
+
);
|
1198
|
+
rugged_exception_check(error);
|
1199
|
+
|
1200
|
+
return rugged_create_oid(&oid);
|
1201
|
+
}
|
1202
|
+
|
1203
|
+
/*
|
1204
|
+
* call-seq:
|
1205
|
+
* repo.write(buffer, type) -> oid
|
1206
|
+
*
|
1207
|
+
* Write the data contained in the +buffer+ string as a raw object of the
|
1208
|
+
* given +type+ into the repository's object database.
|
1209
|
+
*
|
1210
|
+
* +type+ can be either +:tag+, +:commit+, +:tree+ or +:blob+.
|
1211
|
+
*
|
1212
|
+
* Returns the newly created object's oid.
|
1213
|
+
*/
|
1214
|
+
static VALUE rb_git_repo_write(VALUE self, VALUE rb_buffer, VALUE rub_type)
|
1215
|
+
{
|
1216
|
+
git_repository *repo;
|
1217
|
+
git_odb_stream *stream;
|
1218
|
+
|
1219
|
+
git_odb *odb;
|
1220
|
+
git_oid oid;
|
1221
|
+
int error;
|
1222
|
+
|
1223
|
+
git_otype type;
|
1224
|
+
|
1225
|
+
Data_Get_Struct(self, git_repository, repo);
|
1226
|
+
Check_Type(rb_buffer, T_STRING);
|
1227
|
+
|
1228
|
+
error = git_repository_odb(&odb, repo);
|
1229
|
+
rugged_exception_check(error);
|
1230
|
+
|
1231
|
+
type = rugged_otype_get(rub_type);
|
1232
|
+
|
1233
|
+
error = git_odb_open_wstream(&stream, odb, RSTRING_LEN(rb_buffer), type);
|
1234
|
+
git_odb_free(odb);
|
1235
|
+
rugged_exception_check(error);
|
1236
|
+
|
1237
|
+
error = git_odb_stream_write(stream, RSTRING_PTR(rb_buffer), RSTRING_LEN(rb_buffer));
|
1238
|
+
if (!error)
|
1239
|
+
error = git_odb_stream_finalize_write(&oid, stream);
|
1240
|
+
|
1241
|
+
git_odb_stream_free(stream);
|
1242
|
+
rugged_exception_check(error);
|
1243
|
+
|
1244
|
+
return rugged_create_oid(&oid);
|
1245
|
+
}
|
1246
|
+
|
1247
|
+
#define RB_GIT_REPO_GETTER(method) \
|
1248
|
+
git_repository *repo; \
|
1249
|
+
int error; \
|
1250
|
+
Data_Get_Struct(self, git_repository, repo); \
|
1251
|
+
error = git_repository_##method(repo); \
|
1252
|
+
rugged_exception_check(error); \
|
1253
|
+
return error ? Qtrue : Qfalse; \
|
1254
|
+
|
1255
|
+
/*
|
1256
|
+
* call-seq:
|
1257
|
+
* repo.bare? -> true or false
|
1258
|
+
*
|
1259
|
+
* Return whether a repository is bare or not. A bare repository has no
|
1260
|
+
* working directory.
|
1261
|
+
*/
|
1262
|
+
static VALUE rb_git_repo_is_bare(VALUE self)
|
1263
|
+
{
|
1264
|
+
RB_GIT_REPO_GETTER(is_bare);
|
1265
|
+
}
|
1266
|
+
|
1267
|
+
/*
|
1268
|
+
* call-seq:
|
1269
|
+
* repo.shallow? -> true or false
|
1270
|
+
*
|
1271
|
+
* Return whether a repository is a shallow clone or not. A shallow clone has
|
1272
|
+
* a truncated history and can not be cloned or fetched from, nor can be
|
1273
|
+
* pushed from nor into it.
|
1274
|
+
*/
|
1275
|
+
static VALUE rb_git_repo_is_shallow(VALUE self)
|
1276
|
+
{
|
1277
|
+
RB_GIT_REPO_GETTER(is_shallow);
|
1278
|
+
}
|
1279
|
+
|
1280
|
+
/*
|
1281
|
+
* call-seq:
|
1282
|
+
* repo.empty? -> true or false
|
1283
|
+
*
|
1284
|
+
* Return whether a repository is empty or not. An empty repository has just
|
1285
|
+
* been initialized and has no commits yet.
|
1286
|
+
*/
|
1287
|
+
static VALUE rb_git_repo_is_empty(VALUE self)
|
1288
|
+
{
|
1289
|
+
RB_GIT_REPO_GETTER(is_empty);
|
1290
|
+
}
|
1291
|
+
|
1292
|
+
/*
|
1293
|
+
* call-seq:
|
1294
|
+
* repo.head_detached? -> true or false
|
1295
|
+
*
|
1296
|
+
* Return whether the +HEAD+ of a repository is detached or not.
|
1297
|
+
*/
|
1298
|
+
static VALUE rb_git_repo_head_detached(VALUE self)
|
1299
|
+
{
|
1300
|
+
RB_GIT_REPO_GETTER(head_detached);
|
1301
|
+
}
|
1302
|
+
|
1303
|
+
/*
|
1304
|
+
* call-seq:
|
1305
|
+
* repo.head_unborn? -> true or false
|
1306
|
+
*
|
1307
|
+
* Return whether the current branch is unborn (+HEAD+ points to a
|
1308
|
+
* non-existent branch).
|
1309
|
+
*/
|
1310
|
+
static VALUE rb_git_repo_head_unborn(VALUE self)
|
1311
|
+
{
|
1312
|
+
RB_GIT_REPO_GETTER(head_unborn);
|
1313
|
+
}
|
1314
|
+
|
1315
|
+
/*
|
1316
|
+
* call-seq:
|
1317
|
+
* repo.head = str
|
1318
|
+
*
|
1319
|
+
* Make the repository's +HEAD+ point to the specified reference.
|
1320
|
+
*/
|
1321
|
+
static VALUE rb_git_repo_set_head(VALUE self, VALUE rb_head)
|
1322
|
+
{
|
1323
|
+
git_repository *repo;
|
1324
|
+
int error;
|
1325
|
+
|
1326
|
+
Data_Get_Struct(self, git_repository, repo);
|
1327
|
+
|
1328
|
+
Check_Type(rb_head, T_STRING);
|
1329
|
+
error = git_repository_set_head(repo, StringValueCStr(rb_head));
|
1330
|
+
rugged_exception_check(error);
|
1331
|
+
|
1332
|
+
return Qnil;
|
1333
|
+
}
|
1334
|
+
|
1335
|
+
/*
|
1336
|
+
* call-seq:
|
1337
|
+
* repo.head -> ref
|
1338
|
+
*
|
1339
|
+
* Retrieve and resolve the reference pointed at by the repository's +HEAD+.
|
1340
|
+
*
|
1341
|
+
* Returns +nil+ if +HEAD+ is missing.
|
1342
|
+
*/
|
1343
|
+
static VALUE rb_git_repo_get_head(VALUE self)
|
1344
|
+
{
|
1345
|
+
git_repository *repo;
|
1346
|
+
git_reference *head;
|
1347
|
+
int error;
|
1348
|
+
|
1349
|
+
Data_Get_Struct(self, git_repository, repo);
|
1350
|
+
|
1351
|
+
error = git_repository_head(&head, repo);
|
1352
|
+
if (error == GIT_ENOTFOUND)
|
1353
|
+
return Qnil;
|
1354
|
+
else
|
1355
|
+
rugged_exception_check(error);
|
1356
|
+
|
1357
|
+
return rugged_ref_new(rb_cRuggedReference, self, head);
|
1358
|
+
}
|
1359
|
+
|
1360
|
+
/*
|
1361
|
+
* call-seq:
|
1362
|
+
* repo.path -> path
|
1363
|
+
*
|
1364
|
+
* Return the full, normalized path to this repository. For non-bare repositories,
|
1365
|
+
* this is the path of the actual +.git+ folder, not the working directory.
|
1366
|
+
*
|
1367
|
+
* repo.path #=> "/home/foo/workthing/.git"
|
1368
|
+
*/
|
1369
|
+
static VALUE rb_git_repo_path(VALUE self)
|
1370
|
+
{
|
1371
|
+
git_repository *repo;
|
1372
|
+
const char *path;
|
1373
|
+
|
1374
|
+
Data_Get_Struct(self, git_repository, repo);
|
1375
|
+
path = git_repository_path(repo);
|
1376
|
+
|
1377
|
+
return path ? rb_str_new_utf8(path) : Qnil;
|
1378
|
+
}
|
1379
|
+
|
1380
|
+
/*
|
1381
|
+
* call-seq:
|
1382
|
+
* repo.workdir -> path or nil
|
1383
|
+
*
|
1384
|
+
* Return the working directory for this repository, or +nil+ if
|
1385
|
+
* the repository is bare.
|
1386
|
+
*
|
1387
|
+
* repo1.bare? #=> false
|
1388
|
+
* repo1.workdir #=> "/home/foo/workthing/"
|
1389
|
+
*
|
1390
|
+
* repo2.bare? #=> true
|
1391
|
+
* repo2.workdir #=> nil
|
1392
|
+
*/
|
1393
|
+
static VALUE rb_git_repo_workdir(VALUE self)
|
1394
|
+
{
|
1395
|
+
git_repository *repo;
|
1396
|
+
const char *workdir;
|
1397
|
+
|
1398
|
+
Data_Get_Struct(self, git_repository, repo);
|
1399
|
+
workdir = git_repository_workdir(repo);
|
1400
|
+
|
1401
|
+
return workdir ? rb_str_new_utf8(workdir) : Qnil;
|
1402
|
+
}
|
1403
|
+
|
1404
|
+
/*
|
1405
|
+
* call-seq:
|
1406
|
+
* repo.workdir = path
|
1407
|
+
*
|
1408
|
+
* Sets the working directory of +repo+ to +path+. All internal
|
1409
|
+
* operations on +repo+ that affect the working directory will
|
1410
|
+
* instead use +path+.
|
1411
|
+
*
|
1412
|
+
* The +workdir+ can be set on bare repositories to temporarily
|
1413
|
+
* turn them into normal repositories.
|
1414
|
+
*
|
1415
|
+
* repo.bare? #=> true
|
1416
|
+
* repo.workdir = "/tmp/workdir"
|
1417
|
+
* repo.bare? #=> false
|
1418
|
+
* repo.checkout
|
1419
|
+
*/
|
1420
|
+
static VALUE rb_git_repo_set_workdir(VALUE self, VALUE rb_workdir)
|
1421
|
+
{
|
1422
|
+
git_repository *repo;
|
1423
|
+
|
1424
|
+
Data_Get_Struct(self, git_repository, repo);
|
1425
|
+
Check_Type(rb_workdir, T_STRING);
|
1426
|
+
|
1427
|
+
rugged_exception_check(
|
1428
|
+
git_repository_set_workdir(repo, StringValueCStr(rb_workdir), 0)
|
1429
|
+
);
|
1430
|
+
|
1431
|
+
return Qnil;
|
1432
|
+
}
|
1433
|
+
|
1434
|
+
/*
|
1435
|
+
* call-seq:
|
1436
|
+
* Repository.discover(path = nil, across_fs = true) -> repository
|
1437
|
+
*
|
1438
|
+
* Traverse +path+ upwards until a Git working directory with a +.git+
|
1439
|
+
* folder has been found, open it and return it as a +Repository+
|
1440
|
+
* object.
|
1441
|
+
*
|
1442
|
+
* If +path+ is +nil+, the current working directory will be used as
|
1443
|
+
* a starting point.
|
1444
|
+
*
|
1445
|
+
* If +across_fs+ is +true+, the traversal won't stop when reaching
|
1446
|
+
* a different device than the one that contained +path+ (only applies
|
1447
|
+
* to UNIX-based OSses).
|
1448
|
+
*/
|
1449
|
+
static VALUE rb_git_repo_discover(int argc, VALUE *argv, VALUE klass)
|
1450
|
+
{
|
1451
|
+
git_repository *repo;
|
1452
|
+
VALUE rb_path, rb_across_fs;
|
1453
|
+
git_buf repository_path = { NULL };
|
1454
|
+
int error, across_fs = 0;
|
1455
|
+
|
1456
|
+
rb_scan_args(argc, argv, "02", &rb_path, &rb_across_fs);
|
1457
|
+
|
1458
|
+
if (NIL_P(rb_path)) {
|
1459
|
+
VALUE rb_dir = rb_const_get(rb_cObject, rb_intern("Dir"));
|
1460
|
+
rb_path = rb_funcall(rb_dir, rb_intern("pwd"), 0);
|
1461
|
+
}
|
1462
|
+
|
1463
|
+
if (!NIL_P(rb_across_fs)) {
|
1464
|
+
across_fs = rugged_parse_bool(rb_across_fs);
|
1465
|
+
}
|
1466
|
+
|
1467
|
+
Check_Type(rb_path, T_STRING);
|
1468
|
+
|
1469
|
+
error = git_repository_discover(
|
1470
|
+
&repository_path,
|
1471
|
+
StringValueCStr(rb_path),
|
1472
|
+
across_fs,
|
1473
|
+
NULL
|
1474
|
+
);
|
1475
|
+
|
1476
|
+
rugged_exception_check(error);
|
1477
|
+
|
1478
|
+
error = git_repository_open(&repo, repository_path.ptr);
|
1479
|
+
git_buf_free(&repository_path);
|
1480
|
+
|
1481
|
+
rugged_exception_check(error);
|
1482
|
+
|
1483
|
+
return rugged_repo_new(klass, repo);
|
1484
|
+
}
|
1485
|
+
|
1486
|
+
static VALUE flags_to_rb(unsigned int flags)
|
1487
|
+
{
|
1488
|
+
VALUE rb_flags = rb_ary_new();
|
1489
|
+
|
1490
|
+
if (flags & GIT_STATUS_INDEX_NEW)
|
1491
|
+
rb_ary_push(rb_flags, CSTR2SYM("index_new"));
|
1492
|
+
|
1493
|
+
if (flags & GIT_STATUS_INDEX_MODIFIED)
|
1494
|
+
rb_ary_push(rb_flags, CSTR2SYM("index_modified"));
|
1495
|
+
|
1496
|
+
if (flags & GIT_STATUS_INDEX_DELETED)
|
1497
|
+
rb_ary_push(rb_flags, CSTR2SYM("index_deleted"));
|
1498
|
+
|
1499
|
+
if (flags & GIT_STATUS_WT_NEW)
|
1500
|
+
rb_ary_push(rb_flags, CSTR2SYM("worktree_new"));
|
1501
|
+
|
1502
|
+
if (flags & GIT_STATUS_WT_MODIFIED)
|
1503
|
+
rb_ary_push(rb_flags, CSTR2SYM("worktree_modified"));
|
1504
|
+
|
1505
|
+
if (flags & GIT_STATUS_WT_DELETED)
|
1506
|
+
rb_ary_push(rb_flags, CSTR2SYM("worktree_deleted"));
|
1507
|
+
|
1508
|
+
if (flags & GIT_STATUS_IGNORED)
|
1509
|
+
rb_ary_push(rb_flags, CSTR2SYM("ignored"));
|
1510
|
+
|
1511
|
+
return rb_flags;
|
1512
|
+
}
|
1513
|
+
|
1514
|
+
static int rugged__status_cb(const char *path, unsigned int flags, void *payload)
|
1515
|
+
{
|
1516
|
+
rb_funcall((VALUE)payload, rb_intern("call"), 2,
|
1517
|
+
rb_str_new_utf8(path), flags_to_rb(flags)
|
1518
|
+
);
|
1519
|
+
|
1520
|
+
return GIT_OK;
|
1521
|
+
}
|
1522
|
+
|
1523
|
+
/*
|
1524
|
+
* call-seq:
|
1525
|
+
* repo.status { |file, status_data| block }
|
1526
|
+
* repo.status(path) -> status_data
|
1527
|
+
*
|
1528
|
+
* Returns the status for one or more files in the working directory
|
1529
|
+
* of the repository. This is equivalent to the +git status+ command.
|
1530
|
+
*
|
1531
|
+
* The returned +status_data+ is always an array containing one or more
|
1532
|
+
* status flags as Ruby symbols. Possible flags are:
|
1533
|
+
*
|
1534
|
+
* - +:index_new+: the file is new in the index
|
1535
|
+
* - +:index_modified+: the file has been modified in the index
|
1536
|
+
* - +:index_deleted+: the file has been deleted from the index
|
1537
|
+
* - +:worktree_new+: the file is new in the working directory
|
1538
|
+
* - +:worktree_modified+: the file has been modified in the working directory
|
1539
|
+
* - +:worktree_deleted+: the file has been deleted from the working directory
|
1540
|
+
*
|
1541
|
+
* If a +block+ is given, status information will be gathered for every
|
1542
|
+
* single file on the working dir. The +block+ will be called with the
|
1543
|
+
* status data for each file.
|
1544
|
+
*
|
1545
|
+
* repo.status { |file, status_data| puts "#{file} has status: #{status_data.inspect}" }
|
1546
|
+
*
|
1547
|
+
* results in, for example:
|
1548
|
+
*
|
1549
|
+
* src/diff.c has status: [:index_new, :worktree_new]
|
1550
|
+
* README has status: [:worktree_modified]
|
1551
|
+
*
|
1552
|
+
* If a +path+ is given instead, the function will return the +status_data+ for
|
1553
|
+
* the file pointed to by path, or raise an exception if the path doesn't exist.
|
1554
|
+
*
|
1555
|
+
* +path+ must be relative to the repository's working directory.
|
1556
|
+
*
|
1557
|
+
* repo.status('src/diff.c') #=> [:index_new, :worktree_new]
|
1558
|
+
*/
|
1559
|
+
static VALUE rb_git_repo_status(int argc, VALUE *argv, VALUE self)
|
1560
|
+
{
|
1561
|
+
int error;
|
1562
|
+
VALUE rb_path;
|
1563
|
+
git_repository *repo;
|
1564
|
+
|
1565
|
+
Data_Get_Struct(self, git_repository, repo);
|
1566
|
+
|
1567
|
+
if (rb_scan_args(argc, argv, "01", &rb_path) == 1) {
|
1568
|
+
unsigned int flags;
|
1569
|
+
Check_Type(rb_path, T_STRING);
|
1570
|
+
error = git_status_file(&flags, repo, StringValueCStr(rb_path));
|
1571
|
+
rugged_exception_check(error);
|
1572
|
+
|
1573
|
+
return flags_to_rb(flags);
|
1574
|
+
}
|
1575
|
+
|
1576
|
+
if (!rb_block_given_p())
|
1577
|
+
rb_raise(rb_eRuntimeError,
|
1578
|
+
"A block was expected for iterating through "
|
1579
|
+
"the repository contents.");
|
1580
|
+
|
1581
|
+
error = git_status_foreach(
|
1582
|
+
repo,
|
1583
|
+
&rugged__status_cb,
|
1584
|
+
(void *)rb_block_proc()
|
1585
|
+
);
|
1586
|
+
|
1587
|
+
rugged_exception_check(error);
|
1588
|
+
return Qnil;
|
1589
|
+
}
|
1590
|
+
|
1591
|
+
static int rugged__each_id_cb(const git_oid *id, void *payload)
|
1592
|
+
{
|
1593
|
+
int *exception = (int *)payload;
|
1594
|
+
rb_protect(rb_yield, rugged_create_oid(id), exception);
|
1595
|
+
return *exception ? GIT_ERROR : GIT_OK;
|
1596
|
+
}
|
1597
|
+
|
1598
|
+
/*
|
1599
|
+
* call-seq:
|
1600
|
+
* repo.each_id { |id| block }
|
1601
|
+
* repo.each_id -> Iterator
|
1602
|
+
*
|
1603
|
+
* Call the given +block+ once with every object ID found in +repo+
|
1604
|
+
* and all its alternates. Object IDs are passed as 40-character
|
1605
|
+
* strings.
|
1606
|
+
*/
|
1607
|
+
static VALUE rb_git_repo_each_id(VALUE self)
|
1608
|
+
{
|
1609
|
+
git_repository *repo;
|
1610
|
+
git_odb *odb;
|
1611
|
+
int error, exception = 0;
|
1612
|
+
|
1613
|
+
if (!rb_block_given_p())
|
1614
|
+
return rb_funcall(self, rb_intern("to_enum"), 1, CSTR2SYM("each_id"));
|
1615
|
+
|
1616
|
+
Data_Get_Struct(self, git_repository, repo);
|
1617
|
+
|
1618
|
+
error = git_repository_odb(&odb, repo);
|
1619
|
+
rugged_exception_check(error);
|
1620
|
+
|
1621
|
+
error = git_odb_foreach(odb, &rugged__each_id_cb, &exception);
|
1622
|
+
git_odb_free(odb);
|
1623
|
+
|
1624
|
+
if (exception)
|
1625
|
+
rb_jump_tag(exception);
|
1626
|
+
rugged_exception_check(error);
|
1627
|
+
|
1628
|
+
return Qnil;
|
1629
|
+
}
|
1630
|
+
|
1631
|
+
static int parse_reset_type(VALUE rb_reset_type)
|
1632
|
+
{
|
1633
|
+
ID id_reset_type;
|
1634
|
+
|
1635
|
+
Check_Type(rb_reset_type, T_SYMBOL);
|
1636
|
+
id_reset_type = SYM2ID(rb_reset_type);
|
1637
|
+
|
1638
|
+
if (id_reset_type == rb_intern("soft")) {
|
1639
|
+
return GIT_RESET_SOFT;
|
1640
|
+
} else if (id_reset_type == rb_intern("mixed")) {
|
1641
|
+
return GIT_RESET_MIXED;
|
1642
|
+
} else if (id_reset_type == rb_intern("hard")) {
|
1643
|
+
return GIT_RESET_HARD;
|
1644
|
+
} else {
|
1645
|
+
rb_raise(rb_eArgError,
|
1646
|
+
"Invalid reset type. Expected `:soft`, `:mixed` or `:hard`");
|
1647
|
+
}
|
1648
|
+
}
|
1649
|
+
|
1650
|
+
/*
|
1651
|
+
* call-seq:
|
1652
|
+
* repo.reset(target, reset_type) -> nil
|
1653
|
+
*
|
1654
|
+
* Sets the current head to the specified commit oid and optionally
|
1655
|
+
* resets the index and working tree to match.
|
1656
|
+
* - +target+: Rugged::Commit, Rugged::Tag or rev that resolves to a commit or tag object
|
1657
|
+
* - +reset_type+: +:soft+, +:mixed+ or +:hard+
|
1658
|
+
*
|
1659
|
+
* [:soft]
|
1660
|
+
* the head will be moved to the commit.
|
1661
|
+
* [:mixed]
|
1662
|
+
* will trigger a +:soft+ reset, plus the index will be replaced
|
1663
|
+
* with the content of the commit tree.
|
1664
|
+
* [:hard]
|
1665
|
+
* will trigger a +:mixed+ reset and the working directory will be
|
1666
|
+
* replaced with the content of the index. (Untracked and ignored files
|
1667
|
+
* will be left alone)
|
1668
|
+
*
|
1669
|
+
* Examples:
|
1670
|
+
*
|
1671
|
+
* repo.reset('origin/master', :hard) #=> nil
|
1672
|
+
*/
|
1673
|
+
static VALUE rb_git_repo_reset(VALUE self, VALUE rb_target, VALUE rb_reset_type)
|
1674
|
+
{
|
1675
|
+
git_repository *repo;
|
1676
|
+
int reset_type;
|
1677
|
+
git_object *target = NULL;
|
1678
|
+
int error;
|
1679
|
+
|
1680
|
+
Data_Get_Struct(self, git_repository, repo);
|
1681
|
+
|
1682
|
+
reset_type = parse_reset_type(rb_reset_type);
|
1683
|
+
target = rugged_object_get(repo, rb_target, GIT_OBJ_ANY);
|
1684
|
+
|
1685
|
+
error = git_reset(repo, target, reset_type, NULL);
|
1686
|
+
|
1687
|
+
git_object_free(target);
|
1688
|
+
|
1689
|
+
rugged_exception_check(error);
|
1690
|
+
|
1691
|
+
return Qnil;
|
1692
|
+
}
|
1693
|
+
|
1694
|
+
/*
|
1695
|
+
* call-seq:
|
1696
|
+
* repo.reset_path(pathspecs, target=nil) -> nil
|
1697
|
+
*
|
1698
|
+
* Updates entries in the index from the +target+ commit tree, matching
|
1699
|
+
* the given +pathspecs+.
|
1700
|
+
*
|
1701
|
+
* Passing a nil +target+ will result in removing
|
1702
|
+
* entries in the index matching the provided pathspecs.
|
1703
|
+
*
|
1704
|
+
* - +pathspecs+: list of pathspecs to operate on (+String+ or +Array+ of +String+ objects)
|
1705
|
+
* - +target+(optional): Rugged::Commit, Rugged::Tag or rev that resolves to a commit or tag object.
|
1706
|
+
*
|
1707
|
+
* Examples:
|
1708
|
+
* reset_path(File.join('subdir','file.txt'), '441034f860c1d5d90e4188d11ae0d325176869a8') #=> nil
|
1709
|
+
*/
|
1710
|
+
static VALUE rb_git_repo_reset_path(int argc, VALUE *argv, VALUE self)
|
1711
|
+
{
|
1712
|
+
git_repository *repo;
|
1713
|
+
git_object *target = NULL;
|
1714
|
+
git_strarray pathspecs;
|
1715
|
+
VALUE rb_target, rb_paths;
|
1716
|
+
int error = 0;
|
1717
|
+
|
1718
|
+
pathspecs.strings = NULL;
|
1719
|
+
pathspecs.count = 0;
|
1720
|
+
|
1721
|
+
Data_Get_Struct(self, git_repository, repo);
|
1722
|
+
|
1723
|
+
rb_scan_args(argc, argv, "11", &rb_paths, &rb_target);
|
1724
|
+
|
1725
|
+
rugged_rb_ary_to_strarray(rb_paths, &pathspecs);
|
1726
|
+
|
1727
|
+
if (!NIL_P(rb_target))
|
1728
|
+
target = rugged_object_get(repo, rb_target, GIT_OBJ_ANY);
|
1729
|
+
|
1730
|
+
error = git_reset_default(repo, target, &pathspecs);
|
1731
|
+
|
1732
|
+
xfree(pathspecs.strings);
|
1733
|
+
git_object_free(target);
|
1734
|
+
|
1735
|
+
rugged_exception_check(error);
|
1736
|
+
|
1737
|
+
return Qnil;
|
1738
|
+
}
|
1739
|
+
|
1740
|
+
/*
|
1741
|
+
* call-seq:
|
1742
|
+
* repo.close -> nil
|
1743
|
+
*
|
1744
|
+
* Frees all the resources used by this repository immediately. The repository can
|
1745
|
+
* still be used after this call. Resources will be opened as necessary.
|
1746
|
+
*
|
1747
|
+
* It is not required to call this method explicitly. Repositories are closed
|
1748
|
+
* automatically before garbage collection
|
1749
|
+
*/
|
1750
|
+
static VALUE rb_git_repo_close(VALUE self)
|
1751
|
+
{
|
1752
|
+
git_repository *repo;
|
1753
|
+
Data_Get_Struct(self, git_repository, repo);
|
1754
|
+
|
1755
|
+
git_repository__cleanup(repo);
|
1756
|
+
|
1757
|
+
return Qnil;
|
1758
|
+
}
|
1759
|
+
|
1760
|
+
/*
|
1761
|
+
* call-seq:
|
1762
|
+
* repo.namespace = new_namespace
|
1763
|
+
*
|
1764
|
+
* Sets the active namespace for the repository.
|
1765
|
+
* If set to nil, no namespace will be active.
|
1766
|
+
*/
|
1767
|
+
static VALUE rb_git_repo_set_namespace(VALUE self, VALUE rb_namespace)
|
1768
|
+
{
|
1769
|
+
git_repository *repo;
|
1770
|
+
int error;
|
1771
|
+
|
1772
|
+
Data_Get_Struct(self, git_repository, repo);
|
1773
|
+
|
1774
|
+
if (!NIL_P(rb_namespace)) {
|
1775
|
+
Check_Type(rb_namespace, T_STRING);
|
1776
|
+
error = git_repository_set_namespace(repo, StringValueCStr(rb_namespace));
|
1777
|
+
} else {
|
1778
|
+
error = git_repository_set_namespace(repo, NULL);
|
1779
|
+
}
|
1780
|
+
rugged_exception_check(error);
|
1781
|
+
|
1782
|
+
return Qnil;
|
1783
|
+
}
|
1784
|
+
|
1785
|
+
/*
|
1786
|
+
* call-seq:
|
1787
|
+
* repo.namespace -> str
|
1788
|
+
*
|
1789
|
+
* Returns the active namespace for the repository.
|
1790
|
+
*/
|
1791
|
+
static VALUE rb_git_repo_get_namespace(VALUE self)
|
1792
|
+
{
|
1793
|
+
git_repository *repo;
|
1794
|
+
const char *namespace;
|
1795
|
+
|
1796
|
+
Data_Get_Struct(self, git_repository, repo);
|
1797
|
+
|
1798
|
+
namespace = git_repository_get_namespace(repo);
|
1799
|
+
return namespace ? rb_str_new_utf8(namespace) : Qnil;
|
1800
|
+
}
|
1801
|
+
|
1802
|
+
/*
|
1803
|
+
* call-seq:
|
1804
|
+
* repo.ahead_behind(local, upstream) -> Array
|
1805
|
+
*
|
1806
|
+
* Returns a 2 element Array containing the number of commits
|
1807
|
+
* that the upstream object is ahead and behind the local object.
|
1808
|
+
*
|
1809
|
+
* +local+ and +upstream+ can either be strings containing SHA1 OIDs or
|
1810
|
+
* Rugged::Object instances.
|
1811
|
+
*/
|
1812
|
+
static VALUE rb_git_repo_ahead_behind(VALUE self, VALUE rb_local, VALUE rb_upstream) {
|
1813
|
+
git_repository *repo;
|
1814
|
+
int error;
|
1815
|
+
git_oid local, upstream;
|
1816
|
+
size_t ahead, behind;
|
1817
|
+
VALUE rb_result;
|
1818
|
+
|
1819
|
+
Data_Get_Struct(self, git_repository, repo);
|
1820
|
+
|
1821
|
+
error = rugged_oid_get(&local, repo, rb_local);
|
1822
|
+
rugged_exception_check(error);
|
1823
|
+
|
1824
|
+
error = rugged_oid_get(&upstream, repo, rb_upstream);
|
1825
|
+
rugged_exception_check(error);
|
1826
|
+
|
1827
|
+
error = git_graph_ahead_behind(&ahead, &behind, repo, &local, &upstream);
|
1828
|
+
rugged_exception_check(error);
|
1829
|
+
|
1830
|
+
rb_result = rb_ary_new2(2);
|
1831
|
+
rb_ary_push(rb_result, INT2FIX((int) ahead));
|
1832
|
+
rb_ary_push(rb_result, INT2FIX((int) behind));
|
1833
|
+
return rb_result;
|
1834
|
+
}
|
1835
|
+
|
1836
|
+
/*
|
1837
|
+
* call-seq:
|
1838
|
+
* repo.default_signature -> signature or nil
|
1839
|
+
*
|
1840
|
+
* Returns a +Hash+ with the default user +signature+ or +nil+.
|
1841
|
+
*
|
1842
|
+
* Looks up the +user.name+ and +user.email+ from the configuration and
|
1843
|
+
* uses the current time as the timestamp, and creates a new signature
|
1844
|
+
* based on that information. It will return +nil+ if either the
|
1845
|
+
* +user.name+ or +user.email+ are not set.
|
1846
|
+
*
|
1847
|
+
* Returns a +Hash+:
|
1848
|
+
* - +:name+: the +user.name+ config value
|
1849
|
+
* - +:email+: the +user.email+ config value
|
1850
|
+
* - +:time+: the current time as a +Time+ instance
|
1851
|
+
*/
|
1852
|
+
static VALUE rb_git_repo_default_signature(VALUE self) {
|
1853
|
+
int error;
|
1854
|
+
git_repository *repo;
|
1855
|
+
git_signature *signature;
|
1856
|
+
VALUE rb_signature;
|
1857
|
+
|
1858
|
+
Data_Get_Struct(self, git_repository, repo);
|
1859
|
+
|
1860
|
+
error = git_signature_default(&signature, repo);
|
1861
|
+
|
1862
|
+
if (error == GIT_ENOTFOUND)
|
1863
|
+
return Qnil;
|
1864
|
+
|
1865
|
+
rugged_exception_check(error);
|
1866
|
+
|
1867
|
+
rb_signature = rugged_signature_new(signature, NULL);
|
1868
|
+
git_signature_free(signature);
|
1869
|
+
return rb_signature;
|
1870
|
+
}
|
1871
|
+
|
1872
|
+
void rugged__checkout_progress_cb(
|
1873
|
+
const char *path,
|
1874
|
+
size_t completed_steps,
|
1875
|
+
size_t total_steps,
|
1876
|
+
void *data
|
1877
|
+
) {
|
1878
|
+
struct rugged_cb_payload *payload = data;
|
1879
|
+
VALUE args = rb_ary_new2(4);
|
1880
|
+
rb_ary_push(args, payload->rb_data);
|
1881
|
+
rb_ary_push(args, path == NULL ? Qnil : rb_str_new2(path));
|
1882
|
+
rb_ary_push(args, INT2FIX(completed_steps));
|
1883
|
+
rb_ary_push(args, INT2FIX(total_steps));
|
1884
|
+
|
1885
|
+
rb_protect(rugged__block_yield_splat, args, &payload->exception);
|
1886
|
+
}
|
1887
|
+
|
1888
|
+
static int rugged__checkout_notify_cb(
|
1889
|
+
git_checkout_notify_t why,
|
1890
|
+
const char *path,
|
1891
|
+
const git_diff_file *baseline,
|
1892
|
+
const git_diff_file *target,
|
1893
|
+
const git_diff_file *workdir,
|
1894
|
+
void *data
|
1895
|
+
) {
|
1896
|
+
struct rugged_cb_payload *payload = data;
|
1897
|
+
VALUE args = rb_ary_new2(5);
|
1898
|
+
rb_ary_push(args, payload->rb_data);
|
1899
|
+
|
1900
|
+
switch (why) {
|
1901
|
+
case GIT_CHECKOUT_NOTIFY_CONFLICT:
|
1902
|
+
rb_ary_push(args, CSTR2SYM("conflict"));
|
1903
|
+
break;
|
1904
|
+
|
1905
|
+
case GIT_CHECKOUT_NOTIFY_DIRTY:
|
1906
|
+
rb_ary_push(args, CSTR2SYM("dirty"));
|
1907
|
+
break;
|
1908
|
+
|
1909
|
+
case GIT_CHECKOUT_NOTIFY_UPDATED:
|
1910
|
+
rb_ary_push(args, CSTR2SYM("updated"));
|
1911
|
+
break;
|
1912
|
+
|
1913
|
+
case GIT_CHECKOUT_NOTIFY_UNTRACKED:
|
1914
|
+
rb_ary_push(args, CSTR2SYM("untracked"));
|
1915
|
+
break;
|
1916
|
+
|
1917
|
+
case GIT_CHECKOUT_NOTIFY_IGNORED:
|
1918
|
+
rb_ary_push(args, CSTR2SYM("ignored"));
|
1919
|
+
break;
|
1920
|
+
|
1921
|
+
default:
|
1922
|
+
rb_ary_push(args, CSTR2SYM("unknown"));
|
1923
|
+
}
|
1924
|
+
|
1925
|
+
rb_ary_push(args, rb_git_delta_file_fromC(baseline));
|
1926
|
+
rb_ary_push(args, rb_git_delta_file_fromC(target));
|
1927
|
+
rb_ary_push(args, rb_git_delta_file_fromC(workdir));
|
1928
|
+
|
1929
|
+
rb_protect(rugged__block_yield_splat, args, &payload->exception);
|
1930
|
+
|
1931
|
+
return payload->exception ? GIT_ERROR : GIT_OK;
|
1932
|
+
}
|
1933
|
+
|
1934
|
+
/**
|
1935
|
+
* The caller has to free the returned git_checkout_options paths strings array.
|
1936
|
+
*/
|
1937
|
+
static void rugged_parse_checkout_options(git_checkout_options *opts, VALUE rb_options)
|
1938
|
+
{
|
1939
|
+
VALUE rb_value;
|
1940
|
+
|
1941
|
+
if (NIL_P(rb_options))
|
1942
|
+
return;
|
1943
|
+
|
1944
|
+
Check_Type(rb_options, T_HASH);
|
1945
|
+
|
1946
|
+
rb_value = rb_hash_aref(rb_options, CSTR2SYM("progress"));
|
1947
|
+
if (!NIL_P(rb_value)) {
|
1948
|
+
struct rugged_cb_payload *payload = malloc(sizeof(struct rugged_cb_payload));
|
1949
|
+
payload->rb_data = rb_value;
|
1950
|
+
payload->exception = 0;
|
1951
|
+
|
1952
|
+
opts->progress_payload = payload;
|
1953
|
+
opts->progress_cb = &rugged__checkout_progress_cb;
|
1954
|
+
}
|
1955
|
+
|
1956
|
+
rb_value = rb_hash_aref(rb_options, CSTR2SYM("notify"));
|
1957
|
+
if (!NIL_P(rb_value)) {
|
1958
|
+
struct rugged_cb_payload *payload = malloc(sizeof(struct rugged_cb_payload));
|
1959
|
+
payload->rb_data = rb_value;
|
1960
|
+
payload->exception = 0;
|
1961
|
+
|
1962
|
+
opts->notify_payload = payload;
|
1963
|
+
opts->notify_cb = &rugged__checkout_notify_cb;
|
1964
|
+
}
|
1965
|
+
|
1966
|
+
if (!NIL_P(rb_value = rb_hash_aref(rb_options, CSTR2SYM("strategy")))) {
|
1967
|
+
int i;
|
1968
|
+
|
1969
|
+
rb_value = rb_ary_to_ary(rb_value);
|
1970
|
+
for (i = 0; i < RARRAY_LEN(rb_value); ++i) {
|
1971
|
+
VALUE rb_strategy = rb_ary_entry(rb_value, i);
|
1972
|
+
|
1973
|
+
if (rb_strategy == CSTR2SYM("safe")) {
|
1974
|
+
opts->checkout_strategy |= GIT_CHECKOUT_SAFE;
|
1975
|
+
} else if (rb_strategy == CSTR2SYM("force")) {
|
1976
|
+
opts->checkout_strategy |= GIT_CHECKOUT_FORCE;
|
1977
|
+
} else if (rb_strategy == CSTR2SYM("recreate_missing")) {
|
1978
|
+
opts->checkout_strategy |= GIT_CHECKOUT_RECREATE_MISSING;
|
1979
|
+
} else if (rb_strategy == CSTR2SYM("allow_conflicts")) {
|
1980
|
+
opts->checkout_strategy |= GIT_CHECKOUT_ALLOW_CONFLICTS;
|
1981
|
+
} else if (rb_strategy == CSTR2SYM("remove_untracked")) {
|
1982
|
+
opts->checkout_strategy |= GIT_CHECKOUT_REMOVE_UNTRACKED;
|
1983
|
+
} else if (rb_strategy == CSTR2SYM("remove_ignored")) {
|
1984
|
+
opts->checkout_strategy |= GIT_CHECKOUT_REMOVE_IGNORED;
|
1985
|
+
} else if (rb_strategy == CSTR2SYM("update_only")) {
|
1986
|
+
opts->checkout_strategy |= GIT_CHECKOUT_UPDATE_ONLY;
|
1987
|
+
} else if (rb_strategy == CSTR2SYM("dont_update_index")) {
|
1988
|
+
opts->checkout_strategy |= GIT_CHECKOUT_DONT_UPDATE_INDEX;
|
1989
|
+
} else if (rb_strategy == CSTR2SYM("no_refresh")) {
|
1990
|
+
opts->checkout_strategy |= GIT_CHECKOUT_NO_REFRESH;
|
1991
|
+
} else if (rb_strategy == CSTR2SYM("disable_pathspec_match")) {
|
1992
|
+
opts->checkout_strategy |= GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH;
|
1993
|
+
} else if (rb_strategy == CSTR2SYM("skip_locked_directories")) {
|
1994
|
+
opts->checkout_strategy |= GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES;
|
1995
|
+
} else if (rb_strategy == CSTR2SYM("skip_unmerged")) {
|
1996
|
+
opts->checkout_strategy |= GIT_CHECKOUT_SKIP_UNMERGED;
|
1997
|
+
} else if (rb_strategy == CSTR2SYM("use_ours")) {
|
1998
|
+
opts->checkout_strategy |= GIT_CHECKOUT_USE_OURS;
|
1999
|
+
} else if (rb_strategy == CSTR2SYM("use_theirs")) {
|
2000
|
+
opts->checkout_strategy |= GIT_CHECKOUT_USE_THEIRS;
|
2001
|
+
} else if (rb_strategy == CSTR2SYM("update_submodules")) {
|
2002
|
+
opts->checkout_strategy |= GIT_CHECKOUT_UPDATE_SUBMODULES;
|
2003
|
+
} else if (rb_strategy == CSTR2SYM("update_submodules_if_changed")) {
|
2004
|
+
opts->checkout_strategy |= GIT_CHECKOUT_UPDATE_SUBMODULES_IF_CHANGED;
|
2005
|
+
} else if (rb_strategy != CSTR2SYM("none")) {
|
2006
|
+
rb_raise(rb_eArgError, "Unknown checkout strategy");
|
2007
|
+
}
|
2008
|
+
}
|
2009
|
+
}
|
2010
|
+
|
2011
|
+
if (!NIL_P(rb_value = rb_hash_aref(rb_options, CSTR2SYM("notify_flags")))) {
|
2012
|
+
int i;
|
2013
|
+
|
2014
|
+
rb_value = rb_ary_to_ary(rb_value);
|
2015
|
+
for (i = 0; i < RARRAY_LEN(rb_value); ++i) {
|
2016
|
+
VALUE rb_notify_flag = rb_ary_entry(rb_value, i);
|
2017
|
+
|
2018
|
+
if (rb_notify_flag == CSTR2SYM("conflict")) {
|
2019
|
+
opts->notify_flags |= GIT_CHECKOUT_NOTIFY_CONFLICT;
|
2020
|
+
} else if (rb_notify_flag == CSTR2SYM("dirty")) {
|
2021
|
+
opts->notify_flags |= GIT_CHECKOUT_NOTIFY_DIRTY;
|
2022
|
+
} else if (rb_notify_flag == CSTR2SYM("updated")) {
|
2023
|
+
opts->notify_flags |= GIT_CHECKOUT_NOTIFY_UPDATED;
|
2024
|
+
} else if (rb_notify_flag == CSTR2SYM("untracked")) {
|
2025
|
+
opts->notify_flags |= GIT_CHECKOUT_NOTIFY_UNTRACKED;
|
2026
|
+
} else if (rb_notify_flag == CSTR2SYM("ignored")) {
|
2027
|
+
opts->notify_flags |= GIT_CHECKOUT_NOTIFY_IGNORED;
|
2028
|
+
} else if (rb_notify_flag == CSTR2SYM("all")) {
|
2029
|
+
opts->notify_flags |= GIT_CHECKOUT_NOTIFY_ALL;
|
2030
|
+
} else if (rb_notify_flag != CSTR2SYM("none")) {
|
2031
|
+
rb_raise(rb_eArgError, "Unknown checkout notify flag");
|
2032
|
+
}
|
2033
|
+
}
|
2034
|
+
}
|
2035
|
+
|
2036
|
+
opts->disable_filters = RTEST(rb_hash_aref(rb_options, CSTR2SYM("disable_filters")));
|
2037
|
+
|
2038
|
+
rb_value = rb_hash_aref(rb_options, CSTR2SYM("dir_mode"));
|
2039
|
+
if (!NIL_P(rb_value)) {
|
2040
|
+
opts->dir_mode = FIX2UINT(rb_value);
|
2041
|
+
}
|
2042
|
+
|
2043
|
+
rb_value = rb_hash_aref(rb_options, CSTR2SYM("file_mode"));
|
2044
|
+
if (!NIL_P(rb_value)) {
|
2045
|
+
opts->file_mode = FIX2UINT(rb_value);
|
2046
|
+
}
|
2047
|
+
|
2048
|
+
rb_value = rb_hash_aref(rb_options, CSTR2SYM("file_open_flags"));
|
2049
|
+
if (!NIL_P(rb_value)) {
|
2050
|
+
opts->file_mode = FIX2INT(rb_value);
|
2051
|
+
}
|
2052
|
+
|
2053
|
+
rb_value = rb_hash_aref(rb_options, CSTR2SYM("target_directory"));
|
2054
|
+
if (!NIL_P(rb_value)) {
|
2055
|
+
opts->target_directory = StringValueCStr(rb_value);
|
2056
|
+
}
|
2057
|
+
|
2058
|
+
rb_value = rb_hash_aref(rb_options, CSTR2SYM("baseline"));
|
2059
|
+
if (!NIL_P(rb_value)) {
|
2060
|
+
if (rb_obj_is_kind_of(rb_value, rb_cRuggedTree)) {
|
2061
|
+
Data_Get_Struct(rb_value, git_tree, opts->baseline);
|
2062
|
+
} else {
|
2063
|
+
rb_raise(rb_eTypeError, "Expected a Rugged::Tree.");
|
2064
|
+
}
|
2065
|
+
}
|
2066
|
+
|
2067
|
+
rb_value = rb_hash_aref(rb_options, CSTR2SYM("paths"));
|
2068
|
+
rugged_rb_ary_to_strarray(rb_value, &opts->paths);
|
2069
|
+
}
|
2070
|
+
|
2071
|
+
/**
|
2072
|
+
* call-seq:
|
2073
|
+
* repo.checkout_tree(treeish[, options])
|
2074
|
+
*
|
2075
|
+
* Updates files in the index and working tree to match the content of the
|
2076
|
+
* tree pointed at by the +treeish+.
|
2077
|
+
*
|
2078
|
+
* The following options can be passed in the +options+ Hash:
|
2079
|
+
*
|
2080
|
+
* :progress ::
|
2081
|
+
* A callback that will be executed for checkout progress notifications.
|
2082
|
+
* Up to 3 parameters are passed on each execution:
|
2083
|
+
*
|
2084
|
+
* - The path to the last updated file (or +nil+ on the very first invocation).
|
2085
|
+
* - The number of completed checkout steps.
|
2086
|
+
* - The number of total checkout steps to be performed.
|
2087
|
+
*
|
2088
|
+
* :notify ::
|
2089
|
+
* A callback that will be executed for each checkout notification types specified
|
2090
|
+
* with +:notify_flags+. Up to 5 parameters are passed on each execution:
|
2091
|
+
*
|
2092
|
+
* - An array containing the +:notify_flags+ that caused the callback execution.
|
2093
|
+
* - The path of the current file.
|
2094
|
+
* - A hash describing the baseline blob (or +nil+ if it does not exist).
|
2095
|
+
* - A hash describing the target blob (or +nil+ if it does not exist).
|
2096
|
+
* - A hash describing the workdir blob (or +nil+ if it does not exist).
|
2097
|
+
*
|
2098
|
+
* :strategy ::
|
2099
|
+
* A single symbol or an array of symbols representing the strategies to use when
|
2100
|
+
* performing the checkout. Possible values are:
|
2101
|
+
*
|
2102
|
+
* :none ::
|
2103
|
+
* Perform a dry run (default).
|
2104
|
+
*
|
2105
|
+
* :safe ::
|
2106
|
+
* Allow safe updates that cannot overwrite uncommitted data.
|
2107
|
+
*
|
2108
|
+
* :recreate_missing ::
|
2109
|
+
* Allow checkout to recreate missing files.
|
2110
|
+
*
|
2111
|
+
* :force ::
|
2112
|
+
* Allow all updates to force working directory to look like index.
|
2113
|
+
*
|
2114
|
+
* :allow_conflicts ::
|
2115
|
+
* Allow checkout to make safe updates even if conflicts are found.
|
2116
|
+
*
|
2117
|
+
* :remove_untracked ::
|
2118
|
+
* Remove untracked files not in index (that are not ignored).
|
2119
|
+
*
|
2120
|
+
* :remove_ignored ::
|
2121
|
+
* Remove ignored files not in index.
|
2122
|
+
*
|
2123
|
+
* :update_only ::
|
2124
|
+
* Only update existing files, don't create new ones.
|
2125
|
+
*
|
2126
|
+
* :dont_update_index ::
|
2127
|
+
* Normally checkout updates index entries as it goes; this stops that.
|
2128
|
+
*
|
2129
|
+
* :no_refresh ::
|
2130
|
+
* Don't refresh index/config/etc before doing checkout.
|
2131
|
+
*
|
2132
|
+
* :disable_pathspec_match ::
|
2133
|
+
* Treat pathspec as simple list of exact match file paths.
|
2134
|
+
*
|
2135
|
+
* :skip_locked_directories ::
|
2136
|
+
* Ignore directories in use, they will be left empty.
|
2137
|
+
*
|
2138
|
+
* :skip_unmerged ::
|
2139
|
+
* Allow checkout to skip unmerged files (NOT IMPLEMENTED).
|
2140
|
+
*
|
2141
|
+
* :use_ours ::
|
2142
|
+
* For unmerged files, checkout stage 2 from index (NOT IMPLEMENTED).
|
2143
|
+
*
|
2144
|
+
* :use_theirs ::
|
2145
|
+
* For unmerged files, checkout stage 3 from index (NOT IMPLEMENTED).
|
2146
|
+
*
|
2147
|
+
* :update_submodules ::
|
2148
|
+
* Recursively checkout submodules with same options (NOT IMPLEMENTED).
|
2149
|
+
*
|
2150
|
+
* :update_submodules_if_changed ::
|
2151
|
+
* Recursively checkout submodules if HEAD moved in super repo (NOT IMPLEMENTED).
|
2152
|
+
*
|
2153
|
+
* :disable_filters ::
|
2154
|
+
* If +true+, filters like CRLF line conversion will be disabled.
|
2155
|
+
*
|
2156
|
+
* :dir_mode ::
|
2157
|
+
* Mode for newly created directories. Default: +0755+.
|
2158
|
+
*
|
2159
|
+
* :file_mode ::
|
2160
|
+
* Mode for newly created files. Default: +0755+ or +0644+.
|
2161
|
+
*
|
2162
|
+
* :file_open_flags ::
|
2163
|
+
* Mode for opening files. Default: <code>IO::CREAT | IO::TRUNC | IO::WRONLY</code>.
|
2164
|
+
*
|
2165
|
+
* :notify_flags ::
|
2166
|
+
* A single symbol or an array of symbols representing the cases in which the +:notify+
|
2167
|
+
* callback should be invoked. Possible values are:
|
2168
|
+
*
|
2169
|
+
* :none ::
|
2170
|
+
* Do not invoke the +:notify+ callback (default).
|
2171
|
+
*
|
2172
|
+
* :conflict ::
|
2173
|
+
* Invoke the callback for conflicting paths.
|
2174
|
+
*
|
2175
|
+
* :dirty ::
|
2176
|
+
* Invoke the callback for "dirty" files, i.e. those that do not need an update but
|
2177
|
+
* no longer match the baseline.
|
2178
|
+
*
|
2179
|
+
* :updated ::
|
2180
|
+
* Invoke the callback for any file that was changed.
|
2181
|
+
*
|
2182
|
+
* :untracked ::
|
2183
|
+
* Invoke the callback for untracked files.
|
2184
|
+
*
|
2185
|
+
* :ignored ::
|
2186
|
+
* Invoke the callback for ignored files.
|
2187
|
+
*
|
2188
|
+
* :all ::
|
2189
|
+
* Invoke the callback for all these cases.
|
2190
|
+
*
|
2191
|
+
* :paths ::
|
2192
|
+
* A glob string or an array of glob strings specifying which paths should be taken
|
2193
|
+
* into account for the checkout operation. +nil+ will match all files.
|
2194
|
+
* Default: +nil+.
|
2195
|
+
*
|
2196
|
+
* :baseline ::
|
2197
|
+
* A Rugged::Tree that represents the current, expected contents of the workdir.
|
2198
|
+
* Default: +HEAD+.
|
2199
|
+
*
|
2200
|
+
* :target_directory ::
|
2201
|
+
* A path to an alternative workdir directory in which the checkout should be performed.
|
2202
|
+
*/
|
2203
|
+
static VALUE rb_git_checkout_tree(int argc, VALUE *argv, VALUE self)
|
2204
|
+
{
|
2205
|
+
VALUE rb_treeish, rb_options;
|
2206
|
+
git_repository *repo;
|
2207
|
+
git_object *treeish;
|
2208
|
+
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
|
2209
|
+
struct rugged_cb_payload *payload;
|
2210
|
+
int error, exception = 0;
|
2211
|
+
|
2212
|
+
rb_scan_args(argc, argv, "10:", &rb_treeish, &rb_options);
|
2213
|
+
|
2214
|
+
if (TYPE(rb_treeish) == T_STRING) {
|
2215
|
+
rb_treeish = rugged_object_rev_parse(self, rb_treeish, 1);
|
2216
|
+
}
|
2217
|
+
|
2218
|
+
if (!rb_obj_is_kind_of(rb_treeish, rb_cRuggedCommit) &&
|
2219
|
+
!rb_obj_is_kind_of(rb_treeish, rb_cRuggedTag) &&
|
2220
|
+
!rb_obj_is_kind_of(rb_treeish, rb_cRuggedTree)) {
|
2221
|
+
rb_raise(rb_eTypeError, "Expected Rugged::Commit, Rugged::Tag or Rugged::Tree");
|
2222
|
+
}
|
2223
|
+
|
2224
|
+
Data_Get_Struct(self, git_repository, repo);
|
2225
|
+
Data_Get_Struct(rb_treeish, git_object, treeish);
|
2226
|
+
|
2227
|
+
rugged_parse_checkout_options(&opts, rb_options);
|
2228
|
+
|
2229
|
+
error = git_checkout_tree(repo, treeish, &opts);
|
2230
|
+
xfree(opts.paths.strings);
|
2231
|
+
|
2232
|
+
if ((payload = opts.notify_payload) != NULL) {
|
2233
|
+
exception = payload->exception;
|
2234
|
+
xfree(opts.notify_payload);
|
2235
|
+
}
|
2236
|
+
|
2237
|
+
if ((payload = opts.progress_payload) != NULL) {
|
2238
|
+
exception = payload->exception;
|
2239
|
+
xfree(opts.progress_payload);
|
2240
|
+
}
|
2241
|
+
|
2242
|
+
if (exception)
|
2243
|
+
rb_jump_tag(exception);
|
2244
|
+
|
2245
|
+
rugged_exception_check(error);
|
2246
|
+
|
2247
|
+
return Qnil;
|
2248
|
+
}
|
2249
|
+
|
2250
|
+
/**
|
2251
|
+
* call-seq: repo.checkout_index(index[,options]) -> nil
|
2252
|
+
*
|
2253
|
+
* Updates files in the index and the working tree to match the content of the
|
2254
|
+
* commit pointed at by +index+.
|
2255
|
+
*
|
2256
|
+
* See Repository#checkout_tree for a list of supported +options+.
|
2257
|
+
*/
|
2258
|
+
static VALUE rb_git_checkout_index(int argc, VALUE *argv, VALUE self)
|
2259
|
+
{
|
2260
|
+
VALUE rb_index, rb_options;
|
2261
|
+
git_repository *repo;
|
2262
|
+
git_index *index;
|
2263
|
+
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
|
2264
|
+
struct rugged_cb_payload *payload;
|
2265
|
+
int error, exception = 0;
|
2266
|
+
|
2267
|
+
rb_scan_args(argc, argv, "10:", &rb_index, &rb_options);
|
2268
|
+
|
2269
|
+
if (!rb_obj_is_kind_of(rb_index, rb_cRuggedIndex))
|
2270
|
+
rb_raise(rb_eTypeError, "Expected Rugged::Index");
|
2271
|
+
|
2272
|
+
Data_Get_Struct(self, git_repository, repo);
|
2273
|
+
Data_Get_Struct(rb_index, git_index, index);
|
2274
|
+
|
2275
|
+
rugged_parse_checkout_options(&opts, rb_options);
|
2276
|
+
|
2277
|
+
error = git_checkout_index(repo, index, &opts);
|
2278
|
+
xfree(opts.paths.strings);
|
2279
|
+
|
2280
|
+
if ((payload = opts.notify_payload) != NULL) {
|
2281
|
+
exception = payload->exception;
|
2282
|
+
xfree(opts.notify_payload);
|
2283
|
+
}
|
2284
|
+
|
2285
|
+
if ((payload = opts.progress_payload) != NULL) {
|
2286
|
+
exception = payload->exception;
|
2287
|
+
xfree(opts.progress_payload);
|
2288
|
+
}
|
2289
|
+
|
2290
|
+
if (exception)
|
2291
|
+
rb_jump_tag(exception);
|
2292
|
+
|
2293
|
+
rugged_exception_check(error);
|
2294
|
+
|
2295
|
+
return Qnil;
|
2296
|
+
}
|
2297
|
+
|
2298
|
+
/**
|
2299
|
+
* call-seq: repo.checkout_head([options]) -> nil
|
2300
|
+
*
|
2301
|
+
* Updates files in the index and the working tree to match the content of the
|
2302
|
+
* commit pointed at by +HEAD+.
|
2303
|
+
*
|
2304
|
+
* See Repository#checkout_tree for a list of supported +options+.
|
2305
|
+
*/
|
2306
|
+
static VALUE rb_git_checkout_head(int argc, VALUE *argv, VALUE self)
|
2307
|
+
{
|
2308
|
+
VALUE rb_options;
|
2309
|
+
git_repository *repo;
|
2310
|
+
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
|
2311
|
+
struct rugged_cb_payload *payload;
|
2312
|
+
int error, exception = 0;
|
2313
|
+
|
2314
|
+
rb_scan_args(argc, argv, "00:", &rb_options);
|
2315
|
+
|
2316
|
+
Data_Get_Struct(self, git_repository, repo);
|
2317
|
+
|
2318
|
+
rugged_parse_checkout_options(&opts, rb_options);
|
2319
|
+
|
2320
|
+
error = git_checkout_head(repo, &opts);
|
2321
|
+
xfree(opts.paths.strings);
|
2322
|
+
|
2323
|
+
if ((payload = opts.notify_payload) != NULL) {
|
2324
|
+
exception = payload->exception;
|
2325
|
+
xfree(opts.notify_payload);
|
2326
|
+
}
|
2327
|
+
|
2328
|
+
if ((payload = opts.progress_payload) != NULL) {
|
2329
|
+
exception = payload->exception;
|
2330
|
+
xfree(opts.progress_payload);
|
2331
|
+
}
|
2332
|
+
|
2333
|
+
if (exception)
|
2334
|
+
rb_jump_tag(exception);
|
2335
|
+
|
2336
|
+
rugged_exception_check(error);
|
2337
|
+
|
2338
|
+
return Qnil;
|
2339
|
+
}
|
2340
|
+
|
2341
|
+
/*
|
2342
|
+
* call-seq:
|
2343
|
+
* repo.path_ignored?(path) -> true or false
|
2344
|
+
*
|
2345
|
+
* Return whether a path is ignored or not.
|
2346
|
+
*/
|
2347
|
+
static VALUE rb_git_repo_is_path_ignored(VALUE self, VALUE rb_path) {
|
2348
|
+
git_repository *repo;
|
2349
|
+
const char *path;
|
2350
|
+
int error;
|
2351
|
+
int ignored;
|
2352
|
+
|
2353
|
+
Data_Get_Struct(self, git_repository, repo);
|
2354
|
+
path = StringValueCStr(rb_path);
|
2355
|
+
error = git_ignore_path_is_ignored(&ignored, repo, path);
|
2356
|
+
rugged_exception_check(error);
|
2357
|
+
return ignored ? Qtrue : Qfalse;
|
2358
|
+
}
|
2359
|
+
|
2360
|
+
static void rugged_parse_cherrypick_options(git_cherrypick_options *opts, VALUE rb_options)
|
2361
|
+
{
|
2362
|
+
VALUE rb_value;
|
2363
|
+
|
2364
|
+
if (NIL_P(rb_options))
|
2365
|
+
return;
|
2366
|
+
|
2367
|
+
Check_Type(rb_options, T_HASH);
|
2368
|
+
|
2369
|
+
rb_value = rb_hash_aref(rb_options, CSTR2SYM("mainline"));
|
2370
|
+
if (!NIL_P(rb_value)) {
|
2371
|
+
opts->mainline = FIX2UINT(rb_value);
|
2372
|
+
}
|
2373
|
+
}
|
2374
|
+
|
2375
|
+
static VALUE rugged_create_attr(const char *attr)
|
2376
|
+
{
|
2377
|
+
switch (git_attr_value(attr)) {
|
2378
|
+
case GIT_ATTR_TRUE_T:
|
2379
|
+
return Qtrue;
|
2380
|
+
|
2381
|
+
case GIT_ATTR_FALSE_T:
|
2382
|
+
return Qfalse;
|
2383
|
+
|
2384
|
+
case GIT_ATTR_VALUE_T:
|
2385
|
+
return rb_str_new2(attr);
|
2386
|
+
|
2387
|
+
case GIT_ATTR_UNSPECIFIED_T:
|
2388
|
+
default:
|
2389
|
+
return Qnil;
|
2390
|
+
}
|
2391
|
+
}
|
2392
|
+
|
2393
|
+
static int foreach_attr_hash(const char *name, const char *value, void *payload)
|
2394
|
+
{
|
2395
|
+
VALUE rb_hash = (VALUE)payload;
|
2396
|
+
rb_hash_aset(rb_hash, rb_str_new2(name), rugged_create_attr(value));
|
2397
|
+
return 0;
|
2398
|
+
}
|
2399
|
+
|
2400
|
+
static VALUE rb_git_repo_attributes(int argc, VALUE *argv, VALUE self)
|
2401
|
+
{
|
2402
|
+
VALUE rb_path, rb_names, rb_options;
|
2403
|
+
|
2404
|
+
git_repository *repo;
|
2405
|
+
int error, options = 0;
|
2406
|
+
|
2407
|
+
rb_scan_args(argc, argv, "12", &rb_path, &rb_names, &rb_options);
|
2408
|
+
|
2409
|
+
Data_Get_Struct(self, git_repository, repo);
|
2410
|
+
Check_Type(rb_path, T_STRING);
|
2411
|
+
|
2412
|
+
if (!NIL_P(rb_options)) {
|
2413
|
+
Check_Type(rb_options, T_FIXNUM);
|
2414
|
+
options = FIX2INT(rb_options);
|
2415
|
+
}
|
2416
|
+
|
2417
|
+
switch (TYPE(rb_names)) {
|
2418
|
+
case T_ARRAY:
|
2419
|
+
{
|
2420
|
+
VALUE rb_result;
|
2421
|
+
const char **values;
|
2422
|
+
const char **names;
|
2423
|
+
long i, num_attr = RARRAY_LEN(rb_names);
|
2424
|
+
|
2425
|
+
if (num_attr > 32)
|
2426
|
+
rb_raise(rb_eRuntimeError, "Too many attributes requested");
|
2427
|
+
|
2428
|
+
values = alloca(num_attr * sizeof(const char *));
|
2429
|
+
names = alloca(num_attr * sizeof(const char *));
|
2430
|
+
|
2431
|
+
for (i = 0; i < num_attr; ++i) {
|
2432
|
+
VALUE attr = rb_ary_entry(rb_names, i);
|
2433
|
+
Check_Type(attr, T_STRING);
|
2434
|
+
names[i] = StringValueCStr(attr);
|
2435
|
+
}
|
2436
|
+
|
2437
|
+
error = git_attr_get_many(
|
2438
|
+
values, repo, options,
|
2439
|
+
StringValueCStr(rb_path),
|
2440
|
+
(size_t)num_attr, names);
|
2441
|
+
|
2442
|
+
rugged_exception_check(error);
|
2443
|
+
|
2444
|
+
rb_result = rb_hash_new();
|
2445
|
+
for (i = 0; i < num_attr; ++i) {
|
2446
|
+
VALUE attr = rb_ary_entry(rb_names, i);
|
2447
|
+
rb_hash_aset(rb_result, attr, rugged_create_attr(values[i]));
|
2448
|
+
}
|
2449
|
+
return rb_result;
|
2450
|
+
}
|
2451
|
+
|
2452
|
+
case T_STRING:
|
2453
|
+
{
|
2454
|
+
const char *value;
|
2455
|
+
|
2456
|
+
error = git_attr_get(
|
2457
|
+
&value, repo, options,
|
2458
|
+
StringValueCStr(rb_path),
|
2459
|
+
StringValueCStr(rb_names));
|
2460
|
+
|
2461
|
+
rugged_exception_check(error);
|
2462
|
+
|
2463
|
+
return rugged_create_attr(value);
|
2464
|
+
}
|
2465
|
+
|
2466
|
+
case T_NIL:
|
2467
|
+
{
|
2468
|
+
VALUE rb_result = rb_hash_new();
|
2469
|
+
|
2470
|
+
error = git_attr_foreach(
|
2471
|
+
repo, options,
|
2472
|
+
StringValueCStr(rb_path),
|
2473
|
+
&foreach_attr_hash,
|
2474
|
+
(void *)rb_result);
|
2475
|
+
|
2476
|
+
rugged_exception_check(error);
|
2477
|
+
return rb_result;
|
2478
|
+
}
|
2479
|
+
|
2480
|
+
default:
|
2481
|
+
rb_raise(rb_eTypeError,
|
2482
|
+
"Invalid attribute name (expected String or Array)");
|
2483
|
+
}
|
2484
|
+
}
|
2485
|
+
|
2486
|
+
/*
|
2487
|
+
* call-seq:
|
2488
|
+
* repo.cherrypick(commit[, options]) -> nil
|
2489
|
+
*
|
2490
|
+
* Cherry-pick the given commit and update the index and working
|
2491
|
+
* directory accordingly.
|
2492
|
+
*
|
2493
|
+
* `commit` can be either a string containing a commit id or a
|
2494
|
+
* `Rugged::Commit` object.
|
2495
|
+
*
|
2496
|
+
* The following options can be passed in the +options+ Hash:
|
2497
|
+
*
|
2498
|
+
* :mainline ::
|
2499
|
+
* When cherry-picking a merge, you need to specify the parent number
|
2500
|
+
* (starting from 1) which should be considered the mainline.
|
2501
|
+
*/
|
2502
|
+
static VALUE rb_git_repo_cherrypick(int argc, VALUE *argv, VALUE self)
|
2503
|
+
{
|
2504
|
+
VALUE rb_options, rb_commit;
|
2505
|
+
|
2506
|
+
git_repository *repo;
|
2507
|
+
git_commit *commit;
|
2508
|
+
git_cherrypick_options opts = GIT_CHERRYPICK_OPTIONS_INIT;
|
2509
|
+
|
2510
|
+
int error;
|
2511
|
+
|
2512
|
+
rb_scan_args(argc, argv, "10:", &rb_commit, &rb_options);
|
2513
|
+
|
2514
|
+
if (TYPE(rb_commit) == T_STRING) {
|
2515
|
+
rb_commit = rugged_object_rev_parse(self, rb_commit, 1);
|
2516
|
+
}
|
2517
|
+
|
2518
|
+
if (!rb_obj_is_kind_of(rb_commit, rb_cRuggedCommit)) {
|
2519
|
+
rb_raise(rb_eArgError, "Expected a Rugged::Commit.");
|
2520
|
+
}
|
2521
|
+
|
2522
|
+
Data_Get_Struct(self, git_repository, repo);
|
2523
|
+
Data_Get_Struct(rb_commit, git_commit, commit);
|
2524
|
+
|
2525
|
+
rugged_parse_cherrypick_options(&opts, rb_options);
|
2526
|
+
|
2527
|
+
error = git_cherrypick(repo, commit, &opts);
|
2528
|
+
rugged_exception_check(error);
|
2529
|
+
|
2530
|
+
return Qnil;
|
2531
|
+
}
|
2532
|
+
|
2533
|
+
/*
|
2534
|
+
* call-seq:
|
2535
|
+
* repo.cherrypick_commit(commit, our_commit, [mainline, options]) -> nil
|
2536
|
+
*
|
2537
|
+
* Cherry-pick the given commit on the given base in-memory and
|
2538
|
+
* return an index with the result.
|
2539
|
+
*
|
2540
|
+
* `commit` can be either a string containing a commit id or a
|
2541
|
+
* `Rugged::Commit` object.
|
2542
|
+
*
|
2543
|
+
* `our_commit` is the base commit, can be either a string containing
|
2544
|
+
* a commit id or a `Rugged::Commit` object.
|
2545
|
+
*
|
2546
|
+
* `mainline` when cherry-picking a merge, this is the parent number
|
2547
|
+
* (starting from 1) which should be considered the mainline.
|
2548
|
+
*/
|
2549
|
+
static VALUE rb_git_repo_cherrypick_commit(int argc, VALUE *argv, VALUE self)
|
2550
|
+
{
|
2551
|
+
VALUE rb_options, rb_commit, rb_our_commit, rb_mainline;
|
2552
|
+
|
2553
|
+
git_repository *repo;
|
2554
|
+
git_commit *commit, *our_commit;
|
2555
|
+
git_merge_options opts = GIT_MERGE_OPTIONS_INIT;
|
2556
|
+
git_index *index;
|
2557
|
+
int error, mainline;
|
2558
|
+
|
2559
|
+
rb_scan_args(argc, argv, "21:", &rb_commit, &rb_our_commit, &rb_mainline, &rb_options);
|
2560
|
+
|
2561
|
+
if (TYPE(rb_commit) == T_STRING) {
|
2562
|
+
rb_commit = rugged_object_rev_parse(self, rb_commit, 1);
|
2563
|
+
}
|
2564
|
+
if (TYPE(rb_our_commit) == T_STRING) {
|
2565
|
+
rb_our_commit = rugged_object_rev_parse(self, rb_our_commit, 1);
|
2566
|
+
}
|
2567
|
+
|
2568
|
+
if (!rb_obj_is_kind_of(rb_commit, rb_cRuggedCommit)) {
|
2569
|
+
rb_raise(rb_eArgError, "Expected a Rugged::Commit.");
|
2570
|
+
}
|
2571
|
+
if (!rb_obj_is_kind_of(rb_our_commit, rb_cRuggedCommit)) {
|
2572
|
+
rb_raise(rb_eArgError, "Expected a Rugged::Commit.");
|
2573
|
+
}
|
2574
|
+
|
2575
|
+
Data_Get_Struct(self, git_repository, repo);
|
2576
|
+
Data_Get_Struct(rb_commit, git_commit, commit);
|
2577
|
+
Data_Get_Struct(rb_our_commit, git_commit, our_commit);
|
2578
|
+
|
2579
|
+
rugged_parse_merge_options(&opts, rb_options);
|
2580
|
+
|
2581
|
+
mainline = NIL_P(rb_mainline) ? 0 : FIX2UINT(rb_mainline);
|
2582
|
+
error = git_cherrypick_commit(&index, repo, commit, our_commit, mainline, &opts);
|
2583
|
+
rugged_exception_check(error);
|
2584
|
+
|
2585
|
+
return rugged_index_new(rb_cRuggedIndex, self, index);
|
2586
|
+
}
|
2587
|
+
|
2588
|
+
void Init_rugged_repo(void)
|
2589
|
+
{
|
2590
|
+
id_call = rb_intern("call");
|
2591
|
+
|
2592
|
+
rb_cRuggedRepo = rb_define_class_under(rb_mRugged, "Repository", rb_cObject);
|
2593
|
+
|
2594
|
+
rb_define_singleton_method(rb_cRuggedRepo, "new", rb_git_repo_new, -1);
|
2595
|
+
rb_define_singleton_method(rb_cRuggedRepo, "bare", rb_git_repo_open_bare, -1);
|
2596
|
+
rb_define_singleton_method(rb_cRuggedRepo, "hash_data", rb_git_repo_hash, 2);
|
2597
|
+
rb_define_singleton_method(rb_cRuggedRepo, "hash_file", rb_git_repo_hashfile, 2);
|
2598
|
+
rb_define_singleton_method(rb_cRuggedRepo, "init_at", rb_git_repo_init_at, -1);
|
2599
|
+
rb_define_singleton_method(rb_cRuggedRepo, "discover", rb_git_repo_discover, -1);
|
2600
|
+
rb_define_singleton_method(rb_cRuggedRepo, "clone_at", rb_git_repo_clone_at, -1);
|
2601
|
+
|
2602
|
+
rb_define_method(rb_cRuggedRepo, "close", rb_git_repo_close, 0);
|
2603
|
+
|
2604
|
+
rb_define_method(rb_cRuggedRepo, "exists?", rb_git_repo_exists, 1);
|
2605
|
+
rb_define_method(rb_cRuggedRepo, "include?", rb_git_repo_exists, 1);
|
2606
|
+
rb_define_method(rb_cRuggedRepo, "expand_oids", rb_git_repo_expand_oids, -1);
|
2607
|
+
rb_define_method(rb_cRuggedRepo, "descendant_of?", rb_git_repo_descendant_of, 2);
|
2608
|
+
|
2609
|
+
rb_define_method(rb_cRuggedRepo, "read", rb_git_repo_read, 1);
|
2610
|
+
rb_define_method(rb_cRuggedRepo, "read_header", rb_git_repo_read_header, 1);
|
2611
|
+
rb_define_method(rb_cRuggedRepo, "write", rb_git_repo_write, 2);
|
2612
|
+
rb_define_method(rb_cRuggedRepo, "each_id", rb_git_repo_each_id, 0);
|
2613
|
+
|
2614
|
+
rb_define_method(rb_cRuggedRepo, "path", rb_git_repo_path, 0);
|
2615
|
+
rb_define_method(rb_cRuggedRepo, "workdir", rb_git_repo_workdir, 0);
|
2616
|
+
rb_define_method(rb_cRuggedRepo, "workdir=", rb_git_repo_set_workdir, 1);
|
2617
|
+
rb_define_method(rb_cRuggedRepo, "status", rb_git_repo_status, -1);
|
2618
|
+
|
2619
|
+
rb_define_method(rb_cRuggedRepo, "index", rb_git_repo_get_index, 0);
|
2620
|
+
rb_define_method(rb_cRuggedRepo, "index=", rb_git_repo_set_index, 1);
|
2621
|
+
rb_define_method(rb_cRuggedRepo, "config", rb_git_repo_get_config, 0);
|
2622
|
+
rb_define_method(rb_cRuggedRepo, "config=", rb_git_repo_set_config, 1);
|
2623
|
+
|
2624
|
+
rb_define_method(rb_cRuggedRepo, "ident", rb_git_repo_get_ident, 0);
|
2625
|
+
rb_define_method(rb_cRuggedRepo, "ident=", rb_git_repo_set_ident, 1);
|
2626
|
+
|
2627
|
+
rb_define_method(rb_cRuggedRepo, "bare?", rb_git_repo_is_bare, 0);
|
2628
|
+
rb_define_method(rb_cRuggedRepo, "shallow?", rb_git_repo_is_shallow, 0);
|
2629
|
+
rb_define_method(rb_cRuggedRepo, "empty?", rb_git_repo_is_empty, 0);
|
2630
|
+
|
2631
|
+
rb_define_method(rb_cRuggedRepo, "head_detached?", rb_git_repo_head_detached, 0);
|
2632
|
+
rb_define_method(rb_cRuggedRepo, "head_unborn?", rb_git_repo_head_unborn, 0);
|
2633
|
+
rb_define_method(rb_cRuggedRepo, "head=", rb_git_repo_set_head, 1);
|
2634
|
+
rb_define_method(rb_cRuggedRepo, "head", rb_git_repo_get_head, 0);
|
2635
|
+
|
2636
|
+
rb_define_method(rb_cRuggedRepo, "merge_base", rb_git_repo_merge_base, -2);
|
2637
|
+
rb_define_method(rb_cRuggedRepo, "merge_bases", rb_git_repo_merge_bases, -2);
|
2638
|
+
|
2639
|
+
rb_define_method(rb_cRuggedRepo, "merge_analysis", rb_git_repo_merge_analysis, -1);
|
2640
|
+
rb_define_method(rb_cRuggedRepo, "merge_commits", rb_git_repo_merge_commits, -1);
|
2641
|
+
|
2642
|
+
rb_define_method(rb_cRuggedRepo, "revert_commit", rb_git_repo_revert_commit, -1);
|
2643
|
+
|
2644
|
+
rb_define_method(rb_cRuggedRepo, "path_ignored?", rb_git_repo_is_path_ignored, 1);
|
2645
|
+
|
2646
|
+
rb_define_method(rb_cRuggedRepo, "reset", rb_git_repo_reset, 2);
|
2647
|
+
rb_define_method(rb_cRuggedRepo, "reset_path", rb_git_repo_reset_path, -1);
|
2648
|
+
|
2649
|
+
rb_define_method(rb_cRuggedRepo, "namespace=", rb_git_repo_set_namespace, 1);
|
2650
|
+
rb_define_method(rb_cRuggedRepo, "namespace", rb_git_repo_get_namespace, 0);
|
2651
|
+
|
2652
|
+
rb_define_method(rb_cRuggedRepo, "ahead_behind", rb_git_repo_ahead_behind, 2);
|
2653
|
+
|
2654
|
+
rb_define_method(rb_cRuggedRepo, "default_signature", rb_git_repo_default_signature, 0);
|
2655
|
+
|
2656
|
+
rb_define_method(rb_cRuggedRepo, "checkout_tree", rb_git_checkout_tree, -1);
|
2657
|
+
rb_define_method(rb_cRuggedRepo, "checkout_index", rb_git_checkout_index, -1);
|
2658
|
+
rb_define_method(rb_cRuggedRepo, "checkout_head", rb_git_checkout_head, -1);
|
2659
|
+
|
2660
|
+
rb_define_method(rb_cRuggedRepo, "cherrypick", rb_git_repo_cherrypick, -1);
|
2661
|
+
rb_define_method(rb_cRuggedRepo, "cherrypick_commit", rb_git_repo_cherrypick_commit, -1);
|
2662
|
+
rb_define_method(rb_cRuggedRepo, "fetch_attributes", rb_git_repo_attributes, -1);
|
2663
|
+
|
2664
|
+
rb_cRuggedOdbObject = rb_define_class_under(rb_mRugged, "OdbObject", rb_cObject);
|
2665
|
+
rb_define_method(rb_cRuggedOdbObject, "data", rb_git_odbobj_data, 0);
|
2666
|
+
rb_define_method(rb_cRuggedOdbObject, "len", rb_git_odbobj_size, 0);
|
2667
|
+
rb_define_method(rb_cRuggedOdbObject, "type", rb_git_odbobj_type, 0);
|
2668
|
+
rb_define_method(rb_cRuggedOdbObject, "oid", rb_git_odbobj_oid, 0);
|
2669
|
+
}
|