fileutils

package module
v0.0.0-...-38a6457 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 24, 2026 License: MIT Imports: 25 Imported by: 23

README

Simple file utilities for golang, written for working with markup files and other file types (like images) typically associated with documentation.

Included are types for describing a file and configuring a set of associated output files:

  • InputFile describes a file: full path, size, MIME type, ?IsXML, MMCtype, and contents (up to 2 megabytes).

  • MMCtype is meant to function like a MIME type and has three fields. It can be set based on file name and contents, and later updated if the file is XML and has a DOCTYPE declaration. Refer to file mmctype.go

  • OutputFiles makes it easier to create a group of like-named files for an InputFile, in the same directory or optionally in a like-named subdirectory.

Known issues

  • Tested only on macos (i.e. it's sure to fail on Windows)

Example

$ cd /opt
$ ls example*
example.xml
import "github.com/fbaube/fileutils"

IF, _ := fileutils.NewInputFile("example.xml")

fmt.Fprintf(os.Stdout, "You opened: %s \n", IF)
// You opened: /opt/example.xml
println("i.e.", IF.DString())
// i.e. InputFile</opt/example.xml>sz<42>dir?<n>bin?<n>img?<n>mime<text/plain>

// Argument is not "": Creates a subdirectory for associated output files.
OF, _ := IF.NewOutputFiles("_myapp")

// Creates an associated file and returns the io.WriteCloser
w_diag, _ := OF.NewOutputExt("diag")
fmt.Fprintln(w_diag, "Lots of diagnostic info")
w_diag.Close()
$ ls example*
example.xml

example.xml_myapp:
example.diag

Dependencies

  • github.com/hosom/gomagic for MIME type analysis
  • github.com/pkg/errors for wrapping errors
  • github.com/fbaube/stringutils for various

Documentation

Index

Constants

View Source
const MAX_FILE_SIZE = 100_000_000

MAX_FILE_SIZE is set (arbitrarily) to 100 megabytes.

View Source
const MIN_FILE_SIZE = 6

MIN_FILE_SIZE is the minimum that can be analysed for MIME/content type, and is set (arbitrarily) to 6 bytes.

View Source
const PathSep = string(os.PathSeparator)

A token nod to Windoze compatibility.

Variables

Functions

func AbsWRT

func AbsWRT(problyRelFP string, wrtDir string) string

AbsWRT is like "filepath.Abs(..)"": it can convert a possibly-relative filepath to an absolute filepath. The difference is that a relative filepath argument is not resolved w.r.t. the current working directory; it is instead done w.r.t. the supplied directory argument.

func AppendToFileBaseName

func AppendToFileBaseName(name, toAppend string) string

func ClearAndCreateDirectory

func ClearAndCreateDirectory(path string) error

ClearAndCreateDirectory deletes it before re-creating it. The older version (named "ClearDirectory") tried to keep the directory as-is while emptying it.

func ClearDirectory

func ClearDirectory(path string) error

ClearDirectory tries to keep the directory as-is while emptying it.

func CopyDirRecursivelyFromTo

func CopyDirRecursivelyFromTo(src string, dst string) error

CopyDirRecursivelyFromTo copies a whole directory recursively. BOTH arguments should be directories !! Otherwise, hilarity ensures.

func CopyFileFromTo

func CopyFileFromTo(src, dst string) error

CopyFileFromTo copies a single file from src to dst.

func CopyFileGreedily

func CopyFileGreedily(src string, dst string) error

CopyFileGreedily reads the entire file into memory, and is therefore memory-constrained !

func CopyFromTo

func CopyFromTo(src, dst string) error

CopyFromTo copies the contents of src to dst atomically, using a temp file as intermediary.

func CreateEmpty

func CreateEmpty(path AbsFilePath) (*os.File, error)

CreateEmpty opens the filepath as a writable empty file, truncating it if it exists and is non-empty.

func DirectoryContents

func DirectoryContents(f *os.File) ([]os.FileInfo, error)

DirectoryContents returns the results of "(*os.File)Readdir(..)". "File.Name()" might be a relative filepath but if it was opened okay then it at least functions as an absolute filepath. If the path is not a directory then it panics.

The call to "Readdir(..)" reads the contents of the directory associated with arg "File" and returns a slice of "FileInfo" values, as would be returned by "Lstat(..)", in directory order.

func DirectoryFiles

func DirectoryFiles(f *os.File) (int, []os.FileInfo, error)

DirectoryFiles is like "DirectoryContents(..)" except that results that are directories (not files) are nil'ed out. If there were entries but none were files, it return ("0,nil,nil").

func Enhomed

func Enhomed(s string) string

Enhomed shortens a filepath by substituting "~".

func EnsureTrailingPathSep

func EnsureTrailingPathSep(s string) string

func ExcludeFilepath_m5

func ExcludeFilepath_m5(s string) (bool, string)

ExcludeFilepath_m5 returns true (plus a reason) for a filepath that matches a blacklist for prefix or "midfix" or suffix.

  • Excluded prefixes must follow a path separator; this rule should allow "." and "./" (only) to pass thru unexcluded / unimpeded.
  • Excluded suffixes apply to all names, but will not apply to a directory name that has a path separator appended.
  • The path separator is assumed to be slash ("/"), not os.Separator.

.

func FileExists

func FileExists(path string) bool

FileExists returns true *iff* the file exists and is in fact a file.

func GatherDirTreeList

func GatherDirTreeList(path string) (paths []string)

GatherDirTreeList walks a directory tree (fetched via os.DirFS) to gather a list of all item names (file, directories, symlinks, more).

NOTE that for the argument "inpath", it makes no difference whether:

  • inpath is relative or absolute
  • inpath ends with a trailing slash or not
  • inpath is a directory or a symlink to a directory

In the walk process, the item names (as returned by fs.Walkdir) are relative to `inpath` and do not include any information about `inpath` itself, i.e. the portions of the item paths "above" the directory node `inpath`, so the caller has to sort that out.

Regarding values of the argument `inpath`:

  • A valid directory returns at least one item: ".", representing `inpath` itself.
  • A valid file or non-existent path item returns only one item, the `inpath` itself.
  • A symlink to a directory it is followed; behavior for a symlink to a file is not easily summarised.

The docu for os.Dirfs states: The result implements io/fs.StatFS, io/fs.ReadFileFS and io/fs.ReadDirFS.

Therefore API calls that work are:

  • Stat errors should be of type *PathError.
  • Stat(name string) (fs.FileInfo, error)
  • Readfile on success returns a nil error, not io.EOF. The caller is permitted to modify the returned byte slice. This method should return a copy of the underlying data.
  • ReadFile(name string) ([]byte, error)
  • ReadDir reads the named directory and returns a list of directory entries sorted by filename. ReadDir(name string) ([]fs.DirEntry, error)

.

func GetHomeDir

func GetHomeDir() string

GetHomeDir is a convenience function, and refers to the invoking user's home directory.

func GetStringFromStdin

func GetStringFromStdin() (string, error)

GetStringFromStdin reads "os.Stdin" completely (i.e. until "\n^D") and returns a string.

func IsDirAndExists

func IsDirAndExists(path string) bool

IsDirAndExists returns true *iff* the directory exists and is in fact a directory.

func IsFileAtPath

func IsFileAtPath(aPath string) (bool, os.FileInfo, error)

IsFileAtPath checks that the file exists AND that it is "regular" (not dir, symlink, pipe), and also returns size and permissions in *os.FileInfo

Return values:

  • (true, *FileInfo, nil) if a regular file exists (but can be 0-len!)
  • (false, *FileInfo, nil) if something else exists (incl. dir)
  • (false, nil, nil) if nothing at all exists
  • (false, nil, anError) if some unusual error was returned (failing disk?)

Notes & caveats:

  • File emptiness (i.e. length 0) is not checked
  • "~" for user home dir is not expanded and will fail

.

func IsNonEmpty

func IsNonEmpty(path string) bool

IsNonEmpty returns true *iff* the file exists *and* contains at least one byte of data.

func IsXML

func IsXML(path string) bool

IsXML returns true *iff* the file exists *and* appears to be XML. The check is simple though.

func MTypeSub

func MTypeSub(mtype string, i int) string

func MakeDirectoryExist

func MakeDirectoryExist(path string) error

MakeDirectoryExist might not create it ?! (NOTE)

func Must

func Must(f *os.File, e error) *os.File

Must wraps this package's most common return values and panics if it gets an error.

func NewFSObjectSliceFromFilepathSlice

func NewFSObjectSliceFromFilepathSlice(FPs []string) ([]*FSObject, *FSObjectSummaryStats)

NewFSObjectSliceFromFilepathSlice creates a *FSObject for every input string, and itself has no error return value, because FSObject implements Errer, so that every entry is non-nil and either is valid or has its own error message.

It does tho also return summary statistics, so that is is easy to check whether any errors at all were encountered.

The func assumes that entries have been "sanitized" by collecting them using os.Root, so it does check the security of symlinks, or use funcs io/fs.ValidPath or path/filepath.IsLocal.

Accumulated NewContentity errors are counted in the field CotentityFS.nErrors .

func OpenRO

func OpenRO(path string) (f *os.File, e error)

OpenRO opens (and returns) the filepath as a readable file.

func OpenRW

func OpenRW(path string) (f *os.File, e error)

OpenRW opens (and returns) the filepath as a writable file. An existing file is not truncated, merely opened.

func PathDemo

func PathDemo()

func PathExists

func PathExists(path string) bool

PathExists returns true IFF there is a filesystem item at the path (can be file or directory). Note that it is not proven/confirmed that: `Lstat` returns error IFF the item does not exist.

func ReadDirAsMap

func ReadDirAsMap(inpath string) (map[string]*FSObject, error)

ReadDirAsMap assumes that file/dir names are case-sensitive.

func ResolvePath

func ResolvePath(s string) string

ResolvePath is needed because functions in package path/filepath do not handle "~" (home directory) well. If an error occurs (for whatever reason), we punt: simply return the original input argument.

func SameContents

func SameContents(f1, f2 *os.File) bool

SameContents returns: Are the two files' contents identical ?

func SessionSummary

func SessionSummary() string

SessionSummary can be called anytime.

func StripTrailingPathSep

func StripTrailingPathSep(s string) string

func TempDir

func TempDir(dest string) string

Tempdir checks and returns the value of the envar `TMPDIR`.

func WriteAtomic

func WriteAtomic(dest string, write func(w io.Writer) error) (err error)

WriteAtomic is TBS.

func XmlAttrS

func XmlAttrS(a xml.Attr) string

func XmlNameS

func XmlNameS(n xml.Name) string

func XmlStartElmS

func XmlStartElmS(se xml.StartElement) string

Types

type AbsFilePath

type AbsFilePath string

AbsFilePath is a new type, based on `string`. It serves three purposes: - clarify and bring correctness to the processing of absolute path arguments - permit the use of a clearly named struct field - permit the definition of methods on the type

Note that when working with an `os.File`, `Name()` returns the name of the file as was passed to `Open(..)`, so it might be a relative filepath.

func AbsFP

func AbsFP(relFP string) AbsFilePath

AbsFP is like filepath.Abs(..) except using our own types.

func (AbsFilePath) Append

func (afp AbsFilePath) Append(rfp string) AbsFilePath

Append is a convenience function to keep code cleaner.

func (AbsFilePath) BaseName

func (afp AbsFilePath) BaseName() string

func (AbsFilePath) DirExists

func (afp AbsFilePath) DirExists() bool

DirExists returns true *iff* the directory exists and is in fact a directory.

func (AbsFilePath) DirPath

func (afp AbsFilePath) DirPath() AbsFilePath

func (AbsFilePath) Enhomed

func (afp AbsFilePath) Enhomed() string

func (AbsFilePath) FileExists

func (afp AbsFilePath) FileExists() bool

Exists returns true *iff* the file exists and is in fact a file.

func (AbsFilePath) FileExt

func (afp AbsFilePath) FileExt() string

func (AbsFilePath) FileSize

func (afp AbsFilePath) FileSize() int

FileSize returns the size *iff* the filepath exists and is in fact a file.

func (AbsFilePath) HasPrefix

func (afp AbsFilePath) HasPrefix(beg AbsFilePath) bool

StartsWith is like strings.HasPrefix(..) but uses our types.

func (AbsFilePath) OpenExistingDir

func (afp AbsFilePath) OpenExistingDir() (f *os.File, e error)

OpenExistingDir returns the directory *iff* it exists and can be opened for reading. Note that the `os.File` can be nil without error. Thus we cannot (or: *do not*) distinguish btwn non-existence and an actual error. OTOH if it exists but is not a directory, return an error.

func (AbsFilePath) OpenOrCreateDir

func (afp AbsFilePath) OpenOrCreateDir() (f *os.File, e error)

OpenOrCreateDir returns true if (a) the directory exists and can be opened, or (b) it does not exist, and/but it can be created anew.

func (AbsFilePath) S

func (afp AbsFilePath) S() string

S is a utility method to keep code cleaner.

func (AbsFilePath) Tildotted

func (afp AbsFilePath) Tildotted() string

type DirectoryDetails

type DirectoryDetails struct {
	DirName       string
	DirFileInfo   fs.FileInfo
	NamesToItems  map[string]*FSObject
	NamesToHashes map[string]string
	ContentfulFileCount,
	ContentlessFileCount,
	DirCount, MiscCount int
}

DirectoryDetails should NOT follow (or enforce) the convention that a directory name always has a trailing slash, because this struct is intended for comparison operations, where a name may be a directory in one place but not the other.

func ReadDirectoryDetails

func ReadDirectoryDetails(aPath string) (*DirectoryDetails, error)

ReadDirectoryDetails includes "Read" in its name because it works kinda like ReadDir: it does not recurse down into subdirectories.

func (*DirectoryDetails) NamesByHash

func (pDD *DirectoryDetails) NamesByHash(hh string) []string

type Errer

type Errer struct {
	Err error
	// contains filtered or unexported fields
}

Errer is a struct that can be used to embed an error in another struct, when we want to execute a chain of (pointer) methods on a struct in the style of a data pipeline: chainable, and executed left-to-right.

We make the error public so that it is easily set, and so that we can wrap errors easily using the "%w" printf format spec.

Methods are on *Errer, not Errer, so that modification is possible.

NOTE that this resembles a Result type, so we would like the API to resemble https://pkg.go.dev/go.bytecodealliance.org@v0.4.0/cm#Result :

  • type Result
  • func (r *Result) Err() *Err
  • func (r *Result) IsErr() bool
  • func (r *Result) IsOK() bool
  • func (r *Result) OK() *OK
  • func (r Result) Result() (ok OK, err Err, isErr bool)

TODO: This is in package fileutils, so it should be safe to assume that an error here is of type [*PathError]. .

func (*Errer) ClearError

func (p *Errer) ClearError()

func (*Errer) Error

func (p *Errer) Error() string

Error is an NPE-proof improvement on the standard error.Error() .

func (*Errer) GetError

func (p *Errer) GetError() error

GetError is a convenience func because getting Error.Err is ugly. .

func (*Errer) GetPathError

func (p *Errer) GetPathError() *fs.PathError

GetPathError is a convenience func because getting Error.Err is ugly. .

func (*Errer) HasError

func (p *Errer) HasError() bool

HasError is a convenience function. Since Err is publicly visible, HasError is not really needed, but it seems appropriate given that we also have func Error() .

func (*Errer) HasPathError

func (p *Errer) HasPathError() bool

HasPathError is a convenience function. Since Err is publicly visible, HasPathError is not really needed, but it seems appropriate given that we also have func Error() .

func (*Errer) SetError

func (p *Errer) SetError(e error)

SetError is a convenience func because setting Error.Err is ugly. .

type FSO_type

type FSO_type D.SemanticFieldType
const (
	FSO_type_DIRR FSO_type = FSO_type(D.SFT_FSDIR)
	FSO_type_FILE FSO_type = FSO_type(D.SFT_FSFIL)
	FSO_type_SYML FSO_type = FSO_type(D.SFT_FSYML)
	FSO_type_OTHR FSO_type = FSO_type(D.SFT_FSOTH)
)

type FSObject

type FSObject struct {

	// TypedRaw is an outlier, because it is the only
	// field in this struct that cannot be deduced from
	// the FileInfo. Therefore it is a candidate to be
	// removed. It is a ptr, to allow for lazy loading.
	*CT.TypedRaw

	// FileInfo implements interfaces [os.FileInfo] and [fs.DirEntry].
	// It should probably be an unexported, lower case "fi", because
	// its integrity is relied on heavily. We use it as a struct and
	// not as a ptr-to-struct, so that (a) it is not shared-writable,
	// and (b) there is no chance of a NPE. Each path includes the
	// [FP.Base].
	fs.FileInfo
	// FSO_type is closely linked to FileInfo and
	// they should always be updated in lockstep.
	FSO_type
	// FPs has abs & rel paths, and an indicator of which was used to
	// instantiate it. We use it as a struct and not as a ptr-to-struct,
	// so that it is not shared-writable, and so that there is no chance
	// of a NPE.
	//
	// Paths follow our rules:
	//  - a directory MUST end in a slash (or OS sep)
	//  - a symlink MUST NOT end in a slash (or OS sep)
	//
	// Note that an [fs.FileInfo] does not preserve or provide path
	// info, which is part of the motivstion for this too-large struct.
	FPs Filepaths

	// Perms is UNIX-style "rwx" user/group/world
	Perms string
	// Inode and NLinks are for hard link detection.
	Inode, NLinks int // uint64
	// Errer provides an NPE-proof error field
	Errer
}

FSObject is an item identified by a filepath (plus its contents) that we have tried to or will try to read, write, or create. It might be a directory or symlink, either of which requires further processing elsewhere. In the most common usage, it is a file.

CONTAINS RAW, in *CT.TypedRaw

It implements four interfaces:

It might be just a path where nothing exists but we intend to do something. Its filepath(s) can be empty ("") if (for example) its content was created interactively or it so far lives only in memory.

NOTE basically all fields are exported. This will change in the future when the handlng of modifications is tightened up.

NOTE that the file name (aka [FP.Base], the part of the full path after the last directory separator) is not stored separately: it is stored in the AbsFP *and* the RelFP. Note also that this path & name information duplicates what is stored in an instance of orderednodes.Nord .

NOTE that it embeds an fs.FileInfo, and implements interfaces [FSObjecter], fs.FileInfo, and fs.DirEntry), and contains basic file system metadata PLUS the path to the item (whicih FIleInfo does not contain) AND the item contents (but only after lazy loading). The `FileInfo` is the results of a call to os.LStat/fs.Lstat (or perhaps alternatively the contents of a record in sqlar or zip), parsed.

