1// 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 main
16
17import (
18	"io/fs"
19	"io/ioutil"
20	"os"
21	"path/filepath"
22
23	"android/soong/android"
24	"android/soong/bp2build"
25)
26
27// A helper function to generate a Read-only Bazel workspace in outDir
28func createBazelWorkspace(ctx *bp2build.CodegenContext, outDir string, generateFilegroups bool) error {
29	os.RemoveAll(outDir)
30	ruleShims := bp2build.CreateRuleShims(android.ModuleTypeFactories())
31
32	res, err := bp2build.GenerateBazelTargets(ctx, generateFilegroups)
33	if err != nil {
34		panic(err)
35	}
36
37	filesToWrite := bp2build.CreateBazelFiles(ruleShims, res.BuildDirToTargets(), ctx.Mode())
38	bazelRcFiles, err2 := CopyBazelRcFiles()
39	if err2 != nil {
40		return err2
41	}
42	filesToWrite = append(filesToWrite, bazelRcFiles...)
43	for _, f := range filesToWrite {
44		if err := writeReadOnlyFile(outDir, f); err != nil {
45			return err
46		}
47	}
48
49	return nil
50}
51
52// CopyBazelRcFiles creates BazelFiles for all the bazelrc files under
53// build/bazel. They're needed because the rc files are still read when running
54// queryview, so they have to be in the queryview workspace.
55func CopyBazelRcFiles() ([]bp2build.BazelFile, error) {
56	result := make([]bp2build.BazelFile, 0)
57	err := filepath.WalkDir(filepath.Join(topDir, "build/bazel"), func(path string, info fs.DirEntry, err error) error {
58		if filepath.Ext(path) == ".bazelrc" {
59			contents, err := os.ReadFile(path)
60			if err != nil {
61				return err
62			}
63			path, err = filepath.Rel(topDir, path)
64			if err != nil {
65				return err
66			}
67			result = append(result, bp2build.BazelFile{
68				Dir:      filepath.Dir(path),
69				Basename: filepath.Base(path),
70				Contents: string(contents),
71			})
72		}
73		return nil
74	})
75	return result, err
76}
77
78// The auto-conversion directory should be read-only, sufficient for bazel query. The files
79// are not intended to be edited by end users.
80func writeReadOnlyFile(dir string, f bp2build.BazelFile) error {
81	dir = filepath.Join(dir, f.Dir)
82	if err := createDirectoryIfNonexistent(dir); err != nil {
83		return err
84	}
85	pathToFile := filepath.Join(dir, f.Basename)
86
87	// 0444 is read-only
88	err := ioutil.WriteFile(pathToFile, []byte(f.Contents), 0444)
89
90	return err
91}
92
93func writeReadWriteFile(dir string, f bp2build.BazelFile) error {
94	dir = filepath.Join(dir, f.Dir)
95	if err := createDirectoryIfNonexistent(dir); err != nil {
96		return err
97	}
98	pathToFile := filepath.Join(dir, f.Basename)
99
100	// 0644 is read-write
101	err := ioutil.WriteFile(pathToFile, []byte(f.Contents), 0644)
102
103	return err
104}
105
106func createDirectoryIfNonexistent(dir string) error {
107	if _, err := os.Stat(dir); os.IsNotExist(err) {
108		return os.MkdirAll(dir, os.ModePerm)
109	} else {
110		return err
111	}
112}
113