Thorben Güntherpager: Fix shutdown88da9442 years agoHistory
1304 lines · 33.3 KB · Go
RawDownload
package main import (	"bytes"	"context"	"errors"	"fmt"	"io"	"log"	"net/http"	"net/mail"	"os"	"os/exec"	"strings" 	"github.com/dustin/go-humanize" 	"github.com/spf13/cobra" 	"git.sr.ht/~xenrox/hut/srht/listssrht"	"git.sr.ht/~xenrox/hut/termfmt") func newListsCommand() *cobra.Command {	cmd := &cobra.Command{		Use:   "lists",		Short: "Use the lists API",	}	cmd.AddCommand(newListsDeleteCommand())	cmd.AddCommand(newListsListCommand())	cmd.AddCommand(newListsSubscribeCommand())	cmd.AddCommand(newListsUnsubscribeCommand())	cmd.AddCommand(newListsCreateCommand())	cmd.AddCommand(newListsArchiveCommand())	cmd.AddCommand(newListsPatchsetCommand())	cmd.AddCommand(newListsACLCommand())	cmd.AddCommand(newListsUserWebhookCommand())	cmd.AddCommand(newListsWebhookCommand())	cmd.AddCommand(newListsSubscriptions())	cmd.PersistentFlags().StringP("mailing-list", "l", "", "mailing list name")	cmd.RegisterFlagCompletionFunc("mailing-list", completeList)	return cmd} func newListsDeleteCommand() *cobra.Command {	var autoConfirm bool	run := func(cmd *cobra.Command, args []string) {		ctx := cmd.Context() 		var name, owner, instance string		if len(args) > 0 {			name, owner, instance = parseMailingListName(args[0])		} else {			var err error			name, owner, instance, err = getMailingListName(ctx, cmd)			if err != nil {				log.Fatal(err)			}		}		c := createClientWithInstance("lists", cmd, instance)		id := getMailingListID(c, ctx, name, owner) 		if !autoConfirm && !getConfirmation(fmt.Sprintf("Do you really want to delete the list %s", name)) {			log.Println("Aborted")			return		} 		list, err := listssrht.DeleteMailingList(c.Client, ctx, id)		if err != nil {			log.Fatal(err)		} else if list == nil {			log.Fatalf("failed to delete list with ID %d", id)		} 		log.Printf("Deleted mailing list %s\n", list.Name)	} 	cmd := &cobra.Command{		Use:               "delete [list]",		Short:             "Delete a mailing list",		Args:              cobra.MaximumNArgs(1),		ValidArgsFunction: completeList,		Run:               run,	}	cmd.Flags().BoolVarP(&autoConfirm, "yes", "y", false, "auto confirm")	return cmd} func newListsListCommand() *cobra.Command {	cmd := &cobra.Command{		Use:               "list [username]",		Short:             "List mailing lists",		Args:              cobra.MaximumNArgs(1),		ValidArgsFunction: cobra.NoFileCompletions,	}	cmd.Run = func(cmd *cobra.Command, args []string) {		ctx := cmd.Context()		c := createClient("lists", cmd)		var cursor *listssrht.Cursor		var username string		if len(args) > 0 {			username = strings.TrimLeft(args[0], ownerPrefixes)		} 		err := pagerify(func(p pager) error {			var lists *listssrht.MailingListCursor			if len(username) > 0 {				user, err := listssrht.MailingListsByUser(c.Client, ctx, username, cursor)				if err != nil {					return err				} else if user == nil {					return errors.New("no such user")				}				lists = user.Lists			} else {				var err error				user, err := listssrht.MailingLists(c.Client, ctx, cursor)				if err != nil {					return err				}				lists = user.Lists			} 			for _, list := range lists.Results {				printList(p, &list)			} 			cursor = lists.Cursor			if cursor == nil {				return pagerDone			}			return nil		})		if err != nil {			log.Fatal(err)		}	}	return cmd} func printList(w io.Writer, list *listssrht.MailingList) {	fmt.Fprintf(w, "%s (%s)\n", termfmt.Bold.String(list.Name), list.Visibility.TermString())	if list.Description != nil && *list.Description != "" {		fmt.Fprintln(w, "\n"+indent(*list.Description, "  ")+"\n")	}} func newListsSubscribeCommand() *cobra.Command {	run := func(cmd *cobra.Command, args []string) {		ctx := cmd.Context() 		var name, owner, instance string		if len(args) > 0 {			name, owner, instance = parseMailingListName(args[0])		} else {			var err error			name, owner, instance, err = getMailingListName(ctx, cmd)			if err != nil {				log.Fatal(err)			}		}		c := createClientWithInstance("lists", cmd, instance)		id := getMailingListID(c, ctx, name, owner) 		subscription, err := listssrht.MailingListSubscribe(c.Client, ctx, id)		if err != nil {			log.Fatal(err)		} 		log.Printf("Subscribed to %s/%s/%s\n", c.BaseURL, subscription.List.Owner.CanonicalName, subscription.List.Name)	} 	cmd := &cobra.Command{		Use:               "subscribe [list]",		Short:             "Subscribe to a mailing list",		Args:              cobra.MaximumNArgs(1),		ValidArgsFunction: cobra.NoFileCompletions,		Run:               run,	}	return cmd} func newListsUnsubscribeCommand() *cobra.Command {	run := func(cmd *cobra.Command, args []string) {		ctx := cmd.Context() 		var name, owner, instance string		if len(args) > 0 {			name, owner, instance = parseMailingListName(args[0])		} else {			var err error			name, owner, instance, err = getMailingListName(ctx, cmd)			if err != nil {				log.Fatal(err)			}		}		c := createClientWithInstance("lists", cmd, instance)		id := getMailingListID(c, ctx, name, owner) 		subscription, err := listssrht.MailingListUnsubscribe(c.Client, ctx, id)		if err != nil {			log.Fatal(err)		} else if subscription == nil {			log.Fatalf("you were not subscribed to %s/%s/%s", c.BaseURL, owner, name)		} 		log.Printf("Unsubscribed from %s/%s/%s\n", c.BaseURL, subscription.List.Owner.CanonicalName, subscription.List.Name)	} 	cmd := &cobra.Command{		Use:               "unsubscribe [list]",		Short:             "Unubscribe from a mailing list",		Args:              cobra.MaximumNArgs(1),		ValidArgsFunction: cobra.NoFileCompletions,		Run:               run,	}	return cmd} const listsCreatePrefill = `<!--Please write the Markdown description of the new mailing list above.-->` func newListsCreateCommand() *cobra.Command {	var visibility string	var stdin bool	run := func(cmd *cobra.Command, args []string) {		ctx := cmd.Context()		c := createClient("lists", cmd) 		listVisibility, err := listssrht.ParseVisibility(visibility)		if err != nil {			log.Fatal(err)		} 		var description *string 		if stdin {			b, err := io.ReadAll(os.Stdin)			if err != nil {				log.Fatalf("failed to read mailing list description: %v", err)			} 			desc := string(b)			description = &desc		} else {			text, err := getInputWithEditor("hut_mailing-list*.md", listsCreatePrefill)			if err != nil {				log.Fatalf("failed to read mailing list description: %v", err)			} 			text = dropComment(text, listsCreatePrefill)			description = &text		} 		list, err := listssrht.CreateMailingList(c.Client, ctx, args[0], description, listVisibility)		if err != nil {			log.Fatal(err)		} else if list == nil {			log.Fatal("failed to create mailing list")		} 		log.Printf("Created mailing list %q\n", list.Name)	}	cmd := &cobra.Command{		Use:               "create <name>",		Short:             "Create a mailing list",		Args:              cobra.ExactArgs(1),		ValidArgsFunction: cobra.NoFileCompletions,		Run:               run,	}	cmd.Flags().BoolVar(&stdin, "stdin", false, "read mailing list from stdin")	cmd.Flags().StringVarP(&visibility, "visibility", "v", "public", "mailing list visibility")	cmd.RegisterFlagCompletionFunc("visibility", completeVisibility)	return cmd} func newListsArchiveCommand() *cobra.Command {	var days int	run := func(cmd *cobra.Command, args []string) {		ctx := cmd.Context() 		var name, owner, instance string		if len(args) > 0 {			name, owner, instance = parseMailingListName(args[0])		} else {			var err error			name, owner, instance, err = getMailingListName(ctx, cmd)			if err != nil {				log.Fatal(err)			}		} 		c := createClientWithInstance("lists", cmd, instance)		c.HTTP.Timeout = fileTransferTimeout 		var (			user     *listssrht.User			username string			err      error		)		if owner == "" {			user, err = listssrht.Archive(c.Client, ctx, name)		} else {			username = strings.TrimLeft(owner, ownerPrefixes)			user, err = listssrht.ArchiveByUser(c.Client, ctx, username, name)		}		if err != nil {			log.Fatal(err)		} else if user == nil {			log.Fatalf("no such user %q", username)		} else if user.List == nil {			if owner == "" {				log.Fatalf("no such mailing list %s", name)			}			log.Fatalf("no such mailing list %s/%s/%s", c.BaseURL, owner, name)		} 		url := string(user.List.Archive)		if days != 0 {			url = fmt.Sprintf("%s?since=%d", url, days)		} 		req, err := http.NewRequestWithContext(ctx, http.MethodGet, string(url), nil)		if err != nil {			log.Fatalf("Failed to create request to fetch archive: %v", err)		} 		resp, err := c.HTTP.Do(req)		if err != nil {			log.Fatalf("Failed to fetch archive: %v", err)		}		defer resp.Body.Close() 		if _, err := io.Copy(os.Stdout, resp.Body); err != nil {			log.Fatalf("Failed to copy to stdout: %v", err)		}	} 	cmd := &cobra.Command{		Use:               "archive [list]",		Short:             "Download a mailing list archive",		Args:              cobra.MaximumNArgs(1),		ValidArgsFunction: completeList,		Run:               run,	}	cmd.Flags().IntVarP(&days, "days", "d", 0, "number of last days to download")	cmd.RegisterFlagCompletionFunc("days", cobra.NoFileCompletions)	return cmd} func newListsPatchsetCommand() *cobra.Command {	cmd := &cobra.Command{		Use:   "patchset",		Short: "Manage patchsets",	}	cmd.AddCommand(newListsPatchsetListCommand())	cmd.AddCommand(newListsPatchsetUpdateCommand())	cmd.AddCommand(newListsPatchsetApplyCommand())	cmd.AddCommand(newListsPatchsetShowCommand())	return cmd} func newListsPatchsetListCommand() *cobra.Command {	var byUser bool	run := func(cmd *cobra.Command, args []string) {		ctx := cmd.Context() 		var name, owner, instance string		if len(args) > 0 {			name, owner, instance = parseMailingListName(args[0])		} else {			var err error			name, owner, instance, err = getMailingListName(ctx, cmd)			if err != nil {				log.Fatal(err)			}		}		c := createClientWithInstance("lists", cmd, instance) 		var (			cursor   *listssrht.Cursor			patches  *listssrht.PatchsetCursor			user     *listssrht.User			username string			err      error		) 		if byUser {			if len(args) > 0 {				username = strings.TrimLeft(name, ownerPrefixes)			}		} else {			if owner != "" {				username = strings.TrimLeft(owner, ownerPrefixes)			}		} 		err = pagerify(func(p pager) error {			if byUser {				if username != "" {					user, err = listssrht.PatchesByUser(c.Client, ctx, name, cursor)				} else {					user, err = listssrht.Patches(c.Client, ctx, cursor)				} 				if err != nil {					return err				} else if user == nil {					return fmt.Errorf("no such user %q", name)				} 				patches = user.Patches			} else {				if username != "" {					user, err = listssrht.ListPatchesByUser(c.Client, ctx, username, name, cursor)				} else {					user, err = listssrht.ListPatches(c.Client, ctx, name, cursor)				} 				if err != nil {					return err				} else if user == nil {					return fmt.Errorf("no such user %q", username)				} else if user.List == nil {					return fmt.Errorf("no such list %q", name)				} 				patches = user.List.Patches			} 			for _, patchset := range patches.Results {				printPatchset(p, byUser, &patchset)			} 			cursor = patches.Cursor			if cursor == nil {				return pagerDone			} 			return nil		})		if err != nil {			log.Fatal(err)		}	} 	cmd := &cobra.Command{		Use:               "list [list]",		Short:             "List patchsets",		Args:              cobra.MaximumNArgs(1),		ValidArgsFunction: cobra.NoFileCompletions,		Run:               run,	}	cmd.Flags().BoolVarP(&byUser, "user", "u", false, "list patches by user")	return cmd} func printPatchset(w io.Writer, byUser bool, patchset *listssrht.Patchset) {	s := fmt.Sprintf("%s\t%s\t", termfmt.DarkYellow.Sprintf("#%d", patchset.Id), patchset.Status.TermString())	if patchset.Prefix != nil && *patchset.Prefix != "" {		s += fmt.Sprintf("[%s] ", *patchset.Prefix)	}	s += patchset.Subject	if patchset.Version != 1 {		s += fmt.Sprintf(" v%d", patchset.Version)	} 	created := termfmt.Dim.String(humanize.Time(patchset.Created.Time)) 	if byUser {		s += fmt.Sprintf("\t%s/%s\t%s", patchset.List.Owner.CanonicalName,			patchset.List.Name, created)	} else {		s += fmt.Sprintf("\t%s\t%s", patchset.Submitter.CanonicalName, created)	}	fmt.Fprintln(w, s)} func newListsPatchsetUpdateCommand() *cobra.Command {	var status string	run := func(cmd *cobra.Command, args []string) {		ctx := cmd.Context() 		patchStatus, err := listssrht.ParsePatchsetStatus(status)		if err != nil {			log.Fatal(err)		} 		id, instance, err := parsePatchID(ctx, cmd, args[0])		if err != nil {			log.Fatal(err)		}		c := createClientWithInstance("lists", cmd, instance) 		patch, err := listssrht.UpdatePatchset(c.Client, ctx, id, patchStatus)		if err != nil {			log.Fatal(err)		} else if patch == nil {

Lines 1–500 of 1304.