Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace deprecated ioutil usage with the equivalent replacements #198

Merged
merged 2 commits into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
76 changes: 39 additions & 37 deletions README.md
Expand Up @@ -14,65 +14,65 @@ the library in ad-hoc or CI shell scripting outside of Go.

`hc-install` does **not**:

- Determine suitable installation path based on target system. e.g. in `/usr/bin` or `/usr/local/bin` on Unix based system.
- Deal with execution of installed binaries (via service files or otherwise).
- Upgrade existing binaries on your system.
- Add nor link downloaded binaries to your `$PATH`.
- Determine suitable installation path based on target system. e.g. in `/usr/bin` or `/usr/local/bin` on Unix based system.
- Deal with execution of installed binaries (via service files or otherwise).
- Upgrade existing binaries on your system.
- Add nor link downloaded binaries to your `$PATH`.

## API

The `Installer` offers a few high-level methods:

- `Ensure(context.Context, []src.Source)` to find, install, or build a product version
- `Install(context.Context, []src.Installable)` to install a product version
- `Ensure(context.Context, []src.Source)` to find, install, or build a product version
- `Install(context.Context, []src.Installable)` to install a product version

### Sources

The `Installer` methods accept number of different `Source` types.
Each comes with different trade-offs described below.

- `fs.{AnyVersion,ExactVersion,Version}` - Finds a binary in `$PATH` (or additional paths)
- **Pros:**
- This is most convenient when you already have the product installed on your system
- `fs.{AnyVersion,ExactVersion,Version}` - Finds a binary in `$PATH` (or additional paths)
- **Pros:**
- This is most convenient when you already have the product installed on your system
which you already manage.
- **Cons:**
- Only relies on a single version, expects _you_ to manage the installation
- _Not recommended_ for any environment where product installation is not controlled or managed by you (e.g. default GitHub Actions image managed by GitHub)
- `releases.{LatestVersion,ExactVersion}` - Downloads, verifies & installs any known product from `releases.hashicorp.com`
- **Pros:**
- Fast and reliable way of obtaining any pre-built version of any product
- Allows installation of enterprise versions
- **Cons:**
- Installation may consume some bandwidth, disk space and a little time
- Potentially less stable builds (see `checkpoint` below)
- `checkpoint.LatestVersion` - Downloads, verifies & installs any known product available in HashiCorp Checkpoint
- **Pros:**
- Checkpoint typically contains only product versions considered stable
- **Cons:**
- Installation may consume some bandwidth, disk space and a little time
- Currently doesn't allow installation of old versions or enterprise versions (see `releases` above)
- `build.GitRevision` - Clones raw source code and builds the product from it
- **Pros:**
- Useful for catching bugs and incompatibilities as early as possible (prior to product release).
- **Cons:**
- Building from scratch can consume significant amount of time & resources (CPU, memory, bandwith, disk space)
- There are no guarantees that build instructions will always be up-to-date
- There's increased likelihood of build containing bugs prior to release
- Any CI builds relying on this are likely to be fragile
- **Cons:**
- Only relies on a single version, expects _you_ to manage the installation
- _Not recommended_ for any environment where product installation is not controlled or managed by you (e.g. default GitHub Actions image managed by GitHub)
- `releases.{LatestVersion,ExactVersion}` - Downloads, verifies & installs any known product from `releases.hashicorp.com`
- **Pros:**
- Fast and reliable way of obtaining any pre-built version of any product
- Allows installation of enterprise versions
- **Cons:**
- Installation may consume some bandwidth, disk space and a little time
- Potentially less stable builds (see `checkpoint` below)
- `checkpoint.LatestVersion` - Downloads, verifies & installs any known product available in HashiCorp Checkpoint
- **Pros:**
- Checkpoint typically contains only product versions considered stable
- **Cons:**
- Installation may consume some bandwidth, disk space and a little time
- Currently doesn't allow installation of old versions or enterprise versions (see `releases` above)
- `build.GitRevision` - Clones raw source code and builds the product from it
- **Pros:**
- Useful for catching bugs and incompatibilities as early as possible (prior to product release).
- **Cons:**
- Building from scratch can consume significant amount of time & resources (CPU, memory, bandwith, disk space)
- There are no guarantees that build instructions will always be up-to-date
- There's increased likelihood of build containing bugs prior to release
- Any CI builds relying on this are likely to be fragile

## Example Usage

See examples at https://pkg.go.dev/github.com/hashicorp/hc-install#example-Installer.
See examples at <https://pkg.go.dev/github.com/hashicorp/hc-install#example-Installer>.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I struggle to find the meaning of this <URL> syntax - do you mind sharing link to any relevant docs to help me understand the reason for the change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I use markdownlint to format Markdown


## CLI

In addition to the Go library, which is the intended primary use case of `hc-install`, we also distribute CLI.

The CLI comes with some trade-offs:

- more limited interface compared to the flexible Go API (installs specific versions of products via `releases.ExactVersion`)
- minimal environment pre-requisites (no need to compile Go code)
- see ["hc-install is not a package manager"](https://github.com/hashicorp/hc-install#hc-install-is-not-a-package-manager)
- more limited interface compared to the flexible Go API (installs specific versions of products via `releases.ExactVersion`)
- minimal environment pre-requisites (no need to compile Go code)
- see ["hc-install is not a package manager"](https://github.com/hashicorp/hc-install#hc-install-is-not-a-package-manager)

### Installation

Expand Down Expand Up @@ -113,9 +113,11 @@ Usage: hc-install install [options] -version <version> <product>
-log-file Path to file where logs will be written. /dev/stdout
or /dev/stderr can be used to log to STDOUT/STDERR.
```

```sh
hc-install install -version 1.3.7 terraform
```

```
hc-install: will install terraform@1.3.7
installed terraform@1.3.7 to /current/working/dir/terraform
Expand Down
8 changes: 4 additions & 4 deletions build/git_revision.go
Expand Up @@ -6,7 +6,7 @@ package build
import (
"context"
"fmt"
"io/ioutil"
"io"
"log"
"os"
"time"
Expand All @@ -23,7 +23,7 @@ var (
defaultCloneTimeout = 5 * time.Minute
defaultBuildTimeout = 25 * time.Minute

discardLogger = log.New(ioutil.Discard, "", 0)
discardLogger = log.New(io.Discard, "", 0)
)

// GitRevision installs a particular git revision by cloning
Expand Down Expand Up @@ -101,7 +101,7 @@ func (gr *GitRevision) Build(ctx context.Context) (string, error) {
gr.pathsToRemove = make([]string, 0)
}

repoDir, err := ioutil.TempDir("",
repoDir, err := os.MkdirTemp("",
fmt.Sprintf("hc-install-build-%s", gr.Product.Name))
if err != nil {
return "", err
Expand Down Expand Up @@ -160,7 +160,7 @@ func (gr *GitRevision) Build(ctx context.Context) (string, error) {
}
installDir := gr.InstallDir
if installDir == "" {
tmpDir, err := ioutil.TempDir("",
tmpDir, err := os.MkdirTemp("",
fmt.Sprintf("hc-install-%s-%s", gr.Product.Name, head.Hash()))
if err != nil {
return "", err
Expand Down
6 changes: 3 additions & 3 deletions checkpoint/latest_version.go
Expand Up @@ -6,7 +6,7 @@ package checkpoint
import (
"context"
"fmt"
"io/ioutil"
"io"
"log"
"os"
"path/filepath"
Expand All @@ -24,7 +24,7 @@ import (

var (
defaultTimeout = 30 * time.Second
discardLogger = log.New(ioutil.Discard, "", 0)
discardLogger = log.New(io.Discard, "", 0)
)

// LatestVersion installs the latest version known to Checkpoint
Expand Down Expand Up @@ -101,7 +101,7 @@ func (lv *LatestVersion) Install(ctx context.Context) (string, error) {
if dstDir == "" {
var err error
dirName := fmt.Sprintf("%s_*", lv.Product.Name)
dstDir, err = ioutil.TempDir("", dirName)
dstDir, err = os.MkdirTemp("", dirName)
if err != nil {
return "", err
}
Expand Down
10 changes: 5 additions & 5 deletions docs/CONTRIBUTING.md
Expand Up @@ -6,8 +6,8 @@ Releases are made on a reasonably regular basis by the maintainers (HashiCorp st

Release process:

1. Update [`version/VERSION`](https://github.com/hashicorp/hc-install/blob/main/version/VERSION) to remove `-dev` suffix and set it to the intended version to be released
1. Wait for [`build` workflow](https://github.com/hashicorp/hc-install/actions/workflows/build.yml) to finish
1. Run the Release workflow with the appropriate version (matching the one in `version/VERSION`) & SHA (long one).
1. Wait for a message in the Slack channel saying that authorisation is needed to promote artifacts to production. Click on the link and approve.
1. Once notified that promotion is successful, go to https://github.com/hashicorp/crt-workflows-common/actions/workflows/promote-production-packaging.yml, locate the hc-install promote-production-packaging workflow, and approve.
1. Update [`version/VERSION`](https://github.com/hashicorp/hc-install/blob/main/version/VERSION) to remove `-dev` suffix and set it to the intended version to be released
2. Wait for [`build` workflow](https://github.com/hashicorp/hc-install/actions/workflows/build.yml) to finish
3. Run the Release workflow with the appropriate version (matching the one in `version/VERSION`) & SHA (long one).
4. Wait for a message in the Slack channel saying that authorisation is needed to promote artifacts to production. Click on the link and approve.
5. Once notified that promotion is successful, go to <https://github.com/hashicorp/crt-workflows-common/actions/workflows/promote-production-packaging.yml>, locate the hc-install promote-production-packaging workflow, and approve.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind the whitespace removal but I would strongly prefer the indexes to stay as-is, i.e. 1. The reason is that if a human goes to add another item into the middle of the list, they have to re-index any following numbers.

Also similar question here about the <URL> syntax.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure thing, I understand that logic

4 changes: 2 additions & 2 deletions fs/fs.go
Expand Up @@ -4,14 +4,14 @@
package fs

import (
"io/ioutil"
"io"
"log"
"time"
)

var (
defaultTimeout = 10 * time.Second
discardLogger = log.New(ioutil.Discard, "", 0)
discardLogger = log.New(io.Discard, "", 0)
)

type fileCheckFunc func(path string) error
4 changes: 2 additions & 2 deletions installer.go
Expand Up @@ -6,7 +6,7 @@ package install
import (
"context"
"fmt"
"io/ioutil"
"io"
"log"

"github.com/hashicorp/go-multierror"
Expand All @@ -23,7 +23,7 @@ type Installer struct {
type RemoveFunc func(ctx context.Context) error

func NewInstaller() *Installer {
discardLogger := log.New(ioutil.Discard, "", 0)
discardLogger := log.New(io.Discard, "", 0)
return &Installer{
logger: discardLogger,
}
Expand Down
8 changes: 4 additions & 4 deletions internal/build/go_build.go
Expand Up @@ -7,7 +7,7 @@ import (
"bytes"
"context"
"fmt"
"io/ioutil"
"io"
"log"
"os"
"os/exec"
Expand All @@ -17,7 +17,7 @@ import (
"golang.org/x/mod/modfile"
)

var discardLogger = log.New(ioutil.Discard, "", 0)
var discardLogger = log.New(io.Discard, "", 0)

// GoBuild represents a Go builder (to run "go build")
type GoBuild struct {
Expand Down Expand Up @@ -161,7 +161,7 @@ type CleanupFunc func(context.Context)
func guessRequiredGoVersion(repoDir string) (*version.Version, bool) {
goEnvFile := filepath.Join(repoDir, ".go-version")
if fi, err := os.Stat(goEnvFile); err == nil && !fi.IsDir() {
b, err := ioutil.ReadFile(goEnvFile)
b, err := os.ReadFile(goEnvFile)
if err != nil {
return nil, false
}
Expand All @@ -174,7 +174,7 @@ func guessRequiredGoVersion(repoDir string) (*version.Version, bool) {

goModFile := filepath.Join(repoDir, "go.mod")
if fi, err := os.Stat(goModFile); err == nil && !fi.IsDir() {
b, err := ioutil.ReadFile(goModFile)
b, err := os.ReadFile(goModFile)
if err != nil {
return nil, false
}
Expand Down
3 changes: 1 addition & 2 deletions internal/releasesjson/downloader.go
Expand Up @@ -10,7 +10,6 @@ import (
"crypto/sha256"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"net/url"
Expand Down Expand Up @@ -106,7 +105,7 @@ func (d *Downloader) DownloadAndUnpack(ctx context.Context, pv *ProductVersion,

expectedSize := resp.ContentLength

pkgFile, err := ioutil.TempFile("", pb.Filename)
pkgFile, err := os.CreateTemp("", pb.Filename)
if err != nil {
return "", err
}
Expand Down
8 changes: 4 additions & 4 deletions internal/releasesjson/releases.go
Expand Up @@ -7,7 +7,7 @@ import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"io"
"log"
"net/http"
"net/url"
Expand Down Expand Up @@ -55,7 +55,7 @@ type Releases struct {

func NewReleases() *Releases {
return &Releases{
logger: log.New(ioutil.Discard, "", 0),
logger: log.New(io.Discard, "", 0),
BaseURL: defaultBaseURL,
}
}
Expand Down Expand Up @@ -95,7 +95,7 @@ func (r *Releases) ListProductVersions(ctx context.Context, productName string)

r.logger.Printf("received %s", resp.Status)

body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -153,7 +153,7 @@ func (r *Releases) GetProductVersion(ctx context.Context, product string, versio

r.logger.Printf("received %s", resp.Status)

body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions internal/testutil/logger.go
Expand Up @@ -4,7 +4,7 @@
package testutil

import (
"io/ioutil"
"io"
"log"
"os"
"testing"
Expand All @@ -14,5 +14,5 @@ func TestLogger() *log.Logger {
if testing.Verbose() {
return log.New(os.Stdout, "", log.LstdFlags|log.Lshortfile)
}
return log.New(ioutil.Discard, "", 0)
return log.New(io.Discard, "", 0)
}
3 changes: 1 addition & 2 deletions releases/exact_version.go
Expand Up @@ -6,7 +6,6 @@ package releases
import (
"context"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
Expand Down Expand Up @@ -93,7 +92,7 @@ func (ev *ExactVersion) Install(ctx context.Context) (string, error) {
if dstDir == "" {
var err error
dirName := fmt.Sprintf("%s_*", ev.Product.Name)
dstDir, err = ioutil.TempDir("", dirName)
dstDir, err = os.MkdirTemp("", dirName)
if err != nil {
return "", err
}
Expand Down
3 changes: 1 addition & 2 deletions releases/latest_version.go
Expand Up @@ -6,7 +6,6 @@ package releases
import (
"context"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
Expand Down Expand Up @@ -89,7 +88,7 @@ func (lv *LatestVersion) Install(ctx context.Context) (string, error) {
if dstDir == "" {
var err error
dirName := fmt.Sprintf("%s_*", lv.Product.Name)
dstDir, err = ioutil.TempDir("", dirName)
dstDir, err = os.MkdirTemp("", dirName)
if err != nil {
return "", err
}
Expand Down
4 changes: 2 additions & 2 deletions releases/releases.go
Expand Up @@ -4,13 +4,13 @@
package releases

import (
"io/ioutil"
"io"
"log"
"time"
)

var (
defaultInstallTimeout = 30 * time.Second
defaultListTimeout = 10 * time.Second
discardLogger = log.New(ioutil.Discard, "", 0)
discardLogger = log.New(io.Discard, "", 0)
)