]> Sergey Matveev's repositories - btrtrc.git/commitdiff
cmd/torrent: Use anacrolix/args and merge several other cmds in as subcommands
authorMatt Joiner <anacrolix@gmail.com>
Tue, 7 Sep 2021 02:08:31 +0000 (12:08 +1000)
committerMatt Joiner <anacrolix@gmail.com>
Wed, 15 Sep 2021 00:54:14 +0000 (10:54 +1000)
README.md
cmd/torrent-infohash/main.go [deleted file]
cmd/torrent-magnet/main.go [deleted file]
cmd/torrent-metainfo-pprint/main.go [deleted file]
cmd/torrent/announce.go
cmd/torrent/main.go
cmd/torrent/metainfo.go [new file with mode: 0644]
cmd/tracker-announce/main.go [deleted file]
go.mod
go.sum

index 4bda1b91b0f95741822a85e0cf525e7465759676..e821755ee4439613ef9a29b97b5edc9e59478a8c 100644 (file)
--- a/README.md
+++ b/README.md
@@ -55,6 +55,8 @@ Here I'll describe what some of the packages in `./cmd` do. See [installation](#
 
 ### torrent
 
+#### torrent download
+
 Downloads torrents from the command-line.
 
     $ torrent download 'magnet:?xt=urn:btih:KRWPCX3SJUM4IMM4YF5RPHL6ANPYTQPU'
@@ -66,6 +68,15 @@ Downloads torrents from the command-line.
     $ echo such amaze
     wow
 
+#### torrent metainfo magnet
+
+Creates a magnet link from a torrent file. Note the extracted trackers, display name, and info hash.
+
+    $ torrent metainfo testdata/debian-10.8.0-amd64-netinst.iso.torrent magnet
+    magnet:?xt=urn:btih:4090c3c2a394a49974dfbbf2ce7ad0db3cdeddd7&dn=debian-10.8.0-amd64-netinst.iso&tr=http%3A%2F%2Fbttracker.debian.org%3A6969%2Fannounce
+
+See `torrent metainfo --help` for other metainfo related commands.
+
 ### torrentfs
 
 torrentfs mounts a FUSE filesystem at `-mountDir`. The contents are the torrents described by the torrent files and magnet links at `-metainfoDir`. Data for read requests is fetched only as required from the torrent network, and stored at `-downloadDir`.
@@ -81,9 +92,3 @@ torrentfs mounts a FUSE filesystem at `-mountDir`. The contents are the torrents
     996MB 0:04:40 [3.55MB/s] [========================================>] 100%
     1b305d585b1918f297164add46784116  -
 
