a
    \hX                     @   s   d Z ddlZddlZddlZddlZG dd dZG dd dZG dd dZG d	d
 d
ZG dd dZ	e
dkrddlZe  dS )z
@modified: April 25, 2025
@author: Dale Hamel
@author: Brian Fristensky
@contact: frist@cc.umanitoba.ca
The purpose of this class is to Provide support for the various actions that are repeated by several different python scripts
    Nc                   @   sr   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdddZ	dd Z
dd Zdd Zdd Zdd Zdd ZdS )Birchmodz
    Purpose:
    This class provides common safety features to scripts,
    as well as making user interactions more intuitive.
    In particular, this class is intended to provide
    user-readable information when an error occurs
    c                 C   s   || _ || _dS )zBInitializes birchmod to contain the program usage and program nameN)PROGRAMUSAGE)selfZprogZuse r   2/home/psgendb/BIRCHDEV/install-scripts/birchlib.py__init__   s    zBirchmod.__init__c                 C   s   ddl m} |dS )z0return the location of the user's home directoryr   )
expanduser~)Zos.pathr	   )r   r	   r   r   r   
getHomeDir   s    zBirchmod.getHomeDirc                 C   sp   t jd}|dkrht jd}t j|ddd}t|d}| }tdd	 |D rht	 
d
d }t|S )a  return user's email address
        This is currently a bit of a hack. We need to find a better way to do this.
        1. If MAILID environment variable is set, use that.
        2. If MAILID="", then use the mailid in $BIRCH/local/admin/BIRCH.properties
        ZMAILID BIRCHlocaladminBIRCH.propertiesrc                 s   s   | ]}| d V  qdS )zBirchProps.adminEmailN)
startswith).0liner   r   r   	<genexpr>0       z(Birchmod.getEmailAddr.<locals>.<genexpr>=   )osenvirongetpathjoinopen	readlinesanyr   stripsplitstr)r   Z	emailaddrr   ZpropfileZ
propfile_hlinesr   r   r   getEmailAddr#   s    
zBirchmod.getEmailAddrc                 C   s   t j|ddd}t|d}d}d| }| }|  t|}|dkrd}	|	|k r|dkr||	 }
|
ds|
d	}|d |kr|d
 	 }|	d
7 }	qL|S )z
        Retrieve a value from BIRCH.properties. eg. To retrieve the value
        of BirchProps.adminEmail:

        GetBIRCHProperties(BIRCHDIR,"adminEmail")
        r   r   r   r   r   zBirchProps.r   #r   r   )
r   r   r   r   r   closelenr   r"   r!   )r   ZBIRCHDIRZPropNameZPFNZpfileValueZTargetr$   Zplenir   tokensr   r   r   GetBIRCHProperties4   s"    



zBirchmod.GetBIRCHPropertiesc                    sb   t d| d | d  ddl}d	 fdd	}|j|}| }t|d}|| |  dS )
zQDownloads from url specified to the filename/path specified and displays progressz	Fetching z from z

r   Nc                    sr   zt | | d | d}W n   d}Y n0 | dkrnd} jd t| d d t||  d }tj| d S )Nd   r   i@B z	Progress:%z of zMB)minr   r#   sysstdoutwrite)Z	numblocks	blocksizeZfilesizeurlZpercentZMB_CONSTZout_strr   r   r   
reporthookR   s    
*z!Birchmod.wget.<locals>.reporthookwb)N)printZurllib.requestZrequestZurlopenreadr   r2   r'   )r   r4   nameZurllibr6   ZresponseZcontentfr   r5   r   wgetN   s    

zBirchmod.wget.c                 C   s    t |}|| |  dS )zSExtracts the tarfile given by file to current working directory by default, or pathN)tarfiler   
extractallr'   )r   filer   Ztarballr   r   r   untarc   s    

zBirchmod.untarc                 C   s   t j|rt| dS )z5Mimics the behavior or unix rm -rf for the given pathN)r   r   existsshutilrmtree)r   r   r   r   r   rmrfp   s    zBirchmod.rmrfc                 C   s   t | j| j  tdS )zsCalled when a program performs an illegal operation. Causes program to print its appropriate usage, and exit nicelyN)r8   r   r   
SystemExitr5   r   r   r   
printusagev   s    zBirchmod.printusagec                 C   sl   t |}t| jd | d  tj|rBt| jd | d  n"t| jd | d t  d  tdS )zKCalled when reading a file fails, used to provide more comprehensive outputz2An error occurred trying to process file named : ''z
The file 'z"' exists, but may not be accessed.z' does not exist in 'N)r#   r8   r   r   r   isfilegetcwdrF   )r   	file_namer   r   r   
file_error}   s    "zBirchmod.file_errorc                 C   s   t | jd  tdS )zRUsed to indicate to the user that a script did execute, and completed successfullyz Successfully completed executionN)r8   r   rF   r5   r   r   r   exit_success   s    zBirchmod.exit_successc                 C   s0   t |tst| jd  n|tjv r(dS dS dS )z?Returns true if "argId" was a string passed on the command linez/Argument to be check for not supplied as stringTFN)
isinstancer#   r8   r   r0   argv)r   argIdr   r   r   	arg_given   s
    

