diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 704614441..78232dd5b 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -190,7 +190,7 @@ }, { "ImportPath": "github.com/ncw/go-acd", - "Rev": "5622f9ac57985c9fd6e1ad419983c20043e007ce" + "Rev": "fafd639874ad90ef88345a48bd8aeffdbca6480f" }, { "ImportPath": "github.com/ncw/swift", diff --git a/vendor/github.com/ncw/go-acd/account.go b/vendor/github.com/ncw/go-acd/account.go index 8e559b760..65a929d99 100644 --- a/vendor/github.com/ncw/go-acd/account.go +++ b/vendor/github.com/ncw/go-acd/account.go @@ -64,8 +64,8 @@ type AccountInfo struct { Status *string `json:"status"` } -// Provides information about the current user account like the status and the -// accepted “Terms Of Use”. +// GetInfo provides information about the current user account like +// the status and the accepted “Terms Of Use”. func (s *AccountService) GetInfo() (*AccountInfo, *http.Response, error) { req, err := s.client.NewMetadataRequest("GET", "account/info", nil) if err != nil { @@ -88,7 +88,7 @@ type AccountQuota struct { Available *uint64 `json:"available"` } -// Gets account quota and storage availability information. +// GetQuota gets account quota and storage availability information. func (s *AccountService) GetQuota() (*AccountQuota, *http.Response, error) { req, err := s.client.NewMetadataRequest("GET", "account/quota", nil) if err != nil { @@ -112,16 +112,20 @@ type AccountUsage struct { Photo *CategoryUsage `json:"photo"` Video *CategoryUsage `json:"video"` } + +// CategoryUsage defines Total and Billable UsageNumbers type CategoryUsage struct { Total *UsageNumbers `json:"total"` Billable *UsageNumbers `json:"billable"` } + +// UsageNumbers defines Bytes and Count for a metered count type UsageNumbers struct { Bytes *uint64 `json:"bytes"` Count *uint64 `json:"count"` } -// Gets Account Usage information broken down by content category. +// GetUsage gets Account Usage information broken down by content category. func (s *AccountService) GetUsage() (*AccountUsage, *http.Response, error) { req, err := s.client.NewMetadataRequest("GET", "account/usage", nil) if err != nil { diff --git a/vendor/github.com/ncw/go-acd/client.go b/vendor/github.com/ncw/go-acd/client.go index 28c616845..76d8e570c 100644 --- a/vendor/github.com/ncw/go-acd/client.go +++ b/vendor/github.com/ncw/go-acd/client.go @@ -17,6 +17,7 @@ import ( ) const ( + // LibraryVersion is the current version of this library LibraryVersion = "0.1.0" defaultMetadataURL = "https://drive.amazonaws.com/drive/v1/" defaultContentURL = "https://content-na.drive.amazonaws.com/cdproxy/" diff --git a/vendor/github.com/ncw/go-acd/nodes.go b/vendor/github.com/ncw/go-acd/nodes.go index 309ee7222..cc2f32124 100644 --- a/vendor/github.com/ncw/go-acd/nodes.go +++ b/vendor/github.com/ncw/go-acd/nodes.go @@ -22,6 +22,7 @@ import ( ) var ( + // ErrorNodeNotFound is returned from GetFile, GetFolder, GetNode ErrorNodeNotFound = errors.New("Node not found") ) @@ -32,7 +33,7 @@ type NodesService struct { client *Client } -// Gets the root folder of the Amazon Cloud Drive. +// GetRoot gets the root folder of the Amazon Cloud Drive. func (s *NodesService) GetRoot() (*Folder, *http.Response, error) { opts := &NodeListOptions{Filters: "kind:FOLDER AND isRoot:true"} @@ -48,12 +49,12 @@ func (s *NodesService) GetRoot() (*Folder, *http.Response, error) { return &Folder{roots[0]}, resp, nil } -// Gets the list of all nodes. +// GetAllNodes gets the list of all nodes. func (s *NodesService) GetAllNodes(opts *NodeListOptions) ([]*Node, *http.Response, error) { return s.listAllNodes("nodes", opts) } -// Gets a list of nodes, up until the limit (either default or the one set in opts). +// GetNodes gets a list of nodes, up until the limit (either default or the one set in opts). func (s *NodesService) GetNodes(opts *NodeListOptions) ([]*Node, *http.Response, error) { nodes, res, err := s.listNodes("nodes", opts) return nodes, res, err @@ -146,9 +147,9 @@ type Node struct { } // NodeFromId constructs a skeleton Node from an Id and a NodeService -func NodeFromId(Id string, service *NodesService) *Node { +func NodeFromId(ID string, service *NodesService) *Node { return &Node{ - Id: &Id, + Id: &ID, service: service, } } @@ -225,25 +226,82 @@ func (n *Node) GetMetadata() (string, error) { return md.String(), nil } -// Move node -func (n *Node) Move(newParent string) (*Node, *http.Response, error) { - url := fmt.Sprintf("nodes/%s/children", EscapeForFilter(newParent)) - metadata := moveNode{ - Id: *n.Id, - ParentId: n.Parents[0], +type replaceParent struct { + FromParent string `json:"fromParent"` + ChildID string `json:"childId"` +} + +// ReplaceParent puts Node n below a new parent while removing the old one at the same time. +// This is equivalent to calling AddParent and RemoveParent sequentially, but +// only needs one REST call. Can return a 409 Conflict if there's already a +// file or folder in the new location with the same name as Node n. +func (n *Node) ReplaceParent(oldParentID string, newParentID string) (*http.Response, error) { + body := &replaceParent{ + FromParent: oldParentID, + ChildID: *n.Id, + } + url := fmt.Sprintf("nodes/%s/children", newParentID) + req, err := n.service.client.NewMetadataRequest("POST", url, &body) + if err != nil { + return nil, err + } + resp, err := n.service.client.Do(req, nil) + if err != nil { + return resp, err + } + n.Parents = []string{newParentID} + + err = resp.Body.Close() + return resp, err +} + +// AddParent adds an additional parent to Node n. Can return a 409 Conflict if there's +// already a file or folder below the new parent with the same name as Node n. +func (n *Node) AddParent(newParentID string) (*http.Response, error) { + return n.changeParents(newParentID, true) +} + +// RemoveParent removes a parent from Node n. If all parents are removed, the file is instead +// attached to the absolute root folder of AmazonDrive. +func (n *Node) RemoveParent(parentID string) (*http.Response, error) { + return n.changeParents(parentID, false) +} + +func (n *Node) changeParents(parentID string, add bool) (*http.Response, error) { + method := "DELETE" + if add { + method = "PUT" } - req, err := n.service.client.NewMetadataRequest("POST", url, &metadata) + url := fmt.Sprintf("nodes/%s/children/%s", parentID, *n.Id) + req, err := n.service.client.NewMetadataRequest(method, url, nil) if err != nil { - return nil, nil, err + return nil, err + } + resp, err := n.service.client.Do(req, nil) + if err != nil { + return resp, err + } + if add { + n.Parents = append(n.Parents, parentID) + } else { + var removeIndex int + for i := 0; i < len(n.Parents); i++ { + if n.Parents[i] == parentID { + removeIndex = i + break + } + } + n.Parents = append(n.Parents[:removeIndex], n.Parents[removeIndex+1:]...) } - node := &Node{service: n.service} - resp, err := n.service.client.Do(req, node) - if err != nil { - return nil, resp, err - } - return node, resp, nil + err = resp.Body.Close() + return resp, err +} + +// renameNode is a cut down set of parameters for renaming nodes +type renameNode struct { + Name string `json:"name"` } // Rename node @@ -253,17 +311,14 @@ func (n *Node) Rename(newName string) (*Node, *http.Response, error) { Name: newName, } + node := &Node{service: n.service} req, err := n.service.client.NewMetadataRequest("PATCH", url, &metadata) if err != nil { return nil, nil, err } - node := &Node{service: n.service} resp, err := n.service.client.Do(req, node) - if err != nil { - return nil, resp, err - } - return node, resp, nil + return node, resp, err } // Trash places Node n into the trash. If the node is a directory it @@ -286,12 +341,28 @@ func (n *Node) Trash() (*http.Response, error) { } +// Restore moves a previously trashed Node n back into all its connected parents +func (n *Node) Restore() (*Node, *http.Response, error) { + url := fmt.Sprintf("trash/%s/restore", *n.Id) + req, err := n.service.client.NewMetadataRequest("POST", url, nil) + if err != nil { + return nil, nil, err + } + node := &Node{service: n.service} + resp, err := n.service.client.Do(req, node) + if err != nil { + return nil, resp, err + } + err = resp.Body.Close() + return node, resp, err +} + // File represents a file on the Amazon Cloud Drive. type File struct { *Node } -// Open the content of the file f for read +// OpenHeaders opens the content of the file f for read // // Extra headers for the GET can be passed in in headers // @@ -319,7 +390,7 @@ func (f *File) Open() (in io.ReadCloser, resp *http.Response, err error) { return f.OpenHeaders(nil) } -// OpenTempURL opens the content of the file f for read from the TempURL +// OpenTempURLHeaders opens the content of the file f for read from the TempURL // // Pass in an http Client (without authorization) for the download. // @@ -381,25 +452,27 @@ type Folder struct { } // FolderFromId constructs a skeleton Folder from an Id and a NodeService -func FolderFromId(Id string, service *NodesService) *Folder { +func FolderFromId(ID string, service *NodesService) *Folder { return &Folder{ - Node: NodeFromId(Id, service), + Node: NodeFromId(ID, service), } } -// Gets the list of all children. +// GetAllChildren gets the list of all children. func (f *Folder) GetAllChildren(opts *NodeListOptions) ([]*Node, *http.Response, error) { url := fmt.Sprintf("nodes/%s/children", *f.Id) return f.service.listAllNodes(url, opts) } -// Gets a list of children, up until the limit (either default or the one set in opts). +// GetChildren gets a list of children, up until the limit (either +// default or the one set in opts). func (f *Folder) GetChildren(opts *NodeListOptions) ([]*Node, *http.Response, error) { url := fmt.Sprintf("nodes/%s/children", *f.Id) return f.service.listNodes(url, opts) } -// Gets the subfolder by name. It is an error if not exactly one subfolder is found. +// GetFolder gets the subfolder by name. It is an error if not exactly +// one subfolder is found. // // If it isn't found then it returns the error ErrorNodeNotFound func (f *Folder) GetFolder(name string) (*Folder, *http.Response, error) { @@ -410,7 +483,7 @@ func (f *Folder) GetFolder(name string) (*Folder, *http.Response, error) { res, ok := n.Typed().(*Folder) if !ok { - err := errors.New(fmt.Sprintf("Node '%s' is not a folder", name)) + err := fmt.Errorf("Node '%s' is not a folder", name) return nil, resp, err } @@ -424,17 +497,6 @@ type createNode struct { Parents []string `json:"parents"` } -// moveNode is a cut down set of parameters for moving nodes -type moveNode struct { - ParentId string `json:"fromParent"` - Id string `json:"childId"` -} - -// renameNode is a cut down set of parameters for renaming nodes -type renameNode struct { - Name string `json:"name"` -} - // CreateFolder makes a new folder with the given name. // // The new Folder is returned @@ -458,7 +520,7 @@ func (f *Folder) CreateFolder(name string) (*Folder, *http.Response, error) { } -// Gets the file by name. It is an error if not exactly one file is found. +// GetFile gets the file by name. It is an error if not exactly one file is found. // // If it isn't found then it returns the error ErrorNodeNotFound func (f *Folder) GetFile(name string) (*File, *http.Response, error) { @@ -469,7 +531,7 @@ func (f *Folder) GetFile(name string) (*File, *http.Response, error) { res, ok := n.Typed().(*File) if !ok { - err := errors.New(fmt.Sprintf("Node '%s' is not a file", name)) + err := fmt.Errorf("Node '%s' is not a file", name) return nil, resp, err } @@ -492,7 +554,7 @@ func EscapeForFilter(s string) string { return escapeForFilterRe.ReplaceAllString(s, `\$1`) } -// Gets the node by name. It is an error if not exactly one node is found. +// GetNode gets the node by name. It is an error if not exactly one node is found. // // If it isn't found then it returns the error ErrorNodeNotFound func (f *Folder) GetNode(name string) (*Node, *http.Response, error) { @@ -508,7 +570,7 @@ func (f *Folder) GetNode(name string) (*Node, *http.Response, error) { return nil, resp, ErrorNodeNotFound } if len(nodes) > 1 { - err := errors.New(fmt.Sprintf("Too many nodes '%s' found (%v)", name, len(nodes))) + err := fmt.Errorf("Too many nodes '%s' found (%v)", name, len(nodes)) return nil, resp, err } @@ -549,7 +611,7 @@ func (f *Folder) WalkNodes(names ...string) (*Node, []*http.Response, error) { // Put stores the data read from in at path as name on the Amazon Cloud Drive. // Errors if the file already exists on the drive. -func (service *NodesService) putOrOverwrite(in io.Reader, httpVerb, url, name, metadata string) (*File, *http.Response, error) { +func (s *NodesService) putOrOverwrite(in io.Reader, httpVerb, url, name, metadata string) (*File, *http.Response, error) { bodyReader, bodyWriter := io.Pipe() writer := multipart.NewWriter(bodyWriter) contentType := writer.FormDataContentType() @@ -579,15 +641,15 @@ func (service *NodesService) putOrOverwrite(in io.Reader, httpVerb, url, name, m errChan <- writer.Close() }() - req, err := service.client.NewContentRequest(httpVerb, url, bodyReader) + req, err := s.client.NewContentRequest(httpVerb, url, bodyReader) if err != nil { return nil, nil, err } req.Header.Add("Content-Type", contentType) - file := &File{&Node{service: service}} - resp, err := service.client.Do(req, file) + file := &File{&Node{service: s}} + resp, err := s.client.Do(req, file) if err != nil { return nil, resp, err } @@ -602,7 +664,7 @@ func (service *NodesService) putOrOverwrite(in io.Reader, httpVerb, url, name, m // Put stores the data read from in at path as name on the Amazon Cloud Drive. // Errors if the file already exists on the drive. -func (service *NodesService) putOrOverwriteSized(in io.Reader, fileSize int64, httpVerb, url, name, metadata string) (*File, *http.Response, error) { +func (s *NodesService) putOrOverwriteSized(in io.Reader, fileSize int64, httpVerb, url, name, metadata string) (*File, *http.Response, error) { var err error bodyBuf := bytes.NewBufferString("") bodyWriter := multipart.NewWriter(bodyBuf) @@ -621,23 +683,23 @@ func (service *NodesService) putOrOverwriteSized(in io.Reader, fileSize int64, h // need to know the boundary to properly close the part myself. boundary := bodyWriter.Boundary() - close_buf := bytes.NewBufferString(fmt.Sprintf("\r\n--%s--\r\n", boundary)) + closeBuf := bytes.NewBufferString(fmt.Sprintf("\r\n--%s--\r\n", boundary)) // use multi-reader to defer the reading of the file data // until writing to the socket buffer. - request_reader := io.MultiReader(bodyBuf, in, close_buf) + requestReader := io.MultiReader(bodyBuf, in, closeBuf) - req, err := service.client.NewContentRequest(httpVerb, url, request_reader) + req, err := s.client.NewContentRequest(httpVerb, url, requestReader) if err != nil { return nil, nil, err } // Set headers for multipart, and Content Length req.Header.Add("Content-Type", "multipart/form-data; boundary="+boundary) - req.ContentLength = fileSize + int64(bodyBuf.Len()) + int64(close_buf.Len()) + req.ContentLength = fileSize + int64(bodyBuf.Len()) + int64(closeBuf.Len()) - file := &File{&Node{service: service}} - resp, err := service.client.Do(req, file) + file := &File{&Node{service: s}} + resp, err := s.client.Do(req, file) if err != nil { return nil, resp, err } @@ -655,11 +717,11 @@ func (f *Folder) Put(in io.Reader, name string) (*File, *http.Response, error) { Kind: "FILE", Parents: []string{*f.Id}, } - metadataJson, err := json.Marshal(&metadata) + metadataJSON, err := json.Marshal(&metadata) if err != nil { return nil, nil, err } - return f.service.putOrOverwrite(in, "POST", "nodes?suppress=deduplication", name, string(metadataJson)) + return f.service.putOrOverwrite(in, "POST", "nodes?suppress=deduplication", name, string(metadataJSON)) } // Overwrite updates the file contents from in @@ -670,22 +732,22 @@ func (f *File) Overwrite(in io.Reader) (*File, *http.Response, error) { return f.service.putOrOverwrite(in, "PUT", url, *f.Name, "") } -// Put stores the data read from in at path as name on the Amazon Cloud Drive. -// Errors if the file already exists on the drive. +// PutSized stores the data read from in at path as name on the Amazon +// Cloud Drive. Errors if the file already exists on the drive. func (f *Folder) PutSized(in io.Reader, size int64, name string) (*File, *http.Response, error) { metadata := createNode{ Name: name, Kind: "FILE", Parents: []string{*f.Id}, } - metadataJson, err := json.Marshal(&metadata) + metadataJSON, err := json.Marshal(&metadata) if err != nil { return nil, nil, err } - return f.service.putOrOverwriteSized(in, size, "POST", "nodes?suppress=deduplication", name, string(metadataJson)) + return f.service.putOrOverwriteSized(in, size, "POST", "nodes?suppress=deduplication", name, string(metadataJSON)) } -// Overwrite updates the file contents from in +// OverwriteSized updates the file contents from in func (f *File) OverwriteSized(in io.Reader, size int64) (*File, *http.Response, error) { url := fmt.Sprintf("nodes/%s/content", *f.Id) return f.service.putOrOverwriteSized(in, size, "PUT", url, *f.Name, "")