blob: f7c604bf0e51a4f89eec8a64f3779630a83085e2 [file]
#!/usr/bin/python
##############################################################################
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
##############################################################################
# This script clones release branches such as branch-0.9 and then copies the user guide markdown
# for inclusion in the published documentation so that we publish user guides for released versions
# of Comet
import os
import xml.etree.ElementTree as ET
from pathlib import Path
def get_major_minor_version(version: str):
parts = version.split('.')
return f"{parts[0]}.{parts[1]}"
def get_version_from_pom():
pom_path = Path(__file__).parent.parent / "pom.xml"
tree = ET.parse(pom_path)
root = tree.getroot()
namespace = {'maven': 'http://maven.apache.org/POM/4.0.0'}
version_element = root.find('maven:version', namespace)
if version_element is not None:
return version_element.text
else:
raise ValueError("Could not find version in pom.xml")
def replace_in_files(root: str, filename_pattern: str, search: str, replace: str):
root_path = Path(root)
for file in root_path.rglob(filename_pattern):
text = file.read_text(encoding="utf-8")
updated = text.replace(search, replace)
if text != updated:
file.write_text(updated, encoding="utf-8")
print(f"Replaced {search} with {replace} in {file}")
def strip_conditional_blocks(root: str, mode: str):
if mode == "snapshot":
keep_marker = "<!-- IF_SNAPSHOT -->"
drop_marker = "<!-- IF_RELEASE -->"
elif mode == "release":
keep_marker = "<!-- IF_RELEASE -->"
drop_marker = "<!-- IF_SNAPSHOT -->"
else:
raise ValueError(f"mode must be 'snapshot' or 'release', got {mode!r}")
end_marker = "<!-- ENDIF -->"
root_path = Path(root)
for file_pattern in ("*.md", "*.rst"):
for file in root_path.rglob(file_pattern):
lines = file.read_text(encoding="utf-8").splitlines(keepends=True)
out = []
state = None # None, "keep", or "drop"
changed = False
for lineno, line in enumerate(lines, start=1):
stripped = line.strip()
if stripped == keep_marker or stripped == drop_marker:
if state is not None:
raise ValueError(
f"{file}:{lineno}: conditional block opened while already inside a block"
)
state = "keep" if stripped == keep_marker else "drop"
changed = True
elif stripped == end_marker:
if state is None:
raise ValueError(
f"{file}:{lineno}: ENDIF with no matching opener"
)
state = None
changed = True
elif state == "drop":
changed = True
else:
out.append(line)
if state is not None:
raise ValueError(f"{file}: unclosed conditional block")
if changed:
file.write_text("".join(out), encoding="utf-8")
print(f"Processed conditional blocks ({mode}) in {file}")
def insert_warning_after_asf_header(root: str, warning: str):
root_path = Path(root)
for file in root_path.rglob("*.md"):
lines = file.read_text(encoding="utf-8").splitlines(keepends=True)
new_lines = []
inserted = False
for line in lines:
new_lines.append(line)
if not inserted and "-->" in line:
new_lines.append(warning + "\n")
inserted = True
file.write_text("".join(new_lines), encoding="utf-8")
def get_user_guide_dir(major_minor: str):
if major_minor == "0.8" or major_minor == "0.9":
return "docs/source/user-guide"
else:
return "docs/source/user-guide/latest"
def publish_released_version(version: str):
major_minor = get_major_minor_version(version)
dir = get_user_guide_dir(major_minor)
os.system(f"git clone --depth 1 https://github.com/apache/datafusion-comet.git -b branch-{major_minor} comet-{major_minor}")
os.system(f"mkdir temp/user-guide/{major_minor}")
os.system(f"cp -rf comet-{major_minor}/{dir}/* temp/user-guide/{major_minor}")
# Strip snapshot-only content; keep release-only content
strip_conditional_blocks(f"temp/user-guide/{major_minor}", "release")
# Replace $COMET_VERSION with actual version
for file_pattern in ["*.md", "*.rst"]:
replace_in_files(f"temp/user-guide/{major_minor}", file_pattern, "$COMET_VERSION", version)
def generate_docs(snapshot_version: str, latest_released_version: str, previous_versions: list[str]):
# Strip release-only content; keep snapshot-only content for the latest (snapshot) docs
strip_conditional_blocks("temp/user-guide/latest", "snapshot")
# Replace $COMET_VERSION with actual version for snapshot version
for file_pattern in ["*.md", "*.rst"]:
replace_in_files(f"temp/user-guide/latest", file_pattern, "$COMET_VERSION", snapshot_version)
# Add user guide content for latest released versions
publish_released_version(latest_released_version)
# Add user guide content for older released versions
for version in previous_versions:
publish_released_version(version)
# add warning that this is out-of-date documentation
warning = f"""```{{warning}}
This is **out-of-date** documentation. The latest Comet release is version {latest_released_version}.
```"""
major_minor = get_major_minor_version(version)
insert_warning_after_asf_header(f"temp/user-guide/{major_minor}", warning)
if __name__ == "__main__":
print("Generating versioned user guide docs...")
snapshot_version = get_version_from_pom()
latest_released_version = "0.17.0"
previous_versions = ["0.13.0", "0.14.0", "0.15.0", "0.16.0"]
generate_docs(snapshot_version, latest_released_version, previous_versions)