├── .editorconfig
├── .github
├── CODEOWNERS
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── dependabot.yml
└── workflows
│ ├── build.yml
│ ├── release.yml
│ └── release_package.yml
├── .gitignore
├── .go-version
├── .goreleaser.yml
├── .mergify.yml
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── bin
├── release
└── shims
│ ├── go
│ └── gofmt
├── cache
└── .gitignore
├── cmd
├── config.go
├── exec.go
├── global.go
├── info.go
├── init.go
├── install.go
├── license.go
├── local.go
├── rehash.go
├── root.go
├── satisfy.go
├── uninstall.go
├── version.go
└── versions.go
├── config.toml
├── core
├── module
│ ├── charm_select.go
│ ├── charm_spinner.go
│ ├── const.go
│ ├── golang.go
│ └── golang_test.go
├── service
│ ├── file_system.go
│ ├── file_system_test.go
│ ├── installer.go
│ └── installer_test.go
└── util
│ ├── helpers.go
│ └── helpers_test.go
├── go.mod
├── go.sum
├── goenv.go
├── pkg
└── loader.go
├── renovate.json
├── static
├── logo.png
├── logo1.png
└── screenshot-1.png
├── techstack.md
└── techstack.yml
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | insert_final_newline = true
7 | indent_style = space
8 | indent_size = 4
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
14 | [*.{yml,yaml}]
15 | indent_size = 2
16 |
17 | [docker-compose.yml]
18 | indent_size = 4
19 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Docs: https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners
2 | * @clivern
3 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: # clivern
2 | custom: clivern.com/sponsor/
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | ---
5 |
6 | **Describe the bug**
7 | A clear and concise description of what the bug is.
8 |
9 | **Development or production environment**
10 |
11 | - OS: [e.g. Ubuntu 18.04]
12 | - Go 1.13
13 |
14 | **Additional context**
15 | Add any other context about the problem here.
16 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | ---
5 |
6 | **Is your feature request related to a problem? Please describe.**
7 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
8 |
9 | **Describe the solution you'd like**
10 | A clear and concise description of what you want to happen.
11 |
12 | **Additional context**
13 | Add any other context or screenshots about the feature request here.
14 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "gomod"
9 | directory: "/"
10 | schedule:
11 | interval: "daily"
12 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on:
4 | push:
5 | pull_request:
6 |
7 | jobs:
8 | build:
9 | runs-on: ubuntu-latest
10 | strategy:
11 | fail-fast: false
12 | matrix:
13 | go: ["1.18", "1.18.1", "1.19", "1.20", "1.21", "1.22", "1.23"]
14 | name: Go ${{ matrix.go }} run
15 | steps:
16 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
17 | - name: Setup go
18 | uses: actions/setup-go@v5
19 | with:
20 | go-version: ${{ matrix.go }}
21 |
22 | - name: Get dependencies
23 | run: |
24 | export PATH=${PATH}:`go env GOPATH`/bin
25 | make install_revive
26 |
27 | - name: Run make ci
28 | run: |
29 | export PATH=${PATH}:`go env GOPATH`/bin
30 | go get -t .
31 | make ci
32 | make integration
33 | git status
34 | git diff > diff.log
35 | cat diff.log
36 | git clean -fd
37 | git reset --hard
38 | make verify
39 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | push:
5 | tags:
6 | - "*"
7 |
8 | jobs:
9 | goreleaser:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Checkout
13 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
14 | with:
15 | fetch-depth: 0
16 | - name: Set up Go
17 | uses: actions/setup-go@v5
18 | with:
19 | go-version: 1.19
20 | - name: Run GoReleaser
21 | uses: goreleaser/goreleaser-action@v5
22 | with:
23 | version: latest
24 | args: release --rm-dist
25 | env:
26 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27 | TAP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }}
28 |
--------------------------------------------------------------------------------
/.github/workflows/release_package.yml:
--------------------------------------------------------------------------------
1 | name: Release Package
2 |
3 | on:
4 | push:
5 | tags:
6 | - "*"
7 |
8 | jobs:
9 | release:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Checkout
13 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
14 | with:
15 | fetch-depth: 0
16 | - name: Set up Go
17 | uses: actions/setup-go@v5
18 | with:
19 | go-version: 1.19
20 |
21 | - name: Update checksum database
22 | run: |
23 | ./bin/release
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 |
8 | # Test binary, build with `go test -c`
9 | *.test
10 |
11 | # Output of the go coverage tool, specifically when used with LiteIDE
12 | *.out
13 |
14 | # dist dir
15 | dist
16 |
17 | !web/dist
18 |
19 | sync
20 |
21 | *.db
22 |
23 | config.test.yml
24 | coverage.html
--------------------------------------------------------------------------------
/.go-version:
--------------------------------------------------------------------------------
1 | 1.18
2 |
--------------------------------------------------------------------------------
/.goreleaser.yml:
--------------------------------------------------------------------------------
1 | # This is an example .goreleaser.yml file with some sensible defaults.
2 | # Make sure to check the documentation at https://goreleaser.com
3 | before:
4 | hooks:
5 | - "go mod download"
6 | - "go mod tidy"
7 | - "go generate ./..."
8 | builds:
9 | - env:
10 | - CGO_ENABLED=0
11 | goos:
12 | - linux
13 | - windows
14 | - darwin
15 |
16 | archives:
17 | - format: tar.gz
18 | # this name template makes the OS and Arch compatible with the results of uname.
19 | name_template: >-
20 | {{ .ProjectName }}_
21 | {{- title .Os }}_
22 | {{- if eq .Arch "amd64" }}x86_64
23 | {{- else if eq .Arch "386" }}i386
24 | {{- else }}{{ .Arch }}{{ end }}
25 | {{- if .Arm }}v{{ .Arm }}{{ end }}
26 | # use zip for windows archives
27 | format_overrides:
28 | - goos: windows
29 | format: zip
30 | files:
31 | - LICENSE
32 | - README.md
33 | checksum:
34 | name_template: 'checksums.txt'
35 | snapshot:
36 | name_template: "{{ incpatch .Version }}-next"
37 | changelog:
38 | sort: asc
39 | filters:
40 | exclude:
41 | - '^docs:'
42 | - '^test:'
43 | project_name: goenv
44 |
--------------------------------------------------------------------------------
/.mergify.yml:
--------------------------------------------------------------------------------
1 | ---
2 | pull_request_rules:
3 | - actions:
4 | merge:
5 | method: squash
6 | conditions:
7 | - author!=Clivern
8 | - approved-reviews-by=Clivern
9 | - label=release
10 | name: "Automatic Approved Merge 🚀"
11 | - actions:
12 | merge:
13 | method: merge
14 | conditions:
15 | - author=Clivern
16 | - label=release
17 | name: "Automatic Merge 🚀"
18 | - actions:
19 | merge:
20 | method: squash
21 | conditions:
22 | - "author=renovate[bot]"
23 | - label=release
24 | name: "Automatic Merge for Renovate PRs 🚀"
25 | - actions:
26 | comment:
27 | message: "Nice! PR merged successfully."
28 | conditions:
29 | - merged
30 | name: "Merge Done 🚀"
31 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hello@clivern.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Contributing
2 |
3 | - With issues:
4 | - Use the search tool before opening a new issue.
5 | - Please provide source code and commit sha if you found a bug.
6 | - Review existing issues and provide feedback or react to them.
7 |
8 | - With pull requests:
9 | - Open your pull request against `main`
10 | - Your pull request should have no more than two commits, if not you should squash them.
11 | - It should pass all tests in the available continuous integrations systems such as github actions.
12 | - You should add/modify tests to cover your proposed code changes.
13 | - If your pull request contains a new feature, please document it on the README.
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2022 Clivern
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | go ?= go
2 | gofmt ?= $(go)fmt
3 | pkgs = ./...
4 |
5 |
6 | help: Makefile
7 | @echo
8 | @echo " Choose a command run in Goenv:"
9 | @echo
10 | @sed -n 's/^##//p' $< | column -t -s ':' | sed -e 's/^/ /'
11 | @echo
12 |
13 |
14 | ## install_revive: Install revive for linting.
15 | .PHONY: install_revive
16 | install_revive:
17 | @echo ">> ============= Install Revive ============= <<"
18 | $(go) install github.com/mgechev/revive@v1.3.9
19 |
20 |
21 | ## style: Check code style.
22 | .PHONY: style
23 | style:
24 | @echo ">> ============= Checking Code Style ============= <<"
25 | @fmtRes=$$($(gofmt) -d $$(find . -path ./vendor -prune -o -name '*.go' -print)); \
26 | if [ -n "$${fmtRes}" ]; then \
27 | echo "gofmt checking failed!"; echo "$${fmtRes}"; echo; \
28 | echo "Please ensure you are using $$($(go) version) for formatting code."; \
29 | exit 1; \
30 | fi
31 |
32 |
33 | ## check_license: Check if license header on all files.
34 | .PHONY: check_license
35 | check_license:
36 | @echo ">> ============= Checking License Header ============= <<"
37 | @licRes=$$(for file in $$(find . -type f -iname '*.go' ! -path './vendor/*') ; do \
38 | awk 'NR<=3' $$file | grep -Eq "(Copyright|generated|GENERATED)" || echo $$file; \
39 | done); \
40 | if [ -n "$${licRes}" ]; then \
41 | echo "license header checking failed:"; echo "$${licRes}"; \
42 | exit 1; \
43 | fi
44 |
45 |
46 | ## test_short: Run test cases with short flag.
47 | .PHONY: test_short
48 | test_short:
49 | @echo ">> ============= Running Short Tests ============= <<"
50 | $(go) clean -testcache
51 | $(go) test -mod=readonly -short $(pkgs)
52 |
53 |
54 | ## test: Run test cases.
55 | .PHONY: test
56 | test:
57 | @echo ">> ============= Running All Tests ============= <<"
58 | $(go) clean -testcache
59 | $(go) test -mod=readonly -run=Unit -bench=. -benchmem -v -cover $(pkgs)
60 |
61 |
62 | ## integration: Run integration test cases (Requires etcd)
63 | .PHONY: integration
64 | integration:
65 | @echo ">> ============= Running All Tests ============= <<"
66 | $(go) clean -testcache
67 | $(go) test -mod=readonly -run=Integration -bench=. -benchmem -v -cover $(pkgs)
68 |
69 |
70 | ## lint: Lint the code.
71 | .PHONY: lint
72 | lint:
73 | @echo ">> ============= Lint All Files ============= <<"
74 | revive -config config.toml -exclude vendor/... -formatter friendly ./...
75 |
76 |
77 | ## verify: Verify dependencies
78 | .PHONY: verify
79 | verify:
80 | @echo ">> ============= List Dependencies ============= <<"
81 | $(go) list -m all
82 | @echo ">> ============= Verify Dependencies ============= <<"
83 | $(go) mod verify
84 |
85 |
86 | ## format: Format the code.
87 | .PHONY: format
88 | format:
89 | @echo ">> ============= Formatting Code ============= <<"
90 | $(go) fmt $(pkgs)
91 |
92 |
93 | ## vet: Examines source code and reports suspicious constructs.
94 | .PHONY: vet
95 | vet:
96 | @echo ">> ============= Vetting Code ============= <<"
97 | $(go) vet $(pkgs)
98 |
99 |
100 | ## coverage: Create HTML coverage report
101 | .PHONY: coverage
102 | coverage:
103 | @echo ">> ============= Coverage ============= <<"
104 | rm -f coverage.html cover.out
105 | $(go) test -mod=readonly -coverprofile=cover.out $(pkgs)
106 | go tool cover -html=cover.out -o coverage.html
107 |
108 |
109 | ## run: Run the Server
110 | .PHONY: run
111 | run:
112 | @echo ">> ============= Run API Server ============= <<"
113 | $(go) run goenv.go server -c config.dist.yml
114 |
115 |
116 | ## ci: Run all CI tests.
117 | .PHONY: ci
118 | ci: style check_license test vet lint
119 | @echo "\n==> All quality checks passed"
120 |
121 |
122 | .PHONY: help
123 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Goenv
4 | Manage Your Applications Go Environment
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | Goenv helps you to work with multiple `golang` versions at the same time whether on mac or linux operating system. It supports both global and per-application version configuration.
31 |
32 |
33 | ## Usage
34 |
35 | Download [the latest `goenv` binary](https://github.com/clivern/Goenv/releases). Make it executable from everywhere.
36 |
37 | ```zsh
38 | $ export GOENV_LATEST_VERSION=$(curl --silent "https://api.github.com/repos/clivern/Goenv/releases/latest" | jq '.tag_name' | sed -E 's/.*"([^"]+)".*/\1/' | tr -d v)
39 |
40 | # For Linux
41 | $ curl -sL https://github.com/clivern/Goenv/releases/download/v{$GOENV_LATEST_VERSION}/goenv_Linux_x86_64.tar.gz | tar xz
42 |
43 | # For Mac (Arm M chips)
44 | $ curl -sL https://github.com/clivern/Goenv/releases/download/v{$GOENV_LATEST_VERSION}/goenv_Darwin_arm64.tar.gz | tar xz
45 |
46 |
47 | # For Mac (Intel)
48 | $ curl -sL https://github.com/clivern/Goenv/releases/download/v{$GOENV_LATEST_VERSION}/goenv_Darwin_x86_64.tar.gz | tar xz
49 | ```
50 |
51 | Configure the goenv using the following command
52 |
53 | ```zsh
54 | $ goenv config
55 | ```
56 |
57 | Add `goenv` shims to `PATH` using the following command. also append it to `~/.profile` file to make it permanent.
58 |
59 | ```zsh
60 | $ export PATH="$HOME/.goenv/shims:"$PATH
61 |
62 | # OR
63 |
64 | $ eval "$(goenv init)"
65 | ```
66 |
67 | Install a new `go` version `1.18` and set as a global
68 |
69 | ```zsh
70 | $ goenv install 1.18
71 | $ goenv global 1.18
72 | ```
73 |
74 | To configure a local version different from the global
75 |
76 | ```zsh
77 | $ goenv local 1.18
78 | ```
79 |
80 | To Uninstall a version
81 |
82 | ```zsh
83 | $ goenv uninstall 1.18
84 | ```
85 |
86 | Show the used version either from current directory or parent directories or the global version.
87 |
88 | ```zsh
89 | $ goenv version
90 | ```
91 |
92 | To list all installed versions
93 |
94 | ```zsh
95 | $ goenv versions
96 | ```
97 |
98 | for a list of all available commands
99 |
100 | ```zsh
101 | $ goenv --help
102 |
103 | 🐺 Manage Your Applications Go Environment.
104 |
105 | If you have any suggestions, bug reports, or annoyances please report
106 | them to our issue tracker at
107 |
108 | Usage:
109 | goenv [command]
110 |
111 | Available Commands:
112 | completion Generate the autocompletion script for the specified shell
113 | config Configure the goenv application.
114 | exec Show the current go version.
115 | global Set or show the global go version.
116 | help Help about any command
117 | info Print the goenv version
118 | init Init the import path for goenv shims.
119 | install Install a go version.
120 | license Print the license
121 | local Set or show the local application-specific go version.
122 | rehash Refresh binaries under goenv shim directory.
123 | satisfy Satisfy the current directry go version.
124 | uninstall Uninstall a specific go version.
125 | version Show the current go version.
126 | versions List installed go versions.
127 |
128 | Flags:
129 | -h, --help help for goenv
130 |
131 | Use "goenv [command] --help" for more information about a command.
132 | ```
133 |
134 |
135 | ## Under The Hood
136 |
137 | Goenv is inspired by and works like `rbenv`. At a high level, `goenv` intercepts `Go` commands using `shim` executables injected into your `PATH`, determines which Go version has been specified by your application or globally, and passes your commands to the correct `Go` installation `bin` folder.
138 |
139 | **Understanding PATH**
140 |
141 | When you run a command like `go` or `gofmt`, your operating system searches through a list of directories to find an executable file with that name. This list of directories lives in an environment variable called `PATH`, with each directory in the list separated by a colon:
142 |
143 | ```
144 | /usr/local/bin:/usr/bin:/bin
145 | ```
146 |
147 | Directories in `PATH` are searched from left to right, so a matching executable in a directory at the beginning of the list takes precedence over another one at the end. In this example, the `/usr/local/bin` directory will be searched first, then `/usr/bin`, then `/bin`.
148 |
149 | **Understanding Shims**
150 |
151 | `goenv` works by inserting a directory of shims at the front of your `PATH`:
152 |
153 | ```zsh
154 | ~/.goenv/shims:/usr/local/bin:/usr/bin:/bin
155 | ```
156 |
157 | Through a process called rehashing, `goenv` maintains shims in that directory to match every `Go` command across every installed version of `go` like `gofmt` and so on.
158 |
159 | `shims` are lightweight executables that simply pass your command to the right binary under the current go version, your operating system will do the following:
160 |
161 | 1. Search your `PATH` for an executable file named `gofmt`.
162 | 2. Find the goenv shim named `gofmt` at the beginning of your `PATH`
163 | 3. Run the shim named `gofmt`, which in turn fetch the target go version and use the `gofmt` inside `go/bin` directory.
164 |
165 | **Choosing the Go Version**
166 |
167 | When you execute a shim, `goenv` determines which Go version to use by reading it from the following sources, in this order:
168 |
169 | 1. The first `.go-version `file found by searching the current working directory and each of its parent directories until reaching the root of your filesystem. You can modify the `.go-version` file in the current working directory with the `goenv local x.x.x` command.
170 | 2. The global `$HOME/.goenv/.go-version` file. You can modify this file using the `goenv global x.x.x` command.
171 |
172 |
173 | ## Versioning
174 |
175 | For transparency into our release cycle and in striving to maintain backward compatibility, Goenv is maintained under the [Semantic Versioning guidelines](https://semver.org/) and release process is predictable and business-friendly.
176 |
177 | See the [Releases section of our GitHub project](https://github.com/clivern/goenv/releases) for changelogs for each release version of Goenv. It contains summaries of the most noteworthy changes made in each release. Also see the [Milestones section](https://github.com/clivern/goenv/milestones) for the future roadmap.
178 |
179 |
180 | ## Bug tracker
181 |
182 | If you have any suggestions, bug reports, or annoyances please report them to our issue tracker at https://github.com/clivern/goenv/issues
183 |
184 |
185 | ## Security Issues
186 |
187 | If you discover a security vulnerability within Goenv, please send an email to [hello@clivern.com](mailto:hello@clivern.com)
188 |
189 |
190 | ## Contributing
191 |
192 | We are an open source, community-driven project so please feel free to join us. see the [contributing guidelines](CONTRIBUTING.md) for more details.
193 |
194 |
195 | ## License
196 |
197 | © 2022, Clivern. Released under [MIT License](https://opensource.org/licenses/mit-license.php).
198 |
199 | **Goenv** is authored and maintained by [@clivern](http://github.com/clivern).
200 |
--------------------------------------------------------------------------------
/bin/release:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Fetch latest version
4 | export LATEST_VERSION=$(curl --silent "https://api.github.com/repos/clivern/goenv/releases/latest" | jq '.tag_name' | sed -E 's/.*"([^"]+)".*/\1/')
5 |
6 | # Update go checksum database (sum.golang.org) immediately after release
7 | curl --silent https://sum.golang.org/lookup/github.com/clivern/goenv@{$LATEST_VERSION}
8 |
--------------------------------------------------------------------------------
/bin/shims/go:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | GO_BINARY_NAME=go
4 |
5 | GO_VERSION_PATH=$(goenv exec)
6 |
7 | GOENV_ROOT="$HOME/.goenv" \
8 | GOPATH=$GO_VERSION_PATH \
9 | GOBIN=$GO_VERSION_PATH/bin \
10 | "$GO_VERSION_PATH/bin/$GO_BINARY_NAME" "$@"
11 |
12 | if [[ "$@" =~ 'get' ]]
13 | then
14 | goenv rehash
15 | fi
16 |
17 | if [[ "$@" =~ 'install' ]]
18 | then
19 | goenv rehash
20 | fi
21 |
--------------------------------------------------------------------------------
/bin/shims/gofmt:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | GO_BINARY_NAME=gofmt
4 |
5 | GO_VERSION_PATH=$(goenv exec)
6 |
7 | GOENV_ROOT="$HOME/.goenv" \
8 | GOPATH=$GO_VERSION_PATH \
9 | GOBIN=$GO_VERSION_PATH/bin \
10 | "$GO_VERSION_PATH/bin/$GO_BINARY_NAME" "$@"
11 |
--------------------------------------------------------------------------------
/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------
/cmd/config.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | // Package cmd package
6 | package cmd
7 |
8 | import (
9 | "fmt"
10 | "os"
11 |
12 | "github.com/clivern/goenv/core/module"
13 |
14 | "github.com/spf13/cobra"
15 | )
16 |
17 | var configCmd = &cobra.Command{
18 | Use: "config",
19 | Short: "Configure the goenv application.",
20 | Run: func(cmd *cobra.Command, args []string) {
21 |
22 | if HOME == "" {
23 | fmt.Println("Error! `HOME` environment variable is not set")
24 | os.Exit(1)
25 | }
26 |
27 | golang := module.NewGolangEnvironment(HOME)
28 |
29 | err := golang.Configure()
30 |
31 | if err != nil {
32 | fmt.Println(err.Error())
33 | os.Exit(1)
34 | }
35 |
36 | err = golang.Rehash()
37 |
38 | if err != nil {
39 | fmt.Println(err.Error())
40 | os.Exit(1)
41 | }
42 |
43 | fmt.Println("Goenv configured successfully!")
44 | },
45 | }
46 |
47 | func init() {
48 | rootCmd.AddCommand(configCmd)
49 | }
50 |
--------------------------------------------------------------------------------
/cmd/exec.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | package cmd
6 |
7 | import (
8 | "fmt"
9 | "os"
10 |
11 | "github.com/clivern/goenv/core/module"
12 |
13 | "github.com/spf13/cobra"
14 | )
15 |
16 | var execCmd = &cobra.Command{
17 | Use: "exec",
18 | Short: "Show the current go version.",
19 | Run: func(cmd *cobra.Command, args []string) {
20 |
21 | // Get local version path
22 | golang := module.NewGolangEnvironment(HOME)
23 |
24 | cdir, err := os.Getwd()
25 |
26 | if err != nil {
27 | fmt.Println(err.Error())
28 | os.Exit(1)
29 | }
30 |
31 | version, err := golang.GetLocalVersion(cdir)
32 |
33 | if err == nil {
34 | fmt.Printf("%s/%s/%s", golang.RootPath, golang.VersionsDir, version)
35 | return
36 | }
37 |
38 | // Get global version path
39 | version, err = golang.GetGlobalVersion()
40 |
41 | if err == nil {
42 | fmt.Printf("%s/%s/%s", golang.RootPath, golang.VersionsDir, version)
43 | return
44 | }
45 |
46 | fmt.Println(err.Error())
47 | os.Exit(1)
48 | },
49 | }
50 |
51 | func init() {
52 | rootCmd.AddCommand(execCmd)
53 | }
54 |
--------------------------------------------------------------------------------
/cmd/global.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | package cmd
6 |
7 | import (
8 | "fmt"
9 | "os"
10 |
11 | "github.com/clivern/goenv/core/module"
12 |
13 | "github.com/spf13/cobra"
14 | )
15 |
16 | var globalCmd = &cobra.Command{
17 | Use: "global",
18 | Short: "Set or show the global go version.",
19 | Run: func(cmd *cobra.Command, args []string) {
20 |
21 | golang := module.NewGolangEnvironment(HOME)
22 |
23 | if len(args) == 1 {
24 | if !golang.ValidateVersion(args[0]) {
25 | fmt.Printf("Error! Invalid version provided %s\n", args[0])
26 | os.Exit(1)
27 | }
28 |
29 | // Set the global version
30 | err := golang.SetGlobalVersion(args[0])
31 |
32 | if err != nil {
33 | fmt.Println(err.Error())
34 | os.Exit(1)
35 | }
36 |
37 | fmt.Printf("Global version updated into %s\n", args[0])
38 | return
39 | }
40 |
41 | // Get the global version
42 | version, err := golang.GetGlobalVersion()
43 |
44 | if err != nil {
45 | fmt.Println(err.Error())
46 | os.Exit(1)
47 | }
48 |
49 | fmt.Println(version)
50 | },
51 | }
52 |
53 | func init() {
54 | rootCmd.AddCommand(globalCmd)
55 | }
56 |
--------------------------------------------------------------------------------
/cmd/info.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | package cmd
6 |
7 | import (
8 | "fmt"
9 |
10 | "github.com/spf13/cobra"
11 | )
12 |
13 | var (
14 | // Version buildinfo item
15 | Version = "dev"
16 | // Commit buildinfo item
17 | Commit = "none"
18 | // Date buildinfo item
19 | Date = "unknown"
20 | // BuiltBy buildinfo item
21 | BuiltBy = "unknown"
22 | // HOME the home path
23 | HOME = ""
24 | )
25 |
26 | var infoCmd = &cobra.Command{
27 | Use: "info",
28 | Short: "Print the goenv version",
29 | Run: func(cmd *cobra.Command, args []string) {
30 | fmt.Println(
31 | fmt.Sprintf(
32 | `Current Goenv Version %v Commit %v, Built @%v By %v.`,
33 | Version,
34 | Commit,
35 | Date,
36 | BuiltBy,
37 | ),
38 | )
39 | },
40 | }
41 |
42 | func init() {
43 | rootCmd.AddCommand(infoCmd)
44 | }
45 |
--------------------------------------------------------------------------------
/cmd/init.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | package cmd
6 |
7 | import (
8 | "fmt"
9 |
10 | "github.com/clivern/goenv/core/module"
11 |
12 | "github.com/spf13/cobra"
13 | )
14 |
15 | var initCmd = &cobra.Command{
16 | Use: "init",
17 | Short: "Init the import path for goenv shims.",
18 | Run: func(cmd *cobra.Command, args []string) {
19 |
20 | if HOME == "" {
21 | return
22 | }
23 |
24 | golang := module.NewGolangEnvironment(HOME)
25 |
26 | fmt.Printf("export PATH=\"%s/%s:${PATH}\"\n", golang.RootPath, golang.ShimsDir)
27 | },
28 | }
29 |
30 | func init() {
31 | rootCmd.AddCommand(initCmd)
32 | }
33 |
--------------------------------------------------------------------------------
/cmd/install.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | package cmd
6 |
7 | import (
8 | "fmt"
9 | "os"
10 |
11 | "github.com/clivern/goenv/core/module"
12 |
13 | "github.com/spf13/cobra"
14 | )
15 |
16 | var installCmd = &cobra.Command{
17 | Use: "install",
18 | Short: "Install a go version.",
19 | Run: func(cmd *cobra.Command, args []string) {
20 |
21 | golang := module.NewGolangEnvironment(HOME)
22 |
23 | if len(args) == 0 {
24 | // Show the go releases select box
25 | list := module.NewCharmSelect(
26 | "Which go version to install?",
27 | module.GolangReleases,
28 | )
29 |
30 | if err := list.Start(); err != nil {
31 | fmt.Printf("Error showing releases list: %s\n", err.Error())
32 | os.Exit(1)
33 | }
34 | } else {
35 | module.SelectedValue = args[0]
36 | }
37 |
38 | if !golang.ValidateVersion(module.SelectedValue) {
39 | fmt.Printf("Error! Invalid version provided %s\n", module.SelectedValue)
40 | os.Exit(1)
41 | }
42 |
43 | isInstalled, err := golang.ValidateInstalledVersion(module.SelectedValue)
44 |
45 | if err != nil {
46 | fmt.Println(err.Error())
47 | os.Exit(1)
48 | }
49 |
50 | if isInstalled {
51 | fmt.Printf("Error! Version %s is already installed\n", module.SelectedValue)
52 | os.Exit(1)
53 | }
54 |
55 | // Show a loading spinner
56 | spinner := module.NewCharmSpinner(fmt.Sprintf(
57 | "Getting Go v%s Environment Ready",
58 | module.SelectedValue,
59 | ))
60 |
61 | go func() {
62 | // Download and install go selected version
63 | err = golang.Install(module.SelectedValue)
64 |
65 | if err != nil {
66 | fmt.Println(err.Error())
67 | }
68 |
69 | spinner.Quit()
70 | }()
71 |
72 | // Start the spinner
73 | if err := spinner.Start(); err != nil {
74 | fmt.Printf("Error showing loading bar: %s\n", err.Error())
75 | os.Exit(1)
76 | }
77 | },
78 | }
79 |
80 | func init() {
81 | rootCmd.AddCommand(installCmd)
82 | }
83 |
--------------------------------------------------------------------------------
/cmd/license.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | package cmd
6 |
7 | import (
8 | "fmt"
9 |
10 | "github.com/spf13/cobra"
11 | )
12 |
13 | var licenseCmd = &cobra.Command{
14 | Use: "license",
15 | Short: "Print the license",
16 | Run: func(cmd *cobra.Command, args []string) {
17 | fmt.Println(`MIT License
18 |
19 | Copyright (c) 2022 Clivern
20 |
21 | Permission is hereby granted, free of charge, to any person obtaining a copy
22 | of this software and associated documentation files (the "Software"), to deal
23 | in the Software without restriction, including without limitation the rights
24 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25 | copies of the Software, and to permit persons to whom the Software is
26 | furnished to do so, subject to the following conditions:
27 |
28 | The above copyright notice and this permission notice shall be included in all
29 | copies or substantial portions of the Software.
30 |
31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37 | SOFTWARE.`)
38 | },
39 | }
40 |
41 | func init() {
42 | rootCmd.AddCommand(licenseCmd)
43 | }
44 |
--------------------------------------------------------------------------------
/cmd/local.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | package cmd
6 |
7 | import (
8 | "fmt"
9 | "os"
10 |
11 | "github.com/clivern/goenv/core/module"
12 |
13 | "github.com/spf13/cobra"
14 | )
15 |
16 | var localCmd = &cobra.Command{
17 | Use: "local",
18 | Short: "Set or show the local application-specific go version.",
19 | Run: func(cmd *cobra.Command, args []string) {
20 |
21 | golang := module.NewGolangEnvironment(HOME)
22 |
23 | if len(args) == 1 {
24 |
25 | if !golang.ValidateVersion(args[0]) {
26 | fmt.Printf("Error! Invalid version provided %s\n", args[0])
27 | os.Exit(1)
28 | }
29 |
30 | // Set the local version
31 | err := golang.SetLocalVersion(args[0])
32 |
33 | if err != nil {
34 | fmt.Println(err.Error())
35 | os.Exit(1)
36 | }
37 |
38 | fmt.Printf("Local version updated into %s\n", args[0])
39 | return
40 | }
41 |
42 | cdir, err := os.Getwd()
43 |
44 | if err != nil {
45 | fmt.Println(err.Error())
46 | os.Exit(1)
47 | }
48 |
49 | version, err := golang.GetLocalVersion(cdir)
50 |
51 | if err == nil {
52 | fmt.Println(version)
53 | return
54 | }
55 |
56 | fmt.Println("Unable to find local version, fallback into global version")
57 |
58 | version, err = golang.GetGlobalVersion()
59 |
60 | if err == nil {
61 | fmt.Println(version)
62 | return
63 | }
64 |
65 | fmt.Println(err.Error())
66 | os.Exit(1)
67 | },
68 | }
69 |
70 | func init() {
71 | rootCmd.AddCommand(localCmd)
72 | }
73 |
--------------------------------------------------------------------------------
/cmd/rehash.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | package cmd
6 |
7 | import (
8 | "fmt"
9 | "os"
10 |
11 | "github.com/clivern/goenv/core/module"
12 |
13 | "github.com/spf13/cobra"
14 | )
15 |
16 | var rehashCmd = &cobra.Command{
17 | Use: "rehash",
18 | Short: "Refresh binaries under goenv shim directory.",
19 | Run: func(cmd *cobra.Command, args []string) {
20 |
21 | if HOME == "" {
22 | fmt.Println("Error! `HOME` environment variable is not set")
23 | os.Exit(1)
24 | }
25 |
26 | golang := module.NewGolangEnvironment(HOME)
27 |
28 | err := golang.Configure()
29 |
30 | if err != nil {
31 | fmt.Println(err.Error())
32 | os.Exit(1)
33 | }
34 |
35 | err = golang.Rehash()
36 |
37 | if err != nil {
38 | fmt.Println(err.Error())
39 | os.Exit(1)
40 | }
41 | },
42 | }
43 |
44 | func init() {
45 | rootCmd.AddCommand(rehashCmd)
46 | }
47 |
--------------------------------------------------------------------------------
/cmd/root.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | package cmd
6 |
7 | import (
8 | "fmt"
9 | "os"
10 |
11 | "github.com/spf13/cobra"
12 | )
13 |
14 | var config string
15 |
16 | var rootCmd = &cobra.Command{
17 | Use: "goenv",
18 | Short: `🐺 Manage Your Applications Go Environment.
19 |
20 | If you have any suggestions, bug reports, or annoyances please report
21 | them to our issue tracker at `,
22 | }
23 |
24 | // Execute runs cmd tool
25 | func Execute() {
26 | if err := rootCmd.Execute(); err != nil {
27 | fmt.Println(err)
28 | os.Exit(1)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/cmd/satisfy.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | package cmd
6 |
7 | import (
8 | "fmt"
9 | "os"
10 |
11 | "github.com/clivern/goenv/core/module"
12 |
13 | "github.com/spf13/cobra"
14 | )
15 |
16 | var satisfyCmd = &cobra.Command{
17 | Use: "satisfy",
18 | Short: "Satisfy the current directry go version.",
19 | Run: func(cmd *cobra.Command, args []string) {
20 |
21 | golang := module.NewGolangEnvironment(HOME)
22 |
23 | cdir, err := os.Getwd()
24 |
25 | if err != nil {
26 | fmt.Println(err.Error())
27 | os.Exit(1)
28 | }
29 |
30 | version, err := golang.GetLocalVersion(cdir)
31 |
32 | if err == nil {
33 | // Validate version
34 | if !golang.ValidateVersion(version) {
35 | fmt.Printf("Error! Invalid version detected %s\n", version)
36 | os.Exit(1)
37 | }
38 |
39 | isInstalled, err := golang.ValidateInstalledVersion(version)
40 |
41 | if err != nil {
42 | fmt.Println(err.Error())
43 | os.Exit(1)
44 | }
45 |
46 | if isInstalled {
47 | fmt.Printf("Go Version %s is already installed\n", version)
48 | return
49 | }
50 |
51 | // Show a loading spinner
52 | spinner := module.NewCharmSpinner(fmt.Sprintf(
53 | "Getting Go v%s Environment Ready",
54 | version,
55 | ))
56 |
57 | go func() {
58 | // Download and install the go version
59 | err = golang.Install(version)
60 |
61 | if err != nil {
62 | fmt.Println(err.Error())
63 | }
64 |
65 | spinner.Quit()
66 | }()
67 |
68 | // Start the spinner
69 | if err := spinner.Start(); err != nil {
70 | fmt.Printf("Error showing loading bar: %s\n", err.Error())
71 | os.Exit(1)
72 | }
73 |
74 | return
75 | }
76 |
77 | version, err = golang.GetGlobalVersion()
78 |
79 | if err == nil {
80 | // Validate version
81 | if !golang.ValidateVersion(version) {
82 | fmt.Printf("Error! Invalid version detected %s\n", version)
83 | os.Exit(1)
84 | }
85 |
86 | isInstalled, err := golang.ValidateInstalledVersion(version)
87 |
88 | if err != nil {
89 | fmt.Println(err.Error())
90 | os.Exit(1)
91 | }
92 |
93 | if isInstalled {
94 | fmt.Printf("Go Version %s is already installed\n", version)
95 | return
96 | }
97 |
98 | // Show a loading spinner
99 | spinner := module.NewCharmSpinner(fmt.Sprintf(
100 | "Getting Go v%s Environment Ready",
101 | version,
102 | ))
103 |
104 | go func() {
105 | // Download and install the go version
106 | err = golang.Install(version)
107 |
108 | if err != nil {
109 | fmt.Println(err.Error())
110 | }
111 |
112 | spinner.Quit()
113 | }()
114 |
115 | // Start the spinner
116 | if err := spinner.Start(); err != nil {
117 | fmt.Printf("Error showing loading bar: %s\n", err.Error())
118 | os.Exit(1)
119 | }
120 |
121 | return
122 | }
123 |
124 | fmt.Println(err.Error())
125 | os.Exit(1)
126 | },
127 | }
128 |
129 | func init() {
130 | rootCmd.AddCommand(satisfyCmd)
131 | }
132 |
--------------------------------------------------------------------------------
/cmd/uninstall.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | package cmd
6 |
7 | import (
8 | "fmt"
9 | "os"
10 |
11 | "github.com/clivern/goenv/core/module"
12 |
13 | "github.com/spf13/cobra"
14 | )
15 |
16 | var uninstallCmd = &cobra.Command{
17 | Use: "uninstall",
18 | Short: "Uninstall a specific go version.",
19 | Run: func(cmd *cobra.Command, args []string) {
20 |
21 | golang := module.NewGolangEnvironment(HOME)
22 |
23 | if len(args) == 0 {
24 | // Show the go releases select box
25 | versions, err := golang.GetInstalledVersions()
26 |
27 | if err != nil {
28 | fmt.Println(err.Error())
29 | os.Exit(1)
30 | }
31 |
32 | list := module.NewCharmSelect(
33 | "Which go version to uninstall?",
34 | versions,
35 | )
36 |
37 | if err := list.Start(); err != nil {
38 | fmt.Printf("Error showing releases list: %s\n", err.Error())
39 | os.Exit(1)
40 | }
41 | } else {
42 | module.SelectedValue = args[0]
43 | }
44 |
45 | if !golang.ValidateVersion(module.SelectedValue) {
46 | fmt.Printf("Error! Invalid version provided %s\n", module.SelectedValue)
47 | os.Exit(1)
48 | }
49 |
50 | isInstalled, err := golang.ValidateInstalledVersion(module.SelectedValue)
51 |
52 | if err != nil {
53 | fmt.Println(err.Error())
54 | os.Exit(1)
55 | }
56 |
57 | if !isInstalled {
58 | fmt.Printf("Error! Version %s is not installed\n", module.SelectedValue)
59 | os.Exit(1)
60 | }
61 |
62 | // Show a loading spinner
63 | spinner := module.NewCharmSpinner(fmt.Sprintf(
64 | "Removing Go v%s Environment",
65 | module.SelectedValue,
66 | ))
67 |
68 | go func() {
69 | // Download and install go selected version
70 | err = golang.Uninstall(module.SelectedValue)
71 |
72 | if err != nil {
73 | fmt.Println(err.Error())
74 | }
75 |
76 | spinner.Quit()
77 | }()
78 |
79 | // Start the spinner
80 | if err := spinner.Start(); err != nil {
81 | fmt.Printf("Error showing loading bar: %s\n", err.Error())
82 | os.Exit(1)
83 | }
84 | },
85 | }
86 |
87 | func init() {
88 | rootCmd.AddCommand(uninstallCmd)
89 | }
90 |
--------------------------------------------------------------------------------
/cmd/version.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | package cmd
6 |
7 | import (
8 | "fmt"
9 | "os"
10 |
11 | "github.com/clivern/goenv/core/module"
12 |
13 | "github.com/spf13/cobra"
14 | )
15 |
16 | var versionCmd = &cobra.Command{
17 | Use: "version",
18 | Short: "Show the current go version.",
19 | Run: func(cmd *cobra.Command, args []string) {
20 |
21 | golang := module.NewGolangEnvironment(HOME)
22 |
23 | cdir, err := os.Getwd()
24 |
25 | if err != nil {
26 | fmt.Println(err.Error())
27 | os.Exit(1)
28 | }
29 |
30 | version, err := golang.GetLocalVersion(cdir)
31 |
32 | if err == nil {
33 | fmt.Println(version)
34 | return
35 | }
36 |
37 | fmt.Println("Unable to find local version, fallback into global version")
38 |
39 | version, err = golang.GetGlobalVersion()
40 |
41 | if err == nil {
42 | fmt.Println(version)
43 | return
44 | }
45 |
46 | fmt.Println(err.Error())
47 | os.Exit(1)
48 | },
49 | }
50 |
51 | func init() {
52 | rootCmd.AddCommand(versionCmd)
53 | }
54 |
--------------------------------------------------------------------------------
/cmd/versions.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | package cmd
6 |
7 | import (
8 | "fmt"
9 | "os"
10 |
11 | "github.com/clivern/goenv/core/module"
12 |
13 | "github.com/spf13/cobra"
14 | )
15 |
16 | var versionsCmd = &cobra.Command{
17 | Use: "versions",
18 | Short: "List installed go versions.",
19 | Run: func(cmd *cobra.Command, args []string) {
20 |
21 | golang := module.NewGolangEnvironment(HOME)
22 |
23 | versions, err := golang.GetInstalledVersions()
24 |
25 | if err != nil {
26 | fmt.Println(err.Error())
27 | os.Exit(1)
28 | }
29 |
30 | for i := 0; i < len(versions); i++ {
31 | fmt.Println(versions[i])
32 | }
33 | },
34 | }
35 |
36 | func init() {
37 | rootCmd.AddCommand(versionsCmd)
38 | }
39 |
--------------------------------------------------------------------------------
/config.toml:
--------------------------------------------------------------------------------
1 | ignoreGeneratedHeader = false
2 | severity = "warning"
3 | confidence = 0.8
4 | errorCode = 0
5 | warningCode = 0
6 |
7 | [rule.blank-imports]
8 | [rule.context-as-argument]
9 | [rule.context-keys-type]
10 | [rule.dot-imports]
11 | [rule.error-return]
12 | [rule.error-strings]
13 | [rule.error-naming]
14 | [rule.exported]
15 | [rule.if-return]
16 | [rule.increment-decrement]
17 | [rule.var-naming]
18 | [rule.var-declaration]
19 | [rule.package-comments]
20 | [rule.range]
21 | [rule.receiver-naming]
22 | [rule.time-naming]
23 | [rule.unexported-return]
24 | [rule.indent-error-flow]
25 | [rule.errorf]
26 | [rule.empty-block]
27 | [rule.superfluous-else]
28 | [rule.unused-parameter]
29 | [rule.unreachable-code]
30 | [rule.redefines-builtin-id]
--------------------------------------------------------------------------------
/core/module/charm_select.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | // Package module package
6 | package module
7 |
8 | import (
9 | "fmt"
10 | "io"
11 |
12 | "github.com/charmbracelet/bubbles/list"
13 | tea "github.com/charmbracelet/bubbletea"
14 | "github.com/charmbracelet/lipgloss"
15 | )
16 |
17 | // Example
18 | //
19 | // ```
20 | // import (
21 | // "github.com/clivern/goenv/core/module"
22 | // )
23 | //
24 | //
25 | // list := module.NewCharmSelect("Which go version to install?", module.golangReleases)
26 | //
27 | // if err := list.Start(); err != nil {
28 | // fmt.Println("Error running program:", err)
29 | // os.Exit(1)
30 | // }
31 | //
32 | // if module.SelectedValue == "" {
33 | // os.Exit(1)
34 | // }
35 | // ```
36 |
37 | // NewCharmSelect Creates a new instance of tea.Program
38 | func NewCharmSelect(title string, versions []string) *tea.Program {
39 | items := []list.Item{}
40 |
41 | for i := 0; i < len(versions); i++ {
42 | items = append(items, item(versions[i]))
43 | }
44 |
45 | l := list.New(items, itemDelegate{}, defaultWidth, listHeight)
46 | l.Title = title
47 | l.SetShowStatusBar(true)
48 | l.SetFilteringEnabled(false)
49 | l.Styles.Title = titleStyle
50 | l.Styles.PaginationStyle = paginationStyle
51 | l.Styles.HelpStyle = helpStyle
52 |
53 | m := listModel{list: l}
54 |
55 | return tea.NewProgram(m)
56 | }
57 |
58 | // SelectedValue the list selected value
59 | var SelectedValue string
60 |
61 | // listHeight variable
62 | var listHeight = 14
63 |
64 | // defaultWidth variable
65 | var defaultWidth = 20
66 |
67 | // titleStyle variable
68 | var titleStyle = lipgloss.NewStyle().MarginLeft(2)
69 |
70 | // itemStyle variable
71 | var itemStyle = lipgloss.NewStyle().PaddingLeft(4)
72 |
73 | // selectedItemStyle variable
74 | var selectedItemStyle = lipgloss.NewStyle().PaddingLeft(2).Foreground(lipgloss.Color("170"))
75 |
76 | // paginationStyle variable
77 | var paginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4)
78 |
79 | // helpStyle variable
80 | var helpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1)
81 |
82 | // quitTextStyle variable
83 | var quitTextStyle = lipgloss.NewStyle().Margin(1, 0, 2, 4)
84 |
85 | // item type
86 | type item string
87 |
88 | // FilterValue method
89 | func (i item) FilterValue() string {
90 | return ""
91 | }
92 |
93 | // itemDelegate type
94 | type itemDelegate struct{}
95 |
96 | // Height method
97 | func (d itemDelegate) Height() int {
98 | return 1
99 | }
100 |
101 | // Spacing method
102 | func (d itemDelegate) Spacing() int {
103 | return 0
104 | }
105 |
106 | // Update method
107 | func (d itemDelegate) Update(_ tea.Msg, _ *list.Model) tea.Cmd {
108 | return nil
109 | }
110 |
111 | // Render method
112 | func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
113 | i, ok := listItem.(item)
114 | if !ok {
115 | return
116 | }
117 |
118 | str := fmt.Sprintf("%d. %s", index+1, i)
119 |
120 | fn := itemStyle.Render
121 | if index == m.Index() {
122 | fn = func(s string) string {
123 | return selectedItemStyle.Render("> " + s)
124 | }
125 | }
126 |
127 | fmt.Fprintf(w, fn(str))
128 | }
129 |
130 | // listModel type
131 | type listModel struct {
132 | list list.Model
133 | items []item
134 | choice string
135 | quitting bool
136 | }
137 |
138 | // Init init the list model
139 | func (m listModel) Init() tea.Cmd {
140 | return nil
141 | }
142 |
143 | // Update update the list
144 | func (m listModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
145 | switch msg := msg.(type) {
146 |
147 | case tea.WindowSizeMsg:
148 | m.list.SetWidth(msg.Width)
149 | return m, nil
150 |
151 | case tea.KeyMsg:
152 | switch keypress := msg.String(); keypress {
153 | case "ctrl+c":
154 | m.quitting = true
155 | return m, tea.Quit
156 |
157 | case "enter":
158 | i, ok := m.list.SelectedItem().(item)
159 | if ok {
160 | m.choice = string(i)
161 | }
162 | return m, tea.Quit
163 | }
164 | }
165 |
166 | var cmd tea.Cmd
167 | m.list, cmd = m.list.Update(msg)
168 | return m, cmd
169 | }
170 |
171 | // View show the list
172 | func (m listModel) View() string {
173 | if m.choice != "" {
174 | SelectedValue = m.choice
175 | return ""
176 | }
177 |
178 | if m.quitting {
179 | return quitTextStyle.Render("Action cancelled! That’s cool.")
180 | }
181 |
182 | return "\n" + m.list.View()
183 | }
184 |
--------------------------------------------------------------------------------
/core/module/charm_spinner.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | package module
6 |
7 | import (
8 | "fmt"
9 |
10 | "github.com/charmbracelet/bubbles/spinner"
11 | tea "github.com/charmbracelet/bubbletea"
12 | "github.com/charmbracelet/lipgloss"
13 | )
14 |
15 | // Example
16 | //
17 | // ```
18 | // import (
19 | // "github.com/clivern/goenv/core/module"
20 | // )
21 | //
22 | //
23 | // spinner := module.NewCharmSpinner("Getting Environment Ready!")
24 | //
25 | // go func() {
26 | // // Start a long running job
27 | // spinner.Quit()
28 | // }()
29 | //
30 | // if err := spinner.Start(); err != nil {
31 | // fmt.Println(err)
32 | // os.Exit(1)
33 | // }
34 | // ```
35 |
36 | // NewCharmSpinner Creates a new instance of tea.Program
37 | func NewCharmSpinner(loadingMsg string) *tea.Program {
38 | return tea.NewProgram(initialSpinnerModel(loadingMsg))
39 | }
40 |
41 | // errMsg type
42 | type errMsg error
43 |
44 | // spinnerModel spinner type
45 | type spinnerModel struct {
46 | spinner spinner.Model
47 | spin bool
48 | quitting bool
49 | err error
50 | loadingMsg string
51 | }
52 |
53 | // initialSpinnerModel creats a spinner model
54 | func initialSpinnerModel(loadingMsg string) spinnerModel {
55 | s := spinner.New()
56 |
57 | s.Spinner = spinner.Dot
58 | s.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("205"))
59 |
60 | return spinnerModel{
61 | spinner: s,
62 | spin: true,
63 | loadingMsg: loadingMsg,
64 | }
65 | }
66 |
67 | // Init init the spinner model
68 | func (m spinnerModel) Init() tea.Cmd {
69 | return m.spinner.Tick
70 | }
71 |
72 | // Update update the spinner
73 | func (m spinnerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
74 | switch msg := msg.(type) {
75 |
76 | case tea.KeyMsg:
77 | switch msg.String() {
78 | case "q", "esc", "ctrl+c":
79 | m.quitting = true
80 | return m, tea.Quit
81 | default:
82 | return m, nil
83 | }
84 |
85 | case errMsg:
86 | m.err = msg
87 | return m, nil
88 |
89 | case spinner.TickMsg:
90 | var cmd tea.Cmd
91 | // If m.spin is false, don't update on the spinner, effectively stopping it.
92 | if m.spin {
93 | m.spinner, cmd = m.spinner.Update(msg)
94 | }
95 | return m, cmd
96 |
97 | default:
98 | return m, nil
99 | }
100 | }
101 |
102 | // View show the spinner
103 | func (m spinnerModel) View() string {
104 | if m.err != nil {
105 | return m.err.Error()
106 | }
107 |
108 | str := fmt.Sprintf("\n %s %s ...\n", m.spinner.View(), m.loadingMsg)
109 |
110 | if m.quitting {
111 | return str + "\n"
112 | }
113 |
114 | return str
115 | }
116 |
--------------------------------------------------------------------------------
/core/module/const.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | package module
6 |
7 | import (
8 | "runtime"
9 | "strings"
10 | )
11 |
12 | // golangRegistry the registry to download from
13 | var golangRegistry = "https://dl.google.com/go/go${VERSION}.${OS}-${ARCH}.tar.gz"
14 |
15 | // golangRegistryChecksum the registry checksum URL
16 | var golangRegistryChecksum = "https://dl.google.com/go/go${VERSION}.${OS}-${ARCH}.tar.gz.sha256"
17 |
18 | // golangArchive the archive name
19 | var golangArchive = "go${VERSION}.${OS}-${ARCH}.tar.gz"
20 |
21 | // GolangReleases a list of golang releases
22 | var GolangReleases = []string{
23 | "1.5beta1",
24 | "1.5beta2",
25 | "1.5beta3",
26 | "1.5rc1",
27 | "1.5",
28 | "1.5.1",
29 | "1.5.2",
30 | "1.5.3",
31 | "1.5.4",
32 | "1.6beta1",
33 | "1.6beta2",
34 | "1.6rc1",
35 | "1.6rc2",
36 | "1.6",
37 | "1.6.1",
38 | "1.6.2",
39 | "1.6.3",
40 | "1.6.4",
41 | "1.7beta1",
42 | "1.7beta2",
43 | "1.7rc1",
44 | "1.7rc2",
45 | "1.7rc3",
46 | "1.7rc4",
47 | "1.7rc5",
48 | "1.7rc6",
49 | "1.7",
50 | "1.7.1",
51 | "1.7.2",
52 | "1.7.3",
53 | "1.7.4",
54 | "1.7.5",
55 | "1.7.6",
56 | "1.8beta1",
57 | "1.8beta2",
58 | "1.8rc1",
59 | "1.8rc2",
60 | "1.8rc3",
61 | "1.8",
62 | "1.8.1",
63 | "1.8.2",
64 | "1.8.3",
65 | "1.8.4",
66 | "1.8.5",
67 | "1.8.5rc4",
68 | "1.8.6",
69 | "1.8.7",
70 | "1.9beta1",
71 | "1.9beta2",
72 | "1.9rc1",
73 | "1.9rc2",
74 | "1.9",
75 | "1.9.1",
76 | "1.9.2",
77 | "1.9.3",
78 | "1.9.4",
79 | "1.9.5",
80 | "1.9.6",
81 | "1.9.7",
82 | "1.10beta1",
83 | "1.10beta2",
84 | "1.10rc1",
85 | "1.10rc2",
86 | "1.10",
87 | "1.10.1",
88 | "1.10.2",
89 | "1.10.3",
90 | "1.10.4",
91 | "1.10.5",
92 | "1.10.6",
93 | "1.10.7",
94 | "1.10.8",
95 | "1.11beta1",
96 | "1.11beta2",
97 | "1.11beta3",
98 | "1.11rc1",
99 | "1.11rc2",
100 | "1.11",
101 | "1.11.1",
102 | "1.11.2",
103 | "1.11.3",
104 | "1.11.4",
105 | "1.11.5",
106 | "1.11.6",
107 | "1.11.7",
108 | "1.11.8",
109 | "1.11.9",
110 | "1.11.10",
111 | "1.11.11",
112 | "1.11.12",
113 | "1.11.13",
114 | "1.12beta1",
115 | "1.12beta2",
116 | "1.12rc1",
117 | "1.12",
118 | "1.12.1",
119 | "1.12.2",
120 | "1.12.3",
121 | "1.12.4",
122 | "1.12.5",
123 | "1.12.6",
124 | "1.12.7",
125 | "1.12.8",
126 | "1.12.9",
127 | "1.12.10",
128 | "1.12.11",
129 | "1.12.12",
130 | "1.12.13",
131 | "1.12.14",
132 | "1.12.15",
133 | "1.12.16",
134 | "1.12.17",
135 | "1.13beta1",
136 | "1.13rc1",
137 | "1.13rc2",
138 | "1.13",
139 | "1.13.1",
140 | "1.13.2",
141 | "1.13.3",
142 | "1.13.4",
143 | "1.13.5",
144 | "1.13.6",
145 | "1.13.7",
146 | "1.13.8",
147 | "1.13.9",
148 | "1.13.10",
149 | "1.13.11",
150 | "1.13.12",
151 | "1.13.13",
152 | "1.13.14",
153 | "1.13.15",
154 | "1.14beta1",
155 | "1.14rc1",
156 | "1.14",
157 | "1.14.1",
158 | "1.14.2",
159 | "1.14.3",
160 | "1.14.4",
161 | "1.14.5",
162 | "1.14.6",
163 | "1.14.7",
164 | "1.14.8",
165 | "1.14.9",
166 | "1.14.10",
167 | "1.14.11",
168 | "1.14.12",
169 | "1.14.13",
170 | "1.14.14",
171 | "1.14.15",
172 | "1.15beta1",
173 | "1.15rc1",
174 | "1.15rc2",
175 | "1.15",
176 | "1.15.1",
177 | "1.15.2",
178 | "1.15.3",
179 | "1.15.4",
180 | "1.15.5",
181 | "1.15.6",
182 | "1.15.7",
183 | "1.15.8",
184 | "1.15.9",
185 | "1.15.10",
186 | "1.15.11",
187 | "1.15.12",
188 | "1.15.13",
189 | "1.15.14",
190 | "1.15.15",
191 | "1.16beta1",
192 | "1.16rc1",
193 | "1.16",
194 | "1.16.1",
195 | "1.16.2",
196 | "1.16.3",
197 | "1.16.4",
198 | "1.16.5",
199 | "1.16.6",
200 | "1.16.7",
201 | "1.16.8",
202 | "1.16.9",
203 | "1.16.10",
204 | "1.16.11",
205 | "1.16.12",
206 | "1.16.13",
207 | "1.16.14",
208 | "1.16.15",
209 | "1.17beta1",
210 | "1.17rc1",
211 | "1.17rc2",
212 | "1.17",
213 | "1.17.1",
214 | "1.17.2",
215 | "1.17.3",
216 | "1.17.4",
217 | "1.17.5",
218 | "1.17.6",
219 | "1.17.7",
220 | "1.17.8",
221 | "1.17.9",
222 | "1.17.10",
223 | "1.17.11",
224 | "1.17.12",
225 | "1.17.13",
226 | "1.18beta1",
227 | "1.18beta2",
228 | "1.18rc1",
229 | "1.18",
230 | "1.18.1",
231 | "1.18.2",
232 | "1.18.3",
233 | "1.18.4",
234 | "1.18.5",
235 | "1.18.6",
236 | "1.18.7",
237 | "1.18.8",
238 | "1.18.9",
239 | "1.18.10",
240 | "1.19beta1",
241 | "1.19rc1",
242 | "1.19rc2",
243 | "1.19",
244 | "1.19.1",
245 | "1.19.2",
246 | "1.19.3",
247 | "1.19.4",
248 | "1.19.5",
249 | "1.19.6",
250 | "1.19.7",
251 | "1.19.8",
252 | "1.19.9",
253 | "1.19.10",
254 | "1.19.11",
255 | "1.19.12",
256 | "1.19.13",
257 | "1.20rc1",
258 | "1.20rc2",
259 | "1.20rc3",
260 | "1.20",
261 | "1.20.1",
262 | "1.20.2",
263 | "1.20.3",
264 | "1.20.4",
265 | "1.20.5",
266 | "1.20.6",
267 | "1.20.7",
268 | "1.20.8",
269 | "1.20.9",
270 | "1.20.10",
271 | "1.20.11",
272 | "1.20.12",
273 | "1.20.13",
274 | "1.20.14",
275 | "1.21rc1",
276 | "1.21rc2",
277 | "1.21rc3",
278 | "1.21rc4",
279 | "1.21.0",
280 | "1.21.1",
281 | "1.21.2",
282 | "1.21.3",
283 | "1.21.4",
284 | "1.21.5",
285 | "1.21.6",
286 | "1.21.7",
287 | "1.21.8",
288 | "1.21.9",
289 | "1.21.10",
290 | "1.21.11",
291 | "1.21.12",
292 | "1.21.13",
293 | "1.22rc1",
294 | "1.22rc2",
295 | "1.22.0",
296 | "1.22.1",
297 | "1.22.2",
298 | "1.22.3",
299 | "1.22.4",
300 | "1.22.5",
301 | "1.22.6",
302 | "1.22.7",
303 | "1.22.8",
304 | "1.22.9",
305 | "1.22.10",
306 | "1.22.11",
307 | "1.23rc1",
308 | "1.23rc2",
309 | "1.23.0",
310 | "1.23.1",
311 | "1.23.2",
312 | "1.23.3",
313 | "1.23.4",
314 | "1.23.5",
315 | "1.24rc1",
316 | "1.24rc2",
317 | "1.24.0",
318 | "1.24.1",
319 | "1.24.2",
320 | }
321 |
322 | // goShimContent shim for go binary
323 | var goShimContent = `#!/usr/bin/env bash
324 |
325 | GO_BINARY_NAME=go
326 |
327 | GO_VERSION_PATH=$(goenv exec)
328 |
329 | GOENV_ROOT="$HOME/%s" \
330 | GOPATH=$GO_VERSION_PATH \
331 | GOBIN=$GO_VERSION_PATH/bin \
332 | "$GO_VERSION_PATH/bin/$GO_BINARY_NAME" "$@"
333 |
334 | if [[ "$@" =~ 'get' ]]
335 | then
336 | goenv rehash
337 | fi
338 |
339 | if [[ "$@" =~ 'install' ]]
340 | then
341 | goenv rehash
342 | fi
343 |
344 | `
345 |
346 | // binaryShimContent shim other go binaries
347 | var binaryShimContent = `#!/usr/bin/env bash
348 |
349 | GO_BINARY_NAME=%s
350 |
351 | GO_VERSION_PATH=$(goenv exec)
352 |
353 | GOENV_ROOT="$HOME/%s" \
354 | GOPATH=$GO_VERSION_PATH \
355 | GOBIN=$GO_VERSION_PATH/bin \
356 | "$GO_VERSION_PATH/bin/$GO_BINARY_NAME" "$@"
357 |
358 | `
359 |
360 | // getDownloadURL returns the download link
361 | func getDownloadURL(version string) string {
362 | url := strings.Replace(golangRegistry, "${VERSION}", version, -1)
363 | url = strings.Replace(url, "${OS}", runtime.GOOS, -1)
364 | url = strings.Replace(url, "${ARCH}", runtime.GOARCH, -1)
365 |
366 | return url
367 | }
368 |
369 | // getChecksumURL returns the checksum link
370 | func getChecksumURL(version string) string {
371 | url := strings.Replace(golangRegistryChecksum, "${VERSION}", version, -1)
372 | url = strings.Replace(url, "${OS}", runtime.GOOS, -1)
373 | url = strings.Replace(url, "${ARCH}", runtime.GOARCH, -1)
374 |
375 | return url
376 | }
377 |
378 | // getArchiveName returns the archive name
379 | func getArchiveName(version string) string {
380 | name := strings.Replace(golangArchive, "${VERSION}", version, -1)
381 | name = strings.Replace(name, "${OS}", runtime.GOOS, -1)
382 | name = strings.Replace(name, "${ARCH}", runtime.GOARCH, -1)
383 |
384 | return name
385 | }
386 |
--------------------------------------------------------------------------------
/core/module/golang.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | package module
6 |
7 | import (
8 | "fmt"
9 | "os"
10 | "path/filepath"
11 | "strings"
12 |
13 | "github.com/clivern/goenv/core/service"
14 | "github.com/clivern/goenv/core/util"
15 | )
16 |
17 | // Golang type
18 | type Golang struct {
19 | RootPath string
20 | EnvironmentDir string
21 | VersionsDir string
22 | ShimsDir string
23 | VersionFile string
24 | FileSystem *service.FileSystem
25 | Installer *service.Installer
26 | }
27 |
28 | // NewGolangEnvironment creates a new instance
29 | func NewGolangEnvironment(homePath string) *Golang {
30 |
31 | fs := service.NewFileSystem()
32 |
33 | return &Golang{
34 | RootPath: fmt.Sprintf("%s/%s", fs.RemoveTrailingSlash(homePath), ".goenv"),
35 | VersionsDir: "versions",
36 | ShimsDir: "shims",
37 | VersionFile: ".go-version",
38 | EnvironmentDir: ".goenv",
39 | FileSystem: fs,
40 | Installer: service.NewInstaller(),
41 | }
42 | }
43 |
44 | // Install installs a golang version
45 | func (g *Golang) Install(version string) error {
46 |
47 | url := getDownloadURL(version)
48 |
49 | versionsDir := fmt.Sprintf("%s/%s", g.RootPath, g.VersionsDir)
50 |
51 | _, err := g.Installer.DownloadFromURL(
52 | versionsDir,
53 | url,
54 | )
55 |
56 | if err != nil {
57 | return fmt.Errorf(
58 | "Error while downloading go version %s url %s: %s",
59 | version,
60 | url,
61 | err.Error(),
62 | )
63 | }
64 |
65 | // Local Checksum
66 | checksum, err := util.GetFileSha256Sum(fmt.Sprintf("%s/%s", versionsDir, getArchiveName(version)))
67 |
68 | if err != nil {
69 | return fmt.Errorf(
70 | "Error while generating the checksum from file %s: %s",
71 | fmt.Sprintf("%s/%s", versionsDir, getArchiveName(version)),
72 | err.Error(),
73 | )
74 | }
75 |
76 | // Remote Checksum
77 | remoteChecksum, err := util.GetSha256Sum(getChecksumURL(version))
78 |
79 | if err != nil {
80 | return fmt.Errorf(
81 | "Error while fetching the checksum from remote server %s: %s",
82 | getChecksumURL(version),
83 | err.Error(),
84 | )
85 | }
86 |
87 | if (remoteChecksum != "") && (remoteChecksum != checksum) {
88 | return fmt.Errorf(
89 | "Checksum not matching, try downloading again %s != %s",
90 | remoteChecksum,
91 | checksum,
92 | )
93 | }
94 |
95 | err = g.Installer.Untar(
96 | versionsDir,
97 | fmt.Sprintf("%s/%s", versionsDir, getArchiveName(version)),
98 | )
99 |
100 | if err != nil {
101 | return fmt.Errorf(
102 | "Error while uncompressing the go archive version %s url %s: %s",
103 | version,
104 | url,
105 | err.Error(),
106 | )
107 | }
108 |
109 | err = g.FileSystem.Rename(
110 | fmt.Sprintf("%s/go", versionsDir),
111 | fmt.Sprintf("%s/%s", versionsDir, version),
112 | )
113 |
114 | if err != nil {
115 | return fmt.Errorf(
116 | "Error while renaming the go directory from %s to %s: %s",
117 | fmt.Sprintf("%s/go", versionsDir),
118 | fmt.Sprintf("%s/%s", versionsDir, version),
119 | err.Error(),
120 | )
121 | }
122 |
123 | err = g.FileSystem.DeleteFile(fmt.Sprintf(
124 | "%s/%s",
125 | versionsDir,
126 | getArchiveName(version),
127 | ))
128 |
129 | if err != nil {
130 | return fmt.Errorf(
131 | "Error while deleting file %s: %s",
132 | fmt.Sprintf("%s/%s", versionsDir, getArchiveName(version)),
133 | err.Error(),
134 | )
135 | }
136 |
137 | return nil
138 | }
139 |
140 | // Uninstall removes a golang installed version
141 | func (g *Golang) Uninstall(version string) error {
142 |
143 | path := fmt.Sprintf(
144 | "%s/%s/%s",
145 | g.RootPath,
146 | g.VersionsDir,
147 | version,
148 | )
149 |
150 | if !g.FileSystem.DirExists(path) {
151 | return fmt.Errorf(
152 | "Unable to locate version %s path %s",
153 | version,
154 | path,
155 | )
156 | }
157 |
158 | err := g.FileSystem.ClearDir(path)
159 |
160 | if err != nil {
161 | return fmt.Errorf(
162 | "Unable to clear version %s path %s",
163 | version,
164 | path,
165 | )
166 | }
167 |
168 | err = g.FileSystem.DeleteDir(path)
169 |
170 | if err != nil {
171 | return fmt.Errorf(
172 | "Unable to delete version %s path %s",
173 | version,
174 | path,
175 | )
176 | }
177 |
178 | return nil
179 | }
180 |
181 | // SetVersion sets the local or global golang version
182 | func (g *Golang) SetVersion(path, version string) error {
183 |
184 | err := g.FileSystem.StoreFile(path, fmt.Sprintf("%s\n", version))
185 |
186 | if err != nil {
187 | return fmt.Errorf(
188 | "Unable to set go version to %s path %s",
189 | version,
190 | path,
191 | )
192 | }
193 |
194 | return nil
195 | }
196 |
197 | // SetGlobalVersion sets the global golang version
198 | func (g *Golang) SetGlobalVersion(version string) error {
199 |
200 | path := fmt.Sprintf(
201 | "%s/%s",
202 | g.RootPath,
203 | g.VersionFile,
204 | )
205 |
206 | return g.SetVersion(path, version)
207 | }
208 |
209 | // SetLocalVersion sets the local golang version
210 | func (g *Golang) SetLocalVersion(version string) error {
211 |
212 | cdir, err := os.Getwd()
213 |
214 | if err != nil {
215 | return err
216 | }
217 |
218 | path := fmt.Sprintf(
219 | "%s/%s",
220 | g.FileSystem.RemoveTrailingSlash(cdir),
221 | g.VersionFile,
222 | )
223 |
224 | return g.SetVersion(path, version)
225 | }
226 |
227 | // GetLocalVersion returns the local golang version
228 | func (g *Golang) GetLocalVersion(dir string) (string, error) {
229 |
230 | var versionFile string
231 |
232 | baseDir := g.FileSystem.RemoveTrailingSlash(dir)
233 |
234 | for {
235 | if baseDir == "/" {
236 | versionFile = fmt.Sprintf("/%s", g.VersionFile)
237 | } else {
238 | versionFile = fmt.Sprintf("%s/%s", baseDir, g.VersionFile)
239 | }
240 |
241 | if g.FileSystem.FileExists(versionFile) {
242 | break
243 | }
244 |
245 | if baseDir == "/" {
246 | return "", fmt.Errorf("Unable to locate local version file")
247 | }
248 |
249 | baseDir = filepath.Dir(baseDir)
250 | }
251 |
252 | content, err := g.FileSystem.ReadFile(versionFile)
253 |
254 | if err != nil {
255 | return "", fmt.Errorf(
256 | "Unable to read local version file, path %s and error %s",
257 | versionFile,
258 | err.Error(),
259 | )
260 | }
261 |
262 | return strings.TrimSuffix(content, "\n"), nil
263 | }
264 |
265 | // GetGlobalVersion returns the global golang version
266 | func (g *Golang) GetGlobalVersion() (string, error) {
267 |
268 | file := fmt.Sprintf(
269 | "%s/%s",
270 | g.RootPath,
271 | g.VersionFile,
272 | )
273 |
274 | if !g.FileSystem.FileExists(file) {
275 | return "", fmt.Errorf(
276 | "Global go version is not set yet, path %s",
277 | file,
278 | )
279 | }
280 |
281 | content, err := g.FileSystem.ReadFile(file)
282 |
283 | if err != nil {
284 | return "", fmt.Errorf(
285 | "Unable to read global version file, path %s and error %s",
286 | file,
287 | err.Error(),
288 | )
289 | }
290 |
291 | return strings.TrimSuffix(content, "\n"), nil
292 | }
293 |
294 | // Configure configures the environment
295 | func (g *Golang) Configure() error {
296 |
297 | var err error
298 |
299 | if !g.FileSystem.DirExists(g.RootPath) {
300 | err = g.FileSystem.EnsureDir(g.RootPath, 0775)
301 | }
302 |
303 | if err != nil {
304 | return fmt.Errorf("Unable to configure environment: %s", err.Error())
305 | }
306 |
307 | if !g.FileSystem.DirExists(fmt.Sprintf("%s/%s", g.RootPath, g.VersionsDir)) {
308 | err = g.FileSystem.EnsureDir(fmt.Sprintf("%s/%s", g.RootPath, g.VersionsDir), 0775)
309 | }
310 |
311 | if err != nil {
312 | return fmt.Errorf("Unable to configure environment: %s", err.Error())
313 | }
314 |
315 | if !g.FileSystem.DirExists(fmt.Sprintf("%s/%s", g.RootPath, g.ShimsDir)) {
316 | err = g.FileSystem.EnsureDir(fmt.Sprintf("%s/%s", g.RootPath, g.ShimsDir), 0775)
317 | }
318 |
319 | if err != nil {
320 | return fmt.Errorf("Unable to configure environment: %s", err.Error())
321 | }
322 |
323 | return nil
324 | }
325 |
326 | // GetVersions returns a list of all available versions
327 | func (g *Golang) GetVersions() []string {
328 | return GolangReleases
329 | }
330 |
331 | // GetInstalledVersions returns a list of installed versions
332 | func (g *Golang) GetInstalledVersions() ([]string, error) {
333 |
334 | path := fmt.Sprintf("%s/%s", g.RootPath, g.VersionsDir)
335 |
336 | result, err := g.FileSystem.GetSubDirectoriesNames(path)
337 |
338 | versions := []string{}
339 |
340 | if err != nil {
341 | return versions, fmt.Errorf(
342 | "Unable to list directory %s: %s",
343 | path,
344 | err.Error(),
345 | )
346 | }
347 |
348 | for i := 0; i < len(result); i++ {
349 | if !util.InArray(result[i], g.GetVersions()) {
350 | continue
351 | }
352 |
353 | versions = append(versions, result[i])
354 | }
355 |
356 | return versions, nil
357 | }
358 |
359 | // ValidateVersion validates if a version is valid
360 | func (g *Golang) ValidateVersion(version string) bool {
361 | return util.InArray(version, g.GetVersions())
362 | }
363 |
364 | // ValidateInstalledVersion validates if an installed version is valid
365 | func (g *Golang) ValidateInstalledVersion(version string) (bool, error) {
366 |
367 | versions, err := g.GetInstalledVersions()
368 |
369 | if err != nil {
370 | return false, err
371 | }
372 |
373 | return util.InArray(version, versions), nil
374 | }
375 |
376 | // Rehash gets a list of binaries under a certain
377 | // go bin directory and create shim for them
378 | func (g *Golang) Rehash() error {
379 | var err error
380 | var content string
381 |
382 | // create third party binaries
383 | vers, err := g.GetInstalledVersions()
384 |
385 | if err != nil {
386 | return err
387 | }
388 |
389 | for i := 0; i < len(vers); i++ {
390 | bins, err := g.FileSystem.GetDirectoryFileNames(fmt.Sprintf(
391 | "%s/%s/%s/bin",
392 | g.RootPath,
393 | g.VersionsDir,
394 | vers[i],
395 | ))
396 |
397 | if err != nil {
398 | return err
399 | }
400 |
401 | for i := 0; i < len(bins); i++ {
402 | bin := fmt.Sprintf("%s/%s/%s", g.RootPath, g.ShimsDir, bins[i])
403 |
404 | if !g.FileSystem.FileExists(bin) {
405 | // If go, create a go shim
406 | if bins[i] == "go" {
407 | content = fmt.Sprintf(goShimContent, g.EnvironmentDir)
408 | } else {
409 | // If not go, it might be gofmt or other installed binaries
410 | content = fmt.Sprintf(binaryShimContent, bins[i], g.EnvironmentDir)
411 | }
412 |
413 | err = g.FileSystem.StoreFile(bin, content)
414 |
415 | if err != nil {
416 | return err
417 | }
418 |
419 | g.FileSystem.ChangePermission(bin, 0775)
420 | }
421 | }
422 | }
423 |
424 | return nil
425 | }
426 |
--------------------------------------------------------------------------------
/core/module/golang_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | package module
6 |
7 | import (
8 | "fmt"
9 | "testing"
10 |
11 | "github.com/clivern/goenv/pkg"
12 |
13 | "github.com/franela/goblin"
14 | )
15 |
16 | // TestUnitGolang
17 | func TestUnitGolang(t *testing.T) {
18 | g := goblin.Goblin(t)
19 |
20 | baseDir := fmt.Sprintf("%s/cache", pkg.GetBaseDir("cache"))
21 | goenv := NewGolangEnvironment(baseDir)
22 |
23 | g.Describe("#Golang", func() {
24 | g.It("It should satisfy test cases", func() {
25 | // Test GetVersions
26 | g.Assert(len(goenv.GetVersions())).Equal(297)
27 |
28 | // Test SetVersion
29 | versionFile := fmt.Sprintf("%s/.goenv/%s", baseDir, ".go-version")
30 | g.Assert(goenv.SetVersion(versionFile, "1.18")).Equal(nil)
31 |
32 | // Test Configure
33 | g.Assert(goenv.Configure()).Equal(nil)
34 |
35 | // Test GetLocalVersion
36 | out, err := goenv.GetLocalVersion(fmt.Sprintf("%s/.goenv", baseDir))
37 | g.Assert(out).Equal("1.18")
38 | g.Assert(err).Equal(nil)
39 |
40 | // Test GetGlobalVersion
41 | out, err = goenv.GetGlobalVersion()
42 | g.Assert(out).Equal("1.18")
43 | g.Assert(err).Equal(nil)
44 |
45 | // Cleanup
46 | goenv.FileSystem.ClearDir(fmt.Sprintf("%s/.goenv", baseDir))
47 | goenv.FileSystem.DeleteDir(fmt.Sprintf("%s/.goenv", baseDir))
48 | })
49 | })
50 | }
51 |
--------------------------------------------------------------------------------
/core/service/file_system.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | // Package service package
6 | package service
7 |
8 | import (
9 | "fmt"
10 | "io/ioutil"
11 | "os"
12 | "path/filepath"
13 | "strings"
14 | )
15 |
16 | // FileSystem struct
17 | type FileSystem struct {
18 | }
19 |
20 | // NewFileSystem creates a new instance
21 | func NewFileSystem() *FileSystem {
22 | return &FileSystem{}
23 | }
24 |
25 | // FileExists reports whether the named file exists
26 | func (fs *FileSystem) FileExists(path string) bool {
27 | if fi, err := os.Stat(path); err == nil {
28 | if fi.Mode().IsRegular() {
29 | return true
30 | }
31 | }
32 |
33 | return false
34 | }
35 |
36 | // DirExists reports whether the dir exists
37 | func (fs *FileSystem) DirExists(path string) bool {
38 | if fi, err := os.Stat(path); err == nil {
39 | if fi.Mode().IsDir() {
40 | return true
41 | }
42 | }
43 |
44 | return false
45 | }
46 |
47 | // EnsureDir ensures that directory exists
48 | func (fs *FileSystem) EnsureDir(dirName string, mode int) error {
49 | err := os.MkdirAll(dirName, os.FileMode(mode))
50 |
51 | if err == nil || os.IsExist(err) {
52 | return nil
53 | }
54 |
55 | return err
56 | }
57 |
58 | // DeleteDir deletes a dir
59 | func (fs *FileSystem) DeleteDir(dir string) error {
60 | err := os.RemoveAll(dir)
61 |
62 | if err != nil {
63 | return err
64 | }
65 |
66 | return nil
67 | }
68 |
69 | // EnsureTrailingSlash ensure there is a trailing slash
70 | func (fs *FileSystem) EnsureTrailingSlash(dir string) string {
71 | return fmt.Sprintf(
72 | "%s%s",
73 | strings.TrimRight(dir, string(os.PathSeparator)),
74 | string(os.PathSeparator),
75 | )
76 | }
77 |
78 | // RemoveTrailingSlash removes any trailing slash
79 | func (fs *FileSystem) RemoveTrailingSlash(dir string) string {
80 | return strings.TrimRight(dir, string(os.PathSeparator))
81 | }
82 |
83 | // RemoveStartingSlash removes any starting slash
84 | func (fs *FileSystem) RemoveStartingSlash(dir string) string {
85 | return strings.TrimLeft(dir, string(os.PathSeparator))
86 | }
87 |
88 | // ClearDir removes all files and sub dirs
89 | func (fs *FileSystem) ClearDir(dir string) error {
90 | files, err := filepath.Glob(filepath.Join(dir, "*"))
91 | if err != nil {
92 | return err
93 | }
94 | for _, file := range files {
95 | err = os.RemoveAll(file)
96 | if err != nil {
97 | return err
98 | }
99 | }
100 | return nil
101 | }
102 |
103 | // StoreFile stores a file content
104 | func (fs *FileSystem) StoreFile(path, content string) error {
105 | dir := filepath.Dir(path)
106 |
107 | err := os.MkdirAll(dir, 0775)
108 |
109 | if err != nil {
110 | return err
111 | }
112 |
113 | f, err := os.Create(path)
114 |
115 | if err != nil {
116 | return err
117 | }
118 |
119 | defer f.Close()
120 |
121 | _, err = f.WriteString(content)
122 |
123 | return err
124 | }
125 |
126 | // PathExists reports whether the path exists
127 | func (fs *FileSystem) PathExists(path string) bool {
128 | if _, err := os.Stat(path); os.IsNotExist(err) {
129 | return false
130 | }
131 | return true
132 | }
133 |
134 | // DeleteFile deletes a file
135 | func (fs *FileSystem) DeleteFile(path string) error {
136 | return os.Remove(path)
137 | }
138 |
139 | // ReadFile get the file content
140 | func (fs *FileSystem) ReadFile(path string) (string, error) {
141 | data, err := ioutil.ReadFile(path)
142 |
143 | if err != nil {
144 | return "", err
145 | }
146 | return string(data), nil
147 | }
148 |
149 | // Rename rename a dir or a file
150 | func (fs *FileSystem) Rename(old, new string) error {
151 | return os.Rename(old, new)
152 | }
153 |
154 | // GetSubDirectoriesNames gets a list of sub directories
155 | func (fs *FileSystem) GetSubDirectoriesNames(path string) ([]string, error) {
156 | result := []string{}
157 |
158 | files, err := ioutil.ReadDir(path)
159 |
160 | if err != nil {
161 | return result, err
162 | }
163 |
164 | for _, fileInfo := range files {
165 | if fileInfo.IsDir() {
166 | result = append(result, fileInfo.Name())
167 | }
168 | }
169 |
170 | return result, nil
171 | }
172 |
173 | // GetDirectoryFileNames get a list of files inside a directory
174 | func (fs *FileSystem) GetDirectoryFileNames(path string) ([]string, error) {
175 | result := []string{}
176 |
177 | files, err := ioutil.ReadDir(path)
178 |
179 | if err != nil {
180 | return result, err
181 | }
182 |
183 | for _, fileInfo := range files {
184 | if !fileInfo.IsDir() {
185 | result = append(result, fileInfo.Name())
186 | }
187 | }
188 |
189 | return result, nil
190 | }
191 |
192 | // ChangePermission changes the file permission
193 | func (fs *FileSystem) ChangePermission(path string, permisson os.FileMode) {
194 | os.Chmod(path, permisson)
195 | }
196 |
--------------------------------------------------------------------------------
/core/service/file_system_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | package service
6 |
7 | import (
8 | "fmt"
9 | "testing"
10 |
11 | "github.com/clivern/goenv/pkg"
12 |
13 | "github.com/franela/goblin"
14 | )
15 |
16 | // TestUnitFileSystem
17 | func TestUnitFileSystem(t *testing.T) {
18 | g := goblin.Goblin(t)
19 |
20 | fs := NewFileSystem()
21 |
22 | g.Describe("#FileSystem", func() {
23 | g.It("It should satisfy test cases", func() {
24 | g.Assert(fs.FileExists(fmt.Sprintf("%s/.gitignore", pkg.GetBaseDir("cache")))).Equal(true)
25 | g.Assert(fs.FileExists(fmt.Sprintf("%s/not_found.md", pkg.GetBaseDir("cache")))).Equal(false)
26 | g.Assert(fs.DirExists(pkg.GetBaseDir("cache"))).Equal(true)
27 | g.Assert(fs.DirExists(fmt.Sprintf("%s/not_found", pkg.GetBaseDir("cache")))).Equal(false)
28 | g.Assert(fs.EnsureDir(fmt.Sprintf("%s/new", pkg.GetBaseDir("cache")), 775)).Equal(nil)
29 | g.Assert(fs.DirExists(fmt.Sprintf("%s/new", pkg.GetBaseDir("cache")))).Equal(true)
30 | g.Assert(fs.DeleteDir(fmt.Sprintf("%s/new", pkg.GetBaseDir("cache")))).Equal(nil)
31 | })
32 | })
33 | }
34 |
--------------------------------------------------------------------------------
/core/service/installer.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | package service
6 |
7 | import (
8 | "archive/tar"
9 | "compress/gzip"
10 | "fmt"
11 | "io"
12 | "net/http"
13 | "os"
14 | "path/filepath"
15 | "strings"
16 | )
17 |
18 | // Installer struct
19 | type Installer struct {
20 | }
21 |
22 | // NewInstaller creates a new instance
23 | func NewInstaller() *Installer {
24 | return &Installer{}
25 | }
26 |
27 | // DownloadFromURL downloads from a URL
28 | func (i *Installer) DownloadFromURL(dir string, url string) (string, error) {
29 |
30 | tokens := strings.Split(url, "/")
31 |
32 | fileName := tokens[len(tokens)-1]
33 |
34 | response, err := http.Get(url)
35 |
36 | if err != nil {
37 | return "", err
38 | }
39 |
40 | defer response.Body.Close()
41 |
42 | if response.StatusCode != 200 {
43 | return "", fmt.Errorf(
44 | "Unable to download from %s",
45 | url,
46 | )
47 | }
48 |
49 | tarFile := filepath.Join(dir, fileName)
50 |
51 | output, err := os.Create(tarFile)
52 |
53 | if err != nil {
54 | return "", err
55 | }
56 |
57 | defer output.Close()
58 |
59 | _, err = io.Copy(output, response.Body)
60 |
61 | if err != nil {
62 | return "", err
63 | }
64 |
65 | return tarFile, nil
66 | }
67 |
68 | // Untar uncompress a .tar.gz file
69 | func (i *Installer) Untar(extractPath, sourcefilePath string) error {
70 |
71 | file, err := os.Open(sourcefilePath)
72 |
73 | if err != nil {
74 | return err
75 | }
76 |
77 | defer file.Close()
78 |
79 | var fileReader io.ReadCloser = file
80 |
81 | if strings.HasSuffix(sourcefilePath, ".gz") {
82 |
83 | if fileReader, err = gzip.NewReader(file); err != nil {
84 | return err
85 | }
86 |
87 | defer fileReader.Close()
88 | }
89 |
90 | tarBallReader := tar.NewReader(fileReader)
91 |
92 | for {
93 | header, err := tarBallReader.Next()
94 |
95 | if err != nil {
96 | if err == io.EOF {
97 | break
98 | }
99 |
100 | return err
101 | }
102 |
103 | filename := filepath.Join(extractPath, filepath.FromSlash(header.Name))
104 |
105 | switch header.Typeflag {
106 |
107 | case tar.TypeDir:
108 | err = os.MkdirAll(filename, os.FileMode(header.Mode))
109 |
110 | if err != nil {
111 | return err
112 | }
113 |
114 | case tar.TypeReg:
115 | writer, err := os.Create(filename)
116 |
117 | if err != nil {
118 | return err
119 | }
120 |
121 | io.Copy(writer, tarBallReader)
122 |
123 | err = os.Chmod(filename, os.FileMode(header.Mode))
124 |
125 | if err != nil {
126 | return err
127 | }
128 |
129 | writer.Close()
130 | default:
131 | return fmt.Errorf("Unable to untar type: %c in file %s", header.Typeflag, filename)
132 | }
133 | }
134 |
135 | return nil
136 | }
137 |
--------------------------------------------------------------------------------
/core/service/installer_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | package service
6 |
7 | import (
8 | "fmt"
9 | "testing"
10 |
11 | "github.com/clivern/goenv/pkg"
12 |
13 | "github.com/franela/goblin"
14 | )
15 |
16 | // TestUnitInstaller
17 | func TestUnitInstaller(t *testing.T) {
18 | g := goblin.Goblin(t)
19 |
20 | installer := NewInstaller()
21 | fs := NewFileSystem()
22 |
23 | g.Describe("#Installer", func() {
24 | g.It("It should satisfy test cases", func() {
25 | out, err := installer.DownloadFromURL(
26 | fmt.Sprintf("%s/cache/", pkg.GetBaseDir("cache")),
27 | "https://github.com/Clivern/Rhino/releases/download/1.6.1/Rhino_1.6.1_Darwin_x86_64.tar.gz",
28 | )
29 |
30 | g.Assert(err).Equal(nil)
31 | g.Assert(out != "").Equal(true)
32 |
33 | // Create a dir for output
34 | fs.EnsureDir(fmt.Sprintf("%s/cache/rhino", pkg.GetBaseDir("cache")), 0755)
35 |
36 | err = installer.Untar(
37 | fmt.Sprintf("%s/cache/rhino", pkg.GetBaseDir("cache")),
38 | fmt.Sprintf("%s/cache/Rhino_1.6.1_Darwin_x86_64.tar.gz", pkg.GetBaseDir("cache")),
39 | )
40 |
41 | g.Assert(err).Equal(nil)
42 |
43 | g.Assert(fs.FileExists(fmt.Sprintf("%s/cache/rhino/README.md", pkg.GetBaseDir("cache")))).Equal(true)
44 |
45 | // Cleanup
46 | fs.ClearDir(fmt.Sprintf("%s/cache/rhino", pkg.GetBaseDir("cache")))
47 | fs.DeleteDir(fmt.Sprintf("%s/cache/rhino", pkg.GetBaseDir("cache")))
48 | g.Assert(fs.DeleteFile(fmt.Sprintf("%s/cache/Rhino_1.6.1_Darwin_x86_64.tar.gz", pkg.GetBaseDir("cache")))).Equal(nil)
49 | })
50 | })
51 | }
52 |
--------------------------------------------------------------------------------
/core/util/helpers.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | // Package util package
6 | package util
7 |
8 | import (
9 | "crypto/sha256"
10 | "fmt"
11 | "io"
12 | "io/ioutil"
13 | "net/http"
14 | "os"
15 | "reflect"
16 | "strings"
17 | )
18 |
19 | // InArray check if value is on array
20 | func InArray(val interface{}, array interface{}) bool {
21 | switch reflect.TypeOf(array).Kind() {
22 | case reflect.Slice:
23 | s := reflect.ValueOf(array)
24 |
25 | for i := 0; i < s.Len(); i++ {
26 | if reflect.DeepEqual(val, s.Index(i).Interface()) {
27 | return true
28 | }
29 | }
30 | }
31 |
32 | return false
33 | }
34 |
35 | // GetFileSha256Sum gets the file sha256 sum
36 | func GetFileSha256Sum(path string) (string, error) {
37 | f, err := os.Open(path)
38 |
39 | if err != nil {
40 | return "", err
41 | }
42 |
43 | defer f.Close()
44 |
45 | h := sha256.New()
46 |
47 | if _, err := io.Copy(h, f); err != nil {
48 | return "", err
49 | }
50 |
51 | return fmt.Sprintf("%x", h.Sum(nil)), nil
52 | }
53 |
54 | // GetSha256Sum gets the sha256 sum from a URL
55 | func GetSha256Sum(url string) (string, error) {
56 | resp, err := http.Get(url)
57 |
58 | if err != nil {
59 | return "", err
60 | }
61 |
62 | body, err := ioutil.ReadAll(resp.Body)
63 |
64 | if err != nil {
65 | return "", err
66 | }
67 |
68 | if strings.Contains(string(body), "Not Found") {
69 | return "", nil
70 | }
71 |
72 | return string(body), nil
73 | }
74 |
--------------------------------------------------------------------------------
/core/util/helpers_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | //go:build unit
6 | // +build unit
7 |
8 | package util
9 |
10 | import (
11 | "fmt"
12 | "testing"
13 |
14 | "github.com/franela/goblin"
15 | )
16 |
17 | // TesUnitHelpers
18 | func TesUnitHelpers(t *testing.T) {
19 | g := goblin.Goblin(t)
20 |
21 | g.Describe("#TestInArray", func() {
22 | g.It("It should satisfy test cases", func() {
23 | g.Assert(InArray("A", []string{"A", "B", "C", "D"})).Equal(true)
24 | g.Assert(InArray("B", []string{"A", "B", "C", "D"})).Equal(true)
25 | g.Assert(InArray("H", []string{"A", "B", "C", "D"})).Equal(false)
26 | g.Assert(InArray(1, []int{2, 3, 1})).Equal(true)
27 | g.Assert(InArray(9, []int{2, 3, 1})).Equal(false)
28 | })
29 | })
30 | }
31 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/clivern/goenv
2 |
3 | go 1.18
4 |
5 | require (
6 | github.com/charmbracelet/bubbles v0.16.0
7 | github.com/charmbracelet/bubbletea v0.27.0
8 | github.com/charmbracelet/lipgloss v0.6.0
9 | github.com/franela/goblin v0.0.0-20211003143422-0a4f594942bf
10 | github.com/spf13/cobra v1.9.1
11 | )
12 |
13 | require (
14 | github.com/atotto/clipboard v0.1.4 // indirect
15 | github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
16 | github.com/charmbracelet/x/ansi v0.1.4 // indirect
17 | github.com/charmbracelet/x/input v0.1.0 // indirect
18 | github.com/charmbracelet/x/term v0.1.1 // indirect
19 | github.com/charmbracelet/x/windows v0.1.0 // indirect
20 | github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
21 | github.com/inconshreveable/mousetrap v1.1.0 // indirect
22 | github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
23 | github.com/mattn/go-isatty v0.0.18 // indirect
24 | github.com/mattn/go-localereader v0.0.1 // indirect
25 | github.com/mattn/go-runewidth v0.0.15 // indirect
26 | github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
27 | github.com/muesli/cancelreader v0.2.2 // indirect
28 | github.com/muesli/reflow v0.3.0 // indirect
29 | github.com/muesli/termenv v0.15.2 // indirect
30 | github.com/rivo/uniseg v0.4.7 // indirect
31 | github.com/sahilm/fuzzy v0.1.0 // indirect
32 | github.com/spf13/pflag v1.0.6 // indirect
33 | github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
34 | golang.org/x/sync v0.8.0 // indirect
35 | golang.org/x/sys v0.24.0 // indirect
36 | golang.org/x/text v0.3.8 // indirect
37 | )
38 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
2 | github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
3 | github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
4 | github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
5 | github.com/charmbracelet/bubbles v0.16.0 h1:jlJxnPj7T0G4rVQhh3gmG9tZu1Xkn+slKax0itFX6fQ=
6 | github.com/charmbracelet/bubbles v0.16.0/go.mod h1:D4UDwNOTGBU2NtVEWtwfhStJO75L8OsqcO7csWH6RrA=
7 | github.com/charmbracelet/bubbletea v0.27.0 h1:Mznj+vvYuYagD9Pn2mY7fuelGvP0HAXtZYGgRBCbHvU=
8 | github.com/charmbracelet/bubbletea v0.27.0/go.mod h1:5MdP9XH6MbQkgGhnlxUqCNmBXf9I74KRQ8HIidRxV1Y=
9 | github.com/charmbracelet/lipgloss v0.6.0 h1:1StyZB9vBSOyuZxQUcUwGr17JmojPNm87inij9N3wJY=
10 | github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk=
11 | github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM=
12 | github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
13 | github.com/charmbracelet/x/input v0.1.0 h1:TEsGSfZYQyOtp+STIjyBq6tpRaorH0qpwZUj8DavAhQ=
14 | github.com/charmbracelet/x/input v0.1.0/go.mod h1:ZZwaBxPF7IG8gWWzPUVqHEtWhc1+HXJPNuerJGRGZ28=
15 | github.com/charmbracelet/x/term v0.1.1 h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI=
16 | github.com/charmbracelet/x/term v0.1.1/go.mod h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw=
17 | github.com/charmbracelet/x/windows v0.1.0 h1:gTaxdvzDM5oMa/I2ZNF7wN78X/atWemG9Wph7Ika2k4=
18 | github.com/charmbracelet/x/windows v0.1.0/go.mod h1:GLEO/l+lizvFDBPLIOk+49gdX49L9YWMB5t+DZd0jkQ=
19 | github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
20 | github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
21 | github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
22 | github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
23 | github.com/franela/goblin v0.0.0-20211003143422-0a4f594942bf h1:NrF81UtW8gG2LBGkXFQFqlfNnvMt9WdB46sfdJY4oqc=
24 | github.com/franela/goblin v0.0.0-20211003143422-0a4f594942bf/go.mod h1:VzmDKDJVZI3aJmnRI9VjAn9nJ8qPPsN1fqzr9dqInIo=
25 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
26 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
27 | github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
28 | github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
29 | github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
30 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
31 | github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
32 | github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
33 | github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
34 | github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
35 | github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
36 | github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
37 | github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
38 | github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
39 | github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
40 | github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
41 | github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
42 | github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
43 | github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
44 | github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ=
45 | github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
46 | github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
47 | github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs=
48 | github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
49 | github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
50 | github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
51 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
52 | github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
53 | github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
54 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
55 | github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
56 | github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
57 | github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
58 | github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
59 | github.com/spf13/cobra v1.9.0 h1:Py5fIuq/lJsRYxcxfOtsJqpmwJWCMOUy2tMJYV8TNHE=
60 | github.com/spf13/cobra v1.9.0/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
61 | github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
62 | github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
63 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
64 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
65 | github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
66 | github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
67 | github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
68 | github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
69 | golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
70 | golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
71 | golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
72 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
73 | golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
74 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
75 | golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
76 | golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
77 | golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
78 | golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
79 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
80 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
81 |
--------------------------------------------------------------------------------
/goenv.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | // main package
6 | package main
7 |
8 | import (
9 | "os"
10 | "strings"
11 |
12 | "github.com/clivern/goenv/cmd"
13 | )
14 |
15 | var (
16 | version = "dev"
17 | commit = "none"
18 | date = "unknown"
19 | builtBy = "unknown"
20 | )
21 |
22 | func main() {
23 | cmd.Version = version
24 | cmd.Commit = commit
25 | cmd.Date = date
26 | cmd.BuiltBy = builtBy
27 | cmd.HOME = strings.TrimSpace(os.Getenv("HOME"))
28 |
29 | cmd.Execute()
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/loader.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Clivern. All rights reserved.
2 | // Use of this source code is governed by the MIT
3 | // license that can be found in the LICENSE file.
4 |
5 | // Package pkg package
6 | package pkg
7 |
8 | import (
9 | "fmt"
10 | "os"
11 | "path/filepath"
12 | )
13 |
14 | // GetBaseDir returns the project base dir
15 | // Base dir identified if dirName found
16 | // This function for testing purposes only
17 | func GetBaseDir(dirName string) string {
18 | baseDir, _ := os.Getwd()
19 | cacheDir := fmt.Sprintf("%s/%s", baseDir, dirName)
20 |
21 | for {
22 | if fi, err := os.Stat(cacheDir); err == nil {
23 | if fi.Mode().IsDir() {
24 | return baseDir
25 | }
26 | }
27 | baseDir = filepath.Dir(baseDir)
28 | cacheDir = fmt.Sprintf("%s/%s", baseDir, dirName)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["config:base"]
3 | }
4 |
--------------------------------------------------------------------------------
/static/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Clivern/Goenv/e97086d1f9163d416dad1839621c1c6ef8e36937/static/logo.png
--------------------------------------------------------------------------------
/static/logo1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Clivern/Goenv/e97086d1f9163d416dad1839621c1c6ef8e36937/static/logo1.png
--------------------------------------------------------------------------------
/static/screenshot-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Clivern/Goenv/e97086d1f9163d416dad1839621c1c6ef8e36937/static/screenshot-1.png
--------------------------------------------------------------------------------
/techstack.md:
--------------------------------------------------------------------------------
1 |
26 |
27 |
28 | # Tech Stack File
29 |  [Norwik/Goenv](https://github.com/Norwik/Goenv)
30 |
31 | |14
Tools used|12/21/23
Report generated|
32 | |------|------|
33 |
34 |
35 | ##
Languages (1)
36 |
37 |
38 |
39 |
40 | Golang
41 |
42 |
43 | |
44 |
45 |
46 |
47 |
48 | ##
DevOps (2)
49 |
50 |
51 |
52 |
53 | Git
54 |
55 |
56 | |
57 |
58 |
59 |
60 |
61 | GitHub Actions
62 |
63 |
64 | |
65 |
66 |
67 |
68 |
69 | ## Other (1)
70 |
71 |
72 |
73 |
74 | Shell
75 |
76 |
77 | |
78 |
79 |
80 |
81 |
82 |
83 | ##
Open source packages (10)
84 |
85 | ##
Go Packages (10)
86 |
87 | |NAME|VERSION|LAST UPDATED|LAST UPDATED BY|LICENSE|VULNERABILITIES|
88 | |:------|:------|:------|:------|:------|:------|
89 | |[clipboard](https://pkg.go.dev/github.com/atotto/clipboard)|v0.1.4|02/27/21|Clivern |BSD-3-Clause|N/A|
90 | |[cobra](https://pkg.go.dev/github.com/spf13/cobra)|v1.8.0|11/07/23|dependabot[bot] |Apache-2.0|N/A|
91 | |[go-colorful](https://pkg.go.dev/github.com/lucasb-eyer/go-colorful)|v1.2.0|02/27/21|Clivern |MIT|N/A|
92 | |[go-isatty](https://pkg.go.dev/github.com/mattn/go-isatty)|v0.0.14|05/10/23|dependabot[bot] |MIT|N/A|
93 | |[go-runewidth](https://pkg.go.dev/github.com/mattn/go-runewidth)|v0.0.10|11/09/22|renovate[bot] |MIT|N/A|
94 | |[goblin](https://pkg.go.dev/github.com/franela/goblin)|v0.0.0|02/24/21|Clivern |MIT|N/A|
95 | |[mousetrap](https://pkg.go.dev/github.com/inconshreveable/mousetrap)|v1.1.0|04/06/23|dependabot[bot] |Apache-2.0|N/A|
96 | |[pflag](https://pkg.go.dev/github.com/spf13/pflag)|v1.0.5|02/27/21|Clivern |BSD-3-Clause|N/A|
97 | |[sys](https://pkg.go.dev/golang.org/x/sys)|v0.0.0|02/24/21|Clivern |BSD-3-Clause|N/A|
98 | |[text](https://pkg.go.dev/golang.org/x/text)|v0.3.8|05/10/23|dependabot[bot] |BSD-3-Clause|N/A|
99 |
100 |
101 |
102 |
103 | Generated via [Stack File](https://github.com/marketplace/stack-file)
104 |
--------------------------------------------------------------------------------
/techstack.yml:
--------------------------------------------------------------------------------
1 | repo_name: Norwik/Goenv
2 | report_id: aff69af49b0c8c04026a6ecfb45542b6
3 | version: 0.1
4 | repo_type: Public
5 | timestamp: '2023-12-21T15:24:03+00:00'
6 | requested_by: renovate[bot]
7 | provider: github
8 | branch: main
9 | detected_tools_count: 14
10 | tools:
11 | - name: Golang
12 | description: An open source programming language that makes it easy to build simple,
13 | reliable, and efficient software
14 | website_url: http://golang.org/
15 | license: BSD-3-Clause
16 | open_source: true
17 | hosted_saas: false
18 | category: Languages & Frameworks
19 | sub_category: Languages
20 | image_url: https://img.stackshare.io/service/1005/O6AczwfV_400x400.png
21 | detection_source: Repo Metadata
22 | - name: Git
23 | description: Fast, scalable, distributed revision control system
24 | website_url: http://git-scm.com/
25 | open_source: true
26 | hosted_saas: false
27 | category: Build, Test, Deploy
28 | sub_category: Version Control System
29 | image_url: https://img.stackshare.io/service/1046/git.png
30 | detection_source: Repo Metadata
31 | - name: GitHub Actions
32 | description: Automate your workflow from idea to production
33 | website_url: https://github.com/features/actions
34 | open_source: false
35 | hosted_saas: true
36 | category: Build, Test, Deploy
37 | sub_category: Continuous Integration
38 | image_url: https://img.stackshare.io/service/11563/actions.png
39 | detection_source: ".github/workflows/build.yml"
40 | last_updated_by: renovate[bot]
41 | last_updated_on: 2023-12-12 21:15:10.000000000 Z
42 | - name: Shell
43 | description: A shell is a text-based terminal, used for manipulating programs and
44 | files. Shell scripts typically manage program execution.
45 | website_url: https://en.wikipedia.org/wiki/Shell_script
46 | open_source: false
47 | hosted_saas: false
48 | category: Languages & Frameworks
49 | sub_category: Languages
50 | image_url: https://img.stackshare.io/service/4631/default_c2062d40130562bdc836c13dbca02d318205a962.png
51 | detection_source: Repo Metadata
52 | - name: clipboard
53 | description: Clipboard for golang
54 | package_url: https://pkg.go.dev/github.com/atotto/clipboard
55 | version: 0.1.4
56 | license: BSD-3-Clause
57 | open_source: true
58 | hosted_saas: false
59 | category: Libraries
60 | sub_category: Go Modules Packages
61 | image_url: https://img.stackshare.io/package/go-packages/image.png
62 | detection_source_url: https://github.com/Norwik/Goenv/blob/main/go.sum
63 | detection_source: go.mod
64 | last_updated_by: Clivern
65 | last_updated_on: 2021-02-27 16:34:25.000000000 Z
66 | - name: cobra
67 | description: A Commander for modern Go CLI interactions
68 | package_url: https://pkg.go.dev/github.com/spf13/cobra
69 | version: 1.8.0
70 | license: Apache-2.0
71 | open_source: true
72 | hosted_saas: false
73 | category: Libraries
74 | sub_category: Go Modules Packages
75 | image_url: https://img.stackshare.io/package/go-packages/image.png
76 | detection_source_url: https://github.com/Norwik/Goenv/blob/main/go.sum
77 | detection_source: go.mod
78 | last_updated_by: dependabot[bot]
79 | last_updated_on: 2023-11-07 15:18:01.000000000 Z
80 | - name: go-colorful
81 | description: A library for playing with colors in go
82 | package_url: https://pkg.go.dev/github.com/lucasb-eyer/go-colorful
83 | version: 1.2.0
84 | license: MIT
85 | open_source: true
86 | hosted_saas: false
87 | category: Libraries
88 | sub_category: Go Modules Packages
89 | image_url: https://img.stackshare.io/package/go-packages/image.png
90 | detection_source_url: https://github.com/Norwik/Goenv/blob/main/go.sum
91 | detection_source: go.mod
92 | last_updated_by: Clivern
93 | last_updated_on: 2021-02-27 16:34:25.000000000 Z
94 | - name: go-isatty
95 | description: Package isatty implements interface to isatty
96 | package_url: https://pkg.go.dev/github.com/mattn/go-isatty
97 | version: 0.0.14
98 | license: MIT
99 | open_source: true
100 | hosted_saas: false
101 | category: Libraries
102 | sub_category: Go Modules Packages
103 | image_url: https://img.stackshare.io/package/go-packages/image.png
104 | detection_source_url: https://github.com/Norwik/Goenv/blob/main/go.sum
105 | detection_source: go.mod
106 | last_updated_by: dependabot[bot]
107 | last_updated_on: 2023-05-10 15:11:59.000000000 Z
108 | - name: go-runewidth
109 | description: Go-runewidth Provides functions to get fixed width of the character
110 | or string
111 | package_url: https://pkg.go.dev/github.com/mattn/go-runewidth
112 | version: 0.0.10
113 | license: MIT
114 | open_source: true
115 | hosted_saas: false
116 | category: Libraries
117 | sub_category: Go Modules Packages
118 | image_url: https://img.stackshare.io/package/go-packages/image.png
119 | detection_source_url: https://github.com/Norwik/Goenv/blob/main/go.sum
120 | detection_source: go.mod
121 | last_updated_by: renovate[bot]
122 | last_updated_on: 2022-11-09 21:04:51.000000000 Z
123 | - name: goblin
124 | description: Minimal and Beautiful Go testing framework
125 | package_url: https://pkg.go.dev/github.com/franela/goblin
126 | version: 0.0.0
127 | license: MIT
128 | open_source: true
129 | hosted_saas: false
130 | category: Libraries
131 | sub_category: Go Modules Packages
132 | image_url: https://img.stackshare.io/package/go-packages/image.png
133 | detection_source_url: https://github.com/Norwik/Goenv/blob/main/go.sum
134 | detection_source: go.mod
135 | last_updated_by: Clivern
136 | last_updated_on: 2021-02-24 20:50:47.000000000 Z
137 | - name: mousetrap
138 | description: Detect starting from Windows explorer
139 | package_url: https://pkg.go.dev/github.com/inconshreveable/mousetrap
140 | version: 1.1.0
141 | license: Apache-2.0
142 | open_source: true
143 | hosted_saas: false
144 | category: Libraries
145 | sub_category: Go Modules Packages
146 | image_url: https://img.stackshare.io/package/go-packages/image.png
147 | detection_source_url: https://github.com/Norwik/Goenv/blob/main/go.sum
148 | detection_source: go.mod
149 | last_updated_by: dependabot[bot]
150 | last_updated_on: 2023-04-06 00:53:47.000000000 Z
151 | - name: pflag
152 | description: Drop-in replacement for Go's flag package
153 | package_url: https://pkg.go.dev/github.com/spf13/pflag
154 | version: 1.0.5
155 | license: BSD-3-Clause
156 | open_source: true
157 | hosted_saas: false
158 | category: Libraries
159 | sub_category: Go Modules Packages
160 | image_url: https://img.stackshare.io/package/go-packages/image.png
161 | detection_source_url: https://github.com/Norwik/Goenv/blob/main/go.sum
162 | detection_source: go.mod
163 | last_updated_by: Clivern
164 | last_updated_on: 2021-02-27 16:34:25.000000000 Z
165 | - name: sys
166 | description: Go packages for low-level interaction with the operating system
167 | package_url: https://pkg.go.dev/golang.org/x/sys
168 | version: 0.0.0
169 | license: BSD-3-Clause
170 | open_source: true
171 | hosted_saas: false
172 | category: Libraries
173 | sub_category: Go Modules Packages
174 | image_url: https://img.stackshare.io/package/go-packages/image.png
175 | detection_source_url: https://github.com/Norwik/Goenv/blob/main/go.sum
176 | detection_source: go.mod
177 | last_updated_by: Clivern
178 | last_updated_on: 2021-02-24 20:47:01.000000000 Z
179 | - name: text
180 | description: Go text processing support
181 | package_url: https://pkg.go.dev/golang.org/x/text
182 | version: 0.3.8
183 | license: BSD-3-Clause
184 | open_source: true
185 | hosted_saas: false
186 | category: Libraries
187 | sub_category: Go Modules Packages
188 | image_url: https://img.stackshare.io/package/go-packages/image.png
189 | detection_source_url: https://github.com/Norwik/Goenv/blob/main/go.sum
190 | detection_source: go.mod
191 | last_updated_by: dependabot[bot]
192 | last_updated_on: 2023-05-10 15:11:59.000000000 Z
193 |
--------------------------------------------------------------------------------