Skip to content

Instantly share code, notes, and snippets.

@mcclure
Last active December 24, 2023 23:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mcclure/28144d14a2b0ef674ab5590ec76b6bd5 to your computer and use it in GitHub Desktop.
Save mcclure/28144d14a2b0ef674ab5590ec76b6bd5 to your computer and use it in GitHub Desktop.
import click
import os
import os.path
import pathlib as purepath
import shutil
@click.command(help="Clone the json files *only* out of a directory tree")
@click.argument('indir', type=click.STRING)
@click.argument('outdir', type=click.STRING)
@click.option('-X', '--exclude', type=click.STRING, help="Skip this file/directory", multiple=True)
@click.option('--extension', type=click.STRING, help="Use this extension instead of .json", default="json")
def json_backup(indir, outdir, exclude, extension):
if not os.path.isdir(indir):
raise click.ClickException(f"Input directory not a directory: '{indir}'")
os.mkdir(outdir)
exclude = [purepath.Path(x).resolve() for x in exclude]
# Fixup if outdir is inside indir and not excluded
outpath = purepath.Path(outdir).resolve()
if outpath.is_relative_to(purepath.Path(indir).resolve()):
exclude.append(outpath)
for root, dirs, files in os.walk(indir, topdown=True):
#print("VISIT", root)
excluded = False
for path in exclude:
if purepath.Path(root).resolve().is_relative_to(path):
#print("HIT EXCLUDE", path, root)
dirs.clear() # Do not descend
excluded = True
break
if not excluded:
newroot = None
for file in files:
if file.endswith(extension):
path = os.path.join(root, file)
if not newroot:
try:
newroot = os.path.join(outdir, root)
purepath.Path(newroot).mkdir(parents=True)
except FileExistsError:
pass
newpath = os.path.join(newroot, file)
print(f"...Copy '{path} to '{newpath}'")
shutil.copy2(path, newpath)
json_backup()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment