mirror of
https://github.com/gabrie30/ghorg.git
synced 2025-08-06 22:37:21 +02:00
272 lines
6.0 KiB
Go
272 lines
6.0 KiB
Go
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/briandowns/spinner"
|
|
"github.com/gabrie30/ghorg/colorlog"
|
|
"github.com/gabrie30/ghorg/utils"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var lsCmd = &cobra.Command{
|
|
Use: "ls [dir]",
|
|
Short: "List contents of your ghorg home or ghorg directories",
|
|
Long: `If no dir is specified it will list contents of GHORG_ABSOLUTE_PATH_TO_CLONE_TO`,
|
|
Run: lsFunc,
|
|
}
|
|
|
|
var spinningSpinner *spinner.Spinner
|
|
|
|
func init() {
|
|
spinningSpinner = spinner.New(spinner.CharSets[14], 100*time.Millisecond)
|
|
}
|
|
|
|
func lsFunc(cmd *cobra.Command, argz []string) {
|
|
if len(argz) == 0 {
|
|
listGhorgHome()
|
|
}
|
|
|
|
if len(argz) >= 1 {
|
|
for _, arg := range argz {
|
|
listGhorgDir(arg)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func listGhorgHome() {
|
|
path := os.Getenv("GHORG_ABSOLUTE_PATH_TO_CLONE_TO")
|
|
files, err := os.ReadDir(path)
|
|
if err != nil {
|
|
colorlog.PrintError("No clones found. Please clone some and try again.")
|
|
}
|
|
|
|
longFormat := false
|
|
totalFormat := false
|
|
for _, arg := range os.Args {
|
|
if arg == "-l" || arg == "--long" {
|
|
longFormat = true
|
|
}
|
|
if arg == "-t" || arg == "--total" {
|
|
totalFormat = true
|
|
}
|
|
}
|
|
|
|
if !longFormat && !totalFormat {
|
|
for _, f := range files {
|
|
if f.IsDir() {
|
|
colorlog.PrintInfo(path + f.Name())
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
spinningSpinner.Start()
|
|
|
|
var totalDirs int
|
|
var totalSizeMB float64
|
|
var totalRepos int
|
|
|
|
type result struct {
|
|
dirPath string
|
|
dirSizeMB float64
|
|
subDirCount int
|
|
err error
|
|
}
|
|
|
|
results := make(chan result, len(files))
|
|
var wg sync.WaitGroup
|
|
|
|
for _, f := range files {
|
|
if f.IsDir() {
|
|
totalDirs++
|
|
wg.Add(1)
|
|
go func(f os.DirEntry) {
|
|
defer wg.Done()
|
|
dirPath := filepath.Join(path, f.Name())
|
|
dirSizeMB, err := utils.CalculateDirSizeInMb(dirPath)
|
|
if err != nil {
|
|
results <- result{dirPath: dirPath, err: err}
|
|
return
|
|
}
|
|
|
|
subDirCount := 0
|
|
subFiles, err := os.ReadDir(dirPath)
|
|
if err != nil {
|
|
results <- result{dirPath: dirPath, err: err}
|
|
return
|
|
}
|
|
for _, subFile := range subFiles {
|
|
if subFile.IsDir() {
|
|
subDirCount++
|
|
}
|
|
}
|
|
results <- result{dirPath: dirPath, dirSizeMB: dirSizeMB, subDirCount: subDirCount}
|
|
}(f)
|
|
}
|
|
}
|
|
|
|
go func() {
|
|
wg.Wait()
|
|
close(results)
|
|
}()
|
|
|
|
for res := range results {
|
|
if res.err != nil {
|
|
colorlog.PrintError(fmt.Sprintf("Error processing directory %s: %v", res.dirPath, res.err))
|
|
continue
|
|
}
|
|
totalSizeMB += res.dirSizeMB
|
|
totalRepos += res.subDirCount
|
|
if !totalFormat || longFormat {
|
|
spinningSpinner.Stop()
|
|
if longFormat {
|
|
if res.dirSizeMB > 1000 {
|
|
dirSizeGB := res.dirSizeMB / 1000
|
|
colorlog.PrintInfo(fmt.Sprintf("%-90s %10.2f GB %10d repos", res.dirPath, dirSizeGB, res.subDirCount))
|
|
} else {
|
|
colorlog.PrintInfo(fmt.Sprintf("%-90s %10.2f MB %10d repos", res.dirPath, res.dirSizeMB, res.subDirCount))
|
|
}
|
|
} else {
|
|
colorlog.PrintInfo(res.dirPath)
|
|
}
|
|
}
|
|
}
|
|
|
|
spinningSpinner.Stop()
|
|
if totalFormat {
|
|
if totalSizeMB > 1000 {
|
|
totalSizeGB := totalSizeMB / 1000
|
|
colorlog.PrintSuccess(fmt.Sprintf("Total: %d directories, %.2f GB, %d repos", totalDirs, totalSizeGB, totalRepos))
|
|
} else {
|
|
colorlog.PrintSuccess(fmt.Sprintf("Total: %d directories, %.2f MB, %d repos", totalDirs, totalSizeMB, totalRepos))
|
|
}
|
|
}
|
|
}
|
|
|
|
func listGhorgDir(arg string) {
|
|
|
|
path := os.Getenv("GHORG_ABSOLUTE_PATH_TO_CLONE_TO") + arg
|
|
|
|
_, err := os.ReadDir(path)
|
|
if err != nil {
|
|
// ghorg natively uses underscores in folder names, but a user can specify an output dir with underscores
|
|
// so first try what the user types if not then try replace
|
|
arg = strings.ReplaceAll(arg, "-", "_")
|
|
path = os.Getenv("GHORG_ABSOLUTE_PATH_TO_CLONE_TO") + arg
|
|
}
|
|
|
|
files, err := os.ReadDir(path)
|
|
if err != nil {
|
|
colorlog.PrintError("No clones found. Please clone some and try again.")
|
|
}
|
|
|
|
longFormat := false
|
|
totalFormat := false
|
|
for _, arg := range os.Args {
|
|
if arg == "-l" || arg == "--long" {
|
|
longFormat = true
|
|
}
|
|
if arg == "-t" || arg == "--total" {
|
|
totalFormat = true
|
|
}
|
|
}
|
|
|
|
if !longFormat && !totalFormat {
|
|
for _, f := range files {
|
|
if f.IsDir() {
|
|
str := filepath.Join(path, f.Name())
|
|
colorlog.PrintInfo(str)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
spinningSpinner.Start()
|
|
|
|
var totalDirs int
|
|
var totalSizeMB float64
|
|
|
|
type result struct {
|
|
dirPath string
|
|
dirSizeMB float64
|
|
subDirCount int
|
|
err error
|
|
}
|
|
|
|
results := make(chan result)
|
|
var wg sync.WaitGroup
|
|
|
|
for _, f := range files {
|
|
if f.IsDir() {
|
|
wg.Add(1)
|
|
go func(f os.DirEntry) {
|
|
defer wg.Done()
|
|
dirPath := filepath.Join(path, f.Name())
|
|
dirSizeMB, err := utils.CalculateDirSizeInMb(dirPath)
|
|
if err != nil {
|
|
results <- result{dirPath: dirPath, err: err}
|
|
return
|
|
}
|
|
|
|
// Count the number of directories with a depth of 1 inside
|
|
subDirCount := 0
|
|
subFiles, err := os.ReadDir(dirPath)
|
|
if err != nil {
|
|
results <- result{dirPath: dirPath, err: err}
|
|
return
|
|
}
|
|
for _, subFile := range subFiles {
|
|
if subFile.IsDir() {
|
|
subDirCount++
|
|
}
|
|
}
|
|
results <- result{dirPath: dirPath, dirSizeMB: dirSizeMB, subDirCount: subDirCount}
|
|
}(f)
|
|
}
|
|
}
|
|
|
|
go func() {
|
|
wg.Wait()
|
|
close(results)
|
|
}()
|
|
|
|
for res := range results {
|
|
if res.err != nil {
|
|
colorlog.PrintError(fmt.Sprintf("Error processing directory %s: %v", res.dirPath, res.err))
|
|
continue
|
|
}
|
|
totalSizeMB += res.dirSizeMB
|
|
totalDirs++
|
|
if !totalFormat || longFormat {
|
|
spinningSpinner.Stop()
|
|
if longFormat {
|
|
if res.dirSizeMB > 1000 {
|
|
dirSizeGB := res.dirSizeMB / 1000
|
|
colorlog.PrintInfo(fmt.Sprintf("%-90s %10.2f GB ", res.dirPath, dirSizeGB))
|
|
} else {
|
|
colorlog.PrintInfo(fmt.Sprintf("%-90s %10.2f MB", res.dirPath, res.dirSizeMB))
|
|
}
|
|
} else {
|
|
colorlog.PrintInfo(res.dirPath)
|
|
}
|
|
}
|
|
}
|
|
|
|
spinningSpinner.Stop()
|
|
if totalFormat {
|
|
if totalSizeMB > 1000 {
|
|
totalSizeGB := totalSizeMB / 1000
|
|
colorlog.PrintSuccess(fmt.Sprintf("Total: %d repos, %.2f GB", totalDirs, totalSizeGB))
|
|
} else {
|
|
colorlog.PrintSuccess(fmt.Sprintf("Total: %d repos, %.2f MB", totalDirs, totalSizeMB))
|
|
}
|
|
}
|
|
}
|