2021-09-26 21:11:02 +00:00
|
|
|
package types
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2021-09-26 23:59:32 +00:00
|
|
|
"path/filepath"
|
2021-09-26 21:11:02 +00:00
|
|
|
"regexp"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
idRegex = regexp.MustCompile(`(.*?)(@(.*))?:(.*)`)
|
|
|
|
)
|
|
|
|
|
|
|
|
// ID an id of a file consists of at least a Bucket and a Key. Version is optional.
|
|
|
|
// Can also be used as an ID for a directory. When the key ends with "/" it is treated as dir.
|
|
|
|
type ID struct {
|
2021-09-26 23:59:32 +00:00
|
|
|
Bucket string `json:"bucket"` // Name of the bucket
|
|
|
|
Key string `json:"key"` // Key of the object
|
|
|
|
Version string `json:"version"` // Version of the object. For now we ignore it
|
2021-09-26 21:11:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// String Return String representation of an ID
|
|
|
|
// Looks like this: "bucketName@version:/id/of/obj" or "bucketName:/id/of/obj"
|
2021-09-26 23:59:32 +00:00
|
|
|
func (i ID) String() string {
|
2021-09-26 21:11:02 +00:00
|
|
|
if i.Version == "" {
|
|
|
|
return fmt.Sprintf("%s:%s", i.Bucket, i.Key)
|
|
|
|
} else {
|
|
|
|
return fmt.Sprintf("%s@%s:%s", i.Bucket, i.Version, i.Key)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Normalize normalzes the key to have a "/" prefix
|
|
|
|
func (i *ID) Normalize() {
|
2021-09-26 23:59:32 +00:00
|
|
|
if i.Key == "." {
|
|
|
|
i.Key = "/"
|
|
|
|
} else if !strings.HasPrefix(i.Key, "/") {
|
2021-09-26 21:11:02 +00:00
|
|
|
i.Key = "/" + i.Key
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Valid checks if bucket and key is not empty
|
|
|
|
func (i *ID) Valid() bool {
|
|
|
|
return i.Bucket != "" && i.Key != ""
|
|
|
|
}
|
|
|
|
|
2021-09-26 23:59:32 +00:00
|
|
|
func (i *ID) IsDirectory() bool {
|
|
|
|
return strings.HasSuffix(i.Key, "/")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Raw for the Key interface for the dataloaders so ID can be used as a dataloader key
|
|
|
|
func (i ID) Raw() interface{} {
|
|
|
|
return i
|
|
|
|
}
|
|
|
|
|
2021-11-01 23:33:33 +00:00
|
|
|
// Parent returns the parent dir ID. If its a file then return containing directory.
|
|
|
|
// If this is a directory then return the dir one up.
|
2021-09-26 23:59:32 +00:00
|
|
|
func (i ID) Parent() *ID {
|
|
|
|
if i.Key == "/" {
|
|
|
|
// Already at root. We dont have a parent
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-11-01 23:33:33 +00:00
|
|
|
var parent *ID
|
|
|
|
|
|
|
|
if i.IsDirectory() {
|
|
|
|
parts := strings.Split(i.Key, "/")
|
|
|
|
parent = &ID{
|
|
|
|
Bucket: i.Bucket,
|
|
|
|
Key: strings.Join(parts[:len(parts)-2], "/") + "/",
|
|
|
|
}
|
|
|
|
} else {
|
2021-11-25 00:57:24 +00:00
|
|
|
dir := filepath.Dir(i.Key)
|
|
|
|
|
|
|
|
if dir != "/" {
|
|
|
|
dir += "/"
|
|
|
|
}
|
|
|
|
|
2021-11-01 23:33:33 +00:00
|
|
|
parent = &ID{
|
|
|
|
Bucket: i.Bucket,
|
2021-11-25 00:57:24 +00:00
|
|
|
Key: dir,
|
2021-11-01 23:33:33 +00:00
|
|
|
}
|
2021-09-26 23:59:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
parent.Normalize()
|
|
|
|
|
|
|
|
return parent
|
|
|
|
}
|
|
|
|
|
2021-11-23 00:53:04 +00:00
|
|
|
// Name returns filename or directory name
|
|
|
|
func (i ID) Name() string {
|
|
|
|
return filepath.Base(i.Key)
|
|
|
|
}
|
|
|
|
|
2021-09-26 21:11:02 +00:00
|
|
|
// ParseID parses a string to an ID. Null if invalid
|
|
|
|
func ParseID(id string) *ID {
|
|
|
|
match := idRegex.FindStringSubmatch(id)
|
|
|
|
if match == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
rtn := &ID{
|
|
|
|
Bucket: match[1],
|
|
|
|
Version: match[3],
|
|
|
|
Key: match[4],
|
|
|
|
}
|
|
|
|
|
|
|
|
if !rtn.Valid() {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
rtn.Normalize()
|
|
|
|
|
|
|
|
return rtn
|
|
|
|
}
|