-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfiles.go
255 lines (238 loc) · 5.72 KB
/
files.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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
package main
import (
"errors"
"fmt"
"io"
"os"
"github.com/steverusso/lockbook-x/go-lockbook"
)
// Print a document's content.
type catCmd struct {
// Lockbook file path or ID.
//
// clap:arg_required
target string
}
func (c *catCmd) run(core lockbook.Core) error {
id, err := idFromSomething(core, c.target)
if err != nil {
return fmt.Errorf("trying to get id from %q: %w", c.target, err)
}
data, err := core.ReadDocument(id)
if err != nil {
return fmt.Errorf("reading doc %q: %w", c.target, err)
}
fmt.Printf("%s", data)
return nil
}
// Create a directory or do nothing if it exists.
type mkdirCmd struct {
// The path at which to create the directory.
//
// clap:arg_required
path string
}
func (c *mkdirCmd) run(core lockbook.Core) error {
v := c.path
if v != "/" && v[len(v)-1] != '/' {
v += "/"
}
return mk(core, v)
}
// Create a document or do nothing if it exists.
type mkdocCmd struct {
// The path at which to create the document.
//
// clap:arg_required
path string
}
func (c *mkdocCmd) run(core lockbook.Core) error {
v := c.path
if v != "/" && v[len(v)-1] == '/' {
v = v[:len(v)-1]
}
return mk(core, v)
}
func mk(core lockbook.Core, fpath string) error {
_, err := core.CreateFileAtPath(fpath)
if err != nil {
return fmt.Errorf("creating file at path %q: %w", fpath, err)
}
return nil
}
// Rename a file.
//
// clap:cmd_usage [-f] <target> [new-name]
type renameCmd struct {
// Non-interactive (fail instead of prompting for corrections).
//
// clap:opt force,f
force bool
// The file to rename.
//
// clap:arg_required
target string
// The desired new name.
//
// clap:arg_required
newName string
}
func (c *renameCmd) run(core lockbook.Core) error {
if c.newName == "" && c.force {
return errors.New("must provide new name if --force")
}
id, err := idFromSomething(core, c.target)
if err != nil {
return fmt.Errorf("trying to get id from %q: %w", c.target, err)
}
// If we don't have a name, loop until we get one.
for {
if c.newName != "" {
break
}
fmt.Print("choose a new name: ")
fmt.Scanln(&c.newName)
}
// Loop until we find an available file name. If this is forced, it'll just return the
// first error.
for {
err := core.RenameFile(id, c.newName)
// If this is a forced rename, we're not going to inspect the error and guide the
// user on finding an available file name.
if err == nil || c.force {
return err
}
if err, ok := asLbErr(err); !ok || err.Code != lockbook.CodePathTaken {
return err
}
// Loop until we get non-empty new input.
prompt := fmt.Sprintf("the name %q is taken, please try another: ", c.newName)
c.newName = ""
for {
fmt.Print(prompt)
fmt.Scanln(&c.newName)
if c.newName != "" {
break
}
prompt = "choose a new name: "
}
}
}
// Move a file to another parent.
//
// clap:cmd_aliases move
type mvCmd struct {
// The file to move.
//
// clap:arg_required
src string
// The destination directory.
//
// clap:arg_required
dest string
}
func (c *mvCmd) run(core lockbook.Core) error {
srcID, err := idFromSomething(core, c.src)
if err != nil {
return fmt.Errorf("trying to get src id from %q: %w", c.src, err)
}
destID, err := idFromSomething(core, c.dest)
if err != nil {
return fmt.Errorf("trying to get dest id from %q: %w", c.dest, err)
}
err = core.MoveFile(srcID, destID)
if err != nil {
return fmt.Errorf("moving %s -> %s: %w", srcID, destID, err)
}
return nil
}
// Delete a file.
type rmCmd struct {
// Don't prompt for confirmation.
//
// clap:opt force,f
force bool
// Lockbook path or ID to delete.
//
// clap:arg_required
target string
}
func (c *rmCmd) run(core lockbook.Core) error {
targets := []string{c.target} // todo(steve): support multiple targets in the command
ids := make([]lockbook.FileID, len(targets))
for i, t := range targets {
id, err := idFromSomething(core, t)
if err != nil {
return fmt.Errorf("trying to get id from %q: %w", t, err)
}
ids[i] = id
}
for i, id := range ids {
f, err := core.FileByID(id)
if err != nil {
return fmt.Errorf("file by id %q: %w", id, err)
}
if !c.force {
phrase := fmt.Sprintf("delete %q", id)
if t := targets[i]; t != id.String() {
phrase += " (target: " + t + ")"
}
if f.IsDir() {
children, err := core.GetAndGetChildrenRecursively(id)
if err != nil {
return fmt.Errorf("getting all children in order to count: %w", err)
}
phrase += fmt.Sprintf(" and its %d children", len(children))
}
answer := ""
fmt.Printf("are you sure you want to %s? [y/N]: ", phrase)
fmt.Scanln(&answer)
if answer != "y" && answer != "Y" {
fmt.Println("aborted.")
continue
}
}
err = core.DeleteFile(id)
if err != nil {
return fmt.Errorf("deleting file %q: %w", id, err)
}
}
return nil
}
// Write data from stdin to a lockbook document.
//
// clap:cmd_usage [--trunc] <target>
type writeCmd struct {
// Truncate the file instead of appending to it.
//
// clap:opt trunc
trunc bool
// Lockbook path or ID to write.
//
// clap:arg_required
target string
}
func (c *writeCmd) run(core lockbook.Core) error {
if !isStdinPipe() {
return errors.New("to write data to a lockbook document, pipe it into this command, e.g.:\necho 'hi' | lockbook write my-doc.txt")
}
id, err := idFromSomething(core, c.target)
if err != nil {
return fmt.Errorf("trying to get an id from %q: %w", c.target, err)
}
data, err := io.ReadAll(os.Stdin)
if err != nil {
return fmt.Errorf("trying to read from stdin: %w", err)
}
if !c.trunc {
content, err := core.ReadDocument(id)
if err != nil {
return fmt.Errorf("reading doc %q: %w", id, err)
}
data = append(content, data...)
}
if err := core.WriteDocument(id, data); err != nil {
return fmt.Errorf("writing to doc: %w", err)
}
return nil
}