1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
|
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 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 main
import (
"errors"
"fmt"
"github.com/jessevdk/go-flags"
"github.com/snapcore/snapd/client"
"github.com/snapcore/snapd/client/clientutil"
"github.com/snapcore/snapd/i18n"
)
var (
shortModelHelp = i18n.G("Get the active model for this device")
longModelHelp = i18n.G(`
The model command returns the active model assertion information for this
device.
By default, only the essential model identification information is
included in the output, but this can be expanded to include all of an
assertion's non-meta headers.
The verbose output is presented in a structured, yaml-like format.
Similarly, the active serial assertion can be used for the output instead of the
model assertion.
`)
errNoMainAssertion = errors.New(i18n.G("device not ready yet (no assertions found)"))
errNoSerial = errors.New(i18n.G("device not registered yet (no serial assertion found)"))
errNoVerboseAssertion = errors.New(i18n.G("cannot use --verbose with --assertion"))
)
// cmdModelFormatter implements the interface required by clientutil.Print*
// functions, as it formats the output it requires some extra information from
// environment its called from.
type cmdModelFormatter struct {
client *client.Client
esc *escapes
}
func (mf cmdModelFormatter) GetEscapedDash() string {
return mf.esc.dash
}
func (mf cmdModelFormatter) LongPublisher(storeAccountID string) string {
storeAccount, err := mf.client.StoreAccount(storeAccountID)
if err != nil {
return ""
}
// use the longPublisher helper to format the brand store account
// like we do in `snap info`
return longPublisher(mf.esc, storeAccount)
}
type cmdModel struct {
clientMixin
timeMixin
colorMixin
Serial bool `long:"serial"`
Verbose bool `long:"verbose"`
Assertion bool `long:"assertion"`
}
func init() {
addCommand("model",
shortModelHelp,
longModelHelp,
func() flags.Commander {
return &cmdModel{}
}, colorDescs.also(timeDescs).also(map[string]string{
"assertion": i18n.G("Print the raw assertion."),
"verbose": i18n.G("Print all specific assertion fields."),
"serial": i18n.G(
"Print the serial assertion instead of the model assertion."),
}),
[]argDesc{},
)
}
func (x *cmdModel) Execute(args []string) error {
if x.Verbose && x.Assertion {
// can't do a verbose mode for the assertion
return errNoVerboseAssertion
}
serialAssertion, serialErr := x.client.CurrentSerialAssertion()
modelAssertion, modelErr := x.client.CurrentModelAssertion()
// if we didn't get a model assertion bail early
if modelErr != nil {
if client.IsAssertionNotFoundError(modelErr) {
// device is not registered yet - use specific error message
return errNoMainAssertion
}
return modelErr
}
// if the serial assertion error is anything other than not found, also
// bail early
// the serial assertion not being found may not be fatal
if serialErr != nil && !client.IsAssertionNotFoundError(serialErr) {
return serialErr
}
if x.Assertion {
// if we are using the serial assertion and we specifically didn't find the
// serial assertion, bail with specific error
if x.Serial && client.IsAssertionNotFoundError(serialErr) {
return errNoMainAssertion
}
}
termWidth, _ := termSize()
termWidth -= 3
if termWidth > 100 {
// any wider than this and it gets hard to read
termWidth = 100
}
w := tabWriter()
if x.Serial && client.IsAssertionNotFoundError(serialErr) {
// for serial assertion, the primary keys are output (model and
// brand-id), but if we didn't find the serial assertion then we still
// output the brand-id and model from the model assertion, but also
// return a devNotReady error
fmt.Fprintf(w, "brand-id:\t%s\n", modelAssertion.HeaderString("brand-id"))
fmt.Fprintf(w, "model:\t%s\n", modelAssertion.HeaderString("model"))
w.Flush()
return errNoSerial
}
modelFormatter := cmdModelFormatter{
esc: x.getEscapes(),
client: x.client,
}
opts := clientutil.PrintModelAssertionOptions{
TermWidth: termWidth,
AbsTime: x.AbsTime,
Verbose: x.Verbose,
Assertion: x.Assertion,
}
if x.Serial {
if err := clientutil.PrintSerialAssertionYAML(w, *serialAssertion, modelFormatter, opts); err != nil {
return err
}
} else {
if err := clientutil.PrintModelAssertion(w, *modelAssertion, serialAssertion, modelFormatter, opts); err != nil {
return err
}
}
return w.Flush()
}
|