/
config.go
127 lines (105 loc) · 3.5 KB
/
config.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
126
127
package cli
import (
"context"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/gopasspw/gopass/pkg/out"
"github.com/gopasspw/gopass/pkg/store"
"github.com/pkg/errors"
)
const (
fileMode = 0600
)
func (g *Git) fixConfig(ctx context.Context) error {
// set push default, to avoid issues with
// "fatal: The current branch master has multiple upstream branches, refusing to push"
// https://stackoverflow.com/questions/948354/default-behavior-of-git-push-without-a-branch-specified
if err := g.ConfigSet(ctx, "push.default", "matching"); err != nil {
return errors.Wrapf(err, "failed to set git config for push.default")
}
// setup for proper diffs
if err := g.ConfigSet(ctx, "diff.gpg.binary", "true"); err != nil {
out.Yellow(ctx, "Error while initializing git: %s", err)
}
if err := g.ConfigSet(ctx, "diff.gpg.textconv", "gpg --no-tty --decrypt"); err != nil {
out.Yellow(ctx, "Error while initializing git: %s", err)
}
return nil
}
// InitConfig initialized and preparse the git config
func (g *Git) InitConfig(ctx context.Context, userName, userEmail string) error {
if userName == "" || userEmail == "" || !strings.Contains(userEmail, "@") {
return fmt.Errorf("username and email must not be empty and valid")
}
// set commit identity
if err := g.ConfigSet(ctx, "user.name", userName); err != nil {
return errors.Wrapf(err, "failed to set git config user.name")
}
if err := g.ConfigSet(ctx, "user.email", userEmail); err != nil {
return errors.Wrapf(err, "failed to set git config user.email")
}
// ensure sane git config
if err := g.fixConfig(ctx); err != nil {
return errors.Wrapf(err, "failed to fix git config")
}
if err := ioutil.WriteFile(filepath.Join(g.path, ".gitattributes"), []byte("*.gpg diff=gpg\n"), fileMode); err != nil {
return errors.Errorf("Failed to initialize git: %s", err)
}
if err := g.Add(ctx, g.path+"/.gitattributes"); err != nil {
out.Yellow(ctx, "Warning: Failed to add .gitattributes to git")
}
if err := g.Commit(ctx, "Configure git repository for gpg file diff."); err != nil {
out.Yellow(ctx, "Warning: Failed to commit .gitattributes to git")
}
return nil
}
// ConfigSet sets a local config value
func (g *Git) ConfigSet(ctx context.Context, key, value string) error {
return g.Cmd(ctx, "gitConfigSet", "config", "--local", key, value)
}
// ConfigGet returns a given config value
func (g *Git) ConfigGet(ctx context.Context, key string) (string, error) {
if !g.IsInitialized() {
return "", store.ErrGitNotInit
}
buf := &strings.Builder{}
cmd := exec.CommandContext(ctx, "git", "config", "--get", key)
cmd.Dir = g.path
cmd.Stdout = buf
cmd.Stderr = os.Stderr
out.Debug(ctx, "store.gitConfigGet: %s %+v", cmd.Path, cmd.Args)
if err := cmd.Run(); err != nil {
return "", err
}
return strings.TrimSpace(buf.String()), nil
}
// ConfigList returns all git config settings
func (g *Git) ConfigList(ctx context.Context) (map[string]string, error) {
if !g.IsInitialized() {
return nil, store.ErrGitNotInit
}
buf := &strings.Builder{}
cmd := exec.CommandContext(ctx, "git", "config", "--list")
cmd.Dir = g.path
cmd.Stdout = buf
cmd.Stderr = os.Stderr
out.Debug(ctx, "store.gitConfigList: %s %+v", cmd.Path, cmd.Args)
if err := cmd.Run(); err != nil {
return nil, err
}
lines := strings.Split(buf.String(), "\n")
kv := make(map[string]string, len(lines))
for _, line := range lines {
line = strings.TrimSpace(line)
p := strings.SplitN(line, "=", 2)
if len(p) < 2 {
continue
}
kv[p[0]] = p[1]
}
return kv, nil
}