OILS / tools / find / find.py View on Github | oilshell.org

114 lines, 71 significant
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"""
9find.py: Clone of GNU find.
10"""
11
12from __future__ import print_function
13
14import os
15import sys
16
17#from typing import TYPE_CHECKING, Dict, IO
18#if TYPE_CHECKING:
19# from pgen2.parse import PNode
20
21import tokenizer
22import parser
23from _devbuild.gen import find_nt
24from ast import AST
25from eval import EvalExpr, Thing
26import eval
27
28def 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
38def 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')
57def 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
109if __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)