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:
parent
d04f747efb
commit
700f009f53
5 changed files with 131 additions and 127 deletions
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package helpers
|
||||||
|
|
||||||
type Cv struct {
|
type Cv struct {
|
||||||
FirstName string `json:"firstName"`
|
FirstName string `json:"firstName"`
|
86
helpers/helpers.go
Normal file
86
helpers/helpers.go
Normal 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
34
helpers/templatefuncs.go
Normal 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
|
||||||
|
}
|
37
magefile.go
37
magefile.go
|
@ -6,22 +6,22 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/magefile/mage/mg"
|
"github.com/magefile/mage/mg"
|
||||||
"github.com/magefile/mage/sh"
|
"github.com/magefile/mage/sh"
|
||||||
|
"gitlab.com/dananglin/cv/helpers"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
aspellLang string = "en_GB"
|
aspellLang string = "en_GB"
|
||||||
aspellPersonalWordlist string = "./.aspell/.aspell.en.pws"
|
aspellPersonalWordlist string = "./.aspell/.aspell.en.pws"
|
||||||
cvJsonDataFile string = "./data/cv.json"
|
cvJsonDataFile string = "./data/cv.json"
|
||||||
defaultImageName string = "cv-builder"
|
cvOutputDir string = "./__output"
|
||||||
defaultImageTag string = "latest"
|
cvTemplateDir string = "./template/tex/"
|
||||||
|
cvOutputFileName string = "cv.tex"
|
||||||
dockerfile string = "./docker/Dockerfile"
|
dockerfile string = "./docker/Dockerfile"
|
||||||
outputDir string = "./__output"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Default sets the default target.
|
// Default sets the default target.
|
||||||
|
@ -87,10 +87,10 @@ func SpellCheck() error {
|
||||||
// template.
|
// template.
|
||||||
func Tex() error {
|
func Tex() error {
|
||||||
fmt.Println("Generating the tex file...")
|
fmt.Println("Generating the tex file...")
|
||||||
|
|
||||||
mg.Deps(Clean)
|
mg.Deps(Clean)
|
||||||
|
|
||||||
gocmd := mg.GoCmd()
|
return helpers.CreateCVTex(cvJsonDataFile, cvTemplateDir, cvOutputDir, cvOutputFileName)
|
||||||
return sh.Run(gocmd, "run", ".")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pdf takes the output tex file generated by the Tex target and
|
// Pdf takes the output tex file generated by the Tex target and
|
||||||
|
@ -98,7 +98,7 @@ func Tex() error {
|
||||||
func Pdf() error {
|
func Pdf() error {
|
||||||
mg.Deps(Tex)
|
mg.Deps(Tex)
|
||||||
|
|
||||||
pathArg := "--path=" + outputDir
|
pathArg := "--path=" + cvOutputDir
|
||||||
|
|
||||||
fmt.Println("Generating the PDF file...")
|
fmt.Println("Generating the PDF file...")
|
||||||
return sh.Run("mtxrun", pathArg, "--script", "context", "cv.tex")
|
return sh.Run("mtxrun", pathArg, "--script", "context", "cv.tex")
|
||||||
|
@ -106,7 +106,7 @@ func Pdf() error {
|
||||||
|
|
||||||
// Image builds the CV builder docker image.
|
// Image builds the CV builder docker image.
|
||||||
func Image() error {
|
func Image() error {
|
||||||
image := imageName()
|
image := helpers.ImageName()
|
||||||
|
|
||||||
return sh.Run("docker", "build", "-f", dockerfile, "-t", image, ".")
|
return sh.Run("docker", "build", "-f", dockerfile, "-t", image, ".")
|
||||||
}
|
}
|
||||||
|
@ -116,33 +116,16 @@ func Image() error {
|
||||||
func PublishImage() error {
|
func PublishImage() error {
|
||||||
mg.Deps(Image)
|
mg.Deps(Image)
|
||||||
|
|
||||||
image := imageName()
|
image := helpers.ImageName()
|
||||||
return sh.Run("docker", "push", image)
|
return sh.Run("docker", "push", image)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean removes the directory where the output files
|
// Clean removes the directory where the output files
|
||||||
// are generated.
|
// are generated.
|
||||||
func Clean() error {
|
func Clean() error {
|
||||||
if err := sh.Rm(outputDir); err != nil {
|
if err := sh.Rm(cvOutputDir); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
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
99
main.go
|
@ -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
|
|
||||||
}
|
|
Loading…
Reference in a new issue