<commit_before>package dock

import "bytes"

func makeMessageSplitter() func(input []byte) []string {
	buffer := []byte{}

	return func(input []byte) []string {
		buffer = append(buffer, input...)
		msgs := []string{}

		for {
			i := bytes.IndexByte(buffer, '\r')
			if i == -1 {
				break
			}
			msgs = append(msgs, string(buffer[:i]))
			buffer = buffer[i+1:]
		}

		return msgs
	}
}

func msgToEvent(msg string) Event {
	return Event{}
}
<commit_msg>added msgToEvent<commit_after>package dock

import (
	"bytes"
	"fmt"
)

func makeMessageSplitter() func(input []byte) []string {
	buffer := []byte{}

	return func(input []byte) []string {
		buffer = append(buffer, input...)
		msgs := []string{}

		for {
			i := bytes.IndexByte(buffer, '\r')
			if i == -1 {
				break
			}
			msgs = append(msgs, string(buffer[:i]))
			buffer = buffer[i+1:]
		}

		return msgs
	}
}

// u 1/module int,int,int,int....
func msgToEvent(msg string) Event {
	var evtype rune
	var port int
	var module string
	var values [8]int

	n, _ := fmt.Sscanf(msg, "%c %d/%s %d,%d,%d,%d,%d,%d,%d,%d",
		&evtype, &port, &module,
		&values[0], &values[1], &values[2], &values[3],
		&values[4], &values[5], &values[6], &values[7])

	//	fmt.Println(evtype, port, module, values, n, err)

	event := Event{}
	switch evtype {
	case 'c':
		event.EventType = Connected
	case 'd':
		event.EventType = Disconnected
	case 'u':
		event.EventType = Update
	default:
		event.EventType = Invalid
	}

	event.ModuleType = FromString(module)
	event.Port = port
	event.Params = values[:n-3]

	return event
}
<|endoftext|>


<commit_before>package cli

import (
	"fmt"
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/bitrise-io/bitrise-cli/bitrise"
	"github.com/bitrise-io/bitrise-cli/models"
	"github.com/bitrise-io/go-pathutil"
	"github.com/codegangsta/cli"
)

func activateAndRunSteps(workflow models.WorkflowModel) error {
	for _, step := range workflow.Steps {
		stepDir := "./steps/" + step.Id + "/" + step.VersionTag + "/"

		if err := bitrise.RunStepmanActivate(step.Id, step.VersionTag, stepDir); err != nil {
			log.Errorln("[BITRISE_CLI] - Failed to run stepman activate")
			return err
		}

		log.Infof("[BITRISE_CLI] - Step activated: %s (%s)", step.Id, step.VersionTag)

		if err := runStep(step); err != nil {
			log.Errorln("[BITRISE_CLI] - Failed to run step")
			return err
		}
	}
	return nil
}

func runStep(step models.StepModel) error {
	// Add step envs
	for _, input := range step.Inputs {
		if input.Value != nil {
			if err := bitrise.RunEnvmanAdd(*input.MappedTo, *input.Value); err != nil {
				log.Errorln("[BITRISE_CLI] - Failed to run envman add")
				return err
			}
		}
	}

	stepDir := "./steps/" + step.Id + "/" + step.VersionTag + "/"
	stepCmd := fmt.Sprintf("%sstep.sh", stepDir)
	cmd := []string{"bash", stepCmd}

	if err := bitrise.RunEnvmanRun(cmd); err != nil {
		log.Errorln("[BITRISE_CLI] - Failed to run envman run")
		return err
	}

	log.Infof("[BITRISE_CLI] - Step executed: %s (%s)", step.Id, step.VersionTag)
	return nil
}

func doRun(c *cli.Context) {
	log.Info("[BITRISE_CLI] - Run")

	// Input validation
	workflowJsonPath := c.String(PATH_KEY)
	if workflowJsonPath == "" {
		log.Infoln("[BITRISE_CLI] - Workflow json path not defined, try search in current folder")

		if exist, err := pathutil.IsPathExists("./bitrise.json"); err != nil {
			log.Fatalln("Failed to check path:", err)
		} else if !exist {
			log.Fatalln("No workflow json found")
		}
		workflowJsonPath = "./bitrise.json"
	}

	// Envman setup
	if err := os.Setenv(ENVSTORE_PATH_ENV_KEY, ENVSTORE_PATH); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to add env:", err)
	}

	if err := os.Setenv(FORMATTED_OUTPUT_PATH_ENV_KEY, FORMATTED_OUTPUT_PATH); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to add env:", err)
	}

	if err := bitrise.RunEnvmanInit(); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to run envman init")
	}

	// Run work flow
	if workflow, err := bitrise.ReadWorkflowJson(workflowJsonPath); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to read work flow:", err)
	} else {
		if err := activateAndRunSteps(workflow); err != nil {
			log.Fatalln("[BITRISE_CLI] - Failed to activate steps:", err)
		}
	}
}
<commit_msg>minor info text change<commit_after>package cli

import (
	"fmt"
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/bitrise-io/bitrise-cli/bitrise"
	"github.com/bitrise-io/bitrise-cli/models"
	"github.com/bitrise-io/go-pathutil"
	"github.com/codegangsta/cli"
)

func activateAndRunSteps(workflow models.WorkflowModel) error {
	for _, step := range workflow.Steps {
		stepDir := "./steps/" + step.Id + "/" + step.VersionTag + "/"

		if err := bitrise.RunStepmanActivate(step.Id, step.VersionTag, stepDir); err != nil {
			log.Errorln("[BITRISE_CLI] - Failed to run stepman activate")
			return err
		}

		log.Infof("[BITRISE_CLI] - Step activated: %s (%s)", step.Id, step.VersionTag)

		if err := runStep(step); err != nil {
			log.Errorln("[BITRISE_CLI] - Failed to run step")
			return err
		}
	}
	return nil
}

func runStep(step models.StepModel) error {
	// Add step envs
	for _, input := range step.Inputs {
		if input.Value != nil {
			if err := bitrise.RunEnvmanAdd(*input.MappedTo, *input.Value); err != nil {
				log.Errorln("[BITRISE_CLI] - Failed to run envman add")
				return err
			}
		}
	}

	stepDir := "./steps/" + step.Id + "/" + step.VersionTag + "/"
	stepCmd := fmt.Sprintf("%sstep.sh", stepDir)
	cmd := []string{"bash", stepCmd}

	if err := bitrise.RunEnvmanRun(cmd); err != nil {
		log.Errorln("[BITRISE_CLI] - Failed to run envman run")
		return err
	}

	log.Infof("[BITRISE_CLI] - Step executed: %s (%s)", step.Id, step.VersionTag)
	return nil
}

func doRun(c *cli.Context) {
	log.Info("[BITRISE_CLI] - Run")

	// Input validation
	workflowJsonPath := c.String(PATH_KEY)
	if workflowJsonPath == "" {
		log.Infoln("[BITRISE_CLI] - Workflow path not defined, searching for bitrise.json in current folder...")

		if exist, err := pathutil.IsPathExists("./bitrise.json"); err != nil {
			log.Fatalln("Failed to check path:", err)
		} else if !exist {
			log.Fatalln("No workflow json found")
		}
		workflowJsonPath = "./bitrise.json"
	}

	// Envman setup
	if err := os.Setenv(ENVSTORE_PATH_ENV_KEY, ENVSTORE_PATH); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to add env:", err)
	}

	if err := os.Setenv(FORMATTED_OUTPUT_PATH_ENV_KEY, FORMATTED_OUTPUT_PATH); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to add env:", err)
	}

	if err := bitrise.RunEnvmanInit(); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to run envman init")
	}

	// Run work flow
	if workflow, err := bitrise.ReadWorkflowJson(workflowJsonPath); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to read work flow:", err)
	} else {
		if err := activateAndRunSteps(workflow); err != nil {
			log.Fatalln("[BITRISE_CLI] - Failed to activate steps:", err)
		}
	}
}
<|endoftext|>


<commit_before>package cli

import (
	"errors"
	"fmt"
	"os"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/bitrise-io/bitrise-cli/bitrise"
	models "github.com/bitrise-io/bitrise-cli/models/models_1_0_0"
	"github.com/bitrise-io/go-pathutil/pathutil"
	stepmanModels "github.com/bitrise-io/stepman/models"
	"github.com/codegangsta/cli"
)

const (
	// DefaultBitriseConfigFileName ...
	DefaultBitriseConfigFileName = "bitrise.yml"
	// DefaultSecretsFileName ...
	DefaultSecretsFileName = ".bitrise.secrets.yml"
)

var (
	failedSteps   []string
	inventoryPath string

	startTime time.Time
	runTime   time.Duration
)

func isBuildFailed() bool {
	if len(failedSteps) > 0 {
		return true
	}
	return false
}

func exportEnvironmentsList(envsList []stepmanModels.EnvironmentItemModel) error {
	log.Debugln("[BITRISE_CLI] - Exporting environments:", envsList)

	for _, env := range envsList {
		key, value, err := env.GetKeyValuePair()
		if err != nil {
			return err
		}

		opts, err := env.GetOptions()
		if err != nil {
			return err
		}

		if value != "" {
			if err := bitrise.RunEnvmanAdd(key, value, *opts.IsExpand); err != nil {
				log.Errorln("[BITRISE_CLI] - Failed to run envman add")
				return err
			}
		}
	}
	return nil
}

func cleanupStepWorkDir() error {
	stepYMLPth := bitrise.BitriseWorkDirPath + "/current_step.yml"
	if err := bitrise.RemoveFile(stepYMLPth); err != nil {
		return errors.New(fmt.Sprint("Failed to remove step yml: ", err))
	}

	stepDir := bitrise.BitriseWorkStepsDirPath
	if err := bitrise.RemoveDir(stepDir); err != nil {
		return errors.New(fmt.Sprint("Failed to remove step work dir: ", err))
	}
	return nil
}

func activateAndRunSteps(workflow models.WorkflowModel, defaultStepLibSource string) error {
	log.Debugln("[BITRISE_CLI] - Activating and running steps")

	for idx, stepListItm := range workflow.Steps {
		compositeStepIDStr, workflowStep, err := models.GetStepIDStepDataPair(stepListItm)
		if err != nil {
			return err
		}
		stepIDData, err := models.CreateStepIDDataFromString(compositeStepIDStr, defaultStepLibSource)
		if err != nil {
			return err
		}
		log.Debugf("[BITRISE_CLI] - Running Step: %#v", workflowStep)

		stepDir := bitrise.BitriseWorkStepsDirPath

		if err := bitrise.RunStepmanSetup(stepIDData.SteplibSource); err != nil {
			log.Error("Failed to setup stepman:", err)
		}

		if err := cleanupStepWorkDir(); err != nil {
			return err
		}

		stepYMLPth := bitrise.BitriseWorkDirPath + "/current_step.yml"
		if err := bitrise.RunStepmanActivate(stepIDData.SteplibSource, stepIDData.ID, stepIDData.Version, stepDir, stepYMLPth); err != nil {
			log.Errorln("[BITRISE_CLI] - Failed to run stepman activate")
			failedSteps = append(failedSteps, compositeStepIDStr)
		} else {
			log.Debugf("[BITRISE_CLI] - Step activated: %s (%s)", stepIDData.ID, stepIDData.Version)

			specStep, err := bitrise.ReadSpecStep(stepYMLPth)
			log.Debugf("Spec read from YML: %#v\n", specStep)
			if err != nil {
				return err
			}

			if err := models.MergeStepWith(specStep, workflowStep); err != nil {
				return err
			}

			fmt.Println()
			log.Infof("========== (%d) %s ==========", idx, *specStep.Title)
			fmt.Println()

			if isBuildFailed() && !*specStep.IsAlwaysRun {
				log.Infof("A previous step failed and this step was not marked to IsAlwaysRun - skipping step (id:%s) (version:%s)", stepIDData.ID, stepIDData.Version)
			} else {
				if err := runStep(specStep, stepIDData); err != nil {
					log.Errorln("[BITRISE_CLI] - Failed to run step:", err)
					failedSteps = append(failedSteps, compositeStepIDStr)
				}
			}

			fmt.Println()
		}
	}
	return nil
}

func runStep(step stepmanModels.StepModel, stepIDData models.StepIDData) error {
	log.Debugf("[BITRISE_CLI] - Try running step: %s (%s)", stepIDData.ID, stepIDData.Version)

	// Add step envs
	for _, input := range step.Inputs {
		key, value, err := input.GetKeyValuePair()
		if err != nil {
			return err
		}

		opts, err := input.GetOptions()
		if err != nil {
			return err
		}

		if value != "" {
			log.Debugf("Input: %#v\n", input)
			if err := bitrise.RunEnvmanAdd(key, value, *opts.IsExpand); err != nil {
				log.Errorln("[BITRISE_CLI] - Failed to run envman add")
				return err
			}
		}
	}

	stepDir := bitrise.BitriseWorkStepsDirPath
	stepCmd := stepDir + "/" + "step.sh"
	cmd := []string{"bash", stepCmd}
	if err := bitrise.RunEnvmanRunInDir(bitrise.CurrentDir, cmd); err != nil {
		log.Errorln("[BITRISE_CLI] - Failed to run envman run")
		return err
	}

	log.Debugf("[BITRISE_CLI] - Step executed: %s (%s)", stepIDData.ID, stepIDData.Version)
	return nil
}

func handleRunFailed(err error) {
	endTime := time.Now()
	runTime = endTime.Sub(startTime)
	log.Fatal("Build failed error: " + err.Error() + " total run time: " + runTime.String() + " s")
}

func handleRunSuccess() {
	endTime := time.Now()
	runTime = endTime.Sub(startTime)
	log.Info("DONE - Congrats!!")
	log.Info("Total run time: " + runTime.String() + " s")
}

func doRun(c *cli.Context) {
	log.Debugln("[BITRISE_CLI] - Run")

	startTime = time.Now()

	// Cleanup
	if err := bitrise.CleanupBitriseWorkPath(); err != nil {
		handleRunFailed(errors.New("Failed to cleanup bitrise work dir: " + err.Error()))
	}
	failedSteps = []string{}

	// Input validation
	bitriseConfigPath := c.String(PathKey)
	if bitriseConfigPath == "" {
		log.Debugln("[BITRISE_CLI] - Workflow path not defined, searching for " + DefaultBitriseConfigFileName + " in current folder...")

		if exist, err := pathutil.IsPathExists("./" + DefaultBitriseConfigFileName); err != nil {
			log.Fatalln("[BITRISE_CLI] - Failed to check path:", err)
		} else if !exist {
			log.Fatalln("[BITRISE_CLI] - No workflow yml found")
		}
		bitriseConfigPath = "./" + DefaultBitriseConfigFileName
	}

	inventoryPath = c.String(InventoryKey)
	if inventoryPath == "" {
		log.Debugln("[BITRISE_CLI] - Inventory path not defined, searching for " + DefaultSecretsFileName + " in current folder...")
		inventoryPath = bitrise.CurrentDir + "/" + DefaultSecretsFileName

		if exist, err := pathutil.IsPathExists(inventoryPath); err != nil {
			log.Fatalln("[BITRISE_CLI] - Failed to check path:", err)
		} else if !exist {
			log.Debugln("[BITRISE_CLI] - No inventory yml found")
			inventoryPath = ""
		}
	} else {
		if exist, err := pathutil.IsPathExists(inventoryPath); err != nil {
			log.Fatalln("[BITRISE_CLI] - Failed to check path:", err)
		} else if !exist {
			log.Fatalln("[BITRISE_CLI] - No inventory yml found")
		}
	}
	if inventoryPath != "" {
		if err := bitrise.RunEnvmanEnvstoreTest(inventoryPath); err != nil {
			log.Fatal("Invalid invetory format:", err)
		}

		if err := bitrise.RunCopy(inventoryPath, bitrise.EnvstorePath); err != nil {
			log.Fatal("Failed to copy inventory:", err)
		}
	}

	// Workflow selection
	workflowToRunName := ""
	if len(c.Args()) < 1 {
		log.Infoln("No workfow specified!")
	} else {
		workflowToRunName = c.Args()[0]
	}

	// Envman setup
	if err := os.Setenv(bitrise.EnvstorePathEnvKey, bitrise.EnvstorePath); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to add env:", err)
	}

	if err := os.Setenv(bitrise.FormattedOutputPathEnvKey, bitrise.FormattedOutputPath); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to add env:", err)
	}

	if inventoryPath == "" {
		if err := bitrise.RunEnvmanInit(); err != nil {
			log.Fatalln("[BITRISE_CLI] - Failed to run envman init")
		}
	}

	// Run work flow
	bitriseConfig, err := bitrise.ReadBitriseConfig(bitriseConfigPath)
	if err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to read Workflow:", err)
	}

	// check workflow
	if workflowToRunName == "" {
		// no workflow specified
		//  list all the available ones and then exit
		log.Infoln("The following workflows are available:")
		for wfName := range bitriseConfig.Workflows {
			log.Infoln(" * " + wfName)
		}
		os.Exit(1)
	}

	workflowToRun, exist := bitriseConfig.Workflows[workflowToRunName]
	if !exist {
		log.Fatalln("[BITRISE_CLI] - Specified Workflow (" + workflowToRunName + ") does not exist!")
	}
	log.Infoln("[BITRISE_CLI] - Running Workflow:", workflowToRunName)

	// App level environment
	if err := exportEnvironmentsList(bitriseConfig.App.Environments); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to export App environments:", err)
	}

	// Workflow level environments
	if err := exportEnvironmentsList(workflowToRun.Environments); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to export Workflow environments:", err)
	}

	// Run the Workflow
	if err := activateAndRunSteps(workflowToRun, bitriseConfig.DefaultStepLibSource); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to activate steps:", err)
	}

	log.Infoln("")
	if len(failedSteps) > 0 {
		log.Info("Failed steps:", failedSteps)
		log.Info("FINISHED but a couple of steps failed - Ouch")
		os.Exit(1)
	} else {
		log.Infoln("DONE - Congrats!!")
	}
}
<commit_msg>register build status methods<commit_after>package cli

import (
	"errors"
	"fmt"
	"os"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/bitrise-io/bitrise-cli/bitrise"
	models "github.com/bitrise-io/bitrise-cli/models/models_1_0_0"
	"github.com/bitrise-io/go-pathutil/pathutil"
	stepmanModels "github.com/bitrise-io/stepman/models"
	"github.com/codegangsta/cli"
)

const (
	// DefaultBitriseConfigFileName ...
	DefaultBitriseConfigFileName = "bitrise.yml"
	// DefaultSecretsFileName ...
	DefaultSecretsFileName = ".bitrise.secrets.yml"
)

var (
	failedSteps   []string
	inventoryPath string

	startTime time.Time
	runTime   time.Duration
)

func isBuildFailed() bool {
	if len(failedSteps) > 0 {
		return true
	}
	return false
}

func exportEnvironmentsList(envsList []stepmanModels.EnvironmentItemModel) error {
	log.Debugln("[BITRISE_CLI] - Exporting environments:", envsList)

	for _, env := range envsList {
		key, value, err := env.GetKeyValuePair()
		if err != nil {
			return err
		}

		opts, err := env.GetOptions()
		if err != nil {
			return err
		}

		if value != "" {
			if err := bitrise.RunEnvmanAdd(key, value, *opts.IsExpand); err != nil {
				log.Errorln("[BITRISE_CLI] - Failed to run envman add")
				return err
			}
		}
	}
	return nil
}

func cleanupStepWorkDir() error {
	stepYMLPth := bitrise.BitriseWorkDirPath + "/current_step.yml"
	if err := bitrise.RemoveFile(stepYMLPth); err != nil {
		return errors.New(fmt.Sprint("Failed to remove step yml: ", err))
	}

	stepDir := bitrise.BitriseWorkStepsDirPath
	if err := bitrise.RemoveDir(stepDir); err != nil {
		return errors.New(fmt.Sprint("Failed to remove step work dir: ", err))
	}
	return nil
}

func activateAndRunSteps(workflow models.WorkflowModel, defaultStepLibSource string) error {
	log.Debugln("[BITRISE_CLI] - Activating and running steps")

	for idx, stepListItm := range workflow.Steps {
		compositeStepIDStr, workflowStep, err := models.GetStepIDStepDataPair(stepListItm)
		if err != nil {
			return err
		}
		stepIDData, err := models.CreateStepIDDataFromString(compositeStepIDStr, defaultStepLibSource)
		if err != nil {
			return err
		}
		log.Debugf("[BITRISE_CLI] - Running Step: %#v", workflowStep)

		stepDir := bitrise.BitriseWorkStepsDirPath

		if err := bitrise.RunStepmanSetup(stepIDData.SteplibSource); err != nil {
			log.Error("Failed to setup stepman:", err)
		}

		if err := cleanupStepWorkDir(); err != nil {
			return err
		}

		stepYMLPth := bitrise.BitriseWorkDirPath + "/current_step.yml"
		if err := bitrise.RunStepmanActivate(stepIDData.SteplibSource, stepIDData.ID, stepIDData.Version, stepDir, stepYMLPth); err != nil {
			log.Errorln("[BITRISE_CLI] - Failed to run stepman activate")
			failedSteps = append(failedSteps, compositeStepIDStr)
		} else {
			log.Debugf("[BITRISE_CLI] - Step activated: %s (%s)", stepIDData.ID, stepIDData.Version)

			specStep, err := bitrise.ReadSpecStep(stepYMLPth)
			log.Debugf("Spec read from YML: %#v\n", specStep)
			if err != nil {
				return err
			}

			if err := models.MergeStepWith(specStep, workflowStep); err != nil {
				return err
			}

			fmt.Println()
			log.Infof("========== (%d) %s ==========", idx, *specStep.Title)
			fmt.Println()

			if isBuildFailed() && !*specStep.IsAlwaysRun {
				log.Infof("A previous step failed and this step was not marked to IsAlwaysRun - skipping step (id:%s) (version:%s)", stepIDData.ID, stepIDData.Version)
			} else {
				if err := runStep(specStep, stepIDData); err != nil {
					log.Errorln("[BITRISE_CLI] - Failed to run step:", err)
					failedSteps = append(failedSteps, compositeStepIDStr)
				}
			}

			fmt.Println()
		}
	}
	return nil
}

func runStep(step stepmanModels.StepModel, stepIDData models.StepIDData) error {
	log.Debugf("[BITRISE_CLI] - Try running step: %s (%s)", stepIDData.ID, stepIDData.Version)

	// Add step envs
	for _, input := range step.Inputs {
		key, value, err := input.GetKeyValuePair()
		if err != nil {
			return err
		}

		opts, err := input.GetOptions()
		if err != nil {
			return err
		}

		if value != "" {
			log.Debugf("Input: %#v\n", input)
			if err := bitrise.RunEnvmanAdd(key, value, *opts.IsExpand); err != nil {
				log.Errorln("[BITRISE_CLI] - Failed to run envman add")
				return err
			}
		}
	}

	stepDir := bitrise.BitriseWorkStepsDirPath
	stepCmd := stepDir + "/" + "step.sh"
	cmd := []string{"bash", stepCmd}
	if err := bitrise.RunEnvmanRunInDir(bitrise.CurrentDir, cmd); err != nil {
		log.Errorln("[BITRISE_CLI] - Failed to run envman run")
		return err
	}

	log.Debugf("[BITRISE_CLI] - Step executed: %s (%s)", stepIDData.ID, stepIDData.Version)
	return nil
}

func registerRunFailed(err error) {
	endTime := time.Now()
	runTime = endTime.Sub(startTime)
	log.Fatal("Build failed error: " + err.Error() + " total run time: " + runTime.String())
}

func registerRunSuccess() {
	endTime := time.Now()
	runTime = endTime.Sub(startTime)
	log.Info("DONE - Congrats!!")
	log.Info("Total run time: " + runTime.String())
}

func registerRunSuccessWithFailedSteps() {
	endTime := time.Now()
	runTime = endTime.Sub(startTime)
	log.Info("Failed steps:", failedSteps)
	log.Info("FINISHED but a couple of steps failed - Ouch")
	log.Info("Total run time: " + runTime.String())
	os.Exit(1)
}

func doRun(c *cli.Context) {
	log.Debugln("[BITRISE_CLI] - Run")

	startTime = time.Now()

	// Cleanup
	if err := bitrise.CleanupBitriseWorkPath(); err != nil {
		registerRunFailed(errors.New("[BITRISE_CLI] - Failed to cleanup bitrise work dir: " + err.Error()))
	}
	failedSteps = []string{}

	// Input validation
	bitriseConfigPath := c.String(PathKey)
	if bitriseConfigPath == "" {
		log.Debugln("[BITRISE_CLI] - Workflow path not defined, searching for " + DefaultBitriseConfigFileName + " in current folder...")

		if exist, err := pathutil.IsPathExists("./" + DefaultBitriseConfigFileName); err != nil {
			registerRunFailed(errors.New("[BITRISE_CLI] - Failed to check path:" + err.Error()))
		} else if !exist {
			log.Fatalln("[BITRISE_CLI] - No workflow yml found")
			registerRunFailed(errors.New("[BITRISE_CLI] - No workflow yml found"))
		}
		bitriseConfigPath = "./" + DefaultBitriseConfigFileName
	}

	inventoryPath = c.String(InventoryKey)
	if inventoryPath == "" {
		log.Debugln("[BITRISE_CLI] - Inventory path not defined, searching for " + DefaultSecretsFileName + " in current folder...")
		inventoryPath = bitrise.CurrentDir + "/" + DefaultSecretsFileName

		if exist, err := pathutil.IsPathExists(inventoryPath); err != nil {
			registerRunFailed(errors.New("[BITRISE_CLI] - Failed to check path: " + err.Error()))
		} else if !exist {
			log.Debugln("[BITRISE_CLI] - No inventory yml found")
			inventoryPath = ""
		}
	} else {
		if exist, err := pathutil.IsPathExists(inventoryPath); err != nil {
			registerRunFailed(errors.New("[BITRISE_CLI] - Failed to check path: " + err.Error()))
		} else if !exist {
			registerRunFailed(errors.New("[BITRISE_CLI] - No inventory yml found"))
		}
	}
	if inventoryPath != "" {
		if err := bitrise.RunEnvmanEnvstoreTest(inventoryPath); err != nil {
			registerRunFailed(errors.New("Invalid invetory format: " + err.Error()))
		}

		if err := bitrise.RunCopy(inventoryPath, bitrise.EnvstorePath); err != nil {
			registerRunFailed(errors.New("Failed to copy inventory: " + err.Error()))
		}
	}

	// Workflow selection
	workflowToRunName := ""
	if len(c.Args()) < 1 {
		log.Infoln("No workfow specified!")
	} else {
		workflowToRunName = c.Args()[0]
	}

	// Envman setup
	if err := os.Setenv(bitrise.EnvstorePathEnvKey, bitrise.EnvstorePath); err != nil {
		registerRunFailed(errors.New("[BITRISE_CLI] - Failed to add env: " + err.Error()))
	}

	if err := os.Setenv(bitrise.FormattedOutputPathEnvKey, bitrise.FormattedOutputPath); err != nil {
		registerRunFailed(errors.New("[BITRISE_CLI] - Failed to add env: " + err.Error()))
	}

	if inventoryPath == "" {
		if err := bitrise.RunEnvmanInit(); err != nil {
			registerRunFailed(errors.New("[BITRISE_CLI] - Failed to run envman init"))
		}
	}

	// Run work flow
	bitriseConfig, err := bitrise.ReadBitriseConfig(bitriseConfigPath)
	if err != nil {
		registerRunFailed(errors.New("[BITRISE_CLI] - Failed to read Workflow: " + err.Error()))
	}

	// check workflow
	if workflowToRunName == "" {
		// no workflow specified
		//  list all the available ones and then exit
		log.Infoln("The following workflows are available:")
		for wfName := range bitriseConfig.Workflows {
			log.Infoln(" * " + wfName)
		}
		os.Exit(1)
	}

	workflowToRun, exist := bitriseConfig.Workflows[workflowToRunName]
	if !exist {
		registerRunFailed(errors.New("[BITRISE_CLI] - Specified Workflow (" + workflowToRunName + ") does not exist!"))
	}
	log.Infoln("[BITRISE_CLI] - Running Workflow:", workflowToRunName)

	// App level environment
	if err := exportEnvironmentsList(bitriseConfig.App.Environments); err != nil {
		registerRunFailed(errors.New("[BITRISE_CLI] - Failed to export App environments: " + err.Error()))
	}

	// Workflow level environments
	if err := exportEnvironmentsList(workflowToRun.Environments); err != nil {
		registerRunFailed(errors.New("[BITRISE_CLI] - Failed to export Workflow environments: " + err.Error()))
	}

	// Run the Workflow
	if err := activateAndRunSteps(workflowToRun, bitriseConfig.DefaultStepLibSource); err != nil {
		log.Fatalln("[BITRISE_CLI] - Failed to activate steps:", err)
		registerRunFailed(errors.New("[BITRISE_CLI] - Failed to activate steps: " + err.Error()))
	}

	log.Infoln("")
	if len(failedSteps) > 0 {
		registerRunSuccessWithFailedSteps()
	} else {
		registerRunSuccess()
	}
}
<|endoftext|>


<commit_before>package harmonizer_test

import (
	"errors"
	"os"
	"time"

	"code.cloudfoundry.org/clock/fakeclock"
	"code.cloudfoundry.org/lager"
	"code.cloudfoundry.org/lager/lagertest"
	"code.cloudfoundry.org/operationq"
	"code.cloudfoundry.org/operationq/fake_operationq"
	"code.cloudfoundry.org/rep/evacuation/evacuation_context"
	"code.cloudfoundry.org/rep/generator/fake_generator"
	"code.cloudfoundry.org/rep/harmonizer"
	"github.com/cloudfoundry/dropsonde/metric_sender/fake"
	"github.com/cloudfoundry/dropsonde/metrics"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/tedsuo/ifrit"
)

var _ = Describe("Bulker", func() {
	var (
		sender *fake.FakeMetricSender

		logger                 *lagertest.TestLogger
		pollInterval           time.Duration
		evacuationPollInterval time.Duration
		fakeClock              *fakeclock.FakeClock
		fakeGenerator          *fake_generator.FakeGenerator
		fakeQueue              *fake_operationq.FakeQueue
		evacuatable            evacuation_context.Evacuatable
		evacuationNotifier     evacuation_context.EvacuationNotifier

		bulker  *harmonizer.Bulker
		process ifrit.Process
	)

	BeforeEach(func() {
		sender = fake.NewFakeMetricSender()
		metrics.Initialize(sender, nil)

		logger = lagertest.NewTestLogger("test")
		pollInterval = 30 * time.Second
		evacuationPollInterval = 10 * time.Second
		fakeClock = fakeclock.NewFakeClock(time.Unix(123, 456))
		fakeGenerator = new(fake_generator.FakeGenerator)
		fakeQueue = new(fake_operationq.FakeQueue)

		evacuatable, _, evacuationNotifier = evacuation_context.New()

		bulker = harmonizer.NewBulker(logger, pollInterval, evacuationPollInterval, evacuationNotifier, fakeClock, fakeGenerator, fakeQueue)
	})

	JustBeforeEach(func() {
		process = ifrit.Invoke(bulker)
		Eventually(fakeClock.WatcherCount).Should(Equal(1))
	})

	AfterEach(func() {
		process.Signal(os.Interrupt)
		Eventually(process.Wait()).Should(Receive())
	})

	itPerformsBatchOperations := func() {
		Context("when generating the batch operations succeeds", func() {
			var (
				operation1 *fake_operationq.FakeOperation
				operation2 *fake_operationq.FakeOperation
			)

			BeforeEach(func() {
				operation1 = new(fake_operationq.FakeOperation)
				operation2 = new(fake_operationq.FakeOperation)

				fakeGenerator.BatchOperationsStub = func(lager.Logger) (map[string]operationq.Operation, error) {
					fakeClock.Increment(10 * time.Second)
					return map[string]operationq.Operation{"guid1": operation1, "guid2": operation2}, nil
				}
			})

			It("pushes them onto the queue", func() {
				Eventually(fakeQueue.PushCallCount).Should(Equal(2))

				enqueuedOperations := make([]operationq.Operation, 0, 2)
				enqueuedOperations = append(enqueuedOperations, fakeQueue.PushArgsForCall(0))
				enqueuedOperations = append(enqueuedOperations, fakeQueue.PushArgsForCall(1))

				Expect(enqueuedOperations).To(ConsistOf(operation1, operation2))
			})

			It("emits the duration it took to generate the batch operations", func() {
				Eventually(fakeQueue.PushCallCount).Should(Equal(2))

				reportedDuration := sender.GetValue("RepBulkSyncDuration")
				Expect(reportedDuration.Unit).To(Equal("nanos"))
				Expect(reportedDuration.Value).To(BeNumerically("==", 10*time.Second))
			})
		})

		Context("when generating the batch operations fails", func() {
			disaster := errors.New("nope")

			BeforeEach(func() {
				fakeGenerator.BatchOperationsReturns(nil, disaster)
			})

			It("logs the error", func() {
				Eventually(logger).Should(gbytes.Say("failed-to-generate-operations"))
				Eventually(logger).Should(gbytes.Say("nope"))
			})
		})
	}

	Context("when the poll interval elapses", func() {
		JustBeforeEach(func() {
			fakeClock.WaitForWatcherAndIncrement(pollInterval + 1)
		})

		itPerformsBatchOperations()

		Context("and elapses again", func() {
			BeforeEach(func() {
				fakeClock.Increment(pollInterval)
			})

			itPerformsBatchOperations()
		})
	})

	Context("when the poll interval has not elapsed", func() {
		JustBeforeEach(func() {
			fakeClock.WaitForWatcherAndIncrement(pollInterval - 1)
		})

		It("does not fetch batch operations", func() {
			Consistently(fakeGenerator.BatchOperationsCallCount).Should(BeZero())
		})
	})

	Context("when evacuation starts", func() {
		BeforeEach(func() {
			evacuatable.Evacuate()
		})

		itPerformsBatchOperations()

		It("batches operations only once", func() {
			Eventually(fakeGenerator.BatchOperationsCallCount).Should(Equal(1))
			Consistently(fakeGenerator.BatchOperationsCallCount).Should(Equal(1))
		})

		Context("when the evacuation interval elapses", func() {
			It("batches operations again", func() {
				Eventually(fakeGenerator.BatchOperationsCallCount).Should(Equal(1))
				fakeClock.Increment(evacuationPollInterval + time.Second)
				Eventually(fakeGenerator.BatchOperationsCallCount).Should(Equal(2))
				Consistently(fakeGenerator.BatchOperationsCallCount).Should(Equal(2))
			})
		})
	})
})
<commit_msg>improve harmonizer bulker test<commit_after>package harmonizer_test

import (
	"errors"
	"os"
	"time"

	"code.cloudfoundry.org/clock/fakeclock"
	"code.cloudfoundry.org/lager"
	"code.cloudfoundry.org/lager/lagertest"
	"code.cloudfoundry.org/operationq"
	"code.cloudfoundry.org/operationq/fake_operationq"
	"code.cloudfoundry.org/rep/evacuation/evacuation_context"
	"code.cloudfoundry.org/rep/generator/fake_generator"
	"code.cloudfoundry.org/rep/harmonizer"
	"github.com/cloudfoundry/dropsonde/metric_sender/fake"
	"github.com/cloudfoundry/dropsonde/metrics"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/tedsuo/ifrit"
)

var _ = Describe("Bulker", func() {
	var (
		sender *fake.FakeMetricSender

		logger                 *lagertest.TestLogger
		pollInterval           time.Duration
		evacuationPollInterval time.Duration
		fakeClock              *fakeclock.FakeClock
		fakeGenerator          *fake_generator.FakeGenerator
		fakeQueue              *fake_operationq.FakeQueue
		evacuatable            evacuation_context.Evacuatable
		evacuationNotifier     evacuation_context.EvacuationNotifier

		bulker  *harmonizer.Bulker
		process ifrit.Process
	)

	BeforeEach(func() {
		sender = fake.NewFakeMetricSender()
		metrics.Initialize(sender, nil)

		logger = lagertest.NewTestLogger("test")
		pollInterval = 30 * time.Second
		evacuationPollInterval = 10 * time.Second
		fakeClock = fakeclock.NewFakeClock(time.Unix(123, 456))
		fakeGenerator = new(fake_generator.FakeGenerator)
		fakeQueue = new(fake_operationq.FakeQueue)

		evacuatable, _, evacuationNotifier = evacuation_context.New()

		bulker = harmonizer.NewBulker(logger, pollInterval, evacuationPollInterval, evacuationNotifier, fakeClock, fakeGenerator, fakeQueue)
	})

	JustBeforeEach(func() {
		process = ifrit.Invoke(bulker)
		Eventually(fakeClock.WatcherCount).Should(Equal(1))
	})

	AfterEach(func() {
		process.Signal(os.Interrupt)
		Eventually(process.Wait()).Should(Receive())
	})

	itPerformsBatchOperations := func(expectedQueueLength int) {
		Context("when generating the batch operations succeeds", func() {
			var (
				operation1 *fake_operationq.FakeOperation
				operation2 *fake_operationq.FakeOperation
			)

			BeforeEach(func() {
				operation1 = new(fake_operationq.FakeOperation)
				operation2 = new(fake_operationq.FakeOperation)

				fakeGenerator.BatchOperationsStub = func(lager.Logger) (map[string]operationq.Operation, error) {
					fakeClock.Increment(10 * time.Second)
					return map[string]operationq.Operation{"guid1": operation1, "guid2": operation2}, nil
				}
			})

			It("pushes them onto the queue", func() {
				Eventually(fakeQueue.PushCallCount).Should(Equal(expectedQueueLength))

				enqueuedOperations := make([]operationq.Operation, 0, 2)
				enqueuedOperations = append(enqueuedOperations, fakeQueue.PushArgsForCall(expectedQueueLength-2))
				enqueuedOperations = append(enqueuedOperations, fakeQueue.PushArgsForCall(expectedQueueLength-1))

				Expect(enqueuedOperations).To(ConsistOf(operation1, operation2))
			})

			It("emits the duration it took to generate the batch operations", func() {
				Eventually(fakeQueue.PushCallCount).Should(Equal(expectedQueueLength))

				reportedDuration := sender.GetValue("RepBulkSyncDuration")
				Expect(reportedDuration.Unit).To(Equal("nanos"))
				Expect(reportedDuration.Value).To(BeNumerically("==", 10*time.Second))
			})
		})

		Context("when generating the batch operations fails", func() {
			disaster := errors.New("nope")

			BeforeEach(func() {
				fakeGenerator.BatchOperationsReturns(nil, disaster)
			})

			It("logs the error", func() {
				Eventually(logger).Should(gbytes.Say("failed-to-generate-operations"))
				Eventually(logger).Should(gbytes.Say("nope"))
			})
		})
	}

	Context("when the poll interval elapses", func() {
		JustBeforeEach(func() {
			fakeClock.WaitForWatcherAndIncrement(pollInterval + 1)
		})

		itPerformsBatchOperations(2)

		Context("and elapses again", func() {
			JustBeforeEach(func() {
				fakeClock.WaitForWatcherAndIncrement(pollInterval + 1)
			})

			itPerformsBatchOperations(4)
		})
	})

	Context("when the poll interval has not elapsed", func() {
		JustBeforeEach(func() {
			fakeClock.WaitForWatcherAndIncrement(pollInterval - 1)
		})

		It("does not fetch batch operations", func() {
			Consistently(fakeGenerator.BatchOperationsCallCount).Should(BeZero())
		})
	})

	Context("when evacuation starts", func() {
		BeforeEach(func() {
			evacuatable.Evacuate()
		})

		itPerformsBatchOperations(2)

		It("batches operations only once", func() {
			Eventually(fakeGenerator.BatchOperationsCallCount).Should(Equal(1))
			Consistently(fakeGenerator.BatchOperationsCallCount).Should(Equal(1))
		})

		Context("when the evacuation interval elapses", func() {
			It("batches operations again", func() {
				Eventually(fakeGenerator.BatchOperationsCallCount).Should(Equal(1))
				fakeClock.Increment(evacuationPollInterval + time.Second)
				Eventually(fakeGenerator.BatchOperationsCallCount).Should(Equal(2))
				Consistently(fakeGenerator.BatchOperationsCallCount).Should(Equal(2))
			})
		})
	})
})
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"path/filepath"
	//"runtime"
	"strconv"

	"./jsonrpc2"
	"./lsp"
)

var (
	addr       = flag.String("addr", "localhost:2088", "language server address (tcp)")
	rootPath   = flag.String("root-path", ".", "language server root path")
	file       = flag.String("file", "", "File")
	line 	   = flag.Int("line", 1, "Symbol line (1-based")
	column 	   = flag.Int("column", 1, "Symbol column (1-based")
	command    = flag.String("command", "initialize", "LSP command")
)

var reqCounter = 0

func main() {
	flag.Parse()
	log.SetFlags(0)

	if err := run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func run() error {
	client, err := client()
	if err != nil {
		return err
	}
	defer client.Close()

    switch *command {
		case "initialize": initialize(client)
		case "definition": getDefinition(client)
		case "hover": getHover(client)
		case "references": getReferences(client)
		case "external-refs": getWorkspaceSymbols(client, "externals")
		case "exported-symbols": getWorkspaceSymbols(client, "exported")
		case "workspace-symbols": getWorkspaceSymbols(client, "")
		case "global-refs": getGlobalRefs(client, "")
		case "shutdown": shutdown(client);
	}
    // initialize(client);
    // getDefinition(client);
	// getHover(client);
	return nil;
}

func initialize(client *jsonrpc2.Client) error {
// initialize server
	// note that RootPath should point to file path, not URI (at least Java binding expects it to be path)
	_, err := request(client, "initialize", lsp.InitializeParams{
		RootPath: *rootPath,
	})
	if err != nil {
		return err
	}
	return nil;
}

func shutdown(client *jsonrpc2.Client) error {
	_, err := request(client, "shutdown", nil);
	if err != nil {
		return err
	}
	return nil;
}

func getDefinition(client *jsonrpc2.Client) error {
	initialize(client);
	response, err := request(client, "textDocument/definition", lsp.TextDocumentPositionParams{
   		TextDocument: lsp.TextDocumentIdentifier{
   			URI: toUri(filepath.Join(*rootPath, *file)),
   		},
   		Position: lsp.Position{
   			Line:      *line,
   			Character: *column ,
   		},
   	})
   	if err != nil {
   		return err
   	}
   	var location []lsp.Location
   	if err := json.Unmarshal(*response.Result, &location); err != nil {
   		return err
   	}
   	for _, l := range location {
   		println(l.URI, l.Range.Start.Line, l.Range.Start.Character, l.Range.End.Line, l.Range.End.Character)
   	}
	return nil;

}

func getHover(client *jsonrpc2.Client) error {
	    initialize(client);
		response, err := request(client, "textDocument/hover", lsp.TextDocumentPositionParams{
   		TextDocument: lsp.TextDocumentIdentifier{
   			URI: toUri(filepath.Join(*rootPath, *file)),
   		},
   		Position: lsp.Position{
   			Line:      *line,
   			Character: *column ,
   		},
   	});

	if err != nil {
   		return err
   }
	println(*response.Result);
   	// var location []lsp.Location
   	// if err := json.Unmarshal(*response.Result, &location); err != nil {
   	// 	return err
   	// }
	return nil;
}

func getReferences(client *jsonrpc2.Client) error {
	  initialize(client);
		response, err := request(client, "textDocument/references", lsp.ReferenceParams{
		TextDocumentPositionParams: lsp.TextDocumentPositionParams{
   		TextDocument: lsp.TextDocumentIdentifier{
   			URI: toUri(filepath.Join(*rootPath, *file)),
   		},
   		Position: lsp.Position{
   			Line:      *line,
   			Character: *column ,
   		},
		}});
  if err != nil {
   		return err
   	}
  var location []lsp.Location
   	if err := json.Unmarshal(*response.Result, &location); err != nil {
   		return err
   	}
   	for _, l := range location {
   		println(l.URI, l.Range.Start.Line, l.Range.Start.Character, l.Range.End.Line, l.Range.End.Character)
   	}
  return nil;
}

func getWorkspaceSymbols(client *jsonrpc2.Client, query string) error {
	    initialize(client);
		response, err := request(client, "workspace/symbol", lsp.WorkspaceSymbolParams{
   		Query: query,
   	});

	if err != nil {
   		return err
   }
	println(*response.Result);
   	// var location []lsp.Location
   	// if err := json.Unmarshal(*response.Result, &location); err != nil {
   	// 	return err
   	// }
	return nil;
}

func getGlobalRefs(client *jsonrpc2.Client, query string) error {
	    initialize(client);
		response, err := request(client, "textDocument/global-refs", lsp.WorkspaceSymbolParams{
   		Query: query,
   	});

	if err != nil {
   		return err
   }
	println(*response.Result);
   	// var location []lsp.Location
   	// if err := json.Unmarshal(*response.Result, &location); err != nil {
   	// 	return err
   	// }
	return nil;
}

// creates new JSON-RPC client and connects it to remote language server
func client() (*jsonrpc2.Client, error) {
	conn, err := net.Dial("tcp", *addr)
	if err != nil {
		return nil, err
	}
	return jsonrpc2.NewClient(conn), nil
}

// request performs JSON-RPC request using initialized client connection and waits for response.
// This function assembles JSON-RPC requests from method name and parameters, also it assigns unique identifiers to each request
func request(client *jsonrpc2.Client, method string, params interface{}) (*jsonrpc2.Response, error) {
	reqCounter++

	request := &jsonrpc2.Request{
		Method: method,
	}
	if (params != nil) {
      request.SetParams(params);
	}

	request.ID = strconv.Itoa(reqCounter)
	return client.RequestAndWaitForResponse(request)
}

// converts file path to URI file://(/)POSIX-style-path
func toUri(path string) string {
	prefix := "file:///"
	// if runtime.GOOS == "windows" {
	// 	prefix += "/"
	// }
	r, _ := filepath.Rel(*rootPath, path)
	return prefix + filepath.ToSlash(r)
}
<commit_msg>Modify client for new workspace symbol parameters with limit<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"path/filepath"
	//"runtime"
	"strconv"

	"./jsonrpc2"
	"./lsp"
)

var (
	addr       = flag.String("addr", "localhost:2088", "language server address (tcp)")
	rootPath   = flag.String("root-path", ".", "language server root path")
	file       = flag.String("file", "", "File")
	line 	   = flag.Int("line", 1, "Symbol line (1-based")
	column 	   = flag.Int("column", 1, "Symbol column (1-based")
	command    = flag.String("command", "initialize", "LSP command")
	query      = flag.String("query", "Object", "LSP command")
	limit 	   = flag.Int("limit", 100, "Symbol line (1-based")
)

var reqCounter = 0

func main() {
	flag.Parse()
	log.SetFlags(0)

	if err := run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func run() error {
	client, err := client()
	if err != nil {
		return err
	}
	defer client.Close()

    switch *command {
		case "initialize": initialize(client)
		case "definition": getDefinition(client)
		case "hover": getHover(client)
		case "references": getReferences(client)
		case "external-refs": getWorkspaceSymbols(client, "externals", 1000)
		case "exported-symbols": getWorkspaceSymbols(client, "exported", 1000)
		case "workspace-symbols-all": getWorkspaceSymbols(client, "", *limit)
		case "workspace-symbols": getWorkspaceSymbols(client, *query, *limit)
		case "global-refs": getGlobalRefs(client, "")
		case "shutdown": shutdown(client);
	}
    // initialize(client);
    // getDefinition(client);
	// getHover(client);
	return nil;
}

func initialize(client *jsonrpc2.Client) error {
// initialize server
	// note that RootPath should point to file path, not URI (at least Java binding expects it to be path)
	_, err := request(client, "initialize", lsp.InitializeParams{
		RootPath: *rootPath,
	})
	if err != nil {
		return err
	}
	return nil;
}

func shutdown(client *jsonrpc2.Client) error {
	_, err := request(client, "shutdown", nil);
	if err != nil {
		return err
	}
	return nil;
}

func getDefinition(client *jsonrpc2.Client) error {
	initialize(client);
	response, err := request(client, "textDocument/definition", lsp.TextDocumentPositionParams{
   		TextDocument: lsp.TextDocumentIdentifier{
   			URI: toUri(filepath.Join(*rootPath, *file)),
   		},
   		Position: lsp.Position{
   			Line:      *line,
   			Character: *column ,
   		},
   	})
   	if err != nil {
   		return err
   	}
   	var location []lsp.Location
   	if err := json.Unmarshal(*response.Result, &location); err != nil {
   		return err
   	}
   	for _, l := range location {
   		println(l.URI, l.Range.Start.Line, l.Range.Start.Character, l.Range.End.Line, l.Range.End.Character)
   	}
	return nil;

}

func getHover(client *jsonrpc2.Client) error {
	    initialize(client);
		response, err := request(client, "textDocument/hover", lsp.TextDocumentPositionParams{
   		TextDocument: lsp.TextDocumentIdentifier{
   			URI: toUri(filepath.Join(*rootPath, *file)),
   		},
   		Position: lsp.Position{
   			Line:      *line,
   			Character: *column ,
   		},
   	});

	if err != nil {
   		return err
   }
	println(*response.Result);
   	// var location []lsp.Location
   	// if err := json.Unmarshal(*response.Result, &location); err != nil {
   	// 	return err
   	// }
	return nil;
}

func getReferences(client *jsonrpc2.Client) error {
	  initialize(client);
		response, err := request(client, "textDocument/references", lsp.ReferenceParams{
		TextDocumentPositionParams: lsp.TextDocumentPositionParams{
   		TextDocument: lsp.TextDocumentIdentifier{
   			URI: toUri(filepath.Join(*rootPath, *file)),
   		},
   		Position: lsp.Position{
   			Line:      *line,
   			Character: *column ,
   		},
		}});
  if err != nil {
   		return err
   	}
  var location []lsp.Location
   	if err := json.Unmarshal(*response.Result, &location); err != nil {
   		return err
   	}
   	for _, l := range location {
   		println(l.URI, l.Range.Start.Line, l.Range.Start.Character, l.Range.End.Line, l.Range.End.Character)
   	}
  return nil;
}

func getWorkspaceSymbols(client *jsonrpc2.Client, query string, limit int) error {
	    initialize(client);
		response, err := request(client, "workspace/symbol", lsp.WorkspaceSymbolParams{
   		Query: query,
		Limit: limit,
   	});

	if err != nil {
   		return err
   }
	println(*response.Result);
   	// var location []lsp.Location
   	// if err := json.Unmarshal(*response.Result, &location); err != nil {
   	// 	return err
   	// }
	return nil;
}

func getGlobalRefs(client *jsonrpc2.Client, query string) error {
	    initialize(client);
		response, err := request(client, "textDocument/global-refs", lsp.WorkspaceSymbolParams{
   		Query: query,
   	});

	if err != nil {
   		return err
   }
	println(*response.Result);
   	// var location []lsp.Location
   	// if err := json.Unmarshal(*response.Result, &location); err != nil {
   	// 	return err
   	// }
	return nil;
}

// creates new JSON-RPC client and connects it to remote language server
func client() (*jsonrpc2.Client, error) {
	conn, err := net.Dial("tcp", *addr)
	if err != nil {
		return nil, err
	}
	return jsonrpc2.NewClient(conn), nil
}

// request performs JSON-RPC request using initialized client connection and waits for response.
// This function assembles JSON-RPC requests from method name and parameters, also it assigns unique identifiers to each request
func request(client *jsonrpc2.Client, method string, params interface{}) (*jsonrpc2.Response, error) {
	reqCounter++

	request := &jsonrpc2.Request{
		Method: method,
	}
	if (params != nil) {
      request.SetParams(params);
	}

	request.ID = strconv.Itoa(reqCounter)
	return client.RequestAndWaitForResponse(request)
}

// converts file path to URI file://(/)POSIX-style-path
func toUri(path string) string {
	prefix := "file:///"
	// if runtime.GOOS == "windows" {
	// 	prefix += "/"
	// }
	r, _ := filepath.Rel(*rootPath, path)
	return prefix + filepath.ToSlash(r)
}
<|endoftext|>


<commit_before>package clockwork

import (
	"sync"
	"time"
)

// Clock provides an interface that packages can use instead of directly
// using the time module, so that chronology-related behavior can be tested
type Clock interface {
	After(d time.Duration) <-chan time.Time
	Sleep(d time.Duration)
	Now() time.Time
}

// FakeClock provides an interface for a clock which can be
// manually advanceed through time
type FakeClock interface {
	Clock
	// Advance advances the FakeClock to a new point in time, ensuring any existing
	// sleepers are notified appropriately before returning
	Advance(d time.Duration)
	// BlockUntil will block until the FakeClock has the given number of
	// sleepers (callers of Sleep or After)
	BlockUntil(n int)
}

// NewRealClock returns a Clock which simply delegates calls to the actual time
// package; it should be used by packages in production.
func NewRealClock() Clock {
	return &realClock{}
}

// NewFakeClock returns a FakeClock implementation which can be
// manually advanceed through time for testing.
func NewFakeClock() FakeClock {
	return &fakeClock{
		l: sync.RWMutex{},
	}
}

type realClock struct{}

func (rc *realClock) After(d time.Duration) <-chan time.Time {
	return time.After(d)
}

func (rc *realClock) Sleep(d time.Duration) {
	time.Sleep(d)
}

func (rc *realClock) Now() time.Time {
	return time.Now()
}

type fakeClock struct {
	sleepers []*sleeper
	blockers []*blocker
	time     time.Time

	l sync.RWMutex
}

// sleeper represents a caller of After or Sleep
type sleeper struct {
	until time.Time
	done  chan time.Time
}

// blocker represents a caller of BlockUntil
type blocker struct {
	count int
	ch    chan struct{}
}

// After mimics time.After; it waits for the given duration to elapse on the
// fakeClock, then sends the current time on the returned channel.
func (fc *fakeClock) After(d time.Duration) <-chan time.Time {
	fc.l.Lock()
	defer fc.l.Unlock()
	now := fc.time
	done := make(chan time.Time, 1)
	if d.Nanoseconds() == 0 {
		// special case - trigger immediately
		done <- now
	} else {
		// otherwise, add to the set of sleepers
		s := &sleeper{
			until: now.Add(d),
			done:  done,
		}
		fc.sleepers = append(fc.sleepers, s)
		// and notify any blockers
		fc.blockers = notifyBlockers(fc.blockers, len(fc.sleepers))
	}
	return done
}

// notifyBlockers notifies all the blockers waiting until the
// given number of sleepers are waiting on the fakeClock. It
// returns an updated slice of blockers (i.e. those still waiting)
func notifyBlockers(blockers []*blocker, count int) (newBlockers []*blocker) {
	for _, b := range blockers {
		if b.count == count {
			close(b.ch)
		} else {
			newBlockers = append(newBlockers, b)
		}
	}
	return
}

// Sleep blocks until the given duration has passed on the fakeClock
func (fc *fakeClock) Sleep(d time.Duration) {
	<-fc.After(d)
}

// Time returns the current time of the fakeClock
func (fc *fakeClock) Now() time.Time {
	fc.l.Lock()
	defer fc.l.Unlock()
	return fc.time
}

// Advance advances fakeClock to a new point in time, ensuring channels from any
// previous invocations of After are notified appropriately before returning
func (fc *fakeClock) Advance(d time.Duration) {
	fc.l.Lock()
	defer fc.l.Unlock()
	end := fc.time.Add(d)
	var newSleepers []*sleeper
	for _, s := range fc.sleepers {
		if end.Sub(s.until) >= 0 {
			s.done <- end
		} else {
			newSleepers = append(newSleepers, s)
		}
	}
	fc.sleepers = newSleepers
	fc.blockers = notifyBlockers(fc.blockers, len(fc.sleepers))
	fc.time = end
}

// BlockUntil will block until the fakeClock has the given number of sleepers
// (callers of Sleep or After)
func (fc *fakeClock) BlockUntil(n int) {
	fc.l.Lock()
	// Fast path: current number of sleepers is what we're looking for
	if len(fc.sleepers) == n {
		fc.l.Unlock()
		return
	}
	// Otherwise, set up a new blocker
	b := &blocker{
		count: n,
		ch:    make(chan struct{}),
	}
	fc.blockers = append(fc.blockers, b)
	fc.l.Unlock()
	<-b.ch
}
<commit_msg>*: fix typo s/advanceed/advanced/<commit_after>package clockwork

import (
	"sync"
	"time"
)

// Clock provides an interface that packages can use instead of directly
// using the time module, so that chronology-related behavior can be tested
type Clock interface {
	After(d time.Duration) <-chan time.Time
	Sleep(d time.Duration)
	Now() time.Time
}

// FakeClock provides an interface for a clock which can be
// manually advanced through time
type FakeClock interface {
	Clock
	// Advance advances the FakeClock to a new point in time, ensuring any existing
	// sleepers are notified appropriately before returning
	Advance(d time.Duration)
	// BlockUntil will block until the FakeClock has the given number of
	// sleepers (callers of Sleep or After)
	BlockUntil(n int)
}

// NewRealClock returns a Clock which simply delegates calls to the actual time
// package; it should be used by packages in production.
func NewRealClock() Clock {
	return &realClock{}
}

// NewFakeClock returns a FakeClock implementation which can be
// manually advanced through time for testing.
func NewFakeClock() FakeClock {
	return &fakeClock{
		l: sync.RWMutex{},
	}
}

type realClock struct{}

func (rc *realClock) After(d time.Duration) <-chan time.Time {
	return time.After(d)
}

func (rc *realClock) Sleep(d time.Duration) {
	time.Sleep(d)
}

func (rc *realClock) Now() time.Time {
	return time.Now()
}

type fakeClock struct {
	sleepers []*sleeper
	blockers []*blocker
	time     time.Time

	l sync.RWMutex
}

// sleeper represents a caller of After or Sleep
type sleeper struct {
	until time.Time
	done  chan time.Time
}

// blocker represents a caller of BlockUntil
type blocker struct {
	count int
	ch    chan struct{}
}

// After mimics time.After; it waits for the given duration to elapse on the
// fakeClock, then sends the current time on the returned channel.
func (fc *fakeClock) After(d time.Duration) <-chan time.Time {
	fc.l.Lock()
	defer fc.l.Unlock()
	now := fc.time
	done := make(chan time.Time, 1)
	if d.Nanoseconds() == 0 {
		// special case - trigger immediately
		done <- now
	} else {
		// otherwise, add to the set of sleepers
		s := &sleeper{
			until: now.Add(d),
			done:  done,
		}
		fc.sleepers = append(fc.sleepers, s)
		// and notify any blockers
		fc.blockers = notifyBlockers(fc.blockers, len(fc.sleepers))
	}
	return done
}

// notifyBlockers notifies all the blockers waiting until the
// given number of sleepers are waiting on the fakeClock. It
// returns an updated slice of blockers (i.e. those still waiting)
func notifyBlockers(blockers []*blocker, count int) (newBlockers []*blocker) {
	for _, b := range blockers {
		if b.count == count {
			close(b.ch)
		} else {
			newBlockers = append(newBlockers, b)
		}
	}
	return
}

// Sleep blocks until the given duration has passed on the fakeClock
func (fc *fakeClock) Sleep(d time.Duration) {
	<-fc.After(d)
}

// Time returns the current time of the fakeClock
func (fc *fakeClock) Now() time.Time {
	fc.l.Lock()
	defer fc.l.Unlock()
	return fc.time
}

// Advance advances fakeClock to a new point in time, ensuring channels from any
// previous invocations of After are notified appropriately before returning
func (fc *fakeClock) Advance(d time.Duration) {
	fc.l.Lock()
	defer fc.l.Unlock()
	end := fc.time.Add(d)
	var newSleepers []*sleeper
	for _, s := range fc.sleepers {
		if end.Sub(s.until) >= 0 {
			s.done <- end
		} else {
			newSleepers = append(newSleepers, s)
		}
	}
	fc.sleepers = newSleepers
	fc.blockers = notifyBlockers(fc.blockers, len(fc.sleepers))
	fc.time = end
}

// BlockUntil will block until the fakeClock has the given number of sleepers
// (callers of Sleep or After)
func (fc *fakeClock) BlockUntil(n int) {
	fc.l.Lock()
	// Fast path: current number of sleepers is what we're looking for
	if len(fc.sleepers) == n {
		fc.l.Unlock()
		return
	}
	// Otherwise, set up a new blocker
	b := &blocker{
		count: n,
		ch:    make(chan struct{}),
	}
	fc.blockers = append(fc.blockers, b)
	fc.l.Unlock()
	<-b.ch
}
<|endoftext|>


<commit_before>package brightbox

import (
	"fmt"
)

// CloudIP represents a Cloud IP
// https://api.gb1.brightbox.com/1.0/#cloud_ip
type CloudIP struct {
	Id              string
	Name            string
	PublicIP        string `json:"public_ip"`
	PublicIPv4      string `json:"public_ipv4"`
	PublicIPv6      string `json:"public_ipv6"`
	Status          string
	Locked          bool
	ReverseDns      string           `json:"reverse_dns"`
	PortTranslators []PortTranslator `json:"port_translators"`
	Account         Account
	Fqdn            string
	Interface       *ServerInterface
	Server          *Server
	ServerGroup     *ServerGroup    `json:"server_group"`
	LoadBalancer    *LoadBalancer   `json:"load_balancer"`
	DatabaseServer  *DatabaseServer `json:"database_server"`
}

// PortTranslator represents a port translator on a Cloud IP
type PortTranslator struct {
	Incoming int    `json:"incoming"`
	Outgoing int    `json:"outgoing"`
	Protocol string `json:"protocol"`
}

// CloudIPOptions is used in conjunction with CreateCloudIP and UpdateCloudIP to
// create and update cloud IPs.
type CloudIPOptions struct {
	Id              string            `json:"-"`
	ReverseDns      *string           `json:"reverse_dns,omitempty"`
	Name            *string           `json:"name,omitempty"`
	PortTranslators *[]PortTranslator `json:"port_translators,omitempty"`
}

// CloudIPs retrieves a list of all cloud ips
func (c *Client) CloudIPs() ([]CloudIP, error) {
	var cloudips []CloudIP
	_, err := c.MakeApiRequest("GET", "/1.0/cloud_ips", nil, &cloudips)
	if err != nil {
		return nil, err
	}
	return cloudips, err
}

// CloudIP retrieves a detailed view of one cloud ip
func (c *Client) CloudIP(identifier string) (*CloudIP, error) {
	cloudip := new(CloudIP)
	_, err := c.MakeApiRequest("GET", "/1.0/cloud_ips/"+identifier, nil, cloudip)
	if err != nil {
		return nil, err
	}
	return cloudip, err
}

// DestroyCloudIP issues a request to destroy the cloud ip
func (c *Client) DestroyCloudIP(identifier string) error {
	_, err := c.MakeApiRequest("DELETE", "/1.0/cloud_ips/"+identifier, nil, nil)
	if err != nil {
		return err
	}
	return nil
}

// CreateCloudIP creates a new Cloud IP.
//
// It takes a CloudIPOptions struct for specifying name and other attributes.
// Not all attributes can be specified at create time (such as Id, which is
// allocated for you)
func (c *Client) CreateCloudIP(newCloudIP *CloudIPOptions) (*CloudIP, error) {
	cloudip := new(CloudIP)
	_, err := c.MakeApiRequest("POST", "/1.0/cloud_ips", newCloudIP, &cloudip)
	if err != nil {
		return nil, err
	}
	return cloudip, nil
}

// UpdateCloudIP updates an existing cloud ip's attributes. Not all attributes
// can be changed after creation time (such as Id, which is allocated for you).
//
// Specify the cloud ip you want to update using the CloudIPOptions Id field
func (c *Client) UpdateCloudIP(updateCloudIP *CloudIPOptions) (*CloudIP, error) {
	cip := new(CloudIP)
	_, err := c.MakeApiRequest("PUT", "/1.0/cloud_ips/"+updateCloudIP.Id, updateCloudIP, &cip)
	if err != nil {
		return nil, err
	}
	return cip, nil
}

// MapCloudIP issues a request to map the cloud ip to the destination. The
// destination can be an identifier of any resource capable of receiving a Cloud
// IP, such as a server interface, a load balancer, or a cloud sql instace.
//
// To map a Cloud IP to a server, first lookup the server to get it's interface
// identifier (or use the MapCloudIPtoServer convenience method)
func (c *Client) MapCloudIP(identifier string, destination string) error {
	_, err := c.MakeApiRequest("POST", "/1.0/cloud_ips/"+identifier+"/map",
		map[string]string{"destination": destination}, nil)
	if err != nil {
		return err
	}
	return nil
}

// MapCloudIPtoServer is a convenience method to map a Cloud IP to a
// server. First looks up the server to get the network interface id. Uses the
// first interface found.
func (c *Client) MapCloudIPtoServer(identifier string, serverid string) error {
	server, err := c.Server(serverid)
	if err != nil {
		return err
	}
	if len(server.Interfaces) == 0 {
		return fmt.Errorf("Server %s has no interfaces to map cloud ip %s to", server.Id, identifier)
	}
	destination := server.Interfaces[0].Id
	err = c.MapCloudIP(identifier, destination)
	if err != nil {
		return err
	}
	return nil
}

// UnMapCloudIP issues a request to unmap the cloud ip.
func (c *Client) UnMapCloudIP(identifier string) error {
	_, err := c.MakeApiRequest("POST", "/1.0/cloud_ips/"+identifier+"/unmap", nil, nil)
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>Remove redundant pointer indirect on PortTranslators<commit_after>package brightbox

import (
	"fmt"
)

// CloudIP represents a Cloud IP
// https://api.gb1.brightbox.com/1.0/#cloud_ip
type CloudIP struct {
	Id              string
	Name            string
	PublicIP        string `json:"public_ip"`
	PublicIPv4      string `json:"public_ipv4"`
	PublicIPv6      string `json:"public_ipv6"`
	Status          string
	Locked          bool
	ReverseDns      string           `json:"reverse_dns"`
	PortTranslators []PortTranslator `json:"port_translators"`
	Account         Account
	Fqdn            string
	Interface       *ServerInterface
	Server          *Server
	ServerGroup     *ServerGroup    `json:"server_group"`
	LoadBalancer    *LoadBalancer   `json:"load_balancer"`
	DatabaseServer  *DatabaseServer `json:"database_server"`
}

// PortTranslator represents a port translator on a Cloud IP
type PortTranslator struct {
	Incoming int    `json:"incoming"`
	Outgoing int    `json:"outgoing"`
	Protocol string `json:"protocol"`
}

// CloudIPOptions is used in conjunction with CreateCloudIP and UpdateCloudIP to
// create and update cloud IPs.
type CloudIPOptions struct {
	Id              string           `json:"-"`
	ReverseDns      *string          `json:"reverse_dns,omitempty"`
	Name            *string          `json:"name,omitempty"`
	PortTranslators []PortTranslator `json:"port_translators,omitempty"`
}

// CloudIPs retrieves a list of all cloud ips
func (c *Client) CloudIPs() ([]CloudIP, error) {
	var cloudips []CloudIP
	_, err := c.MakeApiRequest("GET", "/1.0/cloud_ips", nil, &cloudips)
	if err != nil {
		return nil, err
	}
	return cloudips, err
}

// CloudIP retrieves a detailed view of one cloud ip
func (c *Client) CloudIP(identifier string) (*CloudIP, error) {
	cloudip := new(CloudIP)
	_, err := c.MakeApiRequest("GET", "/1.0/cloud_ips/"+identifier, nil, cloudip)
	if err != nil {
		return nil, err
	}
	return cloudip, err
}

// DestroyCloudIP issues a request to destroy the cloud ip
func (c *Client) DestroyCloudIP(identifier string) error {
	_, err := c.MakeApiRequest("DELETE", "/1.0/cloud_ips/"+identifier, nil, nil)
	if err != nil {
		return err
	}
	return nil
}

// CreateCloudIP creates a new Cloud IP.
//
// It takes a CloudIPOptions struct for specifying name and other attributes.
// Not all attributes can be specified at create time (such as Id, which is
// allocated for you)
func (c *Client) CreateCloudIP(newCloudIP *CloudIPOptions) (*CloudIP, error) {
	cloudip := new(CloudIP)
	_, err := c.MakeApiRequest("POST", "/1.0/cloud_ips", newCloudIP, &cloudip)
	if err != nil {
		return nil, err
	}
	return cloudip, nil
}

// UpdateCloudIP updates an existing cloud ip's attributes. Not all attributes
// can be changed after creation time (such as Id, which is allocated for you).
//
// Specify the cloud ip you want to update using the CloudIPOptions Id field
func (c *Client) UpdateCloudIP(updateCloudIP *CloudIPOptions) (*CloudIP, error) {
	cip := new(CloudIP)
	_, err := c.MakeApiRequest("PUT", "/1.0/cloud_ips/"+updateCloudIP.Id, updateCloudIP, &cip)
	if err != nil {
		return nil, err
	}
	return cip, nil
}

// MapCloudIP issues a request to map the cloud ip to the destination. The
// destination can be an identifier of any resource capable of receiving a Cloud
// IP, such as a server interface, a load balancer, or a cloud sql instace.
//
// To map a Cloud IP to a server, first lookup the server to get it's interface
// identifier (or use the MapCloudIPtoServer convenience method)
func (c *Client) MapCloudIP(identifier string, destination string) error {
	_, err := c.MakeApiRequest("POST", "/1.0/cloud_ips/"+identifier+"/map",
		map[string]string{"destination": destination}, nil)
	if err != nil {
		return err
	}
	return nil
}

// MapCloudIPtoServer is a convenience method to map a Cloud IP to a
// server. First looks up the server to get the network interface id. Uses the
// first interface found.
func (c *Client) MapCloudIPtoServer(identifier string, serverid string) error {
	server, err := c.Server(serverid)
	if err != nil {
		return err
	}
	if len(server.Interfaces) == 0 {
		return fmt.Errorf("Server %s has no interfaces to map cloud ip %s to", server.Id, identifier)
	}
	destination := server.Interfaces[0].Id
	err = c.MapCloudIP(identifier, destination)
	if err != nil {
		return err
	}
	return nil
}

// UnMapCloudIP issues a request to unmap the cloud ip.
func (c *Client) UnMapCloudIP(identifier string) error {
	_, err := c.MakeApiRequest("POST", "/1.0/cloud_ips/"+identifier+"/unmap", nil, nil)
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


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

package cmd

import (
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/spf13/cobra"

	composer2 "github.com/fubarhouse/drubuild/composer"
	"github.com/fubarhouse/drubuild/make"
	"github.com/spf13/viper"
	"path/filepath"
)

// removeGitFromPath will purge all .git data recursively from the specified path.
func removeGitFromPath(path string) {
	// Generate a list of .git file systems from the input path.
	fileList := []string{}
	filepath.Walk(path, func(path string, f os.FileInfo, err error) error {
		if strings.HasSuffix(path, ".git") && f.IsDir() {
			fileList = append(fileList, path)
		}
		return nil
	})

	// Loop over the generated list to remove them.
	for _, file := range fileList {
		if err := os.RemoveAll(file); err != nil {
			fmt.Printf("could not delete file system %v: %v\n", file, err)
		} else {
			fmt.Printf("removed %v\n", file)
		}
	}
}

// buildCmd represents the build command
var buildCmd = &cobra.Command{
	Use:   "build",
	Short: "The build process for Drubuild",
	Long:  ``,
	Run: func(cmd *cobra.Command, args []string) {

		db_user = viper.GetString("db_user")
		db_pass = viper.GetString("db_pass")
		db_host = viper.GetString("db_host")
		db_port = viper.GetInt("db_port")

		webserver = viper.GetString("webserver")

		alias_template = viper.GetString("alias_template")
		sites_php_template = viper.GetString("sites_php_template")
		virtualhost_path = viper.GetString("virtualhost_path")
		virtualhost_template = viper.GetString("virtualhost_template")

		if docroot == "" {
			log.Printf("docroot value is emptied, sub-folders will not be used.")
			timestamp = 0
		} else if timestamp == 0 {
			timestamp, _ = strconv.ParseInt(time.Now().Format("20060102150405"), 0, 0)
			log.Printf("Timestamp not specified, using %v", timestamp)
		}

		x := make.NewSite("", name, destination, alias, webserver, domain, virtualhost_path, virtualhost_template)
		x.AliasTemplate = alias_template
		x.Docroot = docroot
		if alias == "" {
			x.Alias = domain
		}

		y := make.NewmakeDB(db_host, db_user, db_pass, db_port)
		x.DatabaseSet(y)

		if workingCopy {
			x.WorkingCopy = true
		}

		if composer != "" {
			x.Composer = true
			composer2.InstallComposerCodebase(x.Name, x.TimeStampGet(), composer, x.Path, workingCopy)
		} else if makes != "" {
			x.Make = makes
			MakefilesFormatted := strings.Replace(makes, " ", "", -1)
			MakeFiles := strings.Split(MakefilesFormatted, ",")

			if rewriteSource != "" && rewriteDestination != "" {
				x.MakeFileRewriteSource = rewriteSource
				x.MakeFileRewriteDestination = rewriteDestination
			}
			x.ActionRebuildCodebase(MakeFiles)
		} else {
			cmd.Usage()
			fmt.Println()
			log.Fatalln("makes and/or composer values were not specified")
			os.Exit(1)
		}

		x.InstallSiteRef(sites_php_template)
		if timestamp != 0 {
			x.SymReinstall()
		}

		if !noInstall {
			x.ActionInstall()
		}

		if virtualhost_template != "" {
			if _, err := os.Stat(virtualhost_template); err == nil {
				log.Infof("Found template %v for usage", virtualhost_template)
				x.Template = virtualhost_template
			} else {
				log.Warnln("Could not find configured virtual host template.")
			}
		}

		if vhost {
			x.VhostInstall()
		}

		if alias_template != "" {
			if _, err := os.Stat(alias_template); err == nil {
				x.AliasTemplate = alias_template
			} else {
				log.Warnln("alias file could not be found.")
			}
		}

		if alias == "" {
			x.Alias = domain
		}

		if drupal {
			x.AliasInstall(docroot)
		}

		if workingCopy {
			removeGitFromPath(strings.Join([]string{x.Path, x.Domain + ".latest"}, string(os.PathSeparator)))
		}

		log.Infoln("Based upon the output above, you may need to restart the web service.")
	},
}

func init() {
	RootCmd.AddCommand(buildCmd)
	// Required flags
	buildCmd.Flags().StringVarP(&name, "name", "n", "", "The human-readable name for this site")
	buildCmd.Flags().StringVarP(&alias, "alias", "a", "", "The drush alias for this site")
	buildCmd.Flags().StringVarP(&destination, "destination", "p", "", "The path to where the site(s) exist.")
	buildCmd.Flags().StringVarP(&domain, "domain", "d", "", "The domain this site is to use")
	// Very important but not completely needed > 0 is needed though.
	buildCmd.Flags().StringVarP(&makes, "makes", "m", "", "A comma-separated list of make files for use")
	buildCmd.Flags().StringVarP(&composer, "composer", "c", "", "Path to the composer.json file.")
	// Optional flags
	buildCmd.Flags().StringVarP(&docroot, "docroot", "o", "docroot", "The folder to use for the built codebase.")
	buildCmd.Flags().BoolVarP(&drupal, "drupal", "r", true, "Mark the build process as a Drupal build.")
	buildCmd.Flags().BoolVarP(&noInstall, "no-install", "i", false, "Mark this build so that installation doesn't happen.")
	buildCmd.Flags().Int64VarP(&timestamp, "timestamp", "t", 0, "Optional timestamp in the format YYYYMMDDHHMMSS")
	buildCmd.Flags().BoolVarP(&vhost, "vhost", "v", true, "Include a virtual host as configured with this build.")
	// Deprecated flags
	buildCmd.Flags().StringVarP(&rewriteSource, "rewrite-source", "x", "", "The rewrite string source")
	buildCmd.Flags().StringVarP(&rewriteDestination, "rewrite-destination", "y", "", "The rewrite string destination")
	buildCmd.Flags().BoolVarP(&workingCopy, "working-copy", "w", false, "Mark as a working-copy during the build process.")
	// Hide deprecated fields.
	buildCmd.Flags().MarkHidden("rewrite-source")
	buildCmd.Flags().MarkHidden("rewrite-destination")
	// Mark required flags.
	buildCmd.MarkFlagRequired("name")
	buildCmd.MarkFlagRequired("destination")
	buildCmd.MarkFlagRequired("domain")

	// Database
	db_user = viper.GetString("db_user")
	db_pass = viper.GetString("db_pass")
	db_host = viper.GetString("db_host")
	db_port = viper.GetInt("db_port")

	// Sites.php template
	sites_php_template = viper.GetString("sites_php_template")

	// Alias template
	alias_template = viper.GetString("alias_template")

	// Virtual host
	webserver = viper.GetString("webserver")
	virtualhost_path = viper.GetString("virtualhost_path")
	virtualhost_template = viper.GetString("virtualhost_template")
}
<commit_msg>Reverses logic based upon workingCopy value.<commit_after>// Copyright © 2017 Karl Hepworth <Karl.Hepworth@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/spf13/cobra"

	composer2 "github.com/fubarhouse/drubuild/composer"
	"github.com/fubarhouse/drubuild/make"
	"github.com/spf13/viper"
	"path/filepath"
)

// removeGitFromPath will purge all .git data recursively from the specified path.
func removeGitFromPath(path string) {
	// Generate a list of .git file systems from the input path.
	fileList := []string{}
	filepath.Walk(path, func(path string, f os.FileInfo, err error) error {
		if strings.HasSuffix(path, ".git") && f.IsDir() {
			fileList = append(fileList, path)
		}
		return nil
	})

	// Loop over the generated list to remove them.
	for _, file := range fileList {
		if err := os.RemoveAll(file); err != nil {
			fmt.Printf("could not delete file system %v: %v\n", file, err)
		} else {
			fmt.Printf("removed %v\n", file)
		}
	}
}

// buildCmd represents the build command
var buildCmd = &cobra.Command{
	Use:   "build",
	Short: "The build process for Drubuild",
	Long:  ``,
	Run: func(cmd *cobra.Command, args []string) {

		db_user = viper.GetString("db_user")
		db_pass = viper.GetString("db_pass")
		db_host = viper.GetString("db_host")
		db_port = viper.GetInt("db_port")

		webserver = viper.GetString("webserver")

		alias_template = viper.GetString("alias_template")
		sites_php_template = viper.GetString("sites_php_template")
		virtualhost_path = viper.GetString("virtualhost_path")
		virtualhost_template = viper.GetString("virtualhost_template")

		if docroot == "" {
			log.Printf("docroot value is emptied, sub-folders will not be used.")
			timestamp = 0
		} else if timestamp == 0 {
			timestamp, _ = strconv.ParseInt(time.Now().Format("20060102150405"), 0, 0)
			log.Printf("Timestamp not specified, using %v", timestamp)
		}

		x := make.NewSite("", name, destination, alias, webserver, domain, virtualhost_path, virtualhost_template)
		x.AliasTemplate = alias_template
		x.Docroot = docroot
		if alias == "" {
			x.Alias = domain
		}

		y := make.NewmakeDB(db_host, db_user, db_pass, db_port)
		x.DatabaseSet(y)

		if workingCopy {
			x.WorkingCopy = true
		}

		if composer != "" {
			x.Composer = true
			composer2.InstallComposerCodebase(x.Name, x.TimeStampGet(), composer, x.Path, workingCopy)
		} else if makes != "" {
			x.Make = makes
			MakefilesFormatted := strings.Replace(makes, " ", "", -1)
			MakeFiles := strings.Split(MakefilesFormatted, ",")

			if rewriteSource != "" && rewriteDestination != "" {
				x.MakeFileRewriteSource = rewriteSource
				x.MakeFileRewriteDestination = rewriteDestination
			}
			x.ActionRebuildCodebase(MakeFiles)
		} else {
			cmd.Usage()
			fmt.Println()
			log.Fatalln("makes and/or composer values were not specified")
			os.Exit(1)
		}

		x.InstallSiteRef(sites_php_template)
		if timestamp != 0 {
			x.SymReinstall()
		}

		if !noInstall {
			x.ActionInstall()
		}

		if virtualhost_template != "" {
			if _, err := os.Stat(virtualhost_template); err == nil {
				log.Infof("Found template %v for usage", virtualhost_template)
				x.Template = virtualhost_template
			} else {
				log.Warnln("Could not find configured virtual host template.")
			}
		}

		if vhost {
			x.VhostInstall()
		}

		if alias_template != "" {
			if _, err := os.Stat(alias_template); err == nil {
				x.AliasTemplate = alias_template
			} else {
				log.Warnln("alias file could not be found.")
			}
		}

		if alias == "" {
			x.Alias = domain
		}

		if drupal {
			x.AliasInstall(docroot)
		}

		if !workingCopy {
			removeGitFromPath(strings.Join([]string{x.Path, x.Domain + ".latest"}, string(os.PathSeparator)))
		}

		log.Infoln("Based upon the output above, you may need to restart the web service.")
	},
}

func init() {
	RootCmd.AddCommand(buildCmd)
	// Required flags
	buildCmd.Flags().StringVarP(&name, "name", "n", "", "The human-readable name for this site")
	buildCmd.Flags().StringVarP(&alias, "alias", "a", "", "The drush alias for this site")
	buildCmd.Flags().StringVarP(&destination, "destination", "p", "", "The path to where the site(s) exist.")
	buildCmd.Flags().StringVarP(&domain, "domain", "d", "", "The domain this site is to use")
	// Very important but not completely needed > 0 is needed though.
	buildCmd.Flags().StringVarP(&makes, "makes", "m", "", "A comma-separated list of make files for use")
	buildCmd.Flags().StringVarP(&composer, "composer", "c", "", "Path to the composer.json file.")
	// Optional flags
	buildCmd.Flags().StringVarP(&docroot, "docroot", "o", "docroot", "The folder to use for the built codebase.")
	buildCmd.Flags().BoolVarP(&drupal, "drupal", "r", true, "Mark the build process as a Drupal build.")
	buildCmd.Flags().BoolVarP(&noInstall, "no-install", "i", false, "Mark this build so that installation doesn't happen.")
	buildCmd.Flags().Int64VarP(&timestamp, "timestamp", "t", 0, "Optional timestamp in the format YYYYMMDDHHMMSS")
	buildCmd.Flags().BoolVarP(&vhost, "vhost", "v", true, "Include a virtual host as configured with this build.")
	// Deprecated flags
	buildCmd.Flags().StringVarP(&rewriteSource, "rewrite-source", "x", "", "The rewrite string source")
	buildCmd.Flags().StringVarP(&rewriteDestination, "rewrite-destination", "y", "", "The rewrite string destination")
	buildCmd.Flags().BoolVarP(&workingCopy, "working-copy", "w", false, "Mark as a working-copy during the build process.")
	// Hide deprecated fields.
	buildCmd.Flags().MarkHidden("rewrite-source")
	buildCmd.Flags().MarkHidden("rewrite-destination")
	// Mark required flags.
	buildCmd.MarkFlagRequired("name")
	buildCmd.MarkFlagRequired("destination")
	buildCmd.MarkFlagRequired("domain")

	// Database
	db_user = viper.GetString("db_user")
	db_pass = viper.GetString("db_pass")
	db_host = viper.GetString("db_host")
	db_port = viper.GetInt("db_port")

	// Sites.php template
	sites_php_template = viper.GetString("sites_php_template")

	// Alias template
	alias_template = viper.GetString("alias_template")

	// Virtual host
	webserver = viper.GetString("webserver")
	virtualhost_path = viper.GetString("virtualhost_path")
	virtualhost_template = viper.GetString("virtualhost_template")
}
<|endoftext|>


<commit_before>package cmd

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/url"
	"strconv"

	"github.com/cozy/cozy-stack/client"
	"github.com/cozy/cozy-stack/client/request"
	"github.com/cozy/cozy-stack/model/account"
	"github.com/cozy/cozy-stack/model/app"
	"github.com/cozy/cozy-stack/model/instance/lifecycle"
	"github.com/cozy/cozy-stack/model/job"
	"github.com/cozy/cozy-stack/model/stack"
	"github.com/cozy/cozy-stack/model/vfs"
	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/couchdb"

	"github.com/spf13/cobra"
)

var dryRunFlag bool
var withMetadataFlag bool
var noDryRunFlag bool

var fixerCmdGroup = &cobra.Command{
	Use:   "fixer <command>",
	Short: "A set of tools to fix issues or migrate content for retro-compatibility.",
	RunE: func(cmd *cobra.Command, args []string) error {
		return cmd.Usage()
	},
}

var md5FixerCmd = &cobra.Command{
	Use:   "md5 <domain>",
	Short: "Fix missing md5 from contents in the vfs",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) == 0 {
			return cmd.Usage()
		}
		c := newClient(args[0], consts.Files)
		return c.WalkByPath("/", func(name string, doc *client.DirOrFile, err error) error {
			if err != nil {
				return err
			}
			attrs := doc.Attrs
			if attrs.Type == consts.DirType {
				return nil
			}
			if len(attrs.MD5Sum) > 0 {
				return nil
			}
			fmt.Printf("Recalculate md5 of %s...", name)
			r, err := c.DownloadByID(doc.ID)
			if err != nil {
				fmt.Printf("failed to init download: %s", err.Error())
				return nil
			}
			defer r.Close()
			h := md5.New()
			_, err = io.Copy(h, r)
			if err != nil {
				fmt.Printf("failed to download: %s", err.Error())
				return nil
			}
			_, err = c.UpdateAttrsByID(doc.ID, &client.FilePatch{
				Rev: doc.Rev,
				Attrs: client.FilePatchAttrs{
					MD5Sum: h.Sum(nil),
				},
			})
			if err != nil {
				fmt.Printf("failed to update: %s", err.Error())
				return nil
			}
			fmt.Println("ok.")
			return nil
		})
	},
}

var mimeFixerCmd = &cobra.Command{
	Use:   "mime <domain>",
	Short: "Fix the class computed from the mime-type",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) == 0 {
			return cmd.Usage()
		}
		c := newClient(args[0], consts.Files)
		return c.WalkByPath("/", func(name string, doc *client.DirOrFile, err error) error {
			if err != nil {
				return err
			}
			attrs := doc.Attrs
			if attrs.Type == consts.DirType {
				return nil
			}
			_, class := vfs.ExtractMimeAndClassFromFilename(attrs.Name)
			if class == attrs.Class {
				return nil
			}
			fmt.Printf("Fix %s: %s -> %s\n", attrs.Name, attrs.Class, class)
			_, err = c.UpdateAttrsByID(doc.ID, &client.FilePatch{
				Rev: doc.Rev,
				Attrs: client.FilePatchAttrs{
					Class: class,
				},
			})
			return err
		})
	},
}

var jobsFixer = &cobra.Command{
	Use:   "jobs <domain>",
	Short: "Take a look at the consistency of the jobs",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) == 0 {
			return cmd.Usage()
		}
		c := newClient(args[0], consts.Jobs)
		res, err := c.Req(&request.Options{
			Method: "POST",
			Path:   "/jobs/clean",
		})
		if err != nil {
			return err
		}
		defer res.Body.Close()
		var result struct {
			Deleted int `json:"deleted"`
		}
		err = json.NewDecoder(res.Body).Decode(&result)
		if err != nil {
			return err
		}

		fmt.Printf("Cleaned %d jobs on %s\n", result.Deleted, args[0])
		return nil
	},
}

var redisFixer = &cobra.Command{
	Use:   "redis",
	Short: "Rebuild scheduling data strucutures in redis",
	RunE: func(cmd *cobra.Command, args []string) error {
		c := newAdminClient()
		return c.RebuildRedis()
	},
}

var thumbnailsFixer = &cobra.Command{
	Use:   "thumbnails <domain>",
	Short: "Rebuild thumbnails image for images files",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) != 1 {
			return cmd.Usage()
		}
		domain := args[0]
		c := newClient(domain, "io.cozy.jobs")
		res, err := c.JobPush(&client.JobOptions{
			Worker: "thumbnailck",
			Arguments: struct {
				WithMetadata bool `json:"with_metadata"`
			}{
				WithMetadata: withMetadataFlag,
			},
		})
		if err != nil {
			return err
		}
		b, err := json.MarshalIndent(res, "", "  ")
		if err != nil {
			return err
		}
		fmt.Println(string(b))
		return nil
	},
}

var contentMismatch64Kfixer = &cobra.Command{
	Use:   "content-mismatch <domain>",
	Short: "Fix the content mismatch differences for 64K issue",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) == 0 {
			return cmd.Usage()
		}

		domain := args[0]
		q := url.Values{
			"dry_run": {strconv.FormatBool(!noDryRunFlag)},
		}

		c := newAdminClient()
		res, err := c.Req(&request.Options{
			Method:  "GET",
			Path:    "/instances/" + url.PathEscape(domain) + "/content-mismatch-fixer",
			Queries: q,
		})
		if err != nil {
			return err
		}

		out, err := ioutil.ReadAll(res.Body)
		if err != nil {
			return err
		}
		fmt.Println(string(out))

		return nil
	},
}

var orphanAccountFixer = &cobra.Command{
	Use:   "orphan-account <domain>",
	Short: "Rebuild scheduling data strucutures in redis",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) != 1 {
			return cmd.Usage()
		}

		domain := args[0]
		inst, err := lifecycle.GetInstance(domain)
		if err != nil {
			return err
		}

		var accounts []*account.Account
		err = couchdb.GetAllDocs(inst, consts.Accounts, nil, &accounts)
		if err != nil || len(accounts) == 0 {
			return err
		}

		var konnectors []*app.KonnManifest
		err = couchdb.GetAllDocs(inst, consts.Konnectors, nil, &konnectors)
		if err != nil {
			return err
		}

		var slugsToDelete []string
		for _, acc := range accounts {
			if acc.AccountType == "" {
				continue // Skip the design docs
			}
			found := false
			for _, konn := range konnectors {
				if konn.Slug() == acc.AccountType {
					found = true
					break
				}
			}
			if !found {
				for _, slug := range slugsToDelete {
					if slug == acc.AccountType {
						found = true
						break
					}
				}
				if !found {
					slugsToDelete = append(slugsToDelete, acc.AccountType)
				}
			}
		}
		if len(slugsToDelete) == 0 {
			return nil
		}

		if _, err = stack.Start(); err != nil {
			return err
		}
		jobsSystem := job.System()
		log := inst.Logger().WithField("nspace", "fixer")
		copier := inst.AppsCopier(consts.KonnectorType)

		for _, slug := range slugsToDelete {
			opts := &app.InstallerOptions{
				Operation:  app.Install,
				Type:       consts.KonnectorType,
				SourceURL:  "registry://" + slug,
				Slug:       slug,
				Registries: inst.Registries(),
			}
			ins, err := app.NewInstaller(inst, copier, opts)
			if err != nil {
				return err
			}
			if _, err = ins.RunSync(); err != nil {
				return err
			}

			for _, acc := range accounts {
				if acc.AccountType != slug {
					continue
				}
				acc.ManualCleaning = true
				if err := couchdb.DeleteDoc(inst, acc); err != nil {
					log.Errorf("Cannot delete account: %v", err)
				}
				j, err := account.PushAccountDeletedJob(jobsSystem, inst, acc.ID(), acc.Rev(), slug)
				if err != nil {
					log.Errorf("Cannot push a job for account deletion: %v", err)
				}
				if err = j.WaitUntilDone(inst); err != nil {
					log.Error(err)
				}
			}
			opts.Operation = app.Delete
			ins, err = app.NewInstaller(inst, copier, opts)
			if err != nil {
				return err
			}
			if _, err = ins.RunSync(); err != nil {
				return err
			}
		}

		return nil
	},
}

func init() {

	thumbnailsFixer.Flags().BoolVar(&dryRunFlag, "dry-run", false, "Dry run")
	thumbnailsFixer.Flags().BoolVar(&withMetadataFlag, "with-metadata", false, "Recalculate images metadata")
	contentMismatch64Kfixer.Flags().BoolVar(&noDryRunFlag, "no-dry-run", false, "Do not dry run")

	fixerCmdGroup.AddCommand(jobsFixer)
	fixerCmdGroup.AddCommand(md5FixerCmd)
	fixerCmdGroup.AddCommand(mimeFixerCmd)
	fixerCmdGroup.AddCommand(redisFixer)
	fixerCmdGroup.AddCommand(thumbnailsFixer)
	fixerCmdGroup.AddCommand(contentMismatch64Kfixer)
	fixerCmdGroup.AddCommand(orphanAccountFixer)

	RootCmd.AddCommand(fixerCmdGroup)
}
<commit_msg>Re-add contactsEmailsFixer<commit_after>package cmd

