mirror of
https://github.com/docker/compose.git
synced 2025-07-23 13:45:00 +02:00
abstract model-cli commands execution with a model (pseudo) API
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
parent
1c37f1abb6
commit
17ba6c7188
@ -301,7 +301,7 @@ func (s *composeService) doBuildBake(ctx context.Context, project *types.Project
|
|||||||
}
|
}
|
||||||
cmd := exec.CommandContext(ctx, buildx.Path, args...)
|
cmd := exec.CommandContext(ctx, buildx.Path, args...)
|
||||||
|
|
||||||
err = s.prepareShellOut(ctx, project, cmd)
|
err = s.prepareShellOut(ctx, project.Environment, cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -39,73 +39,67 @@ func (s *composeService) ensureModels(ctx context.Context, project *types.Projec
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
dockerModel, err := manager.GetPlugin("model", s.dockerCli, &cobra.Command{})
|
api, err := s.newModelAPI(project)
|
||||||
if err != nil {
|
|
||||||
if errdefs.IsNotFound(err) {
|
|
||||||
return fmt.Errorf("'models' support requires Docker Model plugin")
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := exec.CommandContext(ctx, dockerModel.Path, "ls", "--json")
|
|
||||||
err = s.prepareShellOut(ctx, project, cmd)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
availableModels, err := api.ListModels(ctx)
|
||||||
|
|
||||||
output, err := cmd.CombinedOutput()
|
eg, ctx := errgroup.WithContext(ctx)
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error checking available models: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
type AvailableModel struct {
|
|
||||||
Id string `json:"id"`
|
|
||||||
Tags []string `json:"tags"`
|
|
||||||
Created int `json:"created"`
|
|
||||||
}
|
|
||||||
|
|
||||||
models := []AvailableModel{}
|
|
||||||
err = json.Unmarshal(output, &models)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error unmarshalling available models: %w", err)
|
|
||||||
}
|
|
||||||
var availableModels []string
|
|
||||||
for _, model := range models {
|
|
||||||
availableModels = append(availableModels, model.Tags...)
|
|
||||||
}
|
|
||||||
|
|
||||||
eg, gctx := errgroup.WithContext(ctx)
|
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
return s.setModelVariables(gctx, dockerModel, project)
|
return api.SetModelVariables(ctx, project)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
w := progress.ContextWriter(ctx)
|
||||||
for name, config := range project.Models {
|
for name, config := range project.Models {
|
||||||
if config.Name == "" {
|
if config.Name == "" {
|
||||||
config.Name = name
|
config.Name = name
|
||||||
}
|
}
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
w := progress.ContextWriter(gctx)
|
|
||||||
if !slices.Contains(availableModels, config.Model) {
|
if !slices.Contains(availableModels, config.Model) {
|
||||||
err = s.pullModel(gctx, dockerModel, project, config, quietPull, w)
|
err = api.PullModel(ctx, config, quietPull, w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s.configureModel(gctx, dockerModel, project, config, w)
|
return api.ConfigureModel(ctx, config, w)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return eg.Wait()
|
return eg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *composeService) pullModel(ctx context.Context, dockerModel *manager.Plugin, project *types.Project, model types.ModelConfig, quietPull bool, w progress.Writer) error {
|
type modelAPI struct {
|
||||||
|
path string
|
||||||
|
env []string
|
||||||
|
prepare func(ctx context.Context, cmd *exec.Cmd) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *composeService) newModelAPI(project *types.Project) (*modelAPI, error) {
|
||||||
|
dockerModel, err := manager.GetPlugin("model", s.dockerCli, &cobra.Command{})
|
||||||
|
if err != nil {
|
||||||
|
if errdefs.IsNotFound(err) {
|
||||||
|
return nil, fmt.Errorf("'models' support requires Docker Model plugin")
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &modelAPI{
|
||||||
|
path: dockerModel.Path,
|
||||||
|
prepare: func(ctx context.Context, cmd *exec.Cmd) error {
|
||||||
|
return s.prepareShellOut(ctx, project.Environment, cmd)
|
||||||
|
},
|
||||||
|
env: project.Environment.Values(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *modelAPI) PullModel(ctx context.Context, model types.ModelConfig, quietPull bool, w progress.Writer) error {
|
||||||
w.Event(progress.Event{
|
w.Event(progress.Event{
|
||||||
ID: model.Name,
|
ID: model.Name,
|
||||||
Status: progress.Working,
|
Status: progress.Working,
|
||||||
Text: "Pulling",
|
Text: "Pulling",
|
||||||
})
|
})
|
||||||
|
|
||||||
cmd := exec.CommandContext(ctx, dockerModel.Path, "pull", model.Model)
|
cmd := exec.CommandContext(ctx, m.path, "pull", model.Model)
|
||||||
err := s.prepareShellOut(ctx, project, cmd)
|
err := m.prepare(ctx, cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -148,7 +142,7 @@ func (s *composeService) pullModel(ctx context.Context, dockerModel *manager.Plu
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *composeService) configureModel(ctx context.Context, dockerModel *manager.Plugin, project *types.Project, config types.ModelConfig, w progress.Writer) error {
|
func (m *modelAPI) ConfigureModel(ctx context.Context, config types.ModelConfig, w progress.Writer) error {
|
||||||
w.Event(progress.Event{
|
w.Event(progress.Event{
|
||||||
ID: config.Name,
|
ID: config.Name,
|
||||||
Status: progress.Working,
|
Status: progress.Working,
|
||||||
@ -164,17 +158,17 @@ func (s *composeService) configureModel(ctx context.Context, dockerModel *manage
|
|||||||
args = append(args, "--")
|
args = append(args, "--")
|
||||||
args = append(args, config.RuntimeFlags...)
|
args = append(args, config.RuntimeFlags...)
|
||||||
}
|
}
|
||||||
cmd := exec.CommandContext(ctx, dockerModel.Path, args...)
|
cmd := exec.CommandContext(ctx, m.path, args...)
|
||||||
err := s.prepareShellOut(ctx, project, cmd)
|
err := m.prepare(ctx, cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return cmd.Run()
|
return cmd.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *composeService) setModelVariables(ctx context.Context, dockerModel *manager.Plugin, project *types.Project) error {
|
func (m *modelAPI) SetModelVariables(ctx context.Context, project *types.Project) error {
|
||||||
cmd := exec.CommandContext(ctx, dockerModel.Path, "status", "--json")
|
cmd := exec.CommandContext(ctx, m.path, "status", "--json")
|
||||||
err := s.prepareShellOut(ctx, project, cmd)
|
err := m.prepare(ctx, cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -228,3 +222,33 @@ type Model struct {
|
|||||||
Size string `json:"size"`
|
Size string `json:"size"`
|
||||||
} `json:"config"`
|
} `json:"config"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *modelAPI) ListModels(ctx context.Context) ([]string, error) {
|
||||||
|
cmd := exec.CommandContext(ctx, m.path, "ls", "--json")
|
||||||
|
err := m.prepare(ctx, cmd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error checking available models: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
type AvailableModel struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Tags []string `json:"tags"`
|
||||||
|
Created int `json:"created"`
|
||||||
|
}
|
||||||
|
|
||||||
|
models := []AvailableModel{}
|
||||||
|
err = json.Unmarshal(output, &models)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error unmarshalling available models: %w", err)
|
||||||
|
}
|
||||||
|
var availableModels []string
|
||||||
|
for _, model := range models {
|
||||||
|
availableModels = append(availableModels, model.Tags...)
|
||||||
|
}
|
||||||
|
return availableModels, nil
|
||||||
|
}
|
||||||
|
@ -197,7 +197,7 @@ func (s *composeService) setupPluginCommand(ctx context.Context, project *types.
|
|||||||
|
|
||||||
cmd := exec.CommandContext(ctx, path, args...)
|
cmd := exec.CommandContext(ctx, path, args...)
|
||||||
|
|
||||||
err := s.prepareShellOut(ctx, project, cmd)
|
err := s.prepareShellOut(ctx, project.Environment, cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -206,7 +206,7 @@ func (s *composeService) setupPluginCommand(ctx context.Context, project *types.
|
|||||||
|
|
||||||
func (s *composeService) getPluginMetadata(path, command string, project *types.Project) ProviderMetadata {
|
func (s *composeService) getPluginMetadata(path, command string, project *types.Project) ProviderMetadata {
|
||||||
cmd := exec.Command(path, "compose", "metadata")
|
cmd := exec.Command(path, "compose", "metadata")
|
||||||
err := s.prepareShellOut(context.Background(), project, cmd)
|
err := s.prepareShellOut(context.Background(), project.Environment, cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("failed to prepare plugin metadata command: %v", err)
|
logrus.Debugf("failed to prepare plugin metadata command: %v", err)
|
||||||
return ProviderMetadata{}
|
return ProviderMetadata{}
|
||||||
|
@ -29,10 +29,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// prepareShellOut prepare a shell-out command to be ran by Compose
|
// prepareShellOut prepare a shell-out command to be ran by Compose
|
||||||
func (s *composeService) prepareShellOut(gctx context.Context, project *types.Project, cmd *exec.Cmd) error {
|
func (s *composeService) prepareShellOut(gctx context.Context, env types.Mapping, cmd *exec.Cmd) error {
|
||||||
// exec command with same environment Compose is running
|
env = env.Clone()
|
||||||
env := types.NewMapping(project.Environment.Values())
|
|
||||||
|
|
||||||
// remove DOCKER_CLI_PLUGIN... variable so a docker-cli plugin will detect it run standalone
|
// remove DOCKER_CLI_PLUGIN... variable so a docker-cli plugin will detect it run standalone
|
||||||
delete(env, manager.ReexecEnvvar)
|
delete(env, manager.ReexecEnvvar)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user