<commit_before>package setup

import (
	"errors"
	"fmt"
	"github.com/skatteetaten/aoc/pkg/cmdoptions"
	"github.com/skatteetaten/aoc/pkg/fileutil"
	"github.com/skatteetaten/aoc/pkg/jsonutil"
	"github.com/skatteetaten/aoc/pkg/openshift"
	"github.com/skatteetaten/aoc/pkg/serverapi"
	"github.com/spf13/viper"
	"path/filepath"
)

type SetupClass struct {
	configLocation  string
	openshiftConfig *openshift.OpenshiftConfig
	apiClusterIndex int
	initDone        bool
}

func (setupClass *SetupClass) init() (err error) {
	if setupClass.initDone {
		return
	}
	setupClass.configLocation = viper.GetString("HOME") + "/.aoc.json"
	setupClass.openshiftConfig, err = openshift.LoadOrInitiateConfigFile(setupClass.configLocation)
	if err != nil {
		err = errors.New("Error in loading OpenShift configuration")
	}
	// Find index for API cluster,that is the first reachable cluster
	if setupClass.openshiftConfig != nil {
		for i := range setupClass.openshiftConfig.Clusters {
			if setupClass.openshiftConfig.Clusters[i].Reachable {
				setupClass.apiClusterIndex = i
				break
			}
		}
	}
	setupClass.initDone = true
	return
}

func (setupClass *SetupClass) getApiCluster() *openshift.OpenshiftCluster {
	var configLocation = viper.GetString("HOME") + "/.aoc.json"
	openshiftConfig, err := openshift.LoadOrInitiateConfigFile(configLocation)
	if err != nil {
		fmt.Println("Error in loading OpenShift configuration")
		return nil
	}
	for i := range openshiftConfig.Clusters {
		if openshiftConfig.Clusters[i].Reachable {
			return openshiftConfig.Clusters[i]
		}
	}
	return nil
}

func (setupClass *SetupClass) validateImportCommand(args []string) (error error) {
	error = setupClass.validateFileFolderArg(args)
	if error != nil {
		return
	}

	if len(args) > 1 {
		error = errors.New("Usage: aoc import file | folder")
		return
	}
	return
}

func (setupClass *SetupClass) ExecuteSetupImport(args []string, overrideFiles []string,
	persistentOptions *cmdoptions.CommonCommandOptions, localDryRun bool, doSetup bool) (
	output string, error error) {

	var errorString string

	setupClass.init()
	if !localDryRun {
		if !serverapi.ValidateLogin(setupClass.openshiftConfig) {
			return "", errors.New("Not logged in, please use aoc login")
		}
	}

	if doSetup {
		error = setupClass.validateSetupCommand(args, overrideFiles)
	} else {
		error = setupClass.validateImportCommand(args)
	}
	if error != nil {
		return
	}

	var apiEndpoint string
	if doSetup {
		apiEndpoint = "/setup"
	} else {
		apiEndpoint = "/auroraconfig/" + setupClass.getAffiliation()
	}

	var env = args[0]
	var overrideJson []string = args[1:]

	var absolutePath string

	absolutePath, _ = filepath.Abs(env)

	var envFile string      // Filename for app
	var envFolder string    // Short folder name (Env)
	var folder string       // Absolute path of folder
	var parentFolder string // Absolute path of parent

	switch fileutil.IsLegalFileFolder(env) {
	case fileutil.SpecIsFile:
		folder = filepath.Dir(absolutePath)
		envFile = filepath.Base(absolutePath)
	case fileutil.SpecIsFolder:
		folder = absolutePath
		envFile = ""
	}

	parentFolder = filepath.Dir(folder)
	envFolder = filepath.Base(folder)

	if folder == parentFolder {
		errorString += fmt.Sprintf("Application configuration file cannot reside in root directory")
		return "", errors.New(errorString)
	}

	// Initialize JSON

	jsonStr, err := jsonutil.GenerateJson(envFile, envFolder, folder, parentFolder, overrideJson, overrideFiles,
		setupClass.getAffiliation(), persistentOptions.DryRun, doSetup)
	if err != nil {
		return "", err
	} else {
		if localDryRun {
			return fmt.Sprintf("%v", string(jsonutil.PrettyPrintJson(jsonStr))), nil
		} else {
			output, err = serverapi.CallApi(apiEndpoint, jsonStr, persistentOptions.ShowConfig,
				persistentOptions.ShowObjects, false, persistentOptions.Localhost,
				persistentOptions.Verbose, setupClass.openshiftConfig, persistentOptions.DryRun, persistentOptions.Debug)
			if err != nil {
				return "", err
			}
		}
	}
	return
}

func (setupClass *SetupClass) validateSetupCommand(args []string, overrideFiles []string) (error error) {
	var errorString = ""

	error = setupClass.validateFileFolderArg(args)
	if error != nil {
		return
	}

	// We have at least one argument, now there should be a correlation between the number of args
	// and the number of override (-f) flags
	if len(overrideFiles) < (len(args) - 1) {
		errorString += fmt.Sprintf("Configuration override specified without file reference flag\n")
	}
	if len(overrideFiles) > (len(args) - 1) {
		errorString += fmt.Sprintf("Configuration overide file reference flag specified without configuration\n")
	}

	// Check for legal JSON argument for each overrideFiles flag
	for i := 1; i < len(args); i++ {
		if !jsonutil.IsLegalJson(args[i]) {
			errorString += fmt.Sprintf("Illegal JSON configuration override: %v\n", args[i])
		}
	}

	if errorString != "" {
		error = errors.New(errorString)
	}
	return
}

func (setupClass *SetupClass) ExecuteDeploy(args []string, persistentOptions *cmdoptions.CommonCommandOptions) (
	output string, error error) {

	error = validateDeploy(args)
	if error != nil {
		return
	}

	setupClass.init()
	if !serverapi.ValidateLogin(setupClass.openshiftConfig) {
		return "", errors.New("Not logged in, please use aoc login")
	}

	// Line of code from Mac
	// Line of code from VDI

	return
}

func validateDeploy(args []string) (error error) {
	if len(args) != 0 {
		error = errors.New("Usage: aoc deploy")
	}

	return
}

func (SetupClass *SetupClass) validateFileFolderArg(args []string) (error error) {
	var errorString string

	if len(args) == 0 {
		errorString += "Missing file/folder "
	} else {
		// Chceck argument 0 for legal file / folder
		validateCode := fileutil.IsLegalFileFolder(args[0])
		if validateCode < 0 {
			errorString += fmt.Sprintf("Illegal file / folder: %v\n", args[0])
		}

	}

	if errorString != "" {
		return errors.New(errorString)
	}
	return

}

func (setupClass *SetupClass) getAffiliation() (affiliation string) {
	if setupClass.openshiftConfig != nil {
		affiliation = setupClass.openshiftConfig.Affiliation
	}
	return
}
<commit_msg>Implemented import command<commit_after>package setup

import (
	"errors"
	"fmt"
	"github.com/skatteetaten/aoc/pkg/cmdoptions"
	"github.com/skatteetaten/aoc/pkg/fileutil"
	"github.com/skatteetaten/aoc/pkg/jsonutil"
	"github.com/skatteetaten/aoc/pkg/openshift"
	"github.com/skatteetaten/aoc/pkg/serverapi"
	"github.com/spf13/viper"
	"path/filepath"
)

type SetupClass struct {
	configLocation  string
	openshiftConfig *openshift.OpenshiftConfig
	apiClusterIndex int
	initDone        bool
}

func (setupClass *SetupClass) init() (err error) {
	if setupClass.initDone {
		return
	}
	setupClass.configLocation = viper.GetString("HOME") + "/.aoc.json"
	setupClass.openshiftConfig, err = openshift.LoadOrInitiateConfigFile(setupClass.configLocation)
	if err != nil {
		err = errors.New("Error in loading OpenShift configuration")
	}
	// Find index for API cluster,that is the first reachable cluster
	if setupClass.openshiftConfig != nil {
		for i := range setupClass.openshiftConfig.Clusters {
			if setupClass.openshiftConfig.Clusters[i].Reachable {
				setupClass.apiClusterIndex = i
				break
			}
		}
	}
	setupClass.initDone = true
	return
}

func (setupClass *SetupClass) getApiCluster() *openshift.OpenshiftCluster {
	var configLocation = viper.GetString("HOME") + "/.aoc.json"
	openshiftConfig, err := openshift.LoadOrInitiateConfigFile(configLocation)
	if err != nil {
		fmt.Println("Error in loading OpenShift configuration")
		return nil
	}
	for i := range openshiftConfig.Clusters {
		if openshiftConfig.Clusters[i].Reachable {
			return openshiftConfig.Clusters[i]
		}
	}
	return nil
}

func (setupClass *SetupClass) validateImportCommand(args []string) (error error) {
	error = setupClass.validateFileFolderArg(args)
	if error != nil {
		return
	}

	if len(args) > 1 {
		error = errors.New("Usage: aoc import file | folder")
		return
	}
	return
}

func (setupClass *SetupClass) ExecuteSetupImport(args []string, overrideFiles []string,
	persistentOptions *cmdoptions.CommonCommandOptions, localDryRun bool, doSetup bool) (
	output string, error error) {

	var errorString string

	setupClass.init()
	if !localDryRun {
		if !serverapi.ValidateLogin(setupClass.openshiftConfig) {
			return "", errors.New("Not logged in, please use aoc login")
		}
	}

	if doSetup {
		error = setupClass.validateSetupCommand(args, overrideFiles)
	} else {
		error = setupClass.validateImportCommand(args)
	}
	if error != nil {
		return
	}

	var apiEndpoint string
	if doSetup {
		apiEndpoint = "/setup"
	} else {
		apiEndpoint = "/auroraconfig/" + setupClass.getAffiliation()
	}

	var env = args[0]
	var overrideJson []string = args[1:]

	var absolutePath string

	absolutePath, _ = filepath.Abs(env)

	var envFile string      // Filename for app
	var envFolder string    // Short folder name (Env)
	var folder string       // Absolute path of folder
	var parentFolder string // Absolute path of parent

	switch fileutil.IsLegalFileFolder(env) {
	case fileutil.SpecIsFile:
		folder = filepath.Dir(absolutePath)
		envFile = filepath.Base(absolutePath)
	case fileutil.SpecIsFolder:
		folder = absolutePath
		envFile = ""
	}

	parentFolder = filepath.Dir(folder)
	envFolder = filepath.Base(folder)

	if folder == parentFolder {
		errorString += fmt.Sprintf("Application configuration file cannot reside in root directory")
		return "", errors.New(errorString)
	}

	// Initialize JSON

	jsonStr, err := jsonutil.GenerateJson(envFile, envFolder, folder, parentFolder, overrideJson, overrideFiles,
		setupClass.getAffiliation(), persistentOptions.DryRun, doSetup)
	if err != nil {
		return "", err
	} else {
		if localDryRun {
			return fmt.Sprintf("%v", string(jsonutil.PrettyPrintJson(jsonStr))), nil
		} else {
			output, err = serverapi.CallApi(apiEndpoint, jsonStr, persistentOptions.ShowConfig,
				persistentOptions.ShowObjects, false, persistentOptions.Localhost,
				persistentOptions.Verbose, setupClass.openshiftConfig, persistentOptions.DryRun, persistentOptions.Debug)
			if err != nil {
				return "", err
			}
		}
	}
	return
}

func (setupClass *SetupClass) validateSetupCommand(args []string, overrideFiles []string) (error error) {
	var errorString = ""

	error = setupClass.validateFileFolderArg(args)
	if error != nil {
		return
	}

	// We have at least one argument, now there should be a correlation between the number of args
	// and the number of override (-f) flags
	if len(overrideFiles) < (len(args) - 1) {
		errorString += fmt.Sprintf("Configuration override specified without file reference flag\n")
	}
	if len(overrideFiles) > (len(args) - 1) {
		errorString += fmt.Sprintf("Configuration overide file reference flag specified without configuration\n")
	}

	// Check for legal JSON argument for each overrideFiles flag
	for i := 1; i < len(args); i++ {
		if !jsonutil.IsLegalJson(args[i]) {
			errorString += fmt.Sprintf("Illegal JSON configuration override: %v\n", args[i])
		}
	}

	if errorString != "" {
		error = errors.New(errorString)
	}
	return
}

func (setupClass *SetupClass) ExecuteDeploy(args []string, persistentOptions *cmdoptions.CommonCommandOptions) (
	output string, error error) {

	error = validateDeploy(args)
	if error != nil {
		return
	}

	setupClass.init()
	if !serverapi.ValidateLogin(setupClass.openshiftConfig) {
		return "", errors.New("Not logged in, please use aoc login")
	}

	// Line of code from Mac
	// Line of code from VDI

	l
	return
}

func validateDeploy(args []string) (error error) {
	if len(args) != 0 {
		error = errors.New("Usage: aoc deploy")
	}

	return
}

func (SetupClass *SetupClass) validateFileFolderArg(args []string) (error error) {
	var errorString string

	if len(args) == 0 {
		errorString += "Missing file/folder "
	} else {
		// Chceck argument 0 for legal file / folder
		validateCode := fileutil.IsLegalFileFolder(args[0])
		if validateCode < 0 {
			errorString += fmt.Sprintf("Illegal file / folder: %v\n", args[0])
		}

	}

	if errorString != "" {
		return errors.New(errorString)
	}
	return

}

func (setupClass *SetupClass) getAffiliation() (affiliation string) {
	if setupClass.openshiftConfig != nil {
		affiliation = setupClass.openshiftConfig.Affiliation
	}
	return
}
<|endoftext|>


<commit_before>package setup

import (
	"errors"
	"fmt"
	"github.com/skatteetaten/aoc/pkg/cmdoptions"
	"github.com/skatteetaten/aoc/pkg/fileutil"
	"github.com/skatteetaten/aoc/pkg/jsonutil"
	"github.com/skatteetaten/aoc/pkg/openshift"
	"github.com/skatteetaten/aoc/pkg/serverapi"
	"github.com/spf13/viper"
	"path/filepath"
)

type SetupClass struct {
	configLocation  string
	openshiftConfig *openshift.OpenshiftConfig
	apiClusterIndex int
	initDone        bool
}

func (setupClass *SetupClass) init() (err error) {
	if setupClass.initDone {
		return
	}
	setupClass.configLocation = viper.GetString("HOME") + "/.aoc.json"
	setupClass.openshiftConfig, err = openshift.LoadOrInitiateConfigFile(setupClass.configLocation)
	if err != nil {
		err = errors.New("Error in loading OpenShift configuration")
	}
	// Find index for API cluster,that is the first reachable cluster
	if setupClass.openshiftConfig != nil {
		for i := range setupClass.openshiftConfig.Clusters {
			if setupClass.openshiftConfig.Clusters[i].Reachable {
				setupClass.apiClusterIndex = i
				break
			}
		}
	}
	setupClass.initDone = true
	return
}

func (setupClass *SetupClass) getApiCluster() *openshift.OpenshiftCluster {
	var configLocation = viper.GetString("HOME") + "/.aoc.json"
	openshiftConfig, err := openshift.LoadOrInitiateConfigFile(configLocation)
	if err != nil {
		fmt.Println("Error in loading OpenShift configuration")
		return nil
	}
	for i := range openshiftConfig.Clusters {
		if openshiftConfig.Clusters[i].Reachable {
			return openshiftConfig.Clusters[i]
		}
	}
	return nil
}

func (setupClass *SetupClass) validateImportCommand(args []string) (error error) {
	error = setupClass.validateFileFolderArg(args)
	if error != nil {
		return
	}

	if len(args) > 1 {
		error = errors.New("Usage: aoc import file | folder")
		return
	}
	return
}

func (setupClass *SetupClass) ExecuteSetupImport(args []string, overrideFiles []string,
	persistentOptions *cmdoptions.CommonCommandOptions, localDryRun bool, doSetup bool) (
	output string, error error) {

	var errorString string

	setupClass.init()
	if !localDryRun {
		if !serverapi.ValidateLogin(setupClass.openshiftConfig) {
			return "", errors.New("Not logged in, please use aoc login")
		}
	}

	if doSetup {
		error = setupClass.validateSetupCommand(args, overrideFiles)
	} else {
		error = setupClass.validateImportCommand(args)
	}
	if error != nil {
		return
	}

	var apiEndpoint string
	if doSetup {
		apiEndpoint = "/setup"
	} else {
		apiEndpoint = "/auroraconfig/" + setupClass.getAffiliation()
	}

	var env = args[0]
	var overrideJson []string = args[1:]

	var absolutePath string

	absolutePath, _ = filepath.Abs(env)

	var envFile string      // Filename for app
	var envFolder string    // Short folder name (Env)
	var folder string       // Absolute path of folder
	var parentFolder string // Absolute path of parent

	switch fileutil.IsLegalFileFolder(env) {
	case fileutil.SpecIsFile:
		folder = filepath.Dir(absolutePath)
		envFile = filepath.Base(absolutePath)
	case fileutil.SpecIsFolder:
		folder = absolutePath
		envFile = ""
	}

	parentFolder = filepath.Dir(folder)
	envFolder = filepath.Base(folder)

	if folder == parentFolder {
		errorString += fmt.Sprintf("Application configuration file cannot reside in root directory")
		return "", errors.New(errorString)
	}

	// Initialize JSON

	jsonStr, err := jsonutil.GenerateJson(envFile, envFolder, folder, parentFolder, overrideJson, overrideFiles,
		setupClass.getAffiliation(), persistentOptions.DryRun, doSetup)
	if err != nil {
		return "", err
	} else {
		if localDryRun {
			return fmt.Sprintf("%v", string(jsonutil.PrettyPrintJson(jsonStr))), nil
		} else {
			output, err = serverapi.CallApi(apiEndpoint, jsonStr, persistentOptions.ShowConfig,
				persistentOptions.ShowObjects, false, persistentOptions.Localhost,
				persistentOptions.Verbose, setupClass.openshiftConfig, persistentOptions.DryRun, persistentOptions.Debug)
			if err != nil {
				return "", err
			}
		}
	}
	return
}

func (setupClass *SetupClass) validateSetupCommand(args []string, overrideFiles []string) (error error) {
	var errorString = ""

	error = setupClass.validateFileFolderArg(args)
	if error != nil {
		return
	}

	// We have at least one argument, now there should be a correlation between the number of args
	// and the number of override (-f) flags
	if len(overrideFiles) < (len(args) - 1) {
		errorString += fmt.Sprintf("Configuration override specified without file reference flag\n")
	}
	if len(overrideFiles) > (len(args) - 1) {
		errorString += fmt.Sprintf("Configuration overide file reference flag specified without configuration\n")
	}

	// Check for legal JSON argument for each overrideFiles flag
	for i := 1; i < len(args); i++ {
		if !jsonutil.IsLegalJson(args[i]) {
			errorString += fmt.Sprintf("Illegal JSON configuration override: %v\n", args[i])
		}
	}

	if errorString != "" {
		error = errors.New(errorString)
	}
	return
}

func (setupClass *SetupClass) ExecuteDeploy(args []string, persistentOptions *cmdoptions.CommonCommandOptions) (
	output string, error error) {

	error = validateDeploy(args)
	if error != nil {
		return
	}

	setupClass.init()
	if !serverapi.ValidateLogin(setupClass.openshiftConfig) {
		return "", errors.New("Not logged in, please use aoc login")
	}

	return
}

func validateDeploy(args []string) (error error) {
	if len(args) != 0 {
		error = errors.New("Usage: aoc deploy")
	}

	return
}

func (SetupClass *SetupClass) validateFileFolderArg(args []string) (error error) {
	var errorString string

	if len(args) == 0 {
		errorString += "Missing file/folder "
	} else {
		// Chceck argument 0 for legal file / folder
		validateCode := fileutil.IsLegalFileFolder(args[0])
		if validateCode < 0 {
			errorString += fmt.Sprintf("Illegal file / folder: %v\n", args[0])
		}

	}

	if errorString != "" {
		return errors.New(errorString)
	}
	return

}

func (setupClass *SetupClass) getAffiliation() (affiliation string) {
	if setupClass.openshiftConfig != nil {
		affiliation = setupClass.openshiftConfig.Affiliation
	}
	return
}
<commit_msg>Started work on Deploy command<commit_after>package setup

import (
	"errors"
	"fmt"
	"github.com/skatteetaten/aoc/pkg/cmdoptions"
	"github.com/skatteetaten/aoc/pkg/fileutil"
	"github.com/skatteetaten/aoc/pkg/jsonutil"
	"github.com/skatteetaten/aoc/pkg/openshift"
	"github.com/skatteetaten/aoc/pkg/serverapi"
	"github.com/spf13/viper"
	"path/filepath"
)

type SetupClass struct {
	configLocation  string
	openshiftConfig *openshift.OpenshiftConfig
	apiClusterIndex int
	initDone        bool
}

func (setupClass *SetupClass) init() (err error) {
	if setupClass.initDone {
		return
	}
	setupClass.configLocation = viper.GetString("HOME") + "/.aoc.json"
	setupClass.openshiftConfig, err = openshift.LoadOrInitiateConfigFile(setupClass.configLocation)
	if err != nil {
		err = errors.New("Error in loading OpenShift configuration")
	}
	// Find index for API cluster,that is the first reachable cluster
	if setupClass.openshiftConfig != nil {
		for i := range setupClass.openshiftConfig.Clusters {
			if setupClass.openshiftConfig.Clusters[i].Reachable {
				setupClass.apiClusterIndex = i
				break
			}
		}
	}
	setupClass.initDone = true
	return
}

func (setupClass *SetupClass) getApiCluster() *openshift.OpenshiftCluster {
	var configLocation = viper.GetString("HOME") + "/.aoc.json"
	openshiftConfig, err := openshift.LoadOrInitiateConfigFile(configLocation)
	if err != nil {
		fmt.Println("Error in loading OpenShift configuration")
		return nil
	}
	for i := range openshiftConfig.Clusters {
		if openshiftConfig.Clusters[i].Reachable {
			return openshiftConfig.Clusters[i]
		}
	}
	return nil
}

func (setupClass *SetupClass) validateImportCommand(args []string) (error error) {
	error = setupClass.validateFileFolderArg(args)
	if error != nil {
		return
	}

	if len(args) > 1 {
		error = errors.New("Usage: aoc import file | folder")
		return
	}
	return
}

func (setupClass *SetupClass) ExecuteSetupImport(args []string, overrideFiles []string,
	persistentOptions *cmdoptions.CommonCommandOptions, localDryRun bool, doSetup bool) (
	output string, error error) {

	var errorString string

	setupClass.init()
	if !localDryRun {
		if !serverapi.ValidateLogin(setupClass.openshiftConfig) {
			return "", errors.New("Not logged in, please use aoc login")
		}
	}

	if doSetup {
		error = setupClass.validateSetupCommand(args, overrideFiles)
	} else {
		error = setupClass.validateImportCommand(args)
	}
	if error != nil {
		return
	}

	var apiEndpoint string
	if doSetup {
		apiEndpoint = "/setup"
	} else {
		apiEndpoint = "/auroraconfig/" + setupClass.getAffiliation()
	}

	var env = args[0]
	var overrideJson []string = args[1:]

	var absolutePath string

	absolutePath, _ = filepath.Abs(env)

	var envFile string      // Filename for app
	var envFolder string    // Short folder name (Env)
	var folder string       // Absolute path of folder
	var parentFolder string // Absolute path of parent

	switch fileutil.IsLegalFileFolder(env) {
	case fileutil.SpecIsFile:
		folder = filepath.Dir(absolutePath)
		envFile = filepath.Base(absolutePath)
	case fileutil.SpecIsFolder:
		folder = absolutePath
		envFile = ""
	}

	parentFolder = filepath.Dir(folder)
	envFolder = filepath.Base(folder)

	if folder == parentFolder {
		errorString += fmt.Sprintf("Application configuration file cannot reside in root directory")
		return "", errors.New(errorString)
	}

	// Initialize JSON

	jsonStr, err := jsonutil.GenerateJson(envFile, envFolder, folder, parentFolder, overrideJson, overrideFiles,
		setupClass.getAffiliation(), persistentOptions.DryRun, doSetup)
	if err != nil {
		return "", err
	} else {
		if localDryRun {
			return fmt.Sprintf("%v", string(jsonutil.PrettyPrintJson(jsonStr))), nil
		} else {
			output, err = serverapi.CallApi(apiEndpoint, jsonStr, persistentOptions.ShowConfig,
				persistentOptions.ShowObjects, false, persistentOptions.Localhost,
				persistentOptions.Verbose, setupClass.openshiftConfig, persistentOptions.DryRun, persistentOptions.Debug)
			if err != nil {
				return "", err
			}
		}
	}
	return
}

func (setupClass *SetupClass) validateSetupCommand(args []string, overrideFiles []string) (error error) {
	var errorString = ""

	error = setupClass.validateFileFolderArg(args)
	if error != nil {
		return
	}

	// We have at least one argument, now there should be a correlation between the number of args
	// and the number of override (-f) flags
	if len(overrideFiles) < (len(args) - 1) {
		errorString += fmt.Sprintf("Configuration override specified without file reference flag\n")
	}
	if len(overrideFiles) > (len(args) - 1) {
		errorString += fmt.Sprintf("Configuration overide file reference flag specified without configuration\n")
	}

	// Check for legal JSON argument for each overrideFiles flag
	for i := 1; i < len(args); i++ {
		if !jsonutil.IsLegalJson(args[i]) {
			errorString += fmt.Sprintf("Illegal JSON configuration override: %v\n", args[i])
		}
	}

	if errorString != "" {
		error = errors.New(errorString)
	}
	return
}

func (setupClass *SetupClass) ExecuteDeploy(args []string, persistentOptions *cmdoptions.CommonCommandOptions) (
	output string, error error) {

	error = validateDeploy(args)
	if error != nil {
		return
	}

	setupClass.init()
	if !serverapi.ValidateLogin(setupClass.openshiftConfig) {
		return "", errors.New("Not logged in, please use aoc login")
	}

	// Line of code from Mac

	return
}

func validateDeploy(args []string) (error error) {
	if len(args) != 0 {
		error = errors.New("Usage: aoc deploy")
	}

	return
}

func (SetupClass *SetupClass) validateFileFolderArg(args []string) (error error) {
	var errorString string

	if len(args) == 0 {
		errorString += "Missing file/folder "
	} else {
		// Chceck argument 0 for legal file / folder
		validateCode := fileutil.IsLegalFileFolder(args[0])
		if validateCode < 0 {
			errorString += fmt.Sprintf("Illegal file / folder: %v\n", args[0])
		}

	}

	if errorString != "" {
		return errors.New(errorString)
	}
	return

}

func (setupClass *SetupClass) getAffiliation() (affiliation string) {
	if setupClass.openshiftConfig != nil {
		affiliation = setupClass.openshiftConfig.Affiliation
	}
	return
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/wafv2"
	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
	"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
)

func resourceAwsWafv2RegexPatternSet() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsWafv2RegexPatternSetCreate,
		Read:   resourceAwsWafv2RegexPatternSetRead,
		Update: resourceAwsWafv2RegexPatternSetUpdate,
		Delete: resourceAwsWafv2RegexPatternSetDelete,
		Importer: &schema.ResourceImporter{
			State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
				idParts := strings.Split(d.Id(), "/")
				if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" {
					return nil, fmt.Errorf("Unexpected format of ID (%q), expected ID/NAME/SCOPE", d.Id())
				}
				id := idParts[0]
				name := idParts[1]
				scope := idParts[2]
				d.SetId(id)
				d.Set("name", name)
				d.Set("scope", scope)
				return []*schema.ResourceData{d}, nil
			},
		},

		Schema: map[string]*schema.Schema{
			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"description": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validation.StringLenBetween(1, 256),
			},
			"lock_token": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"name": {
				Type:         schema.TypeString,
				Required:     true,
				ForceNew:     true,
				ValidateFunc: validation.StringLenBetween(1, 128),
			},
			"regular_expression_list": {
				Type:     schema.TypeSet,
				Required: true,
				MinItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"regex_string": {
							Type:         schema.TypeString,
							Required:     true,
							ValidateFunc: validation.StringLenBetween(1, 512),
						},
					},
				},
			},
			"scope": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
				ValidateFunc: validation.StringInSlice([]string{
					wafv2.ScopeCloudfront,
					wafv2.ScopeRegional,
				}, false),
			},
			"tags": tagsSchema(),
		},
	}
}

func resourceAwsWafv2RegexPatternSetCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).wafv2conn
	var resp *wafv2.CreateRegexPatternSetOutput

	params := &wafv2.CreateRegexPatternSetInput{
		Name:  aws.String(d.Get("name").(string)),
		Scope: aws.String(d.Get("scope").(string)),
	}

	if d.HasChange("description") {
		params.Description = aws.String(d.Get("description").(string))
	}

	if v, ok := d.GetOk("regular_expression_list"); ok && v.(*schema.Set).Len() > 0 {
		params.RegularExpressionList = expandWafv2RegexPatternSet(d.Get("regular_expression_list").(*schema.Set).List())
	}

	if v := d.Get("tags").(map[string]interface{}); len(v) > 0 {
		params.Tags = keyvaluetags.New(v).IgnoreAws().Wafv2Tags()
	}

	err := resource.Retry(15*time.Minute, func() *resource.RetryError {
		var err error
		resp, err = conn.CreateRegexPatternSet(params)
		if err != nil {
			if isAWSErr(err, wafv2.ErrCodeWAFInternalErrorException, "AWS WAF couldn’t perform the operation because of a system problem") {
				return resource.RetryableError(err)
			}
			if isAWSErr(err, wafv2.ErrCodeWAFTagOperationException, "An error occurred during the tagging operation") {
				return resource.RetryableError(err)
			}
			if isAWSErr(err, wafv2.ErrCodeWAFTagOperationInternalErrorException, "AWS WAF couldn’t perform your tagging operation because of an internal error") {
				return resource.RetryableError(err)
			}
			return resource.NonRetryableError(err)
		}
		return nil
	})
	if isResourceTimeoutError(err) {
		_, err = conn.CreateRegexPatternSet(params)
	}
	if err != nil {
		return err
	}
	d.SetId(*resp.Summary.Id)

	return resourceAwsWafv2RegexPatternSetRead(d, meta)
}

func resourceAwsWafv2RegexPatternSetRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).wafv2conn

	params := &wafv2.GetRegexPatternSetInput{
		Id:    aws.String(d.Id()),
		Name:  aws.String(d.Get("name").(string)),
		Scope: aws.String(d.Get("scope").(string)),
	}

	resp, err := conn.GetRegexPatternSet(params)
	if err != nil {
		if isAWSErr(err, wafv2.ErrCodeWAFNonexistentItemException, "AWS WAF couldn’t perform the operation because your resource doesn’t exist") {
			log.Printf("[WARN] WAFV2 RegexPatternSet (%s) not found, removing from state", d.Id())
			d.SetId("")
			return nil
		}

		return err
	}

	d.Set("name", resp.RegexPatternSet.Name)
	d.Set("description", resp.RegexPatternSet.Description)
	d.Set("arn", resp.RegexPatternSet.ARN)
	d.Set("lock_token", resp.LockToken)

	if err := d.Set("regular_expression_list", flattenWafv2RegexPatternSet(resp.RegexPatternSet.RegularExpressionList)); err != nil {
		return fmt.Errorf("Error setting regular_expression_list: %s", err)
	}

	tags, err := keyvaluetags.Wafv2ListTags(conn, *resp.RegexPatternSet.ARN)
	if err != nil {
		return fmt.Errorf("error listing tags for WAFV2 RegexPatternSet (%s): %s", *resp.RegexPatternSet.ARN, err)
	}

	if err := d.Set("tags", tags.IgnoreAws().Map()); err != nil {
		return fmt.Errorf("error setting tags: %s", err)
	}

	return nil
}

func flattenWafv2RegexPatternSet(r []*wafv2.Regex) interface{} {
	regexPatterns := make([]interface{}, len(r))

	for i, regexPattern := range r {
		d := map[string]interface{}{
			"regex_string": *regexPattern.RegexString,
		}
		regexPatterns[i] = d
	}

	return regexPatterns
}

func resourceAwsWafv2RegexPatternSetUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).wafv2conn

	log.Printf("[INFO] Updating WAFV2 RegexPatternSet %s", d.Id())

	err := resource.Retry(15*time.Minute, func() *resource.RetryError {
		u := &wafv2.UpdateRegexPatternSetInput{
			Id:          aws.String(d.Id()),
			Name:        aws.String(d.Get("name").(string)),
			Scope:       aws.String(d.Get("scope").(string)),
			Description: aws.String(d.Get("description").(string)),
			LockToken:   aws.String(d.Get("lock_token").(string)),
		}

		if v, ok := d.GetOk("regular_expression_list"); ok && v.(*schema.Set).Len() > 0 {
			u.RegularExpressionList = expandWafv2RegexPatternSet(d.Get("regular_expression_list").(*schema.Set).List())
		}

		if d.HasChange("description") {
			u.Description = aws.String(d.Get("description").(string))
		}

		_, err := conn.UpdateRegexPatternSet(u)

		if err != nil {
			if isAWSErr(err, wafv2.ErrCodeWAFInternalErrorException, "AWS WAF couldn’t perform the operation because of a system problem") {
				return resource.RetryableError(err)
			}
			return resource.NonRetryableError(err)
		}
		return nil
	})

	if isResourceTimeoutError(err) {
		_, err = conn.UpdateRegexPatternSet(&wafv2.UpdateRegexPatternSetInput{
			Id:        aws.String(d.Id()),
			Name:      aws.String(d.Get("name").(string)),
			Scope:     aws.String(d.Get("scope").(string)),
			LockToken: aws.String(d.Get("lock_token").(string)),
		})
	}

	if err != nil {
		return fmt.Errorf("Error updating WAFV2 RegexPatternSet: %s", err)
	}

	if d.HasChange("tags") {
		o, n := d.GetChange("tags")
		if err := keyvaluetags.Wafv2UpdateTags(conn, d.Get("arn").(string), o, n); err != nil {
			return fmt.Errorf("error updating tags: %s", err)
		}
	}

	return resourceAwsWafv2RegexPatternSetRead(d, meta)
}

func resourceAwsWafv2RegexPatternSetDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).wafv2conn

	log.Printf("[INFO] Deleting WAFV2 RegexPatternSet %s", d.Id())

	err := resource.Retry(15*time.Minute, func() *resource.RetryError {
		_, err := conn.DeleteRegexPatternSet(&wafv2.DeleteRegexPatternSetInput{
			Id:        aws.String(d.Id()),
			Name:      aws.String(d.Get("name").(string)),
			Scope:     aws.String(d.Get("scope").(string)),
			LockToken: aws.String(d.Get("lock_token").(string)),
		})

		if err != nil {
			if isAWSErr(err, wafv2.ErrCodeWAFInternalErrorException, "AWS WAF couldn’t perform the operation because of a system problem") {
				return resource.RetryableError(err)
			}
			return resource.NonRetryableError(err)
		}
		return nil
	})

	if isResourceTimeoutError(err) {
		_, err = conn.DeleteRegexPatternSet(&wafv2.DeleteRegexPatternSetInput{
			Id:        aws.String(d.Id()),
			Name:      aws.String(d.Get("name").(string)),
			Scope:     aws.String(d.Get("scope").(string)),
			LockToken: aws.String(d.Get("lock_token").(string)),
		})
	}

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

	return nil
}

func expandWafv2RegexPatternSet(l []interface{}) []*wafv2.Regex {
	if len(l) == 0 || l[0] == nil {
		return nil
	}

	regexPatterns := make([]*wafv2.Regex, 0)
	for _, regexPattern := range l {
		if regexPattern == nil {
			continue
		}

		regexPatterns = append(regexPatterns, expandWafv2Regex(regexPattern.(map[string]interface{})))
	}

	return regexPatterns
}

func expandWafv2Regex(m map[string]interface{}) *wafv2.Regex {
	if m == nil {
		return nil
	}

	return &wafv2.Regex{
		RegexString: aws.String(m["regex_string"].(string)),
	}
}
<commit_msg>Retry in case association is being removed<commit_after>package aws

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/wafv2"
	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
	"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
)

func resourceAwsWafv2RegexPatternSet() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsWafv2RegexPatternSetCreate,
		Read:   resourceAwsWafv2RegexPatternSetRead,
		Update: resourceAwsWafv2RegexPatternSetUpdate,
		Delete: resourceAwsWafv2RegexPatternSetDelete,
		Importer: &schema.ResourceImporter{
			State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
				idParts := strings.Split(d.Id(), "/")
				if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" {
					return nil, fmt.Errorf("Unexpected format of ID (%q), expected ID/NAME/SCOPE", d.Id())
				}
				id := idParts[0]
				name := idParts[1]
				scope := idParts[2]
				d.SetId(id)
				d.Set("name", name)
				d.Set("scope", scope)
				return []*schema.ResourceData{d}, nil
			},
		},

		Schema: map[string]*schema.Schema{
			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"description": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validation.StringLenBetween(1, 256),
			},
			"lock_token": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"name": {
				Type:         schema.TypeString,
				Required:     true,
				ForceNew:     true,
				ValidateFunc: validation.StringLenBetween(1, 128),
			},
			"regular_expression_list": {
				Type:     schema.TypeSet,
				Required: true,
				MinItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"regex_string": {
							Type:         schema.TypeString,
							Required:     true,
							ValidateFunc: validation.StringLenBetween(1, 512),
						},
					},
				},
			},
			"scope": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
				ValidateFunc: validation.StringInSlice([]string{
					wafv2.ScopeCloudfront,
					wafv2.ScopeRegional,
				}, false),
			},
			"tags": tagsSchema(),
		},
	}
}

func resourceAwsWafv2RegexPatternSetCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).wafv2conn
	var resp *wafv2.CreateRegexPatternSetOutput

	params := &wafv2.CreateRegexPatternSetInput{
		Name:  aws.String(d.Get("name").(string)),
		Scope: aws.String(d.Get("scope").(string)),
	}

	if d.HasChange("description") {
		params.Description = aws.String(d.Get("description").(string))
	}

	if v, ok := d.GetOk("regular_expression_list"); ok && v.(*schema.Set).Len() > 0 {
		params.RegularExpressionList = expandWafv2RegexPatternSet(d.Get("regular_expression_list").(*schema.Set).List())
	}

	if v := d.Get("tags").(map[string]interface{}); len(v) > 0 {
		params.Tags = keyvaluetags.New(v).IgnoreAws().Wafv2Tags()
	}

	err := resource.Retry(15*time.Minute, func() *resource.RetryError {
		var err error
		resp, err = conn.CreateRegexPatternSet(params)
		if err != nil {
			if isAWSErr(err, wafv2.ErrCodeWAFInternalErrorException, "AWS WAF couldn’t perform the operation because of a system problem") {
				return resource.RetryableError(err)
			}
			if isAWSErr(err, wafv2.ErrCodeWAFTagOperationException, "An error occurred during the tagging operation") {
				return resource.RetryableError(err)
			}
			if isAWSErr(err, wafv2.ErrCodeWAFTagOperationInternalErrorException, "AWS WAF couldn’t perform your tagging operation because of an internal error") {
				return resource.RetryableError(err)
			}
			return resource.NonRetryableError(err)
		}
		return nil
	})
	if isResourceTimeoutError(err) {
		_, err = conn.CreateRegexPatternSet(params)
	}
	if err != nil {
		return err
	}
	d.SetId(*resp.Summary.Id)

	return resourceAwsWafv2RegexPatternSetRead(d, meta)
}

func resourceAwsWafv2RegexPatternSetRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).wafv2conn

	params := &wafv2.GetRegexPatternSetInput{
		Id:    aws.String(d.Id()),
		Name:  aws.String(d.Get("name").(string)),
		Scope: aws.String(d.Get("scope").(string)),
	}

	resp, err := conn.GetRegexPatternSet(params)
	if err != nil {
		if isAWSErr(err, wafv2.ErrCodeWAFNonexistentItemException, "AWS WAF couldn’t perform the operation because your resource doesn’t exist") {
			log.Printf("[WARN] WAFV2 RegexPatternSet (%s) not found, removing from state", d.Id())
			d.SetId("")
			return nil
		}

		return err
	}

	d.Set("name", resp.RegexPatternSet.Name)
	d.Set("description", resp.RegexPatternSet.Description)
	d.Set("arn", resp.RegexPatternSet.ARN)
	d.Set("lock_token", resp.LockToken)

	if err := d.Set("regular_expression_list", flattenWafv2RegexPatternSet(resp.RegexPatternSet.RegularExpressionList)); err != nil {
		return fmt.Errorf("Error setting regular_expression_list: %s", err)
	}

	tags, err := keyvaluetags.Wafv2ListTags(conn, *resp.RegexPatternSet.ARN)
	if err != nil {
		return fmt.Errorf("error listing tags for WAFV2 RegexPatternSet (%s): %s", *resp.RegexPatternSet.ARN, err)
	}

	if err := d.Set("tags", tags.IgnoreAws().Map()); err != nil {
		return fmt.Errorf("error setting tags: %s", err)
	}

	return nil
}

func flattenWafv2RegexPatternSet(r []*wafv2.Regex) interface{} {
	regexPatterns := make([]interface{}, len(r))

	for i, regexPattern := range r {
		d := map[string]interface{}{
			"regex_string": *regexPattern.RegexString,
		}
		regexPatterns[i] = d
	}

	return regexPatterns
}

func resourceAwsWafv2RegexPatternSetUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).wafv2conn

	log.Printf("[INFO] Updating WAFV2 RegexPatternSet %s", d.Id())

	err := resource.Retry(15*time.Minute, func() *resource.RetryError {
		u := &wafv2.UpdateRegexPatternSetInput{
			Id:          aws.String(d.Id()),
			Name:        aws.String(d.Get("name").(string)),
			Scope:       aws.String(d.Get("scope").(string)),
			Description: aws.String(d.Get("description").(string)),
			LockToken:   aws.String(d.Get("lock_token").(string)),
		}

		if v, ok := d.GetOk("regular_expression_list"); ok && v.(*schema.Set).Len() > 0 {
			u.RegularExpressionList = expandWafv2RegexPatternSet(d.Get("regular_expression_list").(*schema.Set).List())
		}

		if d.HasChange("description") {
			u.Description = aws.String(d.Get("description").(string))
		}

		_, err := conn.UpdateRegexPatternSet(u)

		if err != nil {
			if isAWSErr(err, wafv2.ErrCodeWAFInternalErrorException, "AWS WAF couldn’t perform the operation because of a system problem") {
				return resource.RetryableError(err)
			}
			return resource.NonRetryableError(err)
		}
		return nil
	})

	if isResourceTimeoutError(err) {
		_, err = conn.UpdateRegexPatternSet(&wafv2.UpdateRegexPatternSetInput{
			Id:        aws.String(d.Id()),
			Name:      aws.String(d.Get("name").(string)),
			Scope:     aws.String(d.Get("scope").(string)),
			LockToken: aws.String(d.Get("lock_token").(string)),
		})
	}

	if err != nil {
		return fmt.Errorf("Error updating WAFV2 RegexPatternSet: %s", err)
	}

	if d.HasChange("tags") {
		o, n := d.GetChange("tags")
		if err := keyvaluetags.Wafv2UpdateTags(conn, d.Get("arn").(string), o, n); err != nil {
			return fmt.Errorf("error updating tags: %s", err)
		}
	}

	return resourceAwsWafv2RegexPatternSetRead(d, meta)
}

func resourceAwsWafv2RegexPatternSetDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).wafv2conn

	log.Printf("[INFO] Deleting WAFV2 RegexPatternSet %s", d.Id())

	err := resource.Retry(15*time.Minute, func() *resource.RetryError {
		_, err := conn.DeleteRegexPatternSet(&wafv2.DeleteRegexPatternSetInput{
			Id:        aws.String(d.Id()),
			Name:      aws.String(d.Get("name").(string)),
			Scope:     aws.String(d.Get("scope").(string)),
			LockToken: aws.String(d.Get("lock_token").(string)),
		})

		if err != nil {
			if isAWSErr(err, wafv2.ErrCodeWAFInternalErrorException, "AWS WAF couldn’t perform the operation because of a system problem") {
				return resource.RetryableError(err)
			}
			if isAWSErr(err, wafv2.ErrCodeWAFAssociatedItemException, "AWS WAF couldn’t perform the operation because your resource is being used by another resource or it’s associated with another resource") {
				return resource.RetryableError(err)
			}
			return resource.NonRetryableError(err)
		}
		return nil
	})

	if isResourceTimeoutError(err) {
		_, err = conn.DeleteRegexPatternSet(&wafv2.DeleteRegexPatternSetInput{
			Id:        aws.String(d.Id()),
			Name:      aws.String(d.Get("name").(string)),
			Scope:     aws.String(d.Get("scope").(string)),
			LockToken: aws.String(d.Get("lock_token").(string)),
		})
	}

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

	return nil
}

func expandWafv2RegexPatternSet(l []interface{}) []*wafv2.Regex {
	if len(l) == 0 || l[0] == nil {
		return nil
	}

	regexPatterns := make([]*wafv2.Regex, 0)
	for _, regexPattern := range l {
		if regexPattern == nil {
			continue
		}

		regexPatterns = append(regexPatterns, expandWafv2Regex(regexPattern.(map[string]interface{})))
	}

	return regexPatterns
}

func expandWafv2Regex(m map[string]interface{}) *wafv2.Regex {
	if m == nil {
		return nil
	}

	return &wafv2.Regex{
		RegexString: aws.String(m["regex_string"].(string)),
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/csv"
	"fmt"
	"io"
	"net/http"
	"os"
)

type redirectInfo struct {
	Url         string
	ExpectedUrl string
}

type actualRedirect struct {
	OriginUrl     string
	RedirectedUrl string
	ErrorCode     int
}

type redirectResult struct {
	Url              string
	ExpectedUrl      string
	Redirects        int
	IntermediateUrls []actualRedirect
	FinalUrl         string
	Error            error
}

func readCsv(name string) []redirectInfo {
	csvFile, err := os.Open(name)
	defer csvFile.Close()

	if err != nil {
		panic(err)
	}

	csvReader := csv.NewReader(csvFile)
	result := make([]redirectInfo, 0)
	for {
		fields, err := csvReader.Read()
		if err == io.EOF {
			break
		} else if err != nil {
			panic(err)
		}

		info := redirectInfo{fields[0], fields[1]}

		result = append(result, info)
	}

	return result
}

func checkUrl(info redirectInfo) redirectResult {
	currentUrl := info.Url
	expected := info.ExpectedUrl

	redirects := 0
	nextUrl := currentUrl
	for {
		if redirects > 5 {
			break
		}

		req, err := http.NewRequest("GET", nextUrl, nil)
		resp, err := http.DefaultTransport.RoundTrip(req)

		if err != nil {
			break
		}

		if resp.StatusCode != 301 {
			break
		}

		redirects++
	}

	result := redirectResult{
		Url:         currentUrl,
		ExpectedUrl: expected,
		Redirects:   redirects,
		//IntermediateUrls:
		//FinalUrl: ,
		//Error: err,
	}

	return result
}

func main() {
	redirects := readCsv("301s.csv")

	fmt.Println(redirects)

	log := make([]redirectResult, 0)

	for _, info := range redirects {
		result := checkUrl(info)
		log = append(log, result)
	}

	fmt.Println(log)
}
<commit_msg>Updates to get urls and track redirects<commit_after>package main

import (
	"encoding/csv"
	"fmt"
	"io"
	"net/http"
	"os"
)

type redirectInfo struct {
	Url         string
	ExpectedUrl string
}

type actualRedirect struct {
	OriginUrl     string
	RedirectedUrl string
	ErrorCode     int
}

type redirectResult struct {
	Url              string
	ExpectedUrl      string
	Redirects        int
	IntermediateUrls []actualRedirect
	FinalUrl         string
	Error            error
}

func (rr *redirectResult) AppendIntermediate(nextUrl string, redirected string, code int) {
	intermediateUrl := actualRedirect{
		OriginUrl:     nextUrl,
		RedirectedUrl: redirected,
		ErrorCode:     code,
	}

	rr.IntermediateUrls = append(rr.IntermediateUrls, intermediateUrl)
}

func readCsv(name string) []redirectInfo {
	csvFile, err := os.Open(name)
	defer csvFile.Close()

	if err != nil {
		panic(err)
	}

	csvReader := csv.NewReader(csvFile)
	result := make([]redirectInfo, 0)
	for {
		fields, err := csvReader.Read()
		if err == io.EOF {
			break
		} else if err != nil {
			panic(err)
		}

		info := redirectInfo{fields[0], fields[1]}

		result = append(result, info)
	}

	return result
}

func checkUrl(info redirectInfo) redirectResult {

	result := redirectResult{
		Url:              info.Url,
		ExpectedUrl:      info.ExpectedUrl,
		Redirects:        0,
		IntermediateUrls: make([]actualRedirect, 0),
		Error:            nil,
	}

	nextUrl := info.Url
	for {
		if result.Redirects > 5 {
			break
		}

		req, err := http.NewRequest("GET", nextUrl, nil)
		resp, err := http.DefaultTransport.RoundTrip(req)

		if err != nil {
			result.Error = err
			break
		}

		redirectTo := resp.Header.Get("Location")
		result.AppendIntermediate(nextUrl, redirectTo, resp.StatusCode)
		result.FinalUrl = nextUrl

		if resp.StatusCode != 301 {
			break
		}

		result.Redirects++

		nextUrl = redirectTo
	}

	return result
}

func main() {
	redirects := readCsv("301s.csv")

	log := make([]redirectResult, 0)

	for _, info := range redirects {
		result := checkUrl(info)
		log = append(log, result)
	}

	for _, logItem := range log {
		fmt.Printf("Original Url: %v\n", logItem.Url)
		fmt.Printf("Final Url: %v\n", logItem.FinalUrl)
		fmt.Printf("Expected Url: %v\n", logItem.ExpectedUrl)
		fmt.Printf("Number of Redirects: %v\n", logItem.Redirects)
		fmt.Printf("\n")
	}

	//fmt.Println(log)
}
<|endoftext|>


<commit_before>package dht

// get_peers and announce_peers.

import (
	"time"

	"github.com/anacrolix/sync"
	"github.com/anacrolix/torrent/logonce"
	"github.com/willf/bloom"

	"github.com/anacrolix/dht/krpc"
)

// Maintains state for an ongoing Announce operation. An Announce is started
// by calling Server.Announce.
type Announce struct {
	mu    sync.Mutex
	Peers chan PeersValues
	// Inner chan is set to nil when on close.
	values     chan PeersValues
	stop       chan struct{}
	triedAddrs *bloom.BloomFilter
	// True when contact with all starting addrs has been initiated. This
	// prevents a race where the first transaction finishes before the rest
	// have been opened, sees no other transactions are pending and ends the
	// announce.
	contactedStartAddrs bool
	// How many transactions are still ongoing.
	pending  int
	server   *Server
	infoHash int160
	// Count of (probably) distinct addresses we've sent get_peers requests
	// to.
	numContacted int
	// The torrent port that we're announcing.
	announcePort int
	// The torrent port should be determined by the receiver in case we're
	// being NATed.
	announcePortImplied bool
}

// Returns the number of distinct remote addresses the announce has queried.
func (a *Announce) NumContacted() int {
	a.mu.Lock()
	defer a.mu.Unlock()
	return a.numContacted
}

func newBloomFilterForTraversal() *bloom.BloomFilter {
	return bloom.NewWithEstimates(1000, 0.5)
}

// This is kind of the main thing you want to do with DHT. It traverses the
// graph toward nodes that store peers for the infohash, streaming them to the
// caller, and announcing the local node to each node if allowed and
// specified.
func (s *Server) Announce(infoHash [20]byte, port int, impliedPort bool) (*Announce, error) {
	startAddrs, err := s.traversalStartingAddrs()
	if err != nil {
		return nil, err
	}
	disc := &Announce{
		Peers:               make(chan PeersValues, 100),
		stop:                make(chan struct{}),
		values:              make(chan PeersValues),
		triedAddrs:          newBloomFilterForTraversal(),
		server:              s,
		infoHash:            int160FromByteArray(infoHash),
		announcePort:        port,
		announcePortImplied: impliedPort,
	}
	// Function ferries from values to Values until discovery is halted.
	go func() {
		defer close(disc.Peers)
		for {
			select {
			case psv := <-disc.values:
				select {
				case disc.Peers <- psv:
				case <-disc.stop:
					return
				}
			case <-disc.stop:
				return
			}
		}
	}()
	go func() {
		disc.mu.Lock()
		defer disc.mu.Unlock()
		for i, addr := range startAddrs {
			if i != 0 {
				disc.mu.Unlock()
				time.Sleep(time.Millisecond)
				disc.mu.Lock()
			}
			disc.contact(addr)
		}
		disc.contactedStartAddrs = true
		// If we failed to contact any of the starting addrs, no transactions
		// will complete triggering a check that there are no pending
		// responses.
		disc.maybeClose()
	}()
	return disc, nil
}

func validNodeAddr(addr Addr) bool {
	ua := addr.UDPAddr()
	if ua.Port == 0 {
		return false
	}
	if ip4 := ua.IP.To4(); ip4 != nil && ip4[0] == 0 {
		return false
	}
	return true
}

// TODO: Merge this with maybeGetPeersFromAddr.
func (a *Announce) gotNodeAddr(addr Addr) {
	if !validNodeAddr(addr) {
		return
	}
	if a.triedAddrs.Test([]byte(addr.String())) {
		return
	}
	if a.server.ipBlocked(addr.UDPAddr().IP) {
		return
	}
	a.contact(addr)
}

// TODO: Merge this with maybeGetPeersFromAddr.
func (a *Announce) contact(addr Addr) {
	a.numContacted++
	a.triedAddrs.Add([]byte(addr.String()))
	a.pending++
	go func() {
		err := a.getPeers(addr)
		if err == nil {
			return
		}
		a.mu.Lock()
		a.transactionClosed()
		a.mu.Unlock()
	}()
}

func (a *Announce) maybeClose() {
	if a.contactedStartAddrs && a.pending == 0 {
		a.close()
	}
}

func (a *Announce) transactionClosed() {
	a.pending--
	a.maybeClose()
}

func (a *Announce) responseNode(node krpc.NodeInfo) {
	a.gotNodeAddr(NewAddr(node.Addr.UDP()))
}

// Announce to a peer, if appropriate.
func (a *Announce) maybeAnnouncePeer(to Addr, token string, peerId *krpc.ID) {
	if !a.server.config.NoSecurity && (peerId == nil || !NodeIdSecure(*peerId, to.UDPAddr().IP)) {
		return
	}
	a.server.mu.Lock()
	defer a.server.mu.Unlock()
	err := a.server.announcePeer(to, a.infoHash, a.announcePort, token, a.announcePortImplied, nil)
	if err != nil {
		logonce.Stderr.Printf("error announcing peer: %s", err)
	}
}

func (a *Announce) getPeers(addr Addr) error {
	a.server.mu.Lock()
	defer a.server.mu.Unlock()
	return a.server.getPeers(addr, a.infoHash, func(m krpc.Msg, err error) {
		// Register suggested nodes closer to the target info-hash.
		if m.R != nil && m.SenderID() != nil {
			expvars.Add("announce get_peers response nodes values", int64(len(m.R.Nodes)))
			expvars.Add("announce get_peers response nodes6 values", int64(len(m.R.Nodes6)))
			a.mu.Lock()
			for _, n := range m.R.Nodes {
				a.responseNode(n)
			}
			for _, n := range m.R.Nodes6 {
				a.responseNode(n)
			}
			a.mu.Unlock()
			select {
			case a.values <- PeersValues{
				Peers: m.R.Values,
				NodeInfo: krpc.NodeInfo{
					Addr: addr.KRPC(),
					ID:   *m.SenderID(),
				},
			}:
			case <-a.stop:
			}
			a.maybeAnnouncePeer(addr, m.R.Token, m.SenderID())
		}
		a.mu.Lock()
		a.transactionClosed()
		a.mu.Unlock()
	})
}

// Corresponds to the "values" key in a get_peers KRPC response. A list of
// peers that a node has reported as being in the swarm for a queried info
// hash.
type PeersValues struct {
	Peers         []Peer // Peers given in get_peers response.
	krpc.NodeInfo        // The node that gave the response.
}

// Stop the announce.
func (a *Announce) Close() {
	a.mu.Lock()
	defer a.mu.Unlock()
	a.close()
}

func (a *Announce) close() {
	select {
	case <-a.stop:
	default:
		close(a.stop)
	}
}
<commit_msg>Raise the traversal bloom filter capacity to 10k<commit_after>package dht

// get_peers and announce_peers.

import (
	"time"

	"github.com/anacrolix/sync"
	"github.com/anacrolix/torrent/logonce"
	"github.com/willf/bloom"

	"github.com/anacrolix/dht/krpc"
)

// Maintains state for an ongoing Announce operation. An Announce is started
// by calling Server.Announce.
type Announce struct {
	mu    sync.Mutex
	Peers chan PeersValues
	// Inner chan is set to nil when on close.
	values     chan PeersValues
	stop       chan struct{}
	triedAddrs *bloom.BloomFilter
	// True when contact with all starting addrs has been initiated. This
	// prevents a race where the first transaction finishes before the rest
	// have been opened, sees no other transactions are pending and ends the
	// announce.
	contactedStartAddrs bool
	// How many transactions are still ongoing.
	pending  int
	server   *Server
	infoHash int160
	// Count of (probably) distinct addresses we've sent get_peers requests
	// to.
	numContacted int
	// The torrent port that we're announcing.
	announcePort int
	// The torrent port should be determined by the receiver in case we're
	// being NATed.
	announcePortImplied bool
}

// Returns the number of distinct remote addresses the announce has queried.
func (a *Announce) NumContacted() int {
	a.mu.Lock()
	defer a.mu.Unlock()
	return a.numContacted
}

func newBloomFilterForTraversal() *bloom.BloomFilter {
	return bloom.NewWithEstimates(10000, 0.5)
}

// This is kind of the main thing you want to do with DHT. It traverses the
// graph toward nodes that store peers for the infohash, streaming them to the
// caller, and announcing the local node to each node if allowed and
// specified.
func (s *Server) Announce(infoHash [20]byte, port int, impliedPort bool) (*Announce, error) {
	startAddrs, err := s.traversalStartingAddrs()
	if err != nil {
		return nil, err
	}
	disc := &Announce{
		Peers:               make(chan PeersValues, 100),
		stop:                make(chan struct{}),
		values:              make(chan PeersValues),
		triedAddrs:          newBloomFilterForTraversal(),
		server:              s,
		infoHash:            int160FromByteArray(infoHash),
		announcePort:        port,
		announcePortImplied: impliedPort,
	}
	// Function ferries from values to Values until discovery is halted.
	go func() {
		defer close(disc.Peers)
		for {
			select {
			case psv := <-disc.values:
				select {
				case disc.Peers <- psv:
				case <-disc.stop:
					return
				}
			case <-disc.stop:
				return
			}
		}
	}()
	go func() {
		disc.mu.Lock()
		defer disc.mu.Unlock()
		for i, addr := range startAddrs {
			if i != 0 {
				disc.mu.Unlock()
				time.Sleep(time.Millisecond)
				disc.mu.Lock()
			}
			disc.contact(addr)
		}
		disc.contactedStartAddrs = true
		// If we failed to contact any of the starting addrs, no transactions
		// will complete triggering a check that there are no pending
		// responses.
		disc.maybeClose()
	}()
	return disc, nil
}

func validNodeAddr(addr Addr) bool {
	ua := addr.UDPAddr()
	if ua.Port == 0 {
		return false
	}
	if ip4 := ua.IP.To4(); ip4 != nil && ip4[0] == 0 {
		return false
	}
	return true
}

// TODO: Merge this with maybeGetPeersFromAddr.
func (a *Announce) gotNodeAddr(addr Addr) {
	if !validNodeAddr(addr) {
		return
	}
	if a.triedAddrs.Test([]byte(addr.String())) {
		return
	}
	if a.server.ipBlocked(addr.UDPAddr().IP) {
		return
	}
	a.contact(addr)
}

// TODO: Merge this with maybeGetPeersFromAddr.
func (a *Announce) contact(addr Addr) {
	a.numContacted++
	a.triedAddrs.Add([]byte(addr.String()))
	a.pending++
	go func() {
		err := a.getPeers(addr)
		if err == nil {
			return
		}
		a.mu.Lock()
		a.transactionClosed()
		a.mu.Unlock()
	}()
}

func (a *Announce) maybeClose() {
	if a.contactedStartAddrs && a.pending == 0 {
		a.close()
	}
}

func (a *Announce) transactionClosed() {
	a.pending--
	a.maybeClose()
}

func (a *Announce) responseNode(node krpc.NodeInfo) {
	a.gotNodeAddr(NewAddr(node.Addr.UDP()))
}

// Announce to a peer, if appropriate.
func (a *Announce) maybeAnnouncePeer(to Addr, token string, peerId *krpc.ID) {
	if !a.server.config.NoSecurity && (peerId == nil || !NodeIdSecure(*peerId, to.UDPAddr().IP)) {
		return
	}
	a.server.mu.Lock()
	defer a.server.mu.Unlock()
	err := a.server.announcePeer(to, a.infoHash, a.announcePort, token, a.announcePortImplied, nil)
	if err != nil {
		logonce.Stderr.Printf("error announcing peer: %s", err)
	}
}

func (a *Announce) getPeers(addr Addr) error {
	a.server.mu.Lock()
	defer a.server.mu.Unlock()
	return a.server.getPeers(addr, a.infoHash, func(m krpc.Msg, err error) {
		// Register suggested nodes closer to the target info-hash.
		if m.R != nil && m.SenderID() != nil {
			expvars.Add("announce get_peers response nodes values", int64(len(m.R.Nodes)))
			expvars.Add("announce get_peers response nodes6 values", int64(len(m.R.Nodes6)))
			a.mu.Lock()
			for _, n := range m.R.Nodes {
				a.responseNode(n)
			}
			for _, n := range m.R.Nodes6 {
				a.responseNode(n)
			}
			a.mu.Unlock()
			select {
			case a.values <- PeersValues{
				Peers: m.R.Values,
				NodeInfo: krpc.NodeInfo{
					Addr: addr.KRPC(),
					ID:   *m.SenderID(),
				},
			}:
			case <-a.stop:
			}
			a.maybeAnnouncePeer(addr, m.R.Token, m.SenderID())
		}
		a.mu.Lock()
		a.transactionClosed()
		a.mu.Unlock()
	})
}

// Corresponds to the "values" key in a get_peers KRPC response. A list of
// peers that a node has reported as being in the swarm for a queried info
// hash.
type PeersValues struct {
	Peers         []Peer // Peers given in get_peers response.
	krpc.NodeInfo        // The node that gave the response.
}

// Stop the announce.
func (a *Announce) Close() {
	a.mu.Lock()
	defer a.mu.Unlock()
	a.close()
}

func (a *Announce) close() {
	select {
	case <-a.stop:
	default:
		close(a.stop)
	}
}
<|endoftext|>


<commit_before>package dht

// get_peers and announce_peers.

import (
	"log"
	"time"

	"github.com/anacrolix/sync"
	"github.com/willf/bloom"

	"github.com/anacrolix/torrent/logonce"
)

// Maintains state for an ongoing Announce operation. An Announce is started
// by calling Server.Announce.
type Announce struct {
	mu    sync.Mutex
	Peers chan PeersValues
	// Inner chan is set to nil when on close.
	values     chan PeersValues
	stop       chan struct{}
	triedAddrs *bloom.BloomFilter
	// True when contact with all starting addrs has been initiated. This
	// prevents a race where the first transaction finishes before the rest
	// have been opened, sees no other transactions are pending and ends the
	// announce.
	contactedStartAddrs bool
	// How many transactions are still ongoing.
	pending  int
	server   *Server
	infoHash string
	// Count of (probably) distinct addresses we've sent get_peers requests
	// to.
	numContacted int
	// The torrent port that we're announcing.
	announcePort int
	// The torrent port should be determined by the receiver in case we're
	// being NATed.
	announcePortImplied bool
}

// Returns the number of distinct remote addresses the announce has queried.
func (a *Announce) NumContacted() int {
	a.mu.Lock()
	defer a.mu.Unlock()
	return a.numContacted
}

// This is kind of the main thing you want to do with DHT. It traverses the
// graph toward nodes that store peers for the infohash, streaming them to the
// caller, and announcing the local node to each node if allowed and
// specified.
func (s *Server) Announce(infoHash string, port int, impliedPort bool) (*Announce, error) {
	s.mu.Lock()
	startAddrs := func() (ret []Addr) {
		for _, n := range s.closestGoodNodes(160, infoHash) {
			ret = append(ret, n.addr)
		}
		return
	}()
	s.mu.Unlock()
	if len(startAddrs) == 0 {
		addrs, err := bootstrapAddrs(s.bootstrapNodes)
		if err != nil {
			return nil, err
		}
		for _, addr := range addrs {
			startAddrs = append(startAddrs, NewAddr(addr))
		}
	}
	disc := &Announce{
		Peers:               make(chan PeersValues, 100),
		stop:                make(chan struct{}),
		values:              make(chan PeersValues),
		triedAddrs:          bloom.NewWithEstimates(1000, 0.5),
		server:              s,
		infoHash:            infoHash,
		announcePort:        port,
		announcePortImplied: impliedPort,
	}
	// Function ferries from values to Values until discovery is halted.
	go func() {
		defer close(disc.Peers)
		for {
			select {
			case psv := <-disc.values:
				select {
				case disc.Peers <- psv:
				case <-disc.stop:
					return
				}
			case <-disc.stop:
				return
			}
		}
	}()
	go func() {
		for i, addr := range startAddrs {
			if i != 0 {
				time.Sleep(time.Millisecond)
			}
			disc.mu.Lock()
			disc.contact(addr)
			disc.mu.Unlock()
		}
		disc.contactedStartAddrs = true
		// If we failed to contact any of the starting addrs, no transactions
		// will complete triggering a check that there are no pending
		// responses.
		disc.maybeClose()
	}()
	return disc, nil
}

// TODO: Merge this with maybeGetPeersFromAddr.
func (a *Announce) gotNodeAddr(addr Addr) {
	if addr.UDPAddr().Port == 0 {
		// Not a contactable address.
		return
	}
	if a.triedAddrs.Test([]byte(addr.String())) {
		return
	}
	if a.server.ipBlocked(addr.UDPAddr().IP) {
		return
	}
	a.server.mu.Lock()
	if a.server.badNodes.Test([]byte(addr.String())) {
		a.server.mu.Unlock()
		return
	}
	a.server.mu.Unlock()
	a.contact(addr)
}

// TODO: Merge this with maybeGetPeersFromAddr.
func (a *Announce) contact(addr Addr) {
	a.numContacted++
	a.triedAddrs.Add([]byte(addr.String()))
	if err := a.getPeers(addr); err != nil {
		log.Printf("error sending get_peers request to %s: %#v", addr, err)
		return
	}
	a.pending++
}

func (a *Announce) maybeClose() {
	if a.contactedStartAddrs && a.pending == 0 {
		a.close()
	}
}

func (a *Announce) transactionClosed() {
	a.pending--
	a.maybeClose()
}

func (a *Announce) responseNode(node NodeInfo) {
	a.gotNodeAddr(node.Addr)
}

func (a *Announce) closingCh() chan struct{} {
	return a.stop
}

// Announce to a peer, if appropriate.
func (a *Announce) maybeAnnouncePeer(to Addr, token, peerId string) {
	a.server.mu.Lock()
	defer a.server.mu.Unlock()
	if !a.server.config.NoSecurity {
		if len(peerId) != 20 {
			return
		}
		if !NodeIdSecure(peerId, to.UDPAddr().IP) {
			return
		}
	}
	err := a.server.announcePeer(to, a.infoHash, a.announcePort, token, a.announcePortImplied)
	if err != nil {
		logonce.Stderr.Printf("error announcing peer: %s", err)
	}
}

func (a *Announce) getPeers(addr Addr) error {
	a.server.mu.Lock()
	defer a.server.mu.Unlock()
	t, err := a.server.getPeers(addr, a.infoHash)
	if err != nil {
		return err
	}
	t.SetResponseHandler(func(m Msg, ok bool) {
		// Register suggested nodes closer to the target info-hash.
		if m.R != nil {
			a.mu.Lock()
			for _, n := range m.R.Nodes {
				a.responseNode(n)
			}
			a.mu.Unlock()

			if vs := m.R.Values; len(vs) != 0 {
				nodeInfo := NodeInfo{
					Addr: t.remoteAddr,
				}
				copy(nodeInfo.ID[:], m.SenderID())
				select {
				case a.values <- PeersValues{
					Peers: func() (ret []Peer) {
						for _, cp := range vs {
							ret = append(ret, Peer(cp))
						}
						return
					}(),
					NodeInfo: nodeInfo,
				}:
				case <-a.stop:
				}
			}

			a.maybeAnnouncePeer(addr, m.R.Token, m.SenderID())
		}

		a.mu.Lock()
		a.transactionClosed()
		a.mu.Unlock()
	})
	return nil
}

// Corresponds to the "values" key in a get_peers KRPC response. A list of
// peers that a node has reported as being in the swarm for a queried info
// hash.
type PeersValues struct {
	Peers    []Peer // Peers given in get_peers response.
	NodeInfo        // The node that gave the response.
}

// Stop the announce.
func (a *Announce) Close() {
	a.mu.Lock()
	defer a.mu.Unlock()
	a.close()
}

func (a *Announce) close() {
	select {
	case <-a.stop:
	default:
		close(a.stop)
	}
}
<commit_msg>dht: Fix race contacting starting addrs in Announce<commit_after>package dht

// get_peers and announce_peers.

import (
	"log"
	"time"

	"github.com/anacrolix/sync"
	"github.com/willf/bloom"

	"github.com/anacrolix/torrent/logonce"
)

// Maintains state for an ongoing Announce operation. An Announce is started
// by calling Server.Announce.
type Announce struct {
	mu    sync.Mutex
	Peers chan PeersValues
	// Inner chan is set to nil when on close.
	values     chan PeersValues
	stop       chan struct{}
	triedAddrs *bloom.BloomFilter
	// True when contact with all starting addrs has been initiated. This
	// prevents a race where the first transaction finishes before the rest
	// have been opened, sees no other transactions are pending and ends the
	// announce.
	contactedStartAddrs bool
	// How many transactions are still ongoing.
	pending  int
	server   *Server
	infoHash string
	// Count of (probably) distinct addresses we've sent get_peers requests
	// to.
	numContacted int
	// The torrent port that we're announcing.
	announcePort int
	// The torrent port should be determined by the receiver in case we're
	// being NATed.
	announcePortImplied bool
}

// Returns the number of distinct remote addresses the announce has queried.
func (a *Announce) NumContacted() int {
	a.mu.Lock()
	defer a.mu.Unlock()
	return a.numContacted
}

// This is kind of the main thing you want to do with DHT. It traverses the
// graph toward nodes that store peers for the infohash, streaming them to the
// caller, and announcing the local node to each node if allowed and
// specified.
func (s *Server) Announce(infoHash string, port int, impliedPort bool) (*Announce, error) {
	s.mu.Lock()
	startAddrs := func() (ret []Addr) {
		for _, n := range s.closestGoodNodes(160, infoHash) {
			ret = append(ret, n.addr)
		}
		return
	}()
	s.mu.Unlock()
	if len(startAddrs) == 0 {
		addrs, err := bootstrapAddrs(s.bootstrapNodes)
		if err != nil {
			return nil, err
		}
		for _, addr := range addrs {
			startAddrs = append(startAddrs, NewAddr(addr))
		}
	}
	disc := &Announce{
		Peers:               make(chan PeersValues, 100),
		stop:                make(chan struct{}),
		values:              make(chan PeersValues),
		triedAddrs:          bloom.NewWithEstimates(1000, 0.5),
		server:              s,
		infoHash:            infoHash,
		announcePort:        port,
		announcePortImplied: impliedPort,
	}
	// Function ferries from values to Values until discovery is halted.
	go func() {
		defer close(disc.Peers)
		for {
			select {
			case psv := <-disc.values:
				select {
				case disc.Peers <- psv:
				case <-disc.stop:
					return
				}
			case <-disc.stop:
				return
			}
		}
	}()
	go func() {
		disc.mu.Lock()
		defer disc.mu.Unlock()
		for i, addr := range startAddrs {
			if i != 0 {
				disc.mu.Unlock()
				time.Sleep(time.Millisecond)
				disc.mu.Lock()
			}
			disc.contact(addr)
		}
		disc.contactedStartAddrs = true
		// If we failed to contact any of the starting addrs, no transactions
		// will complete triggering a check that there are no pending
		// responses.
		disc.maybeClose()
	}()
	return disc, nil
}

// TODO: Merge this with maybeGetPeersFromAddr.
func (a *Announce) gotNodeAddr(addr Addr) {
	if addr.UDPAddr().Port == 0 {
		// Not a contactable address.
		return
	}
	if a.triedAddrs.Test([]byte(addr.String())) {
		return
	}
	if a.server.ipBlocked(addr.UDPAddr().IP) {
		return
	}
	a.server.mu.Lock()
	if a.server.badNodes.Test([]byte(addr.String())) {
		a.server.mu.Unlock()
		return
	}
	a.server.mu.Unlock()
	a.contact(addr)
}

// TODO: Merge this with maybeGetPeersFromAddr.
func (a *Announce) contact(addr Addr) {
	a.numContacted++
	a.triedAddrs.Add([]byte(addr.String()))
	if err := a.getPeers(addr); err != nil {
		log.Printf("error sending get_peers request to %s: %#v", addr, err)
		return
	}
	a.pending++
}

func (a *Announce) maybeClose() {
	if a.contactedStartAddrs && a.pending == 0 {
		a.close()
	}
}

func (a *Announce) transactionClosed() {
	a.pending--
	a.maybeClose()
}

func (a *Announce) responseNode(node NodeInfo) {
	a.gotNodeAddr(node.Addr)
}

func (a *Announce) closingCh() chan struct{} {
	return a.stop
}

// Announce to a peer, if appropriate.
func (a *Announce) maybeAnnouncePeer(to Addr, token, peerId string) {
	a.server.mu.Lock()
	defer a.server.mu.Unlock()
	if !a.server.config.NoSecurity {
		if len(peerId) != 20 {
			return
		}
		if !NodeIdSecure(peerId, to.UDPAddr().IP) {
			return
		}
	}
	err := a.server.announcePeer(to, a.infoHash, a.announcePort, token, a.announcePortImplied)
	if err != nil {
		logonce.Stderr.Printf("error announcing peer: %s", err)
	}
}

func (a *Announce) getPeers(addr Addr) error {
	a.server.mu.Lock()
	defer a.server.mu.Unlock()
	t, err := a.server.getPeers(addr, a.infoHash)
	if err != nil {
		return err
	}
	t.SetResponseHandler(func(m Msg, ok bool) {
		// Register suggested nodes closer to the target info-hash.
		if m.R != nil {
			a.mu.Lock()
			for _, n := range m.R.Nodes {
				a.responseNode(n)
			}
			a.mu.Unlock()

			if vs := m.R.Values; len(vs) != 0 {
				nodeInfo := NodeInfo{
					Addr: t.remoteAddr,
				}
				copy(nodeInfo.ID[:], m.SenderID())
				select {
				case a.values <- PeersValues{
					Peers: func() (ret []Peer) {
						for _, cp := range vs {
							ret = append(ret, Peer(cp))
						}
						return
					}(),
					NodeInfo: nodeInfo,
				}:
				case <-a.stop:
				}
			}

			a.maybeAnnouncePeer(addr, m.R.Token, m.SenderID())
		}

		a.mu.Lock()
		a.transactionClosed()
		a.mu.Unlock()
	})
	return nil
}

// Corresponds to the "values" key in a get_peers KRPC response. A list of
// peers that a node has reported as being in the swarm for a queried info
// hash.
type PeersValues struct {
	Peers    []Peer // Peers given in get_peers response.
	NodeInfo        // The node that gave the response.
}

// Stop the announce.
func (a *Announce) Close() {
	a.mu.Lock()
	defer a.mu.Unlock()
	a.close()
}

func (a *Announce) close() {
	select {
	case <-a.stop:
	default:
		close(a.stop)
	}
}
<|endoftext|>


<commit_before>package quic

import (
	"bytes"
	"errors"
	"fmt"

	"github.com/lucas-clemente/quic-go/crypto"
	"github.com/lucas-clemente/quic-go/frames"
	"github.com/lucas-clemente/quic-go/protocol"
	"github.com/lucas-clemente/quic-go/qerr"
)

type unpackedPacket struct {
	entropyBit bool
	frames     []frames.Frame
}

type packetUnpacker struct {
	version protocol.VersionNumber
	aead    crypto.AEAD
}

func (u *packetUnpacker) Unpack(publicHeaderBinary []byte, hdr *PublicHeader, data []byte) (*unpackedPacket, error) {
	data, err := u.aead.Open(data[:0], data, hdr.PacketNumber, publicHeaderBinary)
	if err != nil {
		// Wrap err in quicError so that public reset is sent by session
		return nil, qerr.Error(qerr.DecryptionFailure, err.Error())
	}
	r := bytes.NewReader(data)

	// read private flag byte, for QUIC Version < 34
	var entropyBit bool
	if u.version < protocol.Version34 {
		var privateFlag uint8
		privateFlag, err = r.ReadByte()
		if err != nil {
			return nil, qerr.MissingPayload
		}
		entropyBit = privateFlag&0x01 > 0
	}

	if r.Len() == 0 {
		return nil, qerr.MissingPayload
	}

	fs := make([]frames.Frame, 0, 2)

	// Read all frames in the packet
ReadLoop:
	for r.Len() > 0 {
		typeByte, _ := r.ReadByte()
		r.UnreadByte()

		var frame frames.Frame
		if typeByte&0x80 == 0x80 {
			frame, err = frames.ParseStreamFrame(r)
			if err != nil {
				err = qerr.Error(qerr.InvalidStreamData, err.Error())
			}
		} else if typeByte&0xc0 == 0x40 {
			frame, err = frames.ParseAckFrame(r, u.version)
			if err != nil {
				err = qerr.Error(qerr.InvalidAckData, err.Error())
			}
		} else if typeByte&0xe0 == 0x20 {
			err = errors.New("unimplemented: CONGESTION_FEEDBACK")
		} else {
			switch typeByte {
			case 0x0: // PAD, end of frames
				break ReadLoop
			case 0x01:
				frame, err = frames.ParseRstStreamFrame(r)
				if err != nil {
					err = qerr.Error(qerr.InvalidRstStreamData, err.Error())
				}
			case 0x02:
				frame, err = frames.ParseConnectionCloseFrame(r)
				if err != nil {
					err = qerr.Error(qerr.InvalidConnectionCloseData, err.Error())
				}
			case 0x03:
				frame, err = frames.ParseGoawayFrame(r)
				if err != nil {
					err = qerr.Error(qerr.InvalidGoawayData, err.Error())
				}
			case 0x04:
				frame, err = frames.ParseWindowUpdateFrame(r)
				if err != nil {
					err = qerr.Error(qerr.InvalidWindowUpdateData, err.Error())
				}
			case 0x05:
				frame, err = frames.ParseBlockedFrame(r)
				if err != nil {
					err = qerr.Error(qerr.InvalidBlockedData, err.Error())
				}
			case 0x06:
				frame, err = frames.ParseStopWaitingFrame(r, hdr.PacketNumber, hdr.PacketNumberLen, u.version)
				if err != nil {
					err = qerr.Error(qerr.InvalidStopWaitingData, err.Error())
				}
			case 0x07:
				frame, err = frames.ParsePingFrame(r)
			default:
				err = qerr.Error(qerr.InvalidFrameData, fmt.Sprintf("unknown type byte 0x%x", typeByte))
			}
		}
		if err != nil {
			return nil, err
		}
		// TODO: Remove once all frames are implemented
		if frame != nil {
			fs = append(fs, frame)
		}
	}

	return &unpackedPacket{
		entropyBit: entropyBit,
		frames:     fs,
	}, nil
}
<commit_msg>fix packet unpacker in-place encryption<commit_after>package quic

import (
	"bytes"
	"errors"
	"fmt"

	"github.com/lucas-clemente/quic-go/crypto"
	"github.com/lucas-clemente/quic-go/frames"
	"github.com/lucas-clemente/quic-go/protocol"
	"github.com/lucas-clemente/quic-go/qerr"
)

type unpackedPacket struct {
	entropyBit bool
	frames     []frames.Frame
}

type packetUnpacker struct {
	version protocol.VersionNumber
	aead    crypto.AEAD
}

func (u *packetUnpacker) Unpack(publicHeaderBinary []byte, hdr *PublicHeader, data []byte) (*unpackedPacket, error) {
	buf := getPacketBuffer()
	defer putPacketBuffer(buf)
	decrypted, err := u.aead.Open(buf, data, hdr.PacketNumber, publicHeaderBinary)
	if err != nil {
		// Wrap err in quicError so that public reset is sent by session
		return nil, qerr.Error(qerr.DecryptionFailure, err.Error())
	}
	r := bytes.NewReader(decrypted)

	// read private flag byte, for QUIC Version < 34
	var entropyBit bool
	if u.version < protocol.Version34 {
		var privateFlag uint8
		privateFlag, err = r.ReadByte()
		if err != nil {
			return nil, qerr.MissingPayload
		}
		entropyBit = privateFlag&0x01 > 0
	}

	if r.Len() == 0 {
		return nil, qerr.MissingPayload
	}

	fs := make([]frames.Frame, 0, 2)

	// Read all frames in the packet
ReadLoop:
	for r.Len() > 0 {
		typeByte, _ := r.ReadByte()
		r.UnreadByte()

		var frame frames.Frame
		if typeByte&0x80 == 0x80 {
			frame, err = frames.ParseStreamFrame(r)
			if err != nil {
				err = qerr.Error(qerr.InvalidStreamData, err.Error())
			}
		} else if typeByte&0xc0 == 0x40 {
			frame, err = frames.ParseAckFrame(r, u.version)
			if err != nil {
				err = qerr.Error(qerr.InvalidAckData, err.Error())
			}
		} else if typeByte&0xe0 == 0x20 {
			err = errors.New("unimplemented: CONGESTION_FEEDBACK")
		} else {
			switch typeByte {
			case 0x0: // PAD, end of frames
				break ReadLoop
			case 0x01:
				frame, err = frames.ParseRstStreamFrame(r)
				if err != nil {
					err = qerr.Error(qerr.InvalidRstStreamData, err.Error())
				}
			case 0x02:
				frame, err = frames.ParseConnectionCloseFrame(r)
				if err != nil {
					err = qerr.Error(qerr.InvalidConnectionCloseData, err.Error())
				}
			case 0x03:
				frame, err = frames.ParseGoawayFrame(r)
				if err != nil {
					err = qerr.Error(qerr.InvalidGoawayData, err.Error())
				}
			case 0x04:
				frame, err = frames.ParseWindowUpdateFrame(r)
				if err != nil {
					err = qerr.Error(qerr.InvalidWindowUpdateData, err.Error())
				}
			case 0x05:
				frame, err = frames.ParseBlockedFrame(r)
				if err != nil {
					err = qerr.Error(qerr.InvalidBlockedData, err.Error())
				}
			case 0x06:
				frame, err = frames.ParseStopWaitingFrame(r, hdr.PacketNumber, hdr.PacketNumberLen, u.version)
				if err != nil {
					err = qerr.Error(qerr.InvalidStopWaitingData, err.Error())
				}
			case 0x07:
				frame, err = frames.ParsePingFrame(r)
			default:
				err = qerr.Error(qerr.InvalidFrameData, fmt.Sprintf("unknown type byte 0x%x", typeByte))
			}
		}
		if err != nil {
			return nil, err
		}
		// TODO: Remove once all frames are implemented
		if frame != nil {
			fs = append(fs, frame)
		}
	}

	return &unpackedPacket{
		entropyBit: entropyBit,
		frames:     fs,
	}, nil
}
<|endoftext|>


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

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"testing"

	"github.com/kelseyhightower/coreos-ipxe-server/config"
	"github.com/kelseyhightower/coreos-ipxe-server/kernel"
)

