Skip to content

Commit 2627510

Browse files
committed
WIP
1 parent 9087a2b commit 2627510

9 files changed

+295
-100
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Base Greengrass directory definitions and structure
1+
# Base Greengrass directory definitions
22

33
GG_BASENAME = "greengrass/v2"
44
GG_ROOT = "${D}/${GG_BASENAME}"

classes/greengrass-component-plugin-common.inc

Lines changed: 0 additions & 12 deletions
This file was deleted.

classes/greengrass-component.bbclass

Lines changed: 109 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# AWS Greengrass Classic Component Class
1+
# AWS Greengrass Classic Component Class (V2 Java / bin)
22
#
33
# This bbclass supports Greengrass Classic (greengrass-bin) components.
44
# For Greengrass Lite components, use greengrass-lite-component.bbclass instead.
@@ -32,7 +32,69 @@
3232
# COMPONENT_ARTIFACTS = "hello_world.py"
3333
# inherit greengrass-component
3434

35-
require greengrass-component-plugin-common.inc
35+
require greengrass-common.inc
36+
37+
# Extract component information from YAML file, allow recipe override
38+
python __anonymous() {
39+
import yaml
40+
import os
41+
42+
# First, check if COMPONENT_NAME and COMPONENT_VERSION are already set in recipe
43+
component_name = d.getVar('COMPONENT_NAME')
44+
component_version = d.getVar('COMPONENT_VERSION')
45+
46+
# Check if component-recipe.yaml exists in SRC_URI
47+
src_uri = d.getVar('SRC_URI') or ''
48+
has_component_recipe = 'component-recipe.yaml' in src_uri
49+
50+
if has_component_recipe and (not component_name or not component_version):
51+
# Try to find the YAML file in the recipe directory
52+
file_dirname = d.getVar('FILE_DIRNAME')
53+
pn = d.getVar('PN')
54+
55+
# Look for component-recipe.yaml in the recipe's files directory
56+
possible_paths = [
57+
os.path.join(file_dirname, pn, 'component-recipe.yaml'),
58+
os.path.join(file_dirname, 'files', 'component-recipe.yaml'),
59+
os.path.join(file_dirname, pn.replace('greengrass-component-', ''), 'component-recipe.yaml')
60+
]
61+
62+
yaml_file = None
63+
for path in possible_paths:
64+
if os.path.exists(path):
65+
yaml_file = path
66+
break
67+
68+
if yaml_file:
69+
try:
70+
with open(yaml_file, 'r') as f:
71+
recipe = yaml.safe_load(f)
72+
73+
# Set COMPONENT_NAME from YAML if not already set in recipe
74+
if not component_name:
75+
yaml_component_name = recipe.get('ComponentName')
76+
if yaml_component_name:
77+
d.setVar('COMPONENT_NAME', yaml_component_name)
78+
bb.note(f"Set COMPONENT_NAME from YAML: {yaml_component_name}")
79+
component_name = yaml_component_name
80+
81+
# Set COMPONENT_VERSION from YAML if not already set in recipe
82+
if not component_version:
83+
yaml_component_version = recipe.get('ComponentVersion', '1.0.0')
84+
d.setVar('COMPONENT_VERSION', yaml_component_version)
85+
bb.note(f"Set COMPONENT_VERSION from YAML: {yaml_component_version}")
86+
component_version = yaml_component_version
87+
88+
except Exception as e:
89+
bb.warn(f"Could not read component info from YAML {yaml_file}: {e}")
90+
91+
# Ensure defaults are set if still not defined
92+
if not component_name:
93+
bb.error("COMPONENT_NAME must be set either in recipe or component-recipe.yaml")
94+
95+
if not component_version:
96+
d.setVar('COMPONENT_VERSION', '1.0.0')
97+
}
3698

3799
inherit deploy
38100

