mirror of
https://github.com/nikdoof/dotfiles.git
synced 2026-01-30 10:58:14 +00:00
Improve stowage
This commit is contained in:
@@ -1,9 +1,13 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
stowage
|
originally stowage, by Keith Gaughan <https://github.com/kgaughan/>
|
||||||
by Keith Gaughan <https://github.com/kgaughan/>
|
modified by Andrew Williams <https://github.com/nikdoof/>
|
||||||
Stow, but in Python, and in a single file.
|
|
||||||
|
A dotfile package manager
|
||||||
|
|
||||||
Copyright (c) Keith Gaughan, 2017.
|
Copyright (c) Keith Gaughan, 2017.
|
||||||
|
Copyright (c) Andrew Williams, 2021.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
the Software without restriction, including without limitation the rights to
|
the Software without restriction, including without limitation the rights to
|
||||||
@@ -32,8 +36,8 @@ import sys
|
|||||||
|
|
||||||
def add(args):
|
def add(args):
|
||||||
target = path.realpath(args.target)
|
target = path.realpath(args.target)
|
||||||
file_path = path.realpath(args.add)
|
file_path = path.realpath(args.file)
|
||||||
package = path.realpath(args.packages[0])
|
package = path.realpath(os.path.join(args.repository, args.packages[0]))
|
||||||
if path.commonprefix([target, file_path]) != target:
|
if path.commonprefix([target, file_path]) != target:
|
||||||
print(f"error: '{args.add}' not under '{args.target}'",
|
print(f"error: '{args.add}' not under '{args.target}'",
|
||||||
file=sys.stderr)
|
file=sys.stderr)
|
||||||
@@ -55,15 +59,16 @@ def add(args):
|
|||||||
|
|
||||||
def install(args, is_excluded):
|
def install(args, is_excluded):
|
||||||
for package in args.packages:
|
for package in args.packages:
|
||||||
if not path.isdir(package):
|
package_dir = os.path.join(args.repository, package)
|
||||||
|
if not path.isdir(package_dir):
|
||||||
print(f"no such package: {package}; skipping", file=sys.stderr)
|
print(f"no such package: {package}; skipping", file=sys.stderr)
|
||||||
continue
|
continue
|
||||||
for root, _, files in os.walk(package, followlinks=True):
|
for root, _, files in os.walk(package_dir, followlinks=True):
|
||||||
files = [
|
files = [
|
||||||
filename for filename in files if not is_excluded(filename)]
|
filename for filename in files if not is_excluded(filename)]
|
||||||
if len(files) == 0:
|
if len(files) == 0:
|
||||||
continue
|
continue
|
||||||
rest = root[len(package) + 1:]
|
rest = root[len(package_dir) + 1:]
|
||||||
dest = path.join(args.target, rest)
|
dest = path.join(args.target, rest)
|
||||||
if rest != "":
|
if rest != "":
|
||||||
if args.verbose:
|
if args.verbose:
|
||||||
@@ -90,15 +95,16 @@ def install(args, is_excluded):
|
|||||||
def uninstall(args, is_excluded):
|
def uninstall(args, is_excluded):
|
||||||
dirs = []
|
dirs = []
|
||||||
for package in args.packages:
|
for package in args.packages:
|
||||||
if not path.isdir(package):
|
package_dir = os.path.join(args.repository, package)
|
||||||
|
if not path.isdir(package_dir):
|
||||||
print(f"no such package: {package}; skipping", file=sys.stderr)
|
print(f"no such package: {package}; skipping", file=sys.stderr)
|
||||||
continue
|
continue
|
||||||
for root, _, files in os.walk(package, followlinks=True):
|
for root, _, files in os.walk(package_dir, followlinks=True):
|
||||||
files = [
|
files = [
|
||||||
filename for filename in files if not is_excluded(filename)]
|
filename for filename in files if not is_excluded(filename)]
|
||||||
if len(files) == 0:
|
if len(files) == 0:
|
||||||
continue
|
continue
|
||||||
rest = root[len(package) + 1:]
|
rest = root[len(package_dir) + 1:]
|
||||||
dest = path.join(args.target, rest)
|
dest = path.join(args.target, rest)
|
||||||
if rest != "":
|
if rest != "":
|
||||||
dirs.append(dest)
|
dirs.append(dest)
|
||||||
@@ -128,15 +134,23 @@ def uninstall(args, is_excluded):
|
|||||||
|
|
||||||
|
|
||||||
def make_argparser():
|
def make_argparser():
|
||||||
parser = argparse.ArgumentParser(description="A symlink farm manager.")
|
parser = argparse.ArgumentParser(description="A dotfile package manager.")
|
||||||
parser.add_argument("--verbose", "-v",
|
parser.add_argument("--verbose", "-v",
|
||||||
action="store_true", help="Verbose output")
|
action="store_true", help="Verbose output")
|
||||||
|
parser.add_argument("--dry-run", "-n",
|
||||||
|
action="store_true", help="Dry run.")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--target",
|
"--target",
|
||||||
"-t",
|
"-t",
|
||||||
default=os.path.expanduser('~'),
|
default=os.path.expanduser('~'),
|
||||||
help="Target directory in which to place symlinks",
|
help="Target directory in which to place symlinks",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--repository",
|
||||||
|
"-r",
|
||||||
|
default=os.path.expanduser('~/.dotfiles'),
|
||||||
|
help="The location of the dotfile repository",
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--exclude",
|
"--exclude",
|
||||||
"-x",
|
"-x",
|
||||||
@@ -145,46 +159,60 @@ def make_argparser():
|
|||||||
metavar="GLOB",
|
metavar="GLOB",
|
||||||
help="Glob pattern of files to exclude",
|
help="Glob pattern of files to exclude",
|
||||||
)
|
)
|
||||||
parser.add_argument("--dry-run", "-n",
|
|
||||||
action="store_true", help="Dry run.")
|
|
||||||
|
|
||||||
group = parser.add_mutually_exclusive_group(required=False)
|
subparsers = parser.add_subparsers(dest='command', help='sub-command help')
|
||||||
group.add_argument(
|
|
||||||
"--uninstall",
|
|
||||||
"-D",
|
|
||||||
action="store_false",
|
|
||||||
dest="install",
|
|
||||||
help="Uninstall symlinks",
|
|
||||||
)
|
|
||||||
group.add_argument(
|
|
||||||
"--add", "-a", metavar="FILE", help="Stow files in a particular package"
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
# List
|
||||||
|
parser_add = subparsers.add_parser('list', help='List packages in the repository')
|
||||||
|
|
||||||
|
# Add
|
||||||
|
parser_add = subparsers.add_parser('add', help='Add a file to a package')
|
||||||
|
parser_add.add_argument(
|
||||||
|
"file", metavar="FILE", help="File to stow"
|
||||||
|
)
|
||||||
|
parser_add.add_argument(
|
||||||
"packages", metavar="PACKAGE", nargs="+", help="Packages to install"
|
"packages", metavar="PACKAGE", nargs="+", help="Packages to install"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Uninstall
|
||||||
|
parser_uninstall = subparsers.add_parser('uninstall', help='Remove a package')
|
||||||
|
parser_uninstall.add_argument(
|
||||||
|
"packages", metavar="PACKAGE", nargs="+", help="Packages to uninstall"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Install
|
||||||
|
parser_install = subparsers.add_parser('install', help='Install packages')
|
||||||
|
parser_install.add_argument(
|
||||||
|
"packages", metavar="PACKAGE", nargs="+", help="Packages to install"
|
||||||
|
)
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = make_argparser()
|
parser = make_argparser()
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
if args.dry_run:
|
||||||
|
args.verbose = True
|
||||||
exclude = [re.compile(fnmatch.translate(pattern))
|
exclude = [re.compile(fnmatch.translate(pattern))
|
||||||
for pattern in args.exclude]
|
for pattern in args.exclude]
|
||||||
|
|
||||||
def is_excluded(filename):
|
def is_excluded(filename):
|
||||||
return any(pattern.match(filename) for pattern in exclude)
|
return any(pattern.match(filename) for pattern in exclude)
|
||||||
|
|
||||||
if args.add:
|
if args.command == 'list':
|
||||||
|
for dir in os.listdir(args.repository):
|
||||||
|
if os.path.isdir(os.path.join(args.repository, dir)) and dir[0] != '.': print(dir)
|
||||||
|
elif args.command == 'add':
|
||||||
if len(args.packages) > 1:
|
if len(args.packages) > 1:
|
||||||
parser.error("--add only works with a single package")
|
parser.error("--add only works with a single package")
|
||||||
args.add = path.normpath(path.join(args.target, args.add))
|
args.file = path.normpath(path.join(args.target, args.file))
|
||||||
if not path.isfile(args.add):
|
if not path.isfile(args.file):
|
||||||
parser.error(f"no such file: {args.add}")
|
parser.error(f"no such file: {args.file}")
|
||||||
add(args)
|
add(args)
|
||||||
elif args.install:
|
elif args.command == 'install':
|
||||||
install(args, is_excluded)
|
install(args, is_excluded)
|
||||||
else:
|
elif args.command == 'uninstall':
|
||||||
uninstall(args, is_excluded)
|
uninstall(args, is_excluded)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
10
bootstrap.sh
10
bootstrap.sh
@@ -10,18 +10,16 @@ fi
|
|||||||
git clone https://github.com/nikdoof/dotfiles.git $HOME/.dotfiles > /dev/null
|
git clone https://github.com/nikdoof/dotfiles.git $HOME/.dotfiles > /dev/null
|
||||||
|
|
||||||
# Clean bash files
|
# Clean bash files
|
||||||
for file in .bash_profile .bashrc .bash_logout; do
|
for file in .bash_profile .bashrc .bash_logout .zshrc; do
|
||||||
if [ -e $file ]; then
|
if [ -e $file ]; then
|
||||||
rm -f $file
|
rm -f $file
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
cd $HOME/.dotfiles/
|
|
||||||
|
|
||||||
# Stow the default packages
|
# Stow the default packages
|
||||||
for package in bin bash; do
|
for package in bin bash zsh; do
|
||||||
echo "Stowing ${package}"
|
echo "Stowing ${package}"
|
||||||
./bin/bin/stowage $package
|
$HOME/.dotfiles/bin/bin/stowage install $package
|
||||||
done
|
done
|
||||||
echo ""
|
echo ""
|
||||||
echo "Done, either source ~/.bash_profile or restart your shell."
|
echo "Done, either source ~/.bash_profile / ~/.zshrc or restart your shell."
|
||||||
Reference in New Issue
Block a user