func newRunLocalOpts()

in internal/pkg/cli/run_local.go [153:311]


func newRunLocalOpts(vars runLocalVars) (*runLocalOpts, error) {
	sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("run local"))
	defaultSess, err := sessProvider.Default()
	if err != nil {
		return nil, err
	}

	store := config.NewSSMStore(identity.New(defaultSess), sdkssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region))
	deployStore, err := deploy.NewStore(sessProvider, store)
	if err != nil {
		return nil, err
	}

	ws, err := workspace.Use(afero.NewOsFs())
	if err != nil {
		return nil, err
	}
	labeledTermPrinter := func(fw syncbuffer.FileWriter, bufs []*syncbuffer.LabeledSyncBuffer, opts ...syncbuffer.LabeledTermPrinterOption) clideploy.LabeledTermPrinter {
		return syncbuffer.NewLabeledTermPrinter(fw, bufs, opts...)
	}
	o := &runLocalOpts{
		runLocalVars:       vars,
		sel:                selector.NewDeploySelect(prompt.New(), store, deployStore),
		store:              store,
		ws:                 ws,
		newInterpolator:    newManifestInterpolator,
		sessProvider:       sessProvider,
		unmarshal:          manifest.UnmarshalWorkload,
		sess:               defaultSess,
		cmd:                exec.NewCmd(),
		dockerEngine:       dockerengine.New(exec.NewCmd()),
		labeledTermPrinter: labeledTermPrinter,
		prog:               termprogress.NewSpinner(log.DiagnosticWriter),
	}
	o.configureClients = func() error {
		defaultSessEnvRegion, err := o.sessProvider.DefaultWithRegion(o.targetEnv.Region)
		if err != nil {
			return fmt.Errorf("create default session with region %s: %w", o.targetEnv.Region, err)
		}
		o.envManagerSess, err = o.sessProvider.FromRole(o.targetEnv.ManagerRoleARN, o.targetEnv.Region)
		if err != nil {
			return fmt.Errorf("create env manager session %s: %w", o.targetEnv.Region, err)
		}

		// EnvManagerRole has permissions to get task def and get SSM values.
		// However, it doesn't have permissions to get secrets from secrets manager,
		// so use the default sess and *hope* they have permissions.
		o.ecsClient = ecs.New(o.envManagerSess)
		o.ssm = ssm.New(o.envManagerSess)
		o.ecsExecutor = awsecs.New(o.envManagerSess)
		o.secretsManager = secretsmanager.New(defaultSessEnvRegion)

		resources, err := cloudformation.New(o.sess, cloudformation.WithProgressTracker(os.Stderr)).GetAppResourcesByRegion(o.targetApp, o.targetEnv.Region)
		if err != nil {
			return fmt.Errorf("get application %s resources from region %s: %w", o.appName, o.envName, err)
		}
		repoName := clideploy.RepoName(o.appName, o.wkldName)
		o.repository = repository.NewWithURI(ecr.New(defaultSessEnvRegion), repoName, resources.RepositoryURLs[o.wkldName])

		idPrefix := fmt.Sprintf("%s-%s-%s-", o.appName, o.envName, o.wkldName)
		colorGen := termcolor.ColorGenerator()
		o.orchestrator = orchestrator.New(o.dockerEngine, idPrefix, func(name string, ctr orchestrator.ContainerDefinition) dockerengine.RunLogOptions {
			return dockerengine.RunLogOptions{
				Color:      colorGen(),
				Output:     os.Stderr,
				LinePrefix: fmt.Sprintf("[%s] ", name),
			}
		})

		o.hostFinder = &hostDiscoverer{
			app:  o.appName,
			env:  o.envName,
			wkld: o.wkldName,
			ecs:  ecs.New(o.envManagerSess),
			rg:   resourcegroups.New(o.envManagerSess),
			rds:  rds.New(o.envManagerSess),
		}
		envDesc, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{
			App:         o.appName,
			Env:         o.envName,
			ConfigStore: store,
		})
		if err != nil {
			return fmt.Errorf("create env describer: %w", err)
		}
		o.envChecker = envDesc
		return nil
	}
	o.buildContainerImages = func(mft manifest.DynamicWorkload) (map[string]string, error) {
		if dockerWkld, ok := mft.Manifest().(dockerWorkload); ok {
			dfDir := filepath.Dir(dockerWkld.Dockerfile())
			o.dockerExcludes, err = dockerfile.ReadDockerignore(afero.NewOsFs(), filepath.Join(ws.Path(), dfDir))
			if err != nil {
				return nil, err
			}
			o.filterDockerExcludes()
		}

		gitShortCommit := imageTagFromGit(o.cmd)
		image := clideploy.ContainerImageIdentifier{
			GitShortCommitTag: gitShortCommit,
		}
		out := &clideploy.UploadArtifactsOutput{}
		if err := clideploy.BuildContainerImages(&clideploy.ImageActionInput{
			Name:               o.wkldName,
			WorkspacePath:      o.ws.Path(),
			Image:              image,
			Mft:                mft.Manifest(),
			GitShortCommitTag:  gitShortCommit,
			Builder:            o.repository,
			Login:              o.repository.Login,
			CheckDockerEngine:  o.dockerEngine.CheckDockerEngineRunning,
			LabeledTermPrinter: o.labeledTermPrinter,
		}, out); err != nil {
			return nil, err
		}

		containerURIs := make(map[string]string, len(out.ImageDigests))
		for name, info := range out.ImageDigests {
			if len(info.RepoTags) == 0 {
				// this shouldn't happen, but just to avoid a panic in case
				return nil, fmt.Errorf("no repo tags for image %q", name)
			}
			containerURIs[name] = info.RepoTags[0]
		}
		return containerURIs, nil
	}
	o.debounceTime = 5 * time.Second
	o.newRecursiveWatcher = func() (recursiveWatcher, error) {
		return file.NewRecursiveWatcher(0)
	}

	// Capture stdout by replacing it with a piped writer and returning an attached io.Reader.
	// Functions are concurrency safe and idempotent.
	var mu sync.Mutex
	var savedWriter, savedStdout *os.File
	savedStdout = os.Stdout
	o.captureStdout = func() (io.Reader, error) {
		if savedWriter != nil {
			savedWriter.Close()
		}
		pipeReader, pipeWriter, err := os.Pipe()
		if err != nil {
			return nil, err
		}
		mu.Lock()
		defer mu.Unlock()
		savedWriter = pipeWriter
		os.Stdout = savedWriter
		return (io.Reader)(pipeReader), nil
	}
	o.releaseStdout = func() {
		mu.Lock()
		defer mu.Unlock()
		os.Stdout = savedStdout
		savedWriter.Close()
	}
	return o, nil
}