Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/refactor path resolve #190

Closed
Closed
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
2 changes: 2 additions & 0 deletions pkg/filesystem/path/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ go_library(
"component_walker.go",
"components_list.go",
"loop_detecting_scope_walker.go",
"parser.go",
"relative_scope_walker.go",
"resolve.go",
"scope_walker.go",
"trace.go",
"unix_parser.go",
"virtual_root_scope_walker_factory.go",
"void_component_walker.go",
"void_scope_walker.go",
Expand Down
9 changes: 5 additions & 4 deletions pkg/filesystem/path/absolute_scope_walker.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ func NewAbsoluteScopeWalker(componentWalker ComponentWalker) ScopeWalker {
}
}

func (pw *absoluteScopeWalker) OnScope(absolute bool) (ComponentWalker, error) {
if !absolute {
return nil, status.Error(codes.InvalidArgument, "Path is relative, while an absolute path was expected")
}
func (pw *absoluteScopeWalker) OnRelative() (ComponentWalker, error) {
return nil, status.Error(codes.InvalidArgument, "Path is relative, while an absolute path was expected")
}

func (pw *absoluteScopeWalker) OnAbsolute() (ComponentWalker, error) {
return pw.componentWalker, nil
}
4 changes: 2 additions & 2 deletions pkg/filesystem/path/absolute_scope_walker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestAbsoluteScopeWalker(t *testing.T) {
componentWalker := mock.NewMockComponentWalker(ctrl)
componentWalker.EXPECT().OnTerminal(path.MustNewComponent("hello"))

require.NoError(t, path.Resolve("/hello", path.NewAbsoluteScopeWalker(componentWalker)))
require.NoError(t, path.Resolve(path.MustNewUNIXParser("/hello"), path.NewAbsoluteScopeWalker(componentWalker)))
})

t.Run("Relative", func(t *testing.T) {
Expand All @@ -28,6 +28,6 @@ func TestAbsoluteScopeWalker(t *testing.T) {
require.Equal(
t,
status.Error(codes.InvalidArgument, "Path is relative, while an absolute path was expected"),
path.Resolve("hello", path.NewAbsoluteScopeWalker(componentWalker)))
path.Resolve(path.MustNewUNIXParser("hello"), path.NewAbsoluteScopeWalker(componentWalker)))
})
}
22 changes: 14 additions & 8 deletions pkg/filesystem/path/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,17 +115,23 @@ type buildingScopeWalker struct {
b *Builder
}

