github.com/supabase/cli@v1.168.1/internal/init/init.go (about) 1 package init 2 3 import ( 4 _ "embed" 5 "encoding/json" 6 "fmt" 7 "io" 8 "os" 9 "path/filepath" 10 11 "github.com/go-errors/errors" 12 "github.com/spf13/afero" 13 "github.com/supabase/cli/internal/utils" 14 ) 15 16 var ( 17 vscodeDir = ".vscode" 18 extensionsPath = filepath.Join(vscodeDir, "extensions.json") 19 settingsPath = filepath.Join(vscodeDir, "settings.json") 20 intellijDir = ".idea" 21 denoPath = filepath.Join(intellijDir, "deno.xml") 22 23 //go:embed templates/.gitignore 24 initGitignore []byte 25 //go:embed templates/.vscode/extensions.json 26 vscodeExtensions string 27 //go:embed templates/.vscode/settings.json 28 vscodeSettings string 29 //go:embed templates/.idea/deno.xml 30 intelliJDeno string 31 ) 32 33 func Run(fsys afero.Fs, createVscodeSettings, createIntellijSettings *bool, params utils.InitParams) error { 34 // 1. Write `config.toml`. 35 if err := utils.InitConfig(params, fsys); err != nil { 36 return err 37 } 38 39 // 2. Create `seed.sql`. 40 if err := initSeed(fsys); err != nil { 41 return err 42 } 43 44 // 3. Append to `.gitignore`. 45 if utils.IsGitRepo() { 46 if err := updateGitIgnore(utils.GitIgnorePath, fsys); err != nil { 47 return err 48 } 49 } 50 51 // 4. Generate VS Code settings. 52 if createVscodeSettings != nil { 53 if *createVscodeSettings { 54 return writeVscodeConfig(fsys) 55 } 56 } else if createIntellijSettings != nil { 57 if *createIntellijSettings { 58 return writeIntelliJConfig(fsys) 59 } 60 } else { 61 console := utils.NewConsole() 62 if isVscode := console.PromptYesNo("Generate VS Code settings for Deno?", false); isVscode { 63 return writeVscodeConfig(fsys) 64 } 65 if isIntelliJ := console.PromptYesNo("Generate IntelliJ Settings for Deno?", false); isIntelliJ { 66 return writeIntelliJConfig(fsys) 67 } 68 } 69 return nil 70 } 71 72 func initSeed(fsys afero.Fs) error { 73 f, err := fsys.OpenFile(utils.SeedDataPath, os.O_WRONLY|os.O_CREATE, 0644) 74 if err != nil { 75 return errors.Errorf("failed to create seed file: %w", err) 76 } 77 defer f.Close() 78 return nil 79 } 80 81 func updateGitIgnore(ignorePath string, fsys afero.Fs) error { 82 var contents []byte 83 84 if contained, err := afero.FileContainsBytes(fsys, ignorePath, initGitignore); contained { 85 return nil 86 } else if err == nil { 87 // Add a line break when appending 88 contents = append(contents, '\n') 89 } else if !errors.Is(err, os.ErrNotExist) { 90 return errors.Errorf("failed to read git ignore file: %w", err) 91 } 92 93 f, err := fsys.OpenFile(ignorePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) 94 if err != nil { 95 return errors.Errorf("failed to create git ignore file: %w", err) 96 } 97 defer f.Close() 98 99 if _, err := f.Write(append(contents, initGitignore...)); err != nil { 100 return errors.Errorf("failed to write git ignore file: %w", err) 101 } 102 103 return nil 104 } 105 106 type VSCodeSettings map[string]interface{} 107 108 func loadUserSettings(path string, fsys afero.Fs) (VSCodeSettings, error) { 109 // Open our jsonFile 110 jsonFile, err := fsys.Open(path) 111 if err != nil { 112 return nil, errors.Errorf("failed to load settings file: %w", err) 113 } 114 defer jsonFile.Close() 115 // Parse and unmarshal JSON file. 116 var userSettings VSCodeSettings 117 dec := json.NewDecoder(jsonFile) 118 if err := dec.Decode(&userSettings); err != nil { 119 return nil, errors.Errorf("failed to parse settings: %w", err) 120 } 121 return userSettings, nil 122 } 123 124 func saveUserSettings(path string, settings VSCodeSettings, fsys afero.Fs) error { 125 // Open our jsonFile 126 jsonFile, err := fsys.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) 127 if err != nil { 128 return errors.Errorf("failed to create settings file: %w", err) 129 } 130 defer jsonFile.Close() 131 // Marshal JSON to file. 132 enc := json.NewEncoder(jsonFile) 133 enc.SetIndent("", " ") 134 if err := enc.Encode(settings); err != nil { 135 return errors.Errorf("failed to save settings: %w", err) 136 } 137 return nil 138 } 139 140 func updateJsonFile(path string, template string, fsys afero.Fs) error { 141 userSettings, err := loadUserSettings(path, fsys) 142 if errors.Is(err, os.ErrNotExist) || errors.Is(err, io.EOF) { 143 return afero.WriteFile(fsys, path, []byte(template), 0644) 144 } else if err != nil { 145 return err 146 } 147 // Merge template into user settings. 148 if err := json.Unmarshal([]byte(template), &userSettings); err != nil { 149 return errors.Errorf("failed to copy template: %w", err) 150 } 151 return saveUserSettings(path, userSettings, fsys) 152 } 153 154 func writeVscodeConfig(fsys afero.Fs) error { 155 // Create VS Code settings for Deno. 156 if err := utils.MkdirIfNotExistFS(fsys, vscodeDir); err != nil { 157 return err 158 } 159 if err := updateJsonFile(extensionsPath, vscodeExtensions, fsys); err != nil { 160 return err 161 } 162 if err := updateJsonFile(settingsPath, vscodeSettings, fsys); err != nil { 163 return err 164 } 165 fmt.Println("Generated VS Code settings in " + utils.Bold(settingsPath) + ". Please install the recommended extension!") 166 return nil 167 } 168 169 func writeIntelliJConfig(fsys afero.Fs) error { 170 if err := utils.WriteFile(denoPath, []byte(intelliJDeno), fsys); err != nil { 171 return err 172 } 173 fmt.Println("Generated IntelliJ settings in " + utils.Bold(denoPath) + ". Please install the Deno plugin!") 174 return nil 175 }