func()

in cli/azd/pkg/project/dotnet_importer.go [465:597]


func (ai *DotNetImporter) SynthAllInfrastructure(ctx context.Context, p *ProjectConfig, svcConfig *ServiceConfig,
) (fs.FS, error) {
	manifest, err := ai.ReadManifest(ctx, svcConfig)
	if err != nil {
		return nil, fmt.Errorf("generating apphost manifest: %w", err)
	}

	generatedFS := memfs.New()

	rootModuleName := DefaultModule
	if p.Infra.Module != "" {
		rootModuleName = p.Infra.Module
	}

	azdOperationsEnabled := ai.alphaFeatureManager.IsEnabled(provisioning.AzdOperationsFeatureKey)
	infraFS, err := apphost.BicepTemplate(rootModuleName, manifest, apphost.AppHostOptions{
		AzdOperations: azdOperationsEnabled,
	})
	if err != nil {
		if errors.Is(err, provisioning.ErrAzdOperationsNotEnabled) {
			// Use a warning for this error about azd operations is required for the current project to fully work
			ai.console.Message(ctx, err.Error())
		} else {
			return nil, fmt.Errorf("generating infra/ folder: %w", err)
		}
	}

	infraPathPrefix := DefaultPath
	if p.Infra.Path != "" {
		infraPathPrefix = p.Infra.Path
	}

	err = fs.WalkDir(infraFS, ".", func(path string, d fs.DirEntry, err error) error {
		if err != nil {
			return err
		}

		if d.IsDir() {
			return nil
		}

		err = generatedFS.MkdirAll(filepath.Join(infraPathPrefix, filepath.Dir(path)), osutil.PermissionDirectoryOwnerOnly)
		if err != nil {
			return err
		}

		contents, err := fs.ReadFile(infraFS, path)
		if err != nil {
			return err
		}

		return generatedFS.WriteFile(filepath.Join(infraPathPrefix, path), contents, d.Type().Perm())
	})
	if err != nil {
		return nil, err
	}

	// Use canonical paths for Rel comparison due to absolute paths provided by ManifestFromAppHost
	// being possibly symlinked paths.
	root, err := filepath.EvalSymlinks(p.Path)
	if err != nil {
		return nil, err
	}

	// writeManifestForResource writes the containerApp.tmpl.yaml or containerApp.bicepparam for the given resource to the
	// generated filesystem. The manifest is written to a file name "containerApp.tmpl.yaml" or
	// "containerApp.tmpl.bicepparam" in the same directory as the project that produces the
	// container we will deploy.
	writeManifestForResource := func(name string) error {
		normalPath, err := filepath.EvalSymlinks(svcConfig.Path())
		if err != nil {
			return err
		}

		projectRelPath, err := filepath.Rel(root, normalPath)
		if err != nil {
			return err
		}

		containerAppManifest, manifestType, err := apphost.ContainerAppManifestTemplateForProject(
			manifest, name, apphost.AppHostOptions{})
		if err != nil {
			return fmt.Errorf("generating containerApp deployment manifest for resource %s: %w", name, err)
		}

		manifestPath := filepath.Join(filepath.Dir(projectRelPath), "infra", fmt.Sprintf("%s.tmpl.yaml", name))
		if manifestType == apphost.ContainerAppManifestTypeBicep {
			manifestPath = filepath.Join(
				filepath.Dir(projectRelPath), "infra", name, fmt.Sprintf("%s.tmpl.bicepparam", name))
		}

		if err := generatedFS.MkdirAll(filepath.Dir(manifestPath), osutil.PermissionDirectoryOwnerOnly); err != nil {
			return err
		}

		err = generatedFS.WriteFile(manifestPath, []byte(containerAppManifest), osutil.PermissionFileOwnerOnly)
		if err != nil {
			return err
		}

		return nil
	}

	for name := range apphost.ProjectPaths(manifest) {
		if err := writeManifestForResource(name); err != nil {
			return nil, err
		}
	}

	for name := range apphost.Dockerfiles(manifest) {
		if err := writeManifestForResource(name); err != nil {
			return nil, err
		}
	}

	for name := range apphost.Containers(manifest) {
		if err := writeManifestForResource(name); err != nil {
			return nil, err
		}
	}

	bcs, err := apphost.BuildContainers(manifest)
	if err != nil {
		return nil, err
	}
	for name := range bcs {
		if err := writeManifestForResource(name); err != nil {
			return nil, err
		}
	}

	return generatedFS, nil
}