Skip to content

Instantly share code, notes, and snippets.

@hartwork
Created June 16, 2016 09:02
Show Gist options
  • Save hartwork/274eefd7cdb0eafb4fbafd262f1cf4d1 to your computer and use it in GitHub Desktop.
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
#! /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