hugo import jekyll support nested _posts directories
authorcoderzh <coderzh@gmail.com>
Wed, 2 Mar 2016 00:06:02 +0000 (08:06 +0800)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Sat, 1 Jul 2017 08:15:22 +0000 (10:15 +0200)
Fixes #1890
Closes #1911

commands/import_jekyll.go

index 26a41c82a0e78aa4914330b205a126bfd72556e8..3d89fee0d70a833e4551d3d2918de0693ff6e49a 100644 (file)
@@ -84,9 +84,17 @@ func importFromJekyll(cmd *cobra.Command, args []string) error {
        }
 
        forceImport, _ := cmd.Flags().GetBool("force")
-       site, err := createSiteFromJekyll(jekyllRoot, targetDir, forceImport)
+
+       fs := afero.NewOsFs()
+       jekyllPostDirs, hasAnyPost := getJekyllDirInfo(fs, jekyllRoot)
+       if !hasAnyPost {
+               return errors.New("Your Jekyll root contains neither posts nor drafts, aborting.")
+       }
+
+       site, err := createSiteFromJekyll(jekyllRoot, targetDir, jekyllPostDirs, forceImport)
+
        if err != nil {
-               return err
+               return newUserError(err)
        }
 
        jww.FEEDBACK.Println("Importing...")
