diff --git a/internal/config/config.go b/internal/config/config.go index 14820f9..7a9b858 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -7,13 +7,15 @@ type Config struct { Logfile string `env:"AZTFY_LOGFILE" default:""` Debug bool `env:"AZTFY_DEBUG" default:"false"` MockClient bool `env:"AZTFY_MOCK_CLIENT" default:"false"` + OutputDir string // specified via CLI option } -func NewConfig(rg string) (*Config, error) { +func NewConfig(rg string, outputDir string) (*Config, error) { var cfg Config if err := babyenv.Parse(&cfg); err != nil { return nil, err } cfg.ResourceGroupName = rg + cfg.OutputDir = outputDir return &cfg, nil } diff --git a/internal/meta/meta.go b/internal/meta/meta.go index 287aebf..13db718 100644 --- a/internal/meta/meta.go +++ b/internal/meta/meta.go @@ -16,5 +16,5 @@ func NewMeta(cfg config.Config) (Meta, error) { if cfg.MockClient { return newMetaDummy(cfg.ResourceGroupName) } - return newMetaImpl(cfg.ResourceGroupName) + return newMetaImpl(cfg.ResourceGroupName, cfg.OutputDir) } diff --git a/internal/meta/meta_impl.go b/internal/meta/meta_impl.go index 8744f58..0e2c979 100644 --- a/internal/meta/meta_impl.go +++ b/internal/meta/meta_impl.go @@ -5,6 +5,7 @@ import ( "context" "encoding/json" "fmt" + "io" "os" "path" "path/filepath" @@ -32,7 +33,7 @@ type MetaImpl struct { armTemplate armtemplate.Template } -func newMetaImpl(rg string) (Meta, error) { +func newMetaImpl(rg string, outputDir string) (Meta, error) { ctx := context.TODO() // Initialize the workspace @@ -53,11 +54,35 @@ func newMetaImpl(rg string) (Meta, error) { } wsp := filepath.Join(rootDir, rg) - if err := os.RemoveAll(wsp); err != nil { - return nil, fmt.Errorf("removing existing workspace %q: %w", wsp, err) - } - if err := os.MkdirAll(wsp, 0755); err != nil { - return nil, fmt.Errorf("creating workspace %q: %w", wsp, err) + + if outputDir != "" { + wsp = outputDir + + // Ensure wsp is an empty directory + stat, err := os.Stat(wsp) + if os.IsNotExist(err) { + return nil, fmt.Errorf("the output directory %q doesn't exist", wsp) + } + if !stat.IsDir() { + return nil, fmt.Errorf("the output path %q is not a directory", wsp) + } + + f, err := os.Open(wsp) + if err != nil { + return nil, err + } + _, err = f.Readdirnames(1) // Or f.Readdir(1) + f.Close() + if err != io.EOF { + return nil, fmt.Errorf("the output directory %q is not empty", wsp) + } + } else { + if err := os.RemoveAll(wsp); err != nil { + return nil, fmt.Errorf("removing existing workspace %q: %w", wsp, err) + } + if err := os.MkdirAll(wsp, 0755); err != nil { + return nil, fmt.Errorf("creating workspace %q: %w", wsp, err) + } } // Authentication diff --git a/main.go b/main.go index 0fd4ed2..6f32844 100644 --- a/main.go +++ b/main.go @@ -12,11 +12,13 @@ import ( ) var ( - flagVersion *bool + flagVersion *bool + flagOutputDir *string ) func init() { flagVersion = flag.Bool("v", false, "Print version") + flagOutputDir = flag.String("o", "", "Specify output dir. Default is a dir under the user cache dir, which is named after the resource group name") } const usage = `aztfy [option] @@ -39,7 +41,7 @@ func main() { os.Exit(1) } - cfg, err := config.NewConfig(flag.Args()[0]) + cfg, err := config.NewConfig(flag.Args()[0], *flagOutputDir) if err != nil { log.Fatal(err) }