zBirchmod.arg_givenc                 C   s4   |  dr,t| jd  ddl}|  dS dS dS )ztcalled by using "pydoc {path to script} pydoc" * note must pass "pydoc" as an argument to toggle documentation mode*z-pydoczGenerating documentation...r   NTF)rQ   r8   r   doctesttestmod)r   rR   r   r   r   
documentor   s    
zBirchmod.documentorN)r=   )__name__
__module____qualname____doc__r   r   r%   r,   r<   rA   rE   rG   rL   rM   rQ   rT   r   r   r   r   r      s   
r   c                   @   sH   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dS )Argumenta"  
    The purpose of this class is to provide a simplified and common way
    for all scripts retrieve arguments from the command line parameters provided (sys.argv)
    This is done by declaring an Argument variable, and specifying any advanced attributes
    with the various augmentation methods provided.

    BUG: Argument will split up a quoted command line argument containing blanks into individual
    tokens. Eg. 'this should be a single argument'.

    DEPRECATED in favor of optparse. Even optparse is deprecated  in favor of agrparse,
    but argparse is new in Python 2.7. Therefore, it is safer to use optparse, which has
    a very similar syntax to argparse, unless you are sure you will be using Python 2.7 or later.
    It is also worth mentioning that optparse will correctly parse command line arguments
    enclosed in quotes. There have been reports that
    argparse will break up strings between blank spaces.

    Examples:

    # optional arguments with parameters
    self.AInf = Argument("-inf", str, BM)
    self.AInf.set_optional()

    self.AOutf = Argument("-outf", str, BM)
    self.AOutf.set_optional()

    # optional argument with no parameters ie. switch
    self.AInvert = Argument("-inv", str, BM)
    self.AInvert.set_is_switch()
    self.AInvert.set_optional()

    # required arguments at a specific position.
    Ainfile = Argument("", str, BM)
    Ainfile.set_position(-2)

    Aoutfile = Argument("", str, BM)
    Aoutfile.set_position(-1)


    try:
        if (BM.arg_given("-inf")):
           self.InFormat = self.AInf.fetch()
        if (BM.arg_given("-outf")):
           self.OutFormat = self.AOutf.fetch()
        self.Invert = BM.arg_given("-inv")
        self.Ifn = Ainfile.fetch()
        self.Ofn = Aoutfile.fetch()
    except ValueError:
        BM.printusage()


    c                 C   sn   t || _d| _d| _d| _d| _d| _t|tr:|| _	n|dkrPd| _d| _	nt
t|trf|| _nt
dS )a  
        Initializer:
        arg_id: The command line flag that specifies an argument parameter is to follow,
                   ex: "-o outfile"
        type: The type that the argument is. This must be a basic type, such as str, float, bool.
                  if you are unsure if something is a basic type, try running "type(yourtypename)" at interpretter
        BM: a pointer to the Birchmod module for the class using this argument (they are coupled)
        Tr   NF)r#   arg_idis_requiredpositionexcludeis_flagBMrN   typearg_type
ValueErrorr   )r   rZ   ra   ZBMODr   r   r   r      s    	


zArgument.__init__c                 C   s   t || _dS )a|  
        Specify the position on sys.argv where the argument is always found.
        Argument 0 is the name of the program, so argument 1 is the first argument.
        Note that arguments near the end can be specified by len(sys.argv)-X,
        where X is the index from the end. "-1" refers to the last argument, "-2"
        refers to the next to last argument, etc.
        N)intr\   )r   r\   r   r   r   set_position  s    zArgument.set_positionc                 C   s<   || j krt| jjd  | jdkr,t | _| j| dS )z`Add an argument (flag) to the list of mutually exclusive argument flags for this Argument's flagz"An argument may not exclude itselfN)rZ   r8   r_   r   r]   listappend)r   r]   r   r   r   add_exclusive  s
    

zArgument.add_exclusivec                 C   s
   d| _ dS )z/Use this if the paramter passed is NOT requiredFN)r[   r5   r   r   r   set_optional  s    zArgument.set_optionalc                 C   s   d| _ d| _dS )zcif this argument is just a switch (with no parameters), set this to true (ex ls -l, -l is a switch)TN)r^   ra   r5   r   r   r   set_is_switch  s    zArgument.set_is_switchc                 C   sH  t | jdkr2| jttjk r,tj| j }ntn| jr| jdkr| jD ]B}|tjv rH| jtjv rHt	| j
jd | d | j d  t  qH| jtjv }nl| jr| jtjvrt	tj tn| | j}n<| jdkr| jD ]}|tjv r| jtjv rtq| | j}| jdkr*| jtjv r*| |}| jtkrD|dkrDd}|S )zh
        This method attempts to fetch the argument with the specified attributes from sys.argv
        r   Nz+Cannot combine mutually exclusive options "z" and ""r   )absr\   r(   r0   rO   rb   r^   r]   rZ   r8   r_   r   exitr[   _Argument__get_argra   r#   )r   Z	to_returnZeachr   r   r   fetch"  s4    

"



zArgument.fetchc                 C   sl   t |}z2tj|d }|ttjk r4tj| W S tW n, tyf   t| jjd | d  Y dS 0 dS )z
        Used as a helper method. Retrieves a flags parameter, assuming it is one index to the right.
        ex "-o outfile", if argId= -o, this will return outfile
        r   z	Argument z not supplied at command line.N)	r#   r0   rO   indexr(   rb   r8   r_   r   )r   rP   r\   r   r   r   Z	__get_arg^  s    zArgument.__get_argN)rU   rV   rW   rX   r   rd   rg   rh   ri   rn   rm   r   r   r   r   rY      s   4#<rY   c                   @   s`   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd ZdS )
HTMLWriterz"Methods for writing html to a filec                 C   s   d| _ d| _d| _dS )zx
          Initializes arguments:
                indentwidth=3
                col=0
                lpad=""
             r   r   N)indentwidthcollpadr5   r   r   r   r   r  s    zHTMLWriter.__init__c                 C   s    | j | j | _ d| j | _dS )z|
          **indent is not currently used by htmlwriter**
          decrease indent using identwidth blank spaces
           N)rs   rr   rjustrt   r5   r   r   r   indent~  s    zHTMLWriter.indentc                 C   s8   | j | j | _ | j dk r&d| _ d| _nd| j | _dS )z|
          **undent is not currently used by htmlwriter**
          decrease indent using identwidth blank spaces
          r   r   ru   N)rs   rr   rt   rv   r5   r   r   r   undent  s
    
zHTMLWriter.undentc                 C   s   | d| | d  dS )aA  
          Write begin tag, with attributes
          @param htmlfile: The name of the html file to write the tag for
          @type htmlfile: str
          @param tagname: The name of the tag
          @type tagname: str
          @param attributes: The tag information itself
          @type attributes: str
          <>
Nr2   )r   htmlfiletagname
attributesr   r   r   start  s    zHTMLWriter.startc                 C   s   | d| d  dS )z
          Write end tag
          @param htmlfile: The of the html file to write tag for
          @type htmlfile: str
          @param tagname: The name of the tag to write
          @type tagname: str
          </rz   Nr{   )r   r|   r}   r   r   r   end  s    	zHTMLWriter.endc                 C   s   | d| d  dS )z
          Write title
          @param htmlfile: The name of the html file to add the title to
          @type htmlfile: str
          @param title: The title to write
          @type title: str
          z<title>birch - z	</title>
Nr{   )r   r|   titler   r   r   
page_title  s    	zHTMLWriter.page_titlec                 C   s&   | d| d | d | d  dS )z
          FIXME
          @param htmlfile:
          @type htmlfile:
          @param url:
          @type url:
          @param attributes:
          @type attributes:
          @param text:
          @type text:
          z	<a href="rj   >z</a>Nr{   )r   r|   r4   r~   textr   r   r   link  s    zHTMLWriter.linkc                 C   s   | d | |dd | || d}| |d| | |dd d}d}| ||d| | d	|  | |d | d
 dS )z
          FIXME
          @param htmlfile:
          @type htmlfile:
          @param title:
          @type title:
          z9<!-- this page generated automatically by htmldoc.py -->
htmlr   z- style ="background-color: rgb(255, 204, 0);"bodyh1z../../index.htmlzO<img alt="birch - " src="../../images/birch_white.png" height="68" width="100">ru   z<br>N)r2   r   r   r   r   )r   r|   r   r~   r4   r   r   r   r   
start_page  s    	
zHTMLWriter.start_pagec                 C   s,   d}|  |d| || | |d dS )z}
          FIXME
          @param htmlfile:
          @type htmlfile:
          @param text:
          @type text:
          z style="margin-left: 40px;"ZdivN)r   r2   r   )r   r|   r   r~   r   r   r   indent_text  s    	
