1 /*
2  * Copyright 2010-2021 The pygit2 contributors
3  *
4  * This file is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License, version 2,
6  * as published by the Free Software Foundation.
7  *
8  * In addition to the permissions in the GNU General Public License,
9  * the authors give you unlimited permission to link the compiled
10  * version of this file into combinations with other programs,
11  * and to distribute those combinations without any restriction
12  * coming from the use of this file.  (The General Public License
13  * restrictions do apply in other respects; for example, they cover
14  * modification of the file, and distribution when not linked into
15  * a combined executable.)
16  *
17  * This file is distributed in the hope that it will be useful, but
18  * WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; see the file COPYING.  If not, write to
24  * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
25  * Boston, MA 02110-1301, USA.
26  */
27 
28 #define PY_SSIZE_T_CLEAN
29 #include <Python.h>
30 #include "error.h"
31 #include "object.h"
32 #include "oid.h"
33 #include "tree.h"
34 #include "utils.h"
35 #include "walker.h"
36 
37 extern PyTypeObject CommitType;
38 
39 void
Walker_dealloc(Walker * self)40 Walker_dealloc(Walker *self)
41 {
42     Py_CLEAR(self->repo);
43     git_revwalk_free(self->walk);
44     PyObject_Del(self);
45 }
46 
47 
48 PyDoc_STRVAR(Walker_hide__doc__,
49   "hide(oid)\n"
50   "\n"
51   "Mark a commit (and its ancestors) uninteresting for the output.");
52 
53 PyObject *
Walker_hide(Walker * self,PyObject * py_hex)54 Walker_hide(Walker *self, PyObject *py_hex)
55 {
56     int err;
57     git_oid oid;
58 
59     err = py_oid_to_git_oid_expand(self->repo->repo, py_hex, &oid);
60     if (err < 0)
61         return NULL;
62 
63     err = git_revwalk_hide(self->walk, &oid);
64     if (err < 0)
65         return Error_set(err);
66 
67     Py_RETURN_NONE;
68 }
69 
70 
71 PyDoc_STRVAR(Walker_push__doc__,
72   "push(oid)\n"
73   "\n"
74   "Mark a commit to start traversal from.");
75 
76 PyObject *
Walker_push(Walker * self,PyObject * py_hex)77 Walker_push(Walker *self, PyObject *py_hex)
78 {
79     int err;
80     git_oid oid;
81 
82     err = py_oid_to_git_oid_expand(self->repo->repo, py_hex, &oid);
83     if (err < 0)
84         return NULL;
85 
86     err = git_revwalk_push(self->walk, &oid);
87     if (err < 0)
88         return Error_set(err);
89 
90     Py_RETURN_NONE;
91 }
92 
93 
94 PyDoc_STRVAR(Walker_sort__doc__,
95   "sort(mode)\n"
96   "\n"
97   "Change the sorting mode (this resets the walker).");
98 
99 PyObject *
Walker_sort(Walker * self,PyObject * py_sort_mode)100 Walker_sort(Walker *self, PyObject *py_sort_mode)
101 {
102     long sort_mode;
103 
104     sort_mode = PyLong_AsLong(py_sort_mode);
105     if (sort_mode == -1 && PyErr_Occurred())
106         return NULL;
107 
108     git_revwalk_sorting(self->walk, (unsigned int)sort_mode);
109 
110     Py_RETURN_NONE;
111 }
112 
113 
114 PyDoc_STRVAR(Walker_reset__doc__,
115   "reset()\n"
116   "\n"
117   "Reset the walking machinery for reuse.");
118 
119 PyObject *
Walker_reset(Walker * self)120 Walker_reset(Walker *self)
121 {
122     git_revwalk_reset(self->walk);
123     Py_RETURN_NONE;
124 }
125 
126 PyDoc_STRVAR(Walker_simplify_first_parent__doc__,
127   "simplify_first_parent()\n"
128   "\n"
129   "Simplify the history by first-parent.");
130 
131 PyObject *
Walker_simplify_first_parent(Walker * self)132 Walker_simplify_first_parent(Walker *self)
133 {
134     git_revwalk_simplify_first_parent(self->walk);
135     Py_RETURN_NONE;
136 }
137 
138 PyObject *
Walker_iter(Walker * self)139 Walker_iter(Walker *self)
140 {
141     Py_INCREF(self);
142     return (PyObject*)self;
143 }
144 
145 PyObject *
Walker_iternext(Walker * self)146 Walker_iternext(Walker *self)
147 {
148     int err;
149     git_commit *commit;
150     git_oid oid;
151 
152     err = git_revwalk_next(&oid, self->walk);
153     if (err < 0)
154         return Error_set(err);
155 
156     err = git_commit_lookup(&commit, self->repo->repo, &oid);
157     if (err < 0)
158         return Error_set(err);
159 
160     return wrap_object((git_object*)commit, self->repo, NULL);
161 }
162 
163 PyMethodDef Walker_methods[] = {
164     METHOD(Walker, hide, METH_O),
165     METHOD(Walker, push, METH_O),
166     METHOD(Walker, reset, METH_NOARGS),
167     METHOD(Walker, simplify_first_parent, METH_NOARGS),
168     METHOD(Walker, sort, METH_O),
169     {NULL}
170 };
171 
172 
173 PyDoc_STRVAR(Walker__doc__, "Revision walker.");
174 
175 PyTypeObject WalkerType = {
176     PyVarObject_HEAD_INIT(NULL, 0)
177     "_pygit2.Walker",                          /* tp_name           */
178     sizeof(Walker),                            /* tp_basicsize      */
179     0,                                         /* tp_itemsize       */
180     (destructor)Walker_dealloc,                /* tp_dealloc        */
181     0,                                         /* tp_print          */
182     0,                                         /* tp_getattr        */
183     0,                                         /* tp_setattr        */
184     0,                                         /* tp_compare        */
185     0,                                         /* tp_repr           */
186     0,                                         /* tp_as_number      */
187     0,                                         /* tp_as_sequence    */
188     0,                                         /* tp_as_mapping     */
189     0,                                         /* tp_hash           */
190     0,                                         /* tp_call           */
191     0,                                         /* tp_str            */
192     0,                                         /* tp_getattro       */
193     0,                                         /* tp_setattro       */
194     0,                                         /* tp_as_buffer      */
195     Py_TPFLAGS_DEFAULT,                        /* tp_flags          */
196     Walker__doc__,                             /* tp_doc            */
197     0,                                         /* tp_traverse       */
198     0,                                         /* tp_clear          */
199     0,                                         /* tp_richcompare    */
200     0,                                         /* tp_weaklistoffset */
201     (getiterfunc)Walker_iter,                  /* tp_iter           */
202     (iternextfunc)Walker_iternext,             /* tp_iternext       */
203     Walker_methods,                            /* tp_methods        */
204     0,                                         /* tp_members        */
205     0,                                         /* tp_getset         */
206     0,                                         /* tp_base           */
207     0,                                         /* tp_dict           */
208     0,                                         /* tp_descr_get      */
209     0,                                         /* tp_descr_set      */
210     0,                                         /* tp_dictoffset     */
211     0,                                         /* tp_init           */
212     0,                                         /* tp_alloc          */
213     0,                                         /* tp_new            */
214 };
215