This commit is contained in:
166
src/cronparse/cli.py
Normal file
166
src/cronparse/cli.py
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
"""Command-line interface for Cron Parser CLI."""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from cronparse import __version__
|
||||||
|
from cronparse.parser import parse_cron, validate_cron
|
||||||
|
from cronparse.nlp import text_to_cron
|
||||||
|
from cronparse.scheduler import get_next_executions, format_timeline
|
||||||
|
from cronparse.generator import generate_cron_interactive
|
||||||
|
from cronparse.describer import describe_cron
|
||||||
|
|
||||||
|
|
||||||
|
@click.group()
|
||||||
|
@click.version_option(version=__version__, prog_name="cronparse")
|
||||||
|
def main():
|
||||||
|
"""Cron Parser CLI - Parse, validate, generate, and explain cron expressions."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@main.command(name="parse")
|
||||||
|
@click.argument("expression", type=str)
|
||||||
|
@click.option("--json", "output_json", is_flag=True, help="Output as JSON format")
|
||||||
|
def parse_command(expression: str, output_json: bool):
|
||||||
|
"""Parse and validate a cron expression, showing field breakdown."""
|
||||||
|
try:
|
||||||
|
is_valid, result = parse_cron(expression)
|
||||||
|
if not is_valid:
|
||||||
|
click.echo(click.style("Error: Invalid cron expression", fg="red"))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if output_json:
|
||||||
|
import json
|
||||||
|
click.echo(json.dumps(result, indent=2))
|
||||||
|
else:
|
||||||
|
click.echo(click.style(f"Valid cron expression: {expression}", fg="green"))
|
||||||
|
click.echo()
|
||||||
|
fields = ["minute", "hour", "day", "month", "day_of_week"]
|
||||||
|
for field in fields:
|
||||||
|
value = result.get(field, "N/A")
|
||||||
|
click.echo(f" {field:15}: {value}")
|
||||||
|
if result.get("command"):
|
||||||
|
click.echo(f" {'command':15}: {result['command']}")
|
||||||
|
except Exception as e:
|
||||||
|
click.echo(click.style(f"Error: {e}", fg="red"))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
@main.command(name="from-text")
|
||||||
|
@click.argument("text", type=str, nargs=-1)
|
||||||
|
@click.option("--json", "output_json", is_flag=True, help="Output as JSON format")
|
||||||
|
def from_text_command(text: tuple, output_json: bool):
|
||||||
|
"""Convert natural language to cron expression.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
\"every Monday at 9am\"
|
||||||
|
\"daily at 14:30\"
|
||||||
|
\"every 5 minutes\"
|
||||||
|
\"on the 1st of every month at midnight\"
|
||||||
|
"""
|
||||||
|
text_str = " ".join(text)
|
||||||
|
try:
|
||||||
|
result = text_to_cron(text_str)
|
||||||
|
if output_json:
|
||||||
|
import json
|
||||||
|
click.echo(json.dumps(result, indent=2))
|
||||||
|
else:
|
||||||
|
click.echo(click.style("Natural Language:", fg="cyan") + f" {text_str}")
|
||||||
|
click.echo(click.style("Cron Expression:", fg="green") + f" {result['cron']}")
|
||||||
|
if result.get("description"):
|
||||||
|
click.echo(click.style("Description:", fg="yellow") + f" {result['description']}")
|
||||||
|
except ValueError as e:
|
||||||
|
click.echo(click.style(f"Error: {e}", fg="red"))
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
click.echo(click.style(f"Error parsing text: {e}", fg="red"))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
@main.command(name="next")
|
||||||
|
@click.argument("expression", type=str)
|
||||||
|
@click.option("--count", "-c", default=5, show_default=True, help="Number of executions to show")
|
||||||
|
@click.option("--json", "output_json", is_flag=True, help="Output as JSON format")
|
||||||
|
@click.option("--timeline/--no-timeline", default=True, help="Show ASCII timeline")
|
||||||
|
def next_command(expression: str, count: int, output_json: bool, timeline: bool):
|
||||||
|
"""Show next execution times for a cron expression."""
|
||||||
|
try:
|
||||||
|
is_valid, _ = validate_cron(expression)
|
||||||
|
if not is_valid:
|
||||||
|
click.echo(click.style("Error: Invalid cron expression", fg="red"))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
executions = get_next_executions(expression, count)
|
||||||
|
if output_json:
|
||||||
|
import json
|
||||||
|
click.echo(json.dumps(executions, indent=2, default=str))
|
||||||
|
else:
|
||||||
|
click.echo(click.style(f"Next {count} executions for: {expression}", fg="cyan"))
|
||||||
|
click.echo()
|
||||||
|
for i, exec_time in enumerate(executions, 1):
|
||||||
|
click.echo(f" {i}. {exec_time.strftime('%Y-%m-%d %H:%M:%S %A')}")
|
||||||
|
|
||||||
|
if timeline:
|
||||||
|
click.echo()
|
||||||
|
timeline_output = format_timeline(executions)
|
||||||
|
click.echo(timeline_output)
|
||||||
|
except Exception as e:
|
||||||
|
click.echo(click.style(f"Error: {e}", fg="red"))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
@main.command(name="generate")
|
||||||
|
@click.option("--json", "output_json", is_flag=True, help="Output as JSON format")
|
||||||
|
def generate_command(output_json: bool):
|
||||||
|
"""Interactive wizard to generate a cron expression."""
|
||||||
|
try:
|
||||||
|
result = generate_cron_interactive()
|
||||||
|
if output_json:
|
||||||
|
import json
|
||||||
|
click.echo(json.dumps(result, indent=2))
|
||||||
|
else:
|
||||||
|
click.echo(click.style("Generated Cron Expression:", fg="green", bold=True))
|
||||||
|
click.echo(f" {result['cron']}")
|
||||||
|
click.echo()
|
||||||
|
click.echo("Field breakdown:")
|
||||||
|
for field, value in result["fields"].items():
|
||||||
|
click.echo(f" {field:15}: {value}")
|
||||||
|
except click.Abort:
|
||||||
|
click.echo(click.style("\nGeneration cancelled.", fg="yellow"))
|
||||||
|
sys.exit(0)
|
||||||
|
except Exception as e:
|
||||||
|
click.echo(click.style(f"Error: {e}", fg="red"))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
@main.command(name="explain")
|
||||||
|
@click.argument("expression", type=str)
|
||||||
|
@click.option("--json", "output_json", is_flag=True, help="Output as JSON format")
|
||||||
|
@click.option("--24h", "use_24h", is_flag=True, help="Use 24-hour time format")
|
||||||
|
def explain_command(expression: str, output_json: bool, use_24h: bool):
|
||||||
|
"""Explain a cron expression in human-readable language."""
|
||||||
|
try:
|
||||||
|
is_valid, _ = validate_cron(expression)
|
||||||
|
if not is_valid:
|
||||||
|
click.echo(click.style("Error: Invalid cron expression", fg="red"))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
description = describe_cron(expression, use_24h=use_24h)
|
||||||
|
if output_json:
|
||||||
|
import json
|
||||||
|
click.echo(json.dumps({
|
||||||
|
"expression": expression,
|
||||||
|
"description": description
|
||||||
|
}, indent=2))
|
||||||
|
else:
|
||||||
|
click.echo(click.style(f"Cron: {expression}", fg="cyan"))
|
||||||
|
click.echo(click.style("Description:", fg="green"))
|
||||||
|
click.echo(f" {description}")
|
||||||
|
except Exception as e:
|
||||||
|
click.echo(click.style(f"Error: {e}", fg="red"))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user