Compare commits
45 Commits
Author | SHA1 | Date |
---|---|---|
CrazyMax | 4e547752af | 2 years ago |
CrazyMax | 95eee3e747 | 2 years ago |
CrazyMax | d5bfd8334f | 2 years ago |
CrazyMax | 2083f24938 | 2 years ago |
CrazyMax | 84da4ec603 | 2 years ago |
Sebastiaan van Stijn | 35dac12ae5 | 2 years ago |
Sebastiaan van Stijn | 27f332f135 | 2 years ago |
Justin Chadwell | 9872040b66 | 2 years ago |
Sebastiaan van Stijn | d8c6c3fc30 | 2 years ago |
Sebastiaan van Stijn | 69f929077b | 2 years ago |
Sebastiaan van Stijn | 87ce701fe0 | 2 years ago |
Justin Chadwell | 6faf7e5688 | 2 years ago |
Justin Chadwell | d21e9fa8c6 | 2 years ago |
Justin Chadwell | 5657006c1f | 2 years ago |
Justin Chadwell | 0424ae14c0 | 2 years ago |
Justin Chadwell | 66fd2bbdee | 2 years ago |
CrazyMax | 3305f18ce5 | 2 years ago |
CrazyMax | a8790788d1 | 2 years ago |
CrazyMax | 0f6513a29a | 2 years ago |
Justin Chadwell | 44f5946a66 | 2 years ago |
CrazyMax | ea610d8f14 | 2 years ago |
Sebastiaan van Stijn | d78c75947d | 2 years ago |
CrazyMax | 7dddd3a7d3 | 2 years ago |
CrazyMax | 54de900931 | 2 years ago |
Justin Chadwell | 50e414f82a | 2 years ago |
Justin Chadwell | a24b6dd4f5 | 2 years ago |
CrazyMax | 66600be6ab | 2 years ago |
Justin Chadwell | b4df08551f | 2 years ago |
Justin Chadwell | f581942d7d | 2 years ago |
Justin Chadwell | 5159571dfc | 2 years ago |
Justin Chadwell | 86a5c77c2b | 2 years ago |
Justin Chadwell | 1602b491f9 | 2 years ago |
CrazyMax | 94baaf3c90 | 2 years ago |
CrazyMax | c5e279f295 | 2 years ago |
CrazyMax | a0f91eb87e | 2 years ago |
CrazyMax | cb1812ec6a | 2 years ago |
CrazyMax | 47e4c2576b | 2 years ago |
CrazyMax | 3702e17ed5 | 2 years ago |
Jhan S. Álvarez | 8b85dbea72 | 2 years ago |
CrazyMax | afcb118e10 | 2 years ago |
David Karlsson | cb4fea66e0 | 2 years ago |
CrazyMax | 74fa66b496 | 2 years ago |
Justin Chadwell | ff87dd183a | 2 years ago |
CrazyMax | 9f844df9f7 | 2 years ago |
Justin Chadwell | bc597e6b5e | 2 years ago |
@ -1,25 +0,0 @@
|
|||||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
|
||||||
// README at: https://github.com/devcontainers/templates/tree/main/src/go
|
|
||||||
{
|
|
||||||
"name": "Go",
|
|
||||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
|
||||||
"image": "mcr.microsoft.com/devcontainers/go:1-1.21-bullseye",
|
|
||||||
"features": {
|
|
||||||
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Features to add to the dev container. More info: https://containers.dev/features.
|
|
||||||
// "features": {},
|
|
||||||
|
|
||||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
|
||||||
// "forwardPorts": [],
|
|
||||||
|
|
||||||
// Use 'postCreateCommand' to run commands after the container is created.
|
|
||||||
// "postCreateCommand": "go version",
|
|
||||||
|
|
||||||
// Configure tool-specific properties.
|
|
||||||
// "customizations": {},
|
|
||||||
|
|
||||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
|
||||||
// "remoteUser": "root"
|
|
||||||
}
|
|
Binary file not shown.
@ -1,267 +0,0 @@
|
|||||||
package tests
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"os/exec"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/containerd/containerd/images"
|
|
||||||
"github.com/containerd/containerd/platforms"
|
|
||||||
"github.com/containerd/continuity/fs/fstest"
|
|
||||||
"github.com/moby/buildkit/util/testutil/integration"
|
|
||||||
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
var imagetoolsTests = []func(t *testing.T, sb integration.Sandbox){
|
|
||||||
testImagetoolsCopyManifest,
|
|
||||||
testImagetoolsCopyIndex,
|
|
||||||
testImagetoolsInspectAndFilter,
|
|
||||||
testImagetoolsAnnotation,
|
|
||||||
}
|
|
||||||
|
|
||||||
func testImagetoolsCopyManifest(t *testing.T, sb integration.Sandbox) {
|
|
||||||
if sb.Name() != "docker-container" {
|
|
||||||
t.Skip("imagetools tests are not driver specific and only run on docker-container")
|
|
||||||
}
|
|
||||||
|
|
||||||
dir := createDockerfile(t)
|
|
||||||
registry, err := sb.NewRegistry()
|
|
||||||
if errors.Is(err, integration.ErrRequirements) {
|
|
||||||
t.Skip(err.Error())
|
|
||||||
}
|
|
||||||
require.NoError(t, err)
|
|
||||||
target := registry + "/buildx/imtools-manifest:latest"
|
|
||||||
|
|
||||||
out, err := buildCmd(sb, withArgs("-t", target, "--push", "--platform=linux/amd64", "--provenance=false", dir))
|
|
||||||
require.NoError(t, err, string(out))
|
|
||||||
|
|
||||||
cmd := buildxCmd(sb, withArgs("imagetools", "inspect", target, "--raw"))
|
|
||||||
dt, err := cmd.CombinedOutput()
|
|
||||||
require.NoError(t, err, string(dt))
|
|
||||||
|
|
||||||
var mfst ocispecs.Manifest
|
|
||||||
err = json.Unmarshal(dt, &mfst)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, images.MediaTypeDockerSchema2Manifest, mfst.MediaType)
|
|
||||||
|
|
||||||
registry2, err := sb.NewRegistry()
|
|
||||||
require.NoError(t, err)
|
|
||||||
target2 := registry2 + "/buildx/imtools2-manifest:latest"
|
|
||||||
|
|
||||||
cmd = buildxCmd(sb, withArgs("imagetools", "create", "-t", target2, target))
|
|
||||||
dt, err = cmd.CombinedOutput()
|
|
||||||
require.NoError(t, err, string(dt))
|
|
||||||
|
|
||||||
cmd = buildxCmd(sb, withArgs("imagetools", "inspect", target2, "--raw"))
|
|
||||||
dt, err = cmd.CombinedOutput()
|
|
||||||
require.NoError(t, err, string(dt))
|
|
||||||
|
|
||||||
var idx2 ocispecs.Index
|
|
||||||
err = json.Unmarshal(dt, &idx2)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, images.MediaTypeDockerSchema2ManifestList, idx2.MediaType)
|
|
||||||
require.Equal(t, 1, len(idx2.Manifests))
|
|
||||||
|
|
||||||
cmd = buildxCmd(sb, withArgs("imagetools", "inspect", target2+"@"+string(idx2.Manifests[0].Digest), "--raw"))
|
|
||||||
dt, err = cmd.CombinedOutput()
|
|
||||||
require.NoError(t, err, string(dt))
|
|
||||||
|
|
||||||
var mfst2 ocispecs.Manifest
|
|
||||||
err = json.Unmarshal(dt, &mfst2)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, images.MediaTypeDockerSchema2Manifest, mfst2.MediaType)
|
|
||||||
|
|
||||||
require.Equal(t, mfst.Config.Digest, mfst2.Config.Digest)
|
|
||||||
require.Equal(t, len(mfst.Layers), len(mfst2.Layers))
|
|
||||||
for i := range mfst.Layers {
|
|
||||||
require.Equal(t, mfst.Layers[i].Digest, mfst2.Layers[i].Digest)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testImagetoolsCopyIndex(t *testing.T, sb integration.Sandbox) {
|
|
||||||
if sb.Name() != "docker-container" {
|
|
||||||
t.Skip("imagetools tests are not driver specific and only run on docker-container")
|
|
||||||
}
|
|
||||||
|
|
||||||
dir := createDockerfile(t)
|
|
||||||
registry, err := sb.NewRegistry()
|
|
||||||
if errors.Is(err, integration.ErrRequirements) {
|
|
||||||
t.Skip(err.Error())
|
|
||||||
}
|
|
||||||
require.NoError(t, err)
|
|
||||||
target := registry + "/buildx/imtools:latest"
|
|
||||||
|
|
||||||
out, err := buildCmd(sb, withArgs("-t", target, "--push", "--platform=linux/amd64,linux/arm64", "--provenance=false", dir))
|
|
||||||
require.NoError(t, err, string(out))
|
|
||||||
|
|
||||||
cmd := buildxCmd(sb, withArgs("imagetools", "inspect", target, "--raw"))
|
|
||||||
dt, err := cmd.CombinedOutput()
|
|
||||||
require.NoError(t, err, string(dt))
|
|
||||||
|
|
||||||
var idx ocispecs.Index
|
|
||||||
err = json.Unmarshal(dt, &idx)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, images.MediaTypeDockerSchema2ManifestList, idx.MediaType)
|
|
||||||
require.Equal(t, 2, len(idx.Manifests))
|
|
||||||
|
|
||||||
registry2, err := sb.NewRegistry()
|
|
||||||
require.NoError(t, err)
|
|
||||||
target2 := registry2 + "/buildx/imtools2:latest"
|
|
||||||
|
|
||||||
cmd = buildxCmd(sb, withArgs("imagetools", "create", "-t", target2, target))
|
|
||||||
dt, err = cmd.CombinedOutput()
|
|
||||||
require.NoError(t, err, string(dt))
|
|
||||||
|
|
||||||
cmd = buildxCmd(sb, withArgs("imagetools", "inspect", target2, "--raw"))
|
|
||||||
dt, err = cmd.CombinedOutput()
|
|
||||||
require.NoError(t, err, string(dt))
|
|
||||||
|
|
||||||
var idx2 ocispecs.Index
|
|
||||||
err = json.Unmarshal(dt, &idx2)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, images.MediaTypeDockerSchema2ManifestList, idx2.MediaType)
|
|
||||||
|
|
||||||
require.Equal(t, len(idx.Manifests), len(idx2.Manifests))
|
|
||||||
for i := range idx.Manifests {
|
|
||||||
require.Equal(t, idx.Manifests[i].Digest, idx2.Manifests[i].Digest)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testImagetoolsInspectAndFilter(t *testing.T, sb integration.Sandbox) {
|
|
||||||
if sb.Name() != "docker-container" {
|
|
||||||
t.Skip("imagetools tests are not driver specific and only run on docker-container")
|
|
||||||
}
|
|
||||||
|
|
||||||
dir := createDockerfile(t)
|
|
||||||
registry, err := sb.NewRegistry()
|
|
||||||
if errors.Is(err, integration.ErrRequirements) {
|
|
||||||
t.Skip(err.Error())
|
|
||||||
}
|
|
||||||
require.NoError(t, err)
|
|
||||||
target := registry + "/buildx/imtools:latest"
|
|
||||||
|
|
||||||
out, err := buildCmd(sb, withArgs("-t", target, "--push", "--platform=linux/amd64,linux/arm64", "--provenance=false", dir))
|
|
||||||
require.NoError(t, err, string(out))
|
|
||||||
|
|
||||||
cmd := buildxCmd(sb, withArgs("imagetools", "inspect", target, "--raw"))
|
|
||||||
dt, err := cmd.CombinedOutput()
|
|
||||||
require.NoError(t, err, string(dt))
|
|
||||||
|
|
||||||
var idx ocispecs.Index
|
|
||||||
err = json.Unmarshal(dt, &idx)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
require.Equal(t, 2, len(idx.Manifests))
|
|
||||||
|
|
||||||
mfst := idx.Manifests[0]
|
|
||||||
require.Equal(t, "linux/amd64", platforms.Format(*mfst.Platform))
|
|
||||||
|
|
||||||
mfst = idx.Manifests[1]
|
|
||||||
require.Equal(t, "linux/arm64", platforms.Format(*mfst.Platform))
|
|
||||||
|
|
||||||
// create amd64 only image
|
|
||||||
cmd = buildxCmd(sb, withArgs("imagetools", "create", "-t", target+"-arm64", target+"@"+string(idx.Manifests[1].Digest)))
|
|
||||||
dt, err = cmd.CombinedOutput()
|
|
||||||
require.NoError(t, err, string(dt))
|
|
||||||
|
|
||||||
cmd = buildxCmd(sb, withArgs("imagetools", "inspect", target+"-arm64", "--raw"))
|
|
||||||
dt, err = cmd.CombinedOutput()
|
|
||||||
require.NoError(t, err, string(dt))
|
|
||||||
|
|
||||||
var idx2 ocispecs.Index
|
|
||||||
err = json.Unmarshal(dt, &idx2)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
require.Equal(t, 1, len(idx2.Manifests))
|
|
||||||
|
|
||||||
require.Equal(t, idx.Manifests[1].Digest, idx2.Manifests[0].Digest)
|
|
||||||
require.Equal(t, platforms.Format(*idx.Manifests[1].Platform), platforms.Format(*idx2.Manifests[0].Platform))
|
|
||||||
}
|
|
||||||
|
|
||||||
func testImagetoolsAnnotation(t *testing.T, sb integration.Sandbox) {
|
|
||||||
if sb.Name() != "docker-container" {
|
|
||||||
t.Skip("imagetools tests are not driver specific and only run on docker-container")
|
|
||||||
}
|
|
||||||
|
|
||||||
dir := createDockerfile(t)
|
|
||||||
registry, err := sb.NewRegistry()
|
|
||||||
if errors.Is(err, integration.ErrRequirements) {
|
|
||||||
t.Skip(err.Error())
|
|
||||||
}
|
|
||||||
require.NoError(t, err)
|
|
||||||
target := registry + "/buildx/imtools:latest"
|
|
||||||
|
|
||||||
out, err := buildCmd(sb, withArgs("--output", "type=registry,oci-mediatypes=true,name="+target, "--platform=linux/amd64,linux/arm64", "--provenance=false", dir))
|
|
||||||
require.NoError(t, err, string(out))
|
|
||||||
|
|
||||||
cmd := buildxCmd(sb, withArgs("imagetools", "inspect", target, "--raw"))
|
|
||||||
dt, err := cmd.CombinedOutput()
|
|
||||||
require.NoError(t, err, string(dt))
|
|
||||||
|
|
||||||
var idx ocispecs.Index
|
|
||||||
err = json.Unmarshal(dt, &idx)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Empty(t, idx.Annotations)
|
|
||||||
|
|
||||||
imagetoolsCmd := func(source []string) *exec.Cmd {
|
|
||||||
args := []string{"imagetools", "create", "-t", target, "--annotation", "index:foo=bar", "--annotation", "index:bar=baz",
|
|
||||||
"--annotation", "manifest-descriptor:foo=bar", "--annotation", "manifest-descriptor[linux/amd64]:bar=baz"}
|
|
||||||
args = append(args, source...)
|
|
||||||
return buildxCmd(sb, withArgs(args...))
|
|
||||||
}
|
|
||||||
sources := [][]string{
|
|
||||||
{
|
|
||||||
target,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
target + "@" + string(idx.Manifests[0].Digest),
|
|
||||||
target + "@" + string(idx.Manifests[1].Digest),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, source := range sources {
|
|
||||||
cmd = imagetoolsCmd(source)
|
|
||||||
dt, err = cmd.CombinedOutput()
|
|
||||||
require.NoError(t, err, string(dt))
|
|
||||||
|
|
||||||
newTarget := registry + "/buildx/imtools:annotations"
|
|
||||||
cmd = buildxCmd(sb, withArgs("imagetools", "create", "-t", newTarget, target))
|
|
||||||
dt, err = cmd.CombinedOutput()
|
|
||||||
require.NoError(t, err, string(dt))
|
|
||||||
|
|
||||||
cmd = buildxCmd(sb, withArgs("imagetools", "inspect", newTarget, "--raw"))
|
|
||||||
dt, err = cmd.CombinedOutput()
|
|
||||||
require.NoError(t, err, string(dt))
|
|
||||||
|
|
||||||
err = json.Unmarshal(dt, &idx)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Len(t, idx.Annotations, 2)
|
|
||||||
require.Equal(t, "bar", idx.Annotations["foo"])
|
|
||||||
require.Equal(t, "baz", idx.Annotations["bar"])
|
|
||||||
require.Len(t, idx.Manifests, 2)
|
|
||||||
for _, mfst := range idx.Manifests {
|
|
||||||
require.Equal(t, "bar", mfst.Annotations["foo"])
|
|
||||||
if platforms.Format(*mfst.Platform) == "linux/amd64" {
|
|
||||||
require.Equal(t, "baz", mfst.Annotations["bar"])
|
|
||||||
} else {
|
|
||||||
require.Empty(t, mfst.Annotations["bar"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func createDockerfile(t *testing.T) string {
|
|
||||||
dockerfile := []byte(`
|
|
||||||
FROM scratch
|
|
||||||
ARG TARGETARCH
|
|
||||||
COPY foo-${TARGETARCH} /foo
|
|
||||||
`)
|
|
||||||
dir := tmpdir(
|
|
||||||
t,
|
|
||||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
|
||||||
fstest.CreateFile("foo-amd64", []byte("foo-amd64"), 0600),
|
|
||||||
fstest.CreateFile("foo-arm64", []byte("foo-arm64"), 0600),
|
|
||||||
)
|
|
||||||
return dir
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
package tests
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/moby/buildkit/util/testutil/integration"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"golang.org/x/mod/module"
|
|
||||||
"golang.org/x/mod/semver"
|
|
||||||
)
|
|
||||||
|
|
||||||
var versionTests = []func(t *testing.T, sb integration.Sandbox){
|
|
||||||
testVersion,
|
|
||||||
}
|
|
||||||
|
|
||||||
func testVersion(t *testing.T, sb integration.Sandbox) {
|
|
||||||
cmd := buildxCmd(sb, withArgs("version"))
|
|
||||||
out, err := cmd.CombinedOutput()
|
|
||||||
require.NoError(t, err, string(out))
|
|
||||||
|
|
||||||
// There should be at least one newline and the first line
|
|
||||||
// of output should contain the name, version, and possibly a revision.
|
|
||||||
firstLine, _, hasNewline := strings.Cut(string(out), "\n")
|
|
||||||
require.True(t, hasNewline, "At least one newline is required in the output")
|
|
||||||
|
|
||||||
// Log the output to make debugging easier.
|
|
||||||
t.Log(firstLine)
|
|
||||||
|
|
||||||
// Split by spaces into at least 2 fields.
|
|
||||||
fields := strings.Fields(firstLine)
|
|
||||||
require.GreaterOrEqual(t, len(fields), 2, "Expected at least 2 fields in the first line")
|
|
||||||
|
|
||||||
// First field should be an import path.
|
|
||||||
// This can be any valid import path for Go
|
|
||||||
// so don't set too many restrictions here.
|
|
||||||
// Just checking if the import path is a valid Go
|
|
||||||
// path should be suitable enough to make sure this is ok.
|
|
||||||
// Using CheckImportPath instead of CheckPath as it is less
|
|
||||||
// restrictive.
|
|
||||||
importPath := fields[0]
|
|
||||||
require.NoError(t, module.CheckImportPath(importPath), "First field was not a valid import path: %+v", importPath)
|
|
||||||
|
|
||||||
// Second field should be a version.
|
|
||||||
// This defaults to something that's still compatible
|
|
||||||
// with semver.
|
|
||||||
version := fields[1]
|
|
||||||
require.True(t, semver.IsValid(version), "Second field was not valid semver: %+v", version)
|
|
||||||
|
|
||||||
// Revision should be empty or should look like a git hash.
|
|
||||||
if len(fields) > 2 && len(fields[2]) > 0 {
|
|
||||||
revision := fields[2]
|
|
||||||
require.Regexp(t, `[0-9a-f]{40}`, revision, "Third field was not a git revision: %+v", revision)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
package workers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/moby/buildkit/util/testutil/integration"
|
|
||||||
)
|
|
||||||
|
|
||||||
var features = map[string]struct{}{}
|
|
||||||
|
|
||||||
func CheckFeatureCompat(t *testing.T, sb integration.Sandbox, reason ...string) {
|
|
||||||
integration.CheckFeatureCompat(t, sb, features, reason...)
|
|
||||||
}
|
|
@ -1,15 +1,21 @@
|
|||||||
package buildflags
|
package buildflags
|
||||||
|
|
||||||
import "github.com/moby/buildkit/util/entitlements"
|
import (
|
||||||
|
"github.com/moby/buildkit/util/entitlements"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
func ParseEntitlements(in []string) ([]entitlements.Entitlement, error) {
|
func ParseEntitlements(in []string) ([]entitlements.Entitlement, error) {
|
||||||
out := make([]entitlements.Entitlement, 0, len(in))
|
out := make([]entitlements.Entitlement, 0, len(in))
|
||||||
for _, v := range in {
|
for _, v := range in {
|
||||||
e, err := entitlements.Parse(v)
|
switch v {
|
||||||
if err != nil {
|
case "security.insecure":
|
||||||
return nil, err
|
out = append(out, entitlements.EntitlementSecurityInsecure)
|
||||||
|
case "network.host":
|
||||||
|
out = append(out, entitlements.EntitlementNetworkHost)
|
||||||
|
default:
|
||||||
|
return nil, errors.Errorf("invalid entitlement: %v", v)
|
||||||
}
|
}
|
||||||
out = append(out, e)
|
|
||||||
}
|
}
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
@ -1,84 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2020 The Compose Specification Authors.
|
|
||||||
|
|
||||||
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 dotenv
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetEnvFromFile(currentEnv map[string]string, workingDir string, filenames []string) (map[string]string, error) {
|
|
||||||
envMap := make(map[string]string)
|
|
||||||
|
|
||||||
dotEnvFiles := filenames
|
|
||||||
if len(dotEnvFiles) == 0 {
|
|
||||||
dotEnvFiles = append(dotEnvFiles, filepath.Join(workingDir, ".env"))
|
|
||||||
}
|
|
||||||
for _, dotEnvFile := range dotEnvFiles {
|
|
||||||
abs, err := filepath.Abs(dotEnvFile)
|
|
||||||
if err != nil {
|
|
||||||
return envMap, err
|
|
||||||
}
|
|
||||||
dotEnvFile = abs
|
|
||||||
|
|
||||||
s, err := os.Stat(dotEnvFile)
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
if len(filenames) == 0 {
|
|
||||||
return envMap, nil
|
|
||||||
}
|
|
||||||
return envMap, errors.Errorf("Couldn't find env file: %s", dotEnvFile)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return envMap, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.IsDir() {
|
|
||||||
if len(filenames) == 0 {
|
|
||||||
return envMap, nil
|
|
||||||
}
|
|
||||||
return envMap, errors.Errorf("%s is a directory", dotEnvFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := os.ReadFile(dotEnvFile)
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return nil, errors.Errorf("Couldn't read env file: %s", dotEnvFile)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return envMap, err
|
|
||||||
}
|
|
||||||
|
|
||||||
env, err := ParseWithLookup(bytes.NewReader(b), func(k string) (string, bool) {
|
|
||||||
v, ok := currentEnv[k]
|
|
||||||
if ok {
|
|
||||||
return v, true
|
|
||||||
}
|
|
||||||
v, ok = envMap[k]
|
|
||||||
return v, ok
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return envMap, errors.Wrapf(err, "failed to read %s", dotEnvFile)
|
|
||||||
}
|
|
||||||
for k, v := range env {
|
|
||||||
envMap[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return envMap, nil
|
|
||||||
}
|
|
@ -1,120 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2020 The Compose Specification Authors.
|
|
||||||
|
|
||||||
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 loader
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/compose-spec/compose-go/dotenv"
|
|
||||||
"github.com/compose-spec/compose-go/types"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// LoadIncludeConfig parse the require config from raw yaml
|
|
||||||
func LoadIncludeConfig(source []interface{}) ([]types.IncludeConfig, error) {
|
|
||||||
var requires []types.IncludeConfig
|
|
||||||
err := Transform(source, &requires)
|
|
||||||
return requires, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var transformIncludeConfig TransformerFunc = func(data interface{}) (interface{}, error) {
|
|
||||||
switch value := data.(type) {
|
|
||||||
case string:
|
|
||||||
return map[string]interface{}{"path": value}, nil
|
|
||||||
case map[string]interface{}:
|
|
||||||
return value, nil
|
|
||||||
default:
|
|
||||||
return data, errors.Errorf("invalid type %T for `include` configuration", value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadInclude(configDetails types.ConfigDetails, model *types.Config, options *Options, loaded []string) (*types.Config, error) {
|
|
||||||
for _, r := range model.Include {
|
|
||||||
for i, p := range r.Path {
|
|
||||||
if !filepath.IsAbs(p) {
|
|
||||||
r.Path[i] = filepath.Join(configDetails.WorkingDir, p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if r.ProjectDirectory == "" {
|
|
||||||
r.ProjectDirectory = filepath.Dir(r.Path[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
loadOptions := options.clone()
|
|
||||||
loadOptions.SetProjectName(model.Name, true)
|
|
||||||
loadOptions.ResolvePaths = true
|
|
||||||
loadOptions.SkipNormalization = true
|
|
||||||
loadOptions.SkipConsistencyCheck = true
|
|
||||||
|
|
||||||
env, err := dotenv.GetEnvFromFile(configDetails.Environment, r.ProjectDirectory, r.EnvFile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
imported, err := load(types.ConfigDetails{
|
|
||||||
WorkingDir: r.ProjectDirectory,
|
|
||||||
ConfigFiles: types.ToConfigFiles(r.Path),
|
|
||||||
Environment: env,
|
|
||||||
}, loadOptions, loaded)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = importResources(model, imported, r.Path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
model.Include = nil
|
|
||||||
return model, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// importResources import into model all resources defined by imported, and report error on conflict
|
|
||||||
func importResources(model *types.Config, imported *types.Project, path []string) error {
|
|
||||||
services := mapByName(model.Services)
|
|
||||||
for _, service := range imported.Services {
|
|
||||||
if _, ok := services[service.Name]; ok {
|
|
||||||
return fmt.Errorf("imported compose file %s defines conflicting service %s", path, service.Name)
|
|
||||||
}
|
|
||||||
model.Services = append(model.Services, service)
|
|
||||||
}
|
|
||||||
for n, network := range imported.Networks {
|
|
||||||
if _, ok := model.Networks[n]; ok {
|
|
||||||
return fmt.Errorf("imported compose file %s defines conflicting network %s", path, n)
|
|
||||||
}
|
|
||||||
model.Networks[n] = network
|
|
||||||
}
|
|
||||||
for n, volume := range imported.Volumes {
|
|
||||||
if _, ok := model.Volumes[n]; ok {
|
|
||||||
return fmt.Errorf("imported compose file %s defines conflicting volume %s", path, n)
|
|
||||||
}
|
|
||||||
model.Volumes[n] = volume
|
|
||||||
}
|
|
||||||
for n, secret := range imported.Secrets {
|
|
||||||
if _, ok := model.Secrets[n]; ok {
|
|
||||||
return fmt.Errorf("imported compose file %s defines conflicting secret %s", path, n)
|
|
||||||
}
|
|
||||||
model.Secrets[n] = secret
|
|
||||||
}
|
|
||||||
for n, config := range imported.Configs {
|
|
||||||
if _, ok := model.Configs[n]; ok {
|
|
||||||
return fmt.Errorf("imported compose file %s defines conflicting config %s", path, n)
|
|
||||||
}
|
|
||||||
model.Configs[n] = config
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,135 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2020 The Compose Specification Authors.
|
|
||||||
|
|
||||||
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 loader
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/compose-spec/compose-go/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ResolveRelativePaths resolves relative paths based on project WorkingDirectory
|
|
||||||
func ResolveRelativePaths(project *types.Project) error {
|
|
||||||
absWorkingDir, err := filepath.Abs(project.WorkingDir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
project.WorkingDir = absWorkingDir
|
|
||||||
|
|
||||||
absComposeFiles, err := absComposeFiles(project.ComposeFiles)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
project.ComposeFiles = absComposeFiles
|
|
||||||
|
|
||||||
for i, s := range project.Services {
|
|
||||||
ResolveServiceRelativePaths(project.WorkingDir, &s)
|
|
||||||
project.Services[i] = s
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, obj := range project.Configs {
|
|
||||||
if obj.File != "" {
|
|
||||||
obj.File = absPath(project.WorkingDir, obj.File)
|
|
||||||
project.Configs[i] = obj
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, obj := range project.Secrets {
|
|
||||||
if obj.File != "" {
|
|
||||||
obj.File = resolveMaybeUnixPath(project.WorkingDir, obj.File)
|
|
||||||
project.Secrets[i] = obj
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, config := range project.Volumes {
|
|
||||||
if config.Driver == "local" && config.DriverOpts["o"] == "bind" {
|
|
||||||
// This is actually a bind mount
|
|
||||||
config.DriverOpts["device"] = resolveMaybeUnixPath(project.WorkingDir, config.DriverOpts["device"])
|
|
||||||
project.Volumes[name] = config
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ResolveServiceRelativePaths(workingDir string, s *types.ServiceConfig) {
|
|
||||||
if s.Build != nil {
|
|
||||||
if !isRemoteContext(s.Build.Context) {
|
|
||||||
s.Build.Context = absPath(workingDir, s.Build.Context)
|
|
||||||
}
|
|
||||||
for name, path := range s.Build.AdditionalContexts {
|
|
||||||
if strings.Contains(path, "://") { // `docker-image://` or any builder specific context type
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if isRemoteContext(path) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
s.Build.AdditionalContexts[name] = absPath(workingDir, path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for j, f := range s.EnvFile {
|
|
||||||
s.EnvFile[j] = absPath(workingDir, f)
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.Extends != nil && s.Extends.File != "" {
|
|
||||||
s.Extends.File = absPath(workingDir, s.Extends.File)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, vol := range s.Volumes {
|
|
||||||
if vol.Type != types.VolumeTypeBind {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
s.Volumes[i].Source = resolveMaybeUnixPath(workingDir, vol.Source)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func absPath(workingDir string, filePath string) string {
|
|
||||||
if strings.HasPrefix(filePath, "~") {
|
|
||||||
home, _ := os.UserHomeDir()
|
|
||||||
return filepath.Join(home, filePath[1:])
|
|
||||||
}
|
|
||||||
if filepath.IsAbs(filePath) {
|
|
||||||
return filePath
|
|
||||||
}
|
|
||||||
return filepath.Join(workingDir, filePath)
|
|
||||||
}
|
|
||||||
|
|
||||||
func absComposeFiles(composeFiles []string) ([]string, error) {
|
|
||||||
for i, composeFile := range composeFiles {
|
|
||||||
absComposefile, err := filepath.Abs(composeFile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
composeFiles[i] = absComposefile
|
|
||||||
}
|
|
||||||
return composeFiles, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// isRemoteContext returns true if the value is a Git reference or HTTP(S) URL.
|
|
||||||
//
|
|
||||||
// Any other value is assumed to be a local filesystem path and returns false.
|
|
||||||
//
|
|
||||||
// See: https://github.com/moby/buildkit/blob/18fc875d9bfd6e065cd8211abc639434ba65aa56/frontend/dockerui/context.go#L76-L79
|
|
||||||
func isRemoteContext(maybeURL string) bool {
|
|
||||||
for _, prefix := range []string{"https://", "http://", "git://", "ssh://", "github.com/", "git@"} {
|
|
||||||
if strings.HasPrefix(maybeURL, prefix) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2020 The Compose Specification Authors.
|
|
||||||
|
|
||||||
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 utils
|
|
||||||
|
|
||||||
import "golang.org/x/exp/slices"
|
|
||||||
|
|
||||||
func MapKeys[T comparable, U any](theMap map[T]U) []T {
|
|
||||||
var result []T
|
|
||||||
for key := range theMap {
|
|
||||||
result = append(result, key)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func MapsAppend[T comparable, U any](target map[T]U, source map[T]U) map[T]U {
|
|
||||||
if target == nil {
|
|
||||||
return source
|
|
||||||
}
|
|
||||||
if source == nil {
|
|
||||||
return target
|
|
||||||
}
|
|
||||||
for key, value := range source {
|
|
||||||
if _, ok := target[key]; !ok {
|
|
||||||
target[key] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return target
|
|
||||||
}
|
|
||||||
|
|
||||||
func ArrayContains[T comparable](source []T, toCheck []T) bool {
|
|
||||||
for _, value := range toCheck {
|
|
||||||
if !slices.Contains(source, value) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
[568].out
|
|
||||||
_go*
|
|
||||||
_test*
|
|
||||||
_obj
|
|
@ -1,17 +0,0 @@
|
|||||||
ARG GOVERSION=1.14
|
|
||||||
FROM golang:${GOVERSION}
|
|
||||||
|
|
||||||
# Set base env.
|
|
||||||
ARG GOOS=linux
|
|
||||||
ARG GOARCH=amd64
|
|
||||||
ENV GOOS=${GOOS} GOARCH=${GOARCH} CGO_ENABLED=0 GOFLAGS='-v -ldflags=-s -ldflags=-w'
|
|
||||||
|
|
||||||
# Pre compile the stdlib for 386/arm (32bits).
|
|
||||||
RUN go build -a std
|
|
||||||
|
|
||||||
# Add the code to the image.
|
|
||||||
WORKDIR pty
|
|
||||||
ADD . .
|
|
||||||
|
|
||||||
# Build the lib.
|
|
||||||
RUN go build
|
|
@ -1,23 +0,0 @@
|
|||||||
# NOTE: Using 1.13 as a base to build the RISCV compiler, the resulting version is based on go1.6.
|
|
||||||
FROM golang:1.13
|
|
||||||
|
|
||||||
# Clone and complie a riscv compatible version of the go compiler.
|
|
||||||
RUN git clone https://review.gerrithub.io/riscv/riscv-go /riscv-go
|
|
||||||
# riscvdev branch HEAD as of 2019-06-29.
|
|
||||||
RUN cd /riscv-go && git checkout 04885fddd096d09d4450726064d06dd107e374bf
|
|
||||||
ENV PATH=/riscv-go/misc/riscv:/riscv-go/bin:$PATH
|
|
||||||
RUN cd /riscv-go/src && GOROOT_BOOTSTRAP=$(go env GOROOT) ./make.bash
|
|
||||||
ENV GOROOT=/riscv-go
|
|
||||||
|
|
||||||
# Set the base env.
|
|
||||||
ENV GOOS=linux GOARCH=riscv CGO_ENABLED=0 GOFLAGS='-v -ldflags=-s -ldflags=-w'
|
|
||||||
|
|
||||||
# Pre compile the stdlib.
|
|
||||||
RUN go build -a std
|
|
||||||
|
|
||||||
# Add the code to the image.
|
|
||||||
WORKDIR pty
|
|
||||||
ADD . .
|
|
||||||
|
|
||||||
# Build the lib.
|
|
||||||
RUN go build
|
|
@ -1,23 +0,0 @@
|
|||||||
Copyright (c) 2011 Keith Rarick
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person
|
|
||||||
obtaining a copy of this software and associated
|
|
||||||
documentation files (the "Software"), to deal in the
|
|
||||||
Software without restriction, including without limitation
|
|
||||||
the rights to use, copy, modify, merge, publish, distribute,
|
|
||||||
sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so,
|
|
||||||
subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall
|
|
||||||
be included in all copies or substantial portions of the
|
|
||||||
Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
|
||||||
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
||||||
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
|
||||||
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
||||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
||||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,107 +0,0 @@
|
|||||||
# pty
|
|
||||||
|
|
||||||
Pty is a Go package for using unix pseudo-terminals.
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
```sh
|
|
||||||
go get github.com/creack/pty
|
|
||||||
```
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
Note that those examples are for demonstration purpose only, to showcase how to use the library. They are not meant to be used in any kind of production environment.
|
|
||||||
|
|
||||||
### Command
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
|
|
||||||
"github.com/creack/pty"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
c := exec.Command("grep", "--color=auto", "bar")
|
|
||||||
f, err := pty.Start(c)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
f.Write([]byte("foo\n"))
|
|
||||||
f.Write([]byte("bar\n"))
|
|
||||||
f.Write([]byte("baz\n"))
|
|
||||||
f.Write([]byte{4}) // EOT
|
|
||||||
}()
|
|
||||||
io.Copy(os.Stdout, f)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Shell
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"os/signal"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/creack/pty"
|
|
||||||
"golang.org/x/term"
|
|
||||||
)
|
|
||||||
|
|
||||||
func test() error {
|
|
||||||
// Create arbitrary command.
|
|
||||||
c := exec.Command("bash")
|
|
||||||
|
|
||||||
// Start the command with a pty.
|
|
||||||
ptmx, err := pty.Start(c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Make sure to close the pty at the end.
|
|
||||||
defer func() { _ = ptmx.Close() }() // Best effort.
|
|
||||||
|
|
||||||
// Handle pty size.
|
|
||||||
ch := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(ch, syscall.SIGWINCH)
|
|
||||||
go func() {
|
|
||||||
for range ch {
|
|
||||||
if err := pty.InheritSize(os.Stdin, ptmx); err != nil {
|
|
||||||
log.Printf("error resizing pty: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
ch <- syscall.SIGWINCH // Initial resize.
|
|
||||||
defer func() { signal.Stop(ch); close(ch) }() // Cleanup signals when done.
|
|
||||||
|
|
||||||
// Set stdin in raw mode.
|
|
||||||
oldState, err := term.MakeRaw(int(os.Stdin.Fd()))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer func() { _ = term.Restore(int(os.Stdin.Fd()), oldState) }() // Best effort.
|
|
||||||
|
|
||||||
// Copy stdin to the pty and the pty to stdout.
|
|
||||||
// NOTE: The goroutine will keep reading until the next keystroke before returning.
|
|
||||||
go func() { _, _ = io.Copy(ptmx, os.Stdin) }()
|
|
||||||
_, _ = io.Copy(os.Stdout, ptmx)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
if err := test(); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,18 +0,0 @@
|
|||||||
// Copyright 2014 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build gc
|
|
||||||
//+build gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// System calls for amd64, Solaris are implemented in runtime/syscall_solaris.go
|
|
||||||
//
|
|
||||||
|
|
||||||
TEXT ·sysvicall6(SB),NOSPLIT,$0-88
|
|
||||||
JMP syscall·sysvicall6(SB)
|
|
||||||
|
|
||||||
TEXT ·rawSysvicall6(SB),NOSPLIT,$0-88
|
|
||||||
JMP syscall·rawSysvicall6(SB)
|
|
@ -1,16 +0,0 @@
|
|||||||
// Package pty provides functions for working with Unix terminals.
|
|
||||||
package pty
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ErrUnsupported is returned if a function is not
|
|
||||||
// available on the current platform.
|
|
||||||
var ErrUnsupported = errors.New("unsupported")
|
|
||||||
|
|
||||||
// Open a pty and its corresponding tty.
|
|
||||||
func Open() (pty, tty *os.File, err error) {
|
|
||||||
return open()
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
//go:build !windows && !solaris && !aix
|
|
||||||
// +build !windows,!solaris,!aix
|
|
||||||
|
|
||||||
package pty
|
|
||||||
|
|
||||||
import "syscall"
|
|
||||||
|
|
||||||
const (
|
|
||||||
TIOCGWINSZ = syscall.TIOCGWINSZ
|
|
||||||
TIOCSWINSZ = syscall.TIOCSWINSZ
|
|
||||||
)
|
|
||||||
|
|
||||||
func ioctl(fd, cmd, ptr uintptr) error {
|
|
||||||
_, _, e := syscall.Syscall(syscall.SYS_IOCTL, fd, cmd, ptr)
|
|
||||||
if e != 0 {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
//go:build darwin || dragonfly || freebsd || netbsd || openbsd
|
|
||||||
// +build darwin dragonfly freebsd netbsd openbsd
|
|
||||||
|
|
||||||
package pty
|
|
||||||
|
|
||||||
// from <sys/ioccom.h>
|
|
||||||
const (
|
|
||||||
_IOC_VOID uintptr = 0x20000000
|
|
||||||
_IOC_OUT uintptr = 0x40000000
|
|
||||||
_IOC_IN uintptr = 0x80000000
|
|
||||||
_IOC_IN_OUT uintptr = _IOC_OUT | _IOC_IN
|
|
||||||
_IOC_DIRMASK = _IOC_VOID | _IOC_OUT | _IOC_IN
|
|
||||||
|
|
||||||
_IOC_PARAM_SHIFT = 13
|
|
||||||
_IOC_PARAM_MASK = (1 << _IOC_PARAM_SHIFT) - 1
|
|
||||||
)
|
|
||||||
|
|
||||||
func _IOC_PARM_LEN(ioctl uintptr) uintptr {
|
|
||||||
return (ioctl >> 16) & _IOC_PARAM_MASK
|
|
||||||
}
|
|
||||||
|
|
||||||
func _IOC(inout uintptr, group byte, ioctl_num uintptr, param_len uintptr) uintptr {
|
|
||||||
return inout | (param_len&_IOC_PARAM_MASK)<<16 | uintptr(group)<<8 | ioctl_num
|
|
||||||
}
|
|
||||||
|
|
||||||
func _IO(group byte, ioctl_num uintptr) uintptr {
|
|
||||||
return _IOC(_IOC_VOID, group, ioctl_num, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _IOR(group byte, ioctl_num uintptr, param_len uintptr) uintptr {
|
|
||||||
return _IOC(_IOC_OUT, group, ioctl_num, param_len)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _IOW(group byte, ioctl_num uintptr, param_len uintptr) uintptr {
|
|
||||||
return _IOC(_IOC_IN, group, ioctl_num, param_len)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _IOWR(group byte, ioctl_num uintptr, param_len uintptr) uintptr {
|
|
||||||
return _IOC(_IOC_IN_OUT, group, ioctl_num, param_len)
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
//go:build solaris
|
|
||||||
// +build solaris
|
|
||||||
|
|
||||||
package pty
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:cgo_import_dynamic libc_ioctl ioctl "libc.so"
|
|
||||||
//go:linkname procioctl libc_ioctl
|
|
||||||
var procioctl uintptr
|
|
||||||
|
|
||||||
const (
|
|
||||||
// see /usr/include/sys/stropts.h
|
|
||||||
I_PUSH = uintptr((int32('S')<<8 | 002))
|
|
||||||
I_STR = uintptr((int32('S')<<8 | 010))
|
|
||||||
I_FIND = uintptr((int32('S')<<8 | 013))
|
|
||||||
|
|
||||||
// see /usr/include/sys/ptms.h
|
|
||||||
ISPTM = (int32('P') << 8) | 1
|
|
||||||
UNLKPT = (int32('P') << 8) | 2
|
|
||||||
PTSSTTY = (int32('P') << 8) | 3
|
|
||||||
ZONEPT = (int32('P') << 8) | 4
|
|
||||||
OWNERPT = (int32('P') << 8) | 5
|
|
||||||
|
|
||||||
// see /usr/include/sys/termios.h
|
|
||||||
TIOCSWINSZ = (uint32('T') << 8) | 103
|
|
||||||
TIOCGWINSZ = (uint32('T') << 8) | 104
|
|
||||||
)
|
|
||||||
|
|
||||||
type strioctl struct {
|
|
||||||
icCmd int32
|
|
||||||
icTimeout int32
|
|
||||||
icLen int32
|
|
||||||
icDP unsafe.Pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defined in asm_solaris_amd64.s.
|
|
||||||
func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
|
||||||
|
|
||||||
func ioctl(fd, cmd, ptr uintptr) error {
|
|
||||||
if _, _, errno := sysvicall6(uintptr(unsafe.Pointer(&procioctl)), 3, fd, cmd, ptr, 0, 0, 0); errno != 0 {
|
|
||||||
return errno
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
//go:build aix
|
|
||||||
// +build aix
|
|
||||||
|
|
||||||
package pty
|
|
||||||
|
|
||||||
const (
|
|
||||||
TIOCGWINSZ = 0
|
|
||||||
TIOCSWINSZ = 0
|
|
||||||
)
|
|
||||||
|
|
||||||
func ioctl(fd, cmd, ptr uintptr) error {
|
|
||||||
return ErrUnsupported
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
GOOSARCH="${GOOS}_${GOARCH}"
|
|
||||||
case "$GOOSARCH" in
|
|
||||||
_* | *_ | _)
|
|
||||||
echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
GODEFS="go tool cgo -godefs"
|
|
||||||
|
|
||||||
$GODEFS types.go |gofmt > ztypes_$GOARCH.go
|
|
||||||
|
|
||||||
case $GOOS in
|
|
||||||
freebsd|dragonfly|netbsd|openbsd)
|
|
||||||
$GODEFS types_$GOOS.go |gofmt > ztypes_$GOOSARCH.go
|
|
||||||
;;
|
|
||||||
esac
|
|
@ -1,68 +0,0 @@
|
|||||||
//go:build darwin
|
|
||||||
// +build darwin
|
|
||||||
|
|
||||||
package pty
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
func open() (pty, tty *os.File, err error) {
|
|
||||||
pFD, err := syscall.Open("/dev/ptmx", syscall.O_RDWR|syscall.O_CLOEXEC, 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
p := os.NewFile(uintptr(pFD), "/dev/ptmx")
|
|
||||||
// In case of error after this point, make sure we close the ptmx fd.
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
_ = p.Close() // Best effort.
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
sname, err := ptsname(p)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := grantpt(p); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := unlockpt(p); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
t, err := os.OpenFile(sname, os.O_RDWR|syscall.O_NOCTTY, 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
return p, t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ptsname(f *os.File) (string, error) {
|
|
||||||
n := make([]byte, _IOC_PARM_LEN(syscall.TIOCPTYGNAME))
|
|
||||||
|
|
||||||
err := ioctl(f.Fd(), syscall.TIOCPTYGNAME, uintptr(unsafe.Pointer(&n[0])))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, c := range n {
|
|
||||||
if c == 0 {
|
|
||||||
return string(n[:i]), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", errors.New("TIOCPTYGNAME string not NUL-terminated")
|
|
||||||
}
|
|
||||||
|
|
||||||
func grantpt(f *os.File) error {
|
|
||||||
return ioctl(f.Fd(), syscall.TIOCPTYGRANT, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func unlockpt(f *os.File) error {
|
|
||||||
return ioctl(f.Fd(), syscall.TIOCPTYUNLK, 0)
|
|
||||||
}
|
|
@ -1,83 +0,0 @@
|
|||||||
//go:build dragonfly
|
|
||||||
// +build dragonfly
|
|
||||||
|
|
||||||
package pty
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// same code as pty_darwin.go
|
|
||||||
func open() (pty, tty *os.File, err error) {
|
|
||||||
p, err := os.OpenFile("/dev/ptmx", os.O_RDWR, 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
// In case of error after this point, make sure we close the ptmx fd.
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
_ = p.Close() // Best effort.
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
sname, err := ptsname(p)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := grantpt(p); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := unlockpt(p); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
t, err := os.OpenFile(sname, os.O_RDWR, 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
return p, t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func grantpt(f *os.File) error {
|
|
||||||
_, err := isptmaster(f.Fd())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func unlockpt(f *os.File) error {
|
|
||||||
_, err := isptmaster(f.Fd())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func isptmaster(fd uintptr) (bool, error) {
|
|
||||||
err := ioctl(fd, syscall.TIOCISPTMASTER, 0)
|
|
||||||
return err == nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
emptyFiodgnameArg fiodgnameArg
|
|
||||||
ioctl_FIODNAME = _IOW('f', 120, unsafe.Sizeof(emptyFiodgnameArg))
|
|
||||||
)
|
|
||||||
|
|
||||||
func ptsname(f *os.File) (string, error) {
|
|
||||||
name := make([]byte, _C_SPECNAMELEN)
|
|
||||||
fa := fiodgnameArg{Name: (*byte)(unsafe.Pointer(&name[0])), Len: _C_SPECNAMELEN, Pad_cgo_0: [4]byte{0, 0, 0, 0}}
|
|
||||||
|
|
||||||
err := ioctl(f.Fd(), ioctl_FIODNAME, uintptr(unsafe.Pointer(&fa)))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, c := range name {
|
|
||||||
if c == 0 {
|
|
||||||
s := "/dev/" + string(name[:i])
|
|
||||||
return strings.Replace(s, "ptm", "pts", -1), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", errors.New("TIOCPTYGNAME string not NUL-terminated")
|
|
||||||
}
|
|
@ -1,81 +0,0 @@
|
|||||||
//go:build freebsd
|
|
||||||
// +build freebsd
|
|
||||||
|
|
||||||
package pty
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
func posixOpenpt(oflag int) (fd int, err error) {
|
|
||||||
r0, _, e1 := syscall.Syscall(syscall.SYS_POSIX_OPENPT, uintptr(oflag), 0, 0)
|
|
||||||
fd = int(r0)
|
|
||||||
if e1 != 0 {
|
|
||||||
err = e1
|
|
||||||
}
|
|
||||||
return fd, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func open() (pty, tty *os.File, err error) {
|
|
||||||
fd, err := posixOpenpt(syscall.O_RDWR | syscall.O_CLOEXEC)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
p := os.NewFile(uintptr(fd), "/dev/pts")
|
|
||||||
// In case of error after this point, make sure we close the pts fd.
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
_ = p.Close() // Best effort.
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
sname, err := ptsname(p)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
t, err := os.OpenFile("/dev/"+sname, os.O_RDWR, 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
return p, t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func isptmaster(fd uintptr) (bool, error) {
|
|
||||||
err := ioctl(fd, syscall.TIOCPTMASTER, 0)
|
|
||||||
return err == nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
emptyFiodgnameArg fiodgnameArg
|
|
||||||
ioctlFIODGNAME = _IOW('f', 120, unsafe.Sizeof(emptyFiodgnameArg))
|
|
||||||
)
|
|
||||||
|
|
||||||
func ptsname(f *os.File) (string, error) {
|
|
||||||
master, err := isptmaster(f.Fd())
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if !master {
|
|
||||||
return "", syscall.EINVAL
|
|
||||||
}
|
|
||||||
|
|
||||||
const n = _C_SPECNAMELEN + 1
|
|
||||||
var (
|
|
||||||
buf = make([]byte, n)
|
|
||||||
arg = fiodgnameArg{Len: n, Buf: (*byte)(unsafe.Pointer(&buf[0]))}
|
|
||||||
)
|
|
||||||
if err := ioctl(f.Fd(), ioctlFIODGNAME, uintptr(unsafe.Pointer(&arg))); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, c := range buf {
|
|
||||||
if c == 0 {
|
|
||||||
return string(buf[:i]), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", errors.New("FIODGNAME string not NUL-terminated")
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue