2021-02-19 06:48:40 +01:00
package bp2build
import (
"fmt"
2021-11-10 15:55:20 +01:00
"os"
"path/filepath"
2021-08-26 14:37:59 +02:00
"strings"
2021-12-08 17:19:06 +01:00
"android/soong/android"
2021-11-10 15:55:20 +01:00
"android/soong/shared"
"android/soong/ui/metrics/bp2build_metrics_proto"
2021-02-19 06:48:40 +01:00
)
// Simple metrics struct to collect information about a Blueprint to BUILD
// conversion process.
type CodegenMetrics struct {
2021-09-20 12:54:27 +02:00
// Total number of Soong modules converted to generated targets
2021-11-10 15:55:20 +01:00
generatedModuleCount uint64
2021-02-19 06:48:40 +01:00
2021-09-20 12:54:27 +02:00
// Total number of Soong modules converted to handcrafted targets
2021-11-10 15:55:20 +01:00
handCraftedModuleCount uint64
2021-09-20 12:54:27 +02:00
// Total number of unconverted Soong modules
2021-11-10 15:55:20 +01:00
unconvertedModuleCount uint64
2021-02-17 19:22:03 +01:00
2021-09-20 12:54:27 +02:00
// Counts of generated Bazel targets per Bazel rule class
2021-11-10 15:55:20 +01:00
ruleClassCount map [ string ] uint64
2021-08-26 14:37:59 +02:00
2021-11-10 15:55:20 +01:00
// List of modules with unconverted deps
// NOTE: NOT in the .proto
2021-08-26 14:37:59 +02:00
moduleWithUnconvertedDepsMsgs [ ] string
2021-09-17 10:40:45 +02:00
2021-11-10 15:55:20 +01:00
// List of converted modules
2021-09-17 10:40:45 +02:00
convertedModules [ ] string
2021-02-19 06:48:40 +01:00
}
2021-11-10 15:55:20 +01:00
// Serialize returns the protoized version of CodegenMetrics: bp2build_metrics_proto.Bp2BuildMetrics
func ( metrics * CodegenMetrics ) Serialize ( ) bp2build_metrics_proto . Bp2BuildMetrics {
return bp2build_metrics_proto . Bp2BuildMetrics {
GeneratedModuleCount : metrics . generatedModuleCount ,
HandCraftedModuleCount : metrics . handCraftedModuleCount ,
UnconvertedModuleCount : metrics . unconvertedModuleCount ,
RuleClassCount : metrics . ruleClassCount ,
ConvertedModules : metrics . convertedModules ,
}
}
2021-02-19 06:48:40 +01:00
// Print the codegen metrics to stdout.
2021-09-20 12:31:46 +02:00
func ( metrics * CodegenMetrics ) Print ( ) {
2021-11-10 15:55:20 +01:00
generatedTargetCount := uint64 ( 0 )
2021-09-20 12:54:27 +02:00
for _ , ruleClass := range android . SortedStringKeys ( metrics . ruleClassCount ) {
count := metrics . ruleClassCount [ ruleClass ]
2021-02-19 06:48:40 +01:00
fmt . Printf ( "[bp2build] %s: %d targets\n" , ruleClass , count )
generatedTargetCount += count
}
fmt . Printf (
2021-12-08 17:19:06 +01:00
"[bp2build] Converted %d Android.bp modules to %d total generated BUILD targets. Included %d handcrafted BUILD targets. There are %d total Android.bp modules.\n%d converted modules have unconverted deps: \n\t%s" ,
metrics . generatedModuleCount ,
2021-02-19 06:48:40 +01:00
generatedTargetCount ,
2021-09-20 12:54:27 +02:00
metrics . handCraftedModuleCount ,
metrics . TotalModuleCount ( ) ,
2021-08-26 14:37:59 +02:00
len ( metrics . moduleWithUnconvertedDepsMsgs ) ,
strings . Join ( metrics . moduleWithUnconvertedDepsMsgs , "\n\t" ) )
2021-02-19 06:48:40 +01:00
}
2021-09-17 10:40:45 +02:00
2021-11-10 15:55:20 +01:00
const bp2buildMetricsFilename = "bp2build_metrics.pb"
// fail prints $PWD to stderr, followed by the given printf string and args (vals),
// then the given alert, and then exits with 1 for failure
func fail ( err error , alertFmt string , vals ... interface { } ) {
cwd , wderr := os . Getwd ( )
if wderr != nil {
cwd = "FAILED TO GET $PWD: " + wderr . Error ( )
}
fmt . Fprintf ( os . Stderr , "\nIn " + cwd + ":\n" + alertFmt + "\n" + err . Error ( ) + "\n" , vals ... )
os . Exit ( 1 )
}
// Write the bp2build-protoized codegen metrics into the given directory
func ( metrics * CodegenMetrics ) Write ( dir string ) {
if _ , err := os . Stat ( dir ) ; os . IsNotExist ( err ) {
// The metrics dir doesn't already exist, so create it (and parents)
if err := os . MkdirAll ( dir , 0755 ) ; err != nil { // rx for all; w for user
fail ( err , "Failed to `mkdir -p` %s" , dir )
}
} else if err != nil {
fail ( err , "Failed to `stat` %s" , dir )
}
metricsFile := filepath . Join ( dir , bp2buildMetricsFilename )
if err := metrics . dump ( metricsFile ) ; err != nil {
fail ( err , "Error outputting %s" , metricsFile )
}
if _ , err := os . Stat ( metricsFile ) ; err != nil {
fail ( err , "MISSING BP2BUILD METRICS OUTPUT: Failed to `stat` %s" , metricsFile )
} else {
fmt . Printf ( "\nWrote bp2build metrics to: %s\n" , metricsFile )
}
}
2021-09-20 12:54:27 +02:00
func ( metrics * CodegenMetrics ) IncrementRuleClassCount ( ruleClass string ) {
metrics . ruleClassCount [ ruleClass ] += 1
}
func ( metrics * CodegenMetrics ) IncrementUnconvertedCount ( ) {
metrics . unconvertedModuleCount += 1
}
2021-11-10 15:55:20 +01:00
func ( metrics * CodegenMetrics ) TotalModuleCount ( ) uint64 {
2021-09-20 12:54:27 +02:00
return metrics . handCraftedModuleCount +
metrics . generatedModuleCount +
metrics . unconvertedModuleCount
}
2021-11-10 15:55:20 +01:00
// Dump serializes the metrics to the given filename
func ( metrics * CodegenMetrics ) dump ( filename string ) ( err error ) {
ser := metrics . Serialize ( )
return shared . Save ( & ser , filename )
}
2021-09-20 12:54:27 +02:00
type ConversionType int
const (
Generated ConversionType = iota
Handcrafted
)
func ( metrics * CodegenMetrics ) AddConvertedModule ( moduleName string , conversionType ConversionType ) {
2021-09-17 10:40:45 +02:00
// Undo prebuilt_ module name prefix modifications
moduleName = android . RemoveOptionalPrebuiltPrefix ( moduleName )
metrics . convertedModules = append ( metrics . convertedModules , moduleName )
2021-09-20 12:54:27 +02:00
if conversionType == Handcrafted {
metrics . handCraftedModuleCount += 1
} else if conversionType == Generated {
metrics . generatedModuleCount += 1
}
2021-09-17 10:40:45 +02:00
}