From 56a562a5ce543405d835270296bb5153df876ff2 Mon Sep 17 00:00:00 2001 From: Maciej Urbanski Date: Wed, 15 May 2024 15:19:17 +0200 Subject: [PATCH] always treat hyphen as stdin alias in b2v4 and above --- CHANGELOG.md | 1 + b2/_internal/b2v3/registry.py | 18 ++++++++++ b2/_internal/console_tool.py | 7 +--- changelog.d/+hyphen_filename.fixed.md | 2 ++ test/unit/console_tool/test_upload_file.py | 38 +++++++++++++++++++--- 5 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 changelog.d/+hyphen_filename.fixed.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 69d85bfc..e97d71ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ upcoming release can be found in [changelog.d](changelog.d). These means following breaking changes: - `b2` will no longer persists credentials and other secrets on disk if credentials were passed through `B2_*` environment variables. To explicitly persist them and keep using local cache for better performance, user can simply call `b2 account account` - `b2 ls` and `b2 rm` no longer accept two positional arguments, instead accepting only `B2 URI` (e.g. `b2://bucketName/path`) + - `-` is no longer supported as a valid filename, always being interpreted as standard input alias instead - Changed `sync` command exit status code from 0 to 1 if any warnings or errors were encountered during the operation. ### Fixed diff --git a/b2/_internal/b2v3/registry.py b/b2/_internal/b2v3/registry.py index 811e4197..400b7d33 100644 --- a/b2/_internal/b2v3/registry.py +++ b/b2/_internal/b2v3/registry.py @@ -92,6 +92,24 @@ class Ls(B2URIMustPointToFolderMixin, B2URIBucketNFolderNameArgMixin, BaseLs): ALLOW_ALL_BUCKETS = True +class HyphenFilenameMixin: + def get_input_stream(self, filename): + if filename == '-' and os.path.exists('-'): + self._print_stderr( + "WARNING: Filename `-` won't be supported in the future and will always be treated as stdin alias." + ) + return '-' + return super().get_input_stream(filename) + + +class UploadUnboundStream(HyphenFilenameMixin, UploadUnboundStream): + __doc__ = UploadUnboundStream.__doc__ + + +class UploadFile(HyphenFilenameMixin, UploadFile): + __doc__ = UploadFile.__doc__ + + B2.register_subcommand(AuthorizeAccount) B2.register_subcommand(CancelAllUnfinishedLargeFiles) B2.register_subcommand(CancelLargeFile) diff --git a/b2/_internal/console_tool.py b/b2/_internal/console_tool.py index 25e3a979..c7418f3e 100644 --- a/b2/_internal/console_tool.py +++ b/b2/_internal/console_tool.py @@ -3434,12 +3434,7 @@ def upload_file_kwargs_to_unbound_upload(self, **kwargs): def get_input_stream(self, filename: str) -> str | int | io.BinaryIO: """Get input stream IF filename points to a FIFO or stdin.""" if filename == "-": - if os.path.exists('-'): - self._print_stderr( - "WARNING: Filename `-` won't be supported in the future and will always be treated as stdin alias." - ) - else: - return sys.stdin.buffer if platform.system() == "Windows" else sys.stdin.fileno() + return sys.stdin.buffer if platform.system() == "Windows" else sys.stdin.fileno() elif points_to_fifo(pathlib.Path(filename)): return filename diff --git a/changelog.d/+hyphen_filename.fixed.md b/changelog.d/+hyphen_filename.fixed.md new file mode 100644 index 00000000..2f467d3a --- /dev/null +++ b/changelog.d/+hyphen_filename.fixed.md @@ -0,0 +1,2 @@ +Fix `-` handling in file upload commands - even if file with `-` name exists, the stdin will be chosen over it. +This change affects `b2v4` (which is also aliased as `b2`), but not `b2v3` to keep backwards compatibility. diff --git a/test/unit/console_tool/test_upload_file.py b/test/unit/console_tool/test_upload_file.py index 6f4a65e8..44ad7750 100644 --- a/test/unit/console_tool/test_upload_file.py +++ b/test/unit/console_tool/test_upload_file.py @@ -10,7 +10,7 @@ import os from test.helpers import skip_on_windows -import b2 +import pytest def test_upload_file__file_info_src_last_modified_millis_and_headers(b2_cli, bucket, tmpdir): @@ -77,10 +77,9 @@ def test_upload_file__named_pipe(b2_cli, bucket, tmpdir, bg_executor): writer.result(timeout=1) +@pytest.mark.apiver(to_ver=3) def test_upload_file__hyphen_file_instead_of_stdin(b2_cli, bucket, tmpdir, monkeypatch): """Test `file upload` will upload file named `-` instead of stdin by default""" - # TODO remove this in v4 - assert b2.__version__ < '4', "`-` filename should not be supported in next major version of CLI" filename = 'stdin.txt' content = "I'm very rare creature, a file named '-'" monkeypatch.chdir(str(tmpdir)) @@ -95,15 +94,44 @@ def test_upload_file__hyphen_file_instead_of_stdin(b2_cli, bucket, tmpdir, monke "size": len(content), } b2_cli.run( - ['file', 'upload', '--no-progress', 'my-bucket', '-', filename], + ['upload-file', '--no-progress', 'my-bucket', '-', filename], expected_json_in_stdout=expected_json, remove_version=True, expected_part_of_stdout=expected_stdout, - expected_stderr= + expected_stderr="WARNING: `upload-file` command is deprecated. Use `file upload` instead.\n" "WARNING: Filename `-` won't be supported in the future and will always be treated as stdin alias.\n", ) +@pytest.mark.apiver(from_ver=4) +def test_upload_file__ignore_hyphen_file(b2_cli, bucket, tmpdir, monkeypatch, mock_stdin): + """Test `file upload` will upload stdin even when file named `-` is explicitly specified""" + content = "I'm very rare creature, a file named '-'" + monkeypatch.chdir(str(tmpdir)) + source_file = tmpdir.join('-') + source_file.write(content) + + content = "stdin input" + filename = 'stdin.txt' + + expected_stdout = f'URL by file name: http://download.example.com/file/my-bucket/{filename}' + expected_json = { + "action": "upload", + "contentSha1": "2ce72aa159d1f190fddf295cc883f20c4787a751", + "fileName": filename, + "size": len(content), + } + mock_stdin.write(content) + mock_stdin.close() + + b2_cli.run( + ['file', 'upload', '--no-progress', 'my-bucket', '-', filename], + expected_json_in_stdout=expected_json, + remove_version=True, + expected_part_of_stdout=expected_stdout, + ) + + def test_upload_file__stdin(b2_cli, bucket, tmpdir, mock_stdin): """Test `file upload` stdin alias support""" content = "stdin input"