Skip to content

Commit

Permalink
Merge pull request #30 from thomasoca/add-installer-command
Browse files Browse the repository at this point in the history
Add installer command
  • Loading branch information
thomasoca committed Jul 16, 2023
2 parents e97ff42 + b0fd40b commit 7056ae0
Show file tree
Hide file tree
Showing 7 changed files with 267 additions and 20 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
*.png
*.tex
*.pdf
/result
/result
*.log
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ https://cv-generator-40m5.onrender.com
```sh
cv-generator [command] [flag]
```
### Install Latex dependencies

```sh
cv-generator install
```
### Run as webserver

```sh
Expand All @@ -51,13 +55,15 @@ Optional flags:

Make sure to install Docker in your system

1. Navigate to the project roots directory, and build the Docker image `docker build -t [TAG_NAME] .`
1. Pull the latest image from the registry by running `docker pull ghcr.io/thomasoca/cv-generator:latest`
2. Run the image and bind the port, i.e. on port 8080 `docker run -p 8170:8170 [TAG_NAME]`
3. Navigate to `localhost:8170` or any other ports that defined in the previous step

### Local Installation

#### Installation from source
1. Install go >= 1.16,
2. Run the LaTeX [installation script](./backend/scripts/setup_latex.sh)
3. Run `export PATH=$PATH:/[YOUR_HOME_DIR]/bin` to make sure that `pdflatex` is executable
4. Run the CLI app in webserver mode or local mode
2. Clone this repository or download the compressed file in the [release](https://github.com/thomasoca/cv-generator/releases) section
3. [Compile and install](https://go.dev/doc/tutorial/compile-install) the application
4. Run the install command `cv-generator install`
5. Run `export PATH=$PATH:/[YOUR_HOME_DIR]/bin` to make sure that `pdflatex` and `tlmgr` is executable
6. Run the CLI app in webserver mode or local mode
30 changes: 30 additions & 0 deletions cmd/installer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package cmd

import (
"fmt"
"os"

"github.com/spf13/cobra"
"github.com/thomasoca/cv-generator/internal/installer"
)

var installerCmd = &cobra.Command{
Use: "install",
Aliases: []string{"ins"},
Short: "Install software dependencies",
Run: func(cmd *cobra.Command, args []string) {
runInstallerCmd()
},
}

func runInstallerCmd() {
err := installer.InstallPrerequisite()
if err != nil {
os.Exit(1)
}
fmt.Println("Installation process completed")
}

func init() {
rootCmd.AddCommand(installerCmd)
}
122 changes: 122 additions & 0 deletions internal/installer/installer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package installer

import (
"fmt"
"io"
"net/http"
"os"
"runtime"

"github.com/thomasoca/cv-generator/pkg/image"
"github.com/thomasoca/cv-generator/pkg/utils"
)

func downloadFile(url, filePath string) error {
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()

out, err := os.Create(filePath)
if err != nil {
return err
}
defer out.Close()

_, err = io.Copy(out, resp.Body)
return err
}

func latexClassMod(class string) error {
switch class {
case "altacv.cls":
err := utils.AltaCvMod()
return err
}
return nil
}

func InstallPrerequisite() error {
// Check if latex class is already in the machine
listOfClasses := []map[string]string{
{"class": "altacv.cls", "url": "https://github.com/liantze/AltaCV/main/altacv.cls"},
{"class": "extarticle.cls", "url": "http://tug.ctan.org/tex-archive/macros/latex/contrib/extsizes/extarticle.cls"},
}

fmt.Println("Checking Latex class availability....")
for _, m := range listOfClasses {
class := m["class"]
url := m["url"]
if !image.IsImageFileExist(class) {
// Download latex class from the author Git repository
if err := downloadFile(url, class); err != nil {
fmt.Println("Failed to download latex class:", err)
return err
}
// Apply mod to the Latex class
if err := latexClassMod(class); err != nil {
fmt.Println("Failed to apply mod to the Latex class:", err)
return err
}
fmt.Printf("%s downloaded successfully.\n", class)
}
}
fmt.Println("All of the Latex classes are available in the system")

// Check if pdflatex is installed
fmt.Println("Checking Latex executables....")
if err := utils.RunCommand("pdflatex", nil, nil, "--version"); err != nil {
if runtime.GOOS == "linux" {
fmt.Println("pdflatex is not installed, starting TinyTex installation process....")

// Download TinyTex for minimal latex installation
tinyTexURL := "https://yihui.org/tinytex/install-bin-unix.sh"
if err := downloadFile(tinyTexURL, "install-bin-unix.sh"); err != nil {
fmt.Println("Failed to download install-bin-unix.sh:", err)
return err
}
fmt.Println("install-bin-unix.sh downloaded successfully.")

// Execute the TinyTex installation script
if err := utils.RunCommand("sh", nil, nil, "install-bin-unix.sh"); err != nil {
fmt.Println("Failed to install TinyTex:", err)
return err
}
fmt.Println("TinyTex installed successfully, cleaning up files.")
err := os.Remove("install-bin-unix.sh")
if err != nil {
fmt.Println("Error removing the file:", err)
return err
}

// Set PATH variable
os.Setenv("PATH", os.Getenv("PATH")+":"+os.Getenv("HOME")+"/bin")

// Install the necessary packages
fmt.Println("Installing necessary Latex packages....")
packages := []string{
"pgf", "fontawesome5", "koma-script", "cmap", "ragged2e", "everysel",
"tcolorbox", "enumitem", "ifmtarg", "dashrule", "changepage", "multirow",
"environ", "paracol", "lato", "fontaxes", "accsupp", "extsizes", "pdfx",
"colorprofiles", "xmpincl", "adjustbox", "collectbox",
}
if err := utils.RunCommand("tlmgr", nil, nil, append([]string{"install"}, packages...)...); err != nil {
fmt.Println("Failed to install packages:", err)
return err
}
fmt.Println("Packages installed successfully.")

// Suggest the user to add the export statement to their .bashrc
fmt.Println("######################## IMPORTANT NOTICE ########################")
fmt.Println("The PATH has been updated for the current session. If you want to persist the changes, add the following line to your ~/.bashrc file:")
fmt.Printf("export PATH=%s\n\n", os.Getenv("PATH")+":"+os.Getenv("HOME")+"/bin")
fmt.Println("Remember to restart your terminal or run 'source ~/.bashrc' to apply the changes.")
return nil
}
fmt.Println("The installer is not configured for this operating system, please refer to https://yihui.org/tinytex/ for more information")
return nil
}
fmt.Println("All of the dependencies already installed, you are good to go!")
return nil
}
24 changes: 10 additions & 14 deletions pkg/generator/resume.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,34 @@ import (
"bytes"
"errors"
"log"
"os/exec"

"github.com/thomasoca/cv-generator/pkg/utils"
)

func createResumeFile(fg FileGenerator) error {
app := "pdflatex"
outdir := "-output-directory=" + fg.DirPath
cmdArgs := []string{outdir, "-interaction=nonstopmode", "-synctex=1", "-halt-on-error", fg.latexPath}
var stderr bytes.Buffer
var out bytes.Buffer
cmd := exec.Command(app, cmdArgs...)
cmd.Stdout = &out
cmd.Stderr = &stderr
err := cmd.Run()
var stdout bytes.Buffer
cmdArgs := []string{outdir, "-interaction=nonstopmode", "-synctex=1", "-halt-on-error", fg.latexPath}
err := utils.RunCommand(app, &stdout, &stderr, cmdArgs...)
if err != nil {
log.Printf("Command finished with error: %v", err)
log.Println(out.String())
log.Println(stdout.String())
return errors.New("there is a problem when running latex in the server")
}
log.Println("Latex file generated successfully")
return err
}

func CheckVersion() error {

var stderr bytes.Buffer
var out bytes.Buffer
cmd := exec.Command("pdflatex", "--version")
cmd.Stdout = &out
cmd.Stderr = &stderr
err := cmd.Run()
var stdout bytes.Buffer
err := utils.RunCommand("pdflatex", &stdout, &stderr, "-version")
if err != nil {
log.Printf("Command finished with error: %v", err)
log.Println(out.String())
log.Println(stdout.String())
return errors.New("latex backend not available")
}
return err
Expand Down
75 changes: 75 additions & 0 deletions pkg/utils/altacv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package utils

import (
"bufio"
"fmt"
"log"
"os"
"strings"
)

func AltaCvMod() error {
// Declare an array of strings
StringArray := []string{"pdfx", "biber", "bibhang", "biblabelsep", "pubtype", "bibsetup", "bibitemsep", "trimclip"}

// Open the altacv.cls file
file, err := os.OpenFile("altacv.cls", os.O_RDWR, 0644)
if err != nil {
log.Println("Error opening file:", err)
return err
}
defer file.Close()

// Read the content of the file
scanner := bufio.NewScanner(file)
var lines []string
for scanner.Scan() {
lines = append(lines, scanner.Text())
}

// Close the file and truncate it to clear its content
file.Close()
file, err = os.Create("altacv.cls")
if err != nil {
log.Println("Error creating file:", err)
return err
}
defer file.Close()

// Remove lines containing the strings from the StringArray
for _, line := range lines {
keepLine := true
for _, val := range StringArray {
if strings.Contains(line, val) {
keepLine = false
break
}
}
if keepLine {
fmt.Fprintln(file, line)
}
}

// Add modifications to altacv.cls
modifications := `
% Modification
\newcommand{\cvproject}[3]{%
{\large\color{emphasis}#1\par}
\smallskip\normalsize
\ifstrequal{#2}{}{}{
\textbf{\color{accent}#2}\par
\smallskip}
\ifstrequal{#3}{}{}{{\small\makebox[0.5\linewidth][l]{\faCalendar~#3}}}%
\medskip\normalsize
}
\newcommand{\cvskillstr}[2]{%
\textcolor{emphasis}{\textbf{#1}}\hfill
\textbf{\color{body}#2}\par
}
`

fmt.Fprintln(file, modifications)

log.Println("Refactor complete.")
return nil
}
17 changes: 17 additions & 0 deletions pkg/utils/utils.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package utils

import (
"bytes"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
)

Expand All @@ -22,3 +24,18 @@ func RemoveFiles(fileName string) {
panic(e)
}
}

func RunCommand(command string, stdout, stderr *bytes.Buffer, args ...string) error {
cmd := exec.Command(command, args...)
if stdout != nil {
cmd.Stdout = stdout
} else {
cmd.Stdout = os.Stdout
}
if stderr != nil {
cmd.Stderr = stderr
} else {
cmd.Stderr = os.Stderr
}
return cmd.Run()
}

0 comments on commit 7056ae0

Please sign in to comment.