Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e444b27
refactor args and implement a func for build label
KollaAdithya Apr 9, 2023
bdfef7a
fetch build label in workload and task run
KollaAdithya Apr 10, 2023
d3f05d8
create a method GenerateDockerBuildArgs on BuildArguments
KollaAdithya Apr 11, 2023
331caa0
remove interface to appease static check
KollaAdithya Apr 11, 2023
b95253b
concurrent build with context cancellation
KollaAdithya Apr 13, 2023
82333d4
remove \n from label
KollaAdithya Apr 13, 2023
6f58be0
remove unused mock
KollaAdithya Apr 13, 2023
11ef4d8
remove some unused termprinter
KollaAdithya Apr 13, 2023
e6e6f61
addr Parag fb: addd name of image in error stmt
KollaAdithya Apr 13, 2023
13665e2
fix test
KollaAdithya Apr 13, 2023
4478437
remove mocks
KollaAdithya Apr 14, 2023
c199567
remove unused mocks
KollaAdithya Apr 14, 2023
526a906
add mocks for labeled termprinter print
KollaAdithya Apr 17, 2023
272650c
changes after rebase
KollaAdithya Apr 17, 2023
9a52d48
addr Efe fb
KollaAdithya Apr 17, 2023
9adf16b
change logic of if block
KollaAdithya Apr 17, 2023
2cf1bda
addrWx fb: change error stmt and declare numLines as const
KollaAdithya Apr 18, 2023
397b04b
fix tests
KollaAdithya Apr 18, 2023
97393fc
fix one more test
KollaAdithya Apr 18, 2023
068d43f
addr fb: add multiples to printall to check for buffers printing only…
KollaAdithya Apr 18, 2023
4cd0f33
add printAll
KollaAdithya Apr 18, 2023
f0c9853
add comment
KollaAdithya Apr 18, 2023
28bb762
addr @dannyrandall fb
KollaAdithya Apr 18, 2023
bfd918c
use defer
KollaAdithya Apr 18, 2023
0830e39
Merge branch 'mainline' into concurrent/build/rebase/dockerbuildlabel
mergify[bot] Apr 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 72 additions & 4 deletions internal/pkg/cli/deploy/mocks/mock_workload.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

111 changes: 87 additions & 24 deletions internal/pkg/cli/deploy/workload.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ package deploy

import (
"bytes"
"context"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"sync"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
Expand All @@ -35,11 +38,14 @@ import (
"github.com/aws/copilot-cli/internal/pkg/template/artifactpath"
"github.com/aws/copilot-cli/internal/pkg/template/diff"
"github.com/aws/copilot-cli/internal/pkg/term/color"
"github.com/aws/copilot-cli/internal/pkg/term/cursor"
"github.com/aws/copilot-cli/internal/pkg/term/log"
termprogress "github.com/aws/copilot-cli/internal/pkg/term/progress"
"github.com/aws/copilot-cli/internal/pkg/term/syncbuffer"
"github.com/aws/copilot-cli/internal/pkg/version"
"github.com/aws/copilot-cli/internal/pkg/workspace"
"github.com/spf13/afero"
"golang.org/x/sync/errgroup"
)

const (
Expand All @@ -56,6 +62,11 @@ const (
labelForVersion = "com.aws.copilot.image.version"
labelForContainerName = "com.aws.copilot.image.container.name"
)
const (
paddingInSpacesForBuildAndPush = 5
pollIntervalForBuildAndPush = 60 * time.Millisecond
defaultNumLinesForBuildAndPush = 5
)

// ActionRecommender contains methods that output action recommendation.
type ActionRecommender interface {
Expand All @@ -70,7 +81,7 @@ func (noopActionRecommender) RecommendedActions() []string {

type repositoryService interface {
Login() (string, error)
BuildAndPush(args *dockerengine.BuildArguments) (string, error)
BuildAndPush(ctx context.Context, args *dockerengine.BuildArguments, w io.Writer) (string, error)
}

type templater interface {
Expand Down Expand Up @@ -105,6 +116,11 @@ type spinner interface {
Stop(label string)
}

type labeledTermPrinter interface {
IsDone() bool
Print() error
}

// StackRuntimeConfiguration contains runtime configuration for a workload CloudFormation stack.
type StackRuntimeConfiguration struct {
ImageDigests map[string]ContainerImageIdentifier // Container name to image.
Expand Down Expand Up @@ -150,18 +166,19 @@ type workloadDeployer struct {
workspacePath string

// Dependencies.
fs afero.Fs
s3Client uploader
addons stackBuilder
repository repositoryService
deployer serviceDeployer
tmplGetter deployedTemplateGetter
endpointGetter endpointGetter
spinner spinner
templateFS template.Reader
envVersionGetter versionGetter
overrider Overrider
customResources customResourcesFunc
fs afero.Fs
s3Client uploader
addons stackBuilder
repository repositoryService
deployer serviceDeployer
tmplGetter deployedTemplateGetter
endpointGetter endpointGetter
spinner spinner
templateFS template.Reader
envVersionGetter versionGetter
overrider Overrider
customResources customResourcesFunc
labeledTermPrinter func(fw syncbuffer.FileWriter, bufs []*syncbuffer.LabeledSyncBuffer, opts ...syncbuffer.LabeledTermPrinterOption) labeledTermPrinter

// Cached variables.
defaultSess *session.Session
Expand Down Expand Up @@ -251,6 +268,9 @@ func newWorkloadDeployer(in *WorkloadDeployerInput) (*workloadDeployer, error) {

cfn := cloudformation.New(envSession, cloudformation.WithProgressTracker(os.Stderr))

labeledTermPrinter := func(fw syncbuffer.FileWriter, bufs []*syncbuffer.LabeledSyncBuffer, opts ...syncbuffer.LabeledTermPrinterOption) labeledTermPrinter {
return syncbuffer.NewLabeledTermPrinter(fw, bufs, opts...)
}
return &workloadDeployer{
name: in.Name,
app: in.App,
Expand All @@ -275,6 +295,7 @@ func newWorkloadDeployer(in *WorkloadDeployerInput) (*workloadDeployer, error) {
envSess: envSession,
store: store,
envConfig: envConfig,
labeledTermPrinter: labeledTermPrinter,
Comment thread
dannyrandall marked this conversation as resolved.

mft: in.Mft,
rawMft: in.RawMft,
Expand Down Expand Up @@ -367,24 +388,66 @@ func (d *workloadDeployer) uploadContainerImages(out *UploadArtifactsOutput) err
if err != nil {
return fmt.Errorf("login to image repository: %w", err)
}

var digestsMu sync.Mutex
out.ImageDigests = make(map[string]ContainerImageIdentifier, len(buildArgsPerContainer))
var labeledBuffers []*syncbuffer.LabeledSyncBuffer
g, ctx := errgroup.WithContext(context.Background())
cursor := cursor.New()
cursor.Hide()
for name, buildArgs := range buildArgsPerContainer {
// create a copy of loop variables to avoid data race.
Comment thread
KollaAdithya marked this conversation as resolved.
name := name
buildArgs := buildArgs

buildArgs.URI = uri
buildArgsList, err := buildArgs.GenerateDockerBuildArgs(dockerengine.New(exec.NewCmd()))
if err != nil {
return fmt.Errorf("generate docker build args: %w", err)
}
// TODO(adi) handle this log in syncBuffer's Print function
log.Infof("Building your container image: docker %s\n", strings.Join(buildArgsList, " "))
digest, err := d.repository.BuildAndPush(buildArgs)
if err != nil {
return fmt.Errorf("build and push image: %w", err)
return fmt.Errorf("generate docker build args for %q: %w", name, err)
}
out.ImageDigests[name] = ContainerImageIdentifier{
Digest: digest,
CustomTag: d.image.CustomTag,
GitShortCommitTag: d.image.GitShortCommitTag,
buf := syncbuffer.New()
labeledBuffers = append(labeledBuffers, buf.WithLabel(fmt.Sprintf("Building your container image %q: docker %s", name, strings.Join(buildArgsList, " "))))
pr, pw := io.Pipe()
g.Go(func() error {
defer pw.Close()
digest, err := d.repository.BuildAndPush(ctx, buildArgs, pw)
if err != nil {
return fmt.Errorf("build and push the image %q: %w", name, err)
}
digestsMu.Lock()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
digestsMu.Lock()
digestsMu.Lock()
defer digestsMu.Unlock()

Copy link
Copy Markdown
Contributor Author

@KollaAdithya KollaAdithya Apr 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it good to unlock the map before return nil? I mean if I use defer then i will unlock after return is executed.

defer digestsMu.Unlock()
out.ImageDigests[name] = ContainerImageIdentifier{
Digest: digest,
CustomTag: d.image.CustomTag,
GitShortCommitTag: d.image.GitShortCommitTag,
}
return nil
})
g.Go(func() error {
if err := buf.Copy(pr); err != nil {
Comment thread
efekarakus marked this conversation as resolved.
return fmt.Errorf("copy build and push output for %q: %w", name, err)
}
return nil
})
}
opts := []syncbuffer.LabeledTermPrinterOption{syncbuffer.WithPadding(paddingInSpacesForBuildAndPush)}
if os.Getenv("CI") != "true" {
opts = append(opts, syncbuffer.WithNumLines(defaultNumLinesForBuildAndPush))
}
ltp := d.labeledTermPrinter(os.Stderr, labeledBuffers, opts...)
g.Go(func() error {
for {
if err := ltp.Print(); err != nil {
return fmt.Errorf("print logs: %w", err)
}
if ltp.IsDone() {
return nil
}
time.Sleep(pollIntervalForBuildAndPush)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
time.Sleep(pollIntervalForBuildAndPush)
select {
case <-ctx.Done():
return nil
case <-time.After(pollIntervalForBuildAndPush):
// loop again
}

so this function stops if ctx is cancelled!

}
})
if err := g.Wait(); err != nil {
return err
}
return nil
}
Expand Down
Loading