Coverage for sources/emcdproj/template.py: 45%
34 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-30 14:01 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-30 14:01 +0000
1# vim: set filetype=python fileencoding=utf-8:
2# -*- coding: utf-8 -*-
4#============================================================================#
5# #
6# Licensed under the Apache License, Version 2.0 (the "License"); #
7# you may not use this file except in compliance with the License. #
8# You may obtain a copy of the License at #
9# #
10# http://www.apache.org/licenses/LICENSE-2.0 #
11# #
12# Unless required by applicable law or agreed to in writing, software #
13# distributed under the License is distributed on an "AS IS" BASIS, #
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
15# See the License for the specific language governing permissions and #
16# limitations under the License. #
17# #
18#============================================================================#
21''' Copier template maintenance and validation. '''
24from __future__ import annotations
26import subprocess as _subprocess
27import tempfile as _tempfile
29from . import __
30from . import interfaces as _interfaces
33class CommandDispatcher(
34 _interfaces.CliCommand, decorators = ( __.standard_tyro_class, ),
35):
36 ''' Dispatches commands for static website maintenance. '''
38 command: __.typx.Union[
39 __.typx.Annotated[
40 SurveyCommand,
41 __.tyro.conf.subcommand( 'survey', prefix_name = False ),
42 ],
43 __.typx.Annotated[
44 ValidateCommand,
45 __.tyro.conf.subcommand( 'validate', prefix_name = False ),
46 ],
47 ]
49 async def __call__(
50 self, auxdata: __.Globals, display: _interfaces.ConsoleDisplay
51 ) -> None:
52 ictr( 1 )( self.command )
53 await self.command( auxdata = auxdata, display = display )
56class SurveyCommand(
57 _interfaces.CliCommand, decorators = ( __.standard_tyro_class, ),
58):
59 ''' Surveys available configuration variants. '''
61 async def __call__(
62 self, auxdata: __.Globals, display: _interfaces.ConsoleDisplay
63 ) -> None:
64 stream = await display.provide_stream( )
65 for variant in survey_variants( auxdata ):
66 print( variant, file = stream )
69class ValidateCommand(
70 _interfaces.CliCommand, decorators = ( __.standard_tyro_class, ),
71):
72 ''' Validates template against configuration variant. '''
74 variant: __.typx.Annotated[
75 str,
76 __.typx.Doc( ''' Configuration variant to validate. ''' ),
77 __.tyro.conf.Positional,
78 ]
80 async def __call__(
81 self, auxdata: __.Globals, display: _interfaces.ConsoleDisplay
82 ) -> None:
83 ''' Copies new project from template for configuration variant. '''
84 # TODO: Validate variant argument.
85 validate_variant( auxdata, self.variant )
88def copy_template( answers_file: __.Path, projectdir: __.Path ) -> None:
89 ''' Copies template to target directory using answers. '''
90 _subprocess.run( # noqa: S603
91 ( 'copier', 'copy', '--data-file', str( answers_file ),
92 '--defaults', '--overwrite', '--vcs-ref', 'HEAD',
93 '.', str( projectdir ) ),
94 cwd = __.Path( ), check = True )
97def survey_variants( auxdata: __.Globals ) -> __.cabc.Sequence[ str ]:
98 ''' Surveys available configuration variants. '''
99 location = auxdata.distribution.provide_data_location( 'copier' )
100 return tuple(
101 fsent.stem.lstrip( 'answers-' )
102 for fsent in location.glob( 'answers-*.yaml' )
103 if fsent.is_file( ) )
106def validate_variant( auxdata: __.Globals, variant: str ) -> None:
107 ''' Validates configuration variant. '''
108 answers_file = (
109 auxdata.distribution.provide_data_location(
110 'copier', f"answers-{variant}.yaml" ) )
111 if not answers_file.is_file( ):
112 # TODO: Raise error.
113 return
114 with _tempfile.TemporaryDirectory( ) as tmpdir:
115 projectdir = __.Path( tmpdir ) / variant
116 copy_template( answers_file, projectdir )
117 validate_variant_project( projectdir )
120def validate_variant_project( projectdir: __.Path ) -> None:
121 ''' Validates standard project as generated from template. '''
122 for command in (
123 ( 'hatch', '--env', 'develop', 'run',
124 'python', '-m', 'pip', 'install',
125 '--upgrade', 'pip', 'build' ),
126 ( 'hatch', '--env', 'develop', 'run', 'make-all' ),
127 ): _subprocess.run( command, cwd = str( projectdir ), check = True ) # noqa: S603