def testTree(self, print_): db.init(path) files, folders = gen_bunch_of_nodes(50) sync.insert_nodes(files + folders) sys.argv.extend(['tree', '-t']) self.assertEqual(run_main(), None) self.assertEqual(len(print_.mock_calls), 51)
def testTree(self, print_): db.init(path) files, folders = gen_bunch_of_nodes(50) sync.insert_nodes(files + folders) sys.argv.extend(['tree', '-t']) self.assertEqual(run_main(), None) self.assertEqual(len(print_.mock_calls), 100)
def testList(self, print_): db.init(path) folder = gen_folder([]) files = [gen_file([folder]) for _ in range(50)] sync.insert_nodes(files + [folder]) sys.argv.extend(['ls', '-t', '/']) self.assertEqual(run_main(), None) self.assertEqual(len(print_.mock_calls), 50)
def testList(self, print_): db.init(path) folder = gen_folder([]) files = [gen_file([folder]) for _ in range(50)] sync.insert_nodes(files + [folder]) sys.argv.extend(['ls', '-t', '/']) self.assertEqual(run_main(), None) self.assertEqual(len(print_.mock_calls), 100)
def old_sync(): db.drop_all() db.init(CACHE_PATH) try: folders = metadata.get_folder_list() folders.extend(metadata.get_trashed_folders()) files = metadata.get_file_list() files.extend(metadata.get_trashed_files()) except RequestError as e: logger.critical('Sync failed.') print(e) return 1 sync.insert_folders(folders) sync.insert_files(files)
def sync_node_list(full=False): cp = sync.get_checkpoint() try: nodes, purged, ncp, full = metadata.get_changes(checkpoint=None if full else cp, include_purged=not full) except RequestError as e: logger.critical('Sync failed.') print(e) return 1 if full: db.drop_all() db.init(CACHE_PATH) else: sync.remove_purged(purged) if len(nodes) > 0: sync.insert_nodes(nodes) sync.set_checkpoint(ncp) return
def sync_node_list(full=False): cp = sync.get_checkpoint() try: nodes, purged, ncp, full = metadata.get_changes( checkpoint=None if full else cp, include_purged=not full) except RequestError as e: logger.critical('Sync failed.') print(e) return 1 if full: db.drop_all() db.init(CACHE_PATH) else: sync.remove_purged(purged) if len(nodes) > 0: sync.insert_nodes(nodes) sync.set_checkpoint(ncp) return
def setUp(self): db.remove_db_file(self.path) db.init(self.path)
def main(): utf_flag = False if sys.stdout.isatty(): if str.lower(sys.stdout.encoding) != 'utf-8': import io sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='utf-8') sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding='utf-8') utf_flag = True opt_parser = argparse.ArgumentParser( prog=_app_name, formatter_class=argparse.RawTextHelpFormatter, epilog='Hints: \n' ' * Remote locations may be specified as path in most cases, e.g. "/folder/file", or via ID \n' ' * If you need to enter a node ID that contains a leading dash (minus) sign, ' 'precede it by two dashes and a space, e.g. \'-- -xfH...\'\n' ' * actions marked with [+] have optional arguments' '') opt_parser.add_argument( '-v', '--verbose', action='count', help= 'prints some info messages to stderr; use "-vv" to also get sqlalchemy info.' ) opt_parser.add_argument('-d', '--debug', action='count', help='turn on debug mode') opt_parser.add_argument('-nw', '--no-wait', action='store_true', help=argparse.SUPPRESS) subparsers = opt_parser.add_subparsers(title='action', dest='action') subparsers.required = True sync_sp = subparsers.add_parser( 'sync', aliases=['s'], help='[+] refresh node list cache; necessary for many actions') sync_sp.add_argument('--full', '-f', action='store_true', help='force a full sync') sync_sp.set_defaults(func=sync_action) old_sync_sp = subparsers.add_parser('old-sync', add_help=False) old_sync_sp.set_defaults(func=old_sync_action) clear_sp = subparsers.add_parser( 'clear-cache', aliases=['cc'], help='clear node cache [offline operation]') clear_sp.set_defaults(func=clear_action) tree_sp = subparsers.add_parser( 'tree', aliases=['t'], help='[+] print directory tree [offline operation]') tree_sp.add_argument('--include-trash', '-t', action='store_true') tree_sp.add_argument('node', nargs='?', default=None, help='root node for the tree') tree_sp.set_defaults(func=tree_action) list_c_sp = subparsers.add_parser( 'children', aliases=['ls', 'dir'], help='[+] list folder\'s children [offline operation]') list_c_sp.add_argument('--include-trash', '-t', action='store_true') list_c_sp.add_argument('--recursive', '-r', action='store_true') list_c_sp.add_argument('node') list_c_sp.set_defaults(func=children_action) find_sp = subparsers.add_parser( 'find', aliases=['f'], help='find nodes by name [offline operation] [case insensitive]') find_sp.add_argument('name') find_sp.set_defaults(func=find_action) find_hash_sp = subparsers.add_parser( 'find-md5', aliases=['fh'], help='find files by MD5 hash [offline operation]') find_hash_sp.add_argument('md5') find_hash_sp.set_defaults(func=find_md5_action) re_dummy_sp = subparsers.add_parser('dummy', add_help=False) re_dummy_sp.add_argument( '--exclude-ending', '-xe', action='append', dest='exclude_fe', default=[], help= 'exclude files whose endings match the given string, e.g. "bak" [case insensitive]' ) re_dummy_sp.add_argument( '--exclude-regex', '-xr', action='append', dest='exclude_re', default=[], help='exclude files whose names match the given regular expression,' ' e.g. "^thumbs\.db$" [case insensitive]') upload_sp = subparsers.add_parser( 'upload', aliases=['ul'], parents=[re_dummy_sp], help='[+] file and directory upload to a remote destination') upload_sp.add_argument( '--overwrite', '-o', action='store_true', help= 'overwrite if local modification time is higher or local ctime is higher than remote ' 'modification time and local/remote file sizes do not match.') upload_sp.add_argument('--force', '-f', action='store_true', help='force overwrite') upload_sp.add_argument('path', nargs='+', help='a path to a local file or directory') upload_sp.add_argument('parent', help='remote parent folder') upload_sp.set_defaults(func=upload_action) overwrite_sp = subparsers.add_parser( 'overwrite', aliases=['ov'], help='overwrite file A [remote] with content of file B [local]') overwrite_sp.add_argument('node') overwrite_sp.add_argument('file') overwrite_sp.set_defaults(func=overwrite_action) download_sp = subparsers.add_parser( 'download', aliases=['dl'], parents=[re_dummy_sp], help='download a remote folder or file; will overwrite local files') download_sp.add_argument('node') download_sp.add_argument('path', nargs='?', default=None, help='local download path [optional]') download_sp.set_defaults(func=download_action) cr_fo_sp = subparsers.add_parser( 'create', aliases=['c', 'mkdir'], help='create folder using an absolute path') cr_fo_sp.add_argument( 'new_folder', help= 'an absolute folder path, e.g. "/my/dir/"; trailing slash is optional') cr_fo_sp.set_defaults(func=create_action) trash_sp = subparsers.add_parser( 'list-trash', aliases=['lt'], help='[+] list trashed nodes [offline operation]') trash_sp.add_argument('--recursive', '-r', action='store_true') trash_sp.set_defaults(func=list_trash_action) m_trash_sp = subparsers.add_parser('trash', aliases=['rm'], help='move node to trash') m_trash_sp.add_argument('node') m_trash_sp.set_defaults(func=trash_action) rest_sp = subparsers.add_parser('restore', aliases=['re'], help='restore from trash') rest_sp.add_argument('node', help='ID of the node') rest_sp.set_defaults(func=restore_action) move_sp = subparsers.add_parser('move', aliases=['mv'], help='move node A into folder B') move_sp.add_argument('child') move_sp.add_argument('parent') move_sp.set_defaults(func=move_action) rename_sp = subparsers.add_parser('rename', aliases=['rn'], help='rename a node') rename_sp.add_argument('node') rename_sp.add_argument('name') rename_sp.set_defaults(func=rename_action) res_sp = subparsers.add_parser('resolve', aliases=['rs'], help='resolve a path to a node ID') res_sp.add_argument('path') res_sp.set_defaults(func=resolve_action) # maybe the child operations should not be exposed # they can be used for creating hardlinks add_c_sp = subparsers.add_parser('add-child', aliases=['ac'], help='add a node to a parent folder') add_c_sp.add_argument('parent') add_c_sp.add_argument('child') add_c_sp.set_defaults(func=add_child_action) rem_c_sp = subparsers.add_parser('remove-child', aliases=['rc'], help='remove a node from a parent folder') rem_c_sp.add_argument('parent') rem_c_sp.add_argument('child') rem_c_sp.set_defaults(func=remove_child_action) usage_sp = subparsers.add_parser('usage', aliases=['u'], help='show drive usage data') usage_sp.set_defaults(func=usage_action) quota_sp = subparsers.add_parser('quota', aliases=['q'], help='show drive quota [raw JSON]') quota_sp.set_defaults(func=quota_action) meta_sp = subparsers.add_parser('metadata', aliases=['m'], help='print a node\'s metadata [raw JSON]') meta_sp.add_argument('node') meta_sp.set_defaults(func=metadata_action) # useful for interactive mode dn_sp = subparsers.add_parser('init', aliases=['i'], add_help=False) dn_sp.set_defaults(func=None) plugin_log = [str(plugins.Plugin)] for plugin in plugins.Plugin: if plugin.check_version(__version__): log = [] plugin.attach(subparsers, log) plugin_log.extend(log) else: plugin_log.append('Script version is not compatible with "%s".' % plugin) args = opt_parser.parse_args() set_log_level(args) for msg in plugin_log: logger.info(msg) if utf_flag: logger.info('Stdout/stderr encoding changed to UTF-8.') migrate_cache_files() # offline actions if args.func not in [ clear_action, tree_action, children_action, list_trash_action, find_action, resolve_action ]: if not common.init(CACHE_PATH): sys.exit(INIT_FAILED_RETVAL) # online actions if args.func not in [usage_action, quota_action]: db.init(CACHE_PATH) if args.no_wait: common.BackOffRequest._wait = lambda: None autoresolve_attrs = ['child', 'parent', 'node'] resolve_remote_path_args(args, autoresolve_attrs, [upload_action, list_trash_action]) # call appropriate sub-parser action if args.func: sys.exit(args.func(args))
def main(): utf_flag = False if sys.stdout.isatty(): if str.lower(sys.stdout.encoding) != 'utf-8': import io sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='utf-8') sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding='utf-8') utf_flag = True opt_parser = argparse.ArgumentParser( prog=_app_name, formatter_class=argparse.RawTextHelpFormatter, epilog='Hints: \n' ' * Remote locations may be specified as path in most cases, e.g. "/folder/file", or via ID \n' ' * If you need to enter a node ID that contains a leading dash (minus) sign, ' 'precede it by two dashes and a space, e.g. \'-- -xfH...\'\n' ' * actions marked with [+] have optional arguments' '') opt_parser.add_argument('-v', '--verbose', action='count', help='prints some info messages to stderr; use "-vv" to also get sqlalchemy info.') opt_parser.add_argument('-d', '--debug', action='count', help='turn on debug mode') opt_parser.add_argument('-nw', '--no-wait', action='store_true', help=argparse.SUPPRESS) subparsers = opt_parser.add_subparsers(title='action', dest='action') subparsers.required = True sync_sp = subparsers.add_parser('sync', aliases=['s'], help='[+] refresh node list cache; necessary for many actions') sync_sp.add_argument('--full', '-f', action='store_true', help='force a full sync') sync_sp.set_defaults(func=sync_action) old_sync_sp = subparsers.add_parser('old-sync', add_help=False) old_sync_sp.set_defaults(func=old_sync_action) clear_sp = subparsers.add_parser('clear-cache', aliases=['cc'], help='clear node cache [offline operation]') clear_sp.set_defaults(func=clear_action) tree_sp = subparsers.add_parser('tree', aliases=['t'], help='[+] print directory tree [offline operation]') tree_sp.add_argument('--include-trash', '-t', action='store_true') tree_sp.add_argument('node', nargs='?', default=None, help='root node for the tree') tree_sp.set_defaults(func=tree_action) list_c_sp = subparsers.add_parser('children', aliases=['ls', 'dir'], help='[+] list folder\'s children [offline operation]') list_c_sp.add_argument('--include-trash', '-t', action='store_true') list_c_sp.add_argument('--recursive', '-r', action='store_true') list_c_sp.add_argument('node') list_c_sp.set_defaults(func=children_action) find_sp = subparsers.add_parser('find', aliases=['f'], help='find nodes by name [offline operation] [case insensitive]') find_sp.add_argument('name') find_sp.set_defaults(func=find_action) find_hash_sp = subparsers.add_parser('find-md5', aliases=['fh'], help='find files by MD5 hash [offline operation]') find_hash_sp.add_argument('md5') find_hash_sp.set_defaults(func=find_md5_action) re_dummy_sp = subparsers.add_parser('dummy', add_help=False) re_dummy_sp.add_argument('--exclude-ending', '-xe', action='append', dest='exclude_fe', default=[], help='exclude files whose endings match the given string, e.g. "bak" [case insensitive]') re_dummy_sp.add_argument('--exclude-regex', '-xr', action='append', dest='exclude_re', default=[], help='exclude files whose names match the given regular expression,' ' e.g. "^thumbs\.db$" [case insensitive]') upload_sp = subparsers.add_parser('upload', aliases=['ul'], parents=[re_dummy_sp], help='[+] file and directory upload to a remote destination') upload_sp.add_argument('--overwrite', '-o', action='store_true', help='overwrite if local modification time is higher or local ctime is higher than remote ' 'modification time and local/remote file sizes do not match.') upload_sp.add_argument('--force', '-f', action='store_true', help='force overwrite') upload_sp.add_argument('path', nargs='+', help='a path to a local file or directory') upload_sp.add_argument('parent', help='remote parent folder') upload_sp.set_defaults(func=upload_action) overwrite_sp = subparsers.add_parser('overwrite', aliases=['ov'], help='overwrite file A [remote] with content of file B [local]') overwrite_sp.add_argument('node') overwrite_sp.add_argument('file') overwrite_sp.set_defaults(func=overwrite_action) download_sp = subparsers.add_parser('download', aliases=['dl'], parents=[re_dummy_sp], help='download a remote folder or file; will overwrite local files') download_sp.add_argument('node') download_sp.add_argument('path', nargs='?', default=None, help='local download path [optional]') download_sp.set_defaults(func=download_action) cr_fo_sp = subparsers.add_parser('create', aliases=['c', 'mkdir'], help='create folder using an absolute path') cr_fo_sp.add_argument('new_folder', help='an absolute folder path, e.g. "/my/dir/"; trailing slash is optional') cr_fo_sp.set_defaults(func=create_action) trash_sp = subparsers.add_parser('list-trash', aliases=['lt'], help='[+] list trashed nodes [offline operation]') trash_sp.add_argument('--recursive', '-r', action='store_true') trash_sp.set_defaults(func=list_trash_action) m_trash_sp = subparsers.add_parser('trash', aliases=['rm'], help='move node to trash') m_trash_sp.add_argument('node') m_trash_sp.set_defaults(func=trash_action) rest_sp = subparsers.add_parser('restore', aliases=['re'], help='restore from trash') rest_sp.add_argument('node', help='ID of the node') rest_sp.set_defaults(func=restore_action) move_sp = subparsers.add_parser('move', aliases=['mv'], help='move node A into folder B') move_sp.add_argument('child') move_sp.add_argument('parent') move_sp.set_defaults(func=move_action) rename_sp = subparsers.add_parser('rename', aliases=['rn'], help='rename a node') rename_sp.add_argument('node') rename_sp.add_argument('name') rename_sp.set_defaults(func=rename_action) res_sp = subparsers.add_parser('resolve', aliases=['rs'], help='resolve a path to a node ID') res_sp.add_argument('path') res_sp.set_defaults(func=resolve_action) # maybe the child operations should not be exposed # they can be used for creating hardlinks add_c_sp = subparsers.add_parser('add-child', aliases=['ac'], help='add a node to a parent folder') add_c_sp.add_argument('parent') add_c_sp.add_argument('child') add_c_sp.set_defaults(func=add_child_action) rem_c_sp = subparsers.add_parser('remove-child', aliases=['rc'], help='remove a node from a parent folder') rem_c_sp.add_argument('parent') rem_c_sp.add_argument('child') rem_c_sp.set_defaults(func=remove_child_action) usage_sp = subparsers.add_parser('usage', aliases=['u'], help='show drive usage data') usage_sp.set_defaults(func=usage_action) quota_sp = subparsers.add_parser('quota', aliases=['q'], help='show drive quota [raw JSON]') quota_sp.set_defaults(func=quota_action) meta_sp = subparsers.add_parser('metadata', aliases=['m'], help='print a node\'s metadata [raw JSON]') meta_sp.add_argument('node') meta_sp.set_defaults(func=metadata_action) # useful for interactive mode dn_sp = subparsers.add_parser('init', aliases=['i'], add_help=False) dn_sp.set_defaults(func=None) plugin_log = [str(plugins.Plugin)] for plugin in plugins.Plugin: if plugin.check_version(__version__): log = [] plugin.attach(subparsers, log) plugin_log.extend(log) else: plugin_log.append('Script version is not compatible with "%s".' % plugin) args = opt_parser.parse_args() set_log_level(args) for msg in plugin_log: logger.info(msg) if utf_flag: logger.info('Stdout/stderr encoding changed to UTF-8.') migrate_cache_files() # offline actions if args.func not in [clear_action, tree_action, children_action, list_trash_action, find_action, resolve_action]: if not common.init(CACHE_PATH): sys.exit(INIT_FAILED_RETVAL) # online actions if args.func not in [usage_action, quota_action]: db.init(CACHE_PATH) if args.no_wait: common.BackOffRequest._wait = lambda: None autoresolve_attrs = ['child', 'parent', 'node'] resolve_remote_path_args(args, autoresolve_attrs, [upload_action, list_trash_action]) # call appropriate sub-parser action if args.func: sys.exit(args.func(args))
def testClearCache(self): sys.argv.append('cc') db.init(path) self.assertEqual(run_main(), None)
def testCheckCacheNonEmpty(self): db.init(path) folder = gen_folder() sync.insert_nodes([folder]) sys.argv.extend(['ls', '/']) self.assertEqual(run_main(), None)
def setUp(self): sys.argv = [acd_cli._app_name] db.init(path)