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
3 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
Branches
Branches containing commit
No related tags found
1 merge request
!1
Restructuring and cleaning scripts for Mkdocs
Changes
1
Show 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 @@
...
@@ -10,10 +10,13 @@
"""
"""
from
__future__
import
annotations
from
__future__
import
annotations
_print
=
print
# save the original print function
from
typing
import
Tuple
,
Generator
from
typing
import
Tuple
,
Generator
import
argparse
import
argparse
from
rich
import
print
,
markdown
from
rich
import
markdown
,
print
import
re
,
sys
,
yaml
import
re
,
sys
,
yaml
,
os
from
contextlib
import
contextmanager
from
contextlib
import
contextmanager
...
@@ -37,13 +40,79 @@ def includeStack(filename:str) -> Generator [None, None, None]:
...
@@ -37,13 +40,79 @@ def includeStack(filename:str) -> Generator [None, None, None]:
Generator: A generator that yields nothing.
Generator: A generator that yields nothing.
"""
"""
if
filename
in
_includeStack
:
if
filename
in
_includeStack
:
print
(
f
'
[red]Circular include detected:
{
filename
}
'
)
raise
Exception
(
f
'
Circular include detected:
{
"
->
"
.
join
(
_includeStack
)
}
->
{
filename
}
'
)
raise
Exception
(
'
Circular include detected
'
)
_includeStack
.
append
(
filename
)
_includeStack
.
append
(
filename
)
yield
yield
_includeStack
.
pop
()
_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
]]:
def
processFrontMatter
(
lines
:
list
[
str
],
args
:
argparse
.
Namespace
)
->
Tuple
[
dict
,
list
[
str
]]:
"""
Process the front matter of a markdown file. This includes extracting
"""
Process the front matter of a markdown file. This includes extracting
the front matter information and returning it as a dictionary.
the front matter information and returning it as a dictionary.
...
@@ -97,7 +166,7 @@ def processFile(args:argparse.Namespace) -> str:
...
@@ -97,7 +166,7 @@ def processFile(args:argparse.Namespace) -> str:
The processed markdown content as a string.
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.
"""
Read a single markdown file and return its content.
Args:
Args:
...
@@ -109,6 +178,14 @@ def processFile(args:argparse.Namespace) -> str:
...
@@ -109,6 +178,14 @@ def processFile(args:argparse.Namespace) -> str:
Returns:
Returns:
The content of the file.
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
):
with
includeStack
(
filename
):
try
:
try
:
...
@@ -118,7 +195,10 @@ def processFile(args:argparse.Namespace) -> str:
...
@@ -118,7 +195,10 @@ def processFile(args:argparse.Namespace) -> str:
print
(
f
'
[red]File not found:
{
filename
}
'
)
print
(
f
'
[red]File not found:
{
filename
}
'
)
raise
raise
# Expand the paths in the markdown file
# extract front matter information
# extract front matter information
lines
=
expandPaths
(
lines
,
currentPath
,
dirname
)
fm
,
lines
=
processFrontMatter
(
lines
,
args
)
fm
,
lines
=
processFrontMatter
(
lines
,
args
)
if
fm
:
if
fm
:
_frontMatter
[
filename
]
=
fm
_frontMatter
[
filename
]
=
fm
...
@@ -129,7 +209,7 @@ def processFile(args:argparse.Namespace) -> str:
...
@@ -129,7 +209,7 @@ def processFile(args:argparse.Namespace) -> str:
inCodeFence
=
False
inCodeFence
=
False
for
line
in
lines
:
for
line
in
lines
:
# Ignore code fences
# Ignore
stuff
code fences
if
re
.
match
(
r
'
^\s*```.*
'
,
line
):
if
re
.
match
(
r
'
^\s*```.*
'
,
line
):
inCodeFence
=
not
inCodeFence
inCodeFence
=
not
inCodeFence
continue
continue
...
@@ -139,15 +219,13 @@ def processFile(args:argparse.Namespace) -> str:
...
@@ -139,15 +219,13 @@ def processFile(args:argparse.Namespace) -> str:
# Check for ::include{file=...} pattern using regex at the beginning of a line
# Check for ::include{file=...} pattern using regex at the beginning of a line
match
=
re
.
search
(
r
'
^::include\{\s*file=(.*?)\s*\}
'
,
line
.
strip
())
match
=
re
.
search
(
r
'
^::include\{\s*file=(.*?)\s*\}
'
,
line
.
strip
())
if
match
:
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
# Read the included file and replace the include statement with its content
include_content
=
handleIncludesForFile
(
include_filename
)
lines
[
lines
.
index
(
line
)]
=
handleIncludesForFile
(
includeFilename
,
os
.
path
.
dirname
(
filename
))
lines
[
lines
.
index
(
line
)]
=
include_content
return
''
.
join
(
lines
)
return
''
.
join
(
lines
)
return
handleIncludesForFile
(
args
.
document
)
return
handleIncludesForFile
(
args
.
document
,
os
.
path
.
dirname
(
args
.
document
))
if
__name__
==
'
__main__
'
:
if
__name__
==
'
__main__
'
:
...
@@ -170,7 +248,7 @@ if __name__ == '__main__':
...
@@ -170,7 +248,7 @@ if __name__ == '__main__':
try
:
try
:
lines
=
processFile
(
args
)
lines
=
processFile
(
args
)
except
Exception
as
e
:
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
)
quit
(
1
)
if
args
.
outputFrontMatter
or
args
.
onlyFrontMatter
:
if
args
.
outputFrontMatter
or
args
.
onlyFrontMatter
:
...
@@ -192,7 +270,7 @@ if __name__ == '__main__':
...
@@ -192,7 +270,7 @@ if __name__ == '__main__':
print
(
markdown
.
Markdown
(
lines
))
print
(
markdown
.
Markdown
(
lines
))
else
:
else
:
# Print the raw markdown content
# 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