diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 75c7b43d4b6..4a0eef2e97b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -230,23 +230,7 @@ jobs: if: runner.os == 'Linux' working-directory: usgslatex/usgsLaTeX run: sudo ./install.sh --all-users - - - name: Install dependencies for ex-gwf-twri example model - if: runner.os == 'Linux' - working-directory: modflow6-examples/etc - run: | - # install extra Python packages - pip install -r requirements.pip.txt - - # the example model needs executables to be on the path - echo "${{ github.workspace }}/modflow6/bin" >> $GITHUB_PATH - echo "${{ github.workspace }}/modflow6/bin/downloaded" >> $GITHUB_PATH - - - name: Build ex-gwf-twri example model - if: runner.os == 'Linux' - working-directory: modflow6-examples/scripts - run: python ex-gwf-twri.py - + - name: Test distribution scripts working-directory: modflow6/distribution env: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1973766a474..d5c43a44ee7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -212,21 +212,16 @@ jobs: working-directory: usgslatex/usgsLaTeX run: sudo ./install.sh --all-users - - name: Install dependencies for ex-gwf-twri example model - if: ${{ runner.os == 'Linux' && inputs.run_tests == true }} - working-directory: modflow6-examples/etc - run: | - # install extra Python packages - pip install -r requirements.pip.txt - - # the example model needs executables to be on the path - echo "${{ github.workspace }}/modflow6/bin" >> $GITHUB_PATH - echo "${{ github.workspace }}/modflow6/bin/downloaded" >> $GITHUB_PATH + # - name: Install dependencies for ex-gwf-twri example model + # if: ${{ runner.os == 'Linux' && inputs.run_tests == true }} + # working-directory: modflow6-examples/etc + # run: | + # # install extra Python packages + # pip install -r requirements.pip.txt - - name: Build ex-gwf-twri example model - if: ${{ runner.os == 'Linux' && inputs.run_tests == true }} - working-directory: modflow6-examples/scripts - run: python ex-gwf-twri.py + # # the example model needs executables to be on the path + # echo "${{ github.workspace }}/modflow6/bin" >> $GITHUB_PATH + # echo "${{ github.workspace }}/modflow6/bin/downloaded" >> $GITHUB_PATH - name: Test distribution scripts if: ${{ inputs.run_tests == true }} @@ -300,6 +295,10 @@ jobs: fi eval "$cmd" + - name: Update FloPy classes + working-directory: modflow6/autotest + run: python update_flopy.py + - name: Download pre-built binaries uses: actions/download-artifact@v3 with: @@ -307,6 +306,7 @@ jobs: path: bin - name: Install dependencies for building models + if: inputs.full == true working-directory: modflow6-examples/etc env: GITHUB_TOKEN: ${{ github.token }} @@ -324,15 +324,6 @@ jobs: # the example model also needs mf2005 get-modflow "${{ github.workspace }}/bin" --subset mf2005,triangle,gridgen - - - name: Update FloPy - working-directory: modflow6/autotest - run: python update_flopy.py - - - name: Build ex-gwf-twri example model - if: inputs.full != true - working-directory: modflow6-examples/scripts - run: python ex-gwf-twri.py - name: Build example models if: inputs.full == true @@ -365,7 +356,7 @@ jobs: GITHUB_TOKEN: ${{ github.token }} run: | mkdir -p "${{ needs.build.outputs.distname }}/doc" - cmd="python modflow6/distribution/build_docs.py -b bin -o doc -e modflow6-examples" + cmd="python modflow6/distribution/build_docs.py -b bin -o doc" if [[ "${{ inputs.full }}" == "true" ]]; then cmd="$cmd --full" fi diff --git a/CITATION.cff b/CITATION.cff index 184ea7a5b8f..2b38284daa0 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -2,8 +2,8 @@ cff-version: 1.2.0 message: If you use this software, please cite the software itself. type: software title: MODFLOW 6 Modular Hydrologic Model -version: 6.4.2+ -date-released: '2023-06-29' +version: 6.5.0.dev0 +date-released: '2023-07-13' doi: 10.5066/F76Q1VQV abstract: MODFLOW 6 is an object-oriented program and framework developed to provide a platform for supporting multiple models and multiple types of models within the diff --git a/README.md b/README.md index 54452bc60ab..ee60e3696c7 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ This is the development repository for the USGS MODFLOW 6 Hydrologic Model. The official USGS distribution is available at [USGS Release Page](https://water.usgs.gov/ogw/modflow/MODFLOW.html). -### Version 6.4.2+ (preliminary) +### Version 6.5.0.dev0 (preliminary) [![GitHub release](https://img.shields.io/github/release/MODFLOW-USGS/modflow6.svg)](https://github.com/MODFLOW-USGS/modflow6/releases/latest) [![MODFLOW 6 continuous integration](https://github.com/MODFLOW-USGS/modflow6/actions/workflows/ci.yml/badge.svg)](https://github.com/MODFLOW-USGS/modflow6/actions/workflows/ci.yml) diff --git a/autotest/test_cli.py b/autotest/test_cli.py index aa9185ceb46..6aa73052988 100644 --- a/autotest/test_cli.py +++ b/autotest/test_cli.py @@ -1,4 +1,3 @@ -import re import subprocess from conftest import project_root_path @@ -6,11 +5,6 @@ bin_path = project_root_path / "bin" -def split_nonnumeric(s): - match = re.compile("[^0-9]").search(s) - return [s[:match.start()], s[match.start():]] if match else s - - def test_cli_version(): output = " ".join( subprocess.check_output([str(bin_path / "mf6"), "-v"]).decode().split() @@ -23,7 +17,5 @@ def test_cli_version(): ) print(version) v_split = version.split(".") - assert len(v_split) == 3 - assert all(s.isdigit() for s in v_split[:2]) - sol = split_nonnumeric(v_split[2]) - assert sol[0].isdigit() + assert len(v_split) >= 2 + assert all(s[-1].isdigit() for s in v_split[:2]) diff --git a/code.json b/code.json index ed1b27fb668..0a579a5b6e2 100644 --- a/code.json +++ b/code.json @@ -18,9 +18,9 @@ "email": "langevin@usgs.gov" }, "laborHours": -1, - "version": "6.4.2+", + "version": "6.5.0.dev0", "date": { - "metadataLastUpdated": "2023-06-29" + "metadataLastUpdated": "2023-07-13" }, "organization": "U.S. Geological Survey", "permissions": { diff --git a/distribution/build_dist.py b/distribution/build_dist.py index f60b76302c6..68c454ec650 100644 --- a/distribution/build_dist.py +++ b/distribution/build_dist.py @@ -4,7 +4,6 @@ import shutil import sys import textwrap -from collections import namedtuple from os import PathLike, environ from pathlib import Path from pprint import pprint @@ -17,56 +16,16 @@ from modflow_devtools.misc import get_model_paths from build_docs import build_documentation -from build_makefiles import ( - build_mf6_makefile, - build_mf5to6_makefile, - build_zbud6_makefile, -) +from build_makefiles import (build_mf5to6_makefile, build_mf6_makefile, + build_zbud6_makefile) from utils import get_project_root_path, run_command -_project_name = "MODFLOW 6" - # default paths _project_root_path = get_project_root_path() -_version_texf_path = _project_root_path / "doc" / "version.tex" _examples_repo_path = _project_root_path.parent / "modflow6-examples" -_examples_path = _examples_repo_path / "examples" _build_path = _project_root_path / "builddir" -_bin_path = _project_root_path / "bin" -_docs_path = _project_root_path / "doc" -_benchmarks_path = _project_root_path / "distribution" / ".benchmarks" - -# top-level directories included in distribution -_included_dir_paths = [ - "bin", - "doc", - "examples", - "src", - "srcbmi", - "msvs", - "make", - "utils", -] - -Makefile = namedtuple("Makefile", ["app", "src_path", "out_path"]) - - -# makefiles included in distribution -_makefiles = [ - Makefile(app="mf6", src_path=_project_root_path / "src", out_path=Path("make")), - Makefile( - app="zbud6", - src_path=_project_root_path / "utils" / "zonebudget" / "src", - out_path=Path("utils") / "zonebudget" / "make", - ), - Makefile( - app="mf5to6", - src_path=_project_root_path / "utils" / "mf5to6" / "src", - out_path=Path("utils") / "mf5to6" / "make", - ), -] - -# system-specific filenames, extensions, etc + +# OS-specific extensions _system = platform.system() _eext = ".exe" if _system == "Windows" else "" _soext = ".dll" if _system == "Windows" else ".so" if _system == "Linux" else ".dylib" @@ -99,8 +58,9 @@ def copy_sources(output_path: PathLike): ignored = shutil.ignore_patterns(".DS_Store") - # copy top-level meson.build + # copy top-level meson.build and meson.options shutil.copy(_project_root_path / "meson.build", output_path) + shutil.copy(_project_root_path / "meson.options", output_path) # copy source folder src_path = _project_root_path / "src" @@ -232,10 +192,6 @@ def setup_examples( print(f"Execute permission set for {script_path}") -def test_setup_examples(): - pass - - def build_programs_meson( build_path: PathLike, bin_path: PathLike, overwrite: bool = False ): @@ -446,13 +402,6 @@ def test_build_distribution(tmp_path, full): default=str(_examples_repo_path), help="Path to directory containing modflow6 example models", ) - # parser.add_argument( - # "-b", - # "--benchmarks-path", - # required=False, - # default=str(_project_root_path / "distribution" / ".benchmarks"), - # help="Path to directory containing benchmark results" - # ) parser.add_argument( "--full", required=False, @@ -469,7 +418,6 @@ def test_build_distribution(tmp_path, full): help="Recreate and overwrite existing artifacts", ) args = parser.parse_args() - build_path = Path(args.build_path) out_path = Path(args.output_path) examples_repo_path = ( diff --git a/distribution/build_docs.py b/distribution/build_docs.py index efc4c8bbc0c..37d5ad57fa6 100644 --- a/distribution/build_docs.py +++ b/distribution/build_docs.py @@ -5,7 +5,7 @@ import sys import textwrap from datetime import datetime -from os import PathLike +from os import PathLike, environ from pathlib import Path from pprint import pprint from tempfile import TemporaryDirectory @@ -16,19 +16,15 @@ import pytest from flaky import flaky from modflow_devtools.build import meson_build -from modflow_devtools.download import ( - list_artifacts, - download_artifact, - get_release, - download_and_unzip, -) +from modflow_devtools.download import (download_and_unzip, download_artifact, + get_release, list_artifacts) from modflow_devtools.markers import requires_exe, requires_github -from modflow_devtools.misc import set_dir, run_cmd, is_in_ci +from modflow_devtools.misc import is_in_ci, run_cmd, set_dir from benchmark import run_benchmarks -from utils import convert_line_endings -from utils import get_project_root_path +from utils import convert_line_endings, get_project_root_path +# paths _project_root_path = get_project_root_path() _bin_path = _project_root_path / "bin" _examples_repo_path = _project_root_path.parent / "modflow6-examples" @@ -47,12 +43,13 @@ _docs_path / "ConverterGuide" / "converter_mf5to6.tex", _docs_path / "SuppTechInfo" / "mf6suptechinfo.tex", ] + +# OS-specific extensions _system = platform.system() _eext = ".exe" if _system == "Windows" else "" _soext = ".dll" if _system == "Windows" else ".so" if _system == "Linux" else ".dylib" - -# publications included in distribution docs +# publications included in full dist docs _publication_urls = [ "https://pubs.usgs.gov/tm/06/a55/tm6a55.pdf", "https://pubs.usgs.gov/tm/06/a56/tm6a56.pdf", @@ -103,10 +100,12 @@ def clean_tex_files(): assert not os.path.isfile(str(pth) + ".pdf") -def download_benchmarks(output_path: PathLike, verbose: bool = False) -> Optional[Path]: +def download_benchmarks( + output_path: PathLike, verbose: bool = False, repo_owner: str = "MODFLOW-USGS" +) -> Optional[Path]: output_path = Path(output_path).expanduser().absolute() name = "run-time-comparison" # todo make configurable - repo = "MODFLOW-USGS/modflow6" # todo make configurable, add pytest/cli args + repo = f"{repo_owner}/modflow6" # todo make configurable, add pytest/cli args artifacts = list_artifacts(repo, name=name, verbose=verbose) artifacts = sorted( artifacts, @@ -127,21 +126,32 @@ def download_benchmarks(output_path: PathLike, verbose: bool = False) -> Optiona return None +@pytest.fixture +def github_user() -> Optional[str]: + return environ.get("GITHUB_USER", None) + + @flaky @requires_github -def test_download_benchmarks(tmp_path): - path = download_benchmarks(tmp_path, verbose=True) +def test_download_benchmarks(tmp_path, github_user): + path = download_benchmarks( + tmp_path, + verbose=True, + repo_owner=github_user if github_user else "MODFLOW-USGS", + ) if path: assert path.name == "run-time-comparison.md" -def build_benchmark_tex(output_path: PathLike, overwrite: bool = False): +def build_benchmark_tex( + output_path: PathLike, overwrite: bool = False, repo_owner: str = "MODFLOW-USGS" +): _benchmarks_path.mkdir(parents=True, exist_ok=True) benchmarks_path = _benchmarks_path / "run-time-comparison.md" # download benchmark artifacts if any exist on GitHub if not benchmarks_path.is_file(): - benchmarks_path = download_benchmarks(_benchmarks_path) + benchmarks_path = download_benchmarks(_benchmarks_path, repo_owner=repo_owner) # run benchmarks again if no benchmarks found on GitHub or overwrite requested if overwrite or not benchmarks_path.is_file(): @@ -426,19 +436,15 @@ def test_build_pdfs_from_tex(tmp_path): def build_documentation( bin_path: PathLike, - output_path: PathLike, - examples_repo_path: PathLike, - # Example to use to render sample mf6 output in the docs. - # Must be a valid directory in modflow6-examples/examples - example_for_sample: str = "ex-gwf-twri01", full: bool = False, + output_path: Optional[PathLike] = None, overwrite: bool = False, + repo_owner: str = "MODFLOW-USGS", ): - print(f"Building {'full' if full else 'full'} documentation") + print(f"Building {'full' if full else 'minimal'} documentation") bin_path = Path(bin_path).expanduser().absolute() output_path = Path(output_path).expanduser().absolute() - examples_repo_path = Path(examples_repo_path).expanduser().absolute() # make sure output directory exists output_path.mkdir(parents=True, exist_ok=True) @@ -448,11 +454,11 @@ def build_documentation( # build LaTeX input/output example model docs with TemporaryDirectory() as temp: - temp_path = Path(temp) + example_path = _project_root_path / ".mf6minsim" build_mf6io_tex_example( - workspace_path=temp_path, + workspace_path=Path(temp), bin_path=bin_path, - example_model_path=examples_repo_path / "examples" / example_for_sample, + example_model_path=example_path, ) # build LaTeX file describing distribution folder structure @@ -463,10 +469,12 @@ def build_documentation( build_pdfs_from_tex(tex_paths=_dev_dist_tex_paths, output_path=output_path) else: # convert benchmarks to LaTex, running them first if necessary - build_benchmark_tex(output_path=output_path, overwrite=overwrite) + build_benchmark_tex( + output_path=output_path, overwrite=overwrite, repo_owner=repo_owner + ) # download example docs - latest = get_release("MODFLOW-USGS/modflow6-examples", "latest") + latest = get_release(f"{repo_owner}/modflow6-examples", "latest") assets = latest["assets"] asset = next(iter([a for a in assets if a["name"] == "mf6examples.pdf"]), None) download_and_unzip(asset["browser_download_url"], output_path, verbose=True) @@ -529,13 +537,6 @@ def test_build_documentation(tmp_path): """ ), ) - parser.add_argument( - "-t", - "--tex-path", - action="append", - required=False, - help="Extra LaTeX files to include", - ) parser.add_argument( "-b", "--bin-path", @@ -544,18 +545,19 @@ def test_build_documentation(tmp_path): help="Location of modflow6 executables", ) parser.add_argument( - "-e", - "--examples-repo-path", + "-f", + "--force", required=False, - default=str(_examples_repo_path), - help="Path to directory containing modflow6 example models", + default=False, + action="store_true", + help="Recreate and overwrite existing artifacts", ) parser.add_argument( - "-s", - "--example-for-sample", + "--full", required=False, - default="ex-gwf-twri01", - help="Name of example model to use for sample mf6 output", + default=False, + action="store_true", + help="Build docs for a full rather than minimal distribution", ) parser.add_argument( "-o", @@ -565,35 +567,19 @@ def test_build_documentation(tmp_path): help="Location to create documentation artifacts", ) parser.add_argument( - "--full", - required=False, - default=False, - action="store_true", - help="Build docs for a full rather than minimal distribution", - ) - parser.add_argument( - "-f", - "--force", + "--repo-owner", required=False, - default=False, - action="store_true", - help="Recreate and overwrite existing artifacts", + default="MODFLOW-USGS", + help="Repository owner (substitute your own for a fork)", ) args = parser.parse_args() - tex_paths = _full_dist_tex_paths + ( - [Path(p) for p in args.tex_path] if args.tex_path else [] - ) output_path = Path(args.output_path).expanduser().absolute() output_path.mkdir(parents=True, exist_ok=True) bin_path = Path(args.bin_path).expanduser().absolute() - examples_repo_path = Path(args.examples_repo_path).expanduser().absolute() - example_for_sample = args.example_for_sample - build_documentation( bin_path=bin_path, - output_path=output_path, - examples_repo_path=examples_repo_path, - example_for_sample=example_for_sample, full=args.full, + output_path=output_path, overwrite=args.force, + repo_owner=args.repo_owner, ) diff --git a/distribution/build_makefiles.py b/distribution/build_makefiles.py index ce441200775..e9fb09645db 100644 --- a/distribution/build_makefiles.py +++ b/distribution/build_makefiles.py @@ -6,8 +6,8 @@ import pymake import pytest from flaky import flaky -from modflow_devtools.misc import set_dir from modflow_devtools.markers import requires_exe +from modflow_devtools.misc import set_dir from utils import get_modified_time, get_project_root_path diff --git a/distribution/check_dist.py b/distribution/check_dist.py index 27be7d087bd..0ee03e974b5 100644 --- a/distribution/check_dist.py +++ b/distribution/check_dist.py @@ -1,5 +1,4 @@ import platform -import re import subprocess from os import environ from pathlib import Path @@ -9,12 +8,33 @@ from utils import split_nonnumeric +# OS-specific extensions _system = platform.system() _eext = ".exe" if _system == "Windows" else "" _soext = ".dll" if _system == "Windows" else ".so" if _system == "Linux" else ".dylib" _scext = ".bat" if _system == "Windows" else ".sh" + +# fortran compiler _fc = environ.get("FC", None) +# directories included in full distribution +_included_dir_paths = { + "full": [ + "bin", + "doc", + "examples", + "src", + "srcbmi", + "msvs", + "make", + "utils", + ], + "minimal": [ + "bin", + "src", + ], +} + @pytest.fixture def approved(request): @@ -47,7 +67,12 @@ def skip(): return path -def test_sources(dist_dir_path, approved, releasemode, full): +def test_directories(dist_dir_path, full): + for dir_path in _included_dir_paths["full" if full else "minimal"]: + assert (dist_dir_path / dir_path).is_dir() + + +def test_sources(dist_dir_path, releasemode, full): if not full: pytest.skip(reason="sources not included in minimal distribution") @@ -142,13 +167,13 @@ def test_examples(dist_dir_path, full): print(f"{len(example_paths)} example models found:") pprint(example_paths) for p in example_paths: - pprint( - subprocess.check_output([str(p / f"run{_scext}")], cwd=p).decode().split() - ) + script_path = p / f"run{_scext}" + if not script_path.is_file(): + continue + pprint(subprocess.check_output([str(script_path)], cwd=p).decode().split()) break - def test_binaries(dist_dir_path, approved): bin_path = dist_dir_path / "bin" assert (bin_path / f"mf6{_eext}").is_file() diff --git a/distribution/conftest.py b/distribution/conftest.py index 860ef1d585b..df18401b2a4 100644 --- a/distribution/conftest.py +++ b/distribution/conftest.py @@ -1,11 +1,11 @@ from pathlib import Path -from update_version import Version +from packaging.version import Version _project_root_path = Path(__file__).resolve().parent.parent _dist_dir_path = ( _project_root_path.parent - / f"mf{str(Version.from_file(_project_root_path / 'version.txt'))}" + / f"mf{str(Version((_project_root_path / 'version.txt').read_text().strip()))}" ) diff --git a/distribution/update_version.py b/distribution/update_version.py index f1112c58761..e09e0c69aef 100755 --- a/distribution/update_version.py +++ b/distribution/update_version.py @@ -31,20 +31,18 @@ import argparse import json import os -import re -import shutil import textwrap from collections import OrderedDict from datetime import datetime -from os import PathLike +from packaging.version import Version from pathlib import Path -from typing import NamedTuple, Optional +from typing import Optional import pytest from filelock import FileLock import yaml -from utils import get_modified_time, split_nonnumeric +from utils import get_modified_time project_name = "MODFLOW 6" project_root_path = Path(__file__).resolve().parent.parent @@ -62,56 +60,6 @@ ] -class Version(NamedTuple): - """Semantic version number, optionally with a short label (e.g, 'rc'). - The label may contain numbers but must begin with a letter.""" - - major: int = 0 - minor: int = 0 - patch: int = 0 - label: Optional[str] = None - - def __repr__(self): - s = f"{self.major}.{self.minor}.{self.patch}" - if self.label is not None and self.label != "": - s += self.label - return s - - @classmethod - def from_string(cls, version: str) -> "Version": - t = version.split(".") - assert len(t) > 2 - vmajor = int(t[0]) - vminor = int(t[1]) - tt = split_nonnumeric(t[2]) - vpatch = int(tt[0]) - vlabel = tt[1] if len(tt) > 1 else None - return cls(major=vmajor, minor=vminor, patch=vpatch, label=vlabel) - - @classmethod - def from_file(cls, path: PathLike) -> "Version": - path = Path(path).expanduser().absolute() - lines = [line.rstrip("\n") for line in open(Path(path), "r")] - vmajor = vminor = vpatch = vlabel = None - for line in lines: - t = line.split() - if "major =" in line: - vmajor = int(t[2]) - elif "minor =" in line: - vminor = int(t[2]) - elif "micro =" in line: - vpatch = int(t[2]) - elif "label =" in line: - vlabel = t[2].replace("'", "") - - msg = "version string must follow semantic version format, with optional label: major.minor.patch[label]" - missing = lambda v: f"Missing {v} number, {msg}" - assert vmajor is not None, missing("major") - assert vminor is not None, missing("minor") - assert vpatch is not None, missing("patch") - return cls(major=vmajor, minor=vminor, patch=vpatch, label=vlabel) - - _approved_fmtdisclaimer = ''' character(len=*), parameter :: FMTDISCLAIMER = & "(/,& &'This software has been approved for release by the U.S. Geological ',/,& @@ -181,25 +129,17 @@ def log_update(path, version: Version): def update_version_txt_and_py(version: Version, timestamp: datetime): with open(version_file_path, "w") as f: + f.write(str(version)) + log_update(version_file_path, version) + + py_path = project_root_path / "doc" / version_file_path.name.replace(".txt", ".py") + with open(py_path, "w") as f: f.write( f"# {project_name} version file automatically " + f"created using...{os.path.basename(__file__)}\n" ) f.write("# created on..." + f"{timestamp.strftime('%B %d, %Y %H:%M:%S')}\n") - f.write("\n") - f.write(f"major = {version.major}\n") - f.write(f"minor = {version.minor}\n") - f.write(f"micro = {version.patch}\n") - f.write( - "label = " + (("'" + version.label + "'") if version.label else "''") + "\n" - ) - f.write("__version__ = '{:d}.{:d}.{:d}'.format(major, minor, micro)\n") - f.write("if label:\n") - f.write("\t__version__ += '{}{}'.format(__version__, label)") - f.close() - log_update(version_file_path, version) - py_path = project_root_path / "doc" / version_file_path.name.replace(".txt", ".py") - shutil.copyfile(version_file_path, py_path) + f.write(f'__version__ = "{version}"\n') log_update(py_path, version) @@ -209,7 +149,7 @@ def update_meson_build(version: Version): with open(path, "w") as f: for line in lines: if "version:" in line and "meson_version:" not in line: - line = f" version: '{version.major}.{version.minor}.{version.patch}{version.label if version.label else ''}'," + line = f" version: '{version}'," f.write(f"{line}\n") log_update(path, version) @@ -217,7 +157,7 @@ def update_meson_build(version: Version): def update_version_tex(version: Version, timestamp: datetime): path = project_root_path / "doc" / "version.tex" with open(path, "w") as f: - line = "\\newcommand{\\modflowversion}{mf" + f"{str(version)}" + "}" + line = "\\newcommand{\\modflowversion}{mf" + str(version) + "}" f.write(f"{line}\n") line = ( "\\newcommand{\\modflowdate}{" + f"{timestamp.strftime('%B %d, %Y')}" + "}" @@ -351,11 +291,11 @@ def update_version( lock_path = Path(version_file_path.name + ".lock") try: lock = FileLock(lock_path) - previous = Version.from_file(version_file_path) + previous = Version(version_file_path.read_text().strip()) version = ( version if version - else Version(previous.major, previous.minor, previous.patch) + else previous ) with lock: @@ -370,8 +310,8 @@ def update_version( lock_path.unlink(missing_ok=True) -_initial_version = Version(0, 0, 1) -_current_version = Version.from_file(version_file_path) +_initial_version = Version("0.0.1") +_current_version = Version(version_file_path.read_text().strip()) @pytest.mark.skip(reason="reverts repo files on cleanup, tread carefully") @@ -379,17 +319,8 @@ def update_version( "version", [ None, - Version( - major=_initial_version.major, - minor=_initial_version.minor, - patch=_initial_version.patch, - ), - Version( - major=_initial_version.major, - minor=_initial_version.minor, - patch=_initial_version.patch, - label="rc", - ), + _initial_version, + Version(f"{_initial_version.major}.{_initial_version.minor}.dev{_initial_version.micro}"), ], ) @pytest.mark.parametrize("approved", [True, False]) @@ -405,7 +336,7 @@ def test_update_version(version, approved, developmode): approved=approved, developmode=developmode, ) - updated = Version.from_file(version_file_path) + updated = Version(version_file_path.read_text().strip()) # check files containing version info were modified for p, t in zip(touched_file_paths, m_times): @@ -414,20 +345,10 @@ def test_update_version(version, approved, developmode): # check version number and optional label are correct if version: # version should be auto-incremented - assert updated.major == _initial_version.major - assert updated.minor == _initial_version.minor - assert updated.patch == _initial_version.patch - if version.label is not None: - assert updated.label == version.label + assert updated == _initial_version else: # version should not have changed - assert updated.major == _current_version.major - assert updated.minor == _current_version.minor - assert updated.patch == _current_version.patch - if version.label is not None: - assert updated.label == version.label - if version.label is not None: - assert updated.label == _initial_version + assert updated == _current_version # check IDEVELOPMODE was set correctly version_f90_path = project_root_path / "src" / "Utilities" / "version.f90" @@ -462,13 +383,10 @@ def test_update_version(version, approved, developmode): provided, the version number will not be changed. A file lock is held to synchronize file access. To indicate a version is production-ready use --approve. This will change the disclaimer and version tag label, - removing 'Release Candidate' from the latter and modifying the former - to reflect approval The IDEVELOPMODE flag is set to 1 for preliminary - versions and 0 for approved versions. The version tag must follow the + removing '(preliminary)' from the latter, and modifying the former to + reflect approval The --releasemode flag controls whether IDEVELOPMODE + is set to 0 instead of the default 1. The version tag must follow the '..' format conventions for semantic versioning. - If --version is provided, --bump-patch, --bump-minor and --bump-major - may not be provided. Likewise, if any of the latter are provided, the - version number must not be specified. """ ), ) @@ -492,24 +410,6 @@ def test_update_version(version, approved, developmode): action="store_true", help="Set IDEVELOPMODE to 0 for release mode (defaults to false for development distributions)", ) - parser.add_argument( - "--bump-major", - required=False, - action="store_true", - help="Increment the major version number (cannot be used with --version, defaults to false)", - ) - parser.add_argument( - "--bump-minor", - required=False, - action="store_true", - help="Increment the minor version number (cannot be used with --version, defaults to false)", - ) - parser.add_argument( - "--bump-patch", - required=False, - action="store_true", - help="Increment the patch version number (cannot be used with --version, defaults to false)", - ) parser.add_argument( "-g", "--get", @@ -518,33 +418,13 @@ def test_update_version(version, approved, developmode): help="Get the current version number, don't update anything (defaults to false)", ) args = parser.parse_args() - - if args.version and (args.bump_major or args.bump_minor or args.bump_patch): - raise ValueError(f"Cannot specify --version and --bump-*, use one or the other") - - bump_flags = [b for b in [args.bump_major, args.bump_minor, args.bump_patch] if b] - if len(bump_flags) > 1: - raise ValueError(f"Cannot specify more than one --bump-* flag, use just one") - if args.get: - print(Version.from_file(project_root_path / "version.txt")) + print(Version((project_root_path / "version.txt").read_text().strip())) else: - if not args.version and not any(bump_flags): - version = _current_version - elif args.version: - version = Version.from_string(args.version) - else: - current = Version.from_file(project_root_path / "version.txt") - if args.bump_major: - print(f"Incrementing major number") - version = Version(current.major + 1, 0, 0) - elif args.bump_minor: - print(f"Incrementing minor number") - version = Version(current.major, current.minor + 1, 0) - else: - print(f"Incrementing patch number") - version = Version(current.major, current.minor, current.patch + 1) - + print(f"Updating to version {args.version} with options") + print(f" releasemode: {args.releasemode}") + print(f" approved: {args.approved}") + version = Version(args.version) if args.version else _current_version update_version( version=version, timestamp=datetime.now(), diff --git a/doc/ReleaseNotes/ReleaseNotes.tex b/doc/ReleaseNotes/ReleaseNotes.tex index 26fbf93e8d8..2655e9d014d 100644 --- a/doc/ReleaseNotes/ReleaseNotes.tex +++ b/doc/ReleaseNotes/ReleaseNotes.tex @@ -189,7 +189,7 @@ \section{Changes Introduced in this Release} This section describes changes introduced into MODFLOW~6 for the current release. These changes may substantially affect users. \begin{itemize} -\input{v6.4.2.tex} +\input{develop.tex} \end{itemize} % ------------------------------------------------- @@ -232,32 +232,34 @@ \section{Known Issues and Incompatibilities} % ------------------------------------------------- \section{Distribution File} -The following distribution file is for use on personal computers: \texttt{\modflowversion.zip}. The distribution file is a compressed zip file. The following directory structure is incorporated in the zip file: +The following distribution file is for use on personal computers: \texttt{\modflowversion\_[ostag].zip}. The distribution file is a compressed zip file. The following directory structure is incorporated in the zip file: % folder structured created by python script \input{folder_struct.tex} -It is recommended that no user files are kept in the \modflowversion~directory structure. If you do plan to put your own files in the \modflowversion~directory structure, do so only by creating additional subdirectories. +It is recommended that no user files are kept in the release directory. If you do plan to put your own files in the release directory, do so only by creating additional subdirectories. % ------------------------------------------------- \section{Installation and Execution} -There is no installation of MODFLOW~6 other than the requirement that \texttt{\modflowversion.zip} must be unzipped into a location where it can be accessed. +There is no installation of MODFLOW~6 other than the requirement that \texttt{\modflowversion\_[ostag].zip} must be unzipped into a location where it can be accessed. To make the executable versions of MODFLOW~6 accessible from any directory, the directory containing the executables should be included in the PATH environment variable. Also, if a prior release of MODFLOW~6 is installed on your system, the directory containing the executables for the prior release should be removed from the PATH environment variable. -As an alternative, the executable file, named ``\texttt{mf6.exe}'' on Windows, in the \modflowversion{}/bin directory can be copied into a directory already included in the PATH environment variable. +As an alternative, the executable file, named ``\texttt{mf6.exe}'' on Windows, in the \modflowversion\_[ostag]/bin directory can be copied into a directory already included in the PATH environment variable. To run MODFLOW~6, simply type \texttt{mf6} in a terminal window. The current working directory must be set to a location where the model input files are located. Upon execution, MODFLOW~6 will immediately look for file with the name \texttt{mfsim.nam} in the current working directory, and will terminate with an error if it does not find this file. % ------------------------------------------------- \section{Compiling MODFLOW~6} -MODFLOW~6 has been compiled using Intel Fortran and GNU Fortran on the Windows, macOS, and Linux operating systems. Because the program uses relatively new Fortran functionality, recent versions of the compilers may be required for successful compilation. MODFLOW~6 is currently tested with gfortran 7-12 on Linux and gfortran 12 on macOS and Windows. If you have gfortran installed on your computer, you can tell which version it is by entering ``\verb|gfortran --version|'' at a terminal window. MODFLOW~6 is currently not compatible with the next-generation Intel Fortran Compiler; a recent version of the Intel Fortran Compiler Classic (e.g. 2021.8.0) must be used. +MODFLOW~6 has been compiled using Intel Fortran and GNU Fortran on Windows, macOS, and several Linux operating systems. All MODFLOW~6 distributions are currently compiled with Intel Fortran. Because the program uses relatively new Fortran functionality, recent versions of the compilers may be required for successful compilation. MODFLOW~6 is not yet compatible with the latest versions of the Intel toolchain, however. + +MODFLOW~6 is currently tested with gfortran 7-12 on Linux and gfortran 12 on macOS and Windows. The gfortran version can be queried with ``\verb|gfortran --version|''. Intel Fortran Compiler Classic version 2022.3.0 is currently tested on all three platforms. Some 2021 versions have also been reported compatible. At this time, MODFLOW~6 is not compatible with the next-generation Intel Fortran Compiler `ifx`. Meson is the recommended build tool for MODFLOW~6. For more detailed compilation instructions, please refer to \url{https://github.com/MODFLOW-USGS/modflow6/blob/develop/DEVELOPER.md#building}. This distribution contains the Microsoft Visual Studio solution and project files for compiling MODFLOW~6 on Windows using the Intel Fortran Compiler Classic. The files have been used successfully with recent versions of Microsoft Visual Studio Community 2019 and the Intel Fortran Compiler Classic. -This distribution also comes with a makefile for compiling MODFLOW~6 with \texttt{gfortran}. The makefile is contained in the \texttt{make} folder. +This distribution also includes a makefile for compiling MODFLOW~6 with \texttt{gfortran}. The makefile is contained in the \texttt{make} folder. For those familiar with Python, the pymake package can also be used to compile MODFLOW~6. Additional information on the Python pymake utility can be found at: \url{https://github.com/modflowpy/pymake}. diff --git a/doc/ReleaseNotes/appendixA.tex b/doc/ReleaseNotes/appendixA.tex index 2bad0245dce..199d7151043 100644 --- a/doc/ReleaseNotes/appendixA.tex +++ b/doc/ReleaseNotes/appendixA.tex @@ -1,5 +1,6 @@ This appendix describes changes introduced into MODFLOW~6 in previous releases. These changes may substantially affect users. + \input{./previous/v6.4.2.tex} \input{./previous/v6.4.1.tex} \input{./previous/v6.4.0.tex} \input{./previous/v6.3.0.tex} diff --git a/doc/ReleaseNotes/develop.tex b/doc/ReleaseNotes/develop.tex new file mode 100644 index 00000000000..5993caf38d2 --- /dev/null +++ b/doc/ReleaseNotes/develop.tex @@ -0,0 +1,61 @@ +% Use this template for starting initializing the release notes +% after a release has just been made. + + \item \currentmodflowversion + + %\underline{NEW FUNCTIONALITY} + %\begin{itemize} + % \item xxx + % \item xxx + % \item xxx + %\end{itemize} + + %\underline{EXAMPLES} + %\begin{itemize} + % \item xxx + % \item xxx + % \item xxx + %\end{itemize} + + %\textbf{\underline{BUG FIXES AND OTHER CHANGES TO EXISTING FUNCTIONALITY}} \\ + %\underline{BASIC FUNCTIONALITY} + %\begin{itemize} + % \item xxx + % \item xxx + % \item xxx + %\end{itemize} + + %\underline{INTERNAL FLOW PACKAGES} + %\begin{itemize} + % \item xxx + % \item xxx + % \item xxx + %\end{itemize} + + %\underline{STRESS PACKAGES} + %\begin{itemize} + % \item xxx + % \item xxx + % \item xxx + %\end{itemize} + + %\underline{ADVANCED STRESS PACKAGES} + %\begin{itemize} + % \item xxx + % \item xxx + % \item xxx + %\end{itemize} + + %\underline{SOLUTION} + %\begin{itemize} + % \item xxx + % \item xxx + % \item xxx + %\end{itemize} + + %\underline{EXCHANGES} + %\begin{itemize} + % \item xxx + % \item xxx + % \item xxx + %\end{itemize} \ No newline at end of file diff --git a/doc/ReleaseNotes/folder_struct.tex b/doc/ReleaseNotes/folder_struct.tex index 51ba1dc21b0..544ea59f8e8 100644 --- a/doc/ReleaseNotes/folder_struct.tex +++ b/doc/ReleaseNotes/folder_struct.tex @@ -1,5 +1,5 @@ \begin{verbatim} -mf6.x.x/ +\modflowversion bin/ doc/ examples/ diff --git a/doc/ReleaseNotes/v6.4.2.tex b/doc/ReleaseNotes/previous/v6.4.2.tex similarity index 99% rename from doc/ReleaseNotes/v6.4.2.tex rename to doc/ReleaseNotes/previous/v6.4.2.tex index 8d718485fc1..afc3511061a 100644 --- a/doc/ReleaseNotes/v6.4.2.tex +++ b/doc/ReleaseNotes/previous/v6.4.2.tex @@ -2,7 +2,7 @@ % after a release has just been made. %\item \currentmodflowversion - \item Version mf6.4.2--June 28, 2023 + \subsection{Version mf6.4.2--June 28, 2023} \underline{NEW FUNCTIONALITY} \begin{itemize} diff --git a/doc/version.py b/doc/version.py index b0cc293a662..6fd599035f7 100644 --- a/doc/version.py +++ b/doc/version.py @@ -1,10 +1,3 @@ # MODFLOW 6 version file automatically created using...update_version.py -# created on...June 29, 2023 00:01:07 - -major = 6 -minor = 4 -micro = 2 -label = '+' -__version__ = '{:d}.{:d}.{:d}'.format(major, minor, micro) -if label: - __version__ += '{}{}'.format(__version__, label) \ No newline at end of file +# created on...July 13, 2023 15:32:29 +__version__ = "6.5.0.dev0" diff --git a/doc/version.tex b/doc/version.tex index ffd8225908d..147b13cfba9 100644 --- a/doc/version.tex +++ b/doc/version.tex @@ -1,3 +1,3 @@ -\newcommand{\modflowversion}{mf6.4.2+} -\newcommand{\modflowdate}{June 29, 2023} +\newcommand{\modflowversion}{mf6.5.0.dev0} +\newcommand{\modflowdate}{July 13, 2023} \newcommand{\currentmodflowversion}{Version \modflowversion---\modflowdate} diff --git a/meson.build b/meson.build index bdab45cebf7..879bf5d4c3a 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'MODFLOW 6', 'fortran', - version: '6.4.2+', + version: '6.5.0.dev0', license: 'CC0', meson_version: '>= 1.1.0', default_options : [ diff --git a/src/Utilities/version.f90 b/src/Utilities/version.f90 index 3008fc2df63..2ae3d52a069 100644 --- a/src/Utilities/version.f90 +++ b/src/Utilities/version.f90 @@ -16,8 +16,8 @@ module VersionModule public ! -- modflow 6 version integer(I4B), parameter :: IDEVELOPMODE = 1 - character(len=*), parameter :: VERSIONNUMBER = '6.4.2+' - character(len=*), parameter :: VERSIONTAG = ' (preliminary) 06/29/2023' + character(len=*), parameter :: VERSIONNUMBER = '6.5.0.dev0' + character(len=*), parameter :: VERSIONTAG = ' (preliminary) 07/13/2023' character(len=40), parameter :: VERSION = VERSIONNUMBER//VERSIONTAG character(len=2), parameter :: MFVNAM = ' 6' character(len=*), parameter :: MFTITLE = & diff --git a/version.txt b/version.txt index b0cc293a662..8d7edccd2da 100644 --- a/version.txt +++ b/version.txt @@ -1,10 +1 @@ -# MODFLOW 6 version file automatically created using...update_version.py -# created on...June 29, 2023 00:01:07 - -major = 6 -minor = 4 -micro = 2 -label = '+' -__version__ = '{:d}.{:d}.{:d}'.format(major, minor, micro) -if label: - __version__ += '{}{}'.format(__version__, label) \ No newline at end of file +6.5.0.dev0 \ No newline at end of file