blob: 31a28835cb8ffedadb8292478930babba01d69b7 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Package pkg contains the in memory representations of a Package in the pm
// system and associated utilities.
package pkg
import (
"errors"
"fmt"
"regexp"
"sort"
"strings"
)
// ErrInvalidPackageName occurs when a package name contains one of InvalidPackageChars or is any of the exact InvalidNames.
var ErrInvalidPackageName = errors.New("pkg: invalid package name")
// ErrInvalidPackageVersion occurs when a package version contains one of InvalidPackageChars or is any of the exact InvalidNames.
var ErrInvalidPackageVersion = errors.New("pkg: invalid package version")
// InvalidPackageChars contains a list of characters that are disallowed in package names
const InvalidPackageChars = "/="
// InvalidNames are package names & versions that are invalid
var InvalidNames = []string{".", ".."}
// ValidPackageName contains RegEx for a valid
// [package name](https://fuchsia.dev/fuchsia-src/concepts/packages/package_url#package-name)
var ValidPackageName = regexp.MustCompile(`^[-_\.a-z0-9]{1,255}$`).MatchString
// Package is a representation of basic package metadata
type Package struct {
Name string `json:"name"`
Version string `json:"version"`
}
// Validate returns an error if the package contains an invalid value in one of it's fields.
func (pkg *Package) Validate() error {
if !ValidPackageName(pkg.Name) {
return fmt.Errorf("pkg: invalid package name \"%v\"", pkg.Name)
}
if strings.ContainsAny(pkg.Version, InvalidPackageChars) {
return ErrInvalidPackageVersion
}
for _, name := range InvalidNames {
if pkg.Name == name {
return ErrInvalidPackageName
}
if pkg.Version == name {
return ErrInvalidPackageVersion
}
}
if pkg.Version != "0" {
return ErrInvalidPackageVersion
}
return nil
}
// ByNameVersion is an implementation of sort.Interface around a slice of Package
type ByNameVersion []Package
func (b ByNameVersion) Len() int {
return len(b)
}
func (b ByNameVersion) Less(i, j int) bool {
v := strings.Compare(b[i].Name, b[j].Name)
if v == 0 {
return strings.Compare(b[i].Version, b[j].Version) < 0
}
return v < 0
}
func (b ByNameVersion) Swap(i, j int) {
b[i], b[j] = b[j], b[i]
}
// check interface implementation
var _ sort.Interface = ByNameVersion(nil)