Merge branch 'master' into 3644-arv-mount-projects
[arvados.git] / crunch_scripts / crunchutil / subst.py
1 import os
2 import glob
3
4 class SubstitutionError(Exception):
5     pass
6
7 def search(c):
8     DEFAULT = 0
9     DOLLAR = 1
10
11     i = 0
12     state = DEFAULT
13     start = None
14     depth = 0
15     while i < len(c):
16         if c[i] == '\\':
17             i += 1
18         elif state == DEFAULT:
19             if c[i] == '$':
20                 state = DOLLAR
21                 if depth == 0:
22                     start = i
23             elif c[i] == ')':
24                 if depth == 1:
25                     return [start, i]
26                 if depth > 0:
27                     depth -= 1
28         elif state == DOLLAR:
29             if c[i] == '(':
30                 depth += 1
31             state = DEFAULT
32         i += 1
33     if depth != 0:
34         raise SubstitutionError("Substitution error, mismatched parentheses {}".format(c))
35     return None
36
37 def sub_file(v):
38     return os.path.join(os.environ['TASK_KEEPMOUNT'], v)
39
40 def sub_dir(v):
41     d = os.path.dirname(v)
42     if d == '':
43         d = v
44     return os.path.join(os.environ['TASK_KEEPMOUNT'], d)
45
46 def sub_basename(v):
47     return os.path.splitext(os.path.basename(v))[0]
48
49 def sub_glob(v):
50     l = glob.glob(v)
51     if len(l) == 0:
52         raise SubstitutionError("$(glob): No match on '%s'" % v)
53     else:
54         return l[0]
55
56 default_subs = {"file ": sub_file,
57                 "dir ": sub_dir,
58                 "basename ": sub_basename,
59                 "glob ": sub_glob}
60
61 def do_substitution(p, c, subs=default_subs):
62     while True:
63         m = search(c)
64         if m is None:
65             return c
66
67         v = do_substitution(p, c[m[0]+2 : m[1]])
68         var = True
69         for sub in subs:
70             if v.startswith(sub):
71                 r = subs[sub](v[len(sub):])
72                 var = False
73                 break
74         if var:
75             if v in p:
76                 r = p[v]
77             else:
78                 raise SubstitutionError("Unknown variable or function '%s' while performing substitution on '%s'" % (v, c))
79             if r is None:
80                 raise SubstitutionError("Substitution for '%s' is null while performing substitution on '%s'" % (v, c))
81             if not isinstance(r, basestring):
82                 raise SubstitutionError("Substitution for '%s' must be a string while performing substitution on '%s'" % (v, c))
83
84         c = c[:m[0]] + r + c[m[1]+1:]