func ReadActionsYaml(r io.Reader) (*Actions, error) {
	data, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}

	result := &Actions{
		ActionSpecs: map[string]ActionSpec{},
	}

	var unmarshaledActions map[string]map[string]interface{}
	if err := yaml.Unmarshal(data, &unmarshaledActions); err != nil {
		return nil, err
	}

	for name, actionSpec := range unmarshaledActions {
		if valid := actionNameRule.MatchString(name); !valid {
			return nil, fmt.Errorf("bad action name %s", name)
		}
		if reserved, reason := reservedName(name); reserved {
			return nil, fmt.Errorf(
				"cannot use action name %s: %s",
				name, reason,
			)
		}

		desc := "No description"
		thisActionSchema := map[string]interface{}{
			"description": desc,
			"type":        "object",
			"title":       name,
			"properties":  map[string]interface{}{},
		}

		for key, value := range actionSpec {
			switch key {
			case "description":
				// These fields must be strings.
				typed, ok := value.(string)
				if !ok {
					return nil, errors.Errorf("value for schema key %q must be a string", key)
				}
				thisActionSchema[key] = typed
				desc = typed
			case "title":
				// These fields must be strings.
				typed, ok := value.(string)
				if !ok {
					return nil, errors.Errorf("value for schema key %q must be a string", key)
				}
				thisActionSchema[key] = typed
			case "required":
				typed, ok := value.([]interface{})
				if !ok {
					return nil, errors.Errorf("value for schema key %q must be a YAML list", key)
				}
				thisActionSchema[key] = typed
			case "params":
				// Clean any map[interface{}]interface{}s out so they don't
				// cause problems with BSON serialization later.
				cleansedParams, err := cleanse(value)
				if err != nil {
					return nil, err
				}

				// JSON-Schema must be a map
				typed, ok := cleansedParams.(map[string]interface{})
				if !ok {
					return nil, errors.New("params failed to parse as a map")
				}
				thisActionSchema["properties"] = typed
			default:
				// In case this has nested maps, we must clean them out.
				typed, err := cleanse(value)
				if err != nil {
					return nil, err
				}
				thisActionSchema[key] = typed
			}
		}

		// Make sure the new Params doc conforms to JSON-Schema
		// Draft 4 (http://json-schema.org/latest/json-schema-core.html)
		schemaLoader := gjs.NewGoLoader(thisActionSchema)
		_, err := gjs.NewSchema(schemaLoader)
		if err != nil {
			return nil, errors.Annotatef(err, "invalid params schema for action schema %s", name)
		}

		// Now assign the resulting schema to the final entry for the result.
		result.ActionSpecs[name] = ActionSpec{
			Description: desc,
			Params:      thisActionSchema,
		}
	}
	return result, nil
}
// ReadActionsYaml builds an Actions spec from a charm's actions.yaml.
ReadActionsYaml builds an Actions spec from a charm's actions.yaml.
// ReadActionsYaml builds an Actions spec from a charm ' s actions . yaml .
func ReadActionsYaml(r io.Reader) (*Actions, error) {
	data, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}
	result := &Actions{
		ActionSpecs: map[string]ActionSpec{},
	}
	var unmarshaledActions map[string]map[string]interface{}
	if err := yaml.Unmarshal(data, &unmarshaledActions); err != nil {
		return nil, err
	}
	for name, actionSpec := range unmarshaledActions {
		if valid := actionNameRule.MatchString(name); !valid {
			return nil, fmt.Errorf("bad action name %s", name)
		}
		if reserved, reason := reservedName(name); reserved {
			return nil, fmt.Errorf(
				"cannot use action name %s: %s",
				name, reason,
			)
		}
		desc := "No description"
		thisActionSchema := map[string]interface{}{
			"description": desc,
			"type":        "object",
			"title":       name,
			"properties":  map[string]interface{}{},
		}
		for key, value := range actionSpec {
			switch key {
			case "description":
				typed, ok := value.(string)
				if !ok {
					return nil, errors.Errorf("value for schema key %q must be a string", key)
				}
				thisActionSchema[key] = typed
				desc = typed
			case "title":
				typed, ok := value.(string)
				if !ok {
					return nil, errors.Errorf("value for schema key %q must be a string", key)
				}
				thisActionSchema[key] = typed
			case "required":
				typed, ok := value.([]interface{})
				if !ok {
					return nil, errors.Errorf("value for schema key %q must be a YAML list", key)
				}
				thisActionSchema[key] = typed
			case "params":
				cleansedParams, err := cleanse(value)
				if err != nil {
					return nil, err
				}
				typed, ok := cleansedParams.(map[string]interface{})
				if !ok {
					return nil, errors.New("params failed to parse as a map")
				}
				thisActionSchema["properties"] = typed
			default:
				typed, err := cleanse(value)
				if err != nil {
					return nil, err
				}
				thisActionSchema[key] = typed
			}
		}
		schemaLoader := gjs.NewGoLoader(thisActionSchema)
		_, err := gjs.NewSchema(schemaLoader)
		if err != nil {
			return nil, errors.Annotatef(err, "invalid params schema for action schema %s", name)
		}
		result.ActionSpecs[name] = ActionSpec{
			Description: desc,
			Params:      thisActionSchema,
		}
	}
	return result, nil
}
func ReadActionsYaml ( r io . Reader ) ( * Actions , error ) { data , err := ioutil . ReadAll ( r ) if err != nil { return nil , err } result := & Actions { ActionSpecs : map [ string ] ActionSpec { } , } var unmarshaledActions map [ string ] map [ string ] interface { } if err := yaml . Unmarshal ( data , & unmarshaledActions ) ; err != nil { return nil , err } for name , actionSpec := range unmarshaledActions { if valid := actionNameRule . MatchString ( name ) ; ! valid { return nil , fmt . Errorf ( " " , name ) } if reserved , reason := reservedName ( name ) ; reserved { return nil , fmt . Errorf ( " " , name , reason , ) } desc := " " thisActionSchema := map [ string ] interface { } { " " : desc , " " : " " , " " : name , " " : map [ string ] interface { } { } , } for key , value := range actionSpec { switch key { case " " : typed , ok := value . ( string ) if ! ok { return nil , errors . Errorf ( " " , key ) } thisActionSchema [ key ] = typed desc = typed case " " : typed , ok := value . ( string ) if ! ok { return nil , errors . Errorf ( " " , key ) } thisActionSchema [ key ] = typed case " " : typed , ok := value . ( [ ] interface { } ) if ! ok { return nil , errors . Errorf ( " " , key ) } thisActionSchema [ key ] = typed case " " : cleansedParams , err := cleanse ( value ) if err != nil { return nil , err } typed , ok := cleansedParams . ( map [ string ] interface { } ) if ! ok { return nil , errors . New ( " " ) } thisActionSchema [ " " ] = typed default : typed , err := cleanse ( value ) if err != nil { return nil , err } thisActionSchema [ key ] = typed } } schemaLoader := gjs . NewGoLoader ( thisActionSchema ) _ , err := gjs . NewSchema ( schemaLoader ) if err != nil { return nil , errors . Annotatef ( err , " " , name ) } result . ActionSpecs [ name ] = ActionSpec { Description : desc , Params : thisActionSchema , } } return result , nil }
ReadActionsYaml builds an Actions spec from a charm's actions.yaml.
ReadActionsYaml builds an Actions spec from a charm ' s actions . yaml .
// These fields must be strings. // These fields must be strings. // Clean any map[interface{}]interface{}s out so they don't // cause problems with BSON serialization later. // JSON-Schema must be a map // In case this has nested maps, we must clean them out. // Make sure the new Params doc conforms to JSON-Schema // Draft 4 (http://json-schema.org/latest/json-schema-core.html) // Now assign the resulting schema to the final entry for the result.