mirror of
				https://github.com/docker/compose.git
				synced 2025-10-31 11:14:02 +01:00 
			
		
		
		
	Use docker/api progress writer
Signed-off-by: aiordache <anca.iordache@docker.com> Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
		
							parent
							
								
									83d65c02a0
								
							
						
					
					
						commit
						de99add26b
					
				| @ -12,6 +12,7 @@ import ( | |||||||
| 	amazon "github.com/docker/ecs-plugin/pkg/amazon/backend" | 	amazon "github.com/docker/ecs-plugin/pkg/amazon/backend" | ||||||
| 	"github.com/docker/ecs-plugin/pkg/amazon/cloudformation" | 	"github.com/docker/ecs-plugin/pkg/amazon/cloudformation" | ||||||
| 	"github.com/docker/ecs-plugin/pkg/docker" | 	"github.com/docker/ecs-plugin/pkg/docker" | ||||||
|  | 	"github.com/docker/ecs-plugin/pkg/progress" | ||||||
| 	"github.com/spf13/cobra" | 	"github.com/spf13/cobra" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -79,7 +80,11 @@ func UpCommand(dockerCli command.Cli, options *composeOptions) *cobra.Command { | |||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
| 			return backend.Up(context.Background(), opts) | 
 | ||||||
|  | 			return progress.Run(context.Background(), func(ctx context.Context) error { | ||||||
|  | 				backend.SetWriter(ctx) | ||||||
|  | 				return backend.Up(ctx, opts) | ||||||
|  | 			}) | ||||||
| 		}), | 		}), | ||||||
| 	} | 	} | ||||||
| 	cmd.Flags().StringVar(&opts.loadBalancerArn, "load-balancer", "", "") | 	cmd.Flags().StringVar(&opts.loadBalancerArn, "load-balancer", "", "") | ||||||
| @ -124,7 +129,10 @@ func DownCommand(dockerCli command.Cli, options *composeOptions) *cobra.Command | |||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
| 			return backend.Down(context.Background(), opts) | 			return progress.Run(context.Background(), func(ctx context.Context) error { | ||||||
|  | 				backend.SetWriter(ctx) | ||||||
|  | 				return backend.Down(ctx, opts) | ||||||
|  | 			}) | ||||||
| 		}), | 		}), | ||||||
| 	} | 	} | ||||||
| 	cmd.Flags().BoolVar(&opts.DeleteCluster, "delete-cluster", false, "Delete cluster") | 	cmd.Flags().BoolVar(&opts.DeleteCluster, "delete-cluster", false, "Delete cluster") | ||||||
| @ -139,7 +147,7 @@ func LogsCommand(dockerCli command.Cli, options *composeOptions) *cobra.Command | |||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
| 			return backend.Logs(context.Background(), opts) | 			return backend.Logs(context.Background(), opts, os.Stdout) | ||||||
| 		}), | 		}), | ||||||
| 	} | 	} | ||||||
| 	return cmd | 	return cmd | ||||||
|  | |||||||
| @ -1,7 +1,6 @@ | |||||||
| module github.com/docker/ecs-plugin | module github.com/docker/ecs-plugin | ||||||
| 
 | 
 | ||||||
