diff --git a/CHANGELOG.md b/CHANGELOG.md index d52ce52..a8773ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) ## [1.9.14] - unreleased ### Added +- GHORG_NO_DIR_SIZE flag to turn off directory size output which is now enabled by default ### Changed ### Deprecated ### Removed diff --git a/cmd/clone.go b/cmd/clone.go index e595512..b2def4b 100644 --- a/cmd/clone.go +++ b/cmd/clone.go @@ -209,6 +209,10 @@ func cloneFunc(cmd *cobra.Command, argz []string) { os.Setenv("GHORG_NO_TOKEN", "true") } + if cmd.Flags().Changed("no-dir-size") { + os.Setenv("GHORG_NO_DIR_SIZE", "true") + } + if cmd.Flags().Changed("preserve-dir") { os.Setenv("GHORG_PRESERVE_DIRECTORY_STRUCTURE", "true") } @@ -916,7 +920,11 @@ func CloneAllRepos(git git.Gitter, cloneTargets []scm.Repo) { } if os.Getenv("GHORG_QUIET") != "true" { - colorlog.PrintSuccess(fmt.Sprintf("\nFinished! %s", outputDirAbsolutePath)) + if os.Getenv("GHORG_NO_DIR_SIZE") == "false" { + printFinishedWithDirSize() + } else { + colorlog.PrintSuccess(fmt.Sprintf("\nFinished! %s", outputDirAbsolutePath)) + } } if os.Getenv("GHORG_EXIT_CODE_ON_CLONE_INFOS") != "0" && len(cloneInfos) > 0 { @@ -941,6 +949,41 @@ func CloneAllRepos(git git.Gitter, cloneTargets []scm.Repo) { } +func printFinishedWithDirSize() { + dirSizeMB, err := calculateDirSizeInMb(outputDirAbsolutePath) + if err != nil { + if os.Getenv("GHORG_DEBUG") == "true" { + colorlog.PrintError(fmt.Sprintf("Error calculating directory size: %v", err)) + } + colorlog.PrintSuccess(fmt.Sprintf("\nFinished! %s", outputDirAbsolutePath)) + } else { + if dirSizeMB > 1000 { + dirSizeGB := dirSizeMB / 1000 + colorlog.PrintSuccess(fmt.Sprintf("\nFinished! %s (Size: %.2f GB)", outputDirAbsolutePath, dirSizeGB)) + } else { + colorlog.PrintSuccess(fmt.Sprintf("\nFinished! %s (Size: %.2f MB)", outputDirAbsolutePath, dirSizeMB)) + } + } +} + +func calculateDirSizeInMb(path string) (float64, error) { + var size int64 + err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if !info.IsDir() { + size += info.Size() + } + return nil + }) + if err != nil { + return 0, err + } + const bytesInMegabyte = 1000 * 1000 + return float64(size) / bytesInMegabyte, nil // Return size in Megabyte +} + func filterByTargetReposPath(cloneTargets []scm.Repo) []scm.Repo { _, err := os.Stat(os.Getenv("GHORG_TARGET_REPOS_PATH")) diff --git a/cmd/root.go b/cmd/root.go index e08ae55..c60bd0d 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -66,6 +66,7 @@ var ( ghorgReCloneEnvConfigOnly bool noToken bool quietMode bool + noDirSize bool args []string cloneErrors []string cloneInfos []string @@ -145,6 +146,8 @@ func getOrSetDefaults(envVar string) { os.Setenv(envVar, "false") case "GHORG_NO_TOKEN": os.Setenv(envVar, "false") + case "GHORG_NO_DIR_SIZE": + os.Setenv(envVar, "false") case "GHORG_RECLONE_VERBOSE": os.Setenv(envVar, "false") case "GHORG_RECLONE_ENV_CONFIG_ONLY": @@ -228,6 +231,7 @@ func InitConfig() { getOrSetDefaults("GHORG_SKIP_FORKS") getOrSetDefaults("GHORG_NO_CLEAN") getOrSetDefaults("GHORG_NO_TOKEN") + getOrSetDefaults("GHORG_NO_DIR_SIZE") getOrSetDefaults("GHORG_FETCH_ALL") getOrSetDefaults("GHORG_PRUNE") getOrSetDefaults("GHORG_PRUNE_NO_CONFIRM") @@ -312,6 +316,7 @@ func init() { cloneCmd.Flags().BoolVar(&cloneSnippets, "clone-snippets", false, "GHORG_CLONE_SNIPPETS - Additionally clone all snippets, gitlab only") cloneCmd.Flags().BoolVar(&skipForks, "skip-forks", false, "GHORG_SKIP_FORKS - Skips repo if its a fork, github/gitlab/gitea only") cloneCmd.Flags().BoolVar(&noToken, "no-token", false, "GHORG_NO_TOKEN - Allows you to run ghorg with no token (GHORG__TOKEN), SCM server needs to specify no auth required for api calls") + cloneCmd.Flags().BoolVar(&noDirSize, "no-dir-size", false, "GHORG_NO_DIR_SIZE - Skips the calculation of the output directory size at the end of a clone operation. This can save time, especially when cloning a large number of repositories.") cloneCmd.Flags().BoolVar(&preserveDir, "preserve-dir", false, "GHORG_PRESERVE_DIRECTORY_STRUCTURE - Clones repos in a directory structure that matches gitlab namespaces eg company/unit/subunit/app would clone into ghorg/unit/subunit/app, gitlab only") cloneCmd.Flags().BoolVar(&backup, "backup", false, "GHORG_BACKUP - Backup mode, clone as mirror, no working copy (ignores branch parameter)") cloneCmd.Flags().BoolVar(&quietMode, "quiet", false, "GHORG_QUIET - Emit critical output only") diff --git a/sample-conf.yaml b/sample-conf.yaml index 578e099..0beb4f3 100644 --- a/sample-conf.yaml +++ b/sample-conf.yaml @@ -151,6 +151,11 @@ GHORG_EXIT_CODE_ON_CLONE_ISSUES: 1 # flag (--no-token) GHORG_NO_TOKEN: false +# Skips the calculation of the output directory size at the end of a clone operation. +# This can save time, especially when cloning a large number of repositories. +# flag (--no-dir-size) +GHORG_NO_DIR_SIZE: false + # Specifies the location of your ghorg conf.yaml, allowing you to have many configuration files, or none at all # default: ghorg looks in $HOME/.config/ghorg/conf.yaml, if not set in that location nor as a commandline flag, ghorg will use all default values # NOTE: this cannot be set in the configuration file. Its supported through CLI flag and ENV var only.