Skip to content

Instantly share code, notes, and snippets.

@taikedz
Last active September 6, 2023 07:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save taikedz/4cda9e4650ad10fe827c1224816e0269 to your computer and use it in GitHub Desktop.
Save taikedz/4cda9e4650ad10fe827c1224816e0269 to your computer and use it in GitHub Desktop.
pathctl

pathctl

A quick and dirty script for loading/appending to PATH

Oftentimes when I write install scripts i have to go looking for a path and its presence to avoid duplication, parsing the .bashrc and .profile scripts .

This is tedious, and prone to issues.

If we could have a basic utility that already took care of this as a default item in the system, it would be handy.

This gist contains one such implementation, in Python 3.

I intend to re-write this in Rust as an excercise, for learning.

The following are the requirements I set out for myself, for reference. If anyone would like to have a go and "standardize" on the excercise, do feel free. It would be neat to get it into a major distro, but I'm not holding my breath.

  • ~/.PATH file contains user's paths, one per line. Lines may be empty. Lines starting with '#' are comments and are to be skipped
  • command may take the argument load to print a path-notation of paths, each separated by colon
  • command may take the arguments add DIR_PATH which will add the path to the end of ~/.PATH
  • command may take the argument version which will print the version string alone
  • any other argument form causes help to be printed, and exits with error code
  • any error should cause print out of error message, without printing stack traces or other debugging noise

In my case, I also check for duplication, though this is not a requirement. I also print the new path notation after adding, again this is not a requirement.

#!/usr/bin/env python3
# LICENSE: "MIT Expat License" (SPDX: MIT-0)
# Do as you wish with this code.
# No warranty or guarantees on suitability, etc.
r"""
Managed paths script
Create an easy target for adding new PATH entries
Install utility:
[[ -f ~/.PATH]] || touch ~/.PATH
# (add custom paths as required to .PATH file)
sudo cp pathctl /usr/local/bin/pathctl
Use in .bashrc:
export PATH="$PATH:$(pathctl load)"
Use in installation scripts:
if [[ -f ~/.PATH ]]; then
pathctl add .../new/path
else
echo "Add '.../new/path' to your \$PATH. Consider using 'pathctl'"
fi
"""
import os
import sys
VERSION="0.0.1"
PATHFILE_PATH = os.path.expanduser("~/.PATH")
def warn(message):
print(f"warn: {message}", file=sys.stderr)
def line_check(line):
if ':' in line:
warn(f"Invalid path: {line}")
return False
if line.strip().startswith("#"):
return False
return True
def load_lines(filepath):
with open(filepath) as fh:
resolved_lines = [L.strip() for L in fh.readlines() if line_check(L)]
return resolved_lines
def append_path(filepath, target):
target = target.strip()
try:
paths = load_lines(PATHFILE_PATH)
except FileNotFoundError:
paths = []
if target in paths:
warn(f"Path already present: {target}")
display_paths(paths)
else:
with open(filepath, 'a') as fh:
fh.write(f"{target}\n")
display_paths([*paths, target])
def display_paths(paths):
print(':'.join(paths))
def main():
if sys.argv[1:] == ['version']:
print(VERSION)
return
elif sys.argv[1:] == ['load']:
display_paths(load_lines(PATHFILE_PATH))
elif len(sys.argv) == 3 and sys.argv[1:2] == ['add']:
append_path(PATHFILE_PATH, sys.argv[2])
else:
raise Exception(f"""Load "~/.PATH" as a `$PATH` string, or append a new path to it
{sys.argv[0]} load
{sys.argv[0]} add DIRECTORY
""")
if __name__ == "__main__":
try:
main()
except Exception as e:
print(e)
exit(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment