/
local_checkout.go
125 lines (113 loc) · 3.52 KB
/
local_checkout.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package cmd
import (
"errors"
"fmt"
"io/fs"
"path/filepath"
"strings"
"github.com/spf13/cobra"
"github.com/treeverse/lakefs/pkg/local"
)
var localCheckoutCmd = &cobra.Command{
Use: "checkout [directory]",
Short: "Sync local directory with the remote state.",
Args: localDefaultArgsRange,
Run: func(cmd *cobra.Command, args []string) {
specifiedRef := Must(cmd.Flags().GetString("ref"))
all := Must(cmd.Flags().GetBool("all"))
_, localPath := getSyncArgs(args, false, all)
if !all {
localCheckout(cmd, localPath, specifiedRef, true)
return
}
fmt.Println("the operation will revert all changes in all directories that are linked with lakeFS.")
confirmation, err := Confirm(cmd.Flags(), "Proceed")
if err != nil || !confirmation {
Die("command aborted", 1)
}
dirs, err := local.FindIndices(localPath)
if err != nil {
DieErr(err)
}
for _, d := range dirs {
localCheckout(cmd, filepath.Join(localPath, d), specifiedRef, false)
}
},
}
func localCheckout(cmd *cobra.Command, localPath string, specifiedRef string, confirmByFlag bool) {
client := getClient()
syncFlags := getSyncFlags(cmd, client)
idx, err := local.ReadIndex(localPath)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
DieFmt("directory %s is not linked to a lakeFS path", localPath)
}
DieErr(err)
}
remote, err := idx.GetCurrentURI()
if err != nil {
DieErr(err)
}
currentBase := remote.WithRef(idx.AtHead)
diffs := local.Undo(localDiff(cmd.Context(), client, currentBase, idx.LocalPath()))
sigCtx := localHandleSyncInterrupt(cmd.Context(), idx, string(checkoutOperation))
syncMgr := local.NewSyncManager(sigCtx, client, syncFlags)
// confirm on local changes
if confirmByFlag && len(diffs) > 0 {
fmt.Println("Uncommitted changes exist, the operation will revert all changes on local directory.")
confirmation, err := Confirm(cmd.Flags(), "Proceed")
if err != nil || !confirmation {
Die("command aborted", 1)
}
}
if specifiedRef != "" {
resolvedRef := MustParseRefURI("ref", specifiedRef)
if resolvedRef.Repository != remote.Repository {
DieFmt("invalid uri, ref repository doesn't match")
}
newRemote := remote.WithRef(resolvedRef.Ref)
newHead := resolveCommitOrDie(cmd.Context(), client, newRemote.Repository, newRemote.Ref)
if newHead != idx.AtHead {
newBase := newRemote.WithRef(newHead)
// write new index
_, err = local.WriteIndex(idx.LocalPath(), remote, newHead, "")
if err != nil {
DieErr(err)
}
newDiffs := local.Undo(localDiff(cmd.Context(), client, newBase, idx.LocalPath()))
diffs = diffs.MergeWith(newDiffs, local.MergeStrategyOther)
currentBase = newBase
}
}
c := make(chan *local.Change, filesChanSize)
go func() {
defer close(c)
for _, dif := range diffs {
c <- &local.Change{
Source: local.ChangeSourceRemote,
Path: strings.TrimPrefix(dif.Path, currentBase.GetPath()),
Type: dif.Type,
}
}
}()
err = syncMgr.Sync(idx.LocalPath(), currentBase, c)
if err != nil {
DieErr(err)
}
Write(localSummaryTemplate, struct {
Operation string
local.Tasks
}{
Operation: "Checkout",
Tasks: syncMgr.Summary(),
})
}
//nolint:gochecknoinits
func init() {
localCheckoutCmd.Flags().StringP("ref", "r", "", "Checkout the given reference")
localCheckoutCmd.Flags().Bool("all", false, "Checkout given source branch or reference for all linked directories")
localCheckoutCmd.MarkFlagsMutuallyExclusive("ref", "all")
AssignAutoConfirmFlag(localCheckoutCmd.Flags())
withSyncFlags(localCheckoutCmd)
localCmd.AddCommand(localCheckoutCmd)
}