Skip to content

Commit

Permalink
Merge branch 'main' of github.com:mkloubert/go-package-manager
Browse files Browse the repository at this point in the history
  • Loading branch information
Marcel Kloubert committed May 26, 2024
2 parents c1a5728 + c8a0cb5 commit 3440116
Show file tree
Hide file tree
Showing 10 changed files with 235 additions and 80 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"editor.formatOnSave": true,
}
15 changes: 10 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@

## 0.15.0

- **BREAKING CHANGE**: `pack` command creates corresponding `.sha256` file by default
- feat: `monitor` command, which displays CPU and memory usage of a process in the console
- feat: `setup git` command, which sets up basic git features like username and email address
- feat: support for `CI` environment variable, which is used by GitHub actions or GitLab runners as well
- refactor: using new and shorter `CheckForError()` function instead of `CloseWithError()` in most cases
- refactor: improve logging
- refactor: using Go template engine now to generate final content of script by `setup updater` command
- chore: update `projects.yaml` with: [hugo](https://github.com/gohugoio/hugo)

## 0.14.0

Expand All @@ -15,7 +20,7 @@
- feat: `init` command, which currently can initialize a `gpm.yaml` file
- feat: add `GPM_AI_CHAT_TEMPERATURE` environment variable, which defines the custom temperature value for AI chat (operations)
- feat: add `--temperature` flag to `chat` command, which can define the initial temperature value for the command
- feat: `setup updater` command, which installs a shell script called `gpm-update` in `$HOME/.gpm/bin` folder of a UNIX environment, like *BSD, Linux or MacOS
- feat: `setup updater` command, which installs a shell script called `gpm-update` in `$HOME/.gpm/bin` folder of a UNIX environment, like \*BSD, Linux or MacOS
- refactor: improve prompting in `chat` command
- refactor: `pack` command now outputs progress with pretty bars
- refactor: code cleanups and improvements
Expand All @@ -26,7 +31,7 @@
- feat: `audit` command, which uses [osv.dev API](https://google.github.io/osv.dev/api/) to scan installed modules for vulnerabilities
- feat: `install` command now supports `--tidy` flag to run `tidy` command after successful installation
- feat: `open alias` command, which opens the URL of an alias from `aliases.yaml` file in `$HOME/.gpm/bin` folder
- feat: `open project` command, which opens the URL of a project from `projects.yaml` file in `$HOME/.gpm/bin` folder
- feat: `open project` command, which opens the URL of a project from `projects.yaml` file in `$HOME/.gpm/bin` folder
- feat: `import aliases` command, which loads aliases from a local or web source and merge them with `aliases.yaml` file in `$HOME/.gpm` folder
- feat: `import projects` command, which loads projects from a local or web source and merge them with `projects.yaml` file in `$HOME/.gpm` folder
- feat: implement `postinstall`, `postpack` and `prepack` scripts for `gpm.yaml` files
Expand All @@ -38,18 +43,18 @@
- feat: `remove binary` command, which removes binary installed with `make` command
- feat: `list binaries` command, which lists binaries installed with `make` command
- feat: `pack` command, which compresses files defined in `files` section of `gpm.yaml` file to zip archive
- fix: setup `Dir` property of commands used in Git* methods of `AppContext` instance
- fix: setup `Dir` property of commands used in Git\* methods of `AppContext` instance
- chore: code cleanups and improvements

## 0.11.0

- feat: load `.env` files from `$HOME/.gpm` and project directories, if exist, automatically
- feat: add `--env-file` file to load environment variables from external variables
- feat: `execute` command which runs shell commands with the environment variables loaded from .env* files
- feat: `execute` command which runs shell commands with the environment variables loaded from .env\* files
- fix: exit app if special files could not be loaded
- feat: `run` command without scripts will run `go run .` now
- feat: `postbuild`, `postinstall`, `posttest`, `prebuild`, `preinstall` and `pretest` script support
- feat: add `--no-script` flags for `build`, `start`, `test` and `tidy`
- feat: add `--no-script` flags for `build`, `start`, `test` and `tidy`

## 0.10.1

Expand Down
86 changes: 57 additions & 29 deletions commands/pack.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ package commands

import (
"archive/zip"
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"os"
Expand All @@ -38,14 +40,14 @@ import (
"github.com/mkloubert/go-package-manager/constants"
"github.com/mkloubert/go-package-manager/types"
"github.com/mkloubert/go-package-manager/utils"
"github.com/schollz/progressbar/v3"
"github.com/spf13/cobra"
)

func Init_Pack_Command(parentCmd *cobra.Command, app *types.AppContext) {
var all bool
var name string
var noArch bool
var noChecksum bool
var noComment bool
var noOs bool
var noPostScript bool
Expand Down Expand Up @@ -145,19 +147,21 @@ func Init_Pack_Command(parentCmd *cobra.Command, app *types.AppContext) {

app.Debug(fmt.Sprintf("Will pack for '%v/%v' ...", goos, goarch))

zipFileName := projectName
fileBaseName := projectName
if !noTag {
if latestVersion != nil {
zipFileName += "-v" + latestVersion.String()
fileBaseName += "-v" + latestVersion.String()
}
}
if !noOs {
zipFileName += "-" + goos
fileBaseName += "-" + goos
}
if !noArch {
zipFileName += "-" + goarch
fileBaseName += "-" + goarch
}
zipFileName += ".zip"

zipFileName := fileBaseName + ".zip"
checksumFileName := zipFileName + ".sha256"

zipFilePath := path.Join(app.Cwd, zipFileName)
app.Debug(fmt.Sprintf("Will pack to '%v' ...", zipFilePath))
Expand Down Expand Up @@ -208,26 +212,14 @@ func Init_Pack_Command(parentCmd *cobra.Command, app *types.AppContext) {
filesToPack, err := app.ListFiles()
utils.CheckForError(err)

bar := progressbar.NewOptions(len(filesToPack),
// progressbar.OptionSetWriter(ansi.NewAnsiStdout()), //you should install "github.com/k0kubun/go-ansi"
progressbar.OptionEnableColorCodes(true),
// progressbar.OptionShowBytes(true),
progressbar.OptionSetWidth(15),
progressbar.OptionSetDescription(
fmt.Sprintf(
"[cyan][%v/%v][reset] Packing file for '%v/%v' ...",
fi+1, len(outputFormats),
goos, goarch,
),
packBar := utils.CreateProgressBar(
len(filesToPack),
fmt.Sprintf(
"[cyan][%v/%v][reset] Packing file for '%v/%v' ...",
fi+1, len(outputFormats),
goos, goarch,
),
progressbar.OptionSetTheme(progressbar.Theme{
Saucer: "[green]=[reset]",
SaucerHead: "[green]>[reset]",
SaucerPadding: " ",
BarStart: "[",
BarEnd: "]",
}))

)
for _, f := range filesToPack {
func() {
fileReader, err := os.Open(f)
Expand All @@ -238,7 +230,10 @@ func Init_Pack_Command(parentCmd *cobra.Command, app *types.AppContext) {
utils.CheckForError(err)

relPath, err := filepath.Rel(app.Cwd, f)
utils.CheckForError(err)
if err != nil {
relPath = f
}
app.Debug(fmt.Sprintf("Packing file '%v' into '%v' ...", relPath, zipFilePath))

header, err := zip.FileInfoHeader(fileInfo)
utils.CheckForError(err)
Expand All @@ -248,14 +243,46 @@ func Init_Pack_Command(parentCmd *cobra.Command, app *types.AppContext) {
fileWriter, err := zipWriter.CreateHeader(header)
utils.CheckForError(err)

app.Debug(fmt.Sprintf("Packing file '%v' into '%v' ...", relPath, zipFilePath))
io.Copy(fileWriter, fileReader)
}()

bar.Add64(1)
packBar.Add(1)
}

fmt.Println()

if !noChecksum {
checksumFilePath := path.Join(app.Cwd, checksumFileName)
app.Debug(fmt.Sprintf("Will hash to '%v' ...", checksumFilePath))

checksumBar := utils.CreateProgressBar(
1,
fmt.Sprintf(
"[cyan][%v/%v][reset] Creating checksum of packed file for '%v/%v' ...",
fi+1, len(outputFormats),
goos, goarch,
),
)

func() {
fileReader, err := os.Open(zipFilePath)
utils.CheckForError(err)
defer fileReader.Close()

hash := sha256.New()

_, err = io.Copy(hash, fileReader)
utils.CheckForError(err)

hashSum := hash.Sum(nil)
checksum := fmt.Sprintln(hex.EncodeToString(hashSum))

os.WriteFile(checksumFilePath, []byte(checksum), constants.DefaultFileMode)
}()

checksumBar.Add(1)

fmt.Println()
}
}()
}

Expand All @@ -272,6 +299,7 @@ func Init_Pack_Command(parentCmd *cobra.Command, app *types.AppContext) {
packCmd.Flags().StringVarP(&name, "name", "", "", "custom name of output executable file")
packCmd.Flags().BoolVarP(&noArch, "no-arch", "", false, "do not add cpu architecture to output filename")
packCmd.Flags().BoolVarP(&noArch, "no-comment", "", false, "do not add global comment to zip file")
packCmd.Flags().BoolVarP(&noChecksum, "no-checksum", "", false, "do not create checksum file")
packCmd.Flags().BoolVarP(&noOs, "no-os", "", false, "do not add operating system to output filename")
packCmd.Flags().BoolVarP(&noPostScript, "no-post-script", "", false, "do not handle '"+constants.PostPackScriptName+"' script")
packCmd.Flags().BoolVarP(&noPreScript, "no-pre-script", "", false, "do not handle '"+constants.PrePackScriptName+"' script")
Expand Down
117 changes: 71 additions & 46 deletions commands/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,76 @@
package commands

import (
"bytes"
"fmt"
"os"
"path"
"regexp"
"runtime"
"strings"
"text/template"

"github.com/alecthomas/chroma/quick"
"github.com/fatih/color"
"github.com/spf13/cobra"

"github.com/mkloubert/go-package-manager/constants"
"github.com/mkloubert/go-package-manager/resources"
"github.com/mkloubert/go-package-manager/types"
"github.com/mkloubert/go-package-manager/utils"
)

func init_setup_git_command(parentCmd *cobra.Command, app *types.AppContext) {
var force bool
var local bool

var setupUpdaterCmd = &cobra.Command{
Use: "git [name] [email]",
Aliases: []string{"g", "gt"},
Args: cobra.MinimumNArgs(2),
Short: "Setup git",
Long: `Sets up git with minimum and required settings like name and email.`,
Run: func(cmd *cobra.Command, args []string) {
name := strings.TrimSpace(args[0])
email := strings.TrimSpace(strings.ToLower(args[1]))

if !force {
const emailRegexPattern = `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`
emailRegex := regexp.MustCompile(emailRegexPattern)

if name == "" {
utils.CloseWithError(fmt.Errorf("no name defined"))
}

if !emailRegex.MatchString(email) {
utils.CloseWithError(fmt.Errorf("no valid email address defined"))
}
}

app.Debug(fmt.Sprintf("Setting up user name as '%v' ...", name))
if local {
app.RunShellCommandByArgs("git", "config", "user.name", name)
} else {
app.RunShellCommandByArgs("git", "config", "--global", "user.name", name)
}

app.Debug(fmt.Sprintf("Setting up user email as '%v' ...", email))
if local {
app.RunShellCommandByArgs("git", "config", "user.email", email)
} else {
app.RunShellCommandByArgs("git", "config", "--global", "user.email", email)
}
},
}

parentCmd.Flags().BoolVarP(&force, "force", "", false, "no checks")
parentCmd.Flags().BoolVarP(&local, "local", "", false, "no --global flag")

parentCmd.AddCommand(
setupUpdaterCmd,
)
}

func init_setup_updater_command(parentCmd *cobra.Command, app *types.AppContext) {
var setupUpdaterCmd = &cobra.Command{
Use: "updater",
Expand Down Expand Up @@ -69,54 +125,22 @@ func init_setup_updater_command(parentCmd *cobra.Command, app *types.AppContext)
}

createScript = func() {
bashScript := fmt.Sprintf(`#!/bin/bash
handle_error() {
echo "Error: $1"
exit 1
}
echo "gpm-update"
echo ""
templateData, err := resources.Templates.ReadFile("templates/gpm-update.sh")
utils.CheckForError(err)

echo "Finding download URL and SHA256 URL ..."
latest_release_info=$(wget -qO- https://api.github.com/repos/mkloubert/go-package-manager/releases/latest) || handle_error "Could not fetch release infos"
download_url=$(echo "$latest_release_info" | jq -r '.assets[].browser_download_url | select(contains("gpm") and contains("%v") and contains("%v") and (. | tostring | contains("sha256") | not))') || handle_error "Could not parse download URL"
sha256_url=$(echo "$latest_release_info" | jq -r '.assets[].browser_download_url | select(contains("gpm") and contains("%v") and contains("%v") and contains("sha256"))') || handle_error "Could not parse SHA256 URL"
template, err := template.New("gpm-update.sh").Parse(string(templateData))
utils.CheckForError(err)

if [ -z "$download_url" ]; then
handle_error "No valid download URL found"
fi
var bashScriptBuffer bytes.Buffer
template.Execute(&bashScriptBuffer, map[string]string{
"GOOS": goos,
"GOARCH": goarch,
"SHA256Command": sha256Command,
})
utils.CheckForError(err)
defer bashScriptBuffer.Reset()

if [ -z "$sha256_url" ]; then
handle_error "No valid SHA256 URL found"
fi
echo "Downloading tarball from '$download_url'..."
wget -q "$download_url" -O gpm.tar.gz || handle_error "Failed to download tarball"
echo "Downloading SHA256 file from '$sha256_url'..."
wget -q "$sha256_url" -O gpm.tar.gz.sha256 || handle_error "Failed to download SHA256 file"
echo "Verifying tarball ..."
%v || handle_error "SHA256 verification failed"
echo "Extracting binary ..."
tar -xzOf gpm.tar.gz gpm > gpm || handle_error "Could not extract 'gpm' binary"
echo "Installing 'gpm' to /usr/local/bin ..."
sudo mv gpm /usr/local/bin/gpm || handle_error "Could not move 'gpm' to '/usr/local/bin'"
sudo chmod +x /usr/local/bin/gpm || handle_error "Could not update permissions of 'gpm' binary"
echo "Cleaning up ..."
rm gpm.tar.gz gpm.tar.gz.sha256 || handle_error "Cleanups failed"
echo "'gpm' successfully installed or updated 👍"
`,
goos, goarch,
goos, goarch,
sha256Command,
)
bashScript := bashScriptBuffer.String()

app.Debug(fmt.Sprintf("Writing bash script to '%v' ...", bashScriptFilePath))
os.WriteFile(bashScriptFilePath, []byte(bashScript), constants.DefaultFileMode)
Expand All @@ -127,7 +151,7 @@ echo "'gpm' successfully installed or updated 👍"
fmt.Sprintln(), fmt.Sprintln(),
)

err := quick.Highlight(os.Stdout, bashScript, "shell", consoleFormatter, consoleStyle)
err = quick.Highlight(os.Stdout, bashScript, "shell", consoleFormatter, consoleStyle)
if err != nil {
fmt.Print(bashScript)
}
Expand Down Expand Up @@ -158,6 +182,7 @@ func Init_Setup_Command(parentCmd *cobra.Command, app *types.AppContext) {
},
}

init_setup_git_command(setupCmd, app)
init_setup_updater_command(setupCmd, app)

parentCmd.AddCommand(
Expand Down
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ package main
import (
"log"
"os"
"strings"

"github.com/spf13/cobra"

Expand All @@ -50,6 +51,7 @@ func main() {
var app types.AppContext
app.L = log.Default()
app.Cwd = cwd
app.IsCI = strings.TrimSpace(strings.ToLower(os.Getenv("CI"))) == "true"

// use "environment flag" everywhere
rootCmd.PersistentFlags().StringVarP(&app.Environment, "environment", "", "", "name of the environment")
Expand Down
1 change: 1 addition & 0 deletions projects.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
projects:
gopass: https://github.com/gopasspw/gopass
gpm: https://github.com/mkloubert/go-package-manager
hugo: https://github.com/gohugoio/hugo
Loading

0 comments on commit 3440116

Please sign in to comment.