blob: 76283343e29403e096bcf58cb7257cc625c7e998 [file] [log] [blame]
Dan Willemsen18490112018-05-25 16:30:04 -07001// Copyright 2018 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
17import (
Harsh Shandilyac82f6ca2019-09-14 15:45:51 +053018// "fmt"
Dan Willemsen18490112018-05-25 16:30:04 -070019 "io/ioutil"
20 "os"
21 "path/filepath"
Dan Willemsen417be1f2018-10-30 23:18:54 -070022 "runtime"
Harsh Shandilyac82f6ca2019-09-14 15:45:51 +053023// "strings"
Dan Willemsen18490112018-05-25 16:30:04 -070024
25 "github.com/google/blueprint/microfactory"
26
27 "android/soong/ui/build/paths"
Nan Zhang17f27672018-12-12 16:01:49 -080028 "android/soong/ui/metrics"
Dan Willemsen18490112018-05-25 16:30:04 -070029)
30
31func parsePathDir(dir string) []string {
32 f, err := os.Open(dir)
33 if err != nil {
34 return nil
35 }
36 defer f.Close()
37
38 if s, err := f.Stat(); err != nil || !s.IsDir() {
39 return nil
40 }
41
42 infos, err := f.Readdir(-1)
43 if err != nil {
44 return nil
45 }
46
47 ret := make([]string, 0, len(infos))
48 for _, info := range infos {
49 if m := info.Mode(); !m.IsDir() && m&0111 != 0 {
50 ret = append(ret, info.Name())
51 }
52 }
53 return ret
54}
55
56func SetupPath(ctx Context, config Config) {
57 if config.pathReplaced {
58 return
59 }
60
Nan Zhang17f27672018-12-12 16:01:49 -080061 ctx.BeginTrace(metrics.RunSetupTool, "path")
Dan Willemsen18490112018-05-25 16:30:04 -070062 defer ctx.EndTrace()
63
64 origPath, _ := config.Environment().Get("PATH")
65 myPath := filepath.Join(config.OutDir(), ".path")
66 interposer := myPath + "_interposer"
67
68 var cfg microfactory.Config
69 cfg.Map("android/soong", "build/soong")
70 cfg.TrimPath, _ = filepath.Abs(".")
71 if _, err := microfactory.Build(&cfg, interposer, "android/soong/cmd/path_interposer"); err != nil {
72 ctx.Fatalln("Failed to build path interposer:", err)
73 }
74
75 if err := ioutil.WriteFile(interposer+"_origpath", []byte(origPath), 0777); err != nil {
76 ctx.Fatalln("Failed to write original path:", err)
77 }
78
Harsh Shandilyac82f6ca2019-09-14 15:45:51 +053079/*
Dan Willemsen18490112018-05-25 16:30:04 -070080 entries, err := paths.LogListener(ctx.Context, interposer+"_log")
81 if err != nil {
82 ctx.Fatalln("Failed to listen for path logs:", err)
83 }
84
85 go func() {
86 for log := range entries {
87 curPid := os.Getpid()
88 for i, proc := range log.Parents {
89 if proc.Pid == curPid {
90 log.Parents = log.Parents[i:]
91 break
92 }
93 }
94 procPrints := []string{
95 "See https://android.googlesource.com/platform/build/+/master/Changes.md#PATH_Tools for more information.",
96 }
97 if len(log.Parents) > 0 {
98 procPrints = append(procPrints, "Process tree:")
99 for i, proc := range log.Parents {
100 procPrints = append(procPrints, fmt.Sprintf("%s→ %s", strings.Repeat(" ", i), proc.Command))
101 }
102 }
103
104 config := paths.GetConfig(log.Basename)
105 if config.Error {
106 ctx.Printf("Disallowed PATH tool %q used: %#v", log.Basename, log.Args)
107 for _, line := range procPrints {
108 ctx.Println(line)
109 }
110 } else {
111 ctx.Verbosef("Unknown PATH tool %q used: %#v", log.Basename, log.Args)
112 for _, line := range procPrints {
113 ctx.Verboseln(line)
114 }
115 }
116 }
117 }()
Harsh Shandilyac82f6ca2019-09-14 15:45:51 +0530118*/
Dan Willemsen18490112018-05-25 16:30:04 -0700119
120 ensureEmptyDirectoriesExist(ctx, myPath)
121
122 var execs []string
123 for _, pathEntry := range filepath.SplitList(origPath) {
124 if pathEntry == "" {
125 // Ignore the current directory
126 continue
127 }
128 // TODO(dwillemsen): remove path entries under TOP? or anything
129 // that looks like an android source dir? They won't exist on
130 // the build servers, since they're added by envsetup.sh.
131 // (Except for the JDK, which is configured in ui/build/config.go)
132
133 execs = append(execs, parsePathDir(pathEntry)...)
134 }
135
136 allowAllSymlinks := config.Environment().IsEnvTrue("TEMPORARY_DISABLE_PATH_RESTRICTIONS")
137 for _, name := range execs {
138 if !paths.GetConfig(name).Symlink && !allowAllSymlinks {
139 continue
140 }
141
142 err := os.Symlink("../.path_interposer", filepath.Join(myPath, name))
143 // Intentionally ignore existing files -- that means that we
144 // just created it, and the first one should win.
145 if err != nil && !os.IsExist(err) {
146 ctx.Fatalln("Failed to create symlink:", err)
147 }
148 }
149
150 myPath, _ = filepath.Abs(myPath)
Dan Willemsen417be1f2018-10-30 23:18:54 -0700151
Dan Willemsen91219732019-02-14 20:00:56 -0800152 // We put some prebuilts in $PATH, since it's infeasible to add dependencies for all of
153 // them.
Dan Willemsen733547d2019-02-14 20:11:26 -0800154 prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
155 myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
Dan Willemsen417be1f2018-10-30 23:18:54 -0700156
Dan Willemsen18490112018-05-25 16:30:04 -0700157 config.Environment().Set("PATH", myPath)
158 config.pathReplaced = true
159}