| 1 | #!/usr/bin/env python2
 | 
| 2 | # Copyright 2019 Wilke Schwiedop. All rights reserved.
 | 
| 3 | # Licensed under the Apache License, Version 2.0 (the "License");
 | 
| 4 | # you may not use this file except in compliance with the License.
 | 
| 5 | # You may obtain a copy of the License at
 | 
| 6 | #
 | 
| 7 | #   http://www.apache.org/licenses/LICENSE-2.0
 | 
| 8 | """
 | 
| 9 | find.py: Clone of GNU find.
 | 
| 10 | """
 | 
| 11 | 
 | 
| 12 | from __future__ import print_function
 | 
| 13 | 
 | 
| 14 | import os
 | 
| 15 | import sys
 | 
| 16 | 
 | 
| 17 | #from typing import TYPE_CHECKING, Dict, IO
 | 
| 18 | #if TYPE_CHECKING:
 | 
| 19 | #	from pgen2.parse import PNode
 | 
| 20 | 
 | 
| 21 | import tokenizer
 | 
| 22 | import parser
 | 
| 23 | from _devbuild.gen import find_nt
 | 
| 24 | from ast import AST
 | 
| 25 | from eval import EvalExpr, Thing
 | 
| 26 | import eval
 | 
| 27 | 
 | 
| 28 | def printTree(pnode, nametable, f=sys.stderr, indentChars="\t"):
 | 
| 29 | 	def _printTree(pnode, nametable, f, i, depth, indentChars):
 | 
| 30 | 		v = pnode.tok[0] if tokenizer.is_terminal(pnode.typ) else ""
 | 
| 31 | 		print(indentChars * depth, '#%d' % i, nametable.get(pnode.typ, "UNKNOWN"), v, file=f)
 | 
| 32 | 		if not pnode.children:
 | 
| 33 | 			return
 | 
| 34 | 		for i, c in enumerate(pnode.children):
 | 
| 35 | 			_printTree(c, nametable, f, i, depth+1, indentChars)
 | 
| 36 | 	_printTree(pnode, nametable, f, 0, 0, indentChars)
 | 
| 37 | 
 | 
| 38 | def contains_print_blocker(node):
 | 
| 39 | 	# all actions except -print and -prune
 | 
| 40 | 	XYZActions = [
 | 
| 41 | 		tokenizer.DELETE, tokenizer.QUIT,
 | 
| 42 | #		tokenizer.PRUNE,
 | 
| 43 | 		tokenizer.PRINT,
 | 
| 44 | 		tokenizer.PRINT0, tokenizer.PRINTF,
 | 
| 45 | 		tokenizer.FPRINT, tokenizer.FPRINT0, tokenizer.FPRINTF,
 | 
| 46 | 		tokenizer.LS,
 | 
| 47 | 		tokenizer.FLS, tokenizer.EXEC, tokenizer.EXECDIR, tokenizer.OK, tokenizer.OKDIR,
 | 
| 48 | 	]
 | 
| 49 | 	return node.typ in XYZActions or (node.children and any(contains_print_blocker(c) for c in node.children))
 | 
| 50 | 
 | 
| 51 | # find
 | 
| 52 | #	for root, dirs, files in os.walk('.', topdown=True):
 | 
| 53 | #		print(root, *(os.path.join(root, f) for f in files), sep='\n')
 | 
| 54 | # find -depth
 | 
| 55 | #	for root, dirs, files in os.walk('.', topdown=False):
 | 
| 56 | #		print(*(os.path.join(root, f) for f in files), root, sep='\n')
 | 
| 57 | def main(argv):
 | 
| 58 | 	i = 1
 | 
| 59 | 	while i < len(argv) and argv[i][0] not in ('!', '(', '-'):
 | 
| 60 | 		i += 1
 | 
| 61 | 
 | 
| 62 | 	paths = argv[1:i]
 | 
| 63 | 	if not paths:
 | 
| 64 | 		paths.append('.')
 | 
| 65 | 
 | 
| 66 | 	tokens = tokenizer.tokenize(argv[i:])
 | 
| 67 | 
 | 
| 68 | 	parse_root = parser.ParseTree(tokens)
 | 
| 69 | 
 | 
| 70 | 	names = tokenizer.tok_name.copy()
 | 
| 71 | 	names.update(parser.nt_name)
 | 
| 72 | 	printTree(parse_root, names)
 | 
| 73 | 
 | 
| 74 | 	ast_root = AST(parse_root)
 | 
| 75 | 
 | 
| 76 | 	ast_root.PrettyPrint(f=sys.stderr)
 | 
| 77 | 	print(file=sys.stderr)
 | 
| 78 | 
 | 
| 79 | 	# if ast contains no actions other than -prune or -print:
 | 
| 80 | 	# ast_root = Conjunction(ast_root, -print)
 | 
| 81 | 	# if ast_root is a Conjunction, append child
 | 
| 82 | 	if not contains_print_blocker(parse_root):
 | 
| 83 | #		print("adding '-a -print'", file=sys.stderr)
 | 
| 84 | 		from _devbuild.gen import find_asdl as asdl
 | 
| 85 | 		if parse_root.children[0].typ == find_nt.conjunction:
 | 
| 86 | 			ast_root.exprs.append(asdl.expr.PrintAction())
 | 
| 87 | 		else:
 | 
| 88 | 			ast_root = asdl.expr.Conjunction([ast_root, asdl.expr.PrintAction()])
 | 
| 89 | 
 | 
| 90 | 	expr = EvalExpr(ast_root)
 | 
| 91 | 	for path in paths:
 | 
| 92 | 		for root, dirs, files in os.walk(path):
 | 
| 93 | 			t = Thing(root)
 | 
| 94 | 			b = expr(t)
 | 
| 95 | 			if t.quit:
 | 
| 96 | 				break
 | 
| 97 | 			if t.prune:
 | 
| 98 | 				del dirs[:]
 | 
| 99 | 				continue
 | 
| 100 | 			for fname in files:
 | 
| 101 | 				t = Thing(os.path.join(root,fname))
 | 
| 102 | 				expr(t)
 | 
| 103 | 				# -prune should be ignored for files
 | 
| 104 | 		else:
 | 
| 105 | 			continue
 | 
| 106 | 		# TODO run -exec ... {} +
 | 
| 107 | 		break
 | 
| 108 | 
 | 
| 109 | if __name__ == '__main__':
 | 
| 110 | 	try:
 | 
| 111 | 		main(sys.argv)
 | 
| 112 | 	except RuntimeError as e:
 | 
| 113 | 		print('FATAL: %s' % e, file=sys.stderr)
 | 
| 114 | 		sys.exit(1)
 |