-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathrtems-pkg
More file actions
executable file
·188 lines (145 loc) · 5.61 KB
/
Copy pathrtems-pkg
File metadata and controls
executable file
·188 lines (145 loc) · 5.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#!/usr/bin/env python3
import argparse
import shutil
import subprocess
import sys
import os
import logging
from abc import ABC, abstractmethod
logging.basicConfig(level=logging.INFO, format='%(message)s')
class PackagerError(Exception):
pass
class Packager(ABC):
def __init__(self, name: str):
self.name = name
def log(self, msg: str, level: str = "info"):
message = f"[{self.name.upper()}] {msg}"
if level == "error":
logging.error(message)
else:
logging.info(message)
@abstractmethod
def get_build_config(self, target: str) -> dict:
"""Subclasses must return the required path, command, and working directory."""
pass
def check_if_packager_exists(self, cmd):
"""Check if the required packaging tool is available in the system."""
tool_name = cmd[0]
if shutil.which(tool_name) is None:
self.log(f"Required tool '{tool_name}' not found in PATH.",
level="error")
raise PackagerError(
f"{tool_name} is not installed or not in PATH.")
def run(self, target: str, board_name: str):
config = self.get_build_config(target)
target_path = config['path']
cmd = config['cmd']
cwd = config.get('cwd') # Optional working directory
self.check_if_packager_exists(cmd)
if not os.path.exists(target_path):
self.log(f"Generated target not found: {target_path}",
level="error")
raise FileNotFoundError(f"Missing required path: {target_path}")
self.log(f"Building package for {board_name} from {target_path}...")
try:
subprocess.run(cmd, cwd=cwd, check=True)
self.log(f"SUCCESS: Package built successfully for {board_name}!")
except subprocess.CalledProcessError as e:
self.log(f"ERROR: Build failed with exit code {e.returncode}",
level="error")
raise PackagerError(f"{self.name} build failed") from e
class DEB(Packager):
def __init__(self):
super().__init__("deb")
def get_build_config(self, target: str) -> dict:
deb_dir = os.path.join('out', f"{target}.debian")
return {
'path': deb_dir,
'cmd': ['dpkg-buildpackage', '-b', '-uc', '-us'],
'cwd': deb_dir # dpkg needs to run inside the directory
}
class RPM(Packager):
def __init__(self):
super().__init__("rpm")
def get_build_config(self, target: str) -> dict:
spec_file = os.path.join('out', f"{target}.spec")
return {
'path': spec_file,
'cmd': ['rpmbuild', '-bb', spec_file],
'cwd': None # rpmbuild can run from anywhere
}
class PORTS(Packager):
def __init__(self):
super().__init__("ports")
def get_build_config(self, target: str) -> dict:
port_path = os.path.join('out', f"{target}.port")
return {
'path': port_path,
'cmd': ['make', 'package'],
'cwd': port_path
}
class PackagerFactory:
_packagers = {
# format_type: (waf_feature, packager_class)
'deb': ["deb", DEB],
'rpm': ["rpmspec", RPM],
'ports': ["ports", PORTS]
}
@classmethod
def get_packager(cls, format_type: str) -> Packager:
packager_class = cls._packagers.get(format_type.lower())
if not packager_class:
raise ValueError(f"Unsupported package format: {format_type}")
return packager_class[1]()
@classmethod
def get_waf_target(cls, format_type: str) -> str:
packager_info = cls._packagers.get(format_type.lower())
if not packager_info:
raise ValueError(f"Unsupported package format: {format_type}")
return packager_info[0] # Return the Waf feature
def main():
# Dynamically get available formats so we don't have to hardcode them
available_formats = list(PackagerFactory._packagers.keys())
parser = argparse.ArgumentParser(
description="RTEMS Deployment Package Builder",
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument(
'--packager',
choices=available_formats, # Dynamically populates: ['deb', 'rpm']
required=True,
help="Choose the packaging format to build")
parser.add_argument(
'--target',
type=str,
required=True,
help="Specify the board target (e.g., amd/amd-kria-k26)")
args = parser.parse_args()
board_name = args.target.split('/')[-1]
# PHASE 1: Generate templates using Waf
waf_target = PackagerFactory.get_waf_target(args.packager)
waf_cmd = ['./waf', waf_target]
logging.info(f"--> Generating templates: {' '.join(waf_cmd)}")
try:
subprocess.run(waf_cmd, check=True)
except subprocess.CalledProcessError as e:
logging.error(
f"[ERROR] Waf template generation failed with exit code {e.returncode}."
)
sys.exit(e.returncode)
except FileNotFoundError:
logging.error(
f"[ERROR] Waf executable not found in the current directory.")
sys.exit(1)
logging.info(f"Target: {args.target} | Board: {board_name}")
# PHASE 2: Execute the actual packaging tool via the Factory
try:
packager = PackagerFactory.get_packager(args.packager)
packager.run(args.target, board_name)
except PackagerError as e:
logging.error(f"Packaging process aborted: {e}")
sys.exit(1)
except ValueError as e:
logging.error(f"Configuration error: {e}")
sys.exit(1)
if __name__ == "__main__":
main()