fix(ci): repair all 3 QEMU workflow job failures
1. Fuzz Tests: add esp_timer_create_args_t, esp_timer_create(), esp_timer_start_periodic(), esp_timer_delete() stubs to esp_stubs.h — csi_collector.c uses these for channel hop timer. 2. QEMU Build: add libgcrypt20-dev to apt dependencies — Espressif QEMU's esp32_flash_enc.c includes <gcrypt.h>. Bump cache key v4→v5 to force rebuild with new dep. 3. NVS Matrix: switch to subprocess-first invocation of nvs_partition_gen to avoid 'str' has no attribute 'size' error from esp_idf_nvs_partition_gen API change. Falls back to direct import with both int and hex size args. Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
parent
8afd76da20
commit
a333951349
|
|
@ -38,7 +38,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
path: /opt/qemu-esp32
|
path: /opt/qemu-esp32
|
||||||
# Include date component so cache refreshes monthly when branch updates
|
# Include date component so cache refreshes monthly when branch updates
|
||||||
key: qemu-esp32s3-${{ env.QEMU_BRANCH }}-v4
|
key: qemu-esp32s3-${{ env.QEMU_BRANCH }}-v5
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
qemu-esp32s3-${{ env.QEMU_BRANCH }}-
|
qemu-esp32s3-${{ env.QEMU_BRANCH }}-
|
||||||
|
|
||||||
|
|
@ -49,6 +49,7 @@ jobs:
|
||||||
sudo apt-get install -y \
|
sudo apt-get install -y \
|
||||||
git build-essential ninja-build pkg-config \
|
git build-essential ninja-build pkg-config \
|
||||||
libglib2.0-dev libpixman-1-dev libslirp-dev \
|
libglib2.0-dev libpixman-1-dev libslirp-dev \
|
||||||
|
libgcrypt20-dev \
|
||||||
python3 python3-venv
|
python3 python3-venv
|
||||||
|
|
||||||
- name: Clone and build Espressif QEMU
|
- name: Clone and build Espressif QEMU
|
||||||
|
|
|
||||||
|
|
@ -33,12 +33,32 @@ typedef int esp_err_t;
|
||||||
/* ---- esp_timer.h ---- */
|
/* ---- esp_timer.h ---- */
|
||||||
typedef void *esp_timer_handle_t;
|
typedef void *esp_timer_handle_t;
|
||||||
|
|
||||||
|
/** Timer callback type (matches ESP-IDF signature). */
|
||||||
|
typedef void (*esp_timer_cb_t)(void *arg);
|
||||||
|
|
||||||
|
/** Timer creation arguments (matches ESP-IDF esp_timer_create_args_t). */
|
||||||
|
typedef struct {
|
||||||
|
esp_timer_cb_t callback;
|
||||||
|
void *arg;
|
||||||
|
const char *name;
|
||||||
|
} esp_timer_create_args_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stub: returns a monotonically increasing microsecond counter.
|
* Stub: returns a monotonically increasing microsecond counter.
|
||||||
* Declared here, defined in esp_stubs.c.
|
* Declared here, defined in esp_stubs.c.
|
||||||
*/
|
*/
|
||||||
int64_t esp_timer_get_time(void);
|
int64_t esp_timer_get_time(void);
|
||||||
|
|
||||||
|
/** Stub: timer lifecycle (no-ops for fuzz testing). */
|
||||||
|
static inline esp_err_t esp_timer_create(const esp_timer_create_args_t *args, esp_timer_handle_t *h) {
|
||||||
|
(void)args; if (h) *h = (void *)1; return ESP_OK;
|
||||||
|
}
|
||||||
|
static inline esp_err_t esp_timer_start_periodic(esp_timer_handle_t h, uint64_t period) {
|
||||||
|
(void)h; (void)period; return ESP_OK;
|
||||||
|
}
|
||||||
|
static inline esp_err_t esp_timer_stop(esp_timer_handle_t h) { (void)h; return ESP_OK; }
|
||||||
|
static inline esp_err_t esp_timer_delete(esp_timer_handle_t h) { (void)h; return ESP_OK; }
|
||||||
|
|
||||||
/* ---- esp_wifi_types.h ---- */
|
/* ---- esp_wifi_types.h ---- */
|
||||||
|
|
||||||
/** Minimal rx_ctrl fields needed by csi_serialize_frame. */
|
/** Minimal rx_ctrl fields needed by csi_serialize_frame. */
|
||||||
|
|
|
||||||
|
|
@ -266,10 +266,10 @@ def generate_nvs_binary(csv_content: str, size: int) -> bytes:
|
||||||
"""Generate an NVS partition binary from CSV content.
|
"""Generate an NVS partition binary from CSV content.
|
||||||
|
|
||||||
Tries multiple methods to find nvs_partition_gen:
|
Tries multiple methods to find nvs_partition_gen:
|
||||||
1. esp_idf_nvs_partition_gen pip package
|
1. Subprocess invocation (most reliable across package versions)
|
||||||
2. Legacy nvs_partition_gen pip package
|
2. esp_idf_nvs_partition_gen pip package (direct import)
|
||||||
3. ESP-IDF bundled script (via IDF_PATH)
|
3. Legacy nvs_partition_gen pip package
|
||||||
4. Module invocation
|
4. ESP-IDF bundled script (via IDF_PATH)
|
||||||
"""
|
"""
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
@ -281,25 +281,36 @@ def generate_nvs_binary(csv_content: str, size: int) -> bytes:
|
||||||
bin_path = csv_path.replace(".csv", ".bin")
|
bin_path = csv_path.replace(".csv", ".bin")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Try pip-installed version first
|
# Method 1: subprocess invocation (most reliable — avoids API changes)
|
||||||
try:
|
for module_name in ["esp_idf_nvs_partition_gen", "nvs_partition_gen"]:
|
||||||
from esp_idf_nvs_partition_gen import nvs_partition_gen
|
try:
|
||||||
nvs_partition_gen.generate(csv_path, bin_path, size)
|
subprocess.check_call(
|
||||||
with open(bin_path, "rb") as f:
|
[sys.executable, "-m", module_name, "generate",
|
||||||
return f.read()
|
csv_path, bin_path, hex(size)],
|
||||||
except ImportError:
|
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
|
||||||
pass
|
)
|
||||||
|
with open(bin_path, "rb") as f:
|
||||||
|
return f.read()
|
||||||
|
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||||
|
continue
|
||||||
|
|
||||||
# Try legacy import
|
# Method 2: direct import (handles older API where generate() takes int)
|
||||||
try:
|
for module_name in ["esp_idf_nvs_partition_gen.nvs_partition_gen",
|
||||||
import nvs_partition_gen
|
"nvs_partition_gen"]:
|
||||||
nvs_partition_gen.generate(csv_path, bin_path, size)
|
try:
|
||||||
with open(bin_path, "rb") as f:
|
mod = __import__(module_name, fromlist=["generate"])
|
||||||
return f.read()
|
# Try int size first, then hex string (API varies by version)
|
||||||
except ImportError:
|
for size_arg in [size, hex(size)]:
|
||||||
pass
|
try:
|
||||||
|
mod.generate(csv_path, bin_path, size_arg)
|
||||||
|
with open(bin_path, "rb") as f:
|
||||||
|
return f.read()
|
||||||
|
except (TypeError, AttributeError):
|
||||||
|
continue
|
||||||
|
except ImportError:
|
||||||
|
continue
|
||||||
|
|
||||||
# Try ESP-IDF bundled script
|
# Method 3: ESP-IDF bundled script
|
||||||
idf_path = os.environ.get("IDF_PATH", "")
|
idf_path = os.environ.get("IDF_PATH", "")
|
||||||
gen_script = os.path.join(
|
gen_script = os.path.join(
|
||||||
idf_path, "components", "nvs_flash",
|
idf_path, "components", "nvs_flash",
|
||||||
|
|
@ -313,25 +324,16 @@ def generate_nvs_binary(csv_content: str, size: int) -> bytes:
|
||||||
with open(bin_path, "rb") as f:
|
with open(bin_path, "rb") as f:
|
||||||
return f.read()
|
return f.read()
|
||||||
|
|
||||||
# Last resort: try as a module
|
print("ERROR: NVS partition generator tool not found.", file=sys.stderr)
|
||||||
try:
|
print("Install: pip install esp-idf-nvs-partition-gen", file=sys.stderr)
|
||||||
subprocess.check_call([
|
print("Or set IDF_PATH to your ESP-IDF installation", file=sys.stderr)
|
||||||
sys.executable, "-m", "nvs_partition_gen", "generate",
|
raise RuntimeError(
|
||||||
csv_path, bin_path, hex(size)
|
"NVS partition generator not available. "
|
||||||
])
|
"Install: pip install esp-idf-nvs-partition-gen"
|
||||||
with open(bin_path, "rb") as f:
|
)
|
||||||
return f.read()
|
|
||||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
||||||
print("ERROR: NVS partition generator tool not found.", file=sys.stderr)
|
|
||||||
print("Install: pip install esp-idf-nvs-partition-gen", file=sys.stderr)
|
|
||||||
print("Or set IDF_PATH to your ESP-IDF installation", file=sys.stderr)
|
|
||||||
raise RuntimeError(
|
|
||||||
"NVS partition generator not available. "
|
|
||||||
"Install: pip install esp-idf-nvs-partition-gen"
|
|
||||||
)
|
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
for p in set((csv_path, bin_path)): # deduplicate in case paths are identical
|
for p in set((csv_path, bin_path)):
|
||||||
if os.path.isfile(p):
|
if os.path.isfile(p):
|
||||||
os.unlink(p)
|
os.unlink(p)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue