| @@ -182,10 +182,37 @@ | |||||
| "special": "iter is unique" | "special": "iter is unique" | ||||
| }, | }, | ||||
| { | { | ||||
| "skip": 1, | |||||
| "title": "dump is correct", | "title": "dump is correct", | ||||
| "cmd": [ "dump" ], | "cmd": [ "dump" ], | ||||
| "exit": 0, | "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 | |||||
| } | } | ||||
| ] | ] | ||||
| @@ -529,6 +529,20 @@ class ObjectStore(object): | |||||
| return obj | 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): | def by_id(self, id): | ||||
| '''Look up an object by it's UUID.''' | '''Look up an object by it's UUID.''' | ||||
| @@ -772,7 +786,7 @@ def cmd_dump(options): | |||||
| persona, objstr = get_objstore(options) | persona, objstr = get_objstore(options) | ||||
| for i in objstr: | for i in objstr: | ||||
| print(repr(i)) | |||||
| print(i.encode('json')) | |||||
| def cmd_list(options): | def cmd_list(options): | ||||
| persona, objstr = get_objstore(options) | persona, objstr = get_objstore(options) | ||||
| @@ -807,6 +821,33 @@ def cmd_list(options): | |||||
| write_objstore(options, objstr) | 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(): | def main(): | ||||
| import argparse | import argparse | ||||
| @@ -847,6 +888,14 @@ def main(): | |||||
| parser_dump = subparsers.add_parser('dump', help='dump all the objects') | parser_dump = subparsers.add_parser('dump', help='dump all the objects') | ||||
| parser_dump.set_defaults(func=cmd_dump) | 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() | options = parser.parse_args() | ||||
| fun = options.func | fun = options.func | ||||
| @@ -1349,10 +1398,19 @@ class _TestCases(unittest.TestCase): | |||||
| with self.subTest(file=f, title=cmd['title']), \ | with self.subTest(file=f, title=cmd['title']), \ | ||||
| mock.patch('os.path.expanduser', | mock.patch('os.path.expanduser', | ||||
| side_effect=expandusermock) as eu, \ | side_effect=expandusermock) as eu, \ | ||||
| mock.patch('sys.stdin', io.StringIO()) as stdin, \ | |||||
| mock.patch('sys.stdout', io.StringIO()) as stdout, \ | mock.patch('sys.stdout', io.StringIO()) as stdout, \ | ||||
| mock.patch('sys.stderr', io.StringIO()) as stderr, \ | mock.patch('sys.stderr', io.StringIO()) as stderr, \ | ||||
| mock.patch('sys.argv', [ 'progname', ] + | mock.patch('sys.argv', [ 'progname', ] + | ||||
| cmd['cmd']) as argv: | 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: | with self.assertRaises(SystemExit) as cm: | ||||
| main() | main() | ||||