forked from go-acd/acd
/
cp.go
170 lines (154 loc) · 4.03 KB
/
cp.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
package cli
import (
"fmt"
"io"
"os"
"path"
"strings"
"gopkg.in/acd.v0/internal/constants"
"gopkg.in/acd.v0/internal/log"
"github.com/codegangsta/cli"
)
var (
cpCommand = cli.Command{
Name: "cp",
Usage: "copy files",
Description: "cp copy files, multiple files can be given. It follows the usage of cp whereas the last entry is the destination and has to be a folder if multiple files were given",
Action: cpAction,
BashComplete: cpBashComplete,
Before: cpBefore,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "recursive, R",
Usage: "cp recursively",
},
},
}
action string
)
func init() {
registerCommand(cpCommand)
}
func cpAction(c *cli.Context) {
if strings.HasPrefix(c.Args()[len(c.Args())-1], "acd://") {
cpUpload(c)
} else {
cpDownload(c)
}
}
func cpUpload(c *cli.Context) {
// make sure the destination is a folder if it exists upstream and more than
// one file is scheduled to be copied.
dest := strings.TrimPrefix(c.Args()[len(c.Args())-1], "acd://")
destNode, err := acdClient.NodeTree.FindNode(dest)
if err == nil {
// make sure if the remote node exists, it is a folder.
if len(c.Args()) > 2 {
if !destNode.IsDir() {
log.Fatalf("cp: target %q is not a directory", dest)
}
}
}
for _, src := range c.Args()[:len(c.Args())-1] {
if strings.HasPrefix(src, "acd://") {
fmt.Printf("cp: target %q is amazon, src cannot be amazon when destination is amazon. Skipping\n", src)
continue
}
stat, err := os.Stat(src)
if err != nil {
if os.IsNotExist(err) {
log.Fatalf("cp: %s: %s", constants.ErrFileNotFound, src)
}
log.Fatalf("cp: %s: %s", constants.ErrStatFile, src)
}
if stat.IsDir() {
if !c.Bool("recursive") {
fmt.Printf("cp: %q is a directory (not copied).", src)
continue
}
destFile := dest
if destNode != nil {
if !destNode.IsDir() {
log.Fatalf("cp: target %q is not a directory", dest)
}
destFile = fmt.Sprintf("%s/%s", dest, path.Base(src))
}
acdClient.UploadFolder(src, destFile, true, true)
continue
}
f, err := os.Open(src)
if err != nil {
log.Fatalf("%s: %s -- %s", constants.ErrOpenFile, err, src)
}
err = acdClient.Upload(dest, true, f)
f.Close()
if err != nil {
log.Fatalf("%s: %s", err, dest)
}
}
}
func cpDownload(c *cli.Context) {
dest := c.Args()[len(c.Args())-1]
destDir := false
destStat, err := os.Stat(dest)
if err == nil && destStat.IsDir() {
destDir = true
}
if len(c.Args()) > 2 {
if err == nil && !destDir {
log.Fatalf("cp: target %q is not a directory", dest)
}
}
for _, src := range c.Args()[:len(c.Args())-1] {
if !strings.HasPrefix(src, "acd://") {
fmt.Printf("cp: source %q is local, src cannot be local when destination is local. Skipping\n", src)
continue
}
srcPath := strings.TrimPrefix(src, "acd://")
destPath := dest
if destDir {
destPath = path.Join(destPath, path.Base(srcPath))
}
srcNode, err := acdClient.GetNodeTree().FindNode(srcPath)
if err != nil {
fmt.Printf("cp: source %q not found. Skipping", src)
continue
}
if srcNode.IsDir() {
acdClient.DownloadFolder(destPath, srcPath, c.Bool("recursive"))
} else {
content, err := acdClient.Download(srcPath)
if err != nil {
fmt.Printf("cp: error downloading source %q. Skipping", src)
}
// TODO: respect umask
if err := os.MkdirAll(path.Dir(destPath), os.FileMode(0755)); err != nil {
fmt.Printf("cp: error creating the parents folders of %q: %s. Skipping", destPath, err)
continue
}
// TODO: respect umask
f, err := os.Create(destPath)
if err != nil {
fmt.Printf("cp: error writing %q: %s. Skipping", destPath, err)
continue
}
io.Copy(f, content)
f.Close()
}
}
}
func cpBashComplete(c *cli.Context) {
}
func cpBefore(c *cli.Context) error {
foundRemote := false
for _, arg := range c.Args() {
if strings.HasPrefix(arg, "acd://") {
foundRemote = true
break
}
}
if !foundRemote {
return fmt.Errorf("cp: at least one path prefixed by acd:// is required. Given: %v", c.Args())
}
return nil
}