bridge_pull.go

  1package commands
  2
  3import (
  4	"context"
  5	"fmt"
  6	"os"
  7	"sync"
  8	"time"
  9
 10	"github.com/araddon/dateparse"
 11	"github.com/pkg/errors"
 12	"github.com/spf13/cobra"
 13
 14	"github.com/MichaelMure/git-bug/bridge"
 15	"github.com/MichaelMure/git-bug/bridge/core"
 16	"github.com/MichaelMure/git-bug/cache"
 17	"github.com/MichaelMure/git-bug/util/interrupt"
 18)
 19
 20var (
 21	bridgePullImportSince string
 22	bridgePullNoResume    bool
 23)
 24
 25func runBridgePull(cmd *cobra.Command, args []string) error {
 26	if bridgePullNoResume && bridgePullImportSince != "" {
 27		return fmt.Errorf("only one of --no-resume and --since flags should be used")
 28	}
 29
 30	backend, err := cache.NewRepoCache(repo)
 31	if err != nil {
 32		return err
 33	}
 34	defer backend.Close()
 35	interrupt.RegisterCleaner(backend.Close)
 36
 37	var b *core.Bridge
 38
 39	if len(args) == 0 {
 40		b, err = bridge.DefaultBridge(backend)
 41	} else {
 42		b, err = bridge.LoadBridge(backend, args[0])
 43	}
 44
 45	if err != nil {
 46		return err
 47	}
 48
 49	parentCtx := context.Background()
 50	ctx, cancel := context.WithCancel(parentCtx)
 51	defer cancel()
 52
 53	// buffered channel to avoid send block at the end
 54	done := make(chan struct{}, 1)
 55
 56	var mu sync.Mutex
 57	interruptCount := 0
 58	interrupt.RegisterCleaner(func() error {
 59		mu.Lock()
 60		if interruptCount > 0 {
 61			fmt.Println("Received another interrupt before graceful stop, terminating...")
 62			os.Exit(0)
 63		}
 64
 65		interruptCount++
 66		mu.Unlock()
 67
 68		fmt.Println("Received interrupt signal, stopping the import...\n(Hit ctrl-c again to kill the process.)")
 69
 70		// send signal to stop the importer
 71		cancel()
 72
 73		// block until importer gracefully shutdown
 74		<-done
 75		return nil
 76	})
 77
 78	var events <-chan core.ImportResult
 79	switch {
 80	case bridgePullNoResume:
 81		events, err = b.ImportAllSince(ctx, time.Time{})
 82	case bridgePullImportSince != "":
 83		since, err2 := parseSince(bridgePullImportSince)
 84		if err2 != nil {
 85			return errors.Wrap(err2, "import time parsing")
 86		}
 87		events, err = b.ImportAllSince(ctx, since)
 88	default:
 89		events, err = b.ImportAll(ctx)
 90	}
 91
 92	if err != nil {
 93		return err
 94	}
 95
 96	importedIssues := 0
 97	importedIdentities := 0
 98	for result := range events {
 99		if result.Event != core.ImportEventNothing {
100			fmt.Println(result.String())
101		}
102
103		switch result.Event {
104		case core.ImportEventBug:
105			importedIssues++
106		case core.ImportEventIdentity:
107			importedIdentities++
108		}
109	}
110
111	fmt.Printf("imported %d issues and %d identities with %s bridge\n", importedIssues, importedIdentities, b.Name)
112
113	// send done signal
114	close(done)
115
116	return nil
117}
118
119func parseSince(since string) (time.Time, error) {
120	duration, err := time.ParseDuration(since)
121	if err == nil {
122		return time.Now().Add(-duration), nil
123	}
124
125	return dateparse.ParseLocal(since)
126}
127
128var bridgePullCmd = &cobra.Command{
129	Use:     "pull [<name>]",
130	Short:   "Pull updates.",
131	PreRunE: loadRepoEnsureUser,
132	RunE:    runBridgePull,
133	Args:    cobra.MaximumNArgs(1),
134}
135
136func init() {
137	bridgeCmd.AddCommand(bridgePullCmd)
138	bridgePullCmd.Flags().BoolVarP(&bridgePullNoResume, "no-resume", "n", false, "force importing all bugs")
139	bridgePullCmd.Flags().StringVarP(&bridgePullImportSince, "since", "s", "", "import only bugs updated after the given date (ex: \"200h\" or \"june 2 2019\")")
140}