Skip to content

rschone/filesync

Repository files navigation

filesync

A bidirectional file synchronization tool for syncing local directories with Google Drive.

Features

  • Bidirectional Sync: Automatically syncs changes between local directories and Google Drive
  • Real-time Monitoring: Detects local file changes instantly using fsnotify
  • Remote Polling: Polls Google Drive for remote changes at configurable intervals
  • Conflict Resolution: Multiple strategies (last_write_wins, local_wins, remote_wins, keep_both)
  • Deletion Policies: Configurable deletion propagation (bidirectional, one-way, or none)
  • Ignore Patterns: Support for .syncignore files and YAML-based patterns
  • Per-Directory Configuration: Override global settings for each sync target
  • SQLite State Tracking: Efficient change detection with local database
  • Graceful Shutdown: Completes in-flight operations before exiting

Prerequisites

  • Go 1.26 or later
  • Google Drive API credentials (OAuth 2.0)
  • macOS, Linux, or Windows

Installation

Build from source

git clone https://github.com/rschone/filesync.git
cd filesync
make build

The binary will be created at ./bin/filesync.

Install to system

sudo cp bin/filesync /usr/local/bin/

Configuration

1. Set Up Google Drive API Credentials

  1. Go to Google Cloud Console
  2. Create a new project (or select existing)
  3. Enable the Google Drive API
  4. Create OAuth 2.0 credentials (Desktop app)
  5. Download the credentials JSON
  6. Extract client_id and client_secret

2. Get OAuth Tokens

You'll need to obtain OAuth tokens. You can use the Google OAuth Playground:

  1. Go to https://developers.google.com/oauthplayground/
  2. Click the gear icon (⚙️) in top right
  3. Check "Use your own OAuth credentials"
  4. Enter your Client ID and Client Secret
  5. In "Step 1", select "Drive API v3" → "https://www.googleapis.com/auth/drive"
  6. Click "Authorize APIs"
  7. Authorize the application
  8. In "Step 2", click "Exchange authorization code for tokens"
  9. Copy the access_token, refresh_token, and expires_in

3. Create Configuration File

Create a configuration file at ~/.filesync/config.yaml:

mkdir -p ~/.filesync
cp config.yaml.example ~/.filesync/config.yaml

Edit the configuration file with your credentials and paths. See Configuration Example below.

Usage

Start Sync

filesync --config ~/.filesync/config.yaml --log-level info

Command-Line Options

  • --config - Path to configuration file (default: ~/.filesync/config.yaml)
  • --log-level - Log level: debug, info, warn, error (default: info)

Stop Sync

Press Ctrl+C to gracefully stop synchronization. The application will complete any in-flight operations before exiting.

Configuration Example

version: "1.0"

# Global default settings
global:
  sync_delay: 2s                      # Debounce delay for local changes
  remote_poll_interval: 60s           # How often to check Google Drive for changes
  conflict_resolution: last_write_wins # Default conflict strategy
  deletion_policy: propagate_both     # Default deletion policy
  initial_sync: merge                 # Default initial sync mode
  workers: 4                          # Number of concurrent sync workers
  retry_attempts: 3                   # Number of retries for failed operations
  retry_backoff: 1s                   # Base delay for exponential backoff
  database_path: ~/.filesync/sync.db  # SQLite database location

  # Global ignore patterns (applied to all targets)
  ignore_patterns:
    - "*.tmp"
    - ".DS_Store"
    - "Thumbs.db"
    - ".git/"
    - "node_modules/"

# Sync targets
targets:
  - id: documents                     # Unique identifier
    local_path: ~/Documents/Work      # Local directory to sync
    remote_path: /Work                # Google Drive folder path
    provider: gdrive                  # Cloud provider (currently only gdrive)
    enabled: true                     # Enable this target

    # Google Drive OAuth2 credentials
    credentials:
      oauth2:
        client_id: "YOUR_CLIENT_ID.apps.googleusercontent.com"
        client_secret: "YOUR_CLIENT_SECRET"
        access_token: "ya29.a0..."
        refresh_token: "1//0g..."
        token_expiry: "2026-03-08T12:00:00Z"

    # Optional: Override global settings for this target
    sync_delay: 5s
    conflict_resolution: keep_both
    ignore_patterns:
      - "*.draft"
      - "temp/"

Configuration Options

Global Settings

Option Type Default Description
sync_delay duration 2s Debounce delay for batching rapid local changes
remote_poll_interval duration 60s How often to poll Google Drive for changes
conflict_resolution string last_write_wins Default conflict resolution strategy
deletion_policy string propagate_both Default deletion propagation policy
initial_sync string merge Default initial synchronization mode
workers int 4 Number of concurrent sync operations
retry_attempts int 3 Number of retry attempts for failed operations
retry_backoff duration 1s Base delay for exponential backoff retries
database_path string ~/.filesync/sync.db SQLite database file location
ignore_patterns []string - Global file ignore patterns

Conflict Resolution Strategies

  • last_write_wins - File with newer modification time wins
  • local_wins - Local changes always take precedence
  • remote_wins - Remote changes always take precedence
  • keep_both - Keep both versions with conflict suffixes

Deletion Policies

  • propagate_both - Deletions sync bidirectionally (default)
  • propagate_local - Only propagate local deletions to remote
  • propagate_remote - Only propagate remote deletions to local
  • none - Never propagate deletions

Initial Sync Modes

  • merge - Combine files from both local and remote (default)
  • local_to_remote - Upload all local files to remote
  • remote_to_local - Download all remote files to local

Ignore Patterns

.syncignore Files

Create a .syncignore file in any directory to exclude files from sync:

# .syncignore example
*.tmp
*.swp
.DS_Store
node_modules/
__pycache__/
*.pyc

Pattern Syntax

  • *.tmp - Match files with .tmp extension
  • node_modules/ - Match directory and all contents
  • **/test - Match "test" in any subdirectory
  • !important.tmp - Negate pattern (not yet implemented)

Patterns are evaluated using glob matching with support for *, ?, [], and **.

Database

Filesync uses SQLite to track file metadata and sync state. The database stores:

  • File paths, sizes, modification times, and hashes
  • Sync state (synced, pending, conflict, error)
  • Last sync timestamps
  • Remote file IDs for efficient lookups
  • Sync operation logs

Database location is configurable via global.database_path.

Development

Build

make build

Run Tests

make test

Run Linters

make check

Clean

make clean

Troubleshooting

"Failed to authenticate with Google Drive"

  • Verify your OAuth credentials are correct
  • Check if the access token has expired (refresh token should auto-renew)
  • Ensure the Google Drive API is enabled in your Google Cloud project

"Database is locked"

  • Another filesync instance may be running
  • Check for stale lock files in the database directory
  • Restart the application

Files not syncing

  • Check the log output for errors (--log-level debug)
  • Verify the file doesn't match ignore patterns
  • Check if the file is being debounced (rapid changes)
  • Ensure you have write permissions

"Optimistic lock failed"

  • Multiple sync operations tried to update the same file simultaneously
  • The operation will be retried automatically
  • If persistent, check for concurrent filesync instances

Architecture

filesync/
├── cmd/filesync/       # Main application
├── internal/
│   ├── config/         # Configuration loading and validation
│   ├── storage/        # SQLite database interface
│   ├── provider/       # Cloud provider implementations
│   │   └── gdrive/     # Google Drive client
│   ├── watcher/        # File system watchers
│   ├── syncer/         # Sync engine and orchestration
│   ├── models/         # Data models
│   └── hash/           # File hashing utilities
└── pkg/logger/         # Structured logging

Contributing

Contributions are welcome! Please feel free to submit pull requests or open issues.

License

TBD

Acknowledgments

Built with:

About

Tool for synchronization of local directories with a cloud

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors