|
@@ -8,6 +8,7 @@ package main
|
|
|
|
|
|
import (
|
|
|
"bytes"
|
|
|
+ "cmp"
|
|
|
"context"
|
|
|
"crypto/tls"
|
|
|
"errors"
|
|
@@ -26,6 +27,7 @@ import (
|
|
|
"sort"
|
|
|
"strconv"
|
|
|
"syscall"
|
|
|
+ "text/tabwriter"
|
|
|
"time"
|
|
|
|
|
|
"github.com/alecthomas/kong"
|
|
@@ -37,6 +39,7 @@ import (
|
|
|
"github.com/syncthing/syncthing/cmd/syncthing/decrypt"
|
|
|
"github.com/syncthing/syncthing/cmd/syncthing/generate"
|
|
|
"github.com/syncthing/syncthing/internal/db"
|
|
|
+ "github.com/syncthing/syncthing/internal/db/sqlite"
|
|
|
_ "github.com/syncthing/syncthing/lib/automaxprocs"
|
|
|
"github.com/syncthing/syncthing/lib/build"
|
|
|
"github.com/syncthing/syncthing/lib/config"
|
|
@@ -825,24 +828,6 @@ func exitCodeForUpgrade(err error) int {
|
|
|
return svcutil.ExitError.AsInt()
|
|
|
}
|
|
|
|
|
|
-// convertLegacyArgs returns the slice of arguments with single dash long
|
|
|
-// flags converted to double dash long flags.
|
|
|
-func convertLegacyArgs(args []string) []string {
|
|
|
- // Legacy args begin with a single dash, followed by two or more characters.
|
|
|
- legacyExp := regexp.MustCompile(`^-\w{2,}`)
|
|
|
-
|
|
|
- res := make([]string, len(args))
|
|
|
- for i, arg := range args {
|
|
|
- if legacyExp.MatchString(arg) {
|
|
|
- res[i] = "-" + arg
|
|
|
- } else {
|
|
|
- res[i] = arg
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return res
|
|
|
-}
|
|
|
-
|
|
|
type versionCmd struct{}
|
|
|
|
|
|
func (versionCmd) Run() error {
|
|
@@ -900,7 +885,8 @@ func (u upgradeCmd) Run() error {
|
|
|
release, err := checkUpgrade()
|
|
|
if err == nil {
|
|
|
lf := flock.New(locations.Get(locations.LockFile))
|
|
|
- locked, err := lf.TryLock()
|
|
|
+ var locked bool
|
|
|
+ locked, err = lf.TryLock()
|
|
|
if err != nil {
|
|
|
l.Warnln("Upgrade:", err)
|
|
|
os.Exit(1)
|
|
@@ -930,7 +916,8 @@ func (browserCmd) Run() error {
|
|
|
}
|
|
|
|
|
|
type debugCmd struct {
|
|
|
- ResetDatabase resetDatabaseCmd `cmd:"" help:"Reset the database, forcing a full rescan and resync"`
|
|
|
+ ResetDatabase resetDatabaseCmd `cmd:"" help:"Reset the database, forcing a full rescan and resync"`
|
|
|
+ DatabaseStatistics databaseStatsCmd `cmd:"" help:"Display database size statistics"`
|
|
|
}
|
|
|
|
|
|
type resetDatabaseCmd struct{}
|
|
@@ -945,6 +932,43 @@ func (resetDatabaseCmd) Run() error {
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
+type databaseStatsCmd struct{}
|
|
|
+
|
|
|
+func (c databaseStatsCmd) Run() error {
|
|
|
+ db, err := sqlite.Open(locations.Get(locations.Database))
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ ds, err := db.Statistics()
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ tw := tabwriter.NewWriter(os.Stdout, 2, 2, 2, ' ', 0)
|
|
|
+ hdr := fmt.Sprintf("%s\t%s\t%s\t%12s\t%7s\n", "DATABASE", "FOLDER ID", "TABLE", "SIZE", "FILL")
|
|
|
+ fmt.Fprint(tw, hdr)
|
|
|
+ fmt.Fprint(tw, regexp.MustCompile(`[A-Z]`).ReplaceAllString(hdr, "="))
|
|
|
+ c.printStat(tw, ds)
|
|
|
+ return tw.Flush()
|
|
|
+}
|
|
|
+
|
|
|
+func (c databaseStatsCmd) printStat(w io.Writer, s *sqlite.DatabaseStatistics) {
|
|
|
+ for _, table := range s.Tables {
|
|
|
+ fmt.Fprintf(w, "%s\t%s\t%s\t%8d KiB\t%5.01f %%\n", s.Name, cmp.Or(s.FolderID, "-"), table.Name, table.Size/1024, float64(table.Size-table.Unused)*100/float64(table.Size))
|
|
|
+ }
|
|
|
+ for _, next := range s.Children {
|
|
|
+ c.printStat(w, &next)
|
|
|
+ s.Total.Size += next.Total.Size
|
|
|
+ s.Total.Unused += next.Total.Unused
|
|
|
+ }
|
|
|
+
|
|
|
+ totalName := s.Name
|
|
|
+ if len(s.Children) > 0 {
|
|
|
+ totalName += " + children"
|
|
|
+ }
|
|
|
+ fmt.Fprintf(w, "%s\t%s\t%s\t%8d KiB\t%5.01f %%\n", totalName, cmp.Or(s.FolderID, "-"), "(total)", s.Total.Size/1024, float64(s.Total.Size-s.Total.Unused)*100/float64(s.Total.Size))
|
|
|
+}
|
|
|
+
|
|
|
func setConfigDataLocationsFromFlags(homeDir, confDir, dataDir string) error {
|
|
|
homeSet := homeDir != ""
|
|
|
confSet := confDir != ""
|