#!/usr/bin/env python3 # vim: ft=python # -*- mode: python -*- import json import os import sys import subprocess help_str = ('A config file `sync.json` has been created in {}. ' 'Please specify the remote host and destination directory in this ' 'config file and then run the sync script again.').format(os.path.join(os.getcwd(), '.config')) config_filename = os.path.join('.config', 'sync.json') rsync_path = os.getenv('RSYNC_PATH', default = 'rsync') def in_source_tree(): return os.path.isfile('tools/socks.sync') def create_sample_config(): if not os.path.isdir('.config'): os.mkdir('.config') config_file = open(config_filename, mode='w') data = { 'targets': { 'example': { 'host': 'Hostname', 'user': 'User to connect to the remote host as (optional)', 'path': 'Destination directory on remote host' } }, 'default_target': 'example' } json.dump(data, config_file, indent=4) def read_config(): config_file = None try: config_file = open(config_filename) except (OSError, FileNotFoundError): create_sample_config() print(help_str) exit(0) return json.load(config_file) def check_config(cfg): if not 'targets' in cfg: print('No targets specified in config file') exit(-1) def make_full_target(target): path = target['path'].replace('\\', '/') if path[-1] != '/': path += '/' out = '{}:{}'.format(target['host'], path) if 'user' in target: out = '{}@{}'.format(target['user'], out) return out def print_available_targets(targets): print('Available targets:') for name, target in targets.items(): print(' * {} ({})'.format(name, make_full_target(target))) if not in_source_tree(): print('This script must be executed from the root of the Socks source tree') exit(-1) config = read_config() check_config(config); targets = config['targets'] if len(sys.argv) < 2: print('No mode specified. Available modes:') print(' * pull: Update the local source tree to match the remote source tree') print(' * push: Upload the remote source tree to match the local source tree') exit(0) mode = sys.argv[1] if mode != 'pull' and mode != 'push': print('Invalid sync mode "{}"'.format(mode)) exit(-1) target_name = '' if len(sys.argv) < 3: if 'default_target' in config: target_name = config['default_target'] print('No target specified. Using default target "{}"'.format(target_name)) else: print('No target specified (and no default target configured)') print_available_targets(config['targets']) exit(0) if target_name not in targets: print('Unknown target "{}"'.format(target_name)) print_available_targets(config['targets']) exit(-1) target = targets[target_name] print('Syncing source tree with {} ({})'.format(make_full_target(target), mode)) rsync_args = [ rsync_path, '-azhP', '--exclude', 'build/' ] if mode == 'pull': rsync_args += [ make_full_target(target), '.' ] else: rsync_args += [ '.', make_full_target(target) ] rsync = subprocess.Popen(rsync_args) rsync.communicate() if rsync.returncode == 0: print('** Sync completed successfully') else: print('** Sync failed (error {})'.format(rsync.errorcode)) exit(rsync.returncode)