From 7d40da876c62a166bdd273209b7cd6bead9266c1 Mon Sep 17 00:00:00 2001 From: satotake Date: Thu, 1 Sep 2022 00:23:31 +0900 Subject: [PATCH] Add `--force` to `hugo new` Closes #9243 --- commands/new.go | 4 ++- create/content.go | 8 +++--- create/content_test.go | 45 ++++++++++++++++++++++++++------- hugolib/content_factory.go | 5 +++- hugolib/content_factory_test.go | 4 +-- 5 files changed, 50 insertions(+), 16 deletions(-) diff --git a/commands/new.go b/commands/new.go index c5b5cd182..bf626a6a5 100644 --- a/commands/new.go +++ b/commands/new.go @@ -32,6 +32,7 @@ var _ cmder = (*newCmd)(nil) type newCmd struct { contentEditor string contentType string + force bool *baseBuilderCmd } @@ -54,6 +55,7 @@ Ensure you run this within the root directory of your site.`, cmd.Flags().StringVarP(&cc.contentType, "kind", "k", "", "content type to create") cmd.Flags().StringVar(&cc.contentEditor, "editor", "", "edit new content with this editor, if provided") + cmd.Flags().BoolVarP(&cc.force, "force", "f", false, "allow to override file") cmd.AddCommand(b.newNewSiteCmd().getCommand()) cmd.AddCommand(b.newNewThemeCmd().getCommand()) @@ -80,7 +82,7 @@ func (n *newCmd) newContent(cmd *cobra.Command, args []string) error { return newUserError("path needs to be provided") } - return create.NewContent(c.hugo(), n.contentType, args[0]) + return create.NewContent(c.hugo(), n.contentType, args[0], n.force) } func mkdir(x ...string) { diff --git a/create/content.go b/create/content.go index 5f05e25f9..0b9f27797 100644 --- a/create/content.go +++ b/create/content.go @@ -52,7 +52,7 @@ draft: true // NewContent creates a new content file in h (or a full bundle if the archetype is a directory) // in targetPath. -func NewContent(h *hugolib.HugoSites, kind, targetPath string) error { +func NewContent(h *hugolib.HugoSites, kind, targetPath string, force bool) error { if h.BaseFs.Content.Dirs == nil { return errors.New("no existing content directory configured for this project") } @@ -76,6 +76,7 @@ func NewContent(h *hugolib.HugoSites, kind, targetPath string) error { kind: kind, targetPath: targetPath, + force: force, } ext := paths.Ext(targetPath) @@ -132,6 +133,7 @@ type contentBuilder struct { kind string isDir bool dirMap archetypeMap + force bool } func (b *contentBuilder) buildDir() error { @@ -145,7 +147,7 @@ func (b *contentBuilder) buildDir() error { for _, fi := range b.dirMap.contentFiles { targetFilename := filepath.Join(b.targetPath, strings.TrimPrefix(fi.Meta().Path, b.archetypeFilename)) - abs, err := b.cf.CreateContentPlaceHolder(targetFilename) + abs, err := b.cf.CreateContentPlaceHolder(targetFilename, b.force) if err != nil { return err } @@ -218,7 +220,7 @@ func (b *contentBuilder) buildDir() error { } func (b *contentBuilder) buildFile() (string, error) { - contentPlaceholderAbsFilename, err := b.cf.CreateContentPlaceHolder(b.targetPath) + contentPlaceholderAbsFilename, err := b.cf.CreateContentPlaceHolder(b.targetPath, b.force) if err != nil { return "", err } diff --git a/create/content_test.go b/create/content_test.go index 80a666093..fdfee6e68 100644 --- a/create/content_test.go +++ b/create/content_test.go @@ -82,7 +82,7 @@ func TestNewContentFromFile(t *testing.T) { cfg, fs := newTestCfg(c, mm) h, err := hugolib.NewHugoSites(deps.DepsCfg{Cfg: cfg, Fs: fs}) c.Assert(err, qt.IsNil) - err = create.NewContent(h, cas.kind, cas.path) + err = create.NewContent(h, cas.kind, cas.path, false) if b, ok := cas.expected.(bool); ok && !b { if !b { @@ -145,7 +145,7 @@ i18n: {{ T "hugo" }} c.Assert(err, qt.IsNil) c.Assert(len(h.Sites), qt.Equals, 2) - c.Assert(create.NewContent(h, "my-bundle", "post/my-post"), qt.IsNil) + c.Assert(create.NewContent(h, "my-bundle", "post/my-post", false), qt.IsNil) cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/resources/hugo1.json")), `hugo1: {{ printf "no template handling in here" }}`) cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/resources/hugo2.xml")), `hugo2: {{ printf "no template handling in here" }}`) @@ -157,7 +157,7 @@ i18n: {{ T "hugo" }} cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/pages/bio.md")), `File: bio.md`, `Site Lang: en`, `Name: Bio`) - c.Assert(create.NewContent(h, "my-theme-bundle", "post/my-theme-post"), qt.IsNil) + c.Assert(create.NewContent(h, "my-theme-bundle", "post/my-theme-post", false), qt.IsNil) cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-theme-post/index.md")), `File: index.md`, `Site Lang: en`, `Name: My Theme Post`, `i18n: Hugo Rocks!`) cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-theme-post/resources/hugo1.json")), `hugo1: {{ printf "no template handling in here" }}`) } @@ -187,19 +187,19 @@ site RegularPages: {{ len site.RegularPages }} c.Assert(err, qt.IsNil) c.Assert(len(h.Sites), qt.Equals, 2) - c.Assert(create.NewContent(h, "my-bundle", "post/my-post"), qt.IsNil) + c.Assert(create.NewContent(h, "my-bundle", "post/my-post", false), qt.IsNil) cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/index.md")), `site RegularPages: 10`) // Default bundle archetype - c.Assert(create.NewContent(h, "", "post/my-post2"), qt.IsNil) + c.Assert(create.NewContent(h, "", "post/my-post2", false), qt.IsNil) cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post2/index.md")), `default archetype index.md`) // Regular file with bundle kind. - c.Assert(create.NewContent(h, "my-bundle", "post/foo.md"), qt.IsNil) + c.Assert(create.NewContent(h, "my-bundle", "post/foo.md", false), qt.IsNil) cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/foo.md")), `draft: true`) // Regular files should fall back to the default archetype (we have no regular file archetype). - c.Assert(create.NewContent(h, "my-bundle", "mypage.md"), qt.IsNil) + c.Assert(create.NewContent(h, "my-bundle", "mypage.md", false), qt.IsNil) cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "mypage.md")), `draft: true`) } @@ -237,7 +237,7 @@ i18n: {{ T "hugo" }} c.Assert(err, qt.IsNil) c.Assert(len(h.Sites), qt.Equals, 2) - c.Assert(create.NewContent(h, "my-bundle", "post/my-post"), qt.IsNil) + c.Assert(create.NewContent(h, "my-bundle", "post/my-post", false), qt.IsNil) cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/resources/hugo1.json")), `hugo1: {{ printf "no template handling in here" }}`) cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/resources/hugo2.xml")), `hugo2: {{ printf "no template handling in here" }}`) @@ -247,11 +247,38 @@ i18n: {{ T "hugo" }} cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/pages/bio.md")), `File: bio.md`, `Name: Bio`) - c.Assert(create.NewContent(h, "my-theme-bundle", "post/my-theme-post"), qt.IsNil) + c.Assert(create.NewContent(h, "my-theme-bundle", "post/my-theme-post", false), qt.IsNil) cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-theme-post/index.md")), `File: index.md`, `Name: My Theme Post`, `i18n: Hugo Rocks!`) cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-theme-post/resources/hugo1.json")), `hugo1: {{ printf "no template handling in here" }}`) } +func TestNewContentForce(t *testing.T) { + mm := afero.NewMemMapFs() + c := qt.New(t) + + archetypeDir := filepath.Join("archetypes", "my-bundle") + c.Assert(mm.MkdirAll(archetypeDir, 0o755), qt.IsNil) + c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "index.md"), []byte(""), 0o755), qt.IsNil) + c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "index.nn.md"), []byte(""), 0o755), qt.IsNil) + + c.Assert(initFs(mm), qt.IsNil) + cfg, fs := newTestCfg(c, mm) + + h, err := hugolib.NewHugoSites(deps.DepsCfg{Cfg: cfg, Fs: fs}) + c.Assert(err, qt.IsNil) + c.Assert(len(h.Sites), qt.Equals, 2) + + // from file + c.Assert(create.NewContent(h, "post", "post/my-post.md", false), qt.IsNil) + c.Assert(create.NewContent(h, "post", "post/my-post.md", false), qt.IsNotNil) + c.Assert(create.NewContent(h, "post", "post/my-post.md", true), qt.IsNil) + + // from dir + c.Assert(create.NewContent(h, "my-bundle", "post/my-post", false), qt.IsNil) + c.Assert(create.NewContent(h, "my-bundle", "post/my-post", false), qt.IsNotNil) + c.Assert(create.NewContent(h, "my-bundle", "post/my-post", true), qt.IsNil) +} + func initFs(fs afero.Fs) error { perm := os.FileMode(0o755) var err error diff --git a/hugolib/content_factory.go b/hugolib/content_factory.go index 0a4d0aa0a..017a0bc97 100644 --- a/hugolib/content_factory.go +++ b/hugolib/content_factory.go @@ -110,7 +110,7 @@ func (f ContentFactory) SectionFromFilename(filename string) (string, error) { // CreateContentPlaceHolder creates a content placeholder file inside the // best matching content directory. -func (f ContentFactory) CreateContentPlaceHolder(filename string) (string, error) { +func (f ContentFactory) CreateContentPlaceHolder(filename string, force bool) (string, error) { filename = filepath.Clean(filename) _, abs, err := f.h.AbsProjectContentDir(filename) @@ -130,6 +130,9 @@ _build: ` + if force { + return abs, afero.WriteReader(f.h.Fs.Source, abs, strings.NewReader(placeholder)) + } return abs, afero.SafeWriteReader(f.h.Fs.Source, abs, strings.NewReader(placeholder)) } diff --git a/hugolib/content_factory_test.go b/hugolib/content_factory_test.go index 23dcd660a..2c4b843a9 100644 --- a/hugolib/content_factory_test.go +++ b/hugolib/content_factory_test.go @@ -43,7 +43,7 @@ Hello World. `) b.CreateSites() cf := NewContentFactory(b.H) - abs, err := cf.CreateContentPlaceHolder(filepath.FromSlash("mcontent/en/blog/mypage.md")) + abs, err := cf.CreateContentPlaceHolder(filepath.FromSlash("mcontent/en/blog/mypage.md"), false) b.Assert(err, qt.IsNil) b.Assert(abs, qt.Equals, filepath.FromSlash("/my/work/mcontent/en/blog/mypage.md")) b.Build(BuildCfg{SkipRender: true}) @@ -69,7 +69,7 @@ theme = 'ipsum' b.WithSourceFile(filepath.Join(themeDir, "content/posts/foo.txt"), `Hello.`) b.CreateSites() cf := NewContentFactory(b.H) - abs, err := cf.CreateContentPlaceHolder(filepath.FromSlash("posts/test.md")) + abs, err := cf.CreateContentPlaceHolder(filepath.FromSlash("posts/test.md"), false) b.Assert(err, qt.IsNil) b.Assert(abs, qt.Equals, filepath.FromSlash("content/posts/test.md"))