go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/projects/blogctl/pkg/cmd/new.go (about)

     1  /*
     2  
     3  Copyright (c) 2023 - Present. Will Charczuk. All rights reserved.
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository.
     5  
     6  */
     7  
     8  package cmd
     9  
    10  import (
    11  	"fmt"
    12  	"os"
    13  	"path/filepath"
    14  	"strings"
    15  	"time"
    16  
    17  	"github.com/urfave/cli/v2"
    18  	"go.charczuk.com/sdk/logutil"
    19  	"go.charczuk.com/sdk/slant"
    20  
    21  	"go.charczuk.com/projects/blogctl/pkg/config"
    22  	"go.charczuk.com/projects/blogctl/pkg/constants"
    23  	"go.charczuk.com/projects/blogctl/pkg/engine"
    24  	"go.charczuk.com/projects/blogctl/pkg/model"
    25  )
    26  
    27  // New returns a new post command.
    28  func New() *cli.Command {
    29  	return &cli.Command{
    30  		Name:      "new",
    31  		Usage:     "Create a new blog post from a file",
    32  		ArgsUsage: "[IMAGE_PATH]",
    33  		Flags: []cli.Flag{
    34  			&cli.StringFlag{Name: "title", Usage: "The title (optional, will default to the file name)"},
    35  			&cli.StringFlag{Name: "location", Usage: "The location (optional)"},
    36  			&cli.StringFlag{Name: "posted", Usage: "The posted effective date (optional)"},
    37  			&cli.StringSliceFlag{Name: "tag", Usage: "The metadata tags (optional)"},
    38  		},
    39  		Action: func(ctx *cli.Context) error {
    40  			imagePath := ctx.Args().First()
    41  			if imagePath == "" {
    42  				return fmt.Errorf("must provide a [IMAGE_PATH]")
    43  			}
    44  
    45  			cfg, persistentFlags, cfgPaths, err := config.ReadConfig(ctx)
    46  			if err != nil {
    47  				return err
    48  			}
    49  
    50  			log := Logger("new")
    51  			slant.Print(os.Stdout, "BLOGCTL")
    52  
    53  			if len(cfgPaths) > 0 {
    54  				logutil.Infof(log, "using config path(s): %s", strings.Join(cfgPaths, ", "))
    55  			}
    56  
    57  			captureDate, err := engine.ExtractCaptureDate(imagePath)
    58  			if err != nil {
    59  				logutil.Error(log, err)
    60  			}
    61  
    62  			var postedDate time.Time
    63  			if posted := ctx.String("posted"); posted != "" {
    64  				postedDate, err = time.Parse("2006-01-02", posted)
    65  				if err != nil {
    66  					return err
    67  				}
    68  			} else if !captureDate.IsZero() {
    69  				postedDate = captureDate
    70  			}
    71  			logutil.Infof(log, "using posted date: %v", postedDate)
    72  
    73  			title := ctx.String("title")
    74  			if title == "" {
    75  				title = filepath.Base(imagePath)
    76  			}
    77  			logutil.Infof(log, "using title: %v", title)
    78  
    79  			tags := ctx.StringSlice("tag")
    80  			if len(tags) > 0 {
    81  				logutil.Infof(log, "using tags: %v", strings.Join(tags, ", "))
    82  			}
    83  
    84  			path := fmt.Sprintf("%s/%s-%s", cfg.PostsPathOrDefault(), postedDate.Format("2006-01-02"), engine.Slugify(title))
    85  
    86  			if persistentFlags.DryRun {
    87  				logutil.Infof(log, "[DRY-RUN] writing new post to %s", path)
    88  				return nil
    89  			}
    90  
    91  			logutil.Infof(log, "writing new post to %s", path)
    92  			if _, err := os.Stat(path); err == nil {
    93  				return fmt.Errorf("post directory already exists, aborting")
    94  			}
    95  			fullPath := filepath.Join(path, filepath.Base(imagePath))
    96  			if err := engine.Copy(imagePath, fullPath); err != nil {
    97  				return err
    98  			}
    99  
   100  			meta := model.Meta{
   101  				Title:    title,
   102  				Location: ctx.String("location"),
   103  				Captured: captureDate,
   104  				Posted:   postedDate,
   105  				Tags:     tags,
   106  			}
   107  			return engine.WriteYAML(filepath.Join(path, constants.FileMeta), meta)
   108  		},
   109  	}
   110  }