You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: keys.go
    path of file: ./repos/docker-ce/components/cli/vendor/github.com/theupdateframework/notary/trustmanager
    
    the code of the file until where you have to start completion: package trustmanager

import (
	"encoding/pem"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"path/filepath"
	"sort"
	"strings"

	"github.com/sirupsen/logrus"
	"github.com/theupdateframework/notary"
	tufdata "github.com/theupdateframework/notary/tuf/data"
	"github.com/theupdateframework/notary/tuf/utils"
)

// Exporter is a simple interface for the two functions we need from the Storage interface
type Exporter interface {
	Get(string) ([]byte, error)
	ListFiles() []string
}

// Importer is a simple interface for the one function we need from the Storage interface
type Importer interface {
	Set(string, []byte) error
}

// ExportKeysByGUN exports all keys filtered to a GUN
func ExportKeysByGUN(to io.Writer, s Exporter, gun string) error {
	keys := s.ListFiles()
	sort.Strings(keys) // ensure consistency. ListFiles has no order guarantee
	for _, loc := range keys {
		keyFile, err := s.Get(loc)
		if err != nil {
			logrus.Warn("Could not parse key file at ", loc)
			continue
		}
		block, _ := pem.Decode(keyFile)
		keyGun := block.Headers["gun"]
		if keyGun == gun { // must be full GUN match
			if err := ExportKeys(to, s, loc); err != nil {
				return err
			}
		}
	}
	return nil
}

// ExportKeysByID exports all keys matching the given ID
func ExportKeysByID(to io.Writer, s Exporter, ids []string) error {
	want := mak
    
func checkValidity(block *pem.Block) (string, error) {
	// A root key or a delegations key should not have a gun
	// Note that a key that is not any of the canonical roles (except root) is a delegations key and should not have a gun
	switch block.Headers["role"] {
	case tufdata.CanonicalSnapshotRole.String(), tufdata.CanonicalTargetsRole.String(), tufdata.CanonicalTimestampRole.String():
		// check if the key is missing a gun header or has an empty gun and error out since we don't know what gun it belongs to
		if block.Headers["gun"] == "" {
			logrus.Warnf("failed to import key (%s) to store: Cannot have canonical role key without a gun, don't know what gun it belongs to", block.Headers["path"])
			return "", errors.New("invalid key pem block")
		}
	default:
		delete(block.Headers, "gun")
	}

	loc, ok := block.Headers["path"]
	// only if the path isn't specified do we get into this parsing path logic
	if !ok || loc == "" {
		// if the path isn't specified, we will try to infer the path rel to trust dir from the role (and then gun)
		// parse key for the keyID which we will save it by.
		// if the key is encrypted at this point, we will generate an error and continue since we don't know the ID to save it by

		decodedKey, err := utils.ParsePEMPrivateKey(pem.EncodeToMemory(block), "")
		if err != nil {
			logrus.Warn("failed to import key to store: Invalid key generated, key may be encrypted and does not contain path header")
			return "", errors.New("invalid key pem block")
		}
		loc = decodedKey.ID()
	}
	return loc, nil
}