blob: 55ada335b1be7c7a5599f602fa85ce1330d2a64c [file] [log] [blame]
Patrice Arruda219eef32020-06-01 17:29:30 +00001// Copyright 2020 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package build
16
17// This file contains the functionality to upload data from one location to
18// another.
19
20import (
21 "io/ioutil"
22 "os"
23 "path/filepath"
24 "time"
25
Patrice Arruda7cc20742020-06-10 18:48:01 +000026 "android/soong/ui/metrics"
Dan Willemsen4591b642021-05-24 14:24:12 -070027
28 "google.golang.org/protobuf/proto"
Patrice Arruda219eef32020-06-01 17:29:30 +000029
30 upload_proto "android/soong/ui/metrics/upload_proto"
31)
32
33const (
Patrice Arruda92dc64f2020-11-16 16:29:16 -080034 // Used to generate a raw protobuf file that contains information
35 // of the list of metrics files from host to destination storage.
Patrice Arruda219eef32020-06-01 17:29:30 +000036 uploadPbFilename = ".uploader.pb"
37)
38
Patrice Arruda7cc20742020-06-10 18:48:01 +000039var (
Patrice Arruda92dc64f2020-11-16 16:29:16 -080040 // For testing purpose.
41 tmpDir = ioutil.TempDir
Patrice Arruda7cc20742020-06-10 18:48:01 +000042)
43
Patrice Arruda7d235cc2020-12-09 22:43:26 +000044// pruneMetricsFiles iterates the list of paths, checking if a path exist.
45// If a path is a file, it is added to the return list. If the path is a
46// directory, a recursive call is made to add the children files of the
47// path.
48func pruneMetricsFiles(paths []string) []string {
49 var metricsFiles []string
50 for _, p := range paths {
51 fi, err := os.Stat(p)
52 // Some paths passed may not exist. For example, build errors protobuf
53 // file may not exist since the build was successful.
54 if err != nil {
55 continue
56 }
57
58 if fi.IsDir() {
59 if l, err := ioutil.ReadDir(p); err == nil {
60 files := make([]string, 0, len(l))
61 for _, fi := range l {
62 files = append(files, filepath.Join(p, fi.Name()))
63 }
64 metricsFiles = append(metricsFiles, pruneMetricsFiles(files)...)
65 }
66 } else {
67 metricsFiles = append(metricsFiles, p)
68 }
69 }
70 return metricsFiles
71}
72
Patrice Arruda219eef32020-06-01 17:29:30 +000073// UploadMetrics uploads a set of metrics files to a server for analysis. An
Patrice Arruda92dc64f2020-11-16 16:29:16 -080074// uploader full path is specified in ANDROID_ENABLE_METRICS_UPLOAD environment
75// variable in order to upload the set of metrics files. The metrics files are
76// first copied to a temporary directory and the uploader is then executed in
77// the background to allow the user/system to continue working. Soong communicates
78// to the uploader through the upload_proto raw protobuf file.
Patrice Arruda7d235cc2020-12-09 22:43:26 +000079func UploadMetrics(ctx Context, config Config, simpleOutput bool, buildStarted time.Time, paths ...string) {
Patrice Arruda7cc20742020-06-10 18:48:01 +000080 ctx.BeginTrace(metrics.RunSetupTool, "upload_metrics")
81 defer ctx.EndTrace()
82
Patrice Arruda219eef32020-06-01 17:29:30 +000083 uploader := config.MetricsUploaderApp()
Patrice Arruda219eef32020-06-01 17:29:30 +000084 if uploader == "" {
Patrice Arruda92dc64f2020-11-16 16:29:16 -080085 // If the uploader path was not specified, no metrics shall be uploaded.
Patrice Arruda219eef32020-06-01 17:29:30 +000086 return
87 }
88
Patrice Arruda7d235cc2020-12-09 22:43:26 +000089 // Several of the files might be directories.
90 metricsFiles := pruneMetricsFiles(paths)
Patrice Arruda219eef32020-06-01 17:29:30 +000091 if len(metricsFiles) == 0 {
92 return
93 }
94
Patrice Arruda7cc20742020-06-10 18:48:01 +000095 // The temporary directory cannot be deleted as the metrics uploader is started
96 // in the background and requires to exist until the operation is done. The
97 // uploader can delete the directory as it is specified in the upload proto.
Patrice Arruda92dc64f2020-11-16 16:29:16 -080098 tmpDir, err := tmpDir("", "upload_metrics")
Patrice Arruda7cc20742020-06-10 18:48:01 +000099 if err != nil {
100 ctx.Fatalf("failed to create a temporary directory to store the list of metrics files: %v\n", err)
101 }
102
103 for i, src := range metricsFiles {
104 dst := filepath.Join(tmpDir, filepath.Base(src))
105 if _, err := copyFile(src, dst); err != nil {
106 ctx.Fatalf("failed to copy %q to %q: %v\n", src, dst, err)
107 }
108 metricsFiles[i] = dst
109 }
110
Patrice Arruda219eef32020-06-01 17:29:30 +0000111 // For platform builds, the branch and target name is hardcoded to specific
112 // values for later extraction of the metrics in the data metrics pipeline.
113 data, err := proto.Marshal(&upload_proto.Upload{
Patrice Arruda73c790f2020-07-13 23:01:18 +0000114 CreationTimestampMs: proto.Uint64(uint64(buildStarted.UnixNano() / int64(time.Millisecond))),
Patrice Arruda219eef32020-06-01 17:29:30 +0000115 CompletionTimestampMs: proto.Uint64(uint64(time.Now().UnixNano() / int64(time.Millisecond))),
116 BranchName: proto.String("developer-metrics"),
117 TargetName: proto.String("platform-build-systems-metrics"),
118 MetricsFiles: metricsFiles,
Patrice Arruda7cc20742020-06-10 18:48:01 +0000119 DirectoriesToDelete: []string{tmpDir},
Patrice Arruda219eef32020-06-01 17:29:30 +0000120 })
121 if err != nil {
122 ctx.Fatalf("failed to marshal metrics upload proto buffer message: %v\n", err)
123 }
124
Patrice Arruda7cc20742020-06-10 18:48:01 +0000125 pbFile := filepath.Join(tmpDir, uploadPbFilename)
Patrice Arruda219eef32020-06-01 17:29:30 +0000126 if err := ioutil.WriteFile(pbFile, data, 0644); err != nil {
127 ctx.Fatalf("failed to write the marshaled metrics upload protobuf to %q: %v\n", pbFile, err)
128 }
Patrice Arruda219eef32020-06-01 17:29:30 +0000129
Patrice Arruda7cc20742020-06-10 18:48:01 +0000130 // Start the uploader in the background as it takes several milliseconds to start the uploader
Patrice Arruda92dc64f2020-11-16 16:29:16 -0800131 // and prepare the metrics for upload. This affects small shell commands like "lunch".
Patrice Arruda7cc20742020-06-10 18:48:01 +0000132 cmd := Command(ctx, config, "upload metrics", uploader, "--upload-metrics", pbFile)
Patrice Arrudaf445ba12020-07-28 17:49:01 +0000133 if simpleOutput {
Patrice Arruda7cc20742020-06-10 18:48:01 +0000134 cmd.RunOrFatal()
135 } else {
136 cmd.RunAndStreamOrFatal()
137 }
Patrice Arruda219eef32020-06-01 17:29:30 +0000138}