shithub: hugo

Download patch

ref: 7ee1f25e9ef3be8f99c171e8e7982f4f82c13e16
parent: 3aa0e16d0caae7cbd084485cdb8ed65606a97b4c
author: coderzh <[email protected]>
date: Wed Mar 2 03:06:02 EST 2016

hugo import jekyll support nested _posts directories

Fixes #1890
Closes #1911

--- a/commands/import_jekyll.go
+++ b/commands/import_jekyll.go
@@ -84,9 +84,17 @@
 	}
 
 	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 @@
 		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,21 +131,67 @@
 		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")
+	jww.FEEDBACK.Println("$ cd " + args[1] + "\n$ hugo server --theme=herring-cove")
+
 	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
@@ -144,7 +198,6 @@
 	}
 
 	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 @@
 
 	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 @@
 
 	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 @@
 	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 @@
 		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 {