From 8d8dc4baad5487be14dcc554aecdf4f22ee52fa9 Mon Sep 17 00:00:00 2001 From: Aravind Date: Wed, 11 Feb 2026 17:59:49 +0530 Subject: [PATCH] Add Feature(build):- auto-generate Modelfile and add --regenerate flag Signed-off-by: Aravind --- cmd/build.go | 58 ++++++++++++++++++++++++++++++++++++++++++--- pkg/config/build.go | 2 ++ 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/cmd/build.go b/cmd/build.go index 25271829..90d1fb1b 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -19,12 +19,17 @@ package cmd import ( "context" "fmt" + "os" + "path/filepath" "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/modelpack/modctl/pkg/backend" "github.com/modelpack/modctl/pkg/config" + + configmodelfile "github.com/modelpack/modctl/pkg/config/modelfile" + modelfilegen "github.com/modelpack/modctl/pkg/modelfile" ) var buildConfig = config.NewBuild() @@ -62,24 +67,71 @@ func init() { flags.BoolVar(&buildConfig.Raw, "raw", true, "turning on this flag will build model artifact layers in raw format") flags.BoolVar(&buildConfig.Reasoning, "reasoning", false, "turning on this flag will mark this model as reasoning model in the config") flags.BoolVar(&buildConfig.NoCreationTime, "no-creation-time", false, "turning on this flag will not set createdAt in the config, which will be helpful for repeated builds") + flags.BoolVar(&buildConfig.Regenerate, "regenerate", false, "force regenerate Modelfile before building") if err := viper.BindPFlags(flags); err != nil { panic(fmt.Errorf("bind cache list flags to viper: %w", err)) } + } -// runBuild runs the build modctl. func runBuild(ctx context.Context, workDir string) error { + + // Determine modelfile path + modelfilePath := buildConfig.Modelfile + if modelfilePath == "" { + modelfilePath = filepath.Join(workDir, configmodelfile.DefaultModelfileName) + } else if !filepath.IsAbs(modelfilePath) { + modelfilePath = filepath.Join(workDir, modelfilePath) + } + + shouldGenerate := buildConfig.Regenerate + + if shouldGenerate { + fmt.Println("Regenerate flag detected. Regenerating Modelfile...") + } else { + _, err := os.Stat(modelfilePath) + if os.IsNotExist(err) { + fmt.Println("No Modelfile found. Generating automatically...") + shouldGenerate = true + } else if err != nil { + return fmt.Errorf("error checking Modelfile at %s: %w", modelfilePath, err) + } + } + + if shouldGenerate { + genConfig := configmodelfile.NewGenerateConfig() + + absWorkDir, err := filepath.Abs(workDir) + if err != nil { + return fmt.Errorf("failed to resolve workspace path: %w", err) + } + + genConfig.Workspace = absWorkDir + genConfig.Overwrite = true + + mf, err := modelfilegen.NewModelfileByWorkspace(genConfig.Workspace, genConfig) + if err != nil { + return fmt.Errorf("failed to auto-generate modelfile: %w", err) + } + + content := mf.Content() + if err := os.WriteFile(modelfilePath, content, 0644); err != nil { + return fmt.Errorf("failed to write modelfile: %w", err) + } + + fmt.Printf("Successfully generated %s\n", modelfilePath) + } + b, err := backend.New(rootConfig.StoargeDir) if err != nil { return err } - if err := b.Build(ctx, buildConfig.Modelfile, workDir, buildConfig.Target, buildConfig); err != nil { + if err := b.Build(ctx, modelfilePath, workDir, buildConfig.Target, buildConfig); err != nil { return err } fmt.Printf("Successfully built model artifact: %s\n", buildConfig.Target) - return nil } diff --git a/pkg/config/build.go b/pkg/config/build.go index 27dd23d5..19e250bb 100644 --- a/pkg/config/build.go +++ b/pkg/config/build.go @@ -36,6 +36,7 @@ type Build struct { Raw bool Reasoning bool NoCreationTime bool + Regenerate bool } func NewBuild() *Build { @@ -52,6 +53,7 @@ func NewBuild() *Build { Raw: false, Reasoning: false, NoCreationTime: false, + Regenerate: false, } }