Updated S++ and added tool script for creating new header & source files.
This commit is contained in:
parent
b3a0e68100
commit
3c7770a2a4
2
external/scons-plus-plus
vendored
2
external/scons-plus-plus
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 161f2e52d86d9aa851f047d011ac9eccc0422c10
|
Subproject commit c3b5244eac5187a64b6f46a1a4dc171416fff313
|
121
tools/common/__init__.py
Normal file
121
tools/common/__init__.py
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Sequence, Callable, Optional, Literal, TypeAlias, TypeVar
|
||||||
|
|
||||||
|
_invalid_file_char_regex = re.compile(r'[^a-zA-Z0-9_]')
|
||||||
|
_invalid_path_char_regex = re.compile(r'[^a-zA-Z0-9_/]')
|
||||||
|
_variable_regex = re.compile(r'@([A-Z_]+)@')
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
T = TypeVar('T')
|
||||||
|
_Validator : TypeAlias = Callable[[T], bool]
|
||||||
|
|
||||||
|
def script_preamble() -> None:
|
||||||
|
logging.basicConfig(level=logging.DEBUG, format='%(message)s')
|
||||||
|
_root = Path(__file__).parent.parent.parent
|
||||||
|
os.chdir(_root)
|
||||||
|
|
||||||
|
def run_script(main_fn: Callable[[],None]) -> None:
|
||||||
|
script_preamble()
|
||||||
|
try:
|
||||||
|
main_fn()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
_logger.warning('Cancelled.')
|
||||||
|
sys.exit(2)
|
||||||
|
except Exception as e:
|
||||||
|
_logger.error('There was an error running the script: %s', e)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def exec_checked(args: Sequence[str], **kwargs) -> None:
|
||||||
|
subprocess.run(args, stdout=sys.stdout, stderr=sys.stderr, check=True, **kwargs)
|
||||||
|
|
||||||
|
def exec_get_output(args: Sequence[str], **kwargs) -> str:
|
||||||
|
return subprocess.run(args, text=True, check=True, capture_output=True).stdout
|
||||||
|
|
||||||
|
def get_project_config() -> dict:
|
||||||
|
raw = exec_get_output(('scons', '-s', '--disable_auto_update', '--dump=config', '--dump_format=json'))
|
||||||
|
return json.loads(raw)
|
||||||
|
|
||||||
|
def prompt(prefix: str = '> ') -> str:
|
||||||
|
sys.stdout.write(prefix)
|
||||||
|
sys.stdout.flush()
|
||||||
|
return sys.stdin.readline()
|
||||||
|
|
||||||
|
|
||||||
|
def prompt_choices[T](message: str, choices: dict[str, T], prefix: str = '> ') -> T:
|
||||||
|
while True:
|
||||||
|
print(f'{message} [{", ".join(choices.keys())}]')
|
||||||
|
val = prompt(prefix).strip().lower()
|
||||||
|
for name, value in choices.items():
|
||||||
|
if name.lower() == val:
|
||||||
|
return value
|
||||||
|
|
||||||
|
def prompt_yesno(message: str, prefix: str = '> ') -> bool:
|
||||||
|
while True:
|
||||||
|
print(f'{message} [(y)es, (n)o]')
|
||||||
|
val = prompt(prefix).strip().lower()
|
||||||
|
if val in ('y', 'yes'):
|
||||||
|
return True
|
||||||
|
if val in ('n', 'no'):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def prompt_path(message: str,
|
||||||
|
prefix: str = '> ',
|
||||||
|
mode: Literal['save']|Literal['load']|None = None,
|
||||||
|
allow_slash: bool = False,
|
||||||
|
allow_absolute: bool = False,
|
||||||
|
relative_to: Optional[Path] = None,
|
||||||
|
validator: Optional[_Validator[Path]] = None) -> Path:
|
||||||
|
while True:
|
||||||
|
print(message)
|
||||||
|
val = prompt(prefix).strip()
|
||||||
|
if val == '':
|
||||||
|
continue
|
||||||
|
if mode != 'load': # no verification needed when loading a file
|
||||||
|
regex = _invalid_path_char_regex if allow_slash else _invalid_file_char_regex
|
||||||
|
invalid_chars = regex.findall(val)
|
||||||
|
if len(invalid_chars) > 0:
|
||||||
|
print(f'Path contains the following invalid chars: {", ".join(invalid_chars)}')
|
||||||
|
continue
|
||||||
|
path = Path(val)
|
||||||
|
if not allow_absolute and path.is_absolute():
|
||||||
|
print('Absolute paths are not allowed.')
|
||||||
|
continue
|
||||||
|
if relative_to is not None:
|
||||||
|
path = relative_to / path
|
||||||
|
if mode == 'load':
|
||||||
|
if not path.exists():
|
||||||
|
print('File does not exist.')
|
||||||
|
continue
|
||||||
|
elif mode == 'save':
|
||||||
|
if path.exists():
|
||||||
|
if not prompt_yesno(f'File {path} already exists. Continue?'):
|
||||||
|
continue
|
||||||
|
if validator is not None and not validator(path):
|
||||||
|
continue
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def escape_filename(name: str) -> str:
|
||||||
|
return _invalid_file_char_regex.sub('_', name)
|
||||||
|
|
||||||
|
def replace_in_file(file: Path, **replacements) -> None:
|
||||||
|
_logger.debug('Patching file "%s"...', file)
|
||||||
|
bakfile = file.with_suffix(f'{file.suffix}.bak')
|
||||||
|
bakfile.unlink(missing_ok=True)
|
||||||
|
file.rename(bakfile)
|
||||||
|
|
||||||
|
with bakfile.open('r') as fin, file.open('w') as fout:
|
||||||
|
for line in fin:
|
||||||
|
def _repl(match: re.Match) -> str:
|
||||||
|
return replacements.get(match.group(1), '<invalid variable>')
|
||||||
|
fout.write(_variable_regex.sub(_repl, line))
|
||||||
|
bakfile.unlink()
|
44
tools/common/jinja.py
Normal file
44
tools/common/jinja.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
from typing import Any, Callable, Optional, TYPE_CHECKING
|
||||||
|
|
||||||
|
try:
|
||||||
|
import jinja2
|
||||||
|
except ImportError:
|
||||||
|
jinja2 = None
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
_JinjaEnv = jinja2.Environment
|
||||||
|
else:
|
||||||
|
_JinjaEnv = object
|
||||||
|
|
||||||
|
def is_jinja_installed() -> bool:
|
||||||
|
return jinja2 is not None
|
||||||
|
|
||||||
|
def verify_jinja() -> None:
|
||||||
|
if not is_jinja_installed():
|
||||||
|
raise RuntimeError('Python module Jinja2 is not installed.')
|
||||||
|
|
||||||
|
def make_env(filters: Optional[dict[str, Callable]] = None,
|
||||||
|
tests: Optional[dict[str, Callable[[Any], bool]]] = None,
|
||||||
|
environment: Optional[dict[str, Any]] = None,
|
||||||
|
templates_path: Optional[Path] = None) -> _JinjaEnv:
|
||||||
|
if templates_path is None:
|
||||||
|
templates_path = (Path(__file__).parent.parent / 'templates').absolute()
|
||||||
|
jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(templates_path))
|
||||||
|
if filters is not None:
|
||||||
|
jinja_env.filters.update(filters)
|
||||||
|
if tests is not None:
|
||||||
|
jinja_env.tests.update(tests)
|
||||||
|
if environment is not None:
|
||||||
|
jinja_env.globals.update(environment)
|
||||||
|
return jinja_env
|
||||||
|
|
||||||
|
|
||||||
|
def generate_file(template: str, target: Path, context: dict[str, Any], **kwargs) -> None:
|
||||||
|
jinja_env = make_env(**kwargs)
|
||||||
|
template = jinja_env.get_template(template)
|
||||||
|
result = template.render(**context)
|
||||||
|
|
||||||
|
target.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
with target.open('w') as f:
|
||||||
|
f.write(result)
|
@ -4,30 +4,18 @@ import logging
|
|||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
from typing import Sequence
|
|
||||||
|
sys.path.append(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
from common import exec_checked, exec_get_output, prompt, escape_filename, replace_in_file, run_script
|
||||||
|
|
||||||
_invalid_file_char_regex = re.compile(r'[^a-zA-Z0-9_]')
|
_invalid_file_char_regex = re.compile(r'[^a-zA-Z0-9_]')
|
||||||
_variable_regex = re.compile(r'@([A-Z_]+)@')
|
_variable_regex = re.compile(r'@([A-Z_]+)@')
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
_root: Path
|
_root: Path
|
||||||
|
|
||||||
def _exec_checked(args: Sequence[str], **kwargs) -> None:
|
|
||||||
subprocess.run(args, stdout=sys.stdout, stderr=sys.stderr, check=True, **kwargs)
|
|
||||||
|
|
||||||
def _exec_get_output(args: Sequence[str], **kwargs) -> str:
|
|
||||||
return subprocess.run(args, text=True, check=True, capture_output=True).stdout
|
|
||||||
|
|
||||||
def _prompt(prefix: str = '> ') -> str:
|
|
||||||
sys.stdout.write(prefix)
|
|
||||||
sys.stdout.flush()
|
|
||||||
return sys.stdin.readline()
|
|
||||||
|
|
||||||
def _escape_filename(name: str) -> str:
|
|
||||||
return _invalid_file_char_regex.sub('_', name)
|
|
||||||
|
|
||||||
def verify_tools() -> None:
|
def verify_tools() -> None:
|
||||||
_logger.debug('Verifying all required tools are available...')
|
_logger.debug('Verifying all required tools are available...')
|
||||||
success = True
|
success = True
|
||||||
@ -42,72 +30,59 @@ def verify_tools() -> None:
|
|||||||
|
|
||||||
def download_spp() -> None:
|
def download_spp() -> None:
|
||||||
_logger.debug('Checking if Scons++ is checked out...')
|
_logger.debug('Checking if Scons++ is checked out...')
|
||||||
output = _exec_get_output(['git', 'submodule', 'status', 'external/scons-plus-plus'])
|
output = exec_get_output(['git', 'submodule', 'status', 'external/scons-plus-plus'])
|
||||||
if output[0] in ('+', ' '):
|
if output[0] in ('+', ' '):
|
||||||
return
|
return
|
||||||
assert output[0] == '-'
|
assert output[0] == '-'
|
||||||
_logger.info('SCons++ not checkout out yet, doing it now.')
|
_logger.info('SCons++ not checkout out yet, doing it now.')
|
||||||
_exec_checked(['git', 'submodule', 'init'])
|
exec_checked(['git', 'submodule', 'init'])
|
||||||
_exec_checked(['git', 'submodule', 'update', 'external/scons-plus-plus'])
|
exec_checked(['git', 'submodule', 'update', 'external/scons-plus-plus'])
|
||||||
|
|
||||||
def update_spp() -> None:
|
def update_spp() -> None:
|
||||||
_logger.debug('Updating SCons++ submodule...')
|
_logger.debug('Updating SCons++ submodule...')
|
||||||
os.chdir(_root / 'external/scons-plus-plus')
|
os.chdir(_root / 'external/scons-plus-plus')
|
||||||
try:
|
try:
|
||||||
_exec_checked(['git', 'fetch', 'origin', 'master'])
|
exec_checked(['git', 'fetch', 'origin', 'master'])
|
||||||
_exec_checked(['git', 'checkout', 'master'])
|
exec_checked(['git', 'checkout', 'master'])
|
||||||
output = _exec_get_output(['git', 'status', '--porcelain'])
|
output = exec_get_output(['git', 'status', '--porcelain'])
|
||||||
if output.strip() == '':
|
if output.strip() == '':
|
||||||
return
|
return
|
||||||
finally:
|
finally:
|
||||||
os.chdir(_root)
|
os.chdir(_root)
|
||||||
_logger.info('Changes in SCons++ detected, creating commit.')
|
_logger.info('Changes in SCons++ detected, creating commit.')
|
||||||
_exec_checked(['git', 'commit', '-m', 'Updated Scons++', 'external/scons-plus-plus'])
|
exec_checked(['git', 'commit', '-m', 'Updated Scons++', 'external/scons-plus-plus'])
|
||||||
|
|
||||||
def verify_unchanged() -> None:
|
def verify_unchanged() -> None:
|
||||||
output = _exec_get_output(['git', 'status', '--porcelain'])
|
output = exec_get_output(['git', 'status', '--porcelain'])
|
||||||
if output != '':
|
if output != '':
|
||||||
raise RuntimeError('There are uncommitted changes. Commit, stash or revert them before running this script.')
|
raise RuntimeError('There are uncommitted changes. Commit, stash or revert them before running this script.')
|
||||||
|
|
||||||
def _replace_in_file(file: Path, **replacements) -> None:
|
|
||||||
_logger.debug('Patching file "%s"...', file)
|
|
||||||
bakfile = file.with_suffix(f'{file.suffix}.bak')
|
|
||||||
bakfile.unlink(missing_ok=True)
|
|
||||||
file.rename(bakfile)
|
|
||||||
|
|
||||||
with bakfile.open('r') as fin, file.open('w') as fout:
|
|
||||||
for line in fin:
|
|
||||||
def _repl(match: re.Match) -> str:
|
|
||||||
return replacements.get(match.group(1), '<invalid variable>')
|
|
||||||
fout.write(_variable_regex.sub(_repl, line))
|
|
||||||
bakfile.unlink()
|
|
||||||
|
|
||||||
def setup_project() -> None:
|
def setup_project() -> None:
|
||||||
project_name = ''
|
project_name = ''
|
||||||
while project_name == '':
|
while project_name == '':
|
||||||
print('Please enter a name for your project.')
|
print('Please enter a name for your project.')
|
||||||
project_name = _prompt().strip()
|
project_name = prompt().strip()
|
||||||
module_name = project_name
|
module_name = project_name
|
||||||
print(f'Please enter a name for the first module. Leave empty to use the project name ("{module_name}").')
|
print(f'Please enter a name for the first module. Leave empty to use the project name ("{module_name}").')
|
||||||
new_name = _prompt().strip()
|
new_name = prompt().strip()
|
||||||
if new_name != '':
|
if new_name != '':
|
||||||
module_name = new_name
|
module_name = new_name
|
||||||
|
|
||||||
module_folder_name = _escape_filename(project_name.lower())
|
module_folder_name = escape_filename(project_name.lower())
|
||||||
print(f'Please enter a folder name for the first module. Leave empty for "{module_folder_name}". Anything but [A-Za-z0-9_] will be replaced with underscores.')
|
print(f'Please enter a folder name for the first module. Leave empty for "{module_folder_name}". Anything but [A-Za-z0-9_] will be replaced with underscores.')
|
||||||
new_name = _prompt().strip()
|
new_name = prompt().strip()
|
||||||
if new_name != '':
|
if new_name != '':
|
||||||
module_folder_name = _escape_filename(new_name) # just enforce nice names
|
module_folder_name = escape_filename(new_name) # just enforce nice names
|
||||||
|
|
||||||
module_exe_name = _escape_filename(module_name.lower())
|
module_exe_name = escape_filename(module_name.lower())
|
||||||
print(f'Please enter a file name for the module executable. Leave empty for "{module_exe_name}". Omit the file suffix. Anything but [A-Za-z0-9_] will be replaced with underscores.')
|
print(f'Please enter a file name for the module executable. Leave empty for "{module_exe_name}". Omit the file suffix. Anything but [A-Za-z0-9_] will be replaced with underscores.')
|
||||||
new_name = _prompt().strip()
|
new_name = prompt().strip()
|
||||||
if new_name != '':
|
if new_name != '':
|
||||||
module_exe_name = _escape_filename(new_name)
|
module_exe_name = escape_filename(new_name)
|
||||||
|
|
||||||
|
|
||||||
_replace_in_file(_root / 'SConstruct', PROJECT_NAME=project_name, MODULE_FOLDER_NAME=module_folder_name)
|
replace_in_file(_root / 'SConstruct', PROJECT_NAME=project_name, MODULE_FOLDER_NAME=module_folder_name)
|
||||||
_replace_in_file(_root / 'private/spp_template/SModule', MODULE_NAME=module_name, EXE_NAME=module_exe_name)
|
replace_in_file(_root / 'private/spp_template/SModule', MODULE_NAME=module_name, EXE_NAME=module_exe_name)
|
||||||
|
|
||||||
template_folder = _root / 'private/spp_template'
|
template_folder = _root / 'private/spp_template'
|
||||||
module_folder = _root / 'private' / module_folder_name
|
module_folder = _root / 'private' / module_folder_name
|
||||||
@ -115,11 +90,11 @@ def setup_project() -> None:
|
|||||||
shutil.move(template_folder, module_folder)
|
shutil.move(template_folder, module_folder)
|
||||||
|
|
||||||
_logger.info('Creating a git commit for the setup.')
|
_logger.info('Creating a git commit for the setup.')
|
||||||
_exec_checked(['git', 'add', '.'])
|
exec_checked(['git', 'add', '.'])
|
||||||
_exec_checked(['git', 'commit', '-m', 'Project setup'])
|
exec_checked(['git', 'commit', '-m', 'Project setup'])
|
||||||
|
|
||||||
def setup_git_remote() -> None:
|
def setup_git_remote() -> None:
|
||||||
current_url = _exec_get_output(['git', 'remote', 'get-url', 'origin'])
|
current_url = exec_get_output(['git', 'remote', 'get-url', 'origin'])
|
||||||
if 'spp_template' not in current_url:
|
if 'spp_template' not in current_url:
|
||||||
_logger.debug('Remote already set up.')
|
_logger.debug('Remote already set up.')
|
||||||
return
|
return
|
||||||
@ -127,21 +102,17 @@ def setup_git_remote() -> None:
|
|||||||
remote_url = ''
|
remote_url = ''
|
||||||
while remote_url == '':
|
while remote_url == '':
|
||||||
print('Please enter a new URL for your git remote.')
|
print('Please enter a new URL for your git remote.')
|
||||||
remote_url = _prompt().strip()
|
remote_url = prompt().strip()
|
||||||
_exec_checked(['git', 'remote', 'set-url', 'origin', remote_url])
|
exec_checked(['git', 'remote', 'set-url', 'origin', remote_url])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
def script_main():
|
||||||
logging.basicConfig(level=logging.DEBUG, format='%(message)s')
|
|
||||||
_root = Path(__file__).parent.parent
|
|
||||||
os.chdir(_root)
|
|
||||||
try:
|
|
||||||
verify_tools()
|
verify_tools()
|
||||||
download_spp()
|
download_spp()
|
||||||
update_spp()
|
update_spp()
|
||||||
verify_unchanged()
|
verify_unchanged()
|
||||||
setup_project()
|
setup_project()
|
||||||
setup_git_remote()
|
setup_git_remote()
|
||||||
except Exception as e:
|
|
||||||
_logger.error('There was an error running the script: %s', e)
|
if __name__ == '__main__':
|
||||||
sys.exit(1)
|
run_script(script_main)
|
||||||
|
104
tools/new_source.py
Normal file
104
tools/new_source.py
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
sys.path.append(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
from common import prompt_choices, prompt_path, prompt_yesno, run_script
|
||||||
|
from common.jinja import is_jinja_installed, generate_file
|
||||||
|
|
||||||
|
|
||||||
|
_PRIVATE_PATH = Path('private')
|
||||||
|
_PUBLIC_PATH = Path('public')
|
||||||
|
_HEADER_TEMPLATE_NAME = 'header.hpp.jinja'
|
||||||
|
_SOURCE_TEMPLATE_NAME = 'source.cpp.jinja'
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
_header_path: Optional[Path] = None
|
||||||
|
_source_path: Optional[Path] = None
|
||||||
|
_namespace: str
|
||||||
|
|
||||||
|
def verify_tools() -> None:
|
||||||
|
success = True
|
||||||
|
if not is_jinja_installed():
|
||||||
|
_logger.error('Python module Jinja2 is not installed.')
|
||||||
|
success = False
|
||||||
|
if not success:
|
||||||
|
raise RuntimeError('one or more required tools could not be found')
|
||||||
|
|
||||||
|
def query_params() -> None:
|
||||||
|
global _header_path, _source_path, _namespace
|
||||||
|
header_folder = prompt_choices('Create Header?', {
|
||||||
|
'public': _PUBLIC_PATH,
|
||||||
|
'private': _PRIVATE_PATH,
|
||||||
|
'no': None
|
||||||
|
})
|
||||||
|
do_create_source = prompt_yesno('Create source?')
|
||||||
|
if header_folder is None and not do_create_source:
|
||||||
|
raise RuntimeError('Neither header nor source selected for creation.')
|
||||||
|
|
||||||
|
def _make_header_path(base_path: Path) -> Path:
|
||||||
|
return header_folder / base_path.with_suffix('.hpp')
|
||||||
|
|
||||||
|
def _make_source_path(base_path: Path) -> Path:
|
||||||
|
return _PRIVATE_PATH / base_path.with_suffix('.cpp')
|
||||||
|
|
||||||
|
def _validate_path(path: Path) -> bool:
|
||||||
|
result = True
|
||||||
|
if header_folder is not None:
|
||||||
|
header_path = _make_header_path(path)
|
||||||
|
if header_path.exists():
|
||||||
|
print(f'Header file {header_path} already exists.')
|
||||||
|
result = False
|
||||||
|
if do_create_source:
|
||||||
|
source_path = _make_source_path(path)
|
||||||
|
if source_path.exists():
|
||||||
|
print(f'Source file {source_path} already exists.')
|
||||||
|
result = False
|
||||||
|
return result
|
||||||
|
|
||||||
|
input_path = prompt_path('Enter basename for the source (relative to public/private folder, no file extension).',
|
||||||
|
allow_slash=True, validator=_validate_path)
|
||||||
|
_namespace = input_path.parts[0]
|
||||||
|
|
||||||
|
if header_folder is not None:
|
||||||
|
_header_path = _make_header_path(input_path)
|
||||||
|
if do_create_source:
|
||||||
|
_source_path = _make_source_path(input_path)
|
||||||
|
|
||||||
|
|
||||||
|
def create_header() -> None:
|
||||||
|
if _header_path is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
_logger.info('Generating header at %s.', str(_header_path))
|
||||||
|
|
||||||
|
guard = '_'.join(_header_path.with_suffix('').parts[1:]).upper()
|
||||||
|
generate_file(_HEADER_TEMPLATE_NAME, _header_path, {
|
||||||
|
'guard': guard,
|
||||||
|
'namespace': _namespace
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def create_source() -> None:
|
||||||
|
if _source_path is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
_logger.info('Generating source at %s.', str(_source_path))
|
||||||
|
generate_file(_SOURCE_TEMPLATE_NAME, _source_path, {
|
||||||
|
'header_path': '/'.join(_header_path.parts[1:]) if _header_path else None,
|
||||||
|
'namespace': _namespace
|
||||||
|
})
|
||||||
|
|
||||||
|
def script_main() -> None:
|
||||||
|
verify_tools()
|
||||||
|
query_params()
|
||||||
|
create_header()
|
||||||
|
create_source()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
run_script(script_main)
|
13
tools/templates/header.hpp.jinja
Normal file
13
tools/templates/header.hpp.jinja
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if !defined({{guard}})
|
||||||
|
#define {{guard}} 1
|
||||||
|
|
||||||
|
namespace {{namespace}}
|
||||||
|
{{ "{" }}
|
||||||
|
|
||||||
|
{{ "}" }} // namespace {{namespace}}
|
||||||
|
|
||||||
|
#endif // !defined({{guard}})
|
||||||
|
|
10
tools/templates/source.cpp.jinja
Normal file
10
tools/templates/source.cpp.jinja
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
{%- if header_path is not none %}
|
||||||
|
#include "{{header_path}}"
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
|
namespace {{namespace}}
|
||||||
|
{{ "{" }}
|
||||||
|
|
||||||
|
{{ "}" }} // namespace {{namespace}}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user