cli: refactor util package to use internal/errors

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6508
Co-authored-by: Aravind K P <8335904+scriptonist@users.noreply.github.com>
GitOrigin-RevId: 41f4842593a7226966c53ffd6314809adbd72266
This commit is contained in:
Mohd Bilal 2022-10-28 15:01:03 +05:30 committed by hasura-bot
parent 3ca779797d
commit e814260ccc
7 changed files with 141 additions and 81 deletions

View File

@ -8,6 +8,8 @@ import (
"path/filepath" "path/filepath"
"github.com/spf13/afero" "github.com/spf13/afero"
"github.com/hasura/graphql-engine/cli/v2/internal/errors"
) )
// from https://gist.github.com/r0l1/92462b38df26839a3ca324697c8cba04 // from https://gist.github.com/r0l1/92462b38df26839a3ca324697c8cba04
@ -17,76 +19,77 @@ import (
// destination file exists, all it's contents will be replaced by the contents // destination file exists, all it's contents will be replaced by the contents
// of the source file. The file mode will be copied from the source and // of the source file. The file mode will be copied from the source and
// the copied data is synced/flushed to stable storage. // the copied data is synced/flushed to stable storage.
func CopyFile(src, dst string) (err error) { func CopyFile(src, dst string) error {
var op errors.Op = "util.CopyFile"
in, err := os.Open(src) in, err := os.Open(src)
if err != nil { if err != nil {
return return errors.E(op, err)
} }
defer in.Close() defer in.Close()
out, err := os.Create(dst) out, err := os.Create(dst)
if err != nil { if err != nil {
return return errors.E(op, err)
} }
defer func() { defer func() {
if e := out.Close(); e != nil { if e := out.Close(); e != nil {
err = e err = errors.E(op, e)
} }
}() }()
_, err = io.Copy(out, in) _, err = io.Copy(out, in)
if err != nil { if err != nil {
return return errors.E(op, err)
} }
err = out.Sync() err = out.Sync()
if err != nil { if err != nil {
return return errors.E(op, err)
} }
si, err := os.Stat(src) si, err := os.Stat(src)
if err != nil { if err != nil {
return return errors.E(op, err)
} }
err = os.Chmod(dst, si.Mode()) err = os.Chmod(dst, si.Mode())
if err != nil { if err != nil {
return return errors.E(op, err)
} }
return nil
return
} }
// CopyDir recursively copies a directory tree, attempting to preserve permissions. // CopyDir recursively copies a directory tree, attempting to preserve permissions.
// Source directory must exist, destination directory must *not* exist. // Source directory must exist, destination directory must *not* exist.
// Symlinks are ignored and skipped. // Symlinks are ignored and skipped.
func CopyDir(src string, dst string) (err error) { func CopyDir(src string, dst string) error {
var op errors.Op = "util.CopyDir"
src = filepath.Clean(src) src = filepath.Clean(src)
dst = filepath.Clean(dst) dst = filepath.Clean(dst)
si, err := os.Stat(src) si, err := os.Stat(src)
if err != nil { if err != nil {
return err return errors.E(op, err)
} }
if !si.IsDir() { if !si.IsDir() {
return fmt.Errorf("source is not a directory") return errors.E(op, fmt.Errorf("source is not a directory"))
} }
_, err = os.Stat(dst) _, err = os.Stat(dst)
if err != nil && !os.IsNotExist(err) { if err != nil && !os.IsNotExist(err) {
return return errors.E(op, err)
} }
if err == nil { if err == nil {
return fmt.Errorf("destination already exists") return errors.E(op, fmt.Errorf("destination already exists"))
} }
err = os.MkdirAll(dst, si.Mode()) err = os.MkdirAll(dst, si.Mode())
if err != nil { if err != nil {
return return errors.E(op, err)
} }
entries, err := ioutil.ReadDir(src) entries, err := ioutil.ReadDir(src)
if err != nil { if err != nil {
return return errors.E(op, err)
} }
for _, entry := range entries { for _, entry := range entries {
@ -96,7 +99,7 @@ func CopyDir(src string, dst string) (err error) {
if entry.IsDir() { if entry.IsDir() {
err = CopyDir(srcPath, dstPath) err = CopyDir(srcPath, dstPath)
if err != nil { if err != nil {
return return errors.E(op, err)
} }
} else { } else {
// Skip symlinks. // Skip symlinks.
@ -106,83 +109,83 @@ func CopyDir(src string, dst string) (err error) {
err = CopyFile(srcPath, dstPath) err = CopyFile(srcPath, dstPath)
if err != nil { if err != nil {
return return errors.E(op, err)
} }
} }
} }
return nil
return
} }
// CopyFile but with Afero // CopyFile but with Afero
func CopyFileAfero(fs afero.Fs, src, dst string) (err error) { func CopyFileAfero(fs afero.Fs, src, dst string) error {
var op errors.Op = "util.CopyFileAfero"
in, err := fs.Open(src) in, err := fs.Open(src)
if err != nil { if err != nil {
return return errors.E(op, err)
} }
defer in.Close() defer in.Close()
out, err := fs.Create(dst) out, err := fs.Create(dst)
if err != nil { if err != nil {
return return errors.E(op, err)
} }
defer func() { defer func() {
if e := out.Close(); e != nil { if e := out.Close(); e != nil {
err = e err = errors.E(op, e)
} }
}() }()
_, err = io.Copy(out, in) _, err = io.Copy(out, in)
if err != nil { if err != nil {
return return errors.E(op, err)
} }
err = out.Sync() err = out.Sync()
if err != nil { if err != nil {
return return errors.E(op, err)
} }
si, err := fs.Stat(src) si, err := fs.Stat(src)
if err != nil { if err != nil {
return return errors.E(op, err)
} }
err = fs.Chmod(dst, si.Mode()) err = fs.Chmod(dst, si.Mode())
if err != nil { if err != nil {
return return errors.E(op, err)
} }
return nil
return
} }
// CopyDir but with afero // CopyDir but with afero
func CopyDirAfero(fs afero.Fs, src string, dst string) (err error) { func CopyDirAfero(fs afero.Fs, src string, dst string) error {
var op errors.Op = "util.CopyDirAfero"
src = filepath.Clean(src) src = filepath.Clean(src)
dst = filepath.Clean(dst) dst = filepath.Clean(dst)
si, err := fs.Stat(src) si, err := fs.Stat(src)
if err != nil { if err != nil {
return err return errors.E(op, err)
} }
if !si.IsDir() { if !si.IsDir() {
return fmt.Errorf("source is not a directory") return errors.E(op, fmt.Errorf("source is not a directory"))
} }
_, err = fs.Stat(dst) _, err = fs.Stat(dst)
if err != nil && !os.IsNotExist(err) { if err != nil && !os.IsNotExist(err) {
return return errors.E(op, err)
} }
if err == nil { if err == nil {
return fmt.Errorf("destination already exists") return errors.E(op, fmt.Errorf("destination already exists"))
} }
err = fs.MkdirAll(dst, si.Mode()) err = fs.MkdirAll(dst, si.Mode())
if err != nil { if err != nil {
return return errors.E(op, err)
} }
entries, err := afero.ReadDir(fs, src) entries, err := afero.ReadDir(fs, src)
if err != nil { if err != nil {
return return errors.E(op, err)
} }
for _, entry := range entries { for _, entry := range entries {
@ -192,7 +195,7 @@ func CopyDirAfero(fs afero.Fs, src string, dst string) (err error) {
if entry.IsDir() { if entry.IsDir() {
err = CopyDirAfero(fs, srcPath, dstPath) err = CopyDirAfero(fs, srcPath, dstPath)
if err != nil { if err != nil {
return return errors.E(op, err)
} }
} else { } else {
// Skip symlinks. // Skip symlinks.
@ -202,10 +205,9 @@ func CopyDirAfero(fs afero.Fs, src string, dst string) (err error) {
err = CopyFileAfero(fs, srcPath, dstPath) err = CopyFileAfero(fs, srcPath, dstPath)
if err != nil { if err != nil {
return return errors.E(op, err)
} }
} }
} }
return nil
return
} }

View File

@ -1,65 +1,73 @@
package util package util
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"path" "path"
"github.com/hasura/graphql-engine/cli/v2/internal/errors"
) )
func FSCheckIfDirPathExists(path string) error { func FSCheckIfDirPathExists(path string) error {
var op errors.Op = "util.FSCheckIfDirPathExists"
stat, err := os.Lstat(path) stat, err := os.Lstat(path)
if err != nil { if err != nil {
return err return errors.E(op, err)
} }
if !stat.IsDir() { if !stat.IsDir() {
err = errors.New("no such directory") err = errors.E(op, "no such directory")
} }
return err return err
} }
func FSCopyFile(src, dst string) error { func FSCopyFile(src, dst string) error {
var op errors.Op = "util.FSCopyFile"
var err error var err error
var srcfd *os.File var srcfd *os.File
var dstfd *os.File var dstfd *os.File
var srcinfo os.FileInfo var srcinfo os.FileInfo
if srcfd, err = os.Open(src); err != nil { if srcfd, err = os.Open(src); err != nil {
return err return errors.E(op, err)
} }
defer srcfd.Close() defer srcfd.Close()
if dstfd, err = os.Create(dst); err != nil { if dstfd, err = os.Create(dst); err != nil {
return err return errors.E(op, err)
} }
defer dstfd.Close() defer dstfd.Close()
if _, err = io.Copy(dstfd, srcfd); err != nil { if _, err = io.Copy(dstfd, srcfd); err != nil {
return err return errors.E(op, err)
} }
if srcinfo, err = os.Stat(src); err != nil { if srcinfo, err = os.Stat(src); err != nil {
return err return errors.E(op, err)
} }
return os.Chmod(dst, srcinfo.Mode()) err = os.Chmod(dst, srcinfo.Mode())
if err != nil {
return errors.E(op, err)
}
return nil
} }
func FSCopyDir(src string, dst string) error { func FSCopyDir(src string, dst string) error {
var op errors.Op = "util.FSCopyDir"
var err error var err error
var fds []os.FileInfo var fds []os.FileInfo
var srcinfo os.FileInfo var srcinfo os.FileInfo
if srcinfo, err = os.Stat(src); err != nil { if srcinfo, err = os.Stat(src); err != nil {
return err return errors.E(op, err)
} }
if err = os.MkdirAll(dst, srcinfo.Mode()); err != nil { if err = os.MkdirAll(dst, srcinfo.Mode()); err != nil {
return err return errors.E(op, err)
} }
if fds, err = ioutil.ReadDir(src); err != nil { if fds, err = ioutil.ReadDir(src); err != nil {
return err return errors.E(op, err)
} }
for _, fd := range fds { for _, fd := range fds {
srcfp := path.Join(src, fd.Name()) srcfp := path.Join(src, fd.Name())

View File

@ -2,6 +2,8 @@ package util
import ( import (
"github.com/Masterminds/semver" "github.com/Masterminds/semver"
"github.com/hasura/graphql-engine/cli/v2/internal/errors"
) )
type VersionFlag struct { type VersionFlag struct {
@ -15,9 +17,10 @@ func NewVersionFlagValue(p *VersionFlag) *VersionFlag {
// Set sets the value of the named command-line flag. // Set sets the value of the named command-line flag.
func (c *VersionFlag) Set(s string) error { func (c *VersionFlag) Set(s string) error {
var op errors.Op = "util.VersionFlag.Set"
v, err := semver.NewVersion(s) v, err := semver.NewVersion(s)
if err != nil { if err != nil {
return err return errors.E(op, err)
} }
c.Version = v c.Version = v
return nil return nil

View File

@ -8,6 +8,8 @@ import (
"gopkg.in/src-d/go-git.v4" "gopkg.in/src-d/go-git.v4"
"gopkg.in/src-d/go-git.v4/config" "gopkg.in/src-d/go-git.v4/config"
"gopkg.in/src-d/go-git.v4/plumbing" "gopkg.in/src-d/go-git.v4/plumbing"
"github.com/hasura/graphql-engine/cli/v2/internal/errors"
) )
// Default Codegen Assets constants // Default Codegen Assets constants
@ -40,79 +42,93 @@ func NewGitUtil(uri string, path string, refName string) *GitUtil {
} }
func (g *GitUtil) EnsureCloned() error { func (g *GitUtil) EnsureCloned() error {
var op errors.Op = "util.GitUtil.EnsureCloned"
if g.DisableCloneOrUpdate { if g.DisableCloneOrUpdate {
g.Logger.Debugf("skipping clone/update for %s", g.URI) g.Logger.Debugf("skipping clone/update for %s", g.URI)
return nil return nil
} }
if ok, err := g.IsGitCloned(); err != nil { if ok, err := g.IsGitCloned(); err != nil {
return err return errors.E(op, err)
} else if !ok { } else if !ok {
_, err := git.PlainClone(g.Path, false, &git.CloneOptions{ _, err := git.PlainClone(g.Path, false, &git.CloneOptions{
URL: g.URI, URL: g.URI,
ReferenceName: g.ReferenceName, ReferenceName: g.ReferenceName,
}) })
if err != nil && err != git.ErrRepositoryAlreadyExists { if err != nil && err != git.ErrRepositoryAlreadyExists {
return err return errors.E(op, err)
} }
} }
return nil return nil
} }
func (g *GitUtil) IsGitCloned() (bool, error) { func (g *GitUtil) IsGitCloned() (bool, error) {
var op errors.Op = "util.GitUtil.IsGitCloned"
f, err := os.Stat(filepath.Join(g.Path, ".git")) f, err := os.Stat(filepath.Join(g.Path, ".git"))
if os.IsNotExist(err) { if os.IsNotExist(err) {
return false, nil return false, nil
} }
return err == nil && f.IsDir(), err if err != nil {
return false, errors.E(op, err)
}
return f.IsDir(), nil
} }
// EnsureUpdated will ensure the destination path exists and is up to date. // EnsureUpdated will ensure the destination path exists and is up to date.
func (g *GitUtil) EnsureUpdated() error { func (g *GitUtil) EnsureUpdated() error {
var op errors.Op = "util.GitUtil.EnsureUpdated"
if g.DisableCloneOrUpdate { if g.DisableCloneOrUpdate {
g.Logger.Debugf("skipping clone/update for %s", g.URI) g.Logger.Debugf("skipping clone/update for %s", g.URI)
return nil return nil
} }
if err := g.EnsureCloned(); err != nil { if err := g.EnsureCloned(); err != nil {
return err return errors.E(op, err)
} }
return g.updateAndCleanUntracked() if err := g.updateAndCleanUntracked(); err != nil {
return errors.E(op, err)
}
return nil
} }
func (g *GitUtil) updateAndCleanUntracked() error { func (g *GitUtil) updateAndCleanUntracked() error {
var op errors.Op = "util.GitUtil.updateAndCleanUntracked"
repo, err := git.PlainOpen(g.Path) repo, err := git.PlainOpen(g.Path)
if err != nil { if err != nil {
return err return errors.E(op, err)
} }
err = repo.Fetch(&git.FetchOptions{ err = repo.Fetch(&git.FetchOptions{
RefSpecs: []config.RefSpec{"refs/*:refs/*"}, RefSpecs: []config.RefSpec{"refs/*:refs/*"},
}) })
if err != nil && err != git.NoErrAlreadyUpToDate { if err != nil && err != git.NoErrAlreadyUpToDate {
return err return errors.E(op, err)
} }
wt, err := repo.Worktree() wt, err := repo.Worktree()
if err != nil { if err != nil {
return err return errors.E(op, err)
} }
err = wt.Checkout(&git.CheckoutOptions{ err = wt.Checkout(&git.CheckoutOptions{
Branch: g.ReferenceName, Branch: g.ReferenceName,
}) })
if err != nil { if err != nil {
return err return errors.E(op, err)
} }
err = wt.Pull(&git.PullOptions{ err = wt.Pull(&git.PullOptions{
ReferenceName: g.ReferenceName, ReferenceName: g.ReferenceName,
Force: true, Force: true,
}) })
if err != nil && err != git.NoErrAlreadyUpToDate { if err != nil && err != git.NoErrAlreadyUpToDate {
return err return errors.E(op, err)
} }
err = wt.Reset(&git.ResetOptions{ err = wt.Reset(&git.ResetOptions{
Mode: git.HardReset, Mode: git.HardReset,
}) })
if err != nil { if err != nil {
return err return errors.E(op, err)
} }
return wt.Clean(&git.CleanOptions{ err = wt.Clean(&git.CleanOptions{
Dir: true, Dir: true,
}) })
if err != nil {
return errors.E(op, err)
}
return nil
} }

View File

@ -2,53 +2,79 @@ package util
import ( import (
"github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2"
"github.com/hasura/graphql-engine/cli/v2/internal/errors"
) )
func GetYesNoPrompt(message string) (promptResp bool, err error) { func GetYesNoPrompt(message string) (promptResp bool, err error) {
var op errors.Op = "util.GetYesNoPrompt"
prompt := &survey.Confirm{ prompt := &survey.Confirm{
Message: message, Message: message,
Default: true, Default: true,
} }
err = survey.AskOne(prompt, &promptResp) err = survey.AskOne(prompt, &promptResp)
return promptResp, err if err != nil {
return promptResp, errors.E(op, err)
}
return promptResp, nil
} }
func GetSelectPrompt(message string, options []string) (selection string, err error) { func GetSelectPrompt(message string, options []string) (selection string, err error) {
var op errors.Op = "util.GetSelectPrompt"
prompt := &survey.Select{ prompt := &survey.Select{
Message: message, Message: message,
Options: options, Options: options,
} }
err = survey.AskOne(prompt, &selection) err = survey.AskOne(prompt, &selection)
return selection, err if err != nil {
return selection, errors.E(op, err)
}
return selection, nil
} }
func GetInputPrompt(message string) (input string, err error) { func GetInputPrompt(message string) (input string, err error) {
var op errors.Op = "util.GetInputPrompt"
prompt := &survey.Input{ prompt := &survey.Input{
Message: message, Message: message,
} }
err = survey.AskOne(prompt, &input) err = survey.AskOne(prompt, &input)
return input, err if err != nil {
return input, errors.E(op, err)
}
return input, nil
} }
func GetInputPromptWithDefault(message string, def string) (input string, err error) { func GetInputPromptWithDefault(message string, def string) (input string, err error) {
var op errors.Op = "util.GetInputPromptWithDefault"
prompt := &survey.Input{ prompt := &survey.Input{
Message: message, Message: message,
Default: def, Default: def,
} }
err = survey.AskOne(prompt, &input) err = survey.AskOne(prompt, &input)
return input, err if err != nil {
return input, errors.E(op, err)
}
return input, nil
} }
func validateDirPath(a interface{}) error { func validateDirPath(a interface{}) error {
var op errors.Op = "util.validateDirPath"
err := FSCheckIfDirPathExists(a.(string)) err := FSCheckIfDirPathExists(a.(string))
return err if err != nil {
return errors.E(op, err)
}
return nil
} }
func GetFSPathPrompt(message string, def string) (input string, err error) { func GetFSPathPrompt(message string, def string) (input string, err error) {
var op errors.Op = "util.GetFSPathPrompt"
prompt := &survey.Input{ prompt := &survey.Input{
Message: message, Message: message,
Default: def, Default: def,
} }
err = survey.AskOne(prompt, &input, survey.WithValidator(validateDirPath)) err = survey.AskOne(prompt, &input, survey.WithValidator(validateDirPath))
return input, err if err != nil {
return input, errors.E(op, err)
}
return input, nil
} }

View File

@ -8,6 +8,7 @@ import (
"net/http" "net/http"
"github.com/hasura/graphql-engine/cli/v2/internal/httpc" "github.com/hasura/graphql-engine/cli/v2/internal/httpc"
"github.com/hasura/graphql-engine/cli/v2/internal/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -99,17 +100,18 @@ func GetServerState(client *httpc.Client, endpoint string, hasMetadataV3 bool, l
} }
func GetServerStatus(versionEndpoint string, httpClient *httpc.Client) (err error) { func GetServerStatus(versionEndpoint string, httpClient *httpc.Client) (err error) {
var op errors.Op = "util.GetServerStatus"
req, err := http.NewRequest("GET", versionEndpoint, nil) req, err := http.NewRequest("GET", versionEndpoint, nil)
if err != nil { if err != nil {
return fmt.Errorf("failed to create GET request to %s: %w", versionEndpoint, err) return errors.E(op, fmt.Errorf("failed to create GET request to %s: %w", versionEndpoint, err))
} }
var responseBs bytes.Buffer var responseBs bytes.Buffer
resp, err := httpClient.Do(context.Background(), req, &responseBs) resp, err := httpClient.Do(context.Background(), req, &responseBs)
if err != nil { if err != nil {
return fmt.Errorf("making http request failed: %w", err) return errors.E(op, fmt.Errorf("making http request failed: %w", err))
} }
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
return fmt.Errorf("request failed: url: %s status code: %v status: %s \n%s", versionEndpoint, resp.StatusCode, resp.Status, responseBs.String()) return errors.E(op, fmt.Errorf("request failed: url: %s status code: %v status: %s \n%s", versionEndpoint, resp.StatusCode, resp.Status, responseBs.String()))
} }
return nil return nil
} }

View File

@ -6,6 +6,8 @@ import (
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
"github.com/hasura/graphql-engine/cli/v2/internal/errors"
) )
// from https://gist.github.com/svett/424e6784facc0ba907ae // from https://gist.github.com/svett/424e6784facc0ba907ae
@ -13,20 +15,21 @@ import (
// Unzip unzips the archive to target. Both archive and target should be paths // Unzip unzips the archive to target. Both archive and target should be paths
// in the filesystem. target is created if it doesn't exist already. // in the filesystem. target is created if it doesn't exist already.
func Unzip(archive, target string) error { func Unzip(archive, target string) error {
var op errors.Op = "util.Unzip"
reader, err := zip.OpenReader(archive) reader, err := zip.OpenReader(archive)
if err != nil { if err != nil {
return err return errors.E(op, err)
} }
if err := os.MkdirAll(target, 0755); err != nil { if err := os.MkdirAll(target, 0755); err != nil {
return err return errors.E(op, err)
} }
for _, file := range reader.File { for _, file := range reader.File {
path := filepath.Join(target, file.Name) path := filepath.Join(target, file.Name)
if file.FileInfo().IsDir() { if file.FileInfo().IsDir() {
if err = os.MkdirAll(path, file.Mode()); err != nil { if err = os.MkdirAll(path, file.Mode()); err != nil {
return fmt.Errorf("error while creating directory and it's parent directories: %w", err) return errors.E(op, fmt.Errorf("error while creating directory and it's parent directories: %w", err))
} }
continue continue
} }
@ -38,7 +41,7 @@ func Unzip(archive, target string) error {
fileReader.Close() fileReader.Close()
} }
return err return errors.E(op, err)
} }
targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode()) targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
@ -49,14 +52,14 @@ func Unzip(archive, target string) error {
targetFile.Close() targetFile.Close()
} }
return err return errors.E(op, err)
} }
if _, err := io.Copy(targetFile, fileReader); err != nil { if _, err := io.Copy(targetFile, fileReader); err != nil {
fileReader.Close() fileReader.Close()
targetFile.Close() targetFile.Close()
return err return errors.E(op, err)
} }
fileReader.Close() fileReader.Close()