func (s *StoreBuildOptionsMap) Run(context map[string]interface{}) error {
	buildPath := context[constants.CTX_BUILD_PATH].(string)
	buildOptionsJson := context[constants.CTX_BUILD_OPTIONS_JSON].(string)

	utils.WriteFile(filepath.Join(buildPath, constants.BUILD_OPTIONS_FILE), buildOptionsJson)

	return nil
}
func (s *GCCPreprocSourceSaver) Run(ctx *types.Context) error {
	preprocPath := ctx.PreprocPath
	err := utils.EnsureFolderExists(preprocPath)
	if err != nil {
		return i18n.WrapError(err)
	}

	err = utils.WriteFile(filepath.Join(preprocPath, constants.FILE_GCC_PREPROC_TARGET), ctx.Source)
	return i18n.WrapError(err)
}
func (s *GCCPreprocSourceSaver) Run(context map[string]interface{}) error {
	preprocPath := context[constants.CTX_PREPROC_PATH].(string)
	err := utils.EnsureFolderExists(preprocPath)
	if err != nil {
		return utils.WrapError(err)
	}

	source := context[constants.CTX_SOURCE].(string)

	err = utils.WriteFile(filepath.Join(preprocPath, constants.FILE_GCC_PREPROC_TARGET), source)
	return utils.WrapError(err)
}
func (s *SketchSaver) Run(ctx *types.Context) error {
	sketch := ctx.Sketch
	sketchBuildPath := ctx.SketchBuildPath

	err := utils.EnsureFolderExists(sketchBuildPath)
	if err != nil {
		return i18n.WrapError(err)
	}

	err = utils.WriteFile(filepath.Join(sketchBuildPath, filepath.Base(sketch.MainFile.Name)+".cpp"), ctx.Source)
	return i18n.WrapError(err)
}
func (s *SketchSaver) Run(context map[string]interface{}) error {
	sketch := context[constants.CTX_SKETCH].(*types.Sketch)
	sketchBuildPath := context[constants.CTX_SKETCH_BUILD_PATH].(string)
	source := context[constants.CTX_SOURCE].(string)

	err := utils.EnsureFolderExists(sketchBuildPath)
	if err != nil {
		return utils.WrapError(err)
	}

	err = utils.WriteFile(filepath.Join(sketchBuildPath, filepath.Base(sketch.MainFile.Name)+".cpp"), source)
	return utils.WrapError(err)
}
func TestLoadPreviousBuildOptionsMap(t *testing.T) {
	context := make(map[string]interface{})

	buildPath := SetupBuildPath(t, context)
	defer os.RemoveAll(buildPath)

	err := utils.WriteFile(filepath.Join(buildPath, constants.BUILD_OPTIONS_FILE), "test")
	NoError(t, err)

	command := builder.LoadPreviousBuildOptionsMap{}
	err = command.Run(context)
	NoError(t, err)

	require.Equal(t, "test", context[constants.CTX_BUILD_OPTIONS_PREVIOUS_JSON])
}
func TestLoadPreviousBuildOptionsMap(t *testing.T) {
	ctx := &types.Context{}

	buildPath := SetupBuildPath(t, ctx)
	defer os.RemoveAll(buildPath)

	err := utils.WriteFile(filepath.Join(buildPath, constants.BUILD_OPTIONS_FILE), "test")
	NoError(t, err)

	command := builder.LoadPreviousBuildOptionsMap{}
	err = command.Run(ctx)
	NoError(t, err)

	require.Equal(t, "test", ctx.BuildOptionsJsonPrevious)
}
func TestReadFileAndStoreInContext(t *testing.T) {
	file, err := ioutil.TempFile("", "test")
	NoError(t, err)
	defer os.RemoveAll(file.Name())

	utils.WriteFile(file.Name(), "test test\nciao")

	context := make(map[string]interface{})
	context[constants.CTX_FILE_PATH_TO_READ] = file.Name()

	command := &builder.ReadFileAndStoreInContext{TargetField: constants.CTX_GCC_MINUS_E_SOURCE}
	err = command.Run(context)
	NoError(t, err)

	require.Equal(t, "test test\nciao", context[constants.CTX_GCC_MINUS_E_SOURCE].(string))
}
func TestReadFileAndStoreInContext(t *testing.T) {
	file, err := ioutil.TempFile("", "test")
	NoError(t, err)
	defer os.RemoveAll(file.Name())

	utils.WriteFile(file.Name(), "test test\nciao")

	ctx := &types.Context{}
	ctx.FileToRead = file.Name()

	command := &builder.ReadFileAndStoreInContext{Target: &ctx.SourceGccMinusE}
	err = command.Run(ctx)
	NoError(t, err)

	require.Equal(t, "test test\nciao", ctx.SourceGccMinusE)
}
func merge(builtSketchPath, bootloaderPath, mergedSketchPath string) error {
	sketch, err := utils.ReadFileToRows(builtSketchPath)
	if err != nil {
		return utils.WrapError(err)
	}
	sketch = sketch[:len(sketch)-2]

	bootloader, err := utils.ReadFileToRows(bootloaderPath)
	if err != nil {
		return utils.WrapError(err)
	}

	for _, row := range bootloader {
		sketch = append(sketch, row)
	}

	return utils.WriteFile(mergedSketchPath, strings.Join(sketch, "\n"))
}
func (s *CTagsTargetFileSaver) Run(context map[string]interface{}) error {
	source := context[s.SourceField].(string)

	preprocPath := context[constants.CTX_PREPROC_PATH].(string)
	err := utils.EnsureFolderExists(preprocPath)
	if err != nil {
		return utils.WrapError(err)
	}

	ctagsTargetFilePath := filepath.Join(preprocPath, s.TargetFileName)
	err = utils.WriteFile(ctagsTargetFilePath, source)
	if err != nil {
		return utils.WrapError(err)
	}

	context[constants.CTX_CTAGS_TEMP_FILE_PATH] = ctagsTargetFilePath

	return nil
}
func (s *CTagsTargetFileSaver) Run(ctx *types.Context) error {
	source := *s.Source

	preprocPath := ctx.PreprocPath
	err := utils.EnsureFolderExists(preprocPath)
	if err != nil {
		return i18n.WrapError(err)
	}

	ctagsTargetFilePath := filepath.Join(preprocPath, s.TargetFileName)
	err = utils.WriteFile(ctagsTargetFilePath, source)
	if err != nil {
		return i18n.WrapError(err)
	}

	ctx.CTagsTargetFile = ctagsTargetFilePath

	return nil
}
func TestMergeSketchWithBootloaderSketchInBuildPath(t *testing.T) {
	DownloadCoresAndToolsAndLibraries(t)

	context := make(map[string]interface{})

	buildPath := SetupBuildPath(t, context)
	defer os.RemoveAll(buildPath)

	context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"}
	context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"}
	context[constants.CTX_FQBN] = "arduino:avr:uno"
	context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"}
	context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"}
	context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch1", "sketch.ino")
	context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600"

	err := utils.EnsureFolderExists(filepath.Join(buildPath, "sketch"))
	NoError(t, err)

	fakeSketchHex := "row 1\n" +
		"row 2\n"
	err = utils.WriteFile(filepath.Join(buildPath, "sketch.ino.hex"), fakeSketchHex)
	NoError(t, err)

	commands := []types.Command{
		&builder.SetupHumanLoggerIfMissing{},
		&builder.ContainerSetupHardwareToolsLibsSketchAndProps{},
		&builder.MergeSketchWithBootloader{},
	}

	for _, command := range commands {
		err := command.Run(context)
		NoError(t, err)
	}

	bytes, err := ioutil.ReadFile(filepath.Join(buildPath, "sketch.ino.with_bootloader.hex"))
	NoError(t, err)
	mergedSketchHex := string(bytes)

	require.True(t, strings.HasPrefix(mergedSketchHex, "row 1\n:107E0000112484B714BE81FFF0D085E080938100F7\n"))
	require.True(t, strings.HasSuffix(mergedSketchHex, ":0400000300007E007B\n:00000001FF\n"))
}
func TestObjFileIsUpToDateDepIsOlder(t *testing.T) {
	sourceFile := tempFile(t, "source")
	defer os.RemoveAll(sourceFile)

	headerFile := tempFile(t, "header")
	defer os.RemoveAll(headerFile)

	sleep(t)

	objFile := tempFile(t, "obj")
	defer os.RemoveAll(objFile)
	depFile := tempFile(t, "dep")
	defer os.RemoveAll(depFile)

	utils.WriteFile(depFile, objFile+": \\\n\t"+sourceFile+" \\\n\t"+headerFile)

	upToDate, err := builder_utils.ObjFileIsUpToDate(sourceFile, objFile, depFile)
	NoError(t, err)
	require.True(t, upToDate)
}
func (s *CoanRunner) Run(context map[string]interface{}) error {
	source := context[constants.CTX_SOURCE].(string)
	source += "\n"
	verbose := context[constants.CTX_VERBOSE].(bool)

	preprocPath := context[constants.CTX_PREPROC_PATH].(string)
	err := utils.EnsureFolderExists(preprocPath)
	if err != nil {
		return utils.WrapError(err)
	}

	coanTargetFileName := filepath.Join(preprocPath, constants.FILE_COAN_TARGET)
	err = utils.WriteFile(coanTargetFileName, source)
	if err != nil {
		return utils.WrapError(err)
	}

	buildProperties := context[constants.CTX_BUILD_PROPERTIES].(props.PropertiesMap)
	properties := buildProperties.Clone()
	properties.Merge(buildProperties.SubTree(constants.BUILD_PROPERTIES_TOOLS_KEY).SubTree(constants.COAN))
	properties[constants.BUILD_PROPERTIES_SOURCE_FILE] = coanTargetFileName

	pattern := properties[constants.BUILD_PROPERTIES_PATTERN]
	if pattern == constants.EMPTY_STRING {
		return utils.Errorf(context, constants.MSG_PATTERN_MISSING, constants.COAN)
	}

	logger := context[constants.CTX_LOGGER].(i18n.Logger)
	commandLine := properties.ExpandPropsInString(pattern)
	command, err := utils.PrepareCommandFilteredArgs(commandLine, filterAllowedArg, logger)

	if verbose {
		fmt.Println(commandLine)
	}

	sourceBytes, _ := command.Output()

	context[constants.CTX_SOURCE] = string(sourceBytes)

	return nil
}
func TestMergeSketchWithBootloaderSketchInBuildPath(t *testing.T) {
	DownloadCoresAndToolsAndLibraries(t)

	ctx := &types.Context{
		HardwareFolders:         []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"},
		ToolsFolders:            []string{"downloaded_tools"},
		BuiltInLibrariesFolders: []string{"downloaded_libraries"},
		OtherLibrariesFolders:   []string{"libraries"},
		SketchLocation:          filepath.Join("sketch1", "sketch.ino"),
		FQBN:                    "arduino:avr:uno",
		ArduinoAPIVersion:       "10600",
	}

	buildPath := SetupBuildPath(t, ctx)
	defer os.RemoveAll(buildPath)

	err := utils.EnsureFolderExists(filepath.Join(buildPath, "sketch"))
	NoError(t, err)

	fakeSketchHex := "row 1\n" +
		"row 2\n"
	err = utils.WriteFile(filepath.Join(buildPath, "sketch.ino.hex"), fakeSketchHex)
	NoError(t, err)

	commands := []types.Command{
		&builder.ContainerSetupHardwareToolsLibsSketchAndProps{},
		&builder.MergeSketchWithBootloader{},
	}

	for _, command := range commands {
		err := command.Run(ctx)
		NoError(t, err)
	}

	bytes, err := ioutil.ReadFile(filepath.Join(buildPath, "sketch.ino.with_bootloader.hex"))
	NoError(t, err)
	mergedSketchHex := string(bytes)

	require.True(t, strings.HasPrefix(mergedSketchHex, "row 1\n:107E0000112484B714BE81FFF0D085E080938100F7\n"))
	require.True(t, strings.HasSuffix(mergedSketchHex, ":0400000300007E007B\n:00000001FF\n"))
}
func (s *StoreBuildOptionsMap) Run(ctx *types.Context) error {
	utils.WriteFile(filepath.Join(ctx.BuildPath, constants.BUILD_OPTIONS_FILE), ctx.BuildOptionsJson)
	return nil
}