import (
	"bytes"
	"crypto/md5"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/mail"
	"net/url"
	"os"
	"regexp"
	"strconv"
	"strings"

	"github.com/cozy/cozy-stack/client"
	"github.com/cozy/cozy-stack/client/request"
	"github.com/cozy/cozy-stack/model/account"
	"github.com/cozy/cozy-stack/model/app"
	"github.com/cozy/cozy-stack/model/contact"
	"github.com/cozy/cozy-stack/model/instance/lifecycle"
	"github.com/cozy/cozy-stack/model/job"
	"github.com/cozy/cozy-stack/model/stack"
	"github.com/cozy/cozy-stack/model/vfs"
	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/couchdb"

	"github.com/spf13/cobra"
)

var dryRunFlag bool
var withMetadataFlag bool
var noDryRunFlag bool

var fixerCmdGroup = &cobra.Command{
	Use:   "fixer <command>",
	Short: "A set of tools to fix issues or migrate content for retro-compatibility.",
	RunE: func(cmd *cobra.Command, args []string) error {
		return cmd.Usage()
	},
}

var md5FixerCmd = &cobra.Command{
	Use:   "md5 <domain>",
	Short: "Fix missing md5 from contents in the vfs",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) == 0 {
			return cmd.Usage()
		}
		c := newClient(args[0], consts.Files)
		return c.WalkByPath("/", func(name string, doc *client.DirOrFile, err error) error {
			if err != nil {
				return err
			}
			attrs := doc.Attrs
			if attrs.Type == consts.DirType {
				return nil
			}
			if len(attrs.MD5Sum) > 0 {
				return nil
			}
			fmt.Printf("Recalculate md5 of %s...", name)
			r, err := c.DownloadByID(doc.ID)
			if err != nil {
				fmt.Printf("failed to init download: %s", err.Error())
				return nil
			}
			defer r.Close()
			h := md5.New()
			_, err = io.Copy(h, r)
			if err != nil {
				fmt.Printf("failed to download: %s", err.Error())
				return nil
			}
			_, err = c.UpdateAttrsByID(doc.ID, &client.FilePatch{
				Rev: doc.Rev,
				Attrs: client.FilePatchAttrs{
					MD5Sum: h.Sum(nil),
				},
			})
			if err != nil {
				fmt.Printf("failed to update: %s", err.Error())
				return nil
			}
			fmt.Println("ok.")
			return nil
		})
	},
}

var mimeFixerCmd = &cobra.Command{
	Use:   "mime <domain>",
	Short: "Fix the class computed from the mime-type",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) == 0 {
			return cmd.Usage()
		}
		c := newClient(args[0], consts.Files)
		return c.WalkByPath("/", func(name string, doc *client.DirOrFile, err error) error {
			if err != nil {
				return err
			}
			attrs := doc.Attrs
			if attrs.Type == consts.DirType {
				return nil
			}
			_, class := vfs.ExtractMimeAndClassFromFilename(attrs.Name)
			if class == attrs.Class {
				return nil
			}
			fmt.Printf("Fix %s: %s -> %s\n", attrs.Name, attrs.Class, class)
			_, err = c.UpdateAttrsByID(doc.ID, &client.FilePatch{
				Rev: doc.Rev,
				Attrs: client.FilePatchAttrs{
					Class: class,
				},
			})
			return err
		})
	},
}

var jobsFixer = &cobra.Command{
	Use:   "jobs <domain>",
	Short: "Take a look at the consistency of the jobs",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) == 0 {
			return cmd.Usage()
		}
		c := newClient(args[0], consts.Jobs)
		res, err := c.Req(&request.Options{
			Method: "POST",
			Path:   "/jobs/clean",
		})
		if err != nil {
			return err
		}
		defer res.Body.Close()
		var result struct {
			Deleted int `json:"deleted"`
		}
		err = json.NewDecoder(res.Body).Decode(&result)
		if err != nil {
			return err
		}

		fmt.Printf("Cleaned %d jobs on %s\n", result.Deleted, args[0])
		return nil
	},
}

var redisFixer = &cobra.Command{
	Use:   "redis",
	Short: "Rebuild scheduling data strucutures in redis",
	RunE: func(cmd *cobra.Command, args []string) error {
		c := newAdminClient()
		return c.RebuildRedis()
	},
}

var thumbnailsFixer = &cobra.Command{
	Use:   "thumbnails <domain>",
	Short: "Rebuild thumbnails image for images files",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) != 1 {
			return cmd.Usage()
		}
		domain := args[0]
		c := newClient(domain, "io.cozy.jobs")
		res, err := c.JobPush(&client.JobOptions{
			Worker: "thumbnailck",
			Arguments: struct {
				WithMetadata bool `json:"with_metadata"`
			}{
				WithMetadata: withMetadataFlag,
			},
		})
		if err != nil {
			return err
		}
		b, err := json.MarshalIndent(res, "", "  ")
		if err != nil {
			return err
		}
		fmt.Println(string(b))
		return nil
	},
}

var contactEmailsFixer = &cobra.Command{
	Use:   "contact-emails",
	Short: "Detect and try to fix invalid emails on contacts",
	RunE: func(cmd *cobra.Command, args []string) error {
		c := newAdminClient()
		instances, err := c.ListInstances()
		if err != nil {
			return err
		}

		semicolonAtEnd := regexp.MustCompile(";$")
		dotAtStart := regexp.MustCompile(`^\.`)
		dotAtEnd := regexp.MustCompile(`\.$`)
		lessThanStart := regexp.MustCompile("^<")
		greaterThanEnd := regexp.MustCompile(">$")
		mailto := regexp.MustCompile("^mailto:")

		fixEmails := func(domain string) error {

			c, err := newClientSafe(domain, consts.Contacts)
			if err != nil {
				return err
			}

			res, err := c.Req(&request.Options{
				Method: "GET",
				Path:   "/data/" + consts.Contacts + "/_all_docs",
				Queries: url.Values{
					"include_docs": {"true"},
				},
			})
			if err != nil {
				return err
			}
			defer res.Body.Close()

			var contacts struct {
				Rows []struct {
					Contact contact.Contact `json:"doc"`
				} `json:"rows"`
			}
			buf, err := ioutil.ReadAll(res.Body)
			if err != nil {
				return err
			}
			err = json.Unmarshal(buf, &contacts)
			if err != nil {
				return err
			}

			for _, r := range contacts.Rows {
				co := r.Contact
				id := co.ID()
				if strings.HasPrefix(id, "_design") {
					continue
				}

				changed := false
				emails, ok := co.Get("emails").([]interface{})
				if !ok {
					continue
				}
				for i := range emails {
					email, ok := emails[i].(map[string]interface{})
					if !ok {
						continue
					}
					address, ok := email["address"].(string)
					if !ok {
						continue
					}
					_, err := mail.ParseAddress(address)
					if err != nil {
						old := address
						address = strings.TrimSpace(address)
						address = strings.Replace(address, "\"", "", -1)
						address = strings.Replace(address, ",", ".", -1)
						address = strings.Replace(address, " .", ".", -1)
						address = strings.Replace(address, ". ", ".", -1)
						address = strings.Replace(address, ". ", ".", -1)
						address = strings.Replace(address, "..", ".", -1)
						address = strings.Replace(address, ".@", "@", -1)
						address = strings.Replace(address, "@.", "@", -1)
						address = strings.Replace(address, " @", "@", -1)
						address = strings.Replace(address, "@ ", "@", -1)
						address = mailto.ReplaceAllString(address, "")
						address = semicolonAtEnd.ReplaceAllString(address, "")
						address = dotAtStart.ReplaceAllString(address, "")
						address = dotAtEnd.ReplaceAllString(address, "")
						address = lessThanStart.ReplaceAllString(address, "")
						address = greaterThanEnd.ReplaceAllString(address, "")
						address = strings.TrimSpace(address)
						_, err := mail.ParseAddress(address)
						if err == nil {
							fmt.Printf("    Email fixed: \"%s\" → \"%s\"\n", old, address)
							changed = true
							email["address"] = address
						} else {
							fmt.Printf("    Invalid email: \"%s\" → \"%s\"\n", old, address)
						}
					}
				}

				if changed {
					co.M["email"] = emails
					json, err := json.Marshal(co)
					if err != nil {
						return err
					}
					body := bytes.NewReader(json)

					_, err = c.Req(&request.Options{
						Method: "PUT",
						Path:   "/data/" + consts.Contacts + "/" + id,
						Body:   body,
					})
					if err != nil {
						return err
					}
				}
			}

			return nil
		}

		for _, instance := range instances {
			domain := instance.Attrs.Domain
			fmt.Fprintf(os.Stderr, "Fixing %s contact emails...\n", domain)
			err := fixEmails(domain)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error occurred: %s\n", err)
			}
		}

		return nil
	},
}

var contentMismatch64Kfixer = &cobra.Command{
	Use:   "content-mismatch <domain>",
	Short: "Fix the content mismatch differences for 64K issue",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) == 0 {
			return cmd.Usage()
		}

		domain := args[0]
		q := url.Values{
			"dry_run": {strconv.FormatBool(!noDryRunFlag)},
		}

		c := newAdminClient()
		res, err := c.Req(&request.Options{
			Method:  "GET",
			Path:    "/instances/" + url.PathEscape(domain) + "/content-mismatch-fixer",
			Queries: q,
		})
		if err != nil {
			return err
		}

		out, err := ioutil.ReadAll(res.Body)
		if err != nil {
			return err
		}
		fmt.Println(string(out))

		return nil
	},
}

var orphanAccountFixer = &cobra.Command{
	Use:   "orphan-account <domain>",
	Short: "Rebuild scheduling data strucutures in redis",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) != 1 {
			return cmd.Usage()
		}

		domain := args[0]
		inst, err := lifecycle.GetInstance(domain)
		if err != nil {
			return err
		}

		var accounts []*account.Account
		err = couchdb.GetAllDocs(inst, consts.Accounts, nil, &accounts)
		if err != nil || len(accounts) == 0 {
			return err
		}

		var konnectors []*app.KonnManifest
		err = couchdb.GetAllDocs(inst, consts.Konnectors, nil, &konnectors)
		if err != nil {
			return err
		}

		var slugsToDelete []string
		for _, acc := range accounts {
			if acc.AccountType == "" {
				continue // Skip the design docs
			}
			found := false
			for _, konn := range konnectors {
				if konn.Slug() == acc.AccountType {
					found = true
					break
				}
			}
			if !found {
				for _, slug := range slugsToDelete {
					if slug == acc.AccountType {
						found = true
						break
					}
				}
				if !found {
					slugsToDelete = append(slugsToDelete, acc.AccountType)
				}
			}
		}
		if len(slugsToDelete) == 0 {
			return nil
		}

		if _, err = stack.Start(); err != nil {
			return err
		}
		jobsSystem := job.System()
		log := inst.Logger().WithField("nspace", "fixer")
		copier := inst.AppsCopier(consts.KonnectorType)

		for _, slug := range slugsToDelete {
			opts := &app.InstallerOptions{
				Operation:  app.Install,
				Type:       consts.KonnectorType,
				SourceURL:  "registry://" + slug,
				Slug:       slug,
				Registries: inst.Registries(),
			}
			ins, err := app.NewInstaller(inst, copier, opts)
			if err != nil {
				return err
			}
			if _, err = ins.RunSync(); err != nil {
				return err
			}

			for _, acc := range accounts {
				if acc.AccountType != slug {
					continue
				}
				acc.ManualCleaning = true
				if err := couchdb.DeleteDoc(inst, acc); err != nil {
					log.Errorf("Cannot delete account: %v", err)
				}
				j, err := account.PushAccountDeletedJob(jobsSystem, inst, acc.ID(), acc.Rev(), slug)
				if err != nil {
					log.Errorf("Cannot push a job for account deletion: %v", err)
				}
				if err = j.WaitUntilDone(inst); err != nil {
					log.Error(err)
				}
			}
			opts.Operation = app.Delete
			ins, err = app.NewInstaller(inst, copier, opts)
			if err != nil {
				return err
			}
			if _, err = ins.RunSync(); err != nil {
				return err
			}
		}

		return nil
	},
}

func init() {

	thumbnailsFixer.Flags().BoolVar(&dryRunFlag, "dry-run", false, "Dry run")
	thumbnailsFixer.Flags().BoolVar(&withMetadataFlag, "with-metadata", false, "Recalculate images metadata")
	contentMismatch64Kfixer.Flags().BoolVar(&noDryRunFlag, "no-dry-run", false, "Do not dry run")

	fixerCmdGroup.AddCommand(jobsFixer)
	fixerCmdGroup.AddCommand(md5FixerCmd)
	fixerCmdGroup.AddCommand(mimeFixerCmd)
	fixerCmdGroup.AddCommand(redisFixer)
	fixerCmdGroup.AddCommand(thumbnailsFixer)
	fixerCmdGroup.AddCommand(contactEmailsFixer)
	fixerCmdGroup.AddCommand(contentMismatch64Kfixer)
	fixerCmdGroup.AddCommand(orphanAccountFixer)

	RootCmd.AddCommand(fixerCmdGroup)
}
<|endoftext|>