refactor: integrate tex generator into mage

This commit integrates the Tex generator functionality from main.go into
the mage system. Changes include:

- Movd helper functions to the new helpers package.
- Move the tex generator from main.go to the helpers package.
- Update the Tex target to use the tex generator helper function.
This commit is contained in:
Dan Anglin 2020-09-12 14:06:28 +01:00
parent d04f747efb
commit 700f009f53
Signed by: dananglin
GPG key ID: 0C1D44CFBEE68638
5 changed files with 131 additions and 127 deletions

View file

@ -1,4 +1,4 @@
package main
package helpers
type Cv struct {
FirstName string `json:"firstName"`

86
helpers/helpers.go Normal file
View file

@ -0,0 +1,86 @@
package helpers
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"text/template"
)
const (
defaultImageName string = "cv-builder"
defaultImageTag string = "latest"
)
// ImageName generates the docker image name from the environment
// variables IMAGE_NAME and IMAGE_TAG. Default vaules will be used
// if these variables are not set or empty.
func ImageName() string {
name := os.Getenv("IMAGE_NAME")
if len(name) == 0 {
name = defaultImageName
}
tag := os.Getenv("IMAGE_TAG")
if len(tag) == 0 {
tag = defaultImageTag
}
return name + ":" + tag
}
// CreateCVTex generates the CV docuemnt as a Tex file.
func CreateCVTex(cvJsonDataFile, cvTemplateDir, cvOutputDir, cvOutputFileName string) error {
fmt.Printf("INFO: Attempting to read data from %s...\n", cvJsonDataFile)
data, err := ioutil.ReadFile(cvJsonDataFile)
if err != nil {
return fmt.Errorf("ERROR: Unable to read data from file. %s\n", err.Error())
}
fmt.Println("INFO: Successfully read data.")
fmt.Println("INFO: Attempting to unmarshal JSON data...")
var cv Cv
if err = json.Unmarshal(data, &cv); err != nil {
return fmt.Errorf("ERROR: Unable to unmarshal JSON data. %s\n", err.Error())
}
fmt.Println("INFO: JSON unmarshalling was successful.")
// if CV_CONTACT_PHONE is set then add it to the CV
phone := os.Getenv("CV_CONTACT_PHONE")
if len(phone) > 0 {
cv.Contact.Phone = phone
}
cvOutputPath := cvOutputDir + "/" + cvOutputFileName
fmt.Printf("INFO: Attempting to create output file %s...\n", cvOutputPath)
if err = os.MkdirAll(cvOutputDir, 0750); err != nil {
return fmt.Errorf("ERROR: Unable to create output directory %s. %s\n", cvOutputDir, err.Error())
}
output, err := os.Create(cvOutputPath)
if err != nil {
return fmt.Errorf("ERROR: Unable to create output file %s. %s\n", cvOutputPath, err.Error())
}
fmt.Printf("INFO: Successfully created output file %s.\n", cvOutputPath)
defer output.Close()
fmt.Println("INFO: Attempting template execution...")
fmap := template.FuncMap{
"notLastElement": notLastElement,
"join": join,
"durationToString": durationToString,
}
t := template.Must(template.New("cv.tmpl.tex").Funcs(fmap).Delims("<<", ">>").ParseGlob(cvTemplateDir + "*.tmpl.tex"))
if err = t.Execute(output, cv); err != nil {
return fmt.Errorf("ERROR: Unable to execute the CV template. %s\n", err.Error())
}
fmt.Println("INFO: Template execution successful.")
return nil
}

34
helpers/templatefuncs.go Normal file
View file

@ -0,0 +1,34 @@
package helpers
import (
"fmt"
"strings"
)
// notLastElement returns true if an element of an array
// or a slice is not the last.
func notLastElement(pos, length int) bool {
return pos < length-1
}
// join uses strings.Join to join all string elements into
// a single string.
func join(s []string) string {
return strings.Join(s, " ")
}
// durationToString outputs the employment/education
// duration as a formatted string.
func durationToString(d Duration) string {
start := fmt.Sprintf("%s, %s", d.Start.Month, d.Start.Year)
present := strings.ToLower(d.Present)
end := ""
if present == "yes" || present == "true" {
end = "Present"
} else {
end = fmt.Sprintf("%s, %s", d.End.Month, d.End.Year)
}
return start + " - " + end
}

View file

