From 8264307278f2e8644244af8b046d0cfd3ca0f0f1 Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Tue, 23 Apr 2024 12:49:53 +0200 Subject: [PATCH] mvn access works! --- .../ocm/accessmethods/mvn/artifact.go | 2 + pkg/contexts/ocm/accessmethods/mvn/method.go | 160 ++++++++----- .../ocm/accessmethods/mvn/method_test.go | 54 ++++- .../5.7.0/sdk-modules-bom-5.7.0.pom | 210 ++++++++++++++++++ .../handlers/generic/mvn/blobhandler.go | 60 ++--- .../handlers/generic/mvn/registration.go | 9 +- pkg/utils/tarutils/pack.go | 20 +- 7 files changed, 416 insertions(+), 99 deletions(-) create mode 100644 pkg/contexts/ocm/accessmethods/mvn/testdata/success/com/sap/cloud/sdk/sdk-modules-bom/5.7.0/sdk-modules-bom-5.7.0.pom diff --git a/pkg/contexts/ocm/accessmethods/mvn/artifact.go b/pkg/contexts/ocm/accessmethods/mvn/artifact.go index 819ba56f16..51297d1139 100644 --- a/pkg/contexts/ocm/accessmethods/mvn/artifact.go +++ b/pkg/contexts/ocm/accessmethods/mvn/artifact.go @@ -95,6 +95,7 @@ func (a *Artifact) MimeType() string { return mime.MIME_TGZ } +/* func IsMimeTypeSupported(mimeType string) bool { switch mimeType { case mime.MIME_JAR, mime.MIME_JSON, mime.MIME_XML, mime.MIME_TGZ, mime.MIME_GZIP: @@ -102,6 +103,7 @@ func IsMimeTypeSupported(mimeType string) bool { } return false } +*/ // ArtifactFromHint creates new Artifact from accessspec-hint. See 'GetReferenceHint'. func ArtifactFromHint(gav string) *Artifact { diff --git a/pkg/contexts/ocm/accessmethods/mvn/method.go b/pkg/contexts/ocm/accessmethods/mvn/method.go index 10bb0a267d..1c42a25014 100644 --- a/pkg/contexts/ocm/accessmethods/mvn/method.go +++ b/pkg/contexts/ocm/accessmethods/mvn/method.go @@ -2,10 +2,8 @@ package mvn import ( "bytes" - "compress/gzip" "context" "crypto" - "crypto/sha256" "fmt" "io" "net/http" @@ -14,6 +12,7 @@ import ( "github.com/mandelsoft/vfs/pkg/osfs" "github.com/mandelsoft/vfs/pkg/vfs" + "github.com/opencontainers/go-digest" "golang.org/x/exp/slices" "golang.org/x/net/html" @@ -62,7 +61,7 @@ type AccessSpec struct { var _ accspeccpi.AccessSpec = (*AccessSpec)(nil) -var log = logging.Context().Logger(identity.REALM) +var logger = logging.Context().Logger(identity.REALM) // New creates a new Maven (mvn) repository access spec version v1. func New(repository, groupId, artifactId, version string, options ...func(*AccessSpec)) *AccessSpec { @@ -155,23 +154,18 @@ type meta struct { } func (a *AccessSpec) GetPackageMeta(ctx accspeccpi.Context) (*meta, error) { - artifact := a.AsArtifact() - var metadata = meta{} - - if artifact.Extension != "" { - metadata.Bin = artifact.Url(a.Repository) - metadata.MimeType = artifact.MimeType() - return &metadata, nil - } - fs := vfsattr.Get(ctx) - fileMap, err := a.GetGAVFiles() + log := logger.WithValues("BaseUrl", a.BaseUrl()) + fileMap, err := a.GavFiles(fs) if err != nil { - return nil, errors.Wrapf(err, "cannot read GAV: %s", a.BaseUrl()) + return nil, err } - singleArtifact := len(fileMap) == 1 + if a.Classifier != "" { + fileMap = filterByClassifier(fileMap, a.Classifier) + } + singleBinary := len(fileMap) == 1 tempFs, err := osfs.NewTempFileSystem() if err != nil { @@ -179,10 +173,12 @@ func (a *AccessSpec) GetPackageMeta(ctx accspeccpi.Context) (*meta, error) { } defer vfs.Cleanup(tempFs) + artifact := a.AsArtifact() + var metadata = meta{} for file, hash := range fileMap { artifact.ClassifierExtensionFrom(file) metadata.Bin = artifact.Url(a.Repository) - log.WithValues("file", metadata.Bin) + log = logger.WithValues("file", metadata.Bin) log.Debug("processing") metadata.MimeType = artifact.MimeType() if hash > 0 { @@ -195,7 +191,9 @@ func (a *AccessSpec) GetPackageMeta(ctx accspeccpi.Context) (*meta, error) { log.Warn("no digest available") } - if singleArtifact { + // single binary dependency, this will never be a complete GAV - no maven uploader support! + if a.Extension != "" || singleBinary && a.Classifier != "" { + // in case you want to transport pom, then you should NOT set the extension return &metadata, nil } @@ -205,36 +203,56 @@ func (a *AccessSpec) GetPackageMeta(ctx accspeccpi.Context) (*meta, error) { return nil, err } defer out.Close() - resp, err := http.Get(metadata.Bin) + reader, err := getReader(metadata.Bin, fs) if err != nil { return nil, err } - defer resp.Body.Close() - _, err = io.Copy(out, resp.Body) - if err != nil { - return nil, err + defer reader.Close() + + if hash > 0 { + dreader := iotools.NewDigestReaderWithHash(hash, reader) + _, err = io.Copy(out, dreader) + if err != nil { + return nil, err + } + sum := dreader.Digest().Encoded() + if metadata.Hash != sum { + return nil, errors.Newf("checksum mismatch for %s", metadata.Bin) + } + } else { + _, err = io.Copy(out, reader) + if err != nil { + return nil, err + } } } // pack all downloaded files into a tar.gz file - tgz, err := blobaccess.NewTempFile("", Type+"-"+artifact.FilePrefix()+"-*.tar.gz", fs) - defer tgz.Close() + // tgz, err := blobaccess.NewTempFile("", Type+"-"+artifact.FilePrefix()+"-*.tar.gz", fs) + tgz, err := vfs.TempFile(fs, "", Type+"-"+artifact.FilePrefix()+"-*.tar.gz") if err != nil { return nil, err } - err = tarutils.TarFs(tempFs, gzip.NewWriter(tgz.Writer())) + defer tgz.Close() + + dw := iotools.NewDigestWriterWith(digest.SHA256, tgz) + defer dw.Close() + err = tarutils.TgzFs(tempFs, dw) if err != nil { return nil, err } + metadata.Bin = "file://" + tgz.Name() + metadata.Hash = dw.Digest().Encoded() + metadata.HashType = crypto.SHA256 log.Debug("created", "file", metadata.Bin) - // calculate digest for the tar.gz file + /*/ calculate digest for the tar.gz file file, err := fs.OpenFile(tgz.Name(), vfs.O_RDONLY, vfs.ModePerm) - defer file.Close() if err != nil { return nil, err } + defer file.Close() hash := sha256.New() if _, err := io.Copy(hash, file); err != nil { return nil, err @@ -242,32 +260,64 @@ func (a *AccessSpec) GetPackageMeta(ctx accspeccpi.Context) (*meta, error) { metadata.Hash = fmt.Sprintf("%x", hash.Sum(nil)) log.Debug("hash", "sum", metadata.Hash) metadata.HashType = crypto.SHA256 + */ metadata.MimeType = mime.MIME_TGZ return &metadata, nil } -// GetGAVFiles returns the files of the Maven (mvn) artifact in the repository and their available digests. -func (a *AccessSpec) GetGAVFiles() (map[string]crypto.Hash, error) { - log.WithValues("repository", a.BaseUrl()) - log.Debug("reading") - req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, a.BaseUrl(), nil) +func filterByClassifier(fileMap map[string]crypto.Hash, classifier string) map[string]crypto.Hash { + var filtered = make(map[string]crypto.Hash) + for file, hash := range fileMap { + if strings.Contains(file, "-"+classifier+".") { + filtered[file] = hash + } + } + return filtered +} + +/* +func (a *AccessSpec) fileListFactory(fs vfs.FileSystem) func() (map[string]crypto.Hash, error) { + return func() (map[string]crypto.Hash, error) { + if strings.HasPrefix(a.BaseUrl(), "file://") { + dir := a.BaseUrl()[7:] + return gavFilesFromDisk(fs, dir) + } + return a.gavOnlineFiles() + } +} +*/ + +func (a *AccessSpec) GavFiles(fs ...vfs.FileSystem) (map[string]crypto.Hash, error) { + if strings.HasPrefix(a.Repository, "file://") && len(fs) > 0 { + dir := a.Repository[7:] + return gavFilesFromDisk(fs[0], dir) + } + return a.gavOnlineFiles() +} + +func gavFilesFromDisk(fs vfs.FileSystem, dir string) (map[string]crypto.Hash, error) { + files, err := tarutils.FlatListSortedFilesInDir(fs, dir) if err != nil { return nil, err } - client := &http.Client{} - resp, err := client.Do(req) + return filesAndHashes(files), nil +} + +// gavOnlineFiles returns the files of the Maven (mvn) artifact in the repository and their available digests. +func (a *AccessSpec) gavOnlineFiles() (map[string]crypto.Hash, error) { + log := logger.WithValues("BaseUrl", a.BaseUrl()) + log.Debug("gavOnlineFiles") + + reader, err := getReader(a.BaseUrl(), nil) if err != nil { return nil, err } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("%s - %s", a.BaseUrl(), resp.Status) - } + defer reader.Close() // Which files are listed in the repository? - log.Debug("parsing html") - htmlDoc, err := html.Parse(resp.Body) + log.Debug("parse-html") + htmlDoc, err := html.Parse(reader) if err != nil { return nil, err } @@ -292,18 +342,22 @@ func (a *AccessSpec) GetGAVFiles() (map[string]crypto.Hash, error) { } process(htmlDoc) + return filesAndHashes(fileList), nil +} + +func filesAndHashes(fileList []string) map[string]crypto.Hash { + // Sort the list of files, to ensure always the same results for e.g. identical tar.gz files. + sort.Strings(fileList) + // Which hash files are available? - var filesAndHashes = make(map[string]crypto.Hash) + var result = make(map[string]crypto.Hash) for _, file := range fileList { if IsArtifact(file) { - filesAndHashes[file] = bestAvailableHash(fileList, file) - log.Debug("found", "file", file) + result[file] = bestAvailableHash(fileList, file) + logger.Debug("found", "file", file) } } - - // Sort the list of files, to ensure always the same results for e.g. identical tar.gz files. - sort.Strings(fileList) - return filesAndHashes, nil + return result } // bestAvailableHash returns the best available hash for the given file. @@ -363,7 +417,7 @@ func getStringData(url string, fs vfs.FileSystem) (string, error) { return string(b), nil } -// getBestHashValue returns the best hash value (SHA-512, SHA-256, SHA-1, MD5) for the given artifact (POM, JAR, ...). +/*/ getBestHashValue returns the best hash value (SHA-512, SHA-256, SHA-1, MD5) for the given artifact (POM, JAR, ...). func getBestHashValue(url string, fs vfs.FileSystem) (crypto.Hash, string, error) { arr := [5]crypto.Hash{crypto.SHA512, crypto.SHA256, crypto.SHA1, crypto.MD5} log := logging.Context().Logger(identity.REALM) @@ -379,6 +433,7 @@ func getBestHashValue(url string, fs vfs.FileSystem) (crypto.Hash, string, error } return 0, "", errors.New("no hash value found") } +*/ // hashUrlExt returns the 'maven' hash extension for the given hash. // Maven usually uses sha1, sha256, sha512, md5 instead of SHA-1, SHA-256, SHA-512, MD5. @@ -414,8 +469,6 @@ func newMethod(c accspeccpi.ComponentVersionAccess, a *AccessSpec) (accspeccpi.A } func getReader(url string, fs vfs.FileSystem) (io.ReadCloser, error) { - c := &http.Client{} - if strings.HasPrefix(url, "file://") { path := url[7:] return fs.OpenFile(path, vfs.O_RDONLY, 0o600) @@ -425,7 +478,8 @@ func getReader(url string, fs vfs.FileSystem) (io.ReadCloser, error) { if err != nil { return nil, err } - resp, err := c.Do(req) + httpClient := &http.Client{} + resp, err := httpClient.Do(req) if err != nil { return nil, err } @@ -434,9 +488,9 @@ func getReader(url string, fs vfs.FileSystem) (io.ReadCloser, error) { buf := &bytes.Buffer{} _, err = io.Copy(buf, io.LimitReader(resp.Body, 2000)) if err != nil { - return nil, errors.Newf("version meta data request %s provides %s", url, resp.Status) + return nil, errors.Newf("http %s error - %s", resp.Status, url) } - return nil, errors.Newf("version meta data request %s provides %s: %s", url, resp.Status, buf.String()) + return nil, errors.Newf("http %s error - %s returned: %s", resp.Status, url, buf.String()) } return resp.Body, nil } diff --git a/pkg/contexts/ocm/accessmethods/mvn/method_test.go b/pkg/contexts/ocm/accessmethods/mvn/method_test.go index 2303af17b4..b0f3ed6de6 100644 --- a/pkg/contexts/ocm/accessmethods/mvn/method_test.go +++ b/pkg/contexts/ocm/accessmethods/mvn/method_test.go @@ -17,7 +17,7 @@ import ( ) const ( - mvnPATH = "/testdata/.m2/repository" + mvnPATH = "/testdata/success" FAILPATH = "/testdata" ) @@ -36,7 +36,7 @@ var _ = Describe("Method", func() { It("get packaging", func() { acc := mvn.New("https://repo1.maven.org/maven2", "com.sap.cloud.sdk", "sdk-modules-bom", "5.7.0") - files, err := acc.GetGAVFiles() + files, err := acc.GavFiles() Expect(err).ToNot(HaveOccurred()) Expect(files).To(HaveLen(1)) Expect(files["sdk-modules-bom-5.7.0.pom"]).To(Equal(crypto.SHA1)) @@ -46,7 +46,7 @@ var _ = Describe("Method", func() { acc := mvn.New("https://repo1.maven.org/maven2", "org.apache.maven", "apache-maven", "3.9.6") Expect(acc).ToNot(BeNil()) Expect(acc.BaseUrl()).To(Equal("https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.9.6")) - files, err := acc.GetGAVFiles() + files, err := acc.GavFiles() Expect(err).ToNot(HaveOccurred()) Expect(files).To(HaveLen(8)) @@ -64,16 +64,51 @@ var _ = Describe("Method", func() { - https://repo1.maven.org/maven2/org/apache/commons/commons-compress/1.26.1/ // cyclonedx - https://repo1.maven.org/maven2/cn/afternode/commons/commons/1.6/ // gradle module! - https://repo1.maven.org/maven2/com/sap/cloud/sdk/sdk-modules-bom/5.7.0/ // one single pom only! + - https://int.repositories.cloud.sap/artifactory/ocm-mvn-test/open-component-model/hello-ocm/0.0.1/ // jar only! */ meta, err := acc.GetPackageMeta(ocm.DefaultContext()) Expect(err).ToNot(HaveOccurred()) - Expect(meta.Bin).To(Equal("https://repo1.maven.org/maven2/com/sap/cloud/sdk/sdk-modules-bom/5.7.0/sdk-modules-bom-5.7.0.pom")) - Expect(meta.Hash).To(Equal("34ccdeb9c008f8aaef90873fc636b09d3ae5c709")) - Expect(meta.HashType).To(Equal(crypto.SHA1)) + Expect(meta.Bin).To(HavePrefix("file://")) + Expect(meta.Bin).To(ContainSubstring("mvn-sdk-modules-bom-5.7.0-")) + Expect(meta.Bin).To(HaveSuffix(".tar.gz")) + Expect(meta.Hash).To(Equal("217feb1e7490015dd0a2b231b9cea45804df3d2a9b37287ac861bb45b8c0de55")) + Expect(meta.HashType).To(Equal(crypto.SHA256)) }) - It("accesses artifact", func() { + /*/ works only internal + It("GetPackageMeta - int.repositories.cloud.sap: hello-ocm", func() { + acc := mvn.New("https://int.repositories.cloud.sap/artifactory/ocm-mvn-test", "open-component-model", "hello-ocm", "0.0.1") + meta, err := acc.GetPackageMeta(ocm.DefaultContext()) + Expect(err).ToNot(HaveOccurred()) + Expect(meta.Bin).To(Equal("https://int.repositories.cloud.sap/artifactory/ocm-mvn-test/open-component-model/hello-ocm/0.0.1/hello-ocm-0.0.1.jar")) + Expect(meta.Hash).To(Equal("")) + Expect(meta.HashType).To(Equal(crypto.Hash(0))) + }) + + */ + + It("accesses local artifact", func() { + acc := mvn.New("file://"+mvnPATH, "com.sap.cloud.sdk", "sdk-modules-bom", "5.7.0") + m := Must(acc.AccessMethod(cv)) + defer m.Close() + Expect(m.MimeType()).To(Equal(mime.MIME_TGZ)) + + r := Must(m.Reader()) + defer r.Close() + dr := iotools.NewDigestReaderWithHash(crypto.SHA1, r) + for { + var buf [8096]byte + _, err := dr.Read(buf[:]) + if err != nil { + break + } + } + Expect(dr.Size()).To(Equal(int64(10))) + Expect(dr.Digest().String()).To(Equal("SHA-1:e727ef4792a349c485d893e60874475a54f24b97")) + }) + + It("accesses local artifact with extension", func() { acc := mvn.New("file://"+mvnPATH, "com.sap.cloud.sdk", "sdk-modules-bom", "5.7.0", mvn.WithExtension("pom")) m := Must(acc.AccessMethod(cv)) defer m.Close() @@ -101,4 +136,9 @@ var _ = Describe("Method", func() { _, err := m.Reader() Expect(err).To(MatchError(ContainSubstring("SHA-1 digest mismatch: expected 44a77645201d1a8fc5213ace787c220eabbd0967, found b3242b8c31f8ce14f729b8fd132ac77bc4bc5bf7"))) }) + + FIt("NewDigestWriterWithHash", func() { + w := iotools.NewDigestWriterWithHash(crypto.SHA1, nil) + Expect(w).ToNot(BeNil()) + }) }) diff --git a/pkg/contexts/ocm/accessmethods/mvn/testdata/success/com/sap/cloud/sdk/sdk-modules-bom/5.7.0/sdk-modules-bom-5.7.0.pom b/pkg/contexts/ocm/accessmethods/mvn/testdata/success/com/sap/cloud/sdk/sdk-modules-bom/5.7.0/sdk-modules-bom-5.7.0.pom new file mode 100644 index 0000000000..b3baaee32f --- /dev/null +++ b/pkg/contexts/ocm/accessmethods/mvn/testdata/success/com/sap/cloud/sdk/sdk-modules-bom/5.7.0/sdk-modules-bom-5.7.0.pom @@ -0,0 +1,210 @@ + + + 4.0.0 + com.sap.cloud.sdk + sdk-modules-bom + 5.7.0 + pom + SAP Cloud SDK - Modules BOM + Bill of Materials (BOM) of the SAP Cloud SDK modules. + https://sap.github.io/cloud-sdk/docs/java/getting-started + + SAP SE + https://www.sap.com + + + + The Apache Software License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + + + + + SAP + cloudsdk@sap.com + SAP SE + https://www.sap.com + + + + + + + + UTF-8 + Public + Stable + + 5.7.0 + + + + + com.sap.cloud.sdk + sdk-core + ${sdk.version} + + + com.sap.cloud.sdk.cloudplatform + scp-cf + ${sdk.version} + + + com.sap.cloud.sdk.cloudplatform + dwc-cf + ${sdk.version} + + + com.sap.cloud.sdk.cloudplatform + cloudplatform-core + ${sdk.version} + + + com.sap.cloud.sdk.cloudplatform + caching + ${sdk.version} + + + com.sap.cloud.sdk.cloudplatform + cloudplatform-connectivity + ${sdk.version} + + + com.sap.cloud.sdk.cloudplatform + connectivity-apache-httpclient4 + ${sdk.version} + + + com.sap.cloud.sdk.cloudplatform + connectivity-apache-httpclient5 + ${sdk.version} + + + com.sap.cloud.sdk.cloudplatform + cloudplatform-connectivity-scp-cf + ${sdk.version} + + + com.sap.cloud.sdk.cloudplatform + connectivity-destination-service + ${sdk.version} + + + com.sap.cloud.sdk.cloudplatform + connectivity-oauth + ${sdk.version} + + + com.sap.cloud.sdk.cloudplatform + connectivity-dwc + ${sdk.version} + + + com.sap.cloud.sdk.cloudplatform + connectivity-ztis + ${sdk.version} + + + com.sap.cloud.sdk.cloudplatform + resilience + ${sdk.version} + + + com.sap.cloud.sdk.cloudplatform + resilience-api + ${sdk.version} + + + com.sap.cloud.sdk.cloudplatform + resilience4j + ${sdk.version} + + + com.sap.cloud.sdk.cloudplatform + security + ${sdk.version} + + + com.sap.cloud.sdk.cloudplatform + servlet-jakarta + ${sdk.version} + + + com.sap.cloud.sdk.cloudplatform + tenant + ${sdk.version} + + + com.sap.cloud.sdk.s4hana + s4hana-core + ${sdk.version} + + + com.sap.cloud.sdk.s4hana + s4hana-connectivity + ${sdk.version} + + + com.sap.cloud.sdk.s4hana + rfc + ${sdk.version} + + + com.sap.cloud.sdk.datamodel + datamodel-metadata-generator + ${sdk.version} + + + com.sap.cloud.sdk.datamodel + odata-generator-utility + ${sdk.version} + + + com.sap.cloud.sdk.datamodel + odata-client + ${sdk.version} + + + com.sap.cloud.sdk.datamodel + odata-core + ${sdk.version} + + + com.sap.cloud.sdk.datamodel + odata-v4-core + ${sdk.version} + + + com.sap.cloud.sdk.datamodel + odata-generator + ${sdk.version} + + + com.sap.cloud.sdk.datamodel + odata-v4-generator + ${sdk.version} + + + com.sap.cloud.sdk.datamodel + openapi-core + ${sdk.version} + + + com.sap.cloud.sdk.datamodel + openapi-generator + ${sdk.version} + + + com.sap.cloud.sdk.datamodel + fluent-result + ${sdk.version} + + + com.sap.cloud.sdk.datamodel + + soap + ${sdk.version} + + + + diff --git a/pkg/contexts/ocm/blobhandler/handlers/generic/mvn/blobhandler.go b/pkg/contexts/ocm/blobhandler/handlers/generic/mvn/blobhandler.go index 2b81df758f..d40b1a7756 100644 --- a/pkg/contexts/ocm/blobhandler/handlers/generic/mvn/blobhandler.go +++ b/pkg/contexts/ocm/blobhandler/handlers/generic/mvn/blobhandler.go @@ -41,9 +41,11 @@ func (b *artifactHandler) StoreBlob(blob cpi.BlobAccess, resourceType string, hi } mimeType := blob.MimeType() if resourcetypes.MVN_ARTIFACT != resourceType { + log.Debug("not a MVN artifact", "resourceType", resourceType) return nil, nil } - if !mvn.IsMimeTypeSupported(mimeType) { + if mime.MIME_TGZ != mimeType { + log.Debug("not a tarball, can't be a complete mvn GAV", "mimeType", mimeType) return nil, nil } if b.spec.Url == "" { @@ -78,45 +80,47 @@ func (b *artifactHandler) StoreBlob(blob cpi.BlobAccess, resourceType string, hi } defer blobReader.Close() - switch mimeType { - case mime.MIME_TGZ: - tempFs, err := osfs.NewTempFileSystem() + //switch mimeType { + //case mime.MIME_TGZ: + tempFs, err := osfs.NewTempFileSystem() + if err != nil { + return nil, err + } + defer vfs.Cleanup(tempFs) + err = tarutils.ExtractTarToFs(tempFs, blobReader) + // err = tarutils.ExtractTarToFs(tempFs, compression.AutoDecompress(blobReader)) // ??? + if err != nil { + return nil, err + } + files, err := tarutils.FlatListSortedFilesInDir(tempFs, "") + if err != nil { + return nil, err + } + for _, file := range files { + log.Debug("uploading", "file", file) + artifact = artifact.ClassifierExtensionFrom(file) + reader, err := tempFs.Open(file) if err != nil { return nil, err } - defer vfs.Cleanup(tempFs) - err = tarutils.ExtractTarToFs(tempFs, blobReader) - // err = tarutils.ExtractTarToFs(tempFs, compression.AutoDecompress(blobReader)) // ??? - if err != nil { + defer reader.Close() + hash := sha256.New() + if _, err := io.Copy(hash, reader); err != nil { return nil, err } - files, err := tarutils.ListSortedFilesInDir(tempFs, "") + err = deploy(artifact, b.spec.Url, reader, username, password, digest.NewDigest(digest.SHA256, hash)) if err != nil { return nil, err } - for _, file := range files { - log.Debug("uploading", "file", file) - artifact = artifact.ClassifierExtensionFrom(file) - reader, err := tempFs.Open(file) - if err != nil { - return nil, err - } - defer reader.Close() - hash := sha256.New() - if _, err := io.Copy(hash, reader); err != nil { - return nil, err - } - err = deploy(artifact, b.spec.Url, reader, username, password, digest.NewDigest(digest.SHA256, hash)) + } + /* + default: + err = deploy(artifact, b.spec.Url, blobReader, username, password, blob.Digest()) if err != nil { return nil, err } } - default: - err = deploy(artifact, b.spec.Url, blobReader, username, password, blob.Digest()) - if err != nil { - return nil, err - } - } + */ log.Debug("done", "artifact", artifact) return mvn.New(b.spec.Url, artifact.GroupId, artifact.ArtifactId, artifact.Version, mvn.WithClassifier(artifact.Classifier), mvn.WithExtension(artifact.Extension)), nil diff --git a/pkg/contexts/ocm/blobhandler/handlers/generic/mvn/registration.go b/pkg/contexts/ocm/blobhandler/handlers/generic/mvn/registration.go index 9784c38f39..7bd4ec73e1 100644 --- a/pkg/contexts/ocm/blobhandler/handlers/generic/mvn/registration.go +++ b/pkg/contexts/ocm/blobhandler/handlers/generic/mvn/registration.go @@ -54,11 +54,6 @@ func (r *RegistrationHandler) RegisterByName(handler string, ctx cpi.Context, co ctx.BlobHandlers().Register(NewArtifactHandler(cfg), cpi.ForArtifactType(resourcetypes.MVN_ARTIFACT), - // see artifact.go#IsMimeTypeSupported() - cpi.ForMimeType(mime.MIME_JAR), - cpi.ForMimeType(mime.MIME_JSON), - cpi.ForMimeType(mime.MIME_XML), - cpi.ForMimeType(mime.MIME_GZIP), cpi.ForMimeType(mime.MIME_TGZ), cpi.NewBlobHandlerOptions(olist...), ) @@ -68,9 +63,9 @@ func (r *RegistrationHandler) RegisterByName(handler string, ctx cpi.Context, co func (r *RegistrationHandler) GetHandlers(_ cpi.Context) registrations.HandlerInfos { return registrations.NewLeafHandlerInfo("uploading mvn artifacts", ` -The `+BLOB_HANDLER_NAME+` uploader is able to upload mvn artifacts +The `+BLOB_HANDLER_NAME+` uploader is able to upload mvn artifacts (whole GAV only!) as artifact archive according to the mvn artifact spec. -If registered the default mime type is: `+mime.MIME_JAR+` +If registered the default mime type is: `+mime.MIME_TGZ+` It accepts a plain string for the URL or a config with the following field: 'url': the URL of the mvn repository. diff --git a/pkg/utils/tarutils/pack.go b/pkg/utils/tarutils/pack.go index f15daf354d..ba839cf9a3 100644 --- a/pkg/utils/tarutils/pack.go +++ b/pkg/utils/tarutils/pack.go @@ -2,6 +2,7 @@ package tarutils import ( "archive/tar" + "compress/gzip" "fmt" "io" "io/fs" @@ -218,11 +219,13 @@ func RegularFileInfoHeader(fi fs.FileInfo) *tar.Header { return h } -func ListSortedFilesInDir(fs vfs.FileSystem, root string) ([]string, error) { +// FlatListSortedFilesInDir returns a flat list of files in a directory sorted by name. +// Attention: Files with same name but in different sub-paths, will be listed only once!!! +func FlatListSortedFilesInDir(fs vfs.FileSystem, root string) ([]string, error) { var files []string err := vfs.Walk(fs, root, func(path string, info vfs.FileInfo, err error) error { if !info.IsDir() { - files = append(files, path) + files = append(files, info.Name()) } return nil }) @@ -230,9 +233,18 @@ func ListSortedFilesInDir(fs vfs.FileSystem, root string) ([]string, error) { return files, err } -func TarFs(fs vfs.FileSystem, writer io.Writer) error { +func TgzFs(fs vfs.FileSystem, writer io.Writer) error { + zip := gzip.NewWriter(writer) + err := TarFlatFs(fs, zip) + if err != nil { + return err + } + return zip.Close() +} + +func TarFlatFs(fs vfs.FileSystem, writer io.Writer) error { tw := tar.NewWriter(writer) - files, err := ListSortedFilesInDir(fs, "") + files, err := FlatListSortedFilesInDir(fs, "") if err != nil { return err }