Skip to content

Commit

Permalink
Refactored down function complexity
Browse files Browse the repository at this point in the history
  • Loading branch information
jahwag committed Jul 25, 2024
1 parent 568d977 commit f26c917
Show file tree
Hide file tree
Showing 3 changed files with 305 additions and 268 deletions.
156 changes: 35 additions & 121 deletions src/claudesync/cli/sync.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import os
import shutil
import sys
import time

import click
from crontab import CronTab

from claudesync.utils import compute_md5_hash, get_local_files
from claudesync.utils import get_local_files
from ..utils import handle_errors, validate_and_get_provider
from datetime import datetime, timezone
from ..syncmanager import SyncManager


@click.command()
Expand Down Expand Up @@ -38,120 +36,32 @@ def ls(config):
def sync(config):
"""Synchronize local files with the active remote project."""
provider = validate_and_get_provider(config)
active_organization_id = config.get("active_organization_id")
active_project_id = config.get("active_project_id")
local_path = config.get("local_path")
upload_delay = config.get("upload_delay", 0.5)
two_way_sync = config.get("two_way_sync", False)

validate_local_path(local_path)

sync_manager = SyncManager(provider, config)
remote_files = provider.list_files(
sync_manager.active_organization_id, sync_manager.active_project_id
)
local_files = get_local_files(local_path)

sync_manager.sync(local_files, remote_files)

click.echo("Sync completed successfully.")


def validate_local_path(local_path):
if not local_path:
click.echo(
"No local path set. Please select or create a project to set the local path."
)
sys.exit(1)

if not os.path.exists(local_path):
click.echo(f"The configured local path does not exist: {local_path}")
click.echo("Please update the local path by selecting or creating a project.")
sys.exit(1)

remote_files = provider.list_files(active_organization_id, active_project_id)
local_files = get_local_files(local_path)

# Track remote files to delete
remote_files_to_delete = set(rf["file_name"] for rf in remote_files)

# Track synced files
synced_files = set()

for local_file, local_checksum in local_files.items():
remote_file = next(
(rf for rf in remote_files if rf["file_name"] == local_file), None
)
if remote_file:
remote_checksum = compute_md5_hash(remote_file["content"])
if local_checksum != remote_checksum:
click.echo(f"Updating {local_file} on remote...")
provider.delete_file(
active_organization_id, active_project_id, remote_file["uuid"]
)
with open(
os.path.join(local_path, local_file), "r", encoding="utf-8"
) as file:
content = file.read()
provider.upload_file(
active_organization_id, active_project_id, local_file, content
)
time.sleep(upload_delay) # Add delay after upload
synced_files.add(local_file)
remote_files_to_delete.remove(local_file)
else:
click.echo(f"Uploading new file {local_file} to remote...")
with open(
os.path.join(local_path, local_file), "r", encoding="utf-8"
) as file:
content = file.read()
provider.upload_file(
active_organization_id, active_project_id, local_file, content
)
time.sleep(upload_delay) # Add delay after upload
synced_files.add(local_file)

# Update local file timestamps only for synced files
remote_files = provider.list_files(active_organization_id, active_project_id)
for remote_file in remote_files:
if remote_file["file_name"] in synced_files:
local_file_path = os.path.join(local_path, remote_file["file_name"])
if os.path.exists(local_file_path):
remote_timestamp = datetime.fromisoformat(
remote_file["created_at"].replace("Z", "+00:00")
).timestamp()
os.utime(local_file_path, (remote_timestamp, remote_timestamp))
click.echo(f"Updated timestamp on local file {local_file_path}")

# Two-way sync: update local files if remote is newer
if two_way_sync:
for remote_file in remote_files:
local_file_path = os.path.join(local_path, remote_file["file_name"])
if os.path.exists(local_file_path):
local_mtime = datetime.fromtimestamp(
os.path.getmtime(local_file_path), tz=timezone.utc
)
remote_mtime = datetime.fromisoformat(
remote_file["created_at"].replace("Z", "+00:00")
)
if remote_mtime > local_mtime:
click.echo(
f"Updating local file {remote_file['file_name']} from remote..."
)
with open(local_file_path, "w", encoding="utf-8") as file:
file.write(remote_file["content"])
synced_files.add(remote_file["file_name"])
if remote_file["file_name"] in remote_files_to_delete:
remote_files_to_delete.remove(remote_file["file_name"])
else:
click.echo(
f"Creating new local file {remote_file['file_name']} from remote..."
)
with open(local_file_path, "w", encoding="utf-8") as file:
file.write(remote_file["content"])
synced_files.add(remote_file["file_name"])
if remote_file["file_name"] in remote_files_to_delete:
remote_files_to_delete.remove(remote_file["file_name"])

# Delete remote files that no longer exist locally
for file_to_delete in remote_files_to_delete:
click.echo(f"Deleting {file_to_delete} from remote...")
remote_file = next(
rf for rf in remote_files if rf["file_name"] == file_to_delete
)
provider.delete_file(
active_organization_id, active_project_id, remote_file["uuid"]
)
time.sleep(upload_delay) # Add delay after deletion

click.echo("Sync completed successfully.")


@click.command()
@click.pass_obj
Expand All @@ -169,20 +79,24 @@ def schedule(config, interval):
sys.exit(1)

if sys.platform.startswith("win"):
click.echo("Windows Task Scheduler setup:")
command = f'schtasks /create /tn "ClaudeSync" /tr "{claudesync_path} sync" /sc minute /mo {interval}'
click.echo(f"Run this command to create the task:\n{command}")
click.echo('\nTo remove the task, run: schtasks /delete /tn "ClaudeSync" /f')
setup_windows_task(claudesync_path, interval)
else:
# Unix-like systems (Linux, macOS)
cron = CronTab(user=True)
job = cron.new(command=f"{claudesync_path} sync")
job.minute.every(interval)
setup_unix_cron(claudesync_path, interval)

cron.write()
click.echo(
f"Cron job created successfully! It will run every {interval} minutes."
)
click.echo(
"\nTo remove the cron job, run: crontab -e and remove the line for ClaudeSync"
)

def setup_windows_task(claudesync_path, interval):
click.echo("Windows Task Scheduler setup:")
command = f'schtasks /create /tn "ClaudeSync" /tr "{claudesync_path} sync" /sc minute /mo {interval}'
click.echo(f"Run this command to create the task:\n{command}")
click.echo('\nTo remove the task, run: schtasks /delete /tn "ClaudeSync" /f')


def setup_unix_cron(claudesync_path, interval):
cron = CronTab(user=True)
job = cron.new(command=f"{claudesync_path} sync")
job.minute.every(interval)
cron.write()
click.echo(f"Cron job created successfully! It will run every {interval} minutes.")
click.echo(
"\nTo remove the cron job, run: crontab -e and remove the line for ClaudeSync"
)
Loading

0 comments on commit f26c917

Please sign in to comment.