Skip to content

Commit dd108d9

Browse files
committed
compose if infra exists
1 parent fdefd93 commit dd108d9

File tree

3 files changed

+100
-41
lines changed

3 files changed

+100
-41
lines changed

cli/azd/pkg/project/importer.go

+59-12
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package project
55

66
import (
77
"context"
8+
"errors"
89
"fmt"
910
"io/fs"
1011
"log"
@@ -15,6 +16,7 @@ import (
1516

1617
"github.com./azure/azure-dev/cli/azd/pkg/alpha"
1718
"github.com./azure/azure-dev/cli/azd/pkg/infra/provisioning"
19+
"github.com./otiai10/copy"
1820
)
1921

2022
type ImportManager struct {
@@ -139,8 +141,64 @@ func (im *ImportManager) ProjectInfrastructure(ctx context.Context, projectConfi
139141
infraRoot = filepath.Join(projectConfig.Path, infraRoot)
140142
}
141143

144+
moduleExists, moduleErr := pathHasModule(infraRoot, projectConfig.Infra.Module)
145+
146+
composeEnabled := im.dotNetImporter.alphaFeatureManager.IsEnabled(featureCompose)
147+
if composeEnabled && len(projectConfig.Resources) > 0 {
148+
if moduleErr == nil && moduleExists {
149+
azdModuleExists, err := pathHasModule(filepath.Join(infraRoot, "azd"), projectConfig.Infra.Module)
150+
if err != nil && !errors.Is(err, os.ErrNotExist) {
151+
return nil, fmt.Errorf("checking if module exists: %w", err)
152+
}
153+
154+
if azdModuleExists {
155+
log.Printf("using fully-synthesized infrastructure from %s directory", infraRoot)
156+
return &Infra{
157+
Options: projectConfig.Infra,
158+
}, nil
159+
}
160+
}
161+
162+
// copy the infra directory to a temporary directory and synthesize the azd directory
163+
tmpDir, err := os.MkdirTemp("", "azd-infra")
164+
if err != nil {
165+
return nil, fmt.Errorf("creating temporary directory: %w", err)
166+
}
167+
168+
azdInfraDir := tmpDir
169+
if moduleErr == nil && moduleExists {
170+
// Copy the base infra directory
171+
if err := copy.Copy(infraRoot, tmpDir); err != nil {
172+
return nil, fmt.Errorf("copying infra directory: %w", err)
173+
}
174+
175+
azdInfraDir = filepath.Join(tmpDir, "azd")
176+
}
177+
178+
err = infraFsToDir(ctx, projectConfig, azdInfraDir)
179+
if err != nil {
180+
return nil, err
181+
}
182+
183+
return &Infra{
184+
Options: provisioning.Options{
185+
Provider: provisioning.Bicep,
186+
Path: tmpDir,
187+
Module: DefaultModule,
188+
},
189+
IsCompose: true,
190+
cleanupDir: tmpDir,
191+
}, nil
192+
}
193+
194+
if !composeEnabled && len(projectConfig.Resources) > 0 {
195+
return nil, fmt.Errorf(
196+
"compose is currently under alpha support and must be explicitly enabled."+
197+
" Run `%s` to enable this feature", alpha.GetEnableCommand(featureCompose))
198+
}
199+
142200
// Allow overriding the infrastructure only when path and module exists.
143-
if moduleExists, err := pathHasModule(infraRoot, projectConfig.Infra.Module); err == nil && moduleExists {
201+
if moduleErr == nil && moduleExists {
144202
log.Printf("using infrastructure from %s directory", infraRoot)
145203
return &Infra{
146204
Options: projectConfig.Infra,
@@ -165,17 +223,6 @@ func (im *ImportManager) ProjectInfrastructure(ctx context.Context, projectConfi
165223
}
166224
}
167225

168-
composeEnabled := im.dotNetImporter.alphaFeatureManager.IsEnabled(featureCompose)
169-
if composeEnabled && len(projectConfig.Resources) > 0 {
170-
return tempInfra(ctx, projectConfig)
171-
}
172-
173-
if !composeEnabled && len(projectConfig.Resources) > 0 {
174-
return nil, fmt.Errorf(
175-
"compose is currently under alpha support and must be explicitly enabled."+
176-
" Run `%s` to enable this feature", alpha.GetEnableCommand(featureCompose))
177-
}
178-
179226
return &Infra{}, nil
180227
}
181228

cli/azd/pkg/project/importer_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,8 @@ func TestImportManagerProjectInfrastructure(t *testing.T) {
233233
lazyEnvManager: lazy.NewLazy(func() (environment.Manager, error) {
234234
return mockEnv, nil
235235
}),
236-
hostCheck: make(map[string]hostCheckResult),
236+
hostCheck: make(map[string]hostCheckResult),
237+
alphaFeatureManager: mockContext.AlphaFeaturesManager,
237238
})
238239

239240
// Do not use defaults

cli/azd/pkg/project/scaffold_gen.go

+39-28
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package project
55

66
import (
77
"context"
8+
"errors"
89
"fmt"
910
"io/fs"
1011
"maps"
@@ -16,7 +17,6 @@ import (
1617
"github.com./azure/azure-dev/cli/azd/internal/scaffold"
1718
"github.com./azure/azure-dev/cli/azd/pkg/environment"
1819
"github.com./azure/azure-dev/cli/azd/pkg/infra"
19-
"github.com./azure/azure-dev/cli/azd/pkg/infra/provisioning"
2020
"github.com./azure/azure-dev/cli/azd/pkg/osutil"
2121
"github.com./psanford/memfs"
2222
)
@@ -41,18 +41,10 @@ func infraFs(_ context.Context, prjConfig *ProjectConfig) (fs.FS, error) {
4141
return files, nil
4242
}
4343

44-
// Returns the infrastructure configuration that points to a temporary, generated `infra` directory on the filesystem.
45-
func tempInfra(
46-
ctx context.Context,
47-
prjConfig *ProjectConfig) (*Infra, error) {
48-
tmpDir, err := os.MkdirTemp("", "azd-infra")
49-
if err != nil {
50-
return nil, fmt.Errorf("creating temporary directory: %w", err)
51-
}
52-
44+
func infraFsToDir(ctx context.Context, prjConfig *ProjectConfig, dir string) error {
5345
files, err := infraFs(ctx, prjConfig)
5446
if err != nil {
55-
return nil, err
47+
return err
5648
}
5749

5850
err = fs.WalkDir(files, ".", func(path string, d fs.DirEntry, err error) error {
@@ -64,7 +56,7 @@ func tempInfra(
6456
return nil
6557
}
6658

67-
target := filepath.Join(tmpDir, path)
59+
target := filepath.Join(dir, path)
6860
if err := os.MkdirAll(filepath.Dir(target), osutil.PermissionDirectoryOwnerOnly); err != nil {
6961
return err
7062
}
@@ -77,18 +69,10 @@ func tempInfra(
7769
return os.WriteFile(target, contents, osutil.PermissionFile)
7870
})
7971
if err != nil {
80-
return nil, fmt.Errorf("writing infrastructure: %w", err)
72+
return fmt.Errorf("writing infrastructure: %w", err)
8173
}
8274

83-
return &Infra{
84-
Options: provisioning.Options{
85-
Provider: provisioning.Bicep,
86-
Path: tmpDir,
87-
Module: DefaultModule,
88-
},
89-
cleanupDir: tmpDir,
90-
IsCompose: true,
91-
}, nil
75+
return nil
9276
}
9377

9478
// Generates the filesystem of all infrastructure files to be placed, rooted at the project directory.
@@ -99,13 +83,32 @@ func infraFsForProject(ctx context.Context, prjConfig *ProjectConfig) (fs.FS, er
9983
return nil, err
10084
}
10185

102-
infraPathPrefix := DefaultPath
86+
infraPrefix := DefaultPath
10387
if prjConfig.Infra.Path != "" {
104-
infraPathPrefix = prjConfig.Infra.Path
88+
infraPrefix = prjConfig.Infra.Path
89+
}
90+
91+
infraRoot := infraPrefix
92+
if !filepath.IsAbs(infraPrefix) {
93+
infraRoot = filepath.Join(prjConfig.Path, infraPrefix)
94+
}
95+
96+
infraDir, err := os.Stat(infraRoot)
97+
if !errors.Is(err, os.ErrNotExist) && err != nil {
98+
return nil, fmt.Errorf("error reading infra directory: %w", err)
99+
}
100+
101+
fi, err := os.Stat(filepath.Join(infraRoot, ".azd"))
102+
if !errors.Is(err, os.ErrNotExist) && err != nil {
103+
return nil, fmt.Errorf("error reading .azd file in infra: %w", err)
104+
}
105+
106+
if infraDir != nil && fi == nil { // if the infra directory is not managed by azd, generate it to infra/azd
107+
infraPrefix = filepath.Join(infraPrefix, "azd")
105108
}
106109

107-
// root the generated content at the project directory
108110
generatedFS := memfs.New()
111+
// root the generated content at the project directory
109112
err = fs.WalkDir(infraFS, ".", func(path string, d fs.DirEntry, err error) error {
110113
if err != nil {
111114
return err
@@ -115,7 +118,7 @@ func infraFsForProject(ctx context.Context, prjConfig *ProjectConfig) (fs.FS, er
115118
return nil
116119
}
117120

118-
err = generatedFS.MkdirAll(filepath.Join(infraPathPrefix, filepath.Dir(path)), osutil.PermissionDirectoryOwnerOnly)
121+
err = generatedFS.MkdirAll(filepath.Join(infraPrefix, filepath.Dir(path)), osutil.PermissionDirectoryOwnerOnly)
119122
if err != nil {
120123
return err
121124
}
@@ -125,10 +128,18 @@ func infraFsForProject(ctx context.Context, prjConfig *ProjectConfig) (fs.FS, er
125128
return err
126129
}
127130

128-
return generatedFS.WriteFile(filepath.Join(infraPathPrefix, path), contents, d.Type().Perm())
131+
return generatedFS.WriteFile(filepath.Join(infraPrefix, path), contents, d.Type().Perm())
129132
})
130133
if err != nil {
131-
return nil, err
134+
return nil, fmt.Errorf("generating: %w", err)
135+
}
136+
137+
if fi == nil {
138+
// create a sentinel file to indicate that the infra directory is managed by azd
139+
err = generatedFS.WriteFile(filepath.Join(infraPrefix, ".azd"), []byte{}, osutil.PermissionFileOwnerOnly)
140+
if err != nil {
141+
return nil, fmt.Errorf("writing sentinel: %w", err)
142+
}
132143
}
133144

134145
return generatedFS, nil

0 commit comments

Comments
 (0)