1- // Licensed to Elasticsearch B.V under one or more agreements.
1+ // Licensed to Elasticsearch B.V under one or more agreements.
22// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
33// See the LICENSE file in the project root for more information
44
5+ using System . Collections . ObjectModel ;
56using System . IO . Abstractions ;
67using System . Text . RegularExpressions ;
78using Elastic . Markdown . IO ;
89using Microsoft . Extensions . Logging ;
910
10- namespace Documentation . Builder . Cli ;
11+ namespace Documentation . Mover ;
1112
12- internal class Move ( IFileSystem fileSystem , DocumentationSet documentationSet , ILoggerFactory loggerFactory )
13+ public class Move ( IFileSystem readFileSystem , IFileSystem writeFileSystem , DocumentationSet documentationSet , ILoggerFactory loggerFactory )
1314{
1415 private readonly ILogger _logger = loggerFactory . CreateLogger < Move > ( ) ;
1516 private readonly List < ( string filePath , string originalContent , string newContent ) > _changes = [ ] ;
17+ private readonly List < LinkModification > _linkModifications = [ ] ;
1618 private const string ChangeFormatString = "Change \e [31m{0}\e [0m to \e [32m{1}\e [0m at \e [34m{2}:{3}:{4}\e [0m" ;
1719
20+ public record LinkModification ( string OldLink , string NewLink , string SourceFile , int LineNumber , int ColumnNumber ) ;
21+
22+
23+ public ReadOnlyCollection < LinkModification > LinkModifications => _linkModifications . AsReadOnly ( ) ;
24+
1825 public async Task < int > Execute ( string ? source , string ? target , bool isDryRun , Cancel ctx = default )
1926 {
27+ _linkModifications . Clear ( ) ;
2028 if ( isDryRun )
2129 _logger . LogInformation ( "Running in dry-run mode" ) ;
2230
@@ -25,12 +33,13 @@ public async Task<int> Execute(string? source, string? target, bool isDryRun, Ca
2533 return 1 ;
2634 }
2735
36+
2837 var sourcePath = Path . GetFullPath ( source ! ) ;
2938 var targetPath = Path . GetFullPath ( target ! ) ;
3039
3140 var ( _, sourceMarkdownFile ) = documentationSet . MarkdownFiles . Single ( i => i . Value . FilePath == sourcePath ) ;
3241
33- var sourceContent = await fileSystem . File . ReadAllTextAsync ( sourceMarkdownFile . FilePath , ctx ) ;
42+ var sourceContent = await readFileSystem . File . ReadAllTextAsync ( sourceMarkdownFile . FilePath , ctx ) ;
3443
3544 var markdownLinkRegex = new Regex ( @"\[([^\]]*)\]\(((?:\.{0,2}\/)?[^:)]+\.md(?:#[^)]*)?)\)" , RegexOptions . Compiled ) ;
3645
@@ -51,16 +60,13 @@ public async Task<int> Execute(string? source, string? target, bool isDryRun, Ca
5160 var newLink = $ "[{ match . Groups [ 1 ] . Value } ]({ newPath } )";
5261 var lineNumber = sourceContent . Substring ( 0 , match . Index ) . Count ( c => c == '\n ' ) + 1 ;
5362 var columnNumber = match . Index - sourceContent . LastIndexOf ( '\n ' , match . Index ) ;
54- _logger . LogInformation (
55- string . Format (
56- ChangeFormatString ,
57- match . Value ,
58- newLink ,
59- sourceMarkdownFile . SourceFile . FullName ,
60- lineNumber ,
61- columnNumber
62- )
63- ) ;
63+ _linkModifications . Add ( new LinkModification (
64+ match . Value ,
65+ newLink ,
66+ sourceMarkdownFile . SourceFile . FullName ,
67+ lineNumber ,
68+ columnNumber
69+ ) ) ;
6470 return newLink ;
6571 } ) ;
6672
@@ -76,22 +82,34 @@ await ProcessMarkdownFile(
7682 ) ;
7783 }
7884
85+ foreach ( var ( oldLink , newLink , sourceFile , lineNumber , columnNumber ) in LinkModifications )
86+ {
87+ _logger . LogInformation ( string . Format (
88+ ChangeFormatString ,
89+ oldLink ,
90+ newLink ,
91+ sourceFile ,
92+ lineNumber ,
93+ columnNumber
94+ ) ) ;
95+ }
96+
7997 if ( isDryRun )
8098 return 0 ;
8199
82100 var targetDirectory = Path . GetDirectoryName ( targetPath ) ;
83- fileSystem . Directory . CreateDirectory ( targetDirectory ! ) ;
84- fileSystem . File . Move ( sourcePath , targetPath ) ;
101+ readFileSystem . Directory . CreateDirectory ( targetDirectory ! ) ;
102+ readFileSystem . File . Move ( sourcePath , targetPath ) ;
85103 try
86104 {
87105 foreach ( var ( filePath , _, newContent ) in _changes )
88- await fileSystem . File . WriteAllTextAsync ( filePath , newContent , ctx ) ;
106+ await writeFileSystem . File . WriteAllTextAsync ( filePath , newContent , ctx ) ;
89107 }
90108 catch ( Exception )
91109 {
92110 foreach ( var ( filePath , originalContent , _) in _changes )
93- await fileSystem . File . WriteAllTextAsync ( filePath , originalContent , ctx ) ;
94- fileSystem . File . Move ( targetPath , sourcePath ) ;
111+ await writeFileSystem . File . WriteAllTextAsync ( filePath , originalContent , ctx ) ;
112+ writeFileSystem . File . Move ( targetPath , sourcePath ) ;
95113 throw ;
96114 }
97115 return 0 ;
@@ -124,13 +142,13 @@ private bool ValidateInputs(string? source, string? target)
124142 return false ;
125143 }
126144
127- if ( ! fileSystem . File . Exists ( source ) )
145+ if ( ! readFileSystem . File . Exists ( source ) )
128146 {
129147 _logger . LogError ( $ "Source file { source } does not exist") ;
130148 return false ;
131149 }
132150
133- if ( fileSystem . File . Exists ( target ) )
151+ if ( readFileSystem . File . Exists ( target ) )
134152 {
135153 _logger . LogError ( $ "Target file { target } already exists") ;
136154 return false ;
@@ -145,7 +163,7 @@ private async Task ProcessMarkdownFile(
145163 MarkdownFile value ,
146164 Cancel ctx )
147165 {
148- var content = await fileSystem . File . ReadAllTextAsync ( value . FilePath , ctx ) ;
166+ var content = await readFileSystem . File . ReadAllTextAsync ( value . FilePath , ctx ) ;
149167 var currentDir = Path . GetDirectoryName ( value . FilePath ) ! ;
150168 var pathInfo = GetPathInfo ( currentDir , source , target ) ;
151169 var linkPattern = BuildLinkPattern ( pathInfo ) ;
@@ -199,30 +217,25 @@ MarkdownFile value
199217 : "" ;
200218
201219 string newLink ;
202- if ( originalPath . StartsWith ( "/" ) )
220+ if ( originalPath . StartsWith ( '/' ) )
203221 {
204- // Absolute style link
205222 newLink = $ "[{ match . Groups [ 1 ] . Value } ]({ absoluteStyleTarget } { anchor } )";
206223 }
207224 else
208225 {
209- // Relative link
210226 var relativeTarget = Path . GetRelativePath ( Path . GetDirectoryName ( value . FilePath ) ! , target ) ;
211227 newLink = $ "[{ match . Groups [ 1 ] . Value } ]({ relativeTarget } { anchor } )";
212228 }
213229
214230 var lineNumber = content . Substring ( 0 , match . Index ) . Count ( c => c == '\n ' ) + 1 ;
215231 var columnNumber = match . Index - content . LastIndexOf ( '\n ' , match . Index ) ;
216- _logger . LogInformation (
217- string . Format (
218- ChangeFormatString ,
219- match . Value ,
220- newLink ,
221- value . SourceFile . FullName ,
222- lineNumber ,
223- columnNumber
224- )
225- ) ;
232+ _linkModifications . Add ( new LinkModification (
233+ match . Value ,
234+ newLink ,
235+ value . SourceFile . FullName ,
236+ lineNumber ,
237+ columnNumber
238+ ) ) ;
226239 return newLink ;
227240 } ) ;
228241}
0 commit comments