Build config, flags, etc

This commit is contained in:
Layla 2023-11-07 03:45:11 -05:00
parent 649d0d87f9
commit b9017499cc
9 changed files with 242 additions and 77 deletions

1
go.mod
View File

@ -3,6 +3,7 @@ module github.com/yeslayla/godot-build-tools
go 1.20
require (
github.com/BurntSushi/toml v1.3.2
github.com/sethvargo/go-envconfig v0.9.0 // indirect
github.com/sethvargo/go-githubactions v1.1.0 // indirect
)

2
go.sum
View File

@ -1,3 +1,5 @@
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/sethvargo/go-envconfig v0.9.0 h1:Q6FQ6hVEeTECULvkJZakq3dZMeBQ3JUpcKMfPQbKMDE=
github.com/sethvargo/go-envconfig v0.9.0/go.mod h1:Iz1Gy1Sf3T64TQlJSvee81qDhf7YIlt8GMUX6yyNFs0=
github.com/sethvargo/go-githubactions v1.1.0 h1:mg03w+b+/s5SMS298/2G6tHv8P0w0VhUFaqL1THIqzY=

54
internal/build_config.go Normal file
View File

@ -0,0 +1,54 @@
package internal
import (
"io/ioutil"
"os"
"github.com/BurntSushi/toml"
"github.com/yeslayla/godot-build-tools/logging"
)
const defaultGodotVersion = "4.1.3"
const defaultGodotRelease = "stable"
type BuildConfig struct {
Godot BuildConfigGodot `toml:"godot"`
}
type BuildConfigGodot struct {
Version string `toml:"version"`
Release string `toml:"release"`
}
func LoadBuildConfig(logger logging.Logger) BuildConfig {
config := BuildConfig{}
content, err := ioutil.ReadFile(".godot-build.toml")
if err != nil {
if os.IsNotExist(err) {
logger.Errorf("Build config not found, please run `gbt init`")
os.Exit(1)
} else {
logger.Errorf("Failed to read build config: %s", err)
}
return config
}
_, err = toml.Decode(string(content), &config)
if err != nil {
logger.Errorf("Failed to parse build config: %s", err)
return config
}
if config.Godot.Release == "" {
logger.Warnf("Godot release not specified, defaulting to %s", defaultGodotRelease)
config.Godot.Release = defaultGodotRelease
}
if config.Godot.Version == "" {
logger.Warnf("Godot version not specified, defaulting to %s", defaultGodotVersion)
config.Godot.Version = defaultGodotVersion
}
return config
}

View File

@ -26,6 +26,20 @@ type Downloader struct {
logger logging.Logger
}
// DefaultBinDir returns the default bin directory to install Godot to for the given target OS.
func DefaultBinDir(targetOS TargetOS) string {
switch targetOS {
case TargetOSLinux:
home, _ := os.UserHomeDir()
return filepath.Join(home, "/.local/bin")
case TargetOSWindows:
return "C:\\Program Files (x86)\\Godot"
case TargetOSMacOS:
return "/Applications/Godot"
}
return ""
}
func NewDownloader(targetOS TargetOS, logger logging.Logger, options *DownloaderOptions) *Downloader {
var url string = options.DownloadRepositoryURL
if url == "" {
@ -33,15 +47,7 @@ func NewDownloader(targetOS TargetOS, logger logging.Logger, options *Downloader
}
var binDir string = options.BinDir
if binDir == "" {
switch targetOS {
case TargetOSLinux:
home, _ := os.UserHomeDir()
binDir = filepath.Join(home, "/.local/bin")
case TargetOSWindows:
binDir = "C:\\Program Files (x86)\\Godot"
case TargetOSMacOS:
binDir = "/Applications/Godot"
}
DefaultBinDir(targetOS)
}
return &Downloader{
@ -51,26 +57,29 @@ func NewDownloader(targetOS TargetOS, logger logging.Logger, options *Downloader
}
}
func getRemoteFileFormat(targetOS TargetOS, version string) string {
// getRemoteFileName returns the name of the Godot package file for the given target OS, version and release.
func getRemoteFileName(targetOS TargetOS, version string, release string) string {
switch targetOS {
case TargetOSLinux:
if version[0] == '3' {
return "Godot_v%s-%s_x11.64.zip"
return fmt.Sprintf("Godot_v%s-%s_x11.64.zip", version, release)
}
return "Godot_v%s-%s_linux.x86_64.zip"
return fmt.Sprintf("Godot_v%s-%s_linux.x86_64.zip", version, release)
case TargetOSWindows:
return "Godot_v%s-%s_win64.exe.zip"
return fmt.Sprintf("Godot_v%s-%s_win64.exe.zip", version, release)
case TargetOSMacOS:
return "Godot_v%s-%s_macos.universal.zip"
return fmt.Sprintf("Godot_v%s-%s_macos.universal.zip", version, release)
}
return ""
}
// DownloadGodot downloads the Godot package for the given target OS, version, and release.
func (d *Downloader) DownloadGodot(targetOS TargetOS, version string, release string) (string, error) {
var fileName string = fmt.Sprintf(getRemoteFileFormat(targetOS, version), version, release)
var fileName string = getRemoteFileName(targetOS, version, release)
// Create output file
tempDir, _ := os.MkdirTemp("", "godot-build-tools")
outFile := filepath.Join(tempDir, fileName)
out, err := os.Create(outFile)
@ -79,6 +88,7 @@ func (d *Downloader) DownloadGodot(targetOS TargetOS, version string, release st
}
defer out.Close()
// Calculate download URL
downloadURL, err := url.Parse(d.downloadRepositoryURL)
if err != nil {
return "", fmt.Errorf("failed to parse download repository URL: %s", err)
@ -92,12 +102,14 @@ func (d *Downloader) DownloadGodot(targetOS TargetOS, version string, release st
downloadURL.Path = path.Join(downloadURL.Path, fileName)
d.logger.Debugf("Download URL: %s", downloadURL.String())
// Download Godot package
resp, err := http.Get(downloadURL.String())
if err != nil {
return "", fmt.Errorf("failed to download Godot: %s", err)
}
defer resp.Body.Close()
// Write Godot package to output file
_, err = io.Copy(out, resp.Body)
if err != nil {
return "", fmt.Errorf("failed to write Godot package to output file: %s", err)
@ -106,6 +118,26 @@ func (d *Downloader) DownloadGodot(targetOS TargetOS, version string, release st
return outFile, nil
}
// isTargetOSBin returns true if the given file name is a binary for the given target OS.
func isTargetOSBin(targetOS TargetOS, fileName string) bool {
switch targetOS {
case TargetOSLinux:
if path.Ext(fileName) == ".x86_64" || path.Ext(fileName) == ".64" {
return true
}
case TargetOSWindows:
if path.Ext(fileName) == ".exe" {
return true
}
case TargetOSMacOS:
if path.Ext(fileName) == ".universal" {
return true
}
}
return false
}
func (d *Downloader) UnzipGodot(targetOS TargetOS, godotPackage string) (string, error) {
files, err := utils.Unzip(godotPackage)
if err != nil {
@ -114,19 +146,8 @@ func (d *Downloader) UnzipGodot(targetOS TargetOS, godotPackage string) (string,
// Look for godot binary
for _, file := range files {
switch targetOS {
case TargetOSLinux:
if path.Ext(file) == ".x86_64" || path.Ext(file) == ".64" {
return file, nil
}
case TargetOSWindows:
if path.Ext(file) == ".exe" {
return file, nil
}
case TargetOSMacOS:
if path.Ext(file) == ".universal" {
return file, nil
}
if isTargetOSBin(targetOS, file) {
return file, nil
}
}

44
internal/flags.go Normal file
View File

@ -0,0 +1,44 @@
package internal
import (
"flag"
"strings"
"github.com/yeslayla/godot-build-tools/logging"
)
type BuildFlags struct {
stepsRaw string
DebugLog bool
}
// Steps returns the steps to run as a slice of strings
func (f *BuildFlags) Steps() []string {
return strings.Split(f.stepsRaw, ",")
}
// HasStep returns true if the given step is in the list of steps to run
func (f *BuildFlags) HasStep(step string) bool {
steps := f.Steps()
for _, s := range steps {
if s == step {
return true
}
}
return false
}
// Parse parses the flags
func (f *BuildFlags) Parse() {
flag.Parse()
}
// NewBuildFlags creates a new BuildFlags instance
func NewBuildFlags(logger logging.Logger) *BuildFlags {
flags := &BuildFlags{}
flag.StringVar(&flags.stepsRaw, "steps", "godot-setup", "Comma-separated list of build steps to run")
flag.BoolVar(&flags.DebugLog, "verbose", false, "Enable debug logging")
return flags
}

View File

@ -2,45 +2,45 @@ package internal
import "strings"
type Godot4ArgBuilder struct {
type DefaultGodotArgBuilder struct {
args []string
}
func NewGodot4ArgBuilder(projectDir string) GodotArgBuilder {
return &Godot4ArgBuilder{
func NewGodotArgBuilder(projectDir string) GodotArgBuilder {
return &DefaultGodotArgBuilder{
args: []string{"--path", projectDir},
}
}
func (b *Godot4ArgBuilder) AddHeadlessFlag() {
func (b *DefaultGodotArgBuilder) AddHeadlessFlag() {
b.args = append(b.args, "--headless")
}
func (b *Godot4ArgBuilder) AddDebugFlag() {
func (b *DefaultGodotArgBuilder) AddDebugFlag() {
b.args = append(b.args, "--debug")
}
func (b *Godot4ArgBuilder) AddVerboseFlag() {
func (b *DefaultGodotArgBuilder) AddVerboseFlag() {
b.args = append(b.args, "--verbose")
}
func (b *Godot4ArgBuilder) AddQuietFlag() {
func (b *DefaultGodotArgBuilder) AddQuietFlag() {
b.args = append(b.args, "--quiet")
}
func (b *Godot4ArgBuilder) AddDumpGDExtensionInterfaceFlag() {
func (b *DefaultGodotArgBuilder) AddDumpGDExtensionInterfaceFlag() {
b.args = append(b.args, "--dump-gdextension-interface")
}
func (b *Godot4ArgBuilder) AddDumpExtensionApiFlag() {
func (b *DefaultGodotArgBuilder) AddDumpExtensionApiFlag() {
b.args = append(b.args, "--dump-extension-api")
}
func (b *Godot4ArgBuilder) AddCheckOnlyFlag() {
func (b *DefaultGodotArgBuilder) AddCheckOnlyFlag() {
b.args = append(b.args, "--check-only")
}
func (b *Godot4ArgBuilder) AddExportFlag(exportType ExportType) {
func (b *DefaultGodotArgBuilder) AddExportFlag(exportType ExportType) {
switch exportType {
case ExportTypeRelease:
b.args = append(b.args, "--export")
@ -51,6 +51,6 @@ func (b *Godot4ArgBuilder) AddExportFlag(exportType ExportType) {
}
}
func (b *Godot4ArgBuilder) GenerateArgs() string {
func (b *DefaultGodotArgBuilder) GenerateArgs() string {
return strings.Join(b.args, " ")
}

View File

@ -1,5 +1,7 @@
package internal
import "runtime"
type TargetOS uint8
const (
@ -7,3 +9,31 @@ const (
TargetOSWindows
TargetOSMacOS
)
func (t TargetOS) String() string {
switch t {
case TargetOSLinux:
return "linux"
case TargetOSWindows:
return "windows"
case TargetOSMacOS:
return "macos"
}
return ""
}
func NewTargetOSFromRuntime(GOOSRuntime string) TargetOS {
switch GOOSRuntime {
case "linux":
return TargetOSLinux
case "windows":
return TargetOSWindows
case "darwin":
return TargetOSMacOS
}
return TargetOSLinux
}
func CurrentTargetOS() TargetOS {
return NewTargetOSFromRuntime(runtime.GOOS)
}

54
main.go
View File

@ -1,51 +1,31 @@
package main
import (
"os"
"runtime"
"github.com/yeslayla/godot-build-tools/internal"
"github.com/yeslayla/godot-build-tools/logging"
"github.com/yeslayla/godot-build-tools/steps"
)
func main() {
logger := logging.NewLogger(&logging.LoggerOptions{})
var targetOS internal.TargetOS
switch runtime.GOOS {
case "linux":
targetOS = internal.TargetOSLinux
case "windows":
targetOS = internal.TargetOSWindows
case "darwin":
targetOS = internal.TargetOSMacOS
flags := internal.NewBuildFlags(logger)
flags.Parse()
if flags.DebugLog {
logger = logging.NewLogger(&logging.LoggerOptions{
Debug: true,
})
}
GodotSetup(logger, targetOS, "3.3.2", "stable")
buildConfig := internal.LoadBuildConfig(logger)
var targetOS internal.TargetOS = internal.CurrentTargetOS()
if flags.HasStep("godot-setup") {
steps.GodotSetup(logger, targetOS, buildConfig.Godot.Version, buildConfig.Godot.Release)
} else {
logger.Debugf("Skipping godot-setup step")
}
}
func GodotSetup(logger logging.Logger, targetOS internal.TargetOS, version string, release string) (string, bool) {
logger.StartGroup("Godot Setup")
defer logger.EndGroup()
downloader := internal.NewDownloader(internal.TargetOSLinux, logger, &internal.DownloaderOptions{})
logger.Infof("Downloading Godot")
godotPackage, err := downloader.DownloadGodot(internal.TargetOSLinux, version, release)
if err != nil {
logger.Errorf("Failed to download Godot: %s", err)
return "", false
}
defer os.Remove(godotPackage)
logger.Infof("Godot package: %s", godotPackage)
logger.Infof("Installing Godot")
godotBin, err := downloader.InstallGodot(godotPackage, internal.TargetOSLinux, version, release)
if err != nil {
logger.Errorf("Failed to install Godot: %s", err)
return "", false
}
logger.Infof("Godot binary: %s", godotBin)
return godotBin, true
}

33
steps/godot_setup.go Normal file
View File

@ -0,0 +1,33 @@
package steps
import (
"os"
"github.com/yeslayla/godot-build-tools/internal"
"github.com/yeslayla/godot-build-tools/logging"
)
func GodotSetup(logger logging.Logger, targetOS internal.TargetOS, version string, release string) (string, bool) {
logger.StartGroup("Godot Setup")
defer logger.EndGroup()
downloader := internal.NewDownloader(internal.TargetOSLinux, logger, &internal.DownloaderOptions{})
logger.Infof("Downloading Godot")
godotPackage, err := downloader.DownloadGodot(internal.TargetOSLinux, version, release)
if err != nil {
logger.Errorf("Failed to download Godot: %s", err)
return "", false
}
defer os.Remove(godotPackage)
logger.Infof("Godot package: %s", godotPackage)
logger.Infof("Installing Godot")
godotBin, err := downloader.InstallGodot(godotPackage, internal.TargetOSLinux, version, release)
if err != nil {
logger.Errorf("Failed to install Godot: %s", err)
return "", false
}
logger.Infof("Godot binary: %s", godotBin)
return godotBin, true
}