The Beman Project's mission is to support the efficient design and adoption of the highest quality C++ Standard libraries through implementation experience, user feedback, and technical expertise. Founded at C++Now in 2024 the project strives to aggregate libraries proposed for ISO standardization making a simple usage experience for the C++ Community to try out new libraries. For library authors we assist by helping to make best modern development practices easy. Including CI, coverage, and packaging. This project is a completely volunteer effort. Please connect with us on our discourse or Discord if you'd like to help.
+
+
+
For Library Users
+
The Beman Project strives to be a distributor of a single-download library collection for C++ libraries proposed for standardization. Our goals are to provide stable distributions that match with the latest versions of C++ proposals. Check The Beman Libraries page. Please note that it's early days for the project so we're still building our tooling and other details. Please join the discussion at our discourse or Discord.
+
+
+
For Library Authors
+
Submission into the Beman Project is easy. Start a discussion on our discourse or Discord and the welcome team will help get you started. A general precondition is an intent to submit a library for standardization. If you don't have repository yet, or you want to upgrade to our standard we can help. Once your library is ready and has a paper, we'll include it in the Beman super project.
"
+ )
+
+
+def first_heading(markdown: str) -> str:
+ for line in markdown.splitlines():
+ if line.startswith("# "):
+ return line[2:].strip()
+ return "Blog post"
+
+
+def normalize_blog_post(source: Path, target: Path, authors: dict) -> dict:
+ metadata, body = strip_frontmatter(source.read_text())
+ slug = metadata.get("slug") or source.parent.name
+ post_date = source.parent.name[:10]
+ author_keys = metadata.get("authors") or []
+ if isinstance(author_keys, str):
+ author_keys = [author_keys]
+ author_names = [
+ authors.get(author_key, {}).get("name", str(author_key))
+ for author_key in author_keys
+ ]
+
+ body = "\n".join(
+ (
+ youtube_embed(line.strip())
+ if "youtu.be/" in line or "youtube.com/watch" in line
+ else line
+ )
+ for line in body.splitlines()
+ )
+ body = body.replace("", "")
+
+ page_meta = {
+ "title": first_heading(body),
+ "blog_post": True,
+ "post_date": post_date,
+ "author_names": ", ".join(author_names),
+ "comments": bool(metadata.get("comments", False)),
+ }
+ write_markdown_page(target / "index.md", page_meta, body)
+ copy_tree_if_exists(source.parent / "images", target / "images")
+ return {
+ "title": page_meta["title"],
+ "url": f"{slug}/",
+ "date": post_date,
+ "authors": page_meta["author_names"],
+ "tags": metadata.get("tags") or [],
+ }
+
+
+def migrate_blog(stage_root: Path, content_root: Path):
+ blog_source = stage_root / "blog"
+ blog_target = content_root / "blog"
+ blog_target.mkdir(parents=True, exist_ok=True)
+ authors = yaml.safe_load((blog_source / "authors.yml").read_text()) or {}
+ posts = []
+
+ for source in sorted(blog_source.glob("*/index.md"), reverse=True):
+ metadata, _ = strip_frontmatter(source.read_text())
+ slug = metadata.get("slug") or source.parent.name
+ posts.append(normalize_blog_post(source, blog_target / slug, authors))
+
+ cards = [
+ "---",
+ "title: Blog",
+ "---",
+ "",
+ "# Blog",
+ "",
+ '
',
+ ]
+ for post in posts:
+ tags = post["tags"]
+ if isinstance(tags, str):
+ tags = [tags]
+ tag_html = "".join(f'{tag}' for tag in tags)
+ cards.extend(
+ [
+ '',
+ f' ',
+ "