Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
sedrubal
Masterarbeit
evaluation_tools
Commits
ef196458
Verified
Commit
ef196458
authored
Sep 13, 2021
by
Sebastian Endres
Browse files
Add create_dirlisting script
parent
33ffcebb
Changes
6
Hide whitespace changes
Inline
Side-by-side
create_dirlisting.py
0 → 100755
View file @
ef196458
#!/usr/bin/env python3
"""Create a human readable static directory listing for a given folder."""
import
argparse
import
shutil
import
os
from
datetime
import
datetime
from
pathlib
import
Path
from
typing
import
NamedTuple
import
jinja2
from
utils
import
YaspinWrapper
,
existing_dir_path
DIRLISTING_STYLE_NAME
=
".dirlisting_style.css"
STYLESHEET_PATH
=
Path
(
__file__
).
parent
/
"templates"
/
"dirlisting_style.css"
class
FileInfo
(
NamedTuple
):
"""A NamedTuple to describe files."""
path
:
Path
size
:
int
date
:
datetime
@
classmethod
def
from_dir
(
cls
,
path
:
Path
)
->
"FileInfo"
:
"""Return a NamedTuple of file information."""
stat
=
path
.
stat
()
size
=
stat
.
st_size
date
=
datetime
.
fromtimestamp
(
stat
.
st_mtime
)
return
FileInfo
(
path
,
size
,
date
)
class
DirInfo
(
NamedTuple
):
"""A NamedTuple to describe directories."""
path
:
Path
date
:
datetime
@
classmethod
def
from_dir
(
cls
,
path
:
Path
)
->
"DirInfo"
:
"""Return a NamedTuple of file information."""
date
=
datetime
.
fromtimestamp
(
path
.
stat
().
st_mtime
)
return
cls
(
path
,
date
)
def
parse_args
():
parser
=
argparse
.
ArgumentParser
()
parser
.
add_argument
(
"roots"
,
nargs
=
"+"
,
type
=
existing_dir_path
,
help
=
"Directories to create dir listing."
,
)
parser
.
add_argument
(
"--debug"
,
action
=
"store_true"
,
help
=
"Debug mode"
,
)
return
parser
.
parse_args
()
class
Cli
:
"""Create a human readable static directory listing for a given folder."""
#: Jinja2 environment for rendeing index.html files.
template_env
=
jinja2
.
Environment
(
loader
=
jinja2
.
FileSystemLoader
(
Path
(
__file__
).
parent
/
"templates"
)
)
#: File names, that will be omitted.
IGNORE_FILES
=
{
"index.html"
,
}
def
__init__
(
self
,
roots
:
list
[
Path
],
debug
=
False
):
self
.
roots
=
roots
self
.
debug
=
debug
def
_render_index_html
(
self
,
cur_root
:
Path
,
root
:
Path
,
dirs
:
list
[
str
],
files
:
list
[
str
]
)
->
str
:
"""Render the index html."""
dir_infos
=
[
DirInfo
.
from_dir
(
cur_root
/
sub_dir
)
for
sub_dir
in
sorted
(
dirs
)]
file_infos
=
[
FileInfo
.
from_dir
(
cur_root
/
file
)
for
file
in
sorted
(
files
)]
template
=
self
.
template_env
.
get_template
(
"dirlisting.html.j2"
)
breadcrumbs
=
cur_root
.
relative_to
(
root
).
parts
breadcrumbs_with_links
=
[
(
bc
,
"../"
*
(
len
(
breadcrumbs
)
-
i
-
1
))
for
i
,
bc
in
enumerate
(
breadcrumbs
)
]
stylesheet_url
=
"../"
*
len
(
breadcrumbs
)
+
DIRLISTING_STYLE_NAME
return
template
.
render
(
{
"dirs"
:
dir_infos
,
"files"
:
file_infos
,
"dirname"
:
cur_root
.
name
,
"breadcrumbs"
:
breadcrumbs_with_links
,
"stylesheet_url"
:
stylesheet_url
,
}
)
def
_write_index_file
(
self
,
cur_root
:
Path
,
root
:
Path
,
dirs
:
list
[
str
],
files
:
list
[
str
],
spinner
:
YaspinWrapper
,
)
->
None
:
"""Create the index file."""
index_html
=
self
.
_render_index_html
(
cur_root
,
root
,
dirs
,
files
)
index_file_name
=
cur_root
/
"index.html"
with
index_file_name
.
open
(
"w"
)
as
index_file
:
index_file
.
write
(
index_html
)
spinner
.
write
(
f
"
{
index_file_name
}
written."
)
def
create_dirlisting_in_root
(
self
,
root
:
Path
,
spinner
:
YaspinWrapper
):
"""docstring for create_dirlisting_in_root"""
shutil
.
copy
(
STYLESHEET_PATH
,
root
/
DIRLISTING_STYLE_NAME
)
for
cur_root
,
dirs
,
files
in
os
.
walk
(
root
):
dirs
[:]
=
[
path
for
path
in
dirs
if
not
path
.
startswith
(
"."
)]
files
[:]
=
[
file
for
file
in
files
if
not
file
.
startswith
(
"."
)
and
not
file
in
self
.
IGNORE_FILES
]
# render and write index.html
self
.
_write_index_file
(
cur_root
=
Path
(
cur_root
),
root
=
root
,
dirs
=
dirs
,
files
=
files
,
spinner
=
spinner
,
)
def
run
(
self
):
"""Run the command."""
with
YaspinWrapper
(
debug
=
self
.
debug
,
color
=
"cyan"
,
text
=
"Rendering..."
)
as
spinner
:
for
i
,
root
in
enumerate
(
self
.
roots
):
progress_str
=
(
f
"
{
i
+
1
:{
len
(
str
(
len
(
self
.
roots
)))
}}
/
{
len
(
self
.
roots
)
}
"
)
spinner
.
text
=
f
"[
{
progress_str
}
] rendering in
{
root
}
."
self
.
create_dirlisting_in_root
(
root
,
spinner
=
spinner
)
def
main
():
args
=
parse_args
()
cli
=
Cli
(
roots
=
args
.
roots
,
debug
=
args
.
debug
)
cli
.
run
()
if
__name__
==
"__main__"
:
main
()
poetry.lock
View file @
ef196458
...
...
@@ -153,6 +153,20 @@ requirements_deprecated_finder = ["pipreqs", "pip-api"]
colors = ["colorama (>=0.4.3,<0.5.0)"]
plugins = ["setuptools"]
[[package]]
name = "jinja2"
version = "3.0.1"
description = "A very fast and expressive template engine."
category = "main"
optional = false
python-versions = ">=3.6"
[package.dependencies]
MarkupSafe = ">=2.0"
[package.extras]
i18n = ["Babel (>=2.7)"]
[[package]]
name = "kiwisolver"
version = "1.3.2"
...
...
@@ -183,6 +197,14 @@ html5 = ["html5lib"]
htmlsoup = ["beautifulsoup4"]
source = ["Cython (>=0.29.7)"]
[[package]]
name = "markupsafe"
version = "2.0.1"
description = "Safely add untrusted strings to HTML/XML markup."
category = "main"
optional = false
python-versions = ">=3.6"
[[package]]
name = "matplotlib"
version = "3.4.3"
...
...
@@ -463,7 +485,7 @@ termcolor = ">=1.1.0,<2.0.0"
[metadata]
lock-version = "1.1"
python-versions = ">=3.9,<3.11"
content-hash = "
3df3d2b86614dbf3530b64458e1fd4d8e7c8170d08f6f2f4f158227d6e4673b4
"
content-hash = "
2ded71ac90683d8f0dfc0800a2b74a4f8d9732b33cf51b1208fabd7bbdf379f1
"
[metadata.files]
appdirs = [
...
...
@@ -521,6 +543,10 @@ isort = [
{file = "isort-5.9.3-py3-none-any.whl", hash = "sha256:e17d6e2b81095c9db0a03a8025a957f334d6ea30b26f9ec70805411e5c7c81f2"},
{file = "isort-5.9.3.tar.gz", hash = "sha256:9c2ea1e62d871267b78307fe511c0838ba0da28698c5732d54e2790bf3ba9899"},
]
jinja2 = [
{file = "Jinja2-3.0.1-py3-none-any.whl", hash = "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4"},
{file = "Jinja2-3.0.1.tar.gz", hash = "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"},
]
kiwisolver = [
{file = "kiwisolver-1.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1d819553730d3c2724582124aee8a03c846ec4362ded1034c16fb3ef309264e6"},
{file = "kiwisolver-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8d93a1095f83e908fc253f2fb569c2711414c0bfd451cab580466465b235b470"},
...
...
@@ -629,6 +655,42 @@ lxml = [
{file = "lxml-4.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:542d454665a3e277f76954418124d67516c5f88e51a900365ed54a9806122b83"},
{file = "lxml-4.6.3.tar.gz", hash = "sha256:39b78571b3b30645ac77b95f7c69d1bffc4cf8c3b157c435a34da72e78c82468"},
]
markupsafe = [
{file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"},
{file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"},
{file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"},
{file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"},
{file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"},
{file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"},
{file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"},
{file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"},
{file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"},
{file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"},
{file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"},
{file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"},
{file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"},
{file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"},
{file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"},
{file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"},
{file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"},
{file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"},
{file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"},
{file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"},
{file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"},
{file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"},
{file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"},
{file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"},
{file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"},
{file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"},
{file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"},
{file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"},
{file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"},
{file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"},
{file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"},
{file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"},
{file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"},
{file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"},
]
matplotlib = [
{file = "matplotlib-3.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5c988bb43414c7c2b0a31bd5187b4d27fd625c080371b463a6d422047df78913"},
{file = "matplotlib-3.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f1c5efc278d996af8a251b2ce0b07bbeccb821f25c8c9846bdcb00ffc7f158aa"},
...
...
pyproject.toml
View file @
ef196458
...
...
@@ -15,6 +15,7 @@ termcolor = "^1.1.0"
numpy
=
"^1.21.2"
yaspin
=
"^2.1.0"
humanize
=
"^3.11.0"
Jinja2
=
"^3.0.1"
[tool.poetry.dev-dependencies]
pylint
=
"^2.6.0"
...
...
templates/dirlisting.html.j2
0 → 100644
View file @
ef196458
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<meta
charset=
"UTF-8"
>
<title>
Index of "{{ dirname }}"
</title>
<link
rel=
"stylesheet"
href=
"{{ stylesheet_url }}"
>
</head>
<body>
<div
class=
"container"
>
<div
class=
"row mt-5"
>
<h1>
Index of "{{ dirname }}"
</h1>
</div>
<div
class=
"row mt-5"
>
<nav
aria-label=
"breadcrumb"
>
<ol
class=
"breadcrumb"
>
{% for bc in breadcrumbs %}
<li
class=
"breadcrumb-item{% if loop.last %} active{% endif %}"
>
<a
href=
"{{ bc[1] }}index.html"
>
{{ bc[0] }}
</a>
</li>
{% endfor %}
</ol>
</nav>
</div>
<div
class=
"row"
>
<table
class=
"table table-striped table-hover table-sm text-monospace"
>
<thead>
<tr>
<th></th>
<th>
Name
</th>
<th>
Modification Date
</th>
<th>
Size
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
‹
</td>
<td><a
href=
"../index.html"
>
Go up
</a></td>
<td></td>
<td></td>
</tr>
{% for dir in dirs %}
<tr>
<td>
🗀
</td>
<td>
<a
href=
"{{ dir.path.name }}/index.html"
>
{{ dir.path.name }}
</a>
</td>
<td>
{{ dir.date.strftime('%Y-%m-%d %H:%M') }}
</td>
<td>
-
</td>
</tr>
{% endfor %}
{% for file in files %}
<tr>
<td>
🗎
</td>
<td>
<a
href=
"{{ file.path.name }}"
>
{{ file.path.name }}
</a>
</td>
<td>
{{ file.date.strftime('%Y-%m-%d %H:%M') }}
</td>
<td>
{{ file.size|filesizeformat(binary=True) }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if not files and not dirs %}
<div
class=
"alert alert-danger"
>
🛇 No file or directory
</div>
{% endif %}
</div>
</div>
</body>
</html>
templates/dirlisting_style.css
0 → 100644
View file @
ef196458
*,
::after
,
::before
{
box-sizing
:
border-box
;
}
body
,
td
,
tfoot
,
th
,
thead
,
tr
{
border-color
:
inherit
;
border-style
:
solid
;
border-width
:
0
;
}
.text-monospace
{
font-family
:
monospace
;
}
.breadcrumb
{
display
:
flex
;
flex-wrap
:
wrap
;
padding
:
0
0
;
margin-bottom
:
1rem
;
list-style
:
none
;
}
.breadcrumb-item.active
{
color
:
#6c757d
;
}
.breadcrumb-item
+
.breadcrumb-item
{
padding-left
:
.5rem
;
}
.breadcrumb-item
+
.breadcrumb-item
::before
{
float
:
left
;
padding-right
:
.5rem
;
color
:
#6c757d
;
content
:
"/"
;
}
.container
{
max-width
:
960px
;
width
:
100%
;
padding-right
:
var
(
--bs-gutter-x
,
.75rem
);
padding-left
:
var
(
--bs-gutter-x
,
.75rem
);
margin-right
:
auto
;
margin-left
:
auto
;
}
.table
{
width
:
100%
;
margin-bottom
:
1rem
;
color
:
#000
;
vertical-align
:
middle
;
border-color
:
#000
;
}
.table
>
:not
(
caption
)
>
*
>
*
{
padding
:
.5rem
.5rem
;
background-color
:
transparent
;
border-bottom-width
:
1px
;
box-shadow
:
inset
0
0
0
9999px
transparent
;
}
.table
>
tbody
{
vertical-align
:
inherit
;
}
.table
>
thead
{
vertical-align
:
bottom
;
}
.table
>
:not
(
:last-child
)
>
:last-child
>
*
{
border-bottom-color
:
rgba
(
0
,
0
,
0
,
0.1
);
}
.table
>
tbody
>
tr
:nth-of-type
(
2
n
+
1
)
{
background-color
:
rgba
(
0
,
0
,
0
,
0.01
);
color
:
#252519
;
}
.table-hover
>
tbody
>
tr
:hover
{
background-color
:
rgba
(
0
,
0
,
0
,
0.05
);
color
:
#252519
;
}
.table-bordered
>
:not
(
caption
)
>
*
{
border-width
:
1px
0
;
}
.table-bordered
>
:not
(
caption
)
>
*
>
*
{
border-width
:
0
1px
;
}
.alert
{
text-align
:
center
;
border-radius
:
0.5rem
;
padding
:
0.5rem
;
}
.alert.alert-danger
{
background-color
:
#fcc
;
border
:
1px
solid
#faa
;
}
utils.py
View file @
ef196458
...
...
@@ -227,6 +227,24 @@ def create_relpath(path1: Path, path2: Optional[Path] = None) -> Path:
return
Path
(
os
.
path
.
relpath
(
path1
,
common_prefix
))
def
existing_dir_path
(
value
:
str
,
allow_none
=
False
)
->
Optional
[
Path
]:
if
not
value
or
value
.
lower
()
==
"none"
:
if
allow_none
:
return
None
else
:
raise
argparse
.
ArgumentTypeError
(
"`none` is not allowed here."
)
path
=
Path
(
value
)
if
path
.
is_file
():
raise
argparse
.
ArgumentTypeError
(
f
"
{
value
}
is a file. A directory is required."
)
elif
not
path
.
is_dir
():
raise
argparse
.
ArgumentTypeError
(
f
"
{
value
}
does not exist."
)
return
path
def
existing_file_path
(
value
:
str
,
allow_none
=
False
)
->
Optional
[
Path
]:
if
not
value
or
value
.
lower
()
==
"none"
:
if
allow_none
:
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment