Skip to content

Commit

Permalink
Implement additional format argument for convert cmd (#10)
Browse files Browse the repository at this point in the history
* feat: Add filename argument

* feat: Add format argument

* feat: Implement yaml support for parser

* refactor: Rename parse command to convert command
  • Loading branch information
MaikelVeen authored May 12, 2024
1 parent 37011bc commit bc9d2ca
Show file tree
Hide file tree
Showing 21 changed files with 404 additions and 307 deletions.
153 changes: 153 additions & 0 deletions cmd/convert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package cmd

import (
"encoding/json"
"errors"
"fmt"
"os"
"path"
"strings"

"github.com/glass-cms/glasscms/item"
"github.com/glass-cms/glasscms/parser"
"github.com/glass-cms/glasscms/sourcer"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"gopkg.in/yaml.v3"
)

const (
ArgOutput = "output"
ArgOutputShorthand = "o"

ArgFormat = "format"
ArgFormatShorthand = "f"

FormatJSON = "json"
FormatYAML = "yaml"
)

var (
ErrArgumentInvalid = errors.New("argument is invalid")
ErrInvalidFormat = errors.New("invalid format")
)

type ConvertCommand struct {
*cobra.Command
}

func NewConvertCommand() *ConvertCommand {
c := &ConvertCommand{}
c.Command = &cobra.Command{
Use: "convert <source>",
Short: "Convert source files",
Long: "Convert source files to a structured format at the specified output directory.",
RunE: c.Execute,
Args: cobra.ExactArgs(1),
PreRunE: func(_ *cobra.Command, _ []string) error {
dir := viper.GetString(ArgOutput)

// Create the output directory if it doesn't exist.
if _, err := os.Stat(dir); os.IsNotExist(err) {
if err = os.MkdirAll(dir, 0755); err != nil {
return err
}
}

format := viper.GetString(ArgFormat)
if format != FormatJSON && format != FormatYAML {
return fmt.Errorf("%w: %s", ErrArgumentInvalid, format)
}

return nil
},
}

flagset := c.Command.Flags()

flagset.StringP(ArgOutput, ArgOutputShorthand, ".", "Output directory")
_ = viper.BindPFlag(ArgOutput, flagset.Lookup(ArgOutput))

flagset.StringP(ArgFormat, ArgFormatShorthand, "json", "Output format (json, yaml)")
_ = viper.BindPFlag(ArgFormat, flagset.Lookup(ArgFormat))

return c
}

func (c *ConvertCommand) Execute(_ *cobra.Command, args []string) error {
sourcePath := args[0]
if err := sourcer.IsValidFileSystemSource(sourcePath); err != nil {
return err
}

dir := viper.GetString(ArgOutput)
format := viper.GetString(ArgFormat)

fileSystemSourcer, err := sourcer.NewFileSystemSourcer(sourcePath)
if err != nil {
return err
}

// Iterate over the source files and parse them.
var items []*item.Item
for {
var src sourcer.Source
src, err = fileSystemSourcer.Next()
if errors.Is(err, sourcer.ErrDone) {
break
}

if err != nil {
return err
}

var i *item.Item
i, err = parser.Parse(src)
if err != nil {
return err
}

items = append(items, i)
}

return writeItems(items, dir, format)
}

func writeItems(items []*item.Item, dir string, format string) error {
for _, i := range items {
fn := strings.ReplaceAll(i.Name, "/", "_")

switch format {
case FormatJSON:
if err := writeItemJSON(i, path.Join(dir, fn+".json")); err != nil {
return err
}
case FormatYAML:
if err := writeItemYAML(i, path.Join(dir, fn+".yaml")); err != nil {
return err
}
default:
return fmt.Errorf("%w: %s", ErrInvalidFormat, format)
}
}

return nil
}

func writeItemJSON(i *item.Item, path string) error {
b, err := json.Marshal(i)
if err != nil {
return err
}

return os.WriteFile(path, b, 0600)
}

func writeItemYAML(i *item.Item, path string) error {
b, err := yaml.Marshal(i)
if err != nil {
return err
}

return os.WriteFile(path, b, 0600)
}
61 changes: 61 additions & 0 deletions cmd/convert_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package cmd_test

import (
"fmt"
"os"
"testing"

"github.com/glass-cms/glasscms/cmd"
"github.com/stretchr/testify/require"
)

func Test_ConvertCommandJSON(t *testing.T) {
tempDir, err := os.MkdirTemp("", "json*")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tempDir)

command := cmd.NewConvertCommand()
command.SetArgs([]string{"../docs/commands", fmt.Sprintf("--%s", cmd.ArgOutput), tempDir})

err = command.Command.Execute()
require.NoError(t, err)

// Check that there are multiple json files in the output directory
files, err := os.ReadDir(tempDir)
require.NoError(t, err)
require.NotEmpty(t, files)

for _, file := range files {
require.Contains(t, file.Name(), ".json")
}
}

func Test_ConvertCommandYAML(t *testing.T) {
tempDir, err := os.MkdirTemp("", "yml*")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tempDir)

command := cmd.NewConvertCommand()
command.SetArgs([]string{
"../docs/commands",
fmt.Sprintf("--%s", cmd.ArgOutput),
tempDir,
fmt.Sprintf("--%s", cmd.ArgFormat),
cmd.FormatYAML})

err = command.Command.Execute()
require.NoError(t, err)

// Check that there are multiple yaml files in the output directory
files, err := os.ReadDir(tempDir)
require.NoError(t, err)
require.NotEmpty(t, files)

for _, file := range files {
require.Contains(t, file.Name(), ".yaml")
}
}
2 changes: 1 addition & 1 deletion cmd/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (c *DocsCommand) Execute(_ *cobra.Command, _ []string) error {
func DocFilePrepender(filename string) string {
type FrontMatter struct {
Title string `yaml:"title"`
CreateTimestamp int64 `yaml:"create_timestamp"`
CreateTimestamp int64 `yaml:"createTime"`
}

name := filepath.Base(filename)
Expand Down
4 changes: 2 additions & 2 deletions cmd/docs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ func TestFilePrepender(t *testing.T) {
require.Contains(t, result, "title: "+expectedTitle)

// Check if the create timestamp is a valid Unix timestamp
require.Contains(t, result, "create_timestamp: ")
timestampStr := strings.Split(strings.Split(result, "create_timestamp: ")[1], "\n")[0]
require.Contains(t, result, "createTime: ")
timestampStr := strings.Split(strings.Split(result, "createTime: ")[1], "\n")[0]
timestamp, err := strconv.ParseInt(timestampStr, 10, 64)
require.NoError(t, err)
require.Greater(t, timestamp, int64(0))
Expand Down
107 changes: 0 additions & 107 deletions cmd/parse.go

This file was deleted.

46 changes: 0 additions & 46 deletions cmd/parse_test.go

This file was deleted.

Loading

0 comments on commit bc9d2ca

Please sign in to comment.