gitee.com/mysnapcore/mysnapd@v0.1.0/cmd/snap/last.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2017 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 main
    21  
    22  import (
    23  	"errors"
    24  	"fmt"
    25  
    26  	"gitee.com/mysnapcore/mysnapd/client"
    27  	"gitee.com/mysnapcore/mysnapd/i18n"
    28  	"gitee.com/mysnapcore/mysnapd/strutil"
    29  )
    30  
    31  type changeIDMixin struct {
    32  	clientMixin
    33  	LastChangeType string `long:"last"`
    34  	Positional     struct {
    35  		ID changeID `positional-arg-name:"<id>"`
    36  	} `positional-args:"yes"`
    37  }
    38  
    39  var changeIDMixinOptDesc = mixinDescs{
    40  	// TRANSLATORS: This should not start with a lowercase letter.
    41  	"last": i18n.G("Select last change of given type (install, refresh, remove, try, auto-refresh, etc.). A question mark at the end of the type means to do nothing (instead of returning an error) if no change of the given type is found. Note the question mark could need protecting from the shell."),
    42  }
    43  
    44  var changeIDMixinArgDesc = []argDesc{{
    45  	// TRANSLATORS: This needs to begin with < and end with >
    46  	name: i18n.G("<change-id>"),
    47  	// TRANSLATORS: This should not start with a lowercase letter.
    48  	desc: i18n.G("Change ID"),
    49  }}
    50  
    51  // should not be user-visible, but keep it clear and polite because mistakes happen
    52  var noChangeFoundOK = errors.New("no change found but that's ok")
    53  
    54  func (l *changeIDMixin) GetChangeID() (string, error) {
    55  	if l.Positional.ID == "" && l.LastChangeType == "" {
    56  		return "", fmt.Errorf(i18n.G("please provide change ID or type with --last=<type>"))
    57  	}
    58  
    59  	if l.Positional.ID != "" {
    60  		if l.LastChangeType != "" {
    61  			return "", fmt.Errorf(i18n.G("cannot use change ID and type together"))
    62  		}
    63  
    64  		return string(l.Positional.ID), nil
    65  	}
    66  
    67  	cli := l.client
    68  	// note that at this point we know l.LastChangeType != ""
    69  	kind := l.LastChangeType
    70  	optional := false
    71  	if l := len(kind) - 1; kind[l] == '?' {
    72  		optional = true
    73  		kind = kind[:l]
    74  	}
    75  	// our internal change types use "-snap" postfix but let user skip it and use short form.
    76  	shortForms := []string{
    77  		// see api_snaps.go:snapInstructionDispTable
    78  		"install", "refresh", "remove", "revert", "enable", "disable", "switch",
    79  		// see api_interfaces.go:changeInterfaces
    80  		"connect", "disconnect",
    81  		// see api_snap_conf.go:setSnapConf
    82  		"configure",
    83  		// see api_sideload_n_try.go:trySnap
    84  		"try",
    85  	}
    86  	if strutil.ListContains(shortForms, kind) {
    87  		kind += "-snap"
    88  	}
    89  	changes, err := queryChanges(cli, &client.ChangesOptions{Selector: client.ChangesAll})
    90  	if err != nil {
    91  		return "", err
    92  	}
    93  	if len(changes) == 0 {
    94  		if optional {
    95  			return "", noChangeFoundOK
    96  		}
    97  		return "", fmt.Errorf(i18n.G("no changes found"))
    98  	}
    99  	chg := findLatestChangeByKind(changes, kind)
   100  	if chg == nil {
   101  		if optional {
   102  			return "", noChangeFoundOK
   103  		}
   104  		return "", fmt.Errorf(i18n.G("no changes of type %q found"), l.LastChangeType)
   105  	}
   106  
   107  	return chg.ID, nil
   108  }
   109  
   110  func findLatestChangeByKind(changes []*client.Change, kind string) (latest *client.Change) {
   111  	for _, chg := range changes {
   112  		if chg.Kind == kind && (latest == nil || latest.SpawnTime.Before(chg.SpawnTime)) {
   113  			latest = chg
   114  		}
   115  	}
   116  	return latest
   117  }