in cli/azd/internal/repository/detect_confirm.go [318:471]
func (d *detectConfirm) add(ctx context.Context) error {
languages := slices.SortedFunc(maps.Keys(add.LanguageMap),
func(a, b appdetect.Language) int {
return strings.Compare(a.Display(), b.Display())
})
frameworks := slices.SortedFunc(maps.Keys(appdetect.WebUIFrameworks),
func(a, b appdetect.Dependency) int {
return strings.Compare(a.Display(), b.Display())
})
// only include databases not already added
allDbs := slices.Collect(maps.Keys(add.DbMap))
databases := make([]appdetect.DatabaseDep, 0, len(allDbs))
for _, db := range allDbs {
if _, ok := d.Databases[db]; !ok {
databases = append(databases, db)
}
}
slices.SortFunc(databases, func(a, b appdetect.DatabaseDep) int {
return strings.Compare(a.Display(), b.Display())
})
selections := make([]string, 0, len(languages)+len(frameworks)+len(databases))
entries := make([]any, 0, len(languages)+len(frameworks)+len(databases))
for _, lang := range languages {
selections = append(selections, fmt.Sprintf("%s\t%s", lang.Display(), "[Language]"))
entries = append(entries, lang)
}
for _, framework := range frameworks {
selections = append(selections, fmt.Sprintf("%s\t%s", framework.Display(), "[Framework]"))
entries = append(entries, framework)
}
for _, db := range databases {
selections = append(selections, fmt.Sprintf("%s\t%s", db.Display(), "[Database]"))
entries = append(entries, db)
}
// only apply tab-align if interactive
if d.console.IsSpinnerInteractive() {
formatted, err := tabWrite(selections, 3)
if err != nil {
return fmt.Errorf("formatting selections: %w", err)
}
selections = formatted
}
i, err := d.console.Select(ctx, input.ConsoleOptions{
Message: "Select a language or database to add",
Options: selections,
})
if err != nil {
return err
}
s := appdetect.Project{}
switch entries[i].(type) {
case appdetect.Language:
s.Language = entries[i].(appdetect.Language)
case appdetect.Dependency:
framework := entries[i].(appdetect.Dependency)
if framework.Language() != "" {
s.Dependencies = []appdetect.Dependency{framework}
s.Language = framework.Language()
}
case appdetect.DatabaseDep:
dbDep := entries[i].(appdetect.DatabaseDep)
d.Databases[dbDep] = EntryKindManual
svcSelect := make([]string, 0, len(d.Services))
for _, svc := range d.Services {
svcSelect = append(svcSelect,
fmt.Sprintf("%s in %s", projectDisplayName(svc), filepath.Base(svc.Path)))
}
idx, err := d.console.Select(ctx, input.ConsoleOptions{
Message: "Select the service that uses this database",
Options: svcSelect,
})
if err != nil {
return err
}
d.Services[idx].DatabaseDeps = append(d.Services[idx].DatabaseDeps, dbDep)
d.Services[idx].DetectionRule = string(EntryKindModified)
d.modified = true
return nil
default:
log.Panic("unhandled entry type")
}
msg := fmt.Sprintf("Enter file path of the directory that uses '%s'", projectDisplayName(s))
path, err := promptDir(ctx, d.console, msg)
if err != nil {
return err
}
// deduplicate the path against existing services
for idx, svc := range d.Services {
if svc.Path == path {
d.console.Message(
ctx,
fmt.Sprintf(
"\nazd previously detected '%s' at %s.\n", projectDisplayName(svc), svc.Path))
confirm, err := d.console.Confirm(ctx, input.ConsoleOptions{
Message: fmt.Sprintf(
"Do you want to change the detected service to '%s'", projectDisplayName(s)),
})
if err != nil {
return err
}
if confirm {
d.modified = true
d.Services[idx].Language = s.Language
d.Services[idx].Dependencies = s.Dependencies
d.Services[idx].DetectionRule = string(EntryKindModified)
}
return nil
}
}
// Provide additional validation for project selection
if s.Language == appdetect.Python {
if _, err := os.Stat(filepath.Join(path, "requirements.txt")); errors.Is(err, os.ErrNotExist) {
d.console.Message(
ctx,
fmt.Sprintf("No '%s' file found in %s.",
output.WithBold("requirements.txt"),
output.WithHighLightFormat(path)))
confirm, err := d.console.Confirm(ctx, input.ConsoleOptions{
Message: "This file may be required when deploying to Azure. Continue?",
})
if err != nil {
return err
}
if !confirm {
return fmt.Errorf("cancelled")
}
}
}
s.Path = filepath.Clean(path)
s.DetectionRule = string(EntryKindManual)
d.Services = append(d.Services, s)
d.modified = true
return nil
}