mirror of
https://github.com/minio/mc.git
synced 2025-11-12 01:02:26 +03:00
Refactoring console printing style, supports --json even for error messages now - fixes #418
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -31,42 +32,51 @@ func runAccessCmd(ctx *cli.Context) {
|
|||||||
cli.ShowCommandHelpAndExit(ctx, "access", 1) // last argument is exit code
|
cli.ShowCommandHelpAndExit(ctx, "access", 1) // last argument is exit code
|
||||||
}
|
}
|
||||||
if !isMcConfigExist() {
|
if !isMcConfigExist() {
|
||||||
console.Fatalln("\"mc\" is not configured. Please run \"mc config generate\".")
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: "Please run \"mc config generate\"",
|
||||||
|
Error: iodine.New(errors.New("\"mc\" is not configured"), nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
config, err := getMcConfig()
|
config, err := getMcConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Fatalf("loading config file failed with following reason: [%s]\n", iodine.ToError(err))
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: "loading config file failed",
|
||||||
|
Error: iodine.New(err, nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
targetURLConfigMap := make(map[string]*hostConfig)
|
targetURLConfigMap := make(map[string]*hostConfig)
|
||||||
targetURLs, err := getExpandedURLs(ctx.Args(), config.Aliases)
|
targetURLs, err := getExpandedURLs(ctx.Args(), config.Aliases)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch e := iodine.ToError(err).(type) {
|
console.Fatalln(console.ErrorMessage{
|
||||||
case errUnsupportedScheme:
|
Message: "Unknown type of URL ",
|
||||||
console.Fatalf("Unknown type of URL ‘%s’. Reason: %s.\n", e.url, e)
|
Error: iodine.New(err, nil),
|
||||||
default:
|
})
|
||||||
console.Fatalf("reading URLs failed with following Reason: %s\n", e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
acl := bucketACL(ctx.Args().First())
|
acl := bucketACL(ctx.Args().First())
|
||||||
if !acl.isValidBucketACL() {
|
if !acl.isValidBucketACL() {
|
||||||
console.Fatalf("Access type ‘%s’ is not supported. Valid types are [private, public, readonly].\n", acl)
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: "Valid types are [private, public, readonly].",
|
||||||
|
Error: iodine.New(errors.New("Invalid ACL Type ‘"+acl.String()+"’"), nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
targetURLs = targetURLs[1:] // 1 or more target URLs
|
targetURLs = targetURLs[1:] // 1 or more target URLs
|
||||||
for _, targetURL := range targetURLs {
|
for _, targetURL := range targetURLs {
|
||||||
targetConfig, err := getHostConfig(targetURL)
|
targetConfig, err := getHostConfig(targetURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Fatalf("Unable to read configuration for host ‘%s’. Reason: %s.\n", targetURL, iodine.ToError(err))
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: "Unable to read configuration for host " + "‘" + targetURL + "’",
|
||||||
|
Error: iodine.New(err, nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
targetURLConfigMap[targetURL] = targetConfig
|
targetURLConfigMap[targetURL] = targetConfig
|
||||||
}
|
}
|
||||||
for targetURL, targetConfig := range targetURLConfigMap {
|
for targetURL, targetConfig := range targetURLConfigMap {
|
||||||
errorMsg, err := doUpdateAccessCmd(targetURL, acl.String(), targetConfig)
|
errorMsg, err := doUpdateAccessCmd(targetURL, acl.String(), targetConfig)
|
||||||
err = iodine.New(err, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errorMsg == "" {
|
console.Errorln(console.ErrorMessage{
|
||||||
errorMsg = "Empty error message. Please rerun this command with --debug and file a bug report."
|
Message: errorMsg,
|
||||||
}
|
Error: iodine.New(err, nil),
|
||||||
console.Errorf("%s", errorMsg)
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,10 +86,8 @@ func doUpdateAccessCmd(targetURL, targetACL string, targetConfig *hostConfig) (s
|
|||||||
var clnt client.Client
|
var clnt client.Client
|
||||||
clnt, err = getNewClient(targetURL, targetConfig)
|
clnt, err = getNewClient(targetURL, targetConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := iodine.New(err, nil)
|
msg := fmt.Sprintf("Unable to initialize client for ‘%s’", targetURL)
|
||||||
msg := fmt.Sprintf("Unable to initialize client for ‘%s’. Reason: %s.\n",
|
return msg, iodine.New(err, nil)
|
||||||
targetURL, iodine.ToError(err))
|
|
||||||
return msg, err
|
|
||||||
}
|
}
|
||||||
return doUpdateAccess(clnt, targetURL, targetACL)
|
return doUpdateAccess(clnt, targetURL, targetACL)
|
||||||
}
|
}
|
||||||
@@ -87,15 +95,14 @@ func doUpdateAccessCmd(targetURL, targetACL string, targetConfig *hostConfig) (s
|
|||||||
func doUpdateAccess(clnt client.Client, targetURL, targetACL string) (string, error) {
|
func doUpdateAccess(clnt client.Client, targetURL, targetACL string) (string, error) {
|
||||||
err := clnt.SetBucketACL(targetACL)
|
err := clnt.SetBucketACL(targetACL)
|
||||||
for i := 0; i < globalMaxRetryFlag && err != nil && isValidRetry(err); i++ {
|
for i := 0; i < globalMaxRetryFlag && err != nil && isValidRetry(err); i++ {
|
||||||
fmt.Println(console.Retry("Retrying ... %d", i))
|
console.Retry("Retrying ...", i)
|
||||||
// Progressively longer delays
|
// Progressively longer delays
|
||||||
time.Sleep(time.Duration(i*i) * time.Second)
|
time.Sleep(time.Duration(i*i) * time.Second)
|
||||||
err = clnt.SetBucketACL(targetACL)
|
err = clnt.SetBucketACL(targetACL)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := iodine.New(err, nil)
|
msg := fmt.Sprintf("Failed to add bucket access policy for URL ‘%s’", targetURL)
|
||||||
msg := fmt.Sprintf("Failed to add bucket access policy for URL ‘%s’. Reason: %s.\n", targetURL, iodine.ToError(err))
|
return msg, iodine.New(err, nil)
|
||||||
return msg, err
|
|
||||||
}
|
}
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|||||||
32
cmd-cat.go
32
cmd-cat.go
@@ -18,6 +18,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
@@ -31,33 +32,42 @@ func runCatCmd(ctx *cli.Context) {
|
|||||||
cli.ShowCommandHelpAndExit(ctx, "cat", 1) // last argument is exit code
|
cli.ShowCommandHelpAndExit(ctx, "cat", 1) // last argument is exit code
|
||||||
}
|
}
|
||||||
if !isMcConfigExist() {
|
if !isMcConfigExist() {
|
||||||
console.Fatalln("\"mc\" is not configured. Please run \"mc config generate\".")
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: "Please run \"mc config generate\"",
|
||||||
|
Error: iodine.New(errors.New("\"mc\" is not configured"), nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
config, err := getMcConfig()
|
config, err := getMcConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Fatalf("Unable to read config file ‘%s’. Reason: %s.\n", mustGetMcConfigPath(), iodine.ToError(err))
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: fmt.Sprintf("Unable to read config file ‘%s’", mustGetMcConfigPath()),
|
||||||
|
Error: iodine.New(err, nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert arguments to URLs: expand alias, fix format...
|
// Convert arguments to URLs: expand alias, fix format...
|
||||||
urls, err := getExpandedURLs(ctx.Args(), config.Aliases)
|
urls, err := getExpandedURLs(ctx.Args(), config.Aliases)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch e := iodine.ToError(err).(type) {
|
console.Fatalln(console.ErrorMessage{
|
||||||
case errUnsupportedScheme:
|
Message: fmt.Sprintf("Unknown type of URL ‘%s’", urls),
|
||||||
console.Fatalf("Unknown type of URL ‘%s’. Reason: %s.\n", e.url, e)
|
Error: iodine.New(err, nil),
|
||||||
default:
|
})
|
||||||
console.Fatalf("Unable to parse arguments. Reason: %s.\n", iodine.ToError(err))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceURLs := urls
|
sourceURLs := urls
|
||||||
sourceURLConfigMap, err := getHostConfigs(sourceURLs)
|
sourceURLConfigMap, err := getHostConfigs(sourceURLs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Fatalf("Unable to read host configuration for ‘%s’ from config file ‘%s’. Reason: %s.\n",
|
console.Fatalln(console.ErrorMessage{
|
||||||
sourceURLs, mustGetMcConfigPath(), iodine.ToError(err))
|
Message: fmt.Sprintf("Unable to read host configuration for ‘%s’ from config file ‘%s’", sourceURLs, mustGetMcConfigPath()),
|
||||||
|
Error: iodine.New(err, nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
humanReadable, err := doCatCmd(sourceURLConfigMap)
|
humanReadable, err := doCatCmd(sourceURLConfigMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Fatalln(humanReadable)
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: humanReadable,
|
||||||
|
Error: iodine.New(err, nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,13 +34,19 @@ func runConfigCmd(ctx *cli.Context) {
|
|||||||
arg := ctx.Args().First()
|
arg := ctx.Args().First()
|
||||||
tailArgs := ctx.Args().Tail()
|
tailArgs := ctx.Args().Tail()
|
||||||
if len(tailArgs) > 2 {
|
if len(tailArgs) > 2 {
|
||||||
console.Fatalln("Incorrect number of arguments, please use \"mc config help\"")
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: "Incorrect number of arguments, please use \"mc config help\"",
|
||||||
|
Error: iodine.New(errInvalidArgument{}, nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
msg, err := doConfig(arg, tailArgs)
|
msg, err := doConfig(arg, tailArgs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Fatalln(msg)
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: msg,
|
||||||
|
Error: err,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
console.Infoln(msg)
|
console.Infoln(console.Message(msg))
|
||||||
}
|
}
|
||||||
|
|
||||||
// saveConfig writes configuration data in json format to config file.
|
// saveConfig writes configuration data in json format to config file.
|
||||||
|
|||||||
21
cmd-cp.go
21
cmd-cp.go
@@ -17,6 +17,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -33,7 +35,7 @@ func doCopy(sourceURL string, sourceConfig *hostConfig, targetURL string, target
|
|||||||
}
|
}
|
||||||
switch globalQuietFlag {
|
switch globalQuietFlag {
|
||||||
case true:
|
case true:
|
||||||
console.Infof("‘%s’ -> ‘%s’\n", sourceURL, targetURL)
|
console.Infoln(console.Message(fmt.Sprintf("‘%s’ -> ‘%s’", sourceURL, targetURL)))
|
||||||
default:
|
default:
|
||||||
// set up progress
|
// set up progress
|
||||||
reader = bar.NewProxyReader(reader)
|
reader = bar.NewProxyReader(reader)
|
||||||
@@ -117,13 +119,21 @@ func runCopyCmd(ctx *cli.Context) {
|
|||||||
if len(ctx.Args()) < 2 || ctx.Args().First() == "help" {
|
if len(ctx.Args()) < 2 || ctx.Args().First() == "help" {
|
||||||
cli.ShowCommandHelpAndExit(ctx, "cp", 1) // last argument is exit code
|
cli.ShowCommandHelpAndExit(ctx, "cp", 1) // last argument is exit code
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isMcConfigExist() {
|
if !isMcConfigExist() {
|
||||||
console.Fatalln("\"mc\" is not configured. Please run \"mc config generate\".")
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: "Please run \"mc config generate\"",
|
||||||
|
Error: iodine.New(errors.New("\"mc\" is not configured"), nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract URLs.
|
// extract URLs.
|
||||||
URLs, err := args2URLs(ctx.Args())
|
URLs, err := args2URLs(ctx.Args())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Fatalln(iodine.ToError(err))
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: fmt.Sprintf("Unknown URL types: ‘%s’", URLs),
|
||||||
|
Error: iodine.New(err, nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Separate source and target. 'cp' can take only one target,
|
// Separate source and target. 'cp' can take only one target,
|
||||||
@@ -138,7 +148,10 @@ func runCopyCmd(ctx *cli.Context) {
|
|||||||
}
|
}
|
||||||
for err := range doCopyCmd(sourceURLs, targetURL, bar) {
|
for err := range doCopyCmd(sourceURLs, targetURL, bar) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Errorln(iodine.ToError(err))
|
console.Errorln(console.ErrorMessage{
|
||||||
|
Message: "Failed with",
|
||||||
|
Error: iodine.New(err, nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !globalQuietFlag {
|
if !globalQuietFlag {
|
||||||
|
|||||||
52
cmd-diff.go
52
cmd-diff.go
@@ -17,6 +17,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/minio/cli"
|
"github.com/minio/cli"
|
||||||
"github.com/minio/mc/pkg/console"
|
"github.com/minio/mc/pkg/console"
|
||||||
"github.com/minio/minio/pkg/iodine"
|
"github.com/minio/minio/pkg/iodine"
|
||||||
@@ -28,11 +31,17 @@ func runDiffCmd(ctx *cli.Context) {
|
|||||||
cli.ShowCommandHelpAndExit(ctx, "diff", 1) // last argument is exit code
|
cli.ShowCommandHelpAndExit(ctx, "diff", 1) // last argument is exit code
|
||||||
}
|
}
|
||||||
if !isMcConfigExist() {
|
if !isMcConfigExist() {
|
||||||
console.Fatalln("\"mc\" is not configured. Please run \"mc config generate\".")
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: "Please run \"mc config generate\"",
|
||||||
|
Error: iodine.New(errors.New("\"mc\" is not configured"), nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
config, err := getMcConfig()
|
config, err := getMcConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Fatalf("Unable to read config file ‘%s’. Reason: %s.\n", mustGetMcConfigPath(), iodine.ToError(err))
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: fmt.Sprintf("Unable to read config file ‘%s’", mustGetMcConfigPath()),
|
||||||
|
Error: err,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
firstURL := ctx.Args().First()
|
firstURL := ctx.Args().First()
|
||||||
@@ -42,40 +51,59 @@ func runDiffCmd(ctx *cli.Context) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
switch iodine.ToError(err).(type) {
|
switch iodine.ToError(err).(type) {
|
||||||
case errUnsupportedScheme:
|
case errUnsupportedScheme:
|
||||||
console.Fatalf("Unknown type of URL ‘%s’.\n", firstURL)
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: fmt.Sprintf("Unknown type of URL ‘%s’.", firstURL),
|
||||||
|
Error: err,
|
||||||
|
})
|
||||||
default:
|
default:
|
||||||
console.Fatalf("Unable to parse argument ‘%s’. Reason: %s.\n", firstURL, iodine.ToError(err))
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: fmt.Sprintf("Unable to parse argument ‘%s’.", firstURL),
|
||||||
|
Error: err,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = getHostConfig(firstURL)
|
_, err = getHostConfig(firstURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Fatalf("Unable to read host configuration for ‘%s’ from config file ‘%s’. Reason: %s.\n",
|
console.Fatalln(console.ErrorMessage{
|
||||||
firstURL, mustGetMcConfigPath(), iodine.ToError(err))
|
Message: fmt.Sprintf("Unable to read host configuration for ‘%s’ from config file ‘%s’.", firstURL, mustGetMcConfigPath()),
|
||||||
|
Error: err,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = getHostConfig(secondURL)
|
_, err = getHostConfig(secondURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Fatalf("Unable to read host configuration for ‘%s’ from config file ‘%s’. Reason: %s.\n",
|
console.Fatalln(console.ErrorMessage{
|
||||||
secondURL, mustGetMcConfigPath(), iodine.ToError(err))
|
Message: fmt.Sprintf("Unable to read host configuration for ‘%s’ from config file ‘%s’. Reason: %s.", secondURL, mustGetMcConfigPath()),
|
||||||
|
Error: err,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
secondURL, err = getExpandedURL(secondURL, config.Aliases)
|
secondURL, err = getExpandedURL(secondURL, config.Aliases)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch iodine.ToError(err).(type) {
|
switch iodine.ToError(err).(type) {
|
||||||
case errUnsupportedScheme:
|
case errUnsupportedScheme:
|
||||||
console.Fatalf("Unknown type of URL ‘%s’. Reason: %s.\n", secondURL, iodine.ToError(err))
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: fmt.Sprintf("Unknown type of URL ‘%s’.", secondURL),
|
||||||
|
Error: err,
|
||||||
|
})
|
||||||
default:
|
default:
|
||||||
console.Fatalf("Unable to parse argument ‘%s’. Reason: %s.\n", secondURL, iodine.ToError(err))
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: fmt.Sprintf("Unable to parse argument ‘%s’.", secondURL),
|
||||||
|
Error: err,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO recursive is not working yet
|
// TODO recursive is not working yet
|
||||||
newFirstURL := stripRecursiveURL(firstURL)
|
newFirstURL := stripRecursiveURL(firstURL)
|
||||||
for diff := range doDiffCmd(newFirstURL, secondURL, isURLRecursive(firstURL)) {
|
for diff := range doDiffCmd(newFirstURL, secondURL, isURLRecursive(firstURL)) {
|
||||||
if diff.err != nil {
|
if diff.err != nil {
|
||||||
console.Fatalln(diff.message)
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: diff.message,
|
||||||
|
Error: diff.err,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
console.Infoln(diff.message)
|
console.Infoln(console.Message(diff.message))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
37
cmd-ls.go
37
cmd-ls.go
@@ -17,6 +17,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/minio/cli"
|
"github.com/minio/cli"
|
||||||
"github.com/minio/mc/pkg/console"
|
"github.com/minio/mc/pkg/console"
|
||||||
"github.com/minio/minio/pkg/iodine"
|
"github.com/minio/minio/pkg/iodine"
|
||||||
@@ -27,12 +30,20 @@ func runListCmd(ctx *cli.Context) {
|
|||||||
if !ctx.Args().Present() || ctx.Args().First() == "help" {
|
if !ctx.Args().Present() || ctx.Args().First() == "help" {
|
||||||
cli.ShowCommandHelpAndExit(ctx, "ls", 1) // last argument is exit code
|
cli.ShowCommandHelpAndExit(ctx, "ls", 1) // last argument is exit code
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isMcConfigExist() {
|
if !isMcConfigExist() {
|
||||||
console.Fatalln("\"mc\" is not configured. Please run \"mc config generate\".")
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: "Please run \"mc config generate\"",
|
||||||
|
Error: iodine.New(errors.New("\"mc\" is not configured"), nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
config, err := getMcConfig()
|
config, err := getMcConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Fatalf("Unable to read config file ‘%s’. Reason: %s.\n", mustGetMcConfigPath(), iodine.ToError(err))
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: fmt.Sprintf("Unable to read config file ‘%s’", mustGetMcConfigPath()),
|
||||||
|
Error: iodine.New(err, nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
targetURLConfigMap := make(map[string]*hostConfig)
|
targetURLConfigMap := make(map[string]*hostConfig)
|
||||||
for _, arg := range ctx.Args() {
|
for _, arg := range ctx.Args() {
|
||||||
@@ -40,15 +51,23 @@ func runListCmd(ctx *cli.Context) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
switch e := iodine.ToError(err).(type) {
|
switch e := iodine.ToError(err).(type) {
|
||||||
case errUnsupportedScheme:
|
case errUnsupportedScheme:
|
||||||
console.Fatalf("Unknown type of URL ‘%s’. Reason: %s.\n", e.url, e)
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: fmt.Sprintf("Unknown type of URL ‘%s’", e.url),
|
||||||
|
Error: iodine.New(e, nil),
|
||||||
|
})
|
||||||
default:
|
default:
|
||||||
console.Fatalf("Unable to parse argument ‘%s’. Reason: %s.\n", arg, iodine.ToError(err))
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: fmt.Sprintf("Unable to parse argument ‘%s’", arg),
|
||||||
|
Error: iodine.New(err, nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
targetConfig, err := getHostConfig(targetURL)
|
targetConfig, err := getHostConfig(targetURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Fatalf("Unable to read host configuration for ‘%s’ from config file ‘%s’. Reason: %s.\n",
|
console.Fatalln(console.ErrorMessage{
|
||||||
targetURL, mustGetMcConfigPath(), iodine.ToError(err))
|
Message: fmt.Sprintf("Unable to read host configuration for ‘%s’ from config file ‘%s’", targetURL, mustGetMcConfigPath()),
|
||||||
|
Error: iodine.New(err, nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
targetURLConfigMap[targetURL] = targetConfig
|
targetURLConfigMap[targetURL] = targetConfig
|
||||||
}
|
}
|
||||||
@@ -56,9 +75,11 @@ func runListCmd(ctx *cli.Context) {
|
|||||||
// if recursive strip off the "..."
|
// if recursive strip off the "..."
|
||||||
newTargetURL := stripRecursiveURL(targetURL)
|
newTargetURL := stripRecursiveURL(targetURL)
|
||||||
err = doListCmd(newTargetURL, targetConfig, isURLRecursive(targetURL))
|
err = doListCmd(newTargetURL, targetConfig, isURLRecursive(targetURL))
|
||||||
err = iodine.New(err, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Fatalf("Failed to list ‘%s’. Reason: %s.\n", targetURL, iodine.ToError(err))
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: fmt.Sprintf("Failed to list ‘%s’", targetURL),
|
||||||
|
Error: iodine.New(err, nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
62
cmd-mb.go
62
cmd-mb.go
@@ -17,6 +17,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -32,37 +33,51 @@ func runMakeBucketCmd(ctx *cli.Context) {
|
|||||||
cli.ShowCommandHelpAndExit(ctx, "mb", 1) // last argument is exit code
|
cli.ShowCommandHelpAndExit(ctx, "mb", 1) // last argument is exit code
|
||||||
}
|
}
|
||||||
if !isMcConfigExist() {
|
if !isMcConfigExist() {
|
||||||
console.Fatalln("\"mc\" is not configured. Please run \"mc config generate\".")
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: "Please run \"mc config generate\"",
|
||||||
|
Error: errors.New("\"mc\" is not configured"),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
config, err := getMcConfig()
|
config, err := getMcConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Fatalf("Unable to read config file ‘%s’. Reason: %s\n", mustGetMcConfigPath(), iodine.ToError(err))
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: "Unable to read config file ‘" + mustGetMcConfigPath() + "’",
|
||||||
|
Error: err,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
targetURLConfigMap := make(map[string]*hostConfig)
|
targetURLConfigMap := make(map[string]*hostConfig)
|
||||||
targetURLs, err := getExpandedURLs(ctx.Args(), config.Aliases)
|
for _, arg := range ctx.Args() {
|
||||||
if err != nil {
|
targetURL, err := getExpandedURL(arg, config.Aliases)
|
||||||
switch e := iodine.ToError(err).(type) {
|
if err != nil {
|
||||||
case errUnsupportedScheme:
|
switch e := iodine.ToError(err).(type) {
|
||||||
console.Fatalf("Unknown URL type ‘%s’ passed. Reason: %s.\n", e.url, e)
|
case errUnsupportedScheme:
|
||||||
default:
|
console.Fatalln(console.ErrorMessage{
|
||||||
console.Fatalf("Error in parsing path or URL. Reason: %s.\n", e)
|
Message: fmt.Sprintf("Unknown type of URL ‘%s’", e.url),
|
||||||
|
Error: e,
|
||||||
|
})
|
||||||
|
default:
|
||||||
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: fmt.Sprintf("Unable to parse argument ‘%s’", arg),
|
||||||
|
Error: err,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
for _, targetURL := range targetURLs {
|
|
||||||
targetConfig, err := getHostConfig(targetURL)
|
targetConfig, err := getHostConfig(targetURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Fatalf("Unable to read configuration for host ‘%s’. Reason: %s.\n", targetURL, iodine.ToError(err))
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: fmt.Sprintf("Unable to read host configuration for ‘%s’ from config file ‘%s’", targetURL, mustGetMcConfigPath()),
|
||||||
|
Error: err,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
targetURLConfigMap[targetURL] = targetConfig
|
targetURLConfigMap[targetURL] = targetConfig
|
||||||
}
|
}
|
||||||
for targetURL, targetConfig := range targetURLConfigMap {
|
for targetURL, targetConfig := range targetURLConfigMap {
|
||||||
errorMsg, err := doMakeBucketCmd(targetURL, targetConfig)
|
errorMsg, err := doMakeBucketCmd(targetURL, targetConfig)
|
||||||
err = iodine.New(err, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errorMsg == "" {
|
console.Errorln(console.ErrorMessage{
|
||||||
errorMsg = "Empty error message. Please rerun this command with --debug and file a bug report."
|
Message: errorMsg,
|
||||||
}
|
Error: err,
|
||||||
console.Errorf("%s", errorMsg)
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,10 +88,8 @@ func doMakeBucketCmd(targetURL string, targetConfig *hostConfig) (string, error)
|
|||||||
var clnt client.Client
|
var clnt client.Client
|
||||||
clnt, err = getNewClient(targetURL, targetConfig)
|
clnt, err = getNewClient(targetURL, targetConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := iodine.New(err, nil)
|
msg := fmt.Sprintf("Unable to initialize client for ‘%s’", targetURL)
|
||||||
msg := fmt.Sprintf("Unable to initialize client for ‘%s’. Reason: %s.\n",
|
return msg, iodine.New(err, nil)
|
||||||
targetURL, iodine.ToError(err))
|
|
||||||
return msg, err
|
|
||||||
}
|
}
|
||||||
return doMakeBucket(clnt, targetURL)
|
return doMakeBucket(clnt, targetURL)
|
||||||
}
|
}
|
||||||
@@ -85,15 +98,14 @@ func doMakeBucketCmd(targetURL string, targetConfig *hostConfig) (string, error)
|
|||||||
func doMakeBucket(clnt client.Client, targetURL string) (string, error) {
|
func doMakeBucket(clnt client.Client, targetURL string) (string, error) {
|
||||||
err := clnt.MakeBucket()
|
err := clnt.MakeBucket()
|
||||||
for i := 0; i < globalMaxRetryFlag && err != nil && isValidRetry(err); i++ {
|
for i := 0; i < globalMaxRetryFlag && err != nil && isValidRetry(err); i++ {
|
||||||
fmt.Println(console.Retry("Retrying ... %d", i))
|
console.Retry("Retrying ...", i)
|
||||||
// Progressively longer delays
|
// Progressively longer delays
|
||||||
time.Sleep(time.Duration(i*i) * time.Second)
|
time.Sleep(time.Duration(i*i) * time.Second)
|
||||||
err = clnt.MakeBucket()
|
err = clnt.MakeBucket()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := iodine.New(err, nil)
|
msg := fmt.Sprintf("Failed to create bucket for URL ‘%s’", targetURL)
|
||||||
msg := fmt.Sprintf("Failed to create bucket for URL ‘%s’. Reason: %s.\n", targetURL, iodine.ToError(err))
|
return msg, iodine.New(err, nil)
|
||||||
return msg, err
|
|
||||||
}
|
}
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|||||||
34
cmd-sync.go
34
cmd-sync.go
@@ -17,6 +17,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -29,12 +31,20 @@ func runSyncCmd(ctx *cli.Context) {
|
|||||||
if len(ctx.Args()) < 2 || ctx.Args().First() == "help" {
|
if len(ctx.Args()) < 2 || ctx.Args().First() == "help" {
|
||||||
cli.ShowCommandHelpAndExit(ctx, "sync", 1) // last argument is exit code
|
cli.ShowCommandHelpAndExit(ctx, "sync", 1) // last argument is exit code
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isMcConfigExist() {
|
if !isMcConfigExist() {
|
||||||
console.Fatalln("\"mc\" is not configured. Please run \"mc config generate\".")
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: "Please run \"mc config generate\"",
|
||||||
|
Error: iodine.New(errors.New("\"mc\" is not configured"), nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
URLs, err := args2URLs(ctx.Args())
|
URLs, err := args2URLs(ctx.Args())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Fatalln(iodine.ToError(err))
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: fmt.Sprintf("Unknown URL types found: ‘%s’", URLs),
|
||||||
|
Error: iodine.New(err, nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Separate source and target. 'sync' can take only one source.
|
// Separate source and target. 'sync' can take only one source.
|
||||||
@@ -66,7 +76,10 @@ func runSyncCmd(ctx *cli.Context) {
|
|||||||
|
|
||||||
for syncURLs := range prepareSyncURLs(sourceURL, targetURLs) {
|
for syncURLs := range prepareSyncURLs(sourceURL, targetURLs) {
|
||||||
if syncURLs.Error != nil {
|
if syncURLs.Error != nil {
|
||||||
console.Errorln(iodine.ToError(syncURLs.Error))
|
console.Errorln(console.ErrorMessage{
|
||||||
|
Message: "Failed with",
|
||||||
|
Error: iodine.New(syncURLs.Error, nil),
|
||||||
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
syncQueue <- true
|
syncQueue <- true
|
||||||
@@ -75,16 +88,25 @@ func runSyncCmd(ctx *cli.Context) {
|
|||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
srcConfig, err := getHostConfig(syncURLs.SourceContent.Name)
|
srcConfig, err := getHostConfig(syncURLs.SourceContent.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Errorln(iodine.ToError(err))
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: "Failed with",
|
||||||
|
Error: iodine.New(err, nil),
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tgtConfig, err := getHostConfig(syncURLs.TargetContent.Name)
|
tgtConfig, err := getHostConfig(syncURLs.TargetContent.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Errorln(iodine.ToError(err))
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: "Failed with",
|
||||||
|
Error: iodine.New(err, nil),
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := doCopy(syncURLs.SourceContent.Name, srcConfig, syncURLs.TargetContent.Name, tgtConfig, bar); err != nil {
|
if err := doCopy(syncURLs.SourceContent.Name, srcConfig, syncURLs.TargetContent.Name, tgtConfig, bar); err != nil {
|
||||||
console.Errorln(iodine.ToError(err))
|
console.Errorln(console.ErrorMessage{
|
||||||
|
Message: "Failed with",
|
||||||
|
Error: iodine.New(err, nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
<-syncQueue
|
<-syncQueue
|
||||||
}(syncURLs, &bar)
|
}(syncURLs, &bar)
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -56,17 +58,24 @@ func runUpdateCmd(ctx *cli.Context) {
|
|||||||
cli.ShowCommandHelpAndExit(ctx, "update", 1) // last argument is exit code
|
cli.ShowCommandHelpAndExit(ctx, "update", 1) // last argument is exit code
|
||||||
}
|
}
|
||||||
if !isMcConfigExist() {
|
if !isMcConfigExist() {
|
||||||
console.Fatalln("\"mc\" is not configured. Please run \"mc config generate\".")
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: "Please run \"mc config generate\"",
|
||||||
|
Error: iodine.New(errors.New("\"mc\" is not configured"), nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
hostConfig, err := getHostConfig(mcUpdateURL)
|
hostConfig, err := getHostConfig(mcUpdateURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Fatalf("Unable to read configuration for host ‘%s’. Reason: %s.\n", mcUpdateURL, iodine.ToError(err))
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: fmt.Sprintf("Unable to read configuration for host ‘%s’", mcUpdateURL),
|
||||||
|
Error: iodine.New(err, nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
msg, err := doUpdateCheck(hostConfig)
|
msg, err := doUpdateCheck(hostConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Fatalln(msg)
|
console.Fatalln(console.ErrorMessage{
|
||||||
}
|
Message: msg,
|
||||||
if msg != "" {
|
Error: iodine.New(err, nil),
|
||||||
console.Infoln(msg)
|
})
|
||||||
}
|
}
|
||||||
|
console.Infoln(console.Message(msg))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ func getMcConfig() (*configV1, error) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// isMcConfigExist returns true/false if config exists
|
// isMcConfigExist returns err if config doesn't exist
|
||||||
func isMcConfigExist() bool {
|
func isMcConfigExist() bool {
|
||||||
configFile, err := getMcConfigPath()
|
configFile, err := getMcConfigPath()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
59
ls.go
59
ls.go
@@ -17,11 +17,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/dustin/go-humanize"
|
"github.com/dustin/go-humanize"
|
||||||
"github.com/minio/mc/pkg/client"
|
"github.com/minio/mc/pkg/client"
|
||||||
@@ -36,49 +32,22 @@ const (
|
|||||||
printDate = "2006-01-02 15:04:05 MST"
|
printDate = "2006-01-02 15:04:05 MST"
|
||||||
)
|
)
|
||||||
|
|
||||||
// printJSON rather than colored output
|
// printContent prints content meta-data
|
||||||
func printJSON(content *client.Content) {
|
func printContent(c *client.Content) {
|
||||||
type jsonContent struct {
|
content := console.Content{}
|
||||||
Filetype string `json:"content-type"`
|
content.Filetype = func() string {
|
||||||
Date string `json:"last-modified"`
|
if c.Type.IsDir() {
|
||||||
Size string `json:"size"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
}
|
|
||||||
contentJSON := new(jsonContent)
|
|
||||||
contentJSON.Date = content.Time.Local().Format(printDate)
|
|
||||||
contentJSON.Size = humanize.IBytes(uint64(content.Size))
|
|
||||||
contentJSON.Filetype = func() string {
|
|
||||||
if content.Type.IsDir() {
|
|
||||||
return "inode/directory"
|
return "inode/directory"
|
||||||
}
|
}
|
||||||
if content.Type.IsRegular() {
|
if c.Type.IsRegular() {
|
||||||
return "application/octet-stream"
|
return "application/octet-stream"
|
||||||
}
|
}
|
||||||
return "application/octet-stream"
|
return "application/octet-stream"
|
||||||
}()
|
}()
|
||||||
contentJSON.Name = content.Name
|
content.Size = humanize.IBytes(uint64(c.Size))
|
||||||
contentBytes, _ := json.MarshalIndent(contentJSON, "", "\t")
|
content.Name = strings.TrimSuffix(c.Name, "/")
|
||||||
fmt.Println(string(contentBytes))
|
content.Time = c.Time.Local().Format(printDate)
|
||||||
}
|
console.ContentInfo(content)
|
||||||
|
|
||||||
// printContent prints content meta-data
|
|
||||||
func printContent(date time.Time, size int64, name string, fileType os.FileMode) {
|
|
||||||
fmt.Printf(console.Time("[%s] ", date.Local().Format(printDate)))
|
|
||||||
fmt.Printf(console.Size("%6s ", humanize.IBytes(uint64(size))))
|
|
||||||
|
|
||||||
// just making it explicit
|
|
||||||
switch {
|
|
||||||
case fileType.IsDir() == true:
|
|
||||||
// if one finds a prior suffix no need to append a new one
|
|
||||||
switch {
|
|
||||||
case strings.HasSuffix(name, "/") == true:
|
|
||||||
fmt.Println(console.Dir("%s", name))
|
|
||||||
default:
|
|
||||||
fmt.Println(console.Dir("%s/", name))
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
fmt.Println(console.File("%s", name))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// doList - list all entities inside a folder
|
// doList - list all entities inside a folder
|
||||||
@@ -97,12 +66,8 @@ func doList(clnt client.Client, targetURL string, recursive bool) error {
|
|||||||
// To be consistent we have to filter them out
|
// To be consistent we have to filter them out
|
||||||
contentName = strings.TrimPrefix(contentName, strings.TrimSuffix(targetURL, "/")+"/")
|
contentName = strings.TrimPrefix(contentName, strings.TrimSuffix(targetURL, "/")+"/")
|
||||||
}
|
}
|
||||||
switch {
|
contentCh.Content.Name = contentName
|
||||||
case globalJSONFlag == true:
|
printContent(contentCh.Content)
|
||||||
printJSON(contentCh.Content)
|
|
||||||
default:
|
|
||||||
printContent(contentCh.Content.Time, contentCh.Content.Size, contentName, contentCh.Content.Type)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return iodine.New(err, map[string]string{"Target": targetURL})
|
return iodine.New(err, map[string]string{"Target": targetURL})
|
||||||
|
|||||||
29
main.go
29
main.go
@@ -17,6 +17,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
@@ -34,7 +35,10 @@ import (
|
|||||||
func checkConfig() {
|
func checkConfig() {
|
||||||
_, err := user.Current()
|
_, err := user.Current()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Fatalln("Unable to determine current user")
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: "Unable to determine current user",
|
||||||
|
Error: err,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// If config doesn't exist, do not attempt to read it
|
// If config doesn't exist, do not attempt to read it
|
||||||
@@ -45,7 +49,10 @@ func checkConfig() {
|
|||||||
// Ensures config file is sane
|
// Ensures config file is sane
|
||||||
_, err = getMcConfig()
|
_, err = getMcConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Fatalf("Unable to read config file: %s\n", mustGetMcConfigPath())
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: fmt.Sprintf("Unable to read config file: %s", mustGetMcConfigPath()),
|
||||||
|
Error: err,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,14 +114,23 @@ func main() {
|
|||||||
app.ExtraInfo = getSystemData()
|
app.ExtraInfo = getSystemData()
|
||||||
console.NoDebugPrint = false
|
console.NoDebugPrint = false
|
||||||
}
|
}
|
||||||
|
if globalJSONFlag {
|
||||||
|
console.NoJSONPrint = false
|
||||||
|
}
|
||||||
themeName := ctx.GlobalString("theme")
|
themeName := ctx.GlobalString("theme")
|
||||||
switch {
|
switch {
|
||||||
case console.IsValidTheme(themeName) != true:
|
case console.IsValidTheme(themeName) != true:
|
||||||
console.Fatalf("Theme ‘%s’ is not supported. Please choose from this list: %s.\n", themeName, console.GetThemeNames())
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: fmt.Sprintf("Please choose from this list: %s.", console.GetThemeNames()),
|
||||||
|
Error: fmt.Errorf("Theme ‘%s’ is not supported.", themeName),
|
||||||
|
})
|
||||||
default:
|
default:
|
||||||
err := console.SetTheme(themeName)
|
err := console.SetTheme(themeName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
console.Fatalf("Failed to set theme ‘%s’. Reason: %s.\n", themeName, iodine.ToError(err))
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: fmt.Sprintf("Failed to set theme ‘%s’.", themeName),
|
||||||
|
Error: err,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkConfig()
|
checkConfig()
|
||||||
@@ -122,7 +138,10 @@ func main() {
|
|||||||
}
|
}
|
||||||
app.After = func(ctx *cli.Context) error {
|
app.After = func(ctx *cli.Context) error {
|
||||||
if !isMcConfigExist() {
|
if !isMcConfigExist() {
|
||||||
console.Fatalln("\"mc\" is not configured. Please run \"mc config generate\".")
|
console.Fatalln(console.ErrorMessage{
|
||||||
|
Message: "Please run \"mc config generate\"",
|
||||||
|
Error: iodine.New(errors.New("\"mc\" is not configured"), nil),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ func (c *s3Client) listInRoutine(contentCh chan client.ContentOnChannel) {
|
|||||||
content := new(client.Content)
|
content := new(client.Content)
|
||||||
content.Name = object.Data.Key
|
content.Name = object.Data.Key
|
||||||
switch {
|
switch {
|
||||||
case object.Data.Size == 0:
|
case strings.HasSuffix(object.Data.Key, "/"):
|
||||||
content.Time = time.Now()
|
content.Time = time.Now()
|
||||||
content.Type = os.ModeDir
|
content.Type = os.ModeDir
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -75,9 +75,10 @@ func (t Trace) Response(res *http.Response) (err error) {
|
|||||||
|
|
||||||
// print HTTP Response
|
// print HTTP Response
|
||||||
func (t Trace) print(data []byte) {
|
func (t Trace) print(data []byte) {
|
||||||
if t.Writer != nil {
|
switch {
|
||||||
|
case t.Writer != nil:
|
||||||
fmt.Fprintf(t.Writer, "%s", data)
|
fmt.Fprintf(t.Writer, "%s", data)
|
||||||
} else {
|
default:
|
||||||
console.Debugf("%s", data)
|
console.Debugln(string(data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package console
|
package console
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -31,6 +32,40 @@ import (
|
|||||||
// NoDebugPrint defines if the input should be printed in debug or not. By default it's set to true.
|
// NoDebugPrint defines if the input should be printed in debug or not. By default it's set to true.
|
||||||
var NoDebugPrint = true
|
var NoDebugPrint = true
|
||||||
|
|
||||||
|
// NoJsonPrint defines if the input should be printed in json formatted or not. By default it's set to true.
|
||||||
|
var NoJSONPrint = true
|
||||||
|
|
||||||
|
// Message info string
|
||||||
|
type Message string
|
||||||
|
|
||||||
|
// ErrorMessage error message structure
|
||||||
|
type ErrorMessage struct {
|
||||||
|
Message string `json:"Message"`
|
||||||
|
Error error `json:"Reason"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Content content message structure
|
||||||
|
type Content struct {
|
||||||
|
Filetype string `json:"ContentType"`
|
||||||
|
Time string `json:"LastModified"`
|
||||||
|
Size string `json:"Size"`
|
||||||
|
Name string `json:"Name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Theme holds console color scheme
|
||||||
|
type Theme struct {
|
||||||
|
Fatal *color.Color
|
||||||
|
Error *color.Color
|
||||||
|
Info *color.Color
|
||||||
|
Debug *color.Color
|
||||||
|
Size *color.Color
|
||||||
|
Time *color.Color
|
||||||
|
File *color.Color
|
||||||
|
Dir *color.Color
|
||||||
|
Retry *color.Color
|
||||||
|
JSON *color.Color
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
mutex = &sync.RWMutex{}
|
mutex = &sync.RWMutex{}
|
||||||
|
|
||||||
@@ -54,78 +89,134 @@ var (
|
|||||||
return theme
|
return theme
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Print prints a error message and exits
|
// Print prints a message
|
||||||
Print = themesDB[currThemeName].Info.Print
|
Print = themesDB[currThemeName].Info.Print
|
||||||
// Println prints a error message with a new line and exits
|
|
||||||
Println = themesDB[currThemeName].Info.Println
|
|
||||||
// Printf prints a error message with formatting and exits
|
|
||||||
Printf = themesDB[currThemeName].Info.Printf
|
|
||||||
|
|
||||||
// Fatal prints a error message and exits
|
// Fatal prints a error message and exits
|
||||||
Fatal = func(a ...interface{}) { print(themesDB[currThemeName].Error, a...); os.Exit(1) }
|
Fatal = func(msg ErrorMessage) {
|
||||||
|
defer os.Exit(1)
|
||||||
|
if msg.Error != nil {
|
||||||
|
if NoJSONPrint {
|
||||||
|
reason := "Reason: " + iodine.ToError(msg.Error).Error()
|
||||||
|
message := msg.Message + ", " + reason
|
||||||
|
print(themesDB[currThemeName].Error, message)
|
||||||
|
if !NoDebugPrint {
|
||||||
|
print(themesDB[currThemeName].Error, msg.Error)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
errorMessageBytes, _ := json.Marshal(&msg)
|
||||||
|
print(themesDB[currThemeName].JSON, string(errorMessageBytes))
|
||||||
|
}
|
||||||
|
}
|
||||||
// Fatalln prints a error message with a new line and exits
|
// Fatalln prints a error message with a new line and exits
|
||||||
Fatalln = func(a ...interface{}) { println(themesDB[currThemeName].Error, a...); os.Exit(1) }
|
Fatalln = func(msg ErrorMessage) {
|
||||||
// Fatalf prints a error message with formatting and exits
|
defer os.Exit(1)
|
||||||
Fatalf = func(f string, a ...interface{}) { printf(themesDB[currThemeName].Error, f, a...); os.Exit(1) }
|
if msg.Error != nil {
|
||||||
|
if NoJSONPrint {
|
||||||
|
reason := "Reason: " + iodine.ToError(msg.Error).Error()
|
||||||
|
message := msg.Message + ", " + reason
|
||||||
|
println(themesDB[currThemeName].Error, message)
|
||||||
|
if !NoDebugPrint {
|
||||||
|
println(themesDB[currThemeName].Error, msg.Error)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
errorMessageBytes, _ := json.Marshal(&msg)
|
||||||
|
println(themesDB[currThemeName].JSON, string(errorMessageBytes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Error prints a error message
|
// Error prints a error message
|
||||||
Error = func(a ...interface{}) { print(themesDB[currThemeName].Error, a...) }
|
Error = func(msg ErrorMessage) {
|
||||||
|
if msg.Error != nil {
|
||||||
|
if NoJSONPrint {
|
||||||
|
reason := "Reason: " + iodine.ToError(msg.Error).Error()
|
||||||
|
message := msg.Message + ", " + reason
|
||||||
|
print(themesDB[currThemeName].Error, message)
|
||||||
|
if !NoDebugPrint {
|
||||||
|
print(themesDB[currThemeName].Error, msg.Error)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
errorMessageBytes, _ := json.Marshal(&msg)
|
||||||
|
print(themesDB[currThemeName].JSON, string(errorMessageBytes))
|
||||||
|
}
|
||||||
|
}
|
||||||
// Errorln prints a error message with a new line
|
// Errorln prints a error message with a new line
|
||||||
Errorln = func(a ...interface{}) { println(themesDB[currThemeName].Error, a...) }
|
Errorln = func(msg ErrorMessage) {
|
||||||
// Errorf prints a error message with formatting
|
if msg.Error != nil {
|
||||||
Errorf = func(f string, a ...interface{}) { printf(themesDB[currThemeName].Error, f, a...) }
|
if NoJSONPrint {
|
||||||
|
reason := "Reason: " + iodine.ToError(msg.Error).Error()
|
||||||
|
message := msg.Message + ", " + reason
|
||||||
|
println(themesDB[currThemeName].Error, message)
|
||||||
|
if !NoDebugPrint {
|
||||||
|
println(themesDB[currThemeName].Error, msg.Error)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
errorMessageBytes, _ := json.Marshal(&msg)
|
||||||
|
println(themesDB[currThemeName].JSON, string(errorMessageBytes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Info prints a informational message
|
// Info prints a informational message
|
||||||
Info = func(a ...interface{}) { print(themesDB[currThemeName].Info, a...) }
|
Info = func(msg Message) {
|
||||||
// Infoln prints a informational message with a new line
|
if NoJSONPrint {
|
||||||
Infoln = func(a ...interface{}) { println(themesDB[currThemeName].Info, a...) }
|
print(themesDB[currThemeName].Info, msg)
|
||||||
// Infof prints a informational message with formatting
|
return
|
||||||
Infof = func(f string, a ...interface{}) { printf(themesDB[currThemeName].Info, f, a...) }
|
}
|
||||||
|
infoBytes, _ := json.Marshal(&msg)
|
||||||
|
print(themesDB[currThemeName].JSON, string(infoBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infoln prints a informational message with a new line
|
||||||
|
Infoln = func(msg Message) {
|
||||||
|
if NoJSONPrint {
|
||||||
|
println(themesDB[currThemeName].Info, msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
infoBytes, _ := json.Marshal(&msg)
|
||||||
|
println(themesDB[currThemeName].JSON, string(infoBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug prints a debug message without a new line
|
||||||
// Debug prints a debug message
|
// Debug prints a debug message
|
||||||
Debug = func(a ...interface{}) {
|
Debug = func(a ...interface{}) {
|
||||||
if !NoDebugPrint {
|
if !NoDebugPrint {
|
||||||
print(themesDB[currThemeName].Debug, a...)
|
print(themesDB[currThemeName].Debug, a...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debugln prints a debug message with a new line
|
// Debugln prints a debug message with a new line
|
||||||
Debugln = func(a ...interface{}) {
|
Debugln = func(a ...interface{}) {
|
||||||
if !NoDebugPrint {
|
if !NoDebugPrint {
|
||||||
println(themesDB[currThemeName].Debug, a...)
|
println(themesDB[currThemeName].Debug, a...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Debugf prints a debug message with formatting
|
// ContentInfo prints a structure Content
|
||||||
Debugf = func(f string, a ...interface{}) {
|
ContentInfo = func(c Content) {
|
||||||
if !NoDebugPrint {
|
if NoJSONPrint {
|
||||||
printf(themesDB[currThemeName].Debug, f, a...)
|
print(themesDB[currThemeName].Time, c.Time)
|
||||||
|
print(themesDB[currThemeName].Size, c.Size)
|
||||||
|
switch c.Filetype {
|
||||||
|
case "inode/directory":
|
||||||
|
println(themesDB[currThemeName].Dir, c.Name)
|
||||||
|
case "application/octet-stream":
|
||||||
|
println(themesDB[currThemeName].File, c.Name)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
contentBytes, _ := json.Marshal(&c)
|
||||||
|
println(themesDB[currThemeName].JSON, string(contentBytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
// File - File("foo.txt")
|
// Retry prints a retry message
|
||||||
File = themesDB[currThemeName].File.SprintfFunc()
|
Retry = func(a ...interface{}) {
|
||||||
// Dir - Dir("dir/")
|
println(themesDB[currThemeName].Retry, a...)
|
||||||
Dir = themesDB[currThemeName].Dir.SprintfFunc()
|
}
|
||||||
// Size - Size("12GB")
|
|
||||||
Size = themesDB[currThemeName].Size.SprintfFunc()
|
|
||||||
// Time - Time("12 Hours")
|
|
||||||
Time = themesDB[currThemeName].Time.SprintfFunc()
|
|
||||||
// Retry - Retry message number
|
|
||||||
Retry = themesDB[currThemeName].Retry.SprintfFunc()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Theme holds console color scheme
|
|
||||||
type Theme struct {
|
|
||||||
Fatal *color.Color
|
|
||||||
Error *color.Color
|
|
||||||
Info *color.Color
|
|
||||||
Debug *color.Color
|
|
||||||
Size *color.Color
|
|
||||||
Time *color.Color
|
|
||||||
File *color.Color
|
|
||||||
Dir *color.Color
|
|
||||||
Retry *color.Color
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// wrap around standard fmt functions
|
// wrap around standard fmt functions
|
||||||
// print prints a message prefixed with message type and program name
|
// print prints a message prefixed with message type and program name
|
||||||
@@ -155,11 +246,24 @@ var (
|
|||||||
c.Print(a...)
|
c.Print(a...)
|
||||||
color.Output = output
|
color.Output = output
|
||||||
mutex.Unlock()
|
mutex.Unlock()
|
||||||
default:
|
case themesDB[currThemeName].Info:
|
||||||
mutex.Lock()
|
mutex.Lock()
|
||||||
c.Print(ProgramName() + ": ")
|
c.Print(ProgramName() + ": ")
|
||||||
c.Print(a...)
|
c.Print(a...)
|
||||||
mutex.Unlock()
|
mutex.Unlock()
|
||||||
|
// special cases only for Content where it requires custom formatting
|
||||||
|
case themesDB[currThemeName].Time:
|
||||||
|
mutex.Lock()
|
||||||
|
c.Print(fmt.Sprintf("[%s]", a...))
|
||||||
|
mutex.Unlock()
|
||||||
|
case themesDB[currThemeName].Size:
|
||||||
|
mutex.Lock()
|
||||||
|
c.Printf(fmt.Sprintf("%6s ", a...))
|
||||||
|
mutex.Unlock()
|
||||||
|
default:
|
||||||
|
mutex.Lock()
|
||||||
|
c.Print(a...)
|
||||||
|
mutex.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,45 +294,23 @@ var (
|
|||||||
c.Println(a...)
|
c.Println(a...)
|
||||||
color.Output = output
|
color.Output = output
|
||||||
mutex.Unlock()
|
mutex.Unlock()
|
||||||
default:
|
case themesDB[currThemeName].Info:
|
||||||
mutex.Lock()
|
mutex.Lock()
|
||||||
c.Print(ProgramName() + ": ")
|
c.Print(ProgramName() + ": ")
|
||||||
c.Println(a...)
|
c.Println(a...)
|
||||||
mutex.Unlock()
|
mutex.Unlock()
|
||||||
}
|
case themesDB[currThemeName].Dir:
|
||||||
}
|
|
||||||
|
|
||||||
// printf - same as print, but takes a format specifier
|
|
||||||
printf = func(c *color.Color, f string, a ...interface{}) {
|
|
||||||
switch c {
|
|
||||||
case themesDB[currThemeName].Debug:
|
|
||||||
mutex.Lock()
|
mutex.Lock()
|
||||||
output := color.Output
|
// ugly but its needed
|
||||||
color.Output = stderrColoredOutput
|
c.Printf("%s/\n", a...)
|
||||||
c.Print(ProgramName() + ": <DEBUG> ")
|
|
||||||
c.Printf(f, a...)
|
|
||||||
color.Output = output
|
|
||||||
mutex.Unlock()
|
mutex.Unlock()
|
||||||
case themesDB[currThemeName].Fatal:
|
case themesDB[currThemeName].File:
|
||||||
mutex.Lock()
|
mutex.Lock()
|
||||||
output := color.Output
|
c.Println(a...)
|
||||||
color.Output = stderrColoredOutput
|
|
||||||
c.Print(ProgramName() + ": <FATAL> ")
|
|
||||||
c.Printf(f, a...)
|
|
||||||
color.Output = output
|
|
||||||
mutex.Unlock()
|
|
||||||
case themesDB[currThemeName].Error:
|
|
||||||
mutex.Lock()
|
|
||||||
output := color.Output
|
|
||||||
color.Output = stderrColoredOutput
|
|
||||||
c.Print(ProgramName() + ": <ERROR> ")
|
|
||||||
c.Printf(f, a...)
|
|
||||||
color.Output = output
|
|
||||||
mutex.Unlock()
|
mutex.Unlock()
|
||||||
default:
|
default:
|
||||||
mutex.Lock()
|
mutex.Lock()
|
||||||
c.Print(ProgramName() + ": ")
|
c.Println(a...)
|
||||||
c.Printf(f, a...)
|
|
||||||
mutex.Unlock()
|
mutex.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -262,46 +344,6 @@ func SetTheme(themeName string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
currThemeName = themeName
|
currThemeName = themeName
|
||||||
theme := themesDB[currThemeName]
|
|
||||||
|
|
||||||
// Error prints a error message
|
|
||||||
Error = func(a ...interface{}) { print(theme.Error, a...) }
|
|
||||||
// Errorln prints a error message with a new line
|
|
||||||
Errorln = func(a ...interface{}) { println(theme.Error, a...) }
|
|
||||||
// Errorf prints a error message with formatting
|
|
||||||
Errorf = func(f string, a ...interface{}) { printf(theme.Error, f, a...) }
|
|
||||||
|
|
||||||
// Info prints a informational message
|
|
||||||
Info = func(a ...interface{}) { print(theme.Info, a...) }
|
|
||||||
// Infoln prints a informational message with a new line
|
|
||||||
Infoln = func(a ...interface{}) { println(theme.Info, a...) }
|
|
||||||
// Infof prints a informational message with formatting
|
|
||||||
Infof = func(f string, a ...interface{}) { printf(theme.Info, f, a...) }
|
|
||||||
|
|
||||||
// Debug prints a debug message
|
|
||||||
Debug = func(a ...interface{}) {
|
|
||||||
if !NoDebugPrint {
|
|
||||||
print(theme.Debug, a...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Debugln prints a debug message with a new line
|
|
||||||
Debugln = func(a ...interface{}) {
|
|
||||||
if !NoDebugPrint {
|
|
||||||
println(theme.Debug, a...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Debugf prints a debug message with formatting
|
|
||||||
Debugf = func(f string, a ...interface{}) {
|
|
||||||
if !NoDebugPrint {
|
|
||||||
printf(theme.Debug, f, a...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Dir = theme.Dir.SprintfFunc()
|
|
||||||
File = theme.File.SprintfFunc()
|
|
||||||
Size = theme.Size.SprintfFunc()
|
|
||||||
Time = theme.Time.SprintfFunc()
|
|
||||||
Retry = theme.Retry.SprintfFunc()
|
|
||||||
|
|
||||||
mutex.Unlock()
|
mutex.Unlock()
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ var MiniTheme = Theme{
|
|||||||
Size: (color.New(color.FgYellow)),
|
Size: (color.New(color.FgYellow)),
|
||||||
Time: (color.New(color.FgGreen)),
|
Time: (color.New(color.FgGreen)),
|
||||||
Retry: (color.New(color.FgMagenta, color.Bold)),
|
Retry: (color.New(color.FgMagenta, color.Bold)),
|
||||||
|
JSON: (color.New(color.FgWhite, color.Italic)),
|
||||||
}
|
}
|
||||||
|
|
||||||
// WhiteTheme - All white color theme
|
// WhiteTheme - All white color theme
|
||||||
@@ -42,6 +43,7 @@ var WhiteTheme = Theme{
|
|||||||
Size: (color.New(color.FgWhite, color.Bold)),
|
Size: (color.New(color.FgWhite, color.Bold)),
|
||||||
Time: (color.New(color.FgWhite, color.Bold)),
|
Time: (color.New(color.FgWhite, color.Bold)),
|
||||||
Retry: (color.New(color.FgWhite, color.Bold)),
|
Retry: (color.New(color.FgWhite, color.Bold)),
|
||||||
|
JSON: (color.New(color.FgWhite, color.Bold, color.Italic)),
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoColorTheme - Disables color theme
|
// NoColorTheme - Disables color theme
|
||||||
@@ -55,4 +57,5 @@ var NoColorTheme = Theme{
|
|||||||
Size: (color.New()),
|
Size: (color.New()),
|
||||||
Time: (color.New()),
|
Time: (color.New()),
|
||||||
Retry: (color.New()),
|
Retry: (color.New()),
|
||||||
|
JSON: (color.New()),
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user