diff --git a/mine/cli.py b/mine/cli.py index 5c4626d..b56800f 100644 --- a/mine/cli.py +++ b/mine/cli.py @@ -114,7 +114,7 @@ def run(path=None, cleanup=True, delay=None, log.info("current computer: %s", computer) if cleanup: - clean(config, status) + data.clean(config, status) if delete: return services.delete_conflicts(root, force=force) @@ -123,11 +123,13 @@ def run(path=None, cleanup=True, delay=None, elif switch: switch = config.computers.match(switch) if switch: - queue(config, status, switch) + data.queue(config, status, switch) while True: - launch(config, status, computer, manager) - update(config, status, computer, manager) + services.delete_conflicts(root, config_only=True, force=True) + + data.launch(config, status, computer, manager) + data.update(config, status, computer, manager) if delay is None: break @@ -137,108 +139,5 @@ def run(path=None, cleanup=True, delay=None, return True -# TODO: consider moving this logic to `data` -def clean(config, status): - """Remove undefined applications and computers.""" - log.info("cleaning up applications and computers...") - for appstatus in status.applications.copy(): - if not config.applications.find(appstatus.application): - status.applications.remove(appstatus) - log.info("removed application: %s", appstatus) - else: - for computerstate in appstatus.computers.copy(): - if not config.computers.find(computerstate.computer): - appstatus.computers.remove(computerstate) - log.info("removed computer: %s", computerstate) - - -# TODO: consider moving this logic to `data` -def queue(config, status, computer): - """Queue applications for launch.""" - log.info("queuing applications for launch...") - for application in config.applications: - if application.queued: - log.debug("queuing %s on %s...", application, computer) - status.queue(application, computer) - else: - log.debug("skipping %s (not queued)...", application) - - -# TODO: consider moving this logic to `data` -def launch(config, status, computer, manager): - """Launch applications that have been queued.""" - log.info("launching queued applications...") - for app_status in status.applications: - if app_status.next: - application = config.applications.get(app_status.application) - show_queued(application, app_status.next) - if app_status.next == computer: - latest = status.get_latest(application) - if latest in (computer, None): - if not manager.is_running(application): - manager.start(application) - app_status.next = None - else: - show_waiting(application, latest) - elif manager.is_running(application): - manager.stop(application) - - -# TODO: consider moving this logic to `data` -def update(config, status, computer, manager): - """Update each application's status.""" - log.info("recording application status...") - for application in config.applications: - if manager.is_running(application): - latest = status.get_latest(application) - if computer != latest: - if status.is_running(application, computer): - # case 1: application just launched remotely - manager.stop(application) - status.stop(application, computer) - show_running(application, latest) - show_stopped(application, computer) - else: - # case 2: application just launched locally - status.start(application, computer) - show_running(application, computer) - else: - # case 3: application already running locally - pass - else: - if status.is_running(application, computer): - # case 4: application just closed locally - status.stop(application, computer) - show_stopped(application, computer) - else: - # case 5: application already closed locally - pass - - -def show_queued(application, computer): - """Display the state of a queued application.""" - print("{} is queued for {}".format(application, computer)) - - -def show_waiting(application, computer): - """Display the old state of a running application.""" - print("{} is still running on {}".format(application, computer)) - - -def show_running(application, computer): - """Display the new state of a running application.""" - print("{} is now running on {}".format(application, computer)) - - -def show_started(application, computer): - """Display the new state of a started application.""" - print("{} is now started on {}".format(application, computer)) - - -def show_stopped(application, computer): - """Display the new state of a stopped application.""" - print("{} is now stopped on {}".format(application, computer)) - - if __name__ == '__main__': # pragma: no cover (manual test) main() diff --git a/mine/data.py b/mine/data.py index 50ee23f..022dfd7 100644 --- a/mine/data.py +++ b/mine/data.py @@ -22,3 +22,102 @@ def __init__(self): def __repr__(self): return "settings" + + @staticmethod + def clean(config, status): + """Remove undefined applications and computers.""" + log.info("cleaning up applications and computers...") + for appstatus in status.applications.copy(): + if not config.applications.find(appstatus.application): + status.applications.remove(appstatus) + log.info("removed application: %s", appstatus) + else: + for computerstate in appstatus.computers.copy(): + if not config.computers.find(computerstate.computer): + appstatus.computers.remove(computerstate) + log.info("removed computer: %s", computerstate) + + @staticmethod + def queue(config, status, computer): + """Queue applications for launch.""" + log.info("queuing applications for launch...") + for application in config.applications: + if application.queued: + log.debug("queuing %s on %s...", application, computer) + status.queue(application, computer) + else: + log.debug("skipping %s (not queued)...", application) + + @staticmethod + def launch(config, status, computer, manager): + """Launch applications that have been queued.""" + log.info("launching queued applications...") + for app_status in status.applications: + if app_status.next: + application = config.applications.get(app_status.application) + show_queued(application, app_status.next) + if app_status.next == computer: + latest = status.get_latest(application) + if latest in (computer, None): + if not manager.is_running(application): + manager.start(application) + app_status.next = None + else: + show_waiting(application, latest) + elif manager.is_running(application): + manager.stop(application) + + @staticmethod + def update(config, status, computer, manager): + """Update each application's status.""" + log.info("recording application status...") + for application in config.applications: + if manager.is_running(application): + latest = status.get_latest(application) + if computer != latest: + if status.is_running(application, computer): + # case 1: application just launched remotely + manager.stop(application) + status.stop(application, computer) + show_running(application, latest) + show_stopped(application, computer) + else: + # case 2: application just launched locally + status.start(application, computer) + show_running(application, computer) + else: + # case 3: application already running locally + pass + else: + if status.is_running(application, computer): + # case 4: application just closed locally + status.stop(application, computer) + show_stopped(application, computer) + else: + # case 5: application already closed locally + pass + + +def show_queued(application, computer): + """Display the state of a queued application.""" + print("{} is queued for {}".format(application, computer)) + + +def show_waiting(application, computer): + """Display the old state of a running application.""" + print("{} is still running on {}".format(application, computer)) + + +def show_running(application, computer): + """Display the new state of a running application.""" + print("{} is now running on {}".format(application, computer)) + + +def show_started(application, computer): + """Display the new state of a started application.""" + print("{} is now started on {}".format(application, computer)) + + +def show_stopped(application, computer): + """Display the new state of a stopped application.""" + print("{} is now stopped on {}".format(application, computer)) diff --git a/mine/services.py b/mine/services.py index d67eeb4..d4f77cf 100755 --- a/mine/services.py +++ b/mine/services.py @@ -15,8 +15,10 @@ 'Dropbox', 'Dropbox (Personal)', ) -CONFLICT = r".+\(.+'s conflicted copy \d+-\d+-\d+.*\).*" -FILENAME = 'mine.yml' +CONFIG = 'mine.yml' +CONFLICT_BASE = r"{} \(.+'s conflicted copy \d+-\d+-\d+.*\).*" +CONFLICT_ANY = CONFLICT_BASE.format(".+") +CONFLICT_CONFIG = CONFLICT_BASE.format("mine") DEPTH = 3 # number of levels to search for the settings file log = common.logger(__name__) @@ -47,19 +49,19 @@ def find_config_path(top=None, root=None): top = top or _default_top() root = root or find_root(top=top) - log.debug("looking for '%s' in '%s'...", FILENAME, root) + log.debug("looking for '%s' in '%s'...", CONFIG, root) for dirpath, dirnames, _, in os.walk(root): depth = dirpath.count(os.path.sep) - root.count(os.path.sep) if depth >= DEPTH: del dirnames[:] continue - path = os.path.join(dirpath, FILENAME) + path = os.path.join(dirpath, CONFIG) if os.path.isfile(path) and \ not os.path.isfile(os.path.join(path, 'setup.py')): log.info("found settings file: %s", path) return path - raise EnvironmentError("no '{}' file found".format(FILENAME)) + raise EnvironmentError("no '{}' file found".format(CONFIG)) def _default_top(): @@ -75,13 +77,14 @@ def _default_top(): raise EnvironmentError("no home directory found for '{}'".format(username)) -def delete_conflicts(root=None, force=False): +def delete_conflicts(root=None, config_only=False, force=False): """Delete all files with conflicted filenames.""" root = root or find_root() log.info("%s conflicted files...", 'deleting' if force else 'displaying') - log.debug("pattern: %r", CONFLICT) - regex = re.compile(CONFLICT) + pattern = CONFLICT_CONFIG if config_only else CONFLICT_ANY + log.debug("pattern: %r", pattern) + regex = re.compile(pattern) count = 0 for dirname, _, filenames in os.walk(root): for filename in filenames: