#!/usr/bin/env python3
# ---
# Copyright 2020 glowinthedark
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
#
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# See the License for the specific language governing permissions and limitations under the License.
# ---
#
# Generate index.html files for
# all subdirectories in a directory tree.
# -handle symlinked files and folders: displayed with custom icons
# By default only the current folder is processed.
# Use -r or --recursive to process nested folders.
import argparse
import datetime
import os
import sys
from pathlib import Path
from urllib.parse import quote
DEFAULT_OUTPUT_FILE = 'index.html'
EXCLUDED_PATHS = ['.git']
def process_dir(top_dir, opts):
path_top_dir: Path
path_top_dir = Path(top_dir)
index_file = None
index_path = Path(path_top_dir, opts.output_file)
if opts.verbose:
print(f'Traversing dir {path_top_dir.absolute()}')
# skip allure report dirs
if os.path.exists(index_path) and os.path.exists(Path(path_top_dir, 'history')) and os.path.exists(Path(path_top_dir, 'data')):
if opts.verbose:
print(f'Skipping Allure test report dir {path_top_dir.absolute()}')
return
try:
index_file = open(index_path, 'w')
except Exception as e:
print('cannot create file %s %s' % (index_path, e))
return
index_file.write("""
""")
# sort dirs first
sorted_entries = sorted(path_top_dir.glob('*'), key=lambda p: (p.is_file(), p.name), reverse=True)
entry: Path
for entry in sorted_entries:
# don't include index.html in the file listing
if entry.name.lower() == opts.output_file.lower():
continue
if entry.name.lower() in EXCLUDED_PATHS:
continue
if entry.is_dir() and opts.recursive:
process_dir(entry, opts)
# From Python 3.6, os.access() accepts path-like objects
if (not entry.is_symlink()) and not os.access(str(entry), os.W_OK):
print(f"*** WARNING *** entry {entry.absolute()} is not writable! SKIPPING!")
continue
if opts.verbose:
print(f'{entry.absolute()}')
size_bytes = -1 ## is a folder
size_pretty = '—'
last_modified = '-'
last_modified_human_readable = '-'
last_modified_iso = ''
try:
if entry.is_file():
size_bytes = entry.stat().st_size
size_pretty = pretty_size(size_bytes)
if entry.is_dir() or entry.is_file():
last_modified = datetime.datetime.fromtimestamp(entry.stat().st_mtime).replace(microsecond=0)
last_modified_iso = last_modified.isoformat()
last_modified_human_readable = last_modified.strftime("%c")
except Exception as e:
print('ERROR accessing file name:', e, entry)
continue
entry_path = str(entry.name)
if entry.is_dir() and not entry.is_symlink():
entry_type = 'folder'
if os.name not in ('nt',):
# append trailing slash to dirs, unless it's windows
entry_path = os.path.join(entry.name, '')
elif entry.is_dir() and entry.is_symlink():
entry_type = 'folder-shortcut'
print('dir-symlink', entry.absolute())
elif entry.is_file() and entry.is_symlink():
entry_type = 'file-shortcut'
print('file-symlink', entry.absolute())
else:
entry_type = 'file'
index_file.write(f"""