func (w *buildingScopeWalker) OnScope(absolute bool) (ComponentWalker, error) {
componentWalker, err := w.base.OnScope(absolute)
func (w *buildingScopeWalker) OnAbsolute() (ComponentWalker, error) {
componentWalker, err := w.base.OnAbsolute()
if err != nil {
return nil, err
}
if absolute {
*w.b = Builder{
absolute: true,
components: w.b.components[:0],
suffix: "/",
}
*w.b = Builder{
absolute: true,
components: w.b.components[:0],
suffix: "/",
}
return w.b.getComponentWalker(componentWalker), nil
}

func (w *buildingScopeWalker) OnRelative() (ComponentWalker, error) {
componentWalker, err := w.base.OnRelative()
if err != nil {
return nil, err
}
return w.b.getComponentWalker(componentWalker), nil
}
Expand Down
18 changes: 9 additions & 9 deletions pkg/filesystem/path/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestBuilder(t *testing.T) {
} {
t.Run(p, func(t *testing.T) {
builder, scopeWalker := path.EmptyBuilder.Join(path.VoidScopeWalker)
require.NoError(t, path.Resolve(p, scopeWalker))
require.NoError(t, path.Resolve(path.MustNewUNIXParser(p), scopeWalker))
require.Equal(t, p, builder.String())
})
}
Expand All @@ -57,7 +57,7 @@ func TestBuilder(t *testing.T) {
} {
t.Run(from, func(t *testing.T) {
builder, scopeWalker := path.EmptyBuilder.Join(path.VoidScopeWalker)
require.NoError(t, path.Resolve(from, scopeWalker))
require.NoError(t, path.Resolve(path.MustNewUNIXParser(from), scopeWalker))
require.Equal(t, to, builder.String())
})
}
Expand All @@ -75,7 +75,7 @@ func TestBuilder(t *testing.T) {
} {
t.Run(from, func(t *testing.T) {
builder, scopeWalker := path.RootBuilder.Join(path.VoidScopeWalker)
require.NoError(t, path.Resolve(from, scopeWalker))
require.NoError(t, path.Resolve(path.MustNewUNIXParser(from), scopeWalker))
require.Equal(t, to, builder.String())
})
}
Expand All @@ -89,15 +89,15 @@ func TestBuilder(t *testing.T) {
t.Run("Reversible1", func(t *testing.T) {
scopeWalker := mock.NewMockScopeWalker(ctrl)
componentWalker1 := mock.NewMockComponentWalker(ctrl)
scopeWalker.EXPECT().OnScope(false).Return(componentWalker1, nil)
scopeWalker.EXPECT().OnRelative().Return(componentWalker1, nil)
componentWalker2 := mock.NewMockComponentWalker(ctrl)
componentWalker1.EXPECT().OnDirectory(path.MustNewComponent("hello")).
Return(path.GotDirectory{Child: componentWalker2, IsReversible: true}, nil)
componentWalker3 := mock.NewMockComponentWalker(ctrl)
componentWalker2.EXPECT().OnUp().Return(componentWalker3, nil)

builder, s := path.EmptyBuilder.Join(scopeWalker)
require.NoError(t, path.Resolve("hello/..", s))
require.NoError(t, path.Resolve(path.MustNewUNIXParser("hello/.."), s))
require.Equal(t, ".", builder.String())
})

Expand All @@ -106,7 +106,7 @@ func TestBuilder(t *testing.T) {
t.Run("Reversible2", func(t *testing.T) {
scopeWalker := mock.NewMockScopeWalker(ctrl)
componentWalker1 := mock.NewMockComponentWalker(ctrl)
scopeWalker.EXPECT().OnScope(false).Return(componentWalker1, nil)
scopeWalker.EXPECT().OnRelative().Return(componentWalker1, nil)
componentWalker2 := mock.NewMockComponentWalker(ctrl)
componentWalker1.EXPECT().OnUp().Return(componentWalker2, nil)
componentWalker3 := mock.NewMockComponentWalker(ctrl)
Expand All @@ -116,7 +116,7 @@ func TestBuilder(t *testing.T) {
componentWalker3.EXPECT().OnUp().Return(componentWalker4, nil)

builder, s := path.EmptyBuilder.Join(scopeWalker)
require.NoError(t, path.Resolve("../hello/..", s))
require.NoError(t, path.Resolve(path.MustNewUNIXParser("../hello/.."), s))
require.Equal(t, "..", builder.String())
})

Expand All @@ -127,7 +127,7 @@ func TestBuilder(t *testing.T) {
t.Run("Reversible3", func(t *testing.T) {
scopeWalker := mock.NewMockScopeWalker(ctrl)
componentWalker1 := mock.NewMockComponentWalker(ctrl)
scopeWalker.EXPECT().OnScope(true).Return(componentWalker1, nil)
scopeWalker.EXPECT().OnAbsolute().Return(componentWalker1, nil)
componentWalker2 := mock.NewMockComponentWalker(ctrl)
componentWalker1.EXPECT().OnDirectory(path.MustNewComponent("hello")).
Return(path.GotDirectory{Child: componentWalker2, IsReversible: false}, nil)
Expand All @@ -138,7 +138,7 @@ func TestBuilder(t *testing.T) {
componentWalker3.EXPECT().OnUp().Return(componentWalker4, nil)

builder, s := path.EmptyBuilder.Join(scopeWalker)
require.NoError(t, path.Resolve("/hello/world/..", s))
require.NoError(t, path.Resolve(path.MustNewUNIXParser("/hello/world/.."), s))
require.Equal(t, "/hello/", builder.String())
})
}
19 changes: 9 additions & 10 deletions pkg/filesystem/path/component_walker.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type GotSymlink struct {
Parent ScopeWalker

// The contents of the symbolic link.
Target string
Target Parser
}

// GotDirectoryOrSymlink is a union type of GotDirectory and GotSymlink.
Expand All @@ -49,17 +49,16 @@ type ComponentWalker interface {
// OnDirectory is called for every pathname component that must
// resolve to a directory or a symbolic link to a directory.
//
// If the pathname component refers to a directory, this
// function will return a GotDirectory containing a new
// ComponentWalker against which successive pathname components
// can be resolved.
// If the pathname component refers to a directory, this function
// will return a GotDirectory containing a new ComponentWalker
// against which successive pathname components can be resolved.
//
// If the pathname component refers to a symbolic link, this
// function will return a GotSymlink containing a ScopeWalker,
// which can be used to perform expansion of the symbolic link.
// The Resolve() function will call into OnScope() to signal
// whether resolution should continue at the root directory or
// at the directory that contained the symbolic link.
// function will return a GotSymlink containing a ScopeWalker, which
// can be used to perform expansion of the symbolic link. The
// Resolve() function will call into OnAbsolute() or OnRelative() to
// signal whether resolution should continue at the root directory
// or at the directory that contained the symbolic link.
OnDirectory(name Component) (GotDirectoryOrSymlink, error)

// OnTerminal is called for the potentially last pathname
Expand Down
15 changes: 13 additions & 2 deletions pkg/filesystem/path/loop_detecting_scope_walker.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,19 @@ func NewLoopDetectingScopeWalker(base ScopeWalker) ScopeWalker {
}
}

func (w *loopDetectingScopeWalker) OnScope(isAbsolute bool) (ComponentWalker, error) {
componentWalker, err := w.base.OnScope(isAbsolute)
func (w *loopDetectingScopeWalker) OnAbsolute() (ComponentWalker, error) {
componentWalker, err := w.base.OnAbsolute()
if err != nil {
return nil, err
}
return &loopDetectingComponentWalker{
base: componentWalker,
symlinksLeft: w.symlinksLeft,
}, nil
}

func (w *loopDetectingScopeWalker) OnRelative() (ComponentWalker, error) {
componentWalker, err := w.base.OnRelative()
if err != nil {
return nil, err
}
Expand Down
14 changes: 7 additions & 7 deletions pkg/filesystem/path/loop_detecting_scope_walker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,27 @@ func TestLoopDetectingScopeWalker(t *testing.T) {
// finite number of expansions before failing.
scopeWalker := mock.NewMockScopeWalker(ctrl)
componentWalker := mock.NewMockComponentWalker(ctrl)
scopeWalker.EXPECT().OnScope(false).Return(componentWalker, nil).Times(41)
scopeWalker.EXPECT().OnRelative().Return(componentWalker, nil).Times(41)
componentWalker.EXPECT().OnTerminal(path.MustNewComponent("foo")).
Return(&path.GotSymlink{Parent: scopeWalker, Target: "foo"}, nil).
Return(&path.GotSymlink{Parent: scopeWalker, Target: path.MustNewUNIXParser("foo")}, nil).
Times(41)

require.Equal(
t,
status.Error(codes.InvalidArgument, "Maximum number of symbolic link redirections reached"),
path.Resolve("foo", path.NewLoopDetectingScopeWalker(scopeWalker)))
path.Resolve(path.MustNewUNIXParser("foo"), path.NewLoopDetectingScopeWalker(scopeWalker)))
})

t.Run("Success", func(t *testing.T) {
// Simple case where a symbolic link is not self-referential.
scopeWalker1 := mock.NewMockScopeWalker(ctrl)
componentWalker1 := mock.NewMockComponentWalker(ctrl)
scopeWalker1.EXPECT().OnScope(true).Return(componentWalker1, nil)
scopeWalker1.EXPECT().OnAbsolute().Return(componentWalker1, nil)
scopeWalker2 := mock.NewMockScopeWalker(ctrl)
componentWalker1.EXPECT().OnTerminal(path.MustNewComponent("tmp")).
Return(&path.GotSymlink{Parent: scopeWalker2, Target: "private/tmp"}, nil)
Return(&path.GotSymlink{Parent: scopeWalker2, Target: path.MustNewUNIXParser("private/tmp")}, nil)
componentWalker2 := mock.NewMockComponentWalker(ctrl)
scopeWalker2.EXPECT().OnScope(false).Return(componentWalker2, nil)
scopeWalker2.EXPECT().OnRelative().Return(componentWalker2, nil)
componentWalker3 := mock.NewMockComponentWalker(ctrl)
componentWalker2.EXPECT().OnDirectory(path.MustNewComponent("private")).
Return(path.GotDirectory{Child: componentWalker3, IsReversible: true}, nil)
Expand All @@ -49,6 +49,6 @@ func TestLoopDetectingScopeWalker(t *testing.T) {

require.NoError(
t,
path.Resolve("/tmp", path.NewLoopDetectingScopeWalker(scopeWalker1)))
path.Resolve(path.MustNewUNIXParser("/tmp"), path.NewLoopDetectingScopeWalker(scopeWalker1)))
})
}
18 changes: 18 additions & 0 deletions pkg/filesystem/path/parser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package path



// Parser is used by Resolve to parse paths in the resolution. Implementations
// of ParseScope() should return a new copy of Parser and leave the current
// instance unmodified. It is permitted to call ParseScope() multiple times.
type Parser interface {
ParseScope(scopeWalker ScopeWalker) (next ComponentWalker, remainder RelativeParser, err error)
}

// RelativeParser is used by Resolve to parse relative paths in the resolution.
// Implementations of ParseFirstComponent() should return a new copy of Parser
// and leave the current instance unmodified. It is permitted to call
// ParseFirstComponent() multiple times.
type RelativeParser interface {
ParseFirstComponent(componentWalker ComponentWalker, mustBeDirectory bool) (next GotDirectoryOrSymlink, remainder RelativeParser, err error)
}
9 changes: 5 additions & 4 deletions pkg/filesystem/path/relative_scope_walker.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ func NewRelativeScopeWalker(componentWalker ComponentWalker) ScopeWalker {
}
}

func (pw *relativeScopeWalker) OnScope(absolute bool) (ComponentWalker, error) {
if absolute {
return nil, status.Error(codes.InvalidArgument, "Path is absolute, while a relative path was expected")
}
func (pw *relativeScopeWalker) OnAbsolute() (ComponentWalker, error) {
return nil, status.Error(codes.InvalidArgument, "Path is absolute, while a relative path was expected")
}

func (pw *relativeScopeWalker) OnRelative() (ComponentWalker, error) {
return pw.componentWalker, nil
}
4 changes: 2 additions & 2 deletions pkg/filesystem/path/relative_scope_walker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestRelativeScopeWalker(t *testing.T) {
componentWalker := mock.NewMockComponentWalker(ctrl)
componentWalker.EXPECT().OnTerminal(path.MustNewComponent("hello"))

require.NoError(t, path.Resolve("hello", path.NewRelativeScopeWalker(componentWalker)))
require.NoError(t, path.Resolve(path.MustNewUNIXParser("hello"), path.NewRelativeScopeWalker(componentWalker)))
})

t.Run("Absolute", func(t *testing.T) {
Expand All @@ -28,6 +28,6 @@ func TestRelativeScopeWalker(t *testing.T) {
require.Equal(
t,
status.Error(codes.InvalidArgument, "Path is absolute, while a relative path was expected"),
path.Resolve("/hello", path.NewRelativeScopeWalker(componentWalker)))
path.Resolve(path.MustNewUNIXParser("/hello"), path.NewRelativeScopeWalker(componentWalker)))
})
}
Loading
Loading