Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
984 changes: 984 additions & 0 deletions Cargo.lock

Large diffs are not rendered by default.

43 changes: 43 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Location: ./Cargo.toml
# Copyright 2025
# SPDX-License-Identifier: Apache-2.0
# Authors: Teryl Taylor
#
# Workspace root for the CPEX Rust crates.

[workspace]
resolver = "2"
members = [
"crates/cpex-core",
"crates/cpex-sdk",
"crates/cpex-ffi",
"crates/cpex-dynamic-plugin",
"crates/cpex-dynamic-plugin/examples/single-plugin",
"crates/cpex-dynamic-plugin/examples/multi-handler",
"crates/cpex-dynamic-plugin/examples/multi-plugin",
"examples/go-demo/ffi",
]

[workspace.package]
version = "0.1.0"
edition = "2021"
license = "Apache-2.0"
authors = ["Teryl Taylor"]

[workspace.dependencies]
tokio = { version = "1", features = ["full"] }
tokio-util = { version = "0.7", features = ["rt"] }
serde = { version = "1", features = ["derive", "rc"] }
serde_yaml = "0.9"
serde_json = "1"
async-trait = "0.1"
thiserror = "2"
tracing = "0.1"
uuid = { version = "1", features = ["v4", "serde"] }
paste = "1"
futures = "0.3"
hashbrown = "0.15"
arc-swap = "1.7"
wildmatch = "2"
rmp-serde = "1"
serde_bytes = "0.11"
249 changes: 249 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,36 @@ help:
@echo " sdist Build source distribution only"
@echo " verify Build and verify package with twine"
@echo ""
@echo "Rust (cpex-core / cpex-ffi / cpex-sdk):"
@echo " rust-build Build the Rust workspace (debug)"
@echo " rust-build-release Build the Rust workspace (release)"
@echo " rust-test Run all Rust workspace tests"
@echo " rust-test-ffi Run only the cpex-ffi crate tests"
@echo " rust-fmt Format Rust code with rustfmt"
@echo " rust-clippy Run clippy on the Rust workspace"
@echo " rust-lint Auto-fix style + clippy issues (alias for rust-lint-fix)"
@echo " rust-lint-fix Same as rust-lint — mutating fmt + clippy --fix"
@echo " rust-lint-check Read-only fmt --check + clippy (CI-safe)"
@echo " rust-clean Remove the Rust target/ directory"
@echo ""
@echo "Go (go/cpex):"
@echo " go-build Build the Go cpex package (requires libcpex_ffi)"
@echo " go-test Run Go tests"
@echo " go-test-race Run Go tests with the race detector"
@echo " go-fmt Format Go code with gofmt"
@echo " go-vet Run go vet"
@echo " go-lint Auto-fix style + lint issues (alias for go-lint-fix)"
@echo " go-lint-fix Same as go-lint — gofmt -w + vet + golangci-lint --fix"
@echo " go-lint-check Read-only gofmt -l + vet + golangci-lint (CI-safe)"
@echo ""
@echo "Examples:"
@echo " examples-build Build all Rust + Go examples (catches stale APIs)"
@echo " examples-run Run all examples end-to-end"
@echo ""
@echo "End-to-end:"
@echo " test-all Run Rust workspace tests + Go tests w/ -race"
@echo " ci Lint-check + tests + examples-build (CI gate)"
@echo ""
@echo "Utilities:"
@echo " clean Remove all artifacts and builds"
@echo " clean-all Remove artifacts, builds, and venv"
Expand Down Expand Up @@ -402,6 +432,225 @@ env-example:
@pip install settings-doc
@settings-doc generate --class cpex.framework.settings.PluginsSettings --output-format dotenv > .env.template

# =============================================================================
# Rust workspace (cpex-core, cpex-ffi, cpex-sdk)
# =============================================================================

CARGO ?= cargo
GO ?= go
GO_DIR = go/cpex

.PHONY: rust-build
rust-build:
@echo "🦀 Building Rust workspace (debug)..."
@$(CARGO) build --workspace
@echo "✅ Rust workspace built"

.PHONY: rust-build-release
rust-build-release:
@echo "🦀 Building Rust workspace (release)..."
@$(CARGO) build --release --workspace
@echo "✅ Rust workspace built (release)"

.PHONY: rust-test
rust-test:
@echo "🧪 Running Rust workspace tests..."
@$(CARGO) test --workspace
@echo "✅ Rust tests passed"

.PHONY: rust-test-ffi
rust-test-ffi:
@echo "🧪 Running cpex-ffi tests..."
@$(CARGO) test -p cpex-ffi --lib
@echo "✅ cpex-ffi tests passed"

.PHONY: rust-fmt
rust-fmt:
@echo "🦀 Formatting Rust code..."
@$(CARGO) fmt --all
@echo "✅ Rust code formatted"

.PHONY: rust-clippy
rust-clippy:
@echo "🦀 Running clippy..."
@$(CARGO) clippy --workspace --all-targets -- -D warnings
@echo "✅ Clippy clean"

# rust-lint is a developer convenience: format the code, then apply
# clippy's auto-fixes. --allow-dirty/--allow-staged let clippy run on
# in-progress edits rather than refusing on a non-clean tree.
.PHONY: rust-lint
rust-lint: rust-lint-fix

.PHONY: rust-lint-fix
rust-lint-fix:
@echo "🦀 Formatting + auto-fixing Rust..."
@$(CARGO) fmt --all
@$(CARGO) clippy --workspace --all-targets --fix --allow-dirty --allow-staged -- -D warnings
@echo "✅ Rust lint-fix complete"

# rust-lint-check is the CI-safe variant: no writes. Fails if formatting
# drifted (fmt --check) or clippy has any warning.
.PHONY: rust-lint-check
rust-lint-check:
@echo "🦀 Checking Rust formatting + clippy (read-only)..."
@$(CARGO) fmt --all -- --check
@$(CARGO) clippy --workspace --all-targets -- -D warnings
@echo "✅ Rust lint-check passed"

.PHONY: rust-clean
rust-clean:
@echo "🧹 Removing Rust target directory..."
@$(CARGO) clean
@echo "✅ target/ removed"

# =============================================================================
# Go bindings (go/cpex)
# =============================================================================
#
# go/cpex links against the cpex-ffi cdylib at target/release. Targets
# below that touch Go ensure the release build is current first — Go's
# linker errors on missing libcpex_ffi.dylib are easy to misread.

.PHONY: go-build
go-build: rust-build-release
@echo "🐹 Building Go cpex package..."
@cd $(GO_DIR) && $(GO) build ./...
@echo "✅ Go package built"

.PHONY: go-test
go-test: rust-build-release
@echo "🧪 Running Go tests..."
@cd $(GO_DIR) && $(GO) test -count=1 ./...
@echo "✅ Go tests passed"

.PHONY: go-test-race
go-test-race: rust-build-release
@echo "🧪 Running Go tests with race detector..."
@cd $(GO_DIR) && $(GO) test -count=1 -race ./...
@echo "✅ Go tests passed (with -race)"

.PHONY: go-vet
go-vet: rust-build-release
@echo "🐹 Running go vet..."
@cd $(GO_DIR) && $(GO) vet ./...
@echo "✅ go vet clean"

# go-fmt rewrites .go files in place via gofmt. Read-only counterpart
# is `gofmt -l`, used inside go-lint-check.
.PHONY: go-fmt
go-fmt:
@echo "🐹 Formatting Go code..."
@cd $(GO_DIR) && $(GO) fmt ./...
@echo "✅ Go code formatted"

# go-lint is a developer convenience: format, vet, then run
# golangci-lint with --fix. We require golangci-lint to be installed —
# print an install hint rather than silently skipping it (skipping
# would let style drift land unnoticed).
GOLANGCI_LINT ?= golangci-lint

.PHONY: go-lint
go-lint: go-lint-fix

.PHONY: go-lint-fix
go-lint-fix: rust-build-release
@command -v $(GOLANGCI_LINT) >/dev/null 2>&1 || { \
echo "❌ golangci-lint not found. Install:"; \
echo " brew install golangci-lint"; \
echo " # or: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest"; \
exit 1; \
}
@echo "🐹 Formatting + auto-fixing Go..."
@cd $(GO_DIR) && $(GO) fmt ./...
@cd $(GO_DIR) && $(GO) vet ./...
@cd $(GO_DIR) && $(GOLANGCI_LINT) run --fix ./...
@echo "✅ Go lint-fix complete"

# go-lint-check is the CI-safe variant: read-only. `gofmt -l` lists
# files that would be reformatted and we fail if that list is non-empty.
.PHONY: go-lint-check
go-lint-check: rust-build-release
@command -v $(GOLANGCI_LINT) >/dev/null 2>&1 || { \
echo "❌ golangci-lint not found. Install:"; \
echo " brew install golangci-lint"; \
echo " # or: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest"; \
exit 1; \
}
@echo "🐹 Checking Go formatting + vet + golangci-lint (read-only)..."
@cd $(GO_DIR) && unformatted=$$(gofmt -l .); \
if [ -n "$$unformatted" ]; then \
echo "❌ Files need formatting:"; echo "$$unformatted"; \
exit 1; \
fi
@cd $(GO_DIR) && $(GO) vet ./...
@cd $(GO_DIR) && $(GOLANGCI_LINT) run ./...
@echo "✅ Go lint-check passed"

# =============================================================================
# Examples
# =============================================================================
#
# Building examples is the cheapest way to catch stale public-API usage:
# cargo test / go test only build code reachable from tests, so an
# example file using a renamed function compiles fine in isolation but
# breaks at example-build time. Wire this into CI.

GO_EXAMPLES_DIR = examples/go-demo

.PHONY: rust-examples-build
rust-examples-build:
@echo "🦀 Building Rust examples..."
@$(CARGO) build --examples --workspace
@echo "✅ Rust examples built"

.PHONY: go-examples-build
go-examples-build: rust-build-release
@echo "🐹 Building Go examples..."
@cd $(GO_EXAMPLES_DIR) && $(GO) build ./...
@echo "✅ Go examples built"

.PHONY: examples-build
examples-build: rust-examples-build go-examples-build
@echo "✅ All examples built"

# Running examples — useful for manual smoke-testing. Output goes to
# stdout and may be noisy. Each example is self-contained: prints
# scenario output and exits 0 on success.
.PHONY: examples-run
examples-run: examples-build
@echo "🏃 Running cpex-core plugin_demo..."
@$(CARGO) run --example plugin_demo -p cpex-core --quiet >/dev/null
@echo "✅ plugin_demo OK"
@echo "🏃 Running cpex-core cmf_capabilities_demo..."
@$(CARGO) run --example cmf_capabilities_demo -p cpex-core --quiet >/dev/null
@echo "✅ cmf_capabilities_demo OK"
@echo "🏃 Running go-demo (generic payload)..."
@cd $(GO_EXAMPLES_DIR) && $(GO) run . >/dev/null
@echo "✅ go-demo OK"
@echo "🏃 Running go-demo cmf-demo..."
@cd $(GO_EXAMPLES_DIR) && $(GO) run ./cmd/cmf-demo >/dev/null
@echo "✅ cmf-demo OK"
@echo "✅ All examples ran successfully"

# =============================================================================
# End-to-end
# =============================================================================

# test-all bundles the Rust workspace tests and the Go tests under
# the race detector. Skips the Python pytest suite — use
# `make test rust-test go-test-race` if you want all three.
.PHONY: test-all
test-all: rust-test go-test-race
@echo "✅ Rust + Go test suites passed"

# ci is the canonical CI gate: read-only lint checks, full test
# suites, and example builds. If this passes locally, the same checks
# will pass in CI.
.PHONY: ci
ci: rust-lint-check test-all examples-build
@echo "✅ CI gate passed (lint + tests + examples)"

# =============================================================================
# Development shortcuts
# =============================================================================
Expand Down
Loading