<commit_before>package aws

import (
	"bytes"
	"fmt"

	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/mutexkv"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
)

// Provider returns a terraform.ResourceProvider.
func Provider() terraform.ResourceProvider {
	// TODO: Move the validation to this, requires conditional schemas
	// TODO: Move the configuration to this, requires validation

	// The actual provider
	return &schema.Provider{
		Schema: map[string]*schema.Schema{
			"access_key": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Default:     "",
				Description: descriptions["access_key"],
			},

			"secret_key": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Default:     "",
				Description: descriptions["secret_key"],
			},

			"profile": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Default:     "",
				Description: descriptions["profile"],
			},

			"shared_credentials_file": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Default:     "",
				Description: descriptions["shared_credentials_file"],
			},

			"token": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Default:     "",
				Description: descriptions["token"],
			},

			"region": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				DefaultFunc: schema.MultiEnvDefaultFunc([]string{
					"AWS_REGION",
					"AWS_DEFAULT_REGION",
				}, nil),
				Description:  descriptions["region"],
				InputDefault: "us-east-1",
			},

			"max_retries": &schema.Schema{
				Type:        schema.TypeInt,
				Optional:    true,
				Default:     11,
				Description: descriptions["max_retries"],
			},

			"allowed_account_ids": &schema.Schema{
				Type:          schema.TypeSet,
				Elem:          &schema.Schema{Type: schema.TypeString},
				Optional:      true,
				ConflictsWith: []string{"forbidden_account_ids"},
				Set:           schema.HashString,
			},

			"forbidden_account_ids": &schema.Schema{
				Type:          schema.TypeSet,
				Elem:          &schema.Schema{Type: schema.TypeString},
				Optional:      true,
				ConflictsWith: []string{"allowed_account_ids"},
				Set:           schema.HashString,
			},

			"dynamodb_endpoint": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Default:     "",
				Description: descriptions["dynamodb_endpoint"],
			},

			"kinesis_endpoint": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Default:     "",
				Description: descriptions["kinesis_endpoint"],
			},
			"endpoints": endpointsSchema(),

			"insecure": &schema.Schema{
				Type:        schema.TypeBool,
				Optional:    true,
				Default:     false,
				Description: descriptions["insecure"],
			},
		},

		ResourcesMap: map[string]*schema.Resource{
			"aws_ami":                              resourceAwsAmi(),
			"aws_ami_copy":                         resourceAwsAmiCopy(),
			"aws_ami_from_instance":                resourceAwsAmiFromInstance(),
			"aws_app_cookie_stickiness_policy":     resourceAwsAppCookieStickinessPolicy(),
			"aws_autoscaling_group":                resourceAwsAutoscalingGroup(),
			"aws_autoscaling_notification":         resourceAwsAutoscalingNotification(),
			"aws_autoscaling_policy":               resourceAwsAutoscalingPolicy(),
			"aws_autoscaling_schedule":             resourceAwsAutoscalingSchedule(),
			"aws_cloudformation_stack":             resourceAwsCloudFormationStack(),
			"aws_cloudtrail":                       resourceAwsCloudTrail(),
			"aws_cloudwatch_log_group":             resourceAwsCloudWatchLogGroup(),
			"aws_autoscaling_lifecycle_hook":       resourceAwsAutoscalingLifecycleHook(),
			"aws_cloudwatch_metric_alarm":          resourceAwsCloudWatchMetricAlarm(),
			"aws_codedeploy_app":                   resourceAwsCodeDeployApp(),
			"aws_codedeploy_deployment_group":      resourceAwsCodeDeployDeploymentGroup(),
			"aws_codecommit_repository":            resourceAwsCodeCommitRepository(),
			"aws_customer_gateway":                 resourceAwsCustomerGateway(),
			"aws_db_instance":                      resourceAwsDbInstance(),
			"aws_db_parameter_group":               resourceAwsDbParameterGroup(),
			"aws_db_security_group":                resourceAwsDbSecurityGroup(),
			"aws_db_subnet_group":                  resourceAwsDbSubnetGroup(),
			"aws_directory_service_directory":      resourceAwsDirectoryServiceDirectory(),
			"aws_dynamodb_table":                   resourceAwsDynamoDbTable(),
			"aws_ebs_volume":                       resourceAwsEbsVolume(),
			"aws_ecr_repository":                   resourceAwsEcrRepository(),
			"aws_ecr_repository_policy":            resourceAwsEcrRepositoryPolicy(),
			"aws_ecs_cluster":                      resourceAwsEcsCluster(),
			"aws_ecs_service":                      resourceAwsEcsService(),
			"aws_ecs_task_definition":              resourceAwsEcsTaskDefinition(),
			"aws_efs_file_system":                  resourceAwsEfsFileSystem(),
			"aws_efs_mount_target":                 resourceAwsEfsMountTarget(),
			"aws_eip":                              resourceAwsEip(),
			"aws_elasticache_cluster":              resourceAwsElasticacheCluster(),
			"aws_elasticache_parameter_group":      resourceAwsElasticacheParameterGroup(),
			"aws_elasticache_security_group":       resourceAwsElasticacheSecurityGroup(),
			"aws_elasticache_subnet_group":         resourceAwsElasticacheSubnetGroup(),
			"aws_elasticsearch_domain":             resourceAwsElasticSearchDomain(),
			"aws_elb":                              resourceAwsElb(),
			"aws_flow_log":                         resourceAwsFlowLog(),
			"aws_glacier_vault":                    resourceAwsGlacierVault(),
			"aws_iam_access_key":                   resourceAwsIamAccessKey(),
			"aws_iam_group_policy":                 resourceAwsIamGroupPolicy(),
			"aws_iam_group":                        resourceAwsIamGroup(),
			"aws_iam_group_membership":             resourceAwsIamGroupMembership(),
			"aws_iam_instance_profile":             resourceAwsIamInstanceProfile(),
			"aws_iam_policy":                       resourceAwsIamPolicy(),
			"aws_iam_policy_attachment":            resourceAwsIamPolicyAttachment(),
			"aws_iam_role_policy":                  resourceAwsIamRolePolicy(),
			"aws_iam_role":                         resourceAwsIamRole(),
			"aws_iam_saml_provider":                resourceAwsIamSamlProvider(),
			"aws_iam_server_certificate":           resourceAwsIAMServerCertificate(),
			"aws_iam_user_policy":                  resourceAwsIamUserPolicy(),
			"aws_iam_user":                         resourceAwsIamUser(),
			"aws_instance":                         resourceAwsInstance(),
			"aws_internet_gateway":                 resourceAwsInternetGateway(),
			"aws_key_pair":                         resourceAwsKeyPair(),
			"aws_kinesis_firehose_delivery_stream": resourceAwsKinesisFirehoseDeliveryStream(),
			"aws_kinesis_stream":                   resourceAwsKinesisStream(),
			"aws_lambda_function":                  resourceAwsLambdaFunction(),
			"aws_lambda_event_source_mapping":      resourceAwsLambdaEventSourceMapping(),
			"aws_lambda_alias":                     resourceAwsLambdaAlias(),
			"aws_launch_configuration":             resourceAwsLaunchConfiguration(),
			"aws_lb_cookie_stickiness_policy":      resourceAwsLBCookieStickinessPolicy(),
			"aws_main_route_table_association":     resourceAwsMainRouteTableAssociation(),
			"aws_nat_gateway":                      resourceAwsNatGateway(),
			"aws_network_acl":                      resourceAwsNetworkAcl(),
			"aws_network_acl_rule":                 resourceAwsNetworkAclRule(),
			"aws_network_interface":                resourceAwsNetworkInterface(),
			"aws_opsworks_stack":                   resourceAwsOpsworksStack(),
			"aws_opsworks_java_app_layer":          resourceAwsOpsworksJavaAppLayer(),
			"aws_opsworks_haproxy_layer":           resourceAwsOpsworksHaproxyLayer(),
			"aws_opsworks_static_web_layer":        resourceAwsOpsworksStaticWebLayer(),
			"aws_opsworks_php_app_layer":           resourceAwsOpsworksPhpAppLayer(),
			"aws_opsworks_rails_app_layer":         resourceAwsOpsworksRailsAppLayer(),
			"aws_opsworks_nodejs_app_layer":        resourceAwsOpsworksNodejsAppLayer(),
			"aws_opsworks_memcached_layer":         resourceAwsOpsworksMemcachedLayer(),
			"aws_opsworks_mysql_layer":             resourceAwsOpsworksMysqlLayer(),
			"aws_opsworks_ganglia_layer":           resourceAwsOpsworksGangliaLayer(),
			"aws_opsworks_custom_layer":            resourceAwsOpsworksCustomLayer(),
			"aws_placement_group":                  resourceAwsPlacementGroup(),
			"aws_proxy_protocol_policy":            resourceAwsProxyProtocolPolicy(),
			"aws_rds_cluster":                      resourceAwsRDSCluster(),
			"aws_rds_cluster_instance":             resourceAwsRDSClusterInstance(),
			"aws_redshift_cluster":                 resourceAwsRedshiftCluster(),
			"aws_redshift_security_group":          resourceAwsRedshiftSecurityGroup(),
			"aws_redshift_parameter_group":         resourceAwsRedshiftParameterGroup(),
			"aws_redshift_subnet_group":            resourceAwsRedshiftSubnetGroup(),
			"aws_route53_delegation_set":           resourceAwsRoute53DelegationSet(),
			"aws_route53_record":                   resourceAwsRoute53Record(),
			"aws_route53_zone_association":         resourceAwsRoute53ZoneAssociation(),
			"aws_route53_zone":                     resourceAwsRoute53Zone(),
			"aws_route53_health_check":             resourceAwsRoute53HealthCheck(),
			"aws_route":                            resourceAwsRoute(),
			"aws_route_table":                      resourceAwsRouteTable(),
			"aws_route_table_association":          resourceAwsRouteTableAssociation(),
			"aws_s3_bucket":                        resourceAwsS3Bucket(),
			"aws_s3_bucket_object":                 resourceAwsS3BucketObject(),
			"aws_security_group":                   resourceAwsSecurityGroup(),
			"aws_security_group_rule":              resourceAwsSecurityGroupRule(),
			"aws_spot_instance_request":            resourceAwsSpotInstanceRequest(),
			"aws_sqs_queue":                        resourceAwsSqsQueue(),
			"aws_sns_topic":                        resourceAwsSnsTopic(),
			"aws_sns_topic_subscription":           resourceAwsSnsTopicSubscription(),
			"aws_subnet":                           resourceAwsSubnet(),
			"aws_volume_attachment":                resourceAwsVolumeAttachment(),
			"aws_vpc_dhcp_options_association":     resourceAwsVpcDhcpOptionsAssociation(),
			"aws_vpc_dhcp_options":                 resourceAwsVpcDhcpOptions(),
			"aws_vpc_peering_connection":           resourceAwsVpcPeeringConnection(),
			"aws_vpc":                              resourceAwsVpc(),
			"aws_vpc_endpoint":                     resourceAwsVpcEndpoint(),
			"aws_vpn_connection":                   resourceAwsVpnConnection(),
			"aws_vpn_connection_route":             resourceAwsVpnConnectionRoute(),
			"aws_vpn_gateway":                      resourceAwsVpnGateway(),
		},

		ConfigureFunc: providerConfigure,
	}
}

var descriptions map[string]string

func init() {
	descriptions = map[string]string{
		"region": "The region where AWS operations will take place. Examples\n" +
			"are us-east-1, us-west-2, etc.",

		"access_key": "The access key for API operations. You can retrieve this\n" +
			"from the 'Security & Credentials' section of the AWS console.",

		"secret_key": "The secret key for API operations. You can retrieve this\n" +
			"from the 'Security & Credentials' section of the AWS console.",

		"profile": "The profile for API operations. If not set, the default profile\n" +
			"created with `aws configure` will be used.",

		"shared_credentials_file": "The path to the shared credentials file. If not set\n" +
			"this defaults to ~/.aws/credentials.",

		"token": "session token. A session token is only required if you are\n" +
			"using temporary security credentials.",

		"max_retries": "The maximum number of times an AWS API request is\n" +
			"being executed. If the API request still fails, an error is\n" +
			"thrown.",

		"dynamodb_endpoint": "Use this to override the default endpoint URL constructed from the `region`.\n" +
			"It's typically used to connect to dynamodb-local.",

		"kinesis_endpoint": "Use this to override the default endpoint URL constructed from the `region`.\n" +
			"It's typically used to connect to kinesalite.",

		"iam_endpoint": "Use this to override the default endpoint URL constructed from the `region`.\n",

		"ec2_endpoint": "Use this to override the default endpoint URL constructed from the `region`.\n",

		"elb_endpoint": "Use this to override the default endpoint URL constructed from the `region`.\n",

		"insecure": "Explicitly allow the provider to perform \"insecure\" SSL requests. If omitted," +
			"default value is `false`",
		"default value is `false`",
	}
}

func providerConfigure(d *schema.ResourceData) (interface{}, error) {
	config := Config{
		AccessKey:        d.Get("access_key").(string),
		SecretKey:        d.Get("secret_key").(string),
		Profile:          d.Get("profile").(string),
		CredsFilename:    d.Get("shared_credentials_file").(string),
		Token:            d.Get("token").(string),
		Region:           d.Get("region").(string),
		MaxRetries:       d.Get("max_retries").(int),
		DynamoDBEndpoint: d.Get("dynamodb_endpoint").(string),
		KinesisEndpoint:  d.Get("kinesis_endpoint").(string),
		Insecure:         d.Get("insecure").(bool),
	}

	endpointsSet := d.Get("endpoints").(*schema.Set)

	for _, endpointsSetI := range endpointsSet.List() {
		endpoints := endpointsSetI.(map[string]interface{})
		config.IamEndpoint = endpoints["iam"].(string)
		config.Ec2Endpoint = endpoints["ec2"].(string)
		config.ElbEndpoint = endpoints["elb"].(string)
	}

	if v, ok := d.GetOk("allowed_account_ids"); ok {
		config.AllowedAccountIds = v.(*schema.Set).List()
	}

	if v, ok := d.GetOk("forbidden_account_ids"); ok {
		config.ForbiddenAccountIds = v.(*schema.Set).List()
	}

	return config.Client()
}

// This is a global MutexKV for use within this plugin.
var awsMutexKV = mutexkv.NewMutexKV()

func endpointsSchema() *schema.Schema {
	return &schema.Schema{
		Type:     schema.TypeSet,
		Optional: true,
		Elem: &schema.Resource{
			Schema: map[string]*schema.Schema{
				"iam": &schema.Schema{
					Type:        schema.TypeString,
					Optional:    true,
					Default:     "",
					Description: descriptions["iam_endpoint"],
				},

				"ec2": &schema.Schema{
					Type:        schema.TypeString,
					Optional:    true,
					Default:     "",
					Description: descriptions["ec2_endpoint"],
				},

				"elb": &schema.Schema{
					Type:        schema.TypeString,
					Optional:    true,
					Default:     "",
					Description: descriptions["elb_endpoint"],
				},
			},
		},
		Set: endpointsToHash,
	}
}

func endpointsToHash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%s-", m["iam"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", m["ec2"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", m["elb"].(string)))

	return hashcode.String(buf.String())
}
<commit_msg>update documentation<commit_after>package aws

import (
	"bytes"
	"fmt"

	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/mutexkv"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
)

// Provider returns a terraform.ResourceProvider.
func Provider() terraform.ResourceProvider {
	// TODO: Move the validation to this, requires conditional schemas
	// TODO: Move the configuration to this, requires validation

	// The actual provider
	return &schema.Provider{
		Schema: map[string]*schema.Schema{
			"access_key": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Default:     "",
				Description: descriptions["access_key"],
			},

			"secret_key": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Default:     "",
				Description: descriptions["secret_key"],
			},

			"profile": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Default:     "",
				Description: descriptions["profile"],
			},

			"shared_credentials_file": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Default:     "",
				Description: descriptions["shared_credentials_file"],
			},

			"token": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Default:     "",
				Description: descriptions["token"],
			},

			"region": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				DefaultFunc: schema.MultiEnvDefaultFunc([]string{
					"AWS_REGION",
					"AWS_DEFAULT_REGION",
				}, nil),
				Description:  descriptions["region"],
				InputDefault: "us-east-1",
			},

			"max_retries": &schema.Schema{
				Type:        schema.TypeInt,
				Optional:    true,
				Default:     11,
				Description: descriptions["max_retries"],
			},

			"allowed_account_ids": &schema.Schema{
				Type:          schema.TypeSet,
				Elem:          &schema.Schema{Type: schema.TypeString},
				Optional:      true,
				ConflictsWith: []string{"forbidden_account_ids"},
				Set:           schema.HashString,
			},

			"forbidden_account_ids": &schema.Schema{
				Type:          schema.TypeSet,
				Elem:          &schema.Schema{Type: schema.TypeString},
				Optional:      true,
				ConflictsWith: []string{"allowed_account_ids"},
				Set:           schema.HashString,
			},

			"dynamodb_endpoint": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Default:     "",
				Description: descriptions["dynamodb_endpoint"],
			},

			"kinesis_endpoint": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Default:     "",
				Description: descriptions["kinesis_endpoint"],
			},
			"endpoints": endpointsSchema(),

			"insecure": &schema.Schema{
				Type:        schema.TypeBool,
				Optional:    true,
				Default:     false,
				Description: descriptions["insecure"],
			},
		},

		ResourcesMap: map[string]*schema.Resource{
			"aws_ami":                              resourceAwsAmi(),
			"aws_ami_copy":                         resourceAwsAmiCopy(),
			"aws_ami_from_instance":                resourceAwsAmiFromInstance(),
			"aws_app_cookie_stickiness_policy":     resourceAwsAppCookieStickinessPolicy(),
			"aws_autoscaling_group":                resourceAwsAutoscalingGroup(),
			"aws_autoscaling_notification":         resourceAwsAutoscalingNotification(),
			"aws_autoscaling_policy":               resourceAwsAutoscalingPolicy(),
			"aws_autoscaling_schedule":             resourceAwsAutoscalingSchedule(),
			"aws_cloudformation_stack":             resourceAwsCloudFormationStack(),
			"aws_cloudtrail":                       resourceAwsCloudTrail(),
			"aws_cloudwatch_log_group":             resourceAwsCloudWatchLogGroup(),
			"aws_autoscaling_lifecycle_hook":       resourceAwsAutoscalingLifecycleHook(),
			"aws_cloudwatch_metric_alarm":          resourceAwsCloudWatchMetricAlarm(),
			"aws_codedeploy_app":                   resourceAwsCodeDeployApp(),
			"aws_codedeploy_deployment_group":      resourceAwsCodeDeployDeploymentGroup(),
			"aws_codecommit_repository":            resourceAwsCodeCommitRepository(),
			"aws_customer_gateway":                 resourceAwsCustomerGateway(),
			"aws_db_instance":                      resourceAwsDbInstance(),
			"aws_db_parameter_group":               resourceAwsDbParameterGroup(),
			"aws_db_security_group":                resourceAwsDbSecurityGroup(),
			"aws_db_subnet_group":                  resourceAwsDbSubnetGroup(),
			"aws_directory_service_directory":      resourceAwsDirectoryServiceDirectory(),
			"aws_dynamodb_table":                   resourceAwsDynamoDbTable(),
			"aws_ebs_volume":                       resourceAwsEbsVolume(),
			"aws_ecr_repository":                   resourceAwsEcrRepository(),
			"aws_ecr_repository_policy":            resourceAwsEcrRepositoryPolicy(),
			"aws_ecs_cluster":                      resourceAwsEcsCluster(),
			"aws_ecs_service":                      resourceAwsEcsService(),
			"aws_ecs_task_definition":              resourceAwsEcsTaskDefinition(),
			"aws_efs_file_system":                  resourceAwsEfsFileSystem(),
			"aws_efs_mount_target":                 resourceAwsEfsMountTarget(),
			"aws_eip":                              resourceAwsEip(),
			"aws_elasticache_cluster":              resourceAwsElasticacheCluster(),
			"aws_elasticache_parameter_group":      resourceAwsElasticacheParameterGroup(),
			"aws_elasticache_security_group":       resourceAwsElasticacheSecurityGroup(),
			"aws_elasticache_subnet_group":         resourceAwsElasticacheSubnetGroup(),
			"aws_elasticsearch_domain":             resourceAwsElasticSearchDomain(),
			"aws_elb":                              resourceAwsElb(),
			"aws_flow_log":                         resourceAwsFlowLog(),
			"aws_glacier_vault":                    resourceAwsGlacierVault(),
			"aws_iam_access_key":                   resourceAwsIamAccessKey(),
			"aws_iam_group_policy":                 resourceAwsIamGroupPolicy(),
			"aws_iam_group":                        resourceAwsIamGroup(),
			"aws_iam_group_membership":             resourceAwsIamGroupMembership(),
			"aws_iam_instance_profile":             resourceAwsIamInstanceProfile(),
			"aws_iam_policy":                       resourceAwsIamPolicy(),
			"aws_iam_policy_attachment":            resourceAwsIamPolicyAttachment(),
			"aws_iam_role_policy":                  resourceAwsIamRolePolicy(),
			"aws_iam_role":                         resourceAwsIamRole(),
			"aws_iam_saml_provider":                resourceAwsIamSamlProvider(),
			"aws_iam_server_certificate":           resourceAwsIAMServerCertificate(),
			"aws_iam_user_policy":                  resourceAwsIamUserPolicy(),
			"aws_iam_user":                         resourceAwsIamUser(),
			"aws_instance":                         resourceAwsInstance(),
			"aws_internet_gateway":                 resourceAwsInternetGateway(),
			"aws_key_pair":                         resourceAwsKeyPair(),
			"aws_kinesis_firehose_delivery_stream": resourceAwsKinesisFirehoseDeliveryStream(),
			"aws_kinesis_stream":                   resourceAwsKinesisStream(),
			"aws_lambda_function":                  resourceAwsLambdaFunction(),
			"aws_lambda_event_source_mapping":      resourceAwsLambdaEventSourceMapping(),
			"aws_lambda_alias":                     resourceAwsLambdaAlias(),
			"aws_launch_configuration":             resourceAwsLaunchConfiguration(),
			"aws_lb_cookie_stickiness_policy":      resourceAwsLBCookieStickinessPolicy(),
			"aws_main_route_table_association":     resourceAwsMainRouteTableAssociation(),
			"aws_nat_gateway":                      resourceAwsNatGateway(),
			"aws_network_acl":                      resourceAwsNetworkAcl(),
			"aws_network_acl_rule":                 resourceAwsNetworkAclRule(),
			"aws_network_interface":                resourceAwsNetworkInterface(),
			"aws_opsworks_stack":                   resourceAwsOpsworksStack(),
			"aws_opsworks_java_app_layer":          resourceAwsOpsworksJavaAppLayer(),
			"aws_opsworks_haproxy_layer":           resourceAwsOpsworksHaproxyLayer(),
			"aws_opsworks_static_web_layer":        resourceAwsOpsworksStaticWebLayer(),
			"aws_opsworks_php_app_layer":           resourceAwsOpsworksPhpAppLayer(),
			"aws_opsworks_rails_app_layer":         resourceAwsOpsworksRailsAppLayer(),
			"aws_opsworks_nodejs_app_layer":        resourceAwsOpsworksNodejsAppLayer(),
			"aws_opsworks_memcached_layer":         resourceAwsOpsworksMemcachedLayer(),
			"aws_opsworks_mysql_layer":             resourceAwsOpsworksMysqlLayer(),
			"aws_opsworks_ganglia_layer":           resourceAwsOpsworksGangliaLayer(),
			"aws_opsworks_custom_layer":            resourceAwsOpsworksCustomLayer(),
			"aws_placement_group":                  resourceAwsPlacementGroup(),
			"aws_proxy_protocol_policy":            resourceAwsProxyProtocolPolicy(),
			"aws_rds_cluster":                      resourceAwsRDSCluster(),
			"aws_rds_cluster_instance":             resourceAwsRDSClusterInstance(),
			"aws_redshift_cluster":                 resourceAwsRedshiftCluster(),
			"aws_redshift_security_group":          resourceAwsRedshiftSecurityGroup(),
			"aws_redshift_parameter_group":         resourceAwsRedshiftParameterGroup(),
			"aws_redshift_subnet_group":            resourceAwsRedshiftSubnetGroup(),
			"aws_route53_delegation_set":           resourceAwsRoute53DelegationSet(),
			"aws_route53_record":                   resourceAwsRoute53Record(),
			"aws_route53_zone_association":         resourceAwsRoute53ZoneAssociation(),
			"aws_route53_zone":                     resourceAwsRoute53Zone(),
			"aws_route53_health_check":             resourceAwsRoute53HealthCheck(),
			"aws_route":                            resourceAwsRoute(),
			"aws_route_table":                      resourceAwsRouteTable(),
			"aws_route_table_association":          resourceAwsRouteTableAssociation(),
			"aws_s3_bucket":                        resourceAwsS3Bucket(),
			"aws_s3_bucket_object":                 resourceAwsS3BucketObject(),
			"aws_security_group":                   resourceAwsSecurityGroup(),
			"aws_security_group_rule":              resourceAwsSecurityGroupRule(),
			"aws_spot_instance_request":            resourceAwsSpotInstanceRequest(),
			"aws_sqs_queue":                        resourceAwsSqsQueue(),
			"aws_sns_topic":                        resourceAwsSnsTopic(),
			"aws_sns_topic_subscription":           resourceAwsSnsTopicSubscription(),
			"aws_subnet":                           resourceAwsSubnet(),
			"aws_volume_attachment":                resourceAwsVolumeAttachment(),
			"aws_vpc_dhcp_options_association":     resourceAwsVpcDhcpOptionsAssociation(),
			"aws_vpc_dhcp_options":                 resourceAwsVpcDhcpOptions(),
			"aws_vpc_peering_connection":           resourceAwsVpcPeeringConnection(),
			"aws_vpc":                              resourceAwsVpc(),
			"aws_vpc_endpoint":                     resourceAwsVpcEndpoint(),
			"aws_vpn_connection":                   resourceAwsVpnConnection(),
			"aws_vpn_connection_route":             resourceAwsVpnConnectionRoute(),
			"aws_vpn_gateway":                      resourceAwsVpnGateway(),
		},

		ConfigureFunc: providerConfigure,
	}
}

