Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion man/build_manual_gallery.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ def main(ext):
if ext == "html":
output.write(header_graphical_index_tmpl)
output.write('<ul class="img-list">\n')
for image, filename in sorted(img_files.items(), key=operator.itemgetter(1)):
for image, filename in sorted(img_files.items(), key=operator.itemgetter(1, 0)):
name = get_module_name(filename, ext)
title = title_from_names(name, image)
if ext == "html":
Expand Down
39 changes: 25 additions & 14 deletions utils/generate_last_commit_file.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#!/usr/bin/env python3

"""
Script for creating an core_modules_with_last_commit.json file contains
all core modules with their last commit. Used by GitHub "Create new
release draft" action workflow.
Script for creating a core_modules_with_last_commit.json file which
contains every documentation page with its last commit. Used by GitHub
"Create new release draft" action workflow.

JSON file structure:

Expand Down Expand Up @@ -33,7 +33,8 @@


def get_last_commit(src_dir):
"""Generate core modules JSON object with the following structure
"""Generate JSON object with an entry per documentation page with the
following structure

"r.pack": {
"commit": "547ff44e6aecfb4c9cbf6a4717fc14e521bec0be",
Expand All @@ -43,17 +44,26 @@ def get_last_commit(src_dir):
commit key value is commit hash
date key value is author date

Entries are keyed by the name of each .html or .md documentation page,
so that pages whose name differs from their directory (r3.mapcalc,
r.watershed, the wxGUI.* pages, the intro pages, ...) and pages which
only exist as Markdown (the doc/ development pages) get an entry too.
The recorded commit is the last commit touching the directory the page
lives in, matching what a build with Git history shows for that page.

:param str src_dir: root source code dir

:return JSON obj result: core modules with last commit and commit
date
:return JSON obj result: documentation pages with last commit and
commit date
"""
result = {}
join_sep = ","
if not shutil.which("git"):
sys.exit("Git command was not found. Please install it.")
for root, _, files in os.walk(src_dir):
if ".html{}".format(join_sep) not in join_sep.join(files) + join_sep:
for root, dirs, files in os.walk(src_dir):
# sort + skip hidden dirs
dirs[:] = sorted(d for d in dirs if not d.startswith("."))
pages = [f for f in files if f.endswith((".html", ".md"))]
if not pages:
continue
rel_path = os.path.relpath(root)
process_result = subprocess.run(
Expand All @@ -79,10 +89,11 @@ def get_last_commit(src_dir):
f"Cannot parse output from git log for '{rel_path}': "
f"{text} because {error}"
)
result[os.path.basename(rel_path)] = {
"commit": commit,
"date": date,
}
for page in sorted(pages):
result[os.path.splitext(page)[0]] = {
"commit": commit,
"date": date,
}
else:
sys.exit(process_result.stderr.decode())
return result
Expand All @@ -99,7 +110,7 @@ def main():
),
"w",
) as f:
json.dump(get_last_commit(src_dir), f, indent=4)
json.dump(get_last_commit(src_dir), f, indent=4, sort_keys=True)


if __name__ == "__main__":
Expand Down
14 changes: 10 additions & 4 deletions utils/mkhtml.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,18 +335,24 @@ def update_toc(data):

# process header
src_data = read_file(src_file)
# The meta page comments override the page title used in the generated
# header and source code section. The title must stay separate from pgm,
# which is the page name used to look up the last commit and the addon
# path, where the overridden title (e.g. "LRS" for the lrs page) would
# not match.
pgm_title = pgm
name = re.search(r"(<!-- meta page name:)(.*)(-->)", src_data, re.IGNORECASE)
pgm_desc = "GRASS Reference Manual"
if name:
pgm = name.group(2).strip().split("-", 1)[0].strip()
pgm_title = name.group(2).strip().split("-", 1)[0].strip()
name_desc = re.search(
r"(<!-- meta page name description:)(.*)(-->)", src_data, re.IGNORECASE
)
if name_desc:
pgm_desc = name_desc.group(2).strip()
desc = re.search(r"(<!-- meta page description:)(.*)(-->)", src_data, re.IGNORECASE)
if desc:
pgm = desc.group(2).strip()
pgm_title = desc.group(2).strip()
header_tmpl = string.Template(header_base + header_nopgm)
elif not pgm_desc:
header_tmpl = string.Template(header_base + header_pgm)
Expand Down Expand Up @@ -380,7 +386,7 @@ def update_toc(data):
",".join(new_keywords_paths),
)
if not re.search(r"<html>", tmp_data, re.IGNORECASE):
sys.stdout.write(header_tmpl.substitute(PGM=pgm, PGM_DESC=pgm_desc))
sys.stdout.write(header_tmpl.substitute(PGM=pgm_title, PGM_DESC=pgm_desc))

if tmp_data:
header_logo_img_el = '<img src="grass_logo.png" alt="GRASS logo">'
Expand Down Expand Up @@ -510,7 +516,7 @@ def to_title(name):
sys.stdout.write(
sourcecode.substitute(
URL_SOURCE=url_source,
PGM=pgm,
PGM=pgm_title,
URL_LOG=url_log,
DATE_TAG=date_tag,
)
Expand Down
54 changes: 28 additions & 26 deletions utils/test_generate_last_commit_file.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#!/usr/bin/env python3

"""
Script for testing an core_modules_with_last_commit.json file contains
all core modules with their last commit. Used by GitHub "Additional Checks"
action workflow.
Script for testing that the core_modules_with_last_commit.json file
contains every documentation page with its last commit. Used by GitHub

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To reread, it's different, but I like the new text better

"Additional Checks" action workflow.

Python lib dependencies:

Expand Down Expand Up @@ -47,47 +47,49 @@ def test_json_file_is_not_empty(read_json_file):
assert len(read_json_file) > 0


# Pairs of documentation page name and the directory its source lives in.
# Besides plain tools, they cover pages whose name differs from their
# directory name and pages which only exist as Markdown, which both rely
# on entries being keyed by page name.
PAGES = [
("v.surf.rst", os.path.join("vector", "v.surf.rst")),
("r.info", os.path.join("raster", "r.info")),
("r3.mapcalc", os.path.join("raster", "r.mapcalc")),
("r.watershed", os.path.join("raster", "r.watershed", "front")),
("wxGUI.components", os.path.join("gui", "wxpython", "docs")),
("databaseintro", "db"),
("style_guide", os.path.join("doc", "development")),
("python_intro", "doc"),
]


@pytest.mark.depends(on=["test_json_file_is_not_empty"])
@pytest.mark.parametrize(
"core_module_path",
[
os.path.join("vector", "v.surf.rst"),
os.path.join("raster", "r.info"),
],
)
def test_core_modules_in_json_file(read_json_file, core_module_path):
core_module = os.path.basename(core_module_path)
assert core_module in read_json_file
@pytest.mark.parametrize(("page", "page_path"), PAGES)
def test_pages_in_json_file(read_json_file, page, page_path):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I'm just confused about fixtures here, but page_path is unused.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is used in test_compare_json_file_data and this way, we can use the same list of PAGES for both.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is way to not have the unused param, without duplicating the list:

  @pytest.mark.depends(on=["test_json_file_is_not_empty"])
  @pytest.mark.parametrize("page", [page for page, _ in PAGES])
  def test_pages_in_json_file(read_json_file, page):
      assert page in read_json_file

but not sure, if it is worth the change.

assert page in read_json_file


@pytest.mark.depends(
on=[
"test_json_file_is_not_empty",
"test_core_modules_in_json_file",
"test_pages_in_json_file",
]
)
@pytest.mark.parametrize(
"core_module_path",
[
os.path.join("vector", "v.surf.rst"),
os.path.join("raster", "r.info"),
],
)
def test_compare_json_file_data(read_json_file, core_module_path):
@pytest.mark.parametrize(("page", "page_path"), PAGES)
def test_compare_json_file_data(read_json_file, page, page_path):
# Get Git commit and commit date from local Git
process_result = subprocess.run(
[
"git",
"log",
"-1",
f"--format=%H,{COMMIT_DATE_FORMAT}",
core_module_path,
page_path,
],
capture_output=True,
check=True,
) # --format=%H,COMMIT_DATE_FORMAT commit hash,author date
commit, date = process_result.stdout.decode().strip().split(",")
core_module = os.path.basename(core_module_path)
# Compare commit and commit date
assert read_json_file[core_module]["commit"] == commit
assert read_json_file[core_module]["date"] == date
assert read_json_file[page]["commit"] == commit
assert read_json_file[page]["date"] == date
Loading