github.com/rigado/snapd@v2.42.5-go-mod+incompatible/cmd/snap/cmd_known.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 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 main 21 22 import ( 23 "fmt" 24 "strings" 25 26 "github.com/snapcore/snapd/asserts" 27 "github.com/snapcore/snapd/i18n" 28 "github.com/snapcore/snapd/overlord/auth" 29 "github.com/snapcore/snapd/store" 30 31 "github.com/jessevdk/go-flags" 32 ) 33 34 type cmdKnown struct { 35 clientMixin 36 KnownOptions struct { 37 // XXX: how to get a list of assert types for completion? 38 AssertTypeName assertTypeName `required:"true"` 39 HeaderFilters []string `required:"0"` 40 } `positional-args:"true" required:"true"` 41 42 Remote bool `long:"remote"` 43 } 44 45 var shortKnownHelp = i18n.G("Show known assertions of the provided type") 46 var longKnownHelp = i18n.G(` 47 The known command shows known assertions of the provided type. 48 If header=value pairs are provided after the assertion type, the assertions 49 shown must also have the specified headers matching the provided values. 50 `) 51 52 func init() { 53 addCommand("known", shortKnownHelp, longKnownHelp, func() flags.Commander { 54 return &cmdKnown{} 55 }, nil, []argDesc{ 56 { 57 // TRANSLATORS: This needs to begin with < and end with > 58 name: i18n.G("<assertion type>"), 59 // TRANSLATORS: This should not start with a lowercase letter. 60 desc: i18n.G("Assertion type name"), 61 }, { 62 // TRANSLATORS: This needs to begin with < and end with > 63 name: i18n.G("<header filter>"), 64 // TRANSLATORS: This should not start with a lowercase letter. 65 desc: i18n.G("Constrain listing to those matching header=value"), 66 }, 67 }) 68 } 69 70 var storeNew = store.New 71 72 func downloadAssertion(typeName string, headers map[string]string) ([]asserts.Assertion, error) { 73 var user *auth.UserState 74 75 // FIXME: set auth context 76 var storeCtx store.DeviceAndAuthContext 77 78 at := asserts.Type(typeName) 79 if at == nil { 80 return nil, fmt.Errorf("cannot find assertion type %q", typeName) 81 } 82 primaryKeys, err := asserts.PrimaryKeyFromHeaders(at, headers) 83 if err != nil { 84 return nil, fmt.Errorf("cannot query remote assertion: %v", err) 85 } 86 87 sto := storeNew(nil, storeCtx) 88 as, err := sto.Assertion(at, primaryKeys, user) 89 if err != nil { 90 return nil, err 91 } 92 93 return []asserts.Assertion{as}, nil 94 } 95 96 func (x *cmdKnown) Execute(args []string) error { 97 if len(args) > 0 { 98 return ErrExtraArgs 99 } 100 101 // TODO: share this kind of parsing once it's clearer how often is used in snap 102 headers := map[string]string{} 103 for _, headerFilter := range x.KnownOptions.HeaderFilters { 104 parts := strings.SplitN(headerFilter, "=", 2) 105 if len(parts) != 2 { 106 return fmt.Errorf(i18n.G("invalid header filter: %q (want key=value)"), headerFilter) 107 } 108 headers[parts[0]] = parts[1] 109 } 110 111 var assertions []asserts.Assertion 112 var err error 113 if x.Remote { 114 assertions, err = downloadAssertion(string(x.KnownOptions.AssertTypeName), headers) 115 } else { 116 assertions, err = x.client.Known(string(x.KnownOptions.AssertTypeName), headers) 117 } 118 if err != nil { 119 return err 120 } 121 122 enc := asserts.NewEncoder(Stdout) 123 for _, a := range assertions { 124 enc.Encode(a) 125 } 126 127 return nil 128 }