FSObject is embedded in struct datarepo/rowmodels/ContentityRow.

This struct is rather large and all-encompassing, but this follows from certain design decisions and certain behavior in the stahdard library.

It might seem odd to include a [TypedRaw] rather than a plain [Raw]. But in general when we are working with serializing and deserializing content ASTs, it is important to know what we are working with, cos sometimes we can - or want to - have to - do things like include HTML in Markdown, or permit HTML tags in LwDITA.

It might also seem odd that MU_type_DIRLIKE is a "markup type", but this avoids many practival problems encountered in trying to process file system trees.

NOTE that RelFP and AbsFP must be exported to be persisted to the DB.

This struct might be somehow applicable to non-file FS nodes and also other hierarchical structures (like XML), but this is not explored yet. .

func NewFSObject

func NewFSObject(anFP string) *FSObject

NewFSObject takes a filepath (absolute or relative) and analyzes the object (assuming one exists) at the path. This func does not load and analyse the content.

A relative path is appended to the CWD, which may not be the desired behavior; in such case, use NewFSObjectRelativeTo (below).

This func does not use os.Root, ao its security is not known. However this func does not follow symlinks: it returns information about the symbolic link itself.

There is only one return value, a pointer, always non-nil. If there is an error to be returned, it is in embedded struct Errer, and the rest of the returned struct may be empty and invalid, except (maybe!) embedded struct [FPs] (a Filepaths).

Note that passing in an empty path is not OK; instead create (by hand) a new pathless FSObject from the content.

If you wish to create a blank FSObject that has no path, simply use a nil ptr instead of calling this func. Passing an empty path to this func is not OK. .

func NewFSObjectSandboxed

func NewFSObjectSandboxed(anFP string, aRoot os.Root) *FSObject

NewFSObjectInRoot takes a filepath (absolute or relative) and analyzes the object (assuming one exists) at the path. This func does not load and analyse the content.

A relative path is used w.r.t. the input os.Root, so the func should be secure. If it can fetch a fs.FileInfo but the path fails to be Valid or Local, a loud warning ss issued.

os.Root is relied upon, so symlinks are followed: os.Root.Stat is called rather than os.Root.LStat. Thus it returns information about the symlink's target, not the symlink itself. If the symlink points to a non- existent item, the result should be fs.ErrNotExist.

There is only one return value, a pointer, always non-nil. If there is an error to be returned, it is in embedded struct Errer, and the rest of the returned struct may be empty and invalid, except (maybe!) embedded struct [FPs] (a Filepaths).

Note that passing in an empty path is not OK; instead create (by hand) a new pathless FSObject from the content.

If you wish to create a blank FSObject that has no path, simply use a nil ptr instead of calling this func. Passing an empty path to this func is not OK. .

func ReadDir

func ReadDir(inpath string) ([]FSObject, error)

ReadDir returns only errors from the initial step of opening the directory. An error returned on an individual directory item is attached to the item via interface Errer.

It might be more useful in mamny use cases to return a slice of pointers, but the pattern in the stdlib is to return struct instances, not pointers. .

func ReadDirAsPtrs

func ReadDirAsPtrs(inpath string) ([]*FSObject, error)

func (*FSObject) Contents

func (p *FSObject) Contents() (string, error)

Contents returns a file's contents. It first lazy-loads the file into field [TypedRaw] IFF

  • it IS a file, and
  • it has not been read in yet

and then it

  • calculates & stores file file's hash, and
  • quickly checks for XML and HTML5 declarations

Contents should always be fresh, even when files are active, so we first fetch a new os.FileInfo to check for changes. If no changes are indicated, and the content has not been changed programmatically (check flag [ContentIsDirty]), do a fast return.

It is tolerant about non-files, non-existent objects, and empty files, returning nil error.

NOTE The call to os.Open defaults to R/W mode, even tho R/O might often suffice. .

func (*FSObject) Debug

func (p *FSObject) Debug() string

Debug implements [Stringser].

func (*FSObject) Echo

func (p *FSObject) Echo() string

Echo implements [Stringser].

func (*FSObject) FSObjectType

func (p *FSObject) FSObjectType() FSO_type

FSObjectType examines the embedded os.FileInfo to return a value in the set of FSO_type_*

func (p *FSObject) HasMultiHardlinks() bool

func (*FSObject) Info

func (p *FSObject) Info() (fs.FileInfo, error)

func (*FSObject) Infos

func (p *FSObject) Infos() string

Infos implements [Stringser].

func (*FSObject) IsDir

func (p *FSObject) IsDir() bool

func (*FSObject) IsDirlike

func (p *FSObject) IsDirlike() bool

IsDirlike is, well, documented elsewhere.

func (*FSObject) IsEmpty

func (p *FSObject) IsEmpty() bool

func (*FSObject) IsFile

func (p *FSObject) IsFile() bool

IsFile is a convenience function.

func (p *FSObject) IsSymlink() bool

func (*FSObject) ListingString

func (p *FSObject) ListingString() string

ListingString prints: rwx,rwx,rwx [or not exist] ... Rawtype (file)Len Name Error? \n

func (*FSObject) ModTime

func (p *FSObject) ModTime() time.Time

func (*FSObject) NewLinesFile

func (pPI *FSObject) NewLinesFile() (*LinesFile, error)

NewLinesFile is pretty self-explanatory.

