Skip to content

Commit 1f00ebf

Browse files
committed
Merge branch 'release/v3.6.12'
2 parents 0afa8ef + 074edba commit 1f00ebf

28 files changed

Lines changed: 2025 additions & 1260 deletions

docs/guide/changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ All notable changes to FoBiS.py are documented here.
44
Versions follow [Semantic Versioning](https://semver.org/).
55
Format follows [Keep a Changelog](https://keepachangelog.com/).
66

7+
## [3.6.12] — 2026-03-16
8+
### Changed
9+
- **cli**: Split monolithic cli_parser.py into per-command subpackage
10+
11+
712
## [3.6.11] — 2026-03-16
813
### Fixed
914
- **cliff**: Fix regex and catch-all parser silencing all git-cliff warnings

fobis/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""FoBiS.py main package"""
22

3-
__version__ = "3.6.11"
3+
__version__ = "3.6.12"
44
# Copyright (C) 2015 Stefano Zaghi
55
#
66
# This file is part of FoBiS.py.

fobis/cli/__init__.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""
2+
fobis.cli — FoBiS.py CLI sub-package.
3+
4+
This package owns the Typer application and all subcommand definitions.
5+
Symbols re-exported here preserve the public API that the rest of
6+
FoBiS.py (and user code) previously imported from ``fobis.cli_parser``.
7+
"""
8+
9+
# Copyright (C) 2015 Stefano Zaghi
10+
#
11+
# This file is part of FoBiS.py.
12+
#
13+
# FoBiS.py is free software: you can redistribute it and/or modify
14+
# it under the terms of the GNU General Public License as published by
15+
# the Free Software Foundation, either version 3 of the License, or
16+
# (at your option) any later version.
17+
#
18+
# FoBiS.py is distributed in the hope that it will be useful,
19+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
20+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21+
# GNU General Public License for more details.
22+
#
23+
# You should have received a copy of the GNU General Public License
24+
# along with FoBiS.py. If not, see <http://www.gnu.org/licenses/>.
25+
26+
from ._app import _normalize_args, app # noqa: F401
27+
from ._constants import ( # noqa: F401
28+
__compiler_supported__,
29+
__extensions_inc__,
30+
__extensions_modern__,
31+
__extensions_old__,
32+
__extensions_parsed__,
33+
)
34+
35+
# Import command modules to register their @app.command decorators
36+
from . import build, clean, doctests, fetch, install, rule # noqa: F401
37+
38+
__all__ = [
39+
"app",
40+
"_normalize_args",
41+
"__extensions_inc__",
42+
"__extensions_old__",
43+
"__extensions_modern__",
44+
"__extensions_parsed__",
45+
"__compiler_supported__",
46+
]

fobis/cli/_app.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
"""
2+
_app.py — Typer application instance, arg normaliser, and namespace factory.
3+
"""
4+
5+
# Copyright (C) 2015 Stefano Zaghi
6+
#
7+
# This file is part of FoBiS.py.
8+
#
9+
# FoBiS.py is free software: you can redistribute it and/or modify
10+
# it under the terms of the GNU General Public License as published by
11+
# the Free Software Foundation, either version 3 of the License, or
12+
# (at your option) any later version.
13+
#
14+
# FoBiS.py is distributed in the hope that it will be useful,
15+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
# GNU General Public License for more details.
18+
#
19+
# You should have received a copy of the GNU General Public License
20+
# along with FoBiS.py. If not, see <http://www.gnu.org/licenses/>.
21+
22+
import argparse
23+
import re
24+
25+
import typer
26+
from typing_extensions import Annotated
27+
28+
# ---------------------------------------------------------------------------
29+
# Argument normaliser — preserves backward compat with argparse-style options
30+
# ---------------------------------------------------------------------------
31+
_MULTI_CHAR_OPT = re.compile(r"^-[A-Za-z][A-Za-z0-9_-]+$")
32+
33+
34+
def _normalize_args(args):
35+
"""
36+
Normalise FoBiS legacy single-dash long options for Click/Typer.
37+
38+
Rules applied to each token:
39+
- Single-dash multi-char option (-compiler, -mode, -get_output_name)
40+
→ double-dash with underscores turned to hyphens (--compiler, --mode, --get-output-name)
41+
- Double-dash option with underscores (--build_dir, --cflags_heritage)
42+
→ double-dash with hyphens (--build-dir, --cflags-heritage)
43+
- Single-char short options (-f, -m, -q), values, and negative numbers
44+
are left unchanged.
45+
"""
46+
result = []
47+
for arg in args:
48+
if _MULTI_CHAR_OPT.match(arg):
49+
result.append("--" + arg[1:].replace("_", "-"))
50+
elif arg.startswith("--") and len(arg) > 2:
51+
if "=" in arg:
52+
opt, val = arg[2:].split("=", 1)
53+
result.append("--" + opt.replace("_", "-") + "=" + val)
54+
else:
55+
result.append("--" + arg[2:].replace("_", "-"))
56+
else:
57+
result.append(arg)
58+
return result
59+
60+
61+
# ---------------------------------------------------------------------------
62+
# Typer application
63+
# ---------------------------------------------------------------------------
64+
app = typer.Typer(
65+
name="FoBiS.py",
66+
help="a Fortran Building System",
67+
no_args_is_help=True,
68+
add_completion=True,
69+
rich_markup_mode=None,
70+
)
71+
72+
73+
def _version_callback(value: bool):
74+
if value:
75+
from .. import __version__
76+
from ..FoBiSConfig import __appname__
77+
78+
typer.echo(f"{__appname__} {__version__}")
79+
raise typer.Exit()
80+
81+
82+
@app.callback()
83+
def _app_callback(
84+
ctx: typer.Context,
85+
version: Annotated[
86+
bool,
87+
typer.Option(
88+
"--version",
89+
"-v",
90+
help="Show version and exit.",
91+
callback=_version_callback,
92+
is_eager=True,
93+
),
94+
] = False,
95+
):
96+
ctx.ensure_object(dict)
97+
98+
99+
# ---------------------------------------------------------------------------
100+
# Namespace factory
101+
# ---------------------------------------------------------------------------
102+
103+
104+
def _ns(**kwargs) -> argparse.Namespace:
105+
"""Build an argparse.Namespace — preserves the duck-type expected by all downstream code."""
106+
return argparse.Namespace(**kwargs)

fobis/cli/_completions.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
"""
2+
_completions.py — Typer autocompletion callbacks for FoBiS.py CLI.
3+
"""
4+
5+
# Copyright (C) 2015 Stefano Zaghi
6+
#
7+
# This file is part of FoBiS.py.
8+
#
9+
# FoBiS.py is free software: you can redistribute it and/or modify
10+
# it under the terms of the GNU General Public License as published by
11+
# the Free Software Foundation, either version 3 of the License, or
12+
# (at your option) any later version.
13+
#
14+
# FoBiS.py is distributed in the hope that it will be useful,
15+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
# GNU General Public License for more details.
18+
#
19+
# You should have received a copy of the GNU General Public License
20+
# along with FoBiS.py. If not, see <http://www.gnu.org/licenses/>.
21+
22+
import typer
23+
24+
from ._constants import __compiler_supported__, __extensions_parsed__
25+
26+
27+
def _complete_compiler(incomplete: str):
28+
return [c for c in __compiler_supported__ if c.startswith(incomplete.lower())]
29+
30+
31+
def _complete_mklib(incomplete: str):
32+
return [m for m in ("static", "shared") if m.startswith(incomplete)]
33+
34+
35+
def _complete_extensions(incomplete: str):
36+
return [e for e in __extensions_parsed__ if e.startswith(incomplete)]
37+
38+
39+
def _complete_doctests_preprocessor(incomplete: str):
40+
return [p for p in ("cpp", "fpp") if p.startswith(incomplete)]
41+
42+
43+
def _complete_fobos_mode(ctx: typer.Context, incomplete: str):
44+
import configparser
45+
import os
46+
47+
fobos_path = ctx.params.get("fobos") or "fobos"
48+
if not os.path.exists(fobos_path):
49+
return []
50+
cp = configparser.RawConfigParser()
51+
cp.read(fobos_path)
52+
if cp.has_option("modes", "modes"):
53+
modes = [m.strip() for m in cp.get("modes", "modes").split()]
54+
return [m for m in modes if m.startswith(incomplete)]
55+
return [
56+
s for s in cp.sections() if s.startswith(incomplete) and s not in ("modes", "rules", "dependencies", "project")
57+
]

fobis/cli/_constants.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"""
2+
_constants.py — file extension and compiler constants for FoBiS.py CLI.
3+
4+
These constants are re-exported from the top-level cli_parser module for
5+
backward compatibility.
6+
"""
7+
8+
# Copyright (C) 2015 Stefano Zaghi
9+
#
10+
# This file is part of FoBiS.py.
11+
#
12+
# FoBiS.py is free software: you can redistribute it and/or modify
13+
# it under the terms of the GNU General Public License as published by
14+
# the Free Software Foundation, either version 3 of the License, or
15+
# (at your option) any later version.
16+
#
17+
# FoBiS.py is distributed in the hope that it will be useful,
18+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
19+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+
# GNU General Public License for more details.
21+
#
22+
# You should have received a copy of the GNU General Public License
23+
# along with FoBiS.py. If not, see <http://www.gnu.org/licenses/>.
24+
25+
__extensions_inc__ = [".inc", ".INC", ".h", ".H"]
26+
__extensions_old__ = [".f", ".F", ".for", ".FOR", ".fpp", ".FPP", ".fortran", ".f77", ".F77"]
27+
__extensions_modern__ = [".f90", ".F90", ".f95", ".F95", ".f03", ".F03", ".f08", ".F08", ".f2k", ".F2K"]
28+
__extensions_parsed__ = __extensions_inc__ + __extensions_old__ + __extensions_modern__
29+
__compiler_supported__ = (
30+
"gnu",
31+
"intel",
32+
"intel_nextgen",
33+
"g95",
34+
"opencoarrays-gnu",
35+
"pgi",
36+
"ibm",
37+
"nag",
38+
"nvfortran",
39+
"amd",
40+
"custom",
41+
)

0 commit comments

Comments
 (0)