Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix project archive download and simplify building the docs for a single project #349

Merged
merged 6 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ doc/gallery/*
!doc/_templates/

# Ignore output of doc_archive_projects
assets/
# but don't ignore the projname/assets/
!*/assets/
*/_archive/

# Ignore output of doc_build_website
jupyter_execute/
Expand Down
4 changes: 1 addition & 3 deletions _extensions/gallery.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,7 @@ def generate_gallery(app):
continue
files = sort_index_first(files)

logger.info("\n\nGenerating %d %s %s examples\n"
"__________________________________________________"
% (len(files), section_title, title))
logger.info(f"building gallery... {section_title}: {len(files)} files")

basenames = []
for f in files:
Expand Down
8 changes: 8 additions & 0 deletions doc/_static/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,11 @@ https://github.com/executablebooks/sphinx-design/blob/cca2cfb1b4c0a55ecf6661889c
div.nbsite-metadata > p {
margin-bottom: 0 !important;
}

code.download.literal.xref.docutils {
background-color: inherit;
border: 0;
font-family: inherit;
font-weight: inherit;
font-size: inherit;
}
50 changes: 36 additions & 14 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@
'css/custom.css',
]

# templates_path += [
# '_templates'
# ]
templates_path.insert(0, '_templates')

# Don't copy the sources (notebook files) in builtdocs/_sources, they're heavy.
Expand Down Expand Up @@ -118,17 +115,15 @@
:columns: auto
:class: nbsite-metadata

:material-outlined:`download;24px` `Download project <../assets/_archives/{projectname}.zip>`_
:download:`Download project <./_archive/{projectname}.zip>`

{deployments}

"""

# Tried using the `download` role, with which Sphinx handles entirely the files to download.
# It grabs them and puts them in a _downloads folder, with a hash to prevent collisions.
# However the link was styled in a weird way (`downloads` not handled by the PyData Sphinx Theme?)
# Keeping that trick around as it is how it should be done, assuming the archives is in doc/projname/
# :download:`Download project <{projectname}.zip>`
# The `download` role indicates Sphinx to grab the file and put it in a _downloads folder,
# and in a hashed subfolder to prevent collisions.
# Some CSS was required to style it as it looked a little weird.

AUTHOR_TEMPLATE = '`{author} <https://github.com/{author}>`_'
DEPLOYMENT_TEMPLATE = """
Expand Down Expand Up @@ -203,9 +198,21 @@ def gallery_spec(name):
'skip': skip,
}

SINGLE_PROJECT = os.getenv('EXAMPLES_HOLOVIZ_DOC_ONE_PROJECT')
all_projects = all_project_names(root='gallery', exclude=DEFAULT_DOC_EXCLUDE)

# Only build the projects found in doc/
projects = all_project_names(root='gallery', exclude=DEFAULT_DOC_EXCLUDE)
print('Projects that will be built:', projects)
projects = [SINGLE_PROJECT] if SINGLE_PROJECT else all_projects

if SINGLE_PROJECT:
# Tell Sphinx to ignore other projects if they are already in doc/
exclude_patterns = [
os.path.join('gallery', project) + '*'
for project in all_projects
if project != SINGLE_PROJECT
]

print('Project(s) that will be built:', projects)

gallery_conf = {
'github_org': 'holoviz-topics',
Expand Down Expand Up @@ -233,13 +240,16 @@ def to_gallery_redirects():
redirects[project] = f'gallery/{project}/{index}'
return redirects


rediraffe_redirects = {
top_level_redirects = {
# For the transition between examples.pyviz.org and examples.holoviz.org
## Top level links
'user_guide': 'getting_started',
'make_project': 'contributing',
'maintenance' : 'index',
}

# Redirects from e.g. examples.holoviz.org/attractors/attractors to examples.holoviz.org/gallery/attractors/attractors
# since projects have been moved to /gallery (to avoid being at the top level and affecting the top-level toctree)
project_direct_links = {
## Direct links (examples moved to /gallery)
'attractors/attractors': 'gallery/attractors/attractors',
'attractors/attractors_panel': 'gallery/attractors/attractors_panel',
Expand Down Expand Up @@ -282,6 +292,18 @@ def to_gallery_redirects():
'uk_researchers/uk_researchers': 'gallery/uk_researchers/uk_researchers',
# TODO: uncomment walker_lake
# 'walker_lake/Walker_Lake': 'gallery/walker_lake/walker_lake',
}

if SINGLE_PROJECT:
project_direct_links = {
k: v
for k, v in project_direct_links.items()
if k.split('/')[0] == SINGLE_PROJECT
}

rediraffe_redirects = {
**top_level_redirects,
**project_direct_links,
# Links from e.g. /attractors to /gallery/attractors/index.html
**to_gallery_redirects(),
}
Expand Down
51 changes: 30 additions & 21 deletions dodo.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
'envs',
'test_data',
'builtdocs',
'assets',
'jupyter_execute',
'_extensions',
*glob.glob( '.*'),
Expand Down Expand Up @@ -1788,7 +1787,7 @@ def copy_notebooks(name):


def task_doc_archive_projects():
"""Archive projects to assets/_archives"""
"""Archive projects to <project>/_archive"""

def archive_project(root='', name='all', extension='.zip'):
projects = all_project_names(root) if name == 'all' else [name]
Expand Down Expand Up @@ -1838,18 +1837,22 @@ def _archive_project(project, extension):
with open(path, 'w') as f:
safe_dump(spec, f, default_flow_style=False, sort_keys=False)

archives_path = os.path.join('assets', '_archives')
if not os.path.exists(archives_path):
os.makedirs(archives_path)
tmp_target = f'{project}{extension}'

# Faster version than calling anaconda-project archive
aproject = Project(project, must_exist=True)
project_ops.archive(aproject, f"assets/_archives/{project}{extension}")
project_ops.archive(aproject, f'{project}{extension}')
# subprocess.run(
# ["anaconda-project", "archive", "--directory", f"{project}", f"assets/_archives/{project}CMD{extension}"],
# ["anaconda-project", "archive", "--directory", f"{project}", f"{project}{extension}"],
# check=True
# )

archive_path = os.path.join(project, '_archive')
if not os.path.exists(archive_path):
os.makedirs(archive_path)

shutil.move(tmp_target, os.path.join(archive_path, f'{project}{extension}'))

shutil.copyfile(tmp_path, path)
os.remove(tmp_path)

Expand All @@ -1861,21 +1864,15 @@ def _archive_project(project, extension):
readme_path.unlink()

def clean_archive():
projects = all_project_names(root='')
for project in projects:
for project in all_project_names(root=''):
_clean_archive(project)
assets_path = pathlib.Path('assets')
remove_empty_dirs(assets_path)

def _clean_archive(project):
_archives_path = pathlib.Path('assets', '_archives')
if not _archives_path.exists():
_archive_path = pathlib.Path(project, '_archive')
if not _archive_path.exists():
return
for ext in ('.zip', '.tar.bz2'):
archive_path = _archives_path / f'{project}{ext}'
if archive_path.exists():
print(f'Removing {archive_path}')
archive_path.unlink(archive_path)
print(f'Removing {_archive_path}')
shutil.rmtree(_archive_path)

return {
'actions': [archive_project],
Expand All @@ -1894,7 +1891,11 @@ def _clean_archive(project):


def task_doc_move_content():
"""Move content (assets, thumbnails, etc.) except notebooks from the project dir to the project doc dir"""
"""Move content like assets/, _archive or thumbnails/ except notebooks from the project dir to the project doc dir.

This allows Sphinx to see these files when building the docs and add them as static files automatically.
It doesn't mean these files are all automatically added to the built docs, they need to be referenced somehow.
"""

def move_content(root='', name='all'):
projects = all_project_names(root) if name == 'all' else [name]
Expand Down Expand Up @@ -2297,7 +2298,7 @@ def task_ae5_sync_project():
"""
Create/Update a project on AE5.

It expects the archive to be a .tar.bz2 saved in assets/_archives/
It expects the archive to be a .tar.bz2 saved in <name>/_archive/
If a project is found it will delete it automatically.
"""

Expand All @@ -2315,7 +2316,7 @@ def _sync_project(name, hostname, username, password):
return
print(f'Found {len(deployments)} deployments to start:\n{deployments}\n')

archive = pathlib.Path('assets', '_archives', f'{name}.tar.bz2')
archive = pathlib.Path(name, 'assets', 'archives', f'{name}.tar.bz2')
if not archive.exists():
raise FileNotFoundError(f'Expected archive {archive} not found')

Expand Down Expand Up @@ -2471,8 +2472,15 @@ def task_doc_project():
Run the following command to clean the outputs:
doit clean doc_project
"""
def setup(name):
os.environ['EXAMPLES_HOLOVIZ_DOC_ONE_PROJECT'] = name

def teardown(name):
os.environ.pop('EXAMPLES_HOLOVIZ_DOC_ONE_PROJECT', None)

return {
'actions': [
setup,
'doit doc_archive_projects --name %(name)s',
'doit doc_move_content --name %(name)s',
'doit doc_build_website',
Expand All @@ -2482,6 +2490,7 @@ def task_doc_project():
'doit clean doc_move_content',
'doit clean doc_build_website',
],
'teardown': [teardown],
'params': [name_param],
}

Expand Down
Loading