diff --git a/CHANGELOG.md b/CHANGELOG.md index 44c29828..331a7b30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ Draft for **2.3.0** (`versions.txt`). Compared to [v2.2.0](https://github.com/my ### Added +- Release archives for **macOS** (`darwin/amd64` Intel and `darwin/arm64` Apple Silicon). - **Created on** timestamp on all stored resources (gateway, node, source, field, firmware, dashboard, data repository, forward payload, schedule, task, handler, virtual device, virtual assistant, user, settings). New records get the current time. Existing records stay at the zero time (shown as empty / never). Policy and service account already had this field. - **Service account enable**: edit form, list, details, and bulk list actions (Enable / Disable), using the same `enabled` field as other resources. Accounts that are not enabled cannot log in or keep a session. - CLI: `myc disable service-account` / `myc enable sa` (optional `--user`). @@ -24,7 +25,7 @@ Draft for **2.3.0** (`versions.txt`). Compared to [v2.2.0](https://github.com/my ### Changed -- Release workflow builds host binaries (Go 1.27.1 in Actions) and copies only those binaries into Alpine 3.24 images on the same runner (no artifact upload/download). Images are pushed to GHCR, Quay, and Docker Hub. `main` republishes the `development` pre-release by deleting and recreating it. +- Release workflow builds host binaries (Go 1.27.1 in Actions) and copies only those binaries into Alpine 3.24 images on the same runner (no artifact upload/download). Images are pushed to GHCR, Quay, and Docker Hub as a single multi-arch `:${VERSION}` tag (no per-arch tags). `main` republishes the `development` pre-release by deleting and recreating it. - Policy **Import** uses `storage.Upsert` so `createdOn` / `modifiedOn` come from the backup file (same as other resources). Built-in policies are still skipped. - Built-in policies (admin / readwrite / readonly) are no longer rewritten on every start. `ModifiedOn` stays unless the code definition changed. Existing rows without `CreatedOn` are backfilled from `ModifiedOn` once. - `make setup-release` now requires both versions: `make setup-release VERSION=x.y.z NEXT_VERSION=x.y.z`. The PR writes `NEXT_VERSION` into `versions.txt`. diff --git a/docker/gateway.Dockerfile b/docker/gateway.Dockerfile index 9c3e9c1f..7df36647 100644 --- a/docker/gateway.Dockerfile +++ b/docker/gateway.Dockerfile @@ -2,7 +2,9 @@ FROM alpine:3.24 LABEL maintainer="Jeeva Kandasamy " -ARG BINARY_PATH=builds/binary/linux-amd64/mycontroller-gateway +ARG TARGETOS +ARG TARGETARCH +ARG TARGETVARIANT ENV APP_HOME="/app" \ DATA_HOME="/mc_home" @@ -10,7 +12,7 @@ ENV APP_HOME="/app" \ RUN apk --no-cache add ca-certificates tzdata \ && mkdir -p ${APP_HOME} ${DATA_HOME} -COPY ${BINARY_PATH} ${APP_HOME}/mycontroller-gateway +COPY builds/binary/${TARGETOS}-${TARGETARCH}${TARGETVARIANT}/mycontroller-gateway ${APP_HOME}/mycontroller-gateway COPY ./resources/sample-docker-gateway.yaml ${APP_HOME}/gateway.yaml RUN chmod +x ${APP_HOME}/mycontroller-gateway diff --git a/docker/handler.Dockerfile b/docker/handler.Dockerfile index 10f6e8c7..eca3ae6f 100644 --- a/docker/handler.Dockerfile +++ b/docker/handler.Dockerfile @@ -2,7 +2,9 @@ FROM alpine:3.24 LABEL maintainer="Jeeva Kandasamy " -ARG BINARY_PATH=builds/binary/linux-amd64/mycontroller-handler +ARG TARGETOS +ARG TARGETARCH +ARG TARGETVARIANT ENV APP_HOME="/app" \ DATA_HOME="/mc_home" @@ -10,7 +12,7 @@ ENV APP_HOME="/app" \ RUN apk --no-cache add ca-certificates tzdata \ && mkdir -p ${APP_HOME} ${DATA_HOME} -COPY ${BINARY_PATH} ${APP_HOME}/mycontroller-handler +COPY builds/binary/${TARGETOS}-${TARGETARCH}${TARGETVARIANT}/mycontroller-handler ${APP_HOME}/mycontroller-handler COPY ./resources/sample-docker-handler.yaml ${APP_HOME}/handler.yaml RUN chmod +x ${APP_HOME}/mycontroller-handler diff --git a/docker/server.Dockerfile b/docker/server.Dockerfile index bfcf791b..be34c329 100644 --- a/docker/server.Dockerfile +++ b/docker/server.Dockerfile @@ -2,7 +2,9 @@ FROM alpine:3.24 LABEL maintainer="Jeeva Kandasamy " -ARG BINARY_PATH=builds/binary/linux-amd64/mycontroller-server +ARG TARGETOS +ARG TARGETARCH +ARG TARGETVARIANT ENV APP_HOME="/app" \ DATA_HOME="/mc_home" @@ -13,7 +15,7 @@ EXPOSE 8080 8443 9443 RUN apk --no-cache add ca-certificates tzdata \ && mkdir -p ${APP_HOME} ${DATA_HOME} -COPY ${BINARY_PATH} ${APP_HOME}/mycontroller-server +COPY builds/binary/${TARGETOS}-${TARGETARCH}${TARGETVARIANT}/mycontroller-server ${APP_HOME}/mycontroller-server COPY ./resources/sample-docker-server.yaml ${APP_HOME}/mycontroller.yaml RUN chmod +x ${APP_HOME}/mycontroller-server diff --git a/go.mod b/go.mod index 6a126298..806014df 100644 --- a/go.mod +++ b/go.mod @@ -32,6 +32,7 @@ require ( github.com/stretchr/testify v1.11.1 github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 github.com/tidwall/sjson v1.2.5 + go.bug.st/serial v1.8.0 go.mongodb.org/mongo-driver v1.17.9 go.uber.org/zap v1.28.0 golang.org/x/crypto v0.54.0 diff --git a/go.sum b/go.sum index 2ac26a2c..c52a16f9 100644 --- a/go.sum +++ b/go.sum @@ -188,6 +188,8 @@ github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfS github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.bug.st/serial v1.8.0 h1:ZtnmN8aYXtPlTghwSvDWPHKBHL9TM6oFDa+KpSn4SQE= +go.bug.st/serial v1.8.0/go.mod h1:d0MmS16Qt9b1m06yoYRNUXhRRTJV5Qg2S5EKqQtnayQ= go.mongodb.org/mongo-driver v1.17.9 h1:IexDdCuuNJ3BHrELgBlyaH9p60JXAvdzWR128q+U5tU= go.mongodb.org/mongo-driver v1.17.9/go.mod h1:LlOhpH5NUEfhxcAwG0UEkMqwYcc4JU18gtCdGudk/tQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= diff --git a/plugin/gateway/protocol/protocol_serial/client.go b/plugin/gateway/protocol/protocol_serial/client.go index 7244a93a..fca197c2 100644 --- a/plugin/gateway/protocol/protocol_serial/client.go +++ b/plugin/gateway/protocol/protocol_serial/client.go @@ -16,7 +16,6 @@ import ( busTY "github.com/mycontroller-org/server/v2/plugin/bus/types" msglogger "github.com/mycontroller-org/server/v2/plugin/gateway/protocol/message_logger" gwTY "github.com/mycontroller-org/server/v2/plugin/gateway/types" - serialDriver "github.com/tarm/serial" "go.uber.org/zap" ) @@ -41,8 +40,8 @@ type Config struct { type Endpoint struct { GwCfg *gwTY.Config Config Config - serCfg *serialDriver.Config - Port *serialDriver.Port + serCfg serialConfig + Port serialPort receiveMsgFunc func(rm *msgTY.RawMessage) error safeClose *concurrency.Channel messageLogger msglogger.MessageLogger @@ -65,10 +64,10 @@ func New(logger *zap.Logger, gwCfg *gwTY.Config, protocol cmap.CustomMap, rxMsgF namedLogger.Debug("updated config data", zap.Any("config", cfg)) - serCfg := &serialDriver.Config{Name: cfg.Portname, Baud: cfg.BaudRate} + serCfg := serialConfig{Name: cfg.Portname, Baud: cfg.BaudRate} namedLogger.Info("opening a serial port", zap.String("gateway", gwCfg.ID), zap.String("port", cfg.Portname)) - port, err := serialDriver.OpenPort(serCfg) + port, err := openSerial(serCfg) if err != nil { // ep.logger.Error("error on opening port", zap.String("gateway", gwCfg.ID), zap.String("port", serCfg.Name), zap.String("error", err.Error())) return nil, err diff --git a/plugin/gateway/protocol/protocol_serial/port.go b/plugin/gateway/protocol/protocol_serial/port.go new file mode 100644 index 00000000..4f4e6c23 --- /dev/null +++ b/plugin/gateway/protocol/protocol_serial/port.go @@ -0,0 +1,13 @@ +package serial + +type serialConfig struct { + Name string + Baud int +} + +type serialPort interface { + Read(p []byte) (int, error) + Write(p []byte) (int, error) + Flush() error + Close() error +} diff --git a/plugin/gateway/protocol/protocol_serial/port_darwin.go b/plugin/gateway/protocol/protocol_serial/port_darwin.go new file mode 100644 index 00000000..5b1b9cfe --- /dev/null +++ b/plugin/gateway/protocol/protocol_serial/port_darwin.go @@ -0,0 +1,24 @@ +//go:build darwin + +package serial + +import bugst "go.bug.st/serial" + +func openSerial(cfg serialConfig) (serialPort, error) { + port, err := bugst.Open(cfg.Name, &bugst.Mode{BaudRate: cfg.Baud}) + if err != nil { + return nil, err + } + return darwinPort{Port: port}, nil +} + +type darwinPort struct { + bugst.Port +} + +func (p darwinPort) Flush() error { + if err := p.Port.ResetInputBuffer(); err != nil { + return err + } + return p.Port.ResetOutputBuffer() +} diff --git a/plugin/gateway/protocol/protocol_serial/port_tarm.go b/plugin/gateway/protocol/protocol_serial/port_tarm.go new file mode 100644 index 00000000..8bbba30c --- /dev/null +++ b/plugin/gateway/protocol/protocol_serial/port_tarm.go @@ -0,0 +1,9 @@ +//go:build !darwin + +package serial + +import serialDriver "github.com/tarm/serial" + +func openSerial(cfg serialConfig) (serialPort, error) { + return serialDriver.OpenPort(&serialDriver.Config{Name: cfg.Name, Baud: cfg.Baud}) +} diff --git a/scripts/generate_executables.sh b/scripts/generate_executables.sh index 0eea0110..99b05846 100755 --- a/scripts/generate_executables.sh +++ b/scripts/generate_executables.sh @@ -116,7 +116,7 @@ copy_docker_binary() { } # platforms to build archives -PLATFORMS=("linux/arm" "linux/arm64" "linux/386" "linux/amd64" "windows/386" "windows/amd64") +PLATFORMS=("linux/arm" "linux/arm64" "linux/386" "linux/amd64" "darwin/amd64" "darwin/arm64" "windows/386" "windows/amd64") # compile for platform in "${PLATFORMS[@]}" diff --git a/scripts/publish_container_images.sh b/scripts/publish_container_images.sh index 612bf9af..cb0f9fc3 100755 --- a/scripts/publish_container_images.sh +++ b/scripts/publish_container_images.sh @@ -16,43 +16,24 @@ if [ "${PUSH_DOCKER_QUAY:-0}" = "1" ]; then REGISTRIES+=("quay.io/mycontroller" "docker.io/mycontroller") fi -PLATFORMS=( - "linux/amd64:linux-amd64" - "linux/arm64:linux-arm64" - "linux/arm/v7:linux-armv7" - "linux/arm/v6:linux-armv6" -) - -for spec in "${PLATFORMS[@]}"; do - platform="${spec%%:*}" - binary_dir="${spec##*:}" - binary_path="builds/binary/${binary_dir}/mycontroller-${TARGET_BINARY}" +for dir in linux-amd64 linux-arm64 linux-armv7 linux-armv6; do + binary_path="builds/binary/${dir}/mycontroller-${TARGET_BINARY}" if [ ! -f "${binary_path}" ]; then echo "missing ${binary_path}; run ./scripts/generate_executables.sh first" >&2 exit 1 fi - - tags=() - for registry in "${REGISTRIES[@]}"; do - tags+=(--tag "${registry}/${TARGET_BINARY}:${IMAGE_TAG}-${binary_dir}") - done - - docker buildx build --push \ - --progress=plain \ - --provenance=false \ - --sbom=false \ - --platform "${platform}" \ - --file "docker/${TARGET_BINARY}.Dockerfile" \ - --build-arg "BINARY_PATH=${binary_path}" \ - "${tags[@]}" \ - . done +tags=() for registry in "${REGISTRIES[@]}"; do - docker buildx imagetools create \ - --tag "${registry}/${TARGET_BINARY}:${IMAGE_TAG}" \ - "${registry}/${TARGET_BINARY}:${IMAGE_TAG}-linux-amd64" \ - "${registry}/${TARGET_BINARY}:${IMAGE_TAG}-linux-arm64" \ - "${registry}/${TARGET_BINARY}:${IMAGE_TAG}-linux-armv7" \ - "${registry}/${TARGET_BINARY}:${IMAGE_TAG}-linux-armv6" + tags+=(--tag "${registry}/${TARGET_BINARY}:${IMAGE_TAG}") done + +docker buildx build --push \ + --progress=plain \ + --provenance=false \ + --sbom=false \ + --platform linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 \ + --file "docker/${TARGET_BINARY}.Dockerfile" \ + "${tags[@]}" \ + .