Created
June 16, 2016 09:02
-
-
Save hartwork/274eefd7cdb0eafb4fbafd262f1cf4d1 to your computer and use it in GitHub Desktop.
Small tool to do poor-man's logrotate and update a "latest" symlink
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env python2 | |
# Copyright (C) 2016 Sebastian Pipping <[email protected]> | |
# Licensed under AGPL v3 or later | |
from __future__ import print_function | |
import argparse | |
import errno | |
import os | |
import re | |
import sys | |
import stat | |
def _try_int(text): | |
try: | |
return int(text) | |
except ValueError: | |
return text | |
def natural(key): | |
return [_try_int(m.group(0)) for m in re.finditer('[0-9]+|[^0-9]+', key)] | |
def good_ones(sorted_files, symlink): | |
for i, filename in enumerate(sorted_files): | |
if filename == symlink: | |
continue | |
try: | |
st = os.lstat(filename) | |
except OSError: | |
continue | |
else: | |
if stat.S_ISLNK(st.st_mode): | |
continue | |
if st.st_size == 0 and i != len(sorted_files) - 1: | |
continue | |
yield filename | |
def clean_all_but(keep_count, sorted_files, verbose): | |
assert keep_count >= 0 | |
keeping = sorted_files[-keep_count:] | |
if verbose: | |
for filename in keeping: | |
print('Kept "%s".' % filename) | |
deleting = sorted_files[:-keep_count] | |
for filename in deleting: | |
if verbose: | |
print('Removing "%s"...' % filename) | |
os.remove(filename) | |
return (keeping, deleting) | |
def rewrite_symlink(filename, content, verbose): | |
if verbose: | |
print('Making "%s" point to "%s"...' % (filename, content)) | |
try: | |
st = os.lstat(filename) | |
except OSError as e: | |
if e.errno != errno.ENOENT: | |
raise | |
else: | |
if not stat.S_ISLNK(st.st_mode): | |
raise OSError(errno.ENOLINK, 'Not a link: "%s"' % filename) | |
os.remove(filename) | |
os.symlink(content, filename) | |
def main(options): | |
if not options.files: | |
return | |
try: | |
if not stat.S_ISLNK(os.lstat(options.symlink).st_mode): | |
return | |
except OSError as e: | |
if e.errno != errno.ENOENT: | |
raise | |
(kept, _) = clean_all_but( | |
options.keep_count, | |
list(good_ones(sorted(options.files, key=natural), options.symlink)), | |
options.verbose) | |
if kept: | |
rewrite_symlink(options.symlink, kept[-1], options.verbose) | |
if __name__ == '__main__': | |
parser = argparse.ArgumentParser() | |
parser.add_argument('--verbose', '-v', default=False, action='store_true') | |
parser.add_argument('keep_count', type=int, metavar='COUNT', | |
help='number of files to keep') | |
parser.add_argument('symlink', metavar='SYMLINK', | |
help='path of symlink to re-wire') | |
parser.add_argument('files', nargs='*', metavar='FILE', | |
help='file to remove potentially') | |
options = parser.parse_args() | |
sys.exit(main(options)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment