1+ //! A library for managing programming guides.
2+ //!
3+ //! See the docs for more information: https://nrx.dnbln.dev/docs/dx/git-voyage/
4+
5+ #![ deny( missing_docs) ]
6+
17pub extern crate git2;
28
39use std:: collections:: BTreeMap ;
@@ -32,22 +38,27 @@ use git2::build::CheckoutBuilder;
3238use serde:: Deserialize ;
3339use serde:: Serialize ;
3440
41+ /// The error type for this library.
3542#[ derive( Debug , thiserror:: Error ) ]
3643pub enum Error {
37- #[ error( "Failed to read steps: {0}" ) ]
38- ReadStepsError ( #[ from] serde_json:: Error ) ,
44+ /// Git error.
3945 #[ error( "git error: {0}" ) ]
4046 GitError ( #[ from] git2:: Error ) ,
47+ /// Dir-structure error.
4148 #[ error( "dir-structure error: {0}" ) ]
4249 DirStructureError ( #[ from] DirStructureError < PathBuf > ) ,
50+ /// IO error.
4351 #[ error( "IO error: {0}" ) ]
4452 IO ( #[ from] io:: Error ) ,
53+ /// Failed to parse step reference.
4554 #[ error( "Failed to parse step reference: {0}" ) ]
4655 ParseStepReferenceError ( String ) ,
4756}
4857
58+ /// A specialized `Result` type for this library.
4959pub type Result < T > = result:: Result < T , Error > ;
5060
61+ /// The main structure representing a guide.
5162#[ derive( DirStructure , HasField ) ]
5263pub struct Guide < Vfs : VfsCore < Path = Path > > {
5364 #[ dir_structure( path = "steps.json" ) ]
@@ -63,6 +74,7 @@ pub struct Guide<Vfs: VfsCore<Path = Path>> {
6374}
6475
6576impl Guide < FsVfs > {
77+ /// Create a new guide with default values.
6678 pub fn new_default ( dir : PathBuf , template_extension : & str ) -> Self {
6779 Self {
6880 steps : Versioned :: new_dirty (
@@ -106,9 +118,10 @@ End of the guide.
106118 }
107119 }
108120
121+ /// Add a new step to the guide.
109122 pub fn add_step (
110123 & mut self ,
111- step : & StepRef ,
124+ step : StepRef ,
112125 after_step : Option < & StepRef > ,
113126 code_extension : Option < Extension > ,
114127 before_after_extension : Option < Extension > ,
@@ -215,25 +228,30 @@ End of the guide.
215228 code_footer : None ,
216229 self_path : resolve_path ! ( [ Guide <FsVfs > @ self . self_path. clone( ) ] . step_dirs. ${ & step. 0 } ) ,
217230 } ;
218- self . step_dirs . push ( step. 0 . clone ( ) , step_dir) ;
231+ self . step_dirs . push ( step. 0 , step_dir) ;
219232 }
220233
234+ /// Get a step directory by its reference.
221235 pub fn get_step_dir ( & self , step : & StepRef ) -> Option < & StepDir < FsVfs > > {
222236 self . step_dirs . get_value_by_name ( & step. 0 )
223237 }
224238
239+ /// Get an iterator over the steps and their directories.
225240 pub fn steps_iter ( & self ) -> StepsIter < ' _ > {
226241 StepsIter ( self . steps . steps . iter ( ) , & self . step_dirs )
227242 }
228243
244+ /// Get the template content.
229245 pub fn template ( & self ) -> & String {
230246 self . template . value ( )
231247 }
232248
249+ /// Render the template with the given steps content.
233250 pub fn render_template ( & self , steps : String ) -> String {
234251 self . template ( ) . replace ( "<__GitVoyageSteps />" , & steps)
235252 }
236253
254+ /// Render the entire guide as a string.
237255 pub fn render_guide ( & self ) -> String {
238256 let mut steps = String :: new ( ) ;
239257 for ( _step, step_dir) in self . steps_iter ( ) {
@@ -243,6 +261,7 @@ End of the guide.
243261 }
244262}
245263
264+ /// A file extension, including the leading dot if any.
246265#[ derive( Debug ) ]
247266pub struct Extension ( String ) ;
248267
@@ -253,18 +272,24 @@ impl fmt::Display for Extension {
253272}
254273
255274impl Extension {
275+ /// Create a new extension from a string.
276+ ///
277+ /// The string should include the leading dot if any, or be empty if not.
256278 pub const fn new ( ext : String ) -> Self {
257279 Self ( ext)
258280 }
259281
282+ /// Default code extension is empty (no extension).
260283 pub fn default_code_extension ( ) -> Self {
261284 Self :: new ( String :: new ( ) )
262285 }
263286
287+ /// Default before/after extension is `.mdx`.
264288 pub fn default_before_after_extension ( ) -> Self {
265289 Self :: new ( String :: from ( ".mdx" ) )
266290 }
267291
292+ /// Get the value of the extension.
268293 pub fn value ( & self ) -> & str {
269294 & self . 0
270295 }
@@ -283,6 +308,7 @@ impl Extension {
283308 }
284309}
285310
311+ /// Iterator over steps and their directories.
286312pub struct StepsIter < ' a > ( slice:: Iter < ' a , StepRef > , & ' a DirChildren < StepDir < FsVfs > > ) ;
287313
288314impl < ' a > Iterator for StepsIter < ' a > {
@@ -313,25 +339,33 @@ impl<'a> DoubleEndedIterator for StepsIter<'a> {
313339 }
314340}
315341
342+ /// A directory representing a single step in the guide.
316343#[ derive( DirStructure , HasField ) ]
317344pub struct StepDir < Vfs : VfsCore < Path = Path > > {
345+ /// The "before" file, optional.
318346 #[ dir_structure( path = self ) ]
319- before : DirChildSingleOpt < Versioned < String , Vfs :: Path > , BeforeFilter , Vfs :: Path > ,
347+ pub before : DirChildSingleOpt < Versioned < String , Vfs :: Path > , BeforeFilter , Vfs :: Path > ,
348+ /// The "after" file, optional.
320349 #[ dir_structure( path = self ) ]
321- after : DirChildSingleOpt < Versioned < String , Vfs :: Path > , AfterFilter , Vfs :: Path > ,
350+ pub after : DirChildSingleOpt < Versioned < String , Vfs :: Path > , AfterFilter , Vfs :: Path > ,
351+ /// The "code" file, required.
322352 #[ dir_structure( path = self ) ]
323353 pub code : DirChildSingle < Versioned < String , Vfs :: Path > , CodeFilter , Vfs :: Path > ,
324354
325- code_header : Option < Versioned < String , Vfs :: Path > > ,
326- code_footer : Option < Versioned < String , Vfs :: Path > > ,
355+ /// Optional code header, if not present, the guide's code header is used if any.
356+ pub code_header : Option < Versioned < String , Vfs :: Path > > ,
357+ /// Optional code footer, if not present, the guide's code footer is used if any.
358+ pub code_footer : Option < Versioned < String , Vfs :: Path > > ,
327359 self_path : PathBuf ,
328360}
329361
330362impl StepDir < FsVfs > {
363+ /// Get the path to the code file.
331364 pub fn code_path ( & self ) -> PathBuf {
332365 self . self_path . join ( self . code . file_name ( ) )
333366 }
334367
368+ /// Render the step as a string. This uses the guide's code header and footer if any, if the step's code_header/footer are not present.
335369 pub fn render_step ( & self , guide : & Guide < FsVfs > ) -> String {
336370 let mut output = String :: new ( ) ;
337371 if let DirChildSingleOpt :: Some ( before) = & self . before {
@@ -351,6 +385,7 @@ impl StepDir<FsVfs> {
351385 output
352386 }
353387
388+ /// Guess the extension for the before/after files, if any.
354389 pub fn before_after_extension ( & self ) -> Option < Extension > {
355390 self . before
356391 . as_ref ( )
@@ -363,30 +398,43 @@ impl StepDir<FsVfs> {
363398 . map ( |dir| Extension :: guess_from ( & dir) )
364399 }
365400
401+ /// Guess the extension for the code file.
366402 pub fn code_extension ( & self ) -> Extension {
367403 Extension :: guess_from ( & self . code )
368404 }
369405}
370406
371- file_prefix_filter ! ( pub TemplateFilter , "template" ) ;
372- file_prefix_filter ! ( pub BeforeFilter , "before" ) ;
373- file_prefix_filter ! ( pub AfterFilter , "after" ) ;
374- file_prefix_filter ! ( pub CodeFilter , "code" ) ;
375-
407+ file_prefix_filter ! (
408+ /// Filter for the template file.
409+ pub TemplateFilter , "template" ) ;
410+ file_prefix_filter ! (
411+ /// Filter for the before file.
412+ pub BeforeFilter , "before" ) ;
413+ file_prefix_filter ! (
414+ /// Filter for the after file.
415+ pub AfterFilter , "after" ) ;
416+ file_prefix_filter ! (
417+ /// Filter for the code file.
418+ pub CodeFilter , "code" ) ;
419+
420+ /// The steps structure, containing a list of step references.
376421#[ derive( Deserialize , Serialize , Debug , Clone , PartialEq , Eq ) ]
377422pub struct Steps {
378423 steps : Vec < StepRef > ,
379424}
380425
426+ /// A reference to a step.
381427#[ derive( Deserialize , Serialize , Debug , Clone , PartialEq , Eq ) ]
382428#[ repr( transparent) ]
383429pub struct StepRef ( String ) ;
384430
385431impl StepRef {
432+ /// Create a new step reference from a string.
386433 pub fn new ( path : String ) -> Self {
387434 Self ( path)
388435 }
389436
437+ /// Get the path (name) of the step.
390438 pub fn path ( & self ) -> & str {
391439 & self . 0
392440 }
@@ -411,8 +459,8 @@ impl<T> DbgGitErr for result::Result<T, git2::Error> {
411459 }
412460}
413461
414- fn perform_patchup (
415- guide : & Guide < FsVfs > ,
462+ fn perform_patchup < V : VfsCore < Path = Path > > (
463+ guide : & Guide < V > ,
416464 step : & StepRef ,
417465 new_code : & str ,
418466 repo_root : & Path ,
@@ -570,8 +618,21 @@ fn perform_patchup(
570618 Ok ( empty_steps)
571619}
572620
573- pub fn patchup (
574- guide : & mut Guide < FsVfs > ,
621+ /// Perform a patchup of a step in the guide, updating the guide's step identified by `step` with the new code provided in `new_code`.
622+ ///
623+ /// This function will then rebase all subsequent steps to ensure they are applied on top of the updated step.
624+ ///
625+ /// If any conflicts arise during the rebase, the provided `resolve_conflict` function will be called with the path to the code file,
626+ /// allowing the user to manually resolve the conflict. This function should open an editor or perform any necessary actions to resolve the conflict,
627+ /// and return `Ok(())` if successful, or an `Err` if the conflict could not be resolved.
628+ ///
629+ /// After resolve_conflict returns, this function will add the resolved code file to the index and continue the rebase process.
630+ ///
631+ /// After everything is done, the guide's steps will be updated to reflect the new code state, but this will not be automatically saved to disk.
632+ ///
633+ /// `dir` is a temporary directory where a temporary git repository will be created. You should ensure this directory exists and is writable.
634+ pub fn patchup < V : VfsCore < Path = Path > > (
635+ guide : & mut Guide < V > ,
575636 dir : & Path ,
576637 step : & StepRef ,
577638 new_code : & str ,
@@ -596,8 +657,8 @@ pub fn patchup(
596657 Ok ( ( ) )
597658}
598659
599- pub fn repatch (
600- guide : & mut Guide < FsVfs > ,
660+ fn repatch < V : VfsCore < Path = Path > > (
661+ guide : & mut Guide < V > ,
601662 dir : & Path ,
602663 empty_commits : & BTreeMap < String , String > ,
603664) -> Result < ( ) > {
0 commit comments