github.com/anacrolix/torrent@v1.61.0/cmd/torrent2/main.go (about)

     1  // This is an alternate to cmd/torrent which has become bloated with awful argument parsing. Since
     2  // this is my most complicated binary, I will try to build something that satisfies only what I need
     3  // here.
     4  package main
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  	"io"
    10  	"os"
    11  
    12  	"github.com/anacrolix/bargle/v2"
    13  	"github.com/anacrolix/log"
    14  
    15  	"github.com/anacrolix/torrent/merkle"
    16  	"github.com/anacrolix/torrent/metainfo"
    17  )
    18  
    19  func assertOk(err error) {
    20  	if err != nil {
    21  		panic(err)
    22  	}
    23  }
    24  
    25  func bail(str string) {
    26  	panic(str)
    27  }
    28  
    29  func main() {
    30  	err := mainErr()
    31  	if err != nil {
    32  		fmt.Fprintf(os.Stderr, "%v\n", err)
    33  		os.Exit(1)
    34  	}
    35  }
    36  
    37  func mainErr() error {
    38  	p := bargle.NewParser()
    39  	defer p.DoHelpIfHelping()
    40  	runMap := func(m map[string]func()) {
    41  		for key, value := range m {
    42  			if p.Parse(bargle.Keyword(key)) {
    43  				value()
    44  				return
    45  			}
    46  		}
    47  		p.Fail()
    48  	}
    49  	parseFileName := func() (ret string) {
    50  		if p.Parse(bargle.Positional("file", bargle.BuiltinUnmarshaler(&ret))) {
    51  			return
    52  		}
    53  		p.SetError(errors.New("file not specified"))
    54  		panic(p.Fail())
    55  	}
    56  	runMap(map[string]func(){
    57  		"metainfo": func() {
    58  			runMap(map[string]func(){
    59  				"validate-v2": func() {
    60  					mi, err := metainfo.LoadFromFile(parseFileName())
    61  					assertOk(err)
    62  					info, err := mi.UnmarshalInfo()
    63  					assertOk(err)
    64  					if !info.HasV2() {
    65  						bail("not a v2 torrent")
    66  					}
    67  					err = metainfo.ValidatePieceLayers(mi.PieceLayers, &info.FileTree, info.PieceLength)
    68  					assertOk(err)
    69  				},
    70  				"pprint": func() {
    71  					mi, err := metainfo.LoadFromFile(parseFileName())
    72  					assertOk(err)
    73  					info, err := mi.UnmarshalInfo()
    74  					assertOk(err)
    75  					fmt.Printf("name: %q\n", info.Name)
    76  					fmt.Printf("# files:\n")
    77  					files := info.UpvertedFiles()
    78  					pieceIndex := 0
    79  					for _, f := range files {
    80  						numPieces := int((f.Length + info.PieceLength - 1) / info.PieceLength)
    81  						endIndex := pieceIndex + numPieces
    82  						hash := "no v2 pieces root"
    83  						for a := range f.PiecesRoot.Iter {
    84  							hash = a.HexString()
    85  						}
    86  						fmt.Printf(
    87  							"%s: %v: pieces (%v-%v)\n",
    88  							hash,
    89  							func() any {
    90  								if info.IsDir() {
    91  									return fmt.Sprintf("%q", f.BestPath())
    92  								}
    93  								return "(single file torrent)"
    94  							}(),
    95  							pieceIndex,
    96  							endIndex-1,
    97  						)
    98  						pieceIndex = endIndex
    99  					}
   100  				},
   101  			})
   102  		},
   103  		"merkle": func() {
   104  			h := merkle.NewHash()
   105  			n, err := io.Copy(h, os.Stdin)
   106  			log.Printf("copied %v bytes", n)
   107  			if err != nil {
   108  				panic(err)
   109  			}
   110  			fmt.Printf("%x\n", h.Sum(nil))
   111  		},
   112  	})
   113  	p.FailIfArgsRemain()
   114  	return p.Err()
   115  }