Test Failed
Push — main ( 519f95...989b39 )
by J
01:55
created

devenv.devenv   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 122
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 16
eloc 70
dl 0
loc 122
rs 10
c 0
b 0
f 0

4 Functions

Rating   Name   Duplication   Size   Complexity  
B main() 0 32 8
A run_scripts() 0 24 4
A copy_scripts() 0 24 3
A parse_args() 0 18 1
1
# -*- coding: utf-8 -*-
2
"""Automate the creation of development environments"""
3
import argparse
4
import os
5
from pathlib import Path
6
from shutil import copytree
7
import subprocess
8
from typing import Dict
9
10
from devenv import SCRIPTS_DIR, VERSION
11
from devenv.utils import check_dir, confirm, print_error
12
13
14
def copy_scripts(
15
    src: Path = Path(__file__).parent / "scripts",
16
    dest: Path = SCRIPTS_DIR,
17
    overwrite: bool = False,
18
) -> bool:
19
    """Copies scripts from the devenv installation to the local script directory
20
21
    Args:
22
        src: The directory to copy to dest.
23
        dest: The directory to copy to. Must be a filepath ending in "scripts"
24
        overwrite: Overwrite the destination directory if it exists
25
26
    Returns:
27
        bool: True for on successful copy, False if the copy fails
28
    """
29
    try:
30
        # TODO: check if directory names
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
31
        copytree(src, dest, dirs_exist_ok=overwrite)
0 ignored issues
show
Bug introduced by
The keyword dirs_exist_ok does not seem to exist for the function call.
Loading history...
32
    except FileExistsError:
33
        # ask before overwriting
34
        if confirm(f"'{dest / 'scripts'}' already exists. Overwrite? [Y/n] "):
35
            return copy_scripts(src, dest, overwrite=True)
36
        return False
37
    return True
38
39
40
def run_scripts(script_dir: Path, lang: str, name: str) -> bool:
41
    """Runs scripts in a given dir
42
43
    Args:
44
        script_dir: The directory to search for scripts
45
        lang: The main language of the project
46
        name: The name of the project
47
48
    Returns:
49
        bool: True for success, False otherwise
50
    """
51
    for script in sorted(script_dir.iterdir()):
52
        if not os.access(script, os.X_OK):
53
            print_error(f"'{script.name}' is not executable! Skipping.")
54
            continue
55
56
        try:
57
            print(f"Running '{script.name}'...")
58
            subprocess.run([str(script.resolve()), lang, name], check=True)
59
        except subprocess.CalledProcessError as err:
60
            print_error(f"Error running '{script}'!")
61
            print_error(err)
62
            return False
63
    return True
64
65
66
def parse_args() -> argparse.Namespace:
67
    """Parse arguments
68
69
    Returns:
70
        argparse.Namespace: a Namespace with all collected arguments
71
    """
72
    parser: argparse.ArgumentParser = argparse.ArgumentParser(prog="devenv")
73
    parser.add_argument("lang", help="the language of the project")
74
    parser.add_argument("name", help="the name of the project")
75
    # TODO: install scripts to user_data_dir upon install
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
76
    parser.add_argument(
77
        "--install_scripts", action="store_true", help="install the builtin scripts"
78
    )
79
    # parser.add_argument(
80
    #     "-q", "--quiet", action="store_true", help="supress error messages"
81
    # )
82
    parser.add_argument("--version", action="version", version=f"%(prog)s {VERSION}")
83
    return parser.parse_args()
84
85
86
def main() -> None:
87
    """Run the program according to arguments provided"""
88
    args = parse_args()
89
90
    if args.install_scripts:
91
        if not copy_scripts():
92
            print_error("Error copying scripts")
93
94
    all_dir: Path = SCRIPTS_DIR / "all"
95
    lang_dir: Path = SCRIPTS_DIR / args.lang
96
    all_running: bool = check_dir(all_dir)
97
    lang_running: bool = check_dir(lang_dir)
98
    script_dirs: Dict[Path, bool] = {all_dir: all_running, lang_dir: lang_running}
99
100
    try:
101
        no_run = 0
102
        for directory, run in script_dirs.items():
103
            if not run:
104
                print_error(
105
                    f"Skipping '{directory}', as there are no runnable scripts.",
106
                    "WARN",
107
                )
108
                no_run += 1
109
                continue
110
            if not run_scripts(directory, args.lang, args.name):
111
                raise SystemExit(1)
112
        if no_run == 2:
113
            print_error(
114
                f"Did not run any scripts; both '{all_dir}' and '{lang_dir}' are empty!"
115
            )
116
    except PermissionError as err:
117
        raise PermissionError from err
118
119
120
if __name__ == "__main__":
121
    main()
122