mirror of
				https://github.com/go-gitea/gitea
				synced 2025-11-03 04:48:25 +00:00 
			
		
		
		
	Result of running `perl -p -i -e 's#interface\{\}#any#g' **/*` and `make fmt`.
Basically the same [as golang did](2580d0e08d).
		
	
		
			
				
	
	
		
			154 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			154 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2022 The Gitea Authors. All rights reserved.
 | 
						|
// SPDX-License-Identifier: MIT
 | 
						|
 | 
						|
package pub
 | 
						|
 | 
						|
import (
 | 
						|
	"archive/tar"
 | 
						|
	"compress/gzip"
 | 
						|
	"io"
 | 
						|
	"regexp"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"code.gitea.io/gitea/modules/util"
 | 
						|
	"code.gitea.io/gitea/modules/validation"
 | 
						|
 | 
						|
	"github.com/hashicorp/go-version"
 | 
						|
	"gopkg.in/yaml.v3"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	ErrMissingPubspecFile  = util.NewInvalidArgumentErrorf("Pubspec file is missing")
 | 
						|
	ErrPubspecFileTooLarge = util.NewInvalidArgumentErrorf("Pubspec file is too large")
 | 
						|
	ErrInvalidName         = util.NewInvalidArgumentErrorf("package name is invalid")
 | 
						|
	ErrInvalidVersion      = util.NewInvalidArgumentErrorf("package version is invalid")
 | 
						|
)
 | 
						|
 | 
						|
var namePattern = regexp.MustCompile(`\A[a-zA-Z_][a-zA-Z0-9_]*\z`)
 | 
						|
 | 
						|
// https://github.com/dart-lang/pub-dev/blob/4d582302a8d10152a5cd6129f65bf4f4dbca239d/pkg/pub_package_reader/lib/pub_package_reader.dart#L143
 | 
						|
const maxPubspecFileSize = 128 * 1024
 | 
						|
 | 
						|
// Package represents a Pub package
 | 
						|
type Package struct {
 | 
						|
	Name     string
 | 
						|
	Version  string
 | 
						|
	Metadata *Metadata
 | 
						|
}
 | 
						|
 | 
						|
// Metadata represents the metadata of a Pub package
 | 
						|
type Metadata struct {
 | 
						|
	Description      string `json:"description,omitempty"`
 | 
						|
	ProjectURL       string `json:"project_url,omitempty"`
 | 
						|
	RepositoryURL    string `json:"repository_url,omitempty"`
 | 
						|
	DocumentationURL string `json:"documentation_url,omitempty"`
 | 
						|
	Readme           string `json:"readme,omitempty"`
 | 
						|
	Pubspec          any    `json:"pubspec"`
 | 
						|
}
 | 
						|
 | 
						|
type pubspecPackage struct {
 | 
						|
	Name          string `yaml:"name"`
 | 
						|
	Version       string `yaml:"version"`
 | 
						|
	Description   string `yaml:"description"`
 | 
						|
	Homepage      string `yaml:"homepage"`
 | 
						|
	Repository    string `yaml:"repository"`
 | 
						|
	Documentation string `yaml:"documentation"`
 | 
						|
}
 | 
						|
 | 
						|
// ParsePackage parses the Pub package file
 | 
						|
func ParsePackage(r io.Reader) (*Package, error) {
 | 
						|
	gzr, err := gzip.NewReader(r)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	defer gzr.Close()
 | 
						|
 | 
						|
	var p *Package
 | 
						|
	var readme string
 | 
						|
 | 
						|
	tr := tar.NewReader(gzr)
 | 
						|
	for {
 | 
						|
		hd, err := tr.Next()
 | 
						|
		if err == io.EOF {
 | 
						|
			break
 | 
						|
		}
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		if hd.Typeflag != tar.TypeReg {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if hd.Name == "pubspec.yaml" {
 | 
						|
			if hd.Size > maxPubspecFileSize {
 | 
						|
				return nil, ErrPubspecFileTooLarge
 | 
						|
			}
 | 
						|
			p, err = ParsePubspecMetadata(tr)
 | 
						|
			if err != nil {
 | 
						|
				return nil, err
 | 
						|
			}
 | 
						|
		} else if strings.ToLower(hd.Name) == "readme.md" {
 | 
						|
			data, err := io.ReadAll(tr)
 | 
						|
			if err != nil {
 | 
						|
				return nil, err
 | 
						|
			}
 | 
						|
			readme = string(data)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if p == nil {
 | 
						|
		return nil, ErrMissingPubspecFile
 | 
						|
	}
 | 
						|
 | 
						|
	p.Metadata.Readme = readme
 | 
						|
 | 
						|
	return p, nil
 | 
						|
}
 | 
						|
 | 
						|
// ParsePubspecMetadata parses a Pubspec file to retrieve the metadata of a Pub package
 | 
						|
func ParsePubspecMetadata(r io.Reader) (*Package, error) {
 | 
						|
	buf, err := io.ReadAll(io.LimitReader(r, maxPubspecFileSize))
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	var p pubspecPackage
 | 
						|
	if err := yaml.Unmarshal(buf, &p); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	if !namePattern.MatchString(p.Name) {
 | 
						|
		return nil, ErrInvalidName
 | 
						|
	}
 | 
						|
 | 
						|
	v, err := version.NewSemver(p.Version)
 | 
						|
	if err != nil {
 | 
						|
		return nil, ErrInvalidVersion
 | 
						|
	}
 | 
						|
 | 
						|
	if !validation.IsValidURL(p.Homepage) {
 | 
						|
		p.Homepage = ""
 | 
						|
	}
 | 
						|
	if !validation.IsValidURL(p.Repository) {
 | 
						|
		p.Repository = ""
 | 
						|
	}
 | 
						|
 | 
						|
	var pubspec any
 | 
						|
	if err := yaml.Unmarshal(buf, &pubspec); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return &Package{
 | 
						|
		Name:    p.Name,
 | 
						|
		Version: v.String(),
 | 
						|
		Metadata: &Metadata{
 | 
						|
			Description:      p.Description,
 | 
						|
			ProjectURL:       p.Homepage,
 | 
						|
			RepositoryURL:    p.Repository,
 | 
						|
			DocumentationURL: p.Documentation,
 | 
						|
			Pubspec:          pubspec,
 | 
						|
		},
 | 
						|
	}, nil
 | 
						|
}
 |