182 lines · 4.7 KB · Go
RawDownload
package main import (	"context"	"encoding/json"	"fmt"	"log"	"os"	"path"	"strings"	"time" 	"github.com/spf13/cobra" 	"git.sr.ht/~xenrox/hut/export") type ExportInfo struct {	Instance string    `json:"instance"`	Service  string    `json:"service"`	Date     time.Time `json:"date"`} type exporter struct {	export.Exporter	Name    string	BaseURL string} func newExportCommand() *cobra.Command {	run := func(cmd *cobra.Command, args []string) {		var exporters []exporter 		mc := createClient("meta", cmd)		meta := export.NewMetaExporter(mc.Client)		exporters = append(exporters, exporter{meta, "meta.sr.ht", mc.BaseURL}) 		gc := createClient("git", cmd)		git := export.NewGitExporter(gc.Client, gc.BaseURL)		exporters = append(exporters, exporter{git, "git.sr.ht", gc.BaseURL}) 		hc := createClient("hg", cmd)		hg := export.NewHgExporter(hc.Client, hc.BaseURL)		exporters = append(exporters, exporter{hg, "hg.sr.ht", hc.BaseURL}) 		bc := createClient("builds", cmd)		builds := export.NewBuildsExporter(bc.Client, bc.HTTP)		exporters = append(exporters, exporter{builds, "builds.sr.ht", bc.BaseURL}) 		pc := createClient("paste", cmd)		paste := export.NewPasteExporter(pc.Client, pc.HTTP)		exporters = append(exporters, exporter{paste, "paste.sr.ht", pc.BaseURL}) 		lc := createClient("lists", cmd)		lists := export.NewListsExporter(lc.Client, lc.HTTP)		exporters = append(exporters, exporter{lists, "lists.sr.ht", lc.BaseURL}) 		tc := createClient("todo", cmd)		todo := export.NewTodoExporter(tc.Client, tc.HTTP)		exporters = append(exporters, exporter{todo, "todo.sr.ht", tc.BaseURL}) 		huc := createClient("hub", cmd)		hub := export.NewHubExporter(huc.Client, huc.HTTP,			lc.Client, gc.Client, hc.Client, tc.Client)		exporters = append(exporters, exporter{hub, "hub.sr.ht", huc.BaseURL}) 		if _, ok := os.LookupEnv("SSH_AUTH_SOCK"); !ok {			log.Println("Warning! SSH_AUTH_SOCK is not set in your environment.")			log.Println("Using an SSH agent is advised to avoid unlocking your SSH keys repeatedly during the export.")		} 		ctx := cmd.Context()		log.Println("Exporting account data...") 		out := args[0]		resources := args[1:] 		// Export all services by default		if len(resources) == 0 {			for _, ex := range exporters {				resources = append(resources, ex.BaseURL)			}		} 		for _, resource := range resources {			log.Println(resource) 			var name, owner, instance string			if res := stripProtocol(resource); !strings.Contains(res, "/") {				instance = res			} else {				name, owner, instance = parseResourceName(resource)				owner = strings.TrimLeft(owner, ownerPrefixes)			} 			var ex *exporter			for _, e := range exporters {				if stripProtocol(e.BaseURL) == instance {					ex = &e					break				}			}			if ex == nil {				log.Fatalf("Unknown resource instance: %s", resource)			} 			var err error			if name == "" && owner == "" {				err = exportService(ctx, out, ex)			} else if name != "" && owner != "" {				err = exportResource(ctx, out, ex, owner, name)			} else {				err = fmt.Errorf("unknown resource")			}			if err != nil {				log.Printf("Failed to export %q: %v", resource, err)			}		} 		log.Println("Export complete.")	}	return &cobra.Command{		Use:   "export <directory> [resource|service...]",		Short: "Export your account data",		Args:  cobra.MinimumNArgs(1),		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {			if len(args) <= 1 {				return nil, cobra.ShellCompDirectiveFilterDirs			}			// TODO: completion on export resources			return nil, cobra.ShellCompDirectiveNoFileComp		},		Run: run,	}} func exportService(ctx context.Context, out string, ex *exporter) error {	base := path.Join(out, ex.Name)	if err := os.MkdirAll(base, 0o755); err != nil {		return fmt.Errorf("failed to create export directory: %v", err)	} 	stamp := path.Join(base, "service.json")	if _, err := os.Stat(stamp); err == nil {		log.Printf("Skipping %s (already exported)", ex.Name)		return nil	} 	if err := ex.Export(ctx, base); err != nil {		return err	} 	info := ExportInfo{		Instance: ex.BaseURL,		Service:  ex.Name,		Date:     time.Now().UTC(),	}	if err := writeExportStamp(stamp, &info); err != nil {		return fmt.Errorf("failed writing stamp: %v", err)	} 	return nil} func writeExportStamp(path string, info *ExportInfo) error {	file, err := os.Create(path)	if err != nil {		return err	}	defer file.Close() 	return json.NewEncoder(file).Encode(info)} func exportResource(ctx context.Context, out string, ex *exporter, owner, name string) error {	base := path.Join(out, ex.Name, name)	if err := os.MkdirAll(base, 0o755); err != nil {		return fmt.Errorf("failed to create export directory: %v", err)	} 	return ex.ExportResource(ctx, base, owner, name)}