parent
b938c60bcf
commit
504dd8ac24
1 changed files with 74 additions and 0 deletions
@ -0,0 +1,74 @@ |
|||||||
|
#!/usr/bin/python |
||||||
|
# (c) 2015 Taeyeon Mori |
||||||
|
# A simple script to make ln -s less painful |
||||||
|
# |
||||||
|
# Because of how symbolic links work (they're just a pathname that the OS reads and follows), |
||||||
|
# the link target path must always be relative to the symlink's containing directory, OR |
||||||
|
# an absolute path altogether. Unfortunately, ln -s does not automatically solve this issue |
||||||
|
# which makes it painful to create a relative symlink somewhere outside the current working |
||||||
|
# directory (It screws up shell completion for instance) |
||||||
|
# This script performs the path transformation before creating the link and can therefore be |
||||||
|
# used without worries of creating broken symlinks because one forgot to apply the correct |
||||||
|
# relative adjustment to the target path |
||||||
|
# |
||||||
|
# ex: |
||||||
|
# $ lns -v some-file dir/some-link |
||||||
|
# ln -s '../some-file' 'dir/some-link' |
||||||
|
# $ lns -v file ../derp/link # inside a directory called 'herp' |
||||||
|
# ln -s '../herp/file' '../derp/link' |
||||||
|
|
||||||
|
|
||||||
|
import os |
||||||
|
import argparse |
||||||
|
|
||||||
|
|
||||||
|
def transport_relpath(path, old_anchor, new_anchor): |
||||||
|
""" |
||||||
|
:brief: Transport a relative path from one anchor to another |
||||||
|
Anchors must both be absolute paths, path must be relative (to old_anchor) |
||||||
|
""" |
||||||
|
return os.path.relpath(os.path.normpath(os.path.join(old_anchor, path)), new_anchor) |
||||||
|
|
||||||
|
|
||||||
|
def verbose_symlink(target, dest): |
||||||
|
print("ln -s '%s' '%s'" % (target, dest)) |
||||||
|
return os.symlink(target, dest) |
||||||
|
|
||||||
|
|
||||||
|
def main(argv): |
||||||
|
# Command line interface to make_symlink() |
||||||
|
parser = argparse.ArgumentParser(prog=argv[0], |
||||||
|
description="A 'ln -s' command that automatically translates relative target paths to be relative to the resulting symlink's containing directory when necessary.") |
||||||
|
parser.add_argument("target", help="The file(s) to create symlink(s) to", nargs="+") |
||||||
|
parser.add_argument("destination", help="The path of the symbolic link(s) to create") |
||||||
|
parser.add_argument("-v", "--verbose", help="Print every operation", |
||||||
|
dest="symlink", const=verbose_symlink, action="store_const", default=os.symlink) |
||||||
|
|
||||||
|
args = parser.parse_args(argv[1:]) |
||||||
|
|
||||||
|
# Multiple |
||||||
|
if len(args.target) > 1: |
||||||
|
if not os.path.isdir(args.destination): |
||||||
|
print("Destination must be an existing directory when multiple targets are passed!") |
||||||
|
for target in args.target: |
||||||
|
dest = os.path.join(args.destination, os.path.basename(target)) |
||||||
|
args.symlink(target if os.path.isabs(target) else transport_relpath(target, os.curdir, args.destination), dest) |
||||||
|
|
||||||
|
# One |
||||||
|
else: |
||||||
|
target = args.target[0] |
||||||
|
|
||||||
|
dest = ldir = args.destination |
||||||
|
if os.path.isdir(dest): |
||||||
|
dest = os.path.join(dest, os.path.basename(target)) |
||||||
|
else: |
||||||
|
ldir = os.path.dirname(dest) |
||||||
|
|
||||||
|
args.symlink(target if os.path.isabs(target) else transport_relpath(target, os.curdir, ldir), dest) |
||||||
|
|
||||||
|
return 0 |
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__": |
||||||
|
import sys |
||||||
|
sys.exit(main(sys.argv)) |
Loading…
Reference in new issue