func (p *FSObject) ResolveSymlinks() *FSObject

ResolveSymlinks will follow links until it finds something else. NOTE that this can be a SECURITY HOLE.

func (*FSObject) String

func (p *FSObject) String() (s string)

func (*FSObject) StringWithPermissions

func (p *FSObject) StringWithPermissions() (s string)

func (*FSObject) Type

func (p *FSObject) Type() fs.FileMode

Type implements fs.DirEntry by returning the fs.FileMode.

type FSObjectSummaryStats

type FSObjectSummaryStats struct {
	NrItems, NrDirs, NrFiles, NrSymLs, NrMiscs, NrErrors int
}

FSObjectSummaryStats is so that NrItems equals the sum of NrDirs + NrFiles + NrSymLs + NrMiscs; NrErrors is independent.

type FileLine

type FileLine struct {
	CT.Raw        // string
	RawLineNr int // source file line number
	// contains filtered or unexported fields
}

FileLine is a record (i.e. a line) in a LinesFile.

type Filepaths

type Filepaths struct {
	// RelFP is tipicly the path given (e.g.) on the command line, and is
	// useful for resolving relative paths in batches of content items.
	// The value might be valid only for the current CLI invocation or
	// user session, but it is persistable to preserve relationships
	// among files in import batches.
	RelFP string
	// AbsFP is the authoritative field when processing individual files.
	AbsFP string
	// Errer helps sometimes.
	Errer
	// GotAbs (from [path/filepath/IsAbs]) describes field [creatPath]
	// and says that this struct was created using an absolute FP, not
	// a relative FP, and so the field [RelFP] is calculated.
	GotAbs bool

	// DoesNotExist is made very visible. If a path does not
	// exist, then as noted in func `newFilepaths`,
	//  - the error (a `*PathError`) is put in field `Errer`
	//  - the field `DoesNotExist` is set to `true`
	//  - no other fields in the struct are set, including paths
	DoesNotExist bool
	IsDir        bool
	IsFile       bool
	IsSymlink    bool
	IsDirlike    bool // dir or symlink
	// Local (from func [path/filepath/IsLocal]) means OK;
	// not-Local might flag the possibility of a security hole.
	IsLocal bool
	// Valid (from func [path/filepath/ValidPath]) fails for
	// absolute paths, but can be set to `true` for them.
	IsValid bool
	// ShortFP is the path shortened by using "." (CWD) or "~" (user's
	// home directory), so it might only be valid for the current CLI
	// invocation or user session and it is def not persistable.
	ShortFP string
	// ContentInMemoryIsDirty signifies that a program has updated
	// the content but that it has not been written out to disk.
	ContentInMemoryIsDirty bool
	// contains filtered or unexported fields
}