func createTestData(profiles map[string]*kernel.Options, sshKeys map[string]string) (string, error) {
	d, err := ioutil.TempDir("", "coreos-ipxe-server")
	if err != nil {
		return "", err
	}
	sshKeyDir := filepath.Join(d, "sshkeys")
	err = os.Mkdir(sshKeyDir, 0755)
	if err != nil {
		return "", err
	}
	for k, v := range sshKeys {
		sshKeyPath := filepath.Join(sshKeyDir, fmt.Sprintf("%s.pub", k))
		err := ioutil.WriteFile(sshKeyPath, []byte(v), 0644)
		if err != nil {
			return "", err
		}
	}

	profileDir := filepath.Join(d, "profiles")
	err = os.Mkdir(profileDir, 0755)
	if err != nil {
		return "", err
	}
	for k, v := range profiles {
		profilePath := filepath.Join(profileDir, fmt.Sprintf("%s.json", k))
		data, err := json.Marshal(v)
		if err != nil {
			return "", err
		}
		err = ioutil.WriteFile(profilePath, data, 0644)
		if err != nil {
			return "", err
		}
	}
	return d, nil
}

var profileAOut = `#!ipxe
set coreos-version 310.1.0
set base-url http://example.com/images/amd64-usr/${coreos-version}
kernel ${base-url}/coreos_production_pxe.vmlinuz
initrd ${base-url}/coreos_production_pxe_image.cpio.gz
boot
`

var profileBOut = `#!ipxe
set coreos-version 310.1.0
set base-url http://example.com/images/amd64-usr/${coreos-version}
kernel ${base-url}/coreos_production_pxe.vmlinuz rootfstype=btrfs console=tty0 console=ttyS0 cloud-config-url=http://example.com/configs/b.yml coreos.autologin=ttyS0 sshkey="ssh-rsa AAAAB3Ncoreos" root=/dev/sda1
initrd ${base-url}/coreos_production_pxe_image.cpio.gz
boot
`
var iPxeBootScriptTests = []struct {
	body string
	code int
	url  string
}{
	{profileAOut, 200, "http://example.com?profile=a"},
	{profileBOut, 200, "http://example.com?profile=b"},
}

func TestIPxeBootScriptServer(t *testing.T) {
	sshkeys := map[string]string{
		"coreos": "ssh-rsa AAAAB3Ncoreos",
	}

	profiles := map[string]*kernel.Options{
		"a": &kernel.Options{
			CloudConfig:     "",
			Console:         []string{},
			CoreOSAutologin: "",
			Root:            "",
			RootFstype:      "",
			SSHKey:          "",
			Version:         "310.1.0",
		},
		"b": &kernel.Options{
			CloudConfig:     "b",
			Console:         []string{"tty0", "ttyS0"},
			CoreOSAutologin: "ttyS0",
			Root:            "/dev/sda1",
			RootFstype:      "btrfs",
			SSHKey:          "coreos",
			Version:         "310.1.0",
		},
	}

	testDataDir, err := createTestData(profiles, sshkeys)
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(testDataDir)

	config.DataDir = testDataDir
	config.BaseUrl = "example.com"
	for _, v := range iPxeBootScriptTests {
		req, err := http.NewRequest("GET", v.url, nil)
		if err != nil {
			t.Error(err)
		}

		w := httptest.NewRecorder()
		ipxeBootScriptServer(w, req)
		if w.Body.String() != v.body {
			t.Errorf("expected %s\ngot %s\n", v.body, w.Body.String())
		}
	}
}
<commit_msg>Added additional tests<commit_after>// Copyright 2014 Kelsey Hightower. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"testing"

	"github.com/kelseyhightower/coreos-ipxe-server/config"
	"github.com/kelseyhightower/coreos-ipxe-server/kernel"
)

func createTestData(profiles map[string]*kernel.Options, sshKeys map[string]string) (string, error) {
	d, err := ioutil.TempDir("", "coreos-ipxe-server")
	if err != nil {
		return "", err
	}
	sshKeyDir := filepath.Join(d, "sshkeys")
	err = os.Mkdir(sshKeyDir, 0755)
	if err != nil {
		return "", err
	}
	for k, v := range sshKeys {
		sshKeyPath := filepath.Join(sshKeyDir, fmt.Sprintf("%s.pub", k))
		err := ioutil.WriteFile(sshKeyPath, []byte(v), 0644)
		if err != nil {
			return "", err
		}
	}

	profileDir := filepath.Join(d, "profiles")
	err = os.Mkdir(profileDir, 0755)
	if err != nil {
		return "", err
	}
	for k, v := range profiles {
		profilePath := filepath.Join(profileDir, fmt.Sprintf("%s.json", k))
		data, err := json.Marshal(v)
		if err != nil {
			return "", err
		}
		err = ioutil.WriteFile(profilePath, data, 0644)
		if err != nil {
			return "", err
		}
	}
	return d, nil
}

var profileAOut = `#!ipxe
set coreos-version 310.1.0
set base-url http://example.com/images/amd64-usr/${coreos-version}
kernel ${base-url}/coreos_production_pxe.vmlinuz
initrd ${base-url}/coreos_production_pxe_image.cpio.gz
boot
`

var profileBOut = `#!ipxe
set coreos-version 310.1.0
set base-url http://example.com/images/amd64-usr/${coreos-version}
kernel ${base-url}/coreos_production_pxe.vmlinuz rootfstype=btrfs console=tty0 console=ttyS0 cloud-config-url=http://example.com/configs/b.yml coreos.autologin=ttyS0 sshkey="ssh-rsa AAAAB3Ncoreos" root=/dev/sda1
initrd ${base-url}/coreos_production_pxe_image.cpio.gz
boot
`

var iPxeBootScriptTests = []struct {
	name    string
	body    string
	code    int
	baseUrl string
	url     string
}{
	{"a", profileAOut, 200, "", "http://example.com?profile=a"},
	{"b", profileBOut, 200, "example.com", "http://example.com?profile=b"},
	{"c", "", 500, "example.com", "http://example.com?profile=c"},
	{"d", "", 500, "example.com", "http://example.com?profile=d"},
}

func TestIPxeBootScriptServer(t *testing.T) {
	sshkeys := map[string]string{
		"coreos": "ssh-rsa AAAAB3Ncoreos",
	}

	profiles := map[string]*kernel.Options{
		"a": &kernel.Options{
			CloudConfig:     "",
			Console:         []string{},
			CoreOSAutologin: "",
			Root:            "",
			RootFstype:      "",
			SSHKey:          "",
			Version:         "310.1.0",
		},
		"b": &kernel.Options{
			CloudConfig:     "b",
			Console:         []string{"tty0", "ttyS0"},
			CoreOSAutologin: "ttyS0",
			Root:            "/dev/sda1",
			RootFstype:      "btrfs",
			SSHKey:          "coreos",
			Version:         "310.1.0",
		},
		"c": &kernel.Options{
			CloudConfig:     "c",
			Console:         []string{"tty0", "ttyS0"},
			CoreOSAutologin: "ttyS0",
			Root:            "/dev/sda1",
			RootFstype:      "btrfs",
			SSHKey:          "imabadkey",
			Version:         "310.1.0",
		},
	}

	testDataDir, err := createTestData(profiles, sshkeys)
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(testDataDir)

	config.DataDir = testDataDir
	for _, v := range iPxeBootScriptTests {
		config.BaseUrl = v.baseUrl
		req, err := http.NewRequest("GET", v.url, nil)
		if err != nil {
			t.Error(err)
		}

		w := httptest.NewRecorder()
		ipxeBootScriptServer(w, req)
		if w.Code == 200 && (v.name == "a" || v.name == "b") {
			if w.Body.String() != v.body {
				t.Errorf("expected %s\ngot %s\n", v.body, w.Body.String())
			}
		} else if (v.name == "c" || v.name == "d") && w.Code != 500 {
			t.Errorf("expected %d\ngot %d\n", v.code, w.Code)
		}
	}
}
<|endoftext|>


<commit_before>package ics

type Attribute interface{}

func attributeFromTokens(pn token, pvs []token) (Attribute, error) {
	return nil, nil
}
<commit_msg>all identifiers are not exported<commit_after>package ics

import (
	"errors"
	"regexp"
)

type attribute interface{}

func attributeFromTokens(pn token, pvs []token) (attribute, error) {
	switch pn.data {
	case "ALTREP":
		if len(pvs) != 1 {
			return nil, ErrIncorrectNumValues
		}
		if pvs[0].typ != tokenParamQValue {
			return nil, ErrIncorrectParamValueType
		}
		return altRep(pvs[0].data), nil
	case "CN":
		if len(pvs) != 1 {
			return nil, ErrIncorrectNumValues
		}
		return commonName(pvs[0].data), nil
	case "CUTYPE":
		if len(pvs) != 1 {
			return nil, ErrIncorrectNumValues
		}
		return calendarUserType(pvs[0].data), nil
	case "DELEGATED-FROM":
		vals := make(delegatedFrom, len(pvs))
		for n := range pvs {
			if pvs[n].typ != tokenParamQValue {
				return nil, ErrIncorrectParamValueType
			}
			vals[n] = pvs[n].data
		}
		return vals, nil
	case "DELEGATED-TO":
		vals := make(delegatedTo, len(pvs))
		for n := range pvs {
			if pvs[n].typ != tokenParamQValue {
				return nil, ErrIncorrectParamValueType
			}
			vals[n] = pvs[n].data
		}
		return vals, nil
	case "DIR":
		if len(pvs) != 1 {
			return nil, ErrIncorrectNumValues
		}
		if pvs[0].typ != tokenParamQValue {
			return nil, ErrIncorrectParamValueType
		}
		return directoryEntryRef(pvs[0].data), nil
	case "ENCODING":
		if len(pvs) != 1 {
			return nil, ErrIncorrectNumValues
		}
		switch pvs[0].data {
		case "8BIT":
			return encoding8Bit, nil
		case "BASE64":
			return encodingBase64, nil
		}
		return nil, ErrUnknownEncoding
	case "FMTYPE":
		if len(pvs) != 1 {
			return nil, ErrIncorrectNumValues
		}
		if !fmTypeRegex.MatchString(pvs[0].data) {
			return nil, ErrInvalidValue
		}
		return formatType(pvs[0].data), nil
	case "FBTYPE":
		if len(pvs) != 1 {
			return nil, ErrIncorrectNumValues
		}
		return freeBusy(pvs[0].data), nil
	case "LANGUAGE":
		if len(pvs) != 1 {
			return nil, ErrIncorrectNumValues
		}
		return language(pvs[0].data), nil //should really validate this
	case "MEMBER":
		vals := make(member, len(pvs))
		for n := range pvs {
			if pvs[n].typ != tokenParamQValue {
				return nil, ErrIncorrectParamValueType
			}
			vals[n] = pvs[n].data
		}
		return vals, nil
	case "PARTSTAT":
		if len(pvs) != 1 {
			return nil, ErrIncorrectNumValues
		}
		return partStat(pvs[0].data), nil
	case "RANGE":
		if len(pvs) != 1 {
			return nil, ErrIncorrectNumValues
		}
		switch pvs[0].data {
		case "THISANDFUTURE":
			return rangeThisAndFuture, nil
		case "THISANDPRIOR":
			return rangeThisAndPrior, nil
		}
		return nil, ErrUnknownRange
	case "RELATED":
		if len(pvs) != 1 {
			return nil, ErrIncorrectNumValues
		}
		switch pvs[0].data {
		case "START":
			return relatedStart, nil
		case "END":
			return relatedEnd, nil
		}
		return nil, ErrUnknownRelated
	case "RELTYPE":
		if len(pvs) != 1 {
			return nil, ErrIncorrectNumValues
		}
		return relType(pvs[0].data), nil
	case "ROLE":
		if len(pvs) != 1 {
			return nil, ErrIncorrectNumValues
		}
		return role(pvs[0].data), nil
	case "RSVP":
		if len(pvs) != 1 {
			return nil, ErrIncorrectNumValues
		}
		switch pvs[0].data {
		case "FALSE":
			return rsvp(false), nil
		case "TRUE":
			return rsvp(true), nil
		}
		return nil, ErrUnknownRSVP
	case "SENT-BY":
		if len(pvs) != 1 {
			return nil, ErrIncorrectNumValues
		}
		if pvs[0].typ != tokenParamQValue {
			return nil, ErrIncorrectParamValueType
		}
		return sentBy(pvs[0].data), nil
	case "TZID":
		if len(pvs) != 1 {
			return nil, ErrIncorrectNumValues
		}
		return timezone(pvs[0].data), nil
	case "VALUE":
		if len(pvs) != 1 {
			return nil, ErrIncorrectNumValues
		}
		return value(pvs[0].data), nil
	default:
		values := make([]string, len(pvs))
		for i := 0; i < len(pvs); i++ {
			values[i] = pvs[i].data
		}
		return unknownAttribute{pn.data, values}, nil
	}
}

type unknownAttribute struct {
	Name   string
	Values []string
}

type altRep string

type commonName string

type calendarUserType string

type delegatedFrom []string

type delegatedTo []string

type directoryEntryRef string

const (
	encoding8Bit   encoding = false
	encodingBase64 encoding = true
)

type encoding bool

var fmTypeRegex *regexp.Regexp

func init() {
	fmTypeRegex = regexp.MustCompile("^[a-zA-Z0-9!#$&.+-^_]{1,127}/[a-zA-Z0-9!#$&.+-^_]{1,127}$")
}

type formatType string

type freeBusy string

type language string

type member []string

type partStat string

const (
	rangeThisAndFuture rangeAttr = false
	rangeThisAndPrior  rangeAttr = true
)

type rangeAttr bool

const (
	relatedStart related = false
	relatedEnd   related = false
)

type related bool

type relType string

type role string

type rsvp bool

type sentBy string

type timezone string

type value string

// Errors

var (
	ErrIncorrectNumValues      = errors.New("incorrect numbers of values for attribute")
	ErrIncorrectParamValueType = errors.New("incorrect param value type")
	ErrUnknownEncoding         = errors.New("unknown encoding type")
	ErrInvalidValue            = errors.New("invalid value")
	ErrUnknownRange            = errors.New("unknown range value")
	ErrUnknownRelated          = errors.New("unknown related value")
	ErrUnknownRSVP             = errors.New("unknown rsvp value")
)
<|endoftext|>


<commit_before>package binary_search_tree

type Bst struct {
	root *node
}

type Data struct {
	key   string
	value int
}

type node struct {
	data  Data
	left  *node
	right *node
}

type dataCallback func(Data)

func NewBst() *Bst {
	return &Bst{nil}
}

func (t *Bst) Get(key string) (value int, ok bool) {
	if n := find(t.root, key); n != nil {
		return n.data.value, true
	}
	return 0, false
}

func (t *Bst) Set(key string, value int) {
	t.root = insert(t.root, key, value)
}

func (t *Bst) Del(key string) {
	t.root = remove(t.root, key)
}

func (t *Bst) All() []Data {
	a := []Data{}
	inOrder(t.root, func(d Data) {
		a = append(a, d)
	})
	return a
}

func find(n *node, key string) *node {
	if n == nil || n.data.key == key {
		return n
	}
	if key < n.data.key {
		return find(n.left, key)
	}
	return find(n.right, key)
}

func insert(n *node, key string, value int) *node {
	if n == nil {
		return &node{Data{key, value}, nil, nil}
	}
	if key == n.data.key {
		n.data.value = value
		return n
	}
	if key < n.data.key {
		n.left = insert(n.left, key, value)
	} else {
		n.right = insert(n.right, key, value)
	}
	return n
}

func remove(n *node, key string) *node {
	if n == nil {
		return nil
	}
	if key == n.data.key {
		if n.left != nil && n.right != nil {
			return removeNodeWithTwoChildren(n)
		}
		return removeNodeWithAtMostOneChild(n)
	}
	if key < n.data.key {
		n.left = remove(n.left, key)
	} else {
		n.right = remove(n.right, key)
	}
	return n
}

func removeNodeWithTwoChildren(n *node) *node {
	var predecessor *node
	n.left, predecessor = removeMax(n.left)
	n.data = predecessor.data
	return n
}

func removeNodeWithAtMostOneChild(n *node) *node {
	if n.left != nil {
		return n.left
	}
	return n.right
}

func removeMax(n *node) (root, max *node) {
	if n.right == nil {
		return n.left, n
	}
	n.right, max = removeMax(n.right)
	return n, max
}

func inOrder(n *node, cb dataCallback) {
	if n == nil {
		return
	}
	inOrder(n.left, cb)
	cb(n.data)
	inOrder(n.right, cb)
}
<commit_msg>[binary_search_tree/go] Cleanup<commit_after>package binary_search_tree

type Bst struct {
	root *node
}

type Data struct {
	key   string
	value int
}

type node struct {
	data  Data
	left  *node
	right *node
}

type dataCallback func(Data)

func NewBst() *Bst {
	return &Bst{nil}
}

func (t *Bst) Get(key string) (value int, ok bool) {
	if n := find(t.root, key); n != nil {
		return n.data.value, true
	}
	return 0, false
}

func (t *Bst) Set(key string, value int) {
	t.root = insert(t.root, key, value)
}

func (t *Bst) Del(key string) {
	t.root = remove(t.root, key)
}

func (t *Bst) All() []Data {
	a := []Data{}
	inOrder(t.root, func(d Data) {
		a = append(a, d)
	})
	return a
}

func find(n *node, key string) *node {
	if n == nil || n.data.key == key {
		return n
	}
	if key < n.data.key {
		return find(n.left, key)
	}
	return find(n.right, key)
}

func insert(n *node, key string, value int) *node {
	if n == nil {
		return &node{Data{key, value}, nil, nil}
	}
	if key == n.data.key {
		n.data.value = value
		return n
	}
	if key < n.data.key {
		n.left = insert(n.left, key, value)
	} else {
		n.right = insert(n.right, key, value)
	}
	return n
}

func remove(n *node, key string) *node {
	if n == nil {
		return nil
	}
	if key == n.data.key {
		if n.left == nil {
			return n.right
		}
		if n.right == nil {
			return n.left
		}
		return removeNodeWithTwoChildren(n)
	}
	if key < n.data.key {
		n.left = remove(n.left, key)
	} else {
		n.right = remove(n.right, key)
	}
	return n
}

func removeNodeWithTwoChildren(n *node) *node {
	var predecessor *node
	n.left, predecessor = removeMax(n.left)
	n.data = predecessor.data
	return n
}

func removeMax(n *node) (root, max *node) {
	if n.right == nil {
		return n.left, n
	}
	n.right, max = removeMax(n.right)
	return n, max
}

func inOrder(n *node, cb dataCallback) {
	if n == nil {
		return
	}
	inOrder(n.left, cb)
	cb(n.data)
	inOrder(n.right, cb)
}
<|endoftext|>


<commit_before>// Copyright 2016-2020 Granitic. All rights reserved.
// Use of this source code is governed by an Apache 2.0 license that can be found in the LICENSE file at the root of this project.

package logging

import (
	"context"
	"testing"
)

func TestUnsupportedContent(t *testing.T) {

	f := JSONField{
		Content: "XXXX",
		Name:    "Unsupported",
	}

	err := ValidateJSONFields([]*JSONField{&f})

	if err == nil {
		t.Fatalf("Failed to detect invalid content type")
	}
}

func TestMissingName(t *testing.T) {

	f := JSONField{
		Content: "MESSAGE",
		Name:    "",
	}

	err := ValidateJSONFields([]*JSONField{&f})

	if err == nil {
		t.Fatalf("Failed to detect invalid content type")
	}
}

func TestMissingContextValueKey(t *testing.T) {

	f := JSONField{
		Content: "CONTEXT_VALUE",
		Name:    "MissingArg",
	}

	err := ValidateJSONFields([]*JSONField{&f})

	if err == nil {
		t.Fatalf("Failed to detect missing context value key")
	}
}

func TestMissingTimestampLayout(t *testing.T) {

	f := JSONField{
		Content: "TIMESTAMP",
		Name:    "MissingArg",
	}

	err := ValidateJSONFields([]*JSONField{&f})

	if err == nil {
		t.Fatalf("Failed to detect missing timestamp layout")
	}
}

func TestTimestampLayout(t *testing.T) {

	f := JSONField{
		Content: "TIMESTAMP",
		Name:    "Stamp",
		Arg:     "Mon Jan 2 15:04:05 MST 2006",
	}

	err := ValidateJSONFields([]*JSONField{&f})

	if err != nil {
		t.Fatalf("Did not accept valid layout")
	}
}

func TestInvalidTimestampLayout(t *testing.T) {

	f := JSONField{
		Content: "TIMESTAMP",
		Name:    "Stamp",
		Arg:     "Mon Jan 32 15:04:05 MST 2006",
	}

	err := ValidateJSONFields([]*JSONField{&f})

	if err == nil {
		t.Fatalf("Did not reject invalid layout")
	}
}

func TestMapBuilder(t *testing.T) {

	cfg := new(JSONConfig)

	f := new(JSONField)

	f.Content = "MESSAGE"
	f.Name = "message"

	cfg.Fields = []*JSONField{f}

	mb, err := CreateMapBuilder(cfg)

	if err != nil {
		t.Fatalf(err.Error())
	}

	m := mb.Build(context.Background(), "TRACE", "MyComp", "some message")

	if m == nil {
		t.FailNow()
	}

}
<commit_msg>Benchmark JSON application logging<commit_after>// Copyright 2016-2020 Granitic. All rights reserved.
// Use of this source code is governed by an Apache 2.0 license that can be found in the LICENSE file at the root of this project.

package logging

import (
	"context"
	"testing"
)

func TestUnsupportedContent(t *testing.T) {

	f := JSONField{
		Content: "XXXX",
		Name:    "Unsupported",
	}

	err := ValidateJSONFields([]*JSONField{&f})

	if err == nil {
		t.Fatalf("Failed to detect invalid content type")
	}
}

func TestMissingName(t *testing.T) {

	f := JSONField{
		Content: "MESSAGE",
		Name:    "",
	}

	err := ValidateJSONFields([]*JSONField{&f})

	if err == nil {
		t.Fatalf("Failed to detect invalid content type")
	}
}

func TestMissingContextValueKey(t *testing.T) {

	f := JSONField{
		Content: "CONTEXT_VALUE",
		Name:    "MissingArg",
	}

	err := ValidateJSONFields([]*JSONField{&f})

	if err == nil {
		t.Fatalf("Failed to detect missing context value key")
	}
}

func TestMissingTimestampLayout(t *testing.T) {

	f := JSONField{
		Content: "TIMESTAMP",
		Name:    "MissingArg",
	}

	err := ValidateJSONFields([]*JSONField{&f})

	if err == nil {
		t.Fatalf("Failed to detect missing timestamp layout")
	}
}

func TestTimestampLayout(t *testing.T) {

	f := JSONField{
		Content: "TIMESTAMP",
		Name:    "Stamp",
		Arg:     "Mon Jan 2 15:04:05 MST 2006",
	}

	err := ValidateJSONFields([]*JSONField{&f})

	if err != nil {
		t.Fatalf("Did not accept valid layout")
	}
}

func TestInvalidTimestampLayout(t *testing.T) {

	f := JSONField{
		Content: "TIMESTAMP",
		Name:    "Stamp",
		Arg:     "Mon Jan 32 15:04:05 MST 2006",
	}

	err := ValidateJSONFields([]*JSONField{&f})

	if err == nil {
		t.Fatalf("Did not reject invalid layout")
	}
}

func TestMapBuilder(t *testing.T) {

	cfg := new(JSONConfig)

	f := new(JSONField)

	f.Content = "MESSAGE"
	f.Name = "message"

	cfg.Fields = []*JSONField{f}

	mb, err := CreateMapBuilder(cfg)

	if err != nil {
		t.Fatalf(err.Error())
	}

	m := mb.Build(context.Background(), "TRACE", "MyComp", "some message")

	if m == nil {
		t.FailNow()
	}

}

func BenchmarkDefaultJSONFormatter(b *testing.B) {

	fields := []*JSONField{
		{Name: "Timestamp", Content: "TIMESTAMP", Arg: "02/Jan/2006:15:04:05 Z0700"},
		{Name: "Level", Content: "LEVEL"},
		{Name: "Source", Content: "COMPONENT_NAME"},
		{Name: "Message", Content: "MESSAGE"},
	}

	cfg := JSONConfig{
		Prefix: "",
		Fields: fields,
		Suffix: "\n",
		UTC:    true,
	}

	mb, _ := CreateMapBuilder(&cfg)

	jf := new(JSONLogFormatter)

	jf.Config = &cfg
	jf.MapBuilder = mb

	for i := 0; i < b.N; i++ {
		jf.Format(nil, "INFO", "someComp", "A benchmark test message of fixed length")
	}
}
<|endoftext|>