Skip to content

Commit

Permalink
v24.2.1
Browse files Browse the repository at this point in the history
  • Loading branch information
tsopokis committed Apr 5, 2024
1 parent d3a5aeb commit 3d21248
Show file tree
Hide file tree
Showing 77 changed files with 4,148 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.cache
.vscode/
/dist
.deploy.log
39 changes: 39 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
ARG GO_VERSION=1.21

FROM golang:${GO_VERSION}-alpine AS builder-image
RUN apk update && apk add \
binutils \
make \
rpm \
ruby \
tar \
msitools \
uuidgen \
coreutils \
zip \
git \
&& gem install fpm

FROM builder-image AS ut-stage
WORKDIR /ut
COPY . .
RUN go install github.com/jstemmer/go-junit-report/v2@latest
RUN go test -v 2>&1 ./... | go-junit-report > ut-report.xml

FROM scratch AS ut-artifacts
COPY --from=ut-stage /ut/ut-report.xml /

FROM builder-image AS build-stage
WORKDIR /app
COPY . .

RUN make msi GOARCH=amd64 && \
make deb GOARCH=amd64 && \
make rpm GOARCH=amd64 && \
make osx GOARCH=amd64 &&\
make deb GOARCH=arm64 && \
make rpm GOARCH=arm64 && \
make osx GOARCH=arm64

FROM scratch AS build-artifacts
COPY --from=build-stage /app/dist /
122 changes: 122 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
VERSION := $(shell git describe --tags)
BUILD_FLAGS := -x -v -ldflags "-X corteca/cmd.appVersion=$(VERSION)"
GOOS ?= $(shell go env GOOS)
GOARCH ?= $(shell go env GOARCH)

CURRDIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
DIST := $(CURRDIR)dist
BIN := $(DIST)/bin
TMP := $(shell mktemp -d)
PACKAGES := $(DIST)/packages
BINARY_NAME = corteca
FULL_BINARY_NAME = $(BINARY_NAME)-$(GOOS)-$(GOARCH)-$(VERSION)

# build main binary
$(BIN)/$(FULL_BINARY_NAME): $(TMP)
go env
CGO_ENABLED=0 GOOS=$(GOOS) GOARCH=$(GOARCH) go build $(BUILD_FLAGS) -o $(BIN)/$(FULL_BINARY_NAME) main.go

$(TMP):
mkdir -p $(TMP)

# run all available tests
test:
go test ./... -v

clean:
rm -rfv $(BIN)
go clean -modcache

distclean: clean
rm -rfv $(DIST)

