kubenetworks/kubevpn

View on GitHub
pkg/cp/filespec.go

Summary

Maintainability
A
0 mins
Test Coverage
package cp

import (
    "path"
    "path/filepath"
    "strings"
)

type fileSpec struct {
    PodName      string
    PodNamespace string
    File         pathSpec
}

type pathSpec interface {
    String() string
}

// localPath represents a client-native path, which will differ based
// on the client OS, its methods will use path/filepath package which
// is OS dependant
type localPath struct {
    file string
}

func newLocalPath(fileName string) localPath {
    file := stripTrailingSlash(fileName)
    return localPath{file: file}
}

func (p localPath) String() string {
    return p.file
}

func (p localPath) Dir() localPath {
    return newLocalPath(filepath.Dir(p.file))
}

func (p localPath) Base() localPath {
    return newLocalPath(filepath.Base(p.file))
}

func (p localPath) Clean() localPath {
    return newLocalPath(filepath.Clean(p.file))
}

func (p localPath) Join(elem pathSpec) localPath {
    return newLocalPath(filepath.Join(p.file, elem.String()))
}

func (p localPath) Glob() (matches []string, err error) {
    return filepath.Glob(p.file)
}

func (p localPath) StripSlashes() localPath {
    return newLocalPath(stripLeadingSlash(p.file))
}

func isRelative(base, target localPath) bool {
    relative, err := filepath.Rel(base.String(), target.String())
    if err != nil {
        return false
    }
    return relative == "." || relative == stripPathShortcuts(relative)
}

// remotePath represents always UNIX path, its methods will use path
// package which is always using `/`
type remotePath struct {
    file string
}

func newRemotePath(fileName string) remotePath {
    // we assume remote file is a linux container but we need to convert
    // windows path separators to unix style for consistent processing
    file := strings.ReplaceAll(stripTrailingSlash(fileName), `\`, "/")
    return remotePath{file: file}
}

func (p remotePath) String() string {
    return p.file
}

func (p remotePath) Dir() remotePath {
    return newRemotePath(path.Dir(p.file))
}

func (p remotePath) Base() remotePath {
    return newRemotePath(path.Base(p.file))
}

func (p remotePath) Clean() remotePath {
    return newRemotePath(path.Clean(p.file))
}

func (p remotePath) Join(elem pathSpec) remotePath {
    return newRemotePath(path.Join(p.file, elem.String()))
}

func (p remotePath) StripShortcuts() remotePath {
    p = p.Clean()
    return newRemotePath(stripPathShortcuts(p.file))
}

func (p remotePath) StripSlashes() remotePath {
    return newRemotePath(stripLeadingSlash(p.file))
}

// strips trailing slash (if any) both unix and windows style
func stripTrailingSlash(file string) string {
    if len(file) == 0 {
        return file
    }
    if file != "/" && strings.HasSuffix(string(file[len(file)-1]), "/") {
        return file[:len(file)-1]
    }
    return file
}

func stripLeadingSlash(file string) string {
    // tar strips the leading '/' and '\' if it's there, so we will too
    return strings.TrimLeft(file, `/\`)
}

// stripPathShortcuts removes any leading or trailing "../" from a given path
func stripPathShortcuts(p string) string {
    newPath := p
    trimmed := strings.TrimPrefix(newPath, "../")

    for trimmed != newPath {
        newPath = trimmed
        trimmed = strings.TrimPrefix(newPath, "../")
    }

    // trim leftover {".", ".."}
    if newPath == "." || newPath == ".." {
        newPath = ""
    }

    if len(newPath) > 0 && string(newPath[0]) == "/" {
        return newPath[1:]
    }

    return newPath
}