Revert "Add path interposer"
This reverts commit a14704c12bbcc1eb207d1c0ff3df0140a4582fc5.
Reason for revert: breaking builds
Change-Id: I920b0ff41823428a0baf59b3fd82cbcc766babca
diff --git a/cmd/path_interposer/Android.bp b/cmd/path_interposer/Android.bp
deleted file mode 100644
index 41a219f..0000000
--- a/cmd/path_interposer/Android.bp
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2018 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-blueprint_go_binary {
- name: "path_interposer",
- deps: ["soong-ui-build-paths"],
- srcs: ["main.go"],
- testSrcs: ["main_test.go"],
-}
diff --git a/cmd/path_interposer/main.go b/cmd/path_interposer/main.go
deleted file mode 100644
index 01fe5d4..0000000
--- a/cmd/path_interposer/main.go
+++ /dev/null
@@ -1,229 +0,0 @@
-// Copyright 2018 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package main
-
-import (
- "bytes"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "os/exec"
- "path/filepath"
- "strconv"
- "syscall"
-
- "android/soong/ui/build/paths"
-)
-
-func main() {
- interposer, err := os.Executable()
- if err != nil {
- fmt.Fprintln(os.Stderr, "Unable to locate interposer executable:", err)
- os.Exit(1)
- }
-
- disableError := false
- if e, ok := os.LookupEnv("TEMPORARY_DISABLE_PATH_RESTRICTIONS"); ok {
- disableError = e == "1" || e == "y" || e == "yes" || e == "on" || e == "true"
- }
-
- exitCode, err := Main(os.Stdout, os.Stderr, interposer, os.Args, mainOpts{
- disableError: disableError,
-
- sendLog: paths.SendLog,
- config: paths.GetConfig,
- lookupParents: lookupParents,
- })
- if err != nil {
- fmt.Fprintln(os.Stderr, err.Error())
- }
- os.Exit(exitCode)
-}
-
-var usage = fmt.Errorf(`To use the PATH interposer:
- * Write the original PATH variable to <interposer>_origpath
- * Set up a directory of symlinks to the PATH interposer, and use that in PATH
-
-If a tool isn't in the allowed list, a log will be posted to the unix domain
-socket at <interposer>_log.`)
-
-type mainOpts struct {
- disableError bool
-
- sendLog func(logSocket string, entry *paths.LogEntry, done chan interface{})
- config func(name string) paths.PathConfig
- lookupParents func() []paths.LogProcess
-}
-
-func Main(stdout, stderr io.Writer, interposer string, args []string, opts mainOpts) (int, error) {
- base := filepath.Base(args[0])
-
- origPathFile := interposer + "_origpath"
- if base == filepath.Base(interposer) {
- return 1, usage
- }
-
- origPath, err := ioutil.ReadFile(origPathFile)
- if err != nil {
- if os.IsNotExist(err) {
- return 1, usage
- } else {
- return 1, fmt.Errorf("Failed to read original PATH: %v", err)
- }
- }
-
- cmd := &exec.Cmd{
- Args: args,
- Env: os.Environ(),
-
- Stdin: os.Stdin,
- Stdout: stdout,
- Stderr: stderr,
- }
-
- if err := os.Setenv("PATH", string(origPath)); err != nil {
- return 1, fmt.Errorf("Failed to set PATH env: %v", err)
- }
-
- if config := opts.config(base); config.Log || config.Error {
- var procs []paths.LogProcess
- if opts.lookupParents != nil {
- procs = opts.lookupParents()
- }
-
- if opts.sendLog != nil {
- waitForLog := make(chan interface{})
- opts.sendLog(interposer+"_log", &paths.LogEntry{
- Basename: base,
- Args: args,
- Parents: procs,
- }, waitForLog)
- defer func() { <-waitForLog }()
- }
- if config.Error && !opts.disableError {
- return 1, fmt.Errorf("%q is not allowed to be used. See https://android.googlesource.com/platform/build/+/master/Changes.md#PATH_Tools for more information.", base)
- }
- }
-
- cmd.Path, err = exec.LookPath(base)
- if err != nil {
- return 1, err
- }
-
- if err = cmd.Run(); err != nil {
- if exitErr, ok := err.(*exec.ExitError); ok {
- if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
- if status.Exited() {
- return status.ExitStatus(), nil
- } else if status.Signaled() {
- exitCode := 128 + int(status.Signal())
- return exitCode, nil
- } else {
- return 1, exitErr
- }
- } else {
- return 1, nil
- }
- }
- }
-
- return 0, nil
-}
-
-type procEntry struct {
- Pid int
- Ppid int
- Command string
-}
-
-func readProcs() map[int]procEntry {
- cmd := exec.Command("ps", "-o", "pid,ppid,command")
- data, err := cmd.Output()
- if err != nil {
- return nil
- }
-
- return parseProcs(data)
-}
-
-func parseProcs(data []byte) map[int]procEntry {
- lines := bytes.Split(data, []byte("\n"))
- if len(lines) < 2 {
- return nil
- }
- // Remove the header
- lines = lines[1:]
-
- ret := make(map[int]procEntry, len(lines))
- for _, line := range lines {
- fields := bytes.SplitN(line, []byte(" "), 2)
- if len(fields) != 2 {
- continue
- }
-
- pid, err := strconv.Atoi(string(fields[0]))
- if err != nil {
- continue
- }
-
- line = bytes.TrimLeft(fields[1], " ")
-
- fields = bytes.SplitN(line, []byte(" "), 2)
- if len(fields) != 2 {
- continue
- }
-
- ppid, err := strconv.Atoi(string(fields[0]))
- if err != nil {
- continue
- }
-
- ret[pid] = procEntry{
- Pid: pid,
- Ppid: ppid,
- Command: string(bytes.TrimLeft(fields[1], " ")),
- }
- }
-
- return ret
-}
-
-func lookupParents() []paths.LogProcess {
- procs := readProcs()
- if procs == nil {
- return nil
- }
-
- list := []paths.LogProcess{}
- pid := os.Getpid()
- for {
- entry, ok := procs[pid]
- if !ok {
- break
- }
-
- list = append([]paths.LogProcess{
- {
- Pid: pid,
- Command: entry.Command,
- },
- }, list...)
-
- pid = entry.Ppid
- }
-
- return list
-}
diff --git a/cmd/path_interposer/main_test.go b/cmd/path_interposer/main_test.go
deleted file mode 100644
index 4b25c44..0000000
--- a/cmd/path_interposer/main_test.go
+++ /dev/null
@@ -1,196 +0,0 @@
-// Copyright 2018 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package main
-
-import (
- "fmt"
- "io/ioutil"
- "os"
- "path/filepath"
- "testing"
-
- "android/soong/ui/build/paths"
-)
-
-var tmpDir string
-var origPATH string
-
-func TestMain(m *testing.M) {
- os.Exit(func() int {
- var err error
- tmpDir, err = ioutil.TempDir("", "interposer_test")
- if err != nil {
- panic(err)
- }
- defer os.RemoveAll(tmpDir)
-
- origPATH = os.Getenv("PATH")
- err = os.Setenv("PATH", "")
- if err != nil {
- panic(err)
- }
-
- return m.Run()
- }())
-}
-
-func setup(t *testing.T) string {
- f, err := ioutil.TempFile(tmpDir, "interposer")
- if err != nil {
- t.Fatal(err)
- }
- defer f.Close()
-
- err = ioutil.WriteFile(f.Name()+"_origpath", []byte(origPATH), 0666)
- if err != nil {
- t.Fatal(err)
- }
- return f.Name()
-}
-
-func TestInterposer(t *testing.T) {
- interposer := setup(t)
-
- logConfig := func(name string) paths.PathConfig {
- if name == "true" {
- return paths.PathConfig{
- Log: false,
- Error: false,
- }
- } else if name == "path_interposer_test_not_allowed" {
- return paths.PathConfig{
- Log: false,
- Error: true,
- }
- }
- return paths.PathConfig{
- Log: true,
- Error: false,
- }
- }
-
- testCases := []struct {
- name string
- args []string
-
- exitCode int
- err error
- logEntry string
- }{
- {
- name: "direct call",
- args: []string{interposer},
-
- exitCode: 1,
- err: usage,
- },
- {
- name: "relative call",
- args: []string{filepath.Base(interposer)},
-
- exitCode: 1,
- err: usage,
- },
- {
- name: "true",
- args: []string{"/my/path/true"},
- },
- {
- name: "relative true",
- args: []string{"true"},
- },
- {
- name: "exit code",
- args: []string{"bash", "-c", "exit 42"},
-
- exitCode: 42,
- logEntry: "bash",
- },
- {
- name: "signal",
- args: []string{"bash", "-c", "kill -9 $$"},
-
- exitCode: 137,
- logEntry: "bash",
- },
- {
- name: "does not exist",
- args: []string{"path_interposer_test_does_not_exist"},
-
- exitCode: 1,
- err: fmt.Errorf(`exec: "path_interposer_test_does_not_exist": executable file not found in $PATH`),
- logEntry: "path_interposer_test_does_not_exist",
- },
- {
- name: "not allowed",
- args: []string{"path_interposer_test_not_allowed"},
-
- exitCode: 1,
- err: fmt.Errorf(`"path_interposer_test_not_allowed" is not allowed to be used. See https://android.googlesource.com/platform/build/+/master/Changes.md#PATH_Tools for more information.`),
- logEntry: "path_interposer_test_not_allowed",
- },
- }
-
- for _, testCase := range testCases {
- t.Run(testCase.name, func(t *testing.T) {
- logged := false
- logFunc := func(logSocket string, entry *paths.LogEntry, done chan interface{}) {
- defer close(done)
-
- logged = true
- if entry.Basename != testCase.logEntry {
- t.Errorf("unexpected log entry:\nwant: %q\n got: %q", testCase.logEntry, entry.Basename)
- }
- }
-
- exitCode, err := Main(ioutil.Discard, ioutil.Discard, interposer, testCase.args, mainOpts{
- sendLog: logFunc,
- config: logConfig,
- })
-
- errstr := func(err error) string {
- if err == nil {
- return ""
- }
- return err.Error()
- }
- if errstr(testCase.err) != errstr(err) {
- t.Errorf("unexpected error:\nwant: %v\n got: %v", testCase.err, err)
- }
- if testCase.exitCode != exitCode {
- t.Errorf("expected exit code %d, got %d", testCase.exitCode, exitCode)
- }
- if !logged && testCase.logEntry != "" {
- t.Errorf("no log entry, but expected %q", testCase.logEntry)
- }
- })
- }
-}
-
-func TestMissingPath(t *testing.T) {
- interposer := setup(t)
- err := os.Remove(interposer + "_origpath")
- if err != nil {
- t.Fatalf("Failed to remove:", err)
- }
-
- exitCode, err := Main(ioutil.Discard, ioutil.Discard, interposer, []string{"true"}, mainOpts{})
- if err != usage {
- t.Errorf("Unexpected error:\n got: %v\nwant: %v", err, usage)
- }
- if exitCode != 1 {
- t.Errorf("expected exit code %d, got %d", 1, exitCode)
- }
-}
diff --git a/python/scripts/stub_template_host.txt b/python/scripts/stub_template_host.txt
index 386298e..b90a28b 100644
--- a/python/scripts/stub_template_host.txt
+++ b/python/scripts/stub_template_host.txt
@@ -18,6 +18,8 @@
for directory in search_path:
if directory == '': continue
path = os.path.join(directory, name)
+ if os.path.islink(path):
+ path = os.path.realpath(path)
# Check if path is actual executable file.
if os.path.isfile(path) and os.access(path, os.X_OK):
return path
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index 1fe5b6f..5809894 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -13,22 +13,9 @@
// limitations under the License.
bootstrap_go_package {
- name: "soong-ui-build-paths",
- pkgPath: "android/soong/ui/build/paths",
- srcs: [
- "paths/config.go",
- "paths/logs.go",
- ],
- testSrcs: [
- "paths/logs_test.go",
- ],
-}
-
-bootstrap_go_package {
name: "soong-ui-build",
pkgPath: "android/soong/ui/build",
deps: [
- "soong-ui-build-paths",
"soong-ui-logger",
"soong-ui-tracer",
"soong-shared",
@@ -46,7 +33,6 @@
"finder.go",
"kati.go",
"ninja.go",
- "path.go",
"proc_sync.go",
"signal.go",
"soong.go",
diff --git a/ui/build/build.go b/ui/build/build.go
index 66dbf03..78eb6a3 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -140,8 +140,6 @@
ensureEmptyDirectoriesExist(ctx, config.TempDir())
- SetupPath(ctx, config)
-
if what&BuildProductConfig != 0 {
// Run make for product config
runMakeProductConfig(ctx, config)
diff --git a/ui/build/config.go b/ui/build/config.go
index 6f2d24a..5622dff 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -51,8 +51,6 @@
targetDeviceDir string
brokenDupRules bool
-
- pathReplaced bool
}
const srcDirFileCheck = "build/soong/root.bp"
diff --git a/ui/build/path.go b/ui/build/path.go
deleted file mode 100644
index 52658ef..0000000
--- a/ui/build/path.go
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright 2018 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package build
-
-import (
- "fmt"
- "io/ioutil"
- "os"
- "path/filepath"
- "strings"
-
- "github.com/google/blueprint/microfactory"
-
- "android/soong/ui/build/paths"
-)
-
-func parsePathDir(dir string) []string {
- f, err := os.Open(dir)
- if err != nil {
- return nil
- }
- defer f.Close()
-
- if s, err := f.Stat(); err != nil || !s.IsDir() {
- return nil
- }
-
- infos, err := f.Readdir(-1)
- if err != nil {
- return nil
- }
-
- ret := make([]string, 0, len(infos))
- for _, info := range infos {
- if m := info.Mode(); !m.IsDir() && m&0111 != 0 {
- ret = append(ret, info.Name())
- }
- }
- return ret
-}
-
-func SetupPath(ctx Context, config Config) {
- if config.pathReplaced {
- return
- }
-
- ctx.BeginTrace("path")
- defer ctx.EndTrace()
-
- origPath, _ := config.Environment().Get("PATH")
- myPath := filepath.Join(config.OutDir(), ".path")
- interposer := myPath + "_interposer"
-
- var cfg microfactory.Config
- cfg.Map("android/soong", "build/soong")
- cfg.TrimPath, _ = filepath.Abs(".")
- if _, err := microfactory.Build(&cfg, interposer, "android/soong/cmd/path_interposer"); err != nil {
- ctx.Fatalln("Failed to build path interposer:", err)
- }
-
- if err := ioutil.WriteFile(interposer+"_origpath", []byte(origPath), 0777); err != nil {
- ctx.Fatalln("Failed to write original path:", err)
- }
-
- entries, err := paths.LogListener(ctx.Context, interposer+"_log")
- if err != nil {
- ctx.Fatalln("Failed to listen for path logs:", err)
- }
-
- go func() {
- for log := range entries {
- curPid := os.Getpid()
- for i, proc := range log.Parents {
- if proc.Pid == curPid {
- log.Parents = log.Parents[i:]
- break
- }
- }
- procPrints := []string{
- "See https://android.googlesource.com/platform/build/+/master/Changes.md#PATH_Tools for more information.",
- }
- if len(log.Parents) > 0 {
- procPrints = append(procPrints, "Process tree:")
- for i, proc := range log.Parents {
- procPrints = append(procPrints, fmt.Sprintf("%s→ %s", strings.Repeat(" ", i), proc.Command))
- }
- }
-
- config := paths.GetConfig(log.Basename)
- if config.Error {
- ctx.Printf("Disallowed PATH tool %q used: %#v", log.Basename, log.Args)
- for _, line := range procPrints {
- ctx.Println(line)
- }
- } else {
- ctx.Verbosef("Unknown PATH tool %q used: %#v", log.Basename, log.Args)
- for _, line := range procPrints {
- ctx.Verboseln(line)
- }
- }
- }
- }()
-
- ensureEmptyDirectoriesExist(ctx, myPath)
-
- var execs []string
- for _, pathEntry := range filepath.SplitList(origPath) {
- if pathEntry == "" {
- // Ignore the current directory
- continue
- }
- // TODO(dwillemsen): remove path entries under TOP? or anything
- // that looks like an android source dir? They won't exist on
- // the build servers, since they're added by envsetup.sh.
- // (Except for the JDK, which is configured in ui/build/config.go)
-
- execs = append(execs, parsePathDir(pathEntry)...)
- }
-
- allowAllSymlinks := config.Environment().IsEnvTrue("TEMPORARY_DISABLE_PATH_RESTRICTIONS")
- for _, name := range execs {
- if !paths.GetConfig(name).Symlink && !allowAllSymlinks {
- continue
- }
-
- err := os.Symlink("../.path_interposer", filepath.Join(myPath, name))
- // Intentionally ignore existing files -- that means that we
- // just created it, and the first one should win.
- if err != nil && !os.IsExist(err) {
- ctx.Fatalln("Failed to create symlink:", err)
- }
- }
-
- myPath, _ = filepath.Abs(myPath)
- config.Environment().Set("PATH", myPath)
- config.pathReplaced = true
-}
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
deleted file mode 100644
index ed44ced..0000000
--- a/ui/build/paths/config.go
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2018 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package paths
-
-type PathConfig struct {
- // Whether to create the symlink in the new PATH for this tool.
- Symlink bool
-
- // Whether to log about usages of this tool to the soong.log
- Log bool
-
- // Whether to exit with an error instead of invoking the underlying tool.
- Error bool
-}
-
-var Allowed = PathConfig{
- Symlink: true,
- Log: false,
- Error: false,
-}
-
-var Forbidden = PathConfig{
- Symlink: false,
- Log: true,
- Error: true,
-}
-
-// The configuration used if the tool is not listed in the config below.
-// Currently this will create the symlink, but log a warning. In the future,
-// I expect this to move closer to Forbidden.
-var Missing = PathConfig{
- Symlink: true,
- Log: true,
- Error: false,
-}
-
-func GetConfig(name string) PathConfig {
- if config, ok := Configuration[name]; ok {
- return config
- }
- return Missing
-}
-
-var Configuration = map[string]PathConfig{
- "awk": Allowed,
- "basename": Allowed,
- "bash": Allowed,
- "bzip2": Allowed,
- "cat": Allowed,
- "chmod": Allowed,
- "cmp": Allowed,
- "comm": Allowed,
- "cp": Allowed,
- "cut": Allowed,
- "date": Allowed,
- "dd": Allowed,
- "diff": Allowed,
- "dirname": Allowed,
- "echo": Allowed,
- "egrep": Allowed,
- "env": Allowed,
- "expr": Allowed,
- "find": Allowed,
- "getconf": Allowed,
- "getopt": Allowed,
- "git": Allowed,
- "grep": Allowed,
- "gzip": Allowed,
- "head": Allowed,
- "hexdump": Allowed,
- "hostname": Allowed,
- "jar": Allowed,
- "java": Allowed,
- "javap": Allowed,
- "ln": Allowed,
- "ls": Allowed,
- "m4": Allowed,
- "make": Allowed,
- "md5sum": Allowed,
- "mkdir": Allowed,
- "mktemp": Allowed,
- "mv": Allowed,
- "openssl": Allowed,
- "patch": Allowed,
- "perl": Allowed,
- "pstree": Allowed,
- "python": Allowed,
- "python2.7": Allowed,
- "python3": Allowed,
- "readlink": Allowed,
- "realpath": Allowed,
- "rm": Allowed,
- "rsync": Allowed,
- "runalarm": Allowed,
- "sed": Allowed,
- "setsid": Allowed,
- "sh": Allowed,
- "sha256sum": Allowed,
- "sha512sum": Allowed,
- "sort": Allowed,
- "stat": Allowed,
- "sum": Allowed,
- "tar": Allowed,
- "tail": Allowed,
- "touch": Allowed,
- "tr": Allowed,
- "true": Allowed,
- "uname": Allowed,
- "uniq": Allowed,
- "unzip": Allowed,
- "wc": Allowed,
- "which": Allowed,
- "whoami": Allowed,
- "xargs": Allowed,
- "xmllint": Allowed,
- "xz": Allowed,
- "zip": Allowed,
- "zipinfo": Allowed,
-
- // Host toolchain is removed. In-tree toolchain should be used instead.
- // GCC also can't find cc1 with this implementation.
- "ar": Forbidden,
- "as": Forbidden,
- "cc": Forbidden,
- "clang": Forbidden,
- "clang++": Forbidden,
- "gcc": Forbidden,
- "g++": Forbidden,
- "ld": Forbidden,
- "ld.bfd": Forbidden,
- "ld.gold": Forbidden,
- "pkg-config": Forbidden,
-
- // We've got prebuilts of these
- //"dtc": Forbidden,
- //"lz4": Forbidden,
- //"lz4c": Forbidden,
-}
diff --git a/ui/build/paths/logs.go b/ui/build/paths/logs.go
deleted file mode 100644
index a44994c..0000000
--- a/ui/build/paths/logs.go
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2018 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package paths
-
-import (
- "context"
- "encoding/gob"
- "net"
- "os"
- "time"
-)
-
-type LogProcess struct {
- Pid int
- Command string
-}
-
-type LogEntry struct {
- Basename string
- Args []string
- Parents []LogProcess
-}
-
-const timeoutDuration = time.Duration(250) * time.Millisecond
-
-func SendLog(logSocket string, entry *LogEntry, done chan interface{}) {
- defer close(done)
-
- dialer := &net.Dialer{}
- conn, err := dialer.Dial("unix", logSocket)
- if err != nil {
- return
- }
- defer conn.Close()
-
- if err := conn.SetDeadline(dialer.Deadline); err != nil {
- return
- }
-
- enc := gob.NewEncoder(conn)
- enc.Encode(entry)
-}
-
-func LogListener(ctx context.Context, logSocket string) (chan *LogEntry, error) {
- ret := make(chan *LogEntry, 5)
-
- if err := os.Remove(logSocket); err != nil && !os.IsNotExist(err) {
- return nil, err
- }
-
- ln, err := net.Listen("unix", logSocket)
- if err != nil {
- return nil, err
- }
-
- go func() {
- for {
- select {
- case <-ctx.Done():
- ln.Close()
- }
- }
- }()
-
- go func() {
- defer close(ret)
-
- for {
- conn, err := ln.Accept()
- if err != nil {
- ln.Close()
- break
- }
- conn.SetDeadline(time.Now().Add(timeoutDuration))
-
- go func() {
- defer conn.Close()
-
- dec := gob.NewDecoder(conn)
- entry := &LogEntry{}
- if err := dec.Decode(entry); err != nil {
- return
- }
- ret <- entry
- }()
- }
- }()
- return ret, nil
-}
diff --git a/ui/build/paths/logs_test.go b/ui/build/paths/logs_test.go
deleted file mode 100644
index 1ec040d..0000000
--- a/ui/build/paths/logs_test.go
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2018 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package paths
-
-import (
- "context"
- "io/ioutil"
- "net"
- "os"
- "path/filepath"
- "reflect"
- "strings"
- "testing"
- "time"
-)
-
-func TestSendLog(t *testing.T) {
- d, err := ioutil.TempDir("", "log_socket")
- if err != nil {
- t.Fatal(err)
- }
- defer os.RemoveAll(d)
- f := filepath.Join(d, "sock")
-
- ctx, _ := context.WithTimeout(context.Background(), 2*timeoutDuration)
-
- recv, err := LogListener(ctx, f)
- if err != nil {
- t.Fatal(err)
- }
-
- go func() {
- for i := 0; i < 10; i++ {
- SendLog(f, &LogEntry{
- Basename: "test",
- Args: []string{"foo", "bar"},
- }, make(chan interface{}))
- }
- }()
-
- count := 0
- for {
- select {
- case entry := <-recv:
- ref := LogEntry{
- Basename: "test",
- Args: []string{"foo", "bar"},
- }
- if !reflect.DeepEqual(ref, *entry) {
- t.Fatalf("Bad log entry: %v", entry)
- }
- count++
-
- if count == 10 {
- return
- }
- case <-ctx.Done():
- t.Error("Hit timeout before receiving all logs")
- }
- }
-}
-
-func TestSendLogError(t *testing.T) {
- d, err := ioutil.TempDir("", "log_socket")
- if err != nil {
- t.Fatal(err)
- }
- defer os.RemoveAll(d)
-
- t.Run("Missing file", func(t *testing.T) {
- start := time.Now()
- SendLog(filepath.Join(d, "missing"), &LogEntry{}, make(chan interface{}))
- elapsed := time.Since(start)
- if elapsed > timeoutDuration {
- t.Errorf("Should have been << timeout (%s), but was %s", timeoutDuration, elapsed)
- }
- })
-
- t.Run("Regular file", func(t *testing.T) {
- f := filepath.Join(d, "file")
- if fp, err := os.Create(f); err == nil {
- fp.Close()
- } else {
- t.Fatal(err)
- }
-
- start := time.Now()
- SendLog(f, &LogEntry{}, make(chan interface{}))
- elapsed := time.Since(start)
- if elapsed > timeoutDuration {
- t.Errorf("Should have been << timeout (%s), but was %s", timeoutDuration, elapsed)
- }
- })
-
- t.Run("Reader not reading", func(t *testing.T) {
- f := filepath.Join(d, "sock1")
-
- ln, err := net.Listen("unix", f)
- if err != nil {
- t.Fatal(err)
- }
- defer ln.Close()
-
- done := make(chan bool, 1)
- go func() {
- for i := 0; i < 1000; i++ {
- SendLog(f, &LogEntry{
- // Ensure a relatively large payload
- Basename: strings.Repeat(" ", 100000),
- }, make(chan interface{}))
- }
- done <- true
- }()
-
- select {
- case <-done:
- break
- case <-time.After(10 * timeoutDuration):
- t.Error("Should have finished")
- }
- })
-}