代码拉取完成,页面将自动刷新
同步操作将从 tupelo-shen/mysnapd 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2018-2019 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 channel
import (
"errors"
"fmt"
"strings"
"gitee.com/mysnapcore/mysnapd/arch"
"gitee.com/mysnapcore/mysnapd/strutil"
)
var channelRisks = []string{"stable", "candidate", "beta", "edge"}
// Channel identifies and describes completely a store channel.
type Channel struct {
Architecture string `json:"architecture"`
Name string `json:"name"`
Track string `json:"track"`
Risk string `json:"risk"`
Branch string `json:"branch,omitempty"`
}
func isSlash(r rune) bool { return r == '/' }
// TODO: currently there's some overlap between the toplevel Full, and
// methods Clean, String, and Full. Needs further refactoring.
func Full(s string) (string, error) {
if s == "" {
return "", nil
}
components := strings.FieldsFunc(s, isSlash)
switch len(components) {
case 0:
return "", nil
case 1:
if strutil.ListContains(channelRisks, components[0]) {
return "latest/" + components[0], nil
}
return components[0] + "/stable", nil
case 2:
if strutil.ListContains(channelRisks, components[0]) {
return "latest/" + strings.Join(components, "/"), nil
}
fallthrough
case 3:
return strings.Join(components, "/"), nil
default:
return "", errors.New("invalid channel")
}
}
// ParseVerbatim parses a string representing a store channel and
// includes the given architecture, if architecture is "" the system
// architecture is included. The channel representation is not normalized.
// Parse() should be used in most cases.
func ParseVerbatim(s string, architecture string) (Channel, error) {
if s == "" {
return Channel{}, fmt.Errorf("channel name cannot be empty")
}
p := strings.Split(s, "/")
var risk, track, branch *string
switch len(p) {
default:
return Channel{}, fmt.Errorf("channel name has too many components: %s", s)
case 3:
track, risk, branch = &p[0], &p[1], &p[2]
case 2:
if strutil.ListContains(channelRisks, p[0]) {
risk, branch = &p[0], &p[1]
} else {
track, risk = &p[0], &p[1]
}
case 1:
if strutil.ListContains(channelRisks, p[0]) {
risk = &p[0]
} else {
track = &p[0]
}
}
if architecture == "" {
architecture = arch.DpkgArchitecture()
}
ch := Channel{
Architecture: architecture,
}
if risk != nil {
if !strutil.ListContains(channelRisks, *risk) {
return Channel{}, fmt.Errorf("invalid risk in channel name: %s", s)
}
ch.Risk = *risk
}
if track != nil {
if *track == "" {
return Channel{}, fmt.Errorf("invalid track in channel name: %s", s)
}
ch.Track = *track
}
if branch != nil {
if *branch == "" {
return Channel{}, fmt.Errorf("invalid branch in channel name: %s", s)
}
ch.Branch = *branch
}
return ch, nil
}
// Parse parses a string representing a store channel and includes given
// architecture, , if architecture is "" the system architecture is included.
// The returned channel's track, risk and name are normalized.
func Parse(s string, architecture string) (Channel, error) {
channel, err := ParseVerbatim(s, architecture)
if err != nil {
return Channel{}, err
}
return channel.Clean(), nil
}
// Clean returns a Channel with a normalized track, risk and name.
func (c Channel) Clean() Channel {
track := c.Track
risk := c.Risk
if track == "latest" {
track = ""
}
if risk == "" {
risk = "stable"
}
// normalized name
name := risk
if track != "" {
name = track + "/" + name
}
if c.Branch != "" {
name = name + "/" + c.Branch
}
return Channel{
Architecture: c.Architecture,
Name: name,
Track: track,
Risk: risk,
Branch: c.Branch,
}
}
func (c Channel) String() string {
return c.Name
}
// Full returns the full name of the channel, inclusive the default track "latest".
func (c *Channel) Full() string {
ch := c.String()
full, err := Full(ch)
if err != nil {
// unpossible
panic("channel.String() returned a malformed channel: " + ch)
}
return full
}
// VerbatimTrackOnly returns whether the channel represents a track only.
func (c *Channel) VerbatimTrackOnly() bool {
return c.Track != "" && c.Risk == "" && c.Branch == ""
}
// VerbatimRiskOnly returns whether the channel represents a risk only.
func (c *Channel) VerbatimRiskOnly() bool {
return c.Track == "" && c.Risk != "" && c.Branch == ""
}
func riskLevel(risk string) int {
for i, r := range channelRisks {
if r == risk {
return i
}
}
return -1
}
// ChannelMatch represents on which fields two channels are matching.
type ChannelMatch struct {
Architecture bool
Track bool
Risk bool
}
// String returns the string represantion of the match, results can be:
// "architecture:track:risk"
// "architecture:track"
// "architecture:risk"
// "track:risk"
// "architecture"
// "track"
// "risk"
// ""
func (cm ChannelMatch) String() string {
matching := []string{}
if cm.Architecture {
matching = append(matching, "architecture")
}
if cm.Track {
matching = append(matching, "track")
}
if cm.Risk {
matching = append(matching, "risk")
}
return strings.Join(matching, ":")
}
// Match returns a ChannelMatch of which fields among architecture,track,risk match between c and c1 store channels, risk is matched taking channel inheritance into account and considering c the requested channel.
func (c *Channel) Match(c1 *Channel) ChannelMatch {
requestedRiskLevel := riskLevel(c.Risk)
rl1 := riskLevel(c1.Risk)
return ChannelMatch{
Architecture: c.Architecture == c1.Architecture,
Track: c.Track == c1.Track,
Risk: requestedRiskLevel >= rl1,
}
}
// Resolve resolves newChannel wrt channel, this means if newChannel
// is risk/branch only it will preserve the track of channel. It
// assumes that if both are not empty, channel is parseable.
func Resolve(channel, newChannel string) (string, error) {
if newChannel == "" {
return channel, nil
}
if channel == "" {
return newChannel, nil
}
ch, err := ParseVerbatim(channel, "-")
if err != nil {
return "", err
}
p := strings.Split(newChannel, "/")
if strutil.ListContains(channelRisks, p[0]) && ch.Track != "" {
// risk/branch inherits the track if any
return ch.Track + "/" + newChannel, nil
}
return newChannel, nil
}
var ErrPinnedTrackSwitch = errors.New("cannot switch pinned track")
// ResolvePinned resolves newChannel wrt a pinned track, newChannel
// can only be risk/branch-only or have the same track, otherwise
// ErrPinnedTrackSwitch is returned.
func ResolvePinned(track, newChannel string) (string, error) {
if track == "" {
return newChannel, nil
}
ch, err := ParseVerbatim(track, "-")
if err != nil || !ch.VerbatimTrackOnly() {
return "", fmt.Errorf("invalid pinned track: %s", track)
}
if newChannel == "" {
return track, nil
}
trackPrefix := ch.Track + "/"
p := strings.Split(newChannel, "/")
if strutil.ListContains(channelRisks, p[0]) && ch.Track != "" {
// risk/branch inherits the track if any
return trackPrefix + newChannel, nil
}
if newChannel != track && !strings.HasPrefix(newChannel, trackPrefix) {
// the track is pinned
return "", ErrPinnedTrackSwitch
}
return newChannel, nil
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。