227 lines
6.4 KiB
Go
227 lines
6.4 KiB
Go
package create
|
|
|
|
import (
|
|
"fmt"
|
|
. "git.gorlug.de/code/ersteller"
|
|
"git.gorlug.de/code/ersteller/starter/env"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"path"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
type DatabaseType string
|
|
|
|
const (
|
|
DatabaseTypePostgres DatabaseType = "postgres"
|
|
DatabaseTypeSqlite DatabaseType = "sqlite"
|
|
)
|
|
|
|
type Params struct {
|
|
DbType DatabaseType
|
|
ProjectDir string
|
|
ModuleName string
|
|
GoPath string
|
|
OverwriteEnv bool
|
|
}
|
|
|
|
type StarterCreator struct {
|
|
params Params
|
|
thisDir string
|
|
}
|
|
|
|
func NewStarterCreator(params Params) StarterCreator {
|
|
// Validate target directory parameter
|
|
if params.ProjectDir == "" {
|
|
log.Printf("StarterCreator.Create: ProjectDir is empty; nothing to do")
|
|
panic("ProjectDir is empty; nothing to do")
|
|
}
|
|
|
|
thisDir := GetPathToThisDir()
|
|
return StarterCreator{
|
|
params: params,
|
|
thisDir: thisDir,
|
|
}
|
|
}
|
|
|
|
func GetPathToThisDir() string {
|
|
// Resolve the path to the starter main.go located at ../main.go relative to this file
|
|
_, thisFile, _, ok := runtime.Caller(0)
|
|
if !ok {
|
|
log.Printf("StarterCreator.Create: unable to resolve current file location via runtime.Caller")
|
|
panic("unable to resolve current file location via runtime.Caller")
|
|
}
|
|
thisDir := filepath.Dir(thisFile)
|
|
return thisDir
|
|
}
|
|
|
|
// Create reads the starter main.go file bundled with this package
|
|
// and writes it into the target project directory as main.go.
|
|
// Minimal, side-effecting function with internal error logging to keep API unchanged.
|
|
func (s StarterCreator) Create() {
|
|
Debug("StarterCreator.Create")
|
|
starterMainPath := filepath.Join(s.thisDir, "..", "main.go")
|
|
|
|
// Read starter main.go
|
|
content, err := os.ReadFile(starterMainPath)
|
|
if err != nil {
|
|
log.Printf("StarterCreator.Create: failed to read starter main.go at %s: %v", starterMainPath, err)
|
|
return
|
|
}
|
|
|
|
// Ensure target directory exists
|
|
if err := os.MkdirAll(s.params.ProjectDir, 0o755); err != nil {
|
|
log.Printf("StarterCreator.Create: failed to create target directory %s: %v", s.params.ProjectDir, err)
|
|
return
|
|
}
|
|
|
|
// Write to <ProjectDir>/main.go
|
|
targetPath := filepath.Join(s.params.ProjectDir, "main.go")
|
|
content = s.replaceImports(content)
|
|
must(os.WriteFile(targetPath, content, 0o644))
|
|
log.Printf("StarterCreator.Create: wrote starter main.go to %s", targetPath)
|
|
|
|
s.copyFile("../../template.air.toml", ".air.toml")
|
|
//s.copyGoMod()
|
|
//s.executeGoModTidy()
|
|
|
|
if s.params.DbType == DatabaseTypeSqlite {
|
|
must(os.MkdirAll(filepath.Join(s.params.ProjectDir, "db"), 0o755))
|
|
}
|
|
|
|
must(os.MkdirAll(filepath.Join(s.params.ProjectDir, "scripts"), 0o755))
|
|
s.copyFile("../../scripts/db-push.sh", "scripts/db-push.sh")
|
|
|
|
if s.params.DbType == DatabaseTypeSqlite {
|
|
s.executeDbPush()
|
|
}
|
|
|
|
s.copyFile("../.gitignore", ".gitignore")
|
|
|
|
s.createEnvironment()
|
|
directories := []string{
|
|
"index",
|
|
"page",
|
|
"routes",
|
|
"static",
|
|
"ent",
|
|
}
|
|
for _, dir := range directories {
|
|
s.copyDirectoryRecursive(path.Join(s.thisDir, "..", dir), path.Join(s.params.ProjectDir, dir))
|
|
}
|
|
s.copySchemaFiles()
|
|
}
|
|
|
|
func (s StarterCreator) copySchemaFiles() {
|
|
s.copyFile("../../schema/ent/pagination_query.tmpl", "ent/pagination_query.tmpl")
|
|
content, err := os.ReadFile(filepath.Join(s.thisDir, "../generate_schema.go"))
|
|
must(err)
|
|
//content = s.replaceImports(content)
|
|
must(os.WriteFile(filepath.Join(s.params.ProjectDir, "generate_schema.go"), content, 0o644))
|
|
}
|
|
|
|
func (s StarterCreator) createEnvironment() {
|
|
if err := os.MkdirAll(s.params.ProjectDir+"/env", 0o755); err != nil {
|
|
log.Printf("StarterCreator.Create: failed to create env target directory%v", err)
|
|
return
|
|
}
|
|
//s.copyFile("../env/environment.go", "env/environment.go")
|
|
content, err := os.ReadFile(filepath.Join(s.thisDir, "../env/environment.go"))
|
|
must(err)
|
|
must(os.WriteFile(filepath.Join(s.params.ProjectDir, "env/environment.go"), content, 0o644))
|
|
|
|
must(env.GenerateEnvFile(s.params.ProjectDir, s.params.OverwriteEnv))
|
|
|
|
}
|
|
|
|
func (s StarterCreator) executeDbPush() {
|
|
// After copying create_db.sh, run it with the project directory as the root
|
|
scriptPath := filepath.Join(s.params.ProjectDir, "scripts", "db-push.sh")
|
|
if runtime.GOOS == "windows" {
|
|
log.Printf("StarterCreator.Create: skipping create_db.sh execution on Windows")
|
|
return
|
|
}
|
|
if err := os.Chmod(scriptPath, 0o755); err != nil {
|
|
log.Printf("StarterCreator.Create: failed to make create_db.sh executable: %v", err)
|
|
return
|
|
}
|
|
|
|
cmd := exec.Command("/bin/sh", scriptPath)
|
|
cmd.Dir = s.params.ProjectDir
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
if err := cmd.Run(); err != nil {
|
|
log.Printf("StarterCreator.Create: failed to run create_db.sh: %v", err)
|
|
} else {
|
|
log.Printf("StarterCreator.Create: successfully ran create_db.sh in %s", s.params.ProjectDir)
|
|
}
|
|
}
|
|
|
|
func (s StarterCreator) copyFile(src string, dst string) {
|
|
content, err := os.ReadFile(filepath.Join(s.thisDir, src))
|
|
must(err)
|
|
must(os.WriteFile(filepath.Join(s.params.ProjectDir, dst), content, 0o644))
|
|
}
|
|
|
|
func (s StarterCreator) copyDirectoryRecursive(src string, dst string) {
|
|
must(os.MkdirAll(dst, 0o755))
|
|
entries, err := os.ReadDir(src)
|
|
must(err)
|
|
for _, entry := range entries {
|
|
srcPath := filepath.Join(src, entry.Name())
|
|
dstPath := filepath.Join(dst, entry.Name())
|
|
Debug("copying srcPath: ", srcPath, " to dstPath: ", dstPath)
|
|
if entry.IsDir() {
|
|
s.copyDirectoryRecursive(srcPath, dstPath)
|
|
continue
|
|
}
|
|
content, err := os.ReadFile(srcPath)
|
|
content = s.replaceImports(content)
|
|
must(err)
|
|
must(os.WriteFile(filepath.Join(dstPath), content, 0o644))
|
|
}
|
|
}
|
|
|
|
func (s StarterCreator) copyGoMod() {
|
|
content, err := os.ReadFile(filepath.Join(s.thisDir, "../go.mod.template"))
|
|
must(err)
|
|
contentString := InlineTemplate(string(content), struct {
|
|
ModuleName string
|
|
}{
|
|
ModuleName: s.params.ModuleName,
|
|
})
|
|
must(os.WriteFile(filepath.Join(s.params.ProjectDir, "go.mod"), []byte(contentString), 0o644))
|
|
}
|
|
|
|
func (s StarterCreator) executeGoModTidy() {
|
|
goCommand := s.getGoCommand()
|
|
cmd := exec.Command(goCommand, "mod", "tidy")
|
|
cmd.Dir = s.params.ProjectDir
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
must(cmd.Run())
|
|
}
|
|
|
|
func (s StarterCreator) getGoCommand() string {
|
|
goCommand := "go"
|
|
if s.params.GoPath != "" {
|
|
goCommand = s.params.GoPath
|
|
}
|
|
return goCommand
|
|
}
|
|
|
|
func (s StarterCreator) replaceImports(content []byte) []byte {
|
|
contentString := string(content)
|
|
contentString = strings.ReplaceAll(contentString, "\"git.gorlug.de/code/ersteller/starter/", fmt.Sprint("\"", s.params.ModuleName, "/"))
|
|
return []byte(contentString)
|
|
}
|
|
|
|
func must(err error) {
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|