2 Miscellaneous utility functions and classes.
6 from wizard.util import *
17 class ChangeDirectory(object):
19 Context for temporarily changing the working directory.
21 >>> with ChangeDirectory("/tmp"):
25 def __init__(self, dir):
29 self.olddir = os.getcwd()
31 def __exit__(self, *args):
34 class Counter(object):
36 Object for counting different values when you don't know what
37 they are a priori. Supports index access and iteration.
39 >>> counter = Counter()
40 >>> counter.count("foo")
41 >>> print counter["foo"]
46 def count(self, value):
47 """Increments count for ``value``."""
48 self.dict.setdefault(value, 0)
50 def __getitem__(self, key):
53 return self.dict.__iter__()
57 A map function for dictionaries. Only changes values.
59 >>> dictmap(lambda x: x + 2, {'a': 1, 'b': 2})
62 return dict((k,f(v)) for k,v in d.items())
64 def get_exception_name(output):
66 Reads the traceback from a Python program and grabs the
67 fully qualified exception name.
69 lines = output.split("\n")
70 for line in lines[1:]: # skip the "traceback" line
72 if line[0] == ' ': continue
79 """Finds the uid of the person who owns this directory."""
80 return os.stat(dir).st_uid
82 def get_dir_owner(dir = "."):
84 Finds the name of the locker this directory is in.
88 This function uses the passwd database and thus
89 only works on scripts servers.
91 return pwd.getpwuid(get_dir_uid(dir)).pw_name
94 """Returns the commit ID of the current Wizard install."""
95 wizard_git = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".git")
96 return subprocess.Popen(["git", "--git-dir=" + wizard_git, "rev-parse", "HEAD"], stdout=subprocess.PIPE).communicate()[0].rstrip()
98 def get_operator_info():
100 Returns tuple of ``(realname, email)`` from Hesiod about the
101 this operator of this script from :func:`get_operator_name`.
102 Useful when generating commit messages.
104 username = get_operator_name()
105 hesinfo = subprocess.Popen(["hesinfo", username, "passwd"],stdout=subprocess.PIPE).communicate()[0]
106 fields = hesinfo.partition(",")[0]
107 realname = fields.rpartition(":")[2]
108 return realname, username + "@mit.edu"
110 def get_operator_git():
112 Returns ``Real Name <username@mit.edu>`` suitable for use in
113 Git ``Something-by:`` string.
115 return "%s <%s>" % get_operator_info()
117 def get_operator_name():
119 Returns username of the person operating this script based
120 off of the :envvar:`SSH_GSSAPI_NAME` environment variable. Throws
121 :exc:`NoOperatorInfo` if environment variable is not available.
125 :envvar:`SSH_GSSAPI_NAME` is not set by a vanilla OpenSSH
126 distributions. Scripts servers are patched to support this
127 environment variable.
129 principal = os.getenv("SSH_GSSAPI_NAME")
130 if not principal: raise NoOperatorInfo
131 instance, _, _ = principal.partition("@")
132 if instance.endswith("/root"):
133 username, _, _ = principal.partition("/")
138 def set_operator_env():
140 Sets :envvar:`GIT_COMMITTER_NAME` and :envvar:`GIT_COMMITTER_EMAIL`
141 environment variables if applicable. Does nothing if
142 :func:`get_operator_info` throws :exc:`NoOperatorInfo`.
145 op_realname, op_email = get_operator_info()
146 os.putenv("GIT_COMMITTER_NAME", op_realname)
147 os.putenv("GIT_COMMITTER_EMAIL", op_email)
148 except NoOperatorInfo:
151 def set_author_env():
153 Sets :envvar:`GIT_AUTHOR_NAME` and :envvar:`GIT_AUTHOR_EMAIL` environment
154 variables if applicable. Does nothing if :func:`get_dir_owner` fails.
157 lockername = get_dir_owner()
158 os.putenv("GIT_AUTHOR_NAME", "%s locker" % lockername)
159 os.putenv("GIT_AUTHOR_EMAIL", "%s@scripts.mit.edu" % lockername)
160 except KeyError: # XXX: This doesn't actually make sense
164 """Sets all appropriate environment variables for Git commits."""
168 def get_git_footer():
169 """Returns strings for placing in Git log info about Wizard."""
170 return "\n".join(["Wizard-revision: %s" % get_revision()
171 ,"Wizard-args: %s" % " ".join(sys.argv)
174 class NoOperatorInfo(wizard.Error):
175 """No information could be found about the operator from Kerberos."""