| require ( | require ( | ||||||
| 	github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect |  | ||||||
| 	github.com/Microsoft/hcsshim v0.8.7 // indirect | 	github.com/Microsoft/hcsshim v0.8.7 // indirect | ||||||
| 	github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d // indirect | 	github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d // indirect | ||||||
| 	github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect | 	github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect | ||||||
| @ -10,11 +9,13 @@ require ( | |||||||
| 	github.com/bitly/go-hostpool v0.1.0 // indirect | 	github.com/bitly/go-hostpool v0.1.0 // indirect | ||||||
| 	github.com/bitly/go-simplejson v0.5.0 // indirect | 	github.com/bitly/go-simplejson v0.5.0 // indirect | ||||||
| 	github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect | 	github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect | ||||||
|  | 	github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129 | ||||||
| 	github.com/bugsnag/bugsnag-go v1.5.3 // indirect | 	github.com/bugsnag/bugsnag-go v1.5.3 // indirect | ||||||
| 	github.com/bugsnag/panicwrap v1.2.0 // indirect | 	github.com/bugsnag/panicwrap v1.2.0 // indirect | ||||||
| 	github.com/cenkalti/backoff v2.2.1+incompatible // indirect | 	github.com/cenkalti/backoff v2.2.1+incompatible // indirect | ||||||
| 	github.com/cloudflare/cfssl v1.4.1 // indirect | 	github.com/cloudflare/cfssl v1.4.1 // indirect | ||||||
| 	github.com/compose-spec/compose-go v0.0.0-20200811091145-837f8f4de457 | 	github.com/compose-spec/compose-go v0.0.0-20200811091145-837f8f4de457 | ||||||
|  | 	github.com/containerd/console v1.0.0 | ||||||
| 	github.com/containerd/containerd v1.3.2 // indirect | 	github.com/containerd/containerd v1.3.2 // indirect | ||||||
| 	github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb // indirect | 	github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb // indirect | ||||||
| 	github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492 | 	github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492 | ||||||
| @ -36,16 +37,17 @@ require ( | |||||||
| 	github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect | 	github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect | ||||||
| 	github.com/miekg/pkcs11 v1.0.3 // indirect | 	github.com/miekg/pkcs11 v1.0.3 // indirect | ||||||
| 	github.com/mitchellh/mapstructure v1.3.3 | 	github.com/mitchellh/mapstructure v1.3.3 | ||||||
| 	github.com/morikuni/aec v1.0.0 // indirect | 	github.com/moby/term v0.0.0-20200611042045-63b9a826fb74 | ||||||
|  | 	github.com/morikuni/aec v1.0.0 | ||||||
| 	github.com/onsi/ginkgo v1.11.0 // indirect | 	github.com/onsi/ginkgo v1.11.0 // indirect | ||||||
| 	github.com/opencontainers/image-spec v1.0.1 // indirect | 	github.com/opencontainers/image-spec v1.0.1 // indirect | ||||||
| 	github.com/pkg/errors v0.9.1 |  | ||||||
| 	github.com/sirupsen/logrus v1.6.0 | 	github.com/sirupsen/logrus v1.6.0 | ||||||
| 	github.com/smartystreets/goconvey v1.6.4 // indirect | 	github.com/smartystreets/goconvey v1.6.4 // indirect | ||||||
| 	github.com/spf13/cobra v0.0.5 | 	github.com/spf13/cobra v0.0.5 | ||||||
| 	github.com/spf13/pflag v1.0.5 | 	github.com/spf13/pflag v1.0.5 | ||||||
| 	github.com/theupdateframework/notary v0.6.1 // indirect | 	github.com/theupdateframework/notary v0.6.1 // indirect | ||||||
| 	github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1 // indirect | 	github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1 // indirect | ||||||
|  | 	golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 | ||||||
| 	golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect | 	golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect | ||||||
| 	google.golang.org/grpc v1.27.0 // indirect | 	google.golang.org/grpc v1.27.0 // indirect | ||||||
| 	gopkg.in/dancannon/gorethink.v3 v3.0.5 // indirect | 	gopkg.in/dancannon/gorethink.v3 v3.0.5 // indirect | ||||||
|  | |||||||
							
								
								
									
										24
									
								
								ecs/go.sum
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								ecs/go.sum
									
									
									
									
									
								
							| @ -34,6 +34,8 @@ github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngE | |||||||
| github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= | github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= | ||||||
| github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= | github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= | ||||||
| github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= | github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= | ||||||
|  | github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129 h1:gfAMKE626QEuKG3si0pdTRcr/YEbBoxY+3GOH3gWvl4= | ||||||
|  | github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129/go.mod h1:u9UyCz2eTrSGy6fbupqJ54eY5c4IC8gREQ1053dK12U= | ||||||
| github.com/bugsnag/bugsnag-go v1.5.3 h1:yeRUT3mUE13jL1tGwvoQsKdVbAsQx9AJ+fqahKveP04= | github.com/bugsnag/bugsnag-go v1.5.3 h1:yeRUT3mUE13jL1tGwvoQsKdVbAsQx9AJ+fqahKveP04= | ||||||
| github.com/bugsnag/bugsnag-go v1.5.3/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= | github.com/bugsnag/bugsnag-go v1.5.3/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= | ||||||
| github.com/bugsnag/panicwrap v1.2.0 h1:OzrKrRvXis8qEvOkfcxNcYbOd2O7xXS2nnKMEMABFQA= | github.com/bugsnag/panicwrap v1.2.0 h1:OzrKrRvXis8qEvOkfcxNcYbOd2O7xXS2nnKMEMABFQA= | ||||||
| @ -54,12 +56,13 @@ github.com/cloudflare/cfssl v1.4.1 h1:vScfU2DrIUI9VPHBVeeAQ0q5A+9yshO1Gz+3QoUQiK | |||||||
| github.com/cloudflare/cfssl v1.4.1/go.mod h1:KManx/OJPb5QY+y0+o/898AMcM128sF0bURvoVUSjTo= | github.com/cloudflare/cfssl v1.4.1/go.mod h1:KManx/OJPb5QY+y0+o/898AMcM128sF0bURvoVUSjTo= | ||||||
| github.com/cloudflare/go-metrics v0.0.0-20151117154305-6a9aea36fb41/go.mod h1:eaZPlJWD+G9wseg1BuRXlHnjntPMrywMsyxf+LTOdP4= | github.com/cloudflare/go-metrics v0.0.0-20151117154305-6a9aea36fb41/go.mod h1:eaZPlJWD+G9wseg1BuRXlHnjntPMrywMsyxf+LTOdP4= | ||||||
| github.com/cloudflare/redoctober v0.0.0-20171127175943-746a508df14c/go.mod h1:6Se34jNoqrd8bTxrmJB2Bg2aoZ2CdSXonils9NsiNgo= | github.com/cloudflare/redoctober v0.0.0-20171127175943-746a508df14c/go.mod h1:6Se34jNoqrd8bTxrmJB2Bg2aoZ2CdSXonils9NsiNgo= | ||||||
| github.com/compose-spec/compose-go v0.0.0-20200716130117-e87e4f7839e3 h1:+ntlMTrEcScJjlnEOP8P1IIrusJaR93Eazr66YgUueA= |  | ||||||
| github.com/compose-spec/compose-go v0.0.0-20200716130117-e87e4f7839e3/go.mod h1:ArodJ6gsEB7iWKrbV3fSHZ08LlBvSVB0Oqg04fX86t4= |  | ||||||
| github.com/compose-spec/compose-go v0.0.0-20200811091145-837f8f4de457 h1:8ely1LF7H02sIWz6QjgU53YBCiRpYlM9F9u1MeE1ZPk= | github.com/compose-spec/compose-go v0.0.0-20200811091145-837f8f4de457 h1:8ely1LF7H02sIWz6QjgU53YBCiRpYlM9F9u1MeE1ZPk= | ||||||
| github.com/compose-spec/compose-go v0.0.0-20200811091145-837f8f4de457/go.mod h1:cS0vAvM6u9yjJgKWIH2yiqYMWO7WGJb+c0Irw+RefqU= | github.com/compose-spec/compose-go v0.0.0-20200811091145-837f8f4de457/go.mod h1:cS0vAvM6u9yjJgKWIH2yiqYMWO7WGJb+c0Irw+RefqU= | ||||||
| github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= | github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= | ||||||
|  | github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1 h1:uict5mhHFTzKLUCufdSLym7z/J0CbBJT59lYbP9wtbg= | ||||||
| github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= | github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= | ||||||
|  | github.com/containerd/console v1.0.0 h1:fU3UuQapBs+zLJu82NhR11Rif1ny2zfMMAyPJzSN5tQ= | ||||||
|  | github.com/containerd/console v1.0.0/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= | ||||||
| github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= | github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= | ||||||
| github.com/containerd/containerd v1.3.2 h1:ForxmXkA6tPIvffbrDAcPUIB32QgXkt2XFj+F0UxetA= | github.com/containerd/containerd v1.3.2 h1:ForxmXkA6tPIvffbrDAcPUIB32QgXkt2XFj+F0UxetA= | ||||||
| github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= | github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= | ||||||
| @ -76,6 +79,8 @@ github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8Nz | |||||||
| github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= | ||||||
| github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= | ||||||
| github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= | github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= | ||||||
|  | github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= | ||||||
|  | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= | ||||||
| github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= | github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= | ||||||
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||||||
| @ -137,8 +142,7 @@ github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB | |||||||
| github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= | ||||||
| github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= | github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= | ||||||
| github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | ||||||
| github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||||||
| github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= |  | ||||||
| github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= | github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= | ||||||
| github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||||||
| github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= | ||||||
| @ -157,8 +161,6 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= | |||||||
| github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= | ||||||
| github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= | github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= | ||||||
| github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= | github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= | ||||||
| github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= |  | ||||||
| github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= |  | ||||||
| github.com/imdario/mergo v0.3.10 h1:6q5mVkdH/vYmqngx7kZQTjJ5HRsx+ImorDIEQ+beJgc= | github.com/imdario/mergo v0.3.10 h1:6q5mVkdH/vYmqngx7kZQTjJ5HRsx+ImorDIEQ+beJgc= | ||||||
| github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= | github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= | ||||||
| github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= | github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= | ||||||
| @ -229,11 +231,11 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG | |||||||
| github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= | ||||||
| github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= | github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= | ||||||
| github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= | ||||||
| github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg= |  | ||||||
| github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= |  | ||||||
| github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= | github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= | ||||||
| github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= | github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= | ||||||
| github.com/mjibson/esc v0.2.0/go.mod h1:9Hw9gxxfHulMF5OJKCyhYD7PzlSdhzXyaGEBRPH1OPs= | github.com/mjibson/esc v0.2.0/go.mod h1:9Hw9gxxfHulMF5OJKCyhYD7PzlSdhzXyaGEBRPH1OPs= | ||||||
|  | github.com/moby/term v0.0.0-20200611042045-63b9a826fb74 h1:kvRIeqJNICemq2UFLx8q/Pj+1IRNZS0XPTaMFkuNsvg= | ||||||
|  | github.com/moby/term v0.0.0-20200611042045-63b9a826fb74/go.mod h1:pJ0Ot5YGdTcMdxnPMyGCfAr6fKXe0g9cDlz16MuFEBE= | ||||||
| github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | ||||||
| github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | ||||||
| github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= | ||||||
| @ -401,7 +403,9 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ | |||||||
| golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
| golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
| golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
|  | golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= | ||||||
| golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
|  | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= | ||||||
| golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
| golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||||
| golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||||
| @ -419,8 +423,8 @@ golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3 h1:4y9KwBHBgBNwDbtu44R5o1fdO | |||||||
| golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3 h1:7TYNF4UdlohbFwpNH04CoPMp1cHUZgO1Ebq5r2hIjfo= | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3 h1:7TYNF4UdlohbFwpNH04CoPMp1cHUZgO1Ebq5r2hIjfo= | ||||||
| golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7 h1:HmbHVPwrPEKPGLAcHSrMe6+hqSUlvZU0rab6x5EXfGU= | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA= | ||||||
| golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= | ||||||
| golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= | ||||||
|  | |||||||
| @ -1,9 +1,12 @@ | |||||||
| package backend | package backend | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"context" | ||||||
|  | 
 | ||||||
| 	"github.com/aws/aws-sdk-go/aws" | 	"github.com/aws/aws-sdk-go/aws" | ||||||
| 	"github.com/aws/aws-sdk-go/aws/session" | 	"github.com/aws/aws-sdk-go/aws/session" | ||||||
| 	"github.com/docker/ecs-plugin/pkg/amazon/sdk" | 	"github.com/docker/ecs-plugin/pkg/amazon/sdk" | ||||||
|  | 	"github.com/docker/ecs-plugin/pkg/progress" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func NewBackend(profile string, region string) (*Backend, error) { | func NewBackend(profile string, region string) (*Backend, error) { | ||||||
| @ -17,6 +20,7 @@ func NewBackend(profile string, region string) (*Backend, error) { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
| 	return &Backend{ | 	return &Backend{ | ||||||
| 		Region: region, | 		Region: region, | ||||||
| 		api:    sdk.NewAPI(sess), | 		api:    sdk.NewAPI(sess), | ||||||
| @ -26,4 +30,9 @@ func NewBackend(profile string, region string) (*Backend, error) { | |||||||
| type Backend struct { | type Backend struct { | ||||||
| 	Region string | 	Region string | ||||||
| 	api    sdk.API | 	api    sdk.API | ||||||
|  | 	writer progress.Writer | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (b *Backend) SetWriter(context context.Context) { | ||||||
|  | 	b.writer = progress.ContextWriter(context) | ||||||
| } | } | ||||||
|  | |||||||
| @ -5,7 +5,6 @@ import ( | |||||||
| 
 | 
 | ||||||
| 	"github.com/compose-spec/compose-go/cli" | 	"github.com/compose-spec/compose-go/cli" | ||||||
| 	"github.com/docker/ecs-plugin/pkg/compose" | 	"github.com/docker/ecs-plugin/pkg/compose" | ||||||
| 	"github.com/docker/ecs-plugin/pkg/console" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func (b *Backend) Down(ctx context.Context, options *cli.ProjectOptions) error { | func (b *Backend) Down(ctx context.Context, options *cli.ProjectOptions) error { | ||||||
| @ -18,13 +17,7 @@ func (b *Backend) Down(ctx context.Context, options *cli.ProjectOptions) error { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 	return b.WaitStackCompletion(ctx, name, compose.StackDelete) | ||||||
| 	w := console.NewProgressWriter() |  | ||||||
| 	err = b.WaitStackCompletion(ctx, name, compose.StackDelete, w) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (b *Backend) projectName(options *cli.ProjectOptions) (string, error) { | func (b *Backend) projectName(options *cli.ProjectOptions) (string, error) { | ||||||
|  | |||||||
| @ -1,8 +1,10 @@ | |||||||
| package backend | package backend | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"bytes" | ||||||
| 	"context" | 	"context" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"io" | ||||||
| 	"os" | 	"os" | ||||||
| 	"os/signal" | 	"os/signal" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| @ -13,7 +15,7 @@ import ( | |||||||
| 	"github.com/docker/ecs-plugin/pkg/console" | 	"github.com/docker/ecs-plugin/pkg/console" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func (b *Backend) Logs(ctx context.Context, options *cli.ProjectOptions) error { | func (b *Backend) Logs(ctx context.Context, options *cli.ProjectOptions, writer io.Writer) error { | ||||||
| 	name := options.Name | 	name := options.Name | ||||||
| 	if name == "" { | 	if name == "" { | ||||||
| 		project, err := cli.ProjectFromOptions(options) | 		project, err := cli.ProjectFromOptions(options) | ||||||
| @ -26,6 +28,7 @@ func (b *Backend) Logs(ctx context.Context, options *cli.ProjectOptions) error { | |||||||
| 	err := b.api.GetLogs(ctx, name, &logConsumer{ | 	err := b.api.GetLogs(ctx, name, &logConsumer{ | ||||||
| 		colors: map[string]console.ColorFunc{}, | 		colors: map[string]console.ColorFunc{}, | ||||||
| 		width:  0, | 		width:  0, | ||||||
|  | 		writer: writer, | ||||||
| 	}) | 	}) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| @ -45,8 +48,10 @@ func (l *logConsumer) Log(service, container, message string) { | |||||||
| 		l.computeWidth() | 		l.computeWidth() | ||||||
| 	} | 	} | ||||||
| 	prefix := fmt.Sprintf("%-"+strconv.Itoa(l.width)+"s |", service) | 	prefix := fmt.Sprintf("%-"+strconv.Itoa(l.width)+"s |", service) | ||||||
|  | 
 | ||||||
| 	for _, line := range strings.Split(message, "\n") { | 	for _, line := range strings.Split(message, "\n") { | ||||||
| 		fmt.Printf("%s %s\n", cf(prefix), line) | 		buf := bytes.NewBufferString(fmt.Sprintf("%s %s\n", cf(prefix), line)) | ||||||
|  | 		l.writer.Write(buf.Bytes()) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -63,4 +68,5 @@ func (l *logConsumer) computeWidth() { | |||||||
| type logConsumer struct { | type logConsumer struct { | ||||||
| 	colors map[string]console.ColorFunc | 	colors map[string]console.ColorFunc | ||||||
| 	width  int | 	width  int | ||||||
|  | 	writer io.Writer | ||||||
| } | } | ||||||
|  | |||||||
| @ -5,12 +5,13 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"os" | 	"os" | ||||||
| 	"os/signal" | 	"os/signal" | ||||||
|  | 	"strings" | ||||||
| 	"syscall" | 	"syscall" | ||||||
| 
 | 
 | ||||||
| 	"github.com/compose-spec/compose-go/cli" | 	"github.com/compose-spec/compose-go/cli" | ||||||
| 	"github.com/compose-spec/compose-go/types" | 	"github.com/compose-spec/compose-go/types" | ||||||
| 	"github.com/docker/ecs-plugin/pkg/compose" | 	"github.com/docker/ecs-plugin/pkg/compose" | ||||||
| 	"github.com/docker/ecs-plugin/pkg/console" | 	"github.com/docker/ecs-plugin/pkg/progress" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func (b *Backend) Up(ctx context.Context, options *cli.ProjectOptions) error { | func (b *Backend) Up(ctx context.Context, options *cli.ProjectOptions) error { | ||||||
| @ -82,10 +83,12 @@ func (b *Backend) Up(ctx context.Context, options *cli.ProjectOptions) error { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fmt.Println() |  | ||||||
| 	w := console.NewProgressWriter() |  | ||||||
| 	for k := range template.Resources { | 	for k := range template.Resources { | ||||||
| 		w.ResourceEvent(k, "PENDING", "") | 		b.writer.Event(progress.Event{ | ||||||
|  | 			ID:         k, | ||||||
|  | 			Status:     progress.Working, | ||||||
|  | 			StatusText: "Pending", | ||||||
|  | 		}) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	signalChan := make(chan os.Signal, 1) | 	signalChan := make(chan os.Signal, 1) | ||||||
| @ -96,7 +99,29 @@ func (b *Backend) Up(ctx context.Context, options *cli.ProjectOptions) error { | |||||||
| 		b.Down(ctx, options) | 		b.Down(ctx, options) | ||||||
| 	}() | 	}() | ||||||
| 
 | 
 | ||||||
| 	return b.WaitStackCompletion(ctx, project.Name, operation, w) | 	err = b.WaitStackCompletion(ctx, project.Name, operation) | ||||||
|  | 	// update status for external resources (LB and cluster) | ||||||
|  | 	loadBalancerName := fmt.Sprintf("%.32s", fmt.Sprintf("%sLoadBalancer", strings.Title(project.Name))) | ||||||
|  | 	for k := range template.Resources { | ||||||
|  | 		switch k { | ||||||
|  | 		case "Cluster": | ||||||
|  | 			if cluster == "" { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 		case loadBalancerName: | ||||||
|  | 			if lb == "" { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 		default: | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		b.writer.Event(progress.Event{ | ||||||
|  | 			ID:         k, | ||||||
|  | 			Status:     progress.Done, | ||||||
|  | 			StatusText: "", | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | 	return err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (b Backend) GetVPC(ctx context.Context, project *types.Project) (string, error) { | func (b Backend) GetVPC(ctx context.Context, project *types.Project) (string, error) { | ||||||
|  | |||||||
| @ -8,10 +8,11 @@ import ( | |||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/aws/aws-sdk-go/aws" | 	"github.com/aws/aws-sdk-go/aws" | ||||||
| 	"github.com/docker/ecs-plugin/pkg/console" | 	"github.com/docker/ecs-plugin/pkg/compose" | ||||||
|  | 	"github.com/docker/ecs-plugin/pkg/progress" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func (b *Backend) WaitStackCompletion(ctx context.Context, name string, operation int, w console.ProgressWriter) error { | func (b *Backend) WaitStackCompletion(ctx context.Context, name string, operation int) error { | ||||||
| 	knownEvents := map[string]struct{}{} | 	knownEvents := map[string]struct{}{} | ||||||
| 
 | 
 | ||||||
| 	// Get the unique Stack ID so we can collect events without getting some from previous deployments with same name | 	// Get the unique Stack ID so we can collect events without getting some from previous deployments with same name | ||||||
| @ -22,7 +23,6 @@ func (b *Backend) WaitStackCompletion(ctx context.Context, name string, operatio | |||||||
| 
 | 
 | ||||||
| 	ticker := time.NewTicker(1 * time.Second) | 	ticker := time.NewTicker(1 * time.Second) | ||||||
| 	done := make(chan bool) | 	done := make(chan bool) | ||||||
| 
 |  | ||||||
| 	go func() { | 	go func() { | ||||||
| 		b.api.WaitStackComplete(ctx, stackID, operation) //nolint:errcheck | 		b.api.WaitStackComplete(ctx, stackID, operation) //nolint:errcheck | ||||||
| 		ticker.Stop() | 		ticker.Stop() | ||||||
| @ -55,11 +55,38 @@ func (b *Backend) WaitStackCompletion(ctx context.Context, name string, operatio | |||||||
| 			resource := aws.StringValue(event.LogicalResourceId) | 			resource := aws.StringValue(event.LogicalResourceId) | ||||||
| 			reason := aws.StringValue(event.ResourceStatusReason) | 			reason := aws.StringValue(event.ResourceStatusReason) | ||||||
| 			status := aws.StringValue(event.ResourceStatus) | 			status := aws.StringValue(event.ResourceStatus) | ||||||
| 			w.ResourceEvent(resource, status, reason) | 			progressStatus := progress.Working | ||||||
| 			if stackErr == nil && strings.HasSuffix(status, "_FAILED") { | 
 | ||||||
| 				stackErr = fmt.Errorf(reason) | 			switch status { | ||||||
|  | 			case "CREATE_COMPLETE": | ||||||
|  | 				if operation == compose.StackCreate { | ||||||
|  | 					progressStatus = progress.Done | ||||||
|  | 
 | ||||||
|  | 				} | ||||||
|  | 			case "UPDATE_COMPLETE": | ||||||
|  | 				if operation == compose.StackUpdate { | ||||||
|  | 					progressStatus = progress.Done | ||||||
|  | 				} | ||||||
|  | 			case "DELETE_COMPLETE": | ||||||
|  | 				if operation == compose.StackDelete { | ||||||
|  | 					progressStatus = progress.Done | ||||||
|  | 				} | ||||||
|  | 			default: | ||||||
|  | 				if strings.HasSuffix(status, "_FAILED") { | ||||||
|  | 					progressStatus = progress.Error | ||||||
|  | 					if stackErr == nil { | ||||||
|  | 						operation = compose.StackDelete | ||||||
|  | 						stackErr = fmt.Errorf(reason) | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
|  | 			b.writer.Event(progress.Event{ | ||||||
|  | 				ID:         resource, | ||||||
|  | 				Status:     progressStatus, | ||||||
|  | 				StatusText: status, | ||||||
|  | 			}) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
| 	return stackErr | 	return stackErr | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ package compose | |||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
|  | 	"io" | ||||||
| 
 | 
 | ||||||
| 	"github.com/awslabs/goformation/v4/cloudformation" | 	"github.com/awslabs/goformation/v4/cloudformation" | ||||||
| 	"github.com/compose-spec/compose-go/cli" | 	"github.com/compose-spec/compose-go/cli" | ||||||
| @ -15,8 +16,8 @@ type API interface { | |||||||
| 	CreateContextData(ctx context.Context, params map[string]string) (contextData interface{}, description string, err error) | 	CreateContextData(ctx context.Context, params map[string]string) (contextData interface{}, description string, err error) | ||||||
| 
 | 
 | ||||||
| 	Convert(project *types.Project) (*cloudformation.Template, error) | 	Convert(project *types.Project) (*cloudformation.Template, error) | ||||||
| 	Logs(ctx context.Context, options *cli.ProjectOptions) error | 	Logs(ctx context.Context, options *cli.ProjectOptions, writer io.Writer) error | ||||||
| 	Ps(background context.Context, options *cli.ProjectOptions) ([]ServiceStatus, error) | 	Ps(ctx context.Context, options *cli.ProjectOptions) ([]ServiceStatus, error) | ||||||
| 
 | 
 | ||||||
| 	CreateSecret(ctx context.Context, secret Secret) (string, error) | 	CreateSecret(ctx context.Context, secret Secret) (string, error) | ||||||
| 	InspectSecret(ctx context.Context, id string) (Secret, error) | 	InspectSecret(ctx context.Context, id string) (Secret, error) | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| package console | package console | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"fmt" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -24,6 +25,14 @@ var Monochrome = func(s string) string { | |||||||
| 	return s | 	return s | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func ansiColor(code, s string) string { | ||||||
|  | 	return fmt.Sprintf("%s%s%s", ansi(code), s, ansi("0")) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func ansi(code string) string { | ||||||
|  | 	return fmt.Sprintf("\033[%sm", code) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func makeColorFunc(code string) ColorFunc { | func makeColorFunc(code string) ColorFunc { | ||||||
| 	return func(s string) string { | 	return func(s string) string { | ||||||
| 		return ansiColor(code, s) | 		return ansiColor(code, s) | ||||||
|  | |||||||
| @ -1,132 +0,0 @@ | |||||||
| package console |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 	"io" |  | ||||||
| 	"os" |  | ||||||
| 	"strconv" |  | ||||||
| 	"strings" |  | ||||||
| 
 |  | ||||||
| 	"github.com/sirupsen/logrus" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| type resource struct { |  | ||||||
| 	name    string |  | ||||||
| 	status  string |  | ||||||
| 	details string |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type progress struct { |  | ||||||
| 	console   console |  | ||||||
| 	resources []*resource |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type ProgressWriter interface { |  | ||||||
| 	ResourceEvent(name string, status string, details string) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func NewProgressWriter() ProgressWriter { |  | ||||||
| 	return &progress{ |  | ||||||
| 		console: ansiConsole{os.Stdout}, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const ( |  | ||||||
| 	blue  = "36;2" |  | ||||||
| 	red   = "31;1" |  | ||||||
| 	green = "32;1" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func (p *progress) ResourceEvent(name string, status string, details string) { |  | ||||||
| 	if logrus.IsLevelEnabled(logrus.DebugLevel) { |  | ||||||
| 		logrus.Debugf("> %s : %s %s\n", name, status, details) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	p.console.MoveUp(len(p.resources)) |  | ||||||
| 
 |  | ||||||
| 	newResource := true |  | ||||||
| 	for _, r := range p.resources { |  | ||||||
| 		if r.name == name { |  | ||||||
| 			newResource = false |  | ||||||
| 			r.status = status |  | ||||||
| 			r.details = details |  | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	if newResource { |  | ||||||
| 		p.resources = append(p.resources, &resource{name, status, details}) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	var width int |  | ||||||
| 	for _, r := range p.resources { |  | ||||||
| 		l := len(r.name) |  | ||||||
| 		if width < l { |  | ||||||
| 			width = l |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	for _, r := range p.resources { |  | ||||||
| 		s := r.status |  | ||||||
| 		if strings.HasSuffix(s, "_IN_PROGRESS") { |  | ||||||
| 			s = p.console.WiP(s) |  | ||||||
| 		} else if strings.HasSuffix(s, "_COMPLETE") { |  | ||||||
| 			s = p.console.OK(s) |  | ||||||
| 		} else if strings.HasSuffix(s, "_FAILED") { |  | ||||||
| 			s = p.console.KO(s) |  | ||||||
| 		} |  | ||||||
| 		p.console.ClearLine() |  | ||||||
| 		p.console.Printf("%-"+strconv.Itoa(width)+"s ... %s %s", r.name, s, r.details) // nolint:errcheck |  | ||||||
| 		p.console.MoveDown(1) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type console interface { |  | ||||||
| 	Printf(format string, a ...interface{}) |  | ||||||
| 	MoveUp(int) |  | ||||||
| 	MoveDown(int) |  | ||||||
| 	ClearLine() |  | ||||||
| 	OK(string) string |  | ||||||
| 	KO(string) string |  | ||||||
| 	WiP(string) string |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type ansiConsole struct { |  | ||||||
| 	out io.Writer |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (c ansiConsole) Printf(format string, a ...interface{}) { |  | ||||||
| 	fmt.Fprintf(c.out, format, a...) // nolint:errcheck |  | ||||||
| 	fmt.Fprintf(c.out, "\r") |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (c ansiConsole) MoveUp(i int) { |  | ||||||
| 	fmt.Fprintf(c.out, "\033[%dA", i) // nolint:errcheck |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (c ansiConsole) MoveDown(i int) { |  | ||||||
| 	fmt.Fprintf(c.out, "\033[%dB", i) // nolint:errcheck |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (c ansiConsole) ClearLine() { |  | ||||||
| 	fmt.Fprint(c.out, "\033[2K\r") // nolint:errcheck |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (c ansiConsole) OK(s string) string { |  | ||||||
| 	return ansiColor(green, s) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (c ansiConsole) KO(s string) string { |  | ||||||
| 	return ansiColor(red, s) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (c ansiConsole) WiP(s string) string { |  | ||||||
| 	return ansiColor(blue, s) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ansiColor(code, s string) string { |  | ||||||
| 	return fmt.Sprintf("%s%s%s", ansi(code), s, ansi("0")) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ansi(code string) string { |  | ||||||
| 	return fmt.Sprintf("\033[%sm", code) |  | ||||||
| } |  | ||||||
| @ -1,65 +0,0 @@ | |||||||
| package console |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 	"testing" |  | ||||||
| 
 |  | ||||||
| 	"gotest.tools/v3/assert" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func TestProgressWriter(t *testing.T) { |  | ||||||
| 	c := &bufferConsole{} |  | ||||||
| 	p := progress{ |  | ||||||
| 		console: c, |  | ||||||
| 	} |  | ||||||
| 	p.ResourceEvent("resource1", "CREATE_IN_PROGRESS", "") |  | ||||||
| 	assert.Equal(t, c.lines[0], "resource1 ... CREATE_IN_PROGRESS ") |  | ||||||
| 
 |  | ||||||
| 	p.ResourceEvent("resource2_long_name", "CREATE_IN_PROGRESS", "ok") |  | ||||||
| 	assert.Equal(t, c.lines[0], "resource1           ... CREATE_IN_PROGRESS ") |  | ||||||
| 	assert.Equal(t, c.lines[1], "resource2_long_name ... CREATE_IN_PROGRESS ok") |  | ||||||
| 
 |  | ||||||
| 	p.ResourceEvent("resource2_long_name", "CREATE_COMPLETE", "done") |  | ||||||
| 	assert.Equal(t, c.lines[0], "resource1           ... CREATE_IN_PROGRESS ") |  | ||||||
| 	assert.Equal(t, c.lines[1], "resource2_long_name ... CREATE_COMPLETE done") |  | ||||||
| 
 |  | ||||||
| 	p.ResourceEvent("resource1", "CREATE_FAILED", "oups") |  | ||||||
| 	assert.Equal(t, c.lines[0], "resource1           ... CREATE_FAILED oups") |  | ||||||
| 	assert.Equal(t, c.lines[1], "resource2_long_name ... CREATE_COMPLETE done") |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type bufferConsole struct { |  | ||||||
| 	pos   int |  | ||||||
| 	lines []string |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (b *bufferConsole) Printf(format string, a ...interface{}) { |  | ||||||
| 	b.lines[b.pos] = fmt.Sprintf(format, a...) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (b *bufferConsole) MoveUp(i int) { |  | ||||||
| 	b.pos -= i |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (b *bufferConsole) MoveDown(i int) { |  | ||||||
| 	b.pos += i |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (b *bufferConsole) ClearLine() { |  | ||||||
| 	if len(b.lines) <= b.pos { |  | ||||||
| 		b.lines = append(b.lines, "") |  | ||||||
| 	} |  | ||||||
| 	b.lines[b.pos] = "" |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (b *bufferConsole) OK(s string) string { |  | ||||||
| 	return s |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (b *bufferConsole) KO(s string) string { |  | ||||||
| 	return s |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (b *bufferConsole) WiP(s string) string { |  | ||||||
| 	return s |  | ||||||
| } |  | ||||||
							
								
								
									
										29
									
								
								ecs/pkg/progress/plain.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								ecs/pkg/progress/plain.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | |||||||
|  | package progress | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type plainWriter struct { | ||||||
|  | 	out  io.Writer | ||||||
|  | 	done chan bool | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (p *plainWriter) Start(ctx context.Context) error { | ||||||
|  | 	select { | ||||||
|  | 	case <-ctx.Done(): | ||||||
|  | 		return ctx.Err() | ||||||
|  | 	case <-p.done: | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (p *plainWriter) Event(e Event) { | ||||||
|  | 	fmt.Println(e.ID, e.Text, e.StatusText) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (p *plainWriter) Stop() { | ||||||
|  | 	p.done <- true | ||||||
|  | } | ||||||
							
								
								
									
										50
									
								
								ecs/pkg/progress/spinner.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								ecs/pkg/progress/spinner.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,50 @@ | |||||||
|  | package progress | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"runtime" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type spinner struct { | ||||||
|  | 	time  time.Time | ||||||
|  | 	index int | ||||||
|  | 	chars []string | ||||||
|  | 	stop  bool | ||||||
|  | 	done  string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func newSpinner() *spinner { | ||||||
|  | 	chars := []string{ | ||||||
|  | 		"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏", | ||||||
|  | 	} | ||||||
|  | 	done := "⠿" | ||||||
|  | 
 | ||||||
|  | 	if runtime.GOOS == "windows" { | ||||||
|  | 		chars = []string{"-"} | ||||||
|  | 		done = "-" | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return &spinner{ | ||||||
|  | 		index: 0, | ||||||
|  | 		time:  time.Now(), | ||||||
|  | 		chars: chars, | ||||||
|  | 		done:  done, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *spinner) String() string { | ||||||
|  | 	if s.stop { | ||||||
|  | 		return s.done | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	d := time.Since(s.time) | ||||||
|  | 	if d.Milliseconds() > 100 { | ||||||
|  | 		s.index = (s.index + 1) % len(s.chars) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return s.chars[s.index] | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *spinner) Stop() { | ||||||
|  | 	s.stop = true | ||||||
|  | } | ||||||
							
								
								
									
										177
									
								
								ecs/pkg/progress/tty.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								ecs/pkg/progress/tty.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,177 @@ | |||||||
|  | package progress | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"runtime" | ||||||
|  | 	"strings" | ||||||
|  | 	"sync" | ||||||
|  | 	"time" | ||||||
|  | 
 | ||||||
|  | 	"github.com/buger/goterm" | ||||||
|  | 	"github.com/morikuni/aec" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type ttyWriter struct { | ||||||
|  | 	out      io.Writer | ||||||
|  | 	events   map[string]Event | ||||||
|  | 	eventIDs []string | ||||||
|  | 	repeated bool | ||||||
|  | 	numLines int | ||||||
|  | 	done     chan bool | ||||||
|  | 	mtx      *sync.RWMutex | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (w *ttyWriter) Start(ctx context.Context) error { | ||||||
|  | 	ticker := time.NewTicker(100 * time.Millisecond) | ||||||
|  | 
 | ||||||
|  | 	for { | ||||||
|  | 		select { | ||||||
|  | 		case <-ctx.Done(): | ||||||
|  | 			w.print() | ||||||
|  | 			return ctx.Err() | ||||||
|  | 		case <-w.done: | ||||||
|  | 			w.print() | ||||||
|  | 			return nil | ||||||
|  | 		case <-ticker.C: | ||||||
|  | 			w.print() | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (w *ttyWriter) Stop() { | ||||||
|  | 	w.done <- true | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (w *ttyWriter) Event(e Event) { | ||||||
|  | 	w.mtx.Lock() | ||||||
|  | 	defer w.mtx.Unlock() | ||||||
|  | 	if !StringContains(w.eventIDs, e.ID) { | ||||||
|  | 		w.eventIDs = append(w.eventIDs, e.ID) | ||||||
|  | 	} | ||||||
|  | 	if _, ok := w.events[e.ID]; ok { | ||||||
|  | 		last := w.events[e.ID] | ||||||
|  | 		switch e.Status { | ||||||
|  | 		case Done, Error: | ||||||
|  | 			if last.Status != e.Status { | ||||||
|  | 				last.stop() | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		last.Status = e.Status | ||||||
|  | 		last.Text = e.Text | ||||||
|  | 		last.StatusText = e.StatusText | ||||||
|  | 		w.events[e.ID] = last | ||||||
|  | 	} else { | ||||||
|  | 		e.startTime = time.Now() | ||||||
|  | 		e.spinner = newSpinner() | ||||||
|  | 		w.events[e.ID] = e | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (w *ttyWriter) print() { | ||||||
|  | 	w.mtx.Lock() | ||||||
|  | 	defer w.mtx.Unlock() | ||||||
|  | 	if len(w.eventIDs) == 0 { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	terminalWidth := goterm.Width() | ||||||
|  | 	b := aec.EmptyBuilder | ||||||
|  | 	for i := 0; i <= w.numLines; i++ { | ||||||
|  | 		b = b.Up(1) | ||||||
|  | 	} | ||||||
|  | 	if !w.repeated { | ||||||
|  | 		b = b.Down(1) | ||||||
|  | 	} | ||||||
|  | 	w.repeated = true | ||||||
|  | 	fmt.Fprint(w.out, b.Column(0).ANSI) | ||||||
|  | 
 | ||||||
|  | 	// Hide the cursor while we are printing | ||||||
|  | 	fmt.Fprint(w.out, aec.Hide) | ||||||
|  | 	defer fmt.Fprint(w.out, aec.Show) | ||||||
|  | 
 | ||||||
|  | 	firstLine := fmt.Sprintf("[+] Running %d/%d", numDone(w.events), w.numLines) | ||||||
|  | 	if w.numLines != 0 && numDone(w.events) == w.numLines { | ||||||
|  | 		firstLine = aec.Apply(firstLine, aec.BlueF) | ||||||
|  | 	} | ||||||
|  | 	fmt.Fprintln(w.out, firstLine) | ||||||
|  | 
 | ||||||
|  | 	var statusPadding int | ||||||
|  | 	for _, v := range w.eventIDs { | ||||||
|  | 		l := len(fmt.Sprintf("%s %s", w.events[v].ID, w.events[v].Text)) | ||||||
|  | 		if statusPadding < l { | ||||||
|  | 			statusPadding = l | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	numLines := 0 | ||||||
|  | 	for _, v := range w.eventIDs { | ||||||
|  | 		line := lineText(w.events[v], terminalWidth, statusPadding, runtime.GOOS != "windows") | ||||||
|  | 		// nolint: errcheck | ||||||
|  | 		fmt.Fprint(w.out, line) | ||||||
|  | 		numLines++ | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	w.numLines = numLines | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func lineText(event Event, terminalWidth, statusPadding int, color bool) string { | ||||||
|  | 	endTime := time.Now() | ||||||
|  | 	if event.Status != Working { | ||||||
|  | 		endTime = event.endTime | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	elapsed := endTime.Sub(event.startTime).Seconds() | ||||||
|  | 
 | ||||||
|  | 	textLen := len(fmt.Sprintf("%s %s", event.ID, event.Text)) | ||||||
|  | 	padding := statusPadding - textLen | ||||||
|  | 	if padding < 0 { | ||||||
|  | 		padding = 0 | ||||||
|  | 	} | ||||||
|  | 	text := fmt.Sprintf(" %s %s %s%s %s", | ||||||
|  | 		event.spinner.String(), | ||||||
|  | 		event.ID, | ||||||
|  | 		event.Text, | ||||||
|  | 		strings.Repeat(" ", padding), | ||||||
|  | 		event.StatusText, | ||||||
|  | 	) | ||||||
|  | 	timer := fmt.Sprintf("%.1fs\n", elapsed) | ||||||
|  | 	o := align(text, timer, terminalWidth) | ||||||
|  | 
 | ||||||
|  | 	if color { | ||||||
|  | 		color := aec.WhiteF | ||||||
|  | 		if event.Status == Done { | ||||||
|  | 			color = aec.BlueF | ||||||
|  | 		} | ||||||
|  | 		if event.Status == Error { | ||||||
|  | 			color = aec.RedF | ||||||
|  | 		} | ||||||
|  | 		return aec.Apply(o, color) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return o | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func numDone(events map[string]Event) int { | ||||||
|  | 	i := 0 | ||||||
|  | 	for _, e := range events { | ||||||
|  | 		if e.Status == Done { | ||||||
|  | 			i++ | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return i | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func align(l, r string, w int) string { | ||||||
|  | 	return fmt.Sprintf("%-[2]*[1]s %[3]s", l, w-len(r)-1, r) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // StringContains check if an array contains a specific value | ||||||
|  | func StringContains(array []string, needle string) bool { | ||||||
|  | 	for _, val := range array { | ||||||
|  | 		if val == needle { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
							
								
								
									
										112
									
								
								ecs/pkg/progress/writer.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								ecs/pkg/progress/writer.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,112 @@ | |||||||
|  | package progress | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"os" | ||||||
|  | 	"sync" | ||||||
|  | 	"time" | ||||||
|  | 
 | ||||||
|  | 	"github.com/containerd/console" | ||||||
|  | 	"github.com/moby/term" | ||||||
|  | 	"golang.org/x/sync/errgroup" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // EventStatus indicates the status of an action | ||||||
|  | type EventStatus int | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	// Working means that the current task is working | ||||||
|  | 	Working EventStatus = iota | ||||||
|  | 	// Done means that the current task is done | ||||||
|  | 	Done | ||||||
|  | 	// Error means that the current task has errored | ||||||
|  | 	Error | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Event reprensents a progress event | ||||||
|  | type Event struct { | ||||||
|  | 	ID         string | ||||||
|  | 	Text       string | ||||||
|  | 	Status     EventStatus | ||||||
|  | 	StatusText string | ||||||
|  | 	Done       bool | ||||||
|  | 
 | ||||||
|  | 	startTime time.Time | ||||||
|  | 	endTime   time.Time | ||||||
|  | 	spinner   *spinner | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (e *Event) stop() { | ||||||
|  | 	e.endTime = time.Now() | ||||||
|  | 	e.spinner.Stop() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Writer can write multiple progress events | ||||||
|  | type Writer interface { | ||||||
|  | 	Start(context.Context) error | ||||||
|  | 	Stop() | ||||||
|  | 	Event(Event) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type writerKey struct{} | ||||||
|  | 
 | ||||||
|  | // WithContextWriter adds the writer to the context | ||||||
|  | func WithContextWriter(ctx context.Context, writer Writer) context.Context { | ||||||
|  | 	return context.WithValue(ctx, writerKey{}, writer) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ContextWriter returns the writer from the context | ||||||
|  | func ContextWriter(ctx context.Context) Writer { | ||||||
|  | 	s, _ := ctx.Value(writerKey{}).(Writer) | ||||||
|  | 	return s | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type progressFunc func(context.Context) error | ||||||
|  | 
 | ||||||
|  | // Run will run a writer and the progress function | ||||||
|  | // in parallel | ||||||
|  | func Run(ctx context.Context, pf progressFunc) error { | ||||||
|  | 	eg, _ := errgroup.WithContext(ctx) | ||||||
|  | 	w, err := NewWriter(os.Stderr) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	eg.Go(func() error { | ||||||
|  | 		return w.Start(context.Background()) | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	ctx = WithContextWriter(ctx, w) | ||||||
|  | 
 | ||||||
|  | 	eg.Go(func() error { | ||||||
|  | 		defer w.Stop() | ||||||
|  | 		return pf(ctx) | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	return eg.Wait() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewWriter returns a new multi-progress writer | ||||||
|  | func NewWriter(out console.File) (Writer, error) { | ||||||
|  | 	_, isTerminal := term.GetFdInfo(out) | ||||||
|  | 
 | ||||||
|  | 	if isTerminal { | ||||||
|  | 		con, err := console.ConsoleFromFile(out) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return &ttyWriter{ | ||||||
|  | 			out:      con, | ||||||
|  | 			eventIDs: []string{}, | ||||||
|  | 			events:   map[string]Event{}, | ||||||
|  | 			repeated: false, | ||||||
|  | 			done:     make(chan bool), | ||||||
|  | 			mtx:      &sync.RWMutex{}, | ||||||
|  | 		}, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return &plainWriter{ | ||||||
|  | 		out:  out, | ||||||
|  | 		done: make(chan bool), | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user