@ -6,22 +6,22 @@ import (
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"strings"
"github.com/magefile/mage/mg"
"github.com/magefile/mage/sh"
"gitlab.com/dananglin/cv/helpers"
)
const (
aspellLang string = "en_GB"
aspellPersonalWordlist string = "./.aspell/.aspell.en.pws"
cvJsonDataFile string = "./data/cv.json"
defaultImageName string = "cv-builder"
defaultImageTag string = "latest"
cvOutputDir string = "./__output"
cvTemplateDir string = "./template/tex/"
cvOutputFileName string = "cv.tex"
dockerfile string = "./docker/Dockerfile"
outputDir string = "./__output"
)
// Default sets the default target.
@ -87,10 +87,10 @@ func SpellCheck() error {
// template.
func Tex() error {
fmt.Println("Generating the tex file...")
mg.Deps(Clean)
gocmd := mg.GoCmd()
return sh.Run(gocmd, "run", ".")
return helpers.CreateCVTex(cvJsonDataFile, cvTemplateDir, cvOutputDir, cvOutputFileName)
}
// Pdf takes the output tex file generated by the Tex target and
@ -98,7 +98,7 @@ func Tex() error {
func Pdf() error {
mg.Deps(Tex)
pathArg := "--path=" + outputDir
pathArg := "--path=" + cvOutputDir
fmt.Println("Generating the PDF file...")
return sh.Run("mtxrun", pathArg, "--script", "context", "cv.tex")
@ -106,7 +106,7 @@ func Pdf() error {
// Image builds the CV builder docker image.
func Image() error {
image := imageName()
image := helpers.ImageName()
return sh.Run("docker", "build", "-f", dockerfile, "-t", image, ".")
}
@ -116,33 +116,16 @@ func Image() error {
func PublishImage() error {
mg.Deps(Image)
image := imageName()
image := helpers.ImageName()
return sh.Run("docker", "push", image)
}
// Clean removes the directory where the output files
// are generated.
func Clean() error {
if err := sh.Rm(outputDir); err != nil {
if err := sh.Rm(cvOutputDir); err != nil {
return err
}
return nil
}
// imageName generates the docker image name from the environment
// variables IMAGE_NAME and IMAGE_TAG. Default vaules will be used
// if these variables are not set or empty.
func imageName() string {
name := os.Getenv("IMAGE_NAME")
if len(name) == 0 {
name = defaultImageName
}
tag := os.Getenv("IMAGE_TAG")
if len(tag) == 0 {
tag = defaultImageTag
}
return name + ":" + tag
}

99
main.go
View file

@ -1,99 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os"
"strings"
"text/template"
)
var (
cvDataPath string = "data/cv.json"
cvTemplateDir string = "template/tex/"
cvOutputDir string = "__output/"
cvOutputFileName string = "cv.tex"
)
func main() {
var cv Cv
cvOutputPath := cvOutputDir + cvOutputFileName
fmap := template.FuncMap{
"notLastElement": notLastElement,
"join": join,
"durationToString": durationToString,
}
// Read the JSON data
log.Printf("INFO: Attempting to read data from %s...", cvDataPath)
data, err := ioutil.ReadFile(cvDataPath)
if err != nil {
log.Fatalf("ERROR: Unable to read data from file. %s", err.Error())
}
log.Print("INFO: Successfully read data.")
log.Printf("INFO: Attempting to unmarshal JSON data...")
if err = json.Unmarshal(data, &cv); err != nil {
log.Fatalf("ERROR: Unable to unmarshal JSON data. %s", err.Error())
}
log.Println("INFO: JSON unmarshalling was successful.")
// if CV_CONTACT_PHONE is set then add it to the CV
phone := os.Getenv("CV_CONTACT_PHONE")
if len(phone) > 0 {
cv.Contact.Phone = phone
}
// Create the Output tex file
log.Printf("INFO: Attempting to create output file %s...", cvOutputPath)
if err = os.MkdirAll(cvOutputDir, 0750); err != nil {
log.Fatalf("ERROR: Unable to create output directory %s. %s", cvOutputDir, err.Error())
}
output, err := os.Create(cvOutputPath)
if err != nil {
log.Fatalf("ERROR: Unable to create output file %s. %s.", cvOutputPath, err.Error())
}
defer output.Close()
log.Printf("INFO: Successfully created output file %s.", cvOutputPath)
// Execute template engine and produce the resulting TEX file
log.Println("INFO: Attempting template execution...")
t := template.Must(template.New("cv.tmpl.tex").Funcs(fmap).Delims("<<", ">>").ParseGlob(cvTemplateDir + "*.tmpl.tex"))
if err = t.Execute(output, cv); err != nil {
log.Fatalf("ERROR: Unable to execute the CV template. %s", err.Error())
}
log.Println("INFO: Template execution successful.")
}
// notLastElement returns true if an element of an array
// or a slice is not the last.
func notLastElement(pos, length int) bool {
return pos < length-1
}
// join uses strings.Join to join all string elements into
// a single string.
func join(s []string) string {
return strings.Join(s, " ")
}
// durationToString outputs the employment/education
// duration as a formatted string.
func durationToString(d Duration) string {
start := fmt.Sprintf("%s, %s", d.Start.Month, d.Start.Year)
present := strings.ToLower(d.Present)
end := ""
if present == "yes" || present == "true" {
end = "Present"
} else {
end = fmt.Sprintf("%s, %s", d.End.Month, d.End.Year)
}
return start + " - " + end
}