mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-13 19:33:55 +03:00
cli: fix permission issues when creating symlinks on windows, misc fix (close #5111, close #4879) (#5164)
This commit is contained in:
parent
9ef6de5113
commit
cd0e2ec8e8
@ -16,6 +16,7 @@
|
||||
- console: support tracking partitioned tables (close #5071) (#5258)
|
||||
- console: add button to cancel one-off scheduled events and cron-trigger events (close #5161) (#5236)
|
||||
- console: handle generated and identity columns in console data section (close #4552, #4863) (#4761)
|
||||
- cli: fix plugins install failing due to permission issues on windows (close #5111)
|
||||
- docs: add note for managed databases in postgres requirements (close #1677, #3783) (#5228)
|
||||
- docs: add 1-click deployment to Nhost page to the deployment guides (#5180)
|
||||
- docs: add hasura cloud to getting started section (close #5206) (#5208)
|
||||
|
@ -30,6 +30,7 @@ require (
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b
|
||||
github.com/microcosm-cc/bluemonday v1.0.2 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/mitchellh/mapstructure v1.1.2
|
||||
github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852
|
||||
github.com/parnurzeal/gorequest v0.2.16
|
||||
github.com/pkg/errors v0.8.1
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
|
||||
"github.com/hasura/graphql-engine/cli/migrate/database"
|
||||
|
||||
"github.com/qor/transition"
|
||||
@ -223,25 +225,25 @@ type HasuraError struct {
|
||||
// MigrationFile is used internally for hasuractl
|
||||
migrationFile string
|
||||
migrationQuery string
|
||||
Path string `json:"path"`
|
||||
ErrorMessage string `json:"error"`
|
||||
Internal *SQLInternalError `json:"internal,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Code string `json:"code"`
|
||||
Path string `json:"path"`
|
||||
ErrorMessage string `json:"error"`
|
||||
Internal interface{} `json:"internal,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Code string `json:"code"`
|
||||
}
|
||||
|
||||
type SQLInternalError struct {
|
||||
Arguments []string `json:"arguments"`
|
||||
Error PostgresError `json:"error"`
|
||||
Prepared bool `json:"prepared"`
|
||||
Statement string `json:"statement"`
|
||||
Arguments []string `json:"arguments" mapstructure:"arguments,omitempty"`
|
||||
Error PostgresError `json:"error" mapstructure:"error,omitempty"`
|
||||
Prepared bool `json:"prepared" mapstructure:"prepared,omitempty"`
|
||||
Statement string `json:"statement" mapstructure:"statement,omitempty"`
|
||||
}
|
||||
type PostgresError struct {
|
||||
StatusCode string `json:"status_code"`
|
||||
ExecStatus string `json:"exec_status"`
|
||||
Message string `json:"message"`
|
||||
Description string `json:"description"`
|
||||
Hint string `json:"hint"`
|
||||
StatusCode string `json:"status_code" mapstructure:"status_code,omitempty"`
|
||||
ExecStatus string `json:"exec_status" mapstructure:"exec_status,omitempty"`
|
||||
Message string `json:"message" mapstructure:"message,omitempty"`
|
||||
Description string `json:"description" mapstructure:"description,omitempty"`
|
||||
Hint string `json:"hint" mapstructure:"hint,omitempty"`
|
||||
}
|
||||
|
||||
type SchemaDump struct {
|
||||
@ -258,14 +260,34 @@ func (h HasuraError) Error() string {
|
||||
if h.migrationQuery != "" {
|
||||
errorStrings = append(errorStrings, fmt.Sprintf("%s", h.migrationQuery))
|
||||
}
|
||||
if h.Internal != nil {
|
||||
// postgres error
|
||||
errorStrings = append(errorStrings, fmt.Sprintf("[%s] %s: %s", h.Internal.Error.StatusCode, h.Internal.Error.ExecStatus, h.Internal.Error.Message))
|
||||
if len(h.Internal.Error.Description) > 0 {
|
||||
errorStrings = append(errorStrings, fmt.Sprintf("Description: %s", h.Internal.Error.Description))
|
||||
var internalError SQLInternalError
|
||||
var internalErrors []SQLInternalError
|
||||
if v, ok := h.Internal.(map[string]interface{}); ok {
|
||||
err := mapstructure.Decode(v, &internalError)
|
||||
if err == nil {
|
||||
// postgres error
|
||||
errorStrings = append(errorStrings, fmt.Sprintf("[%s] %s: %s", internalError.Error.StatusCode, internalError.Error.ExecStatus, internalError.Error.Message))
|
||||
if len(internalError.Error.Description) > 0 {
|
||||
errorStrings = append(errorStrings, fmt.Sprintf("Description: %s", internalError.Error.Description))
|
||||
}
|
||||
if len(internalError.Error.Hint) > 0 {
|
||||
errorStrings = append(errorStrings, fmt.Sprintf("Hint: %s", internalError.Error.Hint))
|
||||
}
|
||||
}
|
||||
if len(h.Internal.Error.Hint) > 0 {
|
||||
errorStrings = append(errorStrings, fmt.Sprintf("Hint: %s", h.Internal.Error.Hint))
|
||||
}
|
||||
if v, ok := h.Internal.([]interface{}); ok {
|
||||
err := mapstructure.Decode(v, &internalErrors)
|
||||
if err == nil {
|
||||
for _, internalError := range internalErrors {
|
||||
// postgres error
|
||||
errorStrings = append(errorStrings, fmt.Sprintf("[%s] %s: %s", internalError.Error.StatusCode, internalError.Error.ExecStatus, internalError.Error.Message))
|
||||
if len(internalError.Error.Description) > 0 {
|
||||
errorStrings = append(errorStrings, fmt.Sprintf("Description: %s", internalError.Error.Description))
|
||||
}
|
||||
if len(internalError.Error.Hint) > 0 {
|
||||
errorStrings = append(errorStrings, fmt.Sprintf("Hint: %s", internalError.Error.Hint))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return strings.Join(errorStrings, "\r\n")
|
||||
|
74
cli/migrate/database/hasuradb/types_test.go
Normal file
74
cli/migrate/database/hasuradb/types_test.go
Normal file
@ -0,0 +1,74 @@
|
||||
package hasuradb
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHasuraError_Error(t *testing.T) {
|
||||
type fields struct {
|
||||
migrationFile string
|
||||
migrationQuery string
|
||||
Path string
|
||||
ErrorMessage string
|
||||
Internal interface{}
|
||||
Message string
|
||||
Code string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want string
|
||||
}{
|
||||
{
|
||||
"can unmarshal internal error",
|
||||
fields{
|
||||
Internal: func() interface{} {
|
||||
d := []byte(`
|
||||
{
|
||||
"error": {
|
||||
"status_code": "1"
|
||||
}
|
||||
}`)
|
||||
var v interface{}
|
||||
json.Unmarshal(d, &v)
|
||||
return v
|
||||
}(),
|
||||
},
|
||||
"[] ()\r\n[1] : ",
|
||||
},
|
||||
{
|
||||
"can unmarshal internal errors",
|
||||
fields{
|
||||
Internal: func() interface{} {
|
||||
d := []byte(`
|
||||
[{
|
||||
"error": {
|
||||
"status_code": "2"
|
||||
}
|
||||
}]`)
|
||||
var v interface{}
|
||||
json.Unmarshal(d, &v)
|
||||
return v
|
||||
}(),
|
||||
},
|
||||
"[] ()\r\n[2] : ",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
h := HasuraError{
|
||||
migrationFile: tt.fields.migrationFile,
|
||||
migrationQuery: tt.fields.migrationQuery,
|
||||
Path: tt.fields.Path,
|
||||
ErrorMessage: tt.fields.ErrorMessage,
|
||||
Internal: tt.fields.Internal,
|
||||
Message: tt.fields.Message,
|
||||
Code: tt.fields.Code,
|
||||
}
|
||||
if got := h.Error(); got != tt.want {
|
||||
t.Errorf("Error() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@ import (
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/hasura/graphql-engine/cli/plugins/download"
|
||||
"github.com/pkg/errors"
|
||||
@ -145,7 +146,22 @@ func createOrUpdateLink(binDir, binary, plugin string) error {
|
||||
|
||||
// Create new
|
||||
if err := os.Symlink(binary, dst); err != nil {
|
||||
return errors.Wrapf(err, "failed to create a symlink from %q to %q", binary, dst)
|
||||
if IsWindows() {
|
||||
// If cloning the symlink fails on Windows because the user
|
||||
// does not have the required privileges, ignore the error and
|
||||
// fall back to copying the file contents.
|
||||
//
|
||||
// ERROR_PRIVILEGE_NOT_HELD is 1314 (0x522):
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms681385(v=vs.85).aspx
|
||||
if lerr, ok := err.(*os.LinkError); ok && lerr.Err != syscall.Errno(1314) {
|
||||
return err
|
||||
}
|
||||
if err := copyFile(binary, dst, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return errors.Wrapf(err, "failed to create a symlink from %q to %q", binary, dst)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -159,7 +175,7 @@ func removeLink(path string) error {
|
||||
return errors.Wrapf(err, "failed to read the symlink in %q", path)
|
||||
}
|
||||
|
||||
if fi.Mode()&os.ModeSymlink == 0 {
|
||||
if fi.Mode()&os.ModeSymlink == 0 && !IsWindows() {
|
||||
return errors.Errorf("file %q is not a symlink (mode=%s)", path, fi.Mode())
|
||||
}
|
||||
if err := os.Remove(path); err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user