Skip to content

Instantly share code, notes, and snippets.

@kra
Created March 29, 2011 01:45
Show Gist options
  • Save kra/891679 to your computer and use it in GitHub Desktop.
Save kra/891679 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
"""
Environment helper for cram.
Proof of concept, would be better implemented inside cram.py,
where we wouldn't have to write a tempfile; in that case, would probably want
to specify a prefix so we could refer to history.
Example usage:
Normal usage - the output is not regexped for clarity, but pin and txid
change with each POST.
$ $TESTDIR/client.py POST /verify/v1/call phone=5035551212 message=message
200 OK
{"stat": "OK", "response": {"pin": "7909", "txid": "0e18f346-891f-4f10-8480-828a126c846c"}}
We need that txid for this GET.
$ $TESTDIR/client.py GET /verify/v1/status txid=XXX
400 Bad Request
{"stat": "FAIL", "code": 40003, "message": "Invalid txid"}
Write environment to /tmp/call-env - we probably want a $SCRATCHDIR.
$ $TESTDIR/cram_helper.py --envout=/tmp/call_env $TESTDIR/client.py \
> POST /verify/v1/call phone=5035551212 message=message
200 OK
{"stat": "OK", "response": {"pin": ".+", "txid": ".+"}} (re)
Now we have a very ugly env dict stored by position - we need a helper
for this, see comments source. Again, not regexped for clarity.
$ cat /tmp/call_env
{'cram_env_2': '{"stat":', 'cram_env_3': '"OK",', 'cram_env_0': '200', 'cram_env_1': 'OK', 'cram_env_6': '"3959",', 'cram_env_7': '"txid":', 'cram_env_4': '"response":', 'cram_env_5': '{"pin":', 'cram_env_8': '"1092e2e0-6d93-4c3f-929b-f22b3545850c"}}'}
Q&D clean up to make it usable - this is not happy.
$ $TESTDIR/env_munger.py /tmp/call_env
Show the cleaned up env file, not regexped for clarity.
$ cat /tmp/call_env
{'cram_env_8': 'fa28aead-583d-4040-bb71-29789532020d'}
Now we can test success with that env var.
$ $TESTDIR/cram_helper.py --envin=/tmp/call_env $TESTDIR/client.py GET /verify/v1/status txid='$cram_env_8'
200 OK
{"stat": "OK", "response": {"info": "Call request initialized", "state": "started", "event": "INITIALIZED"}}
"""
import getopt
import os, sys, subprocess #, shlex
def read_env(env_filename):
"""
Return the evaluated contetns of filename. Contents are assumed to be safe
to eval.
"""
env_file = open(env_filename)
env = eval(env_file.read())
env_file.close()
return env
def write_env(env_d, env_filename):
"""
Write the repr of env_d to env_filename.
"""
env_file = open(env_filename, 'w')
env_file.write(repr(env_d))
env_file.write('\n')
env_file.close()
def usage():
sys.stderr.write(
'usage: %s [--json] [--xml] [--position] '
'[--envin=<file>] [--envout=<file>] '
'<command>...\n'
'only one of --json, --xml, --position can be chosen\n' % sys.argv[0])
sys.exit(1)
def main():
parse_json = False
parse_xml = False
parse_position = False
get_stdin = False
get_stderr = False
env_in = os.environ.copy()
env_out = None
# Since we only get args from the front, we don't need -- or similar.
(optlist, args) = getopt.getopt(
sys.argv[1:], '',
['json', 'xml', 'position', 'envin=', 'envout='])
opt_d = dict(optlist)
# I want json and xml helpers, but would need a way to express how the
# structures should be translated into the env. Maybe it would be good
# enough to be able to specify that the entire parsed stream should be
# written to the env file, so --envin can specify the helper which should
# eval it.
if opt_d.has_key('--json'):
raise NotImplementedError
elif opt_d.has_key('--xml'):
raise NotImplementedError
elif opt_d.has_key('--position'):
parse_position = True
elif opt_d.has_key('--stdin'):
get_stdin = True
elif opt_d.has_key('--stderr'):
get_stderr = True
if opt_d.has_key('--envin'):
env_in.update(read_env(opt_d['--envin']))
if opt_d.has_key('--envout'):
env_out = opt_d['--envout']
# default is position
if not any([parse_json, parse_xml, parse_position]):
parse_position = True
# default is stdin
if not any([get_stdin, get_stderr]):
get_stdin = True
# choose only one
if len(
[opt for opt in [parse_json, parse_xml, parse_position] if opt]) > 1:
usage()
if len([opt for opt in [get_stdin, get_stderr] if opt]) > 1:
usage()
if len(args) < 1:
usage()
command = ' '.join(args)
p = subprocess.Popen(['/bin/sh', '-'], bufsize=-1, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True, env=env_in,
close_fds=os.name == 'posix')
p.stdin.write(' '.join(args))
(stdout, stderr) = p.communicate()
if get_stderr:
stream = stderr
else:
stream = stdout
if env_out:
if parse_position:
# XXX should be able to specify an env var prefix
env_vars = dict(
[('cram_env_%s' % i, var)
for (i, var) in enumerate(stream.split())])
write_env(env_vars, env_out)
else:
raise NotImplementedError # json, xml
sys.stdout.write(stdout)
sys.stderr.write(stderr)
sys.exit(p.returncode)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment