Skip to content

Commit 8a5c536

Browse files
authored
Merge pull request #185 from knitli/claude/fix-relative-paths-01982YFFb4V8714SNxCMGiqq
fix: resolve critical relative path issues in packaged build Approved. There are two failing tests from other work; will be resolved in other commits.
2 parents a1b7b0b + a40113f commit 8a5c536

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+457
-32
lines changed

mise.toml

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,132 @@ git-cliff --tag "${usage_tag:?}" --prepend --output CHANGELOG.md &&
342342
echo "✅ CHANGELOG.md generated for ${usage_tag:?}!"
343343
'''
344344

345+
[tasks.prepare-version]
346+
description = "Prepare build artifacts for a new version release"
347+
usage = '''
348+
arg "[version]" {
349+
help = "Version to prepare (e.g., 1.2.0). If not provided, will prompt."
350+
}
351+
flag "--no-commit" {
352+
help = "Don't commit the changes, just generate artifacts"
353+
}
354+
flag "--no-tag" {
355+
help = "Don't create a git tag"
356+
}
357+
flag "--push" {
358+
help = "Push changes and tags to remote after committing"
359+
}
360+
'''
361+
run = '''
362+
#!/usr/bin/env bash
363+
set -e
364+
365+
# Colors for output
366+
GREEN='\033[0;32m'
367+
YELLOW='\033[1;33m'
368+
BLUE='\033[0;34m'
369+
RED='\033[0;31m'
370+
NC='\033[0m' # No Color
371+
372+
echo -e "${BLUE}[codeweaver]${NC} Preparing version release..."
373+
374+
# Get version
375+
VERSION="${usage_version:-}"
376+
if [ -z "$VERSION" ]; then
377+
read -p "Enter version number (e.g., 1.2.0): " VERSION
378+
fi
379+
380+
# Validate version format
381+
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
382+
echo -e "${RED}Error: Invalid version format. Use semantic versioning (e.g., 1.2.0)${NC}"
383+
exit 1
384+
fi
385+
386+
echo -e "${BLUE}[codeweaver]${NC} Preparing version ${GREEN}v${VERSION}${NC}..."
387+
388+
# Step 1: Run build preparation
389+
echo -e "${BLUE}[codeweaver]${NC} Step 1/5: Running build preparation..."
390+
uv run python scripts/build/prepare-build.py || {
391+
echo -e "${RED}Build preparation failed!${NC}"
392+
exit 1
393+
}
394+
395+
# Step 2: Check for generated artifacts
396+
echo -e "${BLUE}[codeweaver]${NC} Step 2/5: Verifying generated artifacts..."
397+
if [ ! -f "src/codeweaver/data/node_types_cache.pkl" ]; then
398+
echo -e "${YELLOW}Warning: node_types_cache.pkl not found${NC}"
399+
fi
400+
401+
# Step 3: Update CHANGELOG
402+
echo -e "${BLUE}[codeweaver]${NC} Step 3/5: Updating CHANGELOG.md..."
403+
git-cliff --tag "v${VERSION}" --prepend --output CHANGELOG.md || {
404+
echo -e "${YELLOW}Warning: Failed to update CHANGELOG${NC}"
405+
}
406+
407+
# Step 4: Commit if not disabled
408+
if [ -z "${usage_no_commit:-}" ]; then
409+
echo -e "${BLUE}[codeweaver]${NC} Step 4/5: Committing build artifacts..."
410+
git add src/codeweaver/data/node_types_cache.pkl 2>/dev/null || true
411+
git add CHANGELOG.md 2>/dev/null || true
412+
git add schema/ 2>/dev/null || true
413+
414+
if ! git diff --cached --quiet; then
415+
git commit -m "chore: prepare build artifacts for v${VERSION}
416+
417+
- Update node_types cache
418+
- Generate schema for v${VERSION}
419+
- Update CHANGELOG.md" || {
420+
echo -e "${RED}Commit failed!${NC}"
421+
exit 1
422+
}
423+
echo -e "${GREEN}✓ Build artifacts committed${NC}"
424+
else
425+
echo -e "${YELLOW}No changes to commit${NC}"
426+
fi
427+
else
428+
echo -e "${YELLOW}Skipping commit (--no-commit flag)${NC}"
429+
fi
430+
431+
# Step 5: Tag if not disabled
432+
if [ -z "${usage_no_tag:-}" ] && [ -z "${usage_no_commit:-}" ]; then
433+
echo -e "${BLUE}[codeweaver]${NC} Step 5/5: Creating git tag v${VERSION}..."
434+
git tag -a "v${VERSION}" -m "Release v${VERSION}" || {
435+
echo -e "${RED}Tagging failed!${NC}"
436+
exit 1
437+
}
438+
echo -e "${GREEN}✓ Created tag v${VERSION}${NC}"
439+
else
440+
echo -e "${YELLOW}Skipping tag creation${NC}"
441+
fi
442+
443+
# Push if requested
444+
if [ -n "${usage_push:-}" ]; then
445+
echo -e "${BLUE}[codeweaver]${NC} Pushing to remote..."
446+
git push && git push --tags || {
447+
echo -e "${RED}Push failed!${NC}"
448+
exit 1
449+
}
450+
echo -e "${GREEN}✓ Pushed to remote${NC}"
451+
fi
452+
453+
echo ""
454+
echo -e "${GREEN}════════════════════════════════════════════════${NC}"
455+
echo -e "${GREEN}✓ Version ${VERSION} prepared successfully!${NC}"
456+
echo -e "${GREEN}════════════════════════════════════════════════${NC}"
457+
echo ""
458+
echo -e "${BLUE}Next steps:${NC}"
459+
if [ -z "${usage_push:-}" ]; then
460+
echo -e " 1. Review the changes: ${YELLOW}git show${NC}"
461+
echo -e " 2. Push to remote: ${YELLOW}git push && git push --tags${NC}"
462+
fi
463+
echo -e " 3. Create GitHub release from tag v${VERSION}"
464+
echo ""
465+
'''
466+
run_windows = '''
467+
echo [codeweaver] Version preparation on Windows not yet supported. Use WSL or Linux.
468+
exit 1
469+
'''
470+
345471
[tasks.pre-commit]
346472
shell = "zsh -c"
347473
run = [

pyproject.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ __all__ = ("__version__",)
334334
[tool.hatch.build.targets.wheel]
335335
artifacts = ["*.so", "src/**"]
336336
packages = ["src/codeweaver"]
337-
include = ["node_types/**", "typings/**"]
337+
include = ["typings/**"]
338338

339339
[tool.hatch.build.targets.sdist]
340340
include = [
@@ -348,9 +348,10 @@ include = [
348348
"README.md",
349349
"context7.json",
350350
"context7.json.license",
351-
"node_types/**",
352351
"pyproject.toml",
353352
"sbom.spdx",
353+
"schema/**",
354+
"scripts/**",
354355
"src/**",
355356
"typings/**",
356357
"uv.lock",

scripts/build/generate-schema.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#!/usr/bin/env python3
2+
# SPDX-FileCopyrightText: 2025 Knitli Inc.
3+
# SPDX-FileContributor: Adam Poulemanos <adam@knit.li>
4+
#
5+
# SPDX-License-Identifier: MIT OR Apache-2.0
6+
"""Generate JSON schema for CodeWeaver settings.
7+
8+
This script generates the JSON schema file for CodeWeaver settings validation.
9+
It should be run during the build process when the schema version changes or
10+
when the schema file doesn't exist.
11+
"""
12+
13+
from __future__ import annotations
14+
15+
import sys
16+
from pathlib import Path
17+
18+
19+
def main() -> int:
20+
"""Generate the JSON schema file for CodeWeaver settings."""
21+
# Add src to path so we can import codeweaver
22+
repo_root = Path(__file__).parent.parent.parent
23+
src_path = repo_root / "src"
24+
if src_path not in sys.path:
25+
sys.path.insert(0, str(src_path))
26+
27+
from codeweaver.config.settings import CodeWeaverSettings
28+
29+
# Get the schema version from CodeWeaverSettings
30+
version = CodeWeaverSettings.model_fields["__version__"].default
31+
schema_dir = repo_root / "schema" / f"v{version}"
32+
schema_file = schema_dir / "codeweaver.schema.json"
33+
34+
# Check if schema file already exists
35+
if schema_file.exists():
36+
print(f"Schema file already exists: {schema_file}")
37+
print("Skipping schema generation. Delete the file to regenerate.")
38+
return 0
39+
40+
# Generate schema
41+
print(f"Generating schema for version {version}...")
42+
schema_dir.mkdir(parents=True, exist_ok=True)
43+
44+
schema_bytes = CodeWeaverSettings.json_schema()
45+
bytes_written = schema_file.write_bytes(schema_bytes)
46+
47+
print(f"✓ Generated schema file: {schema_file}")
48+
print(f" Size: {bytes_written:,} bytes")
49+
50+
return 0
51+
52+
53+
if __name__ == "__main__":
54+
sys.exit(main())

scripts/build/prepare-build.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#!/usr/bin/env python3
2+
# SPDX-FileCopyrightText: 2025 Knitli Inc.
3+
# SPDX-FileContributor: Adam Poulemanos <adam@knit.li>
4+
#
5+
# SPDX-License-Identifier: MIT OR Apache-2.0
6+
"""Master build preparation script for CodeWeaver.
7+
8+
This script orchestrates all the build preparation steps in the correct order:
9+
1. Generate supported languages list
10+
2. Generate provider lists
11+
3. Update node-types from tree-sitter grammars
12+
4. Preprocess node-types into cached format
13+
5. Generate JSON schema (if needed)
14+
"""
15+
16+
from __future__ import annotations
17+
18+
import subprocess
19+
import sys
20+
from pathlib import Path
21+
22+
23+
def run_script(script_path: Path, *args: str) -> int:
24+
"""Run a script and return its exit code."""
25+
script_name = script_path.name
26+
print(f"\n{'=' * 70}")
27+
print(f"Running: {script_name}")
28+
print(f"{'=' * 70}")
29+
30+
result = subprocess.run(
31+
[sys.executable, str(script_path), *args],
32+
cwd=script_path.parent.parent.parent,
33+
check=False,
34+
)
35+
36+
if result.returncode != 0:
37+
print(f"✗ {script_name} failed with exit code {result.returncode}")
38+
return result.returncode
39+
40+
print(f"✓ {script_name} completed successfully")
41+
return 0
42+
43+
44+
def main() -> int:
45+
"""Run all build preparation steps."""
46+
repo_root = Path(__file__).parent.parent.parent
47+
scripts_build = repo_root / "scripts" / "build"
48+
scripts_lang = repo_root / "scripts" / "language-support"
49+
50+
print("=" * 70)
51+
print("CodeWeaver Build Preparation")
52+
print("=" * 70)
53+
54+
# Step 1: Generate supported languages
55+
exit_code = run_script(scripts_build / "generate-supported-languages.py")
56+
if exit_code != 0:
57+
return exit_code
58+
59+
# Step 2: Generate provider lists
60+
exit_code = run_script(scripts_build / "generate-provider-lists.py")
61+
if exit_code != 0:
62+
return exit_code
63+
64+
# Step 3: Update node-types from tree-sitter grammars
65+
exit_code = run_script(
66+
scripts_lang / "download-ts-grammars.py", "fetch", "--only-update", "--only-node-types"
67+
)
68+
if exit_code != 0:
69+
return exit_code
70+
71+
# Step 4: Preprocess node-types into cache
72+
exit_code = run_script(scripts_build / "preprocess-node-types.py")
73+
if exit_code != 0:
74+
return exit_code
75+
76+
# Step 5: Generate schema (if needed)
77+
exit_code = run_script(scripts_build / "generate-schema.py")
78+
if exit_code != 0:
79+
return exit_code
80+
81+
print("\n" + "=" * 70)
82+
print("✓ Build preparation completed successfully!")
83+
print("=" * 70)
84+
85+
return 0
86+
87+
88+
if __name__ == "__main__":
89+
sys.exit(main())
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#!/usr/bin/env python3
2+
# SPDX-FileCopyrightText: 2025 Knitli Inc.
3+
# SPDX-FileContributor: Adam Poulemanos <adam@knit.li>
4+
#
5+
# SPDX-License-Identifier: MIT OR Apache-2.0
6+
"""Preprocess node-types JSON files and cache the parsed grammar data.
7+
8+
This script loads all tree-sitter node-types.json files, parses them into
9+
CodeWeaver's internal Thing/Category representation, and serializes the
10+
result to a pickle cache. This cache is loaded at runtime for fast startup.
11+
"""
12+
13+
from __future__ import annotations
14+
15+
import pickle
16+
import sys
17+
from pathlib import Path
18+
19+
20+
def main() -> int:
21+
"""Preprocess node types and generate cache file."""
22+
# Add src to path so we can import codeweaver
23+
repo_root = Path(__file__).parent.parent.parent
24+
src_path = repo_root / "src"
25+
if src_path not in sys.path:
26+
sys.path.insert(0, str(src_path))
27+
28+
from codeweaver.semantic.node_type_parser import NodeTypeParser
29+
30+
print("Preprocessing node-types JSON files...")
31+
32+
# Create parser and process all languages (disable cache since we're building it)
33+
parser = NodeTypeParser(use_cache=False)
34+
all_things = parser.parse_all_nodes()
35+
36+
print(f" Parsed {len(all_things)} Things/Categories across all languages")
37+
38+
# Get the cache from the parser's registration cache
39+
# Note: We only cache the registration_cache, not all_things,
40+
# since all_things can be reconstructed from the cache at runtime
41+
cache_data = {
42+
"registration_cache": parser.registration_cache,
43+
}
44+
45+
# Write cache file
46+
cache_file = repo_root / "src" / "codeweaver" / "data" / "node_types_cache.pkl"
47+
print(f"Writing cache to {cache_file}...")
48+
49+
with cache_file.open("wb") as f:
50+
pickle.dump(cache_data, f, protocol=pickle.HIGHEST_PROTOCOL)
51+
52+
cache_size = cache_file.stat().st_size
53+
print(f"✓ Generated node_types cache: {cache_file}")
54+
print(f" Size: {cache_size:,} bytes ({cache_size / 1024:.1f} KB)")
55+
56+
return 0
57+
58+
59+
if __name__ == "__main__":
60+
sys.exit(main())

src/codeweaver/__init__.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,21 @@ def get_version() -> str:
4848
import shutil
4949
import subprocess
5050

51-
from pathlib import Path
52-
53-
if git := (shutil.which("git") is not None):
51+
# Try to get version from git if available
52+
# Git commands work from any directory within a repo, so no need to specify cwd
53+
if git := shutil.which("git"):
5454
git_describe = subprocess.run(
55-
["describe", "--tags", "--always", "--dirty"], # noqa: S607
56-
executable=git,
55+
[git, "describe", "--tags", "--always", "--dirty"],
5756
capture_output=True,
5857
text=True,
59-
check=True,
60-
cwd=str(Path(__file__).parent.parent.parent),
58+
check=False,
6159
)
62-
__version__ = git_describe.stdout.strip()
60+
if git_describe.returncode == 0:
61+
__version__ = git_describe.stdout.strip()
62+
else:
63+
__version__ = "0.0.0"
64+
else:
65+
__version__ = "0.0.0"
6366
except Exception:
6467
__version__ = "0.0.0"
6568
return __version__

0 commit comments

Comments
 (0)