Skip to content
This repository was archived by the owner on Apr 12, 2019. It is now read-only.

Added FollowLink() method to TreeEntry #114

Merged
merged 3 commits into from
Apr 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions error.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ func (err ErrNotExist) Error() string {
return fmt.Sprintf("object does not exist [id: %s, rel_path: %s]", err.ID, err.RelPath)
}

// ErrBadLink entry.FollowLink error
type ErrBadLink struct {
Name string
Message string
}

func (err ErrBadLink) Error() string {
return fmt.Sprintf("%s: %s", err.Name, err.Message)
}

// ErrUnsupportedVersion error when required git version not matched
type ErrUnsupportedVersion struct {
Required string
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x��1n�0 E3�� �-�&����H&F+�ա�o�#d����/��X: ��zS�i��Z�b1�ؔSa��g�@�F�35];̈�'Ɇ%s�D��5������R,��w��_m�೶�k�C�����v�"?��}m�#�8"�#|xDt����f��ET �z���z��/��N�
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion tests/repos/repo1_bare/refs/heads/master
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2
6fbd69e9823458e6c4a2fc5c0f6bc022b2f2acd1
40 changes: 40 additions & 0 deletions tree_entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package git

import (
"io"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -90,6 +91,45 @@ func (te *TreeEntry) Blob() *Blob {
}
}

// FollowLink returns the entry pointed to by a symlink
func (te *TreeEntry) FollowLink() (*TreeEntry, error) {
if !te.IsLink() {
return nil, ErrBadLink{te.Name(), "not a symlink"}
}

// read the link
r, err := te.Blob().Data()
if err != nil {
return nil, err
}
buf := make([]byte, te.Size())
_, err = io.ReadFull(r, buf)
if err != nil {
return nil, err
}

lnk := string(buf)
t := te.ptree

// traverse up directories
for ; t != nil && lnk[:3] == "../"; lnk = lnk[3:] {
t = t.ptree
}

if t == nil {
return nil, ErrBadLink{te.Name(), "points outside of repo"}
}

target, err := t.GetTreeEntryByPath(lnk)
if err != nil {
if IsErrNotExist(err) {
return nil, ErrBadLink{te.Name(), "broken link"}
}
return nil, err
}
return target, nil
}

// GetSubJumpablePathName return the full path of subdirectory jumpable ( contains only one directory )
func (te *TreeEntry) GetSubJumpablePathName() string {
if te.IsSubModule() || !te.IsDir() {
Expand Down
40 changes: 40 additions & 0 deletions tree_entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,43 @@ func TestEntriesCustomSort(t *testing.T) {
assert.Equal(t, "bcd", entries[6].Name())
assert.Equal(t, "abc", entries[7].Name())
}

func TestFollowLink(t *testing.T) {
r, err := OpenRepository("tests/repos/repo1_bare")
assert.NoError(t, err)

commit, err := r.GetCommit("6fbd69e9823458e6c4a2fc5c0f6bc022b2f2acd1")
assert.NoError(t, err)

// get the symlink
lnk, err := commit.Tree.GetTreeEntryByPath("foo/bar/link_to_hello")
assert.NoError(t, err)
assert.True(t, lnk.IsLink())

// should be able to dereference to target
target, err := lnk.FollowLink()
assert.NoError(t, err)
assert.Equal(t, target.Name(), "hello")
assert.False(t, target.IsLink())
assert.Equal(t, target.ID.String(), "b14df6442ea5a1b382985a6549b85d435376c351")

// should error when called on normal file
target, err = commit.Tree.GetTreeEntryByPath("file1.txt")
assert.NoError(t, err)
_, err = target.FollowLink()
assert.Equal(t, err.Error(), "file1.txt: not a symlink")

// should error for broken links
target, err = commit.Tree.GetTreeEntryByPath("foo/broken_link")
assert.NoError(t, err)
assert.True(t, target.IsLink())
_, err = target.FollowLink()
assert.Equal(t, err.Error(), "broken_link: broken link")

// should error for external links
target, err = commit.Tree.GetTreeEntryByPath("foo/outside_repo")
assert.NoError(t, err)
assert.True(t, target.IsLink())
_, err = target.FollowLink()
assert.Equal(t, err.Error(), "outside_repo: points outside of repo")
}