diff --git a/.aspell/.aspell.en.pws b/.aspell/.aspell.en.pws index 6d3d365..b4cfe18 100644 --- a/.aspell/.aspell.en.pws +++ b/.aspell/.aspell.en.pws @@ -1,4 +1,4 @@ -personal_ws-1.1 en 50 +personal_ws-1.1 en 52 Alertmanager Anglin Ansible diff --git a/.gitignore b/.gitignore index d6b618a..f87e660 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,2 @@ __output/* !__output/cv.pdf -tags -notes.txt -aspell_output diff --git a/.gitlab/ci/bin/spellcheck b/.gitlab/ci/bin/spellcheck deleted file mode 100755 index 2db23dc..0000000 --- a/.gitlab/ci/bin/spellcheck +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -ASPELL_LANG='en_GB' -ASPELL_PERSONAL_WORDLIST='./.aspell/.aspell.en.pws' -DEFAULT_OUTPUT='aspell_output' - -RED='\033[1;31m' -AMBER='\033[1;33m' -GREEN='\033[1;32m' -NC='\033[0m' - -inputFile='' -outputFile='' - -usage () { -echo "Usage:" -echo "spellcheck [OPTION]..." -echo -echo "Description:" -echo -e "\tspellcheck is a wrapper script that uses aspell to check the spelling of" -echo -e "\tall words in a file. Any detected spelling errors are printed to screen" -echo -e "\tand to an output file." -echo -echo "Options:" -echo -e "\t-i\tinput file for spell checking." -echo -e "\t-o\toutput file where list of spelling errors are written to." -echo -e "\t\tThe default output file is ${DEFAULT_OUTPUT}." -echo -e "\t-h\tprints usage." -echo -echo -e "Examples:" -echo -e "\tspellcheck -i my_file.txt -o output.txt" -echo -e "\tspellcheck -i my_file" -} - -validate_args() { - if [ -z "$inputFile" ]; then - echo -e "${RED}ERROR: ${NC}Option '-i' is not set or is empty." - usage - return 1 - fi - - if [ -z "$outputFile" ]; then - echo -e "${AMBER}WARNING: ${NC}Option '-o' is not set or is empty. The output file will be set to ${DEFAULT_OUTPUT}" - outputFile=${DEFAULT_OUTPUT} - fi - - return 0 -} - -spellcheck() { - cat ${inputFile} | aspell -d ${ASPELL_LANG} -p ${ASPELL_PERSONAL_WORDLIST} list > ${outputFile} - - let spellingErrors=$( cat ${outputFile} | wc -l ) - if [ $spellingErrors -gt 0 ]; then - echo - echo -e "${RED}ERROR: ${NC}The following spelling errors were found in ${inputFile}:" - cat ${outputFile} - return 1 - else - echo - echo -e "${GREEN}INFO: ${NC}No spelling errors found." - fi - - return 0 -} - -while getopts 'i:o:h' flag; do - case "${flag}" in - i) inputFile=${OPTARG} ;; - o) outputFile=${OPTARG} ;; - h) usage && exit 0 ;; - *) usage && exit 2 ;; - esac -done - -validate_args || exit 1 -spellcheck || exit 1 diff --git a/.gitlab/ci/cv-gitlab-ci.yml b/.gitlab/ci/cv-gitlab-ci.yml index bf02bb3..1637487 100644 --- a/.gitlab/ci/cv-gitlab-ci.yml +++ b/.gitlab/ci/cv-gitlab-ci.yml @@ -27,13 +27,13 @@ test:spellcheck: before_script: - apt-get update - - apt-get -y install aspell make + - apt-get -y install aspell aspell-en extends: - .cv-test-rules - image: ubuntu:18.04 + - .use-cv-builder stage: test script: - - make spellcheck + - go run mage.go spellcheck test:pdf: artifacts: @@ -45,7 +45,7 @@ test:pdf: - .cv-test-rules stage: test script: - - make clean pdf + - go run mage.go pdf publish:pdf: extends: @@ -62,7 +62,7 @@ publish:pdf: - git config --global user.name "${GITLAB_USER_NAME}" stage: publish script: - - make clean pdf + - go run mage.go pdf - git checkout master - git add __output/cv.pdf - 'git commit -m "auto: [skip ci] update CV."' diff --git a/.gitlab/ci/docker-gitlab-ci.yml b/.gitlab/ci/docker-gitlab-ci.yml index abe790c..620a53d 100644 --- a/.gitlab/ci/docker-gitlab-ci.yml +++ b/.gitlab/ci/docker-gitlab-ci.yml @@ -7,7 +7,7 @@ services: - docker:19.03.12-dind before_script: - - apk add --no-cache make + - apk add --no-cache go .dockerfile-lint: stage: test @@ -29,7 +29,7 @@ stage: publish extends: .docker-build-setup before_script: - - apk add --no-cache make + - apk add --no-cache go - docker login -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD} ${CI_REGISTRY} after_script: - docker logout ${CI_REGISTRY} @@ -55,11 +55,11 @@ test:docker:build: - .dockerbuild-test - .docker-test-rules script: - - make image + - go run mage.go image publish:docker-image: extends: - .docker-publish-pre-post - .docker-publish-rules script: - - make publish + - go run mage.go publishImage diff --git a/Makefile b/Makefile deleted file mode 100644 index f528523..0000000 --- a/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -DOCKERFILE = ./docker/Dockerfile -IMAGE_NAME ?= cv-builder -IMAGE_TAG ?= latest -OUTPUT_DIR = __output/ -CV_DATA_FILE = ./data/cv.json - -.PHONY: all image publish tex pdf clean - -all: pdf - -image: - @docker build -f $(DOCKERFILE) -t $(IMAGE_NAME):$(IMAGE_TAG) . - -publish: image - @docker push $(IMAGE_NAME):$(IMAGE_TAG) - -spellcheck: - @./.gitlab/ci/bin/spellcheck -i $(CV_DATA_FILE) - -tex: - @go run . - -pdf: tex - @mtxrun --path=$(OUTPUT_DIR) --script context cv.tex - -clean: - @rm -rf $(OUTPUT_DIR) diff --git a/go.mod b/go.mod index 2827b29..59642e0 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module gitlab.com/dananglin/cv go 1.12 + +require github.com/magefile/mage v1.10.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..547126d --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/magefile/mage v1.10.0 h1:3HiXzCUY12kh9bIuyXShaVe529fJfyqoVM42o/uom2g= +github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= diff --git a/mage.go b/mage.go new file mode 100644 index 0000000..a3f23b4 --- /dev/null +++ b/mage.go @@ -0,0 +1,13 @@ +// +build ignore + +package main + +import ( + "os" + + "github.com/magefile/mage/mage" +) + +func main() { + os.Exit(mage.Main()) +} diff --git a/magefile.go b/magefile.go new file mode 100644 index 0000000..1110dd2 --- /dev/null +++ b/magefile.go @@ -0,0 +1,148 @@ +// +build mage + +package main + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "strings" + + "github.com/magefile/mage/mg" + "github.com/magefile/mage/sh" +) + +const ( + aspellLang string = "en_GB" + aspellPersonalWordlist string = "./.aspell/.aspell.en.pws" + cvJsonDataFile string = "./data/cv.json" + defaultImageName string = "cv-builder" + defaultImageTag string = "latest" + dockerfile string = "./docker/Dockerfile" + outputDir string = "./__output" +) + +// Default sets the default target. +var Default = Pdf + +// SpellCheck checks the CV JSON file for spelling errors. If there are any +// misspelt words found the function returns a list of those words in an error. +// Any error found while gathering the list is returned. +// This function depends on the aspell program. +func SpellCheck() error { + fmt.Printf("Reading data from %s...\n", cvJsonDataFile) + + data, err := ioutil.ReadFile(cvJsonDataFile) + if err != nil { + return fmt.Errorf("unable to read data from %s, %s", cvJsonDataFile, err.Error()) + } + + // declare the aspell command and its standard input pipe. + cmd := exec.Command("aspell", "-d", aspellLang, "-p", aspellPersonalWordlist, "list") + stdin, err := cmd.StdinPipe() + if err != nil { + return err + } + + // write the CV data to standard input for piping. + go func() { + defer stdin.Close() + io.WriteString(stdin, string(data)) + }() + + // run aspell and get the list of mispelt words (if any). + // (the output is a string.) + fmt.Println("Running aspell...") + out, err := cmd.CombinedOutput() + if err != nil { + return err + } + + list := strings.Split(string(out), "\n") + if list[len(list)-1] == "" { + list = list[:len(list)-1] + } + + if len(list) > 0 { + var b strings.Builder + errMsg := fmt.Sprintf("the following spelling errors were found in %s:", cvJsonDataFile) + b.WriteString(errMsg) + + for _, v := range list { + s := "\n- " + v + b.WriteString(s) + } + + return fmt.Errorf(b.String()) + } else { + fmt.Println("No spelling errors were found.") + } + + return nil +} + +// Tex takes the CV data file and generates the output tex file from +// template. +func Tex() error { + fmt.Println("Generating the tex file...") + mg.Deps(Clean) + + gocmd := mg.GoCmd() + return sh.Run(gocmd, "run", ".") +} + +// Pdf takes the output tex file generated by the Tex target and +// generates the output PDF file. +func Pdf() error { + mg.Deps(Tex) + + pathArg := "--path=" + outputDir + + fmt.Println("Generating the PDF file...") + return sh.Run("mtxrun", pathArg, "--script", "context", "cv.tex") +} + +// Image builds the CV builder docker image. +func Image() error { + image := imageName() + + return sh.Run("docker", "build", "-f", dockerfile, "-t", image, ".") +} + +// PublishImage publishes the CV builder docker image +// to the docker registry. +func PublishImage() error { + mg.Deps(Image) + + image := 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 { + 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 +}