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

feat: Added some methods for sanitizing path on different platforms #279

Merged
merged 5 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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: 1 addition & 1 deletion pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -1037,7 +1037,7 @@ func (c *KpmClient) PullFromOci(localPath, source, tag string) error {
}

// Untar the tar file.
storagePath := ociOpts.AddStoragePathSuffix(localPath)
storagePath := ociOpts.SanitizePathWithSuffix(localPath)
err = utils.UnTarDir(matches[0], storagePath)
if err != nil {
return reporter.NewErrorEvent(
Expand Down
6 changes: 6 additions & 0 deletions pkg/opt/opt.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/hashicorp/go-version"
"kcl-lang.io/kcl-go/pkg/kcl"
"kcl-lang.io/kpm/pkg/errors"
"kcl-lang.io/kpm/pkg/path"
"kcl-lang.io/kpm/pkg/reporter"
"oras.land/oras-go/v2"
)
Expand Down Expand Up @@ -278,6 +279,11 @@ func (oci *OciOptions) AddStoragePathSuffix(pathPrefix string) string {
return filepath.Join(filepath.Join(filepath.Join(pathPrefix, oci.Reg), oci.Repo), oci.Tag)
}

// SanitizePathSuffix will take 'Registry/Repo/Tag' as a path suffix and sanitize it.
func (oci *OciOptions) SanitizePathWithSuffix(pathPrefix string) string {
return path.SanitizePath(filepath.Join(filepath.Join(filepath.Join(pathPrefix, oci.Reg), oci.Repo), oci.Tag))
}

type OciManifestOptions struct {
Annotations map[string]string
}
Expand Down
46 changes: 46 additions & 0 deletions pkg/path/path_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package path

import (
"runtime"
"testing"
)

func TestSanitizePath(t *testing.T) {
tests := []struct {
name string
input string
expected string
}{
{
name: "Path with null character",
input: "test\x00file",
expected: "test_file",
},
{
name: "Path without invalid characters",
input: "/usr/local/bin/test",
expected: "/usr/local/bin/test",
},
}

if runtime.GOOS == "windows" {
tests = append(tests, struct {
name string
input string
expected string
}{
name: "Windows style path",
input: "C:\\Program Files\\Test<:>*|",
expected: "C:\\Program Files\\Test______",
})
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
output := SanitizePath(tt.input)
if output != tt.expected {
t.Errorf("expected %s, got %s", tt.expected, output)
}
})
}
}
44 changes: 44 additions & 0 deletions pkg/path/path_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//go:build !windows
// +build !windows

package path

import (
"path/filepath"
"strings"
)

var NeedToSanitize map[rune]bool

func init() {
NeedToSanitize = map[rune]bool{
'\x00': true,
}
}

// sanitizePath cleans a path string by removing or replacing invalid Windows file name characters.
func sanitizePath(path string, sanitize sanitizer, toSanitize map[rune]bool) string {
// replace all slashes with backslashes
path = filepath.FromSlash(path)

// replace all invalid characters
return strings.Map(func(r rune) rune {
if _, isInvalid := toSanitize[r]; isInvalid {
return sanitize(r, toSanitize)
}
return r
}, path)
}

// sanitizer defined how to handle and replace invalid file name characters.
type sanitizer func(rune, map[rune]bool) rune

// SanitizePath replaces invalid characters in a Windows path with a placeholder.
func SanitizePath(path string) string {
return sanitizePath(path, func(r rune, invalidChars map[rune]bool) rune {
if _, ok := invalidChars[r]; ok {
return '_'
}
return r
}, NeedToSanitize)
}
48 changes: 48 additions & 0 deletions pkg/path/path_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//go:build windows
// +build windows

package path

import (
"path/filepath"
"strings"
)

var NeedToSanitize map[rune]bool

func init() {
NeedToSanitize = map[rune]bool{
'<': true, '>': true, ':': true, '"': true, '|': true, '?': true, '*': true,
}
}

// sanitizePath cleans a path string by removing or replacing invalid Windows file name characters.
func sanitizePath(path string, sanitize sanitizer, toSanitize map[rune]bool) string {
// replace all slashes with backslashes
path = filepath.FromSlash(path)

// replace all invalid characters
return strings.Map(func(r rune) rune {
if _, isInvalid := toSanitize[r]; isInvalid {
return sanitize(r, toSanitize)
}
return r
}, path)
}

// sanitizer defined how to handle and replace invalid file name characters.
type sanitizer func(rune, map[rune]bool) rune

// SanitizePath replaces invalid characters in a Windows path with a placeholder.
func SanitizePath(path string) string {
volumeName := filepath.VolumeName(path)
// Only sanitize the part of the path after the volume name
sanitized := sanitizePath(path[len(volumeName):], func(r rune, invalidChars map[rune]bool) rune {
if _, ok := invalidChars[r]; ok {
return '_'
}
return r
}, NeedToSanitize)

return volumeName + sanitized
}
Loading