2023-08-12 10:26:23 +01:00
|
|
|
package cmd
|
2023-08-11 18:33:26 +01:00
|
|
|
|
|
|
|
import (
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
2023-08-12 12:02:44 +01:00
|
|
|
"log/slog"
|
2023-08-11 18:33:26 +01:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"time"
|
|
|
|
|
2023-08-15 17:25:00 +01:00
|
|
|
"codeflow.dananglin.me.uk/apollo/spruce/internal/pdf"
|
2023-08-11 18:33:26 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
type GenerateCommand struct {
|
2023-08-11 19:26:24 +01:00
|
|
|
*flag.FlagSet
|
2023-08-13 17:45:33 +01:00
|
|
|
summary string
|
2023-08-11 18:33:26 +01:00
|
|
|
input string
|
|
|
|
output string
|
|
|
|
employmentHistory int
|
2023-08-12 12:02:44 +01:00
|
|
|
verbose bool
|
2023-08-11 18:33:26 +01:00
|
|
|
}
|
|
|
|
|
2023-08-15 17:25:00 +01:00
|
|
|
type noInputSpecifiedError struct{}
|
|
|
|
|
|
|
|
func (e noInputSpecifiedError) Error() string {
|
|
|
|
return "no input file specified, please set the --input field"
|
|
|
|
}
|
|
|
|
|
2023-08-11 18:33:26 +01:00
|
|
|
func NewGenerateCommand() *GenerateCommand {
|
|
|
|
gc := GenerateCommand{
|
2023-08-11 19:26:24 +01:00
|
|
|
FlagSet: flag.NewFlagSet("generate", flag.ExitOnError),
|
2023-08-13 17:45:33 +01:00
|
|
|
summary: "Generate a PDF file from an existing CV JSON file.",
|
2023-08-11 18:33:26 +01:00
|
|
|
}
|
|
|
|
|
2023-08-11 19:26:24 +01:00
|
|
|
gc.StringVar(&gc.input, "input", "", "specify the CV JSON file that you want to input to the builder.")
|
2023-08-15 17:25:00 +01:00
|
|
|
gc.StringVar(&gc.output, "output", "cv.pdf", "specify the name of the output CV file.")
|
2023-08-11 19:26:24 +01:00
|
|
|
gc.IntVar(&gc.employmentHistory, "employment-history", 10, "show employment history within these number of years.")
|
2023-08-13 17:45:33 +01:00
|
|
|
gc.BoolVar(&gc.verbose, "verbose", false, "set to true to enable verbose logging.")
|
|
|
|
|
|
|
|
gc.Usage = usageFunc(gc.Name(), gc.summary, gc.FlagSet)
|
2023-08-11 18:33:26 +01:00
|
|
|
|
|
|
|
return &gc
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GenerateCommand) Run() error {
|
2023-08-15 17:25:00 +01:00
|
|
|
if g.input == "" {
|
|
|
|
return noInputSpecifiedError{}
|
|
|
|
}
|
|
|
|
|
2023-08-11 18:33:26 +01:00
|
|
|
historyLimit := time.Now().AddDate(-1*g.employmentHistory, 0, 0)
|
|
|
|
|
|
|
|
tempDir, err := os.MkdirTemp("/tmp", "cv-builder-")
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("unable to create a temporary directory; %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
err := os.RemoveAll(tempDir)
|
|
|
|
if err != nil {
|
2023-08-12 12:02:44 +01:00
|
|
|
slog.Warn(fmt.Sprintf("WARN: An error occurred when removing the temporary directory; %v", err))
|
2023-08-11 18:33:26 +01:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2023-08-15 17:25:00 +01:00
|
|
|
pdfFileName, err := pdf.Generate(tempDir, g.input, historyLimit, g.verbose)
|
2023-08-11 18:33:26 +01:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("unable to create the PDF file; %w", err)
|
|
|
|
}
|
|
|
|
|
2023-08-15 17:25:00 +01:00
|
|
|
if err := copyfile(filepath.Join(tempDir, "cv.pdf"), g.output); err != nil {
|
|
|
|
return fmt.Errorf("unable to copy %s to %s; %w", pdfFileName, g.output, err)
|
2023-08-11 18:33:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-08-15 17:25:00 +01:00
|
|
|
func copyfile(source, destination string) error {
|
|
|
|
inputFile, err := os.Open(source)
|
2023-08-11 18:33:26 +01:00
|
|
|
if err != nil {
|
2023-08-15 17:25:00 +01:00
|
|
|
return fmt.Errorf("unable to open %s; %w", source, err)
|
2023-08-11 18:33:26 +01:00
|
|
|
}
|
|
|
|
defer inputFile.Close()
|
|
|
|
|
2023-08-15 17:25:00 +01:00
|
|
|
outputFile, err := os.Create(destination)
|
2023-08-11 18:33:26 +01:00
|
|
|
if err != nil {
|
2023-08-15 17:25:00 +01:00
|
|
|
return fmt.Errorf("unable to create %s; %w", destination, err)
|
2023-08-11 18:33:26 +01:00
|
|
|
}
|
|
|
|
defer outputFile.Close()
|
|
|
|
|
|
|
|
_, err = io.Copy(outputFile, inputFile)
|
|
|
|
if err != nil {
|
2023-08-15 17:25:00 +01:00
|
|
|
return fmt.Errorf("unable to copy %s to %s; %w", source, destination, err)
|
2023-08-11 18:33:26 +01:00
|
|
|
}
|
|
|
|
|
2023-08-15 17:25:00 +01:00
|
|
|
slog.Info("File successfully copied.", "source", source, "destination", destination)
|
|
|
|
|
2023-08-11 18:33:26 +01:00
|
|
|
return nil
|
|
|
|
}
|