Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 16 additions & 27 deletions internal/archiver/archive_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,43 +56,32 @@ type tarReader struct {
closer io.Closer
}

func (t *tarReader) resetReader() error {
err := t.Close()
if err != nil {
return err
}

// Reopen the file
func (t *tarReader) FileNames() ([]string, error) {
f, err := os.Open(t.filename)
if err != nil {
return err
return nil, err
}

if strings.HasSuffix(t.filename, ".tar.gz") || strings.HasSuffix(t.filename, ".tgz") {
gzr, err := gzip.NewReader(f)
defer func(f *os.File) {
err := f.Close()
if err != nil {
cerr := f.Close()
if cerr != nil {
return cerr
}
return err
log.Printf("error closing file: %v", err)
}
t.Reader = tar.NewReader(gzr) // Reset the tar reader with new gzip reader
}
}(f)

return nil
}

func (t *tarReader) FileNames() ([]string, error) {
defer func(t *tarReader) {
err := t.resetReader()
if err != nil {
log.Printf("error resetting reader: %v", err)
gzr, err := gzip.NewReader(f)
if err != nil {
cerr := f.Close()
if cerr != nil {
return nil, cerr
}
}(t)
return nil, err
}
tarReader := tar.NewReader(gzr)

var names []string
for {
hdr, err := t.Next()
hdr, err := tarReader.Next()
if err == io.EOF {
break
}
Expand Down
2 changes: 1 addition & 1 deletion internal/distributions/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func NewDistributionMetadata(filename string) (Distribution, string, string, err
// "bdist_egg": BDist,
}
if err != nil {
return nil, "", "", fmt.Errorf("invalid distribution file: %s, err: %v", filepath.Base(filename), err)
return nil, "", "", fmt.Errorf("invalid distribution file: %s: %v", filepath.Base(filename), err)
}

// If this encounters a metadata version it doesn't support, it may give us
Expand Down
3 changes: 2 additions & 1 deletion internal/distributions/sdist.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ package distributions
import (
"bytes"
"fmt"
"github.com/rstudio/python-distribution-parser/internal/archiver"
"log"
"path/filepath"
"sort"
"strings"

"github.com/rstudio/python-distribution-parser/internal/archiver"
)

type SDist struct {
Expand Down
118 changes: 5 additions & 113 deletions internal/packages/package.go
Original file line number Diff line number Diff line change
@@ -1,37 +1,13 @@
package packages

import (
"errors"
"github.com/rstudio/python-distribution-parser/internal/distributions"
"github.com/samber/lo"
"io"
"log"
"os"
"path/filepath"
)

type PackageFile struct {
Filename string `json:"file_name"`
Comment string `json:"comment"`
BaseFilename string `json:"base_filename"`
Metadata *distributions.Distribution `json:"metadata"`
PythonVersion string `json:"pyversion"`
FileType string `json:"filetype"`
SafeName string `json:"safe_name"`
SignedFilename string `json:"signed_filename"`
SignedBaseFilename string `json:"signed_base_filename"`
GPGSignature *Signature `json:"gpg_signature"`
MD5Digest string `json:"md5_digest"`
SHA2Digest string `json:"sha256_digest"`
Blake2_256Digest string `json:"blake2_256_digest"`
}

type Signature struct {
Filename string `json:"signed_filename"`
Bytes []byte `json:"signed_bytes"`
}
"github.com/rstudio/python-distribution-parser/internal/distributions"
"github.com/rstudio/python-distribution-parser/types"
)

func NewPackageFile(filename string) (*PackageFile, error) {
func NewPackageFile(filename string) (*types.PackageFile, error) {
metadata, pythonVersion, fileType, err := distributions.NewDistributionMetadata(filename)
if err != nil {
return nil, err
Expand All @@ -53,7 +29,7 @@ func NewPackageFile(filename string) (*PackageFile, error) {
}
hexdigest := hashManager.HexDigest()

return &PackageFile{
return &types.PackageFile{
Filename: filename,
Comment: "", // Adding a comment isn't currently possible
BaseFilename: baseFilename,
Expand All @@ -68,87 +44,3 @@ func NewPackageFile(filename string) (*PackageFile, error) {
Blake2_256Digest: hexdigest.blake2,
}, nil
}

func (pf *PackageFile) MetadataMap() map[string][]string {
pkgMap := distributions.StructToMap(pf)
metadata := *pf.Metadata
metadataMap := metadata.MetadataMap()
result := make(map[string][]string, len(pkgMap)+len(metadataMap))
for pk, pv := range pkgMap {
result[pk] = pv
}
for mk, mv := range metadataMap {
result[mk] = mv
}

result["name"] = result["safe_name"]
// This makes the request look more like Twine
result["protocol_version"] = []string{"1"}
result[":action"] = []string{"file_upload"}

ignoredKeys := []string{
"base_filename",
"file_name",
"safe_name",
"signed_base_filename",
"signed_filename",
"metadata",
}

for _, key := range ignoredKeys {
delete(result, key)
}

allowedBlankValues := []string{
"author",
"author_email",
"comment",
"download_url",
"home_page",
"keywords",
"license",
"maintainer",
"pyversion",
"description_content_type",
"maintainer_email",
"requires_python",
}

// remove any keys that are an empty value, unless twine expects them
result = lo.OmitBy(result, func(key string, value []string) bool {
if lo.Contains(allowedBlankValues, key) {
return false
}
return value == nil || len(value) == 1 && (value[0] == "" || value[0] == "<nil>")
})

return result
}

func (pf *PackageFile) AddGPGSignature(signatureFilepath string, signatureFilename string) error {
if pf.GPGSignature != nil {
return errors.New("GPG Signature can only be added once")
}

gpg, err := os.Open(signatureFilepath)
if err != nil {
return err
}
defer func(gpg *os.File) {
err := gpg.Close()
if err != nil {
log.Printf("error closing file: %v", err)
}
}(gpg)

bytes, err := io.ReadAll(gpg)
if err != nil {
return err
}

pf.GPGSignature = &Signature{
Filename: signatureFilename,
Bytes: bytes,
}
return nil
}
49 changes: 27 additions & 22 deletions parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package parse
import (
"errors"
"fmt"
"github.com/rstudio/python-distribution-parser/internal/packages"
"os"
"path/filepath"
"sort"
"strings"

"github.com/rstudio/python-distribution-parser/internal/packages"
"github.com/rstudio/python-distribution-parser/types"
)

func endsWith(str, suffix string) bool {
Expand Down Expand Up @@ -57,10 +59,10 @@ func findDistributions(dists []string) ([]string, error) {
return groupWheelFilesFirst(packages), nil
}

func makePackage(filename string, signatures map[string]string) (*packages.PackageFile, error) {
func makePackage(filename string, signatures map[string]string) (*types.PackageFile, error) {
packageFile, err := packages.NewPackageFile(filename)
if err != nil {
return nil, fmt.Errorf("unable to create packageFile from %s: %v\n", filename, err)
return nil, fmt.Errorf("unable to parse %s, path may not point to a valid Python package: %v\n", filename, err)
}

signedName := packageFile.SignedBaseFilename
Expand All @@ -78,7 +80,7 @@ func makePackage(filename string, signatures map[string]string) (*packages.Packa
return packageFile, nil
}

func parse(dists []string) ([]*packages.PackageFile, error) {
func parse(dists []string) ([]*types.PackageFile, error) {
dists, err := findDistributions(dists)
if err != nil {
return nil, fmt.Errorf("error finding distributions: %v\n", err)
Expand All @@ -98,7 +100,7 @@ func parse(dists []string) ([]*packages.PackageFile, error) {
}
}

var packages []*packages.PackageFile
var packages []*types.PackageFile
for _, filename := range distributions {
p, err := makePackage(filename, signatures)
if err != nil {
Expand All @@ -110,30 +112,33 @@ func parse(dists []string) ([]*packages.PackageFile, error) {
return packages, nil
}

func Parse(path string) ([]*packages.PackageFile, error) {
func Parse(paths ...string) ([]*types.PackageFile, error) {
var files []string
info, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return nil, fmt.Errorf("%s does not exist: %v\n", path, err)
}
return nil, err
}

if info.IsDir() {
dirFiles, err := os.ReadDir(path)
for _, path := range paths {
info, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return nil, fmt.Errorf("%s does not exist: %v\n", path, err)
}
return nil, err
}
for _, entry := range dirFiles {
// Don't recursively go in directories, only go one level deep.
if !entry.IsDir() {
fullPath := filepath.Join(path, entry.Name())
files = append(files, fullPath)

if info.IsDir() {
dirFiles, err := os.ReadDir(path)
if err != nil {
return nil, err
}
for _, entry := range dirFiles {
// Don't recursively go in directories, only go one level deep.
if !entry.IsDir() {
fullPath := filepath.Join(path, entry.Name())
files = append(files, fullPath)
}
}
} else {
files = append(files, path)
}
} else {
files = append(files, path)
}

if len(files) == 0 {
Expand Down
Loading