代码拉取完成,页面将自动刷新
同步操作将从 tupelo-shen/mysnapd 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2016-2021 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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 asserts
import (
"fmt"
"io"
"strings"
)
// Batch allows to accumulate a set of assertions possibly out of
// prerequisite order and then add them in one go to an assertion
// database.
// Nothing will be committed if there are missing prerequisites, for a full
// consistency check beforehand there is the Precheck option.
type Batch struct {
bs Backstore
added []Assertion
// added is in prereq order
inPrereqOrder bool
unsupported func(u *Ref, err error) error
}
// NewBatch creates a new Batch to accumulate assertions to add in one
// go to an assertion database.
// unsupported can be used to ignore/log assertions with unsupported formats,
// default behavior is to error on them.
func NewBatch(unsupported func(u *Ref, err error) error) *Batch {
if unsupported == nil {
unsupported = func(_ *Ref, err error) error {
return err
}
}
return &Batch{
bs: NewMemoryBackstore(),
inPrereqOrder: true, // empty list is trivially so
unsupported: unsupported,
}
}
// Add one assertion to the batch.
func (b *Batch) Add(a Assertion) error {
b.inPrereqOrder = false
if !a.SupportedFormat() {
err := &UnsupportedFormatError{Ref: a.Ref(), Format: a.Format()}
return b.unsupported(a.Ref(), err)
}
if err := b.bs.Put(a.Type(), a); err != nil {
if revErr, ok := err.(*RevisionError); ok {
if revErr.Current >= a.Revision() {
// we already got something more recent
return nil
}
}
return err
}
b.added = append(b.added, a)
return nil
}
// AddStream adds a stream of assertions to the batch.
// Returns references to the assertions effectively added.
func (b *Batch) AddStream(r io.Reader) ([]*Ref, error) {
b.inPrereqOrder = false
start := len(b.added)
dec := NewDecoder(r)
for {
a, err := dec.Decode()
if err == io.EOF {
break
}
if err != nil {
return nil, err
}
if err := b.Add(a); err != nil {
return nil, err
}
}
added := b.added[start:]
if len(added) == 0 {
return nil, nil
}
refs := make([]*Ref, len(added))
for i, a := range added {
refs[i] = a.Ref()
}
return refs, nil
}
// Fetch adds to the batch by invoking fetching to drive an internal
// Fetcher that was built with trustedDB and retrieve.
func (b *Batch) Fetch(trustedDB RODatabase, retrieve func(*Ref) (Assertion, error), fetching func(Fetcher) error) error {
f := NewFetcher(trustedDB, retrieve, b.Add)
return fetching(f)
}
func (b *Batch) precheck(db *Database) error {
db = db.WithStackedBackstore(NewMemoryBackstore())
return b.commitTo(db, nil)
}
type CommitOptions struct {
// Precheck indicates whether to do a full consistency check
// before starting adding the batch.
Precheck bool
}
// CommitTo adds the batch of assertions to the given assertion database.
// Nothing will be committed if there are missing prerequisites, for a full
// consistency check beforehand there is the Precheck option.
func (b *Batch) CommitTo(db *Database, opts *CommitOptions) error {
if opts == nil {
opts = &CommitOptions{}
}
if opts.Precheck {
if err := b.precheck(db); err != nil {
return err
}
}
return b.commitTo(db, nil)
}
// CommitToAndObserve adds the batch of assertions to the given
// assertion database while invoking observe for each one after they
// are added.
// Nothing will be committed if there are missing prerequisites, for a
// full consistency check beforehand there is the Precheck option.
// For convenience observe can be nil in which case is ignored.
func (b *Batch) CommitToAndObserve(db *Database, observe func(Assertion), opts *CommitOptions) error {
if opts == nil {
opts = &CommitOptions{}
}
if opts.Precheck {
if err := b.precheck(db); err != nil {
return err
}
}
return b.commitTo(db, observe)
}
// commitTo does a best effort of adding all the batch assertions to
// the target database.
func (b *Batch) commitTo(db *Database, observe func(Assertion)) error {
if err := b.prereqSort(db); err != nil {
return err
}
// TODO: trigger w. caller a global validity check if something is revoked
// (but try to save as much possible still),
// or err is a check error
var errs []error
for _, a := range b.added {
err := db.Add(a)
if IsUnaccceptedUpdate(err) {
// unsupported format case is handled before
// be idempotent
// system db has already the same or newer
continue
}
if err != nil {
errs = append(errs, err)
} else if observe != nil {
observe(a)
}
}
if len(errs) != 0 {
return &commitError{errs: errs}
}
return nil
}
func (b *Batch) prereqSort(db *Database) error {
if b.inPrereqOrder {
// nothing to do
return nil
}
// put in prereq order using a fetcher
ordered := make([]Assertion, 0, len(b.added))
retrieve := func(ref *Ref) (Assertion, error) {
a, err := b.bs.Get(ref.Type, ref.PrimaryKey, ref.Type.MaxSupportedFormat())
if IsNotFound(err) {
// fallback to pre-existing assertions
a, err = ref.Resolve(db.Find)
}
if err != nil {
return nil, resolveError("cannot resolve prerequisite assertion: %s", ref, err)
}
return a, nil
}
save := func(a Assertion) error {
ordered = append(ordered, a)
return nil
}
f := NewFetcher(db, retrieve, save)
for _, a := range b.added {
if err := f.Fetch(a.Ref()); err != nil {
return err
}
}
b.added = ordered
b.inPrereqOrder = true
return nil
}
func resolveError(format string, ref *Ref, err error) error {
if IsNotFound(err) {
return fmt.Errorf(format, ref)
} else {
return fmt.Errorf(format+": %v", ref, err)
}
}
type commitError struct {
errs []error
}
func (e *commitError) Error() string {
l := []string{""}
for _, e := range e.errs {
l = append(l, e.Error())
}
return fmt.Sprintf("cannot accept some assertions:%s", strings.Join(l, "\n - "))
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。