1package commands
2
3import (
4	"fmt"
5	"runtime"
6	"strconv"
7
8	update "github.com/inconshreveable/go-update"
9	"github.com/vbauerster/mpb/v4"
10	"github.com/vbauerster/mpb/v4/decor"
11
12	"github.com/concourse/concourse"
13	"github.com/concourse/concourse/atc"
14	"github.com/concourse/concourse/fly/commands/internal/displayhelpers"
15	"github.com/concourse/concourse/fly/rc"
16	"github.com/concourse/concourse/fly/ui"
17)
18
19type SyncCommand struct {
20	Force          bool         `long:"force" short:"f" description:"Sync even if versions already match."`
21	ATCURL         string       `long:"concourse-url" short:"c" description:"Concourse URL to sync with"`
22	Insecure       bool         `short:"k" long:"insecure" description:"Skip verification of the endpoint's SSL certificate"`
23	CACert         atc.PathFlag `long:"ca-cert" description:"Path to Concourse PEM-encoded CA certificate file."`
24	ClientCertPath atc.PathFlag `long:"client-cert" description:"Path to a PEM-encoded client certificate file."`
25	ClientKeyPath  atc.PathFlag `long:"client-key" description:"Path to a PEM-encoded client key file."`
26}
27
28func (command *SyncCommand) Execute(args []string) error {
29	var target rc.Target
30	var err error
31
32	if Fly.Target != "" {
33		target, err = rc.LoadTarget(Fly.Target, Fly.Verbose)
34	} else {
35		target, err = rc.NewUnauthenticatedTarget(
36			"dummy",
37			command.ATCURL,
38			"",
39			command.Insecure,
40			string(command.CACert),
41			string(command.ClientCertPath),
42			string(command.ClientKeyPath),
43			Fly.Verbose,
44		)
45	}
46	if err != nil {
47		return err
48	}
49
50	info, err := target.Client().GetInfo()
51	if err != nil {
52		return err
53	}
54
55	if !command.Force && info.Version == concourse.Version {
56		fmt.Printf("version %s already matches; skipping\n", info.Version)
57		return nil
58	}
59
60	updateOptions := update.Options{}
61	err = updateOptions.CheckPermissions()
62	if err != nil {
63		displayhelpers.FailWithErrorf("update failed", err)
64	}
65
66	client := target.Client()
67	body, headers, err := client.GetCLIReader(runtime.GOARCH, runtime.GOOS)
68	if err != nil {
69		return err
70	}
71
72	fmt.Printf("downloading fly from %s...\n", client.URL())
73	fmt.Println()
74
75	size, err := strconv.ParseInt(headers.Get("Content-Length"), 10, 64)
76	if err != nil {
77		fmt.Printf("warning: failed to parse Content-Length: %s\n", err)
78		size = 0
79	}
80
81	progress := mpb.New(mpb.WithWidth(50))
82
83	progressBar := progress.AddBar(
84		size,
85		mpb.PrependDecorators(decor.Name("fly "+ui.Embolden("v"+info.Version))),
86		mpb.AppendDecorators(decor.CountersKibiByte("%.1f/%.1f")),
87	)
88
89	err = update.Apply(progressBar.ProxyReader(body), updateOptions)
90	if err != nil {
91		displayhelpers.FailWithErrorf("failed to apply update", err)
92	}
93
94	if size == 0 {
95		progressBar.SetTotal(progressBar.Current(), true)
96	}
97
98	progress.Wait()
99
100	fmt.Println("done")
101
102	return nil
103}
104