Divorce disting from androidmk

Change AndroidMkEntries.getDistContributions and
AndroidMkInfo.getDistContributions into a freestanding
getDistContributions.

This enables us to not call the AndroidMk related functions in
soong-only builds.

Bug: 398938465
Test: Diff'd the ninja files from "m nothing dist" before/after this cl, no changes
Change-Id: I2f9d537c0d66f0ae3715f083e2f55436e4c0a59f
diff --git a/android/androidmk.go b/android/androidmk.go
index 5cb5a66..6a1701d 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -349,30 +349,15 @@
 	return
 }
 
-// Compute the contributions that the module makes to the dist.
-func (a *AndroidMkEntries) getDistContributions(mod Module) *distContributions {
+// This gets the dist contributuions from the given module that were specified in the Android.bp
+// file using the dist: property. It does not include contribututions that the module's
+// implementation may have defined with ctx.DistForGoals(), for that, see DistProvider.
+func getDistContributions(ctx ConfigAndOtherModuleProviderContext, mod Module) *distContributions {
 	amod := mod.base()
 	name := amod.BaseModuleName()
 
-	// Collate the set of associated tag/paths available for copying to the dist.
-	// Start with an empty (nil) set.
-	var availableTaggedDists TaggedDistFiles
-
-	// If no paths have been provided for the DefaultDistTag and the output file is
-	// valid then add that as the default dist path.
-	if a.OutputFile.Valid() {
-		availableTaggedDists = availableTaggedDists.addPathsForTag(DefaultDistTag, a.OutputFile.Path())
-	}
-
-	info := OtherModuleProviderOrDefault(a.entryContext, mod, InstallFilesProvider)
-	// If the distFiles created by GenerateTaggedDistFiles contains paths for the
-	// DefaultDistTag then that takes priority so delete any existing paths.
-	if _, ok := info.DistFiles[DefaultDistTag]; ok {
-		delete(availableTaggedDists, DefaultDistTag)
-	}
-
-	// Finally, merge the distFiles created by GenerateTaggedDistFiles.
-	availableTaggedDists = availableTaggedDists.merge(info.DistFiles)
+	info := OtherModuleProviderOrDefault(ctx, mod, InstallFilesProvider)
+	availableTaggedDists := info.DistFiles
 
 	if len(availableTaggedDists) == 0 {
 		// Nothing dist-able for this module.
@@ -446,7 +431,7 @@
 
 			productString := ""
 			if dist.Append_artifact_with_product != nil && *dist.Append_artifact_with_product {
-				productString = fmt.Sprintf("_%s", a.entryContext.Config().DeviceProduct())
+				productString = fmt.Sprintf("_%s", ctx.Config().DeviceProduct())
 			}
 
 			if suffix != "" || productString != "" {
@@ -494,7 +479,7 @@
 // Compute the list of Make strings to declare phony goals and dist-for-goals
 // calls from the module's dist and dists properties.
 func (a *AndroidMkEntries) GetDistForGoals(mod Module) []string {
-	distContributions := a.getDistContributions(mod)
+	distContributions := getDistContributions(a.entryContext, mod)
 	if distContributions == nil {
 		return nil
 	}
@@ -903,18 +888,9 @@
 			if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
 				moduleInfoJSONs = append(moduleInfoJSONs, moduleInfoJSON...)
 			}
-			if contribution := info.PrimaryInfo.getDistContributions(ctx, mod, &commonInfo); contribution != nil {
+			if contribution := getDistContributions(ctx, mod); contribution != nil {
 				allDistContributions = append(allDistContributions, *contribution)
 			}
-			for _, ei := range info.ExtraInfo {
-				ei.fillInEntries(ctx, mod, &commonInfo)
-				if ei.disabled() {
-					continue
-				}
-				if contribution := ei.getDistContributions(ctx, mod, &commonInfo); contribution != nil {
-					allDistContributions = append(allDistContributions, *contribution)
-				}
-			}
 		} else {
 			if x, ok := mod.(AndroidMkDataProvider); ok {
 				data := x.AndroidMk()
@@ -930,7 +906,7 @@
 				if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
 					moduleInfoJSONs = append(moduleInfoJSONs, moduleInfoJSON...)
 				}
-				if contribution := data.Entries.getDistContributions(mod); contribution != nil {
+				if contribution := getDistContributions(ctx, mod); contribution != nil {
 					allDistContributions = append(allDistContributions, *contribution)
 				}
 			}
@@ -944,7 +920,7 @@
 					if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
 						moduleInfoJSONs = append(moduleInfoJSONs, moduleInfoJSON...)
 					}
-					if contribution := entries.getDistContributions(mod); contribution != nil {
+					if contribution := getDistContributions(ctx, mod); contribution != nil {
 						allDistContributions = append(allDistContributions, *contribution)
 					}
 				}
@@ -1653,7 +1629,7 @@
 // TODO(b/397766191): Change the signature to take ModuleProxy
 // Please only access the module's internal data through providers.
 func (a *AndroidMkInfo) GetDistForGoals(ctx fillInEntriesContext, mod Module, commonInfo *CommonModuleInfo) []string {
-	distContributions := a.getDistContributions(ctx, mod, commonInfo)
+	distContributions := getDistContributions(ctx, mod)
 	if distContributions == nil {
 		return nil
 	}
@@ -1661,127 +1637,6 @@
 	return generateDistContributionsForMake(distContributions)
 }
 
-// Compute the contributions that the module makes to the dist.
-// TODO(b/397766191): Change the signature to take ModuleProxy
-// Please only access the module's internal data through providers.
-func (a *AndroidMkInfo) getDistContributions(ctx fillInEntriesContext, mod Module,
-	commonInfo *CommonModuleInfo) *distContributions {
-	name := commonInfo.BaseModuleName
-
-	// Collate the set of associated tag/paths available for copying to the dist.
-	// Start with an empty (nil) set.
-	var availableTaggedDists TaggedDistFiles
-
-	// If no paths have been provided for the DefaultDistTag and the output file is
-	// valid then add that as the default dist path.
-	if a.OutputFile.Valid() {
-		availableTaggedDists = availableTaggedDists.addPathsForTag(DefaultDistTag, a.OutputFile.Path())
-	}
-
-	info := OtherModuleProviderOrDefault(ctx, mod, InstallFilesProvider)
-	// If the distFiles created by GenerateTaggedDistFiles contains paths for the
-	// DefaultDistTag then that takes priority so delete any existing paths.
-	if _, ok := info.DistFiles[DefaultDistTag]; ok {
-		delete(availableTaggedDists, DefaultDistTag)
-	}
-
-	// Finally, merge the distFiles created by GenerateTaggedDistFiles.
-	availableTaggedDists = availableTaggedDists.merge(info.DistFiles)
-
-	if len(availableTaggedDists) == 0 {
-		// Nothing dist-able for this module.
-		return nil
-	}
-
-	// Collate the contributions this module makes to the dist.
-	distContributions := &distContributions{}
-
-	if !commonInfo.ExemptFromRequiredApplicableLicensesProperty {
-		distContributions.licenseMetadataFile = info.LicenseMetadataFile
-	}
-
-	// Iterate over this module's dist structs, merged from the dist and dists properties.
-	for _, dist := range commonInfo.Dists {
-		// Get the list of goals this dist should be enabled for. e.g. sdk, droidcore
-		goals := strings.Join(dist.Targets, " ")
-
-		// Get the tag representing the output files to be dist'd. e.g. ".jar", ".proguard_map"
-		var tag string
-		if dist.Tag == nil {
-			// If the dist struct does not specify a tag, use the default output files tag.
-			tag = DefaultDistTag
-		} else {
-			tag = *dist.Tag
-		}
-
-		// Get the paths of the output files to be dist'd, represented by the tag.
-		// Can be an empty list.
-		tagPaths := availableTaggedDists[tag]
-		if len(tagPaths) == 0 {
-			// Nothing to dist for this tag, continue to the next dist.
-			continue
-		}
-
-		if len(tagPaths) > 1 && (dist.Dest != nil || dist.Suffix != nil) {
-			errorMessage := "%s: Cannot apply dest/suffix for more than one dist " +
-				"file for %q goals tag %q in module %s. The list of dist files, " +
-				"which should have a single element, is:\n%s"
-			panic(fmt.Errorf(errorMessage, mod, goals, tag, name, tagPaths))
-		}
-
-		copiesForGoals := distContributions.getCopiesForGoals(goals)
-
-		// Iterate over each path adding a copy instruction to copiesForGoals
-		for _, path := range tagPaths {
-			// It's possible that the Path is nil from errant modules. Be defensive here.
-			if path == nil {
-				tagName := "default" // for error message readability
-				if dist.Tag != nil {
-					tagName = *dist.Tag
-				}
-				panic(fmt.Errorf("Dist file should not be nil for the %s tag in %s", tagName, name))
-			}
-
-			dest := filepath.Base(path.String())
-
-			if dist.Dest != nil {
-				var err error
-				if dest, err = validateSafePath(*dist.Dest); err != nil {
-					// This was checked in ModuleBase.GenerateBuildActions
-					panic(err)
-				}
-			}
-
-			ext := filepath.Ext(dest)
-			suffix := ""
-			if dist.Suffix != nil {
-				suffix = *dist.Suffix
-			}
-
-			productString := ""
-			if dist.Append_artifact_with_product != nil && *dist.Append_artifact_with_product {
-				productString = fmt.Sprintf("_%s", ctx.Config().DeviceProduct())
-			}
-
-			if suffix != "" || productString != "" {
-				dest = strings.TrimSuffix(dest, ext) + suffix + productString + ext
-			}
-
-			if dist.Dir != nil {
-				var err error
-				if dest, err = validateSafePath(*dist.Dir, dest); err != nil {
-					// This was checked in ModuleBase.GenerateBuildActions
-					panic(err)
-				}
-			}
-
-			copiesForGoals.addCopyInstruction(path, dest)
-		}
-	}
-
-	return distContributions
-}
-
 func deepCopyAndroidMkProviderInfo(providerInfo *AndroidMkProviderInfo) AndroidMkProviderInfo {
 	info := AndroidMkProviderInfo{
 		PrimaryInfo: deepCopyAndroidMkInfo(&providerInfo.PrimaryInfo),
diff --git a/android/androidmk_test.go b/android/androidmk_test.go
index 4cdd6a3..cd61133 100644
--- a/android/androidmk_test.go
+++ b/android/androidmk_test.go
@@ -346,7 +346,7 @@
 			if len(entries) != 1 {
 				t.Errorf("Expected a single AndroidMk entry, got %d", len(entries))
 			}
-			distContributions := entries[0].getDistContributions(module)
+			distContributions := getDistContributions(ctx, module)
 
 			if err := compareContributions(expectedContributions, distContributions); err != nil {
 				t.Errorf("%s\nExpected Contributions\n%sActualContributions\n%s",
@@ -648,8 +648,8 @@
 				default_dist_files: "none",
 				dist_output_file: false,
 				dists: [
-					// The following is silently ignored because there is not default file
-					// in either the dist files or the output file.
+					// The following will dist one.out because there's no default dist file provided
+					// (default_dist_files: "none") and one.out is the outputfile for the "" tag.
 					{
 						targets: ["my_goal"],
 					},
@@ -664,6 +664,12 @@
 			{
 				goals: "my_goal",
 				copies: []distCopy{
+					distCopyForTest("one.out", "one.out"),
+				},
+			},
+			{
+				goals: "my_goal",
+				copies: []distCopy{
 					distCopyForTest("two.out", "two.out"),
 					distCopyForTest("three/four.out", "four.out"),
 				},
diff --git a/android/module.go b/android/module.go
index d387c2c..c243d75 100644
--- a/android/module.go
+++ b/android/module.go
@@ -15,6 +15,7 @@
 package android
 
 import (
+	"errors"
 	"fmt"
 	"net/url"
 	"path/filepath"
@@ -1219,6 +1220,13 @@
 		tag := proptools.StringDefault(dist.Tag, DefaultDistTag)
 
 		distFileForTagFromProvider, err := outputFilesForModuleFromProvider(ctx, m.module, tag)
+
+		// If the module doesn't define output files for the DefaultDistTag, try the files under
+		// the "" tag.
+		if tag == DefaultDistTag && errors.Is(err, ErrUnsupportedOutputTag) {
+			distFileForTagFromProvider, err = outputFilesForModuleFromProvider(ctx, m.module, "")
+		}
+
 		if err != OutputFilesProviderNotSet {
 			if err != nil && tag != DefaultDistTag {
 				ctx.PropertyErrorf("dist.tag", "%s", err.Error())
@@ -2945,14 +2953,12 @@
 // If a module doesn't have the OutputFilesProvider, nil is returned.
 func outputFilesForModuleFromProvider(ctx PathContext, module Module, tag string) (Paths, error) {
 	var outputFiles OutputFilesInfo
-	fromProperty := false
 
 	if mctx, isMctx := ctx.(OutputFilesProviderModuleContext); isMctx {
 		if !mctx.EqualModules(mctx.Module(), module) {
 			outputFiles, _ = OtherModuleProvider(mctx, module, OutputFilesProvider)
 		} else {
 			outputFiles = mctx.GetOutputFiles()
-			fromProperty = true
 		}
 	} else if cta, isCta := ctx.(*singletonContextAdaptor); isCta {
 		outputFiles, _ = OtherModuleProvider(cta, module, OutputFilesProvider)
@@ -2969,10 +2975,8 @@
 	} else if taggedOutputFiles, hasTag := outputFiles.TaggedOutputFiles[tag]; hasTag {
 		return taggedOutputFiles, nil
 	} else {
-		if fromProperty {
-			return nil, fmt.Errorf("unsupported tag %q for module getting its own output files", tag)
-		} else {
-			return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+		return nil, UnsupportedOutputTagError{
+			tag: tag,
 		}
 	}
 }
@@ -2991,8 +2995,24 @@
 
 var OutputFilesProvider = blueprint.NewProvider[OutputFilesInfo]()
 
+type UnsupportedOutputTagError struct {
+	tag string
+}
+
+func (u UnsupportedOutputTagError) Error() string {
+	return fmt.Sprintf("unsupported output tag %q", u.tag)
+}
+
+func (u UnsupportedOutputTagError) Is(e error) bool {
+	_, ok := e.(UnsupportedOutputTagError)
+	return ok
+}
+
+var _ error = UnsupportedOutputTagError{}
+
 // This is used to mark the case where OutputFilesProvider is not set on some modules.
 var OutputFilesProviderNotSet = fmt.Errorf("No output files from provider")
+var ErrUnsupportedOutputTag = UnsupportedOutputTagError{}
 
 // Modules can implement HostToolProvider and return a valid OptionalPath from HostToolPath() to
 // specify that they can be used as a tool by a genrule module.
diff --git a/android/provider.go b/android/provider.go
index b48fd91..d005daf 100644
--- a/android/provider.go
+++ b/android/provider.go
@@ -16,6 +16,12 @@
 var _ OtherModuleProviderContext = SingletonContext(nil)
 var _ OtherModuleProviderContext = (*TestContext)(nil)
 
+// ConfigAndOtherModuleProviderContext is OtherModuleProviderContext + ConfigContext
+type ConfigAndOtherModuleProviderContext interface {
+	OtherModuleProviderContext
+	ConfigContext
+}
+
 // OtherModuleProvider reads the provider for the given module.  If the provider has been set the value is
 // returned and the boolean is true.  If it has not been set the zero value of the provider's type  is returned
 // and the boolean is false.  The value returned may be a deep copy of the value originally passed to SetProvider.