aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/cli/internal/turbopath/absolute_system_path.go
diff options
context:
space:
mode:
author简律纯 <hsiangnianian@outlook.com>2023-04-28 01:36:44 +0800
committer简律纯 <hsiangnianian@outlook.com>2023-04-28 01:36:44 +0800
commitdd84b9d64fb98746a230cd24233ff50a562c39c9 (patch)
treeb583261ef00b3afe72ec4d6dacb31e57779a6faf /cli/internal/turbopath/absolute_system_path.go
parent0b46fcd72ac34382387b2bcf9095233efbcc52f4 (diff)
downloadHydroRoll-dd84b9d64fb98746a230cd24233ff50a562c39c9.tar.gz
HydroRoll-dd84b9d64fb98746a230cd24233ff50a562c39c9.zip
Diffstat (limited to 'cli/internal/turbopath/absolute_system_path.go')
-rw-r--r--cli/internal/turbopath/absolute_system_path.go258
1 files changed, 258 insertions, 0 deletions
diff --git a/cli/internal/turbopath/absolute_system_path.go b/cli/internal/turbopath/absolute_system_path.go
new file mode 100644
index 0000000..df65827
--- /dev/null
+++ b/cli/internal/turbopath/absolute_system_path.go
@@ -0,0 +1,258 @@
+package turbopath
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+// AbsoluteSystemPath is a root-relative path using system separators.
+type AbsoluteSystemPath string
+
+// _dirPermissions are the default permission bits we apply to directories.
+const _dirPermissions = os.ModeDir | 0775
+
+// _nonRelativeSentinel is the leading sentinel that indicates traversal.
+const _nonRelativeSentinel = ".."
+
+// ToString returns a string represenation of this Path.
+// Used for interfacing with APIs that require a string.
+func (p AbsoluteSystemPath) ToString() string {
+ return string(p)
+}
+
+// RelativeTo calculates the relative path between two `AbsoluteSystemPath`s.
+func (p AbsoluteSystemPath) RelativeTo(basePath AbsoluteSystemPath) (AnchoredSystemPath, error) {
+ processed, err := filepath.Rel(basePath.ToString(), p.ToString())
+ return AnchoredSystemPath(processed), err
+}
+
+// Join appends relative path segments to this AbsoluteSystemPath.
+func (p AbsoluteSystemPath) Join(additional ...RelativeSystemPath) AbsoluteSystemPath {
+ cast := RelativeSystemPathArray(additional)
+ return AbsoluteSystemPath(filepath.Join(p.ToString(), filepath.Join(cast.ToStringArray()...)))
+}
+
+// ToStringDuringMigration returns a string representation of this path.
+// These instances should eventually be removed.
+func (p AbsoluteSystemPath) ToStringDuringMigration() string {
+ return p.ToString()
+}
+
+// UntypedJoin is a Join that does not constrain the type of the arguments.
+// This enables you to pass in strings, but does not protect you from garbage in.
+func (p AbsoluteSystemPath) UntypedJoin(args ...string) AbsoluteSystemPath {
+ return AbsoluteSystemPath(filepath.Join(p.ToString(), filepath.Join(args...)))
+}
+
+// Dir implements filepath.Dir() for an AbsoluteSystemPath
+func (p AbsoluteSystemPath) Dir() AbsoluteSystemPath {
+ return AbsoluteSystemPath(filepath.Dir(p.ToString()))
+}
+
+// Mkdir implements os.Mkdir(p, perm)
+func (p AbsoluteSystemPath) Mkdir(perm os.FileMode) error {
+ return os.Mkdir(p.ToString(), perm)
+}
+
+// MkdirAll implements os.MkdirAll(p, perm)
+func (p AbsoluteSystemPath) MkdirAll(perm os.FileMode) error {
+ return os.MkdirAll(p.ToString(), perm)
+}
+
+// Open implements os.Open(p) for an AbsoluteSystemPath
+func (p AbsoluteSystemPath) Open() (*os.File, error) {
+ return os.Open(p.ToString())
+}
+
+// OpenFile implements os.OpenFile for an absolute path
+func (p AbsoluteSystemPath) OpenFile(flags int, mode os.FileMode) (*os.File, error) {
+ return os.OpenFile(p.ToString(), flags, mode)
+}
+
+// Lstat implements os.Lstat for absolute path
+func (p AbsoluteSystemPath) Lstat() (os.FileInfo, error) {
+ return os.Lstat(p.ToString())
+}
+
+// Stat implements os.Stat for absolute path
+func (p AbsoluteSystemPath) Stat() (os.FileInfo, error) {
+ return os.Stat(p.ToString())
+}
+
+// Findup checks all parent directories for a file.
+func (p AbsoluteSystemPath) Findup(name RelativeSystemPath) (AbsoluteSystemPath, error) {
+ path, err := FindupFrom(name.ToString(), p.ToString())
+
+ return AbsoluteSystemPath(path), err
+
+}
+
+// Exists returns true if the given path exists.
+func (p AbsoluteSystemPath) Exists() bool {
+ _, err := p.Lstat()
+ return err == nil
+}
+
+// DirExists returns true if the given path exists and is a directory.
+func (p AbsoluteSystemPath) DirExists() bool {
+ info, err := p.Lstat()
+ return err == nil && info.IsDir()
+}
+
+// FileExists returns true if the given path exists and is a file.
+func (p AbsoluteSystemPath) FileExists() bool {
+ info, err := os.Lstat(p.ToString())
+ return err == nil && !info.IsDir()
+}
+
+// ContainsPath returns true if this absolute path is a parent of the
+// argument.
+func (p AbsoluteSystemPath) ContainsPath(other AbsoluteSystemPath) (bool, error) {
+ // In Go, filepath.Rel can return a path that starts with "../" or equivalent.
+ // Checking filesystem-level contains can get extremely complicated
+ // (see https://github.com/golang/dep/blob/f13583b555deaa6742f141a9c1185af947720d60/internal/fs/fs.go#L33)
+ // As a compromise, rely on the stdlib to generate a relative path and then check
+ // if the first step is "../".
+ rel, err := filepath.Rel(p.ToString(), other.ToString())
+ if err != nil {
+ return false, err
+ }
+ return !strings.HasPrefix(rel, _nonRelativeSentinel), nil
+}
+
+// ReadFile reads the contents of the specified file
+func (p AbsoluteSystemPath) ReadFile() ([]byte, error) {
+ return ioutil.ReadFile(p.ToString())
+}
+
+// VolumeName returns the volume of the specified path
+func (p AbsoluteSystemPath) VolumeName() string {
+ return filepath.VolumeName(p.ToString())
+}
+
+// WriteFile writes the contents of the specified file
+func (p AbsoluteSystemPath) WriteFile(contents []byte, mode os.FileMode) error {
+ return ioutil.WriteFile(p.ToString(), contents, mode)
+}
+
+// EnsureDir ensures that the directory containing this file exists
+func (p AbsoluteSystemPath) EnsureDir() error {
+ dir := p.Dir()
+ err := os.MkdirAll(dir.ToString(), _dirPermissions)
+ if err != nil && dir.FileExists() {
+ // It looks like this is a file and not a directory. Attempt to remove it; this can
+ // happen in some cases if you change a rule from outputting a file to a directory.
+ if err2 := dir.Remove(); err2 == nil {
+ err = os.MkdirAll(dir.ToString(), _dirPermissions)
+ } else {
+ return err
+ }
+ }
+ return err
+}
+
+// MkdirAllMode Create directory at path and all necessary parents ensuring that path has the correct mode set
+func (p AbsoluteSystemPath) MkdirAllMode(mode os.FileMode) error {
+ info, err := p.Lstat()
+ if err == nil {
+ if info.IsDir() && info.Mode() == mode {
+ // Dir exists with the correct mode
+ return nil
+ } else if info.IsDir() {
+ // Dir exists with incorrect mode
+ return os.Chmod(p.ToString(), mode)
+ } else {
+ // Path exists as file, remove it
+ if err := p.Remove(); err != nil {
+ return err
+ }
+ }
+ }
+ if err := os.MkdirAll(p.ToString(), mode); err != nil {
+ return err
+ }
+ // This is necessary only when umask results in creating a directory with permissions different than the one passed by the user
+ return os.Chmod(p.ToString(), mode)
+}
+
+// Create is the AbsoluteSystemPath wrapper for os.Create
+func (p AbsoluteSystemPath) Create() (*os.File, error) {
+ return os.Create(p.ToString())
+}
+
+// Ext implements filepath.Ext(p) for an absolute path
+func (p AbsoluteSystemPath) Ext() string {
+ return filepath.Ext(p.ToString())
+}
+
+// RelativePathString returns the relative path from this AbsoluteSystemPath to another absolute path in string form as a string
+func (p AbsoluteSystemPath) RelativePathString(path string) (string, error) {
+ return filepath.Rel(p.ToString(), path)
+}
+
+// PathTo returns the relative path between two absolute paths
+// This should likely eventually return an AnchoredSystemPath
+func (p AbsoluteSystemPath) PathTo(other AbsoluteSystemPath) (string, error) {
+ return p.RelativePathString(other.ToString())
+}
+
+// Symlink implements os.Symlink(target, p) for absolute path
+func (p AbsoluteSystemPath) Symlink(target string) error {
+ return os.Symlink(target, p.ToString())
+}
+
+// Readlink implements os.Readlink(p) for an absolute path
+func (p AbsoluteSystemPath) Readlink() (string, error) {
+ return os.Readlink(p.ToString())
+}
+
+// Remove removes the file or (empty) directory at the given path
+func (p AbsoluteSystemPath) Remove() error {
+ return os.Remove(p.ToString())
+}
+
+// RemoveAll implements os.RemoveAll for absolute paths.
+func (p AbsoluteSystemPath) RemoveAll() error {
+ return os.RemoveAll(p.ToString())
+}
+
+// Base implements filepath.Base for an absolute path
+func (p AbsoluteSystemPath) Base() string {
+ return filepath.Base(p.ToString())
+}
+
+// Rename implements os.Rename(p, dest) for absolute paths
+func (p AbsoluteSystemPath) Rename(dest AbsoluteSystemPath) error {
+ return os.Rename(p.ToString(), dest.ToString())
+}
+
+// EvalSymlinks implements filepath.EvalSymlinks for absolute path
+func (p AbsoluteSystemPath) EvalSymlinks() (AbsoluteSystemPath, error) {
+ result, err := filepath.EvalSymlinks(p.ToString())
+ if err != nil {
+ return "", err
+ }
+ return AbsoluteSystemPath(result), nil
+}
+
+// HasPrefix is strings.HasPrefix for paths, ensuring that it matches on separator boundaries.
+// This does NOT perform Clean in advance.
+func (p AbsoluteSystemPath) HasPrefix(prefix AbsoluteSystemPath) bool {
+ prefixLen := len(prefix)
+ pathLen := len(p)
+
+ if prefixLen > pathLen {
+ // Can't be a prefix if longer.
+ return false
+ } else if prefixLen == pathLen {
+ // Can be a prefix if they're equal, but otherwise no.
+ return p == prefix
+ }
+
+ // otherPath is definitely shorter than p.
+ // We need to confirm that p[len(otherPath)] is a system separator.
+
+ return strings.HasPrefix(p.ToString(), prefix.ToString()) && os.IsPathSeparator(p[prefixLen])
+}