blob: 6c9d90330de11bafb1b877abafa0b0557d63812d [file] [log] [blame]
Liz Kammer2dd9ca42020-11-25 16:06:39 -08001// 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 bp2build
16
17import (
Jingwen Chendaa54bc2020-12-14 02:58:54 -050018 "fmt"
Liz Kammer2dd9ca42020-11-25 16:06:39 -080019 "os"
Chris Parsons520e88b2023-02-09 17:54:00 -050020 "path/filepath"
Liz Kammer6eff3232021-08-26 08:37:59 -040021 "strings"
Chris Parsons3b1f83d2021-10-14 14:08:38 -040022
23 "android/soong/android"
24 "android/soong/bazel"
Chris Parsons520e88b2023-02-09 17:54:00 -050025 "android/soong/shared"
ustaaaf2fd12023-07-01 11:40:36 -040026 "android/soong/starlark_import"
Liz Kammer2dd9ca42020-11-25 16:06:39 -080027)
28
Chris Parsons520e88b2023-02-09 17:54:00 -050029func deleteFilesExcept(ctx *CodegenContext, rootOutputPath android.OutputPath, except []BazelFile) {
30 // Delete files that should no longer be present.
31 bp2buildDirAbs := shared.JoinPath(ctx.topDir, rootOutputPath.String())
32
33 filesToDelete := make(map[string]struct{})
34 err := filepath.Walk(bp2buildDirAbs,
35 func(path string, info os.FileInfo, err error) error {
36 if err != nil {
37 return err
38 }
39 if !info.IsDir() {
40 relPath, err := filepath.Rel(bp2buildDirAbs, path)
41 if err != nil {
42 return err
43 }
44 filesToDelete[relPath] = struct{}{}
45 }
46 return nil
47 })
48 if err != nil {
49 fmt.Printf("ERROR reading %s: %s", bp2buildDirAbs, err)
50 os.Exit(1)
51 }
52
53 for _, bazelFile := range except {
54 filePath := filepath.Join(bazelFile.Dir, bazelFile.Basename)
55 delete(filesToDelete, filePath)
56 }
57 for f, _ := range filesToDelete {
58 absPath := shared.JoinPath(bp2buildDirAbs, f)
59 if err := os.RemoveAll(absPath); err != nil {
60 fmt.Printf("ERROR deleting %s: %s", absPath, err)
61 os.Exit(1)
62 }
63 }
64}
65
Jingwen Chen12b4c272021-03-10 02:05:59 -050066// Codegen is the backend of bp2build. The code generator is responsible for
67// writing .bzl files that are equivalent to Android.bp files that are capable
68// of being built with Bazel.
usta4f5d2c12022-10-28 23:32:01 -040069func Codegen(ctx *CodegenContext) *CodegenMetrics {
ustaaaf2fd12023-07-01 11:40:36 -040070 ctx.Context().BeginEvent("Codegen")
71 defer ctx.Context().EndEvent("Codegen")
Jingwen Chenbf61afb2021-05-06 13:31:18 +000072 // This directory stores BUILD files that could be eventually checked-in.
73 bp2buildDir := android.PathForOutput(ctx, "bp2build")
Liz Kammer2dd9ca42020-11-25 16:06:39 -080074
Liz Kammer6eff3232021-08-26 08:37:59 -040075 res, errs := GenerateBazelTargets(ctx, true)
76 if len(errs) > 0 {
77 errMsgs := make([]string, len(errs))
78 for i, err := range errs {
79 errMsgs[i] = fmt.Sprintf("%q", err)
80 }
81 fmt.Printf("ERROR: Encountered %d error(s): \nERROR: %s", len(errs), strings.Join(errMsgs, "\n"))
82 os.Exit(1)
83 }
ustaaaf2fd12023-07-01 11:40:36 -040084 var bp2buildFiles []BazelFile
Cole Faust6054cdf2023-09-12 10:07:07 -070085 productConfig, err := createProductConfigFiles(ctx, res.metrics)
ustaaaf2fd12023-07-01 11:40:36 -040086 ctx.Context().EventHandler.Do("CreateBazelFile", func() {
Cole Faust6054cdf2023-09-12 10:07:07 -070087 allTargets := make(map[string]BazelTargets)
88 for k, v := range res.buildFileToTargets {
89 allTargets[k] = append(allTargets[k], v...)
90 }
91 for k, v := range productConfig.bp2buildTargets {
92 allTargets[k] = append(allTargets[k], v...)
93 }
94 bp2buildFiles = CreateBazelFiles(nil, allTargets, ctx.mode)
ustaaaf2fd12023-07-01 11:40:36 -040095 })
Cole Faust6054cdf2023-09-12 10:07:07 -070096 bp2buildFiles = append(bp2buildFiles, productConfig.bp2buildFiles...)
97 injectionFiles, err := createSoongInjectionDirFiles(ctx, res.metrics)
Cole Faustf8231dd2023-04-21 17:37:11 -070098 if err != nil {
99 fmt.Printf("%s\n", err.Error())
100 os.Exit(1)
101 }
Cole Faust6054cdf2023-09-12 10:07:07 -0700102 injectionFiles = append(injectionFiles, productConfig.injectionFiles...)
103
Jingwen Chenbf61afb2021-05-06 13:31:18 +0000104 writeFiles(ctx, bp2buildDir, bp2buildFiles)
Chris Parsons520e88b2023-02-09 17:54:00 -0500105 // Delete files under the bp2build root which weren't just written. An
106 // alternative would have been to delete the whole directory and write these
107 // files. However, this would regenerate files which were otherwise unchanged
108 // since the last bp2build run, which would have negative incremental
109 // performance implications.
110 deleteFilesExcept(ctx, bp2buildDir, bp2buildFiles)
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800111
Cole Faust9e384e22023-02-08 17:43:09 -0800112 writeFiles(ctx, android.PathForOutput(ctx, bazel.SoongInjectionDirName), injectionFiles)
Cole Faustc9508aa2023-02-07 11:38:27 -0800113 starlarkDeps, err := starlark_import.GetNinjaDeps()
114 if err != nil {
115 fmt.Fprintf(os.Stderr, "%s\n", err)
116 os.Exit(1)
117 }
118 ctx.AddNinjaFileDeps(starlarkDeps...)
Spandan Das83e787e2023-01-11 02:50:00 +0000119 return &res.metrics
120}
121
Jingwen Chen12b4c272021-03-10 02:05:59 -0500122// Get the output directory and create it if it doesn't exist.
123func getOrCreateOutputDir(outputDir android.OutputPath, ctx android.PathContext, dir string) android.OutputPath {
124 dirPath := outputDir.Join(ctx, dir)
Usta Shresthadb46a9b2022-07-11 11:29:56 -0400125 if err := android.CreateOutputDirIfNonexistent(dirPath, os.ModePerm); err != nil {
126 fmt.Printf("ERROR: path %s: %s", dirPath, err.Error())
127 }
Jingwen Chen12b4c272021-03-10 02:05:59 -0500128 return dirPath
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800129}
130
Jingwen Chenbf61afb2021-05-06 13:31:18 +0000131// writeFiles materializes a list of BazelFile rooted at outputDir.
132func writeFiles(ctx android.PathContext, outputDir android.OutputPath, files []BazelFile) {
133 for _, f := range files {
134 p := getOrCreateOutputDir(outputDir, ctx, f.Dir).Join(ctx, f.Basename)
Usta Shresthadb46a9b2022-07-11 11:29:56 -0400135 if err := writeFile(p, f.Contents); err != nil {
Jingwen Chenbf61afb2021-05-06 13:31:18 +0000136 panic(fmt.Errorf("Failed to write %q (dir %q) due to %q", f.Basename, f.Dir, err))
137 }
138 }
139}
140
Usta Shresthadb46a9b2022-07-11 11:29:56 -0400141func writeFile(pathToFile android.OutputPath, content string) error {
Jingwen Chen12b4c272021-03-10 02:05:59 -0500142 // These files are made editable to allow users to modify and iterate on them
143 // in the source tree.
144 return android.WriteFileToOutputDir(pathToFile, []byte(content), 0644)
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800145}