Created
March 19, 2021 11:53
-
-
Save r-rmcgibbo/9dfc4d105321ed2bae13fd261317087d to your computer and use it in GitHub Desktop.
system: aarch64-linux | build_time: 7 seconds | https://github.com/NixOS/nixpkgs/pull/116831
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sourcing python-remove-tests-dir-hook | |
Sourcing python-catch-conflicts-hook.sh | |
Sourcing python-remove-bin-bytecode-hook.sh | |
Sourcing setuptools-build-hook | |
Using setuptoolsBuildPhase | |
Using setuptoolsShellHook | |
Sourcing pip-install-hook | |
Using pipInstallPhase | |
Sourcing python-imports-check-hook.sh | |
Using pythonImportsCheckPhase | |
Sourcing python-namespaces-hook | |
Sourcing setuptools-check-hook | |
Using setuptoolsCheckPhase | |
Sourcing pytest-check-hook | |
Using pytestCheckPhase | |
Removing setuptoolsCheckPhase | |
@nix { "action": "setPhase", "phase": "unpackPhase" } | |
unpacking sources | |
unpacking source archive /nix/store/nsvj2j4akavyjn5hhx0qdmfjck9w14nc-source | |
source root is source | |
setting SOURCE_DATE_EPOCH to timestamp 315619200 of file source/test/unit/test_console_tool.py | |
@nix { "action": "setPhase", "phase": "patchPhase" } | |
patching sources | |
@nix { "action": "setPhase", "phase": "updateAutotoolsGnuConfigScriptsPhase" } | |
updateAutotoolsGnuConfigScriptsPhase | |
@nix { "action": "setPhase", "phase": "configurePhase" } | |
configuring | |
no configure script, doing nothing | |
@nix { "action": "setPhase", "phase": "buildPhase" } | |
building | |
Executing setuptoolsBuildPhase | |
running bdist_wheel | |
running build | |
running build_py | |
creating build | |
creating build/lib | |
creating build/lib/b2 | |
copying b2/__main__.py -> build/lib/b2 | |
copying b2/version.py -> build/lib/b2 | |
copying b2/json_encoder.py -> build/lib/b2 | |
copying b2/__init__.py -> build/lib/b2 | |
copying b2/arg_parser.py -> build/lib/b2 | |
copying b2/console_tool.py -> build/lib/b2 | |
creating build/lib/test | |
creating build/lib/test/unit | |
copying test/unit/test_arg_parser.py -> build/lib/test/unit | |
copying test/unit/test_console_tool.py -> build/lib/test/unit | |
copying test/unit/__init__.py -> build/lib/test/unit | |
copying test/unit/test_base.py -> build/lib/test/unit | |
creating build/lib/test/static | |
copying test/static/test_licenses.py -> build/lib/test/static | |
copying test/static/__init__.py -> build/lib/test/static | |
creating build/lib/test/integration | |
copying test/integration/__init__.py -> build/lib/test/integration | |
copying test/integration/test_b2_command_line.py -> build/lib/test/integration | |
creating build/lib/test/unit/fixtures | |
copying test/unit/fixtures/__init__.py -> build/lib/test/unit/fixtures | |
creating build/lib/test/unit/fixtures/test_source_mod | |
copying test/unit/fixtures/test_source_mod/z.py -> build/lib/test/unit/fixtures/test_source_mod | |
copying test/unit/fixtures/test_source_mod/__init__.py -> build/lib/test/unit/fixtures/test_source_mod | |
creating build/lib/test/unit/fixtures/test_target_mod | |
copying test/unit/fixtures/test_target_mod/z.py -> build/lib/test/unit/fixtures/test_target_mod | |
copying test/unit/fixtures/test_target_mod/__init__.py -> build/lib/test/unit/fixtures/test_target_mod | |
creating build/lib/test/unit/fixtures/test_source_mod/c | |
copying test/unit/fixtures/test_source_mod/c/d.py -> build/lib/test/unit/fixtures/test_source_mod/c | |
copying test/unit/fixtures/test_source_mod/c/__init__.py -> build/lib/test/unit/fixtures/test_source_mod/c | |
creating build/lib/test/unit/fixtures/test_target_mod/a | |
copying test/unit/fixtures/test_target_mod/a/__init__.py -> build/lib/test/unit/fixtures/test_target_mod/a | |
copying test/unit/fixtures/test_target_mod/a/b.py -> build/lib/test/unit/fixtures/test_target_mod/a | |
creating build/lib/test/unit/fixtures/test_target_mod/c | |
copying test/unit/fixtures/test_target_mod/c/__init__.py -> build/lib/test/unit/fixtures/test_target_mod/c | |
installing to build/bdist.linux-aarch64/wheel | |
running install | |
running install_lib | |
creating build/bdist.linux-aarch64 | |
creating build/bdist.linux-aarch64/wheel | |
creating build/bdist.linux-aarch64/wheel/test | |
creating build/bdist.linux-aarch64/wheel/test/unit | |
copying build/lib/test/unit/test_arg_parser.py -> build/bdist.linux-aarch64/wheel/test/unit | |
creating build/bdist.linux-aarch64/wheel/test/unit/fixtures | |
creating build/bdist.linux-aarch64/wheel/test/unit/fixtures/test_source_mod | |
copying build/lib/test/unit/fixtures/test_source_mod/z.py -> build/bdist.linux-aarch64/wheel/test/unit/fixtures/test_source_mod | |
copying build/lib/test/unit/fixtures/test_source_mod/__init__.py -> build/bdist.linux-aarch64/wheel/test/unit/fixtures/test_source_mod | |
creating build/bdist.linux-aarch64/wheel/test/unit/fixtures/test_source_mod/c | |
copying build/lib/test/unit/fixtures/test_source_mod/c/d.py -> build/bdist.linux-aarch64/wheel/test/unit/fixtures/test_source_mod/c | |
copying build/lib/test/unit/fixtures/test_source_mod/c/__init__.py -> build/bdist.linux-aarch64/wheel/test/unit/fixtures/test_source_mod/c | |
copying build/lib/test/unit/fixtures/__init__.py -> build/bdist.linux-aarch64/wheel/test/unit/fixtures | |
creating build/bdist.linux-aarch64/wheel/test/unit/fixtures/test_target_mod | |
copying build/lib/test/unit/fixtures/test_target_mod/z.py -> build/bdist.linux-aarch64/wheel/test/unit/fixtures/test_target_mod | |
copying build/lib/test/unit/fixtures/test_target_mod/__init__.py -> build/bdist.linux-aarch64/wheel/test/unit/fixtures/test_target_mod | |
creating build/bdist.linux-aarch64/wheel/test/unit/fixtures/test_target_mod/a | |
copying build/lib/test/unit/fixtures/test_target_mod/a/__init__.py -> build/bdist.linux-aarch64/wheel/test/unit/fixtures/test_target_mod/a | |
copying build/lib/test/unit/fixtures/test_target_mod/a/b.py -> build/bdist.linux-aarch64/wheel/test/unit/fixtures/test_target_mod/a | |
creating build/bdist.linux-aarch64/wheel/test/unit/fixtures/test_target_mod/c | |
copying build/lib/test/unit/fixtures/test_target_mod/c/__init__.py -> build/bdist.linux-aarch64/wheel/test/unit/fixtures/test_target_mod/c | |
copying build/lib/test/unit/test_console_tool.py -> build/bdist.linux-aarch64/wheel/test/unit | |
copying build/lib/test/unit/__init__.py -> build/bdist.linux-aarch64/wheel/test/unit | |
copying build/lib/test/unit/test_base.py -> build/bdist.linux-aarch64/wheel/test/unit | |
creating build/bdist.linux-aarch64/wheel/test/static | |
copying build/lib/test/static/test_licenses.py -> build/bdist.linux-aarch64/wheel/test/static | |
copying build/lib/test/static/__init__.py -> build/bdist.linux-aarch64/wheel/test/static | |
creating build/bdist.linux-aarch64/wheel/test/integration | |
copying build/lib/test/integration/__init__.py -> build/bdist.linux-aarch64/wheel/test/integration | |
copying build/lib/test/integration/test_b2_command_line.py -> build/bdist.linux-aarch64/wheel/test/integration | |
creating build/bdist.linux-aarch64/wheel/b2 | |
copying build/lib/b2/__main__.py -> build/bdist.linux-aarch64/wheel/b2 | |
copying build/lib/b2/version.py -> build/bdist.linux-aarch64/wheel/b2 | |
copying build/lib/b2/json_encoder.py -> build/bdist.linux-aarch64/wheel/b2 | |
copying build/lib/b2/__init__.py -> build/bdist.linux-aarch64/wheel/b2 | |
copying build/lib/b2/arg_parser.py -> build/bdist.linux-aarch64/wheel/b2 | |
copying build/lib/b2/console_tool.py -> build/bdist.linux-aarch64/wheel/b2 | |
running install_egg_info | |
running egg_info | |
creating b2.egg-info | |
writing b2.egg-info/PKG-INFO | |
writing dependency_links to b2.egg-info/dependency_links.txt | |
writing entry points to b2.egg-info/entry_points.txt | |
writing requirements to b2.egg-info/requires.txt | |
writing top-level names to b2.egg-info/top_level.txt | |
writing manifest file 'b2.egg-info/SOURCES.txt' | |
reading manifest file 'b2.egg-info/SOURCES.txt' | |
reading manifest template 'MANIFEST.in' | |
writing manifest file 'b2.egg-info/SOURCES.txt' | |
Copying b2.egg-info to build/bdist.linux-aarch64/wheel/b2-2.1.0-py3.8.egg-info | |
running install_scripts | |
adding license file "LICENSE" (matched pattern "LICEN[CS]E*") | |
creating build/bdist.linux-aarch64/wheel/b2-2.1.0.dist-info/WHEEL | |
creating 'dist/b2-2.1.0-py3-none-any.whl' and adding 'build/bdist.linux-aarch64/wheel' to it | |
adding 'b2/__init__.py' | |
adding 'b2/__main__.py' | |
adding 'b2/arg_parser.py' | |
adding 'b2/console_tool.py' | |
adding 'b2/json_encoder.py' | |
adding 'b2/version.py' | |
adding 'test/integration/__init__.py' | |
adding 'test/integration/test_b2_command_line.py' | |
adding 'test/static/__init__.py' | |
adding 'test/static/test_licenses.py' | |
adding 'test/unit/__init__.py' | |
adding 'test/unit/test_arg_parser.py' | |
adding 'test/unit/test_base.py' | |
adding 'test/unit/test_console_tool.py' | |
adding 'test/unit/fixtures/__init__.py' | |
adding 'test/unit/fixtures/test_source_mod/__init__.py' | |
adding 'test/unit/fixtures/test_source_mod/z.py' | |
adding 'test/unit/fixtures/test_source_mod/c/__init__.py' | |
adding 'test/unit/fixtures/test_source_mod/c/d.py' | |
adding 'test/unit/fixtures/test_target_mod/__init__.py' | |
adding 'test/unit/fixtures/test_target_mod/z.py' | |
adding 'test/unit/fixtures/test_target_mod/a/__init__.py' | |
adding 'test/unit/fixtures/test_target_mod/a/b.py' | |
adding 'test/unit/fixtures/test_target_mod/c/__init__.py' | |
adding 'b2-2.1.0.dist-info/LICENSE' | |
adding 'b2-2.1.0.dist-info/METADATA' | |
adding 'b2-2.1.0.dist-info/WHEEL' | |
adding 'b2-2.1.0.dist-info/entry_points.txt' | |
adding 'b2-2.1.0.dist-info/top_level.txt' | |
adding 'b2-2.1.0.dist-info/RECORD' | |
removing build/bdist.linux-aarch64/wheel | |
Finished executing setuptoolsBuildPhase | |
@nix { "action": "setPhase", "phase": "installPhase" } | |
installing | |
Executing pipInstallPhase | |
/build/source/dist /build/source | |
Processing ./b2-2.1.0-py3-none-any.whl | |
Requirement already satisfied: arrow>=0.8.0 in /nix/store/mmlni6r50a1y4lx0wz9dvjrdz34fkqad-python3.8-arrow-1.0.3/lib/python3.8/site-packages (from b2==2.1.0) (1.0.3) | |
Requirement already satisfied: b2sdk<1.3.0,>=1.2.0 in /nix/store/pb7kma9yjlc6mdfmjcjg5ny7lpj2n03r-python3.8-b2sdk-1.2.0/lib/python3.8/site-packages (from b2==2.1.0) (1.2.0) | |
Requirement already satisfied: phx-class-registry==3.0.5 in /nix/store/vc766lbz14lfrk9z5dm5d3hnalwvyxgw-python3.8-phx-class-registry-3.0.5/lib/python3.8/site-packages (from b2==2.1.0) (3.0.5) | |
Requirement already satisfied: python-dateutil>=2.7.0 in /nix/store/i2820g6iww87vyrc88pi8c465a8nwphy-python3.8-python-dateutil-2.8.1/lib/python3.8/site-packages (from arrow>=0.8.0->b2==2.1.0) (2.8.1) | |
Requirement already satisfied: requests>=2.9.1 in /nix/store/izsx4zansdskx4b7g7b7wdqkprdkwncn-python3.8-requests-2.25.1/lib/python3.8/site-packages (from b2sdk<1.3.0,>=1.2.0->b2==2.1.0) (2.25.1) | |
Requirement already satisfied: logfury>=0.1.2 in /nix/store/yhpzi10n89acmxic9mcylls6fzbb86g2-python3.8-logfury-0.1.2/lib/python3.8/site-packages (from b2sdk<1.3.0,>=1.2.0->b2==2.1.0) (0.1.2) | |
Requirement already satisfied: tqdm>=4.5.0 in /nix/store/1j2agpqlnm0m30b887i7apr62w4w8av2-python3.8-tqdm-4.58.0/lib/python3.8/site-packages (from b2sdk<1.3.0,>=1.2.0->b2==2.1.0) (4.58.0) | |
Requirement already satisfied: funcsigs in /nix/store/g13v4dh84p1vmyz3ijjgjnmvqll431hn-python3.8-funcsigs-1.0.2/lib/python3.8/site-packages (from logfury>=0.1.2->b2sdk<1.3.0,>=1.2.0->b2==2.1.0) (1.0.2) | |
Requirement already satisfied: six>=1.10 in /nix/store/297qnsllxb0jxny1qk9bk2wvhpivzcx0-python3.8-six-1.15.0/lib/python3.8/site-packages (from logfury>=0.1.2->b2sdk<1.3.0,>=1.2.0->b2==2.1.0) (1.15.0) | |
Requirement already satisfied: certifi>=2017.4.17 in /nix/store/ysy3j81q1xqif6ymp9zsh7hggh061jph-python3.8-certifi-2020.12.5/lib/python3.8/site-packages (from requests>=2.9.1->b2sdk<1.3.0,>=1.2.0->b2==2.1.0) (2020.12.5) | |
Requirement already satisfied: idna<3,>=2.5 in /nix/store/gcv25pc0zhxbj5p8z5h40s9n4wapwpbp-python3.8-idna-2.10/lib/python3.8/site-packages (from requests>=2.9.1->b2sdk<1.3.0,>=1.2.0->b2==2.1.0) (2.10) | |
Requirement already satisfied: chardet<5,>=3.0.2 in /nix/store/hlaizclgicn1wm57k6yfqnkcdjrmxavp-python3.8-chardet-3.0.4/lib/python3.8/site-packages (from requests>=2.9.1->b2sdk<1.3.0,>=1.2.0->b2==2.1.0) (3.0.4) | |
Requirement already satisfied: urllib3<1.27,>=1.21.1 in /nix/store/p952ss6amdjfm9zy51qx0fh5b0hc89wg-python3.8-urllib3-1.26.3/lib/python3.8/site-packages (from requests>=2.9.1->b2sdk<1.3.0,>=1.2.0->b2==2.1.0) (1.26.3) | |
Installing collected packages: b2 | |
Successfully installed b2-2.1.0 | |
/build/source | |
Finished executing pipInstallPhase | |
@nix { "action": "setPhase", "phase": "fixupPhase" } | |
post-installation fixup | |
shrinking RPATHs of ELF executables and libraries in /nix/store/3xk3s5px6xfp96qq7rxgy91jzbwfzfx1-backblaze-b2-2.1.0 | |
strip is /nix/store/f73f3xbwv4zafyms2gi3djfgb9h3791b-binutils-2.35.1/bin/strip | |
stripping (with command strip and flags -S) in /nix/store/3xk3s5px6xfp96qq7rxgy91jzbwfzfx1-backblaze-b2-2.1.0/lib /nix/store/3xk3s5px6xfp96qq7rxgy91jzbwfzfx1-backblaze-b2-2.1.0/bin | |
patching script interpreter paths in /nix/store/3xk3s5px6xfp96qq7rxgy91jzbwfzfx1-backblaze-b2-2.1.0 | |
checking for references to /build/ in /nix/store/3xk3s5px6xfp96qq7rxgy91jzbwfzfx1-backblaze-b2-2.1.0... | |
Rewriting #!/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/bin/python3.8 to #!/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8 | |
wrapping `/nix/store/3xk3s5px6xfp96qq7rxgy91jzbwfzfx1-backblaze-b2-2.1.0/bin/backblaze-b2'... | |
Executing pythonRemoveTestsDir | |
Finished executing pythonRemoveTestsDir | |
@nix { "action": "setPhase", "phase": "installCheckPhase" } | |
running install tests | |
no Makefile or custom installCheckPhase, doing nothing | |
@nix { "action": "setPhase", "phase": "pythonCatchConflictsPhase" } | |
pythonCatchConflictsPhase | |
@nix { "action": "setPhase", "phase": "pythonRemoveBinBytecodePhase" } | |
pythonRemoveBinBytecodePhase | |
@nix { "action": "setPhase", "phase": "pythonImportsCheckPhase" } | |
pythonImportsCheckPhase | |
Executing pythonImportsCheckPhase | |
@nix { "action": "setPhase", "phase": "pytestCheckPhase" } | |
pytestCheckPhase | |
Executing pytestCheckPhase | |
============================= test session starts ============================== | |
platform linux -- Python 3.8.8, pytest-6.1.2, py-1.9.0, pluggy-0.13.1 | |
rootdir: /build/source | |
collecting ... | |
collecting 5 items | |
collected 52 items / 2 deselected / 50 selected | |
test/unit/test_arg_parser.py .F. [ 6%] | |
test/unit/test_console_tool.py ......................................... [ 88%] | |
...FF. [100%] | |
=================================== FAILURES =================================== | |
__________ TestCustomArgTypes.test_parse_millis_from_float_timestamp ___________ | |
self = <test.unit.test_arg_parser.TestCustomArgTypes testMethod=test_parse_millis_from_float_timestamp> | |
def test_parse_millis_from_float_timestamp(self): | |
> self.assertEqual(1367900664000, parse_millis_from_float_timestamp('1367900664')) | |
test/unit/test_arg_parser.py:25: | |
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
s = '1367900664' | |
def parse_millis_from_float_timestamp(s): | |
""" | |
Parse timestamp, e.g. 1367900664 or 1367900664.152 | |
""" | |
> return int(arrow.get(float(s)).format('XSSS')) | |
E ValueError: invalid literal for int() with base 10: '1367900664.0000' | |
b2/arg_parser.py:83: ValueError | |
__________ TestConsoleTool.test_sync_exclude_if_modified_after_exact ___________ | |
self = ArgumentParser(prog='b2 sync', usage=None, description='\n Copies multiple files from source to destination. Optiona...r uploading)\n', formatter_class=<class 'b2.arg_parser.RawTextHelpFormatter'>, conflict_handler='error', add_help=True) | |
action = _StoreAction(option_strings=['--excludeIfModifiedAfter'], dest='excludeIfModifiedAfter', nargs=None, const=None, defau...one, type=<function parse_millis_from_float_timestamp at 0xfffff674a820>, choices=None, help=None, metavar='TIMESTAMP') | |
arg_string = '1367600664.152' | |
def _get_value(self, action, arg_string): | |
type_func = self._registry_get('type', action.type, action.type) | |
if not callable(type_func): | |
msg = _('%r is not callable') | |
raise ArgumentError(action, msg % type_func) | |
# convert the value to the appropriate type | |
try: | |
> result = type_func(arg_string) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:2422: | |
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
s = '1367600664.152' | |
def parse_millis_from_float_timestamp(s): | |
""" | |
Parse timestamp, e.g. 1367900664 or 1367900664.152 | |
""" | |
> return int(arrow.get(float(s)).format('XSSS')) | |
E ValueError: invalid literal for int() with base 10: '1367600664.152152' | |
b2/arg_parser.py:83: ValueError | |
During handling of the above exception, another exception occurred: | |
self = ArgumentParser(prog='b2 sync', usage=None, description='\n Copies multiple files from source to destination. Optiona...r uploading)\n', formatter_class=<class 'b2.arg_parser.RawTextHelpFormatter'>, conflict_handler='error', add_help=True) | |
args = ['--threads', '1', '--noProgress', '--excludeIfModifiedAfter', '1367600664.152', '/build/tmprb5b94o0', ...] | |
namespace = Namespace(allowEmptySource=False, compareThreshold=None, compareVersions='modTime', debugLogs=False, delete=False, des...Days=None, logConfig=None, noProgress=True, replaceNewer=False, skipNewer=False, source=None, threads=1, verbose=False) | |
def parse_known_args(self, args=None, namespace=None): | |
if args is None: | |
# args default to the system args | |
args = _sys.argv[1:] | |
else: | |
# make sure that args are mutable | |
args = list(args) | |
# default Namespace built from parser defaults | |
if namespace is None: | |
namespace = Namespace() | |
# add any action defaults that aren't present | |
for action in self._actions: | |
if action.dest is not SUPPRESS: | |
if not hasattr(namespace, action.dest): | |
if action.default is not SUPPRESS: | |
setattr(namespace, action.dest, action.default) | |
# add any parser defaults that aren't present | |
for dest in self._defaults: | |
if not hasattr(namespace, dest): | |
setattr(namespace, dest, self._defaults[dest]) | |
# parse the arguments and exit if there are any errors | |
try: | |
> namespace, args = self._parse_known_args(args, namespace) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:1800: | |
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
self = ArgumentParser(prog='b2 sync', usage=None, description='\n Copies multiple files from source to destination. Optiona...r uploading)\n', formatter_class=<class 'b2.arg_parser.RawTextHelpFormatter'>, conflict_handler='error', add_help=True) | |
arg_strings = ['--threads', '1', '--noProgress', '--excludeIfModifiedAfter', '1367600664.152', '/build/tmprb5b94o0', ...] | |
namespace = Namespace(allowEmptySource=False, compareThreshold=None, compareVersions='modTime', debugLogs=False, delete=False, des...Days=None, logConfig=None, noProgress=True, replaceNewer=False, skipNewer=False, source=None, threads=1, verbose=False) | |
def _parse_known_args(self, arg_strings, namespace): | |
# replace arg strings that are file references | |
if self.fromfile_prefix_chars is not None: | |
arg_strings = self._read_args_from_files(arg_strings) | |
# map all mutually exclusive arguments to the other arguments | |
# they can't occur with | |
action_conflicts = {} | |
for mutex_group in self._mutually_exclusive_groups: | |
group_actions = mutex_group._group_actions | |
for i, mutex_action in enumerate(mutex_group._group_actions): | |
conflicts = action_conflicts.setdefault(mutex_action, []) | |
conflicts.extend(group_actions[:i]) | |
conflicts.extend(group_actions[i + 1:]) | |
# find all option indices, and determine the arg_string_pattern | |
# which has an 'O' if there is an option at an index, | |
# an 'A' if there is an argument, or a '-' if there is a '--' | |
option_string_indices = {} | |
arg_string_pattern_parts = [] | |
arg_strings_iter = iter(arg_strings) | |
for i, arg_string in enumerate(arg_strings_iter): | |
# all args after -- are non-options | |
if arg_string == '--': | |
arg_string_pattern_parts.append('-') | |
for arg_string in arg_strings_iter: | |
arg_string_pattern_parts.append('A') | |
# otherwise, add the arg to the arg strings | |
# and note the index if it was an option | |
else: | |
option_tuple = self._parse_optional(arg_string) | |
if option_tuple is None: | |
pattern = 'A' | |
else: | |
option_string_indices[i] = option_tuple | |
pattern = 'O' | |
arg_string_pattern_parts.append(pattern) | |
# join the pieces together to form the pattern | |
arg_strings_pattern = ''.join(arg_string_pattern_parts) | |
# converts arg strings to the appropriate and then takes the action | |
seen_actions = set() | |
seen_non_default_actions = set() | |
def take_action(action, argument_strings, option_string=None): | |
seen_actions.add(action) | |
argument_values = self._get_values(action, argument_strings) | |
# error if this argument is not allowed with other previously | |
# seen arguments, assuming that actions that use the default | |
# value don't really count as "present" | |
if argument_values is not action.default: | |
seen_non_default_actions.add(action) | |
for conflict_action in action_conflicts.get(action, []): | |
if conflict_action in seen_non_default_actions: | |
msg = _('not allowed with argument %s') | |
action_name = _get_action_name(conflict_action) | |
raise ArgumentError(action, msg % action_name) | |
# take the action if we didn't receive a SUPPRESS value | |
# (e.g. from a default) | |
if argument_values is not SUPPRESS: | |
action(self, namespace, argument_values, option_string) | |
# function to convert arg_strings into an optional action | |
def consume_optional(start_index): | |
# get the optional identified at this index | |
option_tuple = option_string_indices[start_index] | |
action, option_string, explicit_arg = option_tuple | |
# identify additional optionals in the same arg string | |
# (e.g. -xyz is the same as -x -y -z if no args are required) | |
match_argument = self._match_argument | |
action_tuples = [] | |
while True: | |
# if we found no optional action, skip it | |
if action is None: | |
extras.append(arg_strings[start_index]) | |
return start_index + 1 | |
# if there is an explicit argument, try to match the | |
# optional's string arguments to only this | |
if explicit_arg is not None: | |
arg_count = match_argument(action, 'A') | |
# if the action is a single-dash option and takes no | |
# arguments, try to parse more single-dash options out | |
# of the tail of the option string | |
chars = self.prefix_chars | |
if arg_count == 0 and option_string[1] not in chars: | |
action_tuples.append((action, [], option_string)) | |
char = option_string[0] | |
option_string = char + explicit_arg[0] | |
new_explicit_arg = explicit_arg[1:] or None | |
optionals_map = self._option_string_actions | |
if option_string in optionals_map: | |
action = optionals_map[option_string] | |
explicit_arg = new_explicit_arg | |
else: | |
msg = _('ignored explicit argument %r') | |
raise ArgumentError(action, msg % explicit_arg) | |
# if the action expect exactly one argument, we've | |
# successfully matched the option; exit the loop | |
elif arg_count == 1: | |
stop = start_index + 1 | |
args = [explicit_arg] | |
action_tuples.append((action, args, option_string)) | |
break | |
# error if a double-dash option did not use the | |
# explicit argument | |
else: | |
msg = _('ignored explicit argument %r') | |
raise ArgumentError(action, msg % explicit_arg) | |
# if there is no explicit argument, try to match the | |
# optional's string arguments with the following strings | |
# if successful, exit the loop | |
else: | |
start = start_index + 1 | |
selected_patterns = arg_strings_pattern[start:] | |
arg_count = match_argument(action, selected_patterns) | |
stop = start + arg_count | |
args = arg_strings[start:stop] | |
action_tuples.append((action, args, option_string)) | |
break | |
# add the Optional to the list and return the index at which | |
# the Optional's string args stopped | |
assert action_tuples | |
for action, args, option_string in action_tuples: | |
take_action(action, args, option_string) | |
return stop | |
# the list of Positionals left to be parsed; this is modified | |
# by consume_positionals() | |
positionals = self._get_positional_actions() | |
# function to convert arg_strings into positional actions | |
def consume_positionals(start_index): | |
# match as many Positionals as possible | |
match_partial = self._match_arguments_partial | |
selected_pattern = arg_strings_pattern[start_index:] | |
arg_counts = match_partial(positionals, selected_pattern) | |
# slice off the appropriate arg strings for each Positional | |
# and add the Positional and its args to the list | |
for action, arg_count in zip(positionals, arg_counts): | |
args = arg_strings[start_index: start_index + arg_count] | |
start_index += arg_count | |
take_action(action, args) | |
# slice off the Positionals that we just parsed and return the | |
# index at which the Positionals' string args stopped | |
positionals[:] = positionals[len(arg_counts):] | |
return start_index | |
# consume Positionals and Optionals alternately, until we have | |
# passed the last option string | |
extras = [] | |
start_index = 0 | |
if option_string_indices: | |
max_option_string_index = max(option_string_indices) | |
else: | |
max_option_string_index = -1 | |
while start_index <= max_option_string_index: | |
# consume any Positionals preceding the next option | |
next_option_string_index = min([ | |
index | |
for index in option_string_indices | |
if index >= start_index]) | |
if start_index != next_option_string_index: | |
positionals_end_index = consume_positionals(start_index) | |
# only try to parse the next optional if we didn't consume | |
# the option string during the positionals parsing | |
if positionals_end_index > start_index: | |
start_index = positionals_end_index | |
continue | |
else: | |
start_index = positionals_end_index | |
# if we consumed all the positionals we could and we're not | |
# at the index of an option string, there were extra arguments | |
if start_index not in option_string_indices: | |
strings = arg_strings[start_index:next_option_string_index] | |
extras.extend(strings) | |
start_index = next_option_string_index | |
# consume the next optional and any arguments for it | |
> start_index = consume_optional(start_index) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:2006: | |
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
start_index = 3 | |
def consume_optional(start_index): | |
# get the optional identified at this index | |
option_tuple = option_string_indices[start_index] | |
action, option_string, explicit_arg = option_tuple | |
# identify additional optionals in the same arg string | |
# (e.g. -xyz is the same as -x -y -z if no args are required) | |
match_argument = self._match_argument | |
action_tuples = [] | |
while True: | |
# if we found no optional action, skip it | |
if action is None: | |
extras.append(arg_strings[start_index]) | |
return start_index + 1 | |
# if there is an explicit argument, try to match the | |
# optional's string arguments to only this | |
if explicit_arg is not None: | |
arg_count = match_argument(action, 'A') | |
# if the action is a single-dash option and takes no | |
# arguments, try to parse more single-dash options out | |
# of the tail of the option string | |
chars = self.prefix_chars | |
if arg_count == 0 and option_string[1] not in chars: | |
action_tuples.append((action, [], option_string)) | |
char = option_string[0] | |
option_string = char + explicit_arg[0] | |
new_explicit_arg = explicit_arg[1:] or None | |
optionals_map = self._option_string_actions | |
if option_string in optionals_map: | |
action = optionals_map[option_string] | |
explicit_arg = new_explicit_arg | |
else: | |
msg = _('ignored explicit argument %r') | |
raise ArgumentError(action, msg % explicit_arg) | |
# if the action expect exactly one argument, we've | |
# successfully matched the option; exit the loop | |
elif arg_count == 1: | |
stop = start_index + 1 | |
args = [explicit_arg] | |
action_tuples.append((action, args, option_string)) | |
break | |
# error if a double-dash option did not use the | |
# explicit argument | |
else: | |
msg = _('ignored explicit argument %r') | |
raise ArgumentError(action, msg % explicit_arg) | |
# if there is no explicit argument, try to match the | |
# optional's string arguments with the following strings | |
# if successful, exit the loop | |
else: | |
start = start_index + 1 | |
selected_patterns = arg_strings_pattern[start:] | |
arg_count = match_argument(action, selected_patterns) | |
stop = start + arg_count | |
args = arg_strings[start:stop] | |
action_tuples.append((action, args, option_string)) | |
break | |
# add the Optional to the list and return the index at which | |
# the Optional's string args stopped | |
assert action_tuples | |
for action, args, option_string in action_tuples: | |
> take_action(action, args, option_string) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:1946: | |
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
action = _StoreAction(option_strings=['--excludeIfModifiedAfter'], dest='excludeIfModifiedAfter', nargs=None, const=None, defau...one, type=<function parse_millis_from_float_timestamp at 0xfffff674a820>, choices=None, help=None, metavar='TIMESTAMP') | |
argument_strings = ['1367600664.152'] | |
option_string = '--excludeIfModifiedAfter' | |
def take_action(action, argument_strings, option_string=None): | |
seen_actions.add(action) | |
> argument_values = self._get_values(action, argument_strings) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:1858: | |
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
self = ArgumentParser(prog='b2 sync', usage=None, description='\n Copies multiple files from source to destination. Optiona...r uploading)\n', formatter_class=<class 'b2.arg_parser.RawTextHelpFormatter'>, conflict_handler='error', add_help=True) | |
action = _StoreAction(option_strings=['--excludeIfModifiedAfter'], dest='excludeIfModifiedAfter', nargs=None, const=None, defau...one, type=<function parse_millis_from_float_timestamp at 0xfffff674a820>, choices=None, help=None, metavar='TIMESTAMP') | |
arg_strings = ['1367600664.152'] | |
def _get_values(self, action, arg_strings): | |
# for everything but PARSER, REMAINDER args, strip out first '--' | |
if action.nargs not in [PARSER, REMAINDER]: | |
try: | |
arg_strings.remove('--') | |
except ValueError: | |
pass | |
# optional argument produces a default when not present | |
if not arg_strings and action.nargs == OPTIONAL: | |
if action.option_strings: | |
value = action.const | |
else: | |
value = action.default | |
if isinstance(value, str): | |
value = self._get_value(action, value) | |
self._check_value(action, value) | |
# when nargs='*' on a positional, if there were no command-line | |
# args, use the default if it is anything other than None | |
elif (not arg_strings and action.nargs == ZERO_OR_MORE and | |
not action.option_strings): | |
if action.default is not None: | |
value = action.default | |
else: | |
value = arg_strings | |
self._check_value(action, value) | |
# single argument or optional argument produces a single value | |
elif len(arg_strings) == 1 and action.nargs in [None, OPTIONAL]: | |
arg_string, = arg_strings | |
> value = self._get_value(action, arg_string) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:2389: | |
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
self = ArgumentParser(prog='b2 sync', usage=None, description='\n Copies multiple files from source to destination. Optiona...r uploading)\n', formatter_class=<class 'b2.arg_parser.RawTextHelpFormatter'>, conflict_handler='error', add_help=True) | |
action = _StoreAction(option_strings=['--excludeIfModifiedAfter'], dest='excludeIfModifiedAfter', nargs=None, const=None, defau...one, type=<function parse_millis_from_float_timestamp at 0xfffff674a820>, choices=None, help=None, metavar='TIMESTAMP') | |
arg_string = '1367600664.152' | |
def _get_value(self, action, arg_string): | |
type_func = self._registry_get('type', action.type, action.type) | |
if not callable(type_func): | |
msg = _('%r is not callable') | |
raise ArgumentError(action, msg % type_func) | |
# convert the value to the appropriate type | |
try: | |
result = type_func(arg_string) | |
# ArgumentTypeErrors indicate errors | |
except ArgumentTypeError: | |
name = getattr(action.type, '__name__', repr(action.type)) | |
msg = str(_sys.exc_info()[1]) | |
raise ArgumentError(action, msg) | |
# TypeErrors or ValueErrors also indicate errors | |
except (TypeError, ValueError): | |
name = getattr(action.type, '__name__', repr(action.type)) | |
args = {'type': name, 'value': arg_string} | |
msg = _('invalid %(type)s value: %(value)r') | |
> raise ArgumentError(action, msg % args) | |
E argparse.ArgumentError: argument --excludeIfModifiedAfter: invalid parse_millis_from_float_timestamp value: '1367600664.152' | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:2435: ArgumentError | |
During handling of the above exception, another exception occurred: | |
self = <test.unit.test_console_tool.TestConsoleTool testMethod=test_sync_exclude_if_modified_after_exact> | |
def test_sync_exclude_if_modified_after_exact(self): | |
self._authorize_account() | |
self._create_my_bucket() | |
with TempDir() as temp_dir: | |
for file, mtime in (('test.txt', 1367900664.152), ('test2.txt', 1367600664.152)): | |
self._make_local_file(temp_dir, file) | |
path = os.path.join(temp_dir, file) | |
os.utime(path, (mtime, mtime)) | |
expected_stdout = ''' | |
upload test2.txt | |
''' | |
command = [ | |
'sync', '--threads', '1', '--noProgress', '--excludeIfModifiedAfter', | |
'1367600664.152', temp_dir, 'b2://my-bucket' | |
] | |
> self._run_command(command, expected_stdout, '', 0) | |
test/unit/test_console_tool.py:1330: | |
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
test/unit/test_console_tool.py:1559: in _run_command | |
actual_status = console_tool.run_command(['b2'] + argv) | |
b2/console_tool.py:1513: in run_command | |
args = b2_command.get_parser().parse_args(argv[1:]) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:1768: in parse_args | |
args, argv = self.parse_known_args(args, namespace) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:1800: in parse_known_args | |
namespace, args = self._parse_known_args(args, namespace) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:1988: in _parse_known_args | |
positionals_end_index = consume_positionals(start_index) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:1965: in consume_positionals | |
take_action(action, args) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:1874: in take_action | |
action(self, namespace, argument_values, option_string) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:1159: in __call__ | |
subnamespace, arg_strings = parser.parse_known_args(arg_strings, None) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:1807: in parse_known_args | |
self.error(str(err)) | |
b2/arg_parser.py:65: in error | |
self.exit(2, '\n%(prog)s: error: %(message)s\n' % args) | |
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
self = ArgumentParser(prog='b2 sync', usage=None, description='\n Copies multiple files from source to destination. Optiona...r uploading)\n', formatter_class=<class 'b2.arg_parser.RawTextHelpFormatter'>, conflict_handler='error', add_help=True) | |
status = 2 | |
message = "\nb2 sync: error: argument --excludeIfModifiedAfter: invalid parse_millis_from_float_timestamp value: '1367600664.152'\n" | |
def exit(self, status=0, message=None): | |
if message: | |
self._print_message(message, _sys.stderr) | |
> _sys.exit(status) | |
E SystemExit: 2 | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:2508: SystemExit | |
----------------------------- Captured stdout call ----------------------------- | |
b2 sync [-h] [--noProgress] [--dryRun] [--allowEmptySource] | |
[--excludeAllSymlinks] [--threads THREADS] | |
[--compareVersions {none,modTime,size}] [--compareThreshold MILLIS] | |
[--excludeRegex REGEX] [--includeRegex REGEX] | |
[--excludeDirRegex REGEX] [--excludeIfModifiedAfter TIMESTAMP] | |
[--skipNewer | --replaceNewer] [--delete | --keepDays DAYS] | |
source destination | |
Copies multiple files from source to destination. Optionally | |
deletes or hides destination files that the source does not have. | |
The synchronizer can copy files: | |
- From a B2 bucket to a local destination. | |
- From a local source to a B2 bucket. | |
- From one B2 bucket to another. | |
- Between different folders in the same B2 bucket. | |
Use "b2://<bucketName>/<prefix>" for B2 paths, e.g. "b2://my-bucket-name/a/path/prefix/". | |
Progress is displayed on the console unless '--noProgress' is | |
specified. A list of actions taken is always printed. | |
Specify '--dryRun' to simulate the actions that would be taken. | |
To allow sync to run when the source directory is empty, potentially | |
deleting all files in a bucket, specify '--allowEmptySource'. | |
The default is to fail when the specified source directory doesn't exist | |
or is empty. (This check only applies to version 1.0 and later.) | |
Users with high-performance networks, or file sets with very small | |
files, will benefit from multi-threaded uploads. The default number | |
of threads is 10. Experiment with the --threads parameter if the | |
default is not working well. | |
Users with low-performance networks may benefit from reducing the | |
number of threads. Using just one thread will minimize the impact | |
on other users of the network. | |
Note that using multiple threads will usually be detrimental to | |
the other users on your network. | |
You can specify --excludeRegex to selectively ignore files that | |
match the given pattern. Ignored files will not copy during | |
the sync operation. The pattern is a regular expression | |
that is tested against the full path of each file. | |
You can specify --includeRegex to selectively override ignoring | |
files that match the given --excludeRegex pattern by an | |
--includeRegex pattern. Similarly to --excludeRegex, the pattern | |
is a regular expression that is tested against the full path | |
of each file. | |
Note that --includeRegex cannot be used without --excludeRegex. | |
You can specify --excludeAllSymlinks to skip symlinks when | |
syncing from a local source. | |
When a directory is excluded by using --excludeDirRegex, all of | |
the files within it are excluded, even if they match an --includeRegex | |
pattern. This means that there is no need to look inside excluded | |
directories, and you can exclude directories containing files for which | |
you don't have read permission and avoid getting errors. | |
The --excludeDirRegex is a regular expression that is tested against | |
the full path of each directory. The path being matched does not have | |
a trailing '/', so don't include on in your regular expression. | |
Multiple regex rules can be applied by supplying them as pipe | |
delimited instructions. Note that the regex for this command | |
is Python regex. Reference: https://docs.python.org/2/library/re.html. | |
Regular expressions are considered a match if they match a substring | |
starting at the first character. ".*e" will match "hello". This is | |
not ideal, but we will maintain this behavior for compatibility. | |
If you want to match the entire path, put a "$" at the end of the | |
regex, such as ".*llo$". | |
You can specify --excludeIfModifiedAfter to selectively ignore file versions | |
(including hide markers) which were synced after given time (for local source) | |
or ignore only specific file versions (for b2 source). | |
Ignored files or file versions will not be taken for consideration during sync. | |
The time should be given as a seconds timestamp (e.g. "1367900664") | |
If you need milliseconds precision, put it after the comma (e.g. "1367900664.152") | |
Files are considered to be the same if they have the same name | |
and modification time. This behaviour can be changed using the | |
--compareVersions option. Possible values are: | |
'none': Comparison using the file name only | |
'modTime': Comparison using the modification time (default) | |
'size': Comparison using the file size | |
A future enhancement may add the ability to compare the SHA1 checksum | |
of the files. | |
Fuzzy comparison of files based on modTime or size can be enabled by | |
specifying the --compareThreshold option. This will treat modTimes | |
(in milliseconds) or sizes (in bytes) as the same if they are within | |
the comparison threshold. Files that match, within the threshold, will | |
not be synced. Specifying --verbose and --dryRun can be useful to | |
determine comparison value differences. | |
When a destination file is present that is not in the source, the | |
default is to leave it there. Specifying --delete means to delete | |
destination files that are not in the source. | |
When the destination is B2, you have the option of leaving older | |
versions in place. Specifying --keepDays will delete any older | |
versions more than the given number of days old, based on the | |
modification time of the file. This option is not available when | |
the destination is a local folder. | |
Files at the source that have a newer modification time are always | |
copied to the destination. If the destination file is newer, the | |
default is to report an error and stop. But with --skipNewer set, | |
those files will just be skipped. With --replaceNewer set, the | |
old file from the source will replace the newer one in the destination. | |
To make the destination exactly match the source, use: | |
b2 sync --delete --replaceNewer ... ... | |
WARNING: Using '--delete' deletes files! We recommend not using it. | |
If you use --keepDays instead, you will have some time to recover your | |
files if you discover they are missing on the source end. | |
To make the destination match the source, but retain previous versions | |
for 30 days: | |
b2 sync --keepDays 30 --replaceNewer ... b2://... | |
Example of sync being used with excludeRegex. This will ignore .DS_Store files | |
and .Spotlight-V100 folders | |
b2 sync -excludeRegex '(.*\.DS_Store)|(.*\.Spotlight-V100)' ... b2://... | |
Requires capabilities: listFiles, readFiles (for downloading), writeFiles (for uploading) | |
positional arguments: | |
source | |
destination | |
optional arguments: | |
-h, --help show this help message and exit | |
--noProgress | |
--dryRun | |
--allowEmptySource | |
--excludeAllSymlinks | |
--threads THREADS | |
--compareVersions {none,modTime,size} | |
--compareThreshold MILLIS | |
--excludeRegex REGEX | |
--includeRegex REGEX | |
--excludeDirRegex REGEX | |
--excludeIfModifiedAfter TIMESTAMP | |
--skipNewer | |
--replaceNewer | |
--delete | |
--keepDays DAYS | |
----------------------------- Captured stderr call ----------------------------- | |
b2 sync: error: argument --excludeIfModifiedAfter: invalid parse_millis_from_float_timestamp value: '1367600664.152' | |
_________ TestConsoleTool.test_sync_exclude_if_modified_after_in_range _________ | |
self = ArgumentParser(prog='b2 sync', usage=None, description='\n Copies multiple files from source to destination. Optiona...r uploading)\n', formatter_class=<class 'b2.arg_parser.RawTextHelpFormatter'>, conflict_handler='error', add_help=True) | |
action = _StoreAction(option_strings=['--excludeIfModifiedAfter'], dest='excludeIfModifiedAfter', nargs=None, const=None, defau...one, type=<function parse_millis_from_float_timestamp at 0xfffff674a820>, choices=None, help=None, metavar='TIMESTAMP') | |
arg_string = '1367700664.152' | |
def _get_value(self, action, arg_string): | |
type_func = self._registry_get('type', action.type, action.type) | |
if not callable(type_func): | |
msg = _('%r is not callable') | |
raise ArgumentError(action, msg % type_func) | |
# convert the value to the appropriate type | |
try: | |
> result = type_func(arg_string) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:2422: | |
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
s = '1367700664.152' | |
def parse_millis_from_float_timestamp(s): | |
""" | |
Parse timestamp, e.g. 1367900664 or 1367900664.152 | |
""" | |
> return int(arrow.get(float(s)).format('XSSS')) | |
E ValueError: invalid literal for int() with base 10: '1367700664.152152' | |
b2/arg_parser.py:83: ValueError | |
During handling of the above exception, another exception occurred: | |
self = ArgumentParser(prog='b2 sync', usage=None, description='\n Copies multiple files from source to destination. Optiona...r uploading)\n', formatter_class=<class 'b2.arg_parser.RawTextHelpFormatter'>, conflict_handler='error', add_help=True) | |
args = ['--threads', '1', '--noProgress', '--excludeIfModifiedAfter', '1367700664.152', '/build/tmpzt9zd3z5', ...] | |
namespace = Namespace(allowEmptySource=False, compareThreshold=None, compareVersions='modTime', debugLogs=False, delete=False, des...Days=None, logConfig=None, noProgress=True, replaceNewer=False, skipNewer=False, source=None, threads=1, verbose=False) | |
def parse_known_args(self, args=None, namespace=None): | |
if args is None: | |
# args default to the system args | |
args = _sys.argv[1:] | |
else: | |
# make sure that args are mutable | |
args = list(args) | |
# default Namespace built from parser defaults | |
if namespace is None: | |
namespace = Namespace() | |
# add any action defaults that aren't present | |
for action in self._actions: | |
if action.dest is not SUPPRESS: | |
if not hasattr(namespace, action.dest): | |
if action.default is not SUPPRESS: | |
setattr(namespace, action.dest, action.default) | |
# add any parser defaults that aren't present | |
for dest in self._defaults: | |
if not hasattr(namespace, dest): | |
setattr(namespace, dest, self._defaults[dest]) | |
# parse the arguments and exit if there are any errors | |
try: | |
> namespace, args = self._parse_known_args(args, namespace) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:1800: | |
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
self = ArgumentParser(prog='b2 sync', usage=None, description='\n Copies multiple files from source to destination. Optiona...r uploading)\n', formatter_class=<class 'b2.arg_parser.RawTextHelpFormatter'>, conflict_handler='error', add_help=True) | |
arg_strings = ['--threads', '1', '--noProgress', '--excludeIfModifiedAfter', '1367700664.152', '/build/tmpzt9zd3z5', ...] | |
namespace = Namespace(allowEmptySource=False, compareThreshold=None, compareVersions='modTime', debugLogs=False, delete=False, des...Days=None, logConfig=None, noProgress=True, replaceNewer=False, skipNewer=False, source=None, threads=1, verbose=False) | |
def _parse_known_args(self, arg_strings, namespace): | |
# replace arg strings that are file references | |
if self.fromfile_prefix_chars is not None: | |
arg_strings = self._read_args_from_files(arg_strings) | |
# map all mutually exclusive arguments to the other arguments | |
# they can't occur with | |
action_conflicts = {} | |
for mutex_group in self._mutually_exclusive_groups: | |
group_actions = mutex_group._group_actions | |
for i, mutex_action in enumerate(mutex_group._group_actions): | |
conflicts = action_conflicts.setdefault(mutex_action, []) | |
conflicts.extend(group_actions[:i]) | |
conflicts.extend(group_actions[i + 1:]) | |
# find all option indices, and determine the arg_string_pattern | |
# which has an 'O' if there is an option at an index, | |
# an 'A' if there is an argument, or a '-' if there is a '--' | |
option_string_indices = {} | |
arg_string_pattern_parts = [] | |
arg_strings_iter = iter(arg_strings) | |
for i, arg_string in enumerate(arg_strings_iter): | |
# all args after -- are non-options | |
if arg_string == '--': | |
arg_string_pattern_parts.append('-') | |
for arg_string in arg_strings_iter: | |
arg_string_pattern_parts.append('A') | |
# otherwise, add the arg to the arg strings | |
# and note the index if it was an option | |
else: | |
option_tuple = self._parse_optional(arg_string) | |
if option_tuple is None: | |
pattern = 'A' | |
else: | |
option_string_indices[i] = option_tuple | |
pattern = 'O' | |
arg_string_pattern_parts.append(pattern) | |
# join the pieces together to form the pattern | |
arg_strings_pattern = ''.join(arg_string_pattern_parts) | |
# converts arg strings to the appropriate and then takes the action | |
seen_actions = set() | |
seen_non_default_actions = set() | |
def take_action(action, argument_strings, option_string=None): | |
seen_actions.add(action) | |
argument_values = self._get_values(action, argument_strings) | |
# error if this argument is not allowed with other previously | |
# seen arguments, assuming that actions that use the default | |
# value don't really count as "present" | |
if argument_values is not action.default: | |
seen_non_default_actions.add(action) | |
for conflict_action in action_conflicts.get(action, []): | |
if conflict_action in seen_non_default_actions: | |
msg = _('not allowed with argument %s') | |
action_name = _get_action_name(conflict_action) | |
raise ArgumentError(action, msg % action_name) | |
# take the action if we didn't receive a SUPPRESS value | |
# (e.g. from a default) | |
if argument_values is not SUPPRESS: | |
action(self, namespace, argument_values, option_string) | |
# function to convert arg_strings into an optional action | |
def consume_optional(start_index): | |
# get the optional identified at this index | |
option_tuple = option_string_indices[start_index] | |
action, option_string, explicit_arg = option_tuple | |
# identify additional optionals in the same arg string | |
# (e.g. -xyz is the same as -x -y -z if no args are required) | |
match_argument = self._match_argument | |
action_tuples = [] | |
while True: | |
# if we found no optional action, skip it | |
if action is None: | |
extras.append(arg_strings[start_index]) | |
return start_index + 1 | |
# if there is an explicit argument, try to match the | |
# optional's string arguments to only this | |
if explicit_arg is not None: | |
arg_count = match_argument(action, 'A') | |
# if the action is a single-dash option and takes no | |
# arguments, try to parse more single-dash options out | |
# of the tail of the option string | |
chars = self.prefix_chars | |
if arg_count == 0 and option_string[1] not in chars: | |
action_tuples.append((action, [], option_string)) | |
char = option_string[0] | |
option_string = char + explicit_arg[0] | |
new_explicit_arg = explicit_arg[1:] or None | |
optionals_map = self._option_string_actions | |
if option_string in optionals_map: | |
action = optionals_map[option_string] | |
explicit_arg = new_explicit_arg | |
else: | |
msg = _('ignored explicit argument %r') | |
raise ArgumentError(action, msg % explicit_arg) | |
# if the action expect exactly one argument, we've | |
# successfully matched the option; exit the loop | |
elif arg_count == 1: | |
stop = start_index + 1 | |
args = [explicit_arg] | |
action_tuples.append((action, args, option_string)) | |
break | |
# error if a double-dash option did not use the | |
# explicit argument | |
else: | |
msg = _('ignored explicit argument %r') | |
raise ArgumentError(action, msg % explicit_arg) | |
# if there is no explicit argument, try to match the | |
# optional's string arguments with the following strings | |
# if successful, exit the loop | |
else: | |
start = start_index + 1 | |
selected_patterns = arg_strings_pattern[start:] | |
arg_count = match_argument(action, selected_patterns) | |
stop = start + arg_count | |
args = arg_strings[start:stop] | |
action_tuples.append((action, args, option_string)) | |
break | |
# add the Optional to the list and return the index at which | |
# the Optional's string args stopped | |
assert action_tuples | |
for action, args, option_string in action_tuples: | |
take_action(action, args, option_string) | |
return stop | |
# the list of Positionals left to be parsed; this is modified | |
# by consume_positionals() | |
positionals = self._get_positional_actions() | |
# function to convert arg_strings into positional actions | |
def consume_positionals(start_index): | |
# match as many Positionals as possible | |
match_partial = self._match_arguments_partial | |
selected_pattern = arg_strings_pattern[start_index:] | |
arg_counts = match_partial(positionals, selected_pattern) | |
# slice off the appropriate arg strings for each Positional | |
# and add the Positional and its args to the list | |
for action, arg_count in zip(positionals, arg_counts): | |
args = arg_strings[start_index: start_index + arg_count] | |
start_index += arg_count | |
take_action(action, args) | |
# slice off the Positionals that we just parsed and return the | |
# index at which the Positionals' string args stopped | |
positionals[:] = positionals[len(arg_counts):] | |
return start_index | |
# consume Positionals and Optionals alternately, until we have | |
# passed the last option string | |
extras = [] | |
start_index = 0 | |
if option_string_indices: | |
max_option_string_index = max(option_string_indices) | |
else: | |
max_option_string_index = -1 | |
while start_index <= max_option_string_index: | |
# consume any Positionals preceding the next option | |
next_option_string_index = min([ | |
index | |
for index in option_string_indices | |
if index >= start_index]) | |
if start_index != next_option_string_index: | |
positionals_end_index = consume_positionals(start_index) | |
# only try to parse the next optional if we didn't consume | |
# the option string during the positionals parsing | |
if positionals_end_index > start_index: | |
start_index = positionals_end_index | |
continue | |
else: | |
start_index = positionals_end_index | |
# if we consumed all the positionals we could and we're not | |
# at the index of an option string, there were extra arguments | |
if start_index not in option_string_indices: | |
strings = arg_strings[start_index:next_option_string_index] | |
extras.extend(strings) | |
start_index = next_option_string_index | |
# consume the next optional and any arguments for it | |
> start_index = consume_optional(start_index) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:2006: | |
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
start_index = 3 | |
def consume_optional(start_index): | |
# get the optional identified at this index | |
option_tuple = option_string_indices[start_index] | |
action, option_string, explicit_arg = option_tuple | |
# identify additional optionals in the same arg string | |
# (e.g. -xyz is the same as -x -y -z if no args are required) | |
match_argument = self._match_argument | |
action_tuples = [] | |
while True: | |
# if we found no optional action, skip it | |
if action is None: | |
extras.append(arg_strings[start_index]) | |
return start_index + 1 | |
# if there is an explicit argument, try to match the | |
# optional's string arguments to only this | |
if explicit_arg is not None: | |
arg_count = match_argument(action, 'A') | |
# if the action is a single-dash option and takes no | |
# arguments, try to parse more single-dash options out | |
# of the tail of the option string | |
chars = self.prefix_chars | |
if arg_count == 0 and option_string[1] not in chars: | |
action_tuples.append((action, [], option_string)) | |
char = option_string[0] | |
option_string = char + explicit_arg[0] | |
new_explicit_arg = explicit_arg[1:] or None | |
optionals_map = self._option_string_actions | |
if option_string in optionals_map: | |
action = optionals_map[option_string] | |
explicit_arg = new_explicit_arg | |
else: | |
msg = _('ignored explicit argument %r') | |
raise ArgumentError(action, msg % explicit_arg) | |
# if the action expect exactly one argument, we've | |
# successfully matched the option; exit the loop | |
elif arg_count == 1: | |
stop = start_index + 1 | |
args = [explicit_arg] | |
action_tuples.append((action, args, option_string)) | |
break | |
# error if a double-dash option did not use the | |
# explicit argument | |
else: | |
msg = _('ignored explicit argument %r') | |
raise ArgumentError(action, msg % explicit_arg) | |
# if there is no explicit argument, try to match the | |
# optional's string arguments with the following strings | |
# if successful, exit the loop | |
else: | |
start = start_index + 1 | |
selected_patterns = arg_strings_pattern[start:] | |
arg_count = match_argument(action, selected_patterns) | |
stop = start + arg_count | |
args = arg_strings[start:stop] | |
action_tuples.append((action, args, option_string)) | |
break | |
# add the Optional to the list and return the index at which | |
# the Optional's string args stopped | |
assert action_tuples | |
for action, args, option_string in action_tuples: | |
> take_action(action, args, option_string) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:1946: | |
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
action = _StoreAction(option_strings=['--excludeIfModifiedAfter'], dest='excludeIfModifiedAfter', nargs=None, const=None, defau...one, type=<function parse_millis_from_float_timestamp at 0xfffff674a820>, choices=None, help=None, metavar='TIMESTAMP') | |
argument_strings = ['1367700664.152'] | |
option_string = '--excludeIfModifiedAfter' | |
def take_action(action, argument_strings, option_string=None): | |
seen_actions.add(action) | |
> argument_values = self._get_values(action, argument_strings) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:1858: | |
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
self = ArgumentParser(prog='b2 sync', usage=None, description='\n Copies multiple files from source to destination. Optiona...r uploading)\n', formatter_class=<class 'b2.arg_parser.RawTextHelpFormatter'>, conflict_handler='error', add_help=True) | |
action = _StoreAction(option_strings=['--excludeIfModifiedAfter'], dest='excludeIfModifiedAfter', nargs=None, const=None, defau...one, type=<function parse_millis_from_float_timestamp at 0xfffff674a820>, choices=None, help=None, metavar='TIMESTAMP') | |
arg_strings = ['1367700664.152'] | |
def _get_values(self, action, arg_strings): | |
# for everything but PARSER, REMAINDER args, strip out first '--' | |
if action.nargs not in [PARSER, REMAINDER]: | |
try: | |
arg_strings.remove('--') | |
except ValueError: | |
pass | |
# optional argument produces a default when not present | |
if not arg_strings and action.nargs == OPTIONAL: | |
if action.option_strings: | |
value = action.const | |
else: | |
value = action.default | |
if isinstance(value, str): | |
value = self._get_value(action, value) | |
self._check_value(action, value) | |
# when nargs='*' on a positional, if there were no command-line | |
# args, use the default if it is anything other than None | |
elif (not arg_strings and action.nargs == ZERO_OR_MORE and | |
not action.option_strings): | |
if action.default is not None: | |
value = action.default | |
else: | |
value = arg_strings | |
self._check_value(action, value) | |
# single argument or optional argument produces a single value | |
elif len(arg_strings) == 1 and action.nargs in [None, OPTIONAL]: | |
arg_string, = arg_strings | |
> value = self._get_value(action, arg_string) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:2389: | |
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
self = ArgumentParser(prog='b2 sync', usage=None, description='\n Copies multiple files from source to destination. Optiona...r uploading)\n', formatter_class=<class 'b2.arg_parser.RawTextHelpFormatter'>, conflict_handler='error', add_help=True) | |
action = _StoreAction(option_strings=['--excludeIfModifiedAfter'], dest='excludeIfModifiedAfter', nargs=None, const=None, defau...one, type=<function parse_millis_from_float_timestamp at 0xfffff674a820>, choices=None, help=None, metavar='TIMESTAMP') | |
arg_string = '1367700664.152' | |
def _get_value(self, action, arg_string): | |
type_func = self._registry_get('type', action.type, action.type) | |
if not callable(type_func): | |
msg = _('%r is not callable') | |
raise ArgumentError(action, msg % type_func) | |
# convert the value to the appropriate type | |
try: | |
result = type_func(arg_string) | |
# ArgumentTypeErrors indicate errors | |
except ArgumentTypeError: | |
name = getattr(action.type, '__name__', repr(action.type)) | |
msg = str(_sys.exc_info()[1]) | |
raise ArgumentError(action, msg) | |
# TypeErrors or ValueErrors also indicate errors | |
except (TypeError, ValueError): | |
name = getattr(action.type, '__name__', repr(action.type)) | |
args = {'type': name, 'value': arg_string} | |
msg = _('invalid %(type)s value: %(value)r') | |
> raise ArgumentError(action, msg % args) | |
E argparse.ArgumentError: argument --excludeIfModifiedAfter: invalid parse_millis_from_float_timestamp value: '1367700664.152' | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:2435: ArgumentError | |
During handling of the above exception, another exception occurred: | |
self = <test.unit.test_console_tool.TestConsoleTool testMethod=test_sync_exclude_if_modified_after_in_range> | |
def test_sync_exclude_if_modified_after_in_range(self): | |
self._authorize_account() | |
self._create_my_bucket() | |
with TempDir() as temp_dir: | |
for file, mtime in (('test.txt', 1367900664.152), ('test2.txt', 1367600664.152)): | |
self._make_local_file(temp_dir, file) | |
path = os.path.join(temp_dir, file) | |
os.utime(path, (mtime, mtime)) | |
expected_stdout = ''' | |
upload test2.txt | |
''' | |
command = [ | |
'sync', '--threads', '1', '--noProgress', '--excludeIfModifiedAfter', | |
'1367700664.152', temp_dir, 'b2://my-bucket' | |
] | |
> self._run_command(command, expected_stdout, '', 0) | |
test/unit/test_console_tool.py:1310: | |
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
test/unit/test_console_tool.py:1559: in _run_command | |
actual_status = console_tool.run_command(['b2'] + argv) | |
b2/console_tool.py:1513: in run_command | |
args = b2_command.get_parser().parse_args(argv[1:]) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:1768: in parse_args | |
args, argv = self.parse_known_args(args, namespace) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:1800: in parse_known_args | |
namespace, args = self._parse_known_args(args, namespace) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:1988: in _parse_known_args | |
positionals_end_index = consume_positionals(start_index) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:1965: in consume_positionals | |
take_action(action, args) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:1874: in take_action | |
action(self, namespace, argument_values, option_string) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:1159: in __call__ | |
subnamespace, arg_strings = parser.parse_known_args(arg_strings, None) | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:1807: in parse_known_args | |
self.error(str(err)) | |
b2/arg_parser.py:65: in error | |
self.exit(2, '\n%(prog)s: error: %(message)s\n' % args) | |
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |
self = ArgumentParser(prog='b2 sync', usage=None, description='\n Copies multiple files from source to destination. Optiona...r uploading)\n', formatter_class=<class 'b2.arg_parser.RawTextHelpFormatter'>, conflict_handler='error', add_help=True) | |
status = 2 | |
message = "\nb2 sync: error: argument --excludeIfModifiedAfter: invalid parse_millis_from_float_timestamp value: '1367700664.152'\n" | |
def exit(self, status=0, message=None): | |
if message: | |
self._print_message(message, _sys.stderr) | |
> _sys.exit(status) | |
E SystemExit: 2 | |
/nix/store/jhac19hl1qq3qgrna4y06v1kyngszlvb-python3-3.8.8/lib/python3.8/argparse.py:2508: SystemExit | |
----------------------------- Captured stdout call ----------------------------- | |
b2 sync [-h] [--noProgress] [--dryRun] [--allowEmptySource] | |
[--excludeAllSymlinks] [--threads THREADS] | |
[--compareVersions {none,modTime,size}] [--compareThreshold MILLIS] | |
[--excludeRegex REGEX] [--includeRegex REGEX] | |
[--excludeDirRegex REGEX] [--excludeIfModifiedAfter TIMESTAMP] | |
[--skipNewer | --replaceNewer] [--delete | --keepDays DAYS] | |
source destination | |
Copies multiple files from source to destination. Optionally | |
deletes or hides destination files that the source does not have. | |
The synchronizer can copy files: | |
- From a B2 bucket to a local destination. | |
- From a local source to a B2 bucket. | |
- From one B2 bucket to another. | |
- Between different folders in the same B2 bucket. | |
Use "b2://<bucketName>/<prefix>" for B2 paths, e.g. "b2://my-bucket-name/a/path/prefix/". | |
Progress is displayed on the console unless '--noProgress' is | |
specified. A list of actions taken is always printed. | |
Specify '--dryRun' to simulate the actions that would be taken. | |
To allow sync to run when the source directory is empty, potentially | |
deleting all files in a bucket, specify '--allowEmptySource'. | |
The default is to fail when the specified source directory doesn't exist | |
or is empty. (This check only applies to version 1.0 and later.) | |
Users with high-performance networks, or file sets with very small | |
files, will benefit from multi-threaded uploads. The default number | |
of threads is 10. Experiment with the --threads parameter if the | |
default is not working well. | |
Users with low-performance networks may benefit from reducing the | |
number of threads. Using just one thread will minimize the impact | |
on other users of the network. | |
Note that using multiple threads will usually be detrimental to | |
the other users on your network. | |
You can specify --excludeRegex to selectively ignore files that | |
match the given pattern. Ignored files will not copy during | |
the sync operation. The pattern is a regular expression | |
that is tested against the full path of each file. | |
You can specify --includeRegex to selectively override ignoring | |
files that match the given --excludeRegex pattern by an | |
--includeRegex pattern. Similarly to --excludeRegex, the pattern | |
is a regular expression that is tested against the full path | |
of each file. | |
Note that --includeRegex cannot be used without --excludeRegex. | |
You can specify --excludeAllSymlinks to skip symlinks when | |
syncing from a local source. | |
When a directory is excluded by using --excludeDirRegex, all of | |
the files within it are excluded, even if they match an --includeRegex | |
pattern. This means that there is no need to look inside excluded | |
directories, and you can exclude directories containing files for which | |
you don't have read permission and avoid getting errors. | |
The --excludeDirRegex is a regular expression that is tested against | |
the full path of each directory. The path being matched does not have | |
a trailing '/', so don't include on in your regular expression. | |
Multiple regex rules can be applied by supplying them as pipe | |
delimited instructions. Note that the regex for this command | |
is Python regex. Reference: https://docs.python.org/2/library/re.html. | |
Regular expressions are considered a match if they match a substring | |
starting at the first character. ".*e" will match "hello". This is | |
not ideal, but we will maintain this behavior for compatibility. | |
If you want to match the entire path, put a "$" at the end of the | |
regex, such as ".*llo$". | |
You can specify --excludeIfModifiedAfter to selectively ignore file versions | |
(including hide markers) which were synced after given time (for local source) | |
or ignore only specific file versions (for b2 source). | |
Ignored files or file versions will not be taken for consideration during sync. | |
The time should be given as a seconds timestamp (e.g. "1367900664") | |
If you need milliseconds precision, put it after the comma (e.g. "1367900664.152") | |
Files are considered to be the same if they have the same name | |
and modification time. This behaviour can be changed using the | |
--compareVersions option. Possible values are: | |
'none': Comparison using the file name only | |
'modTime': Comparison using the modification time (default) | |
'size': Comparison using the file size | |
A future enhancement may add the ability to compare the SHA1 checksum | |
of the files. | |
Fuzzy comparison of files based on modTime or size can be enabled by | |
specifying the --compareThreshold option. This will treat modTimes | |
(in milliseconds) or sizes (in bytes) as the same if they are within | |
the comparison threshold. Files that match, within the threshold, will | |
not be synced. Specifying --verbose and --dryRun can be useful to | |
determine comparison value differences. | |
When a destination file is present that is not in the source, the | |
default is to leave it there. Specifying --delete means to delete | |
destination files that are not in the source. | |
When the destination is B2, you have the option of leaving older | |
versions in place. Specifying --keepDays will delete any older | |
versions more than the given number of days old, based on the | |
modification time of the file. This option is not available when | |
the destination is a local folder. | |
Files at the source that have a newer modification time are always | |
copied to the destination. If the destination file is newer, the | |
default is to report an error and stop. But with --skipNewer set, | |
those files will just be skipped. With --replaceNewer set, the | |
old file from the source will replace the newer one in the destination. | |
To make the destination exactly match the source, use: | |
b2 sync --delete --replaceNewer ... ... | |
WARNING: Using '--delete' deletes files! We recommend not using it. | |
If you use --keepDays instead, you will have some time to recover your | |
files if you discover they are missing on the source end. | |
To make the destination match the source, but retain previous versions | |
for 30 days: | |
b2 sync --keepDays 30 --replaceNewer ... b2://... | |
Example of sync being used with excludeRegex. This will ignore .DS_Store files | |
and .Spotlight-V100 folders | |
b2 sync -excludeRegex '(.*\.DS_Store)|(.*\.Spotlight-V100)' ... b2://... | |
Requires capabilities: listFiles, readFiles (for downloading), writeFiles (for uploading) | |
positional arguments: | |
source | |
destination | |
optional arguments: | |
-h, --help show this help message and exit | |
--noProgress | |
--dryRun | |
--allowEmptySource | |
--excludeAllSymlinks | |
--threads THREADS | |
--compareVersions {none,modTime,size} | |
--compareThreshold MILLIS | |
--excludeRegex REGEX | |
--includeRegex REGEX | |
--excludeDirRegex REGEX | |
--excludeIfModifiedAfter TIMESTAMP | |
--skipNewer | |
--replaceNewer | |
--delete | |
--keepDays DAYS | |
----------------------------- Captured stderr call ----------------------------- | |
b2 sync: error: argument --excludeIfModifiedAfter: invalid parse_millis_from_float_timestamp value: '1367700664.152' | |
=============================== warnings summary =============================== | |
b2/console_tool.py:1143 | |
/build/source/b2/console_tool.py:1143: DeprecationWarning: invalid escape sequence \. | |
""" | |
-- Docs: https://docs.pytest.org/en/stable/warnings.html | |
=========================== short test summary info ============================ | |
FAILED test/unit/test_arg_parser.py::TestCustomArgTypes::test_parse_millis_from_float_timestamp | |
FAILED test/unit/test_console_tool.py::TestConsoleTool::test_sync_exclude_if_modified_after_exact | |
FAILED test/unit/test_console_tool.py::TestConsoleTool::test_sync_exclude_if_modified_after_in_range | |
============ 3 failed, 47 passed, 2 deselected, 1 warning in 5.17s ============= |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment