implemented go client.RemoveBlobs; no idea if it works yet

This commit is contained in:
Brett Slatkin 2011-03-05 12:46:28 -08:00
parent 4de2eb4ebd
commit 16c672506b
2 changed files with 85 additions and 7 deletions

View File

@ -145,7 +145,7 @@ func doPass(sc, dc *client.Client, passNum int) (retErr os.Error) {
bytesCopied += pr.Size
}
if *flagRemoveSource {
if err = sc.Remove(sb.BlobRef); err != nil {
if err = sc.RemoveBlob(sb.BlobRef); err != nil {
errorCount++
log.Printf("Failed to delete %s from source: %v", sb.BlobRef, err)
}

View File

@ -17,15 +17,93 @@ limitations under the License.
package client
import (
"bytes"
"camli/blobref"
"fmt"
// "http"
"http"
"io"
"json"
"os"
"strconv"
"strings"
)
// Remove removes the blob. An error is returned if the blob was failed to
// be removed. Removal of a non-existent blob isn't an error.
func (c *Client) Remove(b *blobref.BlobRef) os.Error {
url := fmt.Sprintf("%s/camli/post", c.server)
return os.NewError(fmt.Sprintf("NOT IMPLEMENTED remove of %s to %s", b, url))
type removeResponse struct {
removed []string
}
// Remove the list of blobs. An error is returned if the server failed to
// remove a blob. Removing a non-existent blob isn't an error.
func (c *Client) RemoveBlobs(blobs []*blobref.BlobRef) os.Error {
url := fmt.Sprintf("%s/camli/remove", c.server)
params := make(map[string][]string) // "blobN" -> BlobRefStr
needsDelete := make(map[string]bool) // BlobRefStr -> true
for n, b := range blobs {
key := fmt.Sprintf("blob%v", n)
params[key] = []string{b.String()}
needsDelete[b.String()] = true
}
body := http.EncodeQuery(params)
req := new(http.Request)
req.Method = "POST"
req.ProtoMajor = 1
req.ProtoMinor = 1
req.Close = true
req.Header = http.Header(make(map[string][]string))
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
req.Header.Add("Content-Length", strconv.Itoa(len(body)))
if c.HasAuthCredentials() {
req.Header.Add("Authorization", c.authHeader())
}
req.URL, _ = http.ParseURL(url)
req.RawURL = url
req.Body = nopCloser{strings.NewReader(body)}
req.ContentLength = int64(len(body))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return os.NewError(fmt.Sprintf("Got status code %d from blobserver for remove %s", resp.StatusCode, body))
}
// The only valid HTTP responses are 200.
if resp.StatusCode != 200 {
return os.NewError(fmt.Sprintf("Invalid http response %d in remove response", resp.StatusCode))
}
// TODO: LimitReader here for paranoia
buf := new(bytes.Buffer)
io.Copy(buf, resp.Body)
resp.Body.Close()
var remResp removeResponse
if jerr := json.Unmarshal(buf.Bytes(), &remResp); jerr != nil {
return jerr
}
for _, value := range remResp.removed {
needsDelete[value] = false, false
}
if len(needsDelete) > 0 {
return os.NewError(fmt.Sprintf("Failed to remove blobs %s", strings.Join(stringKeys(needsDelete), ", ")))
}
return nil
}
// Remove the single blob. An error is returned if the server failed to remove
// the blob. Removing a non-existent blob isn't an error.
func (c *Client) RemoveBlob(b *blobref.BlobRef) os.Error {
return c.RemoveBlobs([]*blobref.BlobRef{b})
}
func stringKeys(v interface{}) (s []string) {
m, ok := v.(map[string]interface{})
if !ok {
panic("Wrong type")
}
s = make([]string, 0, len(m))
for key, _ := range m {
s = append(s, key)
}
return
}