Skip to content

Commit

Permalink
Fix and test prep script.
Browse files Browse the repository at this point in the history
  • Loading branch information
Zemnmez committed Jan 18, 2025
1 parent 0b075cc commit 971fb29
Show file tree
Hide file tree
Showing 13 changed files with 207 additions and 61 deletions.
2 changes: 1 addition & 1 deletion .vscode/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ alias(

alias(
name = "install_sapling_hooks",
actual = "//.vscode/prep:prep_bin",
actual = "//py/devtools/prep:prep_bin",
)

bazel_lint(
Expand Down
51 changes: 0 additions & 51 deletions .vscode/prep/__main__.py

This file was deleted.

15 changes: 14 additions & 1 deletion BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
load("//py:rules.bzl", "py_library")

# Add rules here to build your software
# See https://docs.bazel.build/versions/master/build-ref.html#BUILD_files

Expand Down Expand Up @@ -239,11 +241,14 @@ bazel_lint(
py_venv(
name = "venv",
deps = [
"//.vscode/prep:prep_bin",
"//bzl/versioning",
"//ini/git/merge_drivers/bazel_lockfile",
"//project/cultist/gen/testing",
"//py",
"//py/ci/postUpgrade:postUpgrade_bin",
"//py/devtools",
"//py/devtools/prep",
"//py/devtools/prep:prep_bin",
"//py/hello_world:hello_world_bin",
"//py/ibazel:ibazel_bin",
"//py/ipynb",
Expand All @@ -259,3 +264,11 @@ alias(
name = "go",
actual = "//sh/bin:go",
)

# gazelle:python_root

py_library(
name = "monorepo",
srcs = ["__init__.py"],
visibility = ["//:__subpackages__"],
)
5 changes: 5 additions & 0 deletions __init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""
The monorepo!
Apparently this file is mandatory in a lot of Python versions.
"""
7 changes: 7 additions & 0 deletions py/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
load("//bzl:rules.bzl", "bazel_lint")
load("//py:rules.bzl", "py_library")

"Root for pure python projects."

Expand All @@ -9,3 +10,9 @@ bazel_lint(
"rules.bzl",
],
)

py_library(
name = "py",
srcs = ["__init__.py"],
visibility = ["//:__subpackages__"],
)
2 changes: 2 additions & 0 deletions py/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

#
15 changes: 7 additions & 8 deletions .vscode/prep/BUILD.bazel → py/devtools/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
load("//bzl:rules.bzl", "bazel_lint")
load("//py:rules.bzl", "py_binary")
load("//py:rules.bzl", "py_library")

py_library(
name = "devtools",
srcs = ["__init__.py"],
visibility = ["//:__subpackages__"],
)

bazel_lint(
name = "bazel_lint",
srcs = ["BUILD.bazel"],
)

py_binary(
name = "prep_bin",
srcs = ["__main__.py"],
main = "__main__.py",
visibility = ["//:__subpackages__"],
)
1 change: 1 addition & 0 deletions py/devtools/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#
31 changes: 31 additions & 0 deletions py/devtools/prep/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
load("//bzl:rules.bzl", "bazel_lint")
load("//py:rules.bzl", "py_binary", "py_library", "py_test")

bazel_lint(
name = "bazel_lint",
srcs = ["BUILD.bazel"],
)

py_binary(
name = "prep_bin",
srcs = ["__main__.py"],
main = "__main__.py",
visibility = ["//:__subpackages__"],
deps = [":prep"],
)

py_test(
name = "prep_test",
srcs = ["__test__.py"],
main = "__test__.py",
deps = [":prep"],
)

py_library(
name = "prep",
srcs = [
"__init__.py",
"lib.py",
],
visibility = ["//:__subpackages__"],
)
1 change: 1 addition & 0 deletions py/devtools/prep/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#
3 changes: 3 additions & 0 deletions py/devtools/prep/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from py.devtools.prep.lib import main
if __name__ == "__main__":
main()
54 changes: 54 additions & 0 deletions py/devtools/prep/__test__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import os
import unittest
import tempfile
import shutil

from py.devtools.prep.lib import (
get_sapling_config_dir,
ensure_sapling_include,
configure_sapling,
)

class TestSaplingConfig(unittest.TestCase):
def setUp(self):
"""
Create a fresh temporary directory before each test,
mimicking Pytest's `tmp_path` fixture.
"""
self.tmp_dir = tempfile.mkdtemp()

def tearDown(self):
"""
Remove the temporary directory after each test.
"""
shutil.rmtree(self.tmp_dir)

def test_get_sapling_config_dir(self):
git_path = os.path.join(self.tmp_dir, ".git")
os.mkdir(git_path)
expected_dir = os.path.join(git_path, "sl")
actual_dir = get_sapling_config_dir(self.tmp_dir)
self.assertEqual(actual_dir, expected_dir)

def test_ensure_sapling_include(self):
config_file = os.path.join(self.tmp_dir, "config")

# File doesn’t exist initially
changed = ensure_sapling_include(config_file)
self.assertTrue(changed, "Should create file and prepend line.")

# Calling again detects it's already included
changed_again = ensure_sapling_include(config_file)
self.assertFalse(changed_again, "No change after second include.")

def test_configure_sapling(self):
configure_sapling(self.tmp_dir)
config_dir = os.path.join(self.tmp_dir, ".sl")
self.assertTrue(
os.path.isfile(os.path.join(config_dir, "config")),
"Config file should exist in .sl directory."
)


if __name__ == "__main__":
unittest.main()
81 changes: 81 additions & 0 deletions py/devtools/prep/lib.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#!/usr/bin/env python3

import os
import re
from argparse import ArgumentParser
from tempfile import TemporaryFile
from shutil import copyfileobj

def get_sapling_config_dir(working_directory: str) -> str:
"""
Determine the appropriate config directory for Sapling:
- If .git exists in working_directory, use .git/sl/
- Otherwise, use .sl/
"""
git_dir = os.path.join(working_directory, ".git")
if os.path.isdir(git_dir):
return os.path.join(git_dir, "sl")
return os.path.join(working_directory, ".sl")

def ensure_sapling_include(config_file_path: str) -> bool:
"""
Ensure the Sapling config file includes:
%include ../ini/sl/config.ini
If the include is missing, it is prepended, and the file is updated.
Returns True if the file was changed; False if it was already correct.
"""
# Create the directory for config_file_path if needed
os.makedirs(os.path.dirname(config_file_path), exist_ok=True)

# Open in "a+" mode so that the file is created if it does not exist
with open(config_file_path, "a+") as config_file:
# Move pointer to start for reading
config_file.seek(0)
lines = config_file.readlines()

# Regex to match line exactly: %%include ../ini/sl/config.ini
pattern = re.compile(r"^%include\s+\.\./ini/sl/config\.ini\s*$")

# If any line matches, there's nothing to fix
if any(pattern.match(line.strip()) for line in lines):
return False

print("It seems you're not importing the standard Sapling config. I'll fix this.")

# We need to prepend the missing line
config_file.seek(0)

# Clear the file using truncate, then rebuild
config_file.truncate()

# Prepend the missing line, then original lines
with TemporaryFile(mode="w+") as temp:
temp.write("%include ../ini/sl/config.ini" + os.linesep)
for line in lines:
temp.write(line)

# Copy temporary contents back into the original file
temp.seek(0)
copyfileobj(temp, config_file)

return True

def configure_sapling(working_directory: str) -> None:
"""
High-level function that locates the config directory and ensures the standard Sapling include.
"""
config_dir = get_sapling_config_dir(working_directory)
config_file_path = os.path.join(config_dir, "config")
ensure_sapling_include(config_file_path)

def main():
parser = ArgumentParser(
prog="scm-conf.py",
description="Configure local SCM to use repo config."
)
parser.add_argument(
"working_directory",
help="Directory to run in (exists due to Bazel stubbornness)."
)
args = parser.parse_args()
configure_sapling(args.working_directory)

0 comments on commit 971fb29

Please sign in to comment.