Add --clean flag to control file deletion, default preserves existing models
This commit is contained in:
109
gen.go
109
gen.go
@@ -32,6 +32,9 @@ type GenConfig struct {
|
||||
// SelectedTables is a list of specific table names to generate.
|
||||
// When set, TableFilter is ignored.
|
||||
SelectedTables []string
|
||||
// Clean determines whether to remove existing model files before generation.
|
||||
// When false, only updates or creates models without deleting existing files.
|
||||
Clean bool
|
||||
}
|
||||
|
||||
// defaultConfig returns the default configuration values.
|
||||
@@ -40,6 +43,7 @@ func defaultConfig() GenConfig {
|
||||
OutputDir: "./app/model/dbmodel",
|
||||
PkgName: "dbmodel",
|
||||
TableFilter: "ps_.*",
|
||||
Clean: true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +73,7 @@ func NewWithConfig(db *gorm.DB, cfg GenConfig) *GormGen {
|
||||
if len(cfg.SelectedTables) > 0 {
|
||||
d.SelectedTables = cfg.SelectedTables
|
||||
}
|
||||
d.Clean = cfg.Clean
|
||||
return &GormGen{db: db, cfg: d}
|
||||
}
|
||||
|
||||
@@ -84,9 +89,28 @@ func ConnectDSN(dsn string) (*gorm.DB, error) {
|
||||
}
|
||||
|
||||
// GenModels generates GORM model files and column descriptors for matched tables.
|
||||
// It cleans the output directory, generates models using gorm.io/gen,
|
||||
// It cleans the output directory (if Clean is true), generates models using gorm.io/gen,
|
||||
// and appends <Model>Cols variables with type-safe Field descriptors.
|
||||
func (m *GormGen) GenModels(ctx context.Context) error {
|
||||
dir := m.cfg.OutputDir
|
||||
if !strings.HasPrefix(dir, "./") {
|
||||
dir = "./" + dir
|
||||
}
|
||||
absDir, err := filepath.Abs(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// When Clean is false, backup existing files first.
|
||||
var backupDir string
|
||||
if !m.cfg.Clean {
|
||||
backupDir, err = m.backupDir(absDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to backup existing files: %w", err)
|
||||
}
|
||||
defer os.RemoveAll(backupDir)
|
||||
}
|
||||
|
||||
if err := m.cleanOutputDir(); err != nil {
|
||||
return fmt.Errorf("failed to clean output dir: %w", err)
|
||||
}
|
||||
@@ -140,6 +164,13 @@ func (m *GormGen) GenModels(ctx context.Context) error {
|
||||
return fmt.Errorf("failed to cleanup generated files: %w", err)
|
||||
}
|
||||
|
||||
// Restore backup if Clean was false.
|
||||
if backupDir != "" {
|
||||
if err := m.restoreBackup(absDir, backupDir); err != nil {
|
||||
return fmt.Errorf("failed to restore backup: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := m.generateCols(); err != nil {
|
||||
return fmt.Errorf("failed to generate column descriptors: %w", err)
|
||||
}
|
||||
@@ -147,6 +178,77 @@ func (m *GormGen) GenModels(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// backupDir creates a backup copy of the directory and returns the backup path.
|
||||
func (m *GormGen) backupDir(dir string) (string, error) {
|
||||
backupPath := dir + ".backup"
|
||||
if _, err := os.Stat(backupPath); err == nil {
|
||||
os.RemoveAll(backupPath)
|
||||
}
|
||||
|
||||
if err := copyDir(dir, backupPath); err != nil {
|
||||
return "", err
|
||||
}
|
||||
fmt.Printf("Backed up: %s -> %s\n", dir, backupPath)
|
||||
return backupPath, nil
|
||||
}
|
||||
|
||||
// restoreBackup restores files from backup that don't exist in the target directory.
|
||||
func (m *GormGen) restoreBackup(dir, backupDir string) error {
|
||||
entries, err := os.ReadDir(backupDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
restored := 0
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
targetPath := filepath.Join(dir, entry.Name())
|
||||
if _, err := os.Stat(targetPath); os.IsNotExist(err) {
|
||||
srcPath := filepath.Join(backupDir, entry.Name())
|
||||
data, err := os.ReadFile(srcPath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if err := os.WriteFile(targetPath, data, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Restored: %s\n", targetPath)
|
||||
restored++
|
||||
}
|
||||
}
|
||||
if restored > 0 {
|
||||
fmt.Printf("Restored %d files from backup\n", restored)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// copyDir copies a directory recursively.
|
||||
func copyDir(src, dst string) error {
|
||||
return filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rel, _ := filepath.Rel(src, path)
|
||||
dstPath := filepath.Join(dst, rel)
|
||||
|
||||
if info.IsDir() {
|
||||
return os.MkdirAll(dstPath, info.Mode())
|
||||
}
|
||||
return copyFile(path, dstPath)
|
||||
})
|
||||
}
|
||||
|
||||
// copyFile copies a single file.
|
||||
func copyFile(src, dst string) error {
|
||||
data, err := os.ReadFile(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(dst, data, 0644)
|
||||
}
|
||||
|
||||
// cleanOutputDir removes existing .go files from the output directory
|
||||
// or creates it if it doesn't exist.
|
||||
func (m *GormGen) cleanOutputDir() error {
|
||||
@@ -168,6 +270,11 @@ func (m *GormGen) cleanOutputDir() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Skip cleaning if Clean is false.
|
||||
if !m.cfg.Clean {
|
||||
return nil
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir(absDir)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user