github.com/stulluk/snapd@v0.0.0-20210611110309-f6d5d5bd24b0/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  }