From bb7eb0faacb77436a492d4b9b9775f2771a546d7 Mon Sep 17 00:00:00 2001 From: Stefan Majewsky Date: Wed, 30 May 2018 11:38:52 +0200 Subject: adjust semantics of Object.InspectSymlink, rename to Object.SymlinkHeaders The additional guarantee that Object.SymlinkHeaders becomes equivalent to Object.Headers for non-symlinks will be useful e.g. for swift-http-import's usecase. --- errors.go | 3 --- object.go | 30 +++++++++++++++++++++--------- tests/object_test.go | 14 +++++++------- 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/errors.go b/errors.go index 598419a..825e96a 100644 --- a/errors.go +++ b/errors.go @@ -54,9 +54,6 @@ var ( //provided is malformed or uses features not supported by the LargeObject's //strategy. See documentation for LargeObject.AddSegment() for details. ErrSegmentInvalid = errors.New("segment invalid or incompatible with large object strategy") - //ErrNotASymlink is returned by Object.SymlinkTarget() if the object in - //question exists, but is not a symlink. - ErrNotASymlink = errors.New("not a symlink") ) //UnexpectedStatusCodeError is generated when a request to Swift does not yield diff --git a/object.go b/object.go index affa9c3..776dd21 100644 --- a/object.go +++ b/object.go @@ -93,7 +93,7 @@ func (o *Object) Exists() (bool, error) { //has not been cached yet, a HEAD request is issued on the object. // //For symlinks, this operation returns the metadata for the target object. Use -//Object.InspectSymlink() to obtain the metadata for the symlink instead. +//Object.SymlinkHeaders() to obtain the metadata for the symlink instead. // //This operation fails with http.StatusNotFound if the object does not exist. func (o *Object) Headers() (ObjectHeaders, error) { @@ -526,29 +526,41 @@ func (o *Object) SymlinkTo(target *Object, opts *SymlinkOptions, ropts *RequestO return o.Upload(nil, uopts, ropts) } -//InspectSymlink returns the object that this symlink points to, and the -//metadata of the symlink. ErrNotASymlink is returned if the object is not a -//symlink. +//SymlinkHeaders is similar to Headers, but if the object is a symlink, it +//returns the metadata of the symlink rather than the metadata of the target. +//It also returns a reference to the target object. +// +//If this object is not a symlink, Object.SymlinkHeaders() returns the same +//ObjectHeaders as Object.Headers(), and a nil target object. +// +//In a nutshell, if Object.Headers() is like os.Stat(), then +//Object.SymlinkHeaders() is like os.Lstat(). +// +//If you do not know whether a given object is a symlink or not, it's a good +//idea to call Object.SymlinkHeaders() first: If the object turns out not to be +//a symlink, the cache for Object.Headers() has already been populated. // //This operation fails with http.StatusNotFound if the object does not exist. -func (o *Object) InspectSymlink() (target *Object, headers ObjectHeaders, err error) { +func (o *Object) SymlinkHeaders() (headers ObjectHeaders, target *Object, err error) { if o.symlinkHeaders == nil { o.symlinkHeaders, err = o.fetchHeaders(&RequestOptions{ Values: url.Values{"symlink": []string{"get"}}, }) if err != nil { - return nil, ObjectHeaders{}, err + return ObjectHeaders{}, nil, err } } //is this a symlink? targetFullName := o.symlinkHeaders.Get("X-Symlink-Target") if targetFullName == "" { - return nil, ObjectHeaders{}, ErrNotASymlink + //not a symlink - the o.symlinkHeaders are just the regular headers + o.headers = o.symlinkHeaders + return *o.headers, nil, nil } fields := strings.SplitN(targetFullName, "/", 2) if len(fields) < 2 { - return nil, ObjectHeaders{}, MalformedHeaderError{ + return ObjectHeaders{}, nil, MalformedHeaderError{ Key: "X-Symlink-Target", ParseError: fmt.Errorf("expected \"container/object\", got \"%s\"", targetFullName), } @@ -561,5 +573,5 @@ func (o *Object) InspectSymlink() (target *Object, headers ObjectHeaders, err er targetAccount = targetAccount.SwitchAccount(accountName) } target = targetAccount.Container(fields[0]).Object(fields[1]) - return target, *o.symlinkHeaders, nil + return *o.symlinkHeaders, target, nil } diff --git a/tests/object_test.go b/tests/object_test.go index 618c835..15aa8f2 100644 --- a/tests/object_test.go +++ b/tests/object_test.go @@ -277,21 +277,21 @@ func expectObjectContent(t *testing.T, obj *schwift.Object, expected []byte) { func expectObjectSymlink(t *testing.T, source, expectedTarget *schwift.Object) { t.Helper() - target, _, err := source.InspectSymlink() + _, target, err := source.SymlinkHeaders() if expectedTarget == nil { switch err { - case schwift.ErrNotASymlink: - return //success case nil: - t.Errorf("expected %s to not be a symlink, but found symlink to %s\n", - source.FullName(), target.FullName()) + if target != nil { + t.Errorf("expected %s to not be a symlink, but found symlink to %s\n", + source.FullName(), target.FullName()) + } default: - t.Errorf("got unexpected error from Object.SymlinkTarget() for %s: %s\n", + t.Errorf("got unexpected error from Object.SymlinkHeaders() for %s: %s\n", source.FullName(), err.Error()) } } else { if err != nil { - t.Errorf("expected %s to be a symlink to %s, but Object.SymlinkTarget() returned error: %s\n", + t.Errorf("expected %s to be a symlink to %s, but Object.SymlinkHeaders() returned error: %s\n", source.FullName(), expectedTarget.FullName(), err.Error()) } else if target.FullName() != expectedTarget.FullName() { t.Errorf("expected %s to be a symlink to %s, but got target %s\n", -- cgit v1.2.3