/
cli.go
239 lines (216 loc) · 7.34 KB
/
cli.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
package cli
import (
"context"
"os"
"strconv"
"github.com/logrusorgru/aurora"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"github.com/textileio/textile/buckets/local"
"github.com/textileio/textile/cmd"
"github.com/textileio/uiprogress"
)
const Name = "buck"
var bucks *local.Buckets
func init() {
uiprogress.Empty = ' '
uiprogress.Fill = '-'
}
func Init(baseCmd *cobra.Command) {
baseCmd.AddCommand(initCmd, linksCmd, rootCmd, statusCmd, lsCmd, pushCmd, pullCmd, addCmd, watchCmd, catCmd, destroyCmd, encryptCmd, decryptCmd, archiveCmd)
archiveCmd.AddCommand(archiveStatusCmd, archiveInfoCmd)
initCmd.PersistentFlags().String("key", "", "Bucket key")
initCmd.PersistentFlags().String("thread", "", "Thread ID")
initCmd.PersistentFlags().String("org", "", "Org username")
initCmd.Flags().StringP("name", "n", "", "Bucket name")
initCmd.Flags().BoolP("private", "p", false, "Obfuscates files and folders with encryption")
initCmd.Flags().String("cid", "", "Bootstrap the bucket with a UnixFS Cid from the IPFS network")
initCmd.Flags().BoolP("existing", "e", false, "Initializes from an existing remote bucket if true")
pushCmd.Flags().BoolP("force", "f", false, "Allows non-fast-forward updates if true")
pushCmd.Flags().BoolP("yes", "y", false, "Skips the confirmation prompt if true")
pushCmd.Flags().Int64("maxsize", buckMaxSizeMiB, "Max bucket size in MiB")
pullCmd.Flags().BoolP("force", "f", false, "Force pull all remote files if true")
pullCmd.Flags().Bool("hard", false, "Pulls and prunes local changes if true")
pullCmd.Flags().BoolP("yes", "y", false, "Skips the confirmation prompt if true")
addCmd.Flags().BoolP("yes", "y", false, "Skips confirmations prompts to always overwrite files and merge folders")
encryptCmd.Flags().StringP("password", "p", "", "Encryption password")
decryptCmd.Flags().StringP("password", "p", "", "Decryption password")
archiveStatusCmd.Flags().BoolP("watch", "w", false, "Watch execution log")
}
func SetBucks(b *local.Buckets) {
bucks = b
}
var statusCmd = &cobra.Command{
Use: "status",
Aliases: []string{
"st",
},
Short: "Show bucket object changes",
Long: `Displays paths that have been added to and paths that have been removed or differ from the local bucket root.`,
Args: cobra.ExactArgs(0),
Run: func(c *cobra.Command, args []string) {
ctx, cancel := context.WithTimeout(context.Background(), cmd.Timeout)
defer cancel()
buck, err := bucks.GetLocalBucket(ctx, ".")
cmd.ErrCheck(err)
diff, err := buck.DiffLocal()
cmd.ErrCheck(err)
if len(diff) == 0 {
cmd.End("Everything up-to-date")
}
for _, c := range diff {
cf := local.ChangeColor(c.Type)
cmd.Message("%s %s", cf(local.ChangeType(c.Type)), cf(c.Rel))
}
},
}
var rootCmd = &cobra.Command{
Use: "root",
Short: "Show bucket root CIDs",
Long: `Shows the local and remote bucket root CIDs (these will differ if the bucket is encrypted).`,
Args: cobra.ExactArgs(0),
Run: func(c *cobra.Command, args []string) {
ctx, cancel := context.WithTimeout(context.Background(), cmd.Timeout)
defer cancel()
buck, err := bucks.GetLocalBucket(ctx, ".")
cmd.ErrCheck(err)
r, err := buck.Roots(ctx)
cmd.ErrCheck(err)
cmd.Message("%s (local)", aurora.White(r.Local).Bold())
cmd.Message("%s (remote)", aurora.White(r.Remote).Bold())
},
}
var linksCmd = &cobra.Command{
Use: "links",
Aliases: []string{
"link",
},
Short: "Show links to where this bucket can be accessed",
Long: `Displays a thread, IPNS, and website link to this bucket.`,
Args: cobra.ExactArgs(0),
Run: func(c *cobra.Command, args []string) {
ctx, cancel := context.WithTimeout(context.Background(), cmd.Timeout)
defer cancel()
buck, err := bucks.GetLocalBucket(ctx, ".")
cmd.ErrCheck(err)
links, err := buck.RemoteLinks(ctx)
cmd.ErrCheck(err)
printLinks(links)
},
}
func printLinks(reply local.Links) {
cmd.Message("Your bucket links:")
cmd.Message("%s Thread link", aurora.White(reply.URL).Bold())
cmd.Message("%s IPNS link (propagation can be slow)", aurora.White(reply.IPNS).Bold())
if reply.WWW != "" {
cmd.Message("%s Bucket website", aurora.White(reply.WWW).Bold())
}
}
var lsCmd = &cobra.Command{
Use: "ls [path]",
Aliases: []string{
"list",
},
Short: "List top-level or nested bucket objects",
Long: `Lists top-level or nested bucket objects.`,
Args: cobra.MaximumNArgs(1),
Run: func(c *cobra.Command, args []string) {
ctx, cancel := context.WithTimeout(context.Background(), cmd.Timeout)
defer cancel()
buck, err := bucks.GetLocalBucket(ctx, ".")
cmd.ErrCheck(err)
var pth string
if len(args) > 0 {
pth = args[0]
}
items, err := buck.ListRemotePath(ctx, pth)
cmd.ErrCheck(err)
var data [][]string
if len(items) > 0 {
for _, item := range items {
var links string
if item.IsDir {
links = strconv.Itoa(item.ItemsCount)
} else {
links = "n/a"
}
data = append(data, []string{
item.Name,
strconv.Itoa(int(item.Size)),
strconv.FormatBool(item.IsDir),
links,
item.Cid.String(),
})
}
}
if len(data) > 0 {
cmd.RenderTable([]string{"name", "size", "dir", "objects", "cid"}, data)
}
cmd.Message("Found %d objects", aurora.White(len(data)).Bold())
},
}
var catCmd = &cobra.Command{
Use: "cat [path]",
Short: "Cat bucket objects at path",
Long: `Cats bucket objects at path.`,
Args: cobra.ExactArgs(1),
Run: func(c *cobra.Command, args []string) {
ctx, cancel := context.WithTimeout(context.Background(), cmd.PullTimeout)
defer cancel()
buck, err := bucks.GetLocalBucket(ctx, ".")
cmd.ErrCheck(err)
err = buck.CatRemotePath(ctx, args[0], os.Stdout)
cmd.ErrCheck(err)
},
}
var encryptCmd = &cobra.Command{
Use: "encrypt [file] [password]",
Short: "Encrypt file with a password",
Long: `Encrypts file with a password (WARNING: Password is not recoverable).`,
Args: cobra.ExactArgs(2),
Run: func(c *cobra.Command, args []string) {
ctx, cancel := context.WithTimeout(context.Background(), cmd.Timeout)
defer cancel()
buck, err := bucks.GetLocalBucket(ctx, ".")
cmd.ErrCheck(err)
err = buck.EncryptLocalPath(args[0], args[1], os.Stdout)
cmd.ErrCheck(err)
},
}
var decryptCmd = &cobra.Command{
Use: "decrypt [path] [password]",
Short: "Decrypt bucket objects at path with password",
Long: `Decrypts bucket objects at path with the given password and writes to stdout.`,
Args: cobra.ExactArgs(2),
Run: func(c *cobra.Command, args []string) {
ctx, cancel := context.WithTimeout(context.Background(), cmd.PullTimeout)
defer cancel()
buck, err := bucks.GetLocalBucket(ctx, ".")
cmd.ErrCheck(err)
err = buck.DecryptRemotePath(ctx, args[0], args[1], os.Stdout)
cmd.ErrCheck(err)
},
}
var destroyCmd = &cobra.Command{
Use: "destroy",
Short: "Destroy bucket and all objects",
Long: `Destroys the bucket and all objects.`,
Args: cobra.ExactArgs(0),
Run: func(c *cobra.Command, args []string) {
ctx, cancel := context.WithTimeout(context.Background(), cmd.Timeout)
defer cancel()
buck, err := bucks.GetLocalBucket(ctx, ".")
cmd.ErrCheck(err)
cmd.Warn("%s", aurora.Red("This action cannot be undone. The bucket and all associated data will be permanently deleted."))
prompt := promptui.Prompt{
Label: "Are you absolutely sure",
IsConfirm: true,
}
if _, err = prompt.Run(); err != nil {
cmd.End("")
}
err = buck.Destroy(ctx)
cmd.ErrCheck(err)
cmd.Success("Your bucket has been deleted")
},
}