github.com/motemen/ghq@v1.0.3/cmd_list.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "path/filepath" 6 "strings" 7 "sync" 8 9 "github.com/urfave/cli/v2" 10 ) 11 12 func doList(c *cli.Context) error { 13 var ( 14 w = c.App.Writer 15 query = c.Args().First() 16 exact = c.Bool("exact") 17 vcsBackend = c.String("vcs") 18 printFullPaths = c.Bool("full-path") 19 printUniquePaths = c.Bool("unique") 20 ) 21 22 filterByQuery := func(_ *LocalRepository) bool { 23 return true 24 } 25 if query != "" { 26 if hasSchemePattern.MatchString(query) || scpLikeURLPattern.MatchString(query) { 27 if url, err := newURL(query, false, false); err == nil { 28 if repo, err := LocalRepositoryFromURL(url); err == nil { 29 query = filepath.ToSlash(repo.RelPath) 30 } 31 } 32 } 33 34 if exact { 35 filterByQuery = func(repo *LocalRepository) bool { 36 return repo.Matches(query) 37 } 38 } else { 39 var host string 40 paths := strings.Split(query, "/") 41 if len(paths) > 1 && looksLikeAuthorityPattern.MatchString(paths[0]) { 42 query = strings.Join(paths[1:], "/") 43 host = paths[0] 44 } 45 filterByQuery = func(repo *LocalRepository) bool { 46 return strings.Contains(repo.NonHostPath(), query) && 47 (host == "" || repo.PathParts[0] == host) 48 } 49 } 50 } 51 52 var ( 53 repos []*LocalRepository 54 mu sync.Mutex 55 ) 56 if err := walkLocalRepositories(vcsBackend, func(repo *LocalRepository) { 57 if !filterByQuery(repo) { 58 return 59 } 60 mu.Lock() 61 defer mu.Unlock() 62 repos = append(repos, repo) 63 }); err != nil { 64 return fmt.Errorf("failed to filter repos while walkLocalRepositories(repo): %w", err) 65 } 66 67 if printUniquePaths { 68 subpathCount := map[string]int{} // Count duplicated subpaths (ex. foo/dotfiles and bar/dotfiles) 69 reposCount := map[string]int{} // Check duplicated repositories among roots 70 71 // Primary first 72 for _, repo := range repos { 73 if reposCount[repo.RelPath] == 0 { 74 for _, p := range repo.Subpaths() { 75 subpathCount[p] = subpathCount[p] + 1 76 } 77 } 78 79 reposCount[repo.RelPath] = reposCount[repo.RelPath] + 1 80 } 81 82 for _, repo := range repos { 83 if reposCount[repo.RelPath] > 1 && !repo.IsUnderPrimaryRoot() { 84 continue 85 } 86 87 for _, p := range repo.Subpaths() { 88 if subpathCount[p] == 1 { 89 fmt.Fprintln(w, p) 90 break 91 } 92 } 93 } 94 } else { 95 for _, repo := range repos { 96 if printFullPaths { 97 fmt.Fprintln(w, repo.FullPath) 98 } else { 99 fmt.Fprintln(w, repo.RelPath) 100 } 101 } 102 } 103 return nil 104 }