162 lines
3.8 KiB
Go
162 lines
3.8 KiB
Go
/*
|
|
Copyright 2021 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
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
|
|
}
|