/* * Minio Client (C) 2014, 2015 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package main import ( "errors" "fmt" "runtime" "sync" "github.com/minio/cli" "github.com/minio/mc/pkg/console" "github.com/minio/minio/pkg/iodine" ) // doCopy - Copy a singe file from source to destination func doCopy(sourceURL string, sourceConfig *hostConfig, targetURL string, targetConfig *hostConfig, bar *barSend) error { reader, length, err := getSource(sourceURL, sourceConfig) if err != nil { return iodine.New(err, nil) } switch globalQuietFlag { case true: console.Infoln(console.Message(fmt.Sprintf("‘%s’ -> ‘%s’", sourceURL, targetURL))) default: // set up progress reader = bar.NewProxyReader(reader) } err = putTarget(targetURL, targetConfig, length, reader) if err != nil { return iodine.New(err, nil) } return nil } // args2URLs extracts source and target URLs from command-line args. func args2URLs(args cli.Args) ([]string, error) { config, err := getMcConfig() if err != nil { return nil, iodine.New(err, nil) } // Convert arguments to URLs: expand alias, fix format... URLs, err := getExpandedURLs(args, config.Aliases) if err != nil { return nil, iodine.New(err, nil) } return URLs, nil } func doCopyInRoutine(cpurls *cpURLs, bar *barSend, cpQueue chan bool, ch chan error, wg *sync.WaitGroup) { defer wg.Done() srcConfig, err := getHostConfig(cpurls.SourceContent.Name) if err != nil { ch <- err return } tgtConfig, err := getHostConfig(cpurls.TargetContent.Name) if err != nil { ch <- err return } if err := doCopy(cpurls.SourceContent.Name, srcConfig, cpurls.TargetContent.Name, tgtConfig, bar); err != nil { ch <- err } <-cpQueue } func doCopyCmd(sourceURLs []string, targetURL string, bar barSend) <-chan error { ch := make(chan error) go func(sourceURLs []string, targetURL string, bar barSend, ch chan error) { defer close(ch) go func(sourceURLs []string, targetURL string) { for cpURLs := range prepareCopyURLs(sourceURLs, targetURL) { if cpURLs.Error != nil { // no need to print errors here, any error here // will be printed later during Copy() continue } if !globalQuietFlag { bar.Extend(cpURLs.SourceContent.Size) } } }(sourceURLs, targetURL) cpQueue := make(chan bool, intMax(runtime.NumCPU()-1, 1)) wg := new(sync.WaitGroup) for cpURLs := range prepareCopyURLs(sourceURLs, targetURL) { if cpURLs.Error != nil { ch <- cpURLs.Error continue } cpQueue <- true wg.Add(1) go doCopyInRoutine(cpURLs, &bar, cpQueue, ch, wg) } close(cpQueue) wg.Wait() }(sourceURLs, targetURL, bar, ch) return ch } // runCopyCmd is bound to sub-command func runCopyCmd(ctx *cli.Context) { if len(ctx.Args()) < 2 || ctx.Args().First() == "help" { cli.ShowCommandHelpAndExit(ctx, "cp", 1) // last argument is exit code } if !isMcConfigExist() { console.Fatalln(console.ErrorMessage{ Message: "Please run \"mc config generate\"", Error: iodine.New(errors.New("\"mc\" is not configured"), nil), }) } // extract URLs. URLs, err := args2URLs(ctx.Args()) if err != nil { 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, // but any number of sources, even the recursive URLs mixed in-between. sourceURLs := URLs[:len(URLs)-1] targetURL := URLs[len(URLs)-1] // Last one is target var bar barSend // set up progress bar if !globalQuietFlag { bar = newCpBar() } for err := range doCopyCmd(sourceURLs, targetURL, bar) { if err != nil { console.Errorln(console.ErrorMessage{ Message: "Failed with", Error: iodine.New(err, nil), }) } } if !globalQuietFlag { bar.Finish() } }