| 
 | 1 | +// Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.  | 
 | 2 | + | 
 | 3 | +package oci_tool  | 
 | 4 | + | 
 | 5 | +import (  | 
 | 6 | +	"bufio"  | 
 | 7 | +	"fmt"  | 
 | 8 | +	"io"  | 
 | 9 | +	"io/ioutil"  | 
 | 10 | +	"os"  | 
 | 11 | +	"path"  | 
 | 12 | +	"path/filepath"  | 
 | 13 | +)  | 
 | 14 | + | 
 | 15 | +// Individual file io strategies for different operations  | 
 | 16 | +type FileAction func(string, string) error  | 
 | 17 | + | 
 | 18 | +// Traverse a directory, executing the supplied FileAction on each file  | 
 | 19 | +func ProcessDirectory(targetDir string, backupDir string, fileActionFn FileAction, targetExtns ...string) (err error) {  | 
 | 20 | + | 
 | 21 | +	_, err = os.Stat(targetDir)  | 
 | 22 | + | 
 | 23 | +	if err != nil {  | 
 | 24 | +		return fmt.Errorf("Error reading directory\n %s", err)  | 
 | 25 | +	}  | 
 | 26 | + | 
 | 27 | +	files, err := ioutil.ReadDir(targetDir)  | 
 | 28 | + | 
 | 29 | +	if err != nil {  | 
 | 30 | +		fmt.Errorf("Error reading directory contents \n %s", err)  | 
 | 31 | +	}  | 
 | 32 | + | 
 | 33 | +	for _, res := range files {  | 
 | 34 | +		targetRes := path.Join(targetDir, res.Name())  | 
 | 35 | +		backupRes := path.Join(backupDir, res.Name())  | 
 | 36 | + | 
 | 37 | +		if res.IsDir() {  | 
 | 38 | +			err = ProcessDirectory(targetRes, backupRes, fileActionFn, targetExtns...)  | 
 | 39 | + | 
 | 40 | +			if err != nil {  | 
 | 41 | +				return err  | 
 | 42 | +			}  | 
 | 43 | +		} else {  | 
 | 44 | +			if len(targetExtns) == 0 {  | 
 | 45 | +				err = fileActionFn(targetRes, backupRes)  | 
 | 46 | + | 
 | 47 | +				if err != nil {  | 
 | 48 | +					return err  | 
 | 49 | +				}  | 
 | 50 | +			} else {  | 
 | 51 | +				if contains(targetExtns, filepath.Ext(res.Name())) {  | 
 | 52 | +					err = fileActionFn(targetRes, backupRes)  | 
 | 53 | + | 
 | 54 | +					if err != nil {  | 
 | 55 | +						return err  | 
 | 56 | +					}  | 
 | 57 | +				} else {  | 
 | 58 | +					fmt.Println("Skipping: ", targetDir)  | 
 | 59 | +				}  | 
 | 60 | +			}  | 
 | 61 | +		}  | 
 | 62 | +	}  | 
 | 63 | + | 
 | 64 | +	return  | 
 | 65 | +}  | 
 | 66 | + | 
 | 67 | +// Copy file from targetFile path to backupFile path  | 
 | 68 | +func CopyFile(targetFile string, backupFile string) (err error) {  | 
 | 69 | + | 
 | 70 | +	// make sure directory structure exists  | 
 | 71 | +	bkDir := path.Dir(backupFile)  | 
 | 72 | +	_, err = os.Stat(bkDir)  | 
 | 73 | + | 
 | 74 | +	if err != nil {  | 
 | 75 | +		if os.IsNotExist(err) {  | 
 | 76 | +			oDir := path.Dir(targetFile)  | 
 | 77 | +			fi, err := os.Stat(oDir)  | 
 | 78 | + | 
 | 79 | +			if err != nil {  | 
 | 80 | +				return fmt.Errorf("Error reading original directory %s", err)  | 
 | 81 | +			}  | 
 | 82 | + | 
 | 83 | +			err = os.MkdirAll(bkDir, fi.Mode())  | 
 | 84 | + | 
 | 85 | +			if err != nil {  | 
 | 86 | +				return fmt.Errorf("Error creating directory for file %s", err)  | 
 | 87 | +			}  | 
 | 88 | +		} else {  | 
 | 89 | +			return fmt.Errorf("Unexpected error reading original directory %s", err)  | 
 | 90 | +		}  | 
 | 91 | +	}  | 
 | 92 | + | 
 | 93 | +	src, err := os.Open(targetFile)  | 
 | 94 | + | 
 | 95 | +	if err != nil {  | 
 | 96 | +		return fmt.Errorf("Error reading original file\n %s", err)  | 
 | 97 | +	}  | 
 | 98 | + | 
 | 99 | +	defer src.Close()  | 
 | 100 | + | 
 | 101 | +	dst, err := os.Create(backupFile)  | 
 | 102 | + | 
 | 103 | +	if err != nil {  | 
 | 104 | +		return fmt.Errorf("Error creating backup file\n %s", err)  | 
 | 105 | +	}  | 
 | 106 | + | 
 | 107 | +	defer dst.Close()  | 
 | 108 | + | 
 | 109 | +	fmt.Printf("Copying %s --> %s", targetFile, backupFile)  | 
 | 110 | +	size, err := io.Copy(dst, src)  | 
 | 111 | + | 
 | 112 | +	if err != nil {  | 
 | 113 | +		return fmt.Errorf("Error writing file\n %s", err)  | 
 | 114 | +	}  | 
 | 115 | + | 
 | 116 | +	fmt.Printf(", %d bytes\n", size)  | 
 | 117 | +	return  | 
 | 118 | +}  | 
 | 119 | + | 
 | 120 | +// Read file from backup location, apply transforms and overwrite original file  | 
 | 121 | +func MigratePlanFile(targetFile string, backupFile string) (err error) {  | 
 | 122 | +	src, err := os.Open(backupFile)  | 
 | 123 | + | 
 | 124 | +	if err != nil {  | 
 | 125 | +		return fmt.Errorf("Error reading file\n %s", err)  | 
 | 126 | +	}  | 
 | 127 | + | 
 | 128 | +	defer src.Close()  | 
 | 129 | + | 
 | 130 | +	dst, err := os.Create(targetFile)  | 
 | 131 | + | 
 | 132 | +	if err != nil {  | 
 | 133 | +		return fmt.Errorf("Error creating write location\n %s", err)  | 
 | 134 | +	}  | 
 | 135 | + | 
 | 136 | +	defer dst.Close()  | 
 | 137 | + | 
 | 138 | +	wrtr := bufio.NewWriter(dst)  | 
 | 139 | + | 
 | 140 | +	var replaceStrategy func(string) string  | 
 | 141 | +	if filepath.Ext(backupFile) == ".tf" {  | 
 | 142 | +		replaceStrategy = replaceTemplateTokens  | 
 | 143 | +	} else {  | 
 | 144 | +		replaceStrategy = replaceStatefileTokens  | 
 | 145 | +	}  | 
 | 146 | + | 
 | 147 | +	scanner := bufio.NewScanner(src)  | 
 | 148 | +	for scanner.Scan() {  | 
 | 149 | +		str := scanner.Text()  | 
 | 150 | +		str = replaceStrategy(str)  | 
 | 151 | +		fmt.Fprintln(wrtr, str)  | 
 | 152 | +	}  | 
 | 153 | +	wrtr.Flush()  | 
 | 154 | + | 
 | 155 | +	return  | 
 | 156 | +}  | 
 | 157 | + | 
 | 158 | +// Scan TF files for provider blocks and inject a region value if not specified  | 
 | 159 | +func AddRegionToProvider(targetFile string, backupFile string) error {  | 
 | 160 | +	fmt.Printf("Scanning %s\n", targetFile)  | 
 | 161 | + | 
 | 162 | +	fileInfo, err := os.Stat(targetFile)  | 
 | 163 | + | 
 | 164 | +	const maxSize = 1024 * 1024  | 
 | 165 | +	if fileInfo.Size() > maxSize {  | 
 | 166 | +		return fmt.Errorf("File too large to process")  | 
 | 167 | +	}  | 
 | 168 | + | 
 | 169 | +	fileBytes, err := ioutil.ReadFile(targetFile)  | 
 | 170 | +	str, err := scanAndUpdateProvider(string(fileBytes))  | 
 | 171 | + | 
 | 172 | +	if err != nil {  | 
 | 173 | +		return fmt.Errorf("Error updating provider block\n %s", err)  | 
 | 174 | +	}  | 
 | 175 | + | 
 | 176 | +	ioutil.WriteFile(targetFile, []byte(str), fileInfo.Mode())  | 
 | 177 | + | 
 | 178 | +	return err  | 
 | 179 | +}  | 
 | 180 | + | 
 | 181 | +// find a string in a slice of strings  | 
 | 182 | +func contains(items []string, target string) bool {  | 
 | 183 | +	for _, item := range items {  | 
 | 184 | +		if item == target {  | 
 | 185 | +			return true  | 
 | 186 | +		}  | 
 | 187 | +	}  | 
 | 188 | +	return false  | 
 | 189 | +}  | 
0 commit comments