Filepath embads Errer and containd three paths, and tipicly all three are set, even if the third([ShortFP]) is normally session-specific. Note that directories SHOULD always have a slash (or OS sep) appended, and that symlinks never should.

Important assumptions to bear in mind:

  • If the input path is absolute, the relative path is calculated (and maybe unreliable).
  • If the input path is relative, the absolute path is gotten from the stdlib, which assumes relative to the CWD.

It should execute fairly quickly, because it probably only needs to read the inode, not any disk sectors containing content.

Input from os.Stdin will probably normally use a local file to capture and store the input, and such a file needs special handling.

Note that the file name (aka [FP.Base], the part of the full path after the last directory separator) is not stored separately: it is stored in both AbsFP and RelFP.

The truth values of fields `IsExist` and `IsDir` are subject to change by the actions of a caller, so it is up to the caller to use and maintain the fields properly. .

func GetRootPaths

func GetRootPaths(path string) (rt *os.Root, fp *Filepaths, e error)

GetRootPaths is a convenience function. An error is a *PathError.

func NewFilepaths

func NewFilepaths(anFP string) *Filepaths

NewFilepaths turns a filesystem path into a struct with abs & rel paths, and flags for existence, isaDirectory, isDirlike, isaFile, isaSymlink. It relies on the std lib, and accepts either an absolute or a relative filepath. It does not, however, accept an empty filepath. It probably accepts ".".

