1package _select
2
3import (
4 "fmt"
5 "io"
6 "io/ioutil"
7 "os"
8
9 "github.com/pkg/errors"
10
11 "github.com/MichaelMure/git-bug/cache"
12 "github.com/MichaelMure/git-bug/entity"
13)
14
15const selectFile = "select"
16
17var ErrNoValidId = errors.New("you must provide a bug id or use the \"select\" command first")
18
19// ResolveBug first try to resolve a bug using the first argument of the command
20// line. If it fails, it falls back to the select mechanism.
21//
22// Returns:
23// - the bug if any
24// - the new list of command line arguments with the bug prefix removed if it
25// has been used
26// - an error if the process failed
27func ResolveBug(repo *cache.RepoCache, args []string) (*cache.BugCache, []string, error) {
28 // At first, try to use the first argument as a bug prefix
29 if len(args) > 0 {
30 b, err := repo.Bugs().ResolvePrefix(args[0])
31
32 if err == nil {
33 return b, args[1:], nil
34 }
35
36 if !entity.IsErrNotFound(err) {
37 return nil, nil, err
38 }
39 }
40
41 // first arg is not a valid bug prefix, we can safely use the preselected bug if any
42
43 b, err := selected(repo)
44
45 // selected bug is invalid
46 if entity.IsErrNotFound(err) {
47 // we clear the selected bug
48 err = Clear(repo)
49 if err != nil {
50 return nil, nil, err
51 }
52 return nil, nil, ErrNoValidId
53 }
54
55 // another error when reading the bug
56 if err != nil {
57 return nil, nil, err
58 }
59
60 // bug is successfully retrieved
61 if b != nil {
62 return b, args, nil
63 }
64
65 // no selected bug and no valid first argument
66 return nil, nil, ErrNoValidId
67}
68
69// Select will select a bug for future use
70func Select(repo *cache.RepoCache, id entity.Id) error {
71 f, err := repo.LocalStorage().OpenFile(selectFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
72 if err != nil {
73 return err
74 }
75
76 _, err = f.Write([]byte(id.String()))
77 if err != nil {
78 return err
79 }
80
81 return f.Close()
82}
83
84// Clear will clear the selected bug, if any
85func Clear(repo *cache.RepoCache) error {
86 return repo.LocalStorage().Remove(selectFile)
87}
88
89func selected(repo *cache.RepoCache) (*cache.BugCache, error) {
90 f, err := repo.LocalStorage().Open(selectFile)
91 if err != nil {
92 if os.IsNotExist(err) {
93 return nil, nil
94 } else {
95 return nil, err
96 }
97 }
98
99 buf, err := ioutil.ReadAll(io.LimitReader(f, 100))
100 if err != nil {
101 return nil, err
102 }
103 if len(buf) == 100 {
104 return nil, fmt.Errorf("the select file should be < 100 bytes")
105 }
106
107 id := entity.Id(buf)
108 if err := id.Validate(); err != nil {
109 err = repo.LocalStorage().Remove(selectFile)
110 if err != nil {
111 return nil, errors.Wrap(err, "error while removing invalid select file")
112 }
113
114 return nil, fmt.Errorf("select file in invalid, removing it")
115 }
116
117 b, err := repo.Bugs().Resolve(id)
118 if err != nil {
119 return nil, err
120 }
121
122 err = f.Close()
123 if err != nil {
124 return nil, err
125 }
126
127 return b, nil
128}