Skip to content

Commit a5110dd

Browse files
authored
feat: impl revwalk (#19)
1 parent 152e1a6 commit a5110dd

File tree

5 files changed

+411
-1
lines changed

5 files changed

+411
-1
lines changed

index.d.ts

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,8 @@ export declare class Repository {
543543
revparse(spec: string): Revspec
544544
/** Find a single object, as specified by a revision string. */
545545
revparseSingle(spec: string): string
546+
/** Create a revwalk that can be used to traverse the commit graph. */
547+
revwalk(): Revwalk
546548
}
547549
/**
548550
* A structure to represent a git [object][1]
@@ -660,3 +662,127 @@ export declare class Reference {
660662
*/
661663
rename(newName: string, options?: RenameReferenceOptions | undefined | null): Reference
662664
}
665+
/** Orderings that may be specified for Revwalk iteration. */
666+
export const enum RevwalkSort {
667+
/**
668+
* Sort the repository contents in no particular ordering.
669+
*
670+
* This sorting is arbitrary, implementation-specific, and subject to
671+
* change at any time. This is the default sorting for new walkers.
672+
*/
673+
None = 0,
674+
/**
675+
* Sort the repository contents in topological order (children before
676+
* parents).
677+
*
678+
* This sorting mode can be combined with time sorting.
679+
* (1 << 0)
680+
*/
681+
Topological = 1,
682+
/**
683+
* Sort the repository contents by commit time.
684+
*
685+
* This sorting mode can be combined with topological sorting.
686+
* (1 << 1)
687+
*/
688+
Time = 2,
689+
/**
690+
* Iterate through the repository contents in reverse order.
691+
*
692+
* This sorting mode can be combined with any others.
693+
* (1 << 2)
694+
*/
695+
Reverse = 4
696+
}
697+
/**
698+
* A revwalk allows traversal of the commit graph defined by including one or
699+
* more leaves and excluding one or more roots.
700+
*/
701+
export declare class Revwalk {
702+
[Symbol.iterator](): Iterator<string, void, void>
703+
/**
704+
* Reset a revwalk to allow re-configuring it.
705+
*
706+
* The revwalk is automatically reset when iteration of its commits
707+
* completes.
708+
*/
709+
reset(): this
710+
/** Set the order in which commits are visited. */
711+
setSorting(sort: number): this
712+
/**
713+
* Simplify the history by first-parent
714+
*
715+
* No parents other than the first for each commit will be enqueued.
716+
*/
717+
simplifyFirstParent(): this
718+
/**
719+
* Mark a commit to start traversal from.
720+
*
721+
* The given OID must belong to a commitish on the walked repository.
722+
*
723+
* The given commit will be used as one of the roots when starting the
724+
* revision walk. At least one commit must be pushed onto the walker before
725+
* a walk can be started.
726+
*/
727+
push(oid: string): this
728+
/**
729+
* Push the repository's HEAD
730+
*
731+
* For more information, see `push`.
732+
*/
733+
pushHead(): this
734+
/**
735+
* Push matching references
736+
*
737+
* The OIDs pointed to by the references that match the given glob pattern
738+
* will be pushed to the revision walker.
739+
*
740+
* A leading 'refs/' is implied if not present as well as a trailing `/ \
741+
* *` if the glob lacks '?', ' \ *' or '['.
742+
*
743+
* Any references matching this glob which do not point to a commitish
744+
* will be ignored.
745+
*/
746+
pushGlob(glob: string): this
747+
/**
748+
* Push and hide the respective endpoints of the given range.
749+
*
750+
* The range should be of the form `<commit>..<commit>` where each
751+
* `<commit>` is in the form accepted by `revparse_single`. The left-hand
752+
* commit will be hidden and the right-hand commit pushed.
753+
*/
754+
pushRange(range: string): this
755+
/**
756+
* Push the OID pointed to by a reference
757+
*
758+
* The reference must point to a commitish.
759+
*/
760+
pushRef(reference: string): this
761+
/** Mark a commit as not of interest to this revwalk. */
762+
hide(oid: string): this
763+
/**
764+
* Hide the repository's HEAD
765+
*
766+
* For more information, see `hide`.
767+
*/
768+
hideHead(): this
769+
/**
770+
* Hide matching references.
771+
*
772+
* The OIDs pointed to by the references that match the given glob pattern
773+
* and their ancestors will be hidden from the output on the revision walk.
774+
*
775+
* A leading 'refs/' is implied if not present as well as a trailing `/ \
776+
* *` if the glob lacks '?', ' \ *' or '['.
777+
*
778+
* Any references matching this glob which do not point to a commitish
779+
* will be ignored.
780+
*/
781+
hideGlob(glob: string): this
782+
/**
783+
* Hide the OID pointed to by a reference.
784+
*
785+
* The reference must point to a commitish.
786+
*/
787+
hideRef(reference: string): this
788+
}

