1
0
mirror of https://github.com/minio/mc.git synced 2025-11-14 23:42:27 +03:00

Code cleanup and standardizing in accordance with Golang coding guidelines

This commit is contained in:
Harshavardhana
2015-03-05 01:13:24 -08:00
parent d6aaf2b7c5
commit c1af2ccf67
11 changed files with 161 additions and 132 deletions

View File

@@ -18,6 +18,7 @@ package main
import ( import (
"encoding/json" "encoding/json"
"net/http"
"os" "os"
"os/user" "os/user"
"path" "path"
@@ -33,6 +34,13 @@ func getAuthFilePath() (string, error) {
return path.Join(u.HomeDir, Auth), nil return path.Join(u.HomeDir, Auth), nil
} }
func getNewClient(auth *s3.Auth) (*s3.Client, error) {
return &s3.Client{
Auth: auth,
Transport: http.DefaultTransport,
}, nil
}
func getAWSEnvironment() (auth *s3.Auth, err error) { func getAWSEnvironment() (auth *s3.Auth, err error) {
var s3Auth *os.File var s3Auth *os.File
var accessKey, secretKey, endpoint string var accessKey, secretKey, endpoint string

View File

@@ -2,6 +2,7 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt"
"log" "log"
"os" "os"
"path" "path"
@@ -17,16 +18,22 @@ func parseConfigureInput(c *cli.Context) (auth *s3.Auth, err error) {
pathstyle := c.Bool("pathstyle") pathstyle := c.Bool("pathstyle")
if accessKey == "" { if accessKey == "" {
return nil, configAccessErr return nil, errAccess
} }
if secretKey == "" { if secretKey == "" {
return nil, configSecretErr return nil, errSecret
} }
if endpoint == "" { if endpoint == "" {
return nil, configEndpointErr return nil, errEndpoint
}
auth = &s3.Auth{
AccessKey: accessKey,
SecretAccessKey: secretKey,
Endpoint: endpoint,
S3ForcePathStyle: pathstyle,
} }
auth = s3.NewAuth(accessKey, secretKey, endpoint, pathstyle)
return auth, nil return auth, nil
} }
@@ -39,7 +46,7 @@ func doConfigure(c *cli.Context) {
log.Fatal(err) log.Fatal(err)
} }
jAuth, err = json.Marshal(auth) jAuth, err = json.MarshalIndent(auth, "", " ")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@@ -51,11 +58,10 @@ func doConfigure(c *cli.Context) {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
_, err = s3File.Write(jAuth) _, err = s3File.Write(jAuth)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Println("Written!", path.Join(home, Auth)) fmt.Println("")
log.Println("Now run ``mc --help`` to read on other options") fmt.Println("Configuration written to", path.Join(home, Auth))
} }

View File

@@ -56,8 +56,7 @@ import (
"time" "time"
) )
// See http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?RESTAuthentication.html // Auth - see http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?RESTAuthentication.html
type Auth struct { type Auth struct {
AccessKey string AccessKey string
SecretAccessKey string SecretAccessKey string
@@ -73,7 +72,8 @@ type Auth struct {
S3ForcePathStyle bool S3ForcePathStyle bool
} }
type TlsConfig struct { // TLSConfig - TLS cert and key configuration
type TLSConfig struct {
CertPEMBlock []byte CertPEMBlock []byte
KeyPEMBlock []byte KeyPEMBlock []byte
} }
@@ -85,14 +85,13 @@ func (a *Auth) endpoint() string {
if a.Endpoint != "" { if a.Endpoint != "" {
if strings.HasSuffix(a.Endpoint, "amazonaws.com") { if strings.HasSuffix(a.Endpoint, "amazonaws.com") {
return "https://" + a.Endpoint return "https://" + a.Endpoint
} else {
return "http://" + a.Endpoint
} }
return "http://" + a.Endpoint
} }
return "https://" + standardUSRegionAWS return "https://" + standardUSRegionAWS
} }
func (a *Auth) loadKeys(cert string, key string) (*TlsConfig, error) { func (a *Auth) loadKeys(cert string, key string) (*TLSConfig, error) {
certBlock, err := ioutil.ReadFile(cert) certBlock, err := ioutil.ReadFile(cert)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -101,13 +100,13 @@ func (a *Auth) loadKeys(cert string, key string) (*TlsConfig, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
t := &TlsConfig{} t := &TLSConfig{}
t.CertPEMBlock = certBlock t.CertPEMBlock = certBlock
t.KeyPEMBlock = keyBlock t.KeyPEMBlock = keyBlock
return t, nil return t, nil
} }
func (a *Auth) getTlsTransport() (*http.Transport, error) { func (a *Auth) getTLSTransport() (*http.Transport, error) {
if a.CertPEM == "" || a.KeyPEM == "" { if a.CertPEM == "" || a.KeyPEM == "" {
return &http.Transport{ return &http.Transport{
Dial: (&net.Dialer{ Dial: (&net.Dialer{
@@ -139,7 +138,7 @@ func (a *Auth) getTlsTransport() (*http.Transport, error) {
return transport, nil return transport, nil
} }
func (a *Auth) SignRequest(req *http.Request) { func (a *Auth) signRequest(req *http.Request) {
if date := req.Header.Get("Date"); date == "" { if date := req.Header.Get("Date"); date == "" {
req.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) req.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
} }
@@ -203,7 +202,7 @@ func hasPrefixCaseInsensitive(s, pfx string) bool {
} }
func (a *Auth) writeCanonicalizedAmzHeaders(buf *bytes.Buffer, req *http.Request) { func (a *Auth) writeCanonicalizedAmzHeaders(buf *bytes.Buffer, req *http.Request) {
amzHeaders := make([]string, 0) var amzHeaders []string
vals := make(map[string][]string) vals := make(map[string][]string)
for k, vv := range req.Header { for k, vv := range req.Header {
if hasPrefixCaseInsensitive(k, "x-amz-") { if hasPrefixCaseInsensitive(k, "x-amz-") {

View File

@@ -134,15 +134,15 @@ func TestBucketFromHostname(t *testing.T) {
} }
} }
func TestSignRequest(t *testing.T) { func TestsignRequest(t *testing.T) {
r := req("GET /foo HTTP/1.1\n\n") r := req("GET /foo HTTP/1.1\n\n")
auth := &Auth{AccessKey: "key", SecretAccessKey: "secretkey"} auth := &Auth{AccessKey: "key", SecretAccessKey: "secretkey"}
auth.SignRequest(r) auth.signRequest(r)
if r.Header.Get("Date") == "" { if r.Header.Get("Date") == "" {
t.Error("expected a Date set") t.Error("expected a Date set")
} }
r.Header.Set("Date", "Sat, 02 Apr 2011 04:23:52 GMT") r.Header.Set("Date", "Sat, 02 Apr 2011 04:23:52 GMT")
auth.SignRequest(r) auth.signRequest(r)
if e, g := r.Header.Get("Authorization"), "AWS key:kHpCR/N7Rw3PwRlDd8+5X40CFVc="; e != g { if e, g := r.Header.Get("Authorization"), "AWS key:kHpCR/N7Rw3PwRlDd8+5X40CFVc="; e != g {
t.Errorf("got header %q; expected %q", g, e) t.Errorf("got header %q; expected %q", g, e)
} }

View File

@@ -59,8 +59,9 @@ import (
"time" "time"
) )
// Total max object list
const ( const (
MAX_OBJECT_LIST = 1000 MaxKeys = 1000
) )
// Client is an Amazon S3 client. // Client is an Amazon S3 client.
@@ -69,6 +70,7 @@ type Client struct {
Transport http.RoundTripper // or nil for the default Transport http.RoundTripper // or nil for the default
} }
// Bucket - carries s3 bucket reply header
type Bucket struct { type Bucket struct {
Name string Name string
CreationDate string // 2006-02-03T16:45:09.000Z CreationDate string // 2006-02-03T16:45:09.000Z
@@ -83,26 +85,26 @@ func (c *Client) transport() http.RoundTripper {
// bucketURL returns the URL prefix of the bucket, with trailing slash // bucketURL returns the URL prefix of the bucket, with trailing slash
func (c *Client) bucketURL(bucket string) string { func (c *Client) bucketURL(bucket string) string {
var url_ string var url string
if IsValidBucket(bucket) && !strings.Contains(bucket, ".") { if IsValidBucket(bucket) && !strings.Contains(bucket, ".") {
// if localhost forcePathStyle // if localhost forcePathStyle
if strings.Contains(c.endpoint(), "localhost") || strings.Contains(bucket, "127.0.0.1") { if strings.Contains(c.endpoint(), "localhost") || strings.Contains(bucket, "127.0.0.1") {
url_ = fmt.Sprintf("%s/%s", c.endpoint(), bucket) url = fmt.Sprintf("%s/%s", c.endpoint(), bucket)
goto ret goto ret
} }
if !c.S3ForcePathStyle { if !c.S3ForcePathStyle {
if strings.Contains(c.endpoint(), "amazonaws.com") { if strings.Contains(c.endpoint(), "amazonaws.com") {
url_ = fmt.Sprintf("https://%s.%s/", bucket, strings.TrimPrefix(c.endpoint(), "https://")) url = fmt.Sprintf("https://%s.%s/", bucket, strings.TrimPrefix(c.endpoint(), "https://"))
} else { } else {
url_ = fmt.Sprintf("http://%s.%s/", bucket, strings.TrimPrefix(c.endpoint(), "http://")) url = fmt.Sprintf("http://%s.%s/", bucket, strings.TrimPrefix(c.endpoint(), "http://"))
} }
} else { } else {
url_ = fmt.Sprintf("%s/%s", c.endpoint(), bucket) url = fmt.Sprintf("%s/%s", c.endpoint(), bucket)
} }
} }
ret: ret:
return url_ return url
} }
func (c *Client) keyURL(bucket, key string) string { func (c *Client) keyURL(bucket, key string) string {
@@ -113,8 +115,8 @@ func (c *Client) keyURL(bucket, key string) string {
return c.bucketURL(bucket) + key return c.bucketURL(bucket) + key
} }
func newReq(url_ string) *http.Request { func newReq(url string) *http.Request {
req, err := http.NewRequest("GET", url_, nil) req, err := http.NewRequest("GET", url, nil)
if err != nil { if err != nil {
panic(fmt.Sprintf("s3 client; invalid URL: %v", err)) panic(fmt.Sprintf("s3 client; invalid URL: %v", err))
} }
@@ -122,20 +124,6 @@ func newReq(url_ string) *http.Request {
return req return req
} }
func (c *Client) Buckets() ([]*Bucket, error) {
req := newReq(c.endpoint() + "/")
c.Auth.SignRequest(req)
res, err := c.transport().RoundTrip(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("s3: Unexpected status code %d fetching bucket list", res.StatusCode)
}
return parseListAllMyBuckets(res.Body)
}
func parseListAllMyBuckets(r io.Reader) ([]*Bucket, error) { func parseListAllMyBuckets(r io.Reader) ([]*Bucket, error) {
type allMyBuckets struct { type allMyBuckets struct {
Buckets struct { Buckets struct {
@@ -149,11 +137,28 @@ func parseListAllMyBuckets(r io.Reader) ([]*Bucket, error) {
return res.Buckets.Bucket, nil return res.Buckets.Bucket, nil
} }
// Returns 0, "", os.ErrNotExist if not on S3, otherwise reterr is real. /// Object API operations
// Buckets - Get list of buckets
func (c *Client) Buckets() ([]*Bucket, error) {
req := newReq(c.endpoint() + "/")
c.Auth.signRequest(req)
res, err := c.transport().RoundTrip(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("s3: Unexpected status code %d fetching bucket list", res.StatusCode)
}
return parseListAllMyBuckets(res.Body)
}
// Stat - returns 0, "", os.ErrNotExist if not on S3
func (c *Client) Stat(key, bucket string) (size int64, date string, reterr error) { func (c *Client) Stat(key, bucket string) (size int64, date string, reterr error) {
req := newReq(c.keyURL(bucket, key)) req := newReq(c.keyURL(bucket, key))
req.Method = "HEAD" req.Method = "HEAD"
c.Auth.SignRequest(req) c.Auth.signRequest(req)
res, err := c.transport().RoundTrip(req) res, err := c.transport().RoundTrip(req)
if err != nil { if err != nil {
return 0, "", err return 0, "", err
@@ -175,14 +180,15 @@ func (c *Client) Stat(key, bucket string) (size int64, date string, reterr error
return 0, "", fmt.Errorf("s3: Unexpected status code %d statting object %v", res.StatusCode, key) return 0, "", fmt.Errorf("s3: Unexpected status code %d statting object %v", res.StatusCode, key)
} }
// PutBucket - create new bucket
func (c *Client) PutBucket(bucket string) error { func (c *Client) PutBucket(bucket string) error {
var url_ string var url string
if IsValidBucket(bucket) && !strings.Contains(bucket, ".") { if IsValidBucket(bucket) && !strings.Contains(bucket, ".") {
url_ = fmt.Sprintf("%s/%s", c.endpoint(), bucket) url = fmt.Sprintf("%s/%s", c.endpoint(), bucket)
} }
req := newReq(url_) req := newReq(url)
req.Method = "PUT" req.Method = "PUT"
c.Auth.SignRequest(req) c.Auth.signRequest(req)
res, err := c.transport().RoundTrip(req) res, err := c.transport().RoundTrip(req)
if err != nil { if err != nil {
return err return err
@@ -193,13 +199,13 @@ func (c *Client) PutBucket(bucket string) error {
} }
if res.StatusCode != http.StatusOK { if res.StatusCode != http.StatusOK {
// res.Write(os.Stderr)
return fmt.Errorf("Got response code %d from s3", res.StatusCode) return fmt.Errorf("Got response code %d from s3", res.StatusCode)
} }
return nil return nil
} }
// Put - upload new object to bucket
func (c *Client) Put(bucket, key string, md5 hash.Hash, size int64, body io.Reader) error { func (c *Client) Put(bucket, key string, md5 hash.Hash, size int64, body io.Reader) error {
req := newReq(c.keyURL(bucket, key)) req := newReq(c.keyURL(bucket, key))
req.Method = "PUT" req.Method = "PUT"
@@ -211,7 +217,7 @@ func (c *Client) Put(bucket, key string, md5 hash.Hash, size int64, body io.Read
encoder.Close() encoder.Close()
req.Header.Set("Content-MD5", b64.String()) req.Header.Set("Content-MD5", b64.String())
} }
c.Auth.SignRequest(req) c.Auth.signRequest(req)
req.Body = ioutil.NopCloser(body) req.Body = ioutil.NopCloser(body)
res, err := c.transport().RoundTrip(req) res, err := c.transport().RoundTrip(req)
@@ -229,12 +235,14 @@ func (c *Client) Put(bucket, key string, md5 hash.Hash, size int64, body io.Read
return nil return nil
} }
// Item - object item list
type Item struct { type Item struct {
Key string Key string
LastModified string LastModified string
Size int64 Size int64
} }
// Prefix - common prefix
type Prefix struct { type Prefix struct {
Prefix string Prefix string
} }
@@ -258,14 +266,14 @@ type listBucketResults struct {
CommonPrefixes []*Prefix CommonPrefixes []*Prefix
} }
// BucketLocation returns the S3 endpoint to be used with the given bucket. // BucketLocation - returns the S3 endpoint to be used with the given bucket.
func (c *Client) BucketLocation(bucket string) (location string, err error) { func (c *Client) BucketLocation(bucket string) (location string, err error) {
if !strings.HasSuffix(c.endpoint(), "amazonaws.com") { if !strings.HasSuffix(c.endpoint(), "amazonaws.com") {
return "", errors.New("BucketLocation not implemented for non-Amazon S3 endpoints") return "", errors.New("BucketLocation not implemented for non-Amazon S3 endpoints")
} }
url_ := fmt.Sprintf("%s/%s/?location", c.endpoint(), url.QueryEscape(bucket)) urlReq := fmt.Sprintf("%s/%s/?location", c.endpoint(), url.QueryEscape(bucket))
req := newReq(url_) req := newReq(urlReq)
c.Auth.SignRequest(req) c.Auth.signRequest(req)
res, err := c.transport().RoundTrip(req) res, err := c.transport().RoundTrip(req)
if err != nil { if err != nil {
return return
@@ -285,7 +293,7 @@ func (c *Client) BucketLocation(bucket string) (location string, err error) {
// 'marker' value). If the length of the returned items is equal to // 'marker' value). If the length of the returned items is equal to
// maxKeys, there is no indication whether or not the returned list is truncated. // maxKeys, there is no indication whether or not the returned list is truncated.
func (c *Client) GetBucket(bucket string, startAt, prefix, delimiter string, maxKeys int) (items []*Item, prefixes []*Prefix, err error) { func (c *Client) GetBucket(bucket string, startAt, prefix, delimiter string, maxKeys int) (items []*Item, prefixes []*Prefix, err error) {
var url_ string var urlReq string
var buffer bytes.Buffer var buffer bytes.Buffer
if maxKeys <= 0 { if maxKeys <= 0 {
@@ -295,8 +303,8 @@ func (c *Client) GetBucket(bucket string, startAt, prefix, delimiter string, max
marker := startAt marker := startAt
for len(items) < maxKeys { for len(items) < maxKeys {
fetchN := maxKeys - len(items) fetchN := maxKeys - len(items)
if fetchN > MAX_OBJECT_LIST { if fetchN > MaxKeys {
fetchN = MAX_OBJECT_LIST fetchN = MaxKeys
} }
var bres listBucketResults var bres listBucketResults
buffer.WriteString(fmt.Sprintf("%s?max-keys=%d", c.bucketURL(bucket), fetchN)) buffer.WriteString(fmt.Sprintf("%s?max-keys=%d", c.bucketURL(bucket), fetchN))
@@ -311,15 +319,15 @@ func (c *Client) GetBucket(bucket string, startAt, prefix, delimiter string, max
buffer.WriteString(fmt.Sprintf("&delimiter=%s", url.QueryEscape(delimiter))) buffer.WriteString(fmt.Sprintf("&delimiter=%s", url.QueryEscape(delimiter)))
} }
url_ = buffer.String() urlReq = buffer.String()
// Try the enumerate three times, since Amazon likes to close // Try the enumerate three times, since Amazon likes to close
// https connections a lot, and Go sucks at dealing with it: // https connections a lot, and Go sucks at dealing with it:
// https://code.google.com/p/go/issues/detail?id=3514 // https://code.google.com/p/go/issues/detail?id=3514
const maxTries = 5 const maxTries = 5
for try := 1; try <= maxTries; try++ { for try := 1; try <= maxTries; try++ {
time.Sleep(time.Duration(try-1) * 100 * time.Millisecond) time.Sleep(time.Duration(try-1) * 100 * time.Millisecond)
req := newReq(url_) req := newReq(urlReq)
c.Auth.SignRequest(req) c.Auth.signRequest(req)
res, err := c.transport().RoundTrip(req) res, err := c.transport().RoundTrip(req)
if err != nil { if err != nil {
if try < maxTries { if try < maxTries {
@@ -380,7 +388,6 @@ func (c *Client) GetBucket(bucket string, startAt, prefix, delimiter string, max
} }
if !bres.IsTruncated { if !bres.IsTruncated {
// log.Printf("Not truncated. so breaking. items = %d; len Contents = %d, url = %s", len(items), len(bres.Contents), url_)
break break
} }
if len(items) == 0 { if len(items) == 0 {
@@ -390,9 +397,10 @@ func (c *Client) GetBucket(bucket string, startAt, prefix, delimiter string, max
return items, prefixes, nil return items, prefixes, nil
} }
// Get - download a requested object from a given bucket
func (c *Client) Get(bucket, key string) (body io.ReadCloser, size int64, err error) { func (c *Client) Get(bucket, key string) (body io.ReadCloser, size int64, err error) {
req := newReq(c.keyURL(bucket, key)) req := newReq(c.keyURL(bucket, key))
c.Auth.SignRequest(req) c.Auth.signRequest(req)
res, err := c.transport().RoundTrip(req) res, err := c.transport().RoundTrip(req)
if err != nil { if err != nil {
return return
@@ -423,7 +431,7 @@ func (c *Client) GetPartial(bucket, key string, offset, length int64) (rc io.Rea
} else { } else {
req.Header.Set("Range", fmt.Sprintf("bytes=%d-", offset)) req.Header.Set("Range", fmt.Sprintf("bytes=%d-", offset))
} }
c.Auth.SignRequest(req) c.Auth.signRequest(req)
res, err := c.transport().RoundTrip(req) res, err := c.transport().RoundTrip(req)
if err != nil { if err != nil {
@@ -445,7 +453,7 @@ func (c *Client) GetPartial(bucket, key string, offset, length int64) (rc io.Rea
func (c *Client) Delete(bucket, key string) error { func (c *Client) Delete(bucket, key string) error {
req := newReq(c.keyURL(bucket, key)) req := newReq(c.keyURL(bucket, key))
req.Method = "DELETE" req.Method = "DELETE"
c.Auth.SignRequest(req) c.Auth.signRequest(req)
res, err := c.transport().RoundTrip(req) res, err := c.transport().RoundTrip(req)
if err != nil { if err != nil {
return err return err
@@ -461,23 +469,13 @@ func (c *Client) Delete(bucket, key string) error {
} }
*/ */
func NewAuth(accessKey, secretKey, endpoint string, style bool) (auth *Auth) { // NewClient - get new client
auth = &Auth{ func NewClient(auth *Auth) (client *Client) {
AccessKey: accessKey,
SecretAccessKey: secretKey,
Endpoint: endpoint,
S3ForcePathStyle: style,
}
return
}
func NewS3Client(auth *Auth) (client *Client) {
client = &Client{auth, http.DefaultTransport} client = &Client{auth, http.DefaultTransport}
return return
} }
// IsValid reports whether bucket is a valid bucket name, per Amazon's naming restrictions. // IsValidBucket reports whether bucket is a valid bucket name, per Amazon's naming restrictions.
//
// See http://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html // See http://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html
func IsValidBucket(bucket string) bool { func IsValidBucket(bucket string) bool {
if len(bucket) < 3 || len(bucket) > 63 { if len(bucket) < 3 || len(bucket) > 63 {
@@ -533,7 +531,7 @@ type xmlError struct {
XMLName xml.Name `xml:"Error"` XMLName xml.Name `xml:"Error"`
Code string Code string
Message string Message string
RequestId string RequestID string
Bucket string Bucket string
Endpoint string Endpoint string
StringToSignBytes string StringToSignBytes string

View File

@@ -19,17 +19,16 @@ package main
import "errors" import "errors"
// fs // fs
var fsPathErr = errors.New("Arguments missing <S3Path> or <LocalPath>") var errFspath = errors.New("Arguments missing <S3Path> or <LocalPath>")
var fsUriErr = errors.New("Invalid URI scheme") var errFsuri = errors.New("Invalid uri scheme")
var fsKeyErr = errors.New("Key is needed to get the file") var errFskey = errors.New("Key is needed to get the file")
// configure // configure
var configAccessErr = errors.New("accesskey is mandatory") var errAccess = errors.New("accesskey is mandatory")
var configSecretErr = errors.New("secretkey is mandatory") var errSecret = errors.New("secretkey is mandatory")
var configEndpointErr = errors.New("endpoint is missing") var errEndpoint = errors.New("endpoint is mandatory")
// common // common
var missingAccessSecretErr = errors.New("You can configure your credentials by running `mc configure`") var errMissingaccess = errors.New("Partial credentials found in the env, missing : AWS_ACCESS_KEY_ID")
var missingAccessErr = errors.New("Partial credentials found in the env, missing : AWS_ACCESS_KEY_ID") var errMissingsecret = errors.New("Partial credentials found in the env, missing : AWS_SECRET_ACCESS_KEY")
var missingSecretErr = errors.New("Partial credentials found in the env, missing : AWS_SECRET_ACCESS_KEY") var errInvalidbucket = errors.New("Invalid bucket name")
var invalidBucketErr = errors.New("Invalid bucket name")

View File

@@ -17,6 +17,7 @@
package main package main
import ( import (
"fmt"
"io" "io"
"log" "log"
"os" "os"
@@ -37,16 +38,16 @@ import (
func parseCpOptions(c *cli.Context) (fsoptions fsOptions, err error) { func parseCpOptions(c *cli.Context) (fsoptions fsOptions, err error) {
switch len(c.Args()) { switch len(c.Args()) {
case 1: case 1:
return fsOptions{}, fsPathErr return fsOptions{}, errFspath
case 2: case 2:
if strings.HasPrefix(c.Args().Get(0), "s3://") { if strings.HasPrefix(c.Args().Get(0), "s3://") {
uri := uri.ParseURI(c.Args().Get(0)) uri := uri.ParseURI(c.Args().Get(0))
if uri.Scheme == "" { if uri.Scheme == "" {
return fsOptions{}, fsUriErr return fsOptions{}, errFsuri
} }
fsoptions.bucket = uri.Server fsoptions.bucket = uri.Server
if uri.Path == "" { if uri.Path == "" {
return fsOptions{}, fsKeyErr return fsOptions{}, errFskey
} }
fsoptions.key = strings.TrimPrefix(uri.Path, "/") fsoptions.key = strings.TrimPrefix(uri.Path, "/")
if c.Args().Get(1) == "." { if c.Args().Get(1) == "." {
@@ -59,7 +60,7 @@ func parseCpOptions(c *cli.Context) (fsoptions fsOptions, err error) {
} else if strings.HasPrefix(c.Args().Get(1), "s3://") { } else if strings.HasPrefix(c.Args().Get(1), "s3://") {
uri := uri.ParseURI(c.Args().Get(1)) uri := uri.ParseURI(c.Args().Get(1))
if uri.Scheme == "" { if uri.Scheme == "" {
return fsOptions{}, fsUriErr return fsOptions{}, errFsuri
} }
fsoptions.bucket = uri.Server fsoptions.bucket = uri.Server
if uri.Path == "" { if uri.Path == "" {
@@ -72,7 +73,7 @@ func parseCpOptions(c *cli.Context) (fsoptions fsOptions, err error) {
fsoptions.isput = true fsoptions.isput = true
} }
default: default:
return fsOptions{}, fsPathErr return fsOptions{}, errFspath
} }
return return
} }
@@ -87,13 +88,18 @@ func startBar(size int64) *pb.ProgressBar {
func doFsCopy(c *cli.Context) { func doFsCopy(c *cli.Context) {
var auth *s3.Auth var auth *s3.Auth
var s3c *s3.Client
var err error var err error
var bodyFile *os.File var bodyFile *os.File
auth, err = getAWSEnvironment() auth, err = getAWSEnvironment()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
s3c := s3.NewS3Client(auth) s3c, err = getNewClient(auth)
if err != nil {
log.Fatal(err)
}
var fsoptions fsOptions var fsoptions fsOptions
fsoptions, err = parseCpOptions(c) fsoptions, err = parseCpOptions(c)
if err != nil { if err != nil {
@@ -119,6 +125,7 @@ func doFsCopy(c *cli.Context) {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
fmt.Printf("%s uploaded -- to bucket:%s", fsoptions.key, fsoptions.bucket)
} else if fsoptions.isget { } else if fsoptions.isget {
var objectReader io.ReadCloser var objectReader io.ReadCloser
var objectSize int64 var objectSize int64

View File

@@ -93,6 +93,7 @@ func getBucketAndObject(p string) (bucket, object string) {
func doFsList(c *cli.Context) { func doFsList(c *cli.Context) {
var err error var err error
var auth *s3.Auth var auth *s3.Auth
var s3c *s3.Client
var items []*s3.Item var items []*s3.Item
var prefixes []*s3.Prefix var prefixes []*s3.Prefix
@@ -102,7 +103,10 @@ func doFsList(c *cli.Context) {
} }
var buckets []*s3.Bucket var buckets []*s3.Bucket
s3c := s3.NewS3Client(auth) s3c, err = getNewClient(auth)
if err != nil {
log.Fatal(err)
}
switch len(c.Args()) { switch len(c.Args()) {
case 1: case 1:
input := c.Args().Get(0) input := c.Args().Get(0)
@@ -111,7 +115,7 @@ func doFsList(c *cli.Context) {
} }
bucket, object := getBucketAndObject(input) bucket, object := getBucketAndObject(input)
if object == "" { if object == "" {
items, prefixes, err = s3c.GetBucket(bucket, "", "", string(delimiter), s3.MAX_OBJECT_LIST) items, prefixes, err = s3c.GetBucket(bucket, "", "", string(delimiter), s3.MaxKeys)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@@ -122,7 +126,7 @@ func doFsList(c *cli.Context) {
var size int64 var size int64
size, date, err = s3c.Stat(object, bucket) size, date, err = s3c.Stat(object, bucket)
if err != nil { if err != nil {
items, prefixes, err = s3c.GetBucket(bucket, "", object, string(delimiter), s3.MAX_OBJECT_LIST) items, prefixes, err = s3c.GetBucket(bucket, "", object, string(delimiter), s3.MaxKeys)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@@ -27,7 +27,7 @@ func doFsMb(c *cli.Context) {
switch len(c.Args()) { switch len(c.Args()) {
case 1: case 1:
if !s3.IsValidBucket(c.Args().Get(0)) { if !s3.IsValidBucket(c.Args().Get(0)) {
log.Fatalf("%s: (%s)", invalidBucketErr, c.Args().Get(0)) log.Fatalf("%s: (%s)", errInvalidbucket, c.Args().Get(0))
} }
default: default:
log.Fatal("Needs an argument <BucketName>") log.Fatal("Needs an argument <BucketName>")
@@ -35,11 +35,12 @@ func doFsMb(c *cli.Context) {
bucketName := c.Args().Get(0) bucketName := c.Args().Get(0)
var err error var err error
var auth *s3.Auth var auth *s3.Auth
var s3c *s3.Client
auth, err = getAWSEnvironment() auth, err = getAWSEnvironment()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
s3c := s3.NewS3Client(auth) s3c, err = getNewClient(auth)
err = s3c.PutBucket(bucketName) err = s3c.PutBucket(bucketName)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)

View File

@@ -20,35 +20,35 @@ import (
"github.com/codegangsta/cli" "github.com/codegangsta/cli"
) )
var Cp = cli.Command{ var cp = cli.Command{
Name: "cp", Name: "cp",
Usage: "", Usage: "",
Description: `Copies a local file or Object to another location locally or in S3.`, Description: `Copies a local file or Object to another location locally or in S3.`,
Action: doFsCopy, Action: doFsCopy,
} }
var Ls = cli.Command{ var ls = cli.Command{
Name: "ls", Name: "ls",
Usage: "", Usage: "",
Description: `List Objects and common prefixes under a prefix or all Buckets`, Description: `List Objects and common prefixes under a prefix or all Buckets`,
Action: doFsList, Action: doFsList,
} }
var Mb = cli.Command{ var mb = cli.Command{
Name: "mb", Name: "mb",
Usage: "", Usage: "",
Description: "Creates an S3 bucket", Description: "Creates an S3 bucket",
Action: doFsMb, Action: doFsMb,
} }
var Sync = cli.Command{ var sync = cli.Command{
Name: "sync", Name: "sync",
Usage: "", Usage: "",
Description: "Syncs directories and S3 prefixes", Description: "Syncs directories and S3 prefixes",
Action: doFsSync, Action: doFsSync,
} }
var Configure = cli.Command{ var configure = cli.Command{
Name: "configure", Name: "configure",
Usage: "", Usage: "",
Description: `Configure minio client configuration data. If your config Description: `Configure minio client configuration data. If your config
@@ -88,14 +88,15 @@ type fsOptions struct {
isput bool isput bool
} }
const (
Auth = ".auth"
)
var options = []cli.Command{ var options = []cli.Command{
Cp, cp,
Ls, ls,
Mb, mb,
Sync, sync,
Configure, configure,
} }
// Common authentication file
const (
Auth = ".minio/auth.json"
)

View File

@@ -17,6 +17,7 @@
package main package main
import ( import (
"fmt"
"log" "log"
"os" "os"
"path" "path"
@@ -27,18 +28,6 @@ import (
"github.com/minio-io/mc/pkg/s3" "github.com/minio-io/mc/pkg/s3"
) )
var s3c *s3.Client
func init() {
var auth *s3.Auth
var err error
auth, err = getAWSEnvironment()
if err != nil {
log.Fatal(err)
}
s3c = s3.NewS3Client(auth)
}
func isValidBucketName(p string) { func isValidBucketName(p string) {
if path.IsAbs(p) { if path.IsAbs(p) {
log.Fatal("directory bucketname cannot be absolute") log.Fatal("directory bucketname cannot be absolute")
@@ -47,11 +36,15 @@ func isValidBucketName(p string) {
log.Fatal("Relative directory references not supported") log.Fatal("Relative directory references not supported")
} }
if !s3.IsValidBucket(p) { if !s3.IsValidBucket(p) {
log.Fatal(invalidBucketErr) log.Fatal(errInvalidbucket)
} }
} }
func putWalk(p string, info os.FileInfo, err error) error { type walk struct {
s3 *s3.Client
}
func (w *walk) putWalk(p string, info os.FileInfo, err error) error {
if info.IsDir() { if info.IsDir() {
return nil return nil
} }
@@ -64,15 +57,28 @@ func putWalk(p string, info os.FileInfo, err error) error {
bodyFile, err := os.Open(p) bodyFile, err := os.Open(p)
defer bodyFile.Close() defer bodyFile.Close()
err = s3c.Put(bucketname, key, nil, info.Size(), bodyFile) err = w.s3.Put(bucketname, key, nil, info.Size(), bodyFile)
if err != nil { if err != nil {
return err return err
} }
log.Printf("%s uploaded -- to bucket:%s", key, bucketname) fmt.Printf("%s uploaded -- to bucket:%s\n", key, bucketname)
return nil return nil
} }
func doFsSync(c *cli.Context) { func doFsSync(c *cli.Context) {
var auth *s3.Auth
var s3c *s3.Client
var err error
auth, err = getAWSEnvironment()
if err != nil {
log.Fatal(err)
}
s3c, err = getNewClient(auth)
if err != nil {
log.Fatal(err)
}
p := &walk{s3c}
switch len(c.Args()) { switch len(c.Args()) {
case 1: case 1:
input := path.Clean(c.Args().Get(0)) input := path.Clean(c.Args().Get(0))
@@ -90,7 +96,7 @@ func doFsSync(c *cli.Context) {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
err = filepath.Walk(input, putWalk) err = filepath.Walk(input, p.putWalk)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }