diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 0000000..e88d473
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,4 @@
+{
+ "name": "eclipse-s-core",
+ "image": "ghcr.io/eclipse-score/devcontainer:v1.1.0"
+}
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 930c42b..a7b7976 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -18,6 +18,25 @@ on:
merge_group:
types: [checks_requested]
jobs:
+ gazelle-and-go-build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup Bazel
+ uses: bazel-contrib/setup-bazel@0.9.0
+ with:
+ bazelisk-cache: true
+ disk-cache: ${{ github.workflow }}
+ repository-cache: true
+
+ - name: Run Gazelle
+ run: bazel run //:gazelle
+
+ - name: Build scorex
+ run: bazel build //scorex:scorex
+
qnx-build:
uses: eclipse-score/cicd-workflows/.github/workflows/qnx-build.yml@main
permissions:
diff --git a/.gitignore b/.gitignore
index e7dc329..0a39405 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,9 +17,11 @@
*.dll
# Fortran module files
-*.mod
*.smod
+# Go module file exception - allow go.mod files
+!go.mod
+
# Compiled Static libraries
*.lai
*.la
diff --git a/BUILD b/BUILD
index 473b5d5..929aaef 100644
--- a/BUILD
+++ b/BUILD
@@ -11,10 +11,13 @@
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************
+load("@bazel_gazelle//:def.bzl", "gazelle")
load("@score_docs_as_code//:docs.bzl", "docs")
load("@score_tooling//:defs.bzl", "copyright_checker", "dash_license_checker", "setup_starpls", "use_format_targets")
load("//:project_config.bzl", "PROJECT_CONFIG")
+gazelle(name = "gazelle")
+
setup_starpls(
name = "starpls_server",
visibility = ["//visibility:public"],
@@ -23,6 +26,7 @@ setup_starpls(
copyright_checker(
name = "copyright",
srcs = [
+ "scorex",
"src",
"tests",
"//:BUILD",
diff --git a/MODULE.bazel b/MODULE.bazel
index 2d68af1..ce27145 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -16,7 +16,7 @@ module(
)
# Configure and register the python toolchain.
-bazel_dep(name = "rules_python", version = "1.4.1")
+bazel_dep(name = "rules_python", version = "1.5.1")
PYTHON_VERSION = "3.12"
@@ -25,7 +25,7 @@ python.toolchain(
is_default = True,
python_version = PYTHON_VERSION,
)
-use_repo(python)
+use_repo(python, "python_versions")
# Configure the target toolchain.
bazel_dep(name = "score_toolchains_qnx", version = "0.0.2", dev_dependency = True)
@@ -42,16 +42,13 @@ use_repo(qnx, "toolchains_qnx_qcc")
# register_toolchains("@toolchains_qnx_qcc//:qcc_x86_64")
# Add GoogleTest dependency
-bazel_dep(name = "googletest", version = "1.17.0")
+bazel_dep(name = "googletest", version = "1.17.0.bcr.2")
# Add Rust rules for Rust tests
bazel_dep(name = "rules_rust", version = "0.61.0")
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
rust.toolchain(edition = "2021")
-use_repo(rust, "rust_toolchains")
-
-register_toolchains("@rust_toolchains//:all")
# Add boost dependency
bazel_dep(name = "rules_boost", repo_name = "com_github_nelhage_rules_boost")
@@ -64,15 +61,16 @@ archive_override(
bazel_dep(name = "boost.program_options", version = "1.87.0")
# C/C++ rules for Bazel
-bazel_dep(name = "rules_cc", version = "0.2.1")
+bazel_dep(name = "rules_cc", version = "0.2.14")
# tooling
-bazel_dep(name = "score_tooling", version = "1.0.2")
+bazel_dep(name = "score_tooling", version = "1.0.5")
bazel_dep(name = "aspect_rules_lint", version = "1.5.3")
bazel_dep(name = "buildifier_prebuilt", version = "8.2.0.2")
#docs-as-code
-bazel_dep(name = "score_docs_as_code", version = "2.0.2")
+bazel_dep(name = "score_docs_as_code", version = "2.3.3")
+bazel_dep(name = "score_process", version = "1.4.2")
bazel_dep(name = "score_baselibs", version = "0.1.3")
bazel_dep(name = "score_communication", version = "0.1.1")
bazel_dep(name = "platforms", version = "1.0.0")
@@ -85,3 +83,16 @@ git_override(
commit = "ede35c4411d41abe42b8f19e78f8989ff79ad3d8",
remote = "https://github.com/bmw-software-engineering/trlc.git",
)
+
+bazel_dep(name = "rules_go", version = "0.59.0")
+bazel_dep(name = "gazelle", version = "0.42.0", repo_name = "bazel_gazelle")
+
+go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
+go_sdk.download(version = "1.23.5")
+
+go_deps = use_extension("@bazel_gazelle//:extensions.bzl", "go_deps")
+go_deps.from_file(go_mod = "//scorex:go.mod")
+use_repo(
+ go_deps,
+ "com_github_spf13_cobra",
+)
diff --git a/scorex/BUILD.bazel b/scorex/BUILD.bazel
new file mode 100644
index 0000000..9336d5f
--- /dev/null
+++ b/scorex/BUILD.bazel
@@ -0,0 +1,36 @@
+# *******************************************************************************
+# Copyright (c) 2026 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Apache License Version 2.0 which is available at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+# *******************************************************************************
+load("@rules_go//go:def.bzl", "go_binary", "go_library")
+
+# gazelle:prefix scorex
+exports_files(
+ [
+ "go.mod",
+ "go.sum",
+ ],
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "scorex_lib",
+ srcs = ["main.go"],
+ importpath = "scorex",
+ visibility = ["//visibility:private"],
+ deps = ["//scorex/cmd"],
+)
+
+go_binary(
+ name = "scorex",
+ embed = [":scorex_lib"],
+ visibility = ["//visibility:public"],
+)
diff --git a/scorex/README.md b/scorex/README.md
new file mode 100644
index 0000000..989a8e8
--- /dev/null
+++ b/scorex/README.md
@@ -0,0 +1,79 @@
+
+
+```text
+|=================================|
+| ___ ___ ___ _ __ _____ __ |
+| / __|/ __/ _ \| '__/ _ \ \/ / |
+| \__ \ (_| (_) | | | __/> < |
+| |___/\___\___/|_| \___/_/\_\ |
+| |
+|=================================|
+```
+
+
+
+# scorex
+
+`scorex` is a small CLI helper for generating S-CORE skeleton applications.
+
+It is implemented in Go in [scorex/main.go](scorex/main.go) and uses Cobra for its CLI in
+[scorex/cmd/root.go](scorex/cmd/root.go) and [scorex/cmd/init.go](scorex/cmd/init.go).
+
+## Features
+
+- Generate a new S-CORE Bazel project skeleton
+- Pre-wire `MODULE.bazel`, `.bazelrc`, `.bazelversion`, `BUILD`, and `src/main.cpp`
+- Use a central `known_good.json` to pin module versions and commits
+
+The project layout and files are rendered from the templates in
+[scorex/cmd/templates/application](scorex/cmd/templates/application).
+
+## Installation
+
+From the repository root:
+
+```sh
+cd scorex
+go mod tidy
+go build ./...
+```
+
+This creates a `scorex` binary in the `scorex/` directory.
+
+## Usage
+
+Show help:
+
+```sh
+./scorex --help
+```
+
+Generate a new S-CORE project (example):
+
+```sh
+./scorex init \
+ --module score_baselibs \
+ --module score_communication \
+ --name my_score_app \
+ --dir . \
+ --bazel-version 8.3.0
+```
+
+This will create `./my_score_app` with:
+
+- `MODULE.bazel`
+- `.bazelrc`
+- `.bazelversion`
+- `BUILD`
+- `src/BUILD`
+- `src/main.cpp`
+
+## Options
+
+The `init` command (see [scorex/cmd/init.go](scorex/cmd/init.go)) supports:
+
+- `--module` (repeatable): S-CORE modules to include, e.g. `score_communication`
+- `--name`: Name of the generated project (default: `score_app`)
+- `--dir`: Target directory where the project is created (default: current directory)
+- `--known-good-url`: URL or file path to `known_good.json`
+- `--bazel-version`: Bazel version written into `.bazelversion` (default: `8.3.0`)
diff --git a/scorex/cmd/BUILD.bazel b/scorex/cmd/BUILD.bazel
new file mode 100644
index 0000000..866a8ef
--- /dev/null
+++ b/scorex/cmd/BUILD.bazel
@@ -0,0 +1,30 @@
+# *******************************************************************************
+# Copyright (c) 2026 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Apache License Version 2.0 which is available at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+# *******************************************************************************
+load("@rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "cmd",
+ srcs = [
+ "init.go",
+ "root.go",
+ ],
+ importpath = "scorex/cmd",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//scorex/internal/config",
+ "//scorex/internal/model",
+ "//scorex/internal/service/knowngood",
+ "//scorex/internal/service/projectinit",
+ "@com_github_spf13_cobra//:cobra",
+ ],
+)
diff --git a/scorex/cmd/init.go b/scorex/cmd/init.go
new file mode 100644
index 0000000..7f9d226
--- /dev/null
+++ b/scorex/cmd/init.go
@@ -0,0 +1,450 @@
+/********************************************************************************
+* Copyright (c) 2025 Contributors to the Eclipse Foundation
+*
+* See the NOTICE file(s) distributed with this work for additional
+* information regarding copyright ownership.
+*
+* This program and the accompanying materials are made available under the
+* terms of the Apache License Version 2.0 which is available at
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* SPDX-License-Identifier: Apache-2.0
+********************************************************************************/
+package cmd
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+ "slices"
+ "sort"
+ "strconv"
+ "strings"
+
+ "github.com/spf13/cobra"
+ "scorex/internal/config"
+ "scorex/internal/model"
+ "scorex/internal/service/knowngood"
+ "scorex/internal/service/projectinit"
+)
+
+type initOptions struct {
+ Modules []string
+ TargetDir string
+ Name string
+ KnownGoodURL string
+ BazelVersion string
+ ProjectType string // Application|Module
+ AppType string // daal|feo
+ IncludeDevcontainer bool
+ ModulePreset string
+}
+
+var initOpts = initOptions{}
+
+// initCmd represents the init command
+var initCmd = &cobra.Command{
+ Use: "init",
+ Short: "Generates an S-CORE skeleton application",
+ Long: `Generates a new S-CORE project with selected modules.`,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ if err := config.ValidateModulePresetUsage(initOpts.Modules, initOpts.ModulePreset); err != nil {
+ return err
+ }
+
+ if err := validateInitOptions(initOpts); err != nil {
+ return err
+ }
+
+ if len(initOpts.Modules) == 0 {
+ if initOpts.ModulePreset != "" {
+ if err := applyPresetNonInteractive(&initOpts); err != nil {
+ return err
+ }
+ return runInit(initOpts)
+ }
+ return runInitInteractive(&initOpts)
+ }
+ return runInit(initOpts)
+ },
+}
+
+func init() {
+ rootCmd.AddCommand(initCmd)
+
+ initOpts.ProjectType = "Application"
+ initOpts.AppType = "daal"
+
+ initCmd.Flags().StringSliceVar(&initOpts.Modules, "module", nil, "S-CORE Module(s), e.g.: score_communication, score_baselibs")
+ initCmd.Flags().StringVar(&initOpts.Name, "name", config.DefaultProjectName, "name of the generated project")
+ initCmd.Flags().StringVar(&initOpts.TargetDir, "dir", config.DefaultTargetDir, "targetdirectory of the generated project")
+ initCmd.Flags().StringVar(
+ &initOpts.KnownGoodURL,
+ "known-good-url",
+ config.DefaultKnownGoodURL,
+ "URL or path to known_good.json",
+ )
+ initCmd.Flags().StringVar(&initOpts.BazelVersion, "bazel-version", config.DefaultBazelVersion, "bazel version to be used in project")
+ initCmd.Flags().StringVar(&initOpts.ProjectType, "project-type", initOpts.ProjectType, "project type: Application or Module")
+ initCmd.Flags().StringVar(&initOpts.AppType, "app-type", initOpts.AppType, "application type (for Application projects): daal or feo")
+ initCmd.Flags().BoolVar(&initOpts.IncludeDevcontainer, "devcontainer", false, "include a .devcontainer folder")
+ initCmd.Flags().StringVar(&initOpts.ModulePreset, "module-preset", "", "use a predefined module preset (e.g. feo-standard, daal-standard)")
+}
+
+func runInit(opts initOptions) error {
+ piOpts := projectinit.Options{
+ Modules: opts.Modules,
+ TargetDir: opts.TargetDir,
+ Name: opts.Name,
+ KnownGoodURL: opts.KnownGoodURL,
+ BazelVersion: opts.BazelVersion,
+ ProjectType: opts.ProjectType,
+ AppType: opts.AppType,
+ IncludeDevcontainer: opts.IncludeDevcontainer,
+ }
+
+ result, err := projectinit.Run(piOpts)
+ if err != nil {
+ return err
+ }
+
+ fmt.Println("Generating skeleton in", result.TargetDir, "with modules:", result.SelectedModules)
+ return nil
+}
+
+func runInitInteractive(opts *initOptions) error {
+ reader := bufio.NewReader(os.Stdin)
+
+ appChar := "a"
+ moduleChar := "m"
+
+ // project type
+ fmt.Printf("Project type (%s = application, %s = module): ", appChar, moduleChar)
+ v, err := readLine(reader)
+ if err != nil {
+ return err
+ }
+ v = strings.ToLower(v)
+
+ switch v {
+ case "", appChar: // Default: application
+ opts.ProjectType = "Application"
+ case moduleChar:
+ opts.ProjectType = "Module"
+ default:
+ return fmt.Errorf("invalid project type %q (use %s or %s)", v, appChar, moduleChar)
+ }
+
+ // application type (nur bei Application)
+ if opts.ProjectType == "Application" {
+ feoChar := "f"
+ daalChar := "d"
+
+ fmt.Printf("Application type (%s = FEO, %s = DAAL): ", feoChar, daalChar)
+ v, err := readLine(reader)
+ if err != nil {
+ return err
+ }
+ v = strings.ToLower(v)
+
+ switch v {
+ case "", daalChar: // Default: DAAL
+ opts.AppType = "daal"
+ case feoChar:
+ opts.AppType = "feo"
+ default:
+ return fmt.Errorf("invalid application type %q (use %s or %s)", v, feoChar, daalChar)
+ }
+ }
+
+ // project name
+ fmt.Printf("Project name [%s]: ", opts.Name)
+ if v, err := readLine(reader); err != nil {
+ return err
+ } else if v != "" {
+ opts.Name = v
+ }
+
+ // target directory
+ fmt.Printf("Target directory [%s]: ", opts.TargetDir)
+ if v, err := readLine(reader); err != nil {
+ return err
+ } else if v != "" {
+ opts.TargetDir = v
+ }
+
+ // devcontainer
+ devcontainer, err := confirm(reader, "Use .devcontainer?")
+ if err != nil {
+ return err
+ } else {
+ opts.IncludeDevcontainer = devcontainer
+ }
+
+ // load known-good
+ kg, err := knowngood.Load(opts.KnownGoodURL)
+ if err != nil {
+ return fmt.Errorf("error loading known_good.json: %w", err)
+ }
+
+ // presets (optional)
+ if err := applyPresetInteractive(reader, opts, kg.Modules); err != nil {
+ return err
+ }
+ if len(opts.Modules) > 0 {
+ if err := validateInitOptions(*opts); err != nil {
+ return err
+ }
+ return runInit(*opts)
+ }
+
+ // choose modules
+ modules, err := promptModules(reader, kg.Modules)
+ if err != nil {
+ return err
+ }
+ if len(modules) == 0 {
+ return fmt.Errorf("no modules selected")
+ }
+ opts.Modules = modules
+
+ if err := validateInitOptions(*opts); err != nil {
+ return err
+ }
+ return runInit(*opts)
+}
+
+func applyPresetNonInteractive(opts *initOptions) error {
+ all, err := config.LoadModulePresets()
+ if err != nil {
+ return err
+ }
+ p, ok := config.FindModulePreset(all, opts.ModulePreset)
+ if !ok {
+ return fmt.Errorf("unknown --module-preset %q (known: %s)", opts.ModulePreset, strings.Join(config.KnownPresetIDs(all), ", "))
+ }
+ if p.ProjectType != "" && p.ProjectType != opts.ProjectType {
+ return fmt.Errorf("module preset %q is not applicable to project type %q", p.ID, opts.ProjectType)
+ }
+ if p.AppType != "" && p.AppType != opts.AppType {
+ return fmt.Errorf("module preset %q is not applicable to app type %q", p.ID, opts.AppType)
+ }
+ if len(p.Modules) == 0 {
+ return fmt.Errorf("module preset %q has no modules", p.ID)
+ }
+ opts.Modules = append([]string(nil), p.Modules...)
+ return nil
+}
+
+func applyPresetInteractive(reader *bufio.Reader, opts *initOptions, known map[string]model.ModuleInfo) error {
+ all, err := config.LoadModulePresets()
+ if err != nil {
+ return err
+ }
+ applicable := config.ApplicableModulePresets(all, opts.ProjectType, opts.AppType)
+ if len(applicable) == 0 {
+ return nil
+ }
+
+ fmt.Println("\nModule presets:")
+ fmt.Println(" [0] Custom (select manually)")
+ for i, p := range applicable {
+ fmt.Printf(" [%d] %s (%s)\n", i+1, p.Label, p.ID)
+ }
+ fmt.Print("Select preset [0]: ")
+
+ v, err := readLine(reader)
+ if err != nil {
+ return err
+ }
+ v = strings.TrimSpace(v)
+ if v == "" {
+ v = "0"
+ }
+
+ idx, err := strconv.Atoi(v)
+ if err != nil || idx < 0 || idx > len(applicable) {
+ return fmt.Errorf("invalid preset selection: %q", v)
+ }
+ if idx == 0 {
+ return nil
+ }
+
+ preset := applicable[idx-1]
+ if len(preset.Modules) == 0 {
+ return fmt.Errorf("selected preset %q has no modules", preset.ID)
+ }
+
+ opts.Modules = append([]string(nil), preset.Modules...)
+
+ addMore, err := confirm(reader, "Add more modules on top of the preset?")
+ if err != nil {
+ return err
+ }
+ if !addMore {
+ return nil
+ }
+
+ extra, err := promptModules(reader, known)
+ if err != nil {
+ return err
+ }
+ opts.Modules = mergeUnique(opts.Modules, extra)
+ return nil
+}
+
+func mergeUnique(a, b []string) []string {
+ seen := make(map[string]struct{}, len(a)+len(b))
+ out := make([]string, 0, len(a)+len(b))
+ for _, s := range a {
+ if s == "" {
+ continue
+ }
+ if _, ok := seen[s]; ok {
+ continue
+ }
+ seen[s] = struct{}{}
+ out = append(out, s)
+ }
+ for _, s := range b {
+ if s == "" {
+ continue
+ }
+ if _, ok := seen[s]; ok {
+ continue
+ }
+ seen[s] = struct{}{}
+ out = append(out, s)
+ }
+ return out
+}
+
+func validateInitOptions(opts initOptions) error {
+ validProjectTypes := []string{"Application", "Module"}
+ if opts.ProjectType == "" {
+ return fmt.Errorf("--project-type must be set (Application or Module)")
+ }
+ if !slices.Contains(validProjectTypes, opts.ProjectType) {
+ return fmt.Errorf("invalid --project-type %q (use Application or Module)", opts.ProjectType)
+ }
+
+ if opts.ProjectType == "Application" {
+ validAppTypes := []string{"daal", "feo"}
+ if opts.AppType == "" {
+ return fmt.Errorf("--app-type must be set for Application projects (daal or feo)")
+ }
+ if !slices.Contains(validAppTypes, opts.AppType) {
+ return fmt.Errorf("invalid --app-type %q (use daal or feo)", opts.AppType)
+ }
+ }
+
+ if opts.Name == "" {
+ return fmt.Errorf("--name must be set")
+ }
+ if opts.TargetDir == "" {
+ return fmt.Errorf("--dir must be set")
+ }
+ if opts.KnownGoodURL == "" {
+ return fmt.Errorf("--known-good-url must be set")
+ }
+ if opts.BazelVersion == "" {
+ return fmt.Errorf("--bazel-version must be set")
+ }
+
+ return nil
+}
+
+func readLine(r *bufio.Reader) (string, error) {
+ line, err := r.ReadString('\n')
+ if err != nil && err != io.EOF {
+ return "", err
+ }
+ return strings.TrimSpace(line), nil
+}
+
+func promptModules(r *bufio.Reader, known map[string]model.ModuleInfo) ([]string, error) {
+ if len(known) == 0 {
+ return nil, fmt.Errorf("no modules in known_good.json")
+ }
+
+ // sorted list of module names
+ names := make([]string, 0, len(known))
+ for n := range known {
+ names = append(names, n)
+ }
+ sort.Strings(names)
+
+ fmt.Println("\nAvailable S-CORE modules:")
+ for i, n := range names {
+ fmt.Printf(" [%d] %s\n", i+1, n)
+ }
+ fmt.Print("Select modules (comma-separated indices or names, e.g. 1,3 or score_foo): ")
+
+ sel, err := readLine(r)
+ if err != nil {
+ return nil, err
+ }
+ if sel == "" {
+ return nil, nil
+ }
+
+ parts := strings.Split(sel, ",")
+ var result []string
+ seen := make(map[string]struct{})
+ for _, p := range parts {
+ p = strings.TrimSpace(p)
+ if p == "" {
+ continue
+ }
+
+ // Either an index into the known-good list, or a module name.
+ if idx, err := strconv.Atoi(p); err == nil {
+ if idx < 1 || idx > len(names) {
+ return nil, fmt.Errorf("invalid module index: %q", p)
+ }
+ name := names[idx-1]
+ if _, ok := seen[name]; !ok {
+ result = append(result, name)
+ seen[name] = struct{}{}
+ }
+ continue
+ }
+
+ // Treat as module name.
+ name := p
+ if _, ok := known[name]; !ok {
+ ok, err := confirm(r, fmt.Sprintf("Module %q is not in known_good.json. Add anyway?", name))
+ if err != nil {
+ return nil, err
+ }
+ if !ok {
+ continue
+ }
+ }
+ if _, ok := seen[name]; !ok {
+ result = append(result, name)
+ seen[name] = struct{}{}
+ }
+ }
+ return result, nil
+}
+
+func confirm(r *bufio.Reader, prompt string) (bool, error) {
+ for {
+ fmt.Printf("%s (y/N): ", prompt)
+ v, err := readLine(r)
+ if err != nil {
+ return false, err
+ }
+ v = strings.TrimSpace(strings.ToLower(v))
+ switch v {
+ case "", "n", "no":
+ return false, nil
+ case "y", "yes":
+ return true, nil
+ default:
+ // keep asking
+ }
+ }
+}
diff --git a/scorex/cmd/root.go b/scorex/cmd/root.go
new file mode 100644
index 0000000..0aa4dc0
--- /dev/null
+++ b/scorex/cmd/root.go
@@ -0,0 +1,58 @@
+/********************************************************************************
+* Copyright (c) 2025 Contributors to the Eclipse Foundation
+*
+* See the NOTICE file(s) distributed with this work for additional
+* information regarding copyright ownership.
+*
+* This program and the accompanying materials are made available under the
+* terms of the Apache License Version 2.0 which is available at
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* SPDX-License-Identifier: Apache-2.0
+********************************************************************************/
+package cmd
+
+import (
+ "os"
+
+ "github.com/spf13/cobra"
+)
+
+// rootCmd represents the base command when called without any subcommands
+var rootCmd = &cobra.Command{
+ Use: "scorex",
+ Short: "CLI for creating S-CORE skeleton projects",
+ Long: `
+
+|=================================|
+| ___ ___ ___ _ __ _____ __ |
+| / __|/ __/ _ \| '__/ _ \ \/ / |
+| \__ \ (_| (_) | | | __/> < |
+| |___/\___\___/|_| \___/_/\_\ |
+| |
+|=================================|
+
+Welcome to scorex - a cli for S-CORE development!
+`,
+}
+
+// Execute adds all child commands to the root command and sets flags appropriately.
+// This is called by main.main(). It only needs to happen once to the rootCmd.
+func Execute() {
+ err := rootCmd.Execute()
+ if err != nil {
+ os.Exit(1)
+ }
+}
+
+func init() {
+ // Here you will define your flags and configuration settings.
+ // Cobra supports persistent flags, which, if defined here,
+ // will be global for your application.
+
+ // rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.scorex.yaml)")
+
+ // Cobra also supports local flags, which will only run
+ // when this action is called directly.
+ rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
+}
diff --git a/scorex/go.mod b/scorex/go.mod
new file mode 100644
index 0000000..55ccc8c
--- /dev/null
+++ b/scorex/go.mod
@@ -0,0 +1,10 @@
+module scorex
+
+go 1.23
+
+require github.com/spf13/cobra v1.10.2
+
+require (
+ github.com/inconshreveable/mousetrap v1.1.0 // indirect
+ github.com/spf13/pflag v1.0.9 // indirect
+)
diff --git a/scorex/go.sum b/scorex/go.sum
new file mode 100644
index 0000000..a6ee3e0
--- /dev/null
+++ b/scorex/go.sum
@@ -0,0 +1,10 @@
+github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
+github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
+github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
+github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/scorex/internal/config/BUILD.bazel b/scorex/internal/config/BUILD.bazel
new file mode 100644
index 0000000..3f27b2b
--- /dev/null
+++ b/scorex/internal/config/BUILD.bazel
@@ -0,0 +1,30 @@
+# *******************************************************************************
+# Copyright (c) 2026 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Apache License Version 2.0 which is available at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+# *******************************************************************************
+load("@rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "config",
+ srcs = [
+ "config.go",
+ "known_good.go",
+ "module_presets.go",
+ "project_config.go",
+ ],
+ embedsrcs = ["module_presets.json"],
+ importpath = "scorex/internal/config",
+ visibility = ["//scorex:__subpackages__"],
+ deps = [
+ "//scorex/internal/model",
+ "//scorex/internal/service/knowngood",
+ ],
+)
diff --git a/scorex/internal/config/config.go b/scorex/internal/config/config.go
new file mode 100644
index 0000000..97a7ea7
--- /dev/null
+++ b/scorex/internal/config/config.go
@@ -0,0 +1,8 @@
+package config
+
+const (
+ DefaultProjectName = "score_app"
+ DefaultTargetDir = "."
+ DefaultKnownGoodURL = "https://raw.githubusercontent.com/eclipse-score/reference_integration/main/known_good.json"
+ DefaultBazelVersion = "8.3.0"
+)
diff --git a/scorex/internal/config/known_good.go b/scorex/internal/config/known_good.go
new file mode 100644
index 0000000..48ec666
--- /dev/null
+++ b/scorex/internal/config/known_good.go
@@ -0,0 +1,14 @@
+package config
+
+import (
+ "scorex/internal/model"
+ "scorex/internal/service/knowngood"
+)
+
+// Deprecated: use scorex/internal/model.KnownGood and scorex/internal/service/knowngood.Load.
+type KnownGood = model.KnownGood
+
+// Deprecated: use scorex/internal/service/knowngood.Load.
+func LoadKnownGood(urlOrPath string) (*KnownGood, error) {
+ return knowngood.Load(urlOrPath)
+}
diff --git a/scorex/internal/config/module_presets.go b/scorex/internal/config/module_presets.go
new file mode 100644
index 0000000..4f226d2
--- /dev/null
+++ b/scorex/internal/config/module_presets.go
@@ -0,0 +1,132 @@
+package config
+
+import (
+ _ "embed"
+ "encoding/json"
+ "fmt"
+ "slices"
+ "strings"
+)
+
+type ModulePreset struct {
+ ID string `json:"id"`
+ Label string `json:"label"`
+ ProjectType string `json:"projectType,omitempty"`
+ AppType string `json:"appType,omitempty"`
+ Modules []string `json:"modules"`
+}
+
+type modulePresetFile struct {
+ Presets []ModulePreset `json:"presets"`
+}
+
+//go:embed module_presets.json
+var modulePresetsJSON []byte
+
+func LoadModulePresets() ([]ModulePreset, error) {
+ var f modulePresetFile
+ if err := json.Unmarshal(modulePresetsJSON, &f); err != nil {
+ return nil, fmt.Errorf("parsing embedded module presets: %w", err)
+ }
+
+ seen := make(map[string]struct{}, len(f.Presets))
+ for i := range f.Presets {
+ p := &f.Presets[i]
+ p.ID = strings.TrimSpace(p.ID)
+ p.Label = strings.TrimSpace(p.Label)
+ p.ProjectType = strings.TrimSpace(p.ProjectType)
+ p.AppType = strings.TrimSpace(p.AppType)
+
+ if p.ID == "" {
+ return nil, fmt.Errorf("module preset missing id")
+ }
+ if _, ok := seen[p.ID]; ok {
+ return nil, fmt.Errorf("duplicate module preset id %q", p.ID)
+ }
+ seen[p.ID] = struct{}{}
+
+ if p.Label == "" {
+ p.Label = p.ID
+ }
+
+ // Normalize module names to the score_ prefix (consistent with module resolver).
+ for j := range p.Modules {
+ p.Modules[j] = normalizeModuleName(p.Modules[j])
+ }
+ p.Modules = dedupeStrings(p.Modules)
+ }
+
+ return f.Presets, nil
+}
+
+func ApplicableModulePresets(all []ModulePreset, projectType, appType string) []ModulePreset {
+ var out []ModulePreset
+ for _, p := range all {
+ if p.ProjectType != "" && p.ProjectType != projectType {
+ continue
+ }
+ if p.AppType != "" && p.AppType != appType {
+ continue
+ }
+ out = append(out, p)
+ }
+ return out
+}
+
+func FindModulePreset(all []ModulePreset, id string) (ModulePreset, bool) {
+ id = strings.TrimSpace(id)
+ for _, p := range all {
+ if p.ID == id {
+ return p, true
+ }
+ }
+ return ModulePreset{}, false
+}
+
+func normalizeModuleName(name string) string {
+ name = strings.TrimSpace(name)
+ if name == "" {
+ return ""
+ }
+ if strings.HasPrefix(name, "score_") {
+ return name
+ }
+ return "score_" + name
+}
+
+func dedupeStrings(in []string) []string {
+ seen := make(map[string]struct{}, len(in))
+ out := make([]string, 0, len(in))
+ for _, s := range in {
+ s = strings.TrimSpace(s)
+ if s == "" {
+ continue
+ }
+ if _, ok := seen[s]; ok {
+ continue
+ }
+ seen[s] = struct{}{}
+ out = append(out, s)
+ }
+ // Preserve stable output order: first occurrence wins.
+ return out
+}
+
+func ValidateModulePresetUsage(modules []string, presetID string) error {
+ if presetID == "" {
+ return nil
+ }
+ if len(modules) > 0 {
+ return fmt.Errorf("--module and --module-preset are mutually exclusive")
+ }
+ return nil
+}
+
+func KnownPresetIDs(all []ModulePreset) []string {
+ ids := make([]string, 0, len(all))
+ for _, p := range all {
+ ids = append(ids, p.ID)
+ }
+ slices.Sort(ids)
+ return ids
+}
diff --git a/scorex/internal/config/module_presets.json b/scorex/internal/config/module_presets.json
new file mode 100644
index 0000000..5f1d4e4
--- /dev/null
+++ b/scorex/internal/config/module_presets.json
@@ -0,0 +1,18 @@
+{
+ "presets": [
+ {
+ "id": "feo-standard",
+ "label": "FEO app (standard)",
+ "projectType": "Application",
+ "appType": "feo",
+ "modules": ["score_baselibs", "score_communication", "score_docs_as_code", "score_feo"]
+ },
+ {
+ "id": "daal-standard",
+ "label": "DAAL app (standard)",
+ "projectType": "Application",
+ "appType": "daal",
+ "modules": ["score_baselibs", "score_communication", "score_inc_daal"]
+ }
+ ]
+}
diff --git a/scorex/internal/config/project_config.go b/scorex/internal/config/project_config.go
new file mode 100644
index 0000000..c0b676c
--- /dev/null
+++ b/scorex/internal/config/project_config.go
@@ -0,0 +1,42 @@
+package config
+
+import (
+ "encoding/json"
+ "os"
+ "path/filepath"
+)
+
+type ProjectConfig struct {
+ ProjectName string `json:"project_name"`
+ Template string `json:"template"`
+ BazelVersion string `json:"bazel_version"`
+ KnownGoodURL string `json:"known_good_url"`
+ Modules []string `json:"modules"`
+}
+
+const DefaultConfigFileName = "scorex.json"
+
+func WriteProjectConfig(dir string, cfg *ProjectConfig) error {
+ if err := os.MkdirAll(dir, 0o755); err != nil {
+ return err
+ }
+ data, err := json.MarshalIndent(cfg, "", " ")
+ if err != nil {
+ return err
+ }
+ path := filepath.Join(dir, DefaultConfigFileName)
+ return os.WriteFile(path, data, 0o644)
+}
+
+func ReadProjectConfig(dir string) (*ProjectConfig, error) {
+ path := filepath.Join(dir, DefaultConfigFileName)
+ data, err := os.ReadFile(path)
+ if err != nil {
+ return nil, err
+ }
+ var cfg ProjectConfig
+ if err := json.Unmarshal(data, &cfg); err != nil {
+ return nil, err
+ }
+ return &cfg, nil
+}
diff --git a/scorex/internal/model/BUILD.bazel b/scorex/internal/model/BUILD.bazel
new file mode 100644
index 0000000..42f49a1
--- /dev/null
+++ b/scorex/internal/model/BUILD.bazel
@@ -0,0 +1,23 @@
+# *******************************************************************************
+# Copyright (c) 2026 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Apache License Version 2.0 which is available at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+# *******************************************************************************
+load("@rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "model",
+ srcs = [
+ "known_good.go",
+ "module.go",
+ ],
+ importpath = "scorex/internal/model",
+ visibility = ["//scorex:__subpackages__"],
+)
diff --git a/scorex/internal/model/known_good.go b/scorex/internal/model/known_good.go
new file mode 100644
index 0000000..069c5ce
--- /dev/null
+++ b/scorex/internal/model/known_good.go
@@ -0,0 +1,10 @@
+package model
+
+// KnownGood represents the structure of known_good.json.
+type KnownGood struct {
+ Timestamp string `json:"timestamp"`
+ Modules map[string]ModuleInfo `json:"modules"`
+ ManifestSHA256 string `json:"manifest_sha256"`
+ Suite string `json:"suite"`
+ DurationS int `json:"duration_s"`
+}
diff --git a/scorex/internal/model/module.go b/scorex/internal/model/module.go
new file mode 100644
index 0000000..1f5e718
--- /dev/null
+++ b/scorex/internal/model/module.go
@@ -0,0 +1,8 @@
+package model
+
+type ModuleInfo struct {
+ Version string `json:"version"`
+ Hash string `json:"hash"`
+ Repo string `json:"repo"`
+ Branch string `json:"branch,omitempty"`
+}
diff --git a/scorex/internal/projectinit/BUILD.bazel b/scorex/internal/projectinit/BUILD.bazel
new file mode 100644
index 0000000..1f06f1b
--- /dev/null
+++ b/scorex/internal/projectinit/BUILD.bazel
@@ -0,0 +1,21 @@
+# *******************************************************************************
+# Copyright (c) 2026 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Apache License Version 2.0 which is available at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+# *******************************************************************************
+load("@rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "projectinit",
+ srcs = ["service.go"],
+ importpath = "scorex/internal/projectinit",
+ visibility = ["//scorex:__subpackages__"],
+ deps = ["//scorex/internal/service/projectinit"],
+)
diff --git a/scorex/internal/projectinit/service.go b/scorex/internal/projectinit/service.go
new file mode 100644
index 0000000..3fbfc7f
--- /dev/null
+++ b/scorex/internal/projectinit/service.go
@@ -0,0 +1,14 @@
+package projectinit
+
+import serviceprojectinit "scorex/internal/service/projectinit"
+
+// Deprecated: use scorex/internal/service/projectinit.Options.
+type Options = serviceprojectinit.Options
+
+// Deprecated: use scorex/internal/service/projectinit.Result.
+type Result = serviceprojectinit.Result
+
+// Deprecated: use scorex/internal/service/projectinit.Run.
+func Run(opts Options) (*Result, error) {
+ return serviceprojectinit.Run(opts)
+}
diff --git a/scorex/internal/service/knowngood/BUILD.bazel b/scorex/internal/service/knowngood/BUILD.bazel
new file mode 100644
index 0000000..2991785
--- /dev/null
+++ b/scorex/internal/service/knowngood/BUILD.bazel
@@ -0,0 +1,21 @@
+# *******************************************************************************
+# Copyright (c) 2026 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Apache License Version 2.0 which is available at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+# *******************************************************************************
+load("@rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "knowngood",
+ srcs = ["loader.go"],
+ importpath = "scorex/internal/service/knowngood",
+ visibility = ["//scorex:__subpackages__"],
+ deps = ["//scorex/internal/model"],
+)
diff --git a/scorex/internal/service/knowngood/loader.go b/scorex/internal/service/knowngood/loader.go
new file mode 100644
index 0000000..54161aa
--- /dev/null
+++ b/scorex/internal/service/knowngood/loader.go
@@ -0,0 +1,47 @@
+package knowngood
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "os"
+ "strings"
+
+ "scorex/internal/model"
+)
+
+// Load loads a KnownGood specification from a local file or HTTP(S) URL.
+func Load(urlOrPath string) (*model.KnownGood, error) {
+ var data []byte
+ var err error
+
+ if strings.HasPrefix(urlOrPath, "http://") || strings.HasPrefix(urlOrPath, "https://") {
+ resp, err := http.Get(urlOrPath)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ return nil, fmt.Errorf("HTTP %s", resp.Status)
+ }
+
+ data, err = io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ data, err = os.ReadFile(urlOrPath)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ var kg model.KnownGood
+ if err := json.Unmarshal(data, &kg); err != nil {
+ return nil, err
+ }
+
+ return &kg, nil
+}
diff --git a/scorex/internal/service/module/BUILD.bazel b/scorex/internal/service/module/BUILD.bazel
new file mode 100644
index 0000000..5a89ddf
--- /dev/null
+++ b/scorex/internal/service/module/BUILD.bazel
@@ -0,0 +1,21 @@
+# *******************************************************************************
+# Copyright (c) 2026 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Apache License Version 2.0 which is available at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+# *******************************************************************************
+load("@rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "module",
+ srcs = ["resolver.go"],
+ importpath = "scorex/internal/service/module",
+ visibility = ["//scorex:__subpackages__"],
+ deps = ["//scorex/internal/model"],
+)
diff --git a/scorex/internal/service/module/resolver.go b/scorex/internal/service/module/resolver.go
new file mode 100644
index 0000000..dbc8d6a
--- /dev/null
+++ b/scorex/internal/service/module/resolver.go
@@ -0,0 +1,97 @@
+package module
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "strings"
+ "time"
+
+ "scorex/internal/model"
+)
+
+// ResolveModuleWithFallback tries to resolve a module from knownGood.
+// If not present, it falls back to GitHub "latest release" for the given repo name.
+func ResolveModuleWithFallback(
+ name string,
+ knownGood map[string]model.ModuleInfo,
+) (model.ModuleInfo, error) {
+ if mi, ok := knownGood[name]; ok {
+ return mi, nil
+ }
+
+ repoName := strings.TrimPrefix(name, "score_")
+
+ // Fallback: neuester Commit auf main von GitHub
+ latestCommit, err := fetchLatestGithubMainCommit("eclipse-score", repoName)
+ if err != nil {
+ return model.ModuleInfo{}, fmt.Errorf(
+ "module %q not in known_good and GitHub lookup failed: %w",
+ name, err,
+ )
+ }
+
+ mi := model.ModuleInfo{
+ Version: "0.1.0", //TODO get correct version number
+ Hash: latestCommit,
+ Repo: fmt.Sprintf("https://github.com/eclipse-score/%s.git", repoName),
+ Branch: "main",
+ }
+
+ return mi, nil
+}
+
+// ResolveModules resolves a list of module names against the known-good set,
+// automatically prefixing names with "score_" when missing and falling back
+// to GitHub if a module is not present in known_good.
+func ResolveModules(
+ modules []string,
+ knownGood map[string]model.ModuleInfo,
+) (map[string]model.ModuleInfo, error) {
+ selected := make(map[string]model.ModuleInfo, len(modules))
+
+ for _, name := range modules {
+ moduleName := name
+ if !strings.HasPrefix(moduleName, "score_") {
+ moduleName = "score_" + moduleName
+ }
+
+ mi, err := ResolveModuleWithFallback(moduleName, knownGood)
+ if err != nil {
+ return nil, fmt.Errorf("resolving module %q failed: %w", moduleName, err)
+ }
+ selected[moduleName] = mi
+ }
+
+ return selected, nil
+}
+
+func fetchLatestGithubMainCommit(owner, repo string) (string, error) {
+ url := fmt.Sprintf("https://api.github.com/repos/%s/%s/commits/main", owner, repo)
+
+ client := http.Client{
+ Timeout: 5 * time.Second,
+ }
+
+ resp, err := client.Get(url)
+ if err != nil {
+ return "", err
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ return "", fmt.Errorf("unexpected status %d from GitHub", resp.StatusCode)
+ }
+
+ var payload struct {
+ SHA string `json:"sha"`
+ }
+ if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
+ return "", err
+ }
+
+ if payload.SHA == "" {
+ return "", fmt.Errorf("no sha in GitHub response")
+ }
+ return payload.SHA, nil
+}
diff --git a/scorex/internal/service/projectinit/BUILD.bazel b/scorex/internal/service/projectinit/BUILD.bazel
new file mode 100644
index 0000000..1d63e5f
--- /dev/null
+++ b/scorex/internal/service/projectinit/BUILD.bazel
@@ -0,0 +1,27 @@
+# *******************************************************************************
+# Copyright (c) 2026 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Apache License Version 2.0 which is available at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+# *******************************************************************************
+load("@rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "projectinit",
+ srcs = ["service.go"],
+ importpath = "scorex/internal/service/projectinit",
+ visibility = ["//scorex:__subpackages__"],
+ deps = [
+ "//scorex/internal/config",
+ "//scorex/internal/model",
+ "//scorex/internal/service/knowngood",
+ "//scorex/internal/service/module",
+ "//scorex/internal/service/skeleton",
+ ],
+)
diff --git a/scorex/internal/service/projectinit/service.go b/scorex/internal/service/projectinit/service.go
new file mode 100644
index 0000000..2db9d68
--- /dev/null
+++ b/scorex/internal/service/projectinit/service.go
@@ -0,0 +1,94 @@
+package projectinit
+
+import (
+ "fmt"
+ "path/filepath"
+
+ "scorex/internal/config"
+ "scorex/internal/model"
+ "scorex/internal/service/knowngood"
+ "scorex/internal/service/module"
+ "scorex/internal/service/skeleton"
+)
+
+// Options represents all inputs required to initialize a new project.
+type Options struct {
+ Modules []string
+ TargetDir string
+ Name string
+ KnownGoodURL string
+ BazelVersion string
+ ProjectType string // "Application" or "Module"
+ AppType string // "feo" or "daal"
+ IncludeDevcontainer bool
+}
+
+// Result contains information about the generated project.
+type Result struct {
+ TargetDir string
+ SelectedModules map[string]model.ModuleInfo
+}
+
+// Run performs the full project initialization flow based on the provided options.
+func Run(opts Options) (*Result, error) {
+ if len(opts.Modules) == 0 {
+ return nil, fmt.Errorf("at least one module must be set")
+ }
+
+ kg, err := knowngood.Load(opts.KnownGoodURL)
+ if err != nil {
+ return nil, fmt.Errorf("error loading known_good.json: %w", err)
+ }
+
+ selected, err := module.ResolveModules(opts.Modules, kg.Modules)
+ if err != nil {
+ return nil, err
+ }
+
+ targetDir := filepath.Join(opts.TargetDir, opts.Name)
+
+ props := skeleton.Properties{
+ ProjectName: opts.Name,
+ SelectedModules: selected,
+ BazelVersion: opts.BazelVersion,
+ TargetDir: targetDir,
+ IsApplication: opts.ProjectType == "Application",
+ UseFeo: opts.AppType == "feo",
+ IncludeDevcontainer: opts.IncludeDevcontainer,
+ }
+
+ if err := skeleton.Generate(props); err != nil {
+ return nil, err
+ }
+
+ cfg := &config.ProjectConfig{
+ ProjectName: opts.Name,
+ Template: templateFor(opts.ProjectType, opts.AppType),
+ BazelVersion: opts.BazelVersion,
+ KnownGoodURL: opts.KnownGoodURL,
+ Modules: opts.Modules,
+ }
+
+ if err := config.WriteProjectConfig(targetDir, cfg); err != nil {
+ return nil, fmt.Errorf("writing scorex config: %w", err)
+ }
+
+ return &Result{
+ TargetDir: targetDir,
+ SelectedModules: selected,
+ }, nil
+}
+
+func templateFor(projectType, appType string) string {
+ if projectType != "Application" {
+ return "module"
+ }
+ switch appType {
+ case "feo":
+ return "feo_app"
+ case "daal", "":
+ return "daal_app"
+ default:
+ return "daal_app"
+ }
+}
diff --git a/scorex/internal/service/skeleton/BUILD.bazel b/scorex/internal/service/skeleton/BUILD.bazel
new file mode 100644
index 0000000..c5637b0
--- /dev/null
+++ b/scorex/internal/service/skeleton/BUILD.bazel
@@ -0,0 +1,27 @@
+# *******************************************************************************
+# Copyright (c) 2026 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Apache License Version 2.0 which is available at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+# *******************************************************************************
+load("@rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "skeleton",
+ srcs = [
+ "generator.go",
+ "properties.go",
+ ],
+ importpath = "scorex/internal/service/skeleton",
+ visibility = ["//scorex:__subpackages__"],
+ deps = [
+ "//scorex/internal/model",
+ "//scorex/internal/templates",
+ ],
+)
diff --git a/scorex/internal/service/skeleton/generator.go b/scorex/internal/service/skeleton/generator.go
new file mode 100644
index 0000000..20befcc
--- /dev/null
+++ b/scorex/internal/service/skeleton/generator.go
@@ -0,0 +1,133 @@
+/********************************************************************************
+* Copyright (c) 2025 Contributors to the Eclipse Foundation
+*
+* See the NOTICE file(s) distributed with this work for additional
+* information regarding copyright ownership.
+*
+* This program and the accompanying materials are made available under the
+* terms of the Apache License Version 2.0 which is available at
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* SPDX-License-Identifier: Apache-2.0
+********************************************************************************/
+package skeleton
+
+import (
+ "io/fs"
+ "os"
+ "path/filepath"
+ "strings"
+ "text/template"
+
+ templatesfs "scorex/internal/templates"
+)
+
+type moduleTemplateData struct {
+ ProjectName string
+ SelectedModules map[string]any
+ BazelVersion string
+}
+
+func renderTemplate(tmplPath, dstPath string, data any) error {
+ if err := os.MkdirAll(filepath.Dir(dstPath), 0o755); err != nil {
+ return err
+ }
+
+ t, err := template.ParseFS(templatesfs.FS, tmplPath)
+ if err != nil {
+ return err
+ }
+
+ f, err := os.Create(dstPath)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ return t.Execute(f, data)
+}
+
+func undotifyPath(rel string) string {
+ // Work in slash-form, rewrite each segment, then convert back.
+ parts := strings.Split(filepath.ToSlash(rel), "/")
+ for i, p := range parts {
+ if strings.HasPrefix(p, "point.") {
+ parts[i] = "." + strings.TrimPrefix(p, "point.")
+ }
+ }
+ return filepath.FromSlash(strings.Join(parts, "/"))
+}
+
+// Generate creates a project skeleton based on the provided properties.
+func Generate(props Properties) error {
+ targetDir := props.TargetDir
+
+ if err := os.MkdirAll(targetDir, 0o755); err != nil {
+ return err
+ }
+
+ data := moduleTemplateData{
+ ProjectName: props.ProjectName,
+ SelectedModules: toAnyMap(props.SelectedModules),
+ BazelVersion: props.BazelVersion,
+ }
+
+ templatePath := "module"
+
+ if props.IsApplication {
+ if props.UseFeo {
+ templatePath = filepath.Join("application", "feo_app")
+ } else {
+ templatePath = filepath.Join("application", "daal_app")
+ }
+ }
+
+ err := fs.WalkDir(templatesfs.FS, templatePath, func(path string, d fs.DirEntry, err error) error {
+ if err != nil {
+ return err
+ }
+ if d.IsDir() {
+ return nil
+ }
+ if !strings.HasSuffix(path, ".tmpl") {
+ return nil
+ }
+
+ rel, err := filepath.Rel(templatePath, path)
+ if err != nil {
+ return err
+ }
+
+ // Optional: only include .devcontainer when requested.
+ slashRel := filepath.ToSlash(rel)
+ if !props.IncludeDevcontainer && strings.HasPrefix(slashRel, "point.devcontainer/") {
+ return nil
+ }
+
+ outRel := strings.TrimSuffix(rel, ".tmpl")
+ outRel = undotifyPath(outRel)
+
+ base := filepath.Base(outRel)
+ if strings.HasPrefix(base, "point.") {
+ dir := filepath.Dir(outRel)
+ base = "." + strings.TrimPrefix(base, "point.")
+ outRel = filepath.Join(dir, base)
+ }
+
+ dstPath := filepath.Join(targetDir, outRel)
+ return renderTemplate(path, dstPath, data)
+ })
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func toAnyMap[T any](in map[string]T) map[string]any {
+ out := make(map[string]any, len(in))
+ for k, v := range in {
+ out[k] = v
+ }
+ return out
+}
diff --git a/scorex/internal/service/skeleton/properties.go b/scorex/internal/service/skeleton/properties.go
new file mode 100644
index 0000000..e00b5d2
--- /dev/null
+++ b/scorex/internal/service/skeleton/properties.go
@@ -0,0 +1,14 @@
+package skeleton
+
+import "scorex/internal/model"
+
+// Properties holds all data required to render a project skeleton.
+type Properties struct {
+ ProjectName string
+ SelectedModules map[string]model.ModuleInfo
+ BazelVersion string
+ TargetDir string
+ IsApplication bool
+ UseFeo bool
+ IncludeDevcontainer bool
+}
diff --git a/scorex/internal/skeleton/BUILD.bazel b/scorex/internal/skeleton/BUILD.bazel
new file mode 100644
index 0000000..65fa0b0
--- /dev/null
+++ b/scorex/internal/skeleton/BUILD.bazel
@@ -0,0 +1,24 @@
+# *******************************************************************************
+# Copyright (c) 2026 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Apache License Version 2.0 which is available at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+# *******************************************************************************
+load("@rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "skeleton",
+ srcs = [
+ "generator.go",
+ "properties.go",
+ ],
+ importpath = "scorex/internal/skeleton",
+ visibility = ["//scorex:__subpackages__"],
+ deps = ["//scorex/internal/service/skeleton"],
+)
diff --git a/scorex/internal/skeleton/generator.go b/scorex/internal/skeleton/generator.go
new file mode 100644
index 0000000..7bc5bc1
--- /dev/null
+++ b/scorex/internal/skeleton/generator.go
@@ -0,0 +1,8 @@
+package skeleton
+
+import serviceskeleton "scorex/internal/service/skeleton"
+
+// Deprecated: use scorex/internal/service/skeleton.Generate.
+func Generate(props Properties) error {
+ return serviceskeleton.Generate(props)
+}
diff --git a/scorex/internal/skeleton/properties.go b/scorex/internal/skeleton/properties.go
new file mode 100644
index 0000000..1574288
--- /dev/null
+++ b/scorex/internal/skeleton/properties.go
@@ -0,0 +1,6 @@
+package skeleton
+
+import serviceskeleton "scorex/internal/service/skeleton"
+
+// Deprecated: use scorex/internal/service/skeleton.Properties.
+type Properties = serviceskeleton.Properties
diff --git a/scorex/internal/templates/BUILD.bazel b/scorex/internal/templates/BUILD.bazel
new file mode 100644
index 0000000..54ffcf6
--- /dev/null
+++ b/scorex/internal/templates/BUILD.bazel
@@ -0,0 +1,47 @@
+# *******************************************************************************
+# Copyright (c) 2026 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Apache License Version 2.0 which is available at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+# *******************************************************************************
+load("@rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "templates",
+ srcs = ["fs.go"],
+ embedsrcs = [
+ "application/daal_app/BUILD.tmpl",
+ "application/daal_app/MODULE.bazel.tmpl",
+ "application/daal_app/point.bazelrc.tmpl",
+ "application/daal_app/point.bazelversion.tmpl",
+ "application/daal_app/point.devcontainer/devcontainer.json.tmpl",
+ "application/daal_app/point.devcontainer/prepare_workspace.sh.tmpl",
+ "application/daal_app/src/BUILD.tmpl",
+ "application/daal_app/src/hello_world_app.hpp.tmpl",
+ "application/daal_app/src/main.cpp.tmpl",
+ "application/feo_app/BUILD.tmpl",
+ "application/feo_app/MODULE.bazel.tmpl",
+ "application/feo_app/point.bazelrc.tmpl",
+ "application/feo_app/point.bazelversion.tmpl",
+ "application/feo_app/point.devcontainer/devcontainer.json.tmpl",
+ "application/feo_app/point.devcontainer/prepare_workspace.sh.tmpl",
+ "application/feo_app/src/BUILD.tmpl",
+ "application/feo_app/src/hello_world.rs.tmpl",
+ "module/BUILD.tmpl",
+ "module/MODULE.bazel.tmpl",
+ "module/point.bazelrc.tmpl",
+ "module/point.bazelversion.tmpl",
+ "module/point.devcontainer/devcontainer.json.tmpl",
+ "module/point.devcontainer/prepare_workspace.sh.tmpl",
+ "module/src/BUILD.tmpl",
+ "module/src/main.cpp.tmpl",
+ ],
+ importpath = "scorex/internal/templates",
+ visibility = ["//scorex:__subpackages__"],
+)
diff --git a/scorex/internal/templates/application/daal_app/BUILD.tmpl b/scorex/internal/templates/application/daal_app/BUILD.tmpl
new file mode 100644
index 0000000..e69de29
diff --git a/scorex/internal/templates/application/daal_app/MODULE.bazel.tmpl b/scorex/internal/templates/application/daal_app/MODULE.bazel.tmpl
new file mode 100644
index 0000000..20bdd00
--- /dev/null
+++ b/scorex/internal/templates/application/daal_app/MODULE.bazel.tmpl
@@ -0,0 +1,41 @@
+# *******************************************************************************
+# Copyright (c) 2025 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Apache License Version 2.0 which is available at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+# *******************************************************************************
+module(
+ name = "{{ .ProjectName }}",
+ version = "0.0.1",
+)
+
+bazel_dep(name = "trlc")
+git_override(
+ module_name = "trlc",
+ remote = "https://github.com/bmw-software-engineering/trlc.git",
+ commit = "650b51a47264a4f232b3341f473527710fc32669", # trlc-2.0.2 release
+)
+
+# C/C++ rules for Bazel
+bazel_dep(name = "rules_cc", version = "0.2.1")
+
+{{ range $name, $m := .SelectedModules }}
+# {{ $name }}
+bazel_dep(
+ name = "{{ $name }}",
+ version = "{{ $m.Version }}",
+)
+
+git_override(
+ module_name = "{{ $name }}",
+ remote = "{{ $m.Repo }}",
+ commit = "{{ $m.Hash }}",
+)
+
+{{ end }}
\ No newline at end of file
diff --git a/scorex/internal/templates/application/daal_app/point.bazelrc.tmpl b/scorex/internal/templates/application/daal_app/point.bazelrc.tmpl
new file mode 100755
index 0000000..f693141
--- /dev/null
+++ b/scorex/internal/templates/application/daal_app/point.bazelrc.tmpl
@@ -0,0 +1,15 @@
+# *******************************************************************************
+# Copyright (c) 2025 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Apache License Version 2.0 which is available at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+# *******************************************************************************
+
+common --registry=https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/
+common --registry=https://bcr.bazel.build
diff --git a/scorex/internal/templates/application/daal_app/point.bazelversion.tmpl b/scorex/internal/templates/application/daal_app/point.bazelversion.tmpl
new file mode 100644
index 0000000..3905b2b
--- /dev/null
+++ b/scorex/internal/templates/application/daal_app/point.bazelversion.tmpl
@@ -0,0 +1 @@
+{{ .BazelVersion }}
diff --git a/scorex/internal/templates/application/daal_app/point.devcontainer/devcontainer.json.tmpl b/scorex/internal/templates/application/daal_app/point.devcontainer/devcontainer.json.tmpl
new file mode 100644
index 0000000..cfef9e4
--- /dev/null
+++ b/scorex/internal/templates/application/daal_app/point.devcontainer/devcontainer.json.tmpl
@@ -0,0 +1,6 @@
+{
+ "name": "eclipse-s-core",
+ "image": "ghcr.io/eclipse-score/devcontainer:v1.1.0",
+ "postCreateCommand": "bash .devcontainer/prepare_workspace.sh",
+ "postStartCommand": "ssh-keygen -f '/home/vscode/.ssh/known_hosts' -R '[localhost]:2222' || true"
+}
diff --git a/scorex/internal/templates/application/daal_app/point.devcontainer/prepare_workspace.sh.tmpl b/scorex/internal/templates/application/daal_app/point.devcontainer/prepare_workspace.sh.tmpl
new file mode 100644
index 0000000..0da37bc
--- /dev/null
+++ b/scorex/internal/templates/application/daal_app/point.devcontainer/prepare_workspace.sh.tmpl
@@ -0,0 +1,18 @@
+#!/bin/bash
+set -euo pipefail
+
+# Install pipx
+sudo apt update
+sudo apt install -y pipx
+
+# Install gita
+pipx install gita
+
+# Enable bash autocompletion for gita
+echo "eval \"\$(register-python-argcomplete gita -s bash)\"" >> ~/.bashrc
+
+# Set GITA_PROJECT_HOME environment variable
+echo "export GITA_PROJECT_HOME=$(pwd)/.gita" >> ~/.bashrc
+GITA_PROJECT_HOME=$(pwd)/.gita
+mkdir -p "$GITA_PROJECT_HOME"
+export GITA_PROJECT_HOME
\ No newline at end of file
diff --git a/scorex/internal/templates/application/daal_app/src/BUILD.tmpl b/scorex/internal/templates/application/daal_app/src/BUILD.tmpl
new file mode 100644
index 0000000..38bb2cd
--- /dev/null
+++ b/scorex/internal/templates/application/daal_app/src/BUILD.tmpl
@@ -0,0 +1,29 @@
+# *******************************************************************************
+# Copyright (c) 2025 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Apache License Version 2.0 which is available at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+# *******************************************************************************
+
+cc_binary(
+ name = "af_hello_world",
+ srcs = [
+ "hello_world_app.hpp",
+ "main.cpp",
+ ],
+ deps = [
+ "@score_inc_daal//src:daal_app_executor_builder",
+ "@score_inc_daal//src:daal_app_handler_singleshot",
+ "@score_inc_daal//src:daal_checkpoint",
+ "@score_inc_daal//src:daal_logger",
+ "@score_inc_daal//src:daal_os_helper",
+ "@score_inc_daal//src:daal_trigger",
+ "@score_inc_daal//src:dummy_execution_environment",
+ ],
+)
\ No newline at end of file
diff --git a/scorex/internal/templates/application/daal_app/src/hello_world_app.hpp.tmpl b/scorex/internal/templates/application/daal_app/src/hello_world_app.hpp.tmpl
new file mode 100644
index 0000000..ce07c7d
--- /dev/null
+++ b/scorex/internal/templates/application/daal_app/src/hello_world_app.hpp.tmpl
@@ -0,0 +1,47 @@
+/********************************************************************************
+* Copyright (c) 2025 Contributors to the Eclipse Foundation
+*
+* See the NOTICE file(s) distributed with this work for additional
+* information regarding copyright ownership.
+*
+* This program and the accompanying materials are made available under the
+* terms of the Apache License Version 2.0 which is available at
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* SPDX-License-Identifier: Apache-2.0
+********************************************************************************/
+
+#include "daal/af/app_base/safe_application_base.hpp"
+#include "daal/log/logger.hpp"
+
+namespace daal {
+namespace {{ .ProjectName }} {
+
+class HelloWorldApp : public daal::af::app_base::SafeApplicationBase {
+ public:
+ HelloWorldApp() : logger_(std::make_shared("APP")) { logger_->AddDefaultSinks(); };
+ ~HelloWorldApp() override = default;
+
+ daal::af::app_base::MethodState OnInitialize() override { return daal::af::app_base::MethodState::kSuccessful; }
+
+ daal::af::app_base::MethodState OnStart() override { return daal::af::app_base::MethodState::kSuccessful; }
+
+ daal::af::app_base::MethodState Step() override {
+ static unsigned int cycle_counter = 0;
+
+ logger_->Info("step #{}", cycle_counter);
+ cycle_counter++;
+
+ return daal::af::app_base::MethodState::kSuccessful;
+ }
+
+ daal::af::app_base::MethodState OnStop() override { return daal::af::app_base::MethodState::kSuccessful; }
+
+ daal::af::app_base::MethodState OnTerminate() override { return daal::af::app_base::MethodState::kSuccessful; }
+
+ private:
+ std::shared_ptr logger_;
+};
+
+} // namespace {{ .ProjectName }}
+} // namespace daal
diff --git a/scorex/internal/templates/application/daal_app/src/main.cpp.tmpl b/scorex/internal/templates/application/daal_app/src/main.cpp.tmpl
new file mode 100644
index 0000000..5902e77
--- /dev/null
+++ b/scorex/internal/templates/application/daal_app/src/main.cpp.tmpl
@@ -0,0 +1,62 @@
+/********************************************************************************
+* Copyright (c) 2025 Contributors to the Eclipse Foundation
+*
+* See the NOTICE file(s) distributed with this work for additional
+* information regarding copyright ownership.
+*
+* This program and the accompanying materials are made available under the
+* terms of the Apache License Version 2.0 which is available at
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* SPDX-License-Identifier: Apache-2.0
+********************************************************************************/
+
+#include
+
+#include "daal/af/app_handler/details/single_shot_app_handler.hpp"
+#include "daal/af/checkpoint/details/checkpoint_container.hpp"
+#include "daal/af/env/details/dummy_exec_env.hpp"
+#include "daal/af/exe/builder/executor_builder.hpp"
+#include "daal/af/os/details/posix_helper_impl.hpp"
+#include "daal/af/trigger/details/trigger_impl.hpp"
+#include "daal/log/logger.hpp"
+#include "hello_world_app.hpp"
+using namespace std::chrono_literals;
+
+int main() {
+ auto logger = std::make_shared("MAIN");
+ logger->AddDefaultSinks();
+
+ logger->Info("Starting DAAL hello-world application");
+
+ // (1) create the application
+ // (2) create the application handler (SingleShotAppHandler => we can run only one application)
+ auto my_app = std::make_shared();
+ std::unique_ptr app_handler =
+ std::make_unique(my_app);
+
+ // (3) create the executor with environment, scheduling/trigger and optional checkpoints
+ // here: a dummy environment, the AppHandler is called every 100ms and no checkpoints
+ auto exe = daal::af::exe::ExecutorBuilder()
+ .SetExecutionEnvironment(std::make_unique())
+ .SetPosixHelper(std::make_unique())
+ .SetTrigger(std::make_unique(500ms))
+ .SetCheckpointContainer(std::make_unique())
+ .Start()
+ .End()
+ .Build();
+
+ // (4) finalize the initialization of the exectuor
+ exe->Init();
+ exe->SetApplicationHandler(std::move(app_handler));
+
+ // (5) run the executor (= application) until it's terminated
+ bool ret = exe->Run();
+ if (ret) {
+ logger->Info("Application finished successfully");
+ } else {
+ logger->Error("Application finished with an error");
+ }
+
+ return ret ? 0 : -1;
+}
diff --git a/scorex/internal/templates/application/feo_app/BUILD.tmpl b/scorex/internal/templates/application/feo_app/BUILD.tmpl
new file mode 100644
index 0000000..e69de29
diff --git a/scorex/internal/templates/application/feo_app/MODULE.bazel.tmpl b/scorex/internal/templates/application/feo_app/MODULE.bazel.tmpl
new file mode 100644
index 0000000..da914ac
--- /dev/null
+++ b/scorex/internal/templates/application/feo_app/MODULE.bazel.tmpl
@@ -0,0 +1,52 @@
+# *******************************************************************************
+# Copyright (c) 2025 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Apache License Version 2.0 which is available at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+# *******************************************************************************
+module(
+ name = "{{ .ProjectName }}",
+ version = "0.0.1",
+)
+
+bazel_dep(name = "rules_boost", repo_name = "com_github_nelhage_rules_boost")
+archive_override(
+ module_name = "rules_boost",
+ strip_prefix = "rules_boost-master",
+ urls = ["https://github.com/nelhage/rules_boost/archive/refs/heads/master.tar.gz"],
+)
+
+# Rust rules for Bazel
+bazel_dep(name = "rules_rust", version = "0.67.0")
+bazel_dep(name = "rules_rust_prost", version = "0.67.0")
+
+# C/C++ rules for Bazel
+bazel_dep(name = "rules_cc", version = "0.2.8")
+
+bazel_dep(name = "trlc")
+git_override(
+ module_name = "trlc",
+ remote = "https://github.com/bmw-software-engineering/trlc.git",
+ commit = "650b51a47264a4f232b3341f473527710fc32669", # trlc-2.0.2 release
+)
+
+{{ range $name, $m := .SelectedModules }}
+# {{ $name }}
+bazel_dep(
+ name = "{{ $name }}",
+ version = "{{ $m.Version }}",
+)
+
+git_override(
+ module_name = "{{ $name }}",
+ remote = "{{ $m.Repo }}",
+ commit = "{{ $m.Hash }}",
+)
+
+{{ end }}
\ No newline at end of file
diff --git a/scorex/internal/templates/application/feo_app/point.bazelrc.tmpl b/scorex/internal/templates/application/feo_app/point.bazelrc.tmpl
new file mode 100644
index 0000000..f693141
--- /dev/null
+++ b/scorex/internal/templates/application/feo_app/point.bazelrc.tmpl
@@ -0,0 +1,15 @@
+# *******************************************************************************
+# Copyright (c) 2025 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Apache License Version 2.0 which is available at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+# *******************************************************************************
+
+common --registry=https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/
+common --registry=https://bcr.bazel.build
diff --git a/scorex/internal/templates/application/feo_app/point.bazelversion.tmpl b/scorex/internal/templates/application/feo_app/point.bazelversion.tmpl
new file mode 100644
index 0000000..3905b2b
--- /dev/null
+++ b/scorex/internal/templates/application/feo_app/point.bazelversion.tmpl
@@ -0,0 +1 @@
+{{ .BazelVersion }}
diff --git a/scorex/internal/templates/application/feo_app/point.devcontainer/devcontainer.json.tmpl b/scorex/internal/templates/application/feo_app/point.devcontainer/devcontainer.json.tmpl
new file mode 100644
index 0000000..cfef9e4
--- /dev/null
+++ b/scorex/internal/templates/application/feo_app/point.devcontainer/devcontainer.json.tmpl
@@ -0,0 +1,6 @@
+{
+ "name": "eclipse-s-core",
+ "image": "ghcr.io/eclipse-score/devcontainer:v1.1.0",
+ "postCreateCommand": "bash .devcontainer/prepare_workspace.sh",
+ "postStartCommand": "ssh-keygen -f '/home/vscode/.ssh/known_hosts' -R '[localhost]:2222' || true"
+}
diff --git a/scorex/internal/templates/application/feo_app/point.devcontainer/prepare_workspace.sh.tmpl b/scorex/internal/templates/application/feo_app/point.devcontainer/prepare_workspace.sh.tmpl
new file mode 100644
index 0000000..0da37bc
--- /dev/null
+++ b/scorex/internal/templates/application/feo_app/point.devcontainer/prepare_workspace.sh.tmpl
@@ -0,0 +1,18 @@
+#!/bin/bash
+set -euo pipefail
+
+# Install pipx
+sudo apt update
+sudo apt install -y pipx
+
+# Install gita
+pipx install gita
+
+# Enable bash autocompletion for gita
+echo "eval \"\$(register-python-argcomplete gita -s bash)\"" >> ~/.bashrc
+
+# Set GITA_PROJECT_HOME environment variable
+echo "export GITA_PROJECT_HOME=$(pwd)/.gita" >> ~/.bashrc
+GITA_PROJECT_HOME=$(pwd)/.gita
+mkdir -p "$GITA_PROJECT_HOME"
+export GITA_PROJECT_HOME
\ No newline at end of file
diff --git a/scorex/internal/templates/application/feo_app/src/BUILD.tmpl b/scorex/internal/templates/application/feo_app/src/BUILD.tmpl
new file mode 100644
index 0000000..24fa5b4
--- /dev/null
+++ b/scorex/internal/templates/application/feo_app/src/BUILD.tmpl
@@ -0,0 +1,36 @@
+# *******************************************************************************
+# Copyright (c) 2025 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Apache License Version 2.0 which is available at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+# *******************************************************************************
+
+load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library")
+
+rust_binary(
+ name = "hello_world_app",
+ srcs = [
+ "hello_world.rs",
+ ],
+ crate_features = ["signalling_relayed_tcp"],
+ rustc_flags = [
+ "-Clink-arg=-lstdc++",
+ "-Clink-arg=-lm",
+ "-Clink-arg=-lc",
+ ],
+ visibility = ["//visibility:public"],
+ deps = [
+ "@score_feo//feo:libfeo_rust",
+ "@score_feo//feo-log:libfeo_log_rust",
+ "@score_feo//feo-time:libfeo_time_rust",
+ "@score_feo//feo-logger:libfeo_logger_rust",
+ "@score_feo//feo-tracing:libfeo_tracing_rust",
+ ],
+)
+
diff --git a/scorex/internal/templates/application/feo_app/src/hello_world.rs.tmpl b/scorex/internal/templates/application/feo_app/src/hello_world.rs.tmpl
new file mode 100644
index 0000000..ed08113
--- /dev/null
+++ b/scorex/internal/templates/application/feo_app/src/hello_world.rs.tmpl
@@ -0,0 +1,30 @@
+/********************************************************************************
+ * Copyright (c) 2025 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Apache License Version 2.0 which is available at
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ ********************************************************************************/
+
+use feo::ids::AgentId;
+use feo_log::{info, LevelFilter};
+use feo_time::Duration;
+
+const AGENT_ID: AgentId = AgentId::new(100);
+const DEFAULT_FEO_CYCLE_TIME: Duration = Duration::from_secs(1);
+
+fn main() {
+ // initialize logging & tracing
+ feo_logger::init(LevelFilter::Info, true, true);
+ feo_tracing::init(feo_tracing::LevelFilter::INFO);
+
+ info!(
+ "Hello FEO from agent {AGENT_ID}, default cycle time = {:?}",
+ DEFAULT_FEO_CYCLE_TIME
+ );
+}
\ No newline at end of file
diff --git a/scorex/internal/templates/fs.go b/scorex/internal/templates/fs.go
new file mode 100644
index 0000000..444ce65
--- /dev/null
+++ b/scorex/internal/templates/fs.go
@@ -0,0 +1,7 @@
+package templates
+
+import "embed"
+
+// FS embeds all template files under internal/templates.
+//go:embed application/** module/**
+var FS embed.FS
diff --git a/scorex/internal/templates/module/BUILD.tmpl b/scorex/internal/templates/module/BUILD.tmpl
new file mode 100644
index 0000000..e69de29
diff --git a/scorex/internal/templates/module/MODULE.bazel.tmpl b/scorex/internal/templates/module/MODULE.bazel.tmpl
new file mode 100644
index 0000000..ea0378a
--- /dev/null
+++ b/scorex/internal/templates/module/MODULE.bazel.tmpl
@@ -0,0 +1,38 @@
+# *******************************************************************************
+# Copyright (c) 2025 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Apache License Version 2.0 which is available at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+# *******************************************************************************
+module(
+ name = "{{ .ProjectName }}",
+ version = "0.0.1",
+)
+
+bazel_dep(name = "rules_cc", version = "0.0.9")
+
+bazel_dep(name = "trlc")
+git_override(
+ module_name = "trlc",
+ remote = "https://github.com/bmw-software-engineering/trlc.git",
+ commit = "650b51a47264a4f232b3341f473527710fc32669", # trlc-2.0.2 release
+)
+
+{{ range $name, $m := .SelectedModules }}
+bazel_dep(
+ name = "{{ $name }}",
+ version = "{{ $m.Version }}",
+)
+
+git_override(
+ module_name = "{{ $name }}",
+ remote = "{{ $m.Repo }}",
+ commit = "{{ $m.Hash }}",
+)
+{{ end }}
diff --git a/scorex/internal/templates/module/point.bazelrc.tmpl b/scorex/internal/templates/module/point.bazelrc.tmpl
new file mode 100644
index 0000000..f693141
--- /dev/null
+++ b/scorex/internal/templates/module/point.bazelrc.tmpl
@@ -0,0 +1,15 @@
+# *******************************************************************************
+# Copyright (c) 2025 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Apache License Version 2.0 which is available at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+# *******************************************************************************
+
+common --registry=https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/
+common --registry=https://bcr.bazel.build
diff --git a/scorex/internal/templates/module/point.bazelversion.tmpl b/scorex/internal/templates/module/point.bazelversion.tmpl
new file mode 100644
index 0000000..3905b2b
--- /dev/null
+++ b/scorex/internal/templates/module/point.bazelversion.tmpl
@@ -0,0 +1 @@
+{{ .BazelVersion }}
diff --git a/scorex/internal/templates/module/point.devcontainer/devcontainer.json.tmpl b/scorex/internal/templates/module/point.devcontainer/devcontainer.json.tmpl
new file mode 100644
index 0000000..cfef9e4
--- /dev/null
+++ b/scorex/internal/templates/module/point.devcontainer/devcontainer.json.tmpl
@@ -0,0 +1,6 @@
+{
+ "name": "eclipse-s-core",
+ "image": "ghcr.io/eclipse-score/devcontainer:v1.1.0",
+ "postCreateCommand": "bash .devcontainer/prepare_workspace.sh",
+ "postStartCommand": "ssh-keygen -f '/home/vscode/.ssh/known_hosts' -R '[localhost]:2222' || true"
+}
diff --git a/scorex/internal/templates/module/point.devcontainer/prepare_workspace.sh.tmpl b/scorex/internal/templates/module/point.devcontainer/prepare_workspace.sh.tmpl
new file mode 100644
index 0000000..0da37bc
--- /dev/null
+++ b/scorex/internal/templates/module/point.devcontainer/prepare_workspace.sh.tmpl
@@ -0,0 +1,18 @@
+#!/bin/bash
+set -euo pipefail
+
+# Install pipx
+sudo apt update
+sudo apt install -y pipx
+
+# Install gita
+pipx install gita
+
+# Enable bash autocompletion for gita
+echo "eval \"\$(register-python-argcomplete gita -s bash)\"" >> ~/.bashrc
+
+# Set GITA_PROJECT_HOME environment variable
+echo "export GITA_PROJECT_HOME=$(pwd)/.gita" >> ~/.bashrc
+GITA_PROJECT_HOME=$(pwd)/.gita
+mkdir -p "$GITA_PROJECT_HOME"
+export GITA_PROJECT_HOME
\ No newline at end of file
diff --git a/scorex/internal/templates/module/src/BUILD.tmpl b/scorex/internal/templates/module/src/BUILD.tmpl
new file mode 100644
index 0000000..d63c345
--- /dev/null
+++ b/scorex/internal/templates/module/src/BUILD.tmpl
@@ -0,0 +1,19 @@
+# *******************************************************************************
+# Copyright (c) 2025 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Apache License Version 2.0 which is available at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+# *******************************************************************************
+cc_binary(
+ name = "main",
+ srcs = [
+ "main.cpp",
+ ],
+ visibility = ["//visibility:public"],
+)
diff --git a/scorex/internal/templates/module/src/main.cpp.tmpl b/scorex/internal/templates/module/src/main.cpp.tmpl
new file mode 100644
index 0000000..98e1250
--- /dev/null
+++ b/scorex/internal/templates/module/src/main.cpp.tmpl
@@ -0,0 +1,20 @@
+/********************************************************************************
+* Copyright (c) 2025 Contributors to the Eclipse Foundation
+*
+* See the NOTICE file(s) distributed with this work for additional
+* information regarding copyright ownership.
+*
+* This program and the accompanying materials are made available under the
+* terms of the Apache License Version 2.0 which is available at
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* SPDX-License-Identifier: Apache-2.0
+********************************************************************************/
+#include
+#include
+
+int main()
+{
+ std::cout << "Hello World!" << std::endl;
+ return 0;
+}
diff --git a/scorex/internal/utils/BUILD.bazel b/scorex/internal/utils/BUILD.bazel
new file mode 100644
index 0000000..5b2b315
--- /dev/null
+++ b/scorex/internal/utils/BUILD.bazel
@@ -0,0 +1,28 @@
+# *******************************************************************************
+# Copyright (c) 2026 Contributors to the Eclipse Foundation
+#
+# See the NOTICE file(s) distributed with this work for additional
+# information regarding copyright ownership.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Apache License Version 2.0 which is available at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+# *******************************************************************************
+load("@rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "utils",
+ srcs = [
+ "module_resolver.go",
+ "skeleton_properties.go",
+ ],
+ importpath = "scorex/internal/utils",
+ visibility = ["//scorex:__subpackages__"],
+ deps = [
+ "//scorex/internal/model",
+ "//scorex/internal/service/module",
+ "//scorex/internal/service/skeleton",
+ ],
+)
diff --git a/scorex/internal/utils/module_resolver.go b/scorex/internal/utils/module_resolver.go
new file mode 100644
index 0000000..f301d23
--- /dev/null
+++ b/scorex/internal/utils/module_resolver.go
@@ -0,0 +1,16 @@
+package utils
+
+import (
+ "scorex/internal/model"
+ "scorex/internal/service/module"
+)
+
+// Deprecated: use scorex/internal/service/module.ResolveModuleWithFallback.
+func ResolveModuleWithFallback(name string, knownGood map[string]model.ModuleInfo) (model.ModuleInfo, error) {
+ return module.ResolveModuleWithFallback(name, knownGood)
+}
+
+// Deprecated: use scorex/internal/service/module.ResolveModules.
+func ResolveModules(modules []string, knownGood map[string]model.ModuleInfo) (map[string]model.ModuleInfo, error) {
+ return module.ResolveModules(modules, knownGood)
+}
\ No newline at end of file
diff --git a/scorex/internal/utils/skeleton_properties.go b/scorex/internal/utils/skeleton_properties.go
new file mode 100644
index 0000000..a58a8e4
--- /dev/null
+++ b/scorex/internal/utils/skeleton_properties.go
@@ -0,0 +1,6 @@
+package utils
+
+import "scorex/internal/service/skeleton"
+
+// Deprecated: use scorex/internal/service/skeleton.Properties.
+type SkeletonProperties = skeleton.Properties
\ No newline at end of file
diff --git a/scorex/main.go b/scorex/main.go
new file mode 100644
index 0000000..9a6ef68
--- /dev/null
+++ b/scorex/main.go
@@ -0,0 +1,19 @@
+/********************************************************************************
+* Copyright (c) 2025 Contributors to the Eclipse Foundation
+*
+* See the NOTICE file(s) distributed with this work for additional
+* information regarding copyright ownership.
+*
+* This program and the accompanying materials are made available under the
+* terms of the Apache License Version 2.0 which is available at
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* SPDX-License-Identifier: Apache-2.0
+********************************************************************************/
+package main
+
+import "scorex/cmd"
+
+func main() {
+ cmd.Execute()
+}
diff --git a/src/assert_handler.cpp b/src/assert_handler.cpp
index 11c9c2a..0c8c3c5 100644
--- a/src/assert_handler.cpp
+++ b/src/assert_handler.cpp
@@ -1,15 +1,16 @@
/********************************************************************************
-* Copyright (c) 2025 Contributors to the Eclipse Foundation
-*
-* See the NOTICE file(s) distributed with this work for additional
-* information regarding copyright ownership.
-*
-* This program and the accompanying materials are made available under the
-* terms of the Apache License Version 2.0 which is available at
-* https://www.apache.org/licenses/LICENSE-2.0
-*
-* SPDX-License-Identifier: Apache-2.0
-********************************************************************************/
+ * Copyright (c) 2026 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Apache License Version 2.0 which is available at
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ ********************************************************************************/
+
#include "assert_handler.h"
#include "score/mw/log/logging.h"
diff --git a/src/assert_handler.h b/src/assert_handler.h
index f06108b..086fc25 100644
--- a/src/assert_handler.h
+++ b/src/assert_handler.h
@@ -1,15 +1,16 @@
/********************************************************************************
-* Copyright (c) 2025 Contributors to the Eclipse Foundation
-*
-* See the NOTICE file(s) distributed with this work for additional
-* information regarding copyright ownership.
-*
-* This program and the accompanying materials are made available under the
-* terms of the Apache License Version 2.0 which is available at
-* https://www.apache.org/licenses/LICENSE-2.0
-*
-* SPDX-License-Identifier: Apache-2.0
-********************************************************************************/
+ * Copyright (c) 2026 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Apache License Version 2.0 which is available at
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ ********************************************************************************/
+
#ifndef SCORE_MW_IPC_BRIDGE_ASSERTHANDLER_H
#define SCORE_MW_IPC_BRIDGE_ASSERTHANDLER_H
diff --git a/src/datatype.cpp b/src/datatype.cpp
index 667423f..fa1cad3 100644
--- a/src/datatype.cpp
+++ b/src/datatype.cpp
@@ -1,13 +1,14 @@
/********************************************************************************
-* Copyright (c) 2025 Contributors to the Eclipse Foundation
-*
-* See the NOTICE file(s) distributed with this work for additional
-* information regarding copyright ownership.
-*
-* This program and the accompanying materials are made available under the
-* terms of the Apache License Version 2.0 which is available at
-* https://www.apache.org/licenses/LICENSE-2.0
-*
-* SPDX-License-Identifier: Apache-2.0
-********************************************************************************/
+ * Copyright (c) 2026 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Apache License Version 2.0 which is available at
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ ********************************************************************************/
+
#include "datatype.h"
diff --git a/src/datatype.h b/src/datatype.h
index 8ce6f01..c1ad05c 100644
--- a/src/datatype.h
+++ b/src/datatype.h
@@ -1,15 +1,16 @@
/********************************************************************************
-* Copyright (c) 2025 Contributors to the Eclipse Foundation
-*
-* See the NOTICE file(s) distributed with this work for additional
-* information regarding copyright ownership.
-*
-* This program and the accompanying materials are made available under the
-* terms of the Apache License Version 2.0 which is available at
-* https://www.apache.org/licenses/LICENSE-2.0
-*
-* SPDX-License-Identifier: Apache-2.0
-********************************************************************************/
+ * Copyright (c) 2026 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Apache License Version 2.0 which is available at
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ ********************************************************************************/
+
#ifndef SCORE_IPC_BRIDGE_DATATYPE_H
#define SCORE_IPC_BRIDGE_DATATYPE_H
diff --git a/src/main.cpp b/src/main.cpp
index 29d7a14..4876ca9 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,15 +1,16 @@
/********************************************************************************
-* Copyright (c) 2025 Contributors to the Eclipse Foundation
-*
-* See the NOTICE file(s) distributed with this work for additional
-* information regarding copyright ownership.
-*
-* This program and the accompanying materials are made available under the
-* terms of the Apache License Version 2.0 which is available at
-* https://www.apache.org/licenses/LICENSE-2.0
-*
-* SPDX-License-Identifier: Apache-2.0
-********************************************************************************/
+ * Copyright (c) 2026 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Apache License Version 2.0 which is available at
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ ********************************************************************************/
+
#include "assert_handler.h"
#include "sample_sender_receiver.h"
diff --git a/src/sample_sender_receiver.cpp b/src/sample_sender_receiver.cpp
index 70c607b..5bc1384 100644
--- a/src/sample_sender_receiver.cpp
+++ b/src/sample_sender_receiver.cpp
@@ -1,15 +1,16 @@
/********************************************************************************
-* Copyright (c) 2025 Contributors to the Eclipse Foundation
-*
-* See the NOTICE file(s) distributed with this work for additional
-* information regarding copyright ownership.
-*
-* This program and the accompanying materials are made available under the
-* terms of the Apache License Version 2.0 which is available at
-* https://www.apache.org/licenses/LICENSE-2.0
-*
-* SPDX-License-Identifier: Apache-2.0
-********************************************************************************/
+ * Copyright (c) 2026 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Apache License Version 2.0 which is available at
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ ********************************************************************************/
+
#include "sample_sender_receiver.h"
#include "score/mw/com/impl/generic_proxy.h"
#include "score/mw/com/impl/generic_proxy_event.h"
diff --git a/src/sample_sender_receiver.h b/src/sample_sender_receiver.h
index 9ef7c45..b5e77b4 100644
--- a/src/sample_sender_receiver.h
+++ b/src/sample_sender_receiver.h
@@ -1,15 +1,16 @@
/********************************************************************************
-* Copyright (c) 2025 Contributors to the Eclipse Foundation
-*
-* See the NOTICE file(s) distributed with this work for additional
-* information regarding copyright ownership.
-*
-* This program and the accompanying materials are made available under the
-* terms of the Apache License Version 2.0 which is available at
-* https://www.apache.org/licenses/LICENSE-2.0
-*
-* SPDX-License-Identifier: Apache-2.0
-********************************************************************************/
+ * Copyright (c) 2026 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Apache License Version 2.0 which is available at
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ ********************************************************************************/
+
#ifndef SCORE_MW_COM_IPC_BRIDGE_SAMPLE_SENDER_RECEIVER_H
#define SCORE_MW_COM_IPC_BRIDGE_SAMPLE_SENDER_RECEIVER_H
diff --git a/tests/cpp/test_main.cpp b/tests/cpp/test_main.cpp
index f523107..104e096 100644
--- a/tests/cpp/test_main.cpp
+++ b/tests/cpp/test_main.cpp
@@ -1,15 +1,16 @@
/********************************************************************************
-* Copyright (c) 2025 Contributors to the Eclipse Foundation
-*
-* See the NOTICE file(s) distributed with this work for additional
-* information regarding copyright ownership.
-*
-* This program and the accompanying materials are made available under the
-* terms of the Apache License Version 2.0 which is available at
-* https://www.apache.org/licenses/LICENSE-2.0
-*
-* SPDX-License-Identifier: Apache-2.0
-********************************************************************************/
+ * Copyright (c) 2026 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Apache License Version 2.0 which is available at
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ ********************************************************************************/
+
#include
// Function to be tested
diff --git a/tests/rust/test_main.rs b/tests/rust/test_main.rs
index 9390d5e..7194058 100644
--- a/tests/rust/test_main.rs
+++ b/tests/rust/test_main.rs
@@ -1,3 +1,15 @@
+// *******************************************************************************
+// Copyright (c) 2026 Contributors to the Eclipse Foundation
+//
+// See the NOTICE file(s) distributed with this work for additional
+// information regarding copyright ownership.
+//
+// This program and the accompanying materials are made available under the
+// terms of the Apache License Version 2.0 which is available at
+//
+//
+// SPDX-License-Identifier: Apache-2.0
+// *******************************************************************************
#[test]
fn test_hello() {
assert_eq!(2 + 2, 4);