Skip to content

Commit

Permalink
Add support for embedded definitions
Browse files Browse the repository at this point in the history
- Embedding OpenAPI definitions during build time which allows us to
  distribute a single executable without any additional dependencies
- Extended the definition store to provide embedded OpenAPI documents
- Allowing overriding embedded definitions or adding additional OpenAPI
  specifications by adding them to the definitions/ folder
  • Loading branch information
thschmitt committed Oct 4, 2023
1 parent 64fedec commit a37065f
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 33 deletions.
5 changes: 2 additions & 3 deletions build.ps1
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
Write-Host "Copying OpenAPI definitions"
New-Item -ItemType Directory -Force -Path build/definitions | out-null
Copy-Item definitions/* -Destination build/definitions/
Write-Host "Copying README.md"
New-Item -ItemType Directory -Force -Path build | out-null
Copy-Item README.md -Destination build/README.md

Write-Host "Building Linux (amd64) executable"
Expand Down
5 changes: 2 additions & 3 deletions build.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
#! /bin/bash
set -e

echo "Copying OpenAPI definitions"
mkdir -p build/definitions
cp definitions/* build/definitions/
echo "Copying README.md"
mkdir -p build
cp README.md build/README.md

echo "Building Linux (amd64) executable"
Expand Down
73 changes: 53 additions & 20 deletions commandline/definition_file_store.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package commandline

import (
"embed"
"fmt"
"os"
"path/filepath"
Expand All @@ -11,6 +12,7 @@ import (
// the definitions/ folder and returns the data for a particular definition file.
type DefinitionFileStore struct {
directory string
embedded embed.FS
files []string
definitions []DefinitionData
}
Expand Down Expand Up @@ -68,39 +70,66 @@ func (s *DefinitionFileStore) discoverDefinitions(version string) ([]string, err
return s.files, nil
}

definitionsDirectory, err := s.definitionsPath(version)
if err != nil {
return nil, err
definitionFiles := map[string]string{}

embeddedPaths := s.discoverDefinitionsEmbedded()
for _, path := range embeddedPaths {
definitionFiles[path] = path
}
files, err := os.ReadDir(definitionsDirectory)
if err != nil && os.IsNotExist(err) && version != "" {
return nil, fmt.Errorf("Could not find definition files for version '%s' in folder '%s'", version, definitionsDirectory)
paths := s.discoverDefinitionsDirectory(version)
for _, path := range paths {
definitionFiles[path] = path
}
if err != nil {
return nil, fmt.Errorf("Error reading definition files from folder '%s': %w", definitionsDirectory, err)

if len(definitionFiles) == 0 {
return nil, fmt.Errorf("Could not find definition files in folder '%s'", s.definitionsPath(version))
}

result := []string{}
for _, path := range definitionFiles {
result = append(result, path)
}
s.files = result
return result, nil
}

func (s DefinitionFileStore) discoverDefinitionsEmbedded() []string {
definitionFiles := []string{}
for _, file := range files {
filename := file.Name()
if strings.HasSuffix(filename, "yaml") || strings.HasSuffix(filename, "yml") || strings.HasSuffix(filename, "json") {
path := filepath.Join(definitionsDirectory, file.Name())
embeddedDir, err := s.embedded.ReadDir(DefinitionsDirectory)
if err == nil {
for _, file := range embeddedDir {
path := filepath.Join(DefinitionsDirectory, file.Name())
definitionFiles = append(definitionFiles, path)
}
}
s.files = definitionFiles
return definitionFiles, nil
return definitionFiles
}

func (s DefinitionFileStore) discoverDefinitionsDirectory(version string) []string {
definitionFiles := []string{}
definitionsDirectory := s.definitionsPath(version)
files, err := os.ReadDir(definitionsDirectory)
if err == nil {
for _, file := range files {
filename := file.Name()
if strings.HasSuffix(filename, "yaml") || strings.HasSuffix(filename, "yml") || strings.HasSuffix(filename, "json") {
path := filepath.Join(definitionsDirectory, filename)
definitionFiles = append(definitionFiles, path)
}
}
}
return definitionFiles
}

func (s DefinitionFileStore) definitionsPath(version string) (string, error) {
func (s DefinitionFileStore) definitionsPath(version string) string {
if s.directory != "" {
return s.directory, nil
return s.directory
}
currentDirectory, err := os.Executable()
definitionsDirectory := filepath.Join(filepath.Dir(currentDirectory), DefinitionsDirectory, version)
if err != nil {
return "", fmt.Errorf("Error reading definition files from folder '%s': %w", definitionsDirectory, err)
return filepath.Join(DefinitionsDirectory, version)
}
return definitionsDirectory, nil
return filepath.Join(filepath.Dir(currentDirectory), DefinitionsDirectory, version)
}

func (s DefinitionFileStore) definitionName(path string) string {
Expand All @@ -117,15 +146,19 @@ func (s DefinitionFileStore) definitionNames(paths []string) []string {

func (s DefinitionFileStore) readDefinitionData(path string) ([]byte, error) {
data, err := os.ReadFile(path)
if err != nil {
data, err = s.embedded.ReadFile(path)
}
if err != nil {
return nil, fmt.Errorf("Error reading definition file '%s': %w", path, err)
}
return data, nil
}

func NewDefinitionFileStore(directory string) *DefinitionFileStore {
func NewDefinitionFileStore(directory string, embedded embed.FS) *DefinitionFileStore {
return &DefinitionFileStore{
directory: directory,
embedded: embedded,
}
}

Expand Down
6 changes: 5 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package main

import (
"embed"
"fmt"
"os"
"runtime"
Expand All @@ -20,6 +21,9 @@ import (
"github.com/UiPath/uipathcli/utils"
)

//go:embed definitions/*.yaml
var embedded embed.FS

func authenticators(pluginsCfg config.PluginConfig) []auth.Authenticator {
authenticators := []auth.Authenticator{}
for _, authenticator := range pluginsCfg.Authenticators {
Expand Down Expand Up @@ -71,7 +75,7 @@ func main() {
os.Stderr,
colorsSupported(),
*commandline.NewDefinitionProvider(
commandline.NewDefinitionFileStore(os.Getenv("UIPATH_DEFINITIONS_PATH")),
commandline.NewDefinitionFileStore(os.Getenv("UIPATH_DEFINITIONS_PATH"), embedded),
parser.NewOpenApiParser(),
[]plugin.CommandPlugin{
plugin_digitizer.DigitizeCommand{},
Expand Down
12 changes: 6 additions & 6 deletions package.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,24 @@ rm --force build/packages/*
pushd build/ > /dev/null

echo "Create Linux (amd64) Package"
tar --create --gzip --overwrite --file=packages/uipathcli-linux-amd64.tar.gz --transform='flags=r;s|uipath-linux-amd64|uipath|' uipath-linux-amd64 definitions
tar --create --gzip --overwrite --file=packages/uipathcli-linux-amd64.tar.gz --transform='flags=r;s|uipath-linux-amd64|uipath|' uipath-linux-amd64

echo "Create Windows (amd64) Package"
zip -q packages/uipathcli-windows-amd64.zip uipath-windows-amd64.exe definitions/*
zip -q packages/uipathcli-windows-amd64.zip uipath-windows-amd64.exe
printf "@ uipath-windows-amd64.exe\n@=uipath.exe\n" | zipnote -w packages/uipathcli-windows-amd64.zip

echo "Create MacOS (amd64) Package"
tar --create --gzip --overwrite --file=packages/uipathcli-darwin-amd64.tar.gz --transform='flags=r;s|uipath-darwin-amd64|uipath|' uipath-darwin-amd64 definitions
tar --create --gzip --overwrite --file=packages/uipathcli-darwin-amd64.tar.gz --transform='flags=r;s|uipath-darwin-amd64|uipath|' uipath-darwin-amd64

echo "Create Linux (arm64) Package"
tar --create --gzip --overwrite --file=packages/uipathcli-linux-arm64.tar.gz --transform='flags=r;s|uipath-linux-arm64|uipath|' uipath-linux-arm64 definitions
tar --create --gzip --overwrite --file=packages/uipathcli-linux-arm64.tar.gz --transform='flags=r;s|uipath-linux-arm64|uipath|' uipath-linux-arm64

echo "Create Windows (arm64) Package"
zip -q packages/uipathcli-windows-arm64.zip uipath-windows-arm64.exe definitions/*
zip -q packages/uipathcli-windows-arm64.zip uipath-windows-arm64.exe
printf "@ uipath-windows-arm64.exe\n@=uipath.exe\n" | zipnote -w packages/uipathcli-windows-arm64.zip

echo "Create MacOS (arm64) Package"
tar --create --gzip --overwrite --file=packages/uipathcli-darwin-arm64.tar.gz --transform='flags=r;s|uipath-darwin-arm64|uipath|' uipath-darwin-arm64 definitions
tar --create --gzip --overwrite --file=packages/uipathcli-darwin-arm64.tar.gz --transform='flags=r;s|uipath-darwin-arm64|uipath|' uipath-darwin-arm64

popd > /dev/null
echo "Successfully created packages"

0 comments on commit a37065f

Please sign in to comment.