From 7d235cc24d69f6cdbecd423a6b622b86cd2815f9 Mon Sep 17 00:00:00 2001 From: Patrice Arruda Date: Wed, 9 Dec 2020 22:43:26 +0000 Subject: [PATCH] Allow uploading a directory of metrics files. The upload functionality now supports directories to be uploaded for metrics purpose. Bug: b/174479728 Test: Wrote unit test case. Change-Id: I6906be4c1b7fd76ddf6ff7b94e48fe1c4209c59d --- ui/build/upload.go | 42 +++++++++++++++++++++++++++++--------- ui/build/upload_test.go | 45 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 10 deletions(-) diff --git a/ui/build/upload.go b/ui/build/upload.go index 4f30136b9..55ca800b5 100644 --- a/ui/build/upload.go +++ b/ui/build/upload.go @@ -40,13 +40,42 @@ var ( tmpDir = ioutil.TempDir ) +// pruneMetricsFiles iterates the list of paths, checking if a path exist. +// If a path is a file, it is added to the return list. If the path is a +// directory, a recursive call is made to add the children files of the +// path. +func pruneMetricsFiles(paths []string) []string { + var metricsFiles []string + for _, p := range paths { + fi, err := os.Stat(p) + // Some paths passed may not exist. For example, build errors protobuf + // file may not exist since the build was successful. + if err != nil { + continue + } + + if fi.IsDir() { + if l, err := ioutil.ReadDir(p); err == nil { + files := make([]string, 0, len(l)) + for _, fi := range l { + files = append(files, filepath.Join(p, fi.Name())) + } + metricsFiles = append(metricsFiles, pruneMetricsFiles(files)...) + } + } else { + metricsFiles = append(metricsFiles, p) + } + } + return metricsFiles +} + // UploadMetrics uploads a set of metrics files to a server for analysis. An // uploader full path is specified in ANDROID_ENABLE_METRICS_UPLOAD environment // variable in order to upload the set of metrics files. The metrics files are // first copied to a temporary directory and the uploader is then executed in // the background to allow the user/system to continue working. Soong communicates // to the uploader through the upload_proto raw protobuf file. -func UploadMetrics(ctx Context, config Config, simpleOutput bool, buildStarted time.Time, files ...string) { +func UploadMetrics(ctx Context, config Config, simpleOutput bool, buildStarted time.Time, paths ...string) { ctx.BeginTrace(metrics.RunSetupTool, "upload_metrics") defer ctx.EndTrace() @@ -56,15 +85,8 @@ func UploadMetrics(ctx Context, config Config, simpleOutput bool, buildStarted t return } - // Some files passed in to this function may not exist. For example, - // build errors protobuf file may not exist since the build was successful. - var metricsFiles []string - for _, f := range files { - if _, err := os.Stat(f); err == nil { - metricsFiles = append(metricsFiles, f) - } - } - + // Several of the files might be directories. + metricsFiles := pruneMetricsFiles(paths) if len(metricsFiles) == 0 { return } diff --git a/ui/build/upload_test.go b/ui/build/upload_test.go index 768b03112..b740c1120 100644 --- a/ui/build/upload_test.go +++ b/ui/build/upload_test.go @@ -19,6 +19,8 @@ import ( "io/ioutil" "os" "path/filepath" + "reflect" + "sort" "strconv" "strings" "testing" @@ -27,6 +29,49 @@ import ( "android/soong/ui/logger" ) +func TestPruneMetricsFiles(t *testing.T) { + rootDir := t.TempDir() + + dirs := []string{ + filepath.Join(rootDir, "d1"), + filepath.Join(rootDir, "d1", "d2"), + filepath.Join(rootDir, "d1", "d2", "d3"), + } + + files := []string{ + filepath.Join(rootDir, "d1", "f1"), + filepath.Join(rootDir, "d1", "d2", "f1"), + filepath.Join(rootDir, "d1", "d2", "d3", "f1"), + } + + for _, d := range dirs { + if err := os.MkdirAll(d, 0777); err != nil { + t.Fatalf("got %v, expecting nil error for making directory %q", err, d) + } + } + + for _, f := range files { + if err := ioutil.WriteFile(f, []byte{}, 0777); err != nil { + t.Fatalf("got %v, expecting nil error on writing file %q", err, f) + } + } + + want := []string{ + filepath.Join(rootDir, "d1", "f1"), + filepath.Join(rootDir, "d1", "d2", "f1"), + filepath.Join(rootDir, "d1", "d2", "d3", "f1"), + } + + got := pruneMetricsFiles([]string{rootDir}) + + sort.Strings(got) + sort.Strings(want) + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %q, want %q after pruning metrics files", got, want) + } +} + func TestUploadMetrics(t *testing.T) { ctx := testContext() tests := []struct {