diff --git a/cmd/bundle.go b/cmd/bundle.go index f6c7da93..2e126840 100644 --- a/cmd/bundle.go +++ b/cmd/bundle.go @@ -46,6 +46,7 @@ Examples: if err := bundler.Bundle(bundler.BundleContext{ Context: ctx, Logger: projectContext.Logger, + Project: projectContext.Project, ProjectDir: projectContext.Dir, Production: production, Install: install, diff --git a/internal/bundler/bundler.go b/internal/bundler/bundler.go index cfb4a012..d814cfd5 100644 --- a/internal/bundler/bundler.go +++ b/internal/bundler/bundler.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "io" + "math" "os" "os/exec" "path/filepath" @@ -19,6 +20,7 @@ import ( "github.com/agentuity/go-common/sys" "github.com/agentuity/go-common/tui" "github.com/evanw/esbuild/pkg/api" + "k8s.io/apimachinery/pkg/api/resource" ) var Version = "dev" @@ -34,6 +36,7 @@ type AgentConfig struct { type BundleContext struct { Context context.Context Logger logger.Logger + Project *project.Project ProjectDir string Production bool Install bool @@ -42,6 +45,62 @@ type BundleContext struct { Writer io.Writer } +func dirSize(path string) (int64, error) { + var size int64 + err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if !info.IsDir() { + size += info.Size() + } + return nil + }) + return size, err +} + +func validateDiskRequest(ctx BundleContext, dir string) error { + if !ctx.DevMode { + if !util.Exists(dir) { + return fmt.Errorf("%s not found", dir) + } + size, err := dirSize(dir) + if err != nil { + return fmt.Errorf("error calculating size of %s: %w", dir, err) + } + diskSize := resource.NewQuantity(size, resource.DecimalSI) + val, ok := diskSize.AsInt64() + if ok { + millisValue := fmt.Sprintf("%.0fMi", math.Round(float64(val)/1000/1000)) + askSize, err := resource.ParseQuantity(ctx.Project.Deployment.Resources.Disk) + if err != nil { + return fmt.Errorf("error parsing disk requirement: %w", err) + } + askVal, ok := askSize.AsInt64() + if ok { + if askVal < val { + if tui.HasTTY { + fmt.Println(tui.Warning(fmt.Sprintf("Warning: The deployment is larger (%s) than the requested disk size for the deployment (%s).", millisValue, ctx.Project.Deployment.Resources.Disk))) + if tui.AskForConfirm("Would you like to adjust the disk requirement?", 'y') != 'y' { + fmt.Println() + return fmt.Errorf("Disk request is too small. %s required but %s requested", millisValue, ctx.Project.Deployment.Resources.Disk) + } + fmt.Println() + ctx.Project.Deployment.Resources.Disk = millisValue + if err := ctx.Project.Save(ctx.ProjectDir); err != nil { + return fmt.Errorf("error saving project: %w", err) + } + tui.ShowSuccess("Disk requirement adjusted to %s", millisValue) + } else { + return fmt.Errorf("The deployment is larger (%s) than the requested disk size for the deployment (%s)", millisValue, ctx.Project.Deployment.Resources.Disk) + } + } + } + } + } + return nil +} + func installSourceMapSupportIfNeeded(ctx BundleContext, dir string) error { // only bun needs to install this library to aide in parsing the source maps path := filepath.Join(dir, "node_modules", "source-map-js", "package.json") @@ -199,6 +258,11 @@ func bundleJavascript(ctx BundleContext, dir string, outdir string, theproject * os.Exit(2) return nil // This line will never be reached due to os.Exit } + + if err := validateDiskRequest(ctx, outdir); err != nil { + return err + } + return nil } @@ -248,6 +312,10 @@ func bundlePython(ctx BundleContext, dir string, outdir string, theproject *proj config["environment"] = "production" } + if err := validateDiskRequest(ctx, filepath.Join(dir, ".venv")); err != nil { + return err + } + pyproject := filepath.Join(dir, "pyproject.toml") if sys.Exists(pyproject) { pyprojectData, err := os.ReadFile(pyproject) diff --git a/internal/deployer/deployer.go b/internal/deployer/deployer.go index 7040d2cf..60c69909 100644 --- a/internal/deployer/deployer.go +++ b/internal/deployer/deployer.go @@ -68,17 +68,16 @@ type DeployPreflightCheckData struct { } func PreflightCheck(ctx context.Context, logger logger.Logger, data DeployPreflightCheckData) error { - if data.Project.Bundler.Enabled { - started := time.Now() - if err := bundler.Bundle(bundler.BundleContext{ - Context: context.Background(), - Logger: logger, - ProjectDir: data.Dir, - Production: true, - }); err != nil { - return err - } - logger.Debug("bundled in %s", time.Since(started)) + started := time.Now() + if err := bundler.Bundle(bundler.BundleContext{ + Context: context.Background(), + Logger: logger, + ProjectDir: data.Dir, + Production: true, + Project: data.Project, + }); err != nil { + return err } + logger.Debug("bundled in %s", time.Since(started)) return nil }