blob: 55ca800b5aeb5dd2d380bf865e21f55d1a535d54 [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"
Patrice Arruda219eef32020-06-01 17:29:30 +000027 "github.com/golang/protobuf/proto"
28
29 upload_proto "android/soong/ui/metrics/upload_proto"
30)
31
32const (
Patrice Arruda92dc64f2020-11-16 16:29:16 -080033 // Used to generate a raw protobuf file that contains information
34 // of the list of metrics files from host to destination storage.
Patrice Arruda219eef32020-06-01 17:29:30 +000035 uploadPbFilename = ".uploader.pb"
36)
37
Patrice Arruda7cc20742020-06-10 18:48:01 +000038var (
Patrice Arruda92dc64f2020-11-16 16:29:16 -080039 // For testing purpose.
40 tmpDir = ioutil.TempDir
Patrice Arruda7cc20742020-06-10 18:48:01 +000041)
42
Patrice Arruda7d235cc2020-12-09 22:43:26 +000043// pruneMetricsFiles iterates the list of paths, checking if a path exist.
44// If a path is a file, it is added to the return list. If the path is a
45// directory, a recursive call is made to add the children files of the
46// path.
47func pruneMetricsFiles(paths []string) []string {
48 var metricsFiles []string
49 for _, p := range paths {
50 fi, err := os.Stat(p)
51 // Some paths passed may not exist. For example, build errors protobuf
52 // file may not exist since the build was successful.
53 if err != nil {
54 continue
55 }
56
57 if fi.IsDir() {
58 if l, err := ioutil.ReadDir(p); err == nil {
59 files := make([]string, 0, len(l))
60 for _, fi := range l {
61 files = append(files, filepath.Join(p, fi.Name()))
62 }
63 metricsFiles = append(metricsFiles, pruneMetricsFiles(files)...)
64 }
65 } else {
66 metricsFiles = append(metricsFiles, p)
67 }
68 }
69 return metricsFiles
70}
71
Patrice Arruda219eef32020-06-01 17:29:30 +000072// UploadMetrics uploads a set of metrics files to a server for analysis. An
Patrice Arruda92dc64f2020-11-16 16:29:16 -080073// uploader full path is specified in ANDROID_ENABLE_METRICS_UPLOAD environment
74// variable in order to upload the set of metrics files. The metrics files are
75// first copied to a temporary directory and the uploader is then executed in
76// the background to allow the user/system to continue working. Soong communicates
77// to the uploader through the upload_proto raw protobuf file.
Patrice Arruda7d235cc2020-12-09 22:43:26 +000078func UploadMetrics(ctx Context, config Config, simpleOutput bool, buildStarted time.Time, paths ...string) {
Patrice Arruda7cc20742020-06-10 18:48:01 +000079 ctx.BeginTrace(metrics.RunSetupTool, "upload_metrics")
80 defer ctx.EndTrace()
81
Patrice Arruda219eef32020-06-01 17:29:30 +000082 uploader := config.MetricsUploaderApp()
Patrice Arruda219eef32020-06-01 17:29:30 +000083 if uploader == "" {
Patrice Arruda92dc64f2020-11-16 16:29:16 -080084 // If the uploader path was not specified, no metrics shall be uploaded.
Patrice Arruda219eef32020-06-01 17:29:30 +000085 return
86 }
87
Patrice Arruda7d235cc2020-12-09 22:43:26 +000088 // Several of the files might be directories.
89 metricsFiles := pruneMetricsFiles(paths)
Patrice Arruda219eef32020-06-01 17:29:30 +000090 if len(metricsFiles) == 0 {
91 return
92 }
93
Patrice Arruda7cc20742020-06-10 18:48:01 +000094 // The temporary directory cannot be deleted as the metrics uploader is started
95 // in the background and requires to exist until the operation is done. The
96 // uploader can delete the directory as it is specified in the upload proto.
Patrice Arruda92dc64f2020-11-16 16:29:16 -080097 tmpDir, err := tmpDir("", "upload_metrics")
Patrice Arruda7cc20742020-06-10 18:48:01 +000098 if err != nil {
99 ctx.Fatalf("failed to create a temporary directory to store the list of metrics files: %v\n", err)
100 }
101
102 for i, src := range metricsFiles {
103 dst := filepath.Join(tmpDir, filepath.Base(src))
104 if _, err := copyFile(src, dst); err != nil {
105 ctx.Fatalf("failed to copy %q to %q: %v\n", src, dst, err)
106 }
107 metricsFiles[i] = dst
108 }
109
Patrice Arruda219eef32020-06-01 17:29:30 +0000110 // For platform builds, the branch and target name is hardcoded to specific
111 // values for later extraction of the metrics in the data metrics pipeline.
112 data, err := proto.Marshal(&upload_proto.Upload{
Patrice Arruda73c790f2020-07-13 23:01:18 +0000113 CreationTimestampMs: proto.Uint64(uint64(buildStarted.UnixNano() / int64(time.Millisecond))),
Patrice Arruda219eef32020-06-01 17:29:30 +0000114 CompletionTimestampMs: proto.Uint64(uint64(time.Now().UnixNano() / int64(time.Millisecond))),
115 BranchName: proto.String("developer-metrics"),
116 TargetName: proto.String("platform-build-systems-metrics"),
117 MetricsFiles: metricsFiles,
Patrice Arruda7cc20742020-06-10 18:48:01 +0000118 DirectoriesToDelete: []string{tmpDir},
Patrice Arruda219eef32020-06-01 17:29:30 +0000119 })
120 if err != nil {
121 ctx.Fatalf("failed to marshal metrics upload proto buffer message: %v\n", err)
122 }
123
Patrice Arruda7cc20742020-06-10 18:48:01 +0000124 pbFile := filepath.Join(tmpDir, uploadPbFilename)
Patrice Arruda219eef32020-06-01 17:29:30 +0000125 if err := ioutil.WriteFile(pbFile, data, 0644); err != nil {
126 ctx.Fatalf("failed to write the marshaled metrics upload protobuf to %q: %v\n", pbFile, err)
127 }
Patrice Arruda219eef32020-06-01 17:29:30 +0000128
Patrice Arruda7cc20742020-06-10 18:48:01 +0000129 // Start the uploader in the background as it takes several milliseconds to start the uploader
Patrice Arruda92dc64f2020-11-16 16:29:16 -0800130 // and prepare the metrics for upload. This affects small shell commands like "lunch".
Patrice Arruda7cc20742020-06-10 18:48:01 +0000131 cmd := Command(ctx, config, "upload metrics", uploader, "--upload-metrics", pbFile)
Patrice Arrudaf445ba12020-07-28 17:49:01 +0000132 if simpleOutput {
Patrice Arruda7cc20742020-06-10 18:48:01 +0000133 cmd.RunOrFatal()
134 } else {
135 cmd.RunAndStreamOrFatal()
136 }
Patrice Arruda219eef32020-06-01 17:29:30 +0000137}