github.com/david-imola/snapd@v0.0.0-20210611180407-2de8ddeece6d/snap/revision.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2014-2016 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package snap 21 22 import ( 23 "fmt" 24 "strconv" 25 ) 26 27 // Keep this in sync between snap and client packages. 28 29 type Revision struct { 30 N int 31 } 32 33 func (r Revision) String() string { 34 if r.N == 0 { 35 return "unset" 36 } 37 if r.N < 0 { 38 return fmt.Sprintf("x%d", -r.N) 39 } 40 return strconv.Itoa(int(r.N)) 41 } 42 43 func (r Revision) Unset() bool { 44 return r.N == 0 45 } 46 47 func (r Revision) Local() bool { 48 return r.N < 0 49 } 50 51 func (r Revision) Store() bool { 52 return r.N > 0 53 } 54 55 func (r Revision) MarshalJSON() ([]byte, error) { 56 return []byte(`"` + r.String() + `"`), nil 57 } 58 59 func (r *Revision) UnmarshalYAML(unmarshal func(interface{}) error) error { 60 var s string 61 if err := unmarshal(&s); err != nil { 62 return err 63 } 64 return r.UnmarshalJSON([]byte(`"` + s + `"`)) 65 } 66 67 func (r Revision) MarshalYAML() (interface{}, error) { 68 return r.String(), nil 69 } 70 71 func (r *Revision) UnmarshalJSON(data []byte) error { 72 if len(data) > 0 && data[0] == '"' && data[len(data)-1] == '"' { 73 parsed, err := ParseRevision(string(data[1 : len(data)-1])) 74 if err == nil { 75 *r = parsed 76 return nil 77 } 78 } else { 79 n, err := strconv.ParseInt(string(data), 10, 64) 80 if err == nil { 81 r.N = int(n) 82 return nil 83 } 84 } 85 return fmt.Errorf("invalid snap revision: %q", data) 86 } 87 88 // ParseRevisions returns the representation in r as a revision. 89 // See R for a function more suitable for hardcoded revisions. 90 func ParseRevision(s string) (Revision, error) { 91 if s == "unset" { 92 return Revision{}, nil 93 } 94 if s != "" && s[0] == 'x' { 95 i, err := strconv.Atoi(s[1:]) 96 if err == nil && i > 0 { 97 return Revision{-i}, nil 98 } 99 } 100 i, err := strconv.Atoi(s) 101 if err == nil && i > 0 { 102 return Revision{i}, nil 103 } 104 return Revision{}, fmt.Errorf("invalid snap revision: %#v", s) 105 } 106 107 // R returns a Revision given an int or a string. 108 // Providing an invalid revision type or value causes a runtime panic. 109 // See ParseRevision for a polite function that does not panic. 110 func R(r interface{}) Revision { 111 switch r := r.(type) { 112 case string: 113 revision, err := ParseRevision(r) 114 if err != nil { 115 panic(err) 116 } 117 return revision 118 case int: 119 return Revision{r} 120 default: 121 panic(fmt.Errorf("cannot use %v (%T) as a snap revision", r, r)) 122 } 123 }