a
    xd                  	   @   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mZ ddlmZmZmZmZ ddlmZ dZdZedZed	Zd
Zg dZg dZdddddddddZddgZddddddddddddddded d!dd"ed gZe d#kZejd$kZ e o0e! d d%v Z"e oZe! d d%v pZe! d& d'v Z"d(Z#e$d)Z%d*Z&ej'(d+d,Z)d-d. Z*esddl+Z+d/d0 Z*d1d2 Z,d3d4 Z-G d5d6 d6Z.G d7d8 d8Z/G d9d: d:Z0G d;d< d<e1Z2G d=d> d>e3Z4G d?d@ d@Z5G dAdB dBZ6dCdD Z7G dEdF dFZ8dPdHdIZ9dQdJdKZ:G dLdM dMZ;G dNdO dOeZ<dS )Ra  
from crontab import CronTab
import sys

# Create a new non-installed crontab
cron = CronTab(tab='')
job  = cron.new(command='/usr/bin/echo')

job.minute.during(5,50).every(5)
job.hour.every(4)

job.dow.on('SUN')
job.month.during('APR', 'JUN')
job.month.also.during('OCT', 'DEC')

job.every(2).days()
job.setall(1, 12, None, None, None)

job2 = cron.new(command='/foo/bar', comment='SomeID')
job2.every_reboot()

jobs = list(cron.find_command('bar'))
job3 = jobs[0]
job3.clear()
job3.minute.every(1)

sys.stdout.write(str(cron.render()))

job3.enable(False)

for job4 in cron.find_command('echo'):
    sys.stdout.write(job4)

for job5 in cron.find_comment('SomeID'):
    sys.stdout.write(job5)

for job6 in cron:
    sys.stdout.write(job6)

for job7 in cron:
    job7.every(3).hours()
    sys.stdout.write(job7)
    job7.every().dow()

cron.remove_all(command='/foo/bar')
cron.remove_all(comment='This command')
cron.remove_all(time='* * * * *')
cron.remove_all()

output = cron.render()

cron.write()

cron.write(filename='/tmp/output.txt')

#cron.write_to_user(user=True)

#cron.write_to_user(user='root')

# Croniter Extentions allow you to ask for the scheduled job times, make
# sure you have croniter installed, it's not a hard dependancy.

job3.schedule().get_next()
job3.schedule().get_prev()

    N)sleep)timedatedatetime	timedelta)OrderedDictzpython-crontabz2.7.1za^\s*([^@#\s]+)\s+([^@#\s]+)\s+([^@#\s]+)\s+([^@#\s]+)\s+([^@#\s]+)\s+([^\n]*?)(\s+#\s*([^\n]*)|$)z(^\s*@(\w+)\s([^#\n]*)(\s+#\s*([^\n]*)|$)z>/dev/null 2>&1)sunmontuewedthufrisatr   )Njanfebmaraprmayjunjulaugsepoctnovdec@rebootz	0 * * * *z	0 0 * * *z	0 0 * * 0z	0 0 1 * *z	0 0 1 1 *)ZrebootZhourlyZdailyZweeklyZmonthlyZyearlyannuallymidnightr   r   ;   ZMinutes)maxminname   ZHours      zDay of Month   ZMonth)r   r    r!   enum   zDay of WeekWindowsposix)SunOSZAIXzHP-UX   )ZmipsFZcrontabz/usr/bin/crontabSHELLz/bin/shc                   C   s   d S N r.   r.   r.   ?/var/www/html/Ranjet/env/lib/python3.9/site-packages/crontab.py<lambda>       r0   c                   C   s   t t d S )z(Returns the username of the current userr   )pwdgetpwuidosgetuidr.   r.   r.   r/   current_user   s    r6   c                 O   s   t tj| |dtd}|dd}| D ]L\}}t|dkrh|d| f7 }|durz|t|f7 }q.|d||f f7 }q.t dd	 |t | D }tj	|tj
tj
|d
S )zRuns a program and orders the arguments for compatability.

    a. keyword args are flags and always appear /before/ arguments for bsd
    r)   )r)   envNr$   z-%sz--%s=%sc                 s   s   | ]}|r|V  qd S r-   r.   ).0argr.   r.   r/   	<genexpr>   r1   zopen_pipe.<locals>.<genexpr>)stdoutstderrr7   )tupleshlexsplitpopPOSIXitemslenstrspPopenPIPE)cmdargsflagscmd_argsr7   keyvaluer.   r.   r/   	open_pipe   s    rN   c                 C   s   t | tr| dS | S )z9Convert to the best string format for this python versionutf-8)
isinstancebytesdecodetextr.   r.   r/   _str   s    

