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

Create script to symlink headers to old location #12817

Merged
merged 1 commit into from
Mar 31, 2025
Merged
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
83 changes: 83 additions & 0 deletions maintainers/link-headers
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/usr/bin/env python3

# This script must be run from the root of the Nix repository.
#
# For include path hygiene, we need to put headers in a separate
# directory than sources. But during development, it is nice to paths
# that are similar for headers and source files, e.g.
# `foo/bar/baz.{cc,hh}`, e.g. for less typing when opening one file, and
# then opening the other file.
#
# This script symlinks the headers next to the source files to
# facilitate such a development workflows. It also updates
# `.git/info/exclude` so that the symlinks are not accidentally committed
# by mistake.

from pathlib import Path
import subprocess
import os


def main() -> None:
# Path to the source directory
GIT_TOPLEVEL = Path(
subprocess.run(
["git", "rev-parse", "--show-toplevel"],
text=True,
stdout=subprocess.PIPE,
check=True,
).stdout.strip()
)

# Get header files from git
result = subprocess.run(
["git", "-C", str(GIT_TOPLEVEL), "ls-files", "*/include/nix/**.hh"],
text=True,
stdout=subprocess.PIPE,
check=True,
)
header_files = result.stdout.strip().split("\n")
header_files.sort()

links = []
for file_str in header_files:
project_str, header_str = file_str.split("/include/nix/", 1)
project = Path(project_str)
header = Path(header_str)

# Reconstruct the full path (relative to SRC_DIR) to the header file.
file = project / "include" / "nix" / header

# The symlink should be created at "project/header", i.e. next to the project's sources.
link = project / header

# Compute a relative path from the symlink's parent directory to the actual header file.
relative_source = os.path.relpath(
GIT_TOPLEVEL / file, GIT_TOPLEVEL / link.parent
)

# Create the symbolic link.
full_link_path = GIT_TOPLEVEL / link
full_link_path.parent.mkdir(parents=True, exist_ok=True)
if full_link_path.is_symlink():
full_link_path.unlink()
full_link_path.symlink_to(relative_source)
links.append(link)

# Generate .gitignore file
gitignore_path = GIT_TOPLEVEL / ".git" / "info" / "exclude"
gitignore_path.parent.mkdir(parents=True, exist_ok=True)
with gitignore_path.open("w") as gitignore:
gitignore.write("# DO NOT EDIT! Autogenerated\n")
gitignore.write(
"# Symlinks for headers to be next to sources for development\n"
)
gitignore.write('# Run "maintainers/link-headers" to regenerate\n\n')
gitignore.write('# Run "maintainers/link-headers" to regenerate\n\n')

for link in links:
gitignore.write(f"/{link}\n")


if __name__ == "__main__":
main()
Loading