diff --git a/lfs/client.go b/lfs/client.go index 39594e51..1e1f440a 100644 --- a/lfs/client.go +++ b/lfs/client.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/base64" "encoding/json" - "errors" "fmt" "io" "io/ioutil" @@ -17,6 +16,7 @@ import ( "strconv" "strings" + "github.com/github/git-lfs/api" "github.com/github/git-lfs/config" "github.com/github/git-lfs/git" "github.com/github/git-lfs/httputil" @@ -44,59 +44,6 @@ var ( } ) -type ObjectError struct { - Code int `json:"code"` - Message string `json:"message"` -} - -func (e *ObjectError) Error() string { - return fmt.Sprintf("[%d] %s", e.Code, e.Message) -} - -type ObjectResource struct { - Oid string `json:"oid,omitempty"` - Size int64 `json:"size"` - Actions map[string]*linkRelation `json:"actions,omitempty"` - Links map[string]*linkRelation `json:"_links,omitempty"` - Error *ObjectError `json:"error,omitempty"` -} - -func (o *ObjectResource) NewRequest(relation, method string) (*http.Request, error) { - rel, ok := o.Rel(relation) - if !ok { - if relation == "download" { - return nil, errors.New("Object not found on the server.") - } - return nil, fmt.Errorf("No %q action for this object.", relation) - - } - - req, err := newClientRequest(method, rel.Href, rel.Header) - if err != nil { - return nil, err - } - - return req, nil -} - -func (o *ObjectResource) Rel(name string) (*linkRelation, bool) { - var rel *linkRelation - var ok bool - - if o.Actions != nil { - rel, ok = o.Actions[name] - } else { - rel, ok = o.Links[name] - } - - return rel, ok -} - -type linkRelation struct { - Href string `json:"href"` - Header map[string]string `json:"header,omitempty"` -} - type ClientError struct { Message string `json:"message"` DocumentationUrl string `json:"documentation_url,omitempty"` @@ -122,8 +69,8 @@ func Download(oid string, size int64) (io.ReadCloser, int64, error) { return DownloadLegacy(oid) } - objects := []*ObjectResource{ - &ObjectResource{Oid: oid, Size: size}, + objects := []*api.ObjectResource{ + &api.ObjectResource{Oid: oid, Size: size}, } objs, err := Batch(objects, "download") @@ -173,7 +120,7 @@ type byteCloser struct { *bytes.Reader } -func DownloadCheck(oid string) (*ObjectResource, error) { +func DownloadCheck(oid string) (*api.ObjectResource, error) { req, err := newApiRequest("GET", oid) if err != nil { return nil, Error(err) @@ -193,7 +140,7 @@ func DownloadCheck(oid string) (*ObjectResource, error) { return obj, nil } -func DownloadObject(obj *ObjectResource) (io.ReadCloser, int64, error) { +func DownloadObject(obj *api.ObjectResource) (io.ReadCloser, int64, error) { req, err := obj.NewRequest("download", "GET") if err != nil { return nil, 0, Error(err) @@ -212,7 +159,7 @@ func (b *byteCloser) Close() error { return nil } -func Batch(objects []*ObjectResource, operation string) ([]*ObjectResource, error) { +func Batch(objects []*api.ObjectResource, operation string) ([]*api.ObjectResource, error) { if len(objects) == 0 { return nil, nil } @@ -271,7 +218,7 @@ func Batch(objects []*ObjectResource, operation string) ([]*ObjectResource, erro return objs, nil } -func UploadCheck(oidPath string) (*ObjectResource, error) { +func UploadCheck(oidPath string) (*api.ObjectResource, error) { oid := filepath.Base(oidPath) stat, err := os.Stat(oidPath) @@ -279,7 +226,7 @@ func UploadCheck(oidPath string) (*ObjectResource, error) { return nil, Error(err) } - reqObj := &ObjectResource{ + reqObj := &api.ObjectResource{ Oid: oid, Size: stat.Size(), } @@ -326,7 +273,7 @@ func UploadCheck(oidPath string) (*ObjectResource, error) { return obj, nil } -func UploadObject(o *ObjectResource, cb progress.CopyCallback) error { +func UploadObject(o *api.ObjectResource, cb progress.CopyCallback) error { path, err := LocalMediaPath(o.Oid) if err != nil { return Error(err) @@ -412,14 +359,14 @@ func UploadObject(o *ObjectResource, cb progress.CopyCallback) error { } // doLegacyApiRequest runs the request to the LFS legacy API. -func doLegacyApiRequest(req *http.Request) (*http.Response, *ObjectResource, error) { +func doLegacyApiRequest(req *http.Request) (*http.Response, *api.ObjectResource, error) { via := make([]*http.Request, 0, 4) res, err := doApiRequestWithRedirects(req, via, true) if err != nil { return res, nil, err } - obj := &ObjectResource{} + obj := &api.ObjectResource{} err = decodeApiResponse(res, obj) if err != nil { @@ -443,7 +390,7 @@ func getOperationForHttpRequest(req *http.Request) string { // 401, the repo will be marked as having private access and the request will be // re-run. When the repo is marked as having private access, credentials will // be retrieved. -func doApiBatchRequest(req *http.Request) (*http.Response, []*ObjectResource, error) { +func doApiBatchRequest(req *http.Request) (*http.Response, []*api.ObjectResource, error) { res, err := doAPIRequest(req, config.Config.PrivateAccess(getOperationForHttpRequest(req))) if err != nil { @@ -453,7 +400,7 @@ func doApiBatchRequest(req *http.Request) (*http.Response, []*ObjectResource, er return res, nil, err } - var objs map[string][]*ObjectResource + var objs map[string][]*api.ObjectResource err = decodeApiResponse(res, &objs) if err != nil { diff --git a/lfs/download_queue.go b/lfs/download_queue.go index f07485e7..ba491d9a 100644 --- a/lfs/download_queue.go +++ b/lfs/download_queue.go @@ -1,18 +1,21 @@ package lfs -import "github.com/github/git-lfs/progress" +import ( + "github.com/github/git-lfs/api" + "github.com/github/git-lfs/progress" +) // The ability to check that a file can be downloaded type DownloadCheckable struct { Pointer *WrappedPointer - object *ObjectResource + object *api.ObjectResource } func NewDownloadCheckable(p *WrappedPointer) *DownloadCheckable { return &DownloadCheckable{Pointer: p} } -func (d *DownloadCheckable) Check() (*ObjectResource, error) { +func (d *DownloadCheckable) Check() (*api.ObjectResource, error) { return DownloadCheck(d.Pointer.Oid) } @@ -22,7 +25,7 @@ func (d *DownloadCheckable) Transfer(cb progress.CopyCallback) error { return nil } -func (d *DownloadCheckable) Object() *ObjectResource { +func (d *DownloadCheckable) Object() *api.ObjectResource { return d.object } @@ -38,7 +41,7 @@ func (d *DownloadCheckable) Name() string { return d.Pointer.Name } -func (d *DownloadCheckable) SetObject(o *ObjectResource) { +func (d *DownloadCheckable) SetObject(o *api.ObjectResource) { d.object = o } diff --git a/lfs/download_test.go b/lfs/download_test.go index 64ff393a..acddec97 100644 --- a/lfs/download_test.go +++ b/lfs/download_test.go @@ -11,6 +11,7 @@ import ( "strings" "testing" + "github.com/github/git-lfs/api" "github.com/github/git-lfs/config" ) @@ -39,11 +40,11 @@ func TestSuccessfulDownload(t *testing.T) { t.Error("Invalid Authorization") } - obj := &ObjectResource{ + obj := &api.ObjectResource{ Oid: "oid", Size: 4, - Actions: map[string]*linkRelation{ - "download": &linkRelation{ + Actions: map[string]*api.LinkRelation{ + "download": &api.LinkRelation{ Href: server.URL + "/download", Header: map[string]string{"A": "1"}, }, @@ -173,11 +174,11 @@ func TestSuccessfulDownloadWithRedirects(t *testing.T) { t.Error("Invalid Authorization") } - obj := &ObjectResource{ + obj := &api.ObjectResource{ Oid: "oid", Size: 4, - Actions: map[string]*linkRelation{ - "download": &linkRelation{ + Actions: map[string]*api.LinkRelation{ + "download": &api.LinkRelation{ Href: server.URL + "/download", Header: map[string]string{"A": "1"}, }, @@ -276,11 +277,11 @@ func TestSuccessfulDownloadWithAuthorization(t *testing.T) { t.Error("Invalid Authorization") } - obj := &ObjectResource{ + obj := &api.ObjectResource{ Oid: "oid", Size: 4, - Actions: map[string]*linkRelation{ - "download": &linkRelation{ + Actions: map[string]*api.LinkRelation{ + "download": &api.LinkRelation{ Href: server.URL + "/download", Header: map[string]string{ "A": "1", @@ -387,11 +388,11 @@ func TestSuccessfulDownloadFromSeparateHost(t *testing.T) { t.Error("Invalid Authorization") } - obj := &ObjectResource{ + obj := &api.ObjectResource{ Oid: "oid", Size: 4, - Actions: map[string]*linkRelation{ - "download": &linkRelation{ + Actions: map[string]*api.LinkRelation{ + "download": &api.LinkRelation{ Href: server2.URL + "/download", Header: map[string]string{"A": "1"}, }, @@ -522,11 +523,11 @@ func TestSuccessfulDownloadFromSeparateRedirectedHost(t *testing.T) { t.Error("Invalid Authorization") } - obj := &ObjectResource{ + obj := &api.ObjectResource{ Oid: "oid", Size: 4, - Actions: map[string]*linkRelation{ - "download": &linkRelation{ + Actions: map[string]*api.LinkRelation{ + "download": &api.LinkRelation{ Href: server3.URL + "/download", Header: map[string]string{"A": "1"}, }, @@ -656,11 +657,11 @@ func TestDownloadStorageError(t *testing.T) { t.Error("Invalid Authorization") } - obj := &ObjectResource{ + obj := &api.ObjectResource{ Oid: "oid", Size: 4, - Actions: map[string]*linkRelation{ - "download": &linkRelation{ + Actions: map[string]*api.LinkRelation{ + "download": &api.LinkRelation{ Href: server.URL + "/download", Header: map[string]string{"A": "1"}, }, diff --git a/lfs/pointer_smudge.go b/lfs/pointer_smudge.go index db2f7f93..029001af 100644 --- a/lfs/pointer_smudge.go +++ b/lfs/pointer_smudge.go @@ -10,6 +10,7 @@ import ( "os" "path/filepath" + "github.com/github/git-lfs/api" "github.com/github/git-lfs/config" "github.com/github/git-lfs/progress" "github.com/github/git-lfs/vendor/_nuts/github.com/cheggaaa/pb" @@ -74,7 +75,7 @@ func PointerSmudge(writer io.Writer, ptr *Pointer, workingfile string, download // PointerSmudgeObject uses a Pointer and ObjectResource to download the object to the // media directory. It does not write the file to the working directory. -func PointerSmudgeObject(ptr *Pointer, obj *ObjectResource, cb progress.CopyCallback) error { +func PointerSmudgeObject(ptr *Pointer, obj *api.ObjectResource, cb progress.CopyCallback) error { mediafile, err := LocalMediaPath(obj.Oid) if err != nil { return err @@ -101,7 +102,7 @@ func PointerSmudgeObject(ptr *Pointer, obj *ObjectResource, cb progress.CopyCall return nil } -func downloadObject(ptr *Pointer, obj *ObjectResource, mediafile string, cb progress.CopyCallback) error { +func downloadObject(ptr *Pointer, obj *api.ObjectResource, mediafile string, cb progress.CopyCallback) error { reader, size, err := DownloadObject(obj) if reader != nil { defer reader.Close() diff --git a/lfs/transfer_queue.go b/lfs/transfer_queue.go index 88cb7b4b..c32639cb 100644 --- a/lfs/transfer_queue.go +++ b/lfs/transfer_queue.go @@ -4,6 +4,7 @@ import ( "sync" "sync/atomic" + "github.com/github/git-lfs/api" "github.com/github/git-lfs/config" "github.com/github/git-lfs/git" "github.com/github/git-lfs/progress" @@ -15,13 +16,13 @@ const ( ) type Transferable interface { - Check() (*ObjectResource, error) + Check() (*api.ObjectResource, error) Transfer(progress.CopyCallback) error - Object() *ObjectResource + Object() *api.ObjectResource Oid() string Size() int64 Name() string - SetObject(*ObjectResource) + SetObject(*api.ObjectResource) } // TransferQueue provides a queue that will allow concurrent transfers. @@ -207,9 +208,9 @@ func (q *TransferQueue) batchApiRoutine() { tracerx.Printf("tq: sending batch of size %d", len(batch)) - transfers := make([]*ObjectResource, 0, len(batch)) + transfers := make([]*api.ObjectResource, 0, len(batch)) for _, t := range batch { - transfers = append(transfers, &ObjectResource{Oid: t.Oid(), Size: t.Size()}) + transfers = append(transfers, &api.ObjectResource{Oid: t.Oid(), Size: t.Size()}) } objects, err := Batch(transfers, q.transferKind) diff --git a/lfs/upload_queue.go b/lfs/upload_queue.go index 1f726a14..84536b66 100644 --- a/lfs/upload_queue.go +++ b/lfs/upload_queue.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" + "github.com/github/git-lfs/api" "github.com/github/git-lfs/config" "github.com/github/git-lfs/progress" ) @@ -15,7 +16,7 @@ type Uploadable struct { OidPath string Filename string size int64 - object *ObjectResource + object *api.ObjectResource } // NewUploadable builds the Uploadable from the given information. @@ -40,7 +41,7 @@ func NewUploadable(oid, filename string) (*Uploadable, error) { return &Uploadable{oid: oid, OidPath: localMediaPath, Filename: filename, size: fi.Size()}, nil } -func (u *Uploadable) Check() (*ObjectResource, error) { +func (u *Uploadable) Check() (*api.ObjectResource, error) { return UploadCheck(u.OidPath) } @@ -53,7 +54,7 @@ func (u *Uploadable) Transfer(cb progress.CopyCallback) error { return UploadObject(u.object, wcb) } -func (u *Uploadable) Object() *ObjectResource { +func (u *Uploadable) Object() *api.ObjectResource { return u.object } @@ -69,7 +70,7 @@ func (u *Uploadable) Name() string { return u.Filename } -func (u *Uploadable) SetObject(o *ObjectResource) { +func (u *Uploadable) SetObject(o *api.ObjectResource) { u.object = o } diff --git a/lfs/upload_test.go b/lfs/upload_test.go index 05df4e3f..7e2e0319 100644 --- a/lfs/upload_test.go +++ b/lfs/upload_test.go @@ -12,6 +12,7 @@ import ( "strconv" "testing" + "github.com/github/git-lfs/api" "github.com/github/git-lfs/config" ) @@ -49,7 +50,7 @@ func TestExistingUpload(t *testing.T) { buf := &bytes.Buffer{} tee := io.TeeReader(r.Body, buf) - reqObj := &ObjectResource{} + reqObj := &api.ObjectResource{} err := json.NewDecoder(tee).Decode(reqObj) t.Logf("request header: %v", r.Header) t.Logf("request body: %s", buf.String()) @@ -65,15 +66,15 @@ func TestExistingUpload(t *testing.T) { t.Errorf("invalid size from request: %d", reqObj.Size) } - obj := &ObjectResource{ + obj := &api.ObjectResource{ Oid: reqObj.Oid, Size: reqObj.Size, - Actions: map[string]*linkRelation{ - "upload": &linkRelation{ + Actions: map[string]*api.LinkRelation{ + "upload": &api.LinkRelation{ Href: server.URL + "/upload", Header: map[string]string{"A": "1"}, }, - "verify": &linkRelation{ + "verify": &api.LinkRelation{ Href: server.URL + "/verify", Header: map[string]string{"B": "2"}, }, @@ -191,7 +192,7 @@ func TestUploadWithRedirect(t *testing.T) { buf := &bytes.Buffer{} tee := io.TeeReader(r.Body, buf) - reqObj := &ObjectResource{} + reqObj := &api.ObjectResource{} err := json.NewDecoder(tee).Decode(reqObj) t.Logf("request header: %v", r.Header) t.Logf("request body: %s", buf.String()) @@ -207,13 +208,13 @@ func TestUploadWithRedirect(t *testing.T) { t.Errorf("invalid size from request: %d", reqObj.Size) } - obj := &ObjectResource{ - Actions: map[string]*linkRelation{ - "upload": &linkRelation{ + obj := &api.ObjectResource{ + Actions: map[string]*api.LinkRelation{ + "upload": &api.LinkRelation{ Href: server.URL + "/upload", Header: map[string]string{"A": "1"}, }, - "verify": &linkRelation{ + "verify": &api.LinkRelation{ Href: server.URL + "/verify", Header: map[string]string{"B": "2"}, }, @@ -287,7 +288,7 @@ func TestSuccessfulUploadWithVerify(t *testing.T) { buf := &bytes.Buffer{} tee := io.TeeReader(r.Body, buf) - reqObj := &ObjectResource{} + reqObj := &api.ObjectResource{} err := json.NewDecoder(tee).Decode(reqObj) t.Logf("request header: %v", r.Header) t.Logf("request body: %s", buf.String()) @@ -303,15 +304,15 @@ func TestSuccessfulUploadWithVerify(t *testing.T) { t.Errorf("invalid size from request: %d", reqObj.Size) } - obj := &ObjectResource{ + obj := &api.ObjectResource{ Oid: reqObj.Oid, Size: reqObj.Size, - Actions: map[string]*linkRelation{ - "upload": &linkRelation{ + Actions: map[string]*api.LinkRelation{ + "upload": &api.LinkRelation{ Href: server.URL + "/upload", Header: map[string]string{"A": "1"}, }, - "verify": &linkRelation{ + "verify": &api.LinkRelation{ Href: server.URL + "/verify", Header: map[string]string{"B": "2"}, }, @@ -389,7 +390,7 @@ func TestSuccessfulUploadWithVerify(t *testing.T) { buf := &bytes.Buffer{} tee := io.TeeReader(r.Body, buf) - reqObj := &ObjectResource{} + reqObj := &api.ObjectResource{} err := json.NewDecoder(tee).Decode(reqObj) t.Logf("request header: %v", r.Header) t.Logf("request body: %s", buf.String()) @@ -493,7 +494,7 @@ func TestSuccessfulUploadWithoutVerify(t *testing.T) { buf := &bytes.Buffer{} tee := io.TeeReader(r.Body, buf) - reqObj := &ObjectResource{} + reqObj := &api.ObjectResource{} err := json.NewDecoder(tee).Decode(reqObj) t.Logf("request header: %v", r.Header) t.Logf("request body: %s", buf.String()) @@ -509,11 +510,11 @@ func TestSuccessfulUploadWithoutVerify(t *testing.T) { t.Errorf("invalid size from request: %d", reqObj.Size) } - obj := &ObjectResource{ + obj := &api.ObjectResource{ Oid: reqObj.Oid, Size: reqObj.Size, - Actions: map[string]*linkRelation{ - "upload": &linkRelation{ + Actions: map[string]*api.LinkRelation{ + "upload": &api.LinkRelation{ Href: server.URL + "/upload", Header: map[string]string{"A": "1"}, }, @@ -684,7 +685,7 @@ func TestUploadStorageError(t *testing.T) { buf := &bytes.Buffer{} tee := io.TeeReader(r.Body, buf) - reqObj := &ObjectResource{} + reqObj := &api.ObjectResource{} err := json.NewDecoder(tee).Decode(reqObj) t.Logf("request header: %v", r.Header) t.Logf("request body: %s", buf.String()) @@ -700,15 +701,15 @@ func TestUploadStorageError(t *testing.T) { t.Errorf("invalid size from request: %d", reqObj.Size) } - obj := &ObjectResource{ + obj := &api.ObjectResource{ Oid: reqObj.Oid, Size: reqObj.Size, - Actions: map[string]*linkRelation{ - "upload": &linkRelation{ + Actions: map[string]*api.LinkRelation{ + "upload": &api.LinkRelation{ Href: server.URL + "/upload", Header: map[string]string{"A": "1"}, }, - "verify": &linkRelation{ + "verify": &api.LinkRelation{ Href: server.URL + "/verify", Header: map[string]string{"B": "2"}, }, @@ -804,7 +805,7 @@ func TestUploadVerifyError(t *testing.T) { buf := &bytes.Buffer{} tee := io.TeeReader(r.Body, buf) - reqObj := &ObjectResource{} + reqObj := &api.ObjectResource{} err := json.NewDecoder(tee).Decode(reqObj) t.Logf("request header: %v", r.Header) t.Logf("request body: %s", buf.String()) @@ -820,15 +821,15 @@ func TestUploadVerifyError(t *testing.T) { t.Errorf("invalid size from request: %d", reqObj.Size) } - obj := &ObjectResource{ + obj := &api.ObjectResource{ Oid: reqObj.Oid, Size: reqObj.Size, - Actions: map[string]*linkRelation{ - "upload": &linkRelation{ + Actions: map[string]*api.LinkRelation{ + "upload": &api.LinkRelation{ Href: server.URL + "/upload", Header: map[string]string{"A": "1"}, }, - "verify": &linkRelation{ + "verify": &api.LinkRelation{ Href: server.URL + "/verify", Header: map[string]string{"B": "2"}, }, diff --git a/test/git-lfs-test-server-api/main.go b/test/git-lfs-test-server-api/main.go index 6a8ab197..ac99c784 100644 --- a/test/git-lfs-test-server-api/main.go +++ b/test/git-lfs-test-server-api/main.go @@ -10,6 +10,7 @@ import ( "strconv" "strings" + "github.com/github/git-lfs/api" "github.com/github/git-lfs/config" "github.com/github/git-lfs/lfs" "github.com/github/git-lfs/test" @@ -242,11 +243,11 @@ func addTest(name string, f func(oidsExist, oidsMissing []TestObject) error) { tests = append(tests, ServerTest{Name: name, F: f}) } -func callBatchApi(op string, objs []TestObject) ([]*lfs.ObjectResource, error) { +func callBatchApi(op string, objs []TestObject) ([]*api.ObjectResource, error) { - apiobjs := make([]*lfs.ObjectResource, 0, len(objs)) + apiobjs := make([]*api.ObjectResource, 0, len(objs)) for _, o := range objs { - apiobjs = append(apiobjs, &lfs.ObjectResource{Oid: o.Oid, Size: o.Size}) + apiobjs = append(apiobjs, &api.ObjectResource{Oid: o.Oid, Size: o.Size}) } return lfs.Batch(apiobjs, op) }