diff --git a/src/borg/archiver/create_cmd.py b/src/borg/archiver/create_cmd.py index 2843a5821..ecc356e62 100644 --- a/src/borg/archiver/create_cmd.py +++ b/src/borg/archiver/create_cmd.py @@ -211,6 +211,14 @@ class CreateMixIn: # do not save the archive if the user ctrl-c-ed. raise Error("Got Ctrl-C / SIGINT.") else: + # deal with tags + if args.tags is not None: + tags = {tag for tag in args.tags if tag} + special = {tag for tag in tags if tag.startswith("@")} + if not special.issubset(SPECIAL_TAGS): + raise Error("Unknown special tags given.") + archive.tags = tags + archive.save(comment=args.comment, timestamp=args.timestamp) args.stats |= args.json if args.stats: @@ -595,6 +603,8 @@ class CreateMixIn: The archive will consume almost no disk space for files or parts of files that have already been stored in other archives. + The ``--tags`` option can be used to add a list of tags to the new archive. + The archive name does not need to be unique; you can and should use the same name for a series of archives. The unique archive identifier is its ID (hash), and you can abbreviate the ID as long as it is unique. @@ -995,6 +1005,14 @@ class CreateMixIn: action=Highlander, help="explicitly set username for the archive", ) + archive_group.add_argument( + "--tags", + metavar="TAG", + dest="tags", + type=helpers.tag_validator, + nargs="+", + help="add tags to archive (comma-separated or multiple arguments)", + ) subparser.add_argument("name", metavar="NAME", type=archivename_validator, help="specify the archive name") subparser.add_argument( diff --git a/src/borg/testsuite/archiver/create_cmd_test.py b/src/borg/testsuite/archiver/create_cmd_test.py index 1622b834e..7031632e7 100644 --- a/src/borg/testsuite/archiver/create_cmd_test.py +++ b/src/borg/testsuite/archiver/create_cmd_test.py @@ -15,7 +15,7 @@ from ...constants import zeros from ...manifest import Manifest from ...platform import is_win32 from ...repository import Repository -from ...helpers import CommandError, BackupPermissionError +from ...helpers import CommandError, BackupPermissionError, Error from .. import has_lchflags, has_mknod from .. import changedir from .. import ( @@ -682,6 +682,28 @@ def test_file_status(archivers, request): assert "A input/file2" in output +def test_create_tags(archivers, request): + archiver = request.getfixturevalue(archivers) + create_test_files(archiver.input_path) + cmd(archiver, "repo-create", RK_ENCRYPTION) + cmd(archiver, "create", "--tags", "foo", "bar", "baz", "--", "test", "input") + info = cmd(archiver, "info", "--json", "test") + info = json.loads(info) + assert sorted(info["archives"][0]["tags"]) == ["bar", "baz", "foo"] + + +def test_create_invalid_tags(archivers, request): + archiver = request.getfixturevalue(archivers) + create_test_files(archiver.input_path) + cmd(archiver, "repo-create", RK_ENCRYPTION) + if archiver.FORK_DEFAULT: + output = cmd(archiver, "create", "--tags", "@INVALID", "--", "test", "input", exit_code=EXIT_ERROR) + assert "Unknown special tags given" in output + else: + with pytest.raises(Error): + cmd(archiver, "create", "--tags", "@INVALID", "--", "test", "input") + + @pytest.mark.skipif( is_win32, reason="ctime attribute is file creation time on Windows" ) # see https://docs.python.org/3/library/os.html#os.stat_result.st_ctime