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);