-### torrent-magnet
-
-Creates a magnet link from a torrent file. Note the extracted trackers, display name, and info hash.
-
-    $ torrent-magnet < torrents/ubuntu-14.04.2-desktop-amd64.iso.torrent
-    magnet:?xt=urn:btih:546cf15f724d19c4319cc17b179d7e035f89c1f4&dn=ubuntu-14.04.2-desktop-amd64.iso&tr=http%3A%2F%2Ftorrent.ubuntu.com%3A6969%2Fannounce&tr=http%3A%2F%2Fipv6.torrent.ubuntu.com%3A6969%2Fannounce
diff --git a/cmd/torrent-infohash/main.go b/cmd/torrent-infohash/main.go
deleted file mode 100644 (file)
index 81319c9..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-package main
-
-import (
-       "fmt"
-       "log"
-
-       "github.com/anacrolix/tagflag"
-
-       "github.com/anacrolix/torrent/metainfo"
-)
-
-func main() {
-       var args struct {
-               tagflag.StartPos
-               Files []string `arity:"+" type:"pos"`
-       }
-       tagflag.Parse(&args)
-       for _, arg := range args.Files {
-               mi, err := metainfo.LoadFromFile(arg)
-               if err != nil {
-                       log.Fatal(err)
-               }
-               fmt.Printf("%s: %s\n", mi.HashInfoBytes().HexString(), arg)
-       }
-}
diff --git a/cmd/torrent-magnet/main.go b/cmd/torrent-magnet/main.go
deleted file mode 100644 (file)
index 8f04a37..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-package main
-
-import (
-       "fmt"
-       "os"
-
-       "github.com/anacrolix/tagflag"
-
-       "github.com/anacrolix/torrent/metainfo"
-)
-
-func main() {
-       tagflag.Parse(nil, tagflag.Description("reads a torrent file from stdin and writes out its magnet link to stdout"))
-
-       mi, err := metainfo.Load(os.Stdin)
-       if err != nil {
-               fmt.Fprintf(os.Stderr, "error reading metainfo from stdin: %s", err)
-               os.Exit(1)
-       }
-       info, err := mi.UnmarshalInfo()
-       if err != nil {
-               fmt.Fprintf(os.Stderr, "error unmarshalling info: %s", err)
-               os.Exit(1)
-       }
-
-       fmt.Fprintf(os.Stdout, "%s\n", mi.Magnet(nil, &info).String())
-}
diff --git a/cmd/torrent-metainfo-pprint/main.go b/cmd/torrent-metainfo-pprint/main.go
deleted file mode 100644 (file)
index cfecc22..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-package main
-
-import (
-       "bufio"
-       "encoding/hex"
-       "encoding/json"
-       "fmt"
-       "io"
-       "log"
-       "os"
-
-       "github.com/anacrolix/envpprof"
-       "github.com/anacrolix/tagflag"
-
-       "github.com/anacrolix/torrent/metainfo"
-)
-
-var flags struct {
-       JustName    bool
-       PieceHashes bool
-       Files       bool
-       tagflag.StartPos
-}
-
-func processReader(r io.Reader) error {
-       metainfo, err := metainfo.Load(r)
-       if err != nil {
-               return err
-       }
-       info, err := metainfo.UnmarshalInfo()
-       if err != nil {
-               return fmt.Errorf("error unmarshalling info: %s", err)
-       }
-       if flags.JustName {
-               fmt.Printf("%s\n", info.Name)
-               return nil
-       }
-       d := map[string]interface{}{
-               "Name":         info.Name,
-               "NumPieces":    info.NumPieces(),
-               "PieceLength":  info.PieceLength,
-               "InfoHash":     metainfo.HashInfoBytes().HexString(),
-               "NumFiles":     len(info.UpvertedFiles()),
-               "TotalLength":  info.TotalLength(),
-               "Announce":     metainfo.Announce,
-               "AnnounceList": metainfo.AnnounceList,
-               "UrlList":      metainfo.UrlList,
-       }
-       if len(metainfo.Nodes) > 0 {
-               d["Nodes"] = metainfo.Nodes
-       }
-       if flags.Files {
-               d["Files"] = info.UpvertedFiles()
-       }
-       if flags.PieceHashes {
-               d["PieceHashes"] = func() (ret []string) {
-                       for i, numPieces := 0, info.NumPieces(); i < numPieces; i += 1 {
-                               ret = append(ret, hex.EncodeToString(info.Pieces[i*20:(i+1)*20]))
-                       }
-                       return
-               }()
-       }
-       b, _ := json.MarshalIndent(d, "", "  ")
-       _, err = os.Stdout.Write(b)
-       return err
-}
-
-func main() {
-       defer envpprof.Stop()
-       tagflag.Parse(&flags)
-       err := processReader(bufio.NewReader(os.Stdin))
-       if err != nil {
-               log.Fatal(err)
-       }
-       if !flags.JustName {
-               os.Stdout.WriteString("\n")
-       }
-}
index 990688a2621a5cf6ee149c85b8a7e122ab5b8076..5ba51be4e2165f6ec939977ca67e11833aa37fec 100644 (file)
@@ -14,7 +14,7 @@ type AnnounceCmd struct {
        InfoHash torrent.InfoHash
 }
 
-func announceErr() error {
+func announceErr(flags AnnounceCmd) error {
        response, err := tracker.Announce{
                TrackerUrl: flags.Tracker,
                Request: tracker.AnnounceRequest{
index 95b99e5c8885a136698407502723dfcaf837ae60..624c2a4ee97b082e7cde31ba637f8dcca7256877 100644 (file)
@@ -16,17 +16,15 @@ import (
        "syscall"
        "time"
 
-       "github.com/alexflint/go-arg"
+       "github.com/anacrolix/args"
        "github.com/anacrolix/envpprof"
+       "github.com/anacrolix/log"
        "github.com/anacrolix/missinggo/v2"
+       "github.com/anacrolix/tagflag"
        "github.com/anacrolix/torrent/bencode"
        "github.com/anacrolix/torrent/version"
        "github.com/davecgh/go-spew/spew"
        "github.com/dustin/go-humanize"
-
-       "github.com/anacrolix/log"
-
-       "github.com/anacrolix/tagflag"
        "golang.org/x/time/rate"
 
        "github.com/anacrolix/torrent"
@@ -85,7 +83,7 @@ func (stringAddr) Network() string   { return "" }
 func (me stringAddr) String() string { return string(me) }
 
 func resolveTestPeers(addrs []string) (ret []torrent.PeerInfo) {
-       for _, ta := range flags.TestPeer {
+       for _, ta := range addrs {
                ret = append(ret, torrent.PeerInfo{
                        Addr: stringAddr(ta),
                })
@@ -93,7 +91,7 @@ func resolveTestPeers(addrs []string) (ret []torrent.PeerInfo) {
        return
 }
 
-func addTorrents(client *torrent.Client) error {
+func addTorrents(client *torrent.Client, flags downloadFlags) error {
        testPeers := resolveTestPeers(flags.TestPeer)
        for _, arg := range flags.Torrent {
                t, err := func() (*torrent.Torrent, error) {
@@ -159,20 +157,11 @@ func addTorrents(client *torrent.Client) error {
        return nil
 }
 
-var flags struct {
+type downloadFlags struct {
        Debug bool
-
-       *DownloadCmd      `arg:"subcommand:download"`
-       *ListFilesCmd     `arg:"subcommand:list-files"`
-       *SpewBencodingCmd `arg:"subcommand:spew-bencoding"`
-       *AnnounceCmd      `arg:"subcommand:announce"`
-       *VersionCmd       `arg:"subcommand:version"`
+       DownloadCmd
 }
 
-type VersionCmd struct{}
-
-type SpewBencodingCmd struct{}
-
 type DownloadCmd struct {
        Mmap               bool           `help:"memory-map torrent data"`
        TestPeer           []string       `help:"addresses of some starting peers"`
@@ -202,17 +191,13 @@ type DownloadCmd struct {
        Torrent []string `arity:"+" help:"torrent file path or magnet uri" arg:"positional"`
 }
 
-type ListFilesCmd struct {
-       TorrentPath string `arg:"positional"`
-}
-
 func stdoutAndStderrAreSameFile() bool {
        fi1, _ := os.Stdout.Stat()
        fi2, _ := os.Stderr.Stat()
        return os.SameFile(fi1, fi2)
 }
 
-func statsEnabled() bool {
+func statsEnabled(flags downloadFlags) bool {
        if flags.Stats == nil {
                return flags.Debug
        }
@@ -238,53 +223,73 @@ func main() {
 
 func mainErr() error {
        stdLog.SetFlags(stdLog.Flags() | stdLog.Lshortfile)
-       p := arg.MustParse(&flags)
-       switch {
-       case flags.AnnounceCmd != nil:
-               return announceErr()
-       //case :
-       //      return announceErr(flags.Args, parser)
-       case flags.DownloadCmd != nil:
-               return downloadErr()
-       case flags.ListFilesCmd != nil:
-               mi, err := metainfo.LoadFromFile(flags.ListFilesCmd.TorrentPath)
-               if err != nil {
-                       return fmt.Errorf("loading from file %q: %v", flags.ListFilesCmd.TorrentPath, err)
-               }
-               info, err := mi.UnmarshalInfo()
-               if err != nil {
-                       return fmt.Errorf("unmarshalling info from metainfo at %q: %v", flags.ListFilesCmd.TorrentPath, err)
-               }
-               for _, f := range info.UpvertedFiles() {
-                       fmt.Println(f.DisplayPath(&info))
-               }
-               return nil
-       case flags.SpewBencodingCmd != nil:
-               d := bencode.NewDecoder(os.Stdin)
-               for i := 0; ; i++ {
-                       var v interface{}
-                       err := d.Decode(&v)
-                       if err == io.EOF {
-                               break
+       debug := args.Flag(args.FlagOpt{Long: "debug"})
+       p := args.ParseMain(
+               debug,
+               args.Subcommand("metainfo", metainfoCmd),
+               args.Subcommand("announce", func(p args.SubCmdCtx) error {
+                       var cmd AnnounceCmd
+                       err := p.NewParser().AddParams(
+                               args.Pos("tracker", &cmd.Tracker),
+                               args.Pos("infohash", &cmd.InfoHash)).Parse()
+                       if err != nil {
+                               return err
                        }
+                       return announceErr(cmd)
+               }),
+               args.Subcommand("download", func(p args.SubCmdCtx) error {
+                       var dlf DownloadCmd
+                       err := p.NewParser().AddParams(
+                               append(args.FromStruct(&dlf), debug)...,
+                       ).Parse()
                        if err != nil {
-                               return fmt.Errorf("decoding message index %d: %w", i, err)
+                               return err
                        }
-                       spew.Dump(v)
+                       return downloadErr(downloadFlags{
+                               Debug:       debug.Bool(),
+                               DownloadCmd: dlf,
+                       })
+               }),
+               args.Subcommand(
+                       "spew-bencoding",
+                       func(p args.SubCmdCtx) error {
+                               d := bencode.NewDecoder(os.Stdin)
+                               for i := 0; ; i++ {
+                                       var v interface{}
+                                       err := d.Decode(&v)
+                                       if err == io.EOF {
+                                               break
+                                       }
+                                       if err != nil {
+                                               return fmt.Errorf("decoding message index %d: %w", i, err)
+                                       }
+                                       spew.Dump(v)
+                               }
+                               return nil
+                       },
+                       args.Help("reads bencoding from stdin into Go native types and spews the result"),
+               ),
+               args.Subcommand("version", func(p args.SubCmdCtx) error {
+                       fmt.Printf("HTTP User-Agent: %q\n", version.DefaultHttpUserAgent)
+                       fmt.Printf("Torrent client version: %q\n", version.DefaultExtendedHandshakeClientVersion)
+                       fmt.Printf("Torrent version prefix: %q\n", version.DefaultBep20Prefix)
+                       return nil
+               }),
+       )
+       if p.Err != nil {
+               if errors.Is(p.Err, args.ErrHelped) {
+                       return nil
                }
-               return nil
-       case flags.VersionCmd != nil:
-               fmt.Printf("HTTP User-Agent: %q\n", version.DefaultHttpUserAgent)
-               fmt.Printf("Torrent client version: %q\n", version.DefaultExtendedHandshakeClientVersion)
-               fmt.Printf("Torrent version prefix: %q\n", version.DefaultBep20Prefix)
-               return nil
-       default:
-               p.Fail(fmt.Sprintf("unexpected subcommand: %v", p.Subcommand()))
-               panic("unreachable")
+               return p.Err
        }
+       if !p.RanSubCmd {
+               p.PrintChoices(os.Stderr)
+               args.FatalUsage()
+       }
+       return nil
 }
 
-func downloadErr() error {
+func downloadErr(flags downloadFlags) error {
        clientConfig := torrent.NewDefaultClientConfig()
        clientConfig.DisableWebseeds = flags.DisableWebseeds
        clientConfig.DisableTCP = !flags.TcpPeers
@@ -331,7 +336,7 @@ func downloadErr() error {
 
        client, err := torrent.NewClient(clientConfig)
        if err != nil {
-               return fmt.Errorf("creating client: %v", err)
+               return fmt.Errorf("creating client: %w", err)
        }
        var clientClose sync.Once //In certain situations, close was being called more than once.
        defer clientClose.Do(client.Close)
@@ -346,11 +351,11 @@ func downloadErr() error {
        http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
                client.WriteStatus(w)
        })
-       err = addTorrents(client)
+       err = addTorrents(client, flags)
        if err != nil {
                return fmt.Errorf("adding torrents: %w", err)
        }
-       defer outputStats(client)
+       defer outputStats(client, flags)
        if client.WaitAll() {
                log.Print("downloaded ALL the torrents")
        } else {
@@ -360,15 +365,15 @@ func downloadErr() error {
                if len(client.Torrents()) == 0 {
                        log.Print("no torrents to seed")
                } else {
-                       outputStats(client)
+                       outputStats(client, flags)
                        <-stop.C()
                }
        }
        return nil
 }
 
-func outputStats(cl *torrent.Client) {
-       if !statsEnabled() {
+func outputStats(cl *torrent.Client, args downloadFlags) {
+       if !statsEnabled(args) {
                return
        }
        expvar.Do(func(kv expvar.KeyValue) {
diff --git a/cmd/torrent/metainfo.go b/cmd/torrent/metainfo.go
new file mode 100644 (file)
index 0000000..720ac33
--- /dev/null
@@ -0,0 +1,105 @@
+package main
+
+import (
+       "encoding/hex"
+       "encoding/json"
+       "fmt"
+       "os"
+
+       "github.com/anacrolix/args"
+       "github.com/anacrolix/torrent/metainfo"
+       "github.com/bradfitz/iter"
+)
+
+type pprintMetainfoFlags struct {
+       JustName    bool
+       PieceHashes bool
+       Files       bool
+}
+
+func metainfoCmd(ctx args.SubCmdCtx) (err error) {
+       var metainfoPath string
+       var mi *metainfo.MetaInfo
+       return ctx.NewParser().AddParams(
+               args.Pos("torrent file", &metainfoPath, args.AfterParse(func() (err error) {
+                       mi, err = metainfo.LoadFromFile(metainfoPath)
+                       return
+               })),
+               args.Subcommand("magnet", func(ctx args.SubCmdCtx) (err error) {
+                       info, err := mi.UnmarshalInfo()
+                       if err != nil {
+                               return
+                       }
+                       fmt.Fprintf(os.Stdout, "%s\n", mi.Magnet(nil, &info).String())
+                       return nil
+               }),
+               args.Subcommand("pprint", func(ctx args.SubCmdCtx) (err error) {
+                       var flags pprintMetainfoFlags
+                       err = ctx.NewParser().AddParams(args.FromStruct(&flags)...).Parse()
+                       if err != nil {
+                               return
+                       }
+                       err = pprintMetainfo(mi, flags)
+                       if err != nil {
+                               return
+                       }
+                       if !flags.JustName {
+                               os.Stdout.WriteString("\n")
+                       }
+                       return
+               }),
+               args.Subcommand("infohash", func(ctx args.SubCmdCtx) (err error) {
+                       fmt.Printf("%s: %s\n", mi.HashInfoBytes().HexString(), metainfoPath)
+                       return nil
+               }),
+               args.Subcommand("list-files", func(ctx args.SubCmdCtx) (err error) {
+                       info, err := mi.UnmarshalInfo()
+                       if err != nil {
+                               return fmt.Errorf("unmarshalling info from metainfo at %q: %v", metainfoPath, err)
+                       }
+                       for _, f := range info.UpvertedFiles() {
+                               fmt.Println(f.DisplayPath(&info))
+                       }
+                       return nil
+               }),
+       ).Parse()
+}
+
+func pprintMetainfo(metainfo *metainfo.MetaInfo, flags pprintMetainfoFlags) error {
+       info, err := metainfo.UnmarshalInfo()
+       if err != nil {
+               return fmt.Errorf("error unmarshalling info: %s", err)
+       }
+       if flags.JustName {
+               fmt.Printf("%s\n", info.Name)
+               return nil
+       }
+       d := map[string]interface{}{
+               "Name":         info.Name,
+               "NumPieces":    info.NumPieces(),
+               "PieceLength":  info.PieceLength,
+               "InfoHash":     metainfo.HashInfoBytes().HexString(),
+               "NumFiles":     len(info.UpvertedFiles()),
+               "TotalLength":  info.TotalLength(),
+               "Announce":     metainfo.Announce,
+               "AnnounceList": metainfo.AnnounceList,
+               "UrlList":      metainfo.UrlList,
+       }
+       if len(metainfo.Nodes) > 0 {
+               d["Nodes"] = metainfo.Nodes
+       }
+       if flags.Files {
+               d["Files"] = info.UpvertedFiles()
+       }
+       if flags.PieceHashes {
+               d["PieceHashes"] = func() (ret []string) {
+                       for i := range iter.N(info.NumPieces()) {
+                               ret = append(ret, hex.EncodeToString(info.Pieces[i*20:(i+1)*20]))
+                       }
+                       return
+               }()
+       }
+       b, _ := json.MarshalIndent(d, "", "  ")
+       _, err = os.Stdout.Write(b)
+       return err
+}
diff --git a/cmd/tracker-announce/main.go b/cmd/tracker-announce/main.go
deleted file mode 100644 (file)
index 511c783..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-package main
-
-import (
-       "fmt"
-       "log"
-       "net/url"
-       "os"
-       "strings"
-       "sync"
-       "sync/atomic"
-
-       "github.com/anacrolix/tagflag"
-       "github.com/anacrolix/torrent"
-       "github.com/anacrolix/torrent/metainfo"
-       "github.com/anacrolix/torrent/tracker"
-       "github.com/davecgh/go-spew/spew"
-)
-
-func argSpec(arg string) (ts *torrent.TorrentSpec, _ error) {
-       if strings.HasPrefix(arg, "magnet:") {
-               return torrent.TorrentSpecFromMagnetUri(arg)
-       }
-       mi, fileErr := metainfo.LoadFromFile(arg)
-       if fileErr == nil {
-               ts = torrent.TorrentSpecFromMetaInfo(mi)
-               return
-       }
-       var ih torrent.InfoHash
-       ihErr := ih.FromHexString(arg)
-       if ihErr == nil {
-               ts = &torrent.TorrentSpec{
-                       InfoHash: ih,
-               }
-               return
-       }
-       if len(arg) == 40 {
-               return nil, ihErr
-       } else {
-               return nil, fileErr
-       }
-}
-
-func main() {
-       flags := struct {
-               Port    uint16
-               Tracker []string
-               tagflag.StartPos
-               Torrents []string `arity:"+"`
-       }{
-               Port: 50007,
-       }
-       tagflag.Parse(&flags)
-       var exitCode int32
-       var wg sync.WaitGroup
-       startAnnounce := func(ih torrent.InfoHash, tURI string) {
-               ar := tracker.AnnounceRequest{
-                       NumWant:  -1,
-                       Left:     -1,
-                       Port:     flags.Port,
-                       InfoHash: ih,
-               }
-               wg.Add(1)
-               go func(tURI string) {
-                       defer wg.Done()
-                       if doTracker(tURI, ar) {
-                               atomic.StoreInt32(&exitCode, 1)
-                       }
-               }(tURI)
-       }
-       for _, arg := range flags.Torrents {
-               ts, err := argSpec(arg)
-               if err != nil {
-                       log.Fatal(err)
-               }
-               for _, tier := range ts.Trackers {
-                       for _, tURI := range tier {
-                               startAnnounce(ts.InfoHash, tURI)
-                       }
-               }
-               for _, tUri := range flags.Tracker {
-                       startAnnounce(ts.InfoHash, tUri)
-               }
-       }
-       wg.Wait()
-       os.Exit(int(exitCode))
-}
-
-func doTracker(tURI string, ar tracker.AnnounceRequest) (hadError bool) {
-       for _, res := range announces(tURI, ar) {
-               err := res.error
-               resp := res.AnnounceResponse
-               if err != nil {
-                       hadError = true
-                       log.Printf("error announcing to %q: %s", tURI, err)
-                       continue
-               }
-               fmt.Printf("from %q for %x:\n%s", tURI, ar.InfoHash, spew.Sdump(resp))
-       }
-       return
-}
-
-type announceResult struct {
-       tracker.AnnounceResponse
-       error
-}
-
-func announces(uri string, ar tracker.AnnounceRequest) (ret []announceResult) {
-       u, err := url.Parse(uri)
-       if err != nil {
-               return []announceResult{{error: err}}
-       }
-       a := tracker.Announce{
-               Request:    ar,
-               TrackerUrl: uri,
-       }
-       if u.Scheme == "udp" {
-               a.UdpNetwork = "udp4"
-               ret = append(ret, announce(a))
-               a.UdpNetwork = "udp6"
-               ret = append(ret, announce(a))
-               return
-       }
-       return []announceResult{announce(a)}
-}
-
-func announce(a tracker.Announce) announceResult {
-       resp, err := a.Do()
-       return announceResult{resp, err}
-}
diff --git a/go.mod b/go.mod
index dcbe602c596174a5ab62105dce86986e346008fd..843bee23cf5ee840c94461d3ad90a0c1e7cca69d 100644 (file)
--- a/go.mod
+++ b/go.mod
@@ -5,6 +5,7 @@ require (
        crawshaw.io/sqlite v0.3.3-0.20210127221821-98b1f83c5508
        github.com/RoaringBitmap/roaring v0.9.4
        github.com/alexflint/go-arg v1.4.2
+       github.com/anacrolix/args v0.1.0
        github.com/anacrolix/chansync v0.2.1-0.20210910114620-14955c95ded9
        github.com/anacrolix/confluence v1.8.0 // indirect
        github.com/anacrolix/dht/v2 v2.10.5-0.20210902001729-06cc4fe90e53
diff --git a/go.sum b/go.sum
index 4dc4fcefade9aa12761d402d0361eeb84d1bdcc8..507f5040eb79e3dc7a3548f11db74c609b446923 100644 (file)
--- a/go.sum
+++ b/go.sum
@@ -44,8 +44,9 @@ github.com/alexflint/go-arg v1.4.2/go.mod h1:9iRbDxne7LcR/GSvEr7ma++GLpdIU1zrghf
 github.com/alexflint/go-scalar v1.0.0/go.mod h1:GpHzbCOZXEKMEcygYQ5n/aa4Aq84zbxjy3MxYW0gjYw=
 github.com/alexflint/go-scalar v1.1.0 h1:aaAouLLzI9TChcPXotr6gUhq+Scr8rl0P9P4PnltbhM=
 github.com/alexflint/go-scalar v1.1.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o=
+github.com/anacrolix/args v0.1.0 h1:gcDj4DgjLhe+f311XqQ8eC6wYyKhZocxXUTeDvezAJ0=
+github.com/anacrolix/args v0.1.0/go.mod h1:RCPBt2vU1GJn4gG9rL+fuYu7ivnE9tmK2pHm63t3yO0=
 github.com/anacrolix/chansync v0.0.0-20210524073341-a336ebc2de92/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k=
-github.com/anacrolix/chansync v0.1.0 h1:4cIfJmEV8sYkSEMW2AXnPjX6iQT4plqELJ65pLna6OA=
 github.com/anacrolix/chansync v0.1.0/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k=
 github.com/anacrolix/chansync v0.1.1-0.20210904130811-9cd7139c8dd9 h1:Jk3Mdr+XbO1uvf/+nUXjb/M1dPDNPQThxKmS5MLGE+w=
 github.com/anacrolix/chansync v0.1.1-0.20210904130811-9cd7139c8dd9/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k=