Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
S
Scripts
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Specification Tools
Scripts
Commits
a6bd358c
Commit
a6bd358c
authored
2 months ago
by
Andreas Kraft
Browse files
Options
Downloads
Patches
Plain Diff
Support directory-relative imports (change paths of links, images, includes) in sub-folders
parent
98b64bd6
No related branches found
No related tags found
1 merge request
!1
Restructuring and cleaning scripts for Mkdocs
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
processMDSpec.py
+93
-15
93 additions, 15 deletions
processMDSpec.py
with
93 additions
and
15 deletions
processMDSpec.py
+
93
−
15
View file @
a6bd358c
...
...
@@ -10,10 +10,13 @@
"""
from
__future__
import
annotations
_print
=
print
# save the original print function
from
typing
import
Tuple
,
Generator
import
argparse
from
rich
import
print
,
markdown
import
re
,
sys
,
yaml
from
rich
import
markdown
,
print
import
re
,
sys
,
yaml
,
os
from
contextlib
import
contextmanager
...
...
@@ -37,13 +40,79 @@ def includeStack(filename:str) -> Generator [None, None, None]:
Generator: A generator that yields nothing.
"""
if
filename
in
_includeStack
:
print
(
f
'
[red]Circular include detected:
{
filename
}
'
)
raise
Exception
(
'
Circular include detected
'
)
raise
Exception
(
f
'
Circular include detected:
{
"
->
"
.
join
(
_includeStack
)
}
->
{
filename
}
'
)
_includeStack
.
append
(
filename
)
yield
_includeStack
.
pop
()
def
expandPaths
(
lines
:
list
[
str
],
currentPath
:
str
,
childPath
:
str
)
->
list
[
str
]:
"""
Expand the paths in the markdown file. This means that all paths in links,
images, and include statements are extended so that they would be valid paths
from the root document.
Args:
lines: The lines of the markdown file.
currentPath: The current path of the file being processed.
childPath: The path of the child file being processed.
Returns:
list[str]: The lines of the markdown file with expanded paths.
"""
# Replace all relative paths in the markdown with the new path
# add a path to the current path
if
currentPath
[
-
1
]
!=
'
/
'
:
currentPath
+=
'
/
'
newPath
=
currentPath
+
childPath
# Remove the leading './' from the path
while
newPath
.
startswith
(
'
./
'
):
newPath
=
newPath
[
2
:]
inCodeFence
=
False
for
index
,
line
in
enumerate
(
lines
):
# Ignore stuff in code fences
if
re
.
match
(
r
'
^\s*```.*
'
,
line
):
inCodeFence
=
not
inCodeFence
continue
if
inCodeFence
:
continue
# handle the links in a line (there could be multiple links in a line)
links
=
re
.
findall
(
r
'
\[([^\]]+)\]\(([^\)]+)\)
'
,
line
)
for
linkText
,
linkPath
in
links
:
# Skip URLs and absolute paths
if
linkPath
.
startswith
((
'
http://
'
,
'
https://
'
,
'
/
'
)):
continue
# Construct the new path by adding addedPath to the original path
newLinkPath
=
linkPath
[
2
:]
if
linkPath
.
startswith
(
'
./
'
)
else
linkPath
# Create the updated path
updatedPath
=
f
"
{
newPath
}{
linkPath
}
"
if
newPath
.
endswith
(
'
/
'
)
else
f
"
{
newPath
}
/
{
newLinkPath
}
"
# Replace the original link with the updated one in the markdown
line
=
line
.
replace
(
f
'
[
{
linkText
}
](
{
linkPath
}
)
'
,
f
'
[
{
linkText
}
](
{
updatedPath
}
)
'
)
# handle the include statements (there should only be one per line)
includes
=
re
.
findall
(
r
'
^\s*::include{file=([^\}]+)}
'
,
line
)
for
includePath
in
includes
:
# Construct the new path by adding addedPath to the original path
includePath
=
includePath
[
2
:]
if
includePath
.
startswith
(
'
./
'
)
else
includePath
# Create the updated path
updatedPath
=
f
'
{
newPath
}{
includePath
}
'
if
newPath
.
endswith
(
'
/
'
)
else
f
'
{
newPath
}
/
{
includePath
}
'
# Replace the original include with the updated one in the markdown
line
=
line
.
replace
(
f
'
::include{{file=
{
includePath
}
}}
'
,
f
'
::include{{file=
{
updatedPath
}
}}
'
)
lines
[
index
]
=
line
return
lines
def
processFrontMatter
(
lines
:
list
[
str
],
args
:
argparse
.
Namespace
)
->
Tuple
[
dict
,
list
[
str
]]:
"""
Process the front matter of a markdown file. This includes extracting
the front matter information and returning it as a dictionary.
...
...
@@ -97,7 +166,7 @@ def processFile(args:argparse.Namespace) -> str:
The processed markdown content as a string.
"""
def
handleIncludesForFile
(
filename
:
str
)
->
str
:
def
handleIncludesForFile
(
filename
:
str
,
currentPath
:
str
)
->
str
:
"""
Read a single markdown file and return its content.
Args:
...
...
@@ -109,6 +178,14 @@ def processFile(args:argparse.Namespace) -> str:
Returns:
The content of the file.
"""
# Get the directory path from the filename
dirname
=
os
.
path
.
dirname
(
filename
)
if
dirname
and
not
dirname
.
endswith
(
'
/
'
):
dirname
=
dirname
+
'
/
'
dirname
=
dirname
if
dirname
else
'
.
'
currentPath
=
currentPath
if
currentPath
else
'
.
'
filename
=
os
.
path
.
normpath
(
filename
)
with
includeStack
(
filename
):
try
:
...
...
@@ -117,8 +194,11 @@ def processFile(args:argparse.Namespace) -> str:
except
FileNotFoundError
:
print
(
f
'
[red]File not found:
{
filename
}
'
)
raise
# Expand the paths in the markdown file
# extract front matter information
lines
=
expandPaths
(
lines
,
currentPath
,
dirname
)
fm
,
lines
=
processFrontMatter
(
lines
,
args
)
if
fm
:
_frontMatter
[
filename
]
=
fm
...
...
@@ -129,7 +209,7 @@ def processFile(args:argparse.Namespace) -> str:
inCodeFence
=
False
for
line
in
lines
:
# Ignore code fences
# Ignore
stuff
code fences
if
re
.
match
(
r
'
^\s*```.*
'
,
line
):
inCodeFence
=
not
inCodeFence
continue
...
...
@@ -139,17 +219,15 @@ def processFile(args:argparse.Namespace) -> str:
# Check for ::include{file=...} pattern using regex at the beginning of a line
match
=
re
.
search
(
r
'
^::include\{\s*file=(.*?)\s*\}
'
,
line
.
strip
())
if
match
:
include
_f
ilename
=
match
.
group
(
1
)
include
F
ilename
=
match
.
group
(
1
)
# Read the included file and replace the include statement with its content
include_content
=
handleIncludesForFile
(
include_filename
)
lines
[
lines
.
index
(
line
)]
=
include_content
lines
[
lines
.
index
(
line
)]
=
handleIncludesForFile
(
includeFilename
,
os
.
path
.
dirname
(
filename
))
return
''
.
join
(
lines
)
return
handleIncludesForFile
(
args
.
document
)
return
handleIncludesForFile
(
args
.
document
,
os
.
path
.
dirname
(
args
.
document
)
)
if
__name__
==
'
__main__
'
:
parser
=
argparse
.
ArgumentParser
(
description
=
'
Process markdown specification files.
'
)
...
...
@@ -158,7 +236,7 @@ if __name__ == '__main__':
parser
.
add_argument
(
'
--process-frontmatter
'
,
'
-fm
'
,
dest
=
'
outputFrontMatter
'
,
action
=
'
store_true
'
,
help
=
'
output front matter only
'
)
parser
.
add_argument
(
'
--frontmatter-only
'
,
'
-fmo
'
,
dest
=
'
onlyFrontMatter
'
,
action
=
'
store_true
'
,
help
=
'
output only front matter
'
)
parser
.
add_argument
(
'
--verbose
'
,
'
-v
'
,
action
=
'
store_true
'
,
help
=
'
print debug information to stderr.
'
)
parser
.
add_argument
(
'
document
'
,
type
=
str
,
help
=
'
a markdown specification document to process
'
)
parser
.
add_argument
(
'
document
'
,
type
=
str
,
help
=
'
a markdown specification document to process
'
)
args
=
parser
.
parse_args
()
if
args
.
verbose
:
...
...
@@ -170,7 +248,7 @@ if __name__ == '__main__':
try
:
lines
=
processFile
(
args
)
except
Exception
as
e
:
print
(
f
'
[red]Error processing
file:
{
e
}
'
,
file
=
sys
.
stderr
)
print
(
f
'
[red]Error
while
processing
{
args
.
document
}
\n
{
e
}
'
,
file
=
sys
.
stderr
)
quit
(
1
)
if
args
.
outputFrontMatter
or
args
.
onlyFrontMatter
:
...
...
@@ -192,7 +270,7 @@ if __name__ == '__main__':
print
(
markdown
.
Markdown
(
lines
))
else
:
# Print the raw markdown content
print
(
lines
)
_
print
(
lines
)
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment