Skip to content

Instantly share code, notes, and snippets.

@wecsam
Last active May 14, 2024 19:41
Show Gist options
  • Save wecsam/74aeb122cd3deea3d45ab7c5fad38995 to your computer and use it in GitHub Desktop.
Save wecsam/74aeb122cd3deea3d45ab7c5fad38995 to your computer and use it in GitHub Desktop.
Wait for free space when moving files
#!/usr/bin/env python3
import argparse
import datetime
import humanfriendly # pip install humanfriendly
import os
import shutil
import subprocess
import sys
import time
def print_with_time(*args, **kwargs):
print(datetime.datetime.now(), "-", *args, **kwargs)
def size(s):
try: return humanfriendly.parse_size(s)
except humanfriendly.InvalidSize: raise ValueError
def wait_for_free_space(dst, minimum_free):
while True:
if (free := shutil.disk_usage(dst).free) >= minimum_free: # PEP 572 requires Python 3.8 or later.
break
print_with_time(
"Waiting for free space (available: {}, required: {})...".format(
humanfriendly.format_size(free, binary=True),
humanfriendly.format_size(minimum_free, binary=True)
)
)
# Wait 5 minutes, but try to land on the top of the minute.
time.sleep(300.0 - time.time() % 60.0)
def move_one_file(src, dst, minimum_free):
wait_for_free_space(dst, minimum_free)
print_with_time(src, "->", end=" ")
sys.stdout.flush()
try:
dst = shutil.move(src, dst)
except (OSError, shutil.Error) as e:
print("error:", e)
return
else:
print(dst)
# Free the space up after uploading to OneDrive.
subprocess.run([r"C:\Windows\System32\attrib.exe", "-P", "+U", dst])
def move_tree(src, dst, minimum_free):
for dirpath, dirnames, filenames in os.walk(src):
dst_subdir = os.path.normpath(os.path.join(dst, os.path.relpath(dirpath, src)))
os.makedirs(dst_subdir, exist_ok=True)
for filename in filenames:
move_one_file(os.path.join(dirpath, filename), dst_subdir, minimum_free)
def main():
parser = argparse.ArgumentParser(
description=
"This tool moves a file or recursively moves a directory of files. "
"Before moving each file, it waits for the destination disk to have the specified amount of free space. "
"After moving each file, it sets its attributes so that OneDrive Files on Demand will free its space up."
)
parser.add_argument("src", help="the file to move or the directory from which to move files")
parser.add_argument("dst", help="the directory to which to move files")
parser.add_argument(
"-f", "--free",
type=size,
default="8 GiB",
metavar="size",
dest="minimum_free",
help="the amount of space to leave free on the destination disk (default: %(default)s)"
)
args = parser.parse_args()
if os.path.isdir(args.src):
if not os.path.isdir(args.dst):
parser.error("If the source is a directory, the destination must be a directory.")
move = move_tree
else:
move = move_one_file
try:
move(**vars(args))
except KeyboardInterrupt:
print_with_time("^C", file=sys.stderr)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment