diff --git a/ui/fixtures/cmd.basic.json b/ui/fixtures/cmd.basic.json index 9a6b96b..ba2cfa5 100644 --- a/ui/fixtures/cmd.basic.json +++ b/ui/fixtures/cmd.basic.json @@ -182,10 +182,37 @@ "special": "iter is unique" }, { - "skip": 1, "title": "dump is correct", "cmd": [ "dump" ], "exit": 0, - "stdout": "ERROR: tag needs to start with a \"+\" (add) or a \"-\" (remove).\n" + "stdout_re": "{.*filename.*newfile.txt.*hashes.*90f8342520f0ac57fb5a779f5d331c2fa87aa40f8799940257f9ba619940951e67143a8d746535ed0284924b2b7bc1478f095198800ba96d01847d7b56ca465c.*size.*19.*type.*file.*}\n{.*foo.*bar=baz.*hashes.*90f8342520f0ac57fb5a779f5d331c2fa87aa40f8799940257f9ba619940951e67143a8d746535ed0284924b2b7bc1478f095198800ba96d01847d7b56ca465c.*type.*metadata.*}\n{.*filename.*test.txt.*90f8342520f0ac57fb5a779f5d331c2fa87aa40f8799940257f9ba619940951e67143a8d746535ed0284924b2b7bc1478f095198800ba96d01847d7b56ca465c.*size.*19.*type.*file.*}\n{.*filename.*newfile.txt.*90f8342520f0ac57fb5a779f5d331c2fa87aa40f8799940257f9ba619940951e67143a8d746535ed0284924b2b7bc1478f095198800ba96d01847d7b56ca465c.*size.*19.*type.*file.*}\n{.*filename.*newfile.txt.*90f8342520f0ac57fb5a779f5d331c2fa87aa40f8799940257f9ba619940951e67143a8d746535ed0284924b2b7bc1478f095198800ba96d01847d7b56ca465c.*size.*19.*type.*file.*}\n" +}, +{ + "title": "that import can be done", + "cmd": [ "import" ], + "stdin": "{\"created_by_ref\": \"e7ad5ea1-1203-4951-9dca-ec852a7b8166\", \"foo\": [\"bar=baz\"], \"hashes\": [\"sha512:90f8342520f0ac57fb5a779f5d331c2fa87aa40f8799940257f9ba619940951e67143a8d746535ed0284924b2b7bc1478f095198800ba96d01847d7b56ca465c\"], \"modified\": \"2022-08-21T00:13:51.245871Z\", \"sig\": \"g7k4plXjzz9y8YwJM2ncCIxaqlBpdbITPvKlDtfO7LSFmbZ-qcj0M0lN9h8twNU-n163dNsDGmQA4_s8pJB0liBHDwkjpYQvxfeztQDWNaVN7Xnh2MOj-wBzUbLTVnsJULXwVQrUjngzWjjGQ3jy6gwA\", \"tag\": [\"\"], \"type\": \"metadata\", \"uuid\": \"25ec10e6-c3d0-4363-a762-899dade7f93c\"}\n{\"created_by_ref\": \"2de7a389-410c-4755-8c62-f3254c7e971e\", \"dir\": \"\", \"filename\": \"FreeBSD-14.0-CURRENT-arm64-aarch64-ROCK64-20220331-d53927b0bae-254105.img.xz\", \"hashes\": [\"sha512:3eba2aa09a79fd7adec32ace93c6725e75b91a55192b5bfa827b893fae1c2cdbc040e282138387797f245c1f27da5e8ff7a02f59ff75c73b3d999d1e0a8752ad\"], \"id\": \"d9e8fc1a-9794-5e70-b67b-11d708ec8947\", \"modified\": \"2022-08-02T07:52:50.216428Z\", \"mtime\": \"2022-03-31T10:15:14.000000Z\", \"sig\": \"F3Ch1BQB57RAgFNKNF5btCRZS3jFmafhvcdoWuu6WHo5JzyhuQ7jNvZkv4tzgWqlMfPecLJMMmSAMcwqorykDWi854ZfKUm3F-JOTk8R7qRKdHd23rwVGDEXtVHv-kynkh8WemPsfc2V1HT8JKG9NhwA\", \"size\": 551750948, \"type\": \"file\", \"uuid\": \"89544934-6ed9-46ca-b8d0-77c5209f798d\"}\n" +}, +{ + "special": "verify store object cnt", + "comment": "and the objects were imported", + "count": 7 +}, +{ + "title": "than an object can be dropped", + "cmd": [ "drop", "25ec10e6-c3d0-4363-a762-899dade7f93c" ] +}, +{ + "special": "verify store object cnt", + "comment": "and the object was dropped", + "count": 6 +}, +{ + "title": "than an object can be dropped", + "cmd": [ "drop", "89544934-6ed9-46ca-b8d0-77c5209f798d" ] +}, +{ + "special": "verify store object cnt", + "comment": "and the object was dropped", + "count": 5 } ] diff --git a/ui/medashare/cli.py b/ui/medashare/cli.py index 2cb764d..ce655e0 100644 --- a/ui/medashare/cli.py +++ b/ui/medashare/cli.py @@ -529,6 +529,20 @@ class ObjectStore(object): return obj + def drop_uuid(self, uuid): + uuid = _makeuuid(uuid) + + obj = self.by_id(uuid) + + del self._uuids[uuid] + + if obj.type == 'file': + del self._uuids[obj.id] + + for j in obj.hashes: + h = self.makehash(j) + self._hashes[h].remove(obj) + def by_id(self, id): '''Look up an object by it's UUID.''' @@ -772,7 +786,7 @@ def cmd_dump(options): persona, objstr = get_objstore(options) for i in objstr: - print(repr(i)) + print(i.encode('json')) def cmd_list(options): persona, objstr = get_objstore(options) @@ -807,6 +821,33 @@ def cmd_list(options): write_objstore(options, objstr) +def cmd_import(options): + persona, objstr = get_objstore(options) + + jd = json.JSONDecoder() + + inp = sys.stdin.read() + + while inp: + inp = inp.strip() + jobj, endpos = jd.raw_decode(inp) + + obj = MDBase.create_obj(jobj) + + objstr.loadobj(obj) + + inp = inp[endpos:] + + write_objstore(options, objstr) + +def cmd_drop(options): + persona, objstr = get_objstore(options) + + for i in options.uuids: + objstr.drop_uuid(i) + + write_objstore(options, objstr) + def main(): import argparse @@ -847,6 +888,14 @@ def main(): parser_dump = subparsers.add_parser('dump', help='dump all the objects') parser_dump.set_defaults(func=cmd_dump) + parser_import = subparsers.add_parser('import', help='import objects encoded as json') + parser_import.set_defaults(func=cmd_import) + + parser_drop = subparsers.add_parser('drop', help='drop the object specified by UUID') + parser_drop.add_argument('uuids', nargs='+', + help='UUID of object to drop') + parser_drop.set_defaults(func=cmd_drop) + options = parser.parse_args() fun = options.func @@ -1349,10 +1398,19 @@ class _TestCases(unittest.TestCase): with self.subTest(file=f, title=cmd['title']), \ mock.patch('os.path.expanduser', side_effect=expandusermock) as eu, \ + mock.patch('sys.stdin', io.StringIO()) as stdin, \ mock.patch('sys.stdout', io.StringIO()) as stdout, \ mock.patch('sys.stderr', io.StringIO()) as stderr, \ mock.patch('sys.argv', [ 'progname', ] + cmd['cmd']) as argv: + + # if there is stdin + test_stdin = cmd.get('stdin', '') + + # provide it + stdin.write(test_stdin) + stdin.seek(0) + with self.assertRaises(SystemExit) as cm: main()