Support multiple file/directory arguments for all commands

- Change sum add, sum update, check, and clear to accept 1+ paths
- Update README usage examples to show multiple path support
- Add TODO section with planned future improvements
This commit is contained in:
Jeffrey Paul 2026-02-01 03:21:36 -08:00
parent 9ad48fb9b0
commit c856ea25be
2 changed files with 61 additions and 18 deletions

View File

@ -31,20 +31,20 @@ Semantic Versioning 2.0.0 is used for tags.
## Usage ## Usage
```bash ```bash
# add checksum & timestamp xattrs to every regular file under DIR # add checksum & timestamp xattrs to every regular file under one or more paths
attrsum sum add DIR attrsum sum add DIR1 DIR2 file.txt
# update checksum only when file mtime is newer than stored sumtime # update checksum only when file mtime is newer than stored sumtime
attrsum sum update DIR attrsum sum update DIR1 DIR2
# verify checksums, stop on first error # verify checksums, stop on first error
attrsum check DIR attrsum check DIR1 DIR2
# verify every file, reporting each result, keep going after errors # verify every file, reporting each result, keep going after errors
attrsum -v check --continue DIR attrsum -v check --continue DIR1 DIR2
# remove checksum & timestamp xattrs # remove checksum & timestamp xattrs
attrsum clear DIR attrsum clear DIR1 DIR2
``` ```
| xattr key | meaning | | xattr key | meaning |
@ -71,6 +71,21 @@ required. Now you can trust a USB stick didn't eat your data.
--- ---
## TODO
Future improvements under consideration:
- **Quiet mode (`-q`)** — suppress all output except errors
- **Dry-run mode (`--dry-run`, `-n`)** — show what would be done without making changes
- **JSON output (`--json`)** — machine-readable output for scripting and integration
- **Parallel processing (`-j N`)** — use multiple goroutines for faster checksumming on large trees
- **Progress indicator** — show progress bar or spinner for long-running operations
- **Summary report** — print statistics on completion (files processed, errors, bytes hashed)
- **Read paths from stdin (`-`)** — support piping file lists, e.g. `find ... | attrsum sum add -`
- **Exit code documentation** — formalize and document exit codes for scripting
---
## Contributing ## Contributing
* Author & maintainer: **sneak** <sneak@sneak.berlin> * Author & maintainer: **sneak** <sneak@sneak.berlin>

View File

@ -62,17 +62,31 @@ func newSumCmd() *cobra.Command {
} }
add := &cobra.Command{ add := &cobra.Command{
Use: "add <dir>", Use: "add <path>...",
Short: "Write checksums for files missing them", Short: "Write checksums for files missing them",
Args: cobra.ExactArgs(1), Args: cobra.MinimumNArgs(1),
RunE: func(_ *cobra.Command, a []string) error { return ProcessSumAdd(a[0]) }, RunE: func(_ *cobra.Command, a []string) error {
for _, p := range a {
if err := ProcessSumAdd(p); err != nil {
return err
}
}
return nil
},
} }
upd := &cobra.Command{ upd := &cobra.Command{
Use: "update <dir>", Use: "update <path>...",
Short: "Recalculate checksum when file newer than stored sumtime", Short: "Recalculate checksum when file newer than stored sumtime",
Args: cobra.ExactArgs(1), Args: cobra.MinimumNArgs(1),
RunE: func(_ *cobra.Command, a []string) error { return ProcessSumUpdate(a[0]) }, RunE: func(_ *cobra.Command, a []string) error {
for _, p := range a {
if err := ProcessSumUpdate(p); err != nil {
return err
}
}
return nil
},
} }
cmd.AddCommand(add, upd) cmd.AddCommand(add, upd)
@ -129,10 +143,17 @@ func readSumTime(path string) (time.Time, error) {
func newClearCmd() *cobra.Command { func newClearCmd() *cobra.Command {
return &cobra.Command{ return &cobra.Command{
Use: "clear <dir>", Use: "clear <path>...",
Short: "Remove checksum xattrs from tree", Short: "Remove checksum xattrs from tree",
Args: cobra.ExactArgs(1), Args: cobra.MinimumNArgs(1),
RunE: func(_ *cobra.Command, a []string) error { return ProcessClear(a[0]) }, RunE: func(_ *cobra.Command, a []string) error {
for _, p := range a {
if err := ProcessClear(p); err != nil {
return err
}
}
return nil
},
} }
} }
@ -164,10 +185,17 @@ func ProcessClear(dir string) error {
func newCheckCmd() *cobra.Command { func newCheckCmd() *cobra.Command {
var cont bool var cont bool
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "check <dir>", Use: "check <path>...",
Short: "Verify stored checksums", Short: "Verify stored checksums",
Args: cobra.ExactArgs(1), Args: cobra.MinimumNArgs(1),
RunE: func(_ *cobra.Command, a []string) error { return ProcessCheck(a[0], cont) }, RunE: func(_ *cobra.Command, a []string) error {
for _, p := range a {
if err := ProcessCheck(p, cont); err != nil {
return err
}
}
return nil
},
} }
cmd.Flags().BoolVar(&cont, "continue", false, "continue after errors and report each file") cmd.Flags().BoolVar(&cont, "continue", false, "continue after errors and report each file")
return cmd return cmd