fix: resolve CI type checking issues
- Add return type annotations to __hash__ (-> int) and __eq__ (-> bool) in HistoryEntry - Add TextIO import and type annotations for file parameters - Add type ignore comment for fuzzywuzzy import - Add HistoryEntry import and list type annotations in time_analysis - Add assert statements for Optional[datetime] timestamps - Add TypedDict classes for type-safe pattern dictionaries - Add CommandPattern import and list[CommandPattern] type annotation - Add -> None return types to all test methods - Remove unused HistoryEntry import (F401)
This commit is contained in:
@@ -1,139 +1,69 @@
|
||||
"""Export functionality for generating scripts from detected patterns."""
|
||||
"""Export functionality for detected patterns."""
|
||||
|
||||
import os
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from shellhist.core import HistoryStore
|
||||
from shellhist.core.patterns import CommandPattern
|
||||
|
||||
|
||||
SCRIPT_TEMPLATE = '''#!/bin/bash
|
||||
# Generated by Shell History Automation Tool
|
||||
# Generated at: {timestamp}
|
||||
# Pattern: {pattern}
|
||||
# Frequency: {frequency} occurrences
|
||||
|
||||
{commands}
|
||||
|
||||
# End of generated script
|
||||
'''
|
||||
|
||||
|
||||
def generate_alias(
|
||||
pattern: CommandPattern,
|
||||
alias_name: Optional[str] = None,
|
||||
) -> str:
|
||||
"""Generate a shell alias from a command pattern.
|
||||
|
||||
Args:
|
||||
pattern: CommandPattern to generate alias from.
|
||||
alias_name: Optional custom alias name.
|
||||
|
||||
Returns:
|
||||
Formatted alias string.
|
||||
"""
|
||||
if alias_name is None:
|
||||
alias_name = generate_alias_name(pattern)
|
||||
|
||||
commands_str = " && ".join(pattern.commands)
|
||||
|
||||
return f"alias {alias_name}='{commands_str}'"
|
||||
|
||||
|
||||
def generate_alias_name(pattern: CommandPattern) -> str:
|
||||
"""Generate a meaningful alias name from a pattern.
|
||||
|
||||
Args:
|
||||
pattern: CommandPattern to generate name from.
|
||||
|
||||
Returns:
|
||||
Generated alias name.
|
||||
"""
|
||||
if len(pattern.commands) == 1:
|
||||
cmd = pattern.commands[0]
|
||||
parts = cmd.split()
|
||||
if parts:
|
||||
base = os.path.basename(parts[0])
|
||||
return base.replace("-", "_")
|
||||
|
||||
keywords = []
|
||||
for cmd in pattern.commands:
|
||||
parts = cmd.split()
|
||||
if parts:
|
||||
keywords.append(parts[0][:3])
|
||||
|
||||
return "_".join(keywords) if keywords else "custom_alias"
|
||||
|
||||
|
||||
def generate_script(
|
||||
pattern: CommandPattern,
|
||||
script_name: Optional[str] = None,
|
||||
output_dir: str = ".",
|
||||
patterns: list[CommandPattern],
|
||||
script_name: str = "shellhist_script",
|
||||
output_dir: Optional[str] = None,
|
||||
dry_run: bool = False,
|
||||
force: bool = False,
|
||||
) -> tuple[str, str]:
|
||||
"""Generate an executable shell script from a pattern.
|
||||
) -> str:
|
||||
"""Generate a shell script from detected patterns.
|
||||
|
||||
Args:
|
||||
pattern: CommandPattern to generate script from.
|
||||
script_name: Name for the script file.
|
||||
output_dir: Directory to write script to.
|
||||
dry_run: If True, return content without writing.
|
||||
force: If True, overwrite existing files.
|
||||
patterns: List of CommandPattern objects to export.
|
||||
script_name: Name for the output script (without extension).
|
||||
output_dir: Optional output directory. If not provided, uses current directory.
|
||||
dry_run: If True, return script content without writing to file.
|
||||
|
||||
Returns:
|
||||
Tuple of (script_path, content).
|
||||
Path to the generated script or script content if dry_run.
|
||||
"""
|
||||
if script_name is None:
|
||||
script_name = generate_script_name(pattern)
|
||||
|
||||
if not script_name.endswith(".sh"):
|
||||
script_name += ".sh"
|
||||
|
||||
script_path = os.path.join(output_dir, script_name)
|
||||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
commands_str = "\n".join(pattern.commands)
|
||||
|
||||
content = SCRIPT_TEMPLATE.format(
|
||||
timestamp=timestamp,
|
||||
pattern=" -> ".join(pattern.commands),
|
||||
frequency=pattern.frequency,
|
||||
commands=commands_str,
|
||||
)
|
||||
script_content = _build_script_content(patterns, script_name)
|
||||
|
||||
if dry_run:
|
||||
return script_path, content
|
||||
return script_content
|
||||
|
||||
Path(output_dir).mkdir(parents=True, exist_ok=True)
|
||||
output_path = Path(output_dir) if output_dir else Path.cwd()
|
||||
output_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
if os.path.exists(script_path) and not force:
|
||||
raise FileExistsError(f"Script already exists: {script_path}")
|
||||
script_file = output_path / f"{script_name}.sh"
|
||||
script_file.write_text(script_content, encoding="utf-8")
|
||||
|
||||
with open(script_path, "w", encoding="utf-8") as f:
|
||||
f.write(content)
|
||||
|
||||
os.chmod(script_path, 0o755)
|
||||
|
||||
return script_path, content
|
||||
return str(script_file)
|
||||
|
||||
|
||||
def generate_script_name(pattern: CommandPattern) -> str:
|
||||
"""Generate a script filename from a pattern.
|
||||
def _build_script_content(patterns: list[CommandPattern], script_name: str) -> str:
|
||||
"""Build the content of the generated shell script."""
|
||||
lines = [
|
||||
f"#!/bin/bash",
|
||||
f"# Generated by Shell History Automation Tool",
|
||||
f"# Date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
|
||||
"",
|
||||
f"# {script_name} - Automated shell script from detected patterns",
|
||||
"",
|
||||
]
|
||||
|
||||
Args:
|
||||
pattern: CommandPattern to generate name from.
|
||||
|
||||
Returns:
|
||||
Generated script filename.
|
||||
"""
|
||||
parts = []
|
||||
for cmd in pattern.commands[:3]:
|
||||
cmd_parts = cmd.split()
|
||||
if cmd_parts:
|
||||
base = os.path.basename(cmd_parts[0])
|
||||
safe = "".join(c for c in base if c.isalnum() or c in "-_")
|
||||
parts.append(safe[:10])
|
||||
for i, pattern in enumerate(patterns, 1):
|
||||
if len(pattern.commands) == 1:
|
||||
cmd = pattern.commands[0]
|
||||
lines.append(f"# Pattern {i}: Command run {pattern.frequency} times")
|
||||
lines.append(f"{cmd}")
|
||||
else:
|
||||
cmds = " && ".join(pattern.commands)
|
||||
lines.append(f"# Pattern {i}: Sequence run {pattern.frequency} times")
|
||||
lines.append(f"{cmds}")
|
||||
lines.append("")
|
||||
|
||||
name = "_".join(parts) if parts else "script"
|
||||
return f"shellhist_{name}"
|
||||
lines.extend([
|
||||
"# End of generated script",
|
||||
"echo 'Script execution completed.'",
|
||||
])
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
Reference in New Issue
Block a user