bumpver/src/pycalver/config.py

580 lines
17 KiB
Python
Raw Normal View History

2018-09-02 21:48:12 +02:00
# This file is part of the pycalver project
2019-02-22 10:56:47 +01:00
# https://gitlab.com/mbarkhau/pycalver
2018-09-02 21:48:12 +02:00
#
2020-09-24 11:16:02 +00:00
# Copyright (c) 2018-2020 Manuel Barkhau (mbarkhau@gmail.com) - MIT License
2018-09-02 21:48:12 +02:00
# SPDX-License-Identifier: MIT
2018-11-15 22:16:16 +01:00
"""Parse setup.cfg or pycalver.cfg files."""
2018-09-02 21:48:12 +02:00
2020-09-24 11:16:02 +00:00
import re
2020-09-18 19:52:40 +00:00
import glob
2018-09-02 21:48:12 +02:00
import typing as typ
2020-05-25 07:46:30 +00:00
import logging
2018-09-02 21:48:12 +02:00
import datetime as dt
2020-05-25 07:46:30 +00:00
import configparser
2018-09-02 21:48:12 +02:00
2020-05-25 07:46:30 +00:00
import toml
import pathlib2 as pl
2018-09-02 21:48:12 +02:00
2020-09-19 22:35:48 +00:00
from . import version
from . import v1version
from . import v2version
from . import v1patterns
from . import v2patterns
from .patterns import Pattern
2018-09-02 21:48:12 +02:00
2020-07-19 13:18:42 +00:00
logger = logging.getLogger("pycalver.config")
2018-09-02 21:48:12 +02:00
2020-09-19 22:35:48 +00:00
RawPatterns = typ.List[str]
RawPatternsByFile = typ.Dict[str, RawPatterns]
FileRawPatternsItem = typ.Tuple[str, RawPatterns]
PatternsByFile = typ.Dict[str, typ.List[Pattern]]
FilePatternsItem = typ.Tuple[str, typ.List[Pattern]]
2018-11-15 22:16:16 +01:00
2018-12-08 19:18:47 +01:00
SUPPORTED_CONFIGS = ["setup.cfg", "pyproject.toml", "pycalver.toml"]
2020-09-18 19:34:51 +00:00
DEFAULT_COMMIT_MESSAGE = "bump version to {new_version}"
2018-09-02 21:48:12 +02:00
class ProjectContext(typ.NamedTuple):
"""Container class for project info."""
path : pl.Path
config_filepath: pl.Path
2020-09-19 22:35:48 +00:00
config_rel_path: str
config_format : str
vcs_type : typ.Optional[str]
def init_project_ctx(project_path: typ.Union[str, pl.Path, None] = ".") -> ProjectContext:
"""Initialize ProjectContext from a path."""
2018-12-09 15:57:04 +01:00
if isinstance(project_path, pl.Path):
path = project_path
2018-12-09 15:57:04 +01:00
elif project_path is None:
path = pl.Path(".")
else:
# assume it's a str/unicode
path = pl.Path(project_path)
2018-12-21 19:20:45 +01:00
if (path / "pycalver.toml").exists():
config_filepath = path / "pycalver.toml"
config_format = 'toml'
elif (path / "pyproject.toml").exists():
config_filepath = path / "pyproject.toml"
config_format = 'toml'
2018-12-21 19:20:45 +01:00
elif (path / "setup.cfg").exists():
config_filepath = path / "setup.cfg"
config_format = 'cfg'
else:
2018-12-21 19:20:45 +01:00
# fallback to creating a new pycalver.toml
config_filepath = path / "pycalver.toml"
config_format = 'toml'
2020-09-19 22:35:48 +00:00
if config_filepath.is_absolute():
config_rel_path = str(config_filepath.relative_to(path.absolute()))
else:
config_rel_path = str(config_filepath)
config_filepath = pl.Path.cwd() / config_filepath
2018-12-08 19:18:47 +01:00
vcs_type: typ.Optional[str]
if (path / ".git").exists():
vcs_type = 'git'
elif (path / ".hg").exists():
vcs_type = 'hg'
else:
vcs_type = None
2020-09-19 22:35:48 +00:00
return ProjectContext(path, config_filepath, config_rel_path, config_format, vcs_type)
2020-09-19 22:35:48 +00:00
RawConfig = typ.Dict[str, typ.Any]
MaybeRawConfig = typ.Optional[RawConfig]
2018-09-03 22:23:51 +02:00
class Config(typ.NamedTuple):
"""Container for parameters parsed from a config file."""
2018-09-03 22:23:51 +02:00
2018-11-04 21:11:42 +01:00
current_version: str
version_pattern: str
pep440_version : str
2020-09-18 19:34:51 +00:00
commit_message : str
2018-09-03 22:23:51 +02:00
2020-09-18 19:52:40 +00:00
commit : bool
tag : bool
push : bool
is_new_pattern: bool
2018-09-03 22:23:51 +02:00
2020-09-19 22:35:48 +00:00
file_patterns: PatternsByFile
MaybeConfig = typ.Optional[Config]
2018-09-02 21:48:12 +02:00
2018-09-03 22:23:51 +02:00
def _debug_str(cfg: Config) -> str:
cfg_str_parts = [
2020-05-25 09:40:26 +00:00
"Config Parsed: Config(",
2020-09-19 22:35:48 +00:00
f"\n current_version='{cfg.current_version}',",
f"\n version_pattern='{cfg.version_pattern}',",
f"\n pep440_version='{cfg.pep440_version}',",
f"\n commit_message='{cfg.commit_message}',",
f"\n commit={cfg.commit},",
f"\n tag={cfg.tag},",
f"\n push={cfg.push},",
f"\n is_new_pattern={cfg.is_new_pattern},",
"\n file_patterns={",
]
2018-09-03 22:23:51 +02:00
2020-09-24 11:16:02 +00:00
for filepath, patterns in sorted(cfg.file_patterns.items()):
for pattern in patterns:
2020-09-19 22:35:48 +00:00
cfg_str_parts.append(f"\n '{filepath}': '{pattern.raw_pattern}',")
2018-09-03 22:23:51 +02:00
2020-09-19 22:35:48 +00:00
cfg_str_parts += ["\n }\n)"]
return "".join(cfg_str_parts)
2018-09-02 21:48:12 +02:00
2020-09-19 22:35:48 +00:00
def _parse_cfg_file_patterns(
cfg_parser: configparser.RawConfigParser,
) -> typ.Iterable[FileRawPatternsItem]:
if not cfg_parser.has_section("pycalver:file_patterns"):
return
2018-09-02 21:48:12 +02:00
2020-09-19 22:35:48 +00:00
file_pattern_items: typ.List[typ.Tuple[str, str]] = cfg_parser.items("pycalver:file_patterns")
for filepath, patterns_str in file_pattern_items:
2020-09-19 22:35:48 +00:00
maybe_patterns = (line.strip() for line in patterns_str.splitlines())
patterns = [p for p in maybe_patterns if p]
yield filepath, patterns
2018-09-02 21:48:12 +02:00
2018-11-11 15:08:46 +01:00
2018-12-08 19:18:47 +01:00
class _ConfigParser(configparser.RawConfigParser):
2020-07-19 14:38:57 +00:00
# pylint:disable=too-many-ancestors ; from our perspective, it's just one
2018-12-08 19:18:47 +01:00
"""Custom parser, simply to override optionxform behaviour."""
def optionxform(self, optionstr: str) -> str:
"""Non-xforming (ie. uppercase preserving) override.
This is important because our option names are actually
filenames, so case sensitivity is relevant. The default
behaviour is to do optionstr.lower()
"""
return optionstr
OptionVal = typ.Union[str, bool, None]
BOOL_OPTIONS: typ.Mapping[str, OptionVal] = {'commit': False, 'tag': None, 'push': None}
2018-11-11 15:08:46 +01:00
2019-01-07 18:47:04 +01:00
def _parse_cfg(cfg_buffer: typ.IO[str]) -> RawConfig:
2018-12-08 19:18:47 +01:00
cfg_parser = _ConfigParser()
2018-11-11 15:08:46 +01:00
if hasattr(cfg_parser, 'read_file'):
cfg_parser.read_file(cfg_buffer)
else:
cfg_parser.readfp(cfg_buffer) # python2 compat
2018-11-11 15:08:46 +01:00
if not cfg_parser.has_section("pycalver"):
2018-12-08 19:18:47 +01:00
raise ValueError("Missing [pycalver] section.")
2018-11-11 15:08:46 +01:00
2018-12-08 19:18:47 +01:00
raw_cfg: RawConfig = dict(cfg_parser.items("pycalver"))
2018-11-11 15:08:46 +01:00
2018-12-08 19:18:47 +01:00
for option, default_val in BOOL_OPTIONS.items():
val: OptionVal = raw_cfg.get(option, default_val)
2020-09-10 19:56:06 +00:00
if isinstance(val, (bytes, str)):
2018-12-08 19:18:47 +01:00
val = val.lower() in ("yes", "true", "1", "on")
raw_cfg[option] = val
2018-11-11 15:08:46 +01:00
2020-09-19 22:35:48 +00:00
raw_cfg['file_patterns'] = dict(_parse_cfg_file_patterns(cfg_parser))
2018-11-11 15:08:46 +01:00
2020-10-02 20:52:54 +00:00
_set_raw_config_defaults(raw_cfg)
return raw_cfg
2018-11-11 15:08:46 +01:00
2019-01-07 18:47:04 +01:00
def _parse_toml(cfg_buffer: typ.IO[str]) -> RawConfig:
2019-03-29 21:25:38 +01:00
raw_full_cfg: typ.Any = toml.load(cfg_buffer)
raw_cfg : RawConfig = raw_full_cfg.get('pycalver', {})
2018-12-08 19:18:47 +01:00
for option, default_val in BOOL_OPTIONS.items():
raw_cfg[option] = raw_cfg.get(option, default_val)
2020-10-02 20:52:54 +00:00
_set_raw_config_defaults(raw_cfg)
return raw_cfg
2020-09-19 22:35:48 +00:00
def _iter_glob_expanded_file_patterns(
raw_patterns_by_file: RawPatternsByFile,
) -> typ.Iterable[FileRawPatternsItem]:
for filepath_glob, raw_patterns in raw_patterns_by_file.items():
filepaths = glob.glob(filepath_glob)
if filepaths:
for filepath in filepaths:
yield filepath, raw_patterns
else:
logger.warning(f"Invalid config, no such file: {filepath_glob}")
# fallback to treating it as a simple path
yield filepath_glob, raw_patterns
def _compile_v1_file_patterns(raw_cfg: RawConfig) -> typ.Iterable[FilePatternsItem]:
"""Create inernal/compiled representation of the file_patterns config field.
2019-02-21 15:41:06 +01:00
The result the same, regardless of the config format.
"""
2020-09-19 22:35:48 +00:00
# current_version: str = raw_cfg['current_version']
# current_pep440_version = version.pep440_version(current_version)
2019-01-07 18:47:04 +01:00
2020-09-19 22:35:48 +00:00
version_pattern : str = raw_cfg['version_pattern']
raw_patterns_by_file: RawPatternsByFile = raw_cfg['file_patterns']
2020-09-19 22:35:48 +00:00
for filepath, raw_patterns in _iter_glob_expanded_file_patterns(raw_patterns_by_file):
2020-10-02 20:52:54 +00:00
compiled_patterns = v1patterns.compile_patterns(version_pattern, raw_patterns)
2020-09-19 22:35:48 +00:00
yield filepath, compiled_patterns
2020-09-19 22:35:48 +00:00
def _compile_v2_file_patterns(raw_cfg: RawConfig) -> typ.Iterable[FilePatternsItem]:
"""Create inernal/compiled representation of the file_patterns config field.
The result the same, regardless of the config format.
"""
version_pattern : str = raw_cfg['version_pattern']
raw_patterns_by_file: RawPatternsByFile = raw_cfg['file_patterns']
2020-09-19 22:35:48 +00:00
for filepath, raw_patterns in _iter_glob_expanded_file_patterns(raw_patterns_by_file):
2020-10-02 20:52:54 +00:00
compiled_patterns = v2patterns.compile_patterns(version_pattern, raw_patterns)
2020-09-19 22:35:48 +00:00
yield filepath, compiled_patterns
def _compile_file_patterns(raw_cfg: RawConfig, is_new_pattern: bool) -> PatternsByFile:
if is_new_pattern:
_file_pattern_items = _compile_v2_file_patterns(raw_cfg)
else:
_file_pattern_items = _compile_v1_file_patterns(raw_cfg)
# NOTE (mb 2020-10-03): There can be multiple items for the same
# path, so this is not an option:
#
# return dict(_file_pattern_items)
file_patterns: PatternsByFile = {}
for path, patterns in _file_pattern_items:
if path in file_patterns:
file_patterns[path].extend(patterns)
else:
file_patterns[path] = patterns
return file_patterns
2020-09-18 19:52:40 +00:00
def _validate_version_with_pattern(
current_version: str,
version_pattern: str,
is_new_pattern : bool,
) -> None:
"""Provoke ValueError if version_pattern and current_version are not compatible."""
if is_new_pattern:
v2version.parse_version_info(current_version, version_pattern)
else:
v1version.parse_version_info(current_version, version_pattern)
2020-09-18 19:52:40 +00:00
2020-09-24 11:16:02 +00:00
if is_new_pattern:
invalid_chars = re.search(r"([\s]+)", version_pattern)
2020-09-24 11:16:02 +00:00
if invalid_chars:
errmsg = (
2020-09-24 11:16:02 +00:00
f"Invalid character(s) '{invalid_chars.group(1)}'"
f' in pycalver.version_pattern = "{version_pattern}"'
2020-09-24 11:16:02 +00:00
)
raise ValueError(errmsg)
2020-10-02 23:02:02 +00:00
if not v2version.is_valid_week_pattern(version_pattern):
errmsg = f"Invalid week number pattern: {version_pattern}"
raise ValueError(errmsg)
2020-09-24 11:16:02 +00:00
2020-09-18 19:52:40 +00:00
def _parse_config(raw_cfg: RawConfig) -> Config:
"""Parse configuration which was loaded from an .ini/.cfg or .toml file."""
commit_message: str = raw_cfg.get('commit_message', DEFAULT_COMMIT_MESSAGE)
commit_message = raw_cfg['commit_message'] = commit_message.strip("'\" ")
current_version: str = raw_cfg['current_version']
current_version = raw_cfg['current_version'] = current_version.strip("'\" ")
version_pattern: str = raw_cfg['version_pattern']
version_pattern = raw_cfg['version_pattern'] = version_pattern.strip("'\" ")
is_new_pattern = "{" not in version_pattern and "}" not in version_pattern
_validate_version_with_pattern(current_version, version_pattern, is_new_pattern)
2020-09-19 22:35:48 +00:00
pep440_version = version.to_pep440(current_version)
file_patterns = _compile_file_patterns(raw_cfg, is_new_pattern)
commit = raw_cfg['commit']
tag = raw_cfg['tag']
push = raw_cfg['push']
if tag is None:
tag = raw_cfg['tag'] = False
if push is None:
push = raw_cfg['push'] = False
2018-11-11 15:08:46 +01:00
2018-11-11 15:15:14 +01:00
if tag and not commit:
raise ValueError("pycalver.commit = true required if pycalver.tag = true")
2018-11-11 15:15:14 +01:00
if push and not commit:
raise ValueError("pycalver.commit = true required if pycalver.push = true")
2018-11-11 15:08:46 +01:00
2019-01-07 17:30:02 +01:00
cfg = Config(
2020-09-19 22:35:48 +00:00
current_version=current_version,
2019-01-07 17:30:02 +01:00
version_pattern=version_pattern,
pep440_version=pep440_version,
2020-09-18 19:34:51 +00:00
commit_message=commit_message,
2019-01-07 17:30:02 +01:00
commit=commit,
tag=tag,
push=push,
2020-09-18 19:52:40 +00:00
is_new_pattern=is_new_pattern,
2019-01-07 17:30:02 +01:00
file_patterns=file_patterns,
)
2020-07-19 13:18:42 +00:00
logger.debug(_debug_str(cfg))
return cfg
2018-09-02 21:48:12 +02:00
2018-11-11 15:08:46 +01:00
2020-10-02 20:52:54 +00:00
def _parse_current_version_default_pattern(raw_cfg: RawConfig, raw_cfg_text: str) -> str:
is_pycalver_section = False
for line in raw_cfg_text.splitlines():
if is_pycalver_section and line.startswith("current_version"):
2020-09-19 22:35:48 +00:00
current_version: str = raw_cfg['current_version']
version_pattern: str = raw_cfg['version_pattern']
return line.replace(current_version, version_pattern)
2020-07-19 14:38:57 +00:00
if line.strip() == "[pycalver]":
is_pycalver_section = True
elif line and line[0] == "[" and line[-1] == "]":
is_pycalver_section = False
raise ValueError("Could not parse pycalver.current_version")
2020-10-02 20:52:54 +00:00
def _set_raw_config_defaults(raw_cfg: RawConfig) -> None:
2020-09-19 22:35:48 +00:00
if 'current_version' in raw_cfg:
if not isinstance(raw_cfg['current_version'], str):
err = f"Invalid type for pycalver.current_version = {raw_cfg['current_version']}"
raise TypeError(err)
else:
raise ValueError("Missing 'pycalver.current_version'")
if 'version_pattern' in raw_cfg:
if not isinstance(raw_cfg['version_pattern'], str):
err = f"Invalid type for pycalver.version_pattern = {raw_cfg['version_pattern']}"
raise TypeError(err)
else:
raw_cfg['version_pattern'] = "{pycalver}"
if 'file_patterns' not in raw_cfg:
raw_cfg['file_patterns'] = {}
2020-10-02 20:52:54 +00:00
def _parse_raw_config(ctx: ProjectContext) -> RawConfig:
with ctx.config_filepath.open(mode="rt", encoding="utf-8") as fobj:
if ctx.config_format == 'toml':
raw_cfg = _parse_toml(fobj)
elif ctx.config_format == 'cfg':
raw_cfg = _parse_cfg(fobj)
else:
err_msg = (
f"Invalid config_format='{ctx.config_format}'."
"Supported formats are 'setup.cfg' and 'pyproject.toml'"
)
raise RuntimeError(err_msg)
2020-09-19 22:35:48 +00:00
if ctx.config_rel_path not in raw_cfg['file_patterns']:
2020-10-02 20:52:54 +00:00
with ctx.config_filepath.open(mode="rt", encoding="utf-8") as fobj:
raw_cfg_text = fobj.read()
2020-10-04 13:02:42 +00:00
# NOTE (mb 2020-09-19): By default we always add
# a pattern for the config section itself.
2020-10-02 20:52:54 +00:00
raw_version_pattern = _parse_current_version_default_pattern(raw_cfg, raw_cfg_text)
2020-09-19 22:35:48 +00:00
raw_cfg['file_patterns'][ctx.config_rel_path] = [raw_version_pattern]
return raw_cfg
def parse(ctx: ProjectContext) -> MaybeConfig:
"""Parse config file if available."""
2020-09-24 11:16:02 +00:00
if ctx.config_filepath.exists():
try:
raw_cfg = _parse_raw_config(ctx)
return _parse_config(raw_cfg)
except (TypeError, ValueError) as ex:
logger.warning(f"Couldn't parse {ctx.config_rel_path}: {str(ex)}")
return None
else:
2020-09-19 22:35:48 +00:00
logger.warning(f"File not found: {ctx.config_rel_path}")
2018-09-03 22:23:51 +02:00
return None
2018-11-11 15:08:46 +01:00
2020-10-02 20:52:54 +00:00
def init(
project_path: typ.Union[str, pl.Path, None] = "."
) -> typ.Tuple[ProjectContext, MaybeConfig]:
ctx = init_project_ctx(project_path)
cfg = parse(ctx)
return (ctx, cfg)
2018-12-21 19:20:45 +01:00
DEFAULT_CONFIGPARSER_BASE_TMPL = """
2018-11-11 15:08:46 +01:00
[pycalver]
current_version = "{initial_version}"
2020-10-02 23:25:15 +00:00
version_pattern = "vYYYY0M.BUILD[-RELEASE]"
commit_message = "bump version {{old_version}} -> {{new_version}}"
2018-11-11 15:08:46 +01:00
commit = True
tag = True
push = True
2018-12-08 19:18:47 +01:00
[pycalver:file_patterns]
2019-02-16 10:39:33 +01:00
""".lstrip()
DEFAULT_CONFIGPARSER_SETUP_CFG_STR = """
setup.cfg =
2018-12-21 19:20:45 +01:00
current_version = "{version}"
2019-02-16 10:39:33 +01:00
""".lstrip()
2018-11-11 15:08:46 +01:00
DEFAULT_CONFIGPARSER_SETUP_PY_STR = """
setup.py =
"{version}"
"{pep440_version}"
2019-02-16 10:39:33 +01:00
""".lstrip()
DEFAULT_CONFIGPARSER_README_RST_STR = """
README.rst =
2018-12-21 19:20:45 +01:00
{version}
{pep440_version}
2019-02-16 10:39:33 +01:00
""".lstrip()
2018-11-11 15:08:46 +01:00
DEFAULT_CONFIGPARSER_README_MD_STR = """
README.md =
2018-12-21 19:20:45 +01:00
{version}
{pep440_version}
2019-02-16 10:39:33 +01:00
""".lstrip()
2018-11-11 15:08:46 +01:00
2018-12-21 19:20:45 +01:00
DEFAULT_TOML_BASE_TMPL = """
[pycalver]
current_version = "{initial_version}"
2020-10-02 23:25:15 +00:00
version_pattern = "vYYYY0M.BUILD[-RELEASE]"
commit_message = "bump version {{old_version}} -> {{new_version}}"
commit = true
tag = true
push = true
2018-12-08 19:18:47 +01:00
[pycalver.file_patterns]
2019-02-16 10:39:33 +01:00
""".lstrip()
DEFAULT_TOML_PYCALVER_STR = """
"pycalver.toml" = [
2018-12-21 19:20:45 +01:00
'current_version = "{version}"',
]
2019-02-16 10:39:33 +01:00
""".lstrip()
DEFAULT_TOML_PYPROJECT_STR = """
"pyproject.toml" = [
2018-12-21 19:20:45 +01:00
'current_version = "{version}"',
]
2019-02-16 10:39:33 +01:00
""".lstrip()
DEFAULT_TOML_SETUP_PY_STR = """
"setup.py" = [
"{version}",
"{pep440_version}",
]
2019-02-16 10:39:33 +01:00
""".lstrip()
DEFAULT_TOML_README_RST_STR = """
"README.rst" = [
"{version}",
"{pep440_version}",
]
2019-02-16 10:39:33 +01:00
""".lstrip()
2018-11-11 15:08:46 +01:00
DEFAULT_TOML_README_MD_STR = """
"README.md" = [
"{version}",
"{pep440_version}",
]
2019-02-16 10:39:33 +01:00
""".lstrip()
2018-09-03 22:23:51 +02:00
2018-12-21 19:20:45 +01:00
def _initial_version() -> str:
2020-09-19 22:35:48 +00:00
return dt.datetime.now().strftime("v%Y%m.1001-alpha")
2018-12-21 19:20:45 +01:00
def _initial_version_pep440() -> str:
2020-09-19 22:35:48 +00:00
return dt.datetime.now().strftime("%Y%m.1001a0")
2018-12-21 19:20:45 +01:00
def default_config(ctx: ProjectContext) -> str:
"""Generate initial default config."""
2018-12-08 19:18:47 +01:00
fmt = ctx.config_format
if fmt == 'cfg':
2018-12-21 19:20:45 +01:00
base_tmpl = DEFAULT_CONFIGPARSER_BASE_TMPL
default_pattern_strs_by_filename = {
"setup.cfg" : DEFAULT_CONFIGPARSER_SETUP_CFG_STR,
"setup.py" : DEFAULT_CONFIGPARSER_SETUP_PY_STR,
"README.rst": DEFAULT_CONFIGPARSER_README_RST_STR,
"README.md" : DEFAULT_CONFIGPARSER_README_MD_STR,
}
2018-12-08 19:18:47 +01:00
elif fmt == 'toml':
2018-12-21 19:20:45 +01:00
base_tmpl = DEFAULT_TOML_BASE_TMPL
default_pattern_strs_by_filename = {
"pyproject.toml": DEFAULT_TOML_PYPROJECT_STR,
"pycalver.toml" : DEFAULT_TOML_PYCALVER_STR,
"setup.py" : DEFAULT_TOML_SETUP_PY_STR,
"README.rst" : DEFAULT_TOML_README_RST_STR,
"README.md" : DEFAULT_TOML_README_MD_STR,
}
else:
2018-12-08 19:18:47 +01:00
raise ValueError(f"Invalid config_format='{fmt}', must be either 'toml' or 'cfg'.")
2018-12-21 19:20:45 +01:00
cfg_str = base_tmpl.format(initial_version=_initial_version())
2018-11-11 15:08:46 +01:00
for filename, default_str in default_pattern_strs_by_filename.items():
if (ctx.path / filename).exists():
cfg_str += default_str
2018-09-02 21:48:12 +02:00
2018-12-08 19:18:47 +01:00
has_config_file = any((ctx.path / fn).exists() for fn in SUPPORTED_CONFIGS)
2018-09-02 21:48:12 +02:00
if not has_config_file:
if ctx.config_format == 'cfg':
cfg_str += DEFAULT_CONFIGPARSER_SETUP_CFG_STR
if ctx.config_format == 'toml':
cfg_str += DEFAULT_TOML_PYCALVER_STR
2018-09-02 21:48:12 +02:00
cfg_str += "\n"
2018-11-11 15:08:46 +01:00
return cfg_str
2018-09-02 21:48:12 +02:00
2018-12-08 19:18:47 +01:00
def write_content(ctx: ProjectContext) -> None:
"""Update project config file with initial default config."""
2020-07-19 14:38:57 +00:00
fobj: typ.IO[str]
2019-01-07 18:47:04 +01:00
2018-12-21 19:20:45 +01:00
cfg_content = default_config(ctx)
if ctx.config_filepath.exists():
cfg_content = "\n" + cfg_content
2020-07-19 14:38:57 +00:00
with ctx.config_filepath.open(mode="at", encoding="utf-8") as fobj:
fobj.write(cfg_content)
2020-09-19 22:35:48 +00:00
print(f"Updated {ctx.config_rel_path}")