-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
123 lines (114 loc) · 2.87 KB
/
main.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
package gscp
import (
"context"
"fmt"
"strings"
"github.com/skillian/expr/errors"
"github.com/skillian/interactivity"
)
type MainConfig struct {
FromIndex bool
Source string
ToIndex bool
Dest string
Config Config
}
// Main is the main entry point for the program after the command line
// is parsed.
func Main(ctx context.Context, config MainConfig) error {
sourceInfo := specInfo{
str: config.Source,
index: config.FromIndex,
unsecure: config.Config.Unsecure,
}
destInfo := specInfo{
str: config.Dest,
index: config.ToIndex,
unsecure: config.Config.Unsecure,
}
ctx, asker := ensureAskerInContext(ctx)
source, err := parseSpecInfoAndEnsurePassword(ctx, sourceInfo, "source", asker)
if err != nil {
return err
}
dest, err := parseSpecInfoAndEnsurePassword(ctx, destInfo, "dest", asker)
if err != nil {
return err
}
if config.Config.AllowOverwrite && !dest.Kind.HasAll(IndexSpec) {
return errors.Errorf(
"destination specification must be an index " +
"when used with overwrite.",
)
}
return CopyFromSourceToDestSpec(ctx, source, dest, &config.Config)
}
type specInfo struct {
str string
index bool
unsecure bool
}
func parseSpecInfo(si specInfo) (*Spec, error) {
sp, err := ParseSpec(si.str)
if err != nil {
return nil, err
}
if si.index {
sp.Kind |= IndexSpec
}
if si.unsecure {
sp.Kind |= UnsecureSpec
}
if !sp.IsLocal() && sp.Kind.HasAll(IndexSpec) {
i := strings.LastIndexByte(sp.ArchivePath, '/')
if i == -1 {
// Global-scope search:
sp.Search = sp.ArchivePath
sp.ArchivePath = ""
} else {
sp.Search = sp.ArchivePath[i+1:]
sp.ArchivePath = sp.ArchivePath[:i]
}
}
return sp, nil
}
func parseSpecInfoAndEnsurePassword(ctx context.Context, si specInfo, specDesc string, asker interactivity.Asker) (*Spec, error) {
sp, err := parseSpecInfo(si)
if err != nil {
return nil, err
}
if err = ensureSpecPassword(ctx, asker, sp, specDesc); err != nil {
return nil, err
}
return sp, nil
}
func ensureAskerInContext(ctx context.Context) (context.Context, interactivity.Asker) {
asker, ok := interactivity.AskerFromContext(ctx)
if !ok {
asker = interactivity.ConfirmAsker(
interactivity.AskerFunc(interactivity.ConsoleAsker),
)
ctx = interactivity.AddAskerToContext(ctx, asker)
}
return ctx, asker
}
func ensureSpecPassword(ctx context.Context, asker interactivity.Asker, sp *Spec, specDesc string) (err error) {
if sp.IsLocal() || sp.Password != "" {
return nil
}
sp.Password, err = interactivity.Ask(
ctx, asker,
fmt.Sprintf(
"Password for %s username %s: ",
specDesc, sp.Username,
),
interactivity.IsSecret(true),
)
if err != nil {
return errors.Errorf2From(
err, "failed to get %s %v password",
specDesc, sp,
)
}
return nil
}