Skip to content

Commit b6ffe25

Browse files
committed
Generate Workspace using Gita
This change adds the capability to generate a workspace directly from the known_good.json file. To achieve this, the known_good.json file is transformed into a configuration file for a git workspace management tool called gita, which is then used to check out all mentioned modules on the specific commit/branch that is given in known_good.json. In addition, the score_modules.MODULE.bazel is updated with local_path_overrides to the checked out modules. Hence, a bazel build will immediately work as expected. # Conflicts: # .gitignore
1 parent 73e92bb commit b6ffe25

File tree

5 files changed

+120
-5
lines changed

5 files changed

+120
-5
lines changed

.devcontainer/devcontainer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"name": "eclipse-s-core",
3-
"image": "ghcr.io/eclipse-score/devcontainer:1.0.0",
3+
"image": "ghcr.io/eclipse-score/devcontainer:v1.1.0",
4+
"postCreateCommand": "bash .devcontainer/prepare_workspace.sh",
45
"postStartCommand": "ssh-keygen -f '/home/vscode/.ssh/known_hosts' -R '[localhost]:2222' || true"
56
}

.devcontainer/prepare_workspace.sh

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
# Install pipx
5+
sudo apt update
6+
sudo apt install -y pipx
7+
8+
# Install gita
9+
pipx install gita
10+
11+
# Enable bash autocompletion for gita
12+
echo "eval \"\$(register-python-argcomplete gita -s bash)\"" >> ~/.bashrc
13+
14+
# Set GITA_PROJECT_HOME environment variable
15+
echo "export GITA_PROJECT_HOME=$(pwd)/.gita" >> ~/.bashrc
16+
GITA_PROJECT_HOME=$(pwd)/.gita
17+
mkdir -p "$GITA_PROJECT_HOME"
18+
export GITA_PROJECT_HOME
19+
20+
# Generate .gita-workspace.csv from known_good.json
21+
python3 tools/known_good_to_gita_workspace.py known_good.json .gita-workspace.csv
22+
python3 tools/update_module_from_known_good.py --override-type local_path
23+
24+
# Automagically clone repositories listed in .gita-workspace.csv
25+
echo "Cloning repositories listed in .gita-workspace.csv..."
26+
gita clone --preserve-path --from-file .gita-workspace.csv
27+
# Output the status of all cloned repositories
28+
echo "Status of all cloned repositories:"
29+
gita ll

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,8 @@ __pycache__/
2222
/_build
2323
/docs/ubproject.toml
2424
/docs/_collections
25+
26+
# Workspace files
27+
/score_*/
28+
/.gita/
29+
/.gita-workspace.csv
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/usr/bin/env python3
2+
import argparse
3+
import json
4+
import csv
5+
6+
MODULES_CSV_HEADER = [
7+
"repo_url",
8+
"name",
9+
"workspace_path",
10+
"version",
11+
"hash",
12+
"branch"
13+
]
14+
15+
def main():
16+
parser = argparse.ArgumentParser(description="Convert known_good.json to baseline.csv format.")
17+
parser.add_argument("input_json", help="Path to known_good.json")
18+
parser.add_argument("output_csv", help="Path to output baseline.csv")
19+
args = parser.parse_args()
20+
21+
with open(args.input_json, "r") as f:
22+
data = json.load(f)
23+
24+
modules = data.get("modules", {})
25+
rows = []
26+
for name, info in modules.items():
27+
repo_url = info.get("repo", "")
28+
if not repo_url:
29+
raise RuntimeError("repo must not be empty")
30+
31+
# default branch: main
32+
branch = info.get("branch", "main")
33+
34+
# if no hash is given, use branch
35+
hash_ = info.get("hash", branch)
36+
37+
# workspace_path is not available in known_good.json, default to name of repository
38+
workspace_path = name
39+
40+
# gita format: {url},{name},{path},{prop['type']},{repo_flags},{branch}
41+
row = [repo_url, name, workspace_path, "", "", hash_]
42+
rows.append(row)
43+
44+
with open(args.output_csv, "w", newline="") as f:
45+
writer = csv.writer(f)
46+
for row in rows:
47+
writer.writerow(row)
48+
49+
if __name__ == "__main__":
50+
main()

tools/update_module_from_known_good.py

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,24 @@ def generate_git_override_blocks(modules_dict: Dict[str, Any], repo_commit_dict:
9090

9191
return blocks
9292

93+
def generate_local_override_blocks(modules_dict: Dict[str, Any]) -> List[str]:
94+
"""Generate bazel_dep and local_path_override blocks for each module."""
95+
blocks = []
96+
97+
for name, module in modules_dict.items():
98+
block = (
99+
f'bazel_dep(name = "{name}")\n'
100+
'local_path_override(\n'
101+
f' module_name = "{name}",\n'
102+
f' path = "{name}",\n'
103+
')\n'
104+
)
105+
106+
blocks.append(block)
107+
108+
return blocks
93109

94-
def generate_file_content(modules: Dict[str, Any], repo_commit_dict: Dict[str, str], timestamp: Optional[str] = None) -> str:
110+
def generate_file_content(args: argparse.Namespace, modules: Dict[str, Any], repo_commit_dict: Dict[str, str], timestamp: Optional[str] = None) -> str:
95111
"""Generate the complete content for score_modules.MODULE.bazel."""
96112
# License header assembled with parenthesis grouping (no indentation preserved in output).
97113
header = (
@@ -117,7 +133,15 @@ def generate_file_content(modules: Dict[str, Any], repo_commit_dict: Dict[str, s
117133
"\n"
118134
)
119135

120-
blocks = generate_git_override_blocks(modules, repo_commit_dict)
136+
if args.override_type == "git":
137+
blocks = generate_git_override_blocks(modules, repo_commit_dict)
138+
else:
139+
header += (
140+
"# Note: This file uses local_path overrides. Ensure that local paths are set up correctly.\n"
141+
"\n"
142+
)
143+
blocks = generate_local_override_blocks(modules)
144+
121145

122146
if not blocks:
123147
raise SystemExit("No valid modules to generate git_override blocks")
@@ -149,6 +173,12 @@ def main() -> None:
149173
action="append",
150174
help="Override commit for a specific repo (format: <REPO_URL>@<COMMIT_SHA>)"
151175
)
176+
parser.add_argument(
177+
"--override-type",
178+
choices=["local_path", "git"],
179+
default="git",
180+
help="Type of override to use (default: git)"
181+
)
152182

153183
args = parser.parse_args()
154184

@@ -180,7 +210,7 @@ def main() -> None:
180210

181211
# Generate file content
182212
timestamp = data.get("timestamp") or datetime.now().isoformat()
183-
content = generate_file_content(modules, repo_commit_dict, timestamp)
213+
content = generate_file_content(args, modules, repo_commit_dict, timestamp)
184214

185215
if args.dry_run:
186216
print(f"Dry run: would write to {output_path}\n")
@@ -191,7 +221,7 @@ def main() -> None:
191221
else:
192222
with open(output_path, "w", encoding="utf-8") as f:
193223
f.write(content)
194-
print(f"Generated {output_path} with {len(modules)} git_override entries")
224+
print(f"Generated {output_path} with {len(modules)} {args.override_type}_override entries")
195225

196226

197227
if __name__ == "__main__":

0 commit comments

Comments
 (0)