diff --git a/.github/workflows/job-build.yml b/.github/workflows/job-build.yml index 169e95112ef..85807011a3d 100644 --- a/.github/workflows/job-build.yml +++ b/.github/workflows/job-build.yml @@ -104,7 +104,12 @@ jobs: name: "Run: make binaries with custom BUILDTAGS" run: | set -eux - # no_ipfs: make sure it does not incur any IPFS-related dependency + # Disabling all optional features and ensuring this does not incur any of the related dependencies go mod vendor - rm -rf vendor/github.com/ipfs vendor/github.com/multiformats - BUILDTAGS=no_ipfs make binaries + rm -rf \ + vendor/github.com/ipfs \ + vendor/github.com/multiformats \ + vendor/github.com/containerd/nydus-snapshotter \ + vendor/github.com/containerd/stargz-snapshotter \ + vendor/github.com/containerd/accelerated-container-image + BUILDTAGS=no_ipfs,no_nydus,no_esgz,no_obd make binaries diff --git a/.yamllint b/.yamllint index 17ba29ddcfd..28097c19bf9 100644 --- a/.yamllint +++ b/.yamllint @@ -2,6 +2,9 @@ extends: default +ignore: + - _ + rules: indentation: spaces: 2 diff --git a/BUILDING.md b/BUILDING.md index 775cc2977aa..7fc48fbf646 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -20,3 +20,6 @@ BUILDTAGS=no_ipfs make The following build tags are supported: * `no_ipfs` (since v2.1.3): Disable IPFS +* `no_nydus` (since v2.1.4): Disable Nydus +* `no_esgz` (ibid): Disable Estargz +* `no_obd` (ibid): Disable OverlayBD diff --git a/Makefile b/Makefile index 1dd5fbd0720..ba9efa0eafc 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,9 @@ DOCKER ?= docker GO ?= go GOOS ?= $(shell $(GO) env GOOS) GOARCH ?= $(shell $(GO) env GOARCH) +# The following tags can be used to disable some features: +# BUILDTAGS ?= no_nydus no_esgz no_obd no_ipfs +BUILDTAGS ?= ifeq ($(GOOS),windows) BIN_EXT := .exe endif @@ -46,9 +49,6 @@ LINT_COMMIT_RANGE ?= main..HEAD GO_BUILD_LDFLAGS ?= -s -w GO_BUILD_FLAGS ?= -BUILDTAGS ?= -GO_TAGS=$(if $(BUILDTAGS),-tags "$(strip $(BUILDTAGS))",) - ########################## # Helpers ########################## @@ -57,7 +57,7 @@ ifdef VERBOSE VERBOSE_FLAG_LONG := --verbose endif -export GO_BUILD=CGO_ENABLED=0 GOOS=$(GOOS) $(GO) -C $(MAKEFILE_DIR) build $(GO_TAGS) -ldflags "$(GO_BUILD_LDFLAGS) $(VERBOSE_FLAG) -X $(PACKAGE)/pkg/version.Version=$(VERSION) -X $(PACKAGE)/pkg/version.Revision=$(REVISION)" +export GO_BUILD=CGO_ENABLED=0 GOOS=$(GOOS) $(GO) -C $(MAKEFILE_DIR) build -tags "$(BUILDTAGS)" -ldflags "$(GO_BUILD_LDFLAGS) $(VERBOSE_FLAG) -X $(PACKAGE)/pkg/version.Version=$(VERSION) -X $(PACKAGE)/pkg/version.Revision=$(REVISION)" ifndef NO_COLOR NC := \033[0m @@ -131,7 +131,7 @@ clean: lint-go: $(call title, $@: $(GOOS)) @cd $(MAKEFILE_DIR) \ - && golangci-lint run $(VERBOSE_FLAG_LONG) ./... + && golangci-lint run --build-tags "$(BUILDTAGS)" $(VERBOSE_FLAG_LONG) ./... $(call footer, $@) lint-go-all: @@ -140,7 +140,8 @@ lint-go-all: && GOOS=linux make lint-go \ && GOOS=windows make lint-go \ && GOOS=freebsd make lint-go \ - && GOOS=darwin make lint-go + && GOOS=darwin make lint-go \ + && GOOS=linux BUILDTAGS=no_nydus,no_esgz,no_obd,no_ipfs make lint-go $(call footer, $@) lint-yaml: @@ -194,7 +195,7 @@ lint-licenses-all: fix-go: $(call title, $@: $(GOOS)) @cd $(MAKEFILE_DIR) \ - && golangci-lint run --fix + && golangci-lint run --build-tags "$(BUILDTAGS)" --fix $(call footer, $@) fix-go-all: @@ -203,7 +204,8 @@ fix-go-all: && GOOS=linux make fix-go \ && GOOS=windows make fix-go \ && GOOS=freebsd make fix-go \ - && GOOS=darwin make fix-go + && GOOS=darwin make fix-go \ + && GOOS=linux BUILDTAGS=no_nydus,no_esgz,no_obd,no_ipfs make fix-go $(call footer, $@) fix-mod: diff --git a/mod/tigron/.yamllint b/mod/tigron/.yamllint index 17ba29ddcfd..28097c19bf9 100644 --- a/mod/tigron/.yamllint +++ b/mod/tigron/.yamllint @@ -2,6 +2,9 @@ extends: default +ignore: + - _ + rules: indentation: spaces: 2 diff --git a/pkg/cmd/image/convert.go b/pkg/cmd/image/convert.go index 12a2040d598..9e4f48fe883 100644 --- a/pkg/cmd/image/convert.go +++ b/pkg/cmd/image/convert.go @@ -22,25 +22,16 @@ import ( "errors" "fmt" "io" - "os" "strings" - "github.com/klauspost/compress/zstd" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - overlaybdconvert "github.com/containerd/accelerated-container-image/pkg/convertor" containerd "github.com/containerd/containerd/v2/client" "github.com/containerd/containerd/v2/core/content" "github.com/containerd/containerd/v2/core/images" "github.com/containerd/containerd/v2/core/images/converter" "github.com/containerd/containerd/v2/core/images/converter/uncompress" "github.com/containerd/log" - nydusconvert "github.com/containerd/nydus-snapshotter/pkg/converter" - "github.com/containerd/stargz-snapshotter/estargz" - estargzconvert "github.com/containerd/stargz-snapshotter/nativeconverter/estargz" - estargzexternaltocconvert "github.com/containerd/stargz-snapshotter/nativeconverter/estargz/externaltoc" - zstdchunkedconvert "github.com/containerd/stargz-snapshotter/nativeconverter/zstdchunked" - "github.com/containerd/stargz-snapshotter/recorder" "github.com/containerd/nerdctl/v2/pkg/api/types" "github.com/containerd/nerdctl/v2/pkg/clientutil" @@ -114,61 +105,33 @@ func Convert(ctx context.Context, client *containerd.Client, srcRawRef, targetRa return errors.New("options --estargz, --zstdchunked, --overlaybd, --nydus and --soci lead to conflict, only one of them can be used") } - var convertFunc converter.ConvertFunc + var convertOpt converter.Opt var convertType string switch { case estargz: - convertFunc, finalize, err = getESGZConverter(options) - if err != nil { - return err - } convertType = "estargz" - case zstd: - convertFunc, err = getZstdConverter(options) + convertOpt, finalize, err = converterutil.ESGZConvertOpt(options.EstargzOptions, options.GOptions.Experimental) if err != nil { return err } + case zstd: convertType = "zstd" + convertOpt, err = converterutil.ZstdConvertOpt(options.ZstdOptions) case zstdchunked: - convertFunc, err = getZstdchunkedConverter(options) - if err != nil { - return err - } convertType = "zstdchunked" + convertOpt, err = converterutil.ESGZZstdChunkedConvertOpt(options.ZstdChunkedOptions, options.GOptions.Experimental) case overlaybd: - obdOpts, err := getOBDConvertOpts(options) - if err != nil { - return err - } - obdOpts = append(obdOpts, overlaybdconvert.WithClient(client)) - obdOpts = append(obdOpts, overlaybdconvert.WithImageRef(srcRef)) - convertFunc = overlaybdconvert.IndexConvertFunc(obdOpts...) - convertOpts = append(convertOpts, converter.WithIndexConvertFunc(convertFunc)) convertType = "overlaybd" + convertOpt, err = converterutil.OverlayBDConvertOpt(options.OverlaybdOptions, client, srcRef) case nydus: - nydusOpts, err := getNydusConvertOpts(options) + convertType = "nydus" + var defaultWorkDir string + defaultWorkDir, err = clientutil.DataStore(options.GOptions.DataRoot, options.GOptions.Address) if err != nil { return err } - convertHooks := converter.ConvertHooks{ - PostConvertHook: nydusconvert.ConvertHookFunc(nydusconvert.MergeOption{ - WorkDir: nydusOpts.WorkDir, - BuilderPath: nydusOpts.BuilderPath, - FsVersion: nydusOpts.FsVersion, - ChunkDictPath: nydusOpts.ChunkDictPath, - PrefetchPatterns: nydusOpts.PrefetchPatterns, - OCI: true, - }), - } - convertOpts = append(convertOpts, converter.WithIndexConvertFunc( - converter.IndexConvertFuncWithHook( - nydusconvert.LayerConvertFunc(*nydusOpts), - true, - platMC, - convertHooks, - )), - ) - convertType = "nydus" + + convertOpt, err = converterutil.NydusConvertOpt(options.NydusOptions, platMC, defaultWorkDir) case soci: // Convert image to SOCI format convertedRef, err := snapshotterutil.ConvertSociIndexV2(ctx, client, srcRef, targetRef, options.GOptions, options.Platforms, options.SociOptions) @@ -181,9 +144,12 @@ func Convert(ctx context.Context, client *containerd.Client, srcRawRef, targetRa return printConvertedImage(options.Stdout, options, res) } - if convertType != "overlaybd" { - convertOpts = append(convertOpts, converter.WithLayerConvertFunc(convertFunc)) + if err != nil { + return err } + + convertOpts = append(convertOpts, convertOpt) + if !options.Oci { if nydus || overlaybd { log.G(ctx).Warnf("option --%s should be used in conjunction with --oci, forcibly enabling on oci mediatype for %s conversion", convertType, convertType) @@ -191,6 +157,7 @@ func Convert(ctx context.Context, client *containerd.Client, srcRawRef, targetRa log.G(ctx).Warnf("option --%s should be used in conjunction with --oci", convertType) } } + if options.Uncompress { return fmt.Errorf("option --%s conflicts with --uncompress", convertType) } @@ -232,140 +199,6 @@ func Convert(ctx context.Context, client *containerd.Client, srcRawRef, targetRa return printConvertedImage(options.Stdout, options, res) } -func getESGZConverter(options types.ImageConvertOptions) (convertFunc converter.ConvertFunc, finalize func(ctx context.Context, cs content.Store, ref string, desc *ocispec.Descriptor) (*images.Image, error), _ error) { - if options.EstargzExternalToc && !options.GOptions.Experimental { - return nil, nil, fmt.Errorf("estargz-external-toc requires experimental mode to be enabled") - } - if options.EstargzKeepDiffID && !options.GOptions.Experimental { - return nil, nil, fmt.Errorf("option --estargz-keep-diff-id must be specified with --estargz-external-toc") - } - if options.EstargzExternalToc { - if !options.EstargzKeepDiffID { - esgzOpts, err := getESGZConvertOpts(options) - if err != nil { - return nil, nil, err - } - convertFunc, finalize = estargzexternaltocconvert.LayerConvertFunc(esgzOpts, options.EstargzCompressionLevel) - } else { - convertFunc, finalize = estargzexternaltocconvert.LayerConvertLossLessFunc(estargzexternaltocconvert.LayerConvertLossLessConfig{ - CompressionLevel: options.EstargzCompressionLevel, - ChunkSize: options.EstargzChunkSize, - MinChunkSize: options.EstargzMinChunkSize, - }) - } - } else { - esgzOpts, err := getESGZConvertOpts(options) - if err != nil { - return nil, nil, err - } - convertFunc = estargzconvert.LayerConvertFunc(esgzOpts...) - } - return convertFunc, finalize, nil -} - -func getESGZConvertOpts(options types.ImageConvertOptions) ([]estargz.Option, error) { - - esgzOpts := []estargz.Option{ - estargz.WithCompressionLevel(options.EstargzCompressionLevel), - estargz.WithChunkSize(options.EstargzChunkSize), - estargz.WithMinChunkSize(options.EstargzMinChunkSize), - } - - if options.EstargzRecordIn != "" { - if !options.GOptions.Experimental { - return nil, fmt.Errorf("estargz-record-in requires experimental mode to be enabled") - } - - log.L.Warn("--estargz-record-in flag is experimental and subject to change") - paths, err := readPathsFromRecordFile(options.EstargzRecordIn) - if err != nil { - return nil, err - } - esgzOpts = append(esgzOpts, estargz.WithPrioritizedFiles(paths)) - var ignored []string - esgzOpts = append(esgzOpts, estargz.WithAllowPrioritizeNotFound(&ignored)) - } - return esgzOpts, nil -} - -func getZstdConverter(options types.ImageConvertOptions) (converter.ConvertFunc, error) { - return converterutil.ZstdLayerConvertFunc(options) -} - -func getZstdchunkedConverter(options types.ImageConvertOptions) (converter.ConvertFunc, error) { - - esgzOpts := []estargz.Option{ - estargz.WithChunkSize(options.ZstdChunkedChunkSize), - } - - if options.ZstdChunkedRecordIn != "" { - if !options.GOptions.Experimental { - return nil, fmt.Errorf("zstdchunked-record-in requires experimental mode to be enabled") - } - - log.L.Warn("--zstdchunked-record-in flag is experimental and subject to change") - paths, err := readPathsFromRecordFile(options.ZstdChunkedRecordIn) - if err != nil { - return nil, err - } - esgzOpts = append(esgzOpts, estargz.WithPrioritizedFiles(paths)) - var ignored []string - esgzOpts = append(esgzOpts, estargz.WithAllowPrioritizeNotFound(&ignored)) - } - return zstdchunkedconvert.LayerConvertFuncWithCompressionLevel(zstd.EncoderLevelFromZstd(options.ZstdChunkedCompressionLevel), esgzOpts...), nil -} - -func getNydusConvertOpts(options types.ImageConvertOptions) (*nydusconvert.PackOption, error) { - workDir := options.NydusWorkDir - if workDir == "" { - var err error - workDir, err = clientutil.DataStore(options.GOptions.DataRoot, options.GOptions.Address) - if err != nil { - return nil, err - } - } - return &nydusconvert.PackOption{ - BuilderPath: options.NydusBuilderPath, - // the path will finally be used is /nydus-converter-, - // for example: /var/lib/nerdctl/1935db59/nydus-converter-3269662176/, - // and it will be deleted after the conversion - WorkDir: workDir, - PrefetchPatterns: options.NydusPrefetchPatterns, - Compressor: options.NydusCompressor, - FsVersion: "6", - }, nil -} - -func getOBDConvertOpts(options types.ImageConvertOptions) ([]overlaybdconvert.Option, error) { - obdOpts := []overlaybdconvert.Option{ - overlaybdconvert.WithFsType(options.OverlayFsType), - overlaybdconvert.WithDbstr(options.OverlaydbDBStr), - } - return obdOpts, nil -} - -func readPathsFromRecordFile(filename string) ([]string, error) { - r, err := os.Open(filename) - if err != nil { - return nil, err - } - defer r.Close() - dec := json.NewDecoder(r) - var paths []string - added := make(map[string]struct{}) - for dec.More() { - var e recorder.Entry - if err := dec.Decode(&e); err != nil { - return nil, err - } - if _, ok := added[e.Path]; !ok { - paths = append(paths, e.Path) - added[e.Path] = struct{}{} - } - } - return paths, nil -} - func printConvertedImage(stdout io.Writer, options types.ImageConvertOptions, img converterutil.ConvertedImageInfo) error { switch options.Format { case "json": diff --git a/pkg/features/errors.go b/pkg/features/errors.go new file mode 100644 index 00000000000..eae2bf23da1 --- /dev/null +++ b/pkg/features/errors.go @@ -0,0 +1,10 @@ +package features + +import "errors" + +var ( + ErrIPFSSupportMissing = errors.New("ipfs support has been disabled by the distributor of this build") + ErrESGZSupportMissing = errors.New("estargz support has been disabled by the distributor of this build (eg: build tag `no_esgz`)") + ErrOverlayBDSupportMissing = errors.New("overlaybd support has been disabled by the distributor of this build (eg: build tag `no_obd`)") + ErrNydusSupportMissing = errors.New("nydus support has been disabled by the distributor of this build (eg: build tag `no_nydus`)") +) diff --git a/pkg/imgutil/converter/errors.go b/pkg/imgutil/converter/errors.go new file mode 100644 index 00000000000..dff974aedd8 --- /dev/null +++ b/pkg/imgutil/converter/errors.go @@ -0,0 +1,12 @@ +package converter + +import ( + "errors" +) + +var ( + ErrZstdInRequiresExperimental = errors.New("option --zstdchunked-record-in requires experimental mode to be enabled") + ErrESGZTocRequiresExperimental = errors.New("option --estargz-external-toc requires experimental mode to be enabled") + ErrESGZDiffRequiresExperimental = errors.New("option --estargz-keep-diff-id requires experimental mode to be enabled") + ErrESGSInRequiresExperimental = errors.New("option --estargz-record-in requires experimental mode to be enabled") +) diff --git a/pkg/imgutil/converter/with_nydus_convert.go b/pkg/imgutil/converter/with_nydus_convert.go new file mode 100644 index 00000000000..b81e0d90667 --- /dev/null +++ b/pkg/imgutil/converter/with_nydus_convert.go @@ -0,0 +1,50 @@ +//go:build !no_nydus + +package converter + +import ( + "github.com/containerd/containerd/v2/core/images/converter" + nydusconvert "github.com/containerd/nydus-snapshotter/pkg/converter" + "github.com/containerd/platforms" + + "github.com/containerd/nerdctl/v2/pkg/api/types" +) + +func NydusConvertOpt(options types.NydusOptions, platMC platforms.MatchComparer, defaultWorkDir string) (converter.Opt, error) { + workDir := options.NydusWorkDir + if workDir == "" { + workDir = defaultWorkDir + } + + nydusOpts := getNydusConvertOpts(options, workDir) + convertHooks := converter.ConvertHooks{ + PostConvertHook: nydusconvert.ConvertHookFunc(nydusconvert.MergeOption{ + WorkDir: nydusOpts.WorkDir, + BuilderPath: nydusOpts.BuilderPath, + FsVersion: nydusOpts.FsVersion, + ChunkDictPath: nydusOpts.ChunkDictPath, + PrefetchPatterns: nydusOpts.PrefetchPatterns, + OCI: true, + }), + } + return converter.WithIndexConvertFunc( + converter.IndexConvertFuncWithHook( + nydusconvert.LayerConvertFunc(*nydusOpts), + true, + platMC, + convertHooks, + )), nil +} + +func getNydusConvertOpts(options types.NydusOptions, workDir string) *nydusconvert.PackOption { + return &nydusconvert.PackOption{ + BuilderPath: options.NydusBuilderPath, + // the path will finally be used is /nydus-converter-, + // for example: /var/lib/nerdctl/1935db59/nydus-converter-3269662176/, + // and it will be deleted after the conversion + WorkDir: workDir, + PrefetchPatterns: options.NydusPrefetchPatterns, + Compressor: options.NydusCompressor, + FsVersion: "6", + } +} diff --git a/pkg/imgutil/converter/with_obd_convert.go b/pkg/imgutil/converter/with_obd_convert.go new file mode 100644 index 00000000000..6d8283751b9 --- /dev/null +++ b/pkg/imgutil/converter/with_obd_convert.go @@ -0,0 +1,20 @@ +//go:build !no_obd + +package converter + +import ( + "github.com/containerd/accelerated-container-image/pkg/convertor" + "github.com/containerd/containerd/v2/client" + "github.com/containerd/containerd/v2/core/images/converter" + + "github.com/containerd/nerdctl/v2/pkg/api/types" +) + +func OverlayBDConvertOpt(options types.OverlaybdOptions, client *client.Client, srcRef string) (converter.Opt, error) { + return converter.WithIndexConvertFunc(convertor.IndexConvertFunc( + convertor.WithFsType(options.OverlayFsType), + convertor.WithDbstr(options.OverlaydbDBStr), + convertor.WithClient(client), + convertor.WithImageRef(srcRef), + )), nil +} diff --git a/pkg/imgutil/converter/with_stargz.go b/pkg/imgutil/converter/with_stargz.go new file mode 100644 index 00000000000..214ba395966 --- /dev/null +++ b/pkg/imgutil/converter/with_stargz.go @@ -0,0 +1,125 @@ +//go:build !no_esgz + +package converter + +import ( + "context" + "encoding/json" + "os" + + "github.com/klauspost/compress/zstd" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + + "github.com/containerd/containerd/v2/core/content" + "github.com/containerd/containerd/v2/core/images" + "github.com/containerd/containerd/v2/core/images/converter" + "github.com/containerd/log" + "github.com/containerd/stargz-snapshotter/estargz" + estargzconvert "github.com/containerd/stargz-snapshotter/nativeconverter/estargz" + externaltocconvert "github.com/containerd/stargz-snapshotter/nativeconverter/estargz/externaltoc" + zstdchunkedconvert "github.com/containerd/stargz-snapshotter/nativeconverter/zstdchunked" + "github.com/containerd/stargz-snapshotter/recorder" + + "github.com/containerd/nerdctl/v2/pkg/api/types" +) + +func ESGZZstdChunkedConvertOpt(options types.ZstdChunkedOptions, experimental bool) (converter.Opt, error) { + esgzOpts := []estargz.Option{ + estargz.WithChunkSize(options.ZstdChunkedChunkSize), + } + + if options.ZstdChunkedRecordIn != "" { + if !experimental { + return nil, ErrZstdInRequiresExperimental + } + + log.L.Warn("--zstdchunked-record-in flag is experimental and subject to change") + paths, err := readPathsFromRecordFile(options.ZstdChunkedRecordIn) + if err != nil { + return nil, err + } + esgzOpts = append(esgzOpts, estargz.WithPrioritizedFiles(paths)) + var ignored []string + esgzOpts = append(esgzOpts, estargz.WithAllowPrioritizeNotFound(&ignored)) + } + convertFunc := zstdchunkedconvert.LayerConvertFuncWithCompressionLevel(zstd.EncoderLevelFromZstd(options.ZstdChunkedCompressionLevel), esgzOpts...) + return converter.WithLayerConvertFunc(convertFunc), nil +} + +func ESGZConvertOpt(options types.EstargzOptions, experimental bool) (convertOpt converter.Opt, finalize func(ctx context.Context, cs content.Store, ref string, desc *ocispec.Descriptor) (*images.Image, error), _ error) { + if options.EstargzExternalToc && !experimental { + return nil, nil, ErrESGZTocRequiresExperimental + } + if options.EstargzKeepDiffID && !experimental { + return nil, nil, ErrESGZDiffRequiresExperimental + } + var convertFunc converter.ConvertFunc + if options.EstargzExternalToc { + if !options.EstargzKeepDiffID { + esgzOpts, err := getESGZConvertOpts(options, experimental) + if err != nil { + return nil, nil, err + } + convertFunc, finalize = externaltocconvert.LayerConvertFunc(esgzOpts, options.EstargzCompressionLevel) + } else { + convertFunc, finalize = externaltocconvert.LayerConvertLossLessFunc(externaltocconvert.LayerConvertLossLessConfig{ + CompressionLevel: options.EstargzCompressionLevel, + ChunkSize: options.EstargzChunkSize, + MinChunkSize: options.EstargzMinChunkSize, + }) + } + } else { + esgzOpts, err := getESGZConvertOpts(options, experimental) + if err != nil { + return nil, nil, err + } + convertFunc = estargzconvert.LayerConvertFunc(esgzOpts...) + } + return converter.WithLayerConvertFunc(convertFunc), finalize, nil +} + +func getESGZConvertOpts(options types.EstargzOptions, experimental bool) ([]estargz.Option, error) { + esgzOpts := []estargz.Option{ + estargz.WithCompressionLevel(options.EstargzCompressionLevel), + estargz.WithChunkSize(options.EstargzChunkSize), + estargz.WithMinChunkSize(options.EstargzMinChunkSize), + } + + if options.EstargzRecordIn != "" { + if !experimental { + return nil, ErrESGSInRequiresExperimental + } + + log.L.Warn("--estargz-record-in flag is experimental and subject to change") + paths, err := readPathsFromRecordFile(options.EstargzRecordIn) + if err != nil { + return nil, err + } + esgzOpts = append(esgzOpts, estargz.WithPrioritizedFiles(paths)) + var ignored []string + esgzOpts = append(esgzOpts, estargz.WithAllowPrioritizeNotFound(&ignored)) + } + return esgzOpts, nil +} + +func readPathsFromRecordFile(filename string) ([]string, error) { + r, err := os.Open(filename) + if err != nil { + return nil, err + } + defer r.Close() + dec := json.NewDecoder(r) + var paths []string + added := make(map[string]struct{}) + for dec.More() { + var e recorder.Entry + if err := dec.Decode(&e); err != nil { + return nil, err + } + if _, ok := added[e.Path]; !ok { + paths = append(paths, e.Path) + added[e.Path] = struct{}{} + } + } + return paths, nil +} diff --git a/pkg/imgutil/converter/without_nydus_convert.go b/pkg/imgutil/converter/without_nydus_convert.go new file mode 100644 index 00000000000..b57e63780be --- /dev/null +++ b/pkg/imgutil/converter/without_nydus_convert.go @@ -0,0 +1,15 @@ +//go:build no_nydus + +package converter + +import ( + "github.com/containerd/containerd/v2/core/images/converter" + "github.com/containerd/platforms" + + "github.com/containerd/nerdctl/v2/pkg/api/types" + "github.com/containerd/nerdctl/v2/pkg/features" +) + +func NydusConvertOpt(_ types.NydusOptions, _ platforms.MatchComparer, _ string) (converter.Opt, error) { + return nil, features.ErrNydusSupportMissing +} diff --git a/pkg/imgutil/converter/without_obd_convert.go b/pkg/imgutil/converter/without_obd_convert.go new file mode 100644 index 00000000000..896b55e747d --- /dev/null +++ b/pkg/imgutil/converter/without_obd_convert.go @@ -0,0 +1,15 @@ +//go:build no_obd + +package converter + +import ( + "github.com/containerd/containerd/v2/client" + "github.com/containerd/containerd/v2/core/images/converter" + + "github.com/containerd/nerdctl/v2/pkg/api/types" + "github.com/containerd/nerdctl/v2/pkg/features" +) + +func OverlayBDConvertOpt(_ types.OverlaybdOptions, _ *client.Client, _ string) (converter.Opt, error) { + return nil, features.ErrOverlayBDSupportMissing +} diff --git a/pkg/imgutil/converter/without_stargz.go b/pkg/imgutil/converter/without_stargz.go new file mode 100644 index 00000000000..fc4999b7a46 --- /dev/null +++ b/pkg/imgutil/converter/without_stargz.go @@ -0,0 +1,24 @@ +//go:build no_esgz + +package converter + +import ( + "context" + + "github.com/opencontainers/image-spec/specs-go/v1" + + "github.com/containerd/containerd/v2/core/content" + "github.com/containerd/containerd/v2/core/images" + "github.com/containerd/containerd/v2/core/images/converter" + + "github.com/containerd/nerdctl/v2/pkg/api/types" + "github.com/containerd/nerdctl/v2/pkg/features" +) + +func ESGZZstdChunkedConvertOpt(_ types.ZstdChunkedOptions, _ bool) (converter.Opt, error) { + return nil, features.ErrESGZSupportMissing +} + +func ESGZConvertOpt(_ types.EstargzOptions, _ bool) (converter.Opt, func(ctx context.Context, cs content.Store, ref string, desc *v1.Descriptor) (*images.Image, error), error) { + return nil, nil, features.ErrESGZSupportMissing +} diff --git a/pkg/imgutil/converter/zstd.go b/pkg/imgutil/converter/zstd.go index bb177a63442..e8218a2c30d 100644 --- a/pkg/imgutil/converter/zstd.go +++ b/pkg/imgutil/converter/zstd.go @@ -34,9 +34,17 @@ import ( "github.com/containerd/nerdctl/v2/pkg/api/types" ) +func ZstdConvertOpt(options types.ZstdOptions) (converter.Opt, error) { + convertFunc, err := ZstdLayerConvertFunc(options) + if err != nil { + return nil, err + } + return converter.WithLayerConvertFunc(convertFunc), nil +} + // ZstdLayerConvertFunc converts legacy tar.gz layers into zstd layers with // the specified compression level. -func ZstdLayerConvertFunc(options types.ImageConvertOptions) (converter.ConvertFunc, error) { +func ZstdLayerConvertFunc(options types.ZstdOptions) (converter.ConvertFunc, error) { return func(ctx context.Context, cs content.Store, desc ocispec.Descriptor) (*ocispec.Descriptor, error) { if !images.IsLayerType(desc.MediaType) { // No conversion. No need to return an error here. diff --git a/pkg/ipfs/image_noipfs.go b/pkg/ipfs/image_noipfs.go index 43210f6e9df..603ac98f7f8 100644 --- a/pkg/ipfs/image_noipfs.go +++ b/pkg/ipfs/image_noipfs.go @@ -25,15 +25,16 @@ import ( "github.com/containerd/containerd/v2/core/images/converter" "github.com/containerd/nerdctl/v2/pkg/api/types" + "github.com/containerd/nerdctl/v2/pkg/features" "github.com/containerd/nerdctl/v2/pkg/imgutil" ) // EnsureImage pull the specified image from IPFS. func EnsureImage(ctx context.Context, client *containerd.Client, scheme, ref, ipfsPath string, options types.ImagePullOptions) (*imgutil.EnsuredImage, error) { - return nil, ErrNotImplemented + return nil, features.ErrIPFSSupportMissing } // Push pushes the specified image to IPFS. func Push(ctx context.Context, client *containerd.Client, rawRef string, layerConvert converter.ConvertFunc, allPlatforms bool, platform []string, ensureImage bool, ipfsPath string) (string, error) { - return "", ErrNotImplemented + return "", features.ErrIPFSSupportMissing } diff --git a/pkg/ipfs/noipfs.go b/pkg/ipfs/noipfs.go deleted file mode 100644 index 4a1d29b0d3c..00000000000 --- a/pkg/ipfs/noipfs.go +++ /dev/null @@ -1,25 +0,0 @@ -/* - Copyright The containerd 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 ipfs - -import ( - "fmt" - - "github.com/containerd/errdefs" -) - -var ErrNotImplemented = fmt.Errorf("%w: ipfs is disabled by the distributor of this build", errdefs.ErrNotImplemented) diff --git a/pkg/ipfs/registry_noipfs.go b/pkg/ipfs/registry_noipfs.go index f93c114b9d6..13c17e985c8 100644 --- a/pkg/ipfs/registry_noipfs.go +++ b/pkg/ipfs/registry_noipfs.go @@ -20,8 +20,10 @@ package ipfs import ( "net/http" + + "github.com/containerd/nerdctl/v2/pkg/features" ) func NewRegistry(options RegistryOptions) (http.Handler, error) { - return nil, ErrNotImplemented + return nil, features.ErrIPFSSupportMissing } diff --git a/pkg/referenceutil/cid_ipfs.go b/pkg/referenceutil/with_ipfs.go similarity index 100% rename from pkg/referenceutil/cid_ipfs.go rename to pkg/referenceutil/with_ipfs.go diff --git a/pkg/referenceutil/cid_noipfs.go b/pkg/referenceutil/without_ipfs.go similarity index 81% rename from pkg/referenceutil/cid_noipfs.go rename to pkg/referenceutil/without_ipfs.go index d7a8228925f..8406e5803f3 100644 --- a/pkg/referenceutil/cid_noipfs.go +++ b/pkg/referenceutil/without_ipfs.go @@ -18,12 +18,8 @@ package referenceutil -import ( - "fmt" - - "github.com/containerd/errdefs" -) +import "github.com/containerd/nerdctl/v2/pkg/features" func decodeCid(v string) (string, error) { - return "", fmt.Errorf("%w: ipfs is disabled by the distributor of this build", errdefs.ErrNotImplemented) + return "", features.ErrIPFSSupportMissing }