@@ -110,10 +118,10 @@ func importFromJekyll(cmd *cobra.Command, args []string) error {
                draft := false
 
                switch {
-               case strings.HasPrefix(relPath, "_posts/"):
-                       relPath = "content/post" + relPath[len("_posts"):]
-               case strings.HasPrefix(relPath, "_drafts/"):
-                       relPath = "content/draft" + relPath[len("_drafts"):]
+               case strings.Contains(relPath, "_posts/"):
+                       relPath = filepath.Join("content/post", strings.Replace(relPath, "_posts/", "", -1))
+               case strings.Contains(relPath, "_drafts/"):
+                       relPath = filepath.Join("content/draft", strings.Replace(relPath, "_drafts/", "", -1))
                        draft = true
                default:
                        return nil
@@ -123,11 +131,19 @@ func importFromJekyll(cmd *cobra.Command, args []string) error {
                return convertJekyllPost(site, path, relPath, targetDir, draft)
        }
 
-       err = helpers.SymbolicWalk(hugofs.Os, jekyllRoot, callback)
-
-       if err != nil {
-               return err
+       for jekyllPostDir, hasAnyPostInDir := range jekyllPostDirs {
+               if hasAnyPostInDir {
+                       if err = helpers.SymbolicWalk(hugofs.Os, filepath.Join(jekyllRoot, jekyllPostDir), callback); err != nil {
+                               return err
+                       }
+               }
        }
+
+       jww.FEEDBACK.Println("Congratulations!", fileCount, "post(s) imported!")
+       jww.FEEDBACK.Println("Now, start Hugo by yourself:\n" +
+               "$ git clone https://github.com/spf13/herring-cove.git " + args[1] + "/themes/herring-cove")
+       jww.FEEDBACK.Println("$ cd " + args[1] + "\n$ hugo server --theme=herring-cove")
+
        jww.FEEDBACK.Println("Congratulations!", fileCount, "post(s) imported!")
        jww.FEEDBACK.Println("Now, start Hugo by yourself:\n" +
                "$ git clone https://github.com/spf13/herring-cove.git " + args[1] + "/themes/herring-cove")
@@ -136,15 +152,52 @@ func importFromJekyll(cmd *cobra.Command, args []string) error {
        return nil
 }
 
-// TODO: Consider calling doNewSite() instead?
-func createSiteFromJekyll(jekyllRoot, targetDir string, force bool) (*hugolib.Site, error) {
+func getJekyllDirInfo(fs afero.Fs, jekyllRoot string) (map[string]bool, bool) {
+       postDirs := make(map[string]bool)
+       hasAnyPost := false
+       if entries, err := ioutil.ReadDir(jekyllRoot); err == nil {
+               for _, entry := range entries {
+                       if entry.IsDir() {
+                               subDir := filepath.Join(jekyllRoot, entry.Name())
+                               if isPostDir, hasAnyPostInDir := retrieveJekyllPostDir(fs, subDir); isPostDir {
+                                       postDirs[entry.Name()] = hasAnyPostInDir
+                                       if hasAnyPostInDir {
+                                               hasAnyPost = true
+                                       }
+                               }
+                       }
+               }
+       }
+       return postDirs, hasAnyPost
+}
+
+func retrieveJekyllPostDir(fs afero.Fs, dir string) (bool, bool) {
+       if strings.HasSuffix(dir, "_posts") || strings.HasSuffix(dir, "_drafts") {
+               isEmpty, _ := helpers.IsEmpty(dir, fs)
+               return true, !isEmpty
+       }
+
+       if entries, err := ioutil.ReadDir(dir); err == nil {
+               for _, entry := range entries {
+                       if entry.IsDir() {
+                               subDir := filepath.Join(dir, entry.Name())
+                               if isPostDir, hasAnyPost := retrieveJekyllPostDir(fs, subDir); isPostDir {
+                                       return isPostDir, hasAnyPost
+                               }
+                       }
+               }
+       }
+
+       return false, true
+}
+
+func createSiteFromJekyll(jekyllRoot, targetDir string, jekyllPostDirs map[string]bool, force bool) (*hugolib.Site, error) {
        s, err := hugolib.NewSiteDefaultLang()
        if err != nil {
                return nil, err
        }
 
        fs := s.Fs.Source
-
        if exists, _ := helpers.Exists(targetDir, fs); exists {
                if isDir, _ := helpers.IsDir(targetDir, fs); !isDir {
                        return nil, errors.New("Target path \"" + targetDir + "\" already exists but not a directory")
@@ -159,24 +212,6 @@ func createSiteFromJekyll(jekyllRoot, targetDir string, force bool) (*hugolib.Si
 
        jekyllConfig := loadJekyllConfig(fs, jekyllRoot)
 
-       // Crude test to make sure at least one of _drafts/ and _posts/ exists
-       // and is not empty.
-       hasPostsOrDrafts := false
-       postsDir := filepath.Join(jekyllRoot, "_posts")
-       draftsDir := filepath.Join(jekyllRoot, "_drafts")
-       for _, d := range []string{postsDir, draftsDir} {
-               if exists, _ := helpers.Exists(d, fs); exists {
-                       if isDir, _ := helpers.IsDir(d, fs); isDir {
-                               if isEmpty, _ := helpers.IsEmpty(d, fs); !isEmpty {
-                                       hasPostsOrDrafts = true
-                               }
-                       }
-               }
-       }
-       if !hasPostsOrDrafts {
-               return nil, errors.New("Your Jekyll root contains neither posts nor drafts, aborting.")
-       }
-
        mkdir(targetDir, "layouts")
        mkdir(targetDir, "content")
        mkdir(targetDir, "archetypes")
@@ -186,7 +221,7 @@ func createSiteFromJekyll(jekyllRoot, targetDir string, force bool) (*hugolib.Si
 
        createConfigFromJekyll(fs, targetDir, "yaml", jekyllConfig)
 
-       copyJekyllFilesAndFolders(jekyllRoot, filepath.Join(targetDir, "static"))
+       copyJekyllFilesAndFolders(jekyllRoot, filepath.Join(targetDir, "static"), jekyllPostDirs)
 
        return s, nil
 }
@@ -318,7 +353,7 @@ func copyDir(source string, dest string) error {
        return nil
 }
 
-func copyJekyllFilesAndFolders(jekyllRoot string, dest string) error {
+func copyJekyllFilesAndFolders(jekyllRoot, dest string, jekyllPostDirs map[string]bool) (err error) {
        fi, err := os.Stat(jekyllRoot)
        if err != nil {
                return err
@@ -336,9 +371,11 @@ func copyJekyllFilesAndFolders(jekyllRoot string, dest string) error {
                dfp := filepath.Join(dest, entry.Name())
                if entry.IsDir() {
                        if entry.Name()[0] != '_' && entry.Name()[0] != '.' {
-                               err = copyDir(sfp, dfp)
-                               if err != nil {
-                                       jww.ERROR.Println(err)
+                               if _, ok := jekyllPostDirs[entry.Name()]; !ok {
+                                       err = copyDir(sfp, dfp)
+                                       if err != nil {
+                                               jww.ERROR.Println(err)
+                                       }
                                }
                        }
                } else {