zHTMLWriter.indent_textc                 C   s   |  |d |  |d dS )zP
          FIXME
          @param htmlfile:
          @type htmlfile:
          r   r   N)r   )r   r|   r   r   r   end_page  s    zHTMLWriter.end_pageN)rU   rV   rW   rX   r   rw   rx   r   r   r   r   r   r   r   r   r   r   r   rp   o  s   	rp   c                   @   s4   e Zd Zdd Zdd Zdd Zdd Zd	d
 ZdS )	Htmlutilsc                 C   s   || _ || _dS )z
                FIXME
                @param CATDICT:
                @type CATDICT:
                @param PROGDICT:
                @type PROGDICT:
                N)CATDICTPROGDICT)r   r   r   r   r   r   r     s    zHtmlutils.__init__c                 C   sL   |  }d}|t|k rH|| d||< || dd||< |d }q|S )z`
                FIXME
                @param line:
                @type line:
                r   rj   \r   )r"   r(   r!   replace)r   r   r+   r*   r   r   r   tokenize  s    

zHtmlutils.tokenizec                    s   G  fdddt }|S )a  
                this function simplifies the transition to python 3 by eleiminating the need for the "cmp" function
        this was a recommended workaround for using "cmp"'s in sorts (recommended by: http://wiki.python.org/moin/HowTo/Sorting/)
                c                       s\   e Zd Zdd Z fddZ fddZ fddZ fd	d
Z fddZ fddZ	dS )zHtmlutils.cmp_to_key.<locals>.Kc                 W   s
   || _ dS )z
                                FIXME
                                @param obj:
                                @type obj:
                                @param *args:
                                @type *args:
                                Nobj)r   r   argsr   r   r   r   !  s    z(Htmlutils.cmp_to_key.<locals>.K.__init__c                    s    | j |j dk S z
                                FIXME
                                @param other:
                                @type other:
                                r   r   r   othermycmpr   r   __lt__*  s    z&Htmlutils.cmp_to_key.<locals>.K.__lt__c                    s    | j |j dkS r   r   r   r   r   r   __gt__1  s    z&Htmlutils.cmp_to_key.<locals>.K.__gt__c                    s    | j |j dkS r   r   r   r   r   r   __hash__8  s    z(Htmlutils.cmp_to_key.<locals>.K.__hash__c                    s    | j |j dkS r   r   r   r   r   r   __le__?  s    z&Htmlutils.cmp_to_key.<locals>.K.__le__c                    s    | j |j dkS r   r   r   r   r   r   __ge__F  s    z&Htmlutils.cmp_to_key.<locals>.K.__ge__c                    s    | j |j dkS r   r   r   r   r   r   __ne__M  s    z&Htmlutils.cmp_to_key.<locals>.K.__ne__N)
rU   rV   rW   r   r   r   r   r   r   r   r   r   r   r   K   s   	r   )object)r   r   r   r   r   r   
cmp_to_key  s    4zHtmlutils.cmp_to_keyc                 C   s*   |d dkr"|d |dd  }n|}|S )z
                FIXME
                @param name:
                @type name:
                @param doc_prefix:
                @type doc_prefix:
                r   $/r   Nr   )r   r:   Z
doc_prefixr4   r   r   r   name_to_urlV  s    zHtmlutils.name_to_urlc                 C   sj   t |d}d}|D ] }|dkr*|d|_|d }q|  |jddks\|jddkrbd}nd	}|S )
z
                FIXME
                @param fn:
                @type fn:
                @param p:
                @type p:
                r   r   rq   z\szhttp://r   zfile:///TF)r   r!   	DOCPREFIXr'   find)r   fnpr@   r*   r   Zokayr   r   r   
get_prefixj  s    


 zHtmlutils.get_prefixN)rU   rV   rW   r   r   r   r   r   r   r   r   r   r     s
   ;r   c                   @   s    e Zd ZdZdd Zdd ZdS )	SimpleXMLzOSimple methods for working wth XML files as an alternative to xml or defusedxmlc                 C   s   dS )z	
        Nr   r5   r   r   r   r     s    zSimpleXML.__init__c                 C   s   d}d| d }d| d }t |d}| }d}|dkr|dkr||}	||}
|	dkrz|
dkrz||	t| |
 }| }q2|  |S )a
  
                return a string value from a field of the form <FieldName>Value</FieldName>
                This function ONLY returns the first field in the file that matches the
                pattern, regardless of how many subsequent fields may match.
        r   ry   r   r   r   )r   readliner   r(   r'   )r   FileZ	FieldNamer)   ZBeginTargetZ	EndTargetZ	h_XMLFiler   ZPOSNZLPOSNZRPOSNr   r   r   GetXMLField  s    



zSimpleXML.GetXMLFieldN)rU   rV   rW   rX   r   r   r   r   r   r   r     s   r   __main__)rX   r   r0   r>   rC   r   rY   rp   r   r   rU   rR   rS   r   r   r   r   <module>   s      G 	 