ó
{ŽŠXc           @   sˆ  d  Z  d d l Z d d l Z d d l Z d d l Z d d l Z d d l Z d d l Z d d l Z d d l	 Z	 d d l
 Z
 d d l Z d d l Z d d l Z d d l Z d d l Z d d l Z d d l m Z d „  Z d e f d „  ƒ  YZ d e f d „  ƒ  YZ d	 e f d
 „  ƒ  YZ d e f d „  ƒ  YZ d e f d „  ƒ  YZ d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z  d „  Z! d „  Z" d „  Z# d „  Z$ d „  Z% d „  Z& d d „ Z( d „  Z) d d d  „ Z* d! d" „ Z+ d# „  Z, d$ „  Z- d% e j. f d& „  ƒ  YZ/ d' e0 f d( „  ƒ  YZ1 d) e0 f d* „  ƒ  YZ2 d+ e j. f d, „  ƒ  YZ3 d- e j4 f d. „  ƒ  YZ5 d S(/   s_   
Miscellaneous utility functions and classes.

.. testsetup:: *

    from wizard.util import *
iÿÿÿÿN(   t   userc         C   sm   y t  t |  ƒ ƒ SWnR t t f k
 rh |  d k sZ |  d k sZ |  d k sZ |  d k r^ t St  |  ƒ SXd S(   s  
    Parse the contents of an environment variable as a boolean.
    This recognizes more values as ``False`` than :func:`bool` would.

        >>> boolish("0")
        False
        >>> boolish("no")
        False
        >>> boolish("1")
        True
    t   Not   not   falset   FalseN(   t   boolt   intt
   ValueErrort	   TypeErrorR   (   t   val(    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   boolish   s    0t   ChangeDirectoryc           B   s)   e  Z d  Z d „  Z d „  Z d „  Z RS(   sš   
    Context for temporarily changing the working directory.

        >>> with ChangeDirectory("/tmp"):
        ...    print os.getcwd()
        /tmp
    c         C   s   | |  _  d  |  _ d  S(   N(   t   dirt   Nonet   olddir(   t   selfR   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   __init__7   s    	c         C   s    t  j ƒ  |  _ t |  j ƒ d  S(   N(   t   ost   getcwdR   t   chdirR   (   R   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt	   __enter__:   s    c         G   s   t  |  j ƒ d  S(   N(   R   R   (   R   t   args(    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   __exit__=   s    (   t   __name__t
   __module__t   __doc__R   R   R   (    (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR   /   s   		t   Counterc           B   sM   e  Z d  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z	 RS(   sñ   
    Object for counting different values when you don't know what
    they are a priori.  Supports index access and iteration.

        >>> counter = Counter()
        >>> counter.count("foo")
        >>> print counter["foo"]
        1
    c         C   s   i  |  _  d  S(   N(   t   dict(   R   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR   J   s    c         C   s*   |  j  j | d ƒ |  j  | c d 7<d S(   s   Increments count for ``value``.i    i   N(   R   t
   setdefault(   R   t   value(    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   countL   s    c         C   s   |  j  | S(   N(   R   (   R   t   key(    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   __getitem__P   s    c         C   s   |  j  j ƒ  S(   N(   R   t   __iter__(   R   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR!   R   s    c         C   s   t  |  j j ƒ  ƒ S(   s#   Returns the max counter value seen.(   t   maxR   t   values(   R   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR"   T   s    c         C   s   t  |  j j ƒ  ƒ S(   s&   Returns the sum of all counter values.(   t   sumR   R#   (   R   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR$   W   s    c         C   s   |  j  j ƒ  S(   s   Returns the keys of counters.(   R   t   keys(   R   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR%   Z   s    (
   R   R   R   R   R   R    R!   R"   R$   R%   (    (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR   @   s   							t
   PipeToLessc           B   s    e  Z d  Z d „  Z d „  Z RS(   sa   
    Context for printing output to a pager.  Use this if output
    is expected to be long.
    c         C   s:   t  j d d t  j ƒ|  _ t j |  _ |  j j t _ d  S(   Nt   lesst   stdin(   t
   subprocesst   Popent   PIPEt   proct   syst   stdoutt
   old_stdoutR(   (   R   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR   c   s    c         G   s9   |  j  r5 |  j  j j ƒ  |  j  j ƒ  |  j t _ n  d  S(   N(   R,   R(   t   closet   waitR/   R-   R.   (   R   R   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR   g   s    	(   R   R   R   R   R   (    (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR&   ^   s   	t   IgnoreKeyboardInterruptsc           B   s    e  Z d  Z d „  Z d „  Z RS(   s‡   
    Context for temporarily ignoring keyboard interrupts.  Use this
    if aborting would cause more harm than finishing the job.
    c         C   s   t  j  t  j t  j ƒ d  S(   N(   t   signalt   SIGINTt   SIG_IGN(   R   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR   r   s    c         G   s   t  j  t  j t  j ƒ d  S(   N(   R3   R4   t   default_int_handler(   R   R   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR   t   s    (   R   R   R   R   R   (    (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR2   m   s   	t   LockDirectoryc           B   s,   e  Z d  Z d d „ Z d „  Z d „  Z RS(   s*   
    Context for locking a directory.
    i  c         C   s   | |  _  | |  _ d  S(   N(   t   lockfilet   expiry(   R   R8   R9   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR   {   s    	c      
   C   sô  xÛt  d d ƒ D]Ê} yD t j |  j t j t j Bƒ t |  j d ƒ j d t j ƒ  ƒ Wn|t k
 rØ} | j	 t	 j
 k r«t |  j d ƒ yç t |  j d ƒ j ƒ  j ƒ  } t j j d | ƒ sò t j d |  j ƒ t j |  j ƒ w n  yU t j ƒ  t j |  j ƒ j |  j k rFt j d	 |  j ƒ t j |  j ƒ w n  Wn. t k
 rw} | j	 t	 j k rqw n  ‚  n XWn t k
 rw n XWd  QXt t j ƒ  ƒ ‚ n' | j	 t	 j k rÒt t j ƒ  ƒ ‚ n  ‚  n Xd  SWt t j ƒ  ƒ ‚ d  S(
   Ni    i   t   ws   %dt   _t   rs   /proc/%ss   Breaking orphaned lock at %ss   Breaking stale lock at %s(   t   rangeR   t   openR8   t   O_CREATt   O_EXCLt   writet   getpidt   OSErrort   errnot   EEXISTR7   t   readt   stript   patht   existst   loggingt   warningt   unlinkt   timet   statt   st_mtimeR9   t   ENOENTt   IOErrort   DirectoryLockedErrorR   t   EACCESt   PermissionsError(   R   t   it   et   pid(    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR   ~   s<    '(
c         G   s,   y t  j |  j ƒ Wn t k
 r' n Xd  S(   N(   R   RL   R8   RC   (   R   R   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR   ¤   s    (   R   R   R   R   R   R   (    (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR7   w   s   	&c         C   sm   y t  j |  ƒ WnU t k
 rh } | j t j k rA t ƒ  ‚ qi | j t j k r_ t ƒ  ‚ qi | ‚ n Xd S(   s\   
    Changes a directory, but has special exceptions for certain
    classes of errors.
    N(   R   R   RC   RD   RS   RT   RP   t   NoSuchDirectoryError(   R   RV   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR   ª   s    c            s    t  ‡  f d †  | j ƒ  Dƒ ƒ S(   s‘   
    A map function for dictionaries.  Only changes values.

        >>> dictmap(lambda x: x + 2, {'a': 1, 'b': 2})
        {'a': 3, 'b': 4}
    c         3   s'   |  ] \ } } | ˆ  | ƒ f Vq d  S(   N(    (   t   .0t   kt   v(   t   f(    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pys	   <genexpr>¿   s    (   R   t   items(   R\   t   d(    (   R\   s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   dictmap¸   s    c            s    t  ‡  f d †  | j ƒ  Dƒ ƒ S(   s‘   
    A map function for dictionaries that passes key and value.

        >>> dictkmap(lambda x, y: x + y, {1: 4, 3: 4})
        {1: 5, 3: 7}
    c         3   s*   |  ]  \ } } | ˆ  | | ƒ f Vq d  S(   N(    (   RY   RZ   R[   (   R\   (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pys	   <genexpr>È   s    (   R   R]   (   R\   R^   (    (   R\   s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   dictkmapÁ   s    c         C   s…   |  j  d ƒ } t } d } xc | d D]W } | j ƒ  } | sD q& n  | d d k r` t } q& n  | r& t } | j d ƒ d Sq& W| S(   se   
    Reads the traceback from a Python program and grabs the
    fully qualified exception name.
    s   
s	   (unknown)i   i    t    t   :(   t   splitR   t   rstript   Truet	   partition(   t   outputt   linest   cuet   resultt   line(    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   get_exception_nameÊ   s     c         C   s   t  j |  ƒ j S(   s4   Finds the uid of the person who owns this directory.(   R   RN   t   st_uid(   R   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   get_dir_uidÝ   s    c          C   so   t  j j t  j j t  j j t  j j t ƒ ƒ ƒ d ƒ }  t j d d |  d d g d t j ƒj	 ƒ  d j
 ƒ  S(   s4   Returns the commit ID of the current Wizard install.s   .gitt   gits
   --git-dir=s	   rev-parset   HEADR.   i    (   R   RH   t   joint   dirnamet   abspatht   __file__R)   R*   R+   t   communicateRd   (   t
   wizard_git(    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   get_revisioná   s    9c          C   sD   t  j ƒ  }  |  d k r! t ‚ n  t  j |  ƒ } d | j | j f S(   s³   
    Returns ``Real Name <username@mit.edu>`` suitable for use in
    Git ``Something-by:`` string.  Throws :exc:`NoOperatorInfo` if
    no operator information is available.
    s   %s <%s>N(   R    t   operatorR   t   NoOperatorInfot   pwnamt   realnamet   email(   t   opt   info(    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   get_operator_gité   s
    	c          C   sb   t  j ƒ  }  |  d k r d St  j |  ƒ } | j s8 d St j d | j ƒ t j d | j ƒ d S(   s§   
    Sets :envvar:`GIT_COMMITTER_NAME` and :envvar:`GIT_COMMITTER_EMAIL`
    environment variables if applicable.  Does nothing if no information
    is available
    Nt   GIT_COMMITTER_NAMEt   GIT_COMMITTER_EMAIL(   R    Rx   R   Rz   R{   R   t   putenvR|   (   R}   R~   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   set_operator_envõ   s    	c          C   s[   t  j ƒ  }  |  d k r d S|  j s) d St j d d |  j ƒ t j d d |  j ƒ d S(   s¦   
    Sets :envvar:`GIT_AUTHOR_NAME` and :envvar:`GIT_AUTHOR_EMAIL`
    environment variables if applicable. Does nothing if
    :func:`wizard.user.passwd` fails.
    Nt   GIT_AUTHOR_NAMEs   %st   GIT_AUTHOR_EMAIL(   R    t   passwdR   R{   R   R‚   R|   (   R~   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   set_author_env  s    	c           C   s   t  ƒ  t ƒ  d S(   s;   Sets all appropriate environment variables for Git commits.N(   Rƒ   R‡   (    (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   set_git_env  s    c           C   s*   d j  d t ƒ  d d j  t j ƒ g ƒ S(   s9   Returns strings for placing in Git log info about Wizard.s   
s   Wizard-revision: %ss   Wizard-args: %sRa   (   Rq   Rw   R-   t   argv(    (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   get_git_footer  s    c         C   sw   t  j j |  ƒ s d Sd |  } d } x: t j ƒ  D], } d | | f } t  j j | ƒ s3 Pq3 q3 Wt  j |  | ƒ | S(   s&   Moves a file/dir to a backup location.s   %s.baks   %s.%dN(   R   RH   t   lexistsR   t	   itertoolsR   t   rename(   t   filet   prefixt   nameRU   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   safe_unlink  s    
c         C   s)   y t  j |  ƒ Wn t k
 r$ n Xd S(   s6   Unlink a file, but don't complain if it doesn't exist.N(   R   RL   RC   (   RŽ   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   soft_unlink*  s    c         C   sC   y t  j |  ƒ Wn+ t k
 r> } | j t j k r8 q? ‚  n Xd S(   sv   
    Create a directory path (a la ``mkdir -p`` or ``os.makedirs``),
    but don't complain if it already exists.
    N(   R   t   makedirsRC   RD   RE   (   RH   t   exc(    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR“   1  s    c   
      C   sE  yt  j |  ƒ } | j d ƒ d | j d ƒ } | r” i d d 6} t j d |  | ƒ t j d t j | ƒ ƒ | j	 d | t j | ƒ | ƒ n# t j d |  | ƒ | j	 d | ƒ | j
 ƒ  } t j d	 | j ƒ t j d
 | j ƒ | j ƒ  } | j ƒ  | SWn: t j k
 r@}	 |	 j t j k r:t |  ƒ ‚ qA‚  n Xd  S(   Nt   /s!   application/x-www-form-urlencodeds   Content-types   POST request to http://%s%ss   POST contents:
t   POSTs   GET request to http://%s%st   GETs   Response code: %ds   Response headers: %s(   t   httplibt   HTTPConnectionRd   t   lstripRJ   R~   t   debugt   urllibt	   urlencodet   requestt   getresponset   statust   msgRF   R0   t   sockett   gaierrorRD   t
   EAI_NONAMEt   DNSError(
   t   hostRH   t   subpatht   postt   ht   fullpatht   headersR<   t   dataRV   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   fetch>  s(     "
c         C   s9   t  |  d ƒ } | j ƒ  t | j t ƒ } | j ƒ  | S(   s4   Returns ``True`` if ``filename`` has mixed newlines.t   U(   R>   RF   t
   isinstancet   newlinest   tupleR0   (   t   filenameR\   t   ret(    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   mixed_newlinesW  s
    

s   .gitc   	      C   s  |  d k r t j ƒ  }  n  d } xæ t j |  ƒ D]Õ \ } } } xÃ | D]» } t j j | | ƒ j t j j |  | ƒ ƒ sG t j j | | ƒ } y2 t j j | ƒ rª wG n  | t j j | ƒ 7} Wqt	 k
 rþ } | j
 t
 j k rø t j d | ƒ qÿ ‚  qXqG qG Wq1 W| S(   s¹   
    Recursively determines the disk usage of a directory, excluding
    .git directories.  Value is in bytes.  If ``dir`` is omitted, the
    current working directory is assumed.
    i    s#   %s disappeared before we could statN(   R   R   R   t   walkRH   Rq   t
   startswitht   islinkt   getsizeRC   RD   RP   RJ   RK   (	   R   t   excluded_dirt	   sum_sizest   rootR;   t   filesR   RŽ   RV   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt
   disk_usage_  s      - i   c         C   s   d j  d „  t |  ƒ Dƒ ƒ S(   s7   Generates a random alphanumeric key of ``length`` size.t    c         s   s(   |  ] } t  j t j t j ƒ Vq d  S(   N(   t   randomt   choicet   stringt   letterst   digits(   RY   RU   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pys	   <genexpr>w  s    (   Rq   t   xrange(   t   length(    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt
   random_keyu  s    c         C   s   t  |  ƒ j d ƒ d S(   s.   Truncates the Scripts specific version number.s   -scriptsi    (   t   strRf   (   t   version(    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   truncatey  s    c          C   sv   d }  t  j j |  ƒ s( t  j |  ƒ n  t t  j j |  d ƒ d ƒ j d ƒ t t  j j |  d ƒ d ƒ j d ƒ d S(   su   
    Generates a .wizard directory and initializes it with some common
    files.  This operation is idempotent.
    s   .wizards	   .htaccessR:   s   Deny from all
s
   .gitignores   *
N(   R   RH   t   isdirt   mkdirR>   Rq   RA   (   t
   wizard_dir(    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   init_wizard_dir}  s
    %Ry   c           B   s   e  Z d  Z RS(   s?   No information could be found about the operator from Kerberos.(   R   R   R   (    (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyRy   ‰  s   RT   c           B   s   e  Z e j Z RS(    (   R   R   RD   RS   (    (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyRT     s   RX   c           B   s   e  Z e j Z RS(    (   R   R   RD   RP   (    (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyRX     s   RR   c           B   s   e  Z d  „  Z d „  Z RS(   c         C   s   | |  _  d  S(   N(   R   (   R   R   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR   ”  s    c         C   s   d S(   Nsa   

ERROR: Could not acquire lock on directory.  Maybe there is
another migration process running?
(    (   R   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   __str__–  s    (   R   R   R   RÎ   (    (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyRR   “  s   	R¥   c           B   s)   e  Z e j Z d Z d  „  Z d „  Z RS(   c         C   s   | |  _  d  S(   N(   R¦   (   R   R¦   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR   ¡  s    c         C   s   d |  j  S(   Ns(   

ERROR: Could not resolve hostname %s.
(   R¦   (   R   (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyRÎ   £  s    N(	   R   R   R¢   R¤   RD   R   R¦   R   RÎ   (    (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyR¥     s   		(6   R   t   os.pathR   R)   t   pwdR-   R¢   RD   RŒ   R3   R˜   Rœ   RM   RJ   R¿   RÁ   t   wizardR    R
   t   objectR   R   R&   R2   R7   R   R_   R`   Rl   Rn   Rw   R   Rƒ   R‡   Rˆ   RŠ   R‘   R’   R“   R   R­   R´   R½   RÆ   RÉ   RÍ   t   ErrorRy   RQ   RT   RX   RR   R£   R¥   (    (    (    s9   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/util.pyt   <module>   s`   	
3																			
