o
    fi                  	   @   sz  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 ddlmZmZmZmZ ddl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" oe% d d'v Z&e" oe% d d'v pe% d( d)v Z&d*Z'e(d+Z)ed+pd,Z*ej+,d-d.Z-d/d0 Z.e"sddl/Z/d1d2 Z.d3d4 Z0G d5d6 d6Z1G d7d8 d8Z2G d9d: d:Z3G d;d< d<Z4G d=d> d>e5Z6G d?d@ d@e7Z8G dAdB dBZ9G dCdD dDZ:dEdF Z;G dGdH dHZ<dRdJdKZ=dSdLdMZ>G dNdO dOZ?G dPdQ dQeZ@dS )Ta  
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)
monthrange)sleep)timedatedatetime	timedelta)OrderedDict)whichzpython-crontabz3.2.0za^\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 *)reboothourlydailyweeklymonthlyyearlyannuallymidnightr%   r$   ;   Minutes)maxminname   Hours      zDay of Month   Month)r(   r)   r*   enum   zDay of WeekWindowsposix)SunOSAIXzHP-UX   )mipsFcrontabz/usr/bin/crontabSHELLz/bin/shc                   C   s   d S N r<   r<   r<   :/var/www/html/venv/lib/python3.10/site-packages/crontab.py<lambda>   s    r>   c                   C   s   t t d S )z(Returns the username of the current userr   )pwdgetpwuidosgetuidr<   r<   r<   r=   current_user      rC   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   

rK   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 )ProcesszRuns a program and orders the arguments for compatability.

    a. keyword args are flags and always appear /before/ arguments for bsd
    c                 O   s   t tj||dtd}|dd | _| D ])\}}t|dkr6|d| f7 }|d ur5|t|f7 }q|d| d| f7 }qt dd	 |t | D | _	d
| _
d | _d | _d | _d S )Nr4   )r4   envr.   -z--=c                 s   s    | ]}|r|V  qd S r;   r<   ).0argr<   r<   r=   	<genexpr>   s    z#Process.__init__.<locals>.<genexpr>F)tupleshlexsplitpopPOSIXrM   itemslenstrargshas_runstdoutstderr
returncode)selfcmdr[   flagscmd_argskeyvaluer<   r<   r=   __init__   s   
zProcess.__init__c                 C   s   t j| jt jt j| jdS )z4Run this process and return the popen process object)r]   r^   rM   )spPopenr[   PIPErM   r`   r<   r<   r=   _run   s   zProcess._runc                 C   s8   |   }| \}}|j| _|d| _|d| _| S )z/Run this process and store whatever is returnedrE   )rk   communicater_   rH   r]   r^   )r`   processouterrr<   r<   r=   run   s   zProcess.runc                 C   
   | j  S r;   )r]   striprj   r<   r<   r=   __str__      
zProcess.__str__c                 C   s   d| j  dS )NzProcess())r[   rj   r<   r<   r=   __repr__      zProcess.__repr__c                 C      | j S r;   )r_   rj   r<   r<   r=   __int__      zProcess.__int__c                 C   s   t | |kS r;   rZ   r`   otherr<   r<   r=   __eq__      zProcess.__eq__N)__name__
__module____qualname____doc__rf   rk   rp   rs   rv   ry   r~   r<   r<   r<   r=   rL      s    	rL   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dAddZdBddZdCddZdDddZdd ZdEd d!ZdFd"d#ZdGd$d%Zd&d' Zd(d) Zd*d+ Zed,d- Zed.d/ Zd0d1 Zd2d3 Zd4d5 Zd6d7 Zd8d9 Zd:d; Zd<d= Zd>d? Z   Z!S )H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 ot	
 dk| _|| _|| _|| _| | || _d S )Nr   )linescronsfilenCRON_COMMANDcron_commandrM   r   _parked_envWINOSrA   rB   root_userintabtabfileread_log)r`   usertabr   logr<   r<   r=   rf      s   

zCronTab.__init__c                 C   s   | S r;   r<   rj   r<   r<   r=   	__enter__   s   zCronTab.__enter__c                 C   s   |    d S r;   write)r`   exc_typeexc_valexc_tbr<   r<   r=   __exit__   r   zCronTab.__exit__c                 C   s>   ddl m} | jdu st| jtr|| j| jpdd| _| jS )z?Returns the CronLog object for this tab (user or root tab only)r   )CronLogNr   r   )cronlogr   r   rF   rZ   r   )r`   r   r<   r<   r=   r      s   zCronTab.logc                 C   s   | j du rt S | j S )z4Return user's username of this crontab if applicableTr   rC   rj   r<   r<   r=   r     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ur   rj   r<   r<   r=   user_opt  s   
zCronTab.user_optc                    sZ   |dkr|r|D ]}| j tj|| d|dd qdS |dkr$|r$tdt || dS )z&Catch setting crons and lines directlyr   )cronT)r   r   z(You can NOT set crons attribute directlyN)appendCronItem	from_lineAttributeErrorsuper__setattr__)r`   r*   re   line	__class__r<   r=   r     s   zCronTab.__setattr__c                 C   s   g | _ g | _t | _g }| jdur| jd}n`|r:|| _tj|ddd}|	 }W d   n1 s4w   Y  n>| j
rxzt| jfddi| j }W n ty]   td| j d	w |jrrd
|jvrrtd| j
 d|j |j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
rrE   )encodingl z(Can't read crontab; No crontab program ''zno crontab forzRead crontab : )r   r   OrderedVariableListrM   r   rU   r   codecsopen	readlinesr   rL   r   r   rp   FileNotFoundErrorIOErrorr^   r]   )r`   filenamer   fhlrm   r<   r<   r=   r   "  s,   

 
zCronTab.readr   Fc              
   C   s  t | j}t | j}t|tttfr| |}z t|tt	t
jfr'|^ }}|dur7| j|}| j|}W n tyI } ztd|d}~ww | r|j| j t | _|r~|js~| jr~| jd r~| jd d dkr~|| j dd  d | j|| | j|| dS d|v rd	|vs|d|d	k r|dd\}	}
|
 }
d
D ]}|
d |kr|
d |kr|
|}
 nq|
| j|	 < dS dS | 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.   TrO    z"'r   r   )rY   r   r   rF   rZ   typeITEMREXfind_commentlistrS   typesGeneratorTypeindex
ValueErroris_validrM   updater   r   commentset_commentrV   rr   insertrU   r   replace)r`   itemr   r   beforecron_idline_id_ro   r*   re   quotr<   r<   r=   r   ?  sP   
	




	zCronTab.appendc           
      C   sJ  |r|| _ n|durd| _ d| _|| _| jdur"|  | _| j s"dS | j r,t| j d}nt \}}t|d}|	| j|d
d |  | j s| jsWt| tdzt| j|fi | j }W n tyv   td| j dw | }|dkr|j }	td	| j d
| d|	 |j  |j  t| dS dS )z5Write the crontab to it's source or a given filename.Nwb)errorsrE   z)Please specify user or filename to write.z)Can't write crontab, no crontab program 'r   r   zProgram Error: z
 returned r   )r   r   r   renderr   tempfilemkstemprA   fdopenr   encodecloser   unlinkr   rL   r   r   rk   r   waitr^   r   r]   )
r`   r   r   r   filehfiledpathprocretmsgr<   r<   r=   r   q  sB   





zCronTab.writeTc                 C   s   | j |dS )z8Write the crontab to a user (or root) instead of a file.r   r   )r`   r   r<   r<   r=   write_to_user     zCronTab.write_to_userc                 k   s.    | D ]}|j di |}|dvr|V  qdS )z7Run all commands in this crontab if pending (generator))Nr   Nr<   )run_pending)r`   kwargsjobr   r<   r<   r=   r     s   zCronTab.run_pendingr   <   c                 c   sd    d}||kr0t  }|r|t|d d7 }| j|dD ]}|V  qt| |d7 }||ksdS dS )z4Run the CronTab as an internal scheduler (generator)r   r   )seconds)nowr.   N)r   r   r   r   r   )r`   timeoutcadencewarpcountr   re   r<   r<   r=   run_scheduler  s   zCronTab.run_schedulerc                 C   s   g }| j D ]F}t|ttfr2| ds| s!||  q|s+|d|  qtd| t|trK| s@|s@d|_	||j
|d  qt| jd| }|rb|d dvrb|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: Fspecialsr   r   )r   )r   rF   rZ   rr   
startswithr   r   r   r   enabledr   rM   join)r`   r   r   r   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.)r   pre_comment)r   )r   r   r   r   r   )r`   commandr   r   r   r   r   r<   r<   r=   new  s   zCronTab.newc                 c   sH    t | jD ]}t|ttr||jr|V  q||jv r!|V  qdS )z8Return an iter of jobs matching any part of the command.N)r   r   rF   r   r   findallr   )r`   r   r   r<   r<   r=   find_command     
zCronTab.find_commandc                 c   sH    t | jD ]}t|ttr||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   r   rF   r   r   r   r   )r`   r   r   r<   r<   r=   r     r   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   r   slices
CronSlices)r`   r[   r   r<   r<   r=   	find_time  s   zCronTab.find_timec                 c   s4    g }| j D ]}|j|vr|jV  ||j qdS )z>Return a generator of all unqiue commands used in this crontabN)r   r   r   r`   returnedr   r<   r<   r=   commands  s   

zCronTab.commandsc                 c   s:    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)r   r   r   r   r<   r<   r=   comments  s   
zCronTab.commentsc                 O   st   |rt dd|v r| j| |d  S d|v r"| j| |d  S d|v r0| 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)r   remover   r   r   r   )r`   r[   r   r<   r<   r=   
remove_all  s   zCronTab.remove_allc                 G   s^   d}|D ](}t |tttjfr|D ]	}|| |7 }qqt |tr)|| |7 }qtd|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.)rF   r   rS   r   r   _remover   	TypeError)r`   rX   r   r   subitemr<   r<   r=   r  "  s   
zCronTab.removec                 C   s   | j | j |d d D ]&}t|tr'|j}|j|_|j| ||j_ n|dkr- n| j | q| j| | j | dS )zInternal removal of an itemr.   Nr   )	r   r   rF   r   rM   r   r   r  r   )r`   r   siblingrM   r<   r<   r=   r  0  s   
zCronTab._removec                 C   s\   | j du rdnd}| jrd| d| j dS | jr| jsdS | jr(d| j dS d	| d
S )NFzSystem r   <z	CronTab ''>z<My CronTab>z<User CronTab 'z<Unattached zCronTab>)r   r   r   r   )r`   kindr<   r<   r=   rv   B  s   zCronTab.__repr__c                 c   s     t | j D ]}|V  qdS )z3Return generator so we can track jobs after removalN)r   r   __iter__)r`   r   r<   r<   r=   r  L  s   zCronTab.__iter__c                 C   
   | j | S r;   )r   )r`   ir<   r<   r=   __getitem__Q  rt   zCronTab.__getitem__c                 C   
   t | jS r;   )rY   r   rj   r<   r<   r=   __len__T  rt   zCronTab.__len__c                 C      |   S r;   r   rj   r<   r<   r=   rs   W     zCronTab.__str__NNNNr;   )r   FN)NNFT)r   r   F)FT)r   r   NFN)"r   r   r   r   rf   r   r   propertyr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r  rv   r  r  r  rs   __classcell__r<   r<   r   r=   r      sF    



	



2
+


		


r   c                   @   s  e Zd ZdZdbddZdd Zd	d
 ZedcddZdd Z	ddddZ
ddddZdd ZdeddZdfddZdd Zdd ZdfddZd d! Zdgd#d$Zd%d& Zd'd( Zdhd)d*Zdid+d,Zdjd-d.Zdcd/d0Zdhd1d2Zdhd3d*Zdhd4d5Zd6d7 Zd8d9 Zdhd:d;Zd<d= Zdhd>d?Z d@dA Z!e"dBdC Z#e"dDdE Z$e"dFdG Z%e"dHdI Z&e"dJdK Z'e"dLdM Z(e"dNdO Z)e"dPdQ Z*e"dRdS Z+e"dTdU Z,dVdW Z-dXdY Z.dZd[ Z/d\d] Z0d^d_ Z1d`da Z2dS )kr   zq
    An item which objectifies a single line of a crontab and
    May be considered to be a cron job object.
    r   NFc                 C   s~   d | _ || _d| _d| _d| _d | _d | _d | _t| d| _	d| _
d | _d | _d | _t | _| || |r=| | d S d S )NFT)r   )r   r   validr   specialr   r   last_runr   rM   r   markerstdinr   r   r   r   set_command)r`   r   r   r   r   r<   r<   r=   rf   `  s$   zCronItem.__init__c                 C   s   t | j| j| j| j| jfS r;   )hashr   r   hourminutedowrj   r<   r<   r=   __hash__y  s   zCronItem.__hash__c                 C   s   t |tsdS |  | kS )NF)rF   r   r#  r|   r<   r<   r=   r~   |  s   
zCronItem.__eq__c                 C   s"   | |d}||_ ||  |S )zDGenerate CronItem from a cron-line and parse out command and commentr   )r   parserr   )clsr   r   r   objr<   r<   r=   r     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)r   UnboundLocalErrorr  rj   r<   r<   r=   delete  s   zCronItem.deletec                 C   sJ   |r| dd dd}d|v r|dd\}| _t| | _d| _dS )z$Set the command and filter as needed%r   z\
r.   TN)r   rU   r  rK   rr   r   r  )r`   ra   parse_stdinr<   r<   r=   r    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:AnsibleT)r  lstripr   r   )r`   cmtr   r<   r<   r=   r     s   
zCronItem.set_commentc                 C   sX   t |}|r|d dkrd| _| d }| t|| | t|| dS )z:Parse a cron line string and save the info as the objects.r   r   FN)rK   r   rr   r-  
_set_parser   r   SPECREX)r`   r   r<   r<   r=   r$    s   zCronItem.parsec              
   C   s$  |sdS |d d | _ | jjdu rT|d d dd}| |d d t|dkr/|d | _n/| jr5tjntj	}d| _
d| _t|td	| jdu rKd
n| jjpPd
| n
| |d d d z| j|d dd   W dS  ttfy } z| jrtt| d| _
d| _W Y d}~dS d}~ww )z*Set all the parsed variables into the itemNr   r   Fr.   T   z-Missing user or command in system cron %s: %sr   )r   r   r   rU   r  rY   r   loggingERRORDEBUGr  LOGr   rZ   r   setallr   KeyErrorerror)r`   r   r   r   levelro   r<   r<   r=   r/    s4   zCronItem._set_parseTc                 C   s   |dv r|| _ | j S )z&Set if this cron job is enabled or not)TFr   )r`   r   r<   r<   r=   enable  s   zCronItem.enablec                 C   rx   )z6Return true if this job is enabled (not commented out)r;  rj   r<   r<   r=   
is_enabled     zCronItem.is_enabledc                 C   rx   )z Return true if this job is valid)r  rj   r<   r<   r=   r     r>  zCronItem.is_validc                 C   s  |   s| jrtdt| jdd}d}| jr+| jjdu r+| js&td| jd }| jj	|d}| d| | }| j
rI|d	| j
d
d 7 }| jsPd| }| jrt| j }| _| jrhd| j d| }nd| }tst| jst| 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   r   z %r   z# r   r   )r   r   r   rK   r   r   r   r   r   r   r  r   r  SYSTEMVr   rZ   rM   )r`   r   r   r   rendr   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   r7  rj   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   )r`   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   r7  r`   r[   r<   r<   r=   r7    s   zCronItem.setallc                 C   rq   ) Clear the special and set values)r   rA  rj   r<   r<   r=   rA       
zCronItem.clearc                 C      | j j|dS znReturns the number of times this item will execute in a given year
           (defaults to this year)
        year)r   	frequencyr`   rL  r<   r<   r=   rM       zCronItem.frequencyc                 C   s   | j j||||dS )znReturns the number of times this item will execute in a given hour
           (defaults to this hour)
        )rL  monthdayr   )r   frequency_at_hour)r`   rL  rP  rQ  r   r<   r<   r=   rR    s   zCronItem.frequency_at_hourc                 C   s   | j j|||dS )ziReturns the number of times this item will execute in a given day
           (defaults to today)
        )rL  rP  rQ  )r   frequency_at_day)r`   rL  rP  rQ  r<   r<   r=   rS  $  s   zCronItem.frequency_at_dayc                 C   s   | j j||dS )zpReturns the number of times this item will execute in a given month
           (defaults to this month)
        )rL  rP  )r   frequency_at_month)r`   rL  rP  r<   r<   r=   rT  *  s   zCronItem.frequency_at_monthc                 C   rI  rJ  )r   frequency_at_yearrN  r<   r<   r=   rU  0  rO  zCronItem.frequency_at_yearc                 C      | j |d|   S z1Return frequence per year times frequency per dayrK  frequency_per_yearfrequency_per_dayrN  r<   r<   r=   rM  6     c                 C   rI  )zlReturns the number of /days/ this item will execute on in a year
           (defaults to this year)
        rK  )r   rY  rN  r<   r<   r=   rY  :  rO  zCronItem.frequency_per_yearc                 C   rq   )z<Returns the number of time this item will execute in any day)r   rZ  rj   r<   r<   r=   rZ  @  rH  zCronItem.frequency_per_dayc                 C   rq   )>Returns the number of times this item will execute in any hour)r   frequency_per_hourrj   r<   r<   r=   r]  D  rH  zCronItem.frequency_per_hourc                 C   sN   |pt  }|  r%| jdu r|| _| | j }||k r%|| _|  S dS )zRuns the command if scheduledNr   )r   r   r=  r  scheduleget_nextrp   )r`   r   	next_timer<   r<   r=   r   H  s   
zCronItem.run_pendingc                 C   sT   t j }|| j  | jdt}t|d| j	|d
 }|jr(t|j |S )z Runs the given command as a piper:   z-c)rM   )rA   environcopyr   rM   allgetr:   rL   r   rp   r^   r6  r9  )r`   rM   shellrm   r<   r<   r=   rp   U  s   
zCronItem.runc              
   C   sT   |st  }zddlm} W n ty } ztd|d}~ww || 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 managerN)ret_type)r   r   croniter.croniterrf  ImportErrorr   clean_render)r`   	date_fromrf  ro   r<   r<   r=   r^  _  s   zCronItem.schedulec              
   K   sR   zddl m} W n ty } ztd|d}~ww || 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 managerN)cron_descriptorrl  ri  r   rj  get_description)r`   kwrl  ro   exdescr<   r<   r=   descriptionk  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)r   r   r   for_programr   rj   r<   r<   r=   r   z  s   zCronItem.logc                 C   
   | j d S )zReturn the minute slicer   r   rj   r<   r<   r=   r!       
zCronItem.minutec                 C   rx   )zSame as minute)r!  rj   r<   r<   r=   minutes     zCronItem.minutesc                 C   rs  )zReturn the hour slicer.   rt  rj   r<   r<   r=   r     ru  zCronItem.hourc                 C   rx   )zSame as hour)r   rj   r<   r<   r=   hours  rw  zCronItem.hoursc                 C   rx   )zReturn the day slice)domrj   r<   r<   r=   rQ    rw  zCronItem.dayc                 C   rs  )z!Return the day-of-the month slicer2  rt  rj   r<   r<   r=   ry    ru  zCronItem.domc                 C   rs  )zReturn the month slice   rt  rj   r<   r<   r=   rP    ru  zCronItem.monthc                 C   rx   )zSame as month)rP  rj   r<   r<   r=   months  rw  zCronItem.monthsc                 C   rs  )z Return the day of the week slicer7   rt  rj   r<   r<   r=   r"    ru  zCronItem.dowc                 C      d|  dS )Nz<CronItem 'r
  r<   rj   r<   r<   r=   rv     r   zCronItem.__repr__c                 C      t t| S r;   )rY   rZ   rj   r<   r<   r=   r    r   zCronItem.__len__c                 C   r  r;   rt  )r`   rd   r<   r<   r=   r    rt   zCronItem.__getitem__c                 C   s   |   t|  k S r;   rM  r   r`   re   r<   r<   r=   __lt__     zCronItem.__lt__c                 C   s   |   t|  kS r;   r~  r  r<   r<   r=   __gt__  r  zCronItem.__gt__c                 C   r  r;   r  rj   r<   r<   r=   rs     r  zCronItem.__str__)r   r   NFNNF)r   r  )r.   r;   r  NNN)3r   r   r   r   rf   r#  r~   classmethodr   r(  r  r   r$  r/  r<  r=  r   r   rB  rE  r7  rA  rM  rR  rS  rT  rU  rY  rZ  r]  r   rp   r^  rq  r  r   r!  rv  r   rx  rQ  ry  rP  r{  r"  rv   r  r  r  r  rs   r<   r<   r<   r=   r   [  sv    


	


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











r   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	rC  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 ]\}}t| || |d  t| |d | |d  qd S )N)
r!  r   ry  rP  r"  r)   r   rQ  moonweekday   s)r   rD  	enumeratesetattrset_attr)r`   r   unitsrd   r*   r<   r<   r=   rf     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 targetsr7   r2  r	  N)r   rA  rangeonrE  rD  )rd   r`   targetr<   r=   	innercall  s   
z!Every.set_attr.<locals>.innercallr<   )r`   r  r  r<   r  r=   r    s   zEvery.set_attrc                 C   s,   | j dkrtd| j  d| jd dS )zSpecial every year targetr.   zInvalid value 'z', outside 1 yearz@yearlyN)rD  r   r   r7  rj   r<   r<   r=   rL    s   
z
Every.yearN)r   r   r   r   rf   r  rL  r<   r<   r<   r=   rC    s
    rC  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dZd,d d!Zd-d"d#Zd.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                    s2   t  dd tD  d | _| j|  | j| _d S )Nc                 S      g | ]}t |qS r<   )	CronSlice)rP   infor<   r<   r=   
<listcomp>      z'CronSlices.__init__.<locals>.<listcomp>)r   rf   S_INFOr  r7  is_self_validr   rF  r   r<   r=   rf     s   
zCronSlices.__init__c                 G   s   t j|p| f S )zObject version of is_valid)r   r   rF  r<   r<   r=   r       zCronSlices.is_self_validc              	   G   s(   zt | | W S  ttfy   Y dS w )z4Returns true if the arguments are valid cron patternF)boolr   r8  )r%  r[   r<   r<   r=   r     s
   zCronSlices.is_validc                 G   sr   |    t|dkr| |d \}| _|d dkrdS t|t| kr(tdt| |D ]	\}}|| q-dS )z<Parses the various ways date/time frequency can be specifiedr.   r   r   NzCan not set cron to itself!)rA  rY   _parse_valuer  idAssertionErrorzipr$  )r`   r   set_aset_br<   r<   r=   r7    s   zCronSlices.setallc                 C   s   t | tr| rt| S t | tr| jdfS t | tr(| j| j| j	| j
dgdfS t | tr8| j| jdddgdfS t | trHdd| j	| j
dgdfS t | ttfs[t| j}td| | dfS )z,Parse a single value into an array of slicesN*r   zUnknown type: )rF   rZ   r   
_parse_strr   r   r   r!  r   rQ  rP  r   r   r   rS   r   r   r   )re   typr<   r<   r=   r    s   






zCronSlices._parse_valuec                 C   sp   |  d }| ddkr|  ddfS |tv r&t| dd| fS | dr3td|  d| gdfS )z/Parse a string which contains slice information@r   r7   NzUnknown special 'r   )r-  lowerr   rr   rU   SPECIALSr   r   )re   rd   r<   r<   r=   r    s   

zCronSlices._parse_strc                 C   s   d dd | D S )z*Return just numbered parts of this crontabr   c                 S   r  r<   r{   )rP   r  r<   r<   r=   r  (  r  z+CronSlices.clean_render.<locals>.<listcomp>)r   rj   r<   r<   r=   rj  &  r[  zCronSlices.clean_renderTc                 C   sz   |   }| jr|dur| jdkst| jd |kr| jS ts;|du r;t D ]\}}||kr:|tvr:d|   S q'|S )zAReturn just the first part of a cron job (the numbers or special)Fr   r  T)rj  r  r  rr   r?  rX   SPECIAL_IGNORE)r`   r   r   r*   re   r<   r<   r=   r   *  s   
zCronSlices.renderc                 C   s   d| _ | D ]}|  qdS )rG  N)r  rA  )r`   r   r<   r<   r=   rA  7  s   
zCronSlices.clearNc                 C   rV  rW  rX  rN  r<   r<   r=   rM  =  r[  zCronSlices.frequencyc              
   C   sx   d}|s	t  j}t| d }| d D ]&}| d D ]}zt ||| d d |v r.|d7 }W q ty8   Y qw q|S )zdReturns the number of times this item will execute
           in a given year (default is this year)r   r7   rz  r2  r.      )r   todayrL  r   r  r   )r`   rL  r   weekdaysrP  rQ  r<   r<   r=   rY  A  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.   rY   rj   r<   r<   r=   rZ  S  s   zCronSlices.frequency_per_dayc                 C   s   t | d S )r\  r   r  rj   r<   r<   r=   r]  W  r   zCronSlices.frequency_per_hourc                 C   s6   |st  j}d}tddD ]
}|| ||7 }q|S )zeReturns the number of /days/ this item will execute
           in a given year (default is this year)r   r.      )r   r  rL  r  rT  )r`   rL  totalrP  r<   r<   r=   rU  [  s   
zCronSlices.frequency_at_yearc                 C   s   |du r|du rt  j}t  j}n|du s|du r%td| d| d}|| d v rGt||d }td|d D ]}|| |||7 }q;|S )zkReturns the number of times this item will execute in given month
        (default: current month)
        N&One of more arguments undefined: year=, month=r   rz  r.   )r   r  rL  rP  r   r   r  rS  )r`   rL  rP  r  daysrQ  r<   r<   r=   rT  f  s   
zCronSlices.frequency_at_monthc                 C   s   dd |||fD }t |rt| d t| d  S t|r+td| d| d| d}|| d v rDtd	D ]}|| ||||7 }q7|S )
zhReturns the number of times this item will execute in a day
        (default: any executed day)
        c                 S      g | ]}|d u qS r;   r<   rP   xr<   r<   r=   r  ~  r  z/CronSlices.frequency_at_day.<locals>.<listcomp>r   r.   r  r  , day=r2     )rc  rY   anyr   r  rR  )r`   rL  rP  rQ  	test_noner  r   r<   r<   r=   rS  y  s   zCronSlices.frequency_at_dayc              	   C   s   dd ||||fD }t |rt| d S t|r)td| d| d| d| d}t||| }|| d v rU|| d	 v rU|| d
 v rU|d d | d v rUt| d }|S )zjReturns the number of times this item will execute in a hour
        (default: any executed hour)
        c                 S   r  r;   r<   r  r<   r<   r=   r    r  z0CronSlices.frequency_at_hour.<locals>.<listcomp>r   r  r  r  z, hour=r.   r2  rz  r  r7   )rc  rY   r  r   r   r  )r`   rL  rP  rQ  r   r  r   r  r<   r<   r=   rR    s   zCronSlices.frequency_at_hourc                 C   r  r;   r  rj   r<   r<   r=   rs     r  zCronSlices.__str__c                 C   s   |   t|  kS r;   )r   r   )r`   rQ   r<   r<   r=   r~     r  zCronSlices.__eq__r  r;   r  r  r  )r   r   r   r   rf   r  r  r   r7  staticmethodr  r  rj  r   rA  rM  rY  rZ  r]  rU  rT  rS  rR  rs   r~   r  r<   r<   r   r=   r     s0    









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=   r    s    r  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&  )r`   r&  r<   r<   r=   rf     rt   zAlso.__init__c                 G      | j j|ddiS )zAlso every one of thesealsoT)r&  rE  r`   ar<   r<   r=   rE    rD   z
Also.everyc                 G   r  )zAlso on theser  T)r&  r  r  r<   r<   r=   r    rD   zAlso.onc                 G   r  )zAlso during theser  T)r&  duringr  r<   r<   r=   r    rD   zAlso.duringN)r   r   r   r   rf   rE  r  r  r<   r<   r<   r=   r    s    r  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&d$d%ZdS )(r  z,Cron slice object which shows a time patternNc                 C   sf   t |tr	t| }|dd | _|dd | _|dd | _|dd | _g | _|r1| 	| d S d S )Nr)   r(   r*   r1   )
rF   intr  rd  r)   r(   r*   r1   partsr$  )r`   r  re   r<   r<   r=   rf     s   
zCronSlice.__init__c                 C   r}  r;   )r  rZ   rj   r<   r<   r=   r#    r   zCronSlice.__hash__c                 C   s|   |    |dur:t|dD ],}|ddks#|ddks#|dkr.|  j| |7  _q| j| j|dd qdS dS )zSet values into the slice.N,/r   rN   r  sunday)rA  rZ   rU   findr  	get_ranger   parse_value)r`   re   partr<   r<   r=   r$    s   $zCronSlice.parseFc                 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)

        r  r  )r  _render_values)r`   resolver<   r<   r=   r     s   zCronSlice.renderc                 C   r|  )Nz<CronSlice 'r
  r<   rj   r<   r<   r=   rv     r   zCronSlice.__repr__c                 C   s   t | t |kS r;   r{   r  r<   r<   r=   r~     s   zCronSlice.__eq__c                 C   r  r;   r  rj   r<   r<   r=   rs     r  zCronSlice.__str__c                 C   s8   |  |}|s|   |  j| t|7  _| jd S )zSet the every X units valuer   )
test_valuerA  r  r  r  )r`   n_valuer  r<   r<   r=   rE    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.r  Fr   r  )rd  rA  r  r  )r`   r  optsr  r<   r<   r=   r    s
   zCronSlice.onc                 C   s:   |s|    |  j| t|d t| 7  _| jd S )z(Set the During value, which sets a rangerN   r   )rA  r  r  rZ   )r`   vfromvtor  r<   r<   r=   r    s   $
zCronSlice.duringc                 C      t | S )z+Appends rather than replaces the new values)r  rj   r<   r<   r=   r    s   zCronSlice.alsoc                 C   s
   g | _ dS )z#clear the slice ready for new vauesN)r  rj   r<   r<   r=   rA    rH  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)r`   vranger   r<   r<   r=   r    s   

zCronSlice.get_rangec                 c   sd    i }| j s| d | j D ]}t|tr!| D ]}d||< qqd|t|< q|D ]}|V  q*dS )z(Return the entire element as an iterabler.   N)r  rE  rF   r  r  r  )r`   r   r  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)rY   r   r  rj   r<   r<   r=   r  %  r  zCronSlice.__len__c              
   C   s   |dkr| j }n|dkr| j}zt|| j}W n1 ty0 } ztd| j d| d|d}~w tyH } ztd| j d| d|d}~ww | j||dS )	z=Parse the value of the cron slice and raise any errors needed>r	  zUnrecognised z: 'r   NzNo enumeration for r  )r(   r)   get_cronvaluer1   r   r*   r8  r  )r`   r  r  rn   ro   r<   r<   r=   r  )  s   zCronSlice.parse_valuec              	   C   sp   | j dkrt|dkr|dur|S tdt|| jk s#t|| j kr6td| d| j d| j  d| j |S )	z-Test the value is within range for this slicer2   r  Nz"Detected Sunday as 7 instead of 0!r   z
', not in rN   z for )r(   r  r  r)   r   r*   )r`   re   r  r<   r<   r=   r  7  s   &zCronSlice.test_valuer;   r  )r   r   r   r   rf   r#  r$  r   rv   r~   rs   rE  r  r  r  r  rA  r  r  r  r  r  r<   r<   r<   r=   r    s(    







r  c                 C   s@   t | tr| S t|  rtt| S |stdtt| |S )z=Returns a value as int (pass-through) or a special enum valuezNo enumeration allowed)rF   r  rZ   isdigitr8  	CronValue)re   enumsr<   r<   r=   r  C  s   
r  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 )r  z*Represent a special value in the cron linec                 C   s   || _ || | _d S r;   )rJ   r   r  re   )r`   re   r  r<   r<   r=   rf   P  s   zCronValue.__init__c                 C   s   | j t|k S r;   )re   r  r  r<   r<   r=   r  T  rw   zCronValue.__lt__c                 C   r  r;   r{   rj   r<   r<   r=   rv   W  r  zCronValue.__repr__c                 C   rx   r;   rI   rj   r<   r<   r=   rs   Z  rz   zCronValue.__str__c                 C   rx   r;   )re   rj   r<   r<   r=   ry   ]  rz   zCronValue.__int__N)	r   r   r   r   rf   r  rv   rs   ry   r<   r<   r<   r=   r  N  s    r  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rP   r  r  r<   r=   r  e  s    z"_render_values.<locals>.<listcomp>)rY   sortr   )valuesr   r  r<   r  r=   r  a  s   r  c                 C   s:   t | tr
| |S |rtt| S ttr| dS | S )zReturn a single value rendered02d)rF   r  r   rZ   r  ZERO_PAD)re   r  r<   r<   r=   r  h  s
   

r  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 )r  z7A range between one value and another for a time range.c                 G   s   d | _ || _d | _d| _|s|   d S t|d tr$| |d  d S t|d tt	frFt
|dkr;|\| _| _d S |d | _|   d S d S )Nr.   r   r2  )r  slicer   seqrc  rF   rZ   r$  r  r  rY   r  r  )r`   vslicer  r<   r<   r=   rf   s  s   
zCronRange.__init__c                 C   s8  | ddkr6|d\}}z	| j|| _W n ty%   d| _d}Y nw | jdk s2| j| jjkr6td| ddkr|d\}}| jj|dd| _z	| j|| _	W n tyt   | jdkrfd| _nd| _
| jj|dd| _	Y nw | j	| jk rtd	| j d| j	 d
dS |dkr|   dS td| d)z!Parse a ranged value in a cronjobr  r.   z0-0z*Sequence can not be divided by zero or maxrN   r   r  r2   zBad range 'r   r  zUnknown cron range value ""N)r   rU   r  r  r  r  r(   r   r  r  r  rc  )r`   re   r  r  r  r<   r<   r=   r$    s6   
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)   r  r(   r  rj   r<   r<   r=   rc    s   
zCronRange.allFc                 C   s   d}t | j| jjkst | j| jjk r*| j| jkr t| j}n
t| j| jgd|}| jdkr8|d| jd7 }|dkrJt	rJd
dd |  D }|S )	z%Render the ranged value for a cronjobr  rN   r.   r  dr  c                 S   r  r<   r{   r  r<   r<   r=   r    r  z$CronRange.render.<locals>.<listcomp>)r  r  r  r)   r  r(   rZ   r  r  r?  r   r  )r`   r  re   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.   )r  r  r  r  r  rj   r<   r<   r=   r    s   zCronRange.rangec                 C   s   t || _dS )z&Set the sequence value for this range.N)r  r  r  r<   r<   r=   rE    s   zCronRange.everyc                 C   s   t | jt |k S r;   r  r  r  r<   r<   r=   r       zCronRange.__lt__c                 C   s   t | jt |kS r;   )r  r  r  r<   r<   r=   r    r  zCronRange.__gt__c                 C   r  r;   r  rj   r<   r<   r=   ry     rt   zCronRange.__int__c                 C   r  r;   r  rj   r<   r<   r=   rs     r  zCronRange.__str__Nr  )r   r   r   r   rf   r$  rc  r   r  rE  r  r  ry   rs   r<   r<   r<   r=   r  q  s    
r  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 j|i | d S )Nr   )rV   r   r   rf   )r`   r[   ro  r   r<   r=   rf     s   zOrderedVariableList.__init__c                 C   sP   | j dur&| j jdur&| 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   r   r   r   rM   )r`   r   r<   r<   r=   previous  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  rc  rb  r   )r`   r   r<   r<   r=   rc    s
   

zOrderedVariableList.allc                    s>   | j }|| v rt |S |d ur| | S td| d)NzEnvironment Variable 'z' not found.)r  r   r  rc  r8  )r`   rd   r  r   r<   r=   r    s   zOrderedVariableList.__getitem__c                 C   s|   g }|   D ]-\}}| jr| j |d|krqdt|v s#|dkr)d| d}|| d|  q|d d|S )z4Constructs to variable list output used in cron jobsNr   r   r  rO   r   )rX   r  rc  rd  rZ   r   r   )r`   r   rd   re   r<   r<   r=   rs     s   

zOrderedVariableList.__str__)r   r   r   r   rf   r  r  rc  r  rs   r  r<   r<   r   r=   r     s    	
	r   )r  Fr  )Ar   rA   rerT   r   r   r3  r   platform
subprocessrg   calendarr   r   r   r   r   r   collectionsr   shutilr	   __pkgname____version__compiler   r0  DEVNULL	WEEK_ENUM
MONTH_ENUMr  r  r  systemr   r*   rW   unamer?  r  	getLoggerr6  r   ra  rd  r:   rC   r?   rK   rL   r   r   rC  r   r   r8  r  r  r  r  r  r  r  r  r   r<   r<   r<   r=   <module>   s   C

	


	

/     h" L 

	Y