// mainList - is a handler for mc ls command func mainList(ctx *cli.Context) { // Additional command speific theme customization. console.SetColor("File", color.New(color.FgWhite)) console.SetColor("Dir", color.New(color.FgCyan, color.Bold)) console.SetColor("Size", color.New(color.FgYellow)) console.SetColor("Time", color.New(color.FgGreen)) // Set global flags from context. setGlobalsFromContext(ctx) // check 'ls' cli arguments. checkListSyntax(ctx) // Set command flags from context. isRecursive := ctx.Bool("recursive") isIncomplete := ctx.Bool("incomplete") args := ctx.Args() // mimic operating system tool behavior. if !ctx.Args().Present() { args = []string{"."} } for _, targetURL := range args { var clnt client.Client clnt, err := newClient(targetURL) fatalIf(err.Trace(targetURL), "Unable to initialize target ‘"+targetURL+"’.") err = doList(clnt, isRecursive, isIncomplete) if err != nil { errorIf(err.Trace(clnt.GetURL().String()), "Unable to list target ‘"+clnt.GetURL().String()+"’.") continue } } }
// mainList - is a handler for mc ls command func mainList(ctx *cli.Context) { // Additional command speific theme customization. console.SetColor("File", color.New(color.FgWhite)) console.SetColor("Dir", color.New(color.FgCyan, color.Bold)) console.SetColor("Size", color.New(color.FgYellow)) console.SetColor("Time", color.New(color.FgGreen)) // check 'ls' cli arguments checkListSyntax(ctx) args := ctx.Args() isIncomplete := ctx.Bool("incomplete") // mimic operating system tool behavior if globalMimicFlag && !ctx.Args().Present() { args = []string{"."} } targetURLs, err := args2URLs(args.Head()) fatalIf(err.Trace(args...), "One or more unknown URL types passed.") for _, targetURL := range targetURLs { // if recursive strip off the "..." var clnt client.Client clnt, err = url2Client(stripRecursiveURL(targetURL)) fatalIf(err.Trace(targetURL), "Unable to initialize target ‘"+targetURL+"’.") err = doList(clnt, isURLRecursive(targetURL), isIncomplete) fatalIf(err.Trace(clnt.GetURL().String()), "Unable to list target ‘"+clnt.GetURL().String()+"’.") } }
// diffFolders - diff of contents of two folders only top level content. // // 3: diff(d1, d2) -> []diff(d1/f, d2/f) -> VALID func diffFolders(firstClnt, secondClnt client.Client, outCh chan<- diffMessage) { recursive := false // Range on the List to consume incoming content for contentCh := range firstClnt.List(recursive, false) { if contentCh.Err != nil { outCh <- diffMessage{ Error: contentCh.Err.Trace(firstClnt.GetURL().String()), } continue } // Store incoming content newFirstContent := contentCh.Content newFirstURLStr := newFirstContent.URL.String() // Construct the second URL. newSecondURL := secondClnt.GetURL() // Need to verify the same path from first URL, construct the second URL newSecondURL.Path = filepath.Join(newSecondURL.Path, filepath.Base(contentCh.Content.URL.Path)) newSecondURLStr := newSecondURL.String() // Send a stat to verify _, newSecondContent, err := url2Stat(newSecondURLStr) if err != nil { outCh <- diffMessage{ FirstURL: newFirstURLStr, SecondURL: newSecondURLStr, Diff: "only-in-first", } continue } diffMsg := diffObjects(newFirstContent, newSecondContent) if diffMsg != nil { outCh <- *diffMsg continue } } // Reached EOF }
// doShareURL share files from target func doShareDownloadURL(targetURL string, recursive bool, expires time.Duration) *probe.Error { shareDate := time.Now().UTC() sURLs, err := loadSharedURLsV3() if err != nil { return err.Trace() } var clnt client.Client clnt, err = url2Client(targetURL) if err != nil { return err.Trace() } if expires.Seconds() < 1 { return probe.NewError(errors.New("Too low expires, expiration cannot be less than 1 second.")) } if expires.Seconds() > 604800 { return probe.NewError(errors.New("Too high expires, expiration cannot be larger than 7 days.")) } for contentCh := range clnt.List(recursive, false) { if contentCh.Err != nil { return contentCh.Err.Trace() } var newClnt client.Client newClnt, err = url2Client(contentCh.Content.URL.String()) if err != nil { return err.Trace() } var sharedURL string sharedURL, err = newClnt.ShareDownload(expires) if err != nil { return err.Trace() } var shareMsg interface{} shareMsg = shareMessage{ Expiry: expires, DownloadURL: sharedURL, Key: newClnt.GetURL().String(), } shareMsgV3 := shareMessageV3(shareMsg.(shareMessage)) sURLs.URLs = append(sURLs.URLs, struct { Date time.Time Message shareMessageV3 }{ Date: shareDate, Message: shareMsgV3, }) printMsg(shareMsg.(shareMessage)) } saveSharedURLsV3(sURLs) return nil }
// doList - list all entities inside a folder. func doList(clnt client.Client, isRecursive, isIncomplete bool) *probe.Error { _, parentContent, err := url2Stat(clnt.GetURL().String()) if err != nil { return err.Trace(clnt.GetURL().String()) } for contentCh := range clnt.List(isRecursive, isIncomplete) { if contentCh.Err != nil { switch contentCh.Err.ToGoError().(type) { // handle this specifically for filesystem case client.BrokenSymlink: errorIf(contentCh.Err.Trace(), "Unable to list broken link.") continue case client.TooManyLevelsSymlink: errorIf(contentCh.Err.Trace(), "Unable to list too many levels link.") continue } if os.IsNotExist(contentCh.Err.ToGoError()) || os.IsPermission(contentCh.Err.ToGoError()) { if contentCh.Content != nil { if contentCh.Content.Type.IsDir() { if contentCh.Content.Type&os.ModeSymlink == os.ModeSymlink { errorIf(contentCh.Err.Trace(), "Unable to list broken folder link.") continue } errorIf(contentCh.Err.Trace(), "Unable to list folder.") } } else { errorIf(contentCh.Err.Trace(), "Unable to list.") continue } } err = contentCh.Err.Trace() break } trimmedContent := trimContent(parentContent, contentCh.Content, isRecursive) parsedContent := parseContent(trimmedContent) printMsg(parsedContent) } if err != nil { return err.Trace() } return nil }
func getTargetContent(srcContent *client.Content, targetContent *client.Content, targetCh <-chan client.ContentOnChannel, targetClnt client.Client) (c *client.Content) { if srcContent == nil { // nothing to do for empty source content. return } if targetContent == nil { c = getContent(targetCh) } else { c = targetContent } for ; c != nil; c = getContent(targetCh) { // Remove prefix so that we can properly validate. targetURL := strings.TrimPrefix(c.URL.Path, targetClnt.GetURL().Path) sourceURL := strings.TrimPrefix(srcContent.URL.Path, string(srcContent.URL.Separator)) if sourceURL <= targetURL { break } } return }
// diffFoldersRecursive diff folders for all files recursively. // // 4: diff(d1..., d2) -> []diff(d1/f, d2/f) -> VALID. func diffFoldersRecursive(firstClnt, secondClnt client.Client, outCh chan<- diffMessage) { var scanBar scanBarFunc if !globalQuietFlag && !globalJSONFlag { // set up progress bar scanBar = scanBarFactory() } recursive := true firstListCh := firstClnt.List(recursive, false) // Copy first list channel. for firstContentCh := range firstListCh { if firstContentCh.Err != nil { outCh <- diffMessage{Error: firstContentCh.Err.Trace()} continue } if firstContentCh.Content.Type.IsDir() { // Skip directories there is no concept of directories on S3. continue } firstContent := firstContentCh.Content secondURL := secondClnt.GetURL() secondURL.Path = filepath.Join(secondURL.Path, strings.TrimPrefix(firstContent.URL.Path, url2Dir(firstClnt.GetURL().Path))) _, secondContent, err := url2Stat(secondURL.String()) if err != nil { outCh <- diffMessage{ FirstURL: firstContent.URL.String(), SecondURL: secondURL.String(), Diff: "only-in-first", } continue } if diffMsg := diffObjects(firstContent, secondContent); diffMsg != nil { outCh <- *diffMsg continue } if !globalQuietFlag && !globalJSONFlag { // set up progress bar scanBar(firstContent.URL.String()) } } }
// doList - list all entities inside a folder. func doList(clnt client.Client, isRecursive, isIncomplete bool) *probe.Error { prefixPath := clnt.GetURL().Path separator := string(clnt.GetURL().Separator) if !strings.HasSuffix(prefixPath, separator) { prefixPath = prefixPath[:strings.LastIndex(prefixPath, separator)+1] } for content := range clnt.List(isRecursive, isIncomplete) { if content.Err != nil { switch content.Err.ToGoError().(type) { // handle this specifically for filesystem related errors. case client.BrokenSymlink: errorIf(content.Err.Trace(clnt.GetURL().String()), "Unable to list broken link.") continue case client.TooManyLevelsSymlink: errorIf(content.Err.Trace(clnt.GetURL().String()), "Unable to list too many levels link.") continue case client.PathNotFound: errorIf(content.Err.Trace(clnt.GetURL().String()), "Unable to list folder.") continue case client.PathInsufficientPermission: errorIf(content.Err.Trace(clnt.GetURL().String()), "Unable to list folder.") continue } errorIf(content.Err.Trace(clnt.GetURL().String()), "Unable to list folder.") continue } contentURL := content.URL.Path contentURL = strings.TrimPrefix(contentURL, prefixPath) content.URL.Path = contentURL parsedContent := parseContent(content) // print colorized or jsonized content info. printMsg(parsedContent) } return nil }