mirror of
https://github.com/hasura/graphql-engine.git
synced 2025-01-05 22:34:22 +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: support tracking partitioned tables (close #5071) (#5258)
|
||||||
- console: add button to cancel one-off scheduled events and cron-trigger events (close #5161) (#5236)
|
- 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)
|
- 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 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 1-click deployment to Nhost page to the deployment guides (#5180)
|
||||||
- docs: add hasura cloud to getting started section (close #5206) (#5208)
|
- 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/mgutz/ansi v0.0.0-20170206155736-9520e82c474b
|
||||||
github.com/microcosm-cc/bluemonday v1.0.2 // indirect
|
github.com/microcosm-cc/bluemonday v1.0.2 // indirect
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
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/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852
|
||||||
github.com/parnurzeal/gorequest v0.2.16
|
github.com/parnurzeal/gorequest v0.2.16
|
||||||
github.com/pkg/errors v0.8.1
|
github.com/pkg/errors v0.8.1
|
||||||
|
@ -5,6 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
|
||||||
"github.com/hasura/graphql-engine/cli/migrate/database"
|
"github.com/hasura/graphql-engine/cli/migrate/database"
|
||||||
|
|
||||||
"github.com/qor/transition"
|
"github.com/qor/transition"
|
||||||
@ -223,25 +225,25 @@ type HasuraError struct {
|
|||||||
// MigrationFile is used internally for hasuractl
|
// MigrationFile is used internally for hasuractl
|
||||||
migrationFile string
|
migrationFile string
|
||||||
migrationQuery string
|
migrationQuery string
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
ErrorMessage string `json:"error"`
|
ErrorMessage string `json:"error"`
|
||||||
Internal *SQLInternalError `json:"internal,omitempty"`
|
Internal interface{} `json:"internal,omitempty"`
|
||||||
Message string `json:"message,omitempty"`
|
Message string `json:"message,omitempty"`
|
||||||
Code string `json:"code"`
|
Code string `json:"code"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SQLInternalError struct {
|
type SQLInternalError struct {
|
||||||
Arguments []string `json:"arguments"`
|
Arguments []string `json:"arguments" mapstructure:"arguments,omitempty"`
|
||||||
Error PostgresError `json:"error"`
|
Error PostgresError `json:"error" mapstructure:"error,omitempty"`
|
||||||
Prepared bool `json:"prepared"`
|
Prepared bool `json:"prepared" mapstructure:"prepared,omitempty"`
|
||||||
Statement string `json:"statement"`
|
Statement string `json:"statement" mapstructure:"statement,omitempty"`
|
||||||
}
|
}
|
||||||
type PostgresError struct {
|
type PostgresError struct {
|
||||||
StatusCode string `json:"status_code"`
|
StatusCode string `json:"status_code" mapstructure:"status_code,omitempty"`
|
||||||
ExecStatus string `json:"exec_status"`
|
ExecStatus string `json:"exec_status" mapstructure:"exec_status,omitempty"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message" mapstructure:"message,omitempty"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description" mapstructure:"description,omitempty"`
|
||||||
Hint string `json:"hint"`
|
Hint string `json:"hint" mapstructure:"hint,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SchemaDump struct {
|
type SchemaDump struct {
|
||||||
@ -258,14 +260,34 @@ func (h HasuraError) Error() string {
|
|||||||
if h.migrationQuery != "" {
|
if h.migrationQuery != "" {
|
||||||
errorStrings = append(errorStrings, fmt.Sprintf("%s", h.migrationQuery))
|
errorStrings = append(errorStrings, fmt.Sprintf("%s", h.migrationQuery))
|
||||||
}
|
}
|
||||||
if h.Internal != nil {
|
var internalError SQLInternalError
|
||||||
// postgres error
|
var internalErrors []SQLInternalError
|
||||||
errorStrings = append(errorStrings, fmt.Sprintf("[%s] %s: %s", h.Internal.Error.StatusCode, h.Internal.Error.ExecStatus, h.Internal.Error.Message))
|
if v, ok := h.Internal.(map[string]interface{}); ok {
|
||||||
if len(h.Internal.Error.Description) > 0 {
|
err := mapstructure.Decode(v, &internalError)
|
||||||
errorStrings = append(errorStrings, fmt.Sprintf("Description: %s", h.Internal.Error.Description))
|
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")
|
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"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/hasura/graphql-engine/cli/plugins/download"
|
"github.com/hasura/graphql-engine/cli/plugins/download"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -145,7 +146,22 @@ func createOrUpdateLink(binDir, binary, plugin string) error {
|
|||||||
|
|
||||||
// Create new
|
// Create new
|
||||||
if err := os.Symlink(binary, dst); err != nil {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@ -159,7 +175,7 @@ func removeLink(path string) error {
|
|||||||
return errors.Wrapf(err, "failed to read the symlink in %q", path)
|
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())
|
return errors.Errorf("file %q is not a symlink (mode=%s)", path, fi.Mode())
|
||||||
}
|
}
|
||||||
if err := os.Remove(path); err != nil {
|
if err := os.Remove(path); err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user