var descriptions map[string]string

func init() {
	descriptions = map[string]string{
		"region": "The region where AWS operations will take place. Examples\n" +
			"are us-east-1, us-west-2, etc.",

		"access_key": "The access key for API operations. You can retrieve this\n" +
			"from the 'Security & Credentials' section of the AWS console.",

		"secret_key": "The secret key for API operations. You can retrieve this\n" +
			"from the 'Security & Credentials' section of the AWS console.",

		"profile": "The profile for API operations. If not set, the default profile\n" +
			"created with `aws configure` will be used.",

		"shared_credentials_file": "The path to the shared credentials file. If not set\n" +
			"this defaults to ~/.aws/credentials.",

		"token": "session token. A session token is only required if you are\n" +
			"using temporary security credentials.",

		"max_retries": "The maximum number of times an AWS API request is\n" +
			"being executed. If the API request still fails, an error is\n" +
			"thrown.",

		"dynamodb_endpoint": "Use this to override the default endpoint URL constructed from the `region`.\n" +
			"It's typically used to connect to dynamodb-local.",

		"kinesis_endpoint": "Use this to override the default endpoint URL constructed from the `region`.\n" +
			"It's typically used to connect to kinesalite.",

		"iam_endpoint": "Use this to override the default endpoint URL constructed from the `region`.\n",

		"ec2_endpoint": "Use this to override the default endpoint URL constructed from the `region`.\n",

		"elb_endpoint": "Use this to override the default endpoint URL constructed from the `region`.\n",

		"insecure": "Explicitly allow the provider to perform \"insecure\" SSL requests. If omitted," +
			"default value is `false`",
	}
}

func providerConfigure(d *schema.ResourceData) (interface{}, error) {
	config := Config{
		AccessKey:        d.Get("access_key").(string),
		SecretKey:        d.Get("secret_key").(string),
		Profile:          d.Get("profile").(string),
		CredsFilename:    d.Get("shared_credentials_file").(string),
		Token:            d.Get("token").(string),
		Region:           d.Get("region").(string),
		MaxRetries:       d.Get("max_retries").(int),
		DynamoDBEndpoint: d.Get("dynamodb_endpoint").(string),
		KinesisEndpoint:  d.Get("kinesis_endpoint").(string),
		Insecure:         d.Get("insecure").(bool),
	}

	endpointsSet := d.Get("endpoints").(*schema.Set)

	for _, endpointsSetI := range endpointsSet.List() {
		endpoints := endpointsSetI.(map[string]interface{})
		config.IamEndpoint = endpoints["iam"].(string)
		config.Ec2Endpoint = endpoints["ec2"].(string)
		config.ElbEndpoint = endpoints["elb"].(string)
	}

	if v, ok := d.GetOk("allowed_account_ids"); ok {
		config.AllowedAccountIds = v.(*schema.Set).List()
	}

	if v, ok := d.GetOk("forbidden_account_ids"); ok {
		config.ForbiddenAccountIds = v.(*schema.Set).List()
	}

	return config.Client()
}

// This is a global MutexKV for use within this plugin.
var awsMutexKV = mutexkv.NewMutexKV()

func endpointsSchema() *schema.Schema {
	return &schema.Schema{
		Type:     schema.TypeSet,
		Optional: true,
		Elem: &schema.Resource{
			Schema: map[string]*schema.Schema{
				"iam": &schema.Schema{
					Type:        schema.TypeString,
					Optional:    true,
					Default:     "",
					Description: descriptions["iam_endpoint"],
				},

				"ec2": &schema.Schema{
					Type:        schema.TypeString,
					Optional:    true,
					Default:     "",
					Description: descriptions["ec2_endpoint"],
				},

				"elb": &schema.Schema{
					Type:        schema.TypeString,
					Optional:    true,
					Default:     "",
					Description: descriptions["elb_endpoint"],
				},
			},
		},
		Set: endpointsToHash,
	}
}

func endpointsToHash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%s-", m["iam"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", m["ec2"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", m["elb"].(string)))

	return hashcode.String(buf.String())
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"go/build"
	"math/rand"
	"os"
	"path"
	"path/filepath"
)

var cmdNew = &Command{
	UsageLine: "new [path]",
	Short:     "create a skeleton Revel application",
	Long: `
New creates a few files to get a new Revel application running quickly.

It puts all of the files in the given import path, taking the final element in
the path to be the app name.

For example:

    revel new import/path/helloworld
`,
}

func init() {
	cmdNew.Run = newApp
}

var (
	appDir       string
	skeletonBase string
)

func newApp(args []string) {
	if len(args) == 0 {
		errorf("No path given.\nRun 'revel help new' for usage.\n")
	}

	importPath := args[0]
	_, err := build.Import(importPath, "", build.FindOnly)
	if err == nil {
		fmt.Fprintf(os.Stderr, "Abort: Import path %s already exists.\n", importPath)
		return
	}

	revelPkg, err := build.Import("github.com/robfig/revel", "", build.FindOnly)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Failed to find revel code.")
		return
	}

	appDir := path.Join(revelPkg.SrcRoot, filepath.FromSlash(importPath))
	err = os.MkdirAll(appDir, 0777)
	panicOnError(err, "Failed to create directory "+appDir)

	skeletonBase = path.Join(revelPkg.Dir, "skeleton")
	mustCopyDir(appDir, skeletonBase, map[string]interface{}{
		// app.conf
		"AppName": filepath.Base(appDir),
		"Secret":  genSecret(),
	})

	fmt.Fprintln(os.Stdout, "Your application is ready:\n  ", appDir)
	fmt.Fprintln(os.Stdout, "\nYou can run it with:\n   revel run", importPath)
}

const alphaNumeric = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"

func genSecret() string {
	chars := make([]byte, 64)
	for i := 0; i < 64; i++ {
		chars[i] = alphaNumeric[rand.Intn(len(alphaNumeric))]
	}
	return string(chars)
}
<commit_msg>Fix: Actually copy the skeleton .gitignore<commit_after>package main

import (
	"fmt"
	"go/build"
	"math/rand"
	"os"
	"path"
	"path/filepath"
)

var cmdNew = &Command{
	UsageLine: "new [path]",
	Short:     "create a skeleton Revel application",
	Long: `
New creates a few files to get a new Revel application running quickly.

It puts all of the files in the given import path, taking the final element in
the path to be the app name.

For example:

    revel new import/path/helloworld
`,
}

func init() {
	cmdNew.Run = newApp
}

var (
	appDir       string
	skeletonBase string
)

func newApp(args []string) {
	if len(args) == 0 {
		errorf("No path given.\nRun 'revel help new' for usage.\n")
	}

	importPath := args[0]
	_, err := build.Import(importPath, "", build.FindOnly)
	if err == nil {
		fmt.Fprintf(os.Stderr, "Abort: Import path %s already exists.\n", importPath)
		return
	}

	revelPkg, err := build.Import("github.com/robfig/revel", "", build.FindOnly)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Failed to find revel code.")
		return
	}

	appDir := path.Join(revelPkg.SrcRoot, filepath.FromSlash(importPath))
	err = os.MkdirAll(appDir, 0777)
	panicOnError(err, "Failed to create directory "+appDir)

	skeletonBase = path.Join(revelPkg.Dir, "skeleton")
	mustCopyDir(appDir, skeletonBase, map[string]interface{}{
		// app.conf
		"AppName": filepath.Base(appDir),
		"Secret":  genSecret(),
	})

	// Dotfiles are skipped by mustCopyDir, so we have to explicitly copy the .gitignore.
	gitignore := ".gitignore"
	mustCopyFile(path.Join(appDir, gitignore), path.Join(skeletonBase, gitignore))

	fmt.Fprintln(os.Stdout, "Your application is ready:\n  ", appDir)
	fmt.Fprintln(os.Stdout, "\nYou can run it with:\n   revel run", importPath)
}

const alphaNumeric = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"

func genSecret() string {
	chars := make([]byte, 64)
	for i := 0; i < 64; i++ {
		chars[i] = alphaNumeric[rand.Intn(len(alphaNumeric))]
	}
	return string(chars)
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"os"

	"github.com/beanworks/rex/rabbit"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var Version bool
var CfgFile string
var Config rabbit.Config

var RexCmd = &cobra.Command{
	Use:   "rex",
	Short: "Rex rabbit likes consuming queued messages",
	Long: `Rex rabbit is a command line message queue consumer for RabbitMQ.
Rex pulls messages from a queue, takes a good care of the jobs,
redirects message bodies to other responsible parties.

When Rex is not busy, he also likes to hang out with Octocat.`,
	Run: func(cmd *cobra.Command, args []string) {
		if Version {
			cmd.Println(GetVersionString())
		} else {
			cmd.Help()
		}
	},
}

func Execute() {
	if err := RexCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	RexCmd.PersistentFlags().StringVarP(&CfgFile, "config", "c", "", "config file (default is $HOME/.rex.yml)")
	RexCmd.Flags().BoolVarP(&Version, "version", "v", false, "Show rex version")

	RexCmd.Flags().SetAnnotation("config", cobra.BashCompFilenameExt, []string{"yaml", "yml"})
}

func initConfig() {
	if CfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(CfgFile)
	}

	viper.SetConfigName("config")
	viper.AddConfigPath("/etc/rex/")
	viper.AddConfigPath("$HOME/.rex")
	viper.AddConfigPath(".")
	viper.AutomaticEnv()

	if err := viper.ReadInConfig(); err != nil {
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	} else {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}

	if err := viper.Unmarshal(&Config); err != nil {
		panic(fmt.Errorf("Unable to decode config into struct, %s \n", err))
	}
}
<commit_msg>Change some panic's to Fatalf's<commit_after>package cmd

import (
	"fmt"
	"log"
	"os"

	"github.com/beanworks/rex/rabbit"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var Version bool
var CfgFile string
var Config rabbit.Config

var RexCmd = &cobra.Command{
	Use:   "rex",
	Short: "Rex rabbit likes consuming queued messages",
	Long: `Rex rabbit is a command line message queue consumer for RabbitMQ.
Rex pulls messages from a queue, takes a good care of the jobs,
redirects message bodies to other responsible parties.

When Rex is not busy, he also likes to hang out with Octocat.`,
	Run: func(cmd *cobra.Command, args []string) {
		if Version {
			cmd.Println(GetVersionString())
		} else {
			cmd.Help()
		}
	},
}

func Execute() {
	if err := RexCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	RexCmd.PersistentFlags().StringVarP(&CfgFile, "config", "c", "", "config file (default is $HOME/.rex.yml)")
	RexCmd.Flags().BoolVarP(&Version, "version", "v", false, "Show rex version")

	RexCmd.Flags().SetAnnotation("config", cobra.BashCompFilenameExt, []string{"yaml", "yml"})
}

func initConfig() {
	if CfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(CfgFile)
	}

	viper.SetConfigName("config")
	viper.AddConfigPath("/etc/rex/")
	viper.AddConfigPath("$HOME/.rex")
	viper.AddConfigPath(".")
	viper.AutomaticEnv()

	if err := viper.ReadInConfig(); err != nil {
		log.Fatalf("Fatal error: config file: %s \n", err)
	}

	if err := viper.Unmarshal(&Config); err != nil {
		log.Fatalf("Unable to decode config into struct, %s \n", err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 Unknwon
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package cmd

import (
	"fmt"
	"path"
	"strings"

	"github.com/gpmgo/gopm/modules/base"
	"github.com/gpmgo/gopm/modules/cli"
	"github.com/gpmgo/gopm/modules/doc"
	"github.com/gpmgo/gopm/modules/errors"
	"github.com/gpmgo/gopm/modules/log"
	"github.com/gpmgo/gopm/modules/setting"
)

var CmdRun = cli.Command{
	Name:  "run",
	Usage: "link dependencies and go run",
	Description: `Command run links dependencies according to gopmfile,
and execute 'go run'

gopm run <go run commands>
gopm run -l will recursively find .gopmfile with value localPath
and run the cmd in the .gopmfile, Windows hasn't supported yet,
you need to run the command right at the local_gopath dir.`,
	Action: runRun,
	Flags: []cli.Flag{
		cli.StringFlag{"tags", "", "apply build tags", ""},
		cli.BoolFlag{"local, l", "run command with local gopath context", ""},
		cli.BoolFlag{"verbose, v", "show process details", ""},
	},
}

func valSuffix(val string) string {
	if len(val) > 0 {
		return "." + val
	}
	return ""
}

// validPkgInfo checks if the information of the package is valid.
func validPkgInfo(info string) (doc.RevisionType, string, error) {
	if len(info) == 0 {
		return doc.BRANCH, "", nil
	}

	infos := strings.Split(info, ":")
	tp := doc.RevisionType(infos[0])
	val := infos[1]

	if len(infos) == 2 {
		switch tp {
		case doc.BRANCH, doc.COMMIT, doc.TAG:
		default:
			return "", "", fmt.Errorf("invalid node type: %v", tp)
		}
		return tp, val, nil
	}
	return "", "", fmt.Errorf("cannot parse dependency version: %v", info)
}

func linkVendors(ctx *cli.Context, optTarget string) error {
	gfPath := path.Join(setting.WorkDir, setting.GOPMFILE)
	gf, target, err := parseGopmfile(gfPath)
	if err != nil {
		return fmt.Errorf("fail to parse gopmfile: %v", err)
	}
	if len(optTarget) > 0 {
		target = optTarget
	}
	rootPath := doc.GetRootPath(target)

	// TODO: local support.

	// Make link of self.
	log.Debug("Linking %s...", rootPath)
	from := setting.WorkDir
	to := path.Join(setting.DefaultVendorSrc, rootPath)
	if setting.Debug {
		log.Debug("Linking from %s to %s", from, to)
	}
	if err := autoLink(from, to); err != nil {
		return fmt.Errorf("fail to link self: %v", err)
	}

	// Check and loads dependency packages.
	log.Debug("Loading dependencies...")
	imports, err := doc.ListImports(target, rootPath, setting.DefaultVendor, setting.WorkDir, ctx.String("tags"), ctx.Bool("test"))
	if err != nil {
		return fmt.Errorf("fail to list imports: %v", err)
	}

	stack := make([]*doc.Pkg, len(imports))
	for i, name := range imports {
		name := doc.GetRootPath(name)
		tp, val, err := validPkgInfo(gf.MustValue("deps", name))
		if err != nil {
			return fmt.Errorf("fail to validate package(%s): %v", name, err)
		}

		stack[i] = doc.NewPkg(name, tp, val)
	}

	// FIXME: at least link once, need a set
	lastIdx := len(stack) - 1
	for lastIdx >= 0 {
		pkg := stack[lastIdx]
		linkPath := path.Join(setting.DefaultVendorSrc, pkg.RootPath)
		if setting.Debug {
			log.Debug("Import path: %s", pkg.ImportPath)
			log.Debug("Linking path: %s", linkPath)
		}
		if base.IsExist(linkPath) {
			stack = stack[:lastIdx]
			lastIdx = len(stack) - 1
			continue
		}

		if pkg.IsEmptyVal() && setting.HasGOPATHSetting &&
			base.IsExist(path.Join(setting.InstallGopath, pkg.RootPath)) {
			stack = stack[:lastIdx]
			lastIdx = len(stack) - 1
			continue
		}

		venderPath := path.Join(setting.InstallRepoPath, pkg.RootPath+pkg.ValSuffix())
		if !base.IsExist(venderPath) {
			return fmt.Errorf("package not installed: %s", pkg.RootPath+pkg.VerSuffix())
		}

		log.Debug("Linking %s...", pkg.RootPath+pkg.ValSuffix())
		if err := autoLink(venderPath, linkPath); err != nil {
			return fmt.Errorf("fail to link dependency(%s): %v", pkg.RootPath, err)
		}
		stack = stack[:lastIdx]

		gf, target, err := parseGopmfile(path.Join(linkPath, setting.GOPMFILE))
		if err != nil {
			return fmt.Errorf("fail to parse gopmfile(%s): %v", linkPath, err)
		}
		// parseGopmfile only returns right target when parse work directory.
		target = pkg.RootPath
		rootPath := target
		imports, err := doc.ListImports(target, rootPath, setting.DefaultVendor, linkPath, ctx.String("tags"), ctx.Bool("test"))
		if err != nil {
			errors.SetError(err)
		}
		for _, name := range imports {
			if name == "C" {
				continue
			}

			name := doc.GetRootPath(name)
			tp, val, err := validPkgInfo(gf.MustValue("deps", name))
			if err != nil {
				return fmt.Errorf("fail to validate package(%s): %v", name, err)
			}

			stack = append(stack, doc.NewPkg(name, tp, val))
		}
		lastIdx = len(stack) - 1
	}
	return nil
}

func runRun(ctx *cli.Context) {
	if err := setup(ctx); err != nil {
		errors.SetError(err)
		return
	}

	if err := linkVendors(ctx, ""); err != nil {
		errors.SetError(err)
		return
	}

	log.Info("Running...")

	cmdArgs := []string{"go", "run"}
	if len(ctx.String("tags")) > 0 {
		cmdArgs = append(cmdArgs, "-tags")
		cmdArgs = append(cmdArgs, ctx.String("tags"))
	}
	cmdArgs = append(cmdArgs, ctx.Args()...)
	if err := execCmd(setting.DefaultVendor, setting.WorkDir, cmdArgs...); err != nil {
		errors.SetError(fmt.Errorf("fail to run program: %v", err))
		return
	}

	log.Info("Command executed successfully!")
}
<commit_msg>Check slice size before accessing it.<commit_after>// Copyright 2014 Unknwon
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package cmd

import (
	"fmt"
	"path"
	"strings"

	"github.com/gpmgo/gopm/modules/base"
	"github.com/gpmgo/gopm/modules/cli"
	"github.com/gpmgo/gopm/modules/doc"
	"github.com/gpmgo/gopm/modules/errors"
	"github.com/gpmgo/gopm/modules/log"
	"github.com/gpmgo/gopm/modules/setting"
)

var CmdRun = cli.Command{
	Name:  "run",
	Usage: "link dependencies and go run",
	Description: `Command run links dependencies according to gopmfile,
and execute 'go run'

gopm run <go run commands>
gopm run -l will recursively find .gopmfile with value localPath
and run the cmd in the .gopmfile, Windows hasn't supported yet,
you need to run the command right at the local_gopath dir.`,
	Action: runRun,
	Flags: []cli.Flag{
		cli.StringFlag{"tags", "", "apply build tags", ""},
		cli.BoolFlag{"local, l", "run command with local gopath context", ""},
		cli.BoolFlag{"verbose, v", "show process details", ""},
	},
}

func valSuffix(val string) string {
	if len(val) > 0 {
		return "." + val
	}
	return ""
}

// validPkgInfo checks if the information of the package is valid.
func validPkgInfo(info string) (doc.RevisionType, string, error) {
	if len(info) == 0 {
		return doc.BRANCH, "", nil
	}

	infos := strings.Split(info, ":")

	if len(infos) == 2 {
		tp := doc.RevisionType(infos[0])
		val := infos[1]
		switch tp {
		case doc.BRANCH, doc.COMMIT, doc.TAG:
		default:
			return "", "", fmt.Errorf("invalid node type: %v", tp)
		}
		return tp, val, nil
	}
	return "", "", fmt.Errorf("cannot parse dependency version: %v", info)
}

func linkVendors(ctx *cli.Context, optTarget string) error {
	gfPath := path.Join(setting.WorkDir, setting.GOPMFILE)
	gf, target, err := parseGopmfile(gfPath)
	if err != nil {
		return fmt.Errorf("fail to parse gopmfile: %v", err)
	}
	if len(optTarget) > 0 {
		target = optTarget
	}
	rootPath := doc.GetRootPath(target)

	// TODO: local support.

	// Make link of self.
	log.Debug("Linking %s...", rootPath)
	from := setting.WorkDir
	to := path.Join(setting.DefaultVendorSrc, rootPath)
	if setting.Debug {
		log.Debug("Linking from %s to %s", from, to)
	}
	if err := autoLink(from, to); err != nil {
		return fmt.Errorf("fail to link self: %v", err)
	}

	// Check and loads dependency packages.
	log.Debug("Loading dependencies...")
	imports, err := doc.ListImports(target, rootPath, setting.DefaultVendor, setting.WorkDir, ctx.String("tags"), ctx.Bool("test"))
	if err != nil {
		return fmt.Errorf("fail to list imports: %v", err)
	}

	stack := make([]*doc.Pkg, len(imports))
	for i, name := range imports {
		name := doc.GetRootPath(name)
		tp, val, err := validPkgInfo(gf.MustValue("deps", name))
		if err != nil {
			return fmt.Errorf("fail to validate package(%s): %v", name, err)
		}

		stack[i] = doc.NewPkg(name, tp, val)
	}

	// FIXME: at least link once, need a set
	lastIdx := len(stack) - 1
	for lastIdx >= 0 {
		pkg := stack[lastIdx]
		linkPath := path.Join(setting.DefaultVendorSrc, pkg.RootPath)
		if setting.Debug {
			log.Debug("Import path: %s", pkg.ImportPath)
			log.Debug("Linking path: %s", linkPath)
		}
		if base.IsExist(linkPath) {
			stack = stack[:lastIdx]
			lastIdx = len(stack) - 1
			continue
		}

		if pkg.IsEmptyVal() && setting.HasGOPATHSetting &&
			base.IsExist(path.Join(setting.InstallGopath, pkg.RootPath)) {
			stack = stack[:lastIdx]
			lastIdx = len(stack) - 1
			continue
		}

		venderPath := path.Join(setting.InstallRepoPath, pkg.RootPath+pkg.ValSuffix())
		if !base.IsExist(venderPath) {
			return fmt.Errorf("package not installed: %s", pkg.RootPath+pkg.VerSuffix())
		}

		log.Debug("Linking %s...", pkg.RootPath+pkg.ValSuffix())
		if err := autoLink(venderPath, linkPath); err != nil {
			return fmt.Errorf("fail to link dependency(%s): %v", pkg.RootPath, err)
		}
		stack = stack[:lastIdx]

		gf, target, err := parseGopmfile(path.Join(linkPath, setting.GOPMFILE))
		if err != nil {
			return fmt.Errorf("fail to parse gopmfile(%s): %v", linkPath, err)
		}
		// parseGopmfile only returns right target when parse work directory.
		target = pkg.RootPath
		rootPath := target
		imports, err := doc.ListImports(target, rootPath, setting.DefaultVendor, linkPath, ctx.String("tags"), ctx.Bool("test"))
		if err != nil {
			errors.SetError(err)
		}
		for _, name := range imports {
			if name == "C" {
				continue
			}

			name := doc.GetRootPath(name)
			tp, val, err := validPkgInfo(gf.MustValue("deps", name))
			if err != nil {
				return fmt.Errorf("fail to validate package(%s): %v", name, err)
			}

			stack = append(stack, doc.NewPkg(name, tp, val))
		}
		lastIdx = len(stack) - 1
	}
	return nil
}

func runRun(ctx *cli.Context) {
	if err := setup(ctx); err != nil {
		errors.SetError(err)
		return
	}

	if err := linkVendors(ctx, ""); err != nil {
		errors.SetError(err)
		return
	}

	log.Info("Running...")

	cmdArgs := []string{"go", "run"}
	if len(ctx.String("tags")) > 0 {
		cmdArgs = append(cmdArgs, "-tags")
		cmdArgs = append(cmdArgs, ctx.String("tags"))
	}
	cmdArgs = append(cmdArgs, ctx.Args()...)
	if err := execCmd(setting.DefaultVendor, setting.WorkDir, cmdArgs...); err != nil {
		errors.SetError(fmt.Errorf("fail to run program: %v", err))
		return
	}

	log.Info("Command executed successfully!")
}
<|endoftext|>


<commit_before>package cmd

import (
	"strings"

	"github.com/rancher/go-rancher/v2"

	"github.com/urfave/cli"
)

/*
  -a, --attach=[]                 Attach to STDIN, STDOUT or STDERR
  --add-host=[]                   Add a custom host-to-IP mapping (host:ip)
  --blkio-weight                  Block IO (relative weight), between 10 and 1000
  --blkio-weight-device=[]        Block IO weight (relative device weight)
  --cgroup-parent                 Optional parent cgroup for the container
  --cidfile                       Write the container ID to the file
  --cpu-period                    Limit CPU CFS (Completely Fair Scheduler) period
  --cpu-quota                     Limit CPU CFS (Completely Fair Scheduler) quota
  --cpuset-cpus                   CPUs in which to allow execution (0-3, 0,1)
  --cpuset-mems                   MEMs in which to allow execution (0-3, 0,1)
  -d, --detach                    Run container in background and print container ID
  --detach-keys                   Override the key sequence for detaching a container
  --device-read-bps=[]            Limit read rate (bytes per second) from a device
  --device-read-iops=[]           Limit read rate (IO per second) from a device
  --device-write-bps=[]           Limit write rate (bytes per second) to a device
  --device-write-iops=[]          Limit write rate (IO per second) to a device
  --disable-content-trust=true    Skip image verification
  --dns-opt=[]                    Set DNS options
  -e, --env=[]                    Set environment variables
  --env-file=[]                   Read in a file of environment variables
  --group-add=[]                  Add additional groups to join
  --help                          Print usage
  --ip                            Container IPv4 address (e.g. 172.30.100.104)
  --ip6                           Container IPv6 address (e.g. 2001:db8::33)
  --ipc                           IPC namespace to use
  --isolation                     Container isolation level
  --kernel-memory                 Kernel memory limit
  -l, --label=[]                  Set meta data on a container
  --label-file=[]                 Read in a line delimited file of labels
  --link=[]                       Add link to another container
  --log-driver                    Logging driver for container
  --log-opt=[]                    Log driver options
  --mac-address                   Container MAC address (e.g. 92:d0:c6:0a:29:33)
  --memory-reservation            Memory soft limit
  --memory-swappiness=-1          Tune container memory swappiness (0 to 100)
  --net=default                   Connect a container to a network
  --net-alias=[]                  Add network-scoped alias for the container
  --oom-kill-disable              Disable OOM Killer
  --oom-score-adj                 Tune host's OOM preferences (-1000 to 1000)
  --restart=no                    Restart policy to apply when a container exits
  --rm                            Automatically remove the container when it exits
  --shm-size                      Size of /dev/shm, default value is 64MB
  --sig-proxy=true                Proxy received signals to the process
  --stop-signal=SIGTERM           Signal to stop a container, SIGTERM by default
  --tmpfs=[]                      Mount a tmpfs directory
  --ulimit=[]                     Ulimit options
  --uts                           UTS namespace to use
  -v, --volume=[]                 Bind mount a volume
  --volumes-from=[]               Mount volumes from the specified container(s)
*/

func RunCommand() cli.Command {
	return cli.Command{
		Name:   "run",
		Usage:  "Run services",
		Action: serviceRun,
		Flags: []cli.Flag{
			cli.Int64Flag{
				Name:  "cpu-shares",
				Usage: "CPU shares (relative weight)",
			},
			cli.StringSliceFlag{
				Name:  "cap-add",
				Usage: "Add Linux capabilities",
			},
			cli.StringSliceFlag{
				Name:  "cap-drop",
				Usage: "Drop Linux capabilities",
			},
			cli.StringSliceFlag{
				Name:  "device",
				Usage: "Add a host device to the container",
			},
			cli.StringSliceFlag{
				Name:  "dns",
				Usage: "Set custom DNS servers",
			},
			cli.StringSliceFlag{
				Name:  "dns-search",
				Usage: "Set custom DNS search domains",
			},
			cli.StringSliceFlag{
				Name:  "entrypoint",
				Usage: "Overwrite the default ENTRYPOINT of the image",
			},
			cli.StringSliceFlag{
				Name:  "expose",
				Usage: "Expose a port or a range of ports",
			},
			cli.StringFlag{
				Name:  "hostname",
				Usage: "Container host name",
			},
			cli.BoolFlag{
				Name:  "interactive, i",
				Usage: "Keep STDIN open even if not attached",
			},
			cli.Int64Flag{
				Name:  "memory, m",
				Usage: "Memory limit",
			},
			cli.Int64Flag{
				Name:  "memory-swap",
				Usage: "Swap limit equal to memory plus swap: '-1' to enable unlimited swap",
			},
			cli.StringFlag{
				Name:  "name",
				Usage: "Assign a name to the container",
			},
			cli.BoolFlag{
				Name:  "publish-all",
				Usage: "Publish all exposed ports to random ports",
			},
			cli.StringSliceFlag{
				Name:  "publish, p",
				Usage: "Publish a container's `port`(s) to the host",
			},
			cli.StringFlag{
				Name:  "pid",
				Usage: "PID namespace to use",
			},
			cli.BoolFlag{
				Name:  "privileged",
				Usage: "Give extended privileges to this container",
			},
			cli.BoolFlag{
				Name:  "read-only",
				Usage: "Mount the container's root filesystem as read only",
			},
			cli.StringSliceFlag{
				Name:  "security-opt",
				Usage: "Security Options",
			},
			cli.BoolFlag{
				Name:  "tty, t",
				Usage: "Allocate a pseudo-TTY",
			},
			cli.StringFlag{
				Name:  "user, u",
				Usage: "Username or UID (format: <name|uid>[:<group|gid>])",
			},
			cli.StringFlag{
				Name:  "volume-driver",
				Usage: "Optional volume driver for the container",
			},
			cli.StringFlag{
				Name:  "workdir, w",
				Usage: "Working directory inside the container",
			},
			cli.StringFlag{
				Name:  "log-driver",
				Usage: "Logging driver for container",
			},
			cli.StringSliceFlag{
				Name:  "log-opt",
				Usage: "Log driver options",
			},
			cli.StringSliceFlag{
				Name:  "volume, v",
				Usage: "Bind mount a volume",
			},
			cli.StringFlag{
				Name:  "net",
				Usage: "Connect a container to a network: host, none, bridge, managed",
				Value: "managed",
			},
			cli.IntFlag{
				Name:  "scale",
				Usage: "Number of containers to run",
				Value: 1,
			},
			cli.BoolFlag{
				Name:  "schedule-global",
				Usage: "Run 1 container per host",
			},
			cli.StringSliceFlag{
				Name:  "label,l",
				Usage: "Add label in the form of key=value",
			},
			cli.BoolFlag{
				Name:  "pull",
				Usage: "Always pull image on container start",
			},
		},
	}
}

func ParseName(c *client.RancherClient, name string) (*client.Stack, string, error) {
	stackName := ""
	serviceName := name

	parts := strings.SplitN(name, "/", 2)
	if len(parts) == 2 {
		stackName = parts[0]
		serviceName = parts[1]
	}

	stack, err := GetOrCreateDefaultStack(c, stackName)
	if err != nil {
		return stack, "", err
	}

	if serviceName == "" {
		serviceName = RandomName()
	}

	return stack, serviceName, nil
}

func serviceRun(ctx *cli.Context) error {
	c, err := GetClient(ctx)
	if ctx.NArg() < 1 {
		return cli.NewExitError("Image name is required as the first argument", 1)
	}

	if err != nil {
		return err
	}

	launchConfig := &client.LaunchConfig{
		//BlkioDeviceOptions:
		CapAdd:  ctx.StringSlice("cap-add"),
		CapDrop: ctx.StringSlice("cap-drop"),
		//CpuSet: ctx.String(""),
		CpuShares:  ctx.Int64("cpu-shares"),
		Devices:    ctx.StringSlice("device"),
		Dns:        ctx.StringSlice("dns"),
		DnsSearch:  ctx.StringSlice("dns-search"),
		EntryPoint: ctx.StringSlice("entrypoint"),
		Expose:     ctx.StringSlice("expose"),
		Hostname:   ctx.String("hostname"),
		ImageUuid:  "docker:" + ctx.Args()[0],
		Labels:     map[string]interface{}{},
		//LogConfig:
		Memory:     ctx.Int64("memory"),
		MemorySwap: ctx.Int64("memory-swap"),
		//NetworkIds: ctx.StringSlice("networkids"),
		NetworkMode:     ctx.String("net"),
		PidMode:         ctx.String("pid"),
		Ports:           ctx.StringSlice("publish"),
		Privileged:      ctx.Bool("privileged"),
		PublishAllPorts: ctx.Bool("publish-all"),
		ReadOnly:        ctx.Bool("read-only"),
		SecurityOpt:     ctx.StringSlice("security-opt"),
		StdinOpen:       ctx.Bool("interactive"),
		Tty:             ctx.Bool("tty"),
		User:            ctx.String("user"),
		VolumeDriver:    ctx.String("volume-driver"),
		WorkingDir:      ctx.String("workdir"),
		DataVolumes:     ctx.StringSlice("volume"),
	}

	if ctx.String("log-driver") != "" || len(ctx.StringSlice("log-opt")) > 0 {
		launchConfig.LogConfig = &client.LogConfig{
			Driver: ctx.String("log-driver"),
			Config: map[string]interface{}{},
		}
		for _, opt := range ctx.StringSlice("log-opt") {
			parts := strings.SplitN(opt, "=", 2)
			if len(parts) > 1 {
				launchConfig.LogConfig.Config[parts[0]] = parts[1]
			} else {
				launchConfig.LogConfig.Config[parts[0]] = ""
			}
		}
	}

	for _, label := range ctx.StringSlice("label") {
		parts := strings.SplitN(label, "=", 2)
		value := ""
		if len(parts) > 1 {
			value = parts[1]
		}
		launchConfig.Labels[parts[0]] = value
	}

	if ctx.Bool("schedule-global") {
		launchConfig.Labels["io.rancher.scheduler.global"] = "true"
	}

	if ctx.Bool("pull") {
		launchConfig.Labels["io.rancher.container.pull_image"] = "always"
	}

	args := ctx.Args()[1:]

	if len(args) > 0 {
		launchConfig.Command = args
	}

	stack, name, err := ParseName(c, ctx.String("name"))
	if err != nil {
		return err
	}

	service := &client.Service{
		Name:          name,
		StackId:       stack.Id,
		LaunchConfig:  launchConfig,
		StartOnCreate: true,
		Scale:         int64(ctx.Int("scale")),
	}

	service, err = c.Service.Create(service)
	if err != nil {
		return err
	}

	return WaitFor(ctx, service.Id)
}
<commit_msg>Add cli -e support (#61)<commit_after>package cmd

import (
	"strings"

	"github.com/rancher/go-rancher/v2"

	"github.com/urfave/cli"
	"os"
)

/*
  -a, --attach=[]                 Attach to STDIN, STDOUT or STDERR
  --add-host=[]                   Add a custom host-to-IP mapping (host:ip)
  --blkio-weight                  Block IO (relative weight), between 10 and 1000
  --blkio-weight-device=[]        Block IO weight (relative device weight)
  --cgroup-parent                 Optional parent cgroup for the container
  --cidfile                       Write the container ID to the file
  --cpu-period                    Limit CPU CFS (Completely Fair Scheduler) period
  --cpu-quota                     Limit CPU CFS (Completely Fair Scheduler) quota
  --cpuset-cpus                   CPUs in which to allow execution (0-3, 0,1)
  --cpuset-mems                   MEMs in which to allow execution (0-3, 0,1)
  -d, --detach                    Run container in background and print container ID
  --detach-keys                   Override the key sequence for detaching a container
  --device-read-bps=[]            Limit read rate (bytes per second) from a device
  --device-read-iops=[]           Limit read rate (IO per second) from a device
  --device-write-bps=[]           Limit write rate (bytes per second) to a device
  --device-write-iops=[]          Limit write rate (IO per second) to a device
  --disable-content-trust=true    Skip image verification
  --dns-opt=[]                    Set DNS options
  -e, --env=[]                    Set environment variables
  --env-file=[]                   Read in a file of environment variables
  --group-add=[]                  Add additional groups to join
  --help                          Print usage
  --ip                            Container IPv4 address (e.g. 172.30.100.104)
  --ip6                           Container IPv6 address (e.g. 2001:db8::33)
  --ipc                           IPC namespace to use
  --isolation                     Container isolation level
  --kernel-memory                 Kernel memory limit
  -l, --label=[]                  Set meta data on a container
  --label-file=[]                 Read in a line delimited file of labels
  --link=[]                       Add link to another container
  --log-driver                    Logging driver for container
  --log-opt=[]                    Log driver options
  --mac-address                   Container MAC address (e.g. 92:d0:c6:0a:29:33)
  --memory-reservation            Memory soft limit
  --memory-swappiness=-1          Tune container memory swappiness (0 to 100)
  --net=default                   Connect a container to a network
  --net-alias=[]                  Add network-scoped alias for the container
  --oom-kill-disable              Disable OOM Killer
  --oom-score-adj                 Tune host's OOM preferences (-1000 to 1000)
  --restart=no                    Restart policy to apply when a container exits
  --rm                            Automatically remove the container when it exits
  --shm-size                      Size of /dev/shm, default value is 64MB
  --sig-proxy=true                Proxy received signals to the process
  --stop-signal=SIGTERM           Signal to stop a container, SIGTERM by default
  --tmpfs=[]                      Mount a tmpfs directory
  --ulimit=[]                     Ulimit options
  --uts                           UTS namespace to use
  -v, --volume=[]                 Bind mount a volume
  --volumes-from=[]               Mount volumes from the specified container(s)
*/

func RunCommand() cli.Command {
	return cli.Command{
		Name:   "run",
		Usage:  "Run services",
		Action: serviceRun,
		Flags: []cli.Flag{
			cli.Int64Flag{
				Name:  "cpu-shares",
				Usage: "CPU shares (relative weight)",
			},
			cli.StringSliceFlag{
				Name:  "cap-add",
				Usage: "Add Linux capabilities",
			},
			cli.StringSliceFlag{
				Name:  "cap-drop",
				Usage: "Drop Linux capabilities",
			},
			cli.StringSliceFlag{
				Name:  "device",
				Usage: "Add a host device to the container",
			},
			cli.StringSliceFlag{
				Name:  "dns",
				Usage: "Set custom DNS servers",
			},
			cli.StringSliceFlag{
				Name:  "dns-search",
				Usage: "Set custom DNS search domains",
			},
			cli.StringSliceFlag{
				Name:  "entrypoint",
				Usage: "Overwrite the default ENTRYPOINT of the image",
			},
			cli.StringSliceFlag{
				Name:  "expose",
				Usage: "Expose a port or a range of ports",
			},
			cli.StringFlag{
				Name:  "hostname",
				Usage: "Container host name",
			},
			cli.BoolFlag{
				Name:  "interactive, i",
				Usage: "Keep STDIN open even if not attached",
			},
			cli.Int64Flag{
				Name:  "memory, m",
				Usage: "Memory limit",
			},
			cli.Int64Flag{
				Name:  "memory-swap",
				Usage: "Swap limit equal to memory plus swap: '-1' to enable unlimited swap",
			},
			cli.StringFlag{
				Name:  "name",
				Usage: "Assign a name to the container",
			},
			cli.BoolFlag{
				Name:  "publish-all",
				Usage: "Publish all exposed ports to random ports",
			},
			cli.StringSliceFlag{
				Name:  "publish, p",
				Usage: "Publish a container's `port`(s) to the host",
			},
			cli.StringFlag{
				Name:  "pid",
				Usage: "PID namespace to use",
			},
			cli.BoolFlag{
				Name:  "privileged",
				Usage: "Give extended privileges to this container",
			},
			cli.BoolFlag{
				Name:  "read-only",
				Usage: "Mount the container's root filesystem as read only",
			},
			cli.StringSliceFlag{
				Name:  "security-opt",
				Usage: "Security Options",
			},
			cli.BoolFlag{
				Name:  "tty, t",
				Usage: "Allocate a pseudo-TTY",
			},
			cli.StringFlag{
				Name:  "user, u",
				Usage: "Username or UID (format: <name|uid>[:<group|gid>])",
			},
			cli.StringFlag{
				Name:  "volume-driver",
				Usage: "Optional volume driver for the container",
			},
			cli.StringFlag{
				Name:  "workdir, w",
				Usage: "Working directory inside the container",
			},
			cli.StringFlag{
				Name:  "log-driver",
				Usage: "Logging driver for container",
			},
			cli.StringSliceFlag{
				Name:  "log-opt",
				Usage: "Log driver options",
			},
			cli.StringSliceFlag{
				Name:  "volume, v",
				Usage: "Bind mount a volume",
			},
			cli.StringFlag{
				Name:  "net",
				Usage: "Connect a container to a network: host, none, bridge, managed",
				Value: "managed",
			},
			cli.IntFlag{
				Name:  "scale",
				Usage: "Number of containers to run",
				Value: 1,
			},
			cli.BoolFlag{
				Name:  "schedule-global",
				Usage: "Run 1 container per host",
			},
			cli.StringSliceFlag{
				Name:  "label,l",
				Usage: "Add label in the form of key=value",
			},
			cli.StringSliceFlag{
				Name:  "env,e",
				Usage: "Set one or more environment variable in the form of key=value, key=, and key",
			},
			cli.BoolFlag{
				Name:  "pull",
				Usage: "Always pull image on container start",
			},
		},
	}
}

func ParseName(c *client.RancherClient, name string) (*client.Stack, string, error) {
	stackName := ""
	serviceName := name

	parts := strings.SplitN(name, "/", 2)
	if len(parts) == 2 {
		stackName = parts[0]
		serviceName = parts[1]
	}

	stack, err := GetOrCreateDefaultStack(c, stackName)
	if err != nil {
		return stack, "", err
	}

	if serviceName == "" {
		serviceName = RandomName()
	}

	return stack, serviceName, nil
}

func serviceRun(ctx *cli.Context) error {
	c, err := GetClient(ctx)
	if ctx.NArg() < 1 {
		return cli.NewExitError("Image name is required as the first argument", 1)
	}

	if err != nil {
		return err
	}

	launchConfig := &client.LaunchConfig{
		//BlkioDeviceOptions:
		CapAdd:  ctx.StringSlice("cap-add"),
		CapDrop: ctx.StringSlice("cap-drop"),
		//CpuSet: ctx.String(""),
		CpuShares:   ctx.Int64("cpu-shares"),
		Devices:     ctx.StringSlice("device"),
		Dns:         ctx.StringSlice("dns"),
		DnsSearch:   ctx.StringSlice("dns-search"),
		EntryPoint:  ctx.StringSlice("entrypoint"),
		Expose:      ctx.StringSlice("expose"),
		Hostname:    ctx.String("hostname"),
		ImageUuid:   "docker:" + ctx.Args()[0],
		Labels:      map[string]interface{}{},
		Environment: map[string]interface{}{},
		//LogConfig:
		Memory:     ctx.Int64("memory"),
		MemorySwap: ctx.Int64("memory-swap"),
		//NetworkIds: ctx.StringSlice("networkids"),
		NetworkMode:     ctx.String("net"),
		PidMode:         ctx.String("pid"),
		Ports:           ctx.StringSlice("publish"),
		Privileged:      ctx.Bool("privileged"),
		PublishAllPorts: ctx.Bool("publish-all"),
		ReadOnly:        ctx.Bool("read-only"),
		SecurityOpt:     ctx.StringSlice("security-opt"),
		StdinOpen:       ctx.Bool("interactive"),
		Tty:             ctx.Bool("tty"),
		User:            ctx.String("user"),
		VolumeDriver:    ctx.String("volume-driver"),
		WorkingDir:      ctx.String("workdir"),
		DataVolumes:     ctx.StringSlice("volume"),
	}

	if ctx.String("log-driver") != "" || len(ctx.StringSlice("log-opt")) > 0 {
		launchConfig.LogConfig = &client.LogConfig{
			Driver: ctx.String("log-driver"),
			Config: map[string]interface{}{},
		}
		for _, opt := range ctx.StringSlice("log-opt") {
			parts := strings.SplitN(opt, "=", 2)
			if len(parts) > 1 {
				launchConfig.LogConfig.Config[parts[0]] = parts[1]
			} else {
				launchConfig.LogConfig.Config[parts[0]] = ""
			}
		}
	}

	for _, label := range ctx.StringSlice("label") {
		parts := strings.SplitN(label, "=", 2)
		value := ""
		if len(parts) > 1 {
			value = parts[1]
		}
		launchConfig.Labels[parts[0]] = value
	}

	for _, env := range ctx.StringSlice("env") {
		parts := strings.SplitN(env, "=", 2)
		value := ""
		if len(parts) > 1 {
			value = parts[1]
		} else if len(parts) == 1 {
			value = os.Getenv(parts[0])
		}
		launchConfig.Environment[parts[0]] = value
	}

	if ctx.Bool("schedule-global") {
		launchConfig.Labels["io.rancher.scheduler.global"] = "true"
	}

	if ctx.Bool("pull") {
		launchConfig.Labels["io.rancher.container.pull_image"] = "always"
	}

	args := ctx.Args()[1:]

	if len(args) > 0 {
		launchConfig.Command = args
	}

	stack, name, err := ParseName(c, ctx.String("name"))
	if err != nil {
		return err
	}

	service := &client.Service{
		Name:          name,
		StackId:       stack.Id,
		LaunchConfig:  launchConfig,
		StartOnCreate: true,
		Scale:         int64(ctx.Int("scale")),
	}

	service, err = c.Service.Create(service)
	if err != nil {
		return err
	}

	return WaitFor(ctx, service.Id)
}
<|endoftext|>


<commit_before>package finder

import (
	"bytes"
	"context"
	"fmt"
	"strings"
	"time"

	"github.com/lomik/graphite-clickhouse/helper/clickhouse"
)

type TagState int

const (
	TagRoot     TagState = iota // query = "*"
	TagSkip                     // not _tag prefix
	TagInfoRoot                 // query = "_tag"
	TagList
	TagListSeriesRoot
	TagListSeries
	TagListParam
)

type TagQ struct {
	Param *string
	Value *string
}

func (q TagQ) String() string {
	if q.Param != nil && q.Value != nil {
		return fmt.Sprintf("{\"param\"=%#v, \"value\"=%#v}", *q.Param, *q.Value)
	}
	if q.Param != nil {
		return fmt.Sprintf("{\"param\"=%#v}", *q.Param)
	}
	if q.Value != nil {
		return fmt.Sprintf("{\"value\"=%#v}", *q.Value)
	}
	return "{}"
}

func (q *TagQ) Where(field string) string {
	if q.Param != nil && q.Value != nil && *q.Value != "*" {
		return fmt.Sprintf("%s=%s", field, Q(*q.Param+*q.Value))
	}
	if q.Param != nil {
		return fmt.Sprintf("%s LIKE %s", field, Q(*q.Param+`%`))
	}
	if q.Value != nil && *q.Value != "*" {
		return fmt.Sprintf("%s=%s", field, Q(*q.Value))
	}

	return ""
}

type TagFinder struct {
	wrapped     Finder
	ctx         context.Context // for clickhouse.Query
	url         string          // clickhouse dsn
	table       string          // graphite_tag table
	timeout     time.Duration   // clickhouse query timeout
	state       TagState
	tagQuery    []TagQ
	seriesQuery string
	body        []byte // clickhouse response
}

var EmptyList [][]byte = [][]byte{}

func WrapTag(f Finder, ctx context.Context, url string, table string, timeout time.Duration) *TagFinder {
	return &TagFinder{
		wrapped:  f,
		ctx:      ctx,
		url:      url,
		table:    table,
		timeout:  timeout,
		tagQuery: make([]TagQ, 0),
	}
}

func (t *TagFinder) tagListSQL() (string, error) {
	if len(t.tagQuery) == 0 {
		return "", nil
	}

	w := NewWhere()

	w.Andf("Version>=(SELECT Max(Version) FROM %s WHERE Tag1='' AND Level=0 AND Path='')", t.table)

	// first
	w.And(t.tagQuery[0].Where("Tag1"))

	if len(t.tagQuery) == 1 {
		w.And("Level=1")
		return fmt.Sprintf("SELECT Tag1 FROM %s WHERE %s GROUP BY Tag1", t.table, w), nil
	}

	// 1..(n-1)
	for i := 1; i < len(t.tagQuery)-1; i++ {
		cond := t.tagQuery[i].Where("x")
		if cond != "" {
			w.Andf("arrayExists((x) -> %s, Tags)", cond)
		}
	}

	// last
	w.And(t.tagQuery[len(t.tagQuery)-1].Where("TagN"))

	w.And("IsLeaf=1")

	return fmt.Sprintf("SELECT TagN FROM %s ARRAY JOIN Tags AS TagN WHERE %s GROUP BY TagN", t.table, w), nil
}

func (t *TagFinder) seriesSQL() (string, error) {
	if len(t.tagQuery) == 0 {
		return "", nil
	}

	w := NewWhere()

	w.Andf("Version>=(SELECT Max(Version) FROM %s WHERE Tag1='' AND Level=0 AND Path='')", t.table)
	// first
	w.And(t.tagQuery[0].Where("Tag1"))

	// 1..(n-1)
	for i := 1; i < len(t.tagQuery); i++ {
		cond := t.tagQuery[i].Where("x")
		if cond != "" {
			w.Andf("arrayExists((x) -> %s, Tags)", cond)
		}
	}

	base := &BaseFinder{}
	w.And(base.where(t.seriesQuery))

	return fmt.Sprintf("SELECT Path FROM %s WHERE %s GROUP BY Path", t.table, w), nil
}

func (t *TagFinder) MakeSQL(query string) (string, error) {
	if query == "_tag" {
		t.state = TagInfoRoot
		return "", nil
	}

	qs := strings.Split(query, ".")

	t.tagQuery = make([]TagQ, 0)

	for {
		if len(qs) == 0 {
			break
		}
		if qs[0] == "_tag" {
			if len(qs) >= 2 {
				v := qs[1]
				if len(v) > 0 && v[len(v)-1] == '=' {
					if len(qs) >= 3 {
						t.tagQuery = append(t.tagQuery, TagQ{Param: &v, Value: &qs[2]})
						qs = qs[3:]
					} else {
						t.tagQuery = append(t.tagQuery, TagQ{Param: &v})
						qs = qs[2:]
					}
				} else {
					t.tagQuery = append(t.tagQuery, TagQ{Value: &v})
					qs = qs[2:]
				}
			} else {
				t.tagQuery = append(t.tagQuery, TagQ{})
				qs = qs[1:]
			}
		} else {
			t.seriesQuery = strings.Join(qs, ".")
			break
		}
	}

	if t.seriesQuery == "" {
		if len(t.tagQuery) > 0 && t.tagQuery[len(t.tagQuery)-1].Param != nil {
			t.state = TagListParam
		} else {
			t.state = TagList
		}
		return t.tagListSQL()
	}

	if t.seriesQuery == "*" {
		t.state = TagListSeriesRoot
		return t.seriesSQL()
	}

	t.state = TagListSeries
	return t.seriesSQL()
}

func (t *TagFinder) Execute(query string) error {
	t.state = TagSkip

	if query == "" {
		return t.wrapped.Execute(query)
	}

	if query == "*" {
		t.state = TagRoot
		return t.wrapped.Execute(query)
	}

	if !strings.HasPrefix(query, "_tag.") && query != "_tag" {
		return t.wrapped.Execute(query)
	}

	sql, err := t.MakeSQL(query)
	if err != nil {
		return err
	}

	if sql != "" {
		t.body, err = clickhouse.Query(t.ctx, t.url, sql, t.timeout)
	}

	return err
}

func (t *TagFinder) List() [][]byte {
	switch t.state {
	case TagSkip:
		return t.wrapped.List()
	case TagInfoRoot:
		return [][]byte{[]byte("_tag.")}
	case TagRoot:
		// pass
		return append([][]byte{[]byte("_tag.")}, t.wrapped.List()...)
	}

	if t.body == nil {
		return [][]byte{}
	}

	rows := bytes.Split(t.body, []byte{'\n'})

	skip := 0
	for i := 0; i < len(rows); i++ {
		if len(rows[i]) == 0 {
			skip++
			continue
		}
		if skip > 0 {
			rows[i-skip] = rows[i]
		}
	}

	rows = rows[:len(rows)-skip]

	if t.state == TagList || t.state == TagListParam {
		// add dots
		for i := 0; i < len(rows); i++ {
			eqIndex := bytes.IndexByte(rows[i], '=')
			if eqIndex > 0 && eqIndex < len(rows[i])-1 {
				if t.state == TagListParam {
					rows[i] = append(rows[i][eqIndex+1:], '.')
				} else {
					rows[i][eqIndex+1] = '.'
					rows[i] = rows[i][:eqIndex+2]
				}
			} else {
				rows[i] = append(rows[i], '.')
			}
		}
	}

	if t.state == TagListSeriesRoot {
		rows = append(rows, []byte("_tag."))
	}

	return rows
}

func (t *TagFinder) Series() [][]byte {
	switch t.state {
	case TagSkip:
		return t.wrapped.Series()
	case TagInfoRoot:
		return EmptyList
	case TagRoot:
		return t.wrapped.Series()
	}

	rows := t.List()

	skip := 0
	for i := 0; i < len(rows); i++ {
		if len(rows[i]) == 0 {
			skip++
			continue
		}
		if rows[i][len(rows[i])-1] == '.' {
			skip++
			continue
		}
		if skip > 0 {
			rows[i-skip] = rows[i]
		}
	}

	return rows
}

func (t *TagFinder) Abs(v []byte) []byte {
	// @TODO
	return v
}
<commit_msg>tag finder Abs<commit_after>package finder

import (
	"bytes"
	"context"
	"fmt"
	"strings"
	"time"

	"github.com/lomik/graphite-clickhouse/helper/clickhouse"
)

type TagState int

const (
	TagRoot     TagState = iota // query = "*"
	TagSkip                     // not _tag prefix
	TagInfoRoot                 // query = "_tag"
	TagList
	TagListSeriesRoot
	TagListSeries
	TagListParam
)

type TagQ struct {
	Param *string
	Value *string
}

func (q TagQ) String() string {
	if q.Param != nil && q.Value != nil {
		return fmt.Sprintf("{\"param\"=%#v, \"value\"=%#v}", *q.Param, *q.Value)
	}
	if q.Param != nil {
		return fmt.Sprintf("{\"param\"=%#v}", *q.Param)
	}
	if q.Value != nil {
		return fmt.Sprintf("{\"value\"=%#v}", *q.Value)
	}
	return "{}"
}

func (q *TagQ) Where(field string) string {
	if q.Param != nil && q.Value != nil && *q.Value != "*" {
		return fmt.Sprintf("%s=%s", field, Q(*q.Param+*q.Value))
	}
	if q.Param != nil {
		return fmt.Sprintf("%s LIKE %s", field, Q(*q.Param+`%`))
	}
	if q.Value != nil && *q.Value != "*" {
		return fmt.Sprintf("%s=%s", field, Q(*q.Value))
	}

	return ""
}

type TagFinder struct {
	wrapped     Finder
	ctx         context.Context // for clickhouse.Query
	url         string          // clickhouse dsn
	table       string          // graphite_tag table
	timeout     time.Duration   // clickhouse query timeout
	state       TagState
	tagQuery    []TagQ
	seriesQuery string
	tagPrefix   []byte
	body        []byte // clickhouse response
}

var EmptyList [][]byte = [][]byte{}

func WrapTag(f Finder, ctx context.Context, url string, table string, timeout time.Duration) *TagFinder {
	return &TagFinder{
		wrapped:  f,
		ctx:      ctx,
		url:      url,
		table:    table,
		timeout:  timeout,
		tagQuery: make([]TagQ, 0),
	}
}

func (t *TagFinder) tagListSQL() (string, error) {
	if len(t.tagQuery) == 0 {
		return "", nil
	}

	w := NewWhere()

	w.Andf("Version>=(SELECT Max(Version) FROM %s WHERE Tag1='' AND Level=0 AND Path='')", t.table)

	// first
	w.And(t.tagQuery[0].Where("Tag1"))

	if len(t.tagQuery) == 1 {
		w.And("Level=1")
		return fmt.Sprintf("SELECT Tag1 FROM %s WHERE %s GROUP BY Tag1", t.table, w), nil
	}

	// 1..(n-1)
	for i := 1; i < len(t.tagQuery)-1; i++ {
		cond := t.tagQuery[i].Where("x")
		if cond != "" {
			w.Andf("arrayExists((x) -> %s, Tags)", cond)
		}
	}

	// last
	w.And(t.tagQuery[len(t.tagQuery)-1].Where("TagN"))

	w.And("IsLeaf=1")

	return fmt.Sprintf("SELECT TagN FROM %s ARRAY JOIN Tags AS TagN WHERE %s GROUP BY TagN", t.table, w), nil
}

func (t *TagFinder) seriesSQL() (string, error) {
	if len(t.tagQuery) == 0 {
		return "", nil
	}

	w := NewWhere()

	w.Andf("Version>=(SELECT Max(Version) FROM %s WHERE Tag1='' AND Level=0 AND Path='')", t.table)
	// first
	w.And(t.tagQuery[0].Where("Tag1"))

	// 1..(n-1)
	for i := 1; i < len(t.tagQuery); i++ {
		cond := t.tagQuery[i].Where("x")
		if cond != "" {
			w.Andf("arrayExists((x) -> %s, Tags)", cond)
		}
	}

	base := &BaseFinder{}
	w.And(base.where(t.seriesQuery))

	return fmt.Sprintf("SELECT Path FROM %s WHERE %s GROUP BY Path", t.table, w), nil
}

func (t *TagFinder) MakeSQL(query string) (string, error) {
	if query == "_tag" {
		t.state = TagInfoRoot
		return "", nil
	}

	qs0 := strings.Split(query, ".")
	qs := qs0

	t.tagQuery = make([]TagQ, 0)

	for {
		if len(qs) == 0 {
			break
		}
		if qs[0] == "_tag" {
			if len(qs) >= 2 {
				v := qs[1]
				if len(v) > 0 && v[len(v)-1] == '=' {
					if len(qs) >= 3 {
						t.tagQuery = append(t.tagQuery, TagQ{Param: &v, Value: &qs[2]})
						qs = qs[3:]
					} else {
						t.tagQuery = append(t.tagQuery, TagQ{Param: &v})
						qs = qs[2:]
					}
				} else {
					t.tagQuery = append(t.tagQuery, TagQ{Value: &v})
					qs = qs[2:]
				}
			} else {
				t.tagQuery = append(t.tagQuery, TagQ{})
				qs = qs[1:]
			}
		} else {
			t.seriesQuery = strings.Join(qs, ".")
			break
		}
	}

	if len(qs0) > len(qs) {
		t.tagPrefix = append([]byte(strings.Join(qs0[:len(qs0)-len(qs)], ".")), '.')
	}

	if t.seriesQuery == "" {
		if len(t.tagQuery) > 0 && t.tagQuery[len(t.tagQuery)-1].Param != nil {
			t.state = TagListParam
		} else {
			t.state = TagList
		}
		return t.tagListSQL()
	}

	if t.seriesQuery == "*" {
		t.state = TagListSeriesRoot
		return t.seriesSQL()
	}

	t.state = TagListSeries
	return t.seriesSQL()
}

func (t *TagFinder) Execute(query string) error {
	t.state = TagSkip

	if query == "" {
		return t.wrapped.Execute(query)
	}

	if query == "*" {
		t.state = TagRoot
		return t.wrapped.Execute(query)
	}

	if !strings.HasPrefix(query, "_tag.") && query != "_tag" {
		return t.wrapped.Execute(query)
	}

	sql, err := t.MakeSQL(query)
	if err != nil {
		return err
	}

	if sql != "" {
		t.body, err = clickhouse.Query(t.ctx, t.url, sql, t.timeout)
	}

	return err
}

func (t *TagFinder) List() [][]byte {
	switch t.state {
	case TagSkip:
		return t.wrapped.List()
	case TagInfoRoot:
		return [][]byte{[]byte("_tag.")}
	case TagRoot:
		// pass
		return append([][]byte{[]byte("_tag.")}, t.wrapped.List()...)
	}

	if t.body == nil {
		return [][]byte{}
	}

	rows := bytes.Split(t.body, []byte{'\n'})

	skip := 0
	for i := 0; i < len(rows); i++ {
		if len(rows[i]) == 0 {
			skip++
			continue
		}
		if skip > 0 {
			rows[i-skip] = rows[i]
		}
	}

	rows = rows[:len(rows)-skip]

	if t.state == TagList || t.state == TagListParam {
		// add dots
		for i := 0; i < len(rows); i++ {
			eqIndex := bytes.IndexByte(rows[i], '=')
			if eqIndex > 0 && eqIndex < len(rows[i])-1 {
				if t.state == TagListParam {
					rows[i] = append(rows[i][eqIndex+1:], '.')
				} else {
					rows[i][eqIndex+1] = '.'
					rows[i] = rows[i][:eqIndex+2]
				}
			} else {
				rows[i] = append(rows[i], '.')
			}
		}
	}

	if t.state == TagListSeriesRoot {
		rows = append(rows, []byte("_tag."))
	}

	return rows
}

func (t *TagFinder) Series() [][]byte {
	switch t.state {
	case TagSkip:
		return t.wrapped.Series()
	case TagInfoRoot:
		return EmptyList
	case TagRoot:
		return t.wrapped.Series()
	}

	rows := t.List()

	skip := 0
	for i := 0; i < len(rows); i++ {
		if len(rows[i]) == 0 {
			skip++
			continue
		}
		if rows[i][len(rows[i])-1] == '.' {
			skip++
			continue
		}
		if skip > 0 {
			rows[i-skip] = rows[i]
		}
	}

	return rows
}

func (t *TagFinder) Abs(v []byte) []byte {
	if t.state == TagSkip {
		return t.wrapped.Abs(v)
	}

	return append(t.tagPrefix, v...)
}
<|endoftext|>


<commit_before>package main

func testingDaemon() (d *daemon, err error) {
	dc := DaemonConfig{
		APIAddr: ":9020",
		RPCAddr: ":9021",

		HostDir: "hostDir",

		Threads: 2,

		DownloadDir: "downloadDir",

		WalletDir: "walletDir",
	}

	d, err = newDaemon(dc)
	if err != nil {
		return
	}

	go d.listen(dc.APIAddr)
	return
}
<commit_msg>create daemonTester<commit_after>package main

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"testing"
)

type daemonTester struct {
	*daemon
	*testing.T
}

func newDaemonTester(t *testing.T) *daemonTester {
	dc := DaemonConfig{
		APIAddr: ":9020",
		RPCAddr: ":9021",

		HostDir: "hostDir",

		Threads: 2,

		DownloadDir: "downloadDir",

		WalletDir: "walletDir",
	}

	d, err := newDaemon(dc)
	if err != nil {
		t.Fatal("Could not create daemon:", err)
	}
	go func() {
		listenErr := d.listen()
		if listenErr != nil {
			t.Fatal("API server quit:", listenErr)
		}
	}()

	return &daemonTester{d, t}
}

// get wraps a GET request with a status code check, such that if the GET does
// not return 200, the error will be read and returned. The response body is
// not closed.
func (dt *daemonTester) get(call string) (resp *http.Response) {
	resp, err := http.Get("http://localhost" + dt.apiServer.Addr + call)
	if err != nil {
		dt.Fatalf("GET %s failed: %v", call, err)
	}
	// check error code
	if resp.StatusCode != http.StatusOK {
		errResp, _ := ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		dt.Fatalf("GET %s returned error %v: %v", resp.StatusCode, errResp)
	}
	return
}

// getAPI makes an API call and decodes the response.
func (dt *daemonTester) getAPI(call string, obj interface{}) {
	resp := dt.get(call)
	defer resp.Body.Close()
	err := json.NewDecoder(resp.Body).Decode(obj)
	if err != nil {
		dt.Fatalf("Could not decode API response: %s", call)
	}
	return
}

// callAPI makes an API call and discards the response.
func (dt *daemonTester) callAPI(call string) {
	dt.get(call).Body.Close()
}

// TestCreateDaemon creates a daemonTester and immediately stops it.
func TestCreateDaemon(t *testing.T) {
	newDaemonTester(t).callAPI("/stop")
}
<|endoftext|>


<commit_before>package installer

// Note: .exe is not in that list because we need to
// read part of its contents to decide what we're going to
// do with it: 1) extract it 2) run it as an installer 3)
// just copy it naked
var installerForExt = map[string]InstallerType{

	///////////////////////////////////////////////////////////
	// Generic archives
	///////////////////////////////////////////////////////////

	".zip": InstallerTypeArchive,
	".gz":  InstallerTypeArchive,
	".bz2": InstallerTypeArchive,
	".7z":  InstallerTypeArchive,
	".tar": InstallerTypeArchive,
	".xz":  InstallerTypeArchive,
	".rar": InstallerTypeArchive,

	///////////////////////////////////////////////////////////
	// Known non-supported
	///////////////////////////////////////////////////////////

	".deb": InstallerTypeUnsupported,
	".rpm": InstallerTypeUnsupported,
	".pkg": InstallerTypeUnsupported,

	///////////////////////////////////////////////////////////
	// Platform-specific packages
	///////////////////////////////////////////////////////////

	// Apple disk images
	".dmg": InstallerTypeArchive,

	// Microsoft packages
	".msi": InstallerTypeMSI,

	///////////////////////////////////////////////////////////
	// Known naked that also sniff as other formats
	///////////////////////////////////////////////////////////

	".jar":          InstallerTypeNaked,
	".love":         InstallerTypeNaked,
	".unitypackage": InstallerTypeNaked,

	///////////////////////////////////////////////////////////
	// Books!
	///////////////////////////////////////////////////////////

	".pdf":    InstallerTypeNaked,
	".ps":     InstallerTypeNaked,
	".djvu":   InstallerTypeNaked,
	".cbr":    InstallerTypeNaked,
	".cbz":    InstallerTypeNaked,
	".cb7":    InstallerTypeNaked,
	".cbt":    InstallerTypeNaked,
	".cba":    InstallerTypeNaked,
	".doc":    InstallerTypeNaked,
	".docx":   InstallerTypeNaked,
	".epub":   InstallerTypeNaked,
	".pdb":    InstallerTypeNaked,
	".fb2":    InstallerTypeNaked,
	".xeb":    InstallerTypeNaked,
	".ceb":    InstallerTypeNaked,
	".ibooks": InstallerTypeNaked,
	".txt":    InstallerTypeNaked,

	///////////////////////////////////////////////////////////
	// Media
	///////////////////////////////////////////////////////////

	".ogg": InstallerTypeNaked,
	".mp3": InstallerTypeNaked,
	".wav": InstallerTypeNaked,
	".mp4": InstallerTypeNaked,
	".avi": InstallerTypeNaked,

	///////////////////////////////////////////////////////////
	// Images
	///////////////////////////////////////////////////////////

	".png": InstallerTypeNaked,
	".jpg": InstallerTypeNaked,
	".gif": InstallerTypeNaked,
	".bmp": InstallerTypeNaked,
	".tga": InstallerTypeNaked,

	///////////////////////////////////////////////////////////
	// Game Maker assets
	///////////////////////////////////////////////////////////

	".gmez": InstallerTypeNaked,
	".gmz":  InstallerTypeNaked,
	".yyz":  InstallerTypeNaked,
	".yymp": InstallerTypeNaked,

	///////////////////////////////////////////////////////////
	// ROMs
	///////////////////////////////////////////////////////////

	".gb":  InstallerTypeNaked,
	".sfc": InstallerTypeNaked,
	".smc": InstallerTypeNaked,
	".swc": InstallerTypeNaked,
	".gen": InstallerTypeNaked,
	".sg":  InstallerTypeNaked,
	".smd": InstallerTypeNaked,
	".md":  InstallerTypeNaked,

	///////////////////////////////////////////////////////////
	// Miscellaneous other things
	///////////////////////////////////////////////////////////

	// Some html games provide a single .html file
	// Now that's dedication.
	".html": InstallerTypeNaked,
}
<commit_msg>Use naked strategy for .gbc files, cf. https://github.com/itchio/itch/issues/2076#issuecomment-417774994<commit_after>package installer

// Note: .exe is not in that list because we need to
// read part of its contents to decide what we're going to
// do with it: 1) extract it 2) run it as an installer 3)
// just copy it naked
var installerForExt = map[string]InstallerType{

	///////////////////////////////////////////////////////////
	// Generic archives
	///////////////////////////////////////////////////////////

	".zip": InstallerTypeArchive,
	".gz":  InstallerTypeArchive,
	".bz2": InstallerTypeArchive,
	".7z":  InstallerTypeArchive,
	".tar": InstallerTypeArchive,
	".xz":  InstallerTypeArchive,
	".rar": InstallerTypeArchive,

	///////////////////////////////////////////////////////////
	// Known non-supported
	///////////////////////////////////////////////////////////

	".deb": InstallerTypeUnsupported,
	".rpm": InstallerTypeUnsupported,
	".pkg": InstallerTypeUnsupported,

	///////////////////////////////////////////////////////////
	// Platform-specific packages
	///////////////////////////////////////////////////////////

	// Apple disk images
	".dmg": InstallerTypeArchive,

	// Microsoft packages
	".msi": InstallerTypeMSI,

	///////////////////////////////////////////////////////////
	// Known naked that also sniff as other formats
	///////////////////////////////////////////////////////////

	".jar":          InstallerTypeNaked,
	".love":         InstallerTypeNaked,
	".unitypackage": InstallerTypeNaked,

	///////////////////////////////////////////////////////////
	// Books!
	///////////////////////////////////////////////////////////

	".pdf":    InstallerTypeNaked,
	".ps":     InstallerTypeNaked,
	".djvu":   InstallerTypeNaked,
	".cbr":    InstallerTypeNaked,
	".cbz":    InstallerTypeNaked,
	".cb7":    InstallerTypeNaked,
	".cbt":    InstallerTypeNaked,
	".cba":    InstallerTypeNaked,
	".doc":    InstallerTypeNaked,
	".docx":   InstallerTypeNaked,
	".epub":   InstallerTypeNaked,
	".pdb":    InstallerTypeNaked,
	".fb2":    InstallerTypeNaked,
	".xeb":    InstallerTypeNaked,
	".ceb":    InstallerTypeNaked,
	".ibooks": InstallerTypeNaked,
	".txt":    InstallerTypeNaked,

	///////////////////////////////////////////////////////////
	// Media
	///////////////////////////////////////////////////////////

	".ogg": InstallerTypeNaked,
	".mp3": InstallerTypeNaked,
	".wav": InstallerTypeNaked,
	".mp4": InstallerTypeNaked,
	".avi": InstallerTypeNaked,

	///////////////////////////////////////////////////////////
	// Images
	///////////////////////////////////////////////////////////

	".png": InstallerTypeNaked,
	".jpg": InstallerTypeNaked,
	".gif": InstallerTypeNaked,
	".bmp": InstallerTypeNaked,
	".tga": InstallerTypeNaked,

	///////////////////////////////////////////////////////////
	// Game Maker assets
	///////////////////////////////////////////////////////////

	".gmez": InstallerTypeNaked,
	".gmz":  InstallerTypeNaked,
	".yyz":  InstallerTypeNaked,
	".yymp": InstallerTypeNaked,

	///////////////////////////////////////////////////////////
	// ROMs
	///////////////////////////////////////////////////////////

	".gb":  InstallerTypeNaked,
	".gbc": InstallerTypeNaked,
	".sfc": InstallerTypeNaked,
	".smc": InstallerTypeNaked,
	".swc": InstallerTypeNaked,
	".gen": InstallerTypeNaked,
	".sg":  InstallerTypeNaked,
	".smd": InstallerTypeNaked,
	".md":  InstallerTypeNaked,

	///////////////////////////////////////////////////////////
	// Miscellaneous other things
	///////////////////////////////////////////////////////////

	// Some html games provide a single .html file
	// Now that's dedication.
	".html": InstallerTypeNaked,
}
<|endoftext|>