github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/get-main.go (about) 1 // Copyright (c) 2015-2024 MinIO, Inc. 2 // 3 // This file is part of MinIO Object Storage stack 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package cmd 19 20 import ( 21 "context" 22 "strings" 23 24 "github.com/minio/cli" 25 "github.com/minio/pkg/v2/console" 26 ) 27 28 // get command flags. 29 var ( 30 getFlags = []cli.Flag{} 31 ) 32 33 // Get command. 34 var getCmd = cli.Command{ 35 Name: "get", 36 Usage: "get s3 object to local", 37 Action: mainGet, 38 OnUsageError: onUsageError, 39 Before: setGlobalsFromContext, 40 Flags: append(append(globalFlags, encCFlag), getFlags...), 41 CustomHelpTemplate: `NAME: 42 {{.HelpName}} - {{.Usage}} 43 44 USAGE: 45 {{.HelpName}} [FLAGS] SOURCE TARGET 46 47 FLAGS: 48 {{range .VisibleFlags}}{{.}} 49 {{end}} 50 51 EXAMPLES: 52 1. Get an object from MinIO storage to local file system 53 {{.Prompt}} {{.HelpName}} play/mybucket/object path-to/object 54 55 2. Get an object from MinIO storage using encryption 56 {{.Prompt}} {{.HelpName}} --enc-c "play/mybucket/object=MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDA" play/mybucket/object path-to/object 57 `, 58 } 59 60 // mainGet is the entry point for get command. 61 func mainGet(cliCtx *cli.Context) (e error) { 62 args := cliCtx.Args() 63 if len(args) != 2 { 64 showCommandHelpAndExit(cliCtx, 1) // last argument is exit code. 65 } 66 67 ctx, cancelGet := context.WithCancel(globalContext) 68 defer cancelGet() 69 70 encryptionKeys, err := validateAndCreateEncryptionKeys(cliCtx) 71 if err != nil { 72 err.Trace(cliCtx.Args()...) 73 } 74 fatalIf(err, "unable to parse encryption keys") 75 76 // get source and target 77 sourceURLs := args[:len(args)-1] 78 targetURL := args[len(args)-1] 79 80 getURLsCh := make(chan URLs, 10000) 81 var totalObjects, totalBytes int64 82 83 // Store a progress bar or an accounter 84 var pg ProgressReader 85 // Enable progress bar reader only during default mode. 86 if !globalQuiet && !globalJSON { // set up progress bar 87 pg = newProgressBar(totalBytes) 88 } else { 89 pg = newAccounter(totalBytes) 90 } 91 go func() { 92 opts := prepareCopyURLsOpts{ 93 sourceURLs: sourceURLs, 94 targetURL: targetURL, 95 encKeyDB: encryptionKeys, 96 ignoreBucketExistsCheck: true, 97 } 98 99 for getURLs := range prepareGetURLs(ctx, opts) { 100 if getURLs.Error != nil { 101 getURLsCh <- getURLs 102 break 103 } 104 totalObjects++ 105 getURLsCh <- getURLs 106 } 107 close(getURLsCh) 108 }() 109 for { 110 select { 111 case <-ctx.Done(): 112 showLastProgressBar(pg, nil) 113 return 114 case getURLs, ok := <-getURLsCh: 115 if !ok { 116 showLastProgressBar(pg, nil) 117 return 118 } 119 if getURLs.Error != nil { 120 printGetURLsError(&getURLs) 121 showLastProgressBar(pg, getURLs.Error.ToGoError()) 122 return 123 } 124 urls := doCopy(ctx, doCopyOpts{ 125 cpURLs: getURLs, 126 pg: pg, 127 encryptionKeys: encryptionKeys, 128 updateProgressTotal: true, 129 }) 130 if urls.Error != nil { 131 e = urls.Error.ToGoError() 132 showLastProgressBar(pg, e) 133 return 134 } 135 } 136 } 137 } 138 139 func printGetURLsError(cpURLs *URLs) { 140 // Print in new line and adjust to top so that we 141 // don't print over the ongoing scan bar 142 if !globalQuiet && !globalJSON { 143 console.Eraseline() 144 } 145 146 if strings.Contains(cpURLs.Error.ToGoError().Error(), 147 " is a folder.") { 148 errorIf(cpURLs.Error.Trace(), 149 "Folder cannot be copied. Please use `...` suffix.") 150 } else { 151 errorIf(cpURLs.Error.Trace(), 152 "Unable to download.") 153 } 154 }