index.js

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pub mod reference;
77
pub mod remote;
88
pub mod repository;
99
pub mod revparse;
10+
pub mod revwalk;
1011
pub mod signature;
1112
pub(crate) mod util;
1213

src/revwalk.rs

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
use crate::repository::Repository;
2+
use napi::bindgen_prelude::*;
3+
use napi_derive::napi;
4+
5+
#[napi]
6+
#[repr(u32)]
7+
/// Orderings that may be specified for Revwalk iteration.
8+
pub enum RevwalkSort {
9+
/// Sort the repository contents in no particular ordering.
10+
///
11+
/// This sorting is arbitrary, implementation-specific, and subject to
12+
/// change at any time. This is the default sorting for new walkers.
13+
None = 0,
14+
/// Sort the repository contents in topological order (children before
15+
/// parents).
16+
///
17+
/// This sorting mode can be combined with time sorting.
18+
/// (1 << 0)
19+
Topological = 1,
20+
/// Sort the repository contents by commit time.
21+
///
22+
/// This sorting mode can be combined with topological sorting.
23+
/// (1 << 1)
24+
Time = 2,
25+
/// Iterate through the repository contents in reverse order.
26+
///
27+
/// This sorting mode can be combined with any others.
28+
/// (1 << 2)
29+
Reverse = 4,
30+
}
31+
32+
#[napi(iterator)]
33+
/// A revwalk allows traversal of the commit graph defined by including one or
34+
/// more leaves and excluding one or more roots.
35+
pub struct Revwalk {
36+
pub(crate) inner: SharedReference<Repository, git2::Revwalk<'static>>,
37+
}
38+
39+
#[napi]
40+
impl Generator for Revwalk {
41+
type Yield = String;
42+
type Next = ();
43+
type Return = ();
44+
45+
fn next(&mut self, _value: Option<Self::Next>) -> Option<Self::Yield> {
46+
self.inner.next().and_then(|x| x.ok().map(|x| x.to_string()))
47+
}
48+
}
49+
50+
#[napi]
51+
impl Revwalk {
52+
#[napi]
53+
/// Reset a revwalk to allow re-configuring it.
54+
///
55+
/// The revwalk is automatically reset when iteration of its commits
56+
/// completes.
57+
pub fn reset(&mut self) -> Result<&Self> {
58+
self.inner.reset().map_err(crate::Error::from).map_err(Error::from)?;
59+
Ok(self)
60+
}
61+
62+
#[napi]
63+
/// Set the order in which commits are visited.
64+
pub fn set_sorting(&mut self, sort: u32) -> Result<&Self> {
65+
self
66+
.inner
67+
.set_sorting(git2::Sort::from_bits_retain(sort))
68+
.map_err(crate::Error::from)
69+
.map_err(Error::from)?;
70+
Ok(self)
71+
}
72+
73+
#[napi]
74+
/// Simplify the history by first-parent
75+
///
76+
/// No parents other than the first for each commit will be enqueued.
77+
pub fn simplify_first_parent(&mut self) -> Result<&Self> {
78+
self
79+
.inner
80+
.simplify_first_parent()
81+
.map_err(crate::Error::from)
82+
.map_err(Error::from)?;
83+
Ok(self)
84+
}
85+
86+
#[napi]
87+
/// Mark a commit to start traversal from.
88+
///
89+
/// The given OID must belong to a commitish on the walked repository.
90+
///
91+
/// The given commit will be used as one of the roots when starting the
92+
/// revision walk. At least one commit must be pushed onto the walker before
93+
/// a walk can be started.
94+
pub fn push(&mut self, oid: String) -> Result<&Self> {
95+
let oid = git2::Oid::from_str(&oid)
96+
.map_err(crate::Error::from)
97+
.map_err(Error::from)?;
98+
self.inner.push(oid).map_err(crate::Error::from).map_err(Error::from)?;
99+
Ok(self)
100+
}
101+
102+
#[napi]
103+
/// Push the repository's HEAD
104+
///
105+
/// For more information, see `push`.
106+
pub fn push_head(&mut self) -> Result<&Self> {
107+
self
108+
.inner
109+
.push_head()
110+
.map_err(crate::Error::from)
111+
.map_err(Error::from)?;
112+
Ok(self)
113+
}
114+
115+
#[napi]
116+
/// Push matching references
117+
///
118+
/// The OIDs pointed to by the references that match the given glob pattern
119+
/// will be pushed to the revision walker.
120+
///
121+
/// A leading 'refs/' is implied if not present as well as a trailing `/ \
122+
/// *` if the glob lacks '?', ' \ *' or '['.
123+
///
124+
/// Any references matching this glob which do not point to a commitish
125+
/// will be ignored.
126+
pub fn push_glob(&mut self, glob: String) -> Result<&Self> {
127+
self
128+
.inner
129+
.push_glob(&glob)
130+
.map_err(crate::Error::from)
131+
.map_err(Error::from)?;
132+
Ok(self)
133+
}
134+
135+
#[napi]
136+
/// Push and hide the respective endpoints of the given range.
137+
///
138+
/// The range should be of the form `<commit>..<commit>` where each
139+
/// `<commit>` is in the form accepted by `revparse_single`. The left-hand
140+
/// commit will be hidden and the right-hand commit pushed.
141+
pub fn push_range(&mut self, range: String) -> Result<&Self> {
142+
self
143+
.inner
144+
.push_range(&range)
145+
.map_err(crate::Error::from)
146+
.map_err(Error::from)?;
147+
Ok(self)
148+
}
149+
150+
#[napi]
151+
/// Push the OID pointed to by a reference
152+
///
153+
/// The reference must point to a commitish.
154+
pub fn push_ref(&mut self, reference: String) -> Result<&Self> {
155+
self
156+
.inner
157+
.push_ref(&reference)
158+
.map_err(crate::Error::from)
159+
.map_err(Error::from)?;
160+
Ok(self)
161+
}
162+
163+
#[napi]
164+
/// Mark a commit as not of interest to this revwalk.
165+
pub fn hide(&mut self, oid: String) -> Result<&Self> {
166+
let oid = git2::Oid::from_str(&oid)
167+
.map_err(crate::Error::from)
168+
.map_err(Error::from)?;
169+
self.inner.hide(oid).map_err(crate::Error::from).map_err(Error::from)?;
170+
Ok(self)
171+
}
172+
173+
#[napi]
174+
/// Hide the repository's HEAD
175+
///
176+
/// For more information, see `hide`.
177+
pub fn hide_head(&mut self) -> Result<&Self> {
178+
self
179+
.inner
180+
.hide_head()
181+
.map_err(crate::Error::from)
182+
.map_err(Error::from)?;
183+
Ok(self)
184+
}
185+
186+
#[napi]
187+
/// Hide matching references.
188+
///
189+
/// The OIDs pointed to by the references that match the given glob pattern
190+
/// and their ancestors will be hidden from the output on the revision walk.
191+
///
192+
/// A leading 'refs/' is implied if not present as well as a trailing `/ \
193+
/// *` if the glob lacks '?', ' \ *' or '['.
194+
///
195+
/// Any references matching this glob which do not point to a commitish
196+
/// will be ignored.
197+
pub fn hide_glob(&mut self, glob: String) -> Result<&Self> {
198+
self
199+
.inner
200+
.hide_glob(&glob)
201+
.map_err(crate::Error::from)
202+
.map_err(Error::from)?;
203+
Ok(self)
204+
}
205+
206+
#[napi]
207+
/// Hide the OID pointed to by a reference.
208+
///
209+
/// The reference must point to a commitish.
210+
pub fn hide_ref(&mut self, reference: String) -> Result<&Self> {
211+
self
212+
.inner
213+
.hide_ref(&reference)
214+
.map_err(crate::Error::from)
215+
.map_err(Error::from)?;
216+
Ok(self)
217+
}
218+
}
219+
220+
#[napi]
221+
impl Repository {
222+
#[napi]
223+
/// Create a revwalk that can be used to traverse the commit graph.
224+
pub fn revwalk(&self, this: Reference<Repository>, env: Env) -> crate::Result<Revwalk> {
225+
let inner = this.share_with(env, |repo| {
226+
repo.inner.revwalk().map_err(crate::Error::from).map_err(|e| e.into())
227+
})?;
228+
Ok(Revwalk { inner })
229+
}
230+
}

0 commit comments

Comments
 (0)