Skip to content

Instantly share code, notes, and snippets.

@dariosky
Last active February 17, 2023 19:30
Show Gist options
  • Save dariosky/7484835c7753c2fe373debd04227b047 to your computer and use it in GitHub Desktop.
Save dariosky/7484835c7753c2fe373debd04227b047 to your computer and use it in GitHub Desktop.
A Python script to be run in a Dropbox folder - so it exclude all the node_modules and __pycache__ folders - we want them locally but not in the cloud
#!/usr/bin/env python3
import argparse
import os
import shutil
from xattr import xattr
top_folder = "."
CACHE_FOLDERS = {"__pycache__", ".pytest_cache", ".cache"}
EXCLUDED_FOLDERS = {"node_modules", ".tox"} | CACHE_FOLDERS
NUKED_FOLDERS = {f"{folder} (Ignored Item Conflict)" for folder in EXCLUDED_FOLDERS}
def exclude_folder(root, dir_name):
full_path = os.path.join(root, dir_name)
attrs = xattr(full_path)
if "com.dropbox.ignored" not in attrs:
print(full_path)
xattr(full_path).set("com.dropbox.ignored", b"1")
def empty_folder(folder_path):
content = os.listdir(folder_path)
if content:
print(f"Emptying cache folder {folder_path}")
for f in content:
path = os.path.join(folder_path, f)
if os.path.isdir(path):
shutil.rmtree(path)
else:
os.remove(path)
def main(empty_cache=False):
for root, dirs, files in os.walk(top_folder, topdown=True):
recursive_folders = []
for dir_name in dirs:
if dir_name in NUKED_FOLDERS:
full_path = os.path.join(root, dir_name)
print(f"Nuking the folder {full_path}")
shutil.rmtree(full_path)
continue
# exclude from dropbox all the excluded_folders - and all "build" folders sibilings of "node_modules"
if (
dir_name in EXCLUDED_FOLDERS
or (
dir_name in ("build", "dist") and "node_modules" in dirs
) # builds of Node
or (
dir_name in ("target",) and "Cargo.toml" in files
) # targets of Rust
):
exclude_folder(root, dir_name)
if dir_name in CACHE_FOLDERS and empty_cache:
full_path = os.path.join(root, dir_name)
empty_folder(full_path)
else:
recursive_folders.append(dir_name)
dirs[:] = recursive_folders
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Mark a few fat folder as ignored so they don't sync to Dropbox"
)
parser.add_argument(
"--empty-cache",
help="Empty the cache folders",
default=False,
action="store_true",
)
args = parser.parse_args()
main(empty_cache=args.empty_cache)
@dariosky
Copy link
Author

It use the new dropbox API that ignore files with the attr com.dropbox.ignored set
It uses xattr to read the attribute and set it only if needed (so Dropbox won't resync if you run it several times)

@dariosky
Copy link
Author

Edit: Now it also exclude all the folders called "build" that sit next to a "node_modules" one

@dariosky
Copy link
Author

dariosky commented May 2, 2020

Edit: ignoring a little more folders used for caches - added the --delete-cache to delete the content of the cache folders (the empty folders are kept and marked ignored)

@dariosky
Copy link
Author

Edit: To make it work in mac - I'm calling attr/xattr using the xattr library rather than a shell subprocess

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment