All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@git.madduck.net.
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
7 from datetime import datetime
8 from pathlib import Path
9 from shutil import rmtree, which
10 from tempfile import gettempdir
11 from typing import Any, List, Optional, Union
15 from black_primer import lib
17 # If our environment has uvloop installed lets use it
26 DEFAULT_CONFIG = Path(__file__).parent / "primer.json"
27 _timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
28 DEFAULT_WORKDIR = Path(gettempdir()) / f"primer.{_timestamp}"
29 LOG = logging.getLogger(__name__)
33 ctx: Optional[click.core.Context],
34 param: Optional[Union[click.core.Option, click.core.Parameter]],
35 debug: Union[bool, int, str],
36 ) -> Union[bool, int, str]:
37 """Turn on debugging if asked otherwise INFO default"""
38 log_level = logging.DEBUG if debug else logging.INFO
40 format="[%(asctime)s] %(levelname)s: %(message)s (%(filename)s:%(lineno)d)",
46 def load_projects(config_path: Path) -> List[str]:
47 with open(config_path) as config:
48 return sorted(json.load(config)["projects"].keys())
51 # Unfortunately does import time file IO - but appears to be the only
52 # way to get `black-primer --help` to show projects list
53 DEFAULT_PROJECTS = load_projects(DEFAULT_CONFIG)
56 def _projects_callback(
57 ctx: click.core.Context,
58 param: Optional[Union[click.core.Option, click.core.Parameter]],
61 requested_projects = set(projects.split(","))
62 available_projects = set(
64 if str(DEFAULT_CONFIG) == ctx.params["config"]
65 else load_projects(ctx.params["config"])
68 unavailable = requested_projects - available_projects
70 LOG.error(f"Projects not found: {unavailable}. Available: {available_projects}")
72 return sorted(requested_projects & available_projects)
86 work_path = Path(workdir)
87 if not work_path.exists():
88 LOG.debug(f"Creating {work_path}")
91 if not which("black"):
92 LOG.error("Can not find 'black' executable in PATH. No point in running")
96 ret_val = await lib.process_queue(
108 if not keep and work_path.exists():
109 LOG.debug(f"Removing {work_path}")
110 rmtree(work_path, onerror=lib.handle_PermissionError)
115 @click.command(context_settings={"help_option_names": ["-h", "--help"]})
119 default=str(DEFAULT_CONFIG),
120 type=click.Path(exists=True),
122 help="JSON config file path",
123 # Eager - because config path is used by other callback options
129 callback=_handle_debug,
131 help="Turn on debug logging",
138 help="Keep workdir + repos post run",
145 help="Pull big projects to test",
151 help="Disable showing source file changes in black output",
155 default=",".join(DEFAULT_PROJECTS),
156 callback=_projects_callback,
158 help="Comma separated list of projects to run",
165 help="Rebase project if already checked out",
170 default=str(DEFAULT_WORKDIR),
171 type=click.Path(exists=False),
173 help="Directory path for repo checkouts",
181 help="Number of parallel worker coroutines",
184 def main(ctx: click.core.Context, **kwargs: Any) -> None:
185 """primer - prime projects for blackening... 🏴"""
186 LOG.debug(f"Starting {sys.argv[0]}")
187 # TODO: Change to asyncio.run when Black >= 3.7 only
188 loop = asyncio.get_event_loop()
190 ctx.exit(loop.run_until_complete(async_main(**kwargs)))
195 if __name__ == "__main__": # pragma: nocover