Skip to content

Instantly share code, notes, and snippets.

@craigpalermo
Last active October 4, 2015 05:36
Show Gist options
  • Save craigpalermo/7ad80bb04bd8b55243b1 to your computer and use it in GitHub Desktop.
Save craigpalermo/7ad80bb04bd8b55243b1 to your computer and use it in GitHub Desktop.
A script that moves all files in current directory that haven't been modified in the desired number of days to a different folder.
from datetime import datetime, timedelta
from sets import Set
import argparse
import sys
import os
import time
import shutil
import re
# BEGIN CONFIGURATION
conf_days=14
conf_destination="./Archive"
conf_ignored_extensions= Set([".key", ".kdbx"])
# END CONFIGURATION
def input_is_valid(days):
"""
Returns True if each function argument provided is valid. If an argument
is invalid, prints description of error and then returns False.
"""
is_valid = True
if days and not (is_integer(days) and days >= 0):
is_valid = False
print("'{}' is not a valid number of days.".format(days))
return is_valid
def calculate_start_date(arg_days):
"""
Returns the result of subtracting the time delta of the given arguments
from the current datetime.
"""
days = arg_days if arg_days else conf_days
result = datetime.now() - timedelta(days=int(days))
return result
def move_files(before_date, preview=False, arg_destination=None):
"""
Attempts to move all files (not folders) in current directory that were
last modified before 'before_date'. Returns the number of files affected.
"""
def log_to_console(action, description):
action = action.capitalize() if action else action
print("{}: {}".format(action, description))
dest = arg_destination if arg_destination else conf_destination
change_count = 0
for filename in os.listdir('.'):
if os.path.isfile(filename) and filename != os.path.basename(__file__):
# get time file was last modified
file_ctime = datetime.fromtimestamp(os.path.getctime(filename))
# get file extension
match = re.search(r".+([.][\w]+)", filename)
if match:
file_extension = match.group(1)
# move file if applicable
if file_ctime < before_date:
dest_path = "{}/".format(os.path.abspath(dest), filename)
try:
description = "{} ({})".format(filename, shorten_date(file_ctime))
if (match and file_extension not in conf_ignored_extensions) or not match:
if preview:
log_to_console("will move:", description)
else:
shutil.move(os.path.abspath(filename), dest_path)
log_to_console("moved", description)
change_count += 1
except shutil.Error as e:
log_to_console("unable to move", description)
return change_count
# helper functions
def is_integer(s):
"""
Returns True if 's' is an integer, and False otherwise.
"""
try:
return (float(s) and float(s) % 1 == 0)
except ValueError:
return False
def shorten_date(date):
"""
Returns date as string formatted like Jan 01, 2015, or empty string
if date given is invalid.
"""
try:
result = date.strftime("%b %d, %Y") if date else ""
except Exception:
result = ""
return result
def main(argv=None):
# parse command line arguments
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument(
'--days',
dest='days',
action='store',
help='max age of files to archive in days'
)
parser.add_argument(
'--preview',
dest='preview',
action='store_true',
help='view list of affected files without actually moving anything'
)
args = parser.parse_args()
# exit if invalid input detected
if not input_is_valid(args.days):
return
# calculate max retention cutoff date
cutoff_date = calculate_start_date(args.days)
print("Archiving files last modified before {}.".format(shorten_date(cutoff_date)))
print("Ignored extensions: {}".format(list(conf_ignored_extensions)))
# move applicable files
affected_count = move_files(cutoff_date, preview=args.preview)
print("Files affected: {}".format(affected_count))
if __name__ == "__main__":
sys.exit(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment