<commit_before>package aws

import (
	"fmt"
	"log"
	"regexp"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/iam"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/helper/validation"
)

func resourceAwsIamUser() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsIamUserCreate,
		Read:   resourceAwsIamUserRead,
		Update: resourceAwsIamUserUpdate,
		Delete: resourceAwsIamUserDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},
			/*
				The UniqueID could be used as the Id(), but none of the API
				calls allow specifying a user by the UniqueID: they require the
				name. The only way to locate a user by UniqueID is to list them
				all and that would make this provider unnecessarily complex
				and inefficient. Still, there are other reasons one might want
				the UniqueID, so we can make it available.
			*/
			"unique_id": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"name": {
				Type:         schema.TypeString,
				Required:     true,
				ValidateFunc: validateAwsIamUserName,
			},
			"path": {
				Type:     schema.TypeString,
				Optional: true,
				Default:  "/",
			},
			"permissions_boundary": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validation.StringLenBetween(0, 2048),
			},
			"force_destroy": {
				Type:        schema.TypeBool,
				Optional:    true,
				Default:     false,
				Description: "Delete user even if it has non-Terraform-managed IAM access keys, login profile or MFA devices",
			},
			"tags": tagsSchema(),
		},
	}
}

func resourceAwsIamUserCreate(d *schema.ResourceData, meta interface{}) error {
	iamconn := meta.(*AWSClient).iamconn
	name := d.Get("name").(string)
	path := d.Get("path").(string)

	request := &iam.CreateUserInput{
		Path:     aws.String(path),
		UserName: aws.String(name),
	}

	if v, ok := d.GetOk("permissions_boundary"); ok && v.(string) != "" {
		request.PermissionsBoundary = aws.String(v.(string))
	}

	if v, ok := d.GetOk("tags"); ok {
		tags := tagsFromMapIAM(v.(map[string]interface{}))
		request.Tags = tags
	}

	log.Println("[DEBUG] Create IAM User request:", request)
	createResp, err := iamconn.CreateUser(request)
	if err != nil {
		return fmt.Errorf("Error creating IAM User %s: %s", name, err)
	}

	d.SetId(aws.StringValue(createResp.User.UserName))

	return resourceAwsIamUserRead(d, meta)
}

func resourceAwsIamUserRead(d *schema.ResourceData, meta interface{}) error {
	iamconn := meta.(*AWSClient).iamconn

	request := &iam.GetUserInput{
		UserName: aws.String(d.Id()),
	}

	output, err := iamconn.GetUser(request)
	if err != nil {
		if isAWSErr(err, iam.ErrCodeNoSuchEntityException, "") {
			log.Printf("[WARN] No IAM user by name (%s) found, removing from state", d.Id())
			d.SetId("")
			return nil
		}
		return fmt.Errorf("Error reading IAM User %s: %s", d.Id(), err)
	}

	if output == nil || output.User == nil {
		log.Printf("[WARN] No IAM user by name (%s) found, removing from state", d.Id())
		d.SetId("")
		return nil
	}

	d.Set("arn", output.User.Arn)
	d.Set("name", output.User.UserName)
	d.Set("path", output.User.Path)
	if output.User.PermissionsBoundary != nil {
		d.Set("permissions_boundary", output.User.PermissionsBoundary.PermissionsBoundaryArn)
	}
	d.Set("unique_id", output.User.UserId)
	d.Set("tags", tagsToMapIAM(output.User.Tags))

	return nil
}

func resourceAwsIamUserUpdate(d *schema.ResourceData, meta interface{}) error {
	iamconn := meta.(*AWSClient).iamconn

	if d.HasChange("name") || d.HasChange("path") {
		on, nn := d.GetChange("name")
		_, np := d.GetChange("path")

		request := &iam.UpdateUserInput{
			UserName:    aws.String(on.(string)),
			NewUserName: aws.String(nn.(string)),
			NewPath:     aws.String(np.(string)),
		}

		log.Println("[DEBUG] Update IAM User request:", request)
		_, err := iamconn.UpdateUser(request)
		if err != nil {
			if isAWSErr(err, iam.ErrCodeNoSuchEntityException, "") {
				log.Printf("[WARN] No IAM user by name (%s) found", d.Id())
				d.SetId("")
				return nil
			}
			return fmt.Errorf("Error updating IAM User %s: %s", d.Id(), err)
		}

		d.SetId(nn.(string))
	}

	if d.HasChange("permissions_boundary") {
		permissionsBoundary := d.Get("permissions_boundary").(string)
		if permissionsBoundary != "" {
			input := &iam.PutUserPermissionsBoundaryInput{
				PermissionsBoundary: aws.String(permissionsBoundary),
				UserName:            aws.String(d.Id()),
			}
			_, err := iamconn.PutUserPermissionsBoundary(input)
			if err != nil {
				return fmt.Errorf("error updating IAM User permissions boundary: %s", err)
			}
		} else {
			input := &iam.DeleteUserPermissionsBoundaryInput{
				UserName: aws.String(d.Id()),
			}
			_, err := iamconn.DeleteUserPermissionsBoundary(input)
			if err != nil {
				return fmt.Errorf("error deleting IAM User permissions boundary: %s", err)
			}
		}
	}

	if d.HasChange("tags") {
		// Reset all tags to empty set
		oraw, nraw := d.GetChange("tags")
		o := oraw.(map[string]interface{})
		n := nraw.(map[string]interface{})
		c, r := diffTagsIAM(tagsFromMapIAM(o), tagsFromMapIAM(n))

		_, untagErr := iamconn.UntagUser(&iam.UntagUserInput{
			UserName: aws.String(d.Id()),
			TagKeys:  tagKeysIam(r),
		})
		if untagErr != nil {
			return fmt.Errorf("error deleting IAM user tags: %s", untagErr)
		}

		input := &iam.TagUserInput{
			UserName: aws.String(d.Id()),
			Tags:     c,
		}
		_, tagErr := iamconn.TagUser(input)
		if tagErr != nil {
			return fmt.Errorf("error update IAM user tags: %s", tagErr)
		}
	}

	return resourceAwsIamUserRead(d, meta)
}

func resourceAwsIamUserDelete(d *schema.ResourceData, meta interface{}) error {
	iamconn := meta.(*AWSClient).iamconn

	// IAM Users must be removed from all groups before they can be deleted
	var groups []string
	listGroups := &iam.ListGroupsForUserInput{
		UserName: aws.String(d.Id()),
	}
	pageOfGroups := func(page *iam.ListGroupsForUserOutput, lastPage bool) (shouldContinue bool) {
		for _, g := range page.Groups {
			groups = append(groups, *g.GroupName)
		}
		return !lastPage
	}
	err := iamconn.ListGroupsForUserPages(listGroups, pageOfGroups)
	if err != nil {
		return fmt.Errorf("Error removing user %q from all groups: %s", d.Id(), err)
	}
	for _, g := range groups {
		// use iam group membership func to remove user from all groups
		log.Printf("[DEBUG] Removing IAM User %s from IAM Group %s", d.Id(), g)
		if err := removeUsersFromGroup(iamconn, []*string{aws.String(d.Id())}, g); err != nil {
			return err
		}
	}

	// All access keys, MFA devices and login profile for the user must be removed
	if d.Get("force_destroy").(bool) {

		err = deleteAwsIamUserAccessKeys(iamconn, d.Id())
		if err != nil {
			return err
		}

		err = deleteAwsIamUserSSHKeys(iamconn, d.Id())
		if err != nil {
			return err
		}

		err = deleteAwsIamUserMFADevices(iamconn, d.Id())
		if err != nil {
			return err
		}

		err = deleteAwsIamUserLoginProfile(iamconn, d.Id())
		if err != nil {
			return err
		}
	}

	deleteUserInput := &iam.DeleteUserInput{
		UserName: aws.String(d.Id()),
	}

	log.Println("[DEBUG] Delete IAM User request:", deleteUserInput)
	_, err = iamconn.DeleteUser(deleteUserInput)
	if err != nil {
		if isAWSErr(err, iam.ErrCodeNoSuchEntityException, "") {
			return nil
		}
		return fmt.Errorf("Error deleting IAM User %s: %s", d.Id(), err)
	}

	return nil
}

func validateAwsIamUserName(v interface{}, k string) (ws []string, errors []error) {
	value := v.(string)
	if !regexp.MustCompile(`^[0-9A-Za-z=,.@\-_+]+$`).MatchString(value) {
		errors = append(errors, fmt.Errorf(
			"only alphanumeric characters, hyphens, underscores, commas, periods, @ symbols, plus and equals signs allowed in %q: %q",
			k, value))
	}
	return
}

func deleteAwsIamUserSSHKeys(svc *iam.IAM, username string) error {
	var publicKeys []string
	var err error

	listSSHPublicKeys := &iam.ListSSHPublicKeysInput{
		UserName: aws.String(username),
	}
	pageOfListSSHPublicKeys := func(page *iam.ListSSHPublicKeysOutput, lastPage bool) (shouldContinue bool) {
		for _, k := range page.SSHPublicKeys {
			publicKeys = append(publicKeys, *k.SSHPublicKeyId)
		}
		return !lastPage
	}
	err = svc.ListSSHPublicKeysPages(listSSHPublicKeys, pageOfListSSHPublicKeys)
	if err != nil {
		return fmt.Errorf("Error removing public SSH keys of user %s: %s", username, err)
	}
	for _, k := range publicKeys {
		_, err := svc.DeleteSSHPublicKey(&iam.DeleteSSHPublicKeyInput{
			UserName:       aws.String(username),
			SSHPublicKeyId: aws.String(k),
		})
		if err != nil {
			return fmt.Errorf("Error deleting public SSH key %s: %s", k, err)
		}
	}

	return nil
}

func deleteAwsIamUserMFADevices(svc *iam.IAM, username string) error {
	var MFADevices []string
	var err error

	listMFADevices := &iam.ListMFADevicesInput{
		UserName: aws.String(username),
	}
	pageOfMFADevices := func(page *iam.ListMFADevicesOutput, lastPage bool) (shouldContinue bool) {
		for _, m := range page.MFADevices {
			MFADevices = append(MFADevices, *m.SerialNumber)
		}
		return !lastPage
	}
	err = svc.ListMFADevicesPages(listMFADevices, pageOfMFADevices)
	if err != nil {
		return fmt.Errorf("Error removing MFA devices of user %s: %s", username, err)
	}
	for _, m := range MFADevices {
		_, err := svc.DeactivateMFADevice(&iam.DeactivateMFADeviceInput{
			UserName:     aws.String(username),
			SerialNumber: aws.String(m),
		})
		if err != nil {
			return fmt.Errorf("Error deactivating MFA device %s: %s", m, err)
		}
	}

	return nil
}

func deleteAwsIamUserLoginProfile(svc *iam.IAM, username string) error {
	var err error
	err = resource.Retry(1*time.Minute, func() *resource.RetryError {
		_, err = svc.DeleteLoginProfile(&iam.DeleteLoginProfileInput{
			UserName: aws.String(username),
		})
		if err != nil {
			if isAWSErr(err, iam.ErrCodeNoSuchEntityException, "") {
				return nil
			}
			// EntityTemporarilyUnmodifiable: Login Profile for User XXX cannot be modified while login profile is being created.
			if isAWSErr(err, iam.ErrCodeEntityTemporarilyUnmodifiableException, "") {
				return resource.RetryableError(err)
			}
			return resource.NonRetryableError(err)
		}
		return nil
	})

	if err != nil {
		return fmt.Errorf("Error deleting Account Login Profile: %s", err)
	}

	return nil
}

func deleteAwsIamUserAccessKeys(svc *iam.IAM, username string) error {
	var accessKeys []string
	var err error
	listAccessKeys := &iam.ListAccessKeysInput{
		UserName: aws.String(username),
	}
	pageOfAccessKeys := func(page *iam.ListAccessKeysOutput, lastPage bool) (shouldContinue bool) {
		for _, k := range page.AccessKeyMetadata {
			accessKeys = append(accessKeys, *k.AccessKeyId)
		}
		return !lastPage
	}
	err = svc.ListAccessKeysPages(listAccessKeys, pageOfAccessKeys)
	if err != nil {
		return fmt.Errorf("Error removing access keys of user %s: %s", username, err)
	}
	for _, k := range accessKeys {
		_, err := svc.DeleteAccessKey(&iam.DeleteAccessKeyInput{
			UserName:    aws.String(username),
			AccessKeyId: aws.String(k),
		})
		if err != nil {
			return fmt.Errorf("Error deleting access key %s: %s", k, err)
		}
	}

	return nil
}
<commit_msg>api call when count > 0<commit_after>package aws

import (
	"fmt"
	"log"
	"regexp"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/iam"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/helper/validation"
)

func resourceAwsIamUser() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsIamUserCreate,
		Read:   resourceAwsIamUserRead,
		Update: resourceAwsIamUserUpdate,
		Delete: resourceAwsIamUserDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},
			/*
				The UniqueID could be used as the Id(), but none of the API
				calls allow specifying a user by the UniqueID: they require the
				name. The only way to locate a user by UniqueID is to list them
				all and that would make this provider unnecessarily complex
				and inefficient. Still, there are other reasons one might want
				the UniqueID, so we can make it available.
			*/
			"unique_id": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"name": {
				Type:         schema.TypeString,
				Required:     true,
				ValidateFunc: validateAwsIamUserName,
			},
			"path": {
				Type:     schema.TypeString,
				Optional: true,
				Default:  "/",
			},
			"permissions_boundary": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validation.StringLenBetween(0, 2048),
			},
			"force_destroy": {
				Type:        schema.TypeBool,
				Optional:    true,
				Default:     false,
				Description: "Delete user even if it has non-Terraform-managed IAM access keys, login profile or MFA devices",
			},
			"tags": tagsSchema(),
		},
	}
}

func resourceAwsIamUserCreate(d *schema.ResourceData, meta interface{}) error {
	iamconn := meta.(*AWSClient).iamconn
	name := d.Get("name").(string)
	path := d.Get("path").(string)

	request := &iam.CreateUserInput{
		Path:     aws.String(path),
		UserName: aws.String(name),
	}

	if v, ok := d.GetOk("permissions_boundary"); ok && v.(string) != "" {
		request.PermissionsBoundary = aws.String(v.(string))
	}

	if v, ok := d.GetOk("tags"); ok {
		tags := tagsFromMapIAM(v.(map[string]interface{}))
		request.Tags = tags
	}

	log.Println("[DEBUG] Create IAM User request:", request)
	createResp, err := iamconn.CreateUser(request)
	if err != nil {
		return fmt.Errorf("Error creating IAM User %s: %s", name, err)
	}

	d.SetId(aws.StringValue(createResp.User.UserName))

	return resourceAwsIamUserRead(d, meta)
}

func resourceAwsIamUserRead(d *schema.ResourceData, meta interface{}) error {
	iamconn := meta.(*AWSClient).iamconn

	request := &iam.GetUserInput{
		UserName: aws.String(d.Id()),
	}

	output, err := iamconn.GetUser(request)
	if err != nil {
		if isAWSErr(err, iam.ErrCodeNoSuchEntityException, "") {
			log.Printf("[WARN] No IAM user by name (%s) found, removing from state", d.Id())
			d.SetId("")
			return nil
		}
		return fmt.Errorf("Error reading IAM User %s: %s", d.Id(), err)
	}

	if output == nil || output.User == nil {
		log.Printf("[WARN] No IAM user by name (%s) found, removing from state", d.Id())
		d.SetId("")
		return nil
	}

	d.Set("arn", output.User.Arn)
	d.Set("name", output.User.UserName)
	d.Set("path", output.User.Path)
	if output.User.PermissionsBoundary != nil {
		d.Set("permissions_boundary", output.User.PermissionsBoundary.PermissionsBoundaryArn)
	}
	d.Set("unique_id", output.User.UserId)
	if err := d.Set("tags", tagsToMapIAM(output.User.Tags)); err != nil {
		return fmt.Errorf("error setting tags: %s", err)
	}

	return nil
}

func resourceAwsIamUserUpdate(d *schema.ResourceData, meta interface{}) error {
	iamconn := meta.(*AWSClient).iamconn

	if d.HasChange("name") || d.HasChange("path") {
		on, nn := d.GetChange("name")
		_, np := d.GetChange("path")

		request := &iam.UpdateUserInput{
			UserName:    aws.String(on.(string)),
			NewUserName: aws.String(nn.(string)),
			NewPath:     aws.String(np.(string)),
		}

		log.Println("[DEBUG] Update IAM User request:", request)
		_, err := iamconn.UpdateUser(request)
		if err != nil {
			if isAWSErr(err, iam.ErrCodeNoSuchEntityException, "") {
				log.Printf("[WARN] No IAM user by name (%s) found", d.Id())
				d.SetId("")
				return nil
			}
			return fmt.Errorf("Error updating IAM User %s: %s", d.Id(), err)
		}

		d.SetId(nn.(string))
	}

	if d.HasChange("permissions_boundary") {
		permissionsBoundary := d.Get("permissions_boundary").(string)
		if permissionsBoundary != "" {
			input := &iam.PutUserPermissionsBoundaryInput{
				PermissionsBoundary: aws.String(permissionsBoundary),
				UserName:            aws.String(d.Id()),
			}
			_, err := iamconn.PutUserPermissionsBoundary(input)
			if err != nil {
				return fmt.Errorf("error updating IAM User permissions boundary: %s", err)
			}
		} else {
			input := &iam.DeleteUserPermissionsBoundaryInput{
				UserName: aws.String(d.Id()),
			}
			_, err := iamconn.DeleteUserPermissionsBoundary(input)
			if err != nil {
				return fmt.Errorf("error deleting IAM User permissions boundary: %s", err)
			}
		}
	}

	if d.HasChange("tags") {
		// Reset all tags to empty set
		oraw, nraw := d.GetChange("tags")
		o := oraw.(map[string]interface{})
		n := nraw.(map[string]interface{})
		c, r := diffTagsIAM(tagsFromMapIAM(o), tagsFromMapIAM(n))

		if len(r) > 0 {
			_, err := iamconn.UntagUser(&iam.UntagUserInput{
				UserName: aws.String(d.Id()),
				TagKeys:  tagKeysIam(r),
			})
			if err != nil {
				return fmt.Errorf("error deleting IAM user tags: %s", err)
			}
		}

		if len(c) > 0 {
			input := &iam.TagUserInput{
				UserName: aws.String(d.Id()),
				Tags:     c,
			}
			_, err := iamconn.TagUser(input)
			if err != nil {
				return fmt.Errorf("error update IAM user tags: %s", err)
			}
		}
	}

	return resourceAwsIamUserRead(d, meta)
}

func resourceAwsIamUserDelete(d *schema.ResourceData, meta interface{}) error {
	iamconn := meta.(*AWSClient).iamconn

	// IAM Users must be removed from all groups before they can be deleted
	var groups []string
	listGroups := &iam.ListGroupsForUserInput{
		UserName: aws.String(d.Id()),
	}
	pageOfGroups := func(page *iam.ListGroupsForUserOutput, lastPage bool) (shouldContinue bool) {
		for _, g := range page.Groups {
			groups = append(groups, *g.GroupName)
		}
		return !lastPage
	}
	err := iamconn.ListGroupsForUserPages(listGroups, pageOfGroups)
	if err != nil {
		return fmt.Errorf("Error removing user %q from all groups: %s", d.Id(), err)
	}
	for _, g := range groups {
		// use iam group membership func to remove user from all groups
		log.Printf("[DEBUG] Removing IAM User %s from IAM Group %s", d.Id(), g)
		if err := removeUsersFromGroup(iamconn, []*string{aws.String(d.Id())}, g); err != nil {
			return err
		}
	}

	// All access keys, MFA devices and login profile for the user must be removed
	if d.Get("force_destroy").(bool) {

		err = deleteAwsIamUserAccessKeys(iamconn, d.Id())
		if err != nil {
			return err
		}

		err = deleteAwsIamUserSSHKeys(iamconn, d.Id())
		if err != nil {
			return err
		}

		err = deleteAwsIamUserMFADevices(iamconn, d.Id())
		if err != nil {
			return err
		}

		err = deleteAwsIamUserLoginProfile(iamconn, d.Id())
		if err != nil {
			return err
		}
	}

	deleteUserInput := &iam.DeleteUserInput{
		UserName: aws.String(d.Id()),
	}

	log.Println("[DEBUG] Delete IAM User request:", deleteUserInput)
	_, err = iamconn.DeleteUser(deleteUserInput)
	if err != nil {
		if isAWSErr(err, iam.ErrCodeNoSuchEntityException, "") {
			return nil
		}
		return fmt.Errorf("Error deleting IAM User %s: %s", d.Id(), err)
	}

	return nil
}

func validateAwsIamUserName(v interface{}, k string) (ws []string, errors []error) {
	value := v.(string)
	if !regexp.MustCompile(`^[0-9A-Za-z=,.@\-_+]+$`).MatchString(value) {
		errors = append(errors, fmt.Errorf(
			"only alphanumeric characters, hyphens, underscores, commas, periods, @ symbols, plus and equals signs allowed in %q: %q",
			k, value))
	}
	return
}

func deleteAwsIamUserSSHKeys(svc *iam.IAM, username string) error {
	var publicKeys []string
	var err error

	listSSHPublicKeys := &iam.ListSSHPublicKeysInput{
		UserName: aws.String(username),
	}
	pageOfListSSHPublicKeys := func(page *iam.ListSSHPublicKeysOutput, lastPage bool) (shouldContinue bool) {
		for _, k := range page.SSHPublicKeys {
			publicKeys = append(publicKeys, *k.SSHPublicKeyId)
		}
		return !lastPage
	}
	err = svc.ListSSHPublicKeysPages(listSSHPublicKeys, pageOfListSSHPublicKeys)
	if err != nil {
		return fmt.Errorf("Error removing public SSH keys of user %s: %s", username, err)
	}
	for _, k := range publicKeys {
		_, err := svc.DeleteSSHPublicKey(&iam.DeleteSSHPublicKeyInput{
			UserName:       aws.String(username),
			SSHPublicKeyId: aws.String(k),
		})
		if err != nil {
			return fmt.Errorf("Error deleting public SSH key %s: %s", k, err)
		}
	}

	return nil
}

func deleteAwsIamUserMFADevices(svc *iam.IAM, username string) error {
	var MFADevices []string
	var err error

	listMFADevices := &iam.ListMFADevicesInput{
		UserName: aws.String(username),
	}
	pageOfMFADevices := func(page *iam.ListMFADevicesOutput, lastPage bool) (shouldContinue bool) {
		for _, m := range page.MFADevices {
			MFADevices = append(MFADevices, *m.SerialNumber)
		}
		return !lastPage
	}
	err = svc.ListMFADevicesPages(listMFADevices, pageOfMFADevices)
	if err != nil {
		return fmt.Errorf("Error removing MFA devices of user %s: %s", username, err)
	}
	for _, m := range MFADevices {
		_, err := svc.DeactivateMFADevice(&iam.DeactivateMFADeviceInput{
			UserName:     aws.String(username),
			SerialNumber: aws.String(m),
		})
		if err != nil {
			return fmt.Errorf("Error deactivating MFA device %s: %s", m, err)
		}
	}

	return nil
}

func deleteAwsIamUserLoginProfile(svc *iam.IAM, username string) error {
	var err error
	err = resource.Retry(1*time.Minute, func() *resource.RetryError {
		_, err = svc.DeleteLoginProfile(&iam.DeleteLoginProfileInput{
			UserName: aws.String(username),
		})
		if err != nil {
			if isAWSErr(err, iam.ErrCodeNoSuchEntityException, "") {
				return nil
			}
			// EntityTemporarilyUnmodifiable: Login Profile for User XXX cannot be modified while login profile is being created.
			if isAWSErr(err, iam.ErrCodeEntityTemporarilyUnmodifiableException, "") {
				return resource.RetryableError(err)
			}
			return resource.NonRetryableError(err)
		}
		return nil
	})

	if err != nil {
		return fmt.Errorf("Error deleting Account Login Profile: %s", err)
	}

	return nil
}

func deleteAwsIamUserAccessKeys(svc *iam.IAM, username string) error {
	var accessKeys []string
	var err error
	listAccessKeys := &iam.ListAccessKeysInput{
		UserName: aws.String(username),
	}
	pageOfAccessKeys := func(page *iam.ListAccessKeysOutput, lastPage bool) (shouldContinue bool) {
		for _, k := range page.AccessKeyMetadata {
			accessKeys = append(accessKeys, *k.AccessKeyId)
		}
		return !lastPage
	}
	err = svc.ListAccessKeysPages(listAccessKeys, pageOfAccessKeys)
	if err != nil {
		return fmt.Errorf("Error removing access keys of user %s: %s", username, err)
	}
	for _, k := range accessKeys {
		_, err := svc.DeleteAccessKey(&iam.DeleteAccessKeyInput{
			UserName:    aws.String(username),
			AccessKeyId: aws.String(k),
		})
		if err != nil {
			return fmt.Errorf("Error deleting access key %s: %s", k, err)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package v2

import (
	"encoding/json"
	"io/ioutil"
	"path"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestAmbassadorConfigRoundTrip(t *testing.T) {
	var m []Module
	checkRoundtrip(t, "modules.json", &m)
}

func TestMappingRoundTrip(t *testing.T) {
	var m []Mapping
	checkRoundtrip(t, "mappings.json", &m)
}

func checkRoundtrip(t *testing.T, filename string, ptr interface{}) {
	bytes, err := ioutil.ReadFile(path.Join("testdata", filename))
	require.NoError(t, err)

	err = json.Unmarshal(bytes, ptr)
	require.NoError(t, err)

	var canonical interface{}
	err = json.Unmarshal(bytes, &canonical)
	require.NoError(t, err)

	assert.Equal(t, canonical, roundtrip(ptr))
}

func roundtrip(obj interface{}) (result interface{}) {
	bytes, err := json.Marshal(obj)
	if err != nil {
		panic(err)
	}

	err = json.Unmarshal(bytes, &result)
	if err != nil {
		panic(err)
	}

	return
}
<commit_msg>(from AES) Let roundtrip_test.go report JSON diffs, rather than Golang-structure syntax (courtesy of @LukeShu)<commit_after>package v2

import (
	"encoding/json"
	"io/ioutil"
	"path"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestAmbassadorConfigRoundTrip(t *testing.T) {
	var m []Module
	checkRoundtrip(t, "modules.json", &m)
}

func TestMappingRoundTrip(t *testing.T) {
	var m []Mapping
	checkRoundtrip(t, "mappings.json", &m)
}

func checkRoundtrip(t *testing.T, filename string, ptr interface{}) {
	bytes, err := ioutil.ReadFile(path.Join("testdata", filename))
	require.NoError(t, err)

	canonical := func() string {
		var untyped interface{}
		err = json.Unmarshal(bytes, &untyped)
		require.NoError(t, err)
		canonical, err := json.MarshalIndent(untyped, "", "\t")
		require.NoError(t, err)
		return string(canonical)
	}()

	actual := func() string {
		// Round-trip twice, to get map field ordering, instead of struct field ordering.

		// first
		err = json.Unmarshal(bytes, ptr)
		require.NoError(t, err)
		first, err := json.Marshal(ptr)
		require.NoError(t, err)

		// second
		var untyped interface{}
		err = json.Unmarshal(first, &untyped)
		require.NoError(t, err)
		second, err := json.MarshalIndent(untyped, "", "\t")
		require.NoError(t, err)

		return string(second)
	}()

	assert.Equal(t, canonical, actual)
}
<|endoftext|>


<commit_before>// Copyright 2018 The Hugo Authors. All rights reserved.
//
// 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 publisher

import (
	"errors"
	"io"
	"sync/atomic"

	"github.com/gohugoio/hugo/media"

	"github.com/gohugoio/hugo/minifiers"

	bp "github.com/gohugoio/hugo/bufferpool"
	"github.com/gohugoio/hugo/helpers"

	"github.com/spf13/afero"

	"github.com/gohugoio/hugo/output"
	"github.com/gohugoio/hugo/transform"
	"github.com/gohugoio/hugo/transform/livereloadinject"
	"github.com/gohugoio/hugo/transform/metainject"
	"github.com/gohugoio/hugo/transform/urlreplacers"
)

// Descriptor describes the needed publishing chain for an item.
type Descriptor struct {
	// The content to publish.
	Src io.Reader

	// The OutputFormat of the this content.
	OutputFormat output.Format

	// Where to publish this content. This is a filesystem-relative path.
	TargetPath string

	// Counter for the end build summary.
	StatCounter *uint64

	// Configuration that trigger pre-processing.
	// LiveReload script will be injected if this is > 0
	LiveReloadPort int

	// Enable to inject the Hugo generated tag in the header. Is currently only
	// injected on the home page for HTML type of output formats.
	AddHugoGeneratorTag bool

	// If set, will replace all relative URLs with this one.
	AbsURLPath string

	// Enable to minify the output using the OutputFormat defined above to
	// pick the correct minifier configuration.
	Minify bool
}

// DestinationPublisher is the default and currently only publisher in Hugo. This
// publisher prepares and publishes an item to the defined destination, e.g. /public.
type DestinationPublisher struct {
	fs     afero.Fs
	minify bool
	min    minifiers.Client
}

func NewDestinationPublisher(fs afero.Fs, outputFormats output.Formats, mediaTypes media.Types, minify bool) DestinationPublisher {
	pub := DestinationPublisher{fs: fs}
	if minify {
		pub.min = minifiers.New(mediaTypes, outputFormats)
		pub.minify = true
	}
	return pub
}

// Publish applies any relevant transformations and writes the file
// to its destination, e.g. /public.
func (p DestinationPublisher) Publish(d Descriptor) error {
	if d.TargetPath == "" {
		return errors.New("must provide a TargetPath")
	}

	src := d.Src

	transformers := p.createTransformerChain(d)

	if len(transformers) != 0 {
		b := bp.GetBuffer()
		defer bp.PutBuffer(b)

		if err := transformers.Apply(b, d.Src); err != nil {
			return err
		}

		// This is now what we write to disk.
		src = b
	}

	f, err := helpers.OpenFileForWriting(p.fs, d.TargetPath)
	if err != nil {
		return err
	}

	_, err = io.Copy(f, src)
	if err == nil && d.StatCounter != nil {
		atomic.AddUint64(d.StatCounter, uint64(1))
	}
	return err
}

// Publisher publishes a result file.
type Publisher interface {
	Publish(d Descriptor) error
}

// XML transformer := transform.New(urlreplacers.NewAbsURLInXMLTransformer(path))
func (p DestinationPublisher) createTransformerChain(f Descriptor) transform.Chain {
	transformers := transform.NewEmpty()

	isHTML := f.OutputFormat.IsHTML

	if f.AbsURLPath != "" {
		if isHTML {
			transformers = append(transformers, urlreplacers.NewAbsURLTransformer(f.AbsURLPath))
		} else {
			// Assume XML.
			transformers = append(transformers, urlreplacers.NewAbsURLInXMLTransformer(f.AbsURLPath))
		}
	}

	if isHTML {
		if f.LiveReloadPort > 0 {
			transformers = append(transformers, livereloadinject.New(f.LiveReloadPort))
		}

		// This is only injected on the home page.
		if f.AddHugoGeneratorTag {
			transformers = append(transformers, metainject.HugoGenerator)
		}

	}

	if p.minify {
		minifyTransformer := p.min.Transformer(f.OutputFormat.MediaType)
		if minifyTransformer != nil {
			transformers = append(transformers, minifyTransformer)
		}
	}

	return transformers

}
<commit_msg>publisher: Close file when done<commit_after>// Copyright 2018 The Hugo Authors. All rights reserved.
//
// 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 publisher

import (
	"errors"
	"io"
	"sync/atomic"

	"github.com/gohugoio/hugo/media"

	"github.com/gohugoio/hugo/minifiers"

	bp "github.com/gohugoio/hugo/bufferpool"
	"github.com/gohugoio/hugo/helpers"

	"github.com/spf13/afero"

	"github.com/gohugoio/hugo/output"
	"github.com/gohugoio/hugo/transform"
	"github.com/gohugoio/hugo/transform/livereloadinject"
	"github.com/gohugoio/hugo/transform/metainject"
	"github.com/gohugoio/hugo/transform/urlreplacers"
)

// Descriptor describes the needed publishing chain for an item.
type Descriptor struct {
	// The content to publish.
	Src io.Reader

	// The OutputFormat of the this content.
	OutputFormat output.Format

	// Where to publish this content. This is a filesystem-relative path.
	TargetPath string

	// Counter for the end build summary.
	StatCounter *uint64

	// Configuration that trigger pre-processing.
	// LiveReload script will be injected if this is > 0
	LiveReloadPort int

	// Enable to inject the Hugo generated tag in the header. Is currently only
	// injected on the home page for HTML type of output formats.
	AddHugoGeneratorTag bool

	// If set, will replace all relative URLs with this one.
	AbsURLPath string

	// Enable to minify the output using the OutputFormat defined above to
	// pick the correct minifier configuration.
	Minify bool
}

// DestinationPublisher is the default and currently only publisher in Hugo. This
// publisher prepares and publishes an item to the defined destination, e.g. /public.
type DestinationPublisher struct {
	fs     afero.Fs
	minify bool
	min    minifiers.Client
}

func NewDestinationPublisher(fs afero.Fs, outputFormats output.Formats, mediaTypes media.Types, minify bool) DestinationPublisher {
	pub := DestinationPublisher{fs: fs}
	if minify {
		pub.min = minifiers.New(mediaTypes, outputFormats)
		pub.minify = true
	}
	return pub
}

// Publish applies any relevant transformations and writes the file
// to its destination, e.g. /public.
func (p DestinationPublisher) Publish(d Descriptor) error {
	if d.TargetPath == "" {
		return errors.New("must provide a TargetPath")
	}

	src := d.Src

	transformers := p.createTransformerChain(d)

	if len(transformers) != 0 {
		b := bp.GetBuffer()
		defer bp.PutBuffer(b)

		if err := transformers.Apply(b, d.Src); err != nil {
			return err
		}

		// This is now what we write to disk.
		src = b
	}

	f, err := helpers.OpenFileForWriting(p.fs, d.TargetPath)
	if err != nil {
		return err
	}
	defer f.Close()

	_, err = io.Copy(f, src)
	if err == nil && d.StatCounter != nil {
		atomic.AddUint64(d.StatCounter, uint64(1))
	}
	return err
}

// Publisher publishes a result file.
type Publisher interface {
	Publish(d Descriptor) error
}

// XML transformer := transform.New(urlreplacers.NewAbsURLInXMLTransformer(path))
func (p DestinationPublisher) createTransformerChain(f Descriptor) transform.Chain {
	transformers := transform.NewEmpty()

	isHTML := f.OutputFormat.IsHTML

	if f.AbsURLPath != "" {
		if isHTML {
			transformers = append(transformers, urlreplacers.NewAbsURLTransformer(f.AbsURLPath))
		} else {
			// Assume XML.
			transformers = append(transformers, urlreplacers.NewAbsURLInXMLTransformer(f.AbsURLPath))
		}
	}

	if isHTML {
		if f.LiveReloadPort > 0 {
			transformers = append(transformers, livereloadinject.New(f.LiveReloadPort))
		}

		// This is only injected on the home page.
		if f.AddHugoGeneratorTag {
			transformers = append(transformers, metainject.HugoGenerator)
		}

	}

	if p.minify {
		minifyTransformer := p.min.Transformer(f.OutputFormat.MediaType)
		if minifyTransformer != nil {
			transformers = append(transformers, minifyTransformer)
		}
	}

	return transformers

}
<|endoftext|>


<commit_before>package mknod

import (
	"flag"
	"os"
	"syscall"
	"strings"
)

var (
	flagSet   = flag.NewFlagSet("mknod", flag.PanicOnError)
	majorFlag = flagSet.Int("major", -1, "Major number of the block device")
	minorFlag = flagSet.Int("minor", -1, "Minor number of the block device")
	typeFlag  = flagSet.String("type", "", "Type of the node to create (i.e. socket, link, regular, block, directory, character, fifo)")
	modeFlag  = flagSet.Int("mode", 0644, "Mode to create the node with")
	helpFlag  = flagSet.Bool("help", false, "Show this help")

	typemap = map[string]uint32{
		"socket":    syscall.S_IFSOCK,
		"link":      syscall.S_IFLNK,
		"regular":   syscall.S_IFREG,
		"block":     syscall.S_IFBLK,
		"directory": syscall.S_IFDIR,
		"character": syscall.S_IFCHR,
		"fifo":      syscall.S_IFIFO,
	}
)

func Mknod(call []string) os.Error {
	e := flagSet.Parse(call[1:])
	if e != nil {
		return e
	}

	if flagSet.NArg() <= 0 || *helpFlag {
		println("`mknod` [options] <file>")
		flagSet.PrintDefaults()
		return nil
	}

	mode, ok := typemap[strings.ToLower(*typeFlag)]
	if !ok {
		return os.NewError("Invalid node type \"" + *typeFlag + "\"")
	}

	if mode == syscall.S_IFBLK && (*majorFlag == -1 || *minorFlag == -1) {
		return os.NewError("When creating a block device, both minor and major number have to be given")
	}
	mode |= uint32(*modeFlag)

	errno := syscall.Mknod(flagSet.Arg(0), mode, *majorFlag<<16|*minorFlag)
	if errno != 0 {
		return os.NewError(syscall.Errstr(errno))
	}

	return nil
}
<commit_msg>Mknod: Changed mode flag handling to octal<commit_after>package mknod

import (
	"flag"
	"os"
	"syscall"
	"strings"
	"strconv"
)

var (
	flagSet   = flag.NewFlagSet("mknod", flag.PanicOnError)
	majorFlag = flagSet.Int("major", -1, "Major number of the block device")
	minorFlag = flagSet.Int("minor", -1, "Minor number of the block device")
	typeFlag  = flagSet.String("type", "", "Type of the node to create (i.e. socket, link, regular, block, directory, character, fifo)")
	modeFlag  = flagSet.String("mode", "644", "Mode (in octal) to create the node with")
	helpFlag  = flagSet.Bool("help", false, "Show this help")

	typemap = map[string]uint32{
		"socket":    syscall.S_IFSOCK,
		"link":      syscall.S_IFLNK,
		"regular":   syscall.S_IFREG,
		"block":     syscall.S_IFBLK,
		"directory": syscall.S_IFDIR,
		"character": syscall.S_IFCHR,
		"fifo":      syscall.S_IFIFO,
	}
)

func Mknod(call []string) os.Error {
	e := flagSet.Parse(call[1:])
	if e != nil {
		return e
	}

	if flagSet.NArg() <= 0 || *helpFlag {
		println("`mknod` [options] <file>")
		flagSet.PrintDefaults()
		return nil
	}

	mode, ok := typemap[strings.ToLower(*typeFlag)]
	if !ok {
		return os.NewError("Invalid node type \"" + *typeFlag + "\"")
	}

	if mode == syscall.S_IFBLK && (*majorFlag == -1 || *minorFlag == -1) {
		return os.NewError("When creating a block device, both minor and major number have to be given")
	}

	fmode, e := strconv.Btoui64(*modeFlag, 8)
	if e != nil {
		return e
	}
	mode |= uint32(fmode)

	errno := syscall.Mknod(flagSet.Arg(0), mode, *majorFlag<<16|*minorFlag)
	if errno != 0 {
		return os.NewError(syscall.Errstr(errno))
	}

	return nil
}
<|endoftext|>


<commit_before>// +build ignore

package mp

// #include <vlc/vlc.h>
// #include <stdlib.h>
// #cgo LDFLAGS: -lvlc
//
// extern void vlc_callback_helper_go(struct libvlc_event_t *event, void *userdata);
//
// static inline void callback_helper(const struct libvlc_event_t *event, void *userdata) {
//     /* wrap it here to get rid of the 'const' parameter which doesn't exist in Go */
//     vlc_callback_helper_go((struct libvlc_event_t*)event, userdata);
// }
// static inline libvlc_callback_t callback_helper_var() {
//     return callback_helper;
// }
import "C"
import "unsafe"

import (
	"fmt"
	"time"
)

type VLC struct {
	commandChan chan func(*vlcInstance)
}

// this data is separate to ensure it is only used synchronously
type vlcInstance struct {
	instance  *C.libvlc_instance_t
	player    *C.libvlc_media_player_t
	eventChan chan State
	isPlaying bool
}

type vlcEvent struct {
	id        int
	eventType C.libvlc_event_type_t
	callback  func()
}

// store event data here so the garbage collector doesn't trash them
var vlcEvents = make(map[int]*vlcEvent)
var vlcNextEventId int

//export vlc_callback_helper_go
func vlc_callback_helper_go(event *C.struct_libvlc_event_t, userdata unsafe.Pointer) {
	eventData := (*vlcEvent)(userdata)
	if event._type != C.libvlc_MediaPlayerTimeChanged { // suppress this noisy event
		fmt.Println(time.Now().Format("15:04:05.000"), "vlc event:", C.GoString(C.libvlc_event_type_name(C.libvlc_event_type_t(event._type))))
	}
	eventData.callback() // Yeah! We're finally running our callback!
}

func (v *VLC) initialize() chan State {

	i := vlcInstance{}
	i.instance = C.libvlc_new(0, nil)
	if i.instance == nil {
		panic("C.libvlc_new returned NULL")
	}
	i.player = C.libvlc_media_player_new(i.instance)
	if i.player == nil {
		panic("C.libvlc_media_player_new returned NULL")
	}

	v.commandChan = make(chan func(*vlcInstance))
	i.eventChan = make(chan State)

	eventManager := C.libvlc_media_player_event_manager(i.player)
	// all empty event handlers are there just to trigger the log
	v.addEvent(eventManager, C.libvlc_MediaPlayerMediaChanged, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerTimeChanged, func() {
		if !i.isPlaying {
			i.isPlaying = true
			i.eventChan <- STATE_PLAYING
		}
	})
	v.addEvent(eventManager, C.libvlc_MediaPlayerEncounteredError, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerOpening, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerBuffering, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerPlaying, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerPaused, func() {
		i.isPlaying = false
		i.eventChan <- STATE_PAUSED
	})
	v.addEvent(eventManager, C.libvlc_MediaPlayerStopped, func() {
		i.isPlaying = false
		i.eventChan <- STATE_STOPPED
	})
	v.addEvent(eventManager, C.libvlc_MediaPlayerEndReached, func() {
		i.isPlaying = false
		i.eventChan <- STATE_STOPPED
	})

	go v.run(&i)

	return i.eventChan
}

func (v *VLC) run(i *vlcInstance) {

	for {
		c, ok := <-v.commandChan;

		if !ok {
			C.libvlc_media_player_release(i.player)
			i.player = nil
			C.libvlc_release(i.instance)
			i.instance = nil
			// channel is closed when player must quit

			close(i.eventChan)
			return
		}

		c(i)
	}
}

func (v *VLC) quit() {
	// signal the end of the player
	// Don't allow new commands to be sent
	close(v.commandChan)
}

func (v *VLC) play(stream string, position time.Duration) {
	v.commandChan <- func(i *vlcInstance) {
		cStream := C.CString(stream)
		defer C.free(unsafe.Pointer(cStream))

		media := C.libvlc_media_new_location(i.instance, cStream)
		defer C.libvlc_media_release(media)

		C.libvlc_media_player_set_media(i.player, media)

		// TODO seek to position if needed

		v.checkError(C.libvlc_media_player_play(i.player))
	}
}

func (v *VLC) pause() {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_set_pause(i.player, 1)
	}
}

func (v *VLC) resume() {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_set_pause(i.player, 0)
	}
}

func (v *VLC) getPosition() time.Duration {
	posChan := make(chan time.Duration)
	v.commandChan <- func(i *vlcInstance) {
		position := C.libvlc_media_player_get_time(i.player)
		if position == -1 {
			panic("there is no media while getting position")
		}
		posChan <- time.Duration(position) * time.Millisecond
	}
	return <-posChan
}

func (v *VLC) setPosition(position time.Duration) {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_set_time(i.player, C.libvlc_time_t(position.Seconds()*1000+0.5))
	}
}

func (v *VLC) getVolume() int {
	volumeChan := make(chan int)
	v.commandChan <- func(i *vlcInstance) {
		volume := C.libvlc_audio_get_volume(i.player)
		volumeChan <- int(volume)
	}
	return <-volumeChan
}

func (v *VLC) setVolume(volume int) {
	v.commandChan <- func(i *vlcInstance) {
		v.checkError(C.libvlc_audio_set_volume(i.player, C.int(volume)))
	}
}

func (v *VLC) stop() {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_stop(i.player)
	}
}

func (v *VLC) checkError(status C.int) {
	if status < 0 {
		panic(fmt.Sprintf("libvlc error: %s (%d)\n", C.GoString(C.libvlc_errmsg()), int(status)))
	}
}

func (v *VLC) addEvent(manager *C.libvlc_event_manager_t, eventType C.libvlc_event_type_t, callback func()) {
	id := vlcNextEventId
	vlcNextEventId++

	event := &vlcEvent{id, eventType, callback}
	vlcEvents[id] = event

	v.checkError(C.libvlc_event_attach(manager, eventType, C.callback_helper_var(), unsafe.Pointer(event)))
}
<commit_msg>VLC player: seek to position if needed when starting playback<commit_after>// +build ignore

package mp

// #include <vlc/vlc.h>
// #include <stdlib.h>
// #cgo LDFLAGS: -lvlc
//
// extern void vlc_callback_helper_go(struct libvlc_event_t *event, void *userdata);
//
// static inline void callback_helper(const struct libvlc_event_t *event, void *userdata) {
//     /* wrap it here to get rid of the 'const' parameter which doesn't exist in Go */
//     vlc_callback_helper_go((struct libvlc_event_t*)event, userdata);
// }
// static inline libvlc_callback_t callback_helper_var() {
//     return callback_helper;
// }
import "C"
import "unsafe"

import (
	"fmt"
	"time"
)

type VLC struct {
	commandChan chan func(*vlcInstance)
}

// this data is separate to ensure it is only used synchronously
type vlcInstance struct {
	instance  *C.libvlc_instance_t
	player    *C.libvlc_media_player_t
	eventChan chan State
	isPlaying bool
}

type vlcEvent struct {
	id        int
	eventType C.libvlc_event_type_t
	callback  func()
}

// store event data here so the garbage collector doesn't trash them
var vlcEvents = make(map[int]*vlcEvent)
var vlcNextEventId int

//export vlc_callback_helper_go
func vlc_callback_helper_go(event *C.struct_libvlc_event_t, userdata unsafe.Pointer) {
	eventData := (*vlcEvent)(userdata)
	if event._type != C.libvlc_MediaPlayerTimeChanged { // suppress this noisy event
		fmt.Println(time.Now().Format("15:04:05.000"), "vlc event:", C.GoString(C.libvlc_event_type_name(C.libvlc_event_type_t(event._type))))
	}
	eventData.callback() // Yeah! We're finally running our callback!
}

func (v *VLC) initialize() chan State {

	i := vlcInstance{}
	i.instance = C.libvlc_new(0, nil)
	if i.instance == nil {
		panic("C.libvlc_new returned NULL")
	}
	i.player = C.libvlc_media_player_new(i.instance)
	if i.player == nil {
		panic("C.libvlc_media_player_new returned NULL")
	}

	v.commandChan = make(chan func(*vlcInstance))
	i.eventChan = make(chan State)

	eventManager := C.libvlc_media_player_event_manager(i.player)
	// all empty event handlers are there just to trigger the log
	v.addEvent(eventManager, C.libvlc_MediaPlayerMediaChanged, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerTimeChanged, func() {
		if !i.isPlaying {
			i.isPlaying = true
			i.eventChan <- STATE_PLAYING
		}
	})
	v.addEvent(eventManager, C.libvlc_MediaPlayerEncounteredError, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerOpening, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerBuffering, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerPlaying, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerPaused, func() {
		i.isPlaying = false
		i.eventChan <- STATE_PAUSED
	})
	v.addEvent(eventManager, C.libvlc_MediaPlayerStopped, func() {
		i.isPlaying = false
		i.eventChan <- STATE_STOPPED
	})
	v.addEvent(eventManager, C.libvlc_MediaPlayerEndReached, func() {
		i.isPlaying = false
		i.eventChan <- STATE_STOPPED
	})

	go v.run(&i)

	return i.eventChan
}

func (v *VLC) run(i *vlcInstance) {

	for {
		c, ok := <-v.commandChan;

		if !ok {
			C.libvlc_media_player_release(i.player)
			i.player = nil
			C.libvlc_release(i.instance)
			i.instance = nil
			// channel is closed when player must quit

			close(i.eventChan)
			return
		}

		c(i)
	}
}

func (v *VLC) quit() {
	// signal the end of the player
	// Don't allow new commands to be sent
	close(v.commandChan)
}

func (v *VLC) play(stream string, position time.Duration) {
	v.commandChan <- func(i *vlcInstance) {
		cStream := C.CString(stream)
		defer C.free(unsafe.Pointer(cStream))

		media := C.libvlc_media_new_location(i.instance, cStream)
		defer C.libvlc_media_release(media)

		C.libvlc_media_player_set_media(i.player, media)

		v.checkError(C.libvlc_media_player_play(i.player))

		if position != 0 {
			C.libvlc_media_player_set_time(i.player, C.libvlc_time_t(position.Seconds()*1000+0.5))
		}
	}
}

func (v *VLC) pause() {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_set_pause(i.player, 1)
	}
}

func (v *VLC) resume() {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_set_pause(i.player, 0)
	}
}

func (v *VLC) getPosition() time.Duration {
	posChan := make(chan time.Duration)
	v.commandChan <- func(i *vlcInstance) {
		position := C.libvlc_media_player_get_time(i.player)
		if position == -1 {
			panic("there is no media while getting position")
		}
		posChan <- time.Duration(position) * time.Millisecond
	}
	return <-posChan
}

func (v *VLC) setPosition(position time.Duration) {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_set_time(i.player, C.libvlc_time_t(position.Seconds()*1000+0.5))
	}
}

func (v *VLC) getVolume() int {
	volumeChan := make(chan int)
	v.commandChan <- func(i *vlcInstance) {
		volume := C.libvlc_audio_get_volume(i.player)
		volumeChan <- int(volume)
	}
	return <-volumeChan
}

func (v *VLC) setVolume(volume int) {
	v.commandChan <- func(i *vlcInstance) {
		v.checkError(C.libvlc_audio_set_volume(i.player, C.int(volume)))
	}
}

func (v *VLC) stop() {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_stop(i.player)
	}
}

func (v *VLC) checkError(status C.int) {
	if status < 0 {
		panic(fmt.Sprintf("libvlc error: %s (%d)\n", C.GoString(C.libvlc_errmsg()), int(status)))
	}
}

func (v *VLC) addEvent(manager *C.libvlc_event_manager_t, eventType C.libvlc_event_type_t, callback func()) {
	id := vlcNextEventId
	vlcNextEventId++

	event := &vlcEvent{id, eventType, callback}
	vlcEvents[id] = event

	v.checkError(C.libvlc_event_attach(manager, eventType, C.callback_helper_var(), unsafe.Pointer(event)))
}
<|endoftext|>


<commit_before>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package queue

import (
	. "launchpad.net/gocheck"
	"sync/atomic"
	"time"
)

type ExecutorSuite struct{}

var _ = Suite(&ExecutorSuite{})

func dumb() {
	time.Sleep(1e3)
}

func (s *ExecutorSuite) TestStart(c *C) {
	var ct counter
	h1 := executor{inner: func() { ct.increment() }}
	h1.Start()
	c.Assert(h1.state, Equals, running)
	h1.Stop()
	h1.Wait()
	c.Assert(ct.value(), Not(Equals), 0)
}

func (s *ExecutorSuite) TestPreempt(c *C) {
	h1 := executor{inner: dumb}
	h2 := executor{inner: dumb}
	h3 := executor{inner: dumb}
	h1.Start()
	h2.Start()
	h3.Start()
	Preempt()
	c.Assert(h1.state, Equals, stopped)
	c.Assert(h2.state, Equals, stopped)
	c.Assert(h3.state, Equals, stopped)
}

func (s *ExecutorSuite) TestStopNotRunningExecutor(c *C) {
	h := executor{inner: dumb}
	err := h.Stop()
	c.Assert(err, NotNil)
	c.Assert(err.Error(), Equals, "Not running.")
}

type counter struct {
	v int32
}

func (c *counter) increment() {
	old := atomic.LoadInt32(&c.v)
	swapped := atomic.CompareAndSwapInt32(&c.v, old, old+1)
	for !swapped {
		old = atomic.LoadInt32(&c.v)
		swapped = atomic.CompareAndSwapInt32(&c.v, old, old+1)
	}
}

func (c *counter) value() int32 {
	return atomic.LoadInt32(&c.v)
}
<commit_msg>queue: added compile-time check for interface implementation<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package queue

import (
	. "launchpad.net/gocheck"
	"sync/atomic"
	"time"
)

type ExecutorSuite struct{}

var _ = Suite(&ExecutorSuite{})

func dumb() {
	time.Sleep(1e3)
}

func (s *ExecutorSuite) TestStart(c *C) {
	var ct counter
	h1 := executor{inner: func() { ct.increment() }}
	h1.Start()
	c.Assert(h1.state, Equals, running)
	h1.Stop()
	h1.Wait()
	c.Assert(ct.value(), Not(Equals), 0)
}

func (s *ExecutorSuite) TestPreempt(c *C) {
	h1 := executor{inner: dumb}
	h2 := executor{inner: dumb}
	h3 := executor{inner: dumb}
	h1.Start()
	h2.Start()
	h3.Start()
	Preempt()
	c.Assert(h1.state, Equals, stopped)
	c.Assert(h2.state, Equals, stopped)
	c.Assert(h3.state, Equals, stopped)
}

func (s *ExecutorSuite) TestStopNotRunningExecutor(c *C) {
	h := executor{inner: dumb}
	err := h.Stop()
	c.Assert(err, NotNil)
	c.Assert(err.Error(), Equals, "Not running.")
}

func (s *ExecutorSuite) TestExecutorImplementsHandler(c *C) {
	var _ Handler = &executor{}
}

type counter struct {
	v int32
}

func (c *counter) increment() {
	old := atomic.LoadInt32(&c.v)
	swapped := atomic.CompareAndSwapInt32(&c.v, old, old+1)
	for !swapped {
		old = atomic.LoadInt32(&c.v)
		swapped = atomic.CompareAndSwapInt32(&c.v, old, old+1)
	}
}

func (c *counter) value() int32 {
	return atomic.LoadInt32(&c.v)
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors.

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 jsonpath

import "fmt"

// NodeType identifies the type of a parse tree node.
type NodeType int

// Type returns itself and provides an easy default implementation
func (t NodeType) Type() NodeType {
	return t
}

func (t NodeType) String() string {
	return NodeTypeName[t]
}

const (
	NodeText NodeType = iota
	NodeArray
	NodeList
	NodeField
	NodeIdentifier
	NodeFilter
	NodeInt
	NodeFloat
	NodeWildcard
	NodeRecursive
	NodeUnion
	NodeBool
)

var NodeTypeName = map[NodeType]string{
	NodeText:       "NodeText",
	NodeArray:      "NodeArray",
	NodeList:       "NodeList",
	NodeField:      "NodeField",
	NodeIdentifier: "NodeIdentifier",
	NodeFilter:     "NodeFilter",
	NodeInt:        "NodeInt",
	NodeFloat:      "NodeFloat",
	NodeWildcard:   "NodeWildcard",
	NodeRecursive:  "NodeRecursive",
	NodeUnion:      "NodeUnion",
	NodeBool:       "NodeBool",
}

type Node interface {
	Type() NodeType
	String() string
}

// ListNode holds a sequence of nodes.
type ListNode struct {
	NodeType
	Nodes []Node // The element nodes in lexical order.
}

func newList() *ListNode {
	return &ListNode{NodeType: NodeList}
}

func (l *ListNode) append(n Node) {
	l.Nodes = append(l.Nodes, n)
}

func (l *ListNode) String() string {
	return fmt.Sprintf("%s", l.Type())
}

// TextNode holds plain text.
type TextNode struct {
	NodeType
	Text string // The text; may span newlines.
}

func newText(text string) *TextNode {
	return &TextNode{NodeType: NodeText, Text: text}
}

func (t *TextNode) String() string {
	return fmt.Sprintf("%s: %s", t.Type(), t.Text)
}

// FieldNode holds field of struct
type FieldNode struct {
	NodeType
	Value string
}

func newField(value string) *FieldNode {
	return &FieldNode{NodeType: NodeField, Value: value}
}

func (f *FieldNode) String() string {
	return fmt.Sprintf("%s: %s", f.Type(), f.Value)
}

// IdentifierNode holds an identifier
type IdentifierNode struct {
	NodeType
	Name string
}

func newIdentifier(value string) *IdentifierNode {
	return &IdentifierNode{
		NodeType: NodeIdentifier,
		Name:     value,
	}
}

func (f *IdentifierNode) String() string {
	return fmt.Sprintf("%s: %s", f.Type(), f.Name)
}

// ParamsEntry holds param information for ArrayNode
type ParamsEntry struct {
	Value int
	Known bool // whether the value is known when parse it
}

// ArrayNode holds start, end, step information for array index selection
type ArrayNode struct {
	NodeType
	Params [3]ParamsEntry // start, end, step
}

func newArray(params [3]ParamsEntry) *ArrayNode {
	return &ArrayNode{
		NodeType: NodeArray,
		Params:   params,
	}
}

func (a *ArrayNode) String() string {
	return fmt.Sprintf("%s: %v", a.Type(), a.Params)
}

// FilterNode holds operand and operator information for filter
type FilterNode struct {
	NodeType
	Left     *ListNode
	Right    *ListNode
	Operator string
}

func newFilter(left, right *ListNode, operator string) *FilterNode {
	return &FilterNode{
		NodeType: NodeFilter,
		Left:     left,
		Right:    right,
		Operator: operator,
	}
}

func (f *FilterNode) String() string {
	return fmt.Sprintf("%s: %s %s %s", f.Type(), f.Left, f.Operator, f.Right)
}

// IntNode holds integer value
type IntNode struct {
	NodeType
	Value int
}

func newInt(num int) *IntNode {
	return &IntNode{NodeType: NodeInt, Value: num}
}

func (i *IntNode) String() string {
	return fmt.Sprintf("%s: %d", i.Type(), i.Value)
}

// FloatNode holds float value
type FloatNode struct {
	NodeType
	Value float64
}

func newFloat(num float64) *FloatNode {
	return &FloatNode{NodeType: NodeFloat, Value: num}
}

func (i *FloatNode) String() string {
	return fmt.Sprintf("%s: %f", i.Type(), i.Value)
}

// WildcardNode means a wildcard
type WildcardNode struct {
	NodeType
}

func newWildcard() *WildcardNode {
	return &WildcardNode{NodeType: NodeWildcard}
}

func (i *WildcardNode) String() string {
	return fmt.Sprintf("%s", i.Type())
}

// RecursiveNode means a recursive descent operator
type RecursiveNode struct {
	NodeType
}

func newRecursive() *RecursiveNode {
	return &RecursiveNode{NodeType: NodeRecursive}
}

func (r *RecursiveNode) String() string {
	return fmt.Sprintf("%s", r.Type())
}

// UnionNode is union of ListNode
type UnionNode struct {
	NodeType
	Nodes []*ListNode
}

func newUnion(nodes []*ListNode) *UnionNode {
	return &UnionNode{NodeType: NodeUnion, Nodes: nodes}
}

func (u *UnionNode) String() string {
	return fmt.Sprintf("%s", u.Type())
}

// BoolNode holds bool value
type BoolNode struct {
	NodeType
	Value bool
}

func newBool(value bool) *BoolNode {
	return &BoolNode{NodeType: NodeBool, Value: value}
}

func (b *BoolNode) String() string {
	return fmt.Sprintf("%s: %t", b.Type(), b.Value)
}
<commit_msg>replace fmt.Sprintf(%s, i.Type()) with i.Type().String()<commit_after>/*
Copyright 2015 The Kubernetes Authors.

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 jsonpath

import "fmt"

// NodeType identifies the type of a parse tree node.
type NodeType int

// Type returns itself and provides an easy default implementation
func (t NodeType) Type() NodeType {
	return t
}

func (t NodeType) String() string {
	return NodeTypeName[t]
}

const (
	NodeText NodeType = iota
	NodeArray
	NodeList
	NodeField
	NodeIdentifier
	NodeFilter
	NodeInt
	NodeFloat
	NodeWildcard
	NodeRecursive
	NodeUnion
	NodeBool
)

var NodeTypeName = map[NodeType]string{
	NodeText:       "NodeText",
	NodeArray:      "NodeArray",
	NodeList:       "NodeList",
	NodeField:      "NodeField",
	NodeIdentifier: "NodeIdentifier",
	NodeFilter:     "NodeFilter",
	NodeInt:        "NodeInt",
	NodeFloat:      "NodeFloat",
	NodeWildcard:   "NodeWildcard",
	NodeRecursive:  "NodeRecursive",
	NodeUnion:      "NodeUnion",
	NodeBool:       "NodeBool",
}

type Node interface {
	Type() NodeType
	String() string
}

// ListNode holds a sequence of nodes.
type ListNode struct {
	NodeType
	Nodes []Node // The element nodes in lexical order.
}

func newList() *ListNode {
	return &ListNode{NodeType: NodeList}
}

func (l *ListNode) append(n Node) {
	l.Nodes = append(l.Nodes, n)
}

func (l *ListNode) String() string {
	return l.Type().String()
}

// TextNode holds plain text.
type TextNode struct {
	NodeType
	Text string // The text; may span newlines.
}

func newText(text string) *TextNode {
	return &TextNode{NodeType: NodeText, Text: text}
}

func (t *TextNode) String() string {
	return fmt.Sprintf("%s: %s", t.Type(), t.Text)
}

// FieldNode holds field of struct
type FieldNode struct {
	NodeType
	Value string
}

func newField(value string) *FieldNode {
	return &FieldNode{NodeType: NodeField, Value: value}
}

func (f *FieldNode) String() string {
	return fmt.Sprintf("%s: %s", f.Type(), f.Value)
}

// IdentifierNode holds an identifier
type IdentifierNode struct {
	NodeType
	Name string
}

func newIdentifier(value string) *IdentifierNode {
	return &IdentifierNode{
		NodeType: NodeIdentifier,
		Name:     value,
	}
}

func (f *IdentifierNode) String() string {
	return fmt.Sprintf("%s: %s", f.Type(), f.Name)
}

// ParamsEntry holds param information for ArrayNode
type ParamsEntry struct {
	Value int
	Known bool // whether the value is known when parse it
}

// ArrayNode holds start, end, step information for array index selection
type ArrayNode struct {
	NodeType
	Params [3]ParamsEntry // start, end, step
}

func newArray(params [3]ParamsEntry) *ArrayNode {
	return &ArrayNode{
		NodeType: NodeArray,
		Params:   params,
	}
}

func (a *ArrayNode) String() string {
	return fmt.Sprintf("%s: %v", a.Type(), a.Params)
}

// FilterNode holds operand and operator information for filter
type FilterNode struct {
	NodeType
	Left     *ListNode
	Right    *ListNode
	Operator string
}

func newFilter(left, right *ListNode, operator string) *FilterNode {
	return &FilterNode{
		NodeType: NodeFilter,
		Left:     left,
		Right:    right,
		Operator: operator,
	}
}

func (f *FilterNode) String() string {
	return fmt.Sprintf("%s: %s %s %s", f.Type(), f.Left, f.Operator, f.Right)
}

// IntNode holds integer value
type IntNode struct {
	NodeType
	Value int
}

func newInt(num int) *IntNode {
	return &IntNode{NodeType: NodeInt, Value: num}
}

func (i *IntNode) String() string {
	return fmt.Sprintf("%s: %d", i.Type(), i.Value)
}

// FloatNode holds float value
type FloatNode struct {
	NodeType
	Value float64
}

func newFloat(num float64) *FloatNode {
	return &FloatNode{NodeType: NodeFloat, Value: num}
}

func (i *FloatNode) String() string {
	return fmt.Sprintf("%s: %f", i.Type(), i.Value)
}

// WildcardNode means a wildcard
type WildcardNode struct {
	NodeType
}

func newWildcard() *WildcardNode {
	return &WildcardNode{NodeType: NodeWildcard}
}

func (i *WildcardNode) String() string {
	return i.Type().String()
}

// RecursiveNode means a recursive descent operator
type RecursiveNode struct {
	NodeType
}

func newRecursive() *RecursiveNode {
	return &RecursiveNode{NodeType: NodeRecursive}
}

func (r *RecursiveNode) String() string {
	return r.Type().String()
}

// UnionNode is union of ListNode
type UnionNode struct {
	NodeType
	Nodes []*ListNode
}

func newUnion(nodes []*ListNode) *UnionNode {
	return &UnionNode{NodeType: NodeUnion, Nodes: nodes}
}

func (u *UnionNode) String() string {
	return u.Type().String()
}

// BoolNode holds bool value
type BoolNode struct {
	NodeType
	Value bool
}

func newBool(value bool) *BoolNode {
	return &BoolNode{NodeType: NodeBool, Value: value}
}

func (b *BoolNode) String() string {
	return fmt.Sprintf("%s: %t", b.Type(), b.Value)
}
<|endoftext|>


<commit_before>package report

import (
	"fmt"
	"strconv"
	"strings"
	"time"
)

// ReportParams is holder for common parameters across load and query reports
type ReportParams struct {
	DBType             string
	ReportDatabaseName string
	ReportHost         string
	ReportUser         string
	ReportPassword     string
	ReportTags         [][2]string
	Hostname           string
	DestinationUrl     string
	Workers            int
	ItemLimit          int
}

// LoadReportParams is holder of bulk load specific parameters
type LoadReportParams struct {
	ReportParams

	IsGzip    bool
	BatchSize int
}

// type QueryReportParams is holder of bulk query specific parameters
type QueryReportParams struct {
	ReportParams

	BurnIn int64
}

// ReportLoadResult send results from bulk load to an influxdb according to the given parameters
func ReportLoadResult(params *LoadReportParams, totalItems int64, valueRate float64, inputSpeed float64, loadDuration time.Duration) error {

	c, p, err := initReport(&params.ReportParams, "load_benchmarks")
	if err != nil {
		return err
	}

	p.AddTag("gzip", strconv.FormatBool(params.IsGzip))
	p.AddTag("batch_size", strconv.Itoa(params.BatchSize))

	p.AddInt64Field("total_items", totalItems)
	p.AddFloat64Field("values_rate", valueRate)
	p.AddFloat64Field("input_rate", inputSpeed)
	p.AddFloat64Field("duration", loadDuration.Seconds())

	err = finishReport(c, p)

	return err

}

// initReport prepares a Point and a Collector instance for sending a result report
func initReport(params *ReportParams, measurement string) (*Collector, *Point, error) {
	var authString string
	if len(params.ReportUser) > 0 {
		authString = fmt.Sprintf("%s:%s", params.ReportUser, params.ReportPassword)
	}
	c := NewCollector(params.ReportHost, params.ReportDatabaseName, authString)

	err := c.CreateDatabase()
	if err != nil {
		return nil, nil, err
	}

	p := GetPointFromGlobalPool()
	p.Init(measurement, time.Now().UnixNano())

	for _, tagpair := range params.ReportTags {
		p.AddTag(tagpair[0], tagpair[1])
	}

	p.AddTag("client_hostname", params.Hostname)
	p.AddTag("server_url", strings.Replace(params.DestinationUrl, ",", "\\,", -1))
	if len(params.DBType) > 0 {
		p.AddTag("database_type", params.DBType)
	}
	p.AddTag("item_limit", strconv.Itoa(params.ItemLimit))
	p.AddTag("workers", strconv.Itoa(params.Workers))

	return c, p, nil
}

//finishReport finalizes sending result report and cleaning data
func finishReport(c *Collector, p *Point) error {
	c.Put(p)
	c.PrepBatch()

	err := c.SendBatch()

	PutPointIntoGlobalPool(p)

	return err
}

const escapes = "\t\n\f\r ,="

var escaper = strings.NewReplacer(
	"\t", `\t`,
	"\n", `\n`,
	"\f", `\f`,
	"\r", `\r`,
	`,`, `\,`,
	` `, `\ `,
	`=`, `\=`,
)

func Escape(s string) string {
	if strings.ContainsAny(s, escapes) {
		return escaper.Replace(s)
	} else {
		return s
	}
}

//ReportQueryResult send result from bulk query benchmark to an influxdb according to the given parameters
func ReportQueryResult(params *QueryReportParams, queryName string, minQueryTime float64, meanQueryTime float64, maxQueryTime float64, totalQueries int64, movingMean float64, queryDuration time.Duration) error {

	c, p, err := initReport(&params.ReportParams, "query_benchmarks")
	if err != nil {
		return err
	}

	p.AddTag("burn_in", strconv.Itoa(int(params.BurnIn)))
	p.AddTag("query_name", Escape(queryName))

	p.AddFloat64Field("min_time", minQueryTime)
	if minQueryTime > 0 {
		p.AddFloat64Field("min_rate", 1000/minQueryTime)
	} else {
		p.AddFloat64Field("min_rate", -1)
	}
	p.AddFloat64Field("mean_time", meanQueryTime)
	if meanQueryTime > 0 {
		p.AddFloat64Field("mean_rate", 1000/meanQueryTime)
	} else {
		p.AddFloat64Field("mean_rate", -1)
	}
	p.AddFloat64Field("max_time", maxQueryTime)
	if maxQueryTime > 0 {
		p.AddFloat64Field("max_rate", 1000/maxQueryTime)
	} else {
		p.AddFloat64Field("max_rate", -1)
	}
	p.AddFloat64Field("moving_mean_time", movingMean)
	p.AddInt64Field("total_items", totalQueries)
	p.AddFloat64Field("duration", queryDuration.Seconds())

	err = finishReport(c, p)

	return err

}
<commit_msg>Added possibility to specify extra values<commit_after>package report

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"time"
)

// ReportParams is holder for common parameters across load and query reports
type ReportParams struct {
	DBType             string
	ReportDatabaseName string
	ReportHost         string
	ReportUser         string
	ReportPassword     string
	ReportTags         [][2]string
	Hostname           string
	DestinationUrl     string
	Workers            int
	ItemLimit          int
}

// LoadReportParams is holder of bulk load specific parameters
type LoadReportParams struct {
	ReportParams

	IsGzip    bool
	BatchSize int
}

// type QueryReportParams is holder of bulk query specific parameters
type QueryReportParams struct {
	ReportParams

	BurnIn int64
}

type ExtraVal struct {
	Name  string
	Value interface{}
}

// ReportLoadResult send results from bulk load to an influxdb according to the given parameters
func ReportLoadResult(params *LoadReportParams, totalItems int64, valueRate float64, inputSpeed float64, loadDuration time.Duration) error {

	c, p, err := initReport(&params.ReportParams, "load_benchmarks")
	if err != nil {
		return err
	}

	p.AddTag("gzip", strconv.FormatBool(params.IsGzip))
	p.AddTag("batch_size", strconv.Itoa(params.BatchSize))

	p.AddInt64Field("total_items", totalItems)
	p.AddFloat64Field("values_rate", valueRate)
	p.AddFloat64Field("input_rate", inputSpeed)
	p.AddFloat64Field("duration", loadDuration.Seconds())

	err = finishReport(c, p)

	return err

}

// initReport prepares a Point and a Collector instance for sending a result report
func initReport(params *ReportParams, measurement string) (*Collector, *Point, error) {
	var authString string
	if len(params.ReportUser) > 0 {
		authString = fmt.Sprintf("%s:%s", params.ReportUser, params.ReportPassword)
	}
	c := NewCollector(params.ReportHost, params.ReportDatabaseName, authString)

	err := c.CreateDatabase()
	if err != nil {
		return nil, nil, err
	}

	p := GetPointFromGlobalPool()
	p.Init(measurement, time.Now().UnixNano())

	for _, tagpair := range params.ReportTags {
		p.AddTag(tagpair[0], tagpair[1])
	}

	p.AddTag("client_hostname", params.Hostname)
	p.AddTag("server_url", strings.Replace(params.DestinationUrl, ",", "\\,", -1))
	if len(params.DBType) > 0 {
		p.AddTag("database_type", params.DBType)
	}
	p.AddTag("item_limit", strconv.Itoa(params.ItemLimit))
	p.AddTag("workers", strconv.Itoa(params.Workers))

	return c, p, nil
}

//finishReport finalizes sending result report and cleaning data
func finishReport(c *Collector, p *Point) error {
	c.Put(p)
	c.PrepBatch()

	err := c.SendBatch()

	PutPointIntoGlobalPool(p)

	return err
}

const escapes = "\t\n\f\r ,="

var escaper = strings.NewReplacer(
	"\t", `\t`,
	"\n", `\n`,
	"\f", `\f`,
	"\r", `\r`,
	`,`, `\,`,
	` `, `\ `,
	`=`, `\=`,
)

func Escape(s string) string {
	if strings.ContainsAny(s, escapes) {
		return escaper.Replace(s)
	} else {
		return s
	}
}

//ReportQueryResult send result from bulk query benchmark to an influxdb according to the given parameters
func ReportQueryResult(params *QueryReportParams, queryName string, minQueryTime float64, meanQueryTime float64, maxQueryTime float64, totalQueries int64, movingMean float64, queryDuration time.Duration, extraVals ...ExtraVal) error {

	c, p, err := initReport(&params.ReportParams, "query_benchmarks")
	if err != nil {
		return err
	}

	p.AddTag("burn_in", strconv.Itoa(int(params.BurnIn)))
	p.AddTag("query_name", Escape(queryName))

	p.AddFloat64Field("min_time", minQueryTime)
	if minQueryTime > 0 {
		p.AddFloat64Field("min_rate", 1000/minQueryTime)
	} else {
		p.AddFloat64Field("min_rate", -1)
	}
	p.AddFloat64Field("mean_time", meanQueryTime)
	if meanQueryTime > 0 {
		p.AddFloat64Field("mean_rate", 1000/meanQueryTime)
	} else {
		p.AddFloat64Field("mean_rate", -1)
	}
	p.AddFloat64Field("max_time", maxQueryTime)
	if maxQueryTime > 0 {
		p.AddFloat64Field("max_rate", 1000/maxQueryTime)
	} else {
		p.AddFloat64Field("max_rate", -1)
	}
	p.AddFloat64Field("moving_mean_time", movingMean)
	p.AddInt64Field("total_items", totalQueries)
	p.AddFloat64Field("duration", queryDuration.Seconds())

	for _, v := range extraVals {
		switch v.Value.(type) {
		case float64:
			p.AddFloat64Field(v.Name, v.Value.(float64))
			break
		case int64:
			p.AddInt64Field(v.Name, v.Value.(int64))
			break
		default:
			panic("unsupported type " + reflect.TypeOf(v.Value).String())
		}
	}

	err = finishReport(c, p)

	return err

}
<|endoftext|>


<commit_before>package resolver

import (
	"context"
	"fmt"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/containerd/containerd/images"
	"github.com/containerd/containerd/remotes"
	"github.com/containerd/containerd/remotes/docker"
	distreference "github.com/docker/distribution/reference"
	"github.com/moby/buildkit/session"
	"github.com/moby/buildkit/source"
	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
)

// DefaultPool is the default shared resolver pool instance
var DefaultPool = NewPool()

// Pool is a cache of recently used resolvers
type Pool struct {
	mu sync.Mutex
	m  map[string]*authHandlerNS
}

// NewPool creates a new pool for caching resolvers
func NewPool() *Pool {
	p := &Pool{
		m: map[string]*authHandlerNS{},
	}
	time.AfterFunc(5*time.Minute, p.gc)
	return p
}

func (p *Pool) gc() {
	p.mu.Lock()
	defer p.mu.Unlock()

	for k, ns := range p.m {
		ns.muHandlers.Lock()
		for key, h := range ns.handlers {
			if time.Since(h.lastUsed) < 10*time.Minute {
				continue
			}
			parts := strings.SplitN(key, "/", 2)
			if len(parts) != 2 {
				delete(ns.handlers, key)
				continue
			}
			c, err := ns.sm.Get(context.TODO(), parts[1], true)
			if c == nil || err != nil {
				delete(ns.handlers, key)
			}
		}
		if len(ns.handlers) == 0 {
			delete(p.m, k)
		}
		ns.muHandlers.Unlock()
	}

	time.AfterFunc(5*time.Minute, p.gc)
}

// Clear deletes currently cached items. This may be called on config changes for example.
func (p *Pool) Clear() {
	p.mu.Lock()
	defer p.mu.Unlock()
	p.m = map[string]*authHandlerNS{}
}

// GetResolver gets a resolver for a specified scope from the pool
func (p *Pool) GetResolver(hosts docker.RegistryHosts, ref, scope string, sm *session.Manager, g session.Group) *Resolver {
	name := ref
	named, err := distreference.ParseNormalizedNamed(ref)
	if err == nil {
		name = named.Name()
	}

	key := fmt.Sprintf("%s::%s", name, scope)

	p.mu.Lock()
	defer p.mu.Unlock()
	h, ok := p.m[key]
	if !ok {
		h = newAuthHandlerNS(sm)
		p.m[key] = h
	}
	return newResolver(hosts, h, sm, g)
}

func newResolver(hosts docker.RegistryHosts, handler *authHandlerNS, sm *session.Manager, g session.Group) *Resolver {
	if hosts == nil {
		hosts = docker.ConfigureDefaultRegistries(
			docker.WithClient(newDefaultClient()),
			docker.WithPlainHTTP(docker.MatchLocalhost),
		)
	}
	r := &Resolver{
		hosts:   hosts,
		sm:      sm,
		g:       g,
		handler: handler,
	}
	r.Resolver = docker.NewResolver(docker.ResolverOptions{
		Hosts: r.HostsFunc,
	})
	return r
}

// Resolver is a wrapper around remotes.Resolver
type Resolver struct {
	remotes.Resolver
	hosts   docker.RegistryHosts
	sm      *session.Manager
	g       session.Group
	handler *authHandlerNS
	auth    *dockerAuthorizer

	is   images.Store
	mode source.ResolveMode
}

// HostsFunc implements registry configuration of this Resolver
func (r *Resolver) HostsFunc(host string) ([]docker.RegistryHost, error) {
	return func(domain string) ([]docker.RegistryHost, error) {
		v, err := r.handler.g.Do(context.TODO(), domain, func(ctx context.Context) (interface{}, error) {
			// long lock not needed because flightcontrol.Do
			r.handler.muHosts.Lock()
			v, ok := r.handler.hosts[domain]
			r.handler.muHosts.Unlock()
			if ok {
				return v, nil
			}
			res, err := r.hosts(domain)
			if err != nil {
				return nil, err
			}
			r.handler.muHosts.Lock()
			r.handler.hosts[domain] = res
			r.handler.muHosts.Unlock()
			return res, nil
		})
		if err != nil || v == nil {
			return nil, err
		}
		res := v.([]docker.RegistryHost)
		if len(res) == 0 {
			return nil, nil
		}
		auth := newDockerAuthorizer(res[0].Client, r.handler, r.sm, r.g)
		for i := range res {
			res[i].Authorizer = auth
		}
		return res, nil
	}(host)
}

// WithSession returns a new resolver that works with new session group
func (r *Resolver) WithSession(s session.Group) *Resolver {
	r2 := *r
	r2.auth = nil
	r2.g = s
	return &r2
}

// WithImageStore returns new resolver that can also resolve from local images store
func (r *Resolver) WithImageStore(is images.Store, mode source.ResolveMode) *Resolver {
	r2 := *r
	r2.Resolver = r.Resolver
	r2.is = is
	r2.mode = mode
	return &r2
}

// Fetcher returns a new fetcher for the provided reference.
func (r *Resolver) Fetcher(ctx context.Context, ref string) (remotes.Fetcher, error) {
	if atomic.LoadInt64(&r.handler.counter) == 0 {
		r.Resolve(ctx, ref)
	}
	return r.Resolver.Fetcher(ctx, ref)
}

// Resolve attempts to resolve the reference into a name and descriptor.
func (r *Resolver) Resolve(ctx context.Context, ref string) (string, ocispecs.Descriptor, error) {
	if r.mode == source.ResolveModePreferLocal && r.is != nil {
		if img, err := r.is.Get(ctx, ref); err == nil {
			return ref, img.Target, nil
		}
	}

	n, desc, err := r.Resolver.Resolve(ctx, ref)
	if err == nil {
		atomic.AddInt64(&r.handler.counter, 1)
		return n, desc, err
	}

	if r.mode == source.ResolveModeDefault && r.is != nil {
		if img, err := r.is.Get(ctx, ref); err == nil {
			return ref, img.Target, nil
		}
	}

	return "", ocispecs.Descriptor{}, err
}
<commit_msg>resolver: make sure authorizer is not overwritten on other resolvers <commit_after>package resolver

import (
	"context"
	"fmt"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/containerd/containerd/images"
	"github.com/containerd/containerd/remotes"
	"github.com/containerd/containerd/remotes/docker"
	distreference "github.com/docker/distribution/reference"
	"github.com/moby/buildkit/session"
	"github.com/moby/buildkit/source"
	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
)

// DefaultPool is the default shared resolver pool instance
var DefaultPool = NewPool()

// Pool is a cache of recently used resolvers
type Pool struct {
	mu sync.Mutex
	m  map[string]*authHandlerNS
}

// NewPool creates a new pool for caching resolvers
func NewPool() *Pool {
	p := &Pool{
		m: map[string]*authHandlerNS{},
	}
	time.AfterFunc(5*time.Minute, p.gc)
	return p
}

func (p *Pool) gc() {
	p.mu.Lock()
	defer p.mu.Unlock()

	for k, ns := range p.m {
		ns.muHandlers.Lock()
		for key, h := range ns.handlers {
			if time.Since(h.lastUsed) < 10*time.Minute {
				continue
			}
			parts := strings.SplitN(key, "/", 2)
			if len(parts) != 2 {
				delete(ns.handlers, key)
				continue
			}
			c, err := ns.sm.Get(context.TODO(), parts[1], true)
			if c == nil || err != nil {
				delete(ns.handlers, key)
			}
		}
		if len(ns.handlers) == 0 {
			delete(p.m, k)
		}
		ns.muHandlers.Unlock()
	}

	time.AfterFunc(5*time.Minute, p.gc)
}

// Clear deletes currently cached items. This may be called on config changes for example.
func (p *Pool) Clear() {
	p.mu.Lock()
	defer p.mu.Unlock()
	p.m = map[string]*authHandlerNS{}
}

// GetResolver gets a resolver for a specified scope from the pool
func (p *Pool) GetResolver(hosts docker.RegistryHosts, ref, scope string, sm *session.Manager, g session.Group) *Resolver {
	name := ref
	named, err := distreference.ParseNormalizedNamed(ref)
	if err == nil {
		name = named.Name()
	}

	key := fmt.Sprintf("%s::%s", name, scope)

	p.mu.Lock()
	defer p.mu.Unlock()
	h, ok := p.m[key]
	if !ok {
		h = newAuthHandlerNS(sm)
		p.m[key] = h
	}
	return newResolver(hosts, h, sm, g)
}

func newResolver(hosts docker.RegistryHosts, handler *authHandlerNS, sm *session.Manager, g session.Group) *Resolver {
	if hosts == nil {
		hosts = docker.ConfigureDefaultRegistries(
			docker.WithClient(newDefaultClient()),
			docker.WithPlainHTTP(docker.MatchLocalhost),
		)
	}
	r := &Resolver{
		hosts:   hosts,
		sm:      sm,
		g:       g,
		handler: handler,
	}
	r.Resolver = docker.NewResolver(docker.ResolverOptions{
		Hosts: r.HostsFunc,
	})
	return r
}

// Resolver is a wrapper around remotes.Resolver
type Resolver struct {
	remotes.Resolver
	hosts   docker.RegistryHosts
	sm      *session.Manager
	g       session.Group
	handler *authHandlerNS
	auth    *dockerAuthorizer

	is   images.Store
	mode source.ResolveMode
}

// HostsFunc implements registry configuration of this Resolver
func (r *Resolver) HostsFunc(host string) ([]docker.RegistryHost, error) {
	return func(domain string) ([]docker.RegistryHost, error) {
		v, err := r.handler.g.Do(context.TODO(), domain, func(ctx context.Context) (interface{}, error) {
			// long lock not needed because flightcontrol.Do
			r.handler.muHosts.Lock()
			v, ok := r.handler.hosts[domain]
			r.handler.muHosts.Unlock()
			if ok {
				return v, nil
			}
			res, err := r.hosts(domain)
			if err != nil {
				return nil, err
			}
			r.handler.muHosts.Lock()
			r.handler.hosts[domain] = res
			r.handler.muHosts.Unlock()
			return res, nil
		})
		if err != nil || v == nil {
			return nil, err
		}
		vv := v.([]docker.RegistryHost)
		if len(vv) == 0 {
			return nil, nil
		}
		// make a copy so authorizer is set on unique instance
		res := make([]docker.RegistryHost, len(vv))
		copy(res, vv)
		auth := newDockerAuthorizer(res[0].Client, r.handler, r.sm, r.g)
		for i := range res {
			res[i].Authorizer = auth
		}
		return res, nil
	}(host)
}

// WithSession returns a new resolver that works with new session group
func (r *Resolver) WithSession(s session.Group) *Resolver {
	r2 := *r
	r2.auth = nil
	r2.g = s
	return &r2
}

// WithImageStore returns new resolver that can also resolve from local images store
func (r *Resolver) WithImageStore(is images.Store, mode source.ResolveMode) *Resolver {
	r2 := *r
	r2.Resolver = r.Resolver
	r2.is = is
	r2.mode = mode
	return &r2
}

// Fetcher returns a new fetcher for the provided reference.
func (r *Resolver) Fetcher(ctx context.Context, ref string) (remotes.Fetcher, error) {
	if atomic.LoadInt64(&r.handler.counter) == 0 {
		r.Resolve(ctx, ref)
	}
	return r.Resolver.Fetcher(ctx, ref)
}

// Resolve attempts to resolve the reference into a name and descriptor.
func (r *Resolver) Resolve(ctx context.Context, ref string) (string, ocispecs.Descriptor, error) {
	if r.mode == source.ResolveModePreferLocal && r.is != nil {
		if img, err := r.is.Get(ctx, ref); err == nil {
			return ref, img.Target, nil
		}
	}

	n, desc, err := r.Resolver.Resolve(ctx, ref)
	if err == nil {
		atomic.AddInt64(&r.handler.counter, 1)
		return n, desc, err
	}

	if r.mode == source.ResolveModeDefault && r.is != nil {
		if img, err := r.is.Get(ctx, ref); err == nil {
			return ref, img.Target, nil
		}
	}

	return "", ocispecs.Descriptor{}, err
}
<|endoftext|>


<commit_before>package handlers

import (
	"code.google.com/p/goprotobuf/proto"
	"errors"
	"git.cloudrack.io/aiw3/np-server/environment"
	"git.cloudrack.io/aiw3/np-server/np/protocol"
	"git.cloudrack.io/aiw3/np-server/np/reply"
	"git.cloudrack.io/aiw3/np-server/np/storage"
	"git.cloudrack.io/aiw3/np-server/np/structs"
	"github.com/pzduniak/logger"
	"net"
	"strconv"
	"strings"
	"time"
)

var WrongIPAddress = errors.New("Wrong IP address")

func RPCAuthenticateWithTokenMessage(conn net.Conn, connection_data *structs.ConnData, packet_data *structs.PacketData) error {
	// Unmarshal the data
	msg := new(protocol.AuthenticateWithTokenMessage)
	err := proto.Unmarshal(packet_data.Content, msg)
	if err != nil {
		return err
	}

	// Split the token
	token := string(msg.Token)
	parts := strings.Split(token, ":")

	// uid is the first part
	id, err := strconv.Atoi(parts[0])
	if err != nil {
		return err
	}

	// Convert it to the Npid
	npid := structs.IdToNpid(id)

	// Set connection data
	connection_data.Id = id
	connection_data.Npid = npid
	connection_data.Token = token

	// Verify!
	sess_string, err := environment.Env.Redis.Get("session:" + token).Result()
	if err != nil {
		return err
	}

	// Format is: ip;rank
	sess_parts := strings.Split(sess_string, ";")

	// Verify that user has the same IP as the one used to log in
	if sess_parts[0] != structs.StripPort(conn.RemoteAddr().String()) {
		return WrongIPAddress
	}

	// Get the rank id and save it in the session
	connection_data.RankId, err = strconv.Atoi(sess_parts[1])
	if err != nil {
		return err
	}

	// Authenticate the session
	connection_data.Authenticated = true
	connection_data.Username = sess_parts[2]

	// Add connection to the storage
	storage.SetClientConnection(npid, connection_data)

	// Return a response
	err = reply.Reply(conn, packet_data.Header.Id, &protocol.AuthenticateResultMessage{
		Result:       proto.Int32(0),
		Npid:         &npid,
		SessionToken: msg.Token,
	})
	if err != nil {
		return err
	}

	// No idea what this thing is supposed to do
	time.AfterFunc(time.Millisecond*900, func() {
		err = reply.Reply(conn, 0, &protocol.AuthenticateExternalStatusMessage{
			Status: proto.Int32(0),
		})

		if err != nil {
			logger.Warning(err)
		}
	})

	return nil
}
<commit_msg>Update AuthenticateWithTokenMessage.go<commit_after>package handlers

import (
	"code.google.com/p/goprotobuf/proto"
	"errors"
	"git.cloudrack.io/aiw3/np-server/environment"
	"git.cloudrack.io/aiw3/np-server/np/protocol"
	"git.cloudrack.io/aiw3/np-server/np/reply"
	"git.cloudrack.io/aiw3/np-server/np/storage"
	"git.cloudrack.io/aiw3/np-server/np/structs"
	"github.com/pzduniak/logger"
	"net"
	"strconv"
	"strings"
	"time"
)

var WrongIPAddress = errors.New("Wrong IP address")

func RPCAuthenticateWithTokenMessage(conn net.Conn, connection_data *structs.ConnData, packet_data *structs.PacketData) error {
	// Unmarshal the data
	msg := new(protocol.AuthenticateWithTokenMessage)
	err := proto.Unmarshal(packet_data.Content, msg)
	if err != nil {
		return err
	}

	// Split the token
	token := string(msg.Token)
	parts := strings.Split(token, ":")

	// uid is the first part
	id, err := strconv.Atoi(parts[0])
	if err != nil {
		return err
	}

	// Convert it to the Npid
	npid := structs.IdToNpid(id)

	// Set connection data
	connection_data.Id = id
	connection_data.Npid = npid
	connection_data.Token = token

	// Verify!
	sess_string, err := environment.Env.Redis.Get("session:" + token).Result()
	if err != nil {
		return err
	}

	// Format is: ip;rank;username
	sess_parts := strings.Split(sess_string, ";")

	// Verify that user has the same IP as the one used to log in
	if sess_parts[0] != structs.StripPort(conn.RemoteAddr().String()) {
		return WrongIPAddress
	}

	// Get the rank id and save it in the session
	connection_data.RankId, err = strconv.Atoi(sess_parts[1])
	if err != nil {
		return err
	}

	// Authenticate the session
	connection_data.Authenticated = true
	connection_data.Username = sess_parts[2]

	// Add connection to the storage
	storage.SetClientConnection(npid, connection_data)

	// Return a response
	err = reply.Reply(conn, packet_data.Header.Id, &protocol.AuthenticateResultMessage{
		Result:       proto.Int32(0),
		Npid:         &npid,
		SessionToken: msg.Token,
	})
	if err != nil {
		return err
	}

	// No idea what this thing is supposed to do
	time.AfterFunc(time.Millisecond*900, func() {
		err = reply.Reply(conn, 0, &protocol.AuthenticateExternalStatusMessage{
			Status: proto.Int32(0),
		})

		if err != nil {
			logger.Warning(err)
		}
	})

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package template_test

import (
	"bytes"
	"internal/testenv"
	"os"
	"os/exec"
	"path/filepath"
	"testing"
)

// Issue 36021: verify that text/template doesn't prevent the linker from removing
// unused methods.
func TestLinkerGC(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping in short mode")
	}
	testenv.MustHaveGoBuild(t)
	const prog = `package main

import (
	_ "text/template"
)

type T struct{}

func (t *T) Unused() { println("THIS SHOULD BE ELIMINATED") }
func (t *T) Used() {}

var sink *T

func main() {
	var t T
	sink = &t
	t.Used()
}
`
	td, err := os.MkdirTemp("", "text_template_TestDeadCodeElimination")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(td)

	if err := os.WriteFile(filepath.Join(td, "x.go"), []byte(prog), 0644); err != nil {
		t.Fatal(err)
	}
	cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "x.exe", "x.go")
	cmd.Dir = td
	if out, err := cmd.CombinedOutput(); err != nil {
		t.Fatalf("go build: %v, %s", err, out)
	}
	slurp, err := os.ReadFile(filepath.Join(td, "x.exe"))
	if err != nil {
		t.Fatal(err)
	}
	if bytes.Contains(slurp, []byte("THIS SHOULD BE ELIMINATED")) {
		t.Error("binary contains code that should be deadcode eliminated")
	}
}
<commit_msg>text/template: replace os.MkdirTemp with T.TempDir<commit_after>// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package template_test

import (
	"bytes"
	"internal/testenv"
	"os"
	"os/exec"
	"path/filepath"
	"testing"
)

// Issue 36021: verify that text/template doesn't prevent the linker from removing
// unused methods.
func TestLinkerGC(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping in short mode")
	}
	testenv.MustHaveGoBuild(t)
	const prog = `package main

import (
	_ "text/template"
)

type T struct{}

func (t *T) Unused() { println("THIS SHOULD BE ELIMINATED") }
func (t *T) Used() {}

var sink *T

func main() {
	var t T
	sink = &t
	t.Used()
}
`
	td := t.TempDir()

	if err := os.WriteFile(filepath.Join(td, "x.go"), []byte(prog), 0644); err != nil {
		t.Fatal(err)
	}
	cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "x.exe", "x.go")
	cmd.Dir = td
	if out, err := cmd.CombinedOutput(); err != nil {
		t.Fatalf("go build: %v, %s", err, out)
	}
	slurp, err := os.ReadFile(filepath.Join(td, "x.exe"))
	if err != nil {
		t.Fatal(err)
	}
	if bytes.Contains(slurp, []byte("THIS SHOULD BE ELIMINATED")) {
		t.Error("binary contains code that should be deadcode eliminated")
	}
}
<|endoftext|>