aboutsummaryrefslogtreecommitdiffstats
path: root/commands/env.go
blob: 8d12c5bfa0847a314ac86811589de92ff4533b1a (plain) (blame)
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package commands

import (
	"fmt"
	"io"
	"os"

	"github.com/spf13/cobra"

	"github.com/MichaelMure/git-bug/bug"
	"github.com/MichaelMure/git-bug/cache"
	"github.com/MichaelMure/git-bug/identity"
	"github.com/MichaelMure/git-bug/repository"
	"github.com/MichaelMure/git-bug/util/interrupt"
)

// Env is the environment of a command
type Env struct {
	repo    repository.ClockedRepo
	backend *cache.RepoCache
	out     out
	err     out
}

func newEnv() *Env {
	return &Env{
		repo: nil,
		out:  out{Writer: os.Stdout},
		err:  out{Writer: os.Stderr},
	}
}

type out struct {
	io.Writer
}

func (o out) Printf(format string, a ...interface{}) {
	_, _ = fmt.Fprintf(o, format, a...)
}

func (o out) Print(a ...interface{}) {
	_, _ = fmt.Fprint(o, a...)
}

func (o out) Println(a ...interface{}) {
	_, _ = fmt.Fprintln(o, a...)
}

// loadRepo is a pre-run function that load the repository for use in a command
func loadRepo(env *Env) func(*cobra.Command, []string) error {
	return func(cmd *cobra.Command, args []string) error {
		cwd, err := os.Getwd()
		if err != nil {
			return fmt.Errorf("unable to get the current working directory: %q", err)
		}

		env.repo, err = repository.OpenGoGitRepo(cwd, []repository.ClockLoader{bug.ClockLoader})
		if err == repository.ErrNotARepo {
			return fmt.Errorf("%s must be run from within a git repo", rootCommandName)
		}

		if err != nil {
			return err
		}

		return nil
	}
}

// loadRepoEnsureUser is the same as loadRepo, but also ensure that the user has configured
// an identity. Use this pre-run function when an error after using the configured user won't
// do.
func loadRepoEnsureUser(env *Env) func(*cobra.Command, []string) error {
	return func(cmd *cobra.Command, args []string) error {
		err := loadRepo(env)(cmd, args)
		if err != nil {
			return err
		}

		_, err = identity.GetUserIdentity(env.repo)
		if err != nil {
			return err
		}

		return nil
	}
}

// loadBackend is a pre-run function that load the repository and the backend for use in a command
// When using this function you also need to use closeBackend as a post-run
func loadBackend(env *Env) func(*cobra.Command, []string) error {
	return func(cmd *cobra.Command, args []string) error {
		err := loadRepo(env)(cmd, args)
		if err != nil {
			return err
		}

		env.backend, err = cache.NewRepoCache(env.repo)
		if err != nil {
			return err
		}

		cleaner := func(env *Env) interrupt.CleanerFunc {
			return func() error {
				if env.backend != nil {
					err := env.backend.Close()
					env.backend = nil
					return err
				}
				return nil
			}
		}

		// Cleanup properly on interrupt
		interrupt.RegisterCleaner(cleaner(env))
		return nil
	}
}

// loadBackendEnsureUser is the same as loadBackend, but also ensure that the user has configured
// an identity. Use this pre-run function when an error after using the configured user won't
// do.
func loadBackendEnsureUser(env *Env) func(*cobra.Command, []string) error {
	return func(cmd *cobra.Command, args []string) error {
		err := loadBackend(env)(cmd, args)
		if err != nil {
			return err
		}

		_, err = identity.GetUserIdentity(env.repo)
		if err != nil {
			return err
		}

		return nil
	}
}

// closeBackend is a post-run function that will close the backend properly
// if it has been opened.
func closeBackend(env *Env) func(*cobra.Command, []string) error {
	return func(cmd *cobra.Command, args []string) error {
		if env.backend == nil {
			return nil
		}
		err := env.backend.Close()
		env.backend = nil
		return err
	}
}