func (c *Client) MetaWithChannel(id *charm.URL, result interface{}, channel params.Channel) (*charm.URL, error) {
	if result == nil {
		return nil, fmt.Errorf("expected valid result pointer, not nil")
	}
	resultv := reflect.ValueOf(result)
	resultt := resultv.Type()
	if resultt.Kind() != reflect.Ptr {
		return nil, fmt.Errorf("expected pointer, not %T", result)
	}
	resultt = resultt.Elem()
	if resultt.Kind() != reflect.Struct {
		return nil, fmt.Errorf("expected pointer to struct, not %T", result)
	}
	resultv = resultv.Elem()

	// At this point, resultv refers to the struct value pointed
	// to by result, and resultt is its type.

	numField := resultt.NumField()
	includes := make([]string, 0, numField)

	// If a channel override is specified add it to the query parameters.
	if channel != params.NoChannel {
		includes = append(includes, "channel="+string(channel))
	}

	// results holds an entry for each field in the result value,
	// pointing to the value for that field.
	results := make(map[string]reflect.Value)
	for i := 0; i < numField; i++ {
		field := resultt.Field(i)
		if field.PkgPath != "" {
			// Field is private; ignore it.
			continue
		}
		if field.Anonymous {
			// At some point in the future, it might be nice to
			// support anonymous fields, but for now the
			// additional complexity doesn't seem worth it.
			return nil, fmt.Errorf("anonymous fields not supported")
		}
		apiName := field.Tag.Get("csclient")
		if apiName == "" {
			apiName = hyphenate(field.Name)
		}
		includes = append(includes, "include="+apiName)
		results[apiName] = resultv.FieldByName(field.Name).Addr()
	}
	// We unmarshal into rawResult, then unmarshal each field
	// separately into its place in the final result value.
	// Note that we can't use params.MetaAnyResponse because
	// that will unpack all the values inside the Meta field,
	// but we want to keep them raw so that we can unmarshal
	// them ourselves.
	var rawResult struct {
		Id   *charm.URL
		Meta map[string]json.RawMessage
	}
	path := "/" + id.Path() + "/meta/any"
	if len(includes) > 0 {
		path += "?" + strings.Join(includes, "&")
	}
	if err := c.Get(path, &rawResult); err != nil {
		return nil, errgo.NoteMask(err, fmt.Sprintf("cannot get %q", path), isAPIError)
	}
	// Note that the server is not required to send back values
	// for all fields. "If there is no metadata for the given meta path, the
	// element will be omitted"
	// See https://github.com/juju/charmstore/blob/v4/docs/API.md#get-idmetaany
	for name, r := range rawResult.Meta {
		v, ok := results[name]
		if !ok {
			// The server has produced a result that we
			// don't know about. Ignore it.
			continue
		}
		// Unmarshal the raw JSON into the final struct field.
		err := json.Unmarshal(r, v.Interface())
		if err != nil {
			return nil, errgo.Notef(err, "cannot unmarshal %s", name)
		}
	}
	return rawResult.Id, nil
}
// MetaWithChannel behaves the same as a call to Meta but allows the caller to
// specify a channel which will be passed to the metadata endpoint only for
// this particular lookup.
MetaWithChannel behaves the same as a call to Meta but allows the caller to
specify a channel which will be passed to the metadata endpoint only for
this particular lookup.
// MetaWithChannel behaves the same as a call to Meta but allows the caller to // specify a channel which will be passed to the metadata endpoint only for // this particular lookup .
func (c *Client) MetaWithChannel(id *charm.URL, result interface{}, channel params.Channel) (*charm.URL, error) {
	if result == nil {
		return nil, fmt.Errorf("expected valid result pointer, not nil")
	}
	resultv := reflect.ValueOf(result)
	resultt := resultv.Type()
	if resultt.Kind() != reflect.Ptr {
		return nil, fmt.Errorf("expected pointer, not %T", result)
	}
	resultt = resultt.Elem()
	if resultt.Kind() != reflect.Struct {
		return nil, fmt.Errorf("expected pointer to struct, not %T", result)
	}
	resultv = resultv.Elem()
	numField := resultt.NumField()
	includes := make([]string, 0, numField)
	if channel != params.NoChannel {
		includes = append(includes, "channel="+string(channel))
	}
	results := make(map[string]reflect.Value)
	for i := 0; i < numField; i++ {
		field := resultt.Field(i)
		if field.PkgPath != "" {
			continue
		}
		if field.Anonymous {
			return nil, fmt.Errorf("anonymous fields not supported")
		}
		apiName := field.Tag.Get("csclient")
		if apiName == "" {
			apiName = hyphenate(field.Name)
		}
		includes = append(includes, "include="+apiName)
		results[apiName] = resultv.FieldByName(field.Name).Addr()
	}
	var rawResult struct {
		Id   *charm.URL
		Meta map[string]json.RawMessage
	}
	path := "/" + id.Path() + "/meta/any"
	if len(includes) > 0 {
		path += "?" + strings.Join(includes, "&")
	}
	if err := c.Get(path, &rawResult); err != nil {
		return nil, errgo.NoteMask(err, fmt.Sprintf("cannot get %q", path), isAPIError)
	}
	for name, r := range rawResult.Meta {
		v, ok := results[name]
		if !ok {
			continue
		}
		err := json.Unmarshal(r, v.Interface())
		if err != nil {
			return nil, errgo.Notef(err, "cannot unmarshal %s", name)
		}
	}
	return rawResult.Id, nil
}
func ( c * Client ) MetaWithChannel ( id * charm . URL , result interface { } , channel params . Channel ) ( * charm . URL , error ) { if result == nil { return nil , fmt . Errorf ( " " ) } resultv := reflect . ValueOf ( result ) resultt := resultv . Type ( ) if resultt . Kind ( ) != reflect . Ptr { return nil , fmt . Errorf ( " " , result ) } resultt = resultt . Elem ( ) if resultt . Kind ( ) != reflect . Struct { return nil , fmt . Errorf ( " " , result ) } resultv = resultv . Elem ( ) numField := resultt . NumField ( ) includes := make ( [ ] string , 0 , numField ) if channel != params . NoChannel { includes = append ( includes , " " + string ( channel ) ) } results := make ( map [ string ] reflect . Value ) for i := 0 ; i < numField ; i ++ { field := resultt . Field ( i ) if field . PkgPath != " " { continue } if field . Anonymous { return nil , fmt . Errorf ( " " ) } apiName := field . Tag . Get ( " " ) if apiName == " " { apiName = hyphenate ( field . Name ) } includes = append ( includes , " " + apiName ) results [ apiName ] = resultv . FieldByName ( field . Name ) . Addr ( ) } var rawResult struct { Id * charm . URL Meta map [ string ] json . RawMessage } path := " " + id . Path ( ) + " " if len ( includes ) > 0 { path += " " + strings . Join ( includes , " " ) } if err := c . Get ( path , & rawResult ) ; err != nil { return nil , errgo . NoteMask ( err , fmt . Sprintf ( " " , path ) , isAPIError ) } for name , r := range rawResult . Meta { v , ok := results [ name ] if ! ok { continue } err := json . Unmarshal ( r , v . Interface ( ) ) if err != nil { return nil , errgo . Notef ( err , " " , name ) } } return rawResult . Id , nil }
MetaWithChannel behaves the same as a call to Meta but allows the caller to
specify a channel which will be passed to the metadata endpoint only for
this particular lookup.
MetaWithChannel behaves the same as a call to Meta but allows the caller to specify a channel which will be passed to the metadata endpoint only for this particular lookup .
// At this point, resultv refers to the struct value pointed // to by result, and resultt is its type. // If a channel override is specified add it to the query parameters. // results holds an entry for each field in the result value, // pointing to the value for that field. // Field is private; ignore it. // At some point in the future, it might be nice to // support anonymous fields, but for now the // additional complexity doesn't seem worth it. // We unmarshal into rawResult, then unmarshal each field // separately into its place in the final result value. // Note that we can't use params.MetaAnyResponse because // that will unpack all the values inside the Meta field, // but we want to keep them raw so that we can unmarshal // them ourselves. // Note that the server is not required to send back values // for all fields. "If there is no metadata for the given meta path, the // element will be omitted" // See https://github.com/juju/charmstore/blob/v4/docs/API.md#get-idmetaany // The server has produced a result that we // don't know about. Ignore it. // Unmarshal the raw JSON into the final struct field.