rU   c                       s  e Zd ZdZd?ddZdd Zdd Zed	d
 Zedd Z	edd Z
 fddZd@ddZdAddZdBddZdCddZdd ZdDdd ZdEd!d"ZdFd#d$Zd%d& Zd'd( Zd)d* Zed+d, Zed-d. Zd/d0 Zd1d2 Zd3d4 Zd5d6 Zd7d8 Zd9d: Zd;d< Zd=d> Z   Z!S )GCronTaban  
    Crontab object which can access any time based cron using the standard.

    user    - Set the user of the crontab (default: None)
      * 'user' = Load from $username's crontab (instead of tab or tabfile)
      * None   = Don't load anything from any user crontab.
      * True   = Load from current $USER's crontab (unix only)
      * False  = This is a system crontab, each command has a username

    tab     - Use a string variable as the crontab instead of installed crontab
    tabfile - Use a file for the crontab instead of installed crontab
    log     - Filename for logfile instead of /var/log/syslog
    Nc                 C   s`   d | _ d | _d | _t| _d | _t | _t o6t	
 dk| _|| _|| _|| _| | || _d S )Nr   )linescronsfilenCRON_COMMANDcron_commandr7   r   _parked_envWINOSr4   r5   root_userintabtabfileread_log)selfusertabra   logr.   r.   r/   __init__   s    
zCronTab.__init__c                 C   s   | S r-   r.   rd   r.   r.   r/   	__enter__   s    zCronTab.__enter__c                 C   s   |    d S r-   write)rd   exc_typeexc_valexc_tbr.   r.   r/   __exit__   s    zCronTab.__exit__c                 C   s>   ddl m} | jdu s"t| jtr8|| j| jp0dd| _| jS )z?Returns the CronLog object for this tab (user or root tab only)r   )CronLogNr^   re   )Zcronlogrq   rc   rP   rD   re   )rd   rq   r.   r.   r/   rg      s    zCronTab.logc                 C   s   | j du rt S | j S )z4Return user's username of this crontab if applicableTr_   r6   ri   r.   r.   r/   re      s    
zCronTab.userc                 C   s*   | j r&| j dur&| j t kr&d| j iS i S )z3Returns the user option for the crontab commandlineTurs   ri   r.   r.   r/   user_opt   s    
zCronTab.user_optc                    s^   |dkr2|r2|D ]}| j tj|| d|dd qn(|dkrH|rHtdntt| || dS )z&Catch setting crons and lines directlyrW   )cronT)rb   rX   z(You can NOT set crons attribute directlyN)appendCronItem	from_lineAttributeErrorsuperrV   __setattr__)rd   r!   rM   line	__class__r.   r/   r|      s    
zCronTab.__setattr__c                 C   s   g | _ g | _t | _g }| jdur0| jd}n|rt|| _tj|ddd}|	 }W d   q1 sh0    Y  n^| j
rt| jfddi| j \}}|rdt|v rn|rtd	| j
|f |dd}|| _dS )
z
        Read in the crontab from the system into the object, called
        automatically when listing or using the object. use for refresh.
        N
rrO   )encodingl zno crontab forzRead crontab %s: %s)rX   rW   OrderedVariableListr7   r`   r?   rY   codecsopen	readlinesre   rN   r[   ru   communicaterD   IOErrorrR   )rd   filenamerW   Zfhlouterrr.   r.   r/   rb     s$    
( zCronTab.readr   Fc                 C   s  t | j}t | j}t|tttfr0| |}z@t|tt	t
jfrN|^ }}|durn| j|}| j|}W n ty   tdY n0 | r|j| j t | _|r|js| jr| jd r| jd d dkr|| j dd  d | j|| | j|| nd|v rd	|vs>|d|d	k r|dd\}}	|	 }	d
D ]2}
|	d |
krZ|	d |
krZ|	|
}	 qqZ|	| j| < n:| js| jr| j| j t | _| j|dd dS )a"  Append a CronItem object to this CronTab

        Keyword arguments:
         item   - The CronItem object to append
         line   - The textual line which this item is.
         read   - Internal use only
         before - Append before this CronItem, comment regex or generator
        Nz1Can not find CronItem in crontab to insert beforer   #r$   T= z"'r   r   )rC   rX   rW   rP   rD   typeITEMREXfind_commentlistr=   typesGeneratorTypeindex
ValueErroris_validr7   updater\   r   commentset_commentr@   stripinsertr?   rw   replace)rd   itemr}   rb   beforeZcron_idZline_id_r!   rM   quotr.   r.   r/   rw     sH    	





 

zCronTab.appendc           	      C   s  |r|| _ n|dur&d| _ d| _|| _| jdurD|  | _| j sDdS | j rXt| j d}nt \}}t|d}|	| j|d
d |  | j s| jst| tdt| j|fi | j}| }|dkrtd| j||j |j  |j  t| dS )z5Write the crontab to it's source or a given filename.Nwb)errorsrO   z)Please specify user or filename to write.r   z!Program Error: {} returned {}: {})rY   r`   r_   renderr   tempfilemkstempr4   fdopenrl   encodeclosere   unlinkr   rN   r[   ru   waitformatr<   rb   r;   )	rd   r   re   r   ZfilehZfiledpathprocretr.   r.   r/   rl   O  s:    




zCronTab.writeTc                 C   s   | j |dS )z8Write the crontab to a user (or root) instead of a file.rr   rk   )rd   re   r.   r.   r/   write_to_userw  s    zCronTab.write_to_userc                 k   s,   | D ]"}|j f i |}|dvr|V  qdS )z7Run all commands in this crontab if pending (generator))Nr   N)run_pending)rd   kwargsjobr   r.   r.   r/   r   {  s    zCronTab.run_pendingr   c                 k   sd   d}||kr`t  }d|v r.|t|d d7 }| j|dD ]
}|V  q:t|dd |d7 }qdS )	z4Run the CronTab as an internal scheduler (generator)r   Zwarp<   )seconds)nowZcadencer$   N)r   r   r   r   r   get)rd   timeoutr   countr   rM   r.   r.   r/   run_scheduler  s    zCronTab.run_schedulerc                 C   s   g }| j D ]}t|ttfrd| ds2| sB||  q|sV|d|  qtd| q
t|tr
| s|sd|_	||j
|d  q
t| jd| }|r|d dvr|d7 }|S )	a  Render this crontab as it would be in the crontab.

        errors - Should we not comment out invalid entries and cause errors?
        specials - Turn known times into keywords such as "@daily"
            True - (default) force all values to be converted (unless SYSTEMV)
            False - force all values back from being a keyword
            None - don't change the special keyword use
        r   z# DISABLED LINE
# zInvalid line: %sFspecialsr   r   )r   )rW   rP   rD   r   
startswithrw   r   rx   r   enabledr   r7   join)rd   r   r   rX   r}   resultr.   r.   r/   r     s     	

zCronTab.renderc                 C   s>   |s| j du rtdt||||d}| |_| j||d |S )a  
        Create a new CronItem and append it to the cron.

        Keyword arguments:
         command     - The command that will be run.
         comment     - The comment that should be associated with this command.
         user        - For system cron tabs, the user this command should run as.
         pre_comment - If true the comment will apear just before the command line.
         before      - Append this command before this item instead of at the end.

        Returns the new CronItem object.
        Fz%User is required for system crontabs.)re   pre_comment)r   )re   r   rx   rv   rw   )rd   commandr   re   r   r   r   r.   r.   r/   new  s    zCronTab.newc                 c   sF   t | jD ]6}t|ttr0||jr@|V  q
||jv r
|V  q
dS )z8Return an iter of jobs matching any part of the command.N)r   rX   rP   r   r   findallr   )rd   r   r   r.   r.   r/   find_command  s    
zCronTab.find_commandc                 c   sF   t | jD ]6}t|ttr0||jr@|V  q
||jkr
|V  q
dS )z<Return an iter of jobs that match the comment field exactly.N)r   rX   rP   r   r   r   r   )rd   r   r   r.   r.   r/   r     s    
zCronTab.find_commentc                 g   s(   t | jD ]}|jt| kr
|V  q
dS )z3Return an iter of jobs that match this time patternN)r   rX   slices
CronSlices)rd   rI   r   r.   r.   r/   	find_time  s    zCronTab.find_timec                 c   s2   g }| j D ]"}|j|vr
|jV  ||j q
dS )z>Return a generator of all unqiue commands used in this crontabN)rX   r   rw   rd   Zreturnedrv   r.   r.   r/   commands  s
    

zCronTab.commandsc                 c   s8   g }| j D ](}|jr
|j|vr
|jV  ||j q
dS )zAReturn a generator of all unique comments/Id used in this crontabN)rX   r   rw   r   r.   r.   r/   comments  s
    
zCronTab.commentsc                 O   st   |rt dd|v r(| j| |d  S d|v rD| j| |d  S d|v r`| j| |d  S | j| jdd  S )a+  Removes all crons using the stated command OR that have the
        stated comment OR removes everything if no arguments specified.

           command - Remove all with this command
           comment - Remove all with this comment or ID
           time    - Remove all with this time code
        z&Invalid use: remove_all(command='cmd')r   r   r   N)rz   remover   r   r   rX   )rd   rI   r   r.   r.   r/   
remove_all  s    zCronTab.remove_allc                 G   s`   d}|D ]R}t |tttjfr8|D ]}|| |7 }q"qt |trR|| |7 }qtdq|S )z(Remove a selected cron from the crontab.r   zZYou may only remove CronItem objects, please use remove_all() to specify by name, id, etc.)rP   r   r=   r   r   _removerx   	TypeError)rd   rB   r   r   subitemr.   r.   r/   r     s    

zCronTab.removec                 C   s   | j | j |d d D ]L}t|trN|j}|j|_|j| ||j_ qh|dkrZ qh| j | q| j| | j | dS )zInternal removal of an itemr$   Nr   )	rW   r   rP   rx   r7   r   r   r   rX   )rd   r   Zsiblingr7   r.   r.   r/   r     s    
zCronTab._removec                 C   sN   | j du rdnd}| jr&d|| jf S | jr6| js6dS | jrFd| j S d| S )NFzSystem r   z<%sCronTab '%s'>z<My CronTab>z<User CronTab '%s'>z<Unattached %sCronTab>)r_   rY   re   ru   )rd   kindr.   r.   r/   __repr__  s    
zCronTab.__repr__c                 c   s   t | j D ]
}|V  qdS )z3Return generator so we can track jobs after removalN)r   rX   __iter__)rd   r   r.   r.   r/   r   '  s    zCronTab.__iter__c                 C   s
   | j | S r-   )rX   )rd   ir.   r.   r/   __getitem__,  s    zCronTab.__getitem__c                 C   s
   t | jS r-   )rC   rX   ri   r.   r.   r/   __len__/  s    zCronTab.__len__c                 C   s   |   S r-   r   ri   r.   r.   r/   __str__2  s    zCronTab.__str__)NNNN)N)r   FN)NNF)T)r   )FT)r   r   NFN)"__name__
__module____qualname____doc__rh   rj   rp   propertyrg   re   ru   r|   rb   rw   rl   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   __classcell__r.   r.   r~   r/   rV      sD   



	


2
(



		


rV   c                   @   s  e Zd ZdZdYddZdd Zd	d
 ZedZddZdd Z	d[ddZ
d\ddZdd Zd]ddZd^ddZdd Zdd Zd_ddZd d! Zd`d#d$Zd%d& Zd'd( Zdad)d*Zdbd+d,Zd-d. Zd/d0 Zdcd1d2Zd3d4 Zddd5d6Zd7d8 Zed9d: Zed;d< Z ed=d> Z!ed?d@ Z"edAdB Z#edCdD Z$edEdF Z%edGdH Z&edIdJ Z'edKdL Z(dMdN Z)dOdP Z*dQdR Z+dSdT Z,dUdV Z-dWdX Z.dS )erx   zq
    An item which objectifies a single line of a crontab and
    May be considered to be a cron job object.
    r   NFc                 C   sz   d | _ || _d| _d| _d| _d | _d | _d | _t| d| _	d| _
d | _d | _d | _t | _| || |rv| | d S )NFT)r   )rv   re   validr   specialr   r   last_runr   r7   r   markerstdinrc   r   r   r   set_command)rd   r   r   re   r   r.   r.   r/   rh   ;  s"    zCronItem.__init__c                 C   s   t | j| j| j| j| jfS r-   )hashr   r   hourminutedowri   r.   r.   r/   __hash__T  s    zCronItem.__hash__c                 C   s   t |tsdS |  | kS )NF)rP   rx   r   )rd   otherr.   r.   r/   __eq__W  s    
zCronItem.__eq__c                 C   s"   | |d}||_ ||  |S )zDGenerate CronItem from a cron-line and parse out command and commentrr   )rv   parser   )clsr}   re   rv   objr.   r.   r/   ry   \  s    
zCronItem.from_linec                 C   s   | j std| j |  dS )z/Delete this item and remove it from it's parentzCron item is not in a crontab!N)rv   UnboundLocalErrorr   ri   r.   r.   r/   deleted  s    zCronItem.deletec                 C   sJ   |r2| dd dd}d|v r2|dd\}| _t| | _d| _dS )z$Set the command and filter as needed%r   z\
r$   TN)r   r?   r   rU   r   r   r   )rd   rH   Zparse_stdinr.   r.   r/   r   j  s    zCronItem.set_commandc                 C   s>   |r.|dd dkr.d| _ |dd  }d}|| _|| _dS )zSet the comment and don't filter, pre_comment indicates comment appears
        before the cron, otherwise it appears ont he same line after the command.
        N   zAnsible:ZAnsibleT)r   lstripr   r   )rd   Zcmtr   r.   r.   r/   r   s  s    zCronItem.set_commentc                 C   sV   t |}|r|d dkr.d| _|dd  }| t|| | t|| dS )z:Parse a cron line string and save the info as the objects.r   r   Fr$   N)rU   r   r   
_set_parser   r   SPECREX)rd   r}   r.   r.   r/   r     s    zCronItem.parsec              
   C   s(  |sdS |d d | _ | jjdu r|d d dd}| |d d t|dkr^|d | _q| jrjtjntj	}d| _
d| _t|td	| jdu rd
n
| jjpd
| n| |d d d z| j|d dd   W nL ttfy" } z.| jrtt| d| _
d| _W Y d}~n
d}~0 0 dS )z*Set all the parsed variables into the itemNr   r   Fr$   T   z-Missing user or command in system cron %s: %sr   )r   rv   re   r?   r   rC   r   loggingERRORDEBUGr   LOGrg   rD   ra   setallr   KeyErrorerror)rd   r   r}   r   levelr   r.   r.   r/   r     s0    zCronItem._set_parseTc                 C   s   |dv r|| _ | j S )z&Set if this cron job is enabled or not)TFr   )rd   r   r.   r.   r/   enable  s    zCronItem.enablec                 C   s   | j S )z6Return true if this job is enabled (not commented out)r  ri   r.   r.   r/   
is_enabled  s    zCronItem.is_enabledc                 C   s   | j S )z Return true if this job is valid)r   ri   r.   r.   r/   r     s    zCronItem.is_validc                 C   s  |   s| jrtdt| jdd}d}| jrV| jjdu rV| jsLtd| jd }d| jj	|d	||f }| j
r|d
| j
dd 7 }| jsd| }| jrt| j }| _| jrd| j|f }nd| }ts| js| j
r|d | }n|d| 7 }t| j| S )z$Render this set cron-job to a stringz8Refusing to render invalid crontab. Disable to continue.r   z\%r   Fz'Job to system-cron format, no user set!r   z%s %s%sr   z %r   z# z#%s: %s)r   r   r   rU   r   r   rv   re   r   r   r   r   r   SYSTEMVr   rD   r7   )rd   r   r   re   r   r   r.   r.   r/   r     s,    
zCronItem.renderc                 C   s   |    | jdS )z6Set to every reboot instead of a time pattern: @rebootr   )clearr   r   ri   r.   r.   r/   every_reboot  s    zCronItem.every_rebootr$   c                 C   s   t | j|S )af  
        Replace existing time pattern with a single unit, setting all lower
        units to first value in valid range.

        For instance job.every(3).days() will be `0 0 */3 * *`
        while job.day().every(3) would be `* * */3 * *`

        Many of these patterns exist as special tokens on Linux, such as
        `@midnight` and `@hourly`
        )Everyr   )rd   unitr.   r.   r/   every  s    zCronItem.everyc                 G   s   | j j| S )zReplace existing time pattern with these five values given as args:

           job.setall("1 2 * * *")
           job.setall(1, 2) == '1 2 * * *'
           job.setall(0, 0, None, '>', 'SUN') == '0 0 * 12 SUN'
        )r   r   rd   rI   r.   r.   r/   r     s    zCronItem.setallc                 C   s
   | j  S ) Clear the special and set values)r   r  ri   r.   r.   r/   r    s    zCronItem.clearc                 C   s   | j j|dS )znReturns the number of times this item will execute in a given year
           (defaults to this year)
        year)r   	frequencyrd   r  r.   r.   r/   r    s    zCronItem.frequencyc                 C   s   | j j|dS )zlReturns the number of /days/ this item will execute on in a year
           (defaults to this year)
        r  )r   frequency_per_yearr  r.   r.   r/   r    s    zCronItem.frequency_per_yearc                 C   s
   | j  S )z<Returns the number of time this item will execute in any day)r   frequency_per_dayri   r.   r.   r/   r    s    zCronItem.frequency_per_dayc                 C   s
   | j  S )>Returns the number of times this item will execute in any hour)r   frequency_per_hourri   r.   r.   r/   r    s    zCronItem.frequency_per_hourc                 C   sN   |p
t  }|  rJ| jdu r$|| _| | j }||k rJ|| _|  S dS )zRuns the command if scheduledNr   )r   r   r  r   scheduleZget_nextrun)rd   r   Z	next_timer.   r.   r/   r     s    
zCronItem.run_pendingc                 C   sd   t j }|| j  | jdt}t|d| j	|d
 \}}|rVt|d |d S )z Runs the given command as a piper,   z-c)r7   rO   )r4   environcopyr   r7   allr   r,   rN   r   r   r   r  rR   r   )rd   r7   shellr   r   r.   r.   r/   r    s    
zCronItem.runc                 C   sL   |st  }zddlm} W n ty6   tdY n0 || j |t dS )z(Return a croniter schedule if available.r   )croniterz]Croniter not available. Please install croniter python module via pip or your package manager)Zret_type)r   r   Zcroniter.croniterr  ImportErrorr   clean_render)rd   Z	date_fromr  r.   r.   r/   r    s    zCronItem.schedulec                 K   sJ   zddl m} W n ty*   tdY n0 || j fi |}| S )z
        Returns a description of the crontab's schedule (if available)

        **kw - Keyword arguments to pass to cron_descriptor (see docs)
        r   )ExpressionDescriptorzjcron_descriptor not available. Please installcron_descriptor python module via pip or your package manager)Zcron_descriptorr   r  r   r  get_description)rd   kwr   Zexdescr.   r.   r/   description)  s    zCronItem.descriptionc                 C   s$   | j s| jr| jj| j| _ | j S )z,Return a cron log specific for this job only)rc   rv   rg   Zfor_programr   ri   r.   r.   r/   rg   8  s    zCronItem.logc                 C   s
   | j d S )zReturn the minute slicer   r   ri   r.   r.   r/   r   ?  s    zCronItem.minutec                 C   s   | j S )zSame as minute)r   ri   r.   r.   r/   minutesD  s    zCronItem.minutesc                 C   s
   | j d S )zReturn the hour slicer$   r$  ri   r.   r.   r/   r   I  s    zCronItem.hourc                 C   s   | j S )zSame as hour)r   ri   r.   r.   r/   hoursN  s    zCronItem.hoursc                 C   s   | j S )zReturn the day slice)domri   r.   r.   r/   dayS  s    zCronItem.dayc                 C   s
   | j d S )z!Return the day-of-the month slicer   r$  ri   r.   r.   r/   r'  X  s    zCronItem.domc                 C   s
   | j d S )zReturn the month slice   r$  ri   r.   r.   r/   month]  s    zCronItem.monthc                 C   s   | j S )zSame as month)r*  ri   r.   r.   r/   monthsb  s    zCronItem.monthsc                 C   s
   | j d S )z Return the day of the week slicer+   r$  ri   r.   r.   r/   r   g  s    zCronItem.dowc                 C   s   dt |  S )Nz<CronItem '%s'>rD   ri   r.   r.   r/   r   l  s    zCronItem.__repr__c                 C   s   t t| S r-   )rC   rD   ri   r.   r.   r/   r   o  s    zCronItem.__len__c                 C   s
   | j | S r-   r$  )rd   rL   r.   r.   r/   r   r  s    zCronItem.__getitem__c                 C   s   |   t|  k S r-   r  r   rd   rM   r.   r.   r/   __lt__u  s    zCronItem.__lt__c                 C   s   |   t|  kS r-   r-  r.  r.   r.   r/   __gt__x  s    zCronItem.__gt__c                 C   s   |   S r-   r   ri   r.   r.   r/   r   {  s    zCronItem.__str__)r   r   NF)NN)F)F)r   )T)T)r$   )N)N)N)N)/r   r   r   r   rh   r   r   classmethodry   r   r   r   r   r   r  r  r   r   r	  r  r   r  r  r  r  r  r   r  r  r#  r   rg   r   r%  r   r&  r(  r'  r*  r+  r   r   r   r   r/  r0  r   r.   r.   r.   r/   rx   6  sj   

	





	














rx   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	r
  a1  Provide an interface to the job.every() method:
        Available Calls:
          minute, minutes, hour, hours, dom, doms, month, months, dow, dows

       Once run all units will be cleared (set to *) then proceeding units
       will be set to '0' and the target unit will be set as every x units.
    c                 C   sV   || _ || _tg dD ]8\}}t| || |d  t| |d | |d  qd S )N)
r   r   r'  r*  r   r    r   r(  Zmoonweekday   s)r   r  	enumeratesetattrset_attr)rd   r   ZunitsrL   r!   r.   r.   r/   rh     s
    zEvery.__init__c                    s    fdd}|S )z"Inner set target, returns functionc                     sJ    j   tdkrdpD ]}  j |  d q j   j dS )z-Returned inner call for setting slice targetsr+   r   <N)r   r  rangeonr  r  )rL   rd   targetr.   r/   	innercall  s    
z!Every.set_attr.<locals>.innercallr.   )rd   r<  r=  r.   r;  r/   r7    s    zEvery.set_attrc                 C   s(   | j dkrtd| j  | jd dS )zSpecial every year targetr$   z"Invalid value '%s', outside 1 yearz@yearlyN)r  r   r   r   ri   r.   r.   r/   r    s    
z
Every.yearN)r   r   r   r   rh   r7  r  r.   r.   r.   r/   r
    s   r
  c                       s   e Zd ZdZ fddZdd Zedd Zdd	 Ze	d
d Z
e	dd Zdd Zd"ddZdd Zd#ddZd$ddZdd Zdd Zdd Zd d! Z  ZS )%r   zControls a list of five time 'slices' which reprisent:
        minute frequency, hour frequency, day of month frequency,
        month requency and finally day of the week frequency.
     c                    s6   t t| dd tD  d | _| j|  | j| _d S )Nc                 S   s   g | ]}t |qS r.   )	CronSlice)r8   infor.   r.   r/   
<listcomp>  r1   z'CronSlices.__init__.<locals>.<listcomp>)r{   r   rh   S_INFOr   r   is_self_validr   r  r~   r.   r/   rh     s    
zCronSlices.__init__c                 G   s   t j|p| f S )zObject version of is_valid)r   r   r  r.   r.   r/   rB    s    zCronSlices.is_self_validc              	   G   s,   zt | | W S  ttfy&   Y dS 0 dS )z4Returns true if the arguments are valid cron patternFN)boolr   r  )r   rI   r.   r.   r/   r     s    zCronSlices.is_validc                 G   sr   |    t|dkr8| |d \}| _|d dkr8dS t|t| krPtdt| |D ]\}}|| qZdS )z<Parses the various ways date/time frequency can be specifiedr$   r   r   NzCan not set cron to itself!)r  rC   _parse_valuer   idAssertionErrorzipr   )rd   r   set_aZset_br.   r.   r/   r     s    zCronSlices.setallc                 C   s   t | tr| rt| S t | tr,| jdfS t | trP| j| j| j	| j
dgdfS t | trp| j| jdddgdfS t | trdd| j	| j
dgdfS t | ttfstdt| j| dfS )z,Parse a single value into an array of slicesN*r   zUnknown type: {})rP   rD   r   
_parse_strrx   r   r   r   r   r(  r*  r   r   r   r=   r   r   r   r   rM   r.   r.   r/   rD    s    





zCronSlices._parse_valuec                 C   sr   |  d }| ddkr.|  ddfS |t v rPt| dd| fS | drhtd	| | gdfS )z/Parse a string which contains slice information@r   r+   NzUnknown special '{}')
r   lowerr   r   r?   SPECIALSkeysr   r   r   )rM   rL   r.   r.   r/   rJ    s    
zCronSlices._parse_strc                 C   s   d dd | D S )z*Return just numbered parts of this crontabr   c                 S   s   g | ]}t |qS r.   r,  )r8   r4  r.   r.   r/   r@    r1   z+CronSlices.clean_render.<locals>.<listcomp>)r   ri   r.   r.   r/   r    s    zCronSlices.clean_renderTc                 C   sx   |   }| jr:|dur:| jdks4t| jd |kr:| jS tst|du rtt D ]$\}}||krN|tvrNd|   S qN|S )zAReturn just the first part of a cron job (the numbers or special)Fr   rL  Tz@%s)r  r   rN  r   r  rB   SPECIAL_IGNORE)rd   r   r   r!   rM   r.   r.   r/   r     s    
zCronSlices.renderc                 C   s   d| _ | D ]}|  q
dS )r  N)r   r  )rd   r   r.   r.   r/   r    s    zCronSlices.clearNc                 C   s   | j |d|   S )z1Return frequence per year times frequency per dayr  )r  r  r  r.   r.   r/   r    s    zCronSlices.frequencyc              
   C   s~   d}|st  j}t| d }| d D ]R}| d D ]D}z(t ||| d d |v r\|d7 }W q2 tyt   Y q2Y q20 q2q&|S )zdReturns the number of times this item will execute
           in a given year (default is this year)r   r+   r)  r   r$      )r   todayr  r   r2  r   )rd   r  r   Zweekdaysr*  r(  r.   r.   r/   r    s    
zCronSlices.frequency_per_yearc                 C   s   t | d t | d  S )z=Returns the number of times this item will execute in any dayr   r$   rC   ri   r.   r.   r/   r    s    zCronSlices.frequency_per_dayc                 C   s   t | d S )r  r   rS  ri   r.   r.   r/   r    s    zCronSlices.frequency_per_hourc                 C   s   |   S r-   r   ri   r.   r.   r/   r     s    zCronSlices.__str__c                 C   s   |   t|  kS r-   )r   r   )rd   r9   r.   r.   r/   r     s    zCronSlices.__eq__)T)N)N)r   r   r   r   rh   rB  r1  r   r   staticmethodrD  rJ  r  r   r  r  r  r  r  r   r   r   r.   r.   r~   r/   r     s&   





r   c                   @   s   e Zd ZdZdS )SundayErrorz&Sunday was specified as 7 instead of 0N)r   r   r   r   r.   r.   r.   r/   rU    s   rU  c                   @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )Alsoz;Link range values together (appending instead of replacing)c                 C   s
   || _ d S r-   )r   )rd   r   r.   r.   r/   rh   $  s    zAlso.__init__c                 G   s   | j j|ddiS )zAlso every one of thesealsoT)r   r  rd   ar.   r.   r/   r  '  s    z
Also.everyc                 G   s   | j j|ddiS )zAlso on theserW  T)r   r:  rX  r.   r.   r/   r:  +  s    zAlso.onc                 G   s   | j j|ddiS )zAlso during theserW  T)r   duringrX  r.   r.   r/   rZ  /  s    zAlso.duringN)r   r   r   r   rh   r  r:  rZ  r.   r.   r.   r/   rV  "  s
   rV  c                   @   s   e Zd ZdZd%ddZdd Zdd Zd&ddZdd Zdd Z	dd Z
d'ddZdd Zd(ddZedd Zdd Zdd Zdd  Zd!d" Zd)d#d$ZdS )*r>  z,Cron slice object which shows a time patternNc                 C   sb   t |trt| }|dd | _|dd | _|dd | _|dd | _g | _|r^| 	| d S )Nr    r   r!   r&   )
rP   intrA  r   r    r   r!   r&   partsr   )rd   r?  rM   r.   r.   r/   rh   5  s    
zCronSlice.__init__c                 C   s   t t| S r-   )r   rD   ri   r.   r.   r/   r   @  s    zCronSlice.__hash__c                 C   sx   |    |durtt|dD ]T}|ddksF|ddksF|dkr\|  j| |7  _q| j| j|dd qdS )zSet values into the slice.N,/r   -rI  sunday)r  rD   r?   findr\  	get_rangerw   parse_value)rd   rM   partr.   r.   r/   r   C  s    $zCronSlice.parseFTc                 C   s   | j s
dS t| j d|S )z{Return the slice rendered as a crontab.

        resolve - return integer values instead of enums (default False)

        rI  r]  )r\  _render_values)rd   resolver   r.   r.   r/   r   M  s    zCronSlice.renderc                 C   s   dt |  S )Nz<CronSlice '%s'>r,  ri   r.   r.   r/   r   W  s    zCronSlice.__repr__c                 C   s   t | t |kS r-   r,  r.  r.   r.   r/   r   Z  s    zCronSlice.__eq__c                 C   s   |   S r-   r   ri   r.   r.   r/   r   ]  s    zCronSlice.__str__c                 C   s.   |s|    |  j| t|7  _| jd S )zSet the every X units valuer   )r  r\  rc  r[  )rd   n_valuerW  r.   r.   r/   r  `  s    zCronSlice.everyc                 O   s>   | dds|   |D ]}|  j| j|ddf7  _q| jS )z0Set the time values to the specified placements.rW  Fr   r`  )r   r  r\  rd  )rd   rh  optsrH  r.   r.   r/   r:  g  s
    zCronSlice.onc                 C   s:   |s|    |  j| t|d t| 7  _| jd S )z(Set the During value, which sets a ranger_  r   )r  r\  rc  rD   )rd   vfromvtorW  r.   r.   r/   rZ  o  s    $zCronSlice.duringc                 C   s   t | S )z+Appends rather than replaces the new values)rV  ri   r.   r.   r/   rW  v  s    zCronSlice.alsoc                 C   s
   g | _ dS )z#clear the slice ready for new vauesN)r\  ri   r.   r.   r/   r  {  s    zCronSlice.clearc                 G   s*   t | g|R  }|jdur$|j|gS |gS )z"Return a cron range for this sliceN)	CronRangedangling)rd   vranger   r.   r.   r/   rc    s    

zCronSlice.get_rangec                 c   sb   i }| j s| d | j D ]2}t|tr@| D ]}d||< q0qd|t|< q|D ]
}|V  qRdS )z(Return the entire element as an iterabler$   N)r\  r  rP   rl  r9  r[  )rd   r   re  bitvalr.   r.   r/   r     s    


zCronSlice.__iter__c                 C   s   t t|  S )z<Returns the number of times this slice happens in it's range)rC   r   r   ri   r.   r.   r/   r     s    zCronSlice.__len__c                 C   s   |dkr| j }n|dkr| j}zt|| j}W nF tyR   td| j|f Y n$ tyt   td| j|f Y n0 | j dkrt|dkr|dur|S tdt|| jk st|| j krtd		| ||S )
z=Parse the value of the cron slice and raise any errors needed>r8  zUnrecognised %s: '%s'zNo enumeration for %s: '%s'r'   rQ  Nz"Detected Sunday as 7 instead of 0!z*'{1}', not in {0.min}-{0.max} for {0.name})
r   r    get_cronvaluer&   r   r!   r  r[  rU  r   )rd   rp  ra  r   r.   r.   r/   rd    s"    zCronSlice.parse_value)N)FT)F)F)N)r   r   r   r   rh   r   r   r   r   r   r   r  r:  rZ  r   rW  r  rc  r   r   rd  r.   r.   r.   r/   r>  3  s$   






r>  c                 C   s@   t | tr| S t|  r&tt| S |s2tdtt| |S )z=Returns a value as int (pass-through) or a special enum valuezNo enumeration allowed)rP   r[  rD   isdigitr  	CronValue)rM   enumsr.   r.   r/   rr    s    
rr  c                   @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )rt  z*Represent a special value in the cron linec                 C   s   || _ || | _d S r-   )rT   r   rM  rM   )rd   rM   ru  r.   r.   r/   rh     s    zCronValue.__init__c                 C   s   | j t|k S r-   )rM   r[  r.  r.   r.   r/   r/    s    zCronValue.__lt__c                 C   s   t | S r-   r,  ri   r.   r.   r/   r     s    zCronValue.__repr__c                 C   s   | j S r-   rS   ri   r.   r.   r/   r     s    zCronValue.__str__c                 C   s   | j S r-   rK  ri   r.   r.   r/   __int__  s    zCronValue.__int__N)	r   r   r   r   rh   r/  r   r   rv  r.   r.   r.   r/   rt    s   rt  r]  c                    s,   t | dkr|   | fdd| D S )z7Returns a rendered list, sorted and optionally resolvedr$   c                    s   g | ]}t | qS r.   )_renderr8   rp  rg  r.   r/   r@    r1   z"_render_values.<locals>.<listcomp>)rC   sortr   )valuesr   rg  r.   ry  r/   rf    s    rf  c                 C   s:   t | tr| |S |r$tt| S ttr4d| n| S )zReturn a single value renderedz{:02d})rP   rl  r   rD   r[  ZERO_PADr   )rM   rg  r.   r.   r/   rw    s
    

rw  c                   @   sb   e Zd Z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 )rl  z7A range between one value and another for a time range.c                 G   s   d | _ || _d | _d| _|s&|   n\t|d trD| |d  n>t|d tt	frt
|dkrp|\| _| _n|d | _|   d S )Nr$   r   r   )rm  slicerv   seqr  rP   rD   r   r[  rt  rC   rj  rk  )rd   Zvslicern  r.   r.   r/   rh     s    

zCronRange.__init__c                 C   s.  | ddkrl|d\}}z| j|| _W n tyJ   d| _d}Y n0 | jdk sd| j| jjkrltd| ddkr
|d\}}| jj|dd| _z| j|| _	W n< ty   | jdkrd| _nd| _
| jj|dd| _	Y n0 | j	| jk r*td	| n |d
kr|   ntd| dS )z!Parse a ranged value in a cronjobr^  r$   z0-0z*Sequence can not be divided by zero or maxr_  r   r`  r'   zBad range '{0.vfrom}-{0.vto}'rI  zUnknown cron range value "%s"N)r   r?   r}  rd  r~  rU  r   r   rj  rk  rm  r   r  )rd   rM   r~  rj  rk  r.   r.   r/   r     s0    



