Skip to content

Commit

Permalink
Build context subsystem (#12)
Browse files Browse the repository at this point in the history
* Refactoring

* Refactoring command.go

* renaming mod, adding version support

* Add copyright notice

* Updating text

* Working on contexts

* reworking

* reworking some more

* ported to use project context, got away from pointer hell
  • Loading branch information
hlafaille authored Oct 11, 2024
1 parent ab484ff commit 5f3097b
Show file tree
Hide file tree
Showing 38 changed files with 889 additions and 586 deletions.
3 changes: 2 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"customizations": {
"vscode": {
"extensions": [
"DavidAnson.vscode-markdownlint"
"DavidAnson.vscode-markdownlint",
"redhat.vscode-yaml"
]
}
}
Expand Down
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
build:
go build -ldflags="-X kerosenelabs.com/espresso/core/service.CommitSha=$(shell git rev-parse HEAD) -X kerosenelabs.com/espresso/core/service.Version=$(VERSION)"

install:
sudo mv espresso /usr/local/bin
282 changes: 29 additions & 253 deletions cli/command.go
Original file line number Diff line number Diff line change
@@ -1,144 +1,54 @@
// Copyright (c) 2024 Kerosene Labs
// This file is part of Espresso, which is licensed under the MIT License.
// See the LICENSE file for details.

package cli

import (
"fmt"
"os"
"strings"
"sync"

"github.com/fatih/color"
"github.com/olekukonko/tablewriter"
"github.com/spf13/cobra"
"hlafaille.xyz/espresso/v0/core/dependency"
"hlafaille.xyz/espresso/v0/core/project"
"hlafaille.xyz/espresso/v0/core/registry"
"hlafaille.xyz/espresso/v0/core/toolchain"
"hlafaille.xyz/espresso/v0/core/util"
"kerosenelabs.com/espresso/core/service"
)

// GetVersionCommand gets the prepared "version" command for cobra
func GetVersionCommand() *cobra.Command {
var root = &cobra.Command{
Use: "version",
Short: "Print the version of Espresso",
Aliases: []string{"v"},
Run: func(cmd *cobra.Command, args []string) {
service.PrintVersion()
},
}
return root
}

// GetCleanCommand gets the prepared "clean" command for cobra
func GetCleanCommand() *cobra.Command {
var root = &cobra.Command{
Use: "clean",
Short: "Clean the build context",
Aliases: []string{"c"},
Run: func(cmd *cobra.Command, args []string) {
// get the config
cfg, err := project.GetConfig()
if err != nil {
fmt.Printf("An error occurred while reading the config: %s\n", err)
}

// get the build dir
buildPath, err := toolchain.GetBuildPath(cfg)
if err != nil {
fmt.Printf("An error occurred while getting the build path: %s\n", err)
return
}

// get the dist dir
distPath, err := toolchain.GetDistPath(cfg)
if err != nil {
fmt.Printf("An error occurred while getting the build path: %s\n", err)
return
}

// remove the build dir
err = os.RemoveAll(*buildPath)
if err != nil {
fmt.Printf("An error occurred while deleting the build path: %s\n", err)
return
}

// remove the dist dir
err = os.RemoveAll(*distPath)
if err != nil {
fmt.Printf("An error occurred while deleting the dist path: %s\n", err)
return
}
service.CleanWorkspace()
},
}
return root
}

// GetProjectCommand returns the pre-built Cobra Command 'project'
// GetBuildCommand gets the prepared "build" command for cobra
func GetBuildCommand() *cobra.Command {
var root = &cobra.Command{
Use: "build",
Short: "Build the project, outputting a distributable.",
Aliases: []string{"b"},
Run: func(cmd *cobra.Command, args []string) {
// get the config
cfg, err := project.GetConfig()
if err != nil {
panic(fmt.Sprintf("An error occurred while reading the config: %s\n", err))
}
color.Cyan("-- Building '%s', please ensure you are compliant with all dependency licenses\n", cfg.Name)

// discover source files
files, err := project.DiscoverSourceFiles(cfg)
if err != nil {
ErrorQuit(fmt.Sprintf("An error occurred while discovering source files: %s\n", err))
}

// run the compiler on each source file
var wg sync.WaitGroup
for _, value := range files {
wg.Add(1)
go func(f *project.SourceFile) {
defer wg.Done()
color.Cyan("-- Compiling: " + f.Path)
toolchain.CompileSourceFile(cfg, &value)
}(&value)
}
wg.Wait()

// package the project
color.Cyan("-- Packaging distributable")
err = toolchain.PackageClasses(cfg)
if err != nil {
ErrorQuit(fmt.Sprintf("An error occurred while packaging the classes: %s\n", err))
}
color.Blue("Finished packaging distributable")

// iterate over each dependency, resolve it and copy it
distPath, err := toolchain.GetDistPath(cfg)
if err != nil {
ErrorQuit(fmt.Sprintf("Unable to get dist path: %s", err))
}
os.MkdirAll(*distPath+"/libs", 0755)
var depCopyWg sync.WaitGroup
color.Cyan("-- Copying packages to distributable")
for _, dep := range cfg.Dependencies {
depCopyWg.Add(1)
go func() {
defer depCopyWg.Done()
color.Cyan("-- Beginning copy of '%s:%s' to distributable", dep.Group, dep.Name)
resolved, err := dependency.ResolveDependency(&dep, &cfg.Registries)
if err != nil {
ErrorQuit(fmt.Sprintf("Unable to resolve dependency: %s", err))
}

// calculate the should-be location of this jar locally
espressoPath, err := util.GetEspressoDirectoryPath()
if err != nil {
ErrorQuit(fmt.Sprintf("Unable to get the espresso home: %s", espressoPath))
}
signature := registry.CalculatePackageSignature(resolved.Package, resolved.PackageVersion)
cachedPackageHome := espressoPath + "/cachedPackages" + signature + ".jar"

// copy the file
util.CopyFile(cachedPackageHome, *distPath+"/libs")

color.Blue("Copied '%s:%s' to distributable", dep.Group, dep.Name)
}()
}
depCopyWg.Wait()
color.Green("Done!")
service.BuildProject()
},
}
return root
}

// GetInitCommand gets the prepared "init" command for cobra
func GetInitCommand() *cobra.Command {
var root = &cobra.Command{
Use: "init",
Expand All @@ -148,50 +58,7 @@ func GetInitCommand() *cobra.Command {
var name, _ = cmd.Flags().GetString("name")
var basePackage, _ = cmd.Flags().GetString("package")

// ensure JAVA_HOME is set
javaHome, err := util.GetJavaHome()
if err != nil {
fmt.Println("JAVA_HOME is not set, do you have Java installed?")
}

// ensure a proejct doesn't already exist
cfgExists, err := project.ConfigExists()
if err != nil {
fmt.Println("Error occurred while ensuring a config doesn't already exist")
panic(err)
} else if *cfgExists {
fmt.Println("Config already exists")
os.Exit(1)
}

fmt.Printf("Creating '%s'\n", name)

// create a base config
cfg := project.ProjectConfig{
Name: name,
Version: project.Version{
Major: 0,
Minor: 1,
Patch: 0,
Hotfix: nil,
},
BasePackage: basePackage,
Toolchain: project.Toolchain{
Path: *javaHome,
},
Registries: []project.Registry{{Name: "espresso-registry", Url: "https://github.com/Kerosene-Labs/espresso-registry/archive/refs/heads/main.zip"}},
Dependencies: []project.Dependency{},
}

// write some example code
println("Creating base package, writing example code")
project.WriteExampleCode(&cfg)

// persist the config
println("Persisting project configuration")
project.PersistConfig(&cfg)

println("Done.")
service.InitializeProject(name, &basePackage)
},
}
root.Flags().StringP("name", "n", "", "Name of the project")
Expand All @@ -200,7 +67,7 @@ func GetInitCommand() *cobra.Command {
return root
}

// GetRegistryCommand returns the pre build Cobra Command 'dependency'
// GetRegistryCommand gets the prepared "registry" command for cobra
func GetRegistryCommand() *cobra.Command {
var root = &cobra.Command{
Use: "registry",
Expand All @@ -213,50 +80,7 @@ func GetRegistryCommand() *cobra.Command {
Aliases: []string{"q"},
Run: func(cmd *cobra.Command, args []string) {
var term, _ = cmd.Flags().GetString("term")

// get the config
cfg, err := project.GetConfig()
if err != nil {
panic(fmt.Sprintf("An error occurred while reading the config: %s\n", err))
}

// iterate over each registry, get its packages
var filteredPkgs []registry.Package = []registry.Package{}
for _, reg := range cfg.Registries {
color.Blue("Checking '%s'", reg.Name)
regPkgs, err := registry.GetRegistryPackages(reg)
if err != nil {
panic(fmt.Sprintf("An error occurred while fetching packages from the '%s' registry cache: %s", reg.Name, err))
}

// filter by name
for _, pkg := range regPkgs {
if term == "*" ||
strings.Contains(strings.ToLower(pkg.Name), strings.ToLower(term)) ||
strings.Contains(strings.ToLower(pkg.Description), strings.ToLower(term)) {
filteredPkgs = append(filteredPkgs, pkg)
}
}
}

// print out our packages
color.Cyan("Found %v package(s):", len(filteredPkgs))
data := [][]string{}
for _, filtered := range filteredPkgs {
data = append(data, []string{
filtered.Group,
filtered.Name,
filtered.Versions[len(filtered.Versions)-1].Number,
})
}

table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"Group", "Package", "Latest Version"})

for _, v := range data {
table.Append(v)
}
table.Render()
service.QueryRegistries(term)
},
}
query.Flags().StringP("term", "t", "", "Term to query by")
Expand All @@ -267,35 +91,14 @@ func GetRegistryCommand() *cobra.Command {
Use: "invalidate",
Short: "Invalidate and recache the declared registries.",
Run: func(cmd *cobra.Command, args []string) {
// get the config
cfg, err := project.GetConfig()
if err != nil {
ErrorQuit(fmt.Sprintf("An error occurred while reading the config: %s\n", err))
}

// iterate over each registry, invalidate it
for _, reg := range cfg.Registries {
fmt.Printf("Invalidating cache: %s\n", reg.Url)
err = registry.InvalidateRegistryCache(&reg)
if err != nil {
ErrorQuit(fmt.Sprintf("An error occurred while invalidaing cache(s): %s\n", err))
}
}

// iterate over each registry, download the zip
for _, reg := range cfg.Registries {
fmt.Printf("Downloading archive: %s\n", reg.Url)
err = registry.CacheRegistry(&reg)
if err != nil {
ErrorQuit(fmt.Sprintf("An error occurred while downloading the registry archive: %s\n", err))
}
}
service.InvalidateRegistryCaches()
},
}
root.AddCommand(pull)
return root
}

// GetDependencyCommand gets the prepared "dependency" command for cobra
func GetDependencyCommand() *cobra.Command {
var root = &cobra.Command{
Use: "dependency",
Expand All @@ -307,34 +110,7 @@ func GetDependencyCommand() *cobra.Command {
Short: "Fetch dependencies from the appropriate registries, storing them within their caches for consumption at compile time.",
Aliases: []string{"s"},
Run: func(cmd *cobra.Command, args []string) {
// get the config
cfg, err := project.GetConfig()
if err != nil {
ErrorQuit(fmt.Sprintf("An error occurred while reading the config: %s\n", err))
}

// iterate over the dependencies
var wg sync.WaitGroup
for _, dep := range cfg.Dependencies {
wg.Add(1)
go func() {
defer wg.Done()
displayStr := fmt.Sprintf("%s:%s:%s", dep.Group, dep.Name, project.GetVersionAsString(&dep.Version))
color.Cyan("[%s] Resolving", displayStr)
rdep, err := dependency.ResolveDependency(&dep, &cfg.Registries)
if err != nil {
ErrorQuit(fmt.Sprintf("[%s] An error occurred while resolving dependencies: %s\n", displayStr, err))
}

// cache the resolved dependency
err = dependency.CacheResolvedDependency(rdep)
if err != nil {
ErrorQuit(fmt.Sprintf("[%s] An error occurred while caching the resolved dependency: %s\n", displayStr, err))
}
color.Green("[%s] Cached", displayStr)
}()
}
wg.Wait()
service.SyncDependencies()
},
}
root.AddCommand(sync)
Expand Down
12 changes: 0 additions & 12 deletions cli/util.go

This file was deleted.

Loading

0 comments on commit 5f3097b

Please sign in to comment.