#!/usr/bin/env python3 import os import sys import subprocess import argparse from pathlib import Path # Import helper functions sys.path.append(os.path.join(os.path.dirname(os.path.dirname(__file__)))) from helpers.functions import printfe, command_exists DOTFILES_ROOT = os.path.expanduser("~/.dotfiles") def lint_ansible(fix=False): """Run ansible-lint on Ansible files""" ansible_dir = os.path.join(DOTFILES_ROOT, "config/ansible") if not os.path.isdir(ansible_dir): printfe("yellow", "No ansible directory found at config/ansible") return 0 # Find all YAML files in the ansible directory yaml_files = [] for ext in [".yml", ".yaml"]: yaml_files.extend(list(Path(ansible_dir).glob(f"**/*{ext}"))) if not yaml_files: printfe("yellow", "No Ansible files found in config/ansible to lint") return 0 if not command_exists("ansible-lint"): printfe( "red", "ansible-lint is not installed. Please install it with pip or your package manager.", ) return 1 printfe("blue", f"Running ansible-lint{' with auto-fix' if fix else ''}...") files_to_lint = [str(f) for f in yaml_files] command = ["ansible-lint"] if fix: command.append("--fix") command.extend(files_to_lint) result = subprocess.run(command, check=False) return result.returncode def lint_nix(): """Run nixfmt on Nix files""" nix_files = list(Path(DOTFILES_ROOT).glob("**/*.nix")) if not nix_files: printfe("yellow", "No Nix files found to lint") return 0 if not command_exists("nixfmt"): printfe( "red", "nixfmt is not installed. Please install it with nix-env or your package manager.", ) return 1 printfe("blue", "Running nixfmt...") exit_code = 0 for nix_file in nix_files: printfe("cyan", f"Formatting {nix_file}") result = subprocess.run(["nixfmt", str(nix_file)], check=False) if result.returncode != 0: exit_code = 1 return exit_code def lint_python(fix=False): """Run pylint and black on Python files""" python_files = list(Path(DOTFILES_ROOT).glob("**/*.py")) if not python_files: printfe("yellow", "No Python files found to lint") return 0 exit_code = 0 # Check for pylint if command_exists("pylint"): printfe("blue", "Running pylint...") files_to_lint = [str(f) for f in python_files] result = subprocess.run(["pylint"] + files_to_lint, check=False) if result.returncode != 0: exit_code = 1 else: printfe("yellow", "pylint is not installed. Skipping Python linting.") # Check for black if command_exists("black"): printfe( "blue", f"Running black{'--check' if not fix else ''} on Python files..." ) black_args = ["black"] if not fix: black_args.append("--check") black_args.extend([str(f) for f in python_files]) result = subprocess.run(black_args, check=False) if result.returncode != 0: exit_code = 1 else: printfe("yellow", "black is not installed. Skipping Python formatting.") if not command_exists("pylint") and not command_exists("black"): printfe( "red", "Neither pylint nor black is installed. Please run: `pip install pylint black`", ) return 1 return exit_code def main(): """ Entry point for running linters on dotfiles. This function parses command-line arguments to determine which linters to run and whether to apply auto-fixes. It supports running linters for Ansible, Nix, and Python files. If no specific linter is specified, all linters are executed. Command-line arguments: --ansible: Run only ansible-lint. --nix: Run only nixfmt. --python: Run only Python linters (pylint, black). --fix: Auto-fix issues where possible. Returns: int: Exit code indicating the success or failure of the linting process. A non-zero value indicates that one or more linters reported issues. """ parser = argparse.ArgumentParser(description="Run linters on dotfiles") parser.add_argument("--ansible", action="store_true", help="Run only ansible-lint") parser.add_argument("--nix", action="store_true", help="Run only nixfmt") parser.add_argument( "--python", action="store_true", help="Run only Python linters (pylint, black)" ) parser.add_argument( "--fix", action="store_true", help="Auto-fix issues where possible" ) args = parser.parse_args() # If no specific linter is specified, run all run_ansible = args.ansible or not (args.ansible or args.nix or args.python) run_nix = args.nix or not (args.ansible or args.nix or args.python) run_python = args.python or not (args.ansible or args.nix or args.python) exit_code = 0 if run_ansible: ansible_result = lint_ansible(fix=args.fix) if ansible_result != 0: exit_code = ansible_result if run_nix: nix_result = lint_nix() if nix_result != 0: exit_code = nix_result if run_python: python_result = lint_python(fix=args.fix) if python_result != 0: exit_code = python_result return exit_code if __name__ == "__main__": sys.exit(main())