NOTE that if the path does NOT exist then this func returns AN ERROR but it DOES provide precise info:

  • it sets field [DoesNotExist] AND
  • it puts the error fs.ErrNotExist in field Errer
  • other errors that might be returned are for files & dirs that DO exist, and they are distinguished by
  • [DoesNotExist] remains `false` (its zero value) AND
  • the field Errer is NOT fs.ErrNotExist

Therefore a caller that doesn't necessarily expect anything to be existing yet - at its target filepath - forcing an item to be created - should be ready to check that for an error return, the flag field `DoesNoExist` is set, and then correctly handle (and comprehend) the error.

NOTE that if HasError(),

  • the error (a `*PathError`) is put in field `Errer`
  • no other fields in the struct are set, including paths

Possible errors: input filepath is...

It takes care to remove a trailing slash (or OS sep) before calling functions in path/filepath, so that symlinks are not unintentionally followed.

NOTE that some of the stdlib funcs called here (`Valid`, `IsLocal`) reject absolute filepaths, so it's probably better to call this with a relative filepath when possible.

Ref: type PathError struct { Op string; Path string; Err error } .

func (*Filepaths) CreatPath

func (p *Filepaths) CreatPath() string

CreatPath is the path (whether abs or rel) used to create it. It is "" if the item wasn't/isn't on disk.

func (*Filepaths) EnsurePathSepSuffixes

func (p *Filepaths) EnsurePathSepSuffixes()

func (*Filepaths) OrigPath

func (p *Filepaths) OrigPath() string

func (*Filepaths) String

func (p *Filepaths) String() string

func (*Filepaths) TrimPathSepSuffixes

func (p *Filepaths) TrimPathSepSuffixes()

type LinesFile

type LinesFile struct {
	*FSObject
	Lines []*FileLine
}

LinesFile is for reading a file where each line is a record.

type ValidUTF8Reader

type ValidUTF8Reader struct {
	// contains filtered or unexported fields
}

ValidUTF8Reader implements a Reader which reads only bytes that constitute valid UTF-8.

func NewValidUTF8Reader

func NewValidUTF8Reader(rd io.Reader) ValidUTF8Reader

NewValidUTF8Reader constructs a new `ValidUTF8Reader` that wraps an existing `io.Reader`.

func (ValidUTF8Reader) Read

func (rd ValidUTF8Reader) Read(b []byte) (n int, err error)

Read reads bytes into the byte array passed in. It returns `n`, the number of bytes read.

Directories

Path Synopsis
cmd
dirtree command
pathcheck command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL