Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 118 additions & 1 deletion README.md
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pip install deploycron

# Usage

There's only one function in the package now,
There are two functions in the package now,

```python
def deploycron(filename="", content="", override=False):
Expand Down Expand Up @@ -43,6 +43,123 @@ deploycron(content="* * * * * echo hello > /tmp/hello")
deploycron(content="* * * * * echo hello > /tmp/hello", override=True)
```

and

```python
def undeploycron_between(start_line, stop_line, occur_start, occur_stop):
```

> Uninstall crontab parts between two lines (included).
> If the start_line or the stop_line is not found into the installed crontab,
> it won't be modified.
> Returns `True` if the operation succeded and `False` if the operation failed.
>
>
> `start_line` - start crontab line (the actual line, not the line number) to delimit the crontab block to remove
> `stop_line` - stop crontab line (the actual line, not the line number) to delimit the crontab block to remove
> `occur_start` - number of the occurrence of `start_line` at which the uninstall will start (1 => first occurrence)
> `occur_start` - number of the occurrence of `stop_line` at which the uninstall will stop

Example 1:
```python
from deploycron import deploycron

# Crontab sample
deploycron(content="* * * * * echo Good > /tmp/buffer")
deploycron(content="* * * * * echo day > /tmp/buffer")
deploycron(content="* * * * * echo to > /tmp/buffer")
deploycron(content="* * * * * echo you > /tmp/buffer")
deploycron(content="* * * * * echo mate > /tmp/buffer")

# We want to remove from line 2 to line 4 included
undeploycron_between("* * * * * echo day > /tmp/buffer",
"* * * * * echo mate > /tmp/buffer")
```

With this script, we first get a crontab like this one :

* * * * * echo Good > /tmp/buffer
* * * * * echo day > /tmp/buffer
* * * * * echo to > /tmp/buffer
* * * * * echo you > /tmp/buffer
* * * * * echo mate > /tmp/buffer

And then, after the undeploycron_between(), we get :

* * * * * echo Good > /tmp/buffer
* * * * * echo mate > /tmp/buffer

Example 2:
```python
from deploycron import deploycron

# Crontab sample
deploycron(content="* * * * * echo Good > /tmp/buffer")
deploycron(content="* * * * * echo day > /tmp/buffer")
deploycron(content="* * * * * echo to > /tmp/buffer")
deploycron(content="* * * * * echo you > /tmp/buffer")
deploycron(content="* * * * * echo mate > /tmp/buffer")
deploycron(content="* * * * * echo Good > /tmp/buffer")
deploycron(content="* * * * * echo to > /tmp/buffer")
deploycron(content="* * * * * echo see > /tmp/buffer")
deploycron(content="* * * * * echo you > /tmp/buffer")

# We want to remove from line 6 to line 9 included
undeploycron_between("* * * * * echo Good > /tmp/buffer",
"* * * * * echo you > /tmp/buffer",
2,
2)
```

This script allows us to go from this crontab :

* * * * * echo Good > /tmp/buffer
* * * * * echo day > /tmp/buffer
* * * * * echo to > /tmp/buffer
* * * * * echo you > /tmp/buffer
* * * * * echo mate > /tmp/buffer
* * * * * echo Good > /tmp/buffer
* * * * * echo to > /tmp/buffer
* * * * * echo see > /tmp/buffer
* * * * * echo you > /tmp/buffer

To this one :

* * * * * echo Good > /tmp/buffer
* * * * * echo day > /tmp/buffer
* * * * * echo to > /tmp/buffer
* * * * * echo you > /tmp/buffer
* * * * * echo mate > /tmp/buffer

The undeploy doesn't trigger at the first occurrence of the lines here. Instead, it triggers at the second occurrence of both `start_line` and `stop_line` as precised in the parameters.

## CLI scripts

The package also provides two helpers CLI scripts mapped to corresponding functions:

```
usage: deploycron_file [-h] filepath

positional arguments:
filepath Complete file path of the cron to deploy

optional arguments:
-h, --help show this help message and exit
```

and

```
usage: undeploycron_between [-h] start_line stop_line

positional arguments:
start_line start line to delimit the crontab block to remove
stop_line stop line to delimit the crontab block to remove

optional arguments:
-h, --help show this help message and exit
```

## Note

Only support in unix-like system, eg. Linux/Mac
Expand Down
87 changes: 80 additions & 7 deletions deploycron/__init__.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,7 @@ def deploycron(filename="", content="", override=False):
if override:
installed_content = ""
else:
# currently installed crontabs
retcode, err, installed_content = _runcmd("crontab -l")
if retcode != 0 and 'no crontab for' not in err:
raise OSError("crontab not supported in your system")
# merge the new crontab with the old one
installed_content = _get_installed_content()
installed_content = installed_content.rstrip("\n")
installed_crontabs = installed_content.split("\n")
for crontab in content.split("\n"):
Expand All @@ -42,9 +38,86 @@ def deploycron(filename="", content="", override=False):
if installed_content:
installed_content += "\n"
# install back
retcode, err, out = _runcmd("crontab", installed_content)
_install_content(installed_content)


def undeploycron_between(start_line, stop_line, occur_start=1, occur_stop=1):
"""uninstall crontab parts between two lines (included).
If the start_line or the stop_line is not found into the installed crontab,
it won't be modified.
`start_line` - start crontab line (the actual line, not the line number)
to delimit the crontab block to remove
`stop_line` - stop crontab line (the actual line, not the line number)
to delimit the crontab block to remove
`occur_start` - nth occurence you want to consider as start_line (ex :
choose 2 if you want the 2nd occurence to be chosen as start_line)
`occur_stop` - nth occurence you want to consider as stop_line (ex :
choose 2 if you want the 2nd occurence to be chosen as stop_line)
"""
lines_installed = [x.strip() for x in
_get_installed_content().splitlines()]
start_line = start_line.strip()
stop_line = stop_line.strip()
if start_line not in lines_installed:
return False
if stop_line not in lines_installed:
return False
if occur_start is None or occur_start <= 0:
return False
if occur_stop is None or occur_stop <= 0:
return False

# Check if stop_line is before start_line by getting their indices
index_start = -1
index_stop = -1
try:
# Find the occurence we are interested in
for j in range(occur_start):
index_start = lines_installed.index(start_line, index_start + 1)
except ValueError:
# If the occurence number is too high (nth occurrence not found)
return False
try:
for j in range(occur_stop):
index_stop = lines_installed.index(stop_line, index_stop + 1)
except ValueError:
return False

# If stop is before start, we switch them
if index_stop < index_start:
buffer_var = index_start
index_start = index_stop
index_stop = buffer_var

lines_to_install = []
for i in range(len(lines_installed)):
if i < index_start or i > index_stop:
lines_to_install.append(lines_installed[i])

if len(lines_to_install) > 0:
lines_to_install.append("")
content_to_install = "\n".join(lines_to_install)
_install_content(content_to_install)
return True


def _get_installed_content():
"""get the current installed crontab.
"""
retcode, err, installed_content = _runcmd("crontab -l")
if retcode != 0 and b'no crontab for' not in err:
raise OSError("crontab not supported in your system")
return installed_content.decode("utf-8")


def _install_content(content):
"""install (replace) the given (multilines) string as new crontab...
"""
retcode, err, out = _runcmd("crontab", content)
if retcode != 0:
raise ValueError("failed to install crontab, check if crontab is valid")
raise ValueError("failed to install crontab, check if crontab is "
"valid")


def _runcmd(cmd, input=None):
'''run shell command and return the a tuple of the cmd's return code, std error and std out
Expand Down
24 changes: 24 additions & 0 deletions deploycron/cli_deploycron_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import print_function
import argparse
import os
import sys
import deploycron


def main():
parser = argparse.ArgumentParser()
parser.add_argument("filepath",
help="Complete file path of the cron to deploy")
args = parser.parse_args()
filepath = args.filepath
if not os.path.isfile(filepath):
print("ERROR: filepath [%s] is not a file" % filepath, file=sys.stderr)
sys.exit(1)
deploycron.deploycron(filename=filepath)


if __name__ == "__main__":
main()
24 changes: 24 additions & 0 deletions deploycron/cli_undeploycron_between.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import print_function
import argparse
import deploycron


def main():
parser = argparse.ArgumentParser()
parser.add_argument("start_line",
help="start line to delimit the crontab block to "
"remove")
parser.add_argument("stop_line",
help="stop line to delimit the crontab block to "
"remove")
args = parser.parse_args()
start_line = args.start_line
stop_line = args.stop_line
deploycron.undeploycron_between(start_line, stop_line)


if __name__ == "__main__":
main()
6 changes: 6 additions & 0 deletions setup.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,10 @@
"Topic :: Utilities",
"License :: OSI Approved :: MIT License",
],
entry_points = {
"console_scripts": [
"deploycron_file = deploycron.cli_deploycron_file:main",
"undeploycron_between = deploycron.cli_undeploycron_between:main"
]
}
)