2019-06-04 19:25:17 +00:00
|
|
|
// Copyright © 2019 Ettore Di Giacinto <mudler@gentoo.org>
|
2018-09-21 21:29:50 +00:00
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License along
|
|
|
|
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
package pkg
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/crillab/gophersat/bf"
|
2019-06-11 16:03:50 +00:00
|
|
|
version "github.com/hashicorp/go-version"
|
2018-09-21 21:29:50 +00:00
|
|
|
|
|
|
|
"github.com/jinzhu/copier"
|
|
|
|
)
|
|
|
|
|
2019-06-11 16:03:50 +00:00
|
|
|
// Package is a package interface (TBD)
|
|
|
|
// FIXME: Currently some of the methods are returning DefaultPackages due to JSON serialization of the package
|
2018-09-21 21:29:50 +00:00
|
|
|
type Package interface {
|
|
|
|
Encode() (string, error)
|
|
|
|
SetState(state State) Package
|
2019-06-03 21:06:53 +00:00
|
|
|
BuildFormula() ([]bf.Formula, error)
|
2018-09-21 21:29:50 +00:00
|
|
|
IsFlagged(bool) Package
|
2019-06-04 19:25:17 +00:00
|
|
|
Flagged() bool
|
2019-06-05 15:51:24 +00:00
|
|
|
GetFingerPrint() string
|
2019-06-04 19:25:17 +00:00
|
|
|
Requires([]*DefaultPackage) Package
|
|
|
|
Conflicts([]*DefaultPackage) Package
|
2019-06-05 15:51:24 +00:00
|
|
|
|
|
|
|
GetRequires() []*DefaultPackage
|
|
|
|
GetConflicts() []*DefaultPackage
|
2019-06-11 16:03:50 +00:00
|
|
|
Expand([]Package) ([]Package, error)
|
|
|
|
|
|
|
|
GetName() string
|
|
|
|
GetVersion() string
|
|
|
|
RequiresContains(Package) bool
|
2018-09-21 21:29:50 +00:00
|
|
|
}
|
|
|
|
|
2019-06-11 16:03:50 +00:00
|
|
|
// DefaultPackage represent a standard package definition
|
2018-09-21 21:29:50 +00:00
|
|
|
type DefaultPackage struct {
|
|
|
|
Name string
|
|
|
|
Version string
|
|
|
|
UseFlags []string
|
|
|
|
State State
|
2019-06-04 19:25:17 +00:00
|
|
|
PackageRequires []*DefaultPackage
|
|
|
|
PackageConflicts []*DefaultPackage
|
2018-09-21 21:29:50 +00:00
|
|
|
IsSet bool
|
|
|
|
}
|
|
|
|
|
2019-06-11 16:03:50 +00:00
|
|
|
// State represent the package state
|
2018-09-21 21:29:50 +00:00
|
|
|
type State string
|
|
|
|
|
2019-06-11 16:03:50 +00:00
|
|
|
// NewPackage returns a new package
|
2019-06-04 19:25:17 +00:00
|
|
|
func NewPackage(name, version string, requires []*DefaultPackage, conflicts []*DefaultPackage) *DefaultPackage {
|
2018-09-21 21:29:50 +00:00
|
|
|
return &DefaultPackage{Name: name, Version: version, PackageRequires: requires, PackageConflicts: conflicts}
|
|
|
|
}
|
2019-06-11 16:03:50 +00:00
|
|
|
|
|
|
|
// GetFingerPrint returns a UUID of the package.
|
|
|
|
// FIXME: this needs to be unique, now just name is generalized
|
2019-06-05 15:51:24 +00:00
|
|
|
func (p *DefaultPackage) GetFingerPrint() string {
|
|
|
|
return p.Name
|
|
|
|
}
|
2018-09-21 21:29:50 +00:00
|
|
|
|
2019-06-11 16:03:50 +00:00
|
|
|
// AddUse adds a use to a package
|
2018-09-21 21:29:50 +00:00
|
|
|
func (p *DefaultPackage) AddUse(use string) {
|
|
|
|
for _, v := range p.UseFlags {
|
|
|
|
if v == use {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p.UseFlags = append(p.UseFlags, use)
|
|
|
|
}
|
|
|
|
|
2019-06-11 16:03:50 +00:00
|
|
|
// RemoveUse removes a use to a package
|
2018-09-21 21:29:50 +00:00
|
|
|
func (p *DefaultPackage) RemoveUse(use string) {
|
|
|
|
|
|
|
|
for i := len(p.UseFlags) - 1; i >= 0; i-- {
|
|
|
|
if p.UseFlags[i] == use {
|
|
|
|
p.UseFlags = append(p.UseFlags[:i], p.UseFlags[i+1:]...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-06-11 16:03:50 +00:00
|
|
|
// Encode encodes the package to string.
|
|
|
|
// It returns an ID which can be used to retrieve the package later on.
|
2018-09-21 21:29:50 +00:00
|
|
|
func (p *DefaultPackage) Encode() (string, error) {
|
2019-06-11 21:04:01 +00:00
|
|
|
return NewInMemoryDatabase().CreatePackage(p)
|
2018-09-21 21:29:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *DefaultPackage) WithState(state State) Package {
|
|
|
|
return p.Clone().SetState(state)
|
|
|
|
}
|
|
|
|
func (p *DefaultPackage) IsFlagged(b bool) Package {
|
|
|
|
p.IsSet = b
|
|
|
|
return p
|
|
|
|
}
|
2019-06-04 19:25:17 +00:00
|
|
|
func (p *DefaultPackage) Flagged() bool {
|
|
|
|
return p.IsSet
|
|
|
|
}
|
2019-06-11 16:03:50 +00:00
|
|
|
func (p *DefaultPackage) GetName() string {
|
|
|
|
return p.Name
|
|
|
|
}
|
|
|
|
func (p *DefaultPackage) GetVersion() string {
|
|
|
|
return p.Version
|
|
|
|
}
|
2018-09-21 21:29:50 +00:00
|
|
|
func (p *DefaultPackage) SetState(state State) Package {
|
|
|
|
p.State = state
|
|
|
|
return p
|
|
|
|
}
|
2019-06-05 15:51:24 +00:00
|
|
|
func (p *DefaultPackage) GetRequires() []*DefaultPackage {
|
|
|
|
return p.PackageRequires
|
|
|
|
}
|
|
|
|
func (p *DefaultPackage) GetConflicts() []*DefaultPackage {
|
|
|
|
return p.PackageConflicts
|
|
|
|
}
|
2019-06-04 19:25:17 +00:00
|
|
|
func (p *DefaultPackage) Requires(req []*DefaultPackage) Package {
|
2018-09-21 21:29:50 +00:00
|
|
|
p.PackageRequires = req
|
|
|
|
return p
|
|
|
|
}
|
2019-06-04 19:25:17 +00:00
|
|
|
func (p *DefaultPackage) Conflicts(req []*DefaultPackage) Package {
|
2018-09-21 21:29:50 +00:00
|
|
|
p.PackageConflicts = req
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
func (p *DefaultPackage) Clone() Package {
|
|
|
|
new := &DefaultPackage{}
|
|
|
|
copier.Copy(&new, &p)
|
|
|
|
return new
|
|
|
|
}
|
|
|
|
|
2019-06-11 16:03:50 +00:00
|
|
|
func (p *DefaultPackage) Expand(world []Package) ([]Package, error) {
|
|
|
|
|
|
|
|
var versionsInWorld []Package
|
|
|
|
for _, w := range world {
|
2019-06-11 16:47:07 +00:00
|
|
|
if w.GetName() != p.GetName() {
|
|
|
|
continue
|
|
|
|
}
|
2019-06-11 16:03:50 +00:00
|
|
|
|
2019-06-11 16:47:07 +00:00
|
|
|
v, err := version.NewVersion(w.GetVersion())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
constraints, err := version.NewConstraint(p.GetVersion())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if constraints.Check(v) {
|
|
|
|
versionsInWorld = append(versionsInWorld, w)
|
2019-06-11 16:03:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return versionsInWorld, nil
|
|
|
|
}
|
|
|
|
|
2019-06-04 19:25:17 +00:00
|
|
|
func DecodePackage(ID string) (Package, error) {
|
2019-06-11 21:04:01 +00:00
|
|
|
return NewInMemoryDatabase().GetPackage(ID)
|
2018-09-21 21:29:50 +00:00
|
|
|
}
|
|
|
|
|
2019-06-05 16:40:33 +00:00
|
|
|
func NormalizeFlagged(p Package) {
|
|
|
|
for _, r := range p.GetRequires() {
|
|
|
|
r.IsFlagged(true)
|
|
|
|
NormalizeFlagged(r)
|
|
|
|
}
|
|
|
|
for _, r := range p.GetConflicts() {
|
|
|
|
r.IsFlagged(true)
|
|
|
|
NormalizeFlagged(r)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-11 16:03:50 +00:00
|
|
|
func (p *DefaultPackage) RequiresContains(s Package) bool {
|
|
|
|
for _, re := range p.GetRequires() {
|
|
|
|
if re.GetFingerPrint() == s.GetFingerPrint() {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
if re.RequiresContains(s) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2019-06-03 21:06:53 +00:00
|
|
|
func (p *DefaultPackage) BuildFormula() ([]bf.Formula, error) {
|
2019-06-04 19:25:17 +00:00
|
|
|
encodedA, err := p.IsFlagged(true).Encode()
|
2018-09-21 21:29:50 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-06-05 16:40:33 +00:00
|
|
|
NormalizeFlagged(p)
|
2018-09-21 21:29:50 +00:00
|
|
|
|
|
|
|
A := bf.Var(encodedA)
|
|
|
|
|
2019-06-04 19:57:13 +00:00
|
|
|
var formulas []bf.Formula
|
2018-09-21 21:29:50 +00:00
|
|
|
|
|
|
|
for _, required := range p.PackageRequires {
|
2019-06-05 16:40:33 +00:00
|
|
|
encodedB, err := required.Encode()
|
2018-09-21 21:29:50 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
B := bf.Var(encodedB)
|
2019-06-04 19:25:17 +00:00
|
|
|
formulas = append(formulas, bf.Or(bf.Not(A), B))
|
2018-09-21 21:29:50 +00:00
|
|
|
|
2019-06-03 21:23:02 +00:00
|
|
|
f, err := required.BuildFormula()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
formulas = append(formulas, f...)
|
|
|
|
|
2018-09-21 21:29:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, required := range p.PackageConflicts {
|
2019-06-05 16:40:33 +00:00
|
|
|
encodedB, err := required.Encode()
|
2018-09-21 21:29:50 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
B := bf.Var(encodedB)
|
2019-06-04 19:25:17 +00:00
|
|
|
formulas = append(formulas, bf.Or(bf.Not(A),
|
|
|
|
bf.Not(B)))
|
2019-06-03 21:23:02 +00:00
|
|
|
|
|
|
|
f, err := required.BuildFormula()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
formulas = append(formulas, f...)
|
2018-09-21 21:29:50 +00:00
|
|
|
}
|
2019-06-04 19:25:17 +00:00
|
|
|
return formulas, nil
|
2018-09-21 21:29:50 +00:00
|
|
|
}
|