|  |  | @@ -685,6 +685,10 @@ class FileObject(MDBase): | 
		
	
		
			
			|  |  |  | 'mtime': _makedatetime, | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | @property | 
		
	
		
			
			|  |  |  | def fullname(self): | 
		
	
		
			
			|  |  |  | return os.path.join(self.dir, self.filename) | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | @staticmethod | 
		
	
		
			
			|  |  |  | def make_id(fname, hostid=None): | 
		
	
		
			
			|  |  |  | '''Take a local file name, and make the id for it.  Note that | 
		
	
	
		
			
				|  |  | @@ -1410,6 +1414,45 @@ def cmd_drop(options, persona, objstr, cache): | 
		
	
		
			
			|  |  |  | for i in options.uuids: | 
		
	
		
			
			|  |  |  | objstr.drop_uuid(i) | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | @init_datastructs | 
		
	
		
			
			|  |  |  | def cmd_search(options, persona, objstr, cache): | 
		
	
		
			
			|  |  |  | args = options.args.copy() | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | _type = args.pop(0) | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | searches = [ (x[0], ) + tuple(x[1:].split('=', 1)) for x in args ] | 
		
	
		
			
			|  |  |  | #print(repr(searches), file=_real_stderr) | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | def testfun(x, s=searches): | 
		
	
		
			
			|  |  |  | try: | 
		
	
		
			
			|  |  |  | for i in s: | 
		
	
		
			
			|  |  |  | op, key, value = i | 
		
	
		
			
			|  |  |  | if op == '+': | 
		
	
		
			
			|  |  |  | if value not in x[key]: | 
		
	
		
			
			|  |  |  | return False | 
		
	
		
			
			|  |  |  | elif op == '-': | 
		
	
		
			
			|  |  |  | if value in x[key]: | 
		
	
		
			
			|  |  |  | return False | 
		
	
		
			
			|  |  |  | else: | 
		
	
		
			
			|  |  |  | raise ValueError('unhandled op: %s' % repr(op)) | 
		
	
		
			
			|  |  |  | else: | 
		
	
		
			
			|  |  |  | return True | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | except KeyError: | 
		
	
		
			
			|  |  |  | return False | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | r = [ x for x in objstr if x.type == 'metadata' and testfun(x) ] | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if _type == 'file': | 
		
	
		
			
			|  |  |  | r = [ objstr.by_hash(x['hashes'][0]) for x in r ] | 
		
	
		
			
			|  |  |  | r = [ [ y for y in x if y['type'] == 'file' ] for x in r ] | 
		
	
		
			
			|  |  |  | r = sum(r, []) | 
		
	
		
			
			|  |  |  | r = [ x.fullname for x in r ] | 
		
	
		
			
			|  |  |  | else: | 
		
	
		
			
			|  |  |  | raise ValueError('unhandled type: %s' % repr(_type)) | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | print('\n'.join(r)) | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | def main(): | 
		
	
		
			
			|  |  |  | import argparse | 
		
	
		
			
			|  |  |  | 
 | 
		
	
	
		
			
				|  |  | @@ -1495,6 +1538,12 @@ def main(): | 
		
	
		
			
			|  |  |  | help='UUID of object to drop') | 
		
	
		
			
			|  |  |  | parser_drop.set_defaults(func=cmd_drop) | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | parser_search = subparsers.add_parser('search', | 
		
	
		
			
			|  |  |  | help='find objects', prefix_chars='@') | 
		
	
		
			
			|  |  |  | parser_search.add_argument('args', nargs='+', | 
		
	
		
			
			|  |  |  | help='args') | 
		
	
		
			
			|  |  |  | parser_search.set_defaults(func=cmd_search) | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | options = parser.parse_args() | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | fun = options.func | 
		
	
	
		
			
				|  |  | 
 |