func (p *parser) printUsage(w io.Writer) { fmt.Fprintf(w, "Usage:\n %s", p.program) if p.hasOptions() { fmt.Fprintf(w, " [OPTIONS...]") } for _, arg := range p.posArgs { fs := func() string { switch arg.arity { case arity{0, 1}: return "[%s]" case arity{1, infArity}: return "%s..." case arity{0, infArity}: return "[%s...]" default: return "<%s>" } }() // if arg.arity != arity{1,1} { fmt.Fprintf(w, " "+fs, arg.name) // } // if arg.arity > 1 { // for range iter.N(int(arg.arity - 1)) { // fmt.Fprintf(w, " "+fs, arg.name) // } // } } fmt.Fprintf(w, "\n") if p.description != "" { fmt.Fprintf(w, "\n%s\n", missinggo.Unchomp(p.description)) } if awd := p.posWithHelp(); len(awd) != 0 { fmt.Fprintf(w, "Arguments:\n") tw := newUsageTabwriter(w) for _, a := range awd { fmt.Fprintf(tw, " %s\t(%s)\t%s\n", a.name, a.value.Type(), a.help) } tw.Flush() } var opts []arg for _, v := range p.flags { opts = append(opts, v) } slices.Sort(opts, func(left, right arg) bool { return left.name < right.name }) writeOptionUsage(w, opts) }
// This is a helper that sets Files and Pieces from a root path and its // children. func (info *Info) BuildFromFilePath(root string) (err error) { info.Name = filepath.Base(root) info.Files = nil err = filepath.Walk(root, func(path string, fi os.FileInfo, err error) error { if err != nil { return err } if fi.IsDir() { // Directories are implicit in torrent files. return nil } else if path == root { // The root is a file. info.Length = fi.Size() return nil } relPath, err := filepath.Rel(root, path) log.Println(relPath, err) if err != nil { return fmt.Errorf("error getting relative path: %s", err) } info.Files = append(info.Files, FileInfo{ Path: strings.Split(relPath, string(filepath.Separator)), Length: fi.Size(), }) return nil }) if err != nil { return } slices.Sort(info.Files, func(l, r FileInfo) bool { return strings.Join(l.Path, "/") < strings.Join(r.Path, "/") }) err = info.GeneratePieces(func(fi FileInfo) (io.ReadCloser, error) { return os.Open(filepath.Join(root, strings.Join(fi.Path, string(filepath.Separator)))) }) if err != nil { err = fmt.Errorf("error generating pieces: %s", err) } return }
func (t *Torrent) writeStatus(w io.Writer, cl *Client) { fmt.Fprintf(w, "Infohash: %x\n", t.infoHash) fmt.Fprintf(w, "Metadata length: %d\n", t.metadataSize()) if !t.haveInfo() { fmt.Fprintf(w, "Metadata have: ") for _, h := range t.metadataCompletedChunks { fmt.Fprintf(w, "%c", func() rune { if h { return 'H' } else { return '.' } }()) } fmt.Fprintln(w) } fmt.Fprintf(w, "Piece length: %s\n", func() string { if t.haveInfo() { return fmt.Sprint(t.usualPieceSize()) } else { return "?" } }()) if t.haveInfo() { fmt.Fprintf(w, "Num Pieces: %d\n", t.numPieces()) fmt.Fprint(w, "Piece States:") for _, psr := range t.pieceStateRuns() { w.Write([]byte(" ")) w.Write([]byte(pieceStateRunStatusChars(psr))) } fmt.Fprintln(w) } fmt.Fprintf(w, "Reader Pieces:") t.forReaderOffsetPieces(func(begin, end int) (again bool) { fmt.Fprintf(w, " %d:%d", begin, end) return true }) fmt.Fprintln(w) fmt.Fprintf(w, "Trackers:\n") func() { tw := tabwriter.NewWriter(w, 0, 0, 2, ' ', 0) fmt.Fprintf(tw, " URL\tNext announce\tLast announce\n") for _, ta := range slices.Sort(slices.FromMapElems(t.trackerAnnouncers), func(l, r *trackerScraper) bool { return l.url < r.url }).([]*trackerScraper) { fmt.Fprintf(tw, " %s\n", ta.statusLine()) } tw.Flush() }() fmt.Fprintf(w, "DHT Announces: %d\n", t.numDHTAnnounces) fmt.Fprintf(w, "Pending peers: %d\n", len(t.peers)) fmt.Fprintf(w, "Half open: %d\n", len(t.halfOpen)) fmt.Fprintf(w, "Active peers: %d\n", len(t.conns)) slices.Sort(t.conns, worseConn) for i, c := range t.conns { fmt.Fprintf(w, "%2d. ", i+1) c.WriteStatus(w, t) } }