Skip to content

jeftadlvw/go-pathlib

Repository files navigation

Artwork for go-pathlib.

go-pathlib

A simple one-file library for handling filesystem paths. Utilizing Golang's path/filepath, inspired by Python's pathlib API. It abstracts the standard library by providing a simple immutable struct that acts as a source of truth for file paths.

This library is developed and tested on Unix-based operating systems. Windows should work (in theory), please open an issue if you face any problems.

Minimum tested Go version: 1.18

Getting started 🚀

go get github.com/jeftadlvw/go-pathlib@latest
package main

import (
	"fmt"
	"github.com/jeftadlvw/go-pathlib"
)

func main() {
	p := pathlib.NewPath("path/to/your/destination")
	fmt.Println(p)
}

Features ✨

  • represent file paths as an own struct type with minimal memory overhead
  • many functions for handling file paths
  • implements encoder.TextMarshaler and encoder.TextUnmashaler, enabling automatic integration into first- and third-party parsing libraries (for e.g. text or JSON)

API Documentation 📝

Repository-local documentation can be found at docs/go-pathlib.md. It's auto-generated by gomarkdoc using the docstrings in the source code.

The file is updated regularly and gives a good general overview on the API. Up-to-date documentation can be found in the source code.

Roadmap 📋

Although the core API exists, I'd like to test the look and feel of this library in some other projects before committing to a major release.

🔖 Current version: 0.0.2

The following features are planned and fixed on the roadmap. They extend the API and improve the integration into other ecosystems. Because go-pathlib should stay a single-file library, new features are categorized into optional extensions.

0.0.3

The APIs are nearly complete but still need testing.

  • pathlib_fs.go: filesystem operations (create, move, delete or rename files and directories, get stats, filesystem-level equality check, ...)
  • pathlib_io.go: open files, read, write
  • pathlib_temp.go: API for temporary files and directories

0.0.3 also adds support for Windows-style path strings, which still needs testing for every core function.

Future

  • recursive globbing using double asterisks (stable and tested without using external dependencies)
  • extend globbing to not include directories
  • implement "range over function" for globbing (requires newer go versions)
  • function to check if a file is (semantically) hidden
  • fully tested Windows path support

Planned extensions

  • integration into go-validator (custom field types and validators)

This is a non-exhaustive list. Feel free to suggest other features and integrations!

Intended usage and gotcha's 🌚

Posix vs. Windows path representation

Posix first, Windows derived.

The default constructor NewPath() assumes a Posix path. If you know that your path string is a Windows path representation, use NewPathFromWindows(). This constructor ensures correct handling of existing volume names or UNC-path roots.

Windows paths are transformed to Posix (including some encoding) and transformed back if needed (like String() on Windows runtimes).

\ on Posix vs \ on Windows

Backslashes (\) are allowed in regular Posix path part names, but are seen as path separators in Windows paths. Thus, a path string containing a backslash is interpreted differently on different operating systems. This is a problem if a filepath with backslashes is persisted using Posix and read/used on Windows.

There is really nothing to prevent this behavior, which is why this library prints a warning to stderr if a Posix path string contains a backslash. You can disable these warnings by setting pathlib.PrintBackslashWarningOnPosix to false.

Persisting file paths

When persisting file paths in e.g. configuration files or a database, use lowercase paths and use the posix representation for maximum portability. Also persist a path relative to some base path, and resolve the absolute path at runtime.

Enforce that the start and end of a path are clearly defined to escape whitespace usage. If you store paths in a database, then the path is naturally constrained by the database field. But when persisted in e.g. a configuration file, enclose the path with e.g. quotation marks: "path/to/foo.bar".

Path equality and case sensitivity

Don't assume the underlying filesystem is case-insensitive. This is the case for Windows and MacOS, but not for e.g. Linux.

Whether you design the paths in your application to be case-sensitive or not is your decision. But keep in mind that case sensitivity also comes with path ambiguity (e.g.: should file.txt and FILE.txt be treated equally?).

Although we recommend handling paths in a case-insensitive manner, we respect stricter designs and follow the principle of being strict by default while allowing flexibility explicitly. We provide several functions to check for path equality:

  • Equals: default, lexical, case-sensitive
  • EqualsFlat: lexical, case-insensitive
  • EqualsFs: filesystem equality (only in pathlib_fs.go)

Contributing 👥

Feel free to open issues and pull requests. Any help or feedback is highly appreciated!

Attributions 🖊️

See NOTICE.md for a complete list of used third party projects and source code.

The displayed Gopher in the artwork is licensed under the Creative Commons 4.0 Attribution License as per https://go.dev/brand#logo (last seen: 30-09-2024). This project's artwork falls under the same licence.

About

A simple one-file library for handling filesystem paths. Utilizing Golang's stdlib, inspired by Python's pathlib.

Topics

Resources

License

Stars

Watchers

Forks