@@ -47,11 +109,11 @@ GREENGRASS_VARIANT ?= "classic"
47109
# Validate variant and warn about Lite
48110
python __anonymous() {
49111
variant = d.getVar('GREENGRASS_VARIANT')
50-
112+
51113
# Validate variant value
52114
if variant not in ['classic', 'lite']:
53115
bb.fatal(f"Invalid GREENGRASS_VARIANT '{variant}'. Must be 'classic' or 'lite'")
54-
116+
55117
if variant == 'lite':
56118
bb.warn("GREENGRASS_VARIANT='lite' detected. Consider using 'greengrass-lite-component' class for better Lite support and clearer image-provided component paths.")
57119
# Set basic Lite paths for backward compatibility
@@ -62,47 +124,47 @@ python __anonymous() {
62124
d.setVar('GG_COMPONENT_ROOT', '/${GG_BASENAME}/components')
63125
d.setVar('GG_CONFIG_DIR', '/${GG_BASENAME}/config')
64126
d.setVar('GG_CONFIG_FRAGMENT_DIR', 'greengrass-plugin-fragments')
65-
127+
66128
bb.note(f"Greengrass variant configured: {variant}")
67129
}
68130

69131
# Python function to convert component recipe to config fragment
70132
python convert_recipe_to_fragment() {
71133
import yaml
72134
import os
73-
135+
74136
recipe_file = d.getVar('recipe_file')
75137
output_file = d.getVar('output_file')
76138
variant = d.getVar('GREENGRASS_VARIANT')
77-
139+
78140
if not recipe_file or not os.path.exists(recipe_file):
79141
bb.error(f"Recipe file not found: {recipe_file}")
80142
d.setVar('CONVERSION_SUCCESS', '0')
81143
return
82-
144+
83145
if not output_file:
84146
bb.error("Output file not specified")
85147
d.setVar('CONVERSION_SUCCESS', '0')
86148
return
87-
149+
88150
try:
89151
with open(recipe_file, 'r') as f:
90152
recipe = yaml.safe_load(f)
91153
except Exception as e:
92154
bb.error(f"Error reading recipe file {recipe_file}: {e}")
93155
d.setVar('CONVERSION_SUCCESS', '0')
94156
return
95-
157+
96158
# Extract key information from the recipe
97159
component_name = recipe.get('ComponentName')
98160
component_version = recipe.get('ComponentVersion', '1.0.0')
99161
component_type = recipe.get('ComponentType', 'aws.greengrass.generic')
100-
162+
101163
if not component_name:
102164
bb.error("ComponentName not found in recipe")
103165
d.setVar('CONVERSION_SUCCESS', '0')
104166
return
105-
167+
106168
# Build the config fragment based on variant
107169
if variant == 'lite':
108170
# Greengrass Lite uses simpler YAML structure
@@ -114,12 +176,12 @@ python convert_recipe_to_fragment() {
114176
}
115177
}
116178
}
117-
179+
118180
# Add configuration if present
119181
config = recipe.get('ComponentConfiguration', {}).get('DefaultConfiguration', {})
120182
if config:
121183
fragment['services'][component_name]['configuration'] = config
122-
184+
123185
# Process manifests for lifecycle (simplified for lite)
124186
manifests = recipe.get('Manifests', [])
125187
if manifests:
@@ -137,34 +199,42 @@ python convert_recipe_to_fragment() {
137199
}
138200
}
139201
}
140-
202+
141203
# Add configuration if present
142204
config = recipe.get('ComponentConfiguration', {}).get('DefaultConfiguration', {})
143205
if config:
144206
fragment['services'][component_name]['configuration'] = config
145-
207+
146208
# Process manifests to extract lifecycle and artifacts
147209
manifests = recipe.get('Manifests', [])
148210
if manifests:
149211
# Use the first manifest (typically Linux)
150212
manifest = manifests[0]
151-
213+
152214
# Add lifecycle information
153215
lifecycle = manifest.get('Lifecycle', {})
154216
if lifecycle:
155-
fragment['services'][component_name]['Lifecycle'] = lifecycle
156-
217+
# Replace {artifacts:path} placeholder with actual component path
218+
component_path = f"/greengrass/v2/components/{component_name}/{component_version}"
219+
processed_lifecycle = {}
220+
for key, value in lifecycle.items():
221+
if isinstance(value, str):
222+
processed_lifecycle[key] = value.replace('{artifacts:path}', component_path)
223+
else:
224+
processed_lifecycle[key] = value
225+
fragment['services'][component_name]['Lifecycle'] = processed_lifecycle
226+
157227
# Add artifacts information
158228
artifacts = manifest.get('Artifacts', [])
159229
if artifacts:
160230
fragment['services'][component_name]['Artifacts'] = artifacts
161-
231+
162232
# Add dependencies structure for bin variant
163233
fragment['services']['main'] = {
164234
'dependencies': [component_name],
165235
'lifecycle': {}
166236
}
167-
237+
168238
# Write the fragment
169239
try:
170240
with open(output_file, 'w') as f:
@@ -221,14 +291,14 @@ python do_deploy() {
221291
import shutil
222292
import tempfile
223293
import subprocess
224-
294+
225295
variant = d.getVar('GREENGRASS_VARIANT')
226296
deploydir = d.getVar('DEPLOYDIR')
227297
component_name = d.getVar('COMPONENT_NAME')
228-
298+
229299
# Ensure DEPLOYDIR exists for all variants to satisfy sstate requirements
230300
os.makedirs(deploydir, exist_ok=True)
231-
301+
232302
# Skip actual deploy logic for lite components - everything is handled in do_install
233303
if variant == 'lite':
234304
bb.note("Skipping deploy for greengrass-lite component - config handled in do_install")
@@ -237,22 +307,22 @@ python do_deploy() {
237307
with open(marker_file, 'w') as f:
238308
f.write("Greengrass Lite component deployed via do_install\n")
239309
return
240-
310+
241311
# Only handle greengrass-bin components in deploy
242312
unpackdir = d.getVar('S') # Use S instead of UNPACKDIR for source files
243-
313+
244314
# For Greengrass Bin, use deployment directory for fragment merging
245315
fragment_dir = os.path.join(deploydir, d.getVar('GG_CONFIG_FRAGMENT_DIR'))
246316
os.makedirs(fragment_dir, exist_ok=True)
247317
fragment_file = os.path.join(fragment_dir, f"{component_name}.yaml")
248-
318+
249319
# Priority order for configuration files
250320
config_files = [
251321
'config.yaml.template', # Direct fragment (highest priority)
252322
'component-recipe.yaml', # Standard recipe (convert)
253323
'component-config.yaml.template' # Legacy format (convert)
254324
]
255-
325+
256326
for config_file in config_files:
257327
config_path = os.path.join(unpackdir, config_file)
258328
if os.path.exists(config_path):
@@ -264,11 +334,11 @@ python do_deploy() {
264334
# Convert recipe to fragment using inline function
265335
d.setVar('recipe_file', config_path)
266336
d.setVar('output_file', fragment_file)
267-
337+
268338
# Call conversion function and check success flag
269339
bb.build.exec_func('convert_recipe_to_fragment', d)
270340
success = d.getVar('CONVERSION_SUCCESS')
271-
341+
272342
if success == '1':
273343
bb.note(f"Converted {config_file} to config fragment for greengrass-bin")
274344
else:
@@ -297,7 +367,7 @@ addtask deploy after do_install before do_populate_sysroot
297367
python __anonymous() {
298368
variant = d.getVar('GREENGRASS_VARIANT')
299369
pn = d.getVar('PN')
300-
370+
301371
if variant == 'lite':
302372
# Greengrass Lite files
303373
files = d.getVar('FILES:' + pn) or ''
@@ -309,3 +379,11 @@ python __anonymous() {
309379
files += ' /${GG_BASENAME}/components/'
310380
d.setVar('FILES:' + pn, files)
311381
}
382+
383+
# Ensure all Greengrass plugins/components wait for greengrass-bin to install base structure
384+
python __anonymous() {
385+
pn = d.getVar('PN')
386+
if pn and pn != 'greengrass-bin*':
387+
# Add dependency on greengrass-bin's do_install task
388+
d.appendVarFlag('do_install', 'depends', ' greengrass-bin:do_install')
389+
}

classes/greengrass_lite_component.bbclass renamed to classes/greengrass-lite-component.bbclass

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,68 @@ COMPONENT_NAME ??= ""
1919
COMPONENT_VERSION ??= "1.0.0"
2020
COMPONENT_ARTIFACTS ??= ""
2121

22+
# Extract component information from YAML file, allow recipe override
23+
python __anonymous() {
24+
import yaml
25+
import os
26+
27+
# First, check if COMPONENT_NAME and COMPONENT_VERSION are already set in recipe
28+
component_name = d.getVar('COMPONENT_NAME')
29+
component_version = d.getVar('COMPONENT_VERSION')
30+
31+
# Check if component-recipe.yaml exists in SRC_URI
32+
src_uri = d.getVar('SRC_URI') or ''
33+
has_component_recipe = 'component-recipe.yaml' in src_uri
34+
35+
if has_component_recipe and (not component_name or not component_version):
36+
# Try to find the YAML file in the recipe directory
37+
file_dirname = d.getVar('FILE_DIRNAME')
38+
pn = d.getVar('PN')
39+
40+
# Look for component-recipe.yaml in the recipe's files directory
41+
possible_paths = [
42+
os.path.join(file_dirname, pn, 'component-recipe.yaml'),
43+
os.path.join(file_dirname, 'files', 'component-recipe.yaml'),
44+
os.path.join(file_dirname, pn.replace('greengrass-component-', ''), 'component-recipe.yaml')
45+
]
46+
47+
yaml_file = None
48+
for path in possible_paths:
49+
if os.path.exists(path):
50+
yaml_file = path
51+
break
52+
53+
if yaml_file:
54+
try:
55+
with open(yaml_file, 'r') as f:
56+
recipe = yaml.safe_load(f)
57+
58+
# Set COMPONENT_NAME from YAML if not already set in recipe
59+
if not component_name:
60+
yaml_component_name = recipe.get('ComponentName')
61+
if yaml_component_name:
62+
d.setVar('COMPONENT_NAME', yaml_component_name)
63+
bb.note(f"Set COMPONENT_NAME from YAML: {yaml_component_name}")
64+
component_name = yaml_component_name
65+
66+
# Set COMPONENT_VERSION from YAML if not already set in recipe
67+
if not component_version:
68+
yaml_component_version = recipe.get('ComponentVersion', '1.0.0')
69+
d.setVar('COMPONENT_VERSION', yaml_component_version)
70+
bb.note(f"Set COMPONENT_VERSION from YAML: {yaml_component_version}")
71+
component_version = yaml_component_version
72+
73+
except Exception as e:
74+
bb.warn(f"Could not read component info from YAML {yaml_file}: {e}")
75+
76+
# Ensure defaults are set if still not defined
77+
if not component_name:
78+
bb.error("COMPONENT_NAME must be set either in recipe or component-recipe.yaml")
79+
80+
if not component_version:
81+
d.setVar('COMPONENT_VERSION', '1.0.0')
82+
}
83+
2284
# Inherit base functionality
2385
inherit systemd
2486

0 commit comments

Comments
 (0)