Skip to content

Commit eb01179

Browse files
authored
Merge pull request #329 from online-judge-tools/documentation-of-path
Update the specification of "documentation_of" string
2 parents 016c137 + 4f262ba commit eb01179

File tree

5 files changed

+122
-20
lines changed

5 files changed

+122
-20
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,10 @@ jobs:
2020

2121
- name: Install dependencies
2222
run: pip install .[dev]
23-
24-
# - name: Install boost(ubuntu)
25-
# run: sudo apt-get install libboost-all-dev
26-
# if: matrix.os == 'ubuntu-latest'
27-
28-
# - name: Install boost(windows)
29-
# run: |
30-
# git clone --recursive https://github.com/boostorg/boost.git
31-
# cd boost
32-
# ./bootstrap.bat
33-
# ./b2.exe install -j2
34-
# shell: bash
35-
# if: matrix.os == 'windows-latest'
3623

3724
- name: Run tests
3825
run: |
26+
unset GITHUB_ACTION
3927
oj-verify -h
4028
python setup.py test
4129
shell: bash

.verify-helper/docs/static/document.ja.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,19 +101,22 @@ list_dependencies = "sed 's/^@include \"\\(.*\\)\"$/\\1/ ; t ; d' {path}"
101101
[Front Matter](http://jekyllrb-ja.github.io/docs/front-matter/) 形式で `documentation_of` という項目にファイルを指定しておくと、指定したファイルについての生成されたドキュメント中に、Markdown ファイルの中身が挿入されます。
102102

103103
たとえば、`path/to/segment_tree.hpp` というファイルに説明を Markdown で追加したいときは `for/bar.md` などに次のように書きます。
104-
[Front Matter](https://jekyllrb.com/docs/front-matter/)
105104

106105
```
107106
---
108107
title: Segment Tree
109-
documentation_of: path/to/segment_tree.hpp
108+
documentation_of: ./path/to/segment_tree.hpp
110109
---
111110
112111
## 説明
113112
114113
このファイルでは、……
115114
```
116115

116+
`documentation_of` 文字列は、`./` あるいは `..` から始まる場合は Markdown ファイルのパスからの相対パスであると認識されます。また、`//` から初まる場合は `.verify-helper` ディレクトリがある場所をルートとする絶対パスであると認識されます。
117+
また、ディレクトリ区切り文字には `/` を使い、大文字小文字を正しく入力してください。
118+
119+
117120
### トップページへの Markdown の埋め込み
118121

119122
`.verify-helper/docs/index.md` というファイルを作って、そこに Markdown で書いてください。

.verify-helper/docs/static/document.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,19 @@ For example, to add description to a document of a file `path/to/segment_tree.hp
104104
```
105105
---
106106
title: Segment Tree
107-
documentation_of: path/to/segment_tree.hpp
107+
documentation_of: ./path/to/segment_tree.hpp
108108
---
109109
110110
## Description
111111
112112
In this file, ...
113113
```
114114

115+
The `documentation_of` string is recognized as a relative path from the Markdown file when the string starts with `./` or `..`.
116+
The `documentation_of` string is recognized as a absolute path from the directory which has `.verify-helper` directory as the root when the string starts with `//`.
117+
The path should use `/` as directory separator be case-sensitive.
118+
119+
115120

116121
### Embedding Markdown to the top page
117122

onlinejudge_verify/documentation/configure.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,32 @@ def apply_exclude_list_to_stats(*, excluded_paths: List[pathlib.Path], source_co
212212
return result
213213

214214

215+
def resolve_documentation_of(documentation_of: str, *, markdown_path: pathlib.Path, basedir: pathlib.Path) -> Optional[pathlib.Path]:
216+
if documentation_of.startswith('.'):
217+
# a relative path
218+
path = markdown_path.parent / pathlib.Path(pathlib.PurePosixPath(documentation_of))
219+
if path.exists() and basedir in path.resolve().parents:
220+
return path
221+
elif documentation_of.startswith('//'):
222+
# from the document root
223+
path = basedir / pathlib.Path(pathlib.PurePosixPath(documentation_of[2:]))
224+
if path.exists() and basedir in path.resolve().parents:
225+
return path
226+
227+
# guessing
228+
logger.warning('No file at the expected path from the `documentation_of` path. The `documentation_of` path should use `/` for path separator, and start with `.` for a relative path from the path of the Markdown file, or start with `//` for a absolute path from the root of the repository.: %s', documentation_of)
229+
candidate_paths = [
230+
basedir / pathlib.Path(pathlib.PurePosixPath(documentation_of)),
231+
basedir / pathlib.Path(documentation_of),
232+
markdown_path.parent / pathlib.Path(pathlib.PurePosixPath(documentation_of)),
233+
markdown_path.parent / pathlib.Path(documentation_of),
234+
]
235+
for path in candidate_paths:
236+
if path.exists() and basedir in path.resolve().parents:
237+
return path
238+
return None
239+
240+
215241
def convert_to_page_render_jobs(*, source_code_stats: List[SourceCodeStat], markdown_paths: List[pathlib.Path], site_render_config: SiteRenderConfig) -> List[PageRenderJob]:
216242
basedir = site_render_config.basedir
217243

@@ -230,11 +256,14 @@ def convert_to_page_render_jobs(*, source_code_stats: List[SourceCodeStat], mark
230256
path = markdown_relative_path
231257
documentation_of = front_matter.get(FrontMatterItem.documentation_of.value)
232258
if documentation_of is not None:
233-
if not (basedir / pathlib.Path(documentation_of)).exists():
259+
documentation_of_path = resolve_documentation_of(documentation_of, markdown_path=path, basedir=basedir)
260+
if documentation_of_path is None:
234261
logger.warning('the `documentation_of` path of %s is not found: %s', str(path), documentation_of)
262+
del front_matter[FrontMatterItem.documentation_of.value]
235263
continue
236-
documentation_of_path = (basedir / pathlib.Path(documentation_of)).resolve().relative_to(basedir)
237-
path = documentation_of_path.parent / (documentation_of_path.name + '.md')
264+
documentation_of_relative_path = documentation_of_path.resolve().relative_to(basedir)
265+
front_matter[FrontMatterItem.documentation_of.value] = str(documentation_of_relative_path)
266+
path = documentation_of_relative_path.parent / (documentation_of_path.name + '.md')
238267

239268
job = PageRenderJob(
240269
path=path,

tests/test_docs.py

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,90 @@
11
"""This module has tests for the docs subcommand.
22
"""
33

4+
import pathlib
5+
import random
6+
import textwrap
47
import unittest
8+
from typing import *
59

610
import onlinejudge_verify.main
11+
import tests.utils as utils
712

813

914
class TestDocsSubcommandSmoke(unittest.TestCase):
10-
"""TestDocsSubcommandSmoke is a smoke tests of `docs` subcommand.
15+
"""TestDocsSubcommandSmoke is a class for smoke tests of `docs` subcommand.
1116
"""
1217
def test_run(self) -> None:
1318
onlinejudge_verify.main.subcommand_docs()
19+
20+
21+
class TestDocsSubcommand(unittest.TestCase):
22+
"""TestDocsSubcommand is a class for end-to-end tests of `docs` subcommand.
23+
"""
24+
def test_documentation_of(self) -> None:
25+
get_random_string = lambda: ''.join([random.choice('0123456789abcdef') for _ in range(64)])
26+
random_relative_hpp = get_random_string()
27+
random_absolute_hpp = get_random_string()
28+
random_unsupported_absolute_hpp = get_random_string()
29+
random_no_document_hpp = get_random_string()
30+
random_relative_md = get_random_string()
31+
random_absolute_md = get_random_string()
32+
random_unsupported_absolute_md = get_random_string()
33+
random_standalone_page_md = get_random_string()
34+
35+
files = {
36+
pathlib.Path('src', 'a', 'b', 'relative.hpp'): random_relative_hpp.encode(),
37+
pathlib.Path('src', 'a', 'b', 'absolute.hpp'): random_absolute_hpp.encode(),
38+
pathlib.Path('src', 'a', 'b', 'unsupported-absolute.hpp'): random_unsupported_absolute_hpp.encode(),
39+
pathlib.Path('src', 'a', 'b', 'no-document.hpp'): random_no_document_hpp.encode(),
40+
pathlib.Path('docs', 'x', 'y', 'relative.md'): textwrap.dedent(f"""\
41+
---
42+
title: relative.md
43+
documentation_of: ../../../src/a/b/relative.hpp
44+
---
45+
46+
{random_relative_md}
47+
""").encode(),
48+
pathlib.Path('docs', 'x', 'y', 'unsupported-absolute.md'): textwrap.dedent(f"""\
49+
---
50+
title: unsupported-absolute.md
51+
documentation_of: src/a/b/unsupported-absolute.hpp
52+
---
53+
54+
{random_unsupported_absolute_md}
55+
""").encode(),
56+
pathlib.Path('docs', 'x', 'y', 'absolute.md'): textwrap.dedent(f"""\
57+
---
58+
title: absolute.md
59+
documentation_of: //src/a/b/absolute.hpp
60+
---
61+
62+
{random_absolute_md}
63+
""").encode(),
64+
pathlib.Path('docs', 'x', 'y', 'standalone-page.md'): textwrap.dedent(f"""\
65+
---
66+
title: standalone page
67+
---
68+
69+
{random_standalone_page_md}
70+
""").encode(),
71+
}
72+
73+
destination_dir = pathlib.Path('.verify-helper', 'markdown')
74+
expected: Dict[pathlib.Path, List[str]] = {
75+
destination_dir / 'src' / 'a' / 'b' / 'relative.hpp.md': [random_relative_hpp, random_relative_md],
76+
destination_dir / 'src' / 'a' / 'b' / 'absolute.hpp.md': [random_absolute_hpp, random_absolute_md],
77+
destination_dir / 'src' / 'a' / 'b' / 'unsupported-absolute.hpp.md': [random_unsupported_absolute_hpp, random_unsupported_absolute_md],
78+
destination_dir / 'src' / 'a' / 'b' / 'no-document.hpp.md': [random_no_document_hpp],
79+
destination_dir / 'docs' / 'x' / 'y' / 'standalone-page.md': [random_standalone_page_md],
80+
}
81+
82+
with utils.load_files_pathlib(files) as tempdir:
83+
with utils.chdir(tempdir):
84+
onlinejudge_verify.main.subcommand_docs()
85+
for path, keywords in expected.items():
86+
self.assertTrue((tempdir / path).exists())
87+
with open(tempdir / path) as fh:
88+
content = fh.read()
89+
for keyword in keywords:
90+
self.assertIn(keyword, content)

0 commit comments

Comments
 (0)