mirror of
https://github.com/novoid/appendfilename.git
synced 2026-02-16 12:54:15 +00:00
When renaming a symlink, its source file with matching name is renamed as well
This commit is contained in:
parent
95a22cf2a5
commit
4e40543e44
2 changed files with 150 additions and 4 deletions
50
README.org
50
README.org
|
|
@ -1,4 +1,4 @@
|
|||
## Time-stamp: <2016-09-11 17:43:41 vk>
|
||||
## Time-stamp: <2017-08-29 17:55:01 vk>
|
||||
## -*- coding: utf-8 -*-
|
||||
## This file is best viewed with GNU Emacs Org-mode: http://orgmode.org/
|
||||
|
||||
|
|
@ -71,6 +71,54 @@ For a complete list of parameters, please try:
|
|||
The file names within the current working directory is read in and all
|
||||
found words can be completed via TAB.
|
||||
|
||||
-----------------------
|
||||
|
||||
#+BEGIN_SRC sh :results output :wrap src
|
||||
./appendfilename.py --help
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_src
|
||||
Usage:
|
||||
./appendfilename.py [<options>] <list of files>
|
||||
|
||||
This tool inserts text between the old file name and optional tags or file extension.
|
||||
|
||||
|
||||
Text within file names is placed between the actual file name and
|
||||
the file extension or (if found) between the actual file namd and
|
||||
a set of tags separated with " -- ".
|
||||
Update for the Boss <NEW TEXT HERE>.pptx
|
||||
2013-05-16T15.31.42 Error message <NEW TEXT HERE> -- screenshot projectB.png
|
||||
|
||||
When renaming a symbolic link whose source file has a matching file
|
||||
name, the source file gets renamed as well.
|
||||
|
||||
Example usages:
|
||||
./appendfilename.py --text="of projectA" "the presentation.pptx"
|
||||
... results in "the presentation of projectA.pptx"
|
||||
./appendfilename.py "2013-05-09T16.17_img_00042 -- fun.jpeg"
|
||||
... with interactive input of "Peter" results in:
|
||||
"2013-05-09T16.17_img_00042 Peter -- fun.jpeg"
|
||||
|
||||
|
||||
:copyright: (c) 2013 or later by Karl Voit <tools@Karl-Voit.at>
|
||||
:license: GPL v3 or any later version
|
||||
:URL: https://github.com/novoid/filetag
|
||||
:bugreports: via github or <tools@Karl-Voit.at>
|
||||
:version: 2017-08-29
|
||||
|
||||
|
||||
Options:
|
||||
-h, --help show this help message and exit
|
||||
-t TEXT, --text=TEXT the text to add to the file name
|
||||
-s, --dryrun enable dryrun mode: just simulate what would happen,
|
||||
do not modify file(s)
|
||||
-v, --verbose enable verbose mode
|
||||
-q, --quiet enable quiet mode
|
||||
--version display version and exit
|
||||
#+END_src
|
||||
|
||||
|
||||
** Installation
|
||||
|
||||
Get it from [[https://github.com/novoid/appendfilename][GitHub]] or install it via «pip install appendfilename».
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
PROG_VERSION = u"Time-stamp: <2017-08-29 14:42:43 vk>"
|
||||
PROG_VERSION = u"Time-stamp: <2017-08-29 17:54:10 vk>"
|
||||
|
||||
# TODO:
|
||||
# * fix parts marked with «FIXXME»
|
||||
|
|
@ -25,6 +25,7 @@ INVOCATION_TIME = time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime())
|
|||
FILENAME_TAG_SEPARATOR = ' -- ' # between file name and (optional) list of tags
|
||||
BETWEEN_TAG_SEPARATOR = ' ' # between tags (not that relevant in this tool)
|
||||
TEXT_SEPARATOR = ' ' # between old file name and inserted text
|
||||
RENAME_SYMLINK_ORIGINALS_WHEN_RENAMING_SYMLINKS = True # if current file is a symlink with the same name, also rename source file
|
||||
|
||||
USAGE = "\n\
|
||||
" + sys.argv[0] + " [<options>] <list of files>\n\
|
||||
|
|
@ -39,6 +40,9 @@ a set of tags separated with \"" + FILENAME_TAG_SEPARATOR + "\".\n\
|
|||
2013-05-16T15.31.42 Error message" + TEXT_SEPARATOR + "<NEW TEXT HERE>" \
|
||||
+ FILENAME_TAG_SEPARATOR + "screenshot" + BETWEEN_TAG_SEPARATOR + "projectB.png\n\
|
||||
\n\
|
||||
When renaming a symbolic link whose source file has a matching file\n\
|
||||
name, the source file gets renamed as well.\n\
|
||||
\n\
|
||||
Example usages:\n\
|
||||
" + sys.argv[0] + " --text=\"of projectA\" \"the presentation.pptx\"\n\
|
||||
... results in \"the presentation" + TEXT_SEPARATOR + "of projectA.pptx\"\n\
|
||||
|
|
@ -173,12 +177,97 @@ def locate_and_parse_controlled_vocabulary():
|
|||
return False
|
||||
|
||||
|
||||
def is_broken_link(name):
|
||||
"""
|
||||
This function determines if the given name points to a file that is a broken link.
|
||||
It returns False for any other cases such as non existing files and so forth.
|
||||
|
||||
@param name: an unicode string containing a file name
|
||||
@param return: boolean
|
||||
"""
|
||||
|
||||
if os.path.isfile(name):
|
||||
return False
|
||||
|
||||
try:
|
||||
return not os.path.exists(os.readlink(name))
|
||||
except FileNotFoundError:
|
||||
return False
|
||||
|
||||
|
||||
def is_nonbroken_symlink_file(filename):
|
||||
"""
|
||||
Returns true if the filename is a non-broken symbolic link and not just an ordinary file. False, for any other case like no file at all.
|
||||
|
||||
@param filename: an unicode string containing a file name
|
||||
@param return: bookean
|
||||
"""
|
||||
|
||||
if os.path.isfile(filename):
|
||||
if os.path.islink(filename):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def get_link_source_file(filename):
|
||||
"""
|
||||
Return a string representing the path to which the symbolic link points.
|
||||
|
||||
@param filename: an unicode string containing a file name
|
||||
@param return: file path string
|
||||
"""
|
||||
|
||||
assert(os.path.islink(filename))
|
||||
return os.readlink(filename)
|
||||
|
||||
|
||||
def handle_file_and_symlink_source_if_found(filename, text, dryrun):
|
||||
"""
|
||||
Wraps handle_file() so that if the current filename is a symbolic link,
|
||||
modify the source file and re-link its new name before handling the
|
||||
current filename.
|
||||
|
||||
@param filename: string containing one file name
|
||||
@param text: string that shall be added to file name(s)
|
||||
@param dryrun: boolean which defines if files should be changed (False) or not (True)
|
||||
@param return: error value or new filename
|
||||
"""
|
||||
|
||||
# if filename is a symbolic link and has same basename, tag the source file as well:
|
||||
if RENAME_SYMLINK_ORIGINALS_WHEN_RENAMING_SYMLINKS and is_nonbroken_symlink_file(filename):
|
||||
old_sourcefilename = get_link_source_file(filename)
|
||||
|
||||
if os.path.basename(old_sourcefilename) == os.path.basename(filename):
|
||||
|
||||
new_sourcefilename = handle_file(old_sourcefilename, text, dryrun)
|
||||
if old_sourcefilename != new_sourcefilename:
|
||||
logging.info('Renaming the symlink-destination file of "' + filename + '" ("' +
|
||||
old_sourcefilename + '") as well …')
|
||||
if options.dryrun:
|
||||
logging.debug('I would re-link the old sourcefilename "' + old_sourcefilename +
|
||||
'" to the new one "' + new_sourcefilename + '"')
|
||||
else:
|
||||
logging.debug('re-linking symlink "' + filename + '" from the old sourcefilename "' +
|
||||
old_sourcefilename + '" to the new one "' + new_sourcefilename + '"')
|
||||
os.remove(filename)
|
||||
os.symlink(new_sourcefilename, filename)
|
||||
else:
|
||||
logging.debug('The old sourcefilename "' + old_sourcefilename + '" did not change. So therefore I don\'t re-link.')
|
||||
else:
|
||||
logging.debug('The file "' + os.path.basename(filename) + '" is a symlink to "' + old_sourcefilename +
|
||||
'" but they two do have different basenames. Therefore I ignore the original file.')
|
||||
|
||||
# after handling potential symlink originals, I now handle the file we were talking about in the first place:
|
||||
return handle_file(filename, text, dryrun)
|
||||
|
||||
|
||||
def handle_file(filename, text, dryrun):
|
||||
"""
|
||||
@param filename: one file name
|
||||
@param text: string that shall be added to file name(s)
|
||||
@param dryrun: boolean which defines if files should be changed (False) or not (True)
|
||||
@param return: error value
|
||||
@param return: error value or new filename
|
||||
"""
|
||||
|
||||
assert(isinstance(filename, str))
|
||||
|
|
@ -216,6 +305,8 @@ def handle_file(filename, text, dryrun):
|
|||
except:
|
||||
error_exit(9, "Error while trying to rename file: " + str(sys.exc_info()))
|
||||
|
||||
return new_filename
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function"""
|
||||
|
|
@ -272,7 +363,14 @@ def main():
|
|||
|
||||
logging.debug("iterate over files ...")
|
||||
for filename in files:
|
||||
handle_file(filename, text, options.dryrun)
|
||||
|
||||
if is_broken_link(filename):
|
||||
# skip broken links completely and write error message:
|
||||
logging.error('File "' + filename + '" is a broken symbolic link. Skipping this one …')
|
||||
|
||||
else:
|
||||
# if filename is a symbolic link, tag the source file as well:
|
||||
handle_file_and_symlink_source_if_found(filename, text, options.dryrun)
|
||||
|
||||
logging.debug("successfully finished.")
|
||||
if options.verbose:
|
||||
|
|
|
|||
Loading…
Reference in a new issue