@@ -18,10 +18,12 @@ import (
1818 "context"
1919 "fmt"
2020 "path/filepath"
21+ "slices"
2122 "strings"
2223 "time"
2324
2425 "github.com/bep/simplecobra"
26+ "github.com/gohugoio/hugo/common/hugio"
2527 "github.com/gohugoio/hugo/config"
2628 "github.com/gohugoio/hugo/helpers"
2729 "github.com/gohugoio/hugo/hugofs"
@@ -200,6 +202,56 @@ func (c *convertCommand) convertAndSavePage(p page.Page, site *hugolib.Site, tar
200202 return nil
201203}
202204
205+ func (c * convertCommand ) copyContentDirsForOutput (pagesBackedByFile page.Pages ) error {
206+ contentDirs := make (map [string ]bool )
207+ for _ , p := range pagesBackedByFile {
208+ filename := p .File ().Filename ()
209+ contentDir := strings .TrimSuffix (filename , p .File ().Path ())
210+ if contentDir == filename {
211+ continue
212+ }
213+ contentDirs [filepath .Clean (contentDir )] = true
214+ }
215+
216+ var contentDirList []string
217+ for contentDir := range contentDirs {
218+ contentDirList = append (contentDirList , contentDir )
219+ }
220+ slices .Sort (contentDirList )
221+
222+ outputDirAbs , err := filepath .Abs (c .outputDir )
223+ if err != nil {
224+ return fmt .Errorf ("failed to resolve output path %q: %w" , c .outputDir , err )
225+ }
226+
227+ for _ , contentDir := range contentDirList {
228+ outputContentDirAbs := filepath .Join (outputDirAbs , filepath .Base (contentDir ))
229+
230+ skipDirs := make (map [string ]bool )
231+ relToOutputDir , err := filepath .Rel (contentDir , outputDirAbs )
232+ if err == nil && relToOutputDir != ".." && ! strings .HasPrefix (relToOutputDir , ".." + string (filepath .Separator )) {
233+ skipDirs [filepath .Clean (outputDirAbs )] = true
234+ }
235+ relToOutputContentDir , err := filepath .Rel (contentDir , outputContentDirAbs )
236+ if err == nil && relToOutputContentDir != ".." && ! strings .HasPrefix (relToOutputContentDir , ".." + string (filepath .Separator )) {
237+ skipDirs [filepath .Clean (outputContentDirAbs )] = true
238+ }
239+
240+ var shouldCopy func (filename string ) bool
241+ if len (skipDirs ) > 0 {
242+ shouldCopy = func (filename string ) bool {
243+ return ! skipDirs [filepath .Clean (filename )]
244+ }
245+ }
246+
247+ if err := hugio .CopyDir (hugofs .Os , contentDir , outputContentDirAbs , shouldCopy ); err != nil {
248+ return fmt .Errorf ("failed to copy %q to %q: %w" , contentDir , outputContentDirAbs , err )
249+ }
250+ }
251+
252+ return nil
253+ }
254+
203255func (c * convertCommand ) convertContents (format metadecoders.Format ) error {
204256 if c .outputDir == "" && ! c .unsafe {
205257 return newUserError ("Unsafe operation not allowed, use --unsafe or set a different output path" )
@@ -219,6 +271,12 @@ func (c *convertCommand) convertContents(format metadecoders.Format) error {
219271 pagesBackedByFile = append (pagesBackedByFile , p )
220272 }
221273
274+ if c .outputDir != "" {
275+ if err := c .copyContentDirsForOutput (pagesBackedByFile ); err != nil {
276+ return err
277+ }
278+ }
279+
222280 site .Log .Println ("processing" , len (pagesBackedByFile ), "content files" )
223281 for _ , p := range site .AllPages () {
224282 if err := c .convertAndSavePage (p , site , format ); err != nil {
0 commit comments