$(GOOS)-target: $(BIN)/$(FULL_BINARY_NAME)
mkdir -p $(DESTDIR)/opt/corteca $(DESTDIR)/etc/corteca $(DESTDIR)/usr/bin
cp -v $(BIN)/$(FULL_BINARY_NAME) $(DESTDIR)/opt/corteca/$(BINARY_NAME)
ln -sf /opt/corteca/$(BINARY_NAME) $(DESTDIR)/usr/bin/
cp -rv data/* $(DESTDIR)/etc/corteca/

install: $(GOOS)-target

uninstall:
@if [ -e $(DESTDIR)/usr/bin/$(BINARY_NAME) ]; then unlink $(DESTDIR)/usr/bin/$(BINARY_NAME) && echo "removed '$(DESTDIR)/usr/bin/$(BINARY_NAME)' symlink"; fi
@if [ -e $(DESTDIR)/opt/corteca/$(BINARY_NAME) ]; then rm -v $(DESTDIR)/opt/corteca/$(BINARY_NAME) && rmdir -v $(DESTDIR)/opt/corteca; fi
rm -rfv $(DESTDIR)/etc/corteca

$(PACKAGES):
mkdir -p $(PACKAGES)

deb: GOOS := linux
deb: DESTDIR := $(TMP)/$(BINARY_NAME)_$(GOOS)_$(VERSION)_$(GOARCH)
deb: PKGNAME := $(BINARY_NAME)_$(VERSION)_$(GOARCH).deb
deb: $(GOOS)-target | $(PACKAGES)
fpm -f -s dir \
-t deb \
-C "$(DESTDIR)" \
--name corteca-cli \
--version $(VERSION) \
--iteration 1 \
--description "Corteca Developer Toolkit cli" \
--no-deb-generate-changes \
--package $(PACKAGES)/$(PKGNAME) \
--depends "docker.io | docker-ce | podman-docker" \
--architecture $(GOARCH) \
--maintainer "Nokia" \
--url "https://nokia.com"

rpm: GOOS := linux
rpm: DESTDIR := $(TMP)/$(BINARY_NAME)_$(GOOS)_$(VERSION)_$(GOARCH)
rpm: PKGNAME := $(BINARY_NAME)_$(VERSION)_$(GOARCH).rpm
rpm: $(GOOS)-target | $(PACKAGES)
fpm -f -s dir \
-t rpm \
-C "$(DESTDIR)" \
--name corteca-cli \
--version $(VERSION) \
--iteration 1 \
--description "Corteca Developer Toolkit cli" \
--package $(PACKAGES)/$(PKGNAME) \
--architecture $(GOARCH) \
--maintainer "Nokia" \
--url "https://nokia.com"

osx: GOOS := darwin
osx: DESTDIR := $(TMP)/$(BINARY_NAME)_$(GOOS)_$(VERSION)_$(GOARCH)
osx: PKGNAME := $(BINARY_NAME)_$(VERSION)_$(GOARCH).osxpkg
osx: $(GOOS)-target | $(PACKAGES)
(cd $(TMP) && zip -r $(PACKAGES)/$(BINARY_NAME)_$(VERSION)_$(GOARCH).zip "$(BINARY_NAME)_$(GOOS)_$(VERSION)_$(GOARCH)")
# mkdir -p $(PACKAGES)
# @echo This can only run on OSX
# fpm -f -s dir \
# -t osxpkg \
# -C "$(DESTDIR)" \
# --name corteca-cli \
# --version $(VERSION) \
# --iteration 1 \
# --description "Corteca Developer Toolkit cli" \
# --package $(PACKAGES)/$(PKGNAME) \
# --architecture $(GOARCH) \
# --maintainer "Nokia" \
# --url "https://nokia.com" .

msi: GOOS := windows
msi: DESTDIR := $(TMP)/$(BINARY_NAME)_$(GOOS)_$(VERSION)_$(GOARCH)
msi: PKGNAME := $(BINARY_NAME)_$(VERSION)_$(GOARCH).msi
msi: GUID := $(shell uuidgen)
msi: INSTALLER_XML := corteca.wxs
msi: DEST_REL_PATH := $(shell realpath --relative-to=$(CURRDIR) $(DESTDIR))
msi: $(GOOS)-target | $(PACKAGES)
mv $(DESTDIR)/opt/corteca/$(BINARY_NAME) $(DESTDIR)/opt/corteca/$(BINARY_NAME).exe

@echo Generating XML files for corteca components...
find $(DESTDIR)/opt/corteca | wixl-heat -p $(DESTDIR)/opt/corteca/ --component-group CortecaExeComponentGroup --var var.SourceDir \
--directory-ref=INSTALLFOLDER > $(DESTDIR)/exec.wxs
find $(DESTDIR)/etc/corteca | wixl-heat -p $(DESTDIR)/etc/corteca/ --component-group CortecaConfigComponentGroup --var var.SourceConfigDir \
--directory-ref=PROGRAMDATADIR > $(DESTDIR)/config.wxs

@echo Building MSI...
wixl -v -o $(PACKAGES)/$(PKGNAME) $(INSTALLER_XML) $(DESTDIR)/exec.wxs $(DESTDIR)/config.wxs -D SourceDir="$(DEST_REL_PATH)/opt/corteca" -D SourceConfigDir="$(DEST_REL_PATH)/etc/corteca" -D Guid="$(GUID)" -D Version="$(VERSION)" --arch x64

all-packages: msi deb rpm osx

.PHONY: all-packages osx rpm deb msi win-binary osx-binary linux-binary uninstall install distclean clean test linux-target windows-target darwin-target
150 changes: 150 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# Corteca Command Line Interface (Corteca CLI)

Part of Corteca Developer Toolkit, Corteca CLI facilitates bootstapping and development of container applications compatible with [Corteca Marketplace](https://www.nokia.com/networks/fixed-networks/corteca-applications/). Developers can easily create a basic structure and ensures the appropriate format for the applications by targetting to specific platform/architectures.

## Build

### Build using native Go toolchain

To build the tool, use the provided `Makefile` as follows:

```bash
make
```

Keep in mind that Go v1.21 is required.

### Build using docker

If you don't have the required development environment you can also build using
docker (BuildKit is required, see below). Use the following command inside
the project root folder:

```bash
docker build --output ./dist .
```

#### Installing docker BuildKit builder

As per the [documentation](https://docs.docker.com/build/buildkit/#getting-started),
if you are using a docker engine prior to v23.0 you need to manually (install
and) enable the buildkit builder. In Ubuntu v22.04, you can use the following
cmd to install it:

```bash
sudo apt-get install docker-buildx-plugin
```

Afterwards, either prepend `DOCKER_BUILDKIT=1` to each of the afforementioned
`docker build ...` commands, or follow the instructions in the provided link, to
enable buildkit by default.

## Install

To install the binary in the default `$GOBIN` path (defaults to `$HOME/go/bin`)
as well as the necessary template files (in `$HOME/.config/corteca`), use
the following command:

```bash
make install
```

To uninstall a previous installation, use:

```bash
make uninstall
```

## Usage

Use `corteca help` to obtain information on how to invoke the various
commands supported by the tool.

### Generate a new application skeleton

To generate a new application in the current folder, use:

```bash
corteca create <appdir>
```

This will prompt you to enter information about the application and also select
the application language.

### Build the application to produce an app package

To build the application, use:

```text
corteca build [<TOOLCHAIN>]
```

If `<TOOLCHAIN>` is omitted, the default toolchain is used. To see the
available toolchains, use the following:

```bash
corteca config get toolchain.targets
```

## Writing templates

A template is collection of files that are rendered using Golang's [text/template](https://pkg.go.dev/text/template) package. `corteca` scans for available templates in a `templates` folder that resides in the global config folder (defaults to `$HOME/.config/corteca`). You can override the global config folder using the `--configRoot` flag.

Each subfolder containing a `.template-info.yaml` file will be treated as a template and will be rendered with all configuration variables available for rendering. For more information, see [Configuration](#configuration) below.

### `.template-info.yaml`

Here is an overview of the file's contents:

```yaml
# name of the template
name: "c"
description: "Short template description"
# a collection of custom options available for rendering
options:
# this will be available inside template context
- name: "include_libhlapi"
# text used to prompt the user
description: "Include hlapi C lib"
# One of: "boolean", "text" or "choice"
type: "boolean"
# true/false for boolean type, any text value for "text" or "choice"
default: true
# available options for "choices" type
# values:
# - option1
```

### Rendering

The template is rendered using the following rules:

1. Starting from the parent folder containing the `.template-info.yaml` file, a list of full paths to every regular file in the folder structure is produced
1. Each entry in the list is rendered by the template engine into a path string; this allowes template variable usage in both file and directory names
1. A file is created in the destination folder using the full relative (rendered) path and is filled with the content of the original rendered template file.
1. If any path element is rendered into an empty string, this path entry is skipped
from the rest of the sequence; this allows for conditional generation of folder sub-structure. For example, consider the following structure:

```text
{{.app.name}}
├── {{.app.name}}.c
├── {{if .app.options.include_libhlapi}}libs{{end}}
│   └── lib.h
└── {{if .app.options.include_libhlapi}}libs.inc{{end}}
If the `.app.options.use_libhlapi` evaluates to false, the whole filename template will be rendered empty; thus both the `libs` subfolder (and all its containing items), as well as the `libs.inc` regular file will be omitted from the resulting file structure.
```

### Configuration

Configuration values are read cascadingly from the following sources:

1. System-wide configuration: `/etc/corteca/corteca.yaml`
1. User global configuration: `$HOME/.config/corteca/corteca.yaml`
1. user local (project) configuration: `.corteca.yaml`

The last is searched in the working directory where `corteca` binary is executed; if
not found, it will continue searching in the parent folder(s), until it finds a
configuration file or reaches filesystem root. Thus, provided that a local
configuration file exists in the project root folder, `corteca` commands can be run from
any subfolder inside that.
71 changes: 71 additions & 0 deletions cmd/build.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright 2024 Nokia
// Licensed under the BSD 3-Clause License.
// SPDX-License-Identifier: BSD-3-Clause

package cmd

import (
"corteca/internal/configuration"
"corteca/internal/toolchain"
"corteca/internal/tui"
"fmt"

"github.com/spf13/cobra"
)

var buildCmd = &cobra.Command{
Use: "build [TOOLCHAIN]",
Short: "Build application",
Long: `Build the application using the appropriate build toolchain`,
Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
toolchain := ""
if len(args) > 0 {
toolchain = args[0]
}

doBuildApp(toolchain)
},
}

var buildAll bool

func init() {
buildCmd.PersistentFlags().BoolVar(&buildAll, "all", false, "Build for all platforms")
rootCmd.AddCommand(buildCmd)
}

func doBuildApp(selectedName string) {
requireProjectContext()

if selectedName == "" {
selectedName = config.Build.Default
} else if _, ok := config.Build.Toolchains[selectedName]; !ok {
failOperation(fmt.Sprintf("no configuration present for toolchain: \"%v\"", selectedName))
}

for toolchainName, toolchain := range config.Build.Toolchains {

if !buildAll && selectedName != toolchainName {
continue
}

fmt.Printf("Building with toolchain '%s'...\n", toolchainName)
err := doBuildTarget(toolchain.Image, toolchain.ConfigFile, config.Build.Options)
if err != nil {
tui.DisplayErrorMsg(fmt.Sprintf("Error building '%s': %s", toolchainName, err.Error()))
failOperation("Build failed")
}
tui.DisplaySuccessMsg(fmt.Sprintf("Application '%v' was built successfully with toolchain '%v'\n", config.App.Name, toolchainName))
}
}

func doBuildTarget(targetImage string, customConfig string, buildOptions configuration.BuildOptions) error {
err := toolchain.Invoke(targetImage, projectRoot, customConfig, buildOptions)

if err != nil {
return fmt.Errorf("invoking toolchain image '%v': %v", targetImage, err)
}

return nil
}
Loading

0 comments on commit 3d21248

Please sign in to comment.