github.com/hwaf/hwaf@v0.0.0-20140814122253-5465f73b20f1/py-hwaftools/orch/mungers.py (about) 1 #!/usr/bin/env python 2 ''' 3 This module primarily provides the functions: 4 5 - construct :: create mungers from configuration items 6 - apply :: apply a list of mungers to an environment 7 8 In this module "environment munging" or "munge" refers to mutating a 9 dictionary of environment variables. 10 11 A munger is a callable object with the signature: 12 13 munger(**environ) --> new_environ 14 15 The returned environment is a copy an so mungers may be chained via apply(). 16 17 Mungers are constructed from key/value configuration items like: 18 19 <prefix><name> = <command><delim><payload> 20 21 Where: 22 23 - prefix :: indicates some domain ("export_", "buildenv_"). Note it includes any separator character(s) 24 - name :: a <command>-specific label. For commands setting specific environment variables it provides the variable name. For shell commands it is ignored (but may be used for ordering). 25 - command :: one of "append", "prepend", "set" or "shell". If not of this set then "set" is assumed and no <delim> is expected 26 - delim :: A single character delimiter used for "append" and "prepend" commands and otherwise required but ignored (unless no command given as above) 27 - payload :: the value to apply to the command. For "shell" commands it is a shell command line, for all else it is an environment variable value. 28 29 ''' 30 31 import os 32 import tempfile 33 34 from . import util 35 36 def split_var_munger_command(cmdstr, cmd): 37 'cmd<delim><string> --> (<delim>,<string>' 38 rest = cmdstr[len(cmd):] 39 return rest[0], rest[1:] 40 41 def update_var(name, cmdstr, **environ): 42 ''' 43 A munger body which will apply the cmdstr to the named environment 44 variable to the given environ keywords and return the result. 45 ''' 46 #print 'munger: apply: %s: "%s"' % (name, cmdstr) 47 48 oldval = environ.get(name) 49 if cmdstr.startswith('append'): 50 delim,val = split_var_munger_command(cmdstr, 'append') 51 newval = oldval + delim + val if oldval else val 52 elif cmdstr.startswith('prepend'): 53 delim,val = split_var_munger_command(cmdstr, 'prepend') 54 newval = val + delim + oldval if oldval else val 55 elif cmdstr.startswith('set'): 56 delim,val = split_var_munger_command(cmdstr, 'set') 57 newval = val 58 else: 59 newval = cmdstr 60 environ[name] = newval 61 return environ 62 63 64 # by default, rely on this being in the PATH 65 env_executable = "env" 66 def cmd_munger(cmd, **environ): 67 ''' 68 A munger body which will execute the shell cmd in the given 69 environment and return the post-execution environment. This is 70 done by parsing the output to the "env" command as set by the 71 "env_executable" variable. 72 ''' 73 #print 'munger: apply: "%s"' % cmd 74 #print 'PATH=%s' % environ.get('PATH','') 75 fd, fname = tempfile.mkstemp() 76 cmd += ' && %s > %s' % (env_executable, fname) 77 util.check_output(cmd, shell=True, env=environ) 78 os.close(fd) 79 envtext = open(fname).read() 80 ret = dict() 81 for k,v in util.envvars(envtext).items(): 82 ret[k.strip()] = v.strip() 83 return ret 84 85 def make_munger(name, cmdstr): 86 ''' 87 Dispatch based on the command of the cmdstr (<command><delim><payload>). 88 89 Returns a munger object. 90 ''' 91 #print 'munger: %s: "%s"' % (name, cmdstr) 92 93 if cmdstr.startswith('shell'): 94 delim, cmdline = split_var_munger_command(cmdstr, 'shell') 95 return lambda **environ: cmd_munger(cmdline, **environ) 96 return lambda **environ: update_var(name, cmdstr, **environ) 97 98 def construct(prefix, **pkg_kwds): 99 ''' 100 Any package configuration items with keys starting with prefix are 101 interpreted as munging commands. 102 ''' 103 104 ret = list() 105 for key, cmdstr in pkg_kwds.items(): 106 if not key.startswith(prefix): 107 continue 108 name = key[len(prefix):] 109 m = make_munger(name, cmdstr) 110 ret.append(m) 111 return ret 112 113 def apply(mungers, **environ): 114 ''' 115 Run the given environment through the given mungers and return the result. 116 117 If no keyword arguments are given the current process environment 118 (os.environ) is used as a starting environment.. 119 ''' 120 if not environ: 121 environ = dict(os.environ) 122 for m in mungers: 123 environ = m(**environ) 124 return environ