Skip to content

Commit 790db71

Browse files
author
Emmanuel Odeke
committed
edit-file functionality added
1 parent 4d42326 commit 790db71

File tree

7 files changed

+245
-74
lines changed

7 files changed

+245
-74
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
- [Listing Files](#listing-files)
3333
- [Stating Files](#stating-files)
3434
- [Retrieving md5 checksums](#retrieving-md5-checksums)
35+
- [Editing Description](#editing-description)
3536
- [New File](#new-file)
3637
- [Quota](#quota)
3738
- [Features](#features)
@@ -709,6 +710,21 @@ $ drive new --mime-key form taxForm2016 taxFormCounty
709710
$ drive new flux.txt oxen.pdf # Allow auto type resolution from the extension
710711
```
711712
713+
### Editing Description
714+
715+
You can edit the description of a file like this
716+
717+
```shell
718+
$ drive edit-desc --description "This is a new file description" freshFolders/1.txt commonCore/
719+
$ drive edit-description --description "This is a new file description" freshFolders/1.txt commonCore/
720+
```
721+
722+
Even more conveniently by piping content
723+
724+
```shell
725+
$ cat fileDescriptions | drive edit-desc --piped targetFile influx/1.txt
726+
```
727+
712728
### Quota
713729
714730
The `quota` command prints information about your drive, such as the account type, bytes used/free, and the total amount of storage available.

cmd/drive/main.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ func main() {
8080
bindCommandWithAliases(drive.IndexKey, drive.DescIndex, &indexCmd{}, []string{})
8181
bindCommandWithAliases(drive.UrlKey, drive.DescUrl, &urlCmd{}, []string{})
8282
bindCommandWithAliases(drive.OpenKey, drive.DescOpen, &openCmd{}, []string{})
83+
bindCommandWithAliases(drive.EditDescriptionKey, drive.DescEdit, &editDescriptionCmd{}, []string{})
8384

8485
command.DefineHelp(&helpCmd{})
8586
command.ParseAndRun()
@@ -200,6 +201,39 @@ func (cmd *openCmd) Run(args []string) {
200201
exitWithError(drive.New(context, &opts).Open(openType))
201202
}
202203

204+
type editDescriptionCmd struct {
205+
byId *bool
206+
description *string
207+
piped *bool
208+
}
209+
210+
func (cmd *editDescriptionCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
211+
cmd.byId = fs.Bool(drive.CLIOptionId, false, "open by id instead of path")
212+
cmd.description = fs.String(drive.CLIOptionDescription, "", drive.DescDescription)
213+
cmd.piped = fs.Bool(drive.CLIOptionPiped, false, drive.DescPiped)
214+
return fs
215+
}
216+
217+
func (cmd *editDescriptionCmd) Run(args []string) {
218+
sources, context, path := preprocessArgsByToggle(args, *cmd.byId)
219+
220+
meta := map[string][]string{
221+
drive.EditDescriptionKey: []string{*cmd.description},
222+
}
223+
224+
if *cmd.piped {
225+
meta[drive.PipedKey] = []string{fmt.Sprintf("%v", *cmd.piped)}
226+
}
227+
228+
opts := drive.Options{
229+
Meta: &meta,
230+
Path: path,
231+
Sources: sources,
232+
}
233+
234+
exitWithError(drive.New(context, &opts).EditDescription(*cmd.byId))
235+
}
236+
203237
type urlCmd struct {
204238
byId *bool
205239
}

src/edit.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Copyright 2015 Google Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package drive
16+
17+
import (
18+
"fmt"
19+
"strings"
20+
)
21+
22+
func noopOnFile(f *File) interface{} {
23+
return f
24+
}
25+
26+
func noopOnIgnorer(s string) bool {
27+
return false
28+
}
29+
30+
func (g *Commands) EditDescription(byId bool) (composedErr error) {
31+
metaPtr := g.opts.Meta
32+
33+
if metaPtr == nil {
34+
return fmt.Errorf("edit: no descriptions passed in")
35+
}
36+
37+
meta := *metaPtr
38+
39+
description := strings.Join(meta[EditDescriptionKey], "\n")
40+
41+
if _, ok := meta[PipedKey]; ok {
42+
clauses, err := readFileFromStdin(noopOnIgnorer)
43+
if err != nil {
44+
return err
45+
}
46+
47+
description = strings.Join(clauses, "\n")
48+
}
49+
50+
kvChan := resolver(g, byId, g.opts.Sources, noopOnFile)
51+
52+
for kv := range kvChan {
53+
file, ok := kv.value.(*File)
54+
if !ok {
55+
g.log.LogErrf("%s: %s\n", kv.key, kv.value)
56+
continue
57+
}
58+
59+
if file == nil {
60+
continue
61+
}
62+
63+
updatedFile, err := g.rem.updateDescription(file.Id, description)
64+
if err != nil {
65+
composedErr = reComposeError(composedErr, fmt.Sprintf("%q %v", kv.key, err))
66+
} else if updatedFile != nil {
67+
name := fmt.Sprintf("%q", kv.key)
68+
if kv.key != updatedFile.Id {
69+
name = fmt.Sprintf("%s aka %q", name, updatedFile.Id)
70+
}
71+
g.log.LogErrf("Description updated for %s\n", name)
72+
}
73+
}
74+
75+
return
76+
}

src/help.go

Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -25,37 +25,40 @@ import (
2525
)
2626

2727
const (
28-
AboutKey = "about"
29-
AllKey = "all"
30-
CopyKey = "copy"
31-
DeleteKey = "delete"
32-
DiffKey = "diff"
33-
EmptyTrashKey = "emptytrash"
34-
FeaturesKey = "features"
35-
HelpKey = "help"
36-
InitKey = "init"
37-
DeInitKey = "deinit"
38-
LinkKey = "Link"
39-
ListKey = "list"
40-
MoveKey = "move"
41-
OSLinuxKey = "linux"
42-
PullKey = "pull"
43-
PushKey = "push"
44-
PubKey = "pub"
45-
RenameKey = "rename"
46-
QuotaKey = "quota"
47-
ShareKey = "share"
48-
StatKey = "stat"
49-
TouchKey = "touch"
50-
TrashKey = "trash"
51-
UnshareKey = "unshare"
52-
UntrashKey = "untrash"
53-
UnpubKey = "unpub"
54-
VersionKey = "version"
55-
Md5sumKey = "md5sum"
56-
NewKey = "new"
57-
IndexKey = "index"
58-
PruneKey = "prune"
28+
AboutKey = "about"
29+
AllKey = "all"
30+
CopyKey = "copy"
31+
DeleteKey = "delete"
32+
EditDescriptionKey = "edit-description"
33+
EditDescriptionShortKey = "edit-desc"
34+
DiffKey = "diff"
35+
EmptyTrashKey = "emptytrash"
36+
FeaturesKey = "features"
37+
HelpKey = "help"
38+
InitKey = "init"
39+
DeInitKey = "deinit"
40+
LinkKey = "Link"
41+
ListKey = "list"
42+
MoveKey = "move"
43+
OSLinuxKey = "linux"
44+
PipedKey = "piped"
45+
PullKey = "pull"
46+
PushKey = "push"
47+
PubKey = "pub"
48+
RenameKey = "rename"
49+
QuotaKey = "quota"
50+
ShareKey = "share"
51+
StatKey = "stat"
52+
TouchKey = "touch"
53+
TrashKey = "trash"
54+
UnshareKey = "unshare"
55+
UntrashKey = "untrash"
56+
UnpubKey = "unpub"
57+
VersionKey = "version"
58+
Md5sumKey = "md5sum"
59+
NewKey = "new"
60+
IndexKey = "index"
61+
PruneKey = "prune"
5962

6063
CoercedMimeKeyKey = "coerced-mime"
6164
DepthKey = "depth"
@@ -98,6 +101,7 @@ const (
98101
DescCopy = "copy remote paths to a destination"
99102
DescDelete = "deletes the items permanently. This operation is irreversible"
100103
DescDiff = "compares local files with their remote equivalent"
104+
DescEdit = "edit the attributes of a file"
101105
DescEmptyTrash = "permanently cleans out your trash"
102106
DescExcludeOps = "exclude operations"
103107
DescFeatures = "returns information about the features of your drive"
@@ -107,6 +111,7 @@ const (
107111
DescDeInit = "removes the user's credentials and initialized files"
108112
DescList = "lists the contents of remote path"
109113
DescMove = "move files/folders"
114+
DescPiped = "get content in from standard input (stdin)"
110115
DescQuota = "prints out information related to your quota space"
111116
DescPublish = "publishes a file and prints its publicly available url"
112117
DescRename = "renames a file/folder"
@@ -144,9 +149,11 @@ const (
144149
DescUrl = "returns the remote URL of each file"
145150
DescVerbose = "show step by step information verbosely"
146151
DescFixClashes = "fix clashes by renaming files"
152+
DescDescription = "set the description"
147153
)
148154

149155
const (
156+
CLIOptionDescription = "description"
150157
CLIOptionExplicitlyExport = "explicitly-export"
151158
CLIOptionIgnoreChecksum = "ignore-checksum"
152159
CLIOptionIgnoreConflict = "ignore-conflict"
@@ -170,6 +177,7 @@ const (
170177
CLIOptionWebBrowser = "web-browser"
171178
CLIOptionFileBrowser = "file-browser"
172179
CLIOptionFixClashesKey = "fix-clashes"
180+
CLIOptionPiped = "piped"
173181
)
174182

175183
const (
@@ -208,6 +216,9 @@ var docMap = map[string][]string{
208216
DescDiff, "Accepts multiple remote paths for line by line comparison",
209217
skipChecksumNote,
210218
},
219+
EditDescriptionShortKey: []string{
220+
DescEdit, "Accepts multiple remote paths as well as ids",
221+
},
211222
EmptyTrashKey: []string{
212223
DescEmptyTrash,
213224
},
@@ -291,10 +302,11 @@ var docMap = map[string][]string{
291302

292303
func createAndRegisterAliases() map[string][]string {
293304
aliases := map[string][]string{
294-
CopyKey: []string{"cp"},
295-
ListKey: []string{"ls"},
296-
MoveKey: []string{"mv"},
297-
DeleteKey: []string{"del"},
305+
CopyKey: []string{"cp"},
306+
ListKey: []string{"ls"},
307+
MoveKey: []string{"mv"},
308+
DeleteKey: []string{"del"},
309+
EditDescriptionKey: []string{EditDescriptionShortKey},
298310
}
299311

300312
for originalKey, aliasList := range aliases {

src/misc.go

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"bufio"
1919
"errors"
2020
"fmt"
21+
"io"
2122
"io/ioutil"
2223
"os"
2324
"path"
@@ -355,20 +356,10 @@ func ReadFullFile(p string) (clauses []string, err error) {
355356
return readFile_(p, nil)
356357
}
357358

358-
func readFile_(p string, ignorer func(string) bool) (clauses []string, err error) {
359-
f, fErr := os.Open(p)
360-
if fErr != nil || f == nil {
361-
err = fErr
362-
return
363-
}
364-
365-
defer f.Close()
359+
func fReadFile_(f io.Reader, ignorer func(string) bool) (clauses []string, err error) {
366360
scanner := bufio.NewScanner(f)
367361

368-
for {
369-
if !scanner.Scan() {
370-
break
371-
}
362+
for scanner.Scan() {
372363
line := scanner.Text()
373364
line = strings.Trim(line, " ")
374365
line = strings.Trim(line, "\n")
@@ -377,6 +368,25 @@ func readFile_(p string, ignorer func(string) bool) (clauses []string, err error
377368
}
378369
clauses = append(clauses, line)
379370
}
371+
372+
return
373+
}
374+
375+
func readFileFromStdin(ignorer func(string) bool) (clauses []string, err error) {
376+
return fReadFile_(os.Stdin, ignorer)
377+
}
378+
379+
func readFile_(p string, ignorer func(string) bool) (clauses []string, err error) {
380+
f, fErr := os.Open(p)
381+
if fErr != nil || f == nil {
382+
err = fErr
383+
return
384+
}
385+
386+
defer f.Close()
387+
388+
clauses, err = fReadFile_(f, ignorer)
389+
380390
return
381391
}
382392

@@ -751,3 +761,29 @@ func list(flArg *fsListingArg) (fileChan chan *File, err error) {
751761
}()
752762
return
753763
}
764+
765+
func resolver(g *Commands, byId bool, sources []string, fileOp func(*File) interface{}) (kvChan chan *keyValue) {
766+
resolve := g.rem.FindByPath
767+
if byId {
768+
resolve = g.rem.FindById
769+
}
770+
771+
kvChan = make(chan *keyValue)
772+
773+
go func() {
774+
defer close(kvChan)
775+
776+
for _, source := range sources {
777+
f, err := resolve(source)
778+
779+
kv := keyValue{key: source, value: err}
780+
if err == nil {
781+
kv.value = fileOp(f)
782+
}
783+
784+
kvChan <- &kv
785+
}
786+
}()
787+
788+
return kvChan
789+
}

0 commit comments

Comments
 (0)