gitee.com/mirrors/Hugo-Go@v0.47.1/commands/convert.go (about) 1 // Copyright 2015 The Hugo Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package commands 15 16 import ( 17 "fmt" 18 "time" 19 20 src "github.com/gohugoio/hugo/source" 21 22 "github.com/gohugoio/hugo/hugolib" 23 24 "path/filepath" 25 26 "github.com/gohugoio/hugo/parser" 27 "github.com/spf13/cast" 28 "github.com/spf13/cobra" 29 ) 30 31 var ( 32 _ cmder = (*convertCmd)(nil) 33 ) 34 35 type convertCmd struct { 36 hugoBuilderCommon 37 38 outputDir string 39 unsafe bool 40 41 *baseCmd 42 } 43 44 func newConvertCmd() *convertCmd { 45 cc := &convertCmd{} 46 47 cc.baseCmd = newBaseCmd(&cobra.Command{ 48 Use: "convert", 49 Short: "Convert your content to different formats", 50 Long: `Convert your content (e.g. front matter) to different formats. 51 52 See convert's subcommands toJSON, toTOML and toYAML for more information.`, 53 RunE: nil, 54 }) 55 56 cc.cmd.AddCommand( 57 &cobra.Command{ 58 Use: "toJSON", 59 Short: "Convert front matter to JSON", 60 Long: `toJSON converts all front matter in the content directory 61 to use JSON for the front matter.`, 62 RunE: func(cmd *cobra.Command, args []string) error { 63 return cc.convertContents(rune([]byte(parser.JSONLead)[0])) 64 }, 65 }, 66 &cobra.Command{ 67 Use: "toTOML", 68 Short: "Convert front matter to TOML", 69 Long: `toTOML converts all front matter in the content directory 70 to use TOML for the front matter.`, 71 RunE: func(cmd *cobra.Command, args []string) error { 72 return cc.convertContents(rune([]byte(parser.TOMLLead)[0])) 73 }, 74 }, 75 &cobra.Command{ 76 Use: "toYAML", 77 Short: "Convert front matter to YAML", 78 Long: `toYAML converts all front matter in the content directory 79 to use YAML for the front matter.`, 80 RunE: func(cmd *cobra.Command, args []string) error { 81 return cc.convertContents(rune([]byte(parser.YAMLLead)[0])) 82 }, 83 }, 84 ) 85 86 cc.cmd.PersistentFlags().StringVarP(&cc.outputDir, "output", "o", "", "filesystem path to write files to") 87 cc.cmd.PersistentFlags().StringVarP(&cc.source, "source", "s", "", "filesystem path to read files relative from") 88 cc.cmd.PersistentFlags().BoolVar(&cc.unsafe, "unsafe", false, "enable less safe operations, please backup first") 89 cc.cmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{}) 90 91 return cc 92 } 93 94 func (cc *convertCmd) convertContents(mark rune) error { 95 if cc.outputDir == "" && !cc.unsafe { 96 return newUserError("Unsafe operation not allowed, use --unsafe or set a different output path") 97 } 98 99 c, err := initializeConfig(true, false, &cc.hugoBuilderCommon, cc, nil) 100 if err != nil { 101 return err 102 } 103 104 h, err := hugolib.NewHugoSites(*c.DepsCfg) 105 if err != nil { 106 return err 107 } 108 109 if err := h.Build(hugolib.BuildCfg{SkipRender: true}); err != nil { 110 return err 111 } 112 113 site := h.Sites[0] 114 115 site.Log.FEEDBACK.Println("processing", len(site.AllPages), "content files") 116 for _, p := range site.AllPages { 117 if err := cc.convertAndSavePage(p, site, mark); err != nil { 118 return err 119 } 120 } 121 return nil 122 } 123 124 func (cc *convertCmd) convertAndSavePage(p *hugolib.Page, site *hugolib.Site, mark rune) error { 125 // The resources are not in .Site.AllPages. 126 for _, r := range p.Resources.ByType("page") { 127 if err := cc.convertAndSavePage(r.(*hugolib.Page), site, mark); err != nil { 128 return err 129 } 130 } 131 132 if p.Filename() == "" { 133 // No content file. 134 return nil 135 } 136 137 site.Log.INFO.Println("Attempting to convert", p.LogicalName()) 138 newPage, err := site.NewPage(p.LogicalName()) 139 if err != nil { 140 return err 141 } 142 143 f, _ := p.File.(src.ReadableFile) 144 file, err := f.Open() 145 if err != nil { 146 site.Log.ERROR.Println("Error reading file:", p.Path()) 147 file.Close() 148 return nil 149 } 150 151 psr, err := parser.ReadFrom(file) 152 if err != nil { 153 site.Log.ERROR.Println("Error processing file:", p.Path()) 154 file.Close() 155 return err 156 } 157 158 file.Close() 159 160 metadata, err := psr.Metadata() 161 if err != nil { 162 site.Log.ERROR.Println("Error processing file:", p.Path()) 163 return err 164 } 165 166 // better handling of dates in formats that don't have support for them 167 if mark == parser.FormatToLeadRune("json") || mark == parser.FormatToLeadRune("yaml") || mark == parser.FormatToLeadRune("toml") { 168 newMetadata := cast.ToStringMap(metadata) 169 for k, v := range newMetadata { 170 switch vv := v.(type) { 171 case time.Time: 172 newMetadata[k] = vv.Format(time.RFC3339) 173 } 174 } 175 metadata = newMetadata 176 } 177 178 newPage.SetSourceContent(psr.Content()) 179 if err = newPage.SetSourceMetaData(metadata, mark); err != nil { 180 site.Log.ERROR.Printf("Failed to set source metadata for file %q: %s. For more info see For more info see https://github.com/gohugoio/hugo/issues/2458", newPage.FullFilePath(), err) 181 return nil 182 } 183 184 newFilename := p.Filename() 185 if cc.outputDir != "" { 186 newFilename = filepath.Join(cc.outputDir, p.Dir(), newPage.LogicalName()) 187 } 188 189 if err = newPage.SaveSourceAs(newFilename); err != nil { 190 return fmt.Errorf("Failed to save file %q: %s", newFilename, err) 191 } 192 193 return nil 194 }