Forklift buildx provider

This commit is contained in:
Bryce Lampe
2024-03-25 11:40:33 -07:00
parent 2b348f84e4
commit d50d156bd8
349 changed files with 61549 additions and 1141 deletions

1
.gitignore vendored
View File

@@ -5,6 +5,7 @@
**/.vs
**/.idea
**/.ionide
**/.vscode
*.swp
Pulumi.*.yaml
yarn.lock

View File

@@ -1,36 +1,61 @@
linters:
enable-all: false
enable:
- depguard
- errcheck
- exhaustive
- prealloc
- gofumpt
- revive
- exportloopref
- gci
- gocritic
- gofumpt
- goheader
- gosec
- govet
- importas
- ineffassign
- lll
- misspell
- nolintlint
- nakedret
- unconvert
- unused
- nolintlint
- paralleltest
- perfsprint
- depguard
- importas
- prealloc
- revive
- unconvert
- unused
linters-settings:
nakedret:
# Make an issue if func has more lines of code than this setting, and it has naked returns.
# Default: 30
max-func-lines: 60
nolintlint:
# Some linter exclusions are added to generated or templated files
# pre-emptively.
# Don't complain about these.
allow-unused: true
depguard:
rules:
protobuf:
deny:
- pkg: "github.com/golang/protobuf"
desc: Use google.golang.org/protobuf instead
gci:
sections:
- standard # Standard section: captures all standard library packages.
- blank # Blank section: contains all blank imports.
- default # Default section: contains all imports that could not be matched to another section type.
- prefix(github.com/pulumi/) # Custom section: groups all imports with the github.com/pulumi/ prefix.
- prefix(github.com/pulumi/pulumi-dockerbuild/) # Custom section: local imports
custom-order: true
gocritic:
enable-all: true
goheader:
template: |-
Copyright 2024, Pulumi Corporation.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
govet:
enable:
- nilness
@@ -40,22 +65,18 @@ linters-settings:
- sortslice
# Detect write to struct/arrays by-value that aren't read again.
- unusedwrite
gci:
sections:
- standard # Standard section: captures all standard library packages.
- blank # Blank section: contains all blank imports.
- default # Default section: contains all imports that could not be matched to another section type.
- prefix(github.com/pulumi/) # Custom section: groups all imports with the github.com/pulumi/ prefix.
- prefix(github.com/pulumi/pulumi-dockerbuild) # Custom section: local imports
custom-order: true
depguard:
rules:
protobuf:
deny:
- pkg: "github.com/golang/protobuf"
desc: Use google.golang.org/protobuf instead
nakedret:
# Make an issue if func has more lines of code than this setting, and it has naked returns.
# Default: 30
max-func-lines: 60
nolintlint:
# Some linter exclusions are added to generated or templated files
# pre-emptively.
# Don't complain about these.
allow-unused: true
issues:
exclude-use-default: false
exclude-rules:
# Don't warn on unused parameters.
# Parameter names are useful; replacing them with '_' is undesirable.

View File

@@ -44,7 +44,11 @@ test_all:: test_provider test_examples
gen_examples:
examples: $(shell mkdir -p examples)
examples: sdk examples/go examples/nodejs examples/python examples/dotnet examples/java
examples: sdk examples/yaml examples/go examples/nodejs examples/python examples/dotnet examples/java
examples/yaml:
rm -rf ${WORKING_DIR}/examples/yaml/app
cp -r ${WORKING_DIR}/examples/app ${WORKING_DIR}/examples/yaml/app
examples/go: ${PULUMI} bin/${PROVIDER} ${WORKING_DIR}/examples/yaml/Pulumi.yaml
$(call example,go)
@@ -75,7 +79,6 @@ define pulumi_login
endef
define example
echo "GOT $(1)"
rm -rf ${WORKING_DIR}/examples/$(1)
$(PULUMI) convert \
--cwd ${WORKING_DIR}/examples/yaml \
@@ -84,6 +87,7 @@ define example
--non-interactive \
--language $(1) \
--out ${WORKING_DIR}/examples/$(1)
cp -r ${WORKING_DIR}/examples/app ${WORKING_DIR}/examples/$(1)/app
endef
up::
@@ -236,3 +240,7 @@ sdk/java: $(PULUMI) bin/${PROVIDER}
$(PULUMI) package gen-sdk --language java bin/${PROVIDER} -o ${TMPDIR}
cd ${TMPDIR}/java/ && gradle --console=plain build
mv -f ${TMPDIR}/java ${WORKING_DIR}/sdk/.
docs: $(shell find docs/yaml -type f)
go generate docs/generate.go
@touch docs

206
docs/generate.go Normal file
View File

@@ -0,0 +1,206 @@
// Copyright 2024, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:generate go run generate.go yaml ../provider/internal/embed
// Package main ingests a multi-document YAML file and converts it into
// Markdown examples.
package main
import (
"fmt"
"io"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"gopkg.in/yaml.v3"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
)
func main() {
if len(os.Args) < 3 {
fmt.Fprintf(os.Stdout, "Usage: %s <yaml source dir path> <markdown destination path>\n", os.Args[0])
os.Exit(1)
}
yamlPath := os.Args[1]
mdPath := os.Args[2]
if !filepath.IsAbs(yamlPath) {
cwd, err := os.Getwd()
contract.AssertNoErrorf(err, "getting working directory")
yamlPath = filepath.Join(cwd, yamlPath)
}
if err := os.MkdirAll(mdPath, 0o750); err != nil {
panic(err)
}
fileInfo, err := os.Lstat(mdPath)
if err != nil || !fileInfo.IsDir() {
fmt.Fprintf(os.Stderr, "Expect markdown destination %q to be a directory\n", mdPath)
os.Exit(1)
}
yamlFiles, err := os.ReadDir(yamlPath)
if err != nil {
panic(err)
}
for _, yamlFile := range yamlFiles {
if err := processYaml(filepath.Join(yamlPath, yamlFile.Name()), mdPath); err != nil {
log.Fatal(fmt.Errorf("processing %q: %w", yamlFile.Name(), err))
}
}
}
func markdownExamples(examples []string) string {
s := "{{% examples %}}\n## Example Usage\n"
for _, example := range examples {
s += example
}
s += "{{% /examples %}}"
return s
}
func markdownExample(description string,
typescript string,
python string,
csharp string,
golang string,
yaml string,
java string,
) string {
return fmt.Sprintf("{{%% example %%}}\n### %s\n\n"+
"```typescript\n%s```\n"+
"```python\n%s```\n"+
"```csharp\n%s```\n"+
"```go\n%s```\n"+
"```yaml\n%s```\n"+
"```java\n%s```\n"+
"{{%% /example %%}}\n",
description, typescript, python, csharp, golang, yaml, java)
}
func convert(language, tempDir, programFile string) (string, error) {
exampleDir := filepath.Join(tempDir, "example"+language)
//nolint:gosec // No user-provided input.
cmd := exec.Command(
"pulumi",
"convert",
"--language",
language,
"--out",
filepath.Clean(filepath.Join(tempDir, exampleDir)),
"--generate-only",
)
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
cmd.Dir = tempDir
if err := cmd.Run(); err != nil {
return "", fmt.Errorf("converting: %w", err)
}
content, err := os.ReadFile(filepath.Clean(filepath.Join(tempDir, exampleDir, programFile)))
if err != nil {
return "", fmt.Errorf("reading: %w", err)
}
return string(content), nil
}
func processYaml(path string, mdDir string) error {
yamlFile, err := os.Open(filepath.Clean(path))
if err != nil {
return err
}
base := filepath.Base(path)
md := strings.NewReplacer(".yaml", ".md", ".yml", ".md").Replace(base)
defer contract.IgnoreClose(yamlFile)
decoder := yaml.NewDecoder(yamlFile)
exampleStrings := []string{}
for {
example := map[string]interface{}{}
err := decoder.Decode(&example)
if err == io.EOF {
break
}
description, ok := example["description"].(string)
if !ok {
description = "TODO: Description"
}
dir, err := os.MkdirTemp("", "")
if err != nil {
return err
}
defer func() {
contract.IgnoreError(os.RemoveAll(dir))
}()
src, err := os.OpenFile(filepath.Clean(filepath.Join(dir, "Pulumi.yaml")), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o600)
if err != nil {
return err
}
fmt.Println("Converting:", example)
if err = yaml.NewEncoder(src).Encode(example); err != nil {
return err
}
contract.AssertNoErrorf(src.Close(), "closing")
typescript, err := convert("typescript", dir, "index.ts")
if err != nil {
return err
}
python, err := convert("python", dir, "__main__.py")
if err != nil {
return err
}
csharp, err := convert("csharp", dir, "Program.cs")
if err != nil {
return err
}
golang, err := convert("go", dir, "main.go")
if err != nil {
return err
}
java, err := convert("java", dir, "src/main/java/generated_program/App.java")
if err != nil {
return err
}
yamlContent, err := os.ReadFile(filepath.Clean(filepath.Join(dir, "Pulumi.yaml")))
if err != nil {
return err
}
yaml := string(yamlContent)
exampleStrings = append(exampleStrings, markdownExample(description, typescript, python, csharp, golang, yaml, java))
}
fmt.Fprintf(os.Stdout, "Writing %s\n", filepath.Join(mdDir, md))
f, err := os.OpenFile(filepath.Clean(filepath.Join(mdDir, md)), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o600)
if err != nil {
return err
}
defer contract.IgnoreClose(f)
_, err = f.Write([]byte(markdownExamples(exampleStrings)))
contract.AssertNoErrorf(err, "writing examples")
return nil
}

View File

@@ -0,0 +1,180 @@
name: ecr
description: Push to AWS ECR with caching
outputs:
ref: ${my-image.ref}
resources:
ecr-repository:
type: aws:ecr:Repository
my-image:
type: dockerbuild:index:Image
properties:
tags:
- ${ecr-repository.repositoryUrl}:latest
push: true
context:
location: ./app
cacheFrom:
- registry:
ref: ${ecr-repository.repositoryUrl}:cache
cacheTo:
- registry:
ref: ${ecr-repository.repositoryUrl}:cache
imageManifest: true
ociMediaTypes: true
registries:
- username: ${auth-token.userName}
password: ${auth-token.password}
address: ${ecr-repository.repositoryUrl}
runtime: yaml
variables:
auth-token:
fn::aws:ecr:getAuthorizationToken:
registryId: ${ecr-repository.registryId}
---
name: multi-platform
runtime: yaml
description: Multi-platform image
resources:
image:
type: dockerbuild:index:Image
properties:
context:
location: "app"
platforms:
- plan9/amd64
- plan9/386
---
name: registry
runtime: yaml
description: Registry export
resources:
image:
type: dockerbuild:index:Image
properties:
tags:
- "docker.io/pulumi/pulumi:3.107.0"
context:
location: "app"
push: true
registries:
- address: docker.io
username: pulumibot
password: ${dockerHubPassword}
outputs:
ref: ${my-image.ref}
---
name: caching
runtime: yaml
description: Caching
resources:
image:
type: dockerbuild:index:Image
properties:
context:
location: "app"
cacheTo:
- local:
dest: tmp/cache
mode: max
cacheFrom:
- local:
src: tmp/cache
---
name: dbc
runtime: yaml
description: Docker Build Cloud
resources:
image:
type: dockerbuild:index:Image
properties:
context:
location: "app"
exec: true
builder:
name: cloud-builder-name
---
name: build-args
runtime: yaml
description: Build arguments
resources:
image:
type: dockerbuild:index:Image
properties:
context:
location: "app"
buildArgs:
SET_ME_TO_TRUE: "true"
---
name: build-target
runtime: yaml
description: Build target
resources:
image:
type: dockerbuild:index:Image
properties:
context:
location: "app"
target: "build-me"
---
name: named-contexts
runtime: yaml
description: Named contexts
resources:
image:
type: dockerbuild:index:Image
properties:
context:
location: app
named:
"golang:latest":
location: "docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984"
---
name: remote-context
runtime: yaml
description: Remote context
resources:
image:
type: dockerbuild:index:Image
properties:
context:
location: "https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile"
---
name: inline
runtime: yaml
description: Inline Dockerfile
resources:
image:
type: dockerbuild:index:Image
properties:
dockerfile:
inline: |
FROM busybox
COPY hello.c ./
context:
location: "app"
---
name: remote-context
runtime: yaml
description: Remote context
resources:
image:
type: dockerbuild:index:Image
properties:
dockerfile:
location: app/Dockerfile
context:
location: "https://github.com/docker-library/hello-world.git"
---
name: docker-load
runtime: yaml
description: Local export
resources:
image:
type: dockerbuild:index:Image
properties:
context:
location: "app"
exports:
- docker:
tar: true

View File

@@ -0,0 +1,48 @@
name: registry-caching
description: Multi-platform registry caching
runtime: yaml
resources:
arm64:
type: dockerbuild:index:Image
properties:
context:
location: "app"
platforms:
- linux/arm64
tags:
- "docker.io/pulumi/pulumi:3.107.0-arm64"
cacheTo:
- registry:
ref: "docker.io/pulumi/pulumi:cache-arm64"
mode: max
cacheFrom:
- registry:
ref: "docker.io/pulumi/pulumi:cache-arm64"
amd64:
type: dockerbuild:index:Image
properties:
context:
location: "app"
platforms:
- linux/amd64
tags:
- "docker.io/pulumi/pulumi:3.107.0-amd64"
cacheTo:
- registry:
ref: "docker.io/pulumi/pulumi:cache-amd64"
mode: max
cacheFrom:
- registry:
ref: "docker.io/pulumi/pulumi:cache-amd64"
index:
type: dockerbuild:index:Index
properties:
tag: "docker.io/pulumi/pulumi:3.107.0"
sources:
- ${amd64.ref}
- ${arm64.ref}
outputs:
ref: ${index.ref}

2
examples/app/Dockerfile Normal file
View File

@@ -0,0 +1,2 @@
FROM alpine
RUN echo 👍

View File

@@ -0,0 +1,5 @@
FROM alpine
ARG SET_ME_TO_TRUE
RUN [ "$SET_ME_TO_TRUE" = "true" ]
RUN echo "That's the correct build arg, thanks! 👍"

View File

@@ -0,0 +1,2 @@
FROM alpine
RUN echo "This image doesn't use any local files, so it doesn't need a context parameter 👍"

View File

@@ -0,0 +1,3 @@
FROM bash AS base
RUN getent hosts metadata.google.internal

View File

@@ -0,0 +1,7 @@
FROM --platform=$BUILDPLATFORM alpine as build
RUN echo ${BUILDPLATFORM} > buildplatform
RUN echo ${TARGETPLATFORM} > targetplatform
FROM build
RUN cat buildplatform
RUN cat targetplatform

View File

@@ -0,0 +1,5 @@
# syntax=docker/dockerfile:1.4
FROM golang:latest
RUN version="$(go version)" && echo $version && [ "$version" = "go version go1.21.7 linux/amd64" ]
RUN echo "This image uses named contexts to pin golang:latest to a specific SHA 👍"

View File

@@ -0,0 +1,4 @@
FROM alpine
RUN --mount=type=secret,id=password [ "$(cat /run/secrets/password)" = "hunter2" ]

View File

@@ -0,0 +1,5 @@
FROM alpine
RUN apk add openssh-client
RUN --mount=type=ssh ssh-add -l

View File

@@ -0,0 +1,8 @@
FROM alpine as build-me
RUN echo 👍
FROM build-me as also-build-me
RUN echo 🤙
FROM build-me as dont-build-me
RUN [ "true" = "false" ]

View File

@@ -5,14 +5,254 @@ using Dockerbuild = Pulumi.Dockerbuild;
return await Deployment.RunAsync(() =>
{
var myRandomResource = new Dockerbuild.Random("myRandomResource", new()
var config = new Config();
var dockerHubPassword = config.Require("dockerHubPassword");
var multiPlatform = new Dockerbuild.Image("multiPlatform", new()
{
Length = 24,
Dockerfile = new Dockerbuild.Inputs.DockerfileArgs
{
Location = "./app/Dockerfile.multiPlatform",
},
Context = new Dockerbuild.Inputs.BuildContextArgs
{
Location = "./app",
},
Platforms = new[]
{
Dockerbuild.Platform.Plan9_amd64,
Dockerbuild.Platform.Plan9_386,
},
});
var registryPush = new Dockerbuild.Image("registryPush", new()
{
Context = new Dockerbuild.Inputs.BuildContextArgs
{
Location = "./app",
},
Tags = new[]
{
"docker.io/pulumibot/buildkit-e2e:example",
},
Exports = new[]
{
new Dockerbuild.Inputs.ExportArgs
{
Registry = new Dockerbuild.Inputs.ExportRegistryArgs
{
OciMediaTypes = true,
Push = false,
},
},
},
Registries = new[]
{
new Dockerbuild.Inputs.RegistryArgs
{
Address = "docker.io",
Username = "pulumibot",
Password = dockerHubPassword,
},
},
});
var cached = new Dockerbuild.Image("cached", new()
{
Context = new Dockerbuild.Inputs.BuildContextArgs
{
Location = "./app",
},
CacheTo = new[]
{
new Dockerbuild.Inputs.CacheToArgs
{
Local = new Dockerbuild.Inputs.CacheToLocalArgs
{
Dest = "tmp/cache",
Mode = Dockerbuild.CacheMode.Max,
},
},
},
CacheFrom = new[]
{
new Dockerbuild.Inputs.CacheFromArgs
{
Local = new Dockerbuild.Inputs.CacheFromLocalArgs
{
Src = "tmp/cache",
},
},
},
});
var buildArgs = new Dockerbuild.Image("buildArgs", new()
{
Dockerfile = new Dockerbuild.Inputs.DockerfileArgs
{
Location = "./app/Dockerfile.buildArgs",
},
Context = new Dockerbuild.Inputs.BuildContextArgs
{
Location = "./app",
},
BuildArgs =
{
{ "SET_ME_TO_TRUE", "true" },
},
});
var extraHosts = new Dockerbuild.Image("extraHosts", new()
{
Dockerfile = new Dockerbuild.Inputs.DockerfileArgs
{
Location = "./app/Dockerfile.extraHosts",
},
Context = new Dockerbuild.Inputs.BuildContextArgs
{
Location = "./app",
},
AddHosts = new[]
{
"metadata.google.internal:169.254.169.254",
},
});
var sshMount = new Dockerbuild.Image("sshMount", new()
{
Dockerfile = new Dockerbuild.Inputs.DockerfileArgs
{
Location = "./app/Dockerfile.sshMount",
},
Context = new Dockerbuild.Inputs.BuildContextArgs
{
Location = "./app",
},
Ssh = new[]
{
new Dockerbuild.Inputs.SSHArgs
{
Id = "default",
},
},
});
var secrets = new Dockerbuild.Image("secrets", new()
{
Dockerfile = new Dockerbuild.Inputs.DockerfileArgs
{
Location = "./app/Dockerfile.secrets",
},
Context = new Dockerbuild.Inputs.BuildContextArgs
{
Location = "./app",
},
Secrets =
{
{ "password", "hunter2" },
},
});
var labels = new Dockerbuild.Image("labels", new()
{
Context = new Dockerbuild.Inputs.BuildContextArgs
{
Location = "./app",
},
Labels =
{
{ "description", "This image will get a descriptive label 👍" },
},
});
var target = new Dockerbuild.Image("target", new()
{
Dockerfile = new Dockerbuild.Inputs.DockerfileArgs
{
Location = "./app/Dockerfile.target",
},
Context = new Dockerbuild.Inputs.BuildContextArgs
{
Location = "./app",
},
Target = "build-me",
});
var namedContexts = new Dockerbuild.Image("namedContexts", new()
{
Dockerfile = new Dockerbuild.Inputs.DockerfileArgs
{
Location = "./app/Dockerfile.namedContexts",
},
Context = new Dockerbuild.Inputs.BuildContextArgs
{
Location = "./app",
Named =
{
{ "golang:latest", new Dockerbuild.Inputs.ContextArgs
{
Location = "docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984",
} },
},
},
});
var remoteContext = new Dockerbuild.Image("remoteContext", new()
{
Context = new Dockerbuild.Inputs.BuildContextArgs
{
Location = "https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile",
},
});
var remoteContextWithInline = new Dockerbuild.Image("remoteContextWithInline", new()
{
Dockerfile = new Dockerbuild.Inputs.DockerfileArgs
{
Inline = @"FROM busybox
COPY hello.c ./
",
},
Context = new Dockerbuild.Inputs.BuildContextArgs
{
Location = "https://github.com/docker-library/hello-world.git",
},
});
var inline = new Dockerbuild.Image("inline", new()
{
Dockerfile = new Dockerbuild.Inputs.DockerfileArgs
{
Inline = @"FROM alpine
RUN echo ""This uses an inline Dockerfile! 👍""
",
},
Context = new Dockerbuild.Inputs.BuildContextArgs
{
Location = "./app",
},
});
var dockerLoad = new Dockerbuild.Image("dockerLoad", new()
{
Context = new Dockerbuild.Inputs.BuildContextArgs
{
Location = "./app",
},
Exports = new[]
{
new Dockerbuild.Inputs.ExportArgs
{
Docker = new Dockerbuild.Inputs.ExportDockerArgs
{
Tar = true,
},
},
},
});
return new Dictionary<string, object?>
{
["value"] = myRandomResource.Result,
["platforms"] = multiPlatform.Platforms,
};
});

View File

@@ -1,5 +1,9 @@
name: provider-dockerbuild
runtime: dotnet
config:
dockerHubPassword:
type: string
secret: true
plugins:
providers:
- name: dockerbuild

View File

@@ -0,0 +1,2 @@
FROM alpine
RUN echo 👍

View File

@@ -0,0 +1,5 @@
FROM alpine
ARG SET_ME_TO_TRUE
RUN [ "$SET_ME_TO_TRUE" = "true" ]
RUN echo "That's the correct build arg, thanks! 👍"

View File

@@ -0,0 +1,2 @@
FROM alpine
RUN echo "This image doesn't use any local files, so it doesn't need a context parameter 👍"

View File

@@ -0,0 +1,3 @@
FROM bash AS base
RUN getent hosts metadata.google.internal

View File

@@ -0,0 +1,7 @@
FROM --platform=$BUILDPLATFORM alpine as build
RUN echo ${BUILDPLATFORM} > buildplatform
RUN echo ${TARGETPLATFORM} > targetplatform
FROM build
RUN cat buildplatform
RUN cat targetplatform

View File

@@ -0,0 +1,5 @@
# syntax=docker/dockerfile:1.4
FROM golang:latest
RUN version="$(go version)" && echo $version && [ "$version" = "go version go1.21.7 linux/amd64" ]
RUN echo "This image uses named contexts to pin golang:latest to a specific SHA 👍"

View File

@@ -0,0 +1,4 @@
FROM alpine
RUN --mount=type=secret,id=password [ "$(cat /run/secrets/password)" = "hunter2" ]

View File

@@ -0,0 +1,5 @@
FROM alpine
RUN apk add openssh-client
RUN --mount=type=ssh ssh-add -l

View File

@@ -0,0 +1,8 @@
FROM alpine as build-me
RUN echo 👍
FROM build-me as also-build-me
RUN echo 🤙
FROM build-me as dont-build-me
RUN [ "true" = "false" ]

View File

@@ -1,5 +1,9 @@
name: provider-dockerbuild
runtime: go
config:
dockerHubPassword:
type: string
secret: true
plugins:
providers:
- name: dockerbuild

View File

@@ -0,0 +1,2 @@
FROM alpine
RUN echo 👍

View File

@@ -0,0 +1,5 @@
FROM alpine
ARG SET_ME_TO_TRUE
RUN [ "$SET_ME_TO_TRUE" = "true" ]
RUN echo "That's the correct build arg, thanks! 👍"

View File

@@ -0,0 +1,2 @@
FROM alpine
RUN echo "This image doesn't use any local files, so it doesn't need a context parameter 👍"

View File

@@ -0,0 +1,3 @@
FROM bash AS base
RUN getent hosts metadata.google.internal

View File

@@ -0,0 +1,7 @@
FROM --platform=$BUILDPLATFORM alpine as build
RUN echo ${BUILDPLATFORM} > buildplatform
RUN echo ${TARGETPLATFORM} > targetplatform
FROM build
RUN cat buildplatform
RUN cat targetplatform

View File

@@ -0,0 +1,5 @@
# syntax=docker/dockerfile:1.4
FROM golang:latest
RUN version="$(go version)" && echo $version && [ "$version" = "go version go1.21.7 linux/amd64" ]
RUN echo "This image uses named contexts to pin golang:latest to a specific SHA 👍"

View File

@@ -0,0 +1,4 @@
FROM alpine
RUN --mount=type=secret,id=password [ "$(cat /run/secrets/password)" = "hunter2" ]

View File

@@ -0,0 +1,5 @@
FROM alpine
RUN apk add openssh-client
RUN --mount=type=ssh ssh-add -l

View File

@@ -0,0 +1,8 @@
FROM alpine as build-me
RUN echo 👍
FROM build-me as also-build-me
RUN echo 🤙
FROM build-me as dont-build-me
RUN [ "true" = "false" ]

View File

@@ -3,17 +3,220 @@ package main
import (
"github.com/pulumi/pulumi-dockerbuild/sdk/go/dockerbuild"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
myRandomResource, err := dockerbuild.NewRandom(ctx, "myRandomResource", &dockerbuild.RandomArgs{
Length: pulumi.Int(24),
cfg := config.New(ctx, "")
dockerHubPassword := cfg.Require("dockerHubPassword")
multiPlatform, err := dockerbuild.NewImage(ctx, "multiPlatform", &dockerbuild.ImageArgs{
Dockerfile: &dockerbuild.DockerfileArgs{
Location: pulumi.String("./app/Dockerfile.multiPlatform"),
},
Context: &dockerbuild.BuildContextArgs{
Location: pulumi.String("./app"),
},
Platforms: dockerbuild.PlatformArray{
dockerbuild.Platform_Plan9_amd64,
dockerbuild.Platform_Plan9_386,
},
})
if err != nil {
return err
}
ctx.Export("value", myRandomResource.Result)
_, err = dockerbuild.NewImage(ctx, "registryPush", &dockerbuild.ImageArgs{
Context: &dockerbuild.BuildContextArgs{
Location: pulumi.String("./app"),
},
Tags: pulumi.StringArray{
pulumi.String("docker.io/pulumibot/buildkit-e2e:example"),
},
Exports: dockerbuild.ExportArray{
&dockerbuild.ExportArgs{
Registry: &dockerbuild.ExportRegistryArgs{
OciMediaTypes: pulumi.Bool(true),
Push: pulumi.Bool(false),
},
},
},
Registries: dockerbuild.RegistryArray{
&dockerbuild.RegistryArgs{
Address: pulumi.String("docker.io"),
Username: pulumi.String("pulumibot"),
Password: pulumi.String(dockerHubPassword),
},
},
})
if err != nil {
return err
}
_, err = dockerbuild.NewImage(ctx, "cached", &dockerbuild.ImageArgs{
Context: &dockerbuild.BuildContextArgs{
Location: pulumi.String("./app"),
},
CacheTo: dockerbuild.CacheToArray{
&dockerbuild.CacheToArgs{
Local: &dockerbuild.CacheToLocalArgs{
Dest: pulumi.String("tmp/cache"),
Mode: dockerbuild.CacheModeMax,
},
},
},
CacheFrom: dockerbuild.CacheFromArray{
&dockerbuild.CacheFromArgs{
Local: &dockerbuild.CacheFromLocalArgs{
Src: pulumi.String("tmp/cache"),
},
},
},
})
if err != nil {
return err
}
_, err = dockerbuild.NewImage(ctx, "buildArgs", &dockerbuild.ImageArgs{
Dockerfile: &dockerbuild.DockerfileArgs{
Location: pulumi.String("./app/Dockerfile.buildArgs"),
},
Context: &dockerbuild.BuildContextArgs{
Location: pulumi.String("./app"),
},
BuildArgs: pulumi.StringMap{
"SET_ME_TO_TRUE": pulumi.String("true"),
},
})
if err != nil {
return err
}
_, err = dockerbuild.NewImage(ctx, "extraHosts", &dockerbuild.ImageArgs{
Dockerfile: &dockerbuild.DockerfileArgs{
Location: pulumi.String("./app/Dockerfile.extraHosts"),
},
Context: &dockerbuild.BuildContextArgs{
Location: pulumi.String("./app"),
},
AddHosts: pulumi.StringArray{
pulumi.String("metadata.google.internal:169.254.169.254"),
},
})
if err != nil {
return err
}
_, err = dockerbuild.NewImage(ctx, "sshMount", &dockerbuild.ImageArgs{
Dockerfile: &dockerbuild.DockerfileArgs{
Location: pulumi.String("./app/Dockerfile.sshMount"),
},
Context: &dockerbuild.BuildContextArgs{
Location: pulumi.String("./app"),
},
Ssh: dockerbuild.SSHArray{
&dockerbuild.SSHArgs{
Id: pulumi.String("default"),
},
},
})
if err != nil {
return err
}
_, err = dockerbuild.NewImage(ctx, "secrets", &dockerbuild.ImageArgs{
Dockerfile: &dockerbuild.DockerfileArgs{
Location: pulumi.String("./app/Dockerfile.secrets"),
},
Context: &dockerbuild.BuildContextArgs{
Location: pulumi.String("./app"),
},
Secrets: pulumi.StringMap{
"password": pulumi.String("hunter2"),
},
})
if err != nil {
return err
}
_, err = dockerbuild.NewImage(ctx, "labels", &dockerbuild.ImageArgs{
Context: &dockerbuild.BuildContextArgs{
Location: pulumi.String("./app"),
},
Labels: pulumi.StringMap{
"description": pulumi.String("This image will get a descriptive label 👍"),
},
})
if err != nil {
return err
}
_, err = dockerbuild.NewImage(ctx, "target", &dockerbuild.ImageArgs{
Dockerfile: &dockerbuild.DockerfileArgs{
Location: pulumi.String("./app/Dockerfile.target"),
},
Context: &dockerbuild.BuildContextArgs{
Location: pulumi.String("./app"),
},
Target: pulumi.String("build-me"),
})
if err != nil {
return err
}
_, err = dockerbuild.NewImage(ctx, "namedContexts", &dockerbuild.ImageArgs{
Dockerfile: &dockerbuild.DockerfileArgs{
Location: pulumi.String("./app/Dockerfile.namedContexts"),
},
Context: &dockerbuild.BuildContextArgs{
Location: pulumi.String("./app"),
Named: dockerbuild.ContextMap{
"golang:latest": &dockerbuild.ContextArgs{
Location: pulumi.String("docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984"),
},
},
},
})
if err != nil {
return err
}
_, err = dockerbuild.NewImage(ctx, "remoteContext", &dockerbuild.ImageArgs{
Context: &dockerbuild.BuildContextArgs{
Location: pulumi.String("https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile"),
},
})
if err != nil {
return err
}
_, err = dockerbuild.NewImage(ctx, "remoteContextWithInline", &dockerbuild.ImageArgs{
Dockerfile: &dockerbuild.DockerfileArgs{
Inline: pulumi.String("FROM busybox\nCOPY hello.c ./\n"),
},
Context: &dockerbuild.BuildContextArgs{
Location: pulumi.String("https://github.com/docker-library/hello-world.git"),
},
})
if err != nil {
return err
}
_, err = dockerbuild.NewImage(ctx, "inline", &dockerbuild.ImageArgs{
Dockerfile: &dockerbuild.DockerfileArgs{
Inline: pulumi.String("FROM alpine\nRUN echo \"This uses an inline Dockerfile! 👍\"\n"),
},
Context: &dockerbuild.BuildContextArgs{
Location: pulumi.String("./app"),
},
})
if err != nil {
return err
}
_, err = dockerbuild.NewImage(ctx, "dockerLoad", &dockerbuild.ImageArgs{
Context: &dockerbuild.BuildContextArgs{
Location: pulumi.String("./app"),
},
Exports: dockerbuild.ExportArray{
&dockerbuild.ExportArgs{
Docker: &dockerbuild.ExportDockerArgs{
Tar: pulumi.Bool(true),
},
},
},
})
if err != nil {
return err
}
ctx.Export("platforms", multiPlatform.Platforms)
return nil
})
}

View File

@@ -1,5 +1,9 @@
name: provider-dockerbuild
runtime: java
config:
dockerHubPassword:
type: string
secret: true
plugins:
providers:
- name: dockerbuild

View File

@@ -0,0 +1,2 @@
FROM alpine
RUN echo 👍

View File

@@ -0,0 +1,5 @@
FROM alpine
ARG SET_ME_TO_TRUE
RUN [ "$SET_ME_TO_TRUE" = "true" ]
RUN echo "That's the correct build arg, thanks! 👍"

View File

@@ -0,0 +1,2 @@
FROM alpine
RUN echo "This image doesn't use any local files, so it doesn't need a context parameter 👍"

View File

@@ -0,0 +1,3 @@
FROM bash AS base
RUN getent hosts metadata.google.internal

View File

@@ -0,0 +1,7 @@
FROM --platform=$BUILDPLATFORM alpine as build
RUN echo ${BUILDPLATFORM} > buildplatform
RUN echo ${TARGETPLATFORM} > targetplatform
FROM build
RUN cat buildplatform
RUN cat targetplatform

View File

@@ -0,0 +1,5 @@
# syntax=docker/dockerfile:1.4
FROM golang:latest
RUN version="$(go version)" && echo $version && [ "$version" = "go version go1.21.7 linux/amd64" ]
RUN echo "This image uses named contexts to pin golang:latest to a specific SHA 👍"

View File

@@ -0,0 +1,4 @@
FROM alpine
RUN --mount=type=secret,id=password [ "$(cat /run/secrets/password)" = "hunter2" ]

View File

@@ -0,0 +1,5 @@
FROM alpine
RUN apk add openssh-client
RUN --mount=type=ssh ssh-add -l

View File

@@ -0,0 +1,8 @@
FROM alpine as build-me
RUN echo 👍
FROM build-me as also-build-me
RUN echo 🤙
FROM build-me as dont-build-me
RUN [ "true" = "false" ]

View File

@@ -3,8 +3,19 @@ package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.dockerbuild.Random;
import com.pulumi.dockerbuild.RandomArgs;
import com.pulumi.dockerbuild.Image;
import com.pulumi.dockerbuild.ImageArgs;
import com.pulumi.dockerbuild.inputs.DockerfileArgs;
import com.pulumi.dockerbuild.inputs.BuildContextArgs;
import com.pulumi.dockerbuild.inputs.ExportArgs;
import com.pulumi.dockerbuild.inputs.ExportRegistryArgs;
import com.pulumi.dockerbuild.inputs.RegistryArgs;
import com.pulumi.dockerbuild.inputs.CacheToArgs;
import com.pulumi.dockerbuild.inputs.CacheToLocalArgs;
import com.pulumi.dockerbuild.inputs.CacheFromArgs;
import com.pulumi.dockerbuild.inputs.CacheFromLocalArgs;
import com.pulumi.dockerbuild.inputs.SSHArgs;
import com.pulumi.dockerbuild.inputs.ExportDockerArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
@@ -18,10 +29,165 @@ public class App {
}
public static void stack(Context ctx) {
var myRandomResource = new Random("myRandomResource", RandomArgs.builder()
.length(24)
final var config = ctx.config();
final var dockerHubPassword = config.get("dockerHubPassword");
var multiPlatform = new Image("multiPlatform", ImageArgs.builder()
.dockerfile(DockerfileArgs.builder()
.location("./app/Dockerfile.multiPlatform")
.build())
.context(BuildContextArgs.builder()
.location("./app")
.build())
.platforms(
"plan9/amd64",
"plan9/386")
.build());
ctx.export("value", myRandomResource.result());
var registryPush = new Image("registryPush", ImageArgs.builder()
.context(BuildContextArgs.builder()
.location("./app")
.build())
.tags("docker.io/pulumibot/buildkit-e2e:example")
.exports(ExportArgs.builder()
.registry(ExportRegistryArgs.builder()
.ociMediaTypes(true)
.push(false)
.build())
.build())
.registries(RegistryArgs.builder()
.address("docker.io")
.username("pulumibot")
.password(dockerHubPassword)
.build())
.build());
var cached = new Image("cached", ImageArgs.builder()
.context(BuildContextArgs.builder()
.location("./app")
.build())
.cacheTo(CacheToArgs.builder()
.local(CacheToLocalArgs.builder()
.dest("tmp/cache")
.mode("max")
.build())
.build())
.cacheFrom(CacheFromArgs.builder()
.local(CacheFromLocalArgs.builder()
.src("tmp/cache")
.build())
.build())
.build());
var buildArgs = new Image("buildArgs", ImageArgs.builder()
.dockerfile(DockerfileArgs.builder()
.location("./app/Dockerfile.buildArgs")
.build())
.context(BuildContextArgs.builder()
.location("./app")
.build())
.buildArgs(Map.of("SET_ME_TO_TRUE", "true"))
.build());
var extraHosts = new Image("extraHosts", ImageArgs.builder()
.dockerfile(DockerfileArgs.builder()
.location("./app/Dockerfile.extraHosts")
.build())
.context(BuildContextArgs.builder()
.location("./app")
.build())
.addHosts("metadata.google.internal:169.254.169.254")
.build());
var sshMount = new Image("sshMount", ImageArgs.builder()
.dockerfile(DockerfileArgs.builder()
.location("./app/Dockerfile.sshMount")
.build())
.context(BuildContextArgs.builder()
.location("./app")
.build())
.ssh(SSHArgs.builder()
.id("default")
.build())
.build());
var secrets = new Image("secrets", ImageArgs.builder()
.dockerfile(DockerfileArgs.builder()
.location("./app/Dockerfile.secrets")
.build())
.context(BuildContextArgs.builder()
.location("./app")
.build())
.secrets(Map.of("password", "hunter2"))
.build());
var labels = new Image("labels", ImageArgs.builder()
.context(BuildContextArgs.builder()
.location("./app")
.build())
.labels(Map.of("description", "This image will get a descriptive label 👍"))
.build());
var target = new Image("target", ImageArgs.builder()
.dockerfile(DockerfileArgs.builder()
.location("./app/Dockerfile.target")
.build())
.context(BuildContextArgs.builder()
.location("./app")
.build())
.target("build-me")
.build());
var namedContexts = new Image("namedContexts", ImageArgs.builder()
.dockerfile(DockerfileArgs.builder()
.location("./app/Dockerfile.namedContexts")
.build())
.context(BuildContextArgs.builder()
.location("./app")
.named(Map.of("golang:latest", Map.of("location", "docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984")))
.build())
.build());
var remoteContext = new Image("remoteContext", ImageArgs.builder()
.context(BuildContextArgs.builder()
.location("https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile")
.build())
.build());
var remoteContextWithInline = new Image("remoteContextWithInline", ImageArgs.builder()
.dockerfile(DockerfileArgs.builder()
.inline("""
FROM busybox
COPY hello.c ./
""")
.build())
.context(BuildContextArgs.builder()
.location("https://github.com/docker-library/hello-world.git")
.build())
.build());
var inline = new Image("inline", ImageArgs.builder()
.dockerfile(DockerfileArgs.builder()
.inline("""
FROM alpine
RUN echo "This uses an inline Dockerfile! 👍"
""")
.build())
.context(BuildContextArgs.builder()
.location("./app")
.build())
.build());
var dockerLoad = new Image("dockerLoad", ImageArgs.builder()
.context(BuildContextArgs.builder()
.location("./app")
.build())
.exports(ExportArgs.builder()
.docker(ExportDockerArgs.builder()
.tar(true)
.build())
.build())
.build());
ctx.export("platforms", multiPlatform.platforms());
}
}

View File

@@ -1,5 +1,9 @@
name: provider-dockerbuild
runtime: nodejs
config:
dockerHubPassword:
type: string
secret: true
plugins:
providers:
- name: dockerbuild

View File

@@ -0,0 +1,2 @@
FROM alpine
RUN echo 👍

View File

@@ -0,0 +1,5 @@
FROM alpine
ARG SET_ME_TO_TRUE
RUN [ "$SET_ME_TO_TRUE" = "true" ]
RUN echo "That's the correct build arg, thanks! 👍"

View File

@@ -0,0 +1,2 @@
FROM alpine
RUN echo "This image doesn't use any local files, so it doesn't need a context parameter 👍"

View File

@@ -0,0 +1,3 @@
FROM bash AS base
RUN getent hosts metadata.google.internal

View File

@@ -0,0 +1,7 @@
FROM --platform=$BUILDPLATFORM alpine as build
RUN echo ${BUILDPLATFORM} > buildplatform
RUN echo ${TARGETPLATFORM} > targetplatform
FROM build
RUN cat buildplatform
RUN cat targetplatform

View File

@@ -0,0 +1,5 @@
# syntax=docker/dockerfile:1.4
FROM golang:latest
RUN version="$(go version)" && echo $version && [ "$version" = "go version go1.21.7 linux/amd64" ]
RUN echo "This image uses named contexts to pin golang:latest to a specific SHA 👍"

View File

@@ -0,0 +1,4 @@
FROM alpine
RUN --mount=type=secret,id=password [ "$(cat /run/secrets/password)" = "hunter2" ]

View File

@@ -0,0 +1,5 @@
FROM alpine
RUN apk add openssh-client
RUN --mount=type=ssh ssh-add -l

View File

@@ -0,0 +1,8 @@
FROM alpine as build-me
RUN echo 👍
FROM build-me as also-build-me
RUN echo 🤙
FROM build-me as dont-build-me
RUN [ "true" = "false" ]

View File

@@ -1,5 +1,156 @@
import * as pulumi from "@pulumi/pulumi";
import * as dockerbuild from "@pulumi/dockerbuild";
const myRandomResource = new dockerbuild.Random("myRandomResource", {length: 24});
export const value = myRandomResource.result;
const config = new pulumi.Config();
const dockerHubPassword = config.require("dockerHubPassword");
const multiPlatform = new dockerbuild.Image("multiPlatform", {
dockerfile: {
location: "./app/Dockerfile.multiPlatform",
},
context: {
location: "./app",
},
platforms: [
dockerbuild.Platform.Plan9_amd64,
dockerbuild.Platform.Plan9_386,
],
});
const registryPush = new dockerbuild.Image("registryPush", {
context: {
location: "./app",
},
tags: ["docker.io/pulumibot/buildkit-e2e:example"],
exports: [{
registry: {
ociMediaTypes: true,
push: false,
},
}],
registries: [{
address: "docker.io",
username: "pulumibot",
password: dockerHubPassword,
}],
});
const cached = new dockerbuild.Image("cached", {
context: {
location: "./app",
},
cacheTo: [{
local: {
dest: "tmp/cache",
mode: dockerbuild.CacheMode.Max,
},
}],
cacheFrom: [{
local: {
src: "tmp/cache",
},
}],
});
const buildArgs = new dockerbuild.Image("buildArgs", {
dockerfile: {
location: "./app/Dockerfile.buildArgs",
},
context: {
location: "./app",
},
buildArgs: {
SET_ME_TO_TRUE: "true",
},
});
const extraHosts = new dockerbuild.Image("extraHosts", {
dockerfile: {
location: "./app/Dockerfile.extraHosts",
},
context: {
location: "./app",
},
addHosts: ["metadata.google.internal:169.254.169.254"],
});
const sshMount = new dockerbuild.Image("sshMount", {
dockerfile: {
location: "./app/Dockerfile.sshMount",
},
context: {
location: "./app",
},
ssh: [{
id: "default",
}],
});
const secrets = new dockerbuild.Image("secrets", {
dockerfile: {
location: "./app/Dockerfile.secrets",
},
context: {
location: "./app",
},
secrets: {
password: "hunter2",
},
});
const labels = new dockerbuild.Image("labels", {
context: {
location: "./app",
},
labels: {
description: "This image will get a descriptive label 👍",
},
});
const target = new dockerbuild.Image("target", {
dockerfile: {
location: "./app/Dockerfile.target",
},
context: {
location: "./app",
},
target: "build-me",
});
const namedContexts = new dockerbuild.Image("namedContexts", {
dockerfile: {
location: "./app/Dockerfile.namedContexts",
},
context: {
location: "./app",
named: {
"golang:latest": {
location: "docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984",
},
},
},
});
const remoteContext = new dockerbuild.Image("remoteContext", {context: {
location: "https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile",
}});
const remoteContextWithInline = new dockerbuild.Image("remoteContextWithInline", {
dockerfile: {
inline: `FROM busybox
COPY hello.c ./
`,
},
context: {
location: "https://github.com/docker-library/hello-world.git",
},
});
const inline = new dockerbuild.Image("inline", {
dockerfile: {
inline: `FROM alpine
RUN echo "This uses an inline Dockerfile! 👍"
`,
},
context: {
location: "./app",
},
});
const dockerLoad = new dockerbuild.Image("dockerLoad", {
context: {
location: "./app",
},
exports: [{
docker: {
tar: true,
},
}],
});
export const platforms = multiPlatform.platforms;

View File

@@ -1,5 +1,9 @@
name: provider-dockerbuild
runtime: python
config:
dockerHubPassword:
type: string
secret: true
plugins:
providers:
- name: dockerbuild

View File

@@ -1,5 +1,143 @@
import pulumi
import pulumi_dockerbuild as dockerbuild
my_random_resource = dockerbuild.Random("myRandomResource", length=24)
pulumi.export("value", my_random_resource.result)
config = pulumi.Config()
docker_hub_password = config.require("dockerHubPassword")
multi_platform = dockerbuild.Image("multiPlatform",
dockerfile=dockerbuild.DockerfileArgs(
location="./app/Dockerfile.multiPlatform",
),
context=dockerbuild.BuildContextArgs(
location="./app",
),
platforms=[
dockerbuild.Platform.PLAN9_AMD64,
dockerbuild.Platform.PLAN9_386,
])
registry_push = dockerbuild.Image("registryPush",
context=dockerbuild.BuildContextArgs(
location="./app",
),
tags=["docker.io/pulumibot/buildkit-e2e:example"],
exports=[dockerbuild.ExportArgs(
registry=dockerbuild.ExportRegistryArgs(
oci_media_types=True,
push=False,
),
)],
registries=[dockerbuild.RegistryArgs(
address="docker.io",
username="pulumibot",
password=docker_hub_password,
)])
cached = dockerbuild.Image("cached",
context=dockerbuild.BuildContextArgs(
location="./app",
),
cache_to=[dockerbuild.CacheToArgs(
local=dockerbuild.CacheToLocalArgs(
dest="tmp/cache",
mode=dockerbuild.CacheMode.MAX,
),
)],
cache_from=[dockerbuild.CacheFromArgs(
local=dockerbuild.CacheFromLocalArgs(
src="tmp/cache",
),
)])
build_args = dockerbuild.Image("buildArgs",
dockerfile=dockerbuild.DockerfileArgs(
location="./app/Dockerfile.buildArgs",
),
context=dockerbuild.BuildContextArgs(
location="./app",
),
build_args={
"SET_ME_TO_TRUE": "true",
})
extra_hosts = dockerbuild.Image("extraHosts",
dockerfile=dockerbuild.DockerfileArgs(
location="./app/Dockerfile.extraHosts",
),
context=dockerbuild.BuildContextArgs(
location="./app",
),
add_hosts=["metadata.google.internal:169.254.169.254"])
ssh_mount = dockerbuild.Image("sshMount",
dockerfile=dockerbuild.DockerfileArgs(
location="./app/Dockerfile.sshMount",
),
context=dockerbuild.BuildContextArgs(
location="./app",
),
ssh=[dockerbuild.SSHArgs(
id="default",
)])
secrets = dockerbuild.Image("secrets",
dockerfile=dockerbuild.DockerfileArgs(
location="./app/Dockerfile.secrets",
),
context=dockerbuild.BuildContextArgs(
location="./app",
),
secrets={
"password": "hunter2",
})
labels = dockerbuild.Image("labels",
context=dockerbuild.BuildContextArgs(
location="./app",
),
labels={
"description": "This image will get a descriptive label 👍",
})
target = dockerbuild.Image("target",
dockerfile=dockerbuild.DockerfileArgs(
location="./app/Dockerfile.target",
),
context=dockerbuild.BuildContextArgs(
location="./app",
),
target="build-me")
named_contexts = dockerbuild.Image("namedContexts",
dockerfile=dockerbuild.DockerfileArgs(
location="./app/Dockerfile.namedContexts",
),
context=dockerbuild.BuildContextArgs(
location="./app",
named={
"golang:latest": dockerbuild.ContextArgs(
location="docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984",
),
},
))
remote_context = dockerbuild.Image("remoteContext", context=dockerbuild.BuildContextArgs(
location="https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile",
))
remote_context_with_inline = dockerbuild.Image("remoteContextWithInline",
dockerfile=dockerbuild.DockerfileArgs(
inline="""FROM busybox
COPY hello.c ./
""",
),
context=dockerbuild.BuildContextArgs(
location="https://github.com/docker-library/hello-world.git",
))
inline = dockerbuild.Image("inline",
dockerfile=dockerbuild.DockerfileArgs(
inline="""FROM alpine
RUN echo "This uses an inline Dockerfile! 👍"
""",
),
context=dockerbuild.BuildContextArgs(
location="./app",
))
docker_load = dockerbuild.Image("dockerLoad",
context=dockerbuild.BuildContextArgs(
location="./app",
),
exports=[dockerbuild.ExportArgs(
docker=dockerbuild.ExportDockerArgs(
tar=True,
),
)])
pulumi.export("platforms", multi_platform.platforms)

View File

@@ -0,0 +1,2 @@
FROM alpine
RUN echo 👍

View File

@@ -0,0 +1,5 @@
FROM alpine
ARG SET_ME_TO_TRUE
RUN [ "$SET_ME_TO_TRUE" = "true" ]
RUN echo "That's the correct build arg, thanks! 👍"

View File

@@ -0,0 +1,2 @@
FROM alpine
RUN echo "This image doesn't use any local files, so it doesn't need a context parameter 👍"

View File

@@ -0,0 +1,3 @@
FROM bash AS base
RUN getent hosts metadata.google.internal

View File

@@ -0,0 +1,7 @@
FROM --platform=$BUILDPLATFORM alpine as build
RUN echo ${BUILDPLATFORM} > buildplatform
RUN echo ${TARGETPLATFORM} > targetplatform
FROM build
RUN cat buildplatform
RUN cat targetplatform

View File

@@ -0,0 +1,5 @@
# syntax=docker/dockerfile:1.4
FROM golang:latest
RUN version="$(go version)" && echo $version && [ "$version" = "go version go1.21.7 linux/amd64" ]
RUN echo "This image uses named contexts to pin golang:latest to a specific SHA 👍"

View File

@@ -0,0 +1,4 @@
FROM alpine
RUN --mount=type=secret,id=password [ "$(cat /run/secrets/password)" = "hunter2" ]

View File

@@ -0,0 +1,5 @@
FROM alpine
RUN apk add openssh-client
RUN --mount=type=ssh ssh-add -l

View File

@@ -0,0 +1,8 @@
FROM alpine as build-me
RUN echo 👍
FROM build-me as also-build-me
RUN echo 🤙
FROM build-me as dont-build-me
RUN [ "true" = "false" ]

View File

@@ -17,7 +17,8 @@ func TestPythonExample(t *testing.T) {
require.NoError(t, err)
test := integration.ProgramTestOptions{
Dir: path.Join(cwd, "python"),
Dir: path.Join(cwd, "python"),
RelativeWorkDir: ".",
Dependencies: []string{
path.Join("..", "sdk", "python", "bin"),
},

View File

@@ -6,10 +6,176 @@ plugins:
path: ../../bin
resources:
myRandomResource:
type: dockerbuild:Random
# docker buildx build -f app/Dockerfile.multiPlatform --platform plan9/amd64,plan9/386 app
multiPlatform:
type: dockerbuild:index:Image
properties:
length: 24
dockerfile:
location: "./app/Dockerfile.multiPlatform"
context:
location: "./app"
platforms:
- plan9/amd64
- plan9/386
# docker buildx build --output=type=registry app
registryPush:
type: dockerbuild:index:Image
properties:
context:
location: "./app"
tags: ["docker.io/pulumibot/buildkit-e2e:example"]
exports:
- registry:
ociMediaTypes: true
push: false # Omit this to actually push images.
registries:
- address: docker.io
username: pulumibot
password: ${dockerHubPassword}
# docker buildx build --cache-to=type=local,dest=tmp/cache,mode=max --cache-from=type=local,src=tmp/cache app
cached:
type: dockerbuild:index:Image
properties:
context:
location: "./app"
cacheTo:
- local:
dest: tmp/cache
mode: max
cacheFrom:
- local:
src: tmp/cache
# docker buildx build -f app/Dockerfile.buildArgs --build-arg SET_ME_TO_TRUE=true app
buildArgs:
type: dockerbuild:index:Image
properties:
dockerfile:
location: "./app/Dockerfile.buildArgs"
context:
location: "./app"
buildArgs:
SET_ME_TO_TRUE: "true"
# docker buildx build -f app/Dockerfile.extraHosts --add-host metadata.google.internal:169.254.169.254 app
extraHosts:
type: dockerbuild:index:Image
properties:
dockerfile:
location: "./app/Dockerfile.extraHosts"
context:
location: "./app"
addHosts:
- "metadata.google.internal:169.254.169.254"
# docker buildx build -f app/Dockerfile.sshMount --ssh default app
sshMount:
type: dockerbuild:index:Image
properties:
dockerfile:
location: "./app/Dockerfile.sshMount"
context:
location: "./app"
ssh:
- id: default
# PASSWORD=hunter2 docker buildx build -f app/Dockerfile.secrets --secret id=password,env=PASSWORD app
secrets:
type: dockerbuild:index:Image
properties:
dockerfile:
location: "./app/Dockerfile.secrets"
context:
location: "./app"
secrets:
password: hunter2
# docker buildx build --label "description=This image will get a descriptive label 👍" app
labels:
type: dockerbuild:index:Image
properties:
context:
location: "./app"
labels:
description: "This image will get a descriptive label 👍"
# docker buildx build -f app/Dockerfile.target --target build-me app
target:
type: dockerbuild:index:Image
properties:
dockerfile:
location: "./app/Dockerfile.target"
context:
location: "./app"
target: "build-me"
# docker buildx build -f app/Dockerfile.namedContexts \
# --build-context golang:latest=docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984 app
namedContexts:
type: dockerbuild:index:Image
properties:
dockerfile:
location: "./app/Dockerfile.namedContexts"
context:
location: "./app"
named:
"golang:latest":
location: "docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984"
# docker buildx build https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile
remoteContext:
type: dockerbuild:index:Image
properties:
context:
location: "https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile"
# docker buildx build -f - https://github.com/docker-library/hello-world.git <<EOF
# FROM busybox
# COPY hello.c ./
# EOF
remoteContextWithInline:
type: dockerbuild:index:Image
properties:
dockerfile:
inline: |
FROM busybox
COPY hello.c ./
context:
location: "https://github.com/docker-library/hello-world.git"
# echo "FROM alpine" | docker buildx build -f - .
inline:
type: dockerbuild:index:Image
properties:
dockerfile:
inline: |
FROM alpine
RUN echo "This uses an inline Dockerfile! 👍"
context:
location: "./app"
# docker buildx build --load .
dockerLoad:
type: dockerbuild:index:Image
properties:
context:
location: "./app"
exports:
- docker:
tar: true
# docker buildx build - < app/Dockerfile.emptyContext
#emptyContext:
# type: dockerbuild:index:Image
# properties:
# file: "app/Dockerfile.emptyContext"
# context: "-"
config:
dockerHubPassword:
type: string
secret: true
outputs:
value: ${myRandomResource.result}
platforms: ${multiPlatform.platforms}

View File

@@ -0,0 +1,2 @@
FROM alpine
RUN echo 👍

View File

@@ -0,0 +1,5 @@
FROM alpine
ARG SET_ME_TO_TRUE
RUN [ "$SET_ME_TO_TRUE" = "true" ]
RUN echo "That's the correct build arg, thanks! 👍"

View File

@@ -0,0 +1,2 @@
FROM alpine
RUN echo "This image doesn't use any local files, so it doesn't need a context parameter 👍"

View File

@@ -0,0 +1,3 @@
FROM bash AS base
RUN getent hosts metadata.google.internal

View File

@@ -0,0 +1,7 @@
FROM --platform=$BUILDPLATFORM alpine as build
RUN echo ${BUILDPLATFORM} > buildplatform
RUN echo ${TARGETPLATFORM} > targetplatform
FROM build
RUN cat buildplatform
RUN cat targetplatform

View File

@@ -0,0 +1,5 @@
# syntax=docker/dockerfile:1.4
FROM golang:latest
RUN version="$(go version)" && echo $version && [ "$version" = "go version go1.21.7 linux/amd64" ]
RUN echo "This image uses named contexts to pin golang:latest to a specific SHA 👍"

View File

@@ -0,0 +1,4 @@
FROM alpine
RUN --mount=type=secret,id=password [ "$(cat /run/secrets/password)" = "hunter2" ]

View File

@@ -0,0 +1,5 @@
FROM alpine
RUN apk add openssh-client
RUN --mount=type=ssh ssh-add -l

View File

@@ -0,0 +1,8 @@
FROM alpine as build-me
RUN echo 👍
FROM build-me as also-build-me
RUN echo 🤙
FROM build-me as dont-build-me
RUN [ "true" = "false" ]

237
go.mod
View File

@@ -4,24 +4,41 @@ go 1.21.7
require (
github.com/blang/semver v3.5.1+incompatible
github.com/pulumi/pulumi-go-provider v0.14.1-0.20240301190400-aeddefa8dc54
github.com/pulumi/pulumi-go-provider/integration v0.10.0
github.com/distribution/reference v0.5.0
github.com/docker/buildx v0.12.0-rc2.0.20240214233841-c9d1c41d206c
github.com/docker/cli v25.0.3+incompatible
github.com/docker/distribution v2.8.2+incompatible
github.com/docker/docker v25.0.2+incompatible
github.com/moby/buildkit v0.13.0-beta3.0.20240205165705-d6e142600ee5
github.com/moby/patternmatcher v0.6.0
github.com/muesli/reflow v0.3.0
github.com/otiai10/copy v1.14.0
github.com/pulumi/pulumi-go-provider v0.14.1-0.20240314105842-9fbffb634faf
github.com/pulumi/pulumi-go-provider/integration v0.10.1-0.20240314105842-9fbffb634faf
github.com/pulumi/pulumi-java/pkg v0.9.9
github.com/pulumi/pulumi/pkg/v3 v3.111.1
github.com/pulumi/pulumi/sdk/v3 v3.111.1
github.com/pulumi/pulumi/pkg/v3 v3.111.2-0.20240324200353-583e06df0c70
github.com/pulumi/pulumi/sdk/v3 v3.111.2-0.20240324200353-583e06df0c70
github.com/regclient/regclient v0.0.0-20240308005156-a7434cff9c6b
github.com/sirupsen/logrus v1.9.3
github.com/spf13/afero v1.9.5
github.com/stretchr/testify v1.8.4
github.com/tonistiigi/fsutil v0.0.0-20240301111122-7525a1af2bb5
go.uber.org/mock v0.3.0
google.golang.org/protobuf v1.33.0
gopkg.in/yaml.v3 v3.0.1
)
require (
cloud.google.com/go v0.110.10 // indirect
cloud.google.com/go v0.112.0 // indirect
cloud.google.com/go/compute v1.23.3 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v1.1.5 // indirect
cloud.google.com/go/kms v1.15.5 // indirect
cloud.google.com/go/logging v1.8.1 // indirect
cloud.google.com/go/logging v1.9.0 // indirect
cloud.google.com/go/longrunning v0.5.4 // indirect
cloud.google.com/go/storage v1.35.1 // indirect
cloud.google.com/go/storage v1.36.0 // indirect
dario.cat/mergo v1.0.0 // indirect
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
github.com/AlecAivazis/survey/v2 v2.3.7 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 // indirect
@@ -35,123 +52,163 @@ require (
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0 // indirect
github.com/BurntSushi/toml v1.2.1 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/Microsoft/hcsshim v0.11.4 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
github.com/agext/levenshtein v1.2.3 // indirect
github.com/alecthomas/chroma v0.10.0 // indirect
github.com/apparentlymart/go-cidr v1.1.0 // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
github.com/armon/go-metrics v0.4.0 // indirect
github.com/armon/go-metrics v0.4.1 // indirect
github.com/armon/go-radix v1.0.0 // indirect
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aws/aws-sdk-go v1.49.0 // indirect
github.com/aws/aws-sdk-go-v2 v1.24.0 // indirect
github.com/aws/aws-sdk-go-v2 v1.24.1 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 // indirect
github.com/aws/aws-sdk-go-v2/config v1.26.1 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.16.12 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 // indirect
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.7 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9 // indirect
github.com/aws/aws-sdk-go-v2/config v1.26.6 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.16.16 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.15 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.10 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.10 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.10 // indirect
github.com/aws/aws-sdk-go-v2/service/kms v1.27.5 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.47.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.48.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 // indirect
github.com/aws/smithy-go v1.19.0 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/ccojocar/zxcvbn-go v1.0.1 // indirect
github.com/cenkalti/backoff/v3 v3.2.2 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/charmbracelet/bubbles v0.16.1 // indirect
github.com/charmbracelet/bubbletea v0.24.2 // indirect
github.com/charmbracelet/glamour v0.6.0 // indirect
github.com/charmbracelet/lipgloss v0.7.1 // indirect
github.com/cheggaaa/pb v1.0.29 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/compose-spec/compose-go/v2 v2.0.0-rc.8 // indirect
github.com/containerd/console v1.0.4 // indirect
github.com/containerd/containerd v1.7.12 // indirect
github.com/containerd/continuity v0.4.2 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/ttrpc v1.2.2 // indirect
github.com/containerd/typeurl/v2 v2.1.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/deckarep/golang-set/v2 v2.5.0 // indirect
github.com/djherbis/times v1.5.0 // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/docker/cli-docs-tool v0.6.0 // indirect
github.com/docker/docker-credential-helpers v0.8.0 // indirect
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-metrics v0.0.1 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/edsrzf/mmap-go v1.1.0 // indirect
github.com/emicklei/go-restful/v3 v3.10.1 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/erikgeiser/promptkit v0.9.0 // indirect
github.com/ettle/strcase v0.1.1 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/frankban/quicktest v1.14.4 // indirect
github.com/fvbommel/sortorder v1.1.0 // indirect
github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.5.0 // indirect
github.com/go-git/go-git/v5 v5.11.0 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/logr v1.3.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/gofrs/uuid v4.3.1+incompatible // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.20.0 // indirect
github.com/go-openapi/swag v0.21.1 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/gofrs/uuid v4.2.0+incompatible // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v5 v5.1.0 // indirect
github.com/golang/glog v1.1.2 // indirect
github.com/golang/glog v1.2.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20230406165453-00490a63f317 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.4.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/google/wire v0.5.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/gorilla/css v1.0.0 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-hclog v1.2.2 // indirect
github.com/hashicorp/go-cty-funcs v0.0.0-20230405223818-a090f58aa992 // indirect
github.com/hashicorp/go-hclog v1.5.0 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-plugin v1.4.6 // indirect
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
github.com/hashicorp/go-plugin v1.6.0 // indirect
github.com/hashicorp/go-retryablehttp v0.7.2 // indirect
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 // indirect
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/hcl/v2 v2.18.0 // indirect
github.com/hashicorp/hcl/v2 v2.19.1 // indirect
github.com/hashicorp/vault/api v1.8.2 // indirect
github.com/hashicorp/vault/sdk v0.6.1 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/hexops/valast v1.4.4 // indirect
github.com/iancoleman/strcase v0.2.0 // indirect
github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/in-toto/in-toto-golang v0.5.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.17.4 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-localereader v0.0.1 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mattn/go-shellwords v1.0.12 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/microcosm-cc/bluemonday v1.0.21 // indirect
github.com/miekg/pkcs11 v1.1.1 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-ps v1.0.0 // indirect
@@ -159,20 +216,30 @@ require (
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/moby v23.0.3+incompatible // indirect
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/moby/locker v1.0.1 // indirect
github.com/moby/moby v25.0.4+incompatible // indirect
github.com/moby/spdystream v0.2.0 // indirect
github.com/moby/sys/mountinfo v0.7.1 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
github.com/moby/sys/signal v0.7.0 // indirect
github.com/moby/sys/user v0.1.0 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/natefinch/atomic v1.0.1 // indirect
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
github.com/opentracing/basictracer-go v1.1.0 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/petar-dambovaliev/aho-corasick v0.0.0-20230725210150-fb29fc3c913e // indirect
github.com/pgavlin/diff v0.0.0-20230503175810-113847418e2e // indirect
github.com/pgavlin/fx v0.1.6 // indirect
@@ -185,6 +252,10 @@ require (
github.com/pkg/term v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/prometheus/client_golang v1.16.0 // indirect
github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect
github.com/pulumi/appdash v0.0.0-20231130102222-75f619a67231 // indirect
github.com/pulumi/esc v0.6.2 // indirect
github.com/pulumi/pulumi-yaml v1.6.0 // indirect
@@ -193,66 +264,92 @@ require (
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/ryanuber/go-glob v1.0.0 // indirect
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 // indirect
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect
github.com/segmentio/asm v1.2.0 // indirect
github.com/segmentio/encoding v0.3.6 // indirect
github.com/santhosh-tekuri/jsonschema/v5 v5.0.0 // indirect
github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect
github.com/segmentio/asm v1.1.3 // indirect
github.com/segmentio/encoding v0.3.5 // indirect
github.com/sergi/go-diff v1.3.1 // indirect
github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002 // indirect
github.com/shibumi/go-pathspec v1.3.0 // indirect
github.com/shirou/gopsutil/v3 v3.22.3 // indirect
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 // indirect
github.com/skeema/knownhosts v1.2.1 // indirect
github.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67 // indirect
github.com/spf13/afero v1.9.5 // indirect
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/cobra v1.7.0 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/cobra v1.8.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/texttheater/golang-levenshtein v1.0.1 // indirect
github.com/theupdateframework/notary v0.7.0 // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.4.0 // indirect
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531 // indirect
github.com/tweekmonster/luser v0.0.0-20161003172636-3fa38070dbd7 // indirect
github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect
github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
github.com/ulikunitz/xz v0.5.11 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/yuin/goldmark v1.5.2 // indirect
github.com/yuin/goldmark-emoji v1.0.1 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
github.com/zclconf/go-cty v1.14.0 // indirect
github.com/zclconf/go-cty v1.14.1 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/otel v1.19.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.45.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect
go.opentelemetry.io/otel v1.21.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 // indirect
go.opentelemetry.io/otel/metric v1.19.0 // indirect
go.opentelemetry.io/otel/sdk v1.19.0 // indirect
go.opentelemetry.io/otel/trace v1.19.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 // indirect
go.opentelemetry.io/otel/exporters/prometheus v0.42.0 // indirect
go.opentelemetry.io/otel/metric v1.21.0 // indirect
go.opentelemetry.io/otel/sdk v1.21.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.19.0 // indirect
go.opentelemetry.io/otel/trace v1.21.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
go.pennock.tech/tabular v1.1.3 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
gocloud.dev v0.36.0 // indirect
gocloud.dev/secrets/hashivault v0.27.0 // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect
gocloud.dev/secrets/hashivault v0.28.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/oauth2 v0.14.0 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/term v0.15.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/oauth2 v0.16.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.4.0 // indirect
golang.org/x/tools v0.15.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.17.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/api v0.151.0 // indirect
google.golang.org/api v0.155.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect
google.golang.org/grpc v1.59.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect
google.golang.org/grpc v1.62.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/api v0.26.7 // indirect
k8s.io/apimachinery v0.26.7 // indirect
k8s.io/apiserver v0.26.7 // indirect
k8s.io/client-go v0.26.7 // indirect
k8s.io/klog/v2 v2.90.1 // indirect
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 // indirect
lukechampine.com/frand v1.4.2 // indirect
mvdan.cc/gofumpt v0.5.0 // indirect
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)

1184
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
// Copyright 2016-2023, Pulumi Corporation.
// Copyright 2024, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,13 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package main invokes the provider as a gRPC server and runs forever.
package main
import (
p "github.com/pulumi/pulumi-go-provider"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/cmdutil"
xyz "github.com/pulumi/pulumi-dockerbuild/provider"
"github.com/pulumi/pulumi-dockerbuild/provider"
)
// Serve the provider against Pulumi's Provider protocol.
func main() { _ = p.RunProvider(xyz.Name, xyz.Version, xyz.Provider()) }
func main() {
err := provider.Serve()
if err != nil {
cmdutil.ExitError(err.Error())
}
}

File diff suppressed because one or more lines are too long

16
provider/doc.go Normal file
View File

@@ -0,0 +1,16 @@
// Copyright 2024, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package provider serves a Docker Buildx Pulumi provider.
package provider

31
provider/internal/auth.go Normal file
View File

@@ -0,0 +1,31 @@
// Copyright 2024, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package internal
import "github.com/pulumi/pulumi-go-provider/infer"
// Registry contains credentials for authenticating with a remote registry.
type Registry struct {
Address string `pulumi:"address"`
Password string `pulumi:"password,optional" provider:"secret"`
Username string `pulumi:"username,optional"`
}
// Annotate sets docstrings on Registry.
func (r *Registry) Annotate(a infer.Annotator) {
a.Describe(&r.Address, `The registry's address (e.g. "docker.io").`)
a.Describe(&r.Username, `Username for the registry.`)
a.Describe(&r.Password, `Password or token for the registry.`)
}

View File

@@ -0,0 +1,38 @@
// Copyright 2024, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package internal
import (
"github.com/pulumi/pulumi-go-provider/infer"
)
var _ = (infer.Annotated)((*BuilderConfig)(nil))
// BuilderConfig configures the builder to use for an image build.
type BuilderConfig struct {
Name string `pulumi:"name,optional"`
}
// Annotate sets docstrings on BuilderConfig.
func (b *BuilderConfig) Annotate(a infer.Annotator) {
a.Describe(&b.Name, dedent(`
Name of an existing buildx builder to use.
Only "docker-container", "kubernetes", or "remote" drivers are
supported. The legacy "docker" driver is not supported.
Equivalent to Docker's "--builder" flag.
`))
}

743
provider/internal/cache.go Normal file
View File

@@ -0,0 +1,743 @@
// Copyright 2024, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package internal
import (
"fmt"
"strings"
controllerapi "github.com/docker/buildx/controller/pb"
"github.com/docker/buildx/util/buildflags"
"github.com/pulumi/pulumi-go-provider/infer"
)
var (
_ = (fmt.Stringer)((*CacheFrom)(nil))
_ = (fmt.Stringer)((*CacheFromAzureBlob)(nil))
_ = (fmt.Stringer)((*CacheFromGitHubActions)(nil))
_ = (fmt.Stringer)((*CacheFromLocal)(nil))
_ = (fmt.Stringer)((*CacheFromRegistry)(nil))
_ = (fmt.Stringer)((*CacheFromS3)(nil))
_ = (fmt.Stringer)((*CacheTo)(nil))
_ = (fmt.Stringer)((*CacheToAzureBlob)(nil))
_ = (fmt.Stringer)((*CacheToGitHubActions)(nil))
_ = (fmt.Stringer)((*CacheToInline)(nil))
_ = (fmt.Stringer)((*CacheToLocal)(nil))
_ = (fmt.Stringer)((*CacheToRegistry)(nil))
_ = (fmt.Stringer)((*CacheToS3)(nil))
_ = (fmt.Stringer)(CacheWithCompression{})
_ = (fmt.Stringer)(CacheWithIgnoreError{})
_ = (fmt.Stringer)(CacheWithMode{})
_ = (fmt.Stringer)(CacheWithOCI{})
_ = (infer.Annotated)((*CacheFrom)(nil))
_ = (infer.Annotated)((*CacheFromAzureBlob)(nil))
_ = (infer.Annotated)((*CacheFromGitHubActions)(nil))
_ = (infer.Annotated)((*CacheFromLocal)(nil))
_ = (infer.Annotated)((*CacheFromRegistry)(nil))
_ = (infer.Annotated)((*CacheFromS3)(nil))
_ = (infer.Annotated)((*CacheTo)(nil))
_ = (infer.Annotated)((*CacheToInline)(nil))
_ = (infer.Annotated)((*CacheToLocal)(nil))
_ = (infer.Annotated)((*CacheWithCompression)(nil))
_ = (infer.Annotated)((*CacheWithIgnoreError)(nil))
_ = (infer.Annotated)((*CacheWithMode)(nil))
_ = (infer.Annotated)((*CacheWithOCI)(nil))
_ = (infer.Enum[CacheMode])((*CacheMode)(nil))
_ = (infer.Enum[CompressionType])((*CompressionType)(nil))
)
// CacheFromLocal pulls cache manifests from a local directory.
type CacheFromLocal struct {
Src string `pulumi:"src"`
Digest string `pulumi:"digest,optional"`
}
// String returns the CLI-encoded value of these cache options, or an empty
// string if the receiver is nil.
func (c *CacheFromLocal) String() string {
if c == nil {
return ""
}
parts := []string{"type=local"}
if c.Src != "" {
parts = append(parts, fmt.Sprintf("src=%s", c.Src))
}
if c.Digest != "" {
parts = append(parts, fmt.Sprintf("digest=%s", c.Digest))
}
return strings.Join(parts, ",")
}
// Annotate sets docstrings on CacheFromLocal.
func (c *CacheFromLocal) Annotate(a infer.Annotator) {
a.Describe(&c.Src, "Path of the local directory where cache gets imported from.")
a.Describe(&c.Digest, "Digest of manifest to import.")
}
// CacheFromRegistry pulls cache manifests from a registry ref.
type CacheFromRegistry struct {
Ref string `pulumi:"ref"`
}
// Annotate sets docstrings on CacheFromRegistry.
func (c *CacheFromRegistry) Annotate(a infer.Annotator) {
a.Describe(&c.Ref, "Fully qualified name of the cache image to import.")
}
// String returns the CLI-encoded value of these cache options, or an empty
// string if the receiver is nil.
func (c *CacheFromRegistry) String() string {
if c == nil {
return ""
}
return fmt.Sprintf("type=registry,ref=%s", c.Ref)
}
// CacheWithOCI exposes OCI media type options.
type CacheWithOCI struct {
OCI *bool `pulumi:"ociMediaTypes,optional"`
ImageManifest *bool `pulumi:"imageManifest,optional"`
}
// Annotate sets docstrings on CacheWithOCI.
func (c *CacheWithOCI) Annotate(a infer.Annotator) {
a.Describe(&c.OCI, dedent(`
Whether to use OCI media types in exported manifests. Defaults to
"true".
`))
a.Describe(&c.ImageManifest, dedent(`
Export cache manifest as an OCI-compatible image manifest instead of a
manifest list. Requires "ociMediaTypes" to also be "true".
Some registries like AWS ECR will not work with caching if this is
"false".
Defaults to "false" to match Docker's default behavior.
`))
a.SetDefault(&c.OCI, true)
a.SetDefault(&c.ImageManifest, false)
}
// String returns the CLI-encoded value of these cache options, or an empty
// string if unknown.
func (c CacheWithOCI) String() string {
if c.OCI == nil {
return ""
}
parts := []string{fmt.Sprintf("oci-mediatypes=%t", *c.OCI)}
if c.ImageManifest != nil {
parts = append(parts, fmt.Sprintf("image-manifest=%t", *c.ImageManifest))
}
return strings.Join(parts, ",")
}
// CacheFromGitHubActions pulls cache manifests from the GitHub actions cache.
type CacheFromGitHubActions struct {
URL string `pulumi:"url,optional"`
Token string `pulumi:"token,optional" provider:"secret"`
Scope string `pulumi:"scope,optional"`
}
// Annotate sets docstrings on CacheFromGitHubActions.
func (c *CacheFromGitHubActions) Annotate(a infer.Annotator) {
a.SetDefault(&c.URL, "", "ACTIONS_RUNTIME_URL")
a.SetDefault(&c.Token, "", "ACTIONS_RUNTIME_TOKEN")
a.SetDefault(&c.Scope, "", "buildkit")
a.Describe(&c.URL, dedent(`
The cache server URL to use for artifacts.
Defaults to "$ACTIONS_RUNTIME_URL", although a separate action like
"crazy-max/ghaction-github-runtime" is recommended to expose this
environment variable to your jobs.
`))
a.Describe(&c.Token, dedent(`
The GitHub Actions token to use. This is not a personal access tokens
and is typically generated automatically as part of each job.
Defaults to "$ACTIONS_RUNTIME_TOKEN", although a separate action like
"crazy-max/ghaction-github-runtime" is recommended to expose this
environment variable to your jobs.
`))
a.Describe(&c.Scope, dedent(`
The scope to use for cache keys. Defaults to "buildkit".
This should be set if building and caching multiple images in one
workflow, otherwise caches will overwrite each other.
`))
}
func (c *CacheFromGitHubActions) String() string {
if c == nil {
return ""
}
parts := []string{"type=gha"}
if c.Scope != "" {
parts = append(parts, fmt.Sprintf("scope=%s", c.Scope))
}
if c.Token != "" {
parts = append(parts, fmt.Sprintf("token=%s", c.Token))
}
if c.URL != "" {
parts = append(parts, fmt.Sprintf("url=%s", c.URL))
}
return strings.Join(parts, ",")
}
// CacheFromAzureBlob pulls cache manifests from Azure
// blob storage.
type CacheFromAzureBlob struct {
Name string `pulumi:"name"`
AccountURL string `pulumi:"accountUrl,optional"`
SecretAccessKey string `pulumi:"secretAccessKey,optional" provider:"secret"`
}
// String returns the CLI-encoded value of these cache options, or an empty
// string if the receiver is nil.
func (c *CacheFromAzureBlob) String() string {
if c == nil {
return ""
}
parts := []string{"type=azblob"}
if c.Name != "" {
parts = append(parts, fmt.Sprintf("name=%s", c.Name))
}
if c.AccountURL != "" {
parts = append(parts, fmt.Sprintf("account_url=%s", c.AccountURL))
}
if c.SecretAccessKey != "" {
parts = append(parts, fmt.Sprintf("secret_access_key=%s", c.SecretAccessKey))
}
return strings.Join(parts, ",")
}
// Annotate sets docstrings on CacheFromAzureBlob.
func (c *CacheFromAzureBlob) Annotate(a infer.Annotator) {
a.Describe(&c.Name, "The name of the cache image.")
a.Describe(&c.AccountURL, "Base URL of the storage account.")
a.Describe(&c.SecretAccessKey, "Blob storage account key.")
}
// CacheToAzureBlob pushes cache manifests to Azure blob storage.
type CacheToAzureBlob struct {
CacheWithMode
CacheWithIgnoreError
CacheFromAzureBlob
}
func (c *CacheToAzureBlob) String() string {
if c == nil {
return ""
}
return join(&c.CacheFromAzureBlob, c.CacheWithMode, c.CacheWithIgnoreError)
}
// CacheFromS3 pulls cache manifests from S3-compatible APIs.
type CacheFromS3 struct {
Region string `pulumi:"region"`
Bucket string `pulumi:"bucket"`
Name string `pulumi:"name,optional"`
EndpointURL string `pulumi:"endpointUrl,optional"`
BlobsPrefix string `pulumi:"blobsPrefix,optional"`
ManifestsPrefix string `pulumi:"manifestsPrefix,optional"`
UsePathStyle *bool `pulumi:"usePathStyle,optional"`
AccessKeyID string `pulumi:"accessKeyId,optional"`
SecretAccessKey string `pulumi:"secretAccessKey,optional" provider:"secret"`
SessionToken string `pulumi:"sessionToken,optional" provider:"secret"`
}
// Annotate sets docstrings and defaults on CacheFromS3.
func (c *CacheFromS3) Annotate(a infer.Annotator) {
a.SetDefault(&c.Region, "", "AWS_REGION")
a.SetDefault(&c.AccessKeyID, "", "AWS_ACCESS_KEY_ID")
a.SetDefault(&c.SecretAccessKey, "", "AWS_SECRET_ACCESS_KEY")
a.SetDefault(&c.SessionToken, "", "AWS_SESSION_TOKEN")
a.Describe(&c.Bucket, dedent(`
Name of the S3 bucket.
`))
a.Describe(&c.Region, dedent(`
The geographic location of the bucket. Defaults to "$AWS_REGION".
`))
a.Describe(&c.AccessKeyID, dedent(`
Defaults to "$AWS_ACCESS_KEY_ID".
`))
a.Describe(&c.SecretAccessKey, dedent(`
Defaults to "$AWS_SECRET_ACCESS_KEY".
`))
a.Describe(&c.SessionToken, dedent(`
Defaults to "$AWS_SESSION_TOKEN".
`))
a.Describe(&c.BlobsPrefix, dedent(`
Prefix to prepend to blob filenames.
`))
a.Describe(&c.EndpointURL, dedent(`
Endpoint of the S3 bucket.
`))
a.Describe(&c.ManifestsPrefix, dedent(`
Prefix to prepend on manifest filenames.
`))
a.Describe(&c.Name, dedent(`
Name of the cache image.
`))
a.Describe(&c.UsePathStyle, dedent(`
Uses "bucket" in the URL instead of hostname when "true".
`))
}
// String returns the CLI-encoded value of these cache options, or an empty
// string if the receiver is nil.
func (c *CacheFromS3) String() string {
if c == nil {
return ""
}
parts := []string{"type=s3"}
if c.Bucket != "" {
parts = append(parts, fmt.Sprintf("bucket=%s", c.Bucket))
}
if c.Name != "" {
parts = append(parts, fmt.Sprintf("name=%s", c.Name))
}
if c.EndpointURL != "" {
parts = append(parts, fmt.Sprintf("endpoint_url=%s", c.EndpointURL))
}
if c.BlobsPrefix != "" {
parts = append(parts, fmt.Sprintf("blobs_prefix=%s", c.BlobsPrefix))
}
if c.ManifestsPrefix != "" {
parts = append(parts, fmt.Sprintf("manifests_prefix=%s", c.ManifestsPrefix))
}
if c.UsePathStyle != nil {
parts = append(parts, fmt.Sprintf("use_path_type=%t", *c.UsePathStyle))
}
if c.AccessKeyID != "" {
parts = append(parts, fmt.Sprintf("access_key_id=%s", c.AccessKeyID))
}
if c.SecretAccessKey != "" {
parts = append(parts, fmt.Sprintf("secret_access_key=%s", c.SecretAccessKey))
}
if c.SessionToken != "" {
parts = append(parts, fmt.Sprintf("session_token=%s", c.SessionToken))
}
return strings.Join(parts, ",")
}
// CacheWithMode is a cache that can configure its mode.
type CacheWithMode struct {
Mode CacheMode `pulumi:"mode,optional"`
}
// Annotate sets docstrings and defaults on CacheWithMode.
func (c *CacheWithMode) Annotate(a infer.Annotator) {
a.SetDefault(&c.Mode, Min)
a.Describe(&c.Mode, dedent(`
The cache mode to use. Defaults to "min".
`))
}
func (c CacheWithMode) String() string {
if c.Mode == "" {
return ""
}
return fmt.Sprintf("mode=%s", c.Mode)
}
// CacheWithIgnoreError exposes an option to ignore errors during caching.
type CacheWithIgnoreError struct {
IgnoreError *bool `pulumi:"ignoreError,optional"`
}
// Annotate sets docstrings and defaults on CacheWithIgnoreError.
func (c *CacheWithIgnoreError) Annotate(a infer.Annotator) {
a.SetDefault(&c.IgnoreError, false)
a.Describe(&c.IgnoreError, "Ignore errors caused by failed cache exports.")
}
func (c CacheWithIgnoreError) String() string {
if c.IgnoreError == nil {
return ""
}
return fmt.Sprintf("ignore-error=%t", *c.IgnoreError)
}
// CacheToS3 pushes cache manifests to an S3-compatible API.
type CacheToS3 struct {
CacheWithMode
CacheWithIgnoreError
CacheFromS3
}
// String returns the CLI-encoded value of these cache options, or an empty
// string if the receiver is nil.
func (c *CacheToS3) String() string {
if c == nil {
return ""
}
return join(&c.CacheFromS3, c.CacheWithMode, c.CacheWithIgnoreError)
}
// Raw is a CLI-encoded cache entry appropriate for passing directly to the
// CLI. Useful if the Docker backend supports cache types not captured by our
// API, or if the user just prefers "type=..." inputs.
type Raw string
// String return the raw string as-is. This can be empty during previews where
// the user has provided a value but it is unknown.
func (c Raw) String() string {
return string(c)
}
// CacheFrom is a "union" type for all of our available `--cache-from` options.
type CacheFrom struct {
Local *CacheFromLocal `pulumi:"local,optional"`
Registry *CacheFromRegistry `pulumi:"registry,optional"`
GHA *CacheFromGitHubActions `pulumi:"gha,optional"`
AZBlob *CacheFromAzureBlob `pulumi:"azblob,optional"`
S3 *CacheFromS3 `pulumi:"s3,optional"`
Raw Raw `pulumi:"raw,optional"`
Disabled bool `pulumi:"disabled,optional"`
}
// Annotate sets docstrings and defaults on CacheFrom.
func (c *CacheFrom) Annotate(a infer.Annotator) {
a.Describe(&c.Local, dedent(`
A simple backend which caches images on your local filesystem.
`))
a.Describe(&c.Registry, dedent(`
Upload build caches to remote registries.
`))
a.Describe(&c.GHA, dedent(`
Recommended for use with GitHub Actions workflows.
An action like "crazy-max/ghaction-github-runtime" is recommended to
expose appropriate credentials to your GitHub workflow.
`))
a.Describe(&c.AZBlob, dedent(`
Upload build caches to Azure's blob storage service.
`))
a.Describe(&c.S3, dedent(`
Upload build caches to AWS S3 or an S3-compatible services such as
MinIO.
`))
a.Describe(&c.Raw, dedent(`
A raw string as you would provide it to the Docker CLI (e.g.,
"type=inline").
`))
a.Describe(&c.Disabled, dedent(`
When "true" this entry will be excluded. Defaults to "false".
`))
}
// String returns a CLI-encoded value for this `--cache-from` entry, or an
// empty string if disabled. `validate` should be called to ensure only one
// entry was set.
func (c CacheFrom) String() string {
if c.Disabled {
return ""
}
return join(c.Local, c.Registry, c.GHA, c.AZBlob, c.S3, c.Raw)
}
func (c CacheFrom) validate(preview bool) (*controllerapi.CacheOptionsEntry, error) {
if strings.Count(c.String(), "type=") > 1 {
return nil, fmt.Errorf("cacheFrom should only specify one cache type")
}
parsed, err := buildflags.ParseCacheEntry([]string{c.String()})
if err != nil {
return nil, err
}
if len(parsed) == 0 {
// This can happen for example if we have a GHA cache but no GitHub
// environment variables set.
// Shouldn't happen...
return nil, nil
}
return parsed[0], nil
}
// CacheToInline embeds cache information directly into an image.
type CacheToInline struct{}
// String returns the CLI-encoded value of these cache options, or an empty
// string if unknown.
func (c *CacheToInline) String() string {
if c == nil {
return ""
}
return "type=inline"
}
// Annotate sets docstrings on CacheToInline.
func (c *CacheToInline) Annotate(a infer.Annotator) {
a.Describe(&c, dedent(`
Include an inline cache with the exported image.
`))
}
// CacheToLocal writes cache manifests to a local directory.
type CacheToLocal struct {
CacheWithCompression
CacheWithIgnoreError
CacheWithMode
Dest string `pulumi:"dest"`
}
// Annotate sets docstrings on CacheToLocal.
func (c *CacheToLocal) Annotate(a infer.Annotator) {
a.Describe(&c.Dest, dedent(`
Path of the local directory to export the cache.
`))
}
// String returns the CLI-encoded value of these cache options, or an empty
// string if the receiver is nil.
func (c *CacheToLocal) String() string {
if c == nil {
return ""
}
return join(
Raw(fmt.Sprintf("type=local,dest=%s", c.Dest)),
c.CacheWithCompression,
c.CacheWithIgnoreError,
)
}
// CacheToRegistry pushes cache manifests to a remote registry.
type CacheToRegistry struct {
CacheWithMode
CacheWithIgnoreError
CacheWithOCI
CacheWithCompression
CacheFromRegistry
}
// String returns the CLI-encoded value of these cache options, or an empty
// string if the receiver is nil.
func (c *CacheToRegistry) String() string {
if c == nil {
return ""
}
return join(
&c.CacheFromRegistry,
c.CacheWithMode,
c.CacheWithIgnoreError,
c.CacheWithOCI,
c.CacheWithCompression,
)
}
// CacheWithCompression is a cache with options to configure compression
// settings.
type CacheWithCompression struct {
Compression CompressionType `pulumi:"compression,optional"`
CompressionLevel int `pulumi:"compressionLevel,optional"`
ForceCompression *bool `pulumi:"forceCompression,optional"`
}
// Annotate sets docstrings and defaults on CacheWithCompression.
func (c *CacheWithCompression) Annotate(a infer.Annotator) {
a.SetDefault(&c.Compression, Gzip)
a.SetDefault(&c.CompressionLevel, 0)
a.SetDefault(&c.ForceCompression, false)
a.Describe(&c.Compression, "The compression type to use.")
a.Describe(&c.CompressionLevel, "Compression level from 0 to 22.")
a.Describe(&c.ForceCompression, "Forcefully apply compression.")
}
// String returns the CLI-encoded value of these cache options, or an empty
// string if the receiver is nil.
func (c CacheWithCompression) String() string {
if c.CompressionLevel == 0 {
return ""
}
parts := []string{}
if c.Compression != "" {
parts = append(parts, fmt.Sprintf("compression=%s", c.Compression))
}
if c.CompressionLevel > 0 {
cl := c.CompressionLevel
if cl > 22 {
cl = 22
}
parts = append(parts, fmt.Sprintf("compression-level=%d", cl))
}
if c.ForceCompression != nil {
parts = append(parts, fmt.Sprintf("force-compression=%t", *c.ForceCompression))
}
return strings.Join(parts, ",")
}
// CacheToGitHubActions pushes cache manifests to the GitHub Actions cache
// backend.
type CacheToGitHubActions struct {
CacheWithMode
CacheWithIgnoreError
CacheFromGitHubActions
}
// String returns the CLI-encoded value of these cache options, or an empty
// string if the receiver is nil.
func (c *CacheToGitHubActions) String() string {
if c == nil {
return ""
}
return join(&c.CacheFromGitHubActions, c.CacheWithMode, c.CacheWithIgnoreError)
}
// CacheTo is a "union" type for all of our available `--cache-to` options.
type CacheTo struct {
Inline *CacheToInline `pulumi:"inline,optional"`
Local *CacheToLocal `pulumi:"local,optional"`
Registry *CacheToRegistry `pulumi:"registry,optional"`
GHA *CacheToGitHubActions `pulumi:"gha,optional"`
AZBlob *CacheToAzureBlob `pulumi:"azblob,optional"`
S3 *CacheToS3 `pulumi:"s3,optional"`
Raw Raw `pulumi:"raw,optional"`
Disabled bool `pulumi:"disabled,optional"`
}
// Annotate sets docstrings and defaults on CacheTo.
func (c *CacheTo) Annotate(a infer.Annotator) {
a.Describe(&c.Inline, dedent(`
The inline cache storage backend is the simplest implementation to get
started with, but it does not handle multi-stage builds. Consider the
"registry" cache backend instead.
`))
a.Describe(&c.Local, dedent(`
A simple backend which caches imagines on your local filesystem.
`))
a.Describe(&c.Registry, dedent(`
Push caches to remote registries. Incompatible with the "docker" build
driver.
`))
a.Describe(&c.GHA, dedent(`
Recommended for use with GitHub Actions workflows.
An action like "crazy-max/ghaction-github-runtime" is recommended to
expose appropriate credentials to your GitHub workflow.
`))
a.Describe(&c.AZBlob, dedent(`
Push cache to Azure's blob storage service.
`))
a.Describe(&c.S3, dedent(`
Push cache to AWS S3 or S3-compatible services such as MinIO.
`))
a.Describe(&c.Raw, dedent(`
A raw string as you would provide it to the Docker CLI (e.g.,
"type=inline")`,
))
a.Describe(&c.Disabled, dedent(`
When "true" this entry will be excluded. Defaults to "false".
`))
}
// String returns a CLI-encoded value for this `--cache-to` entry, or an
// empty string if disabled. `validate` should be called to ensure only one
// entry was set.
func (c CacheTo) String() string {
if c.Disabled {
return ""
}
return join(c.Inline, c.Local, c.Registry, c.GHA, c.AZBlob, c.S3, c.Raw)
}
func (c CacheTo) validate(preview bool) (*controllerapi.CacheOptionsEntry, error) {
if strings.Count(c.String(), "type=") > 1 {
return nil, fmt.Errorf("cacheTo should only specify one cache type")
}
parsed, err := buildflags.ParseCacheEntry([]string{c.String()})
if err != nil {
return nil, err
}
if len(parsed) == 0 {
// This can happen for example if we have a GHA cache but no GitHub
// environment variables set.
// Shouldn't happen...
return nil, nil
}
return parsed[0], nil
}
// CacheMode controls the complexity of exported cache manifests.
type CacheMode string
const (
Min CacheMode = "min" // Min cache mode.
Max CacheMode = "max" // Max cache mode.
)
// Values returns all valid CacheMode values for SDK generation.
func (CacheMode) Values() []infer.EnumValue[CacheMode] {
return []infer.EnumValue[CacheMode]{
{
Value: Min,
Description: "Only layers that are exported into the resulting image are cached.",
},
{
Value: Max,
Description: "All layers are cached, even those of intermediate steps.",
},
}
}
// CompressionType is the algorithm used for compressing blobs.
type CompressionType string
const (
Gzip CompressionType = "gzip" // Gzip compression.
Estargz CompressionType = "estargz" // Estargz compression.
Zstd CompressionType = "zstd" // Zstd compression.
)
// Values returns all valid CompressionType values for SDK generation.
func (CompressionType) Values() []infer.EnumValue[CompressionType] {
return []infer.EnumValue[CompressionType]{
{Value: Gzip, Description: "Use `gzip` for compression."},
{Value: Estargz, Description: "Use `estargz` for compression."},
{Value: Zstd, Description: "Use `zstd` for compression."},
}
}
type joiner struct{ sep string }
func (j joiner) join(ss ...fmt.Stringer) string {
parts := []string{}
for _, s := range ss {
p := s.String()
if p == "" {
continue
}
parts = append(parts, p)
}
return strings.Join(parts, j.sep)
}
func join(ss ...fmt.Stringer) string {
return joiner{","}.join(ss...)
}

View File

@@ -0,0 +1,133 @@
// Copyright 2024, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package internal
import (
"fmt"
"testing"
"github.com/docker/buildx/util/buildflags"
"github.com/stretchr/testify/assert"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func TestCacheString(t *testing.T) {
t.Parallel()
tests := []struct {
name string
given fmt.Stringer
want string
}{
{
name: "s3",
given: CacheTo{S3: &CacheToS3{
CacheFromS3: CacheFromS3{
Region: "us-west-2",
Bucket: "bucket-foo",
Name: "myname",
EndpointURL: "https://some.endpoint",
BlobsPrefix: "blob-prefix",
ManifestsPrefix: "manifest-prefix",
UsePathStyle: pulumi.BoolRef(true),
AccessKeyID: "access-key-id",
SecretAccessKey: "secret-key",
SessionToken: "session",
},
}},
//nolint:lll
want: "type=s3,bucket=bucket-foo,name=myname,endpoint_url=https://some.endpoint,blobs_prefix=blob-prefix,manifests_prefix=manifest-prefix,use_path_type=true,access_key_id=access-key-id,secret_access_key=secret-key,session_token=session",
},
{
name: "gha",
given: CacheTo{GHA: &CacheToGitHubActions{}},
want: "type=gha",
},
{
name: "from-local",
given: CacheFrom{Local: &CacheFromLocal{Src: "/foo/bar"}},
want: "type=local,src=/foo/bar",
},
{
name: "to-local",
given: CacheTo{Local: &CacheToLocal{Dest: "/foo/bar"}},
want: "type=local,dest=/foo/bar",
},
{
name: "inline",
given: CacheTo{Inline: &CacheToInline{}},
want: "type=inline",
},
{
name: "raw",
given: CacheTo{Raw: Raw("type=gha")},
want: "type=gha",
},
{
name: "compression",
given: CacheTo{Local: &CacheToLocal{
Dest: "/foo",
CacheWithCompression: CacheWithCompression{
Compression: "gz2",
CompressionLevel: 100,
ForceCompression: pulumi.BoolRef(true),
},
}},
want: "type=local,dest=/foo,compression=gz2,compression-level=22,force-compression=true",
},
{
name: "ignore-error",
given: CacheTo{
AZBlob: &CacheToAzureBlob{CacheWithIgnoreError: CacheWithIgnoreError{pulumi.BoolRef(true)}},
},
want: "type=azblob,ignore-error=true",
},
{
name: "oci",
given: CacheTo{
Registry: &CacheToRegistry{
CacheFromRegistry: CacheFromRegistry{Ref: "docker.io/foo/bar:baz"},
CacheWithOCI: CacheWithOCI{OCI: pulumi.BoolRef(true), ImageManifest: pulumi.BoolRef(true)},
},
},
want: "type=registry,ref=docker.io/foo/bar:baz,oci-mediatypes=true,image-manifest=true",
},
{
name: "disabled-to",
given: CacheTo{
Raw: Raw("type=gha"),
Disabled: true,
},
want: "",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
actual := tt.given.String()
assert.Equal(t, tt.want, actual)
if tt.want != "" {
// Our output should be parsable by Docker.
_, err := buildflags.ParseCacheEntry([]string{actual})
assert.NoError(t, err)
}
})
}
}

379
provider/internal/cli.go Normal file
View File

@@ -0,0 +1,379 @@
// Copyright 2024, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package internal
import (
"bufio"
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/docker/buildx/commands"
"github.com/docker/cli/cli-plugins/manager"
"github.com/docker/cli/cli/command"
cfgtypes "github.com/docker/cli/cli/config/types"
"github.com/docker/cli/cli/streams"
"github.com/moby/buildkit/client"
cp "github.com/otiai10/copy"
"github.com/regclient/regclient"
"github.com/regclient/regclient/config"
provider "github.com/pulumi/pulumi-go-provider"
"github.com/pulumi/pulumi/sdk/v3/go/common/diag"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
)
// cli wraps a DockerCLI instance with scoped auth credentials. It satisfies
// the Cli interface so it can be used with Docker's cobra.Commands directly.
//
// It buffers stdout/stderr, and layers temporary auth configs on top of the
// host's existing auth.
type cli struct {
command.Cli
auths map[string]cfgtypes.AuthConfig
host *host
in string // stdin
r, w *os.File // stdout
err bytes.Buffer // stderr
done chan struct{} // signaled when all logs have been forwarded to the engine.
}
// wrap creates a new cli client with auth configs layered on top of our host's
// auth.
func wrap(host *host, registries ...Registry) (*cli, error) {
// We need to create a new DockerCLI instance because we don't want the
// auth changes we make to the ConfigFile to leak to the host.
docker, err := newDockerCLI(host.config)
if err != nil {
return nil, err
}
auths := map[string]cfgtypes.AuthConfig{}
for k, v := range host.auths {
auths[k] = v
}
for _, r := range registries {
// HostNewName takes care of DockerHub's special-casing for us.
h := config.HostNewName(r.Address)
auths[h.CredHost] = cfgtypes.AuthConfig{
ServerAddress: h.Hostname,
Username: r.Username,
Password: r.Password,
}
}
// Override our config's auth and disable any credential helpers. Auth
// lookups will now only return whatever we have in memory.
cfg := docker.ConfigFile()
cfg.AuthConfigs = auths
cfg.CredentialHelpers = nil
cfg.CredentialsStore = ""
r, w, err := os.Pipe()
if err != nil {
return nil, err
}
wrapped := &cli{
Cli: docker,
host: host,
auths: auths,
r: r,
w: w,
}
return wrapped, nil
}
func (c *cli) In() *streams.In {
return streams.NewIn(io.NopCloser(strings.NewReader(c.in)))
}
func (c *cli) Out() *streams.Out {
return streams.NewOut(c.w)
}
func (c *cli) Err() io.Writer {
return &c.err
}
// rc returns a registry client with matching auth.
func (c *cli) rc() *regclient.RegClient {
hosts := []config.Host{}
for k, v := range c.auths {
h := config.HostNewName(k)
h.User = v.Username
h.Pass = v.Password
hosts = append(hosts, *h)
}
return regclient.New(
regclient.WithConfigHost(hosts...),
)
}
// tail is meant to be called as a goroutine and will pipe output from the CLI
// back to the Pulumi engine. Requires a corresponding call to close.
func (c *cli) tail(ctx provider.Context) {
c.done = make(chan struct{}, 1)
defer func() {
c.done <- struct{}{}
if err := recover(); err != nil {
fmt.Fprintf(os.Stderr, "recovered: %s\n", err)
}
}()
s := bufio.NewScanner(c.r)
for s.Scan() {
ctx.LogStatus(diag.Info, s.Text())
}
ctx.LogStatus(diag.Info, "") // clear confusing "DONE" statements.
}
// close flushes any outstanding logs and cleans up resources.
func (c *cli) Close() error {
err := c.w.Close()
err = errors.Join(err, c.r.Close())
if c.done != nil {
<-c.done
}
return err
}
// execBuild performs a build by os.Exec'ing the docker-buildx binary.
// Credentials are communicated to docker-buildx via a temporary directory.
// Secrets are communicated via dynamic environment variables.
func (c *cli) execBuild(b Build) (*client.SolveResponse, error) {
// Setup a temporary directory for auth, and clean it up when we're done.
tmp, err := os.MkdirTemp("", "pulumi-docker-")
if err != nil {
return nil, err
}
defer contract.IgnoreError(os.RemoveAll(tmp))
opts := b.BuildOptions()
builder, err := c.host.builderFor(b)
if err != nil {
return nil, err
}
// Docker expects a "$DOCKER_CONFIG/contexts" directory in addition to
// "$DOCKER_CONFIG/config.json", so we attempt to copy this from the host
// to our temporary directory. This doesn't always exist, so we ignore errors.
hostConfigDir := filepath.Dir(c.ConfigFile().Filename)
_ = cp.Copy(
filepath.Join(hostConfigDir, "contexts"),
filepath.Join(tmp, "contexts"),
)
// Save our temporary credentials to $tmp/config.json.
tmpCfg := filepath.Join(tmp, filepath.Base(c.ConfigFile().Filename))
c.ConfigFile().Filename = tmpCfg
err = c.ConfigFile().Save()
if err != nil {
return nil, err
}
// We will spawn docker-buildx with DOCKER_CONFIG set to our temporary
// directory for auth, but BUILDX_CONFIG will point to the host. There's a
// bunch of builder state in there that we want to preserve.
env := []string{
fmt.Sprintf("DOCKER_CONFIG=%s", tmp),
fmt.Sprintf("BUILDX_CONFIG=%s", filepath.Join(hostConfigDir, "buildx")),
}
// We need to write to this file in order to recover information about the
// build, like the digest.
metadata := filepath.Clean(filepath.Join(tmp, "metadata.json"))
args := []string{
"buildx",
"build",
"--progress", "plain",
"--metadata-file", metadata,
"--builder", builder.name,
}
// TODO: --allow
// TODO: --annotation
// TODO: --attest
// TODO: --cgroup-parent
for k, v := range opts.BuildArgs {
args = append(args, "--build-arg", fmt.Sprintf("%s=%s", k, v))
}
if opts.Builder != "" {
args = append(args, "--builder", opts.Builder)
}
for _, c := range opts.CacheFrom {
args = append(args, "--cache-from", attrcsv(c.Type, c.Attrs))
}
for _, c := range opts.CacheTo {
args = append(args, "--cache-to", attrcsv(c.Type, c.Attrs))
}
if opts.ExportLoad {
args = append(args, "--load")
}
if opts.ExportPush {
args = append(args, "--push")
}
for _, e := range opts.Exports {
args = append(args, "--output", attrcsv(e.Type, e.Attrs))
}
for _, h := range opts.ExtraHosts {
args = append(args, "--add-host", h)
}
for k, v := range opts.NamedContexts {
args = append(args, "--build-context", fmt.Sprintf("%s=%s", k, v))
}
for k, v := range opts.Labels {
args = append(args, "--label", fmt.Sprintf("%s=%s", k, v))
}
if opts.NetworkMode != "" {
args = append(args, "--network", opts.NetworkMode)
}
if opts.NoCache {
args = append(args, "--no-cache")
}
for _, p := range opts.Platforms {
args = append(args, "--platform", p)
}
if opts.Pull {
args = append(args, "--pull")
}
for _, ssh := range opts.SSH {
s := ssh.ID
if len(ssh.Paths) > 0 {
s += "=" + strings.Join(ssh.Paths, ",")
}
args = append(args, "--ssh", s)
}
for _, t := range opts.Tags {
args = append(args, "--tag", t)
}
if opts.Target != "" {
args = append(args, "--target", opts.Target)
}
if opts.DockerfileName != "" {
args = append(args, "-f", opts.DockerfileName)
}
if in := b.Inline(); in != "" {
c.in = in
args = append(args, "-f", "-")
}
if opts.ContextPath != "" {
args = append(args, opts.ContextPath)
}
// We pass secrets by value via dynamic PULUMI_DOCKER_* environment
// variables.
for _, s := range opts.Secrets {
envvar, err := resource.NewUniqueHex("PULUMI_DOCKER_", 0, 0)
if err != nil {
return nil, err
}
// We abuse the pb.Secret proto by stuffing the secret's value in
// XXX_unrecognized. We never serialize this proto so this is tolerable.
env = append(env, fmt.Sprintf("%s=%s", envvar, s.XXX_unrecognized))
args = append(args, "--secret", fmt.Sprintf("id=%s,env=%s", s.ID, envvar))
}
// Invoke docker-buildx.
err = c.exec(args, env)
if err != nil {
return nil, err
}
// Read the metadata file and transform it back into the map[string]string
// structure originally returned by the exporter.
_, err = os.Stat(metadata)
if err != nil {
return nil, fmt.Errorf("missing metadata: %w", err)
}
out, err := os.ReadFile(metadata)
if err != nil {
return nil, err
}
var raw map[string]any
err = json.Unmarshal(out, &raw)
if err != nil {
return nil, err
}
resp := map[string]string{}
for k, v := range raw {
switch vv := v.(type) {
case string:
resp[k] = vv
default:
out, err := json.Marshal(v)
if err != nil {
continue
}
resp[k] = string(out)
}
}
return &client.SolveResponse{ExporterResponse: resp}, nil
}
// exec invokes a Docker plugin binary. The first argument should be the name
// of the plugin's subcommand, e.g. "buildx".
func (c *cli) exec(args []string, extraEnv []string) error {
if len(args) == 0 {
return fmt.Errorf("args must be non-empty")
}
name := args[0]
root := commands.NewRootCmd(name, false, c)
plug, err := manager.GetPlugin(name, c, root)
if err != nil {
return err
}
if plug.Err != nil {
return plug.Err
}
defer contract.IgnoreClose(c.w)
cmd, err := manager.PluginRunCommand(c, name, root)
if err != nil {
return err
}
cmd.Args = append([]string{cmd.Args[0]}, args...)
cmd.Stderr = c.Err() // TODO: This is build output...
cmd.Stdout = c.Out()
cmd.Stdin = c.In()
cmd.Env = append(cmd.Env, extraEnv...)
return cmd.Run()
}
// attrcsv transforms key/values into a CSV: key1=value1,key2=value2,...
func attrcsv(typ string, m map[string]string) string {
s := []string{fmt.Sprintf("type=%s", typ)}
for k, v := range m {
s = append(s, fmt.Sprintf("%s=%s", k, v))
}
return strings.Join(s, ",")
}

View File

@@ -0,0 +1,39 @@
// Copyright 2024, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package internal
import (
"io"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestExec(t *testing.T) {
t.Parallel()
h, err := newHost(nil)
require.NoError(t, err)
cli, err := wrap(h)
require.NoError(t, err)
err = cli.exec([]string{"buildx", "version"}, nil)
assert.NoError(t, err)
out, err := io.ReadAll(cli.r)
require.NoError(t, err)
assert.Contains(t, string(out), "github.com/docker/buildx")
}

359
provider/internal/client.go Normal file
View File

@@ -0,0 +1,359 @@
// Copyright 2024, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:generate go run go.uber.org/mock/mockgen -typed -package internal -source client.go -destination mockclient_test.go --self_package github.com/pulumi/pulumi-dockerbuild/provider/internal
package internal
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/distribution/reference"
buildx "github.com/docker/buildx/build"
"github.com/docker/buildx/commands"
controllerapi "github.com/docker/buildx/controller/pb"
"github.com/docker/buildx/util/dockerutil"
"github.com/docker/buildx/util/platformutil"
"github.com/docker/buildx/util/progress"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/flags"
"github.com/docker/docker/api/types"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/session/auth/authprovider"
"github.com/moby/buildkit/util/progress/progressui"
"github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/ref"
"github.com/sirupsen/logrus"
provider "github.com/pulumi/pulumi-go-provider"
"github.com/pulumi/pulumi/sdk/v3/go/common/diag"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
)
// Client handles all our Docker API calls.
type Client interface {
Build(ctx provider.Context, b Build) (*client.SolveResponse, error)
BuildKitEnabled() (bool, error)
Inspect(ctx context.Context, id string) ([]descriptor.Descriptor, error)
Delete(ctx context.Context, id string) error
ManifestCreate(ctx provider.Context, push bool, target string, refs ...string) error
ManifestInspect(ctx provider.Context, target string) (string, error)
ManifestDelete(ctx provider.Context, target string) error
}
// Build encapsulates all of the user-provider build parameters and options.
type Build interface {
BuildOptions() controllerapi.BuildOptions
Inline() string
ShouldExec() bool
Secrets() session.Attachable
}
var _ Client = (*cli)(nil)
func newDockerCLI(config *Config) (*command.DockerCli, error) {
cli, err := command.NewDockerCli(
command.WithDefaultContextStoreConfig(),
command.WithContentTrustFromEnv(),
)
if err != nil {
return nil, err
}
opts := flags.NewClientOptions()
if config != nil && config.Host != "" {
opts.Hosts = append(opts.Hosts, config.Host)
}
err = cli.Initialize(opts)
if err != nil {
return nil, err
}
// TODO: Log some version information for debugging.
// Disable the CLI's tendency to log randomly to stdout.
logrus.SetOutput(io.Discard)
return cli, nil
}
// Build performs a BuildKit build. Returns a map of target names (or one name,
// "default", if no targets were specified) to SolveResponses, which capture
// the build's digest and tags (if any).
func (c *cli) Build(
pctx provider.Context,
build Build,
) (*client.SolveResponse, error) {
ctx := context.Context(pctx)
opts := build.BuildOptions()
go c.tail(pctx)
defer contract.IgnoreClose(c)
if build.ShouldExec() {
return c.execBuild(build)
}
b, err := c.host.builderFor(build)
if err != nil {
return nil, err
}
printer, err := progress.NewPrinter(ctx, c.w,
progressui.PlainMode,
progress.WithDesc(
fmt.Sprintf("building with %q instance using %s driver", b.name, b.driver),
fmt.Sprintf("%s:%s", b.driver, b.name),
),
)
if err != nil {
return nil, fmt.Errorf("creating printer: %w", err)
}
cacheFrom := []client.CacheOptionsEntry{}
for _, c := range opts.CacheFrom {
cacheFrom = append(cacheFrom, client.CacheOptionsEntry{
Type: c.Type,
Attrs: c.Attrs,
})
}
cacheTo := []client.CacheOptionsEntry{}
for _, c := range opts.CacheTo {
cacheTo = append(cacheTo, client.CacheOptionsEntry{
Type: c.Type,
Attrs: c.Attrs,
})
}
exports := []client.ExportEntry{}
for _, e := range opts.Exports {
exports = append(exports, client.ExportEntry{
Type: e.Type,
Attrs: e.Attrs,
OutputDir: e.Destination,
})
}
platforms, _ := platformutil.Parse(opts.Platforms)
platforms = platformutil.Dedupe(platforms)
namedContexts := map[string]buildx.NamedContext{}
for k, v := range opts.NamedContexts {
ref, err := reference.ParseNormalizedNamed(k)
if err != nil {
return nil, err
}
name := strings.TrimSuffix(reference.FamiliarString(ref), ":latest")
namedContexts[name] = buildx.NamedContext{Path: v}
}
ssh, err := controllerapi.CreateSSH(opts.SSH)
if err != nil {
return nil, err
}
target := opts.Target
if target == "" {
target = "default"
}
payload := map[string]buildx.Options{
target: {
Inputs: buildx.Inputs{
ContextPath: opts.ContextPath,
DockerfilePath: opts.DockerfileName,
DockerfileInline: build.Inline(),
NamedContexts: namedContexts,
InStream: strings.NewReader(""),
},
// Disable default provenance for now. Docker's `manifest create`
// doesn't handle manifests with provenance included; more reason
// to use imagetools instead.
Attests: map[string]*string{"provenance": nil},
BuildArgs: opts.BuildArgs,
CacheFrom: cacheFrom,
CacheTo: cacheTo,
Exports: exports,
ExtraHosts: opts.ExtraHosts,
NetworkMode: opts.NetworkMode,
NoCache: opts.NoCache,
Labels: opts.Labels,
Platforms: platforms,
Pull: opts.Pull,
Tags: opts.Tags,
Target: opts.Target,
Session: []session.Attachable{
ssh,
authprovider.NewDockerAuthProvider(c.ConfigFile(), nil),
build.Secrets(),
},
},
}
// Perform the build.
results, err := buildx.Build(
ctx,
b.nodes,
payload,
dockerutil.NewClient(c),
filepath.Dir(c.ConfigFile().Filename),
printer,
)
if err != nil {
return nil, err
}
if printErr := printer.Wait(); printErr != nil {
return results[target], printErr
}
for _, w := range printer.Warnings() {
b := &bytes.Buffer{}
fmt.Fprintf(b, "%s", w.Short)
for _, d := range w.Detail {
fmt.Fprintf(b, "\n%s", d)
}
pctx.Log(diag.Warning, b.String())
}
return results[target], err
}
// BuildKitEnabled returns true if the client supports buildkit.
func (c *cli) BuildKitEnabled() (bool, error) {
return c.Cli.BuildKitEnabled()
}
func (c *cli) ManifestCreate(ctx provider.Context, push bool, target string, refs ...string) error {
// TODO: Create this manifest with regclient or imagetools.
go c.tail(ctx)
defer contract.IgnoreClose(c)
args := []string{
// "buildx",
"imagetools",
"create",
"--tag", target,
}
if !push {
args = append(args, "--dry-run")
}
args = append(args, refs...)
cmd := commands.NewRootCmd(os.Args[0], false, c)
cmd.SetArgs(args)
return cmd.ExecuteContext(ctx)
}
func (c *cli) ManifestInspect(ctx provider.Context, target string) (string, error) {
rc := c.rc()
ref, err := ref.New(target)
if err != nil {
return "", err
}
m, err := rc.ManifestHead(ctx, ref)
if err != nil {
return "", fmt.Errorf("fetching head: %w", err)
}
return string(m.GetDescriptor().Digest), nil
}
func (c *cli) ManifestDelete(ctx provider.Context, target string) error {
rc := c.rc()
ref, err := ref.New(target)
if err != nil {
return err
}
err = rc.ManifestDelete(context.Context(ctx), ref)
if errors.Is(err, errs.ErrHTTPStatus) {
ctx.Log(diag.Warning, "this registry does not support deletions")
return nil
}
if err != nil {
return err
}
return nil
}
// Inspect inspects an image.
func (c *cli) Inspect(ctx context.Context, r string) ([]descriptor.Descriptor, error) {
ref, err := ref.New(r)
if err != nil {
return nil, err
}
rc := c.rc()
m, err := rc.ManifestGet(ctx, ref)
if err != nil {
return nil, err
}
if mi, ok := m.(manifest.Indexer); ok {
return mi.GetManifestList()
}
return []descriptor.Descriptor{m.GetDescriptor()}, nil
}
// Delete attempts to delete an image with the given ref. Many registries don't
// support the DELETE API yet, so this operation is not guaranteed to work.
func (c *cli) Delete(ctx context.Context, r string) error {
// Attempt to delete the ref locally if it exists.
_, _ = c.Client().ImageRemove(ctx, r, types.ImageRemoveOptions{
Force: true, // Needed in case the image has multiple tags.
})
// Attempt to delete the ref remotely if it was pushed -- requires a
// digest.
ref, err := ref.New(r)
if err != nil || ref.Digest == "" {
return nil
}
rc := c.rc()
// TODO: Multi-platform manifests are left dangling on ECR.
_ = rc.ManifestDelete(ctx, ref)
return nil
}
func normalizeReference(ref string) (reference.Named, error) {
namedRef, err := reference.ParseNormalizedNamed(ref)
if err != nil {
return nil, err
}
if _, isDigested := namedRef.(reference.Canonical); !isDigested {
return reference.TagNameOnly(namedRef), nil
}
return namedRef, nil
}

View File

@@ -0,0 +1,374 @@
// Copyright 2024, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package internal
import (
"context"
"os"
"path/filepath"
"testing"
"github.com/docker/docker/api/types/registry"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
)
func TestAuth(t *testing.T) {
t.Parallel()
user := "pulumibot"
if u := os.Getenv("DOCKER_HUB_USER"); u != "" {
user = u
}
password := os.Getenv("DOCKER_HUB_PASSWORD")
address := "docker.io"
cli := testcli(t, true, Registry{
Address: address,
Username: user,
Password: password,
})
_, err := cli.Client().RegistryLogin(context.Background(), registry.AuthConfig{ServerAddress: address})
assert.NoError(t, err)
}
func TestCustomHost(t *testing.T) {
socket := "unix:///foo/bar.sock"
//nolint:paralleltest // not compatible with Setenv
t.Run("env", func(t *testing.T) {
t.Setenv("DOCKER_HOST", socket)
h, err := newHost(nil)
require.NoError(t, err)
cli, err := wrap(h)
require.NoError(t, err)
assert.Equal(t, socket, cli.Client().DaemonHost())
assert.Equal(t, socket, cli.DockerEndpoint().Host)
})
t.Run("config", func(t *testing.T) {
t.Parallel()
h, err := newHost(&Config{Host: socket})
require.NoError(t, err)
cli, err := wrap(h)
require.NoError(t, err)
assert.Equal(t, socket, cli.Client().DaemonHost())
assert.Equal(t, socket, cli.DockerEndpoint().Host)
})
}
func TestBuild(t *testing.T) {
t.Parallel()
// Workaround for https://github.com/pulumi/pulumi-go-provider/issues/159
ctrl, ctx := gomock.WithContext(context.Background(), t)
pctx := NewMockProviderContext(ctrl)
pctx.EXPECT().Log(gomock.Any(), gomock.Any()).AnyTimes()
pctx.EXPECT().LogStatus(gomock.Any(), gomock.Any()).AnyTimes()
pctx.EXPECT().Done().Return(ctx.Done()).AnyTimes()
pctx.EXPECT().Value(gomock.Any()).DoAndReturn(func(key any) any { return ctx.Value(key) }).AnyTimes()
pctx.EXPECT().Err().Return(ctx.Err()).AnyTimes()
pctx.EXPECT().Deadline().Return(ctx.Deadline()).AnyTimes()
tmpdir := t.TempDir()
exampleContext := BuildContext{Context: Context{Location: "../../examples/app"}}
tests := []struct {
name string
skip bool
args ImageArgs
auths []Registry
}{
{
name: "multiPlatform",
args: ImageArgs{
Context: exampleContext,
Dockerfile: Dockerfile{
Location: "../../examples/app/Dockerfile.multiPlatform",
},
Platforms: []Platform{"plan9/amd64", "plan9/arm64"},
},
},
{
name: "registryPush",
skip: os.Getenv("DOCKER_HUB_PASSWORD") == "",
args: ImageArgs{
Context: exampleContext,
Tags: []string{"docker.io/pulumibot/buildkit-e2e:unit"},
Push: true,
},
auths: []Registry{{
Address: "docker.io",
Username: "pulumibot",
Password: os.Getenv("DOCKER_HUB_PASSWORD"),
}},
},
{
name: "cached",
args: ImageArgs{
Context: exampleContext,
Tags: []string{"cached"},
CacheTo: []CacheTo{{Local: &CacheToLocal{
Dest: filepath.Join(tmpdir, "cache"),
CacheWithMode: CacheWithMode{Mode: "max"},
}}},
CacheFrom: []CacheFrom{{Local: &CacheFromLocal{
Src: filepath.Join(tmpdir, "cache"),
}}},
},
},
{
name: "buildArgs",
args: ImageArgs{
Context: exampleContext,
Dockerfile: Dockerfile{
Location: "../../examples/app/Dockerfile.buildArgs",
},
BuildArgs: map[string]string{
"SET_ME_TO_TRUE": "true",
},
},
},
{
name: "extraHosts",
args: ImageArgs{
Context: exampleContext,
Dockerfile: Dockerfile{
Location: "../../examples/app/Dockerfile.extraHosts",
},
AddHosts: []string{
"metadata.google.internal:169.254.169.254",
},
},
},
{
name: "sshMount",
skip: os.Getenv("SSH_AUTH_SOCK") == "",
args: ImageArgs{
Context: exampleContext,
Dockerfile: Dockerfile{
Location: "../../examples/app/Dockerfile.sshMount",
},
SSH: []SSH{{ID: "default"}},
},
},
{
name: "secrets",
args: ImageArgs{
Context: exampleContext,
Dockerfile: Dockerfile{
Location: "../../examples/app/Dockerfile.secrets",
},
Secrets: map[string]string{
"password": "hunter2",
},
NoCache: true,
},
},
{
name: "labels",
args: ImageArgs{
Context: exampleContext,
Labels: map[string]string{
"description": "foo",
},
},
},
{
name: "target",
args: ImageArgs{
Context: exampleContext,
Dockerfile: Dockerfile{
Location: "../../examples/app/Dockerfile.target",
},
Target: "build-me",
},
},
{
name: "namedContext",
args: ImageArgs{
Context: BuildContext{
Context: Context{
Location: "../../examples/app",
},
Named: NamedContexts{
"golang:latest": Context{
Location: "docker-image://golang@sha256:b8e62cf593cdaff36efd90aa3a37de268e6781a2e68c6610940c48f7cdf36984",
},
},
},
Dockerfile: Dockerfile{
Location: "../../examples/app/Dockerfile.namedContexts",
},
},
},
{
name: "remoteContext",
args: ImageArgs{
Context: BuildContext{
Context: Context{
Location: "https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile",
},
},
},
},
{
name: "remoteContextWithInline",
args: ImageArgs{
Context: BuildContext{
Context: Context{
Location: "https://github.com/docker-library/hello-world.git",
},
},
Dockerfile: Dockerfile{
Inline: dedent(`
FROM busybox
COPY hello.c ./
`),
},
},
},
{
name: "inline",
args: ImageArgs{
Context: exampleContext,
Dockerfile: Dockerfile{
Inline: dedent(`
FROM alpine
RUN echo 👍
`),
},
},
},
{
name: "dockerLoad",
args: ImageArgs{
Context: exampleContext,
Load: true,
},
},
}
// Add an exec: true version for all of our test cases.
for _, tt := range tests {
tt := tt
tt.name = "exec-" + tt.name
tt.args.Exec = true
tmpdir := filepath.Join(t.TempDir(), "exec")
for _, c := range tt.args.CacheTo {
if c.Local != nil {
c.Local.Dest = tmpdir
}
}
for _, c := range tt.args.CacheFrom {
if c.Local != nil {
c.Local.Src = tmpdir
}
}
tests = append(tests, tt)
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if tt.skip {
t.Skip()
}
cli := testcli(t, true, tt.auths...)
build, err := tt.args.toBuild(pctx, false)
require.NoError(t, err)
_, err = cli.Build(pctx, build)
assert.NoError(t, err, cli.err.String())
})
}
}
func TestBuildkitEnabled(t *testing.T) {
t.Parallel()
cli := testcli(t, false)
ok, err := cli.BuildKitEnabled()
assert.NoError(t, err)
assert.True(t, ok)
}
func TestInspect(t *testing.T) {
t.Parallel()
cli := testcli(t, false)
descriptors, err := cli.Inspect(context.Background(), "pulumibot/myapp:buildx")
assert.NoError(t, err)
assert.Equal(t, "application/vnd.docker.distribution.manifest.v2+json", descriptors[0].MediaType)
}
func TestNormalizatReference(t *testing.T) {
t.Parallel()
tests := []struct {
ref string
want string
wantErr string
}{
{
ref: "foo",
want: "docker.io/library/foo:latest",
},
{
ref: "pulumi/pulumi:v3.100.0",
want: "docker.io/pulumi/pulumi:v3.100.0",
},
{
ref: "invalid:ref:format",
wantErr: "invalid reference format",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.ref, func(t *testing.T) {
t.Parallel()
ref, err := normalizeReference(tt.ref)
if err != nil {
assert.ErrorContains(t, err, tt.wantErr)
} else {
assert.Equal(t, ref.String(), tt.want)
}
})
}
}
// testcli returns a new standalone CLI instance. Set ping to true if a live
// daemon is required -- the test will be skipped if the daemon is not available.
func testcli(t *testing.T, ping bool, auths ...Registry) *cli {
h, err := newHost(nil)
require.NoError(t, err)
cli, err := wrap(h, auths...)
require.NoError(t, err)
if ping {
_, err := cli.Client().Ping(context.Background())
if err != nil {
t.Skip(err)
}
}
return cli
}

View File

@@ -0,0 +1,319 @@
// Copyright 2024, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package internal
import (
"context"
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"hash"
"io"
gofs "io/fs"
"os"
"path"
"path/filepath"
"syscall"
buildx "github.com/docker/buildx/build"
"github.com/moby/patternmatcher/ignorefile"
"github.com/spf13/afero"
"github.com/tonistiigi/fsutil"
"github.com/pulumi/pulumi-go-provider/infer"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
)
var (
_ = (infer.Annotated)((*Context)(nil))
_ = (infer.Annotated)((*BuildContext)(nil))
)
// Context represents Docker's `PATH | URL | -` context argument. Inline
// context isn't supported yet.
type Context struct {
Location string `pulumi:"location"` // Location is a local directory or URL.
}
// BuildContext represents Docker's named and unamed contexts.
type BuildContext struct {
Context
Named NamedContexts `pulumi:"named,optional"`
}
// NamedContexts correspond to Docker's `--build-context name=path` options.
// The path can be local or a remote URL.
type NamedContexts map[string]Context
// Map returns NamedContexts as a simple map.
func (nc NamedContexts) Map() map[string]string {
m := map[string]string{}
for k, v := range nc {
m[k] = v.Location
}
return m
}
// Annotate sets docstrings on Context.
func (c *Context) Annotate(a infer.Annotator) {
a.Describe(&c.Location, dedent(`
Resources to use for build context.
The location can be:
* A relative or absolute path to a local directory (".", "./app",
"/app", etc.).
* A remote URL of a Git repository, tarball, or plain text file
("https://github.com/user/myrepo.git", "http://server/context.tar.gz",
etc.).
`))
}
// validate returns a non-nil CheckError if the Context is invalid. The
// returned Dockerfile may have defaults set to match Docker's default
// handling. The returned Dockerfile should be validated separately.
func (c *Context) validate(preview bool, d Dockerfile) (Dockerfile, error) {
if c.Location == "" && preview {
// The field is required so we normally wouldn't need to check if it
// exists, but during previews it can still be empty if the value is
// unknown. This isn't an error, but it does prevent us from performing
// a build later.
return d, nil
}
if buildx.IsRemoteURL(c.Location) {
// We assume remote URLs are always valid.
return d, nil
}
abs, err := filepath.Abs(c.Location)
if err != nil {
return d, newCheckFailure(err, "context.location")
}
if d.Location == "" && d.Inline == "" {
// If a Dockerfile wasn't provided and our context is on-disk, then
// set our Dockerfile to a default of <PATH>/Dockerfile.
d.Location = filepath.Join(c.Location, "Dockerfile")
}
if isLocalDir(afero.NewOsFs(), abs) {
// Our context exists -- nothing else to check.
return d, nil
}
if c.Location != "-" {
return d, newCheckFailure(fmt.Errorf("%q: not a valid directory or URL", c.Location), "context.location")
}
return d, nil
}
// Annotate sets docstrings on BuildContext.
func (bc *BuildContext) Annotate(a infer.Annotator) {
a.Describe(&bc.Named, dedent(`
Additional build contexts to use.
These contexts are accessed with "FROM name" or "--from=name"
statements when using Dockerfile 1.4+ syntax.
Values can be local paths, HTTP URLs, or "docker-image://" images.
`))
}
// hashFile hashes a file's contents and accumulates it into the provider Hash.
func hashFile(
h hash.Hash,
fs fsutil.FS,
relativePath string,
fileMode gofs.FileMode,
) error {
if fileMode.IsDir() {
return nil
}
if !(fileMode.IsRegular() || fileMode.Type() == os.ModeSymlink) {
return nil
}
f, err := fs.Open(relativePath)
if err != nil {
return fmt.Errorf("could not open %q: %w", relativePath, err)
}
defer contract.IgnoreClose(f)
_, err = io.Copy(h, f)
if errors.Is(err, syscall.EISDIR) {
// Ignore symlinks to directories.
return nil
}
if err != nil {
return fmt.Errorf("could not copy %q to hash: %w", relativePath, err)
}
h.Write([]byte(filepath.ToSlash(path.Clean(relativePath))))
h.Write([]byte(fileMode.String()))
return nil
}
// hashBuildContext accumulates hashes for files in a directory. If the file is
// a symlink, the location it points to is hashed. If it is a regular file, we
// hash the contents of the file. In order to detect file renames and mode
// changes, we also write to the accumulator a relative name and file mode.
func hashBuildContext(contextPath, dockerfilePath string, namedContexts map[string]string) (string, error) {
h := sha256.New()
fs := afero.NewOsFs()
// Grab .dockerignore if our context and/or Dockerfile is on-disk.
excludes := []string{}
if isLocalDir(fs, contextPath) || isLocalFile(fs, dockerfilePath) {
e, err := getIgnorePatterns(fs, dockerfilePath, contextPath)
if err != nil {
return "", err
}
excludes = e
}
if isLocalFile(fs, dockerfilePath) {
err := hashDockerfile(h, dockerfilePath)
if err != nil {
return "", nil
}
}
if isLocalDir(fs, contextPath) {
// Hash our context if it's on-disk.
fs, err := rootFS(contextPath, excludes)
if err != nil {
return "", err
}
if _, err := hashPath(h, fs); err != nil {
return "", err
}
}
// Hash any local named contexts.
for _, namedContext := range namedContexts {
if isLocalDir(fs, namedContext) {
fs, err := rootFS(namedContext, excludes)
if err != nil {
return "", err
}
if _, err := hashPath(h, fs); err != nil {
return "", err
}
}
}
return hex.EncodeToString(h.Sum(nil)), nil
}
// hashPath hashes all paths within the provided FS.
func hashPath(h hash.Hash, fs fsutil.FS) (string, error) {
err := fs.Walk(context.Background(), "/", func(filePath string, dir gofs.DirEntry, err error) error {
if err != nil {
return err
}
if dir.IsDir() {
return nil
}
// fsutil.Walk makes filePath relative to the root, we join it back to get an absolute path to
// the file to hash.
fi, err := dir.Info()
if err != nil {
return err
}
return hashFile(h, fs, filePath, fi.Mode())
})
if err != nil {
return "", fmt.Errorf("unable to hash build context: %w", err)
}
// create a hash of the entire input of the hash accumulator
return hex.EncodeToString(h.Sum(nil)), nil
}
// hashDockerfile hashes the contents of a Dockerfile.
func hashDockerfile(h hash.Hash, path string) error {
// The Dockerfile might be capture by .dockerignore, so we explicitly hash
// its content (but not filename -- to match Docker) in order to detect
// changes in it.
df, err := os.ReadFile(filepath.Clean(path))
if err != nil {
return fmt.Errorf("error reading dockerfile %q: %w", path, err)
}
_, err = h.Write(df)
if err != nil {
return fmt.Errorf("error hashing dockerfile %q: %w", path, err)
}
return nil
}
// getIgnorePatterns returns all patterns to ignore when constructing a build
// context for the given Dockerfile, if any such patterns exist.
//
// Precedence is given to Dockerfile-specific ignore-files as per
// https://docs.docker.com/build/building/context/#filename-and-location.
func getIgnorePatterns(fs afero.Fs, dockerfilePath, contextRoot string) ([]string, error) {
paths := []string{
// Prefer <Dockerfile>.dockerignore if it's present.
dockerfilePath + ".dockerignore",
}
if isLocalDir(fs, contextRoot) {
// Otherwise fall back to the ignore-file at the root of our build context.
paths = append(paths, filepath.Join(contextRoot, ".dockerignore"))
}
// Attempt to parse our candidate ignore-files, skipping any that don't
// exist.
for _, p := range paths {
f, err := fs.Open(p)
if errors.Is(err, afero.ErrFileNotFound) {
continue
}
if err != nil {
return nil, fmt.Errorf("reading %q: %w", p, err)
}
defer contract.IgnoreClose(f)
ignorePatterns, err := ignorefile.ReadAll(f)
if err != nil {
return nil, fmt.Errorf("unable to parse %q: %w", p, err)
}
return ignorePatterns, nil
}
return nil, nil
}
func isLocalDir(fs afero.Fs, path string) bool {
stat, err := fs.Stat(path)
return err == nil && stat.IsDir()
}
func isLocalFile(fs afero.Fs, path string) bool {
stat, err := fs.Stat(path)
return err == nil && !stat.IsDir()
}
// rootFS returns a new fsutil.FS scoped to the given root and with the given
// exclusions.
func rootFS(root string, excludes []string) (fsutil.FS, error) {
fs, err := fsutil.NewFS(root)
if err != nil {
return nil, err
}
return fsutil.NewFilterFS(fs, &fsutil.FilterOpt{ExcludePatterns: excludes})
}

View File

@@ -0,0 +1,374 @@
// Copyright 2024, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package internal
import (
"bufio"
"os"
"path/filepath"
"strings"
"syscall"
"testing"
"github.com/spf13/afero"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var _dockerfile = "Dockerfile"
func TestContextValidate(t *testing.T) {
t.Parallel()
tests := []struct {
name string
c Context
givenD Dockerfile
preview bool
wantD *Dockerfile
wantErr string
}{
{
name: "relative",
c: Context{
Location: "../internal/../internal/testdata/noop",
},
wantD: &Dockerfile{
Location: "../internal/testdata/noop/Dockerfile",
},
},
{
name: "missing directory",
c: Context{
Location: "/does/not/exist/",
},
wantErr: "not a valid directory",
},
{
name: "missing default Dockerfile",
c: Context{
Location: "testdata",
},
wantD: &Dockerfile{Location: "testdata/Dockerfile"},
},
{
name: "with explicit Dockerfile",
c: Context{
Location: "testdata",
},
givenD: Dockerfile{
Location: "testdata/Dockerfile.invalid",
},
},
{
name: "default location",
c: Context{},
wantD: &Dockerfile{Location: "Dockerfile"},
},
{
name: "remote context doesn't default to local Dockerfile",
c: Context{
Location: "https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile",
},
wantD: &Dockerfile{},
},
{
name: "preview",
c: Context{},
preview: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
d, err := tt.c.validate(tt.preview, tt.givenD)
if tt.wantErr == "" {
assert.NoError(t, err)
} else {
assert.ErrorContains(t, err, tt.wantErr)
}
if tt.wantD != nil {
assert.Equal(t, tt.wantD.Location, d.Location)
assert.Equal(t, tt.wantD.Inline, d.Inline)
}
})
}
}
func TestHashIgnoresFile(t *testing.T) {
t.Parallel()
step1Dir := "./testdata/ignores/basedir"
baseResult, err := hashBuildContext(step1Dir, filepath.Join(step1Dir, _dockerfile), nil)
require.NoError(t, err)
step2Dir := "./testdata/ignores/basedir-with-ignored-files"
result, err := hashBuildContext(step2Dir, filepath.Join(step2Dir, _dockerfile), nil)
require.NoError(t, err)
assert.Equal(t, result, baseResult)
}
// Tests that we handle .dockerignore exclusions such as "!foo/*/bar".
//
// See:
// - https://github.com/moby/moby/issues/30018
// - https://github.com/moby/moby/issues/45608
//
// Buildkit handles these correctly (according to spec), Docker's classic builder does not.
func TestHashIgnoresWildcards(t *testing.T) {
t.Parallel()
baselineDir := "testdata/ignores-wildcard/basedir"
baselineResult, err := hashBuildContext(baselineDir, filepath.Join(baselineDir, _dockerfile), nil)
require.NoError(t, err)
modIgnoredDir := "testdata/ignores-wildcard/basedir-modified-ignored-file"
modIgnoredResult, err := hashBuildContext(modIgnoredDir, filepath.Join(modIgnoredDir, _dockerfile), nil)
require.NoError(t, err)
modIncludedDir := "testdata/ignores-wildcard/basedir-modified-included-file"
modIncludedResult, err := hashBuildContext(modIncludedDir, filepath.Join(modIncludedDir, _dockerfile), nil)
require.NoError(t, err)
assert.Equal(t, baselineResult, modIgnoredResult, "hash should not change when modifying ignored files")
assert.NotEqual(t, baselineResult, modIncludedResult,
"hash should change when modifying included (via wildcard ignore exclusion) files")
}
func BenchmarkHashBuildContext(b *testing.B) {
dir := "testdata/ignores-wildcard/basedir-modified-ignored-file"
for n := 0; n < b.N; n++ {
_, err := hashBuildContext(dir, filepath.Join(dir, _dockerfile), nil)
require.NoError(b, err)
}
}
// Tests that we handle .dockerignore exclusions such as "!foo/*/bar", as above, when using a
// relative context path.
//
//nolint:paralleltest // Incompatible with os.Chdir.
func TestHashIgnoresWildcardsRelative(t *testing.T) {
err := os.Chdir("testdata")
require.NoError(t, err)
defer func() {
err = os.Chdir("..")
require.NoError(t, err)
}()
baselineDir := "../testdata/ignores-wildcard/basedir"
baselineResult, err := hashBuildContext(baselineDir, filepath.Join(baselineDir, _dockerfile), nil)
require.NoError(t, err)
modIgnoredDir := "../testdata/ignores-wildcard/basedir-modified-ignored-file"
modIgnoredResult, err := hashBuildContext(modIgnoredDir, filepath.Join(modIgnoredDir, _dockerfile), nil)
require.NoError(t, err)
modIncludedDir := "../testdata/ignores-wildcard/basedir-modified-included-file"
modIncludedResult, err := hashBuildContext(modIncludedDir, filepath.Join(modIncludedDir, _dockerfile), nil)
require.NoError(t, err)
assert.Equal(t, baselineResult, modIgnoredResult, "hash should not change when modifying ignored files")
assert.NotEqual(t, baselineResult, modIncludedResult,
"hash should change when modifying included (via wildcard ignore exclusion) files")
}
func TestHashIgnoresDockerfileOutsideDirMove(t *testing.T) {
t.Parallel()
appDir := "./testdata/dockerfile-location-irrelevant/app"
baseResult, err := hashBuildContext(appDir, "./testdata/dockerfile-location-irrelevant/step1.Dockerfile", nil)
require.NoError(t, err)
result, err := hashBuildContext(appDir, "./testdata/dockerfile-location-irrelevant/step2.Dockerfile", nil)
require.NoError(t, err)
assert.Equal(t, result, baseResult)
}
func TestHashRenamingMatters(t *testing.T) {
t.Parallel()
step1Dir := "./testdata/filemode-matters/step1"
baseResult, err := hashBuildContext(step1Dir, filepath.Join(step1Dir, _dockerfile), nil)
require.NoError(t, err)
step2Dir := "./testdata/renaming-matters/step2"
result, err := hashBuildContext(step2Dir, filepath.Join(step2Dir, _dockerfile), nil)
require.NoError(t, err)
assert.NotEqual(t, result, baseResult)
}
func TestHashFilemodeMatters(t *testing.T) {
t.Parallel()
step1Dir := "./testdata/filemode-matters/step1"
baseResult, err := hashBuildContext(step1Dir, filepath.Join(step1Dir, _dockerfile), nil)
require.NoError(t, err)
step2Dir := "./testdata/filemode-matters/step2-chmod-x"
result, err := hashBuildContext(step2Dir, filepath.Join(step2Dir, _dockerfile), nil)
require.NoError(t, err)
assert.NotEqual(t, result, baseResult)
}
func TestHashDeepSymlinks(t *testing.T) {
t.Parallel()
dir := "./testdata/symlinks"
_, err := hashBuildContext(dir, filepath.Join(dir, "Dockerfile"), nil)
assert.NoError(t, err)
}
func TestIgnoreIrregularFiles(t *testing.T) {
t.Parallel()
dir := t.TempDir()
// Create a Dockerfile
dockerfile := filepath.Join(dir, "Dockerfile")
err := os.WriteFile(dockerfile, []byte{}, 0o600)
require.NoError(t, err)
// Create a pipe which should be ignored. (We will time out trying to read
// it if it's not.)
pipe := filepath.Join(dir, "pipe")
err = syscall.Mkfifo(pipe, 0o666)
require.NoError(t, err)
// Confirm it's irregular.
fi, err := os.Stat(pipe)
require.NoError(t, err)
assert.False(t, fi.Mode().IsRegular())
_, err = hashBuildContext(dir, dockerfile, nil)
assert.NoError(t, err)
}
func TestHashUnignoredDirs(t *testing.T) {
t.Parallel()
step1Dir := "./testdata/unignores/basedir"
baseResult, err := hashBuildContext(step1Dir, filepath.Join(step1Dir, _dockerfile), nil)
require.NoError(t, err)
step2Dir := "./testdata/unignores/basedir-with-unignored-files"
unignoreResult, err := hashBuildContext(step2Dir, filepath.Join(step2Dir, _dockerfile), nil)
require.NoError(t, err)
assert.Equal(t, baseResult, unignoreResult)
}
func TestDockerIgnore(t *testing.T) {
t.Parallel()
tests := []struct {
name string
dockerfile string
context string
fs map[string]string
want []string
wantErr error
}{
{
name: "Dockerfile with root dockerignore",
dockerfile: "./foo/Dockerfile",
fs: map[string]string{
".dockerignore": "rootignore",
},
want: []string{"rootignore"},
},
{
name: "Dockerfile with root dockerignore and custom dockerignore",
dockerfile: "./foo/Dockerfile",
fs: map[string]string{
"foo/Dockerfile.dockerignore": "customignore",
".dockerignore": "rootignore",
},
want: []string{"customignore"},
},
{
name: "Dockerfile with root dockerignore and relative context",
dockerfile: "./foo/Dockerfile",
context: "../",
fs: map[string]string{
"../.dockerignore": "rootignore",
},
want: []string{"rootignore"},
},
{
name: "Dockerfile without root dockerignore",
dockerfile: "./foo/Dockerfile",
want: nil,
},
{
name: "Dockerfile with invalid root dockerignore",
dockerfile: "./foo/Dockerfile",
fs: map[string]string{
".dockerignore": strings.Repeat("*", bufio.MaxScanTokenSize),
},
wantErr: bufio.ErrTooLong,
},
{
name: "custom.Dockerfile without custom dockerignore and without root dockerignore",
dockerfile: "./foo/custom.Dockerfile",
want: nil,
},
{
name: "custom.Dockerfile with custom dockerignore and without root dockerignore",
dockerfile: "./foo/custom.Dockerfile",
fs: map[string]string{
"foo/custom.Dockerfile.dockerignore": "customignore",
},
want: []string{"customignore"},
},
{
name: "custom.Dockerfile with custom dockerignore and with root dockerignore",
dockerfile: "foo/custom.Dockerfile",
fs: map[string]string{
"foo/custom.Dockerfile.dockerignore": "customignore",
".dockerignore": "rootignore",
},
want: []string{"customignore"},
},
{
name: "custom.Dockerfile without custom dockerignore and with root dockerignore",
dockerfile: "foo/custom.Dockerfile",
fs: map[string]string{
".dockerignore": "rootignore",
},
want: []string{"rootignore"},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
fs := afero.NewMemMapFs()
for fname, fdata := range tt.fs {
f, err := fs.Create(fname)
require.NoError(t, err)
_, err = f.Write([]byte(fdata))
require.NoError(t, err)
}
actual, err := getIgnorePatterns(fs, tt.dockerfile, tt.context)
assert.ErrorIs(t, err, tt.wantErr)
assert.Equal(t, tt.want, actual)
})
}
}

View File

@@ -0,0 +1,870 @@
mode: set
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:34.47,36.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:38.65,40.9 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:40.9,42.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:43.2,44.9 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:44.9,46.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:47.2,48.9 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:48.9,50.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:51.2,51.46 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:51.46,53.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:54.2,55.18 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:60.3,62.27 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:62.27,64.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:68.2,68.13 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:68.13,70.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:72.2,73.62 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:73.62,75.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:77.2,81.59 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:81.59,83.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:83.16,85.4 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:87.3,88.23 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:88.23,90.4 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:92.3,92.17 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:95.2,95.66 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:98.69,99.13 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:100.17,101.42 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:102.27,103.38 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:104.15,105.52 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:106.10,107.61 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:111.66,118.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:123.36,127.16 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:127.16,129.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:131.2,134.9 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:134.9,136.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:138.2,141.19 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:141.19,144.3 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:146.2,146.78 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:146.78,150.3 3 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:152.2,152.24 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:152.24,154.17 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:154.17,156.4 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:157.3,157.23 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:157.23,160.4 2 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:161.3,161.17 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:166.2,166.21 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:166.21,168.46 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:168.46,171.4 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:174.2,174.16 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:178.102,185.18 4 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:185.18,186.31 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:186.31,188.4 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:189.3,189.21 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:193.2,193.27 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:193.27,196.17 3 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:196.17,198.4 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:198.9,198.22 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:198.22,199.36 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:199.36,200.13 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:202.4,202.67 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:202.67,203.13 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:205.4,205.19 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/deprecated/configencoding.go:209.2,209.20 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/auth.go:11.53,15.2 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/builder.go:13.53,22.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/buildx.go:33.46,36.2 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/buildx.go:39.54,46.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/buildx.go:46.16,48.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/buildx.go:49.2,56.12 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/buildx.go:60.44,76.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/buildx.go:79.69,84.2 4 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:39.42,40.14 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:40.14,42.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:43.2,44.17 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:44.17,46.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:47.2,47.20 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:47.20,49.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:50.2,50.33 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:53.54,56.2 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:62.57,64.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:66.45,67.14 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:67.14,69.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:70.2,70.51 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:78.52,92.2 4 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:94.39,95.18 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:95.18,97.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:98.2,99.28 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:99.28,101.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:102.2,102.33 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:111.62,138.2 6 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:140.50,141.14 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:141.14,143.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:144.2,145.19 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:145.19,147.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:148.2,148.19 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:148.19,150.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:151.2,151.17 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:151.17,153.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:154.2,154.33 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:163.46,164.14 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:164.14,166.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:167.2,168.18 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:168.18,170.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:171.2,171.24 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:171.24,173.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:174.2,174.29 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:174.29,176.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:177.2,177.33 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:180.58,184.2 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:193.44,194.14 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:194.14,196.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:197.2,197.77 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:213.51,249.2 14 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:251.39,252.14 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:252.14,254.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:255.2,256.20 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:256.20,258.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:259.2,259.18 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:259.18,261.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:262.2,262.25 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:262.25,264.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:265.2,265.25 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:265.25,267.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:268.2,268.29 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:268.29,270.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:271.2,271.27 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:271.27,273.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:274.2,274.25 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:274.25,276.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:277.2,277.29 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:277.29,279.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:280.2,280.26 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:280.26,282.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:284.2,284.33 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:291.53,296.2 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:298.40,299.18 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:299.18,301.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:302.2,302.39 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:309.60,312.2 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:314.47,315.26 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:315.26,317.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:318.2,318.55 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:328.37,329.14 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:329.14,331.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:332.2,332.70 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:337.30,339.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:352.54,380.2 7 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:382.41,383.16 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:383.16,385.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:386.2,386.64 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:391.41,392.14 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:392.14,394.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:395.2,395.22 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:406.52,410.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:412.40,413.14 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:413.14,415.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:416.2,420.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:432.43,433.14 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:433.14,435.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:436.2,442.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:451.60,459.2 6 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:461.47,462.29 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:462.29,464.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:465.2,466.25 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:466.25,468.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:469.2,469.28 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:469.28,471.14 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:471.14,473.4 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:474.3,474.65 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:476.2,476.31 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:476.31,478.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:479.2,479.33 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:489.48,490.14 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:490.14,492.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:493.2,493.81 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:508.52,541.2 8 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:543.39,544.16 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:544.16,546.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:547.2,547.74 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:557.56,568.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:578.68,584.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:588.49,590.23 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:590.23,592.14 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:592.14,593.12 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:595.3,595.27 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:597.2,597.35 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cache.go:600.38,602.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:31.62,33.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:33.16,35.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:55.2,56.28 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:56.28,58.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:60.2,60.31 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:60.31,67.3 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:80.2,100.16 6 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:100.16,102.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:104.2,114.21 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:177.32,179.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:181.34,183.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:185.31,187.2 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:190.41,192.28 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:192.28,197.3 4 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:198.2,200.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:205.42,207.15 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:207.15,209.35 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:209.35,211.4 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:214.2,215.15 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:215.15,217.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:218.2,218.30 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:222.29,225.19 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:225.19,227.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:228.2,228.12 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:231.76,235.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:235.16,237.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:238.2,243.16 4 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:243.16,245.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:251.2,252.52 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:252.52,257.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:260.2,263.16 4 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:263.16,265.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:266.2,298.35 4 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:298.35,300.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:301.2,301.24 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:301.24,303.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:304.2,304.35 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:304.35,306.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:307.2,307.33 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:307.33,309.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:310.2,310.21 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:310.21,312.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:313.2,313.21 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:313.21,315.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:316.2,316.33 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:316.33,318.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:319.2,319.36 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:319.36,321.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:322.2,322.39 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:322.39,324.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:325.2,325.32 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:325.32,327.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:328.2,328.18 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:328.18,330.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:331.2,331.35 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:331.35,333.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:334.2,334.15 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:334.15,336.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:337.2,337.31 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:337.31,339.25 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:339.25,341.4 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:342.3,342.34 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:344.2,344.30 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:344.30,346.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:347.2,347.23 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:347.23,349.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:350.2,350.31 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:350.31,352.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:353.2,353.32 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:353.32,356.3 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:357.2,357.28 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:357.28,359.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:361.2,361.33 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:361.33,367.3 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:369.2,370.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:370.16,372.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:376.2,377.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:377.16,379.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:380.2,381.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:381.16,383.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:384.2,386.16 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:386.16,388.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:389.2,390.24 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:390.24,391.25 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:392.15,393.16 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:394.11,396.18 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:396.18,397.13 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:399.4,399.25 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:403.2,404.18 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:404.18,406.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:407.2,409.8 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:414.60,417.20 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:417.20,419.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:420.2,425.16 4 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:425.16,427.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:428.2,428.21 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:428.21,430.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:432.2,445.16 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:445.16,447.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:448.2,455.18 6 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:467.54,469.22 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:469.22,471.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/cli.go:472.2,472.29 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:71.63,101.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:101.16,103.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:105.2,106.40 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:106.40,108.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:109.2,111.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:111.16,113.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:118.2,120.17 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:193.45,212.24 5 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:212.24,214.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:231.2,232.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:232.16,234.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:235.2,242.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:242.16,244.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:246.2,247.35 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:247.35,252.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:253.2,254.33 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:254.33,259.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:260.2,261.33 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:261.33,267.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:268.2,280.39 4 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:280.39,282.17 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:282.17,284.4 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:285.3,286.53 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:289.2,290.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:290.16,292.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:294.2,295.18 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:295.18,297.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:298.2,339.16 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:339.16,341.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:343.2,343.49 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:343.49,345.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:346.2,346.39 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:346.39,349.30 3 0
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:349.30,351.4 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:352.3,352.37 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:355.2,355.21 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:359.47,361.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:363.100,441.16 10 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:441.16,443.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:445.2,445.11 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:445.11,447.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:449.2,453.16 5 0
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:453.16,455.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:456.2,456.12 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:459.84,472.16 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:472.16,474.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:476.2,477.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:477.16,479.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:481.2,481.46 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:547.73,561.56 8 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:561.56,563.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:567.2,567.12 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:571.94,573.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:573.16,575.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:578.2,579.85 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:579.85,581.21 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:581.21,583.4 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:584.3,584.49 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:597.2,603.80 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:603.80,607.3 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:609.2,609.23 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:613.86,617.2 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:619.62,621.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:621.16,623.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:624.2,624.66 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:624.66,626.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/client.go:627.2,627.22 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:40.49,42.23 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:42.23,44.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:45.2,45.10 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:48.47,59.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:61.53,70.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:77.9,78.22 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:78.22,80.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:81.2,81.66 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:81.66,83.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:85.2,86.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:86.16,88.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:89.2,91.36 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:91.36,94.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:95.2,95.16 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:95.16,97.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:99.2,102.12 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:109.105,115.68 4 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:115.68,117.17 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:117.17,119.4 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:120.3,120.15 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:123.2,123.37 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:123.37,125.17 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:125.17,127.4 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:130.2,130.33 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:130.33,133.17 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:133.17,135.4 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:136.3,136.44 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:136.44,138.4 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:142.2,142.45 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:142.45,143.35 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:143.35,145.18 2 0
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:145.18,147.5 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:148.4,148.45 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:148.45,150.5 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:154.2,154.44 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:158.70,160.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:162.58,163.102 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:163.102,164.17 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:164.17,166.4 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:167.3,167.18 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:167.18,169.4 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:172.3,173.17 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:173.17,175.4 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:176.3,176.46 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:178.2,178.16 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:178.16,180.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:182.2,182.44 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:185.53,190.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:190.16,192.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:193.2,194.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:194.16,196.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:197.2,197.12 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:205.91,211.33 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:211.33,214.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:218.2,218.26 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:218.26,220.44 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:220.44,221.12 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:223.3,223.17 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:223.17,225.4 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:226.3,229.17 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:229.17,231.4 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:232.3,232.29 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:235.2,235.17 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:238.48,241.2 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:243.49,246.2 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:250.64,252.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:252.16,254.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/context.go:255.2,255.77 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/dedent.go:9.30,13.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/dockerfile.go:12.50,29.2 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:48.51,79.2 9 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:81.38,82.16 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:82.16,84.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:85.2,85.87 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:88.36,89.17 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:89.17,91.17 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:91.17,93.4 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:94.3,94.40 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:96.2,96.23 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:96.23,98.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:99.2,99.20 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:99.20,101.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:102.2,102.14 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:107.43,108.14 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:108.14,110.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:111.2,111.25 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:124.52,129.2 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:131.40,132.14 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:132.14,134.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:135.2,136.18 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:136.18,138.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:139.2,139.18 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:139.18,141.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:143.2,150.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:157.49,160.2 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:162.37,163.14 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:163.14,165.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:166.2,166.79 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:184.51,213.2 8 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:215.39,216.14 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:216.14,218.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:219.2,220.19 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:220.19,222.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:223.2,223.27 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:223.27,225.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:226.2,226.23 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:226.23,228.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:229.2,229.32 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:229.32,231.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:232.2,232.28 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:232.28,234.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:235.2,235.21 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:235.21,237.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:238.2,238.20 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:238.20,240.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:241.2,248.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:255.54,257.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:259.42,260.14 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:260.14,262.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:263.2,263.82 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:270.39,271.14 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:271.14,273.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:274.2,274.50 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:277.51,279.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:285.37,286.14 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:286.14,288.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:289.2,289.48 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:296.53,299.2 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:301.40,302.18 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:302.18,304.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:305.2,305.49 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:314.61,322.2 6 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:324.48,325.29 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:325.29,327.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:328.2,329.25 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:329.25,331.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:332.2,332.28 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:332.28,334.14 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:334.14,336.4 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:337.3,337.65 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:339.2,339.31 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:339.31,341.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:342.2,342.33 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:349.42,351.28 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:351.28,353.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:354.2,354.33 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:357.55,359.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:365.48,367.34 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:367.34,369.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:370.2,371.33 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:374.61,378.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/export.go:380.61,382.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:24.45,26.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:26.16,28.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:30.2,31.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:31.16,33.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:34.2,40.15 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:49.64,55.43 4 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:55.43,57.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:59.2,60.70 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:60.70,62.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:63.2,67.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:67.16,69.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:74.2,74.42 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:74.42,76.17 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:76.17,78.4 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:79.3,82.17 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:82.17,84.4 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:85.2,86.31 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:86.31,87.23 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:87.23,88.13 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:90.4,90.40 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:90.40,91.13 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:93.4,93.23 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:93.23,94.13 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:96.4,97.18 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:97.18,98.13 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:100.4,100.28 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:100.28,101.24 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:101.24,102.26 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:104.5,104.66 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:104.66,105.26 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:111.4,112.9 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:119.2,120.39 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:120.39,122.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/host.go:124.2,127.20 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:62.45,83.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:112.50,285.2 23 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:297.51,328.2 4 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:330.96,333.55 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:333.55,335.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:337.2,344.33 4 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:354.47,356.38 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:356.38,358.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:361.2,363.58 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:363.58,365.26 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:365.26,366.38 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:366.38,368.5 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:391.2,391.28 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:398.39,400.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:402.63,404.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:406.62,432.2 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:434.39,438.2 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:441.40,442.13 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:442.13,444.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:445.2,445.31 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:445.31,446.17 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:446.17,448.4 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:450.2,450.14 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:453.50,454.30 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:454.30,456.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:457.2,457.22 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:467.58,469.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:471.32,473.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:475.45,477.30 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:477.30,479.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:480.2,480.35 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:483.34,485.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:490.20,492.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:492.16,494.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:496.2,496.26 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:496.26,501.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:503.2,503.54 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:503.54,507.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:509.2,511.8 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:517.87,520.25 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:520.25,524.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:525.2,525.24 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:525.24,529.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:530.2,530.49 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:530.49,534.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:536.2,536.31 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:536.31,538.53 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:538.53,539.66 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:539.66,541.62 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:541.62,546.6 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:548.9,548.84 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:548.84,553.4 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:556.2,556.34 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:556.34,558.54 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:558.54,561.4 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:564.2,564.32 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:564.32,566.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:570.2,573.19 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:573.19,575.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:576.2,576.19 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:576.19,578.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:579.2,579.37 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:579.37,580.23 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:580.23,581.12 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:583.3,583.45 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:583.45,591.12 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:593.3,594.17 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:594.17,596.12 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:598.3,599.74 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:599.74,607.12 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:609.3,609.33 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:612.2,612.13 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:612.13,614.29 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:614.29,615.25 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:615.25,617.5 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:621.2,622.39 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:622.39,624.17 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:624.17,626.12 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:628.3,628.44 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:631.2,632.39 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:632.39,633.23 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:633.23,634.12 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:636.3,636.45 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:636.45,644.12 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:646.3,647.17 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:647.17,649.12 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:651.3,651.23 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:651.23,652.12 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:654.3,654.43 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:657.2,658.37 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:658.37,659.23 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:659.23,660.12 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:662.3,662.45 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:662.45,670.12 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:672.3,673.17 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:673.17,675.12 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:677.3,677.23 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:677.23,678.12 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:680.3,680.39 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:683.2,684.33 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:684.33,686.17 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:686.17,688.12 2 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:690.3,690.23 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:690.23,691.12 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:693.3,693.31 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:696.2,696.76 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:696.76,704.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:706.2,706.34 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:706.34,707.47 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:707.47,709.4 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:712.2,713.37 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:713.37,718.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:720.2,741.23 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:751.23,755.16 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:755.16,757.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:759.2,760.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:760.16,762.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:763.2,763.9 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:763.9,765.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:767.2,768.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:768.16,770.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:772.2,777.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:777.16,779.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:780.2,782.46 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:782.46,784.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:785.2,785.35 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:785.35,788.3 2 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:790.2,791.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:791.16,793.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:795.2,795.41 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:795.41,798.17 3 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:798.17,800.4 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:805.2,805.30 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:805.30,806.74 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:806.74,808.4 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:811.2,811.24 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:811.24,814.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:818.2,818.33 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:818.33,820.10 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:820.10,821.12 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:824.3,825.8 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:828.2,828.19 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:837.31,840.2 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:854.3,856.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:856.16,858.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:867.2,867.25 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:867.25,870.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:872.2,875.33 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:875.33,877.10 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:877.10,880.9 2 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:884.3,885.17 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:885.17,887.12 2 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:890.3,890.27 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:890.27,891.87 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:891.87,893.13 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:895.4,895.20 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:895.20,897.13 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:900.4,901.9 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:907.2,907.49 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:907.49,909.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:911.2,913.32 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:923.9,925.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:925.16,927.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:929.2,931.33 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:931.33,933.17 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:933.17,934.12 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:936.3,937.30 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:937.30,938.12 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:940.3,942.31 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:942.31,943.23 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:943.23,945.5 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:946.4,946.24 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:946.24,948.5 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:954.2,954.17 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:964.34,968.54 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:968.54,970.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:971.2,971.56 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:971.56,973.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:974.2,974.48 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:974.48,976.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:977.2,977.52 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:977.52,979.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:980.2,980.56 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:980.56,982.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:983.2,983.52 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:983.52,985.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:986.2,986.52 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:986.52,988.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:989.2,989.64 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:989.64,991.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:992.2,992.58 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:992.58,994.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:995.2,995.54 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:995.54,997.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:999.2,999.58 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:999.58,1001.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1002.2,1002.50 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1002.50,1004.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1005.2,1005.28 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1005.28,1007.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1008.2,1008.34 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1008.34,1010.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1011.2,1011.52 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1011.52,1013.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1014.2,1014.56 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1014.56,1016.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1017.2,1017.28 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1017.28,1019.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1020.2,1020.28 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1020.28,1022.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1023.2,1023.52 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1023.52,1025.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1026.2,1026.44 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1026.44,1028.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1029.2,1029.46 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1029.46,1031.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1032.2,1032.50 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1032.50,1034.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1038.2,1038.68 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1038.68,1040.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1043.2,1048.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1048.16,1050.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1051.2,1051.30 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1051.30,1053.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1056.2,1056.50 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1056.50,1058.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1058.8,1059.42 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1059.42,1061.74 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1061.74,1062.13 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1064.4,1065.9 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1069.2,1073.8 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1076.41,1078.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1078.16,1080.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1081.2,1082.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1082.16,1084.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1085.2,1085.12 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1091.51,1093.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1093.16,1095.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1096.2,1097.48 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1097.48,1099.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1101.2,1104.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1104.16,1106.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/image.go:1108.2,1108.28 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:40.46,50.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:52.50,71.2 4 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:78.32,81.2 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:89.24,93.16 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:93.16,95.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:97.2,97.13 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:97.13,99.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:103.2,104.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:104.16,106.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:108.2,109.19 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:117.44,122.16 4 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:122.16,124.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:132.2,133.84 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:133.84,136.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:137.2,137.85 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:137.85,140.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:141.2,141.16 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:141.16,143.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:145.2,145.49 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:145.49,147.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:149.2,149.32 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:157.48,159.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:159.16,161.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:176.2,176.74 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:176.74,184.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:186.2,186.35 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:186.35,187.61 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:187.61,195.4 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:198.2,198.28 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:201.82,203.16 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:203.16,205.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:206.2,208.70 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:208.70,210.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:211.2,211.12 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:219.34,223.26 3 0
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:223.26,225.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:226.2,226.52 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:226.52,228.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:229.2,229.52 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:229.52,231.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:232.2,232.54 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:232.54,234.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:237.2,241.8 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:248.19,251.55 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:251.55,253.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/images.go:255.2,259.33 4 1
github.com/pulumi/pulumi-docker/provider/v4/internal/network.go:15.60,30.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/platform.go:26.54,57.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/platform.go:59.35,61.2 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:14.49,16.26 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:16.26,17.17 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:17.17,18.12 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:20.3,20.29 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:22.2,22.15 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:28.43,29.16 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:29.16,31.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:32.2,32.16 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:39.43,40.16 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:40.16,42.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:43.2,43.41 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:52.51,53.16 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:53.16,55.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:56.2,56.44 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:62.64,63.31 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:63.31,65.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:66.2,68.26 3 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:68.26,69.20 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:69.20,70.12 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:72.3,72.20 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:72.20,73.12 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:75.3,75.22 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:77.2,77.17 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:82.59,83.38 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:83.38,85.3 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:87.2,89.29 3 0
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:89.29,90.42 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:90.42,91.12 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:93.3,93.15 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/preview.go:96.2,99.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/ssh.go:14.43,31.2 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/ssh.go:33.30,34.16 1 1
github.com/pulumi/pulumi-docker/provider/v4/internal/ssh.go:34.16,36.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/ssh.go:38.2,40.22 2 1
github.com/pulumi/pulumi-docker/provider/v4/internal/ssh.go:40.22,42.3 1 0
github.com/pulumi/pulumi-docker/provider/v4/internal/ssh.go:44.2,44.10 1 1

View File

@@ -0,0 +1,27 @@
// Copyright 2024, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package internal
import (
"strings"
dd "github.com/muesli/reflow/dedent"
)
func dedent(s string) string {
return strings.TrimSpace(dd.String(
strings.ReplaceAll(s, `"`, "`"),
))
}

View File

@@ -0,0 +1,51 @@
// Copyright 2024, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package internal
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestDedent(t *testing.T) {
t.Parallel()
tests := []struct {
name string
given string
want string
}{
{
name: "simple case",
given: `
An optional map of named build-time argument variables to set during
the Docker build. This flag allows you to pass build-time variables that
can be accessed like environment variables inside the "RUN"
instruction.`,
want: `An optional map of named build-time argument variables to set during
the Docker build. This flag allows you to pass build-time variables that
can be accessed like environment variables inside the ` + "`RUN`\n" + `instruction.`,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
actual := dedent(tt.given)
assert.Equal(t, tt.want, actual)
})
}
}

View File

@@ -0,0 +1,211 @@
// Copyright 2024, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package deprecated
import (
"encoding/json"
"fmt"
"sort"
"google.golang.org/protobuf/types/known/structpb"
"github.com/pulumi/pulumi/pkg/v3/codegen/schema"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource/plugin"
)
// ConfigEncoding handles unmarshaling legacy JSON provider config.
type ConfigEncoding struct {
schema schema.ConfigSpec
}
// New constructs a new config encoder for the provided spec.
func New(s schema.ConfigSpec) *ConfigEncoding {
return &ConfigEncoding{schema: s}
}
func (*ConfigEncoding) tryUnwrapSecret(encoded any) (any, bool) {
m, ok := encoded.(map[string]any)
if !ok {
return nil, false
}
sig, ok := m["4dabf18193072939515e22adb298388d"]
if !ok {
return nil, false
}
ss, ok := sig.(string)
if !ok {
return nil, false
}
if ss != "1b47061264138c4ac30d75fd1eb44270" {
return nil, false
}
value, ok := m["value"]
return value, ok
}
func (enc *ConfigEncoding) convertStringToPropertyValue(s string, prop schema.PropertySpec) (
resource.PropertyValue, error,
) {
// If the schema expects a string, we can just return this as-is.
if prop.Type == "string" {
return resource.NewStringProperty(s), nil
}
// Otherwise, we will attempt to deserialize the input string as JSON and convert the result into a Pulumi
// property. If the input string is empty, we will return an appropriate zero value.
if s == "" {
return enc.zeroValue(prop.Type), nil
}
var jsonValue interface{}
if err := json.Unmarshal([]byte(s), &jsonValue); err != nil {
return resource.PropertyValue{}, err
}
opts := enc.unmarshalOpts()
// Instead of using resource.NewPropertyValue, specialize it to detect nested json-encoded secrets.
var replv func(encoded any) (resource.PropertyValue, bool)
replv = func(encoded any) (resource.PropertyValue, bool) {
encodedSecret, isSecret := enc.tryUnwrapSecret(encoded)
if !isSecret {
return resource.NewNullProperty(), false
}
v := resource.NewPropertyValueRepl(encodedSecret, nil, replv)
if opts.KeepSecrets {
v = resource.MakeSecret(v)
}
return v, true
}
return resource.NewPropertyValueRepl(jsonValue, nil, replv), nil
}
func (*ConfigEncoding) zeroValue(typ string) resource.PropertyValue {
switch typ {
case "boolean":
return resource.NewPropertyValue(false)
case "integer", "number":
return resource.NewPropertyValue(0)
case "array":
return resource.NewPropertyValue([]interface{}{})
default:
return resource.NewPropertyValue(map[string]interface{}{})
}
}
func (enc *ConfigEncoding) unmarshalOpts() plugin.MarshalOptions {
return plugin.MarshalOptions{
Label: "config",
KeepUnknowns: true,
SkipNulls: true,
RejectAssets: true,
}
}
// Like plugin.UnmarshalPropertyValue but overrides string parsing with convertStringToPropertyValue.
func (enc *ConfigEncoding) unmarshalPropertyValue(key resource.PropertyKey,
v *structpb.Value,
) (*resource.PropertyValue, error) {
opts := enc.unmarshalOpts()
pv, err := plugin.UnmarshalPropertyValue(key, v, enc.unmarshalOpts())
if err != nil {
return nil, fmt.Errorf("error unmarshalling property %q: %w", key, err)
}
prop, ok := enc.schema.Variables[string(key)]
// Only apply JSON-encoded recognition for known fields.
if !ok {
return pv, nil
}
var jsonString string
var jsonStringDetected, jsonStringSecret bool
if pv.IsString() {
jsonString = pv.StringValue()
jsonStringDetected = true
}
if opts.KeepSecrets && pv.IsSecret() && pv.SecretValue().Element.IsString() {
jsonString = pv.SecretValue().Element.StringValue()
jsonStringDetected = true
jsonStringSecret = true
}
if jsonStringDetected {
v, err := enc.convertStringToPropertyValue(jsonString, prop)
if err != nil {
return nil, fmt.Errorf("error unmarshalling property %q: %w", key, err)
}
if jsonStringSecret {
s := resource.MakeSecret(v)
return &s, nil
}
return &v, nil
}
// Computed sentinels are coming in as always having an empty string, but the encoding coerses them to a zero
// value of the appropriate type.
if pv.IsComputed() {
el := pv.V.(resource.Computed).Element
if el.IsString() && el.StringValue() == "" {
res := resource.MakeComputed(enc.zeroValue(prop.Type))
return &res, nil
}
}
return pv, nil
}
// UnmarshalProperties is copied from plugin.UnmarshalProperties substituting plugin.UnmarshalPropertyValue.
func (enc *ConfigEncoding) UnmarshalProperties(props *structpb.Struct) (resource.PropertyMap, error) {
opts := enc.unmarshalOpts()
result := make(resource.PropertyMap)
// First sort the keys so we enumerate them in order (in case errors happen, we want determinism).
var keys []string
if props != nil {
for k := range props.Fields {
keys = append(keys, k)
}
sort.Strings(keys)
}
// And now unmarshal every field it into the map.
for _, key := range keys {
pk := resource.PropertyKey(key)
v, err := enc.unmarshalPropertyValue(pk, props.Fields[key])
if err != nil {
return nil, err
} else if v != nil {
if opts.SkipNulls && v.IsNull() {
continue
}
if opts.SkipInternalKeys && resource.IsInternalPropertyKey(pk) {
continue
}
result[pk] = *v
}
}
return result, nil
}

Some files were not shown because too many files have changed in this diff Show More