zCronRange.parsec                 C   s   | j j| _| j j| _dS )z<Set this slice to all units between the miniumum and maximumN)r}  r    rj  r   rk  ri   r.   r.   r/   r    s    
zCronRange.allFc                 C   s   d}t | j| jjks(t | j| jjk rT| j| jkr@t| j}nt| j| jgd|}| jdkrl|d| j 7 }|dkrt	rd
dd |  D }|S )z%Render the ranged value for a cronjobrI  r_  r$   z/%dr]  c                 S   s   g | ]}t |qS r.   r,  rx  r.   r.   r/   r@    r1   z$CronRange.render.<locals>.<listcomp>)r[  rj  r}  r    rk  r   rD   rf  r~  r  r   r9  )rd   rg  rM   r.   r.   r/   r     s    $
zCronRange.renderc                 C   s   t t| jt| jd | jS )z7Returns the range of this cron slice as a iterable listr$   )r9  r[  rj  rk  r~  ri   r.   r.   r/   r9  "  s    zCronRange.rangec                 C   s   t || _dS )z&Set the sequence value for this range.N)r[  r~  r.  r.   r.   r/   r  &  s    zCronRange.everyc                 C   s   t | jt |k S r-   r[  rj  r.  r.   r.   r/   r/  *  s    zCronRange.__lt__c                 C   s   t | jt |kS r-   )r[  rk  r.  r.   r.   r/   r0  -  s    zCronRange.__gt__c                 C   s
   t | jS r-   r  ri   r.   r.   r/   rv  0  s    zCronRange.__int__c                 C   s   |   S r-   r   ri   r.   r.   r/   r   3  s    zCronRange.__str__N)F)r   r   r   r   rh   r   r  r   r9  r  r/  r0  rv  r   r.   r.   r.   r/   rl    s   
rl  c                       sH   e Zd ZdZ fddZedd Zdd Z fdd	Zd
d Z	  Z
S )r   a4  An ordered dictionary with a linked list containing
    the previous OrderedVariableList which this list depends.

    Duplicates in this list are weeded out in favour of the previous
    list in the chain.

    This is all in aid of the ENV variables list which must exist one
    per job in the chain.
    c                    s(   | dd | _tt| j|i | d S )Nr   )r@   r   r{   r   rh   )rd   rI   r"  r~   r.   r/   rh   A  s    zOrderedVariableList.__init__c                 C   sP   | j durL| j jdurL| j jj| j }|dkr:| j jjS | j j|d  jS dS )z8Returns the previous env in the list of jobs in the cronNr   r$   )r   rv   rX   r   r7   )rd   r   r.   r.   r/   previousE  s    
zOrderedVariableList.previousc                 C   s.   | j dur&| j  }||  |S |  S )z|
        Returns the full dictionary, everything from this dictionary
        plus all those in the chain above us.
        N)r   r  r  r  r   )rd   r   r.   r.   r/   r  O  s
    

zOrderedVariableList.allc                    sB   | j }|| v rtt| |S |d ur2| | S td| d S )Nz$Environment Variable '%s' not found.)r  r{   r   r   r  r  )rd   rL   r  r~   r.   r/   r   Z  s    zOrderedVariableList.__getitem__c                 C   sz   g }|   D ]X\}}| jr2| j |d|kr2qdt|v sF|dkrNd| }|d|t|f  q|d d|S )z4Constructs to variable list output used in cron jobsNr   r   z"%s"z%s=%sr   )rB   r  r  r   rD   rw   r   )rd   r   rL   rM   r.   r.   r/   r   b  s    
zOrderedVariableList.__str__)r   r   r   r   rh   r   r  r  r   r   r   r.   r.   r~   r/   r   7  s   	
	r   )r]  F)F)=r   r4   rer>   r   r   r   r   platform
subprocessrE   r   r   r   r   r   collectionsr   Z__pkgname____version__compiler   r   DEVNULLZ	WEEK_ENUMZ
MONTH_ENUMrN  rP  rA  systemr]   r!   rA   unamer  r|  	getLoggerr   rZ   r  r   r,   r6   r2   rN   rU   rV   rx   r
  r   r   r  rU  rV  r>  rr  rt  rf  rw  rl  r   r.   r.   r.   r/   <module>   s   C

	


	

      K"~}

	Y