| 1 | # Copyright 2019 Wilke Schwiedop. All rights reserved.
 | 
| 2 | # Licensed under the Apache License, Version 2.0 (the "License");
 | 
| 3 | # you may not use this file except in compliance with the License.
 | 
| 4 | # You may obtain a copy of the License at
 | 
| 5 | #
 | 
| 6 | #   http://www.apache.org/licenses/LICENSE-2.0
 | 
| 7 | """
 | 
| 8 | eval.py: evaluator for find.
 | 
| 9 | """
 | 
| 10 | 
 | 
| 11 | from __future__ import print_function
 | 
| 12 | 
 | 
| 13 | import fnmatch
 | 
| 14 | import os
 | 
| 15 | import stat
 | 
| 16 | import sys
 | 
| 17 | 
 | 
| 18 | from _devbuild.gen import find_asdl as asdl
 | 
| 19 | 
 | 
| 20 | def _path(v):
 | 
| 21 | 	return v.path
 | 
| 22 | def _basename(v):
 | 
| 23 | 	return os.path.basename(v.path)
 | 
| 24 | 
 | 
| 25 | pathAccMap = {
 | 
| 26 | 	asdl.pathAccessor_e.FullPath.enum_id : _path,
 | 
| 27 | 	asdl.pathAccessor_e.Filename.enum_id : _basename,
 | 
| 28 | }
 | 
| 29 | 
 | 
| 30 | def _accessTime(v):
 | 
| 31 | 	assert False
 | 
| 32 | 	return stat.ST_ATIME(v.stat.st_mode)
 | 
| 33 | def _creationTime(v):
 | 
| 34 | 	assert False
 | 
| 35 | 	return stat.ST_CTIME(v.stat.st_mode)
 | 
| 36 | def _modificationTime(v):
 | 
| 37 | 	assert False
 | 
| 38 | 	return stat.ST_MTIME(v.stat.st_mode)
 | 
| 39 | def _filesystem(v):
 | 
| 40 | 	assert False
 | 
| 41 | 	return stat.ST_DEV(v.stat.st_mode) # ???
 | 
| 42 | def _inode(v):
 | 
| 43 | 	return stat.ST_INO(v.stat.st_mode)
 | 
| 44 | def _linkCount(v):
 | 
| 45 | 	return stat.ST_NLINK(v.stat.st_mode)
 | 
| 46 | def _mode(v):
 | 
| 47 | 	return stat.S_IMODE(v.stat.st_mode)
 | 
| 48 | def _filetype(v):
 | 
| 49 | 	return stat.S_IFMT(v.stat.st_mode)
 | 
| 50 | def _uid(v):
 | 
| 51 | 	return stat.ST_UID(v.stat.st_mode)
 | 
| 52 | def _gid(v):
 | 
| 53 | 	return stat.ST_GID(v.stat.st_mode)
 | 
| 54 | def _username(v):
 | 
| 55 | 	assert False
 | 
| 56 | def _groupname(v):
 | 
| 57 | 	assert False
 | 
| 58 | def _size(v):
 | 
| 59 | 	return stat.ST_SIZE(v.stat.st_mode)
 | 
| 60 | 
 | 
| 61 | statAccMap = {
 | 
| 62 | 	asdl.statAccessor_e.AccessTime.enum_id		: _accessTime,
 | 
| 63 | 	asdl.statAccessor_e.CreationTime.enum_id	: _creationTime,
 | 
| 64 | 	asdl.statAccessor_e.ModificationTime.enum_id	: _modificationTime,
 | 
| 65 | 	asdl.statAccessor_e.Filesystem.enum_id	: _filesystem,
 | 
| 66 | 	asdl.statAccessor_e.Inode.enum_id		: _inode,
 | 
| 67 | #	asdl.statAccessor_e.LinkCount.enum_id	: _linkCount,
 | 
| 68 | 	asdl.statAccessor_e.Mode.enum_id		: _mode,
 | 
| 69 | 	asdl.statAccessor_e.Filetype.enum_id	: _filetype,
 | 
| 70 | 	asdl.statAccessor_e.Uid.enum_id		: _uid,
 | 
| 71 | 	asdl.statAccessor_e.Gid.enum_id		: _gid,
 | 
| 72 | 	asdl.statAccessor_e.Username.enum_id	: _username,
 | 
| 73 | 	asdl.statAccessor_e.Groupname.enum_id	: _groupname,
 | 
| 74 | 	asdl.statAccessor_e.Size.enum_id		: _size,
 | 
| 75 | }
 | 
| 76 | 
 | 
| 77 | def _stringMatch(acc, test):
 | 
| 78 | 	string = test.p.str
 | 
| 79 | 	return lambda x: acc(x) == string
 | 
| 80 | def _globMatch(acc, test):
 | 
| 81 | 	glob = test.p.glob
 | 
| 82 | 	return lambda x: fnmatch.fnmatch(acc(x), glob)
 | 
| 83 | def _regexMatch(acc, test):
 | 
| 84 | 	assert False
 | 
| 85 | def _eq(acc, test):
 | 
| 86 | 	n = test.p.n
 | 
| 87 | 	return lambda x: acc(x) == n
 | 
| 88 | def _ge(acc, test):
 | 
| 89 | 	n = test.p.n
 | 
| 90 | 	return lambda x: acc(x) >= n
 | 
| 91 | def _le(acc, test):
 | 
| 92 | 	n = test.p.n
 | 
| 93 | 	return lambda x: acc(x) <= n
 | 
| 94 | def _readable(acc, test):
 | 
| 95 | 	return lambda x: os.access(acc(x), os.R_OK)
 | 
| 96 | def _writable(acc, test):
 | 
| 97 | 	return lambda x: os.access(acc(x), os.W_OK)
 | 
| 98 | def _executable(acc, test):
 | 
| 99 | 	return lambda x: os.access(acc(x), os.X_OK)
 | 
| 100 | 
 | 
| 101 | predicateMap = {
 | 
| 102 | 	asdl.predicate_e.StringMatch : _stringMatch,
 | 
| 103 | 	asdl.predicate_e.GlobMatch : _globMatch,
 | 
| 104 | 	asdl.predicate_e.RegexMatch : _regexMatch,
 | 
| 105 | 	asdl.predicate_e.EQ : _eq,
 | 
| 106 | 	asdl.predicate_e.GE : _ge,
 | 
| 107 | 	asdl.predicate_e.LE : _le,
 | 
| 108 | 	asdl.predicate_e.Readable	: _readable,
 | 
| 109 | 	asdl.predicate_e.Writable	: _writable,
 | 
| 110 | 	asdl.predicate_e.Executable	: _executable,
 | 
| 111 | }
 | 
| 112 | 
 | 
| 113 | def _true(_):
 | 
| 114 | 	return lambda _: True
 | 
| 115 | def _false(_):
 | 
| 116 | 	return lambda _: False
 | 
| 117 | def _concatenation(test):
 | 
| 118 | 	return lambda x: [EvalExpr(e)(x) for e in test.exprs][-1]
 | 
| 119 | def _disjunction(test):
 | 
| 120 | 	return lambda x: any(EvalExpr(e)(x) for e in test.exprs)
 | 
| 121 | def _conjunction(test):
 | 
| 122 | 	return lambda x: all(EvalExpr(e)(x) for e in test.exprs)
 | 
| 123 | def _negation(test):
 | 
| 124 | 	return lambda x: not EvalExpr(test.expr)(x)
 | 
| 125 | def _pathTest(test):
 | 
| 126 | 	pred = predicateMap[test.p.tag]
 | 
| 127 | 	acc = pathAccMap[test.a.enum_id]
 | 
| 128 | 	return pred(acc, test)
 | 
| 129 | def _statTest(test):
 | 
| 130 | 	pred = predicateMap[test.p.tag]
 | 
| 131 | 	acc = statAccMap[test.a.enum_id]
 | 
| 132 | 	return pred(acc, test)
 | 
| 133 | def _delete(_):
 | 
| 134 | 	def __delete(v):
 | 
| 135 | 		print("pretend delete", v, file=sys.stderr)
 | 
| 136 | 		return True
 | 
| 137 | 	return __delete
 | 
| 138 | def _prune(_):
 | 
| 139 | 	def __prune(v):
 | 
| 140 | 		v.prune = True
 | 
| 141 | 		return True
 | 
| 142 | 	return __prune
 | 
| 143 | def _quit(_):
 | 
| 144 | 	def __quit(v):
 | 
| 145 | 		v.quit = True
 | 
| 146 | 		return True
 | 
| 147 | 	return __quit
 | 
| 148 | def _print(action):
 | 
| 149 | 	# TODO handle output-file
 | 
| 150 | 	# TODO handle format
 | 
| 151 | 	def __print(v):
 | 
| 152 | 		print(v.path)
 | 
| 153 | 		return True
 | 
| 154 | 	return __print
 | 
| 155 | def _ls(action):
 | 
| 156 | 	return _true
 | 
| 157 | def _exec(action):
 | 
| 158 | 	# TODO return exit status
 | 
| 159 | 	return _true
 | 
| 160 | 
 | 
| 161 | exprMap = {
 | 
| 162 | 	asdl.expr_e.True_	: _true,
 | 
| 163 | 	asdl.expr_e.False_	: _false,
 | 
| 164 | 	asdl.expr_e.Concatenation	: _concatenation,
 | 
| 165 | 	asdl.expr_e.Disjunction	: _disjunction,
 | 
| 166 | 	asdl.expr_e.Conjunction	: _conjunction,
 | 
| 167 | 	asdl.expr_e.Negation		: _negation,
 | 
| 168 | 	asdl.expr_e.PathTest	: _pathTest,
 | 
| 169 | 	asdl.expr_e.StatTest	: _statTest,
 | 
| 170 | 	asdl.expr_e.DeleteAction	: _delete,
 | 
| 171 | 	asdl.expr_e.PruneAction	: _prune,
 | 
| 172 | 	asdl.expr_e.QuitAction	: _quit,
 | 
| 173 | 	asdl.expr_e.PrintAction	: _print,
 | 
| 174 | 	asdl.expr_e.LsAction	: _ls,
 | 
| 175 | 	asdl.expr_e.ExecAction	: _exec,
 | 
| 176 | }
 | 
| 177 | 
 | 
| 178 | def EvalExpr(ast):
 | 
| 179 | 	return exprMap[ast.tag](ast)
 | 
| 180 | 
 | 
| 181 | class Thing:
 | 
| 182 | 	def __init__(self, path, stat=None):
 | 
| 183 | 		self.path = path
 | 
| 184 | 		self._stat = stat
 | 
| 185 | 		self.prune = False
 | 
| 186 | 		self.quit = False
 | 
| 187 | 	@property
 | 
| 188 | 	def stat(self):
 | 
| 189 | 		if self._stat is None:
 | 
| 190 | 			# TODO stat for tests that require it?
 | 
| 191 | 			self._stat = os.lstat(self.path)
 | 
| 192 | 		return self._stat
 | 
| 193 | 	def __repr__(self):
 | 
| 194 | 		return self.path
 |