From b4797ae1ade3eaabd58e1f6e56c96e902238a7e2 Mon Sep 17 00:00:00 2001 From: Zhongpeng Lin <zplin@uber.com> Date: Wed, 11 Oct 2023 15:47:55 -0700 Subject: [PATCH 1/8] Embed Python scripts revert changes in pythonconfig remove runtime deps --- gazelle/def.bzl | 2 -- gazelle/python/BUILD.bazel | 22 +++------------------- gazelle/python/parse.py | 0 gazelle/python/parser.go | 24 +++++++++++------------- gazelle/python/std_modules.go | 21 +++++---------------- 5 files changed, 19 insertions(+), 50 deletions(-) mode change 100644 => 100755 gazelle/python/parse.py diff --git a/gazelle/def.bzl b/gazelle/def.bzl index 80b11576e6..084b5a4a05 100644 --- a/gazelle/def.bzl +++ b/gazelle/def.bzl @@ -16,6 +16,4 @@ """ GAZELLE_PYTHON_RUNTIME_DEPS = [ - "@rules_python_gazelle_plugin//python:parse", - "@rules_python_gazelle_plugin//python:std_modules", ] diff --git a/gazelle/python/BUILD.bazel b/gazelle/python/BUILD.bazel index 4cb755de25..15e6bc1aea 100644 --- a/gazelle/python/BUILD.bazel +++ b/gazelle/python/BUILD.bazel @@ -1,6 +1,5 @@ load("@bazel_gazelle//:def.bzl", "gazelle_binary") load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") -load("@rules_python//python:defs.bzl", "py_binary") go_library( name = "python", @@ -16,9 +15,9 @@ go_library( "std_modules.go", "target.go", ], - data = [ - ":parse", - ":std_modules", + embedsrcs = [ + "parse.py", + "std_modules.py", ], importpath = "github.com/bazelbuild/rules_python/gazelle/python", visibility = ["//visibility:public"], @@ -36,29 +35,14 @@ go_library( "@com_github_emirpasic_gods//lists/singlylinkedlist", "@com_github_emirpasic_gods//sets/treeset", "@com_github_emirpasic_gods//utils", - "@io_bazel_rules_go//go/runfiles", ], ) -py_binary( - name = "parse", - srcs = ["parse.py"], - visibility = ["//visibility:public"], -) - -py_binary( - name = "std_modules", - srcs = ["std_modules.py"], - visibility = ["//visibility:public"], -) - go_test( name = "python_test", srcs = ["python_test.go"], data = [ ":gazelle_binary", - ":parse", - ":std_modules", ] + glob(["testdata/**"]), deps = [ "@bazel_gazelle//testtools:go_default_library", diff --git a/gazelle/python/parse.py b/gazelle/python/parse.py old mode 100644 new mode 100755 diff --git a/gazelle/python/parser.go b/gazelle/python/parser.go index 60a3c24269..86275ebea7 100644 --- a/gazelle/python/parser.go +++ b/gazelle/python/parser.go @@ -17,16 +17,17 @@ package python import ( "bufio" "context" + _ "embed" "encoding/json" "fmt" "io" "log" "os" "os/exec" + "path" "strings" "sync" - "github.com/bazelbuild/rules_go/go/runfiles" "github.com/emirpasic/gods/sets/treeset" godsutils "github.com/emirpasic/gods/utils" ) @@ -35,23 +36,19 @@ var ( parserStdin io.WriteCloser parserStdout io.Reader parserMutex sync.Mutex + //go:embed parse.py + parser []byte + parserPath = path.Join(os.TempDir(), "parse.py") ) func startParserProcess(ctx context.Context) { - rfiles, err := runfiles.New() - if err != nil { - log.Printf("failed to create a runfiles object: %v\n", err) + // "python -c" doesn't like parse.py for some reason, possibly due to the + // thread pool. So we need to write the code to a tmp file and execute it. + if err := os.WriteFile(parserPath, parser, 0644); err != nil { + log.Printf("cannot write %q: %s", parserPath, err.Error()) os.Exit(1) } - - parseScriptRunfile, err := rfiles.Rlocation("rules_python_gazelle_plugin/python/parse") - if err != nil { - log.Printf("failed to initialize parser: %v\n", err) - os.Exit(1) - } - - cmd := exec.CommandContext(ctx, parseScriptRunfile) - cmd.Env = append(os.Environ(), rfiles.Env()...) + cmd := exec.CommandContext(ctx, "python3", parserPath) cmd.Stderr = os.Stderr @@ -86,6 +83,7 @@ func shutdownParserProcess() { if err := parserStdin.Close(); err != nil { fmt.Fprintf(os.Stderr, "error closing parser: %v", err) } + //os.Remove(parserPath) } // python3Parser implements a parser for Python files that extracts the modules diff --git a/gazelle/python/std_modules.go b/gazelle/python/std_modules.go index a87deec366..d4f755717f 100644 --- a/gazelle/python/std_modules.go +++ b/gazelle/python/std_modules.go @@ -17,6 +17,7 @@ package python import ( "bufio" "context" + _ "embed" "fmt" "io" "log" @@ -25,8 +26,6 @@ import ( "strconv" "strings" "sync" - - "github.com/bazelbuild/rules_go/go/runfiles" ) var ( @@ -34,28 +33,18 @@ var ( stdModulesStdout io.Reader stdModulesMutex sync.Mutex stdModulesSeen map[string]struct{} + //go:embed std_modules.py + stdModue []byte ) func startStdModuleProcess(ctx context.Context) { stdModulesSeen = make(map[string]struct{}) - rfiles, err := runfiles.New() - if err != nil { - log.Printf("failed to create a runfiles object: %v\n", err) - os.Exit(1) - } - - stdModulesScriptRunfile, err := rfiles.Rlocation("rules_python_gazelle_plugin/python/std_modules") - if err != nil { - log.Printf("failed to initialize std_modules: %v\n", err) - os.Exit(1) - } - - cmd := exec.CommandContext(ctx, stdModulesScriptRunfile) + cmd := exec.CommandContext(ctx, "python3", "-c", string(stdModue)) cmd.Stderr = os.Stderr // All userland site-packages should be ignored. - cmd.Env = append([]string{"PYTHONNOUSERSITE=1"}, rfiles.Env()...) + cmd.Env = []string{"PYTHONNOUSERSITE=1"} stdin, err := cmd.StdinPipe() if err != nil { From e95db20567c5daf27460d2ad9d641a7807956c3d Mon Sep 17 00:00:00 2001 From: Zhongpeng Lin <zplin@uber.com> Date: Thu, 12 Oct 2023 14:34:52 -0700 Subject: [PATCH 2/8] embedding python zip files --- gazelle/def.bzl | 2 ++ gazelle/python/BUILD.bazel | 28 ++++++++++++++++++++++++---- gazelle/python/parser.go | 6 ++---- gazelle/python/std_modules.go | 12 +++++++++--- 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/gazelle/def.bzl b/gazelle/def.bzl index 084b5a4a05..80b11576e6 100644 --- a/gazelle/def.bzl +++ b/gazelle/def.bzl @@ -16,4 +16,6 @@ """ GAZELLE_PYTHON_RUNTIME_DEPS = [ + "@rules_python_gazelle_plugin//python:parse", + "@rules_python_gazelle_plugin//python:std_modules", ] diff --git a/gazelle/python/BUILD.bazel b/gazelle/python/BUILD.bazel index 15e6bc1aea..eba7cb0380 100644 --- a/gazelle/python/BUILD.bazel +++ b/gazelle/python/BUILD.bazel @@ -1,5 +1,6 @@ load("@bazel_gazelle//:def.bzl", "gazelle_binary") load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") +load("@rules_python//python:defs.bzl", "py_binary") go_library( name = "python", @@ -15,10 +16,7 @@ go_library( "std_modules.go", "target.go", ], - embedsrcs = [ - "parse.py", - "std_modules.py", - ], + embedsrcs = [":zip_files"], importpath = "github.com/bazelbuild/rules_python/gazelle/python", visibility = ["//visibility:public"], deps = [ @@ -35,7 +33,29 @@ go_library( "@com_github_emirpasic_gods//lists/singlylinkedlist", "@com_github_emirpasic_gods//sets/treeset", "@com_github_emirpasic_gods//utils", + "@io_bazel_rules_go//go/runfiles", + ], +) + +py_binary( + name = "parse", + srcs = ["parse.py"], + visibility = ["//visibility:public"], +) + +py_binary( + name = "std_modules", + srcs = ["std_modules.py"], + visibility = ["//visibility:public"], +) + +filegroup( + name = "zip_files", + srcs = [ + ":parse", + ":std_modules" ], + output_group = "python_zip_file", ) go_test( diff --git a/gazelle/python/parser.go b/gazelle/python/parser.go index 86275ebea7..c4fe9b40fe 100644 --- a/gazelle/python/parser.go +++ b/gazelle/python/parser.go @@ -36,14 +36,12 @@ var ( parserStdin io.WriteCloser parserStdout io.Reader parserMutex sync.Mutex - //go:embed parse.py + //go:embed parse.zip parser []byte - parserPath = path.Join(os.TempDir(), "parse.py") + parserPath = path.Join(os.TempDir(), "parse.zip") ) func startParserProcess(ctx context.Context) { - // "python -c" doesn't like parse.py for some reason, possibly due to the - // thread pool. So we need to write the code to a tmp file and execute it. if err := os.WriteFile(parserPath, parser, 0644); err != nil { log.Printf("cannot write %q: %s", parserPath, err.Error()) os.Exit(1) diff --git a/gazelle/python/std_modules.go b/gazelle/python/std_modules.go index d4f755717f..fc48b14f35 100644 --- a/gazelle/python/std_modules.go +++ b/gazelle/python/std_modules.go @@ -23,6 +23,7 @@ import ( "log" "os" "os/exec" + "path" "strconv" "strings" "sync" @@ -33,14 +34,19 @@ var ( stdModulesStdout io.Reader stdModulesMutex sync.Mutex stdModulesSeen map[string]struct{} - //go:embed std_modules.py - stdModue []byte + //go:embed std_modules.zip + stdModule []byte + stdModulePath = path.Join(os.TempDir(), "std_modules.zip") ) func startStdModuleProcess(ctx context.Context) { stdModulesSeen = make(map[string]struct{}) - cmd := exec.CommandContext(ctx, "python3", "-c", string(stdModue)) + if err := os.WriteFile(stdModulePath, stdModule, 0644); err != nil { + log.Printf("cannot write %q: %s", stdModulePath, err.Error()) + os.Exit(1) + } + cmd := exec.CommandContext(ctx, "python3", stdModulePath) cmd.Stderr = os.Stderr // All userland site-packages should be ignored. From 982d730647aa9730653456f4c41f42792d375405 Mon Sep 17 00:00:00 2001 From: Zhongpeng Lin <zplin@uber.com> Date: Fri, 13 Oct 2023 21:00:32 -0700 Subject: [PATCH 3/8] embed pyz file --- gazelle/python/BUILD.bazel | 25 ++++++++++--------------- gazelle/python/__main__.py | 31 +++++++++++++++++++++++++++++++ gazelle/python/lifecycle.go | 18 ++++++++++++++++++ gazelle/python/parser.go | 11 +---------- gazelle/python/python_test.go | 13 ++++--------- gazelle/python/std_modules.go | 10 +--------- 6 files changed, 65 insertions(+), 43 deletions(-) create mode 100644 gazelle/python/__main__.py diff --git a/gazelle/python/BUILD.bazel b/gazelle/python/BUILD.bazel index eba7cb0380..ca3944e658 100644 --- a/gazelle/python/BUILD.bazel +++ b/gazelle/python/BUILD.bazel @@ -16,7 +16,7 @@ go_library( "std_modules.go", "target.go", ], - embedsrcs = [":zip_files"], + embedsrcs = [":helper.zip"], importpath = "github.com/bazelbuild/rules_python/gazelle/python", visibility = ["//visibility:public"], deps = [ @@ -33,28 +33,23 @@ go_library( "@com_github_emirpasic_gods//lists/singlylinkedlist", "@com_github_emirpasic_gods//sets/treeset", "@com_github_emirpasic_gods//utils", - "@io_bazel_rules_go//go/runfiles", ], ) py_binary( - name = "parse", - srcs = ["parse.py"], - visibility = ["//visibility:public"], -) - -py_binary( - name = "std_modules", - srcs = ["std_modules.py"], + name = "helper", + srcs = [ + "__main__.py", + "parse.py", + "std_modules.py", + ], + main = "__main__.py", visibility = ["//visibility:public"], ) filegroup( - name = "zip_files", - srcs = [ - ":parse", - ":std_modules" - ], + name = "helper.zip", + srcs = [":helper"], output_group = "python_zip_file", ) diff --git a/gazelle/python/__main__.py b/gazelle/python/__main__.py new file mode 100644 index 0000000000..2f5a4a16ca --- /dev/null +++ b/gazelle/python/__main__.py @@ -0,0 +1,31 @@ +# Copyright 2023 The Bazel Authors. 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. + +# parse.py is a long-living program that communicates over STDIN and STDOUT. +# STDIN receives parse requests, one per line. It outputs the parsed modules and +# comments from all the files from each request. + +import parse +import std_modules +import sys + +if __name__ == "__main__": + if len(sys.argv) < 2: + sys.exit("Please provide subcommand, either print or std_modules") + if sys.argv[1] == "parse": + sys.exit(parse.main(sys.stdin, sys.stdout)) + elif sys.argv[1] == "std_modules": + sys.exit(std_modules.main(sys.stdin, sys.stdout)) + else: + sys.exit("Unknown subcommand: " + sys.argv[1]) diff --git a/gazelle/python/lifecycle.go b/gazelle/python/lifecycle.go index 592b322a3c..910763c8dc 100644 --- a/gazelle/python/lifecycle.go +++ b/gazelle/python/lifecycle.go @@ -16,7 +16,16 @@ package python import ( "context" + _ "embed" "github.com/bazelbuild/bazel-gazelle/language" + "log" + "os" +) + +var ( + //go:embed helper.zip + pythonZip []byte + pyzPath string ) type LifeCycleManager struct { @@ -24,6 +33,14 @@ type LifeCycleManager struct { } func (l *LifeCycleManager) Before(ctx context.Context) { + pyzFile, err := os.CreateTemp("", "python_zip_") + if err != nil { + log.Fatalf("failed to write parser zip: %v", err) + } + pyzPath = pyzFile.Name() + if _, err := pyzFile.Write(pythonZip); err != nil { + log.Fatalf("cannot write %q: %v", pyzPath, err) + } startParserProcess(ctx) startStdModuleProcess(ctx) } @@ -34,4 +51,5 @@ func (l *LifeCycleManager) DoneGeneratingRules() { func (l *LifeCycleManager) AfterResolvingDeps(ctx context.Context) { shutdownStdModuleProcess() + os.Remove(pyzPath) } diff --git a/gazelle/python/parser.go b/gazelle/python/parser.go index c4fe9b40fe..91c5ea928a 100644 --- a/gazelle/python/parser.go +++ b/gazelle/python/parser.go @@ -24,7 +24,6 @@ import ( "log" "os" "os/exec" - "path" "strings" "sync" @@ -36,17 +35,10 @@ var ( parserStdin io.WriteCloser parserStdout io.Reader parserMutex sync.Mutex - //go:embed parse.zip - parser []byte - parserPath = path.Join(os.TempDir(), "parse.zip") ) func startParserProcess(ctx context.Context) { - if err := os.WriteFile(parserPath, parser, 0644); err != nil { - log.Printf("cannot write %q: %s", parserPath, err.Error()) - os.Exit(1) - } - cmd := exec.CommandContext(ctx, "python3", parserPath) + cmd := exec.CommandContext(ctx, "python3", pyzPath, "parse") cmd.Stderr = os.Stderr @@ -81,7 +73,6 @@ func shutdownParserProcess() { if err := parserStdin.Close(); err != nil { fmt.Fprintf(os.Stderr, "error closing parser: %v", err) } - //os.Remove(parserPath) } // python3Parser implements a parser for Python files that extracts the modules diff --git a/gazelle/python/python_test.go b/gazelle/python/python_test.go index 79450ad584..23225c15a7 100644 --- a/gazelle/python/python_test.go +++ b/gazelle/python/python_test.go @@ -21,18 +21,15 @@ package python_test import ( "bytes" - "context" "errors" + "github.com/bazelbuild/bazel-gazelle/testtools" + "github.com/bazelbuild/rules_go/go/tools/bazel" + "github.com/ghodss/yaml" "os" "os/exec" "path/filepath" "strings" "testing" - "time" - - "github.com/bazelbuild/bazel-gazelle/testtools" - "github.com/bazelbuild/rules_go/go/tools/bazel" - "github.com/ghodss/yaml" ) const ( @@ -152,9 +149,7 @@ func testPath(t *testing.T, name string, files []bazel.RunfileEntry) { args := []string{"-build_file_name=BUILD,BUILD.bazel"} - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) - t.Cleanup(cancel) - cmd := exec.CommandContext(ctx, gazellePath, args...) + cmd := exec.Command(gazellePath, args...) var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr diff --git a/gazelle/python/std_modules.go b/gazelle/python/std_modules.go index fc48b14f35..5aa2f62222 100644 --- a/gazelle/python/std_modules.go +++ b/gazelle/python/std_modules.go @@ -23,7 +23,6 @@ import ( "log" "os" "os/exec" - "path" "strconv" "strings" "sync" @@ -34,19 +33,12 @@ var ( stdModulesStdout io.Reader stdModulesMutex sync.Mutex stdModulesSeen map[string]struct{} - //go:embed std_modules.zip - stdModule []byte - stdModulePath = path.Join(os.TempDir(), "std_modules.zip") ) func startStdModuleProcess(ctx context.Context) { stdModulesSeen = make(map[string]struct{}) - if err := os.WriteFile(stdModulePath, stdModule, 0644); err != nil { - log.Printf("cannot write %q: %s", stdModulePath, err.Error()) - os.Exit(1) - } - cmd := exec.CommandContext(ctx, "python3", stdModulePath) + cmd := exec.CommandContext(ctx, "python3", pyzPath, "std_modules") cmd.Stderr = os.Stderr // All userland site-packages should be ignored. From 007c1237c3d8898d0424d16b2e302afc26296564 Mon Sep 17 00:00:00 2001 From: Zhongpeng Lin <zplin@uber.com> Date: Fri, 13 Oct 2023 21:14:41 -0700 Subject: [PATCH 4/8] no runtime deps anymore --- gazelle/def.bzl | 2 -- 1 file changed, 2 deletions(-) diff --git a/gazelle/def.bzl b/gazelle/def.bzl index 80b11576e6..084b5a4a05 100644 --- a/gazelle/def.bzl +++ b/gazelle/def.bzl @@ -16,6 +16,4 @@ """ GAZELLE_PYTHON_RUNTIME_DEPS = [ - "@rules_python_gazelle_plugin//python:parse", - "@rules_python_gazelle_plugin//python:std_modules", ] From db35bdbf3dccbf701f76a8187e3e66b456f0d8d2 Mon Sep 17 00:00:00 2001 From: Zhongpeng Lin <zplin@uber.com> Date: Sun, 15 Oct 2023 10:34:09 -0700 Subject: [PATCH 5/8] comments change log change log --- CHANGELOG.md | 1 + examples/build_file_generation/BUILD.bazel | 2 -- .../bzlmod_build_file_generation/BUILD.bazel | 2 -- gazelle/README.md | 2 -- gazelle/python/BUILD.bazel | 2 ++ gazelle/python/lifecycle.go | 28 ++++++++++++------- gazelle/python/parse.py | 0 gazelle/python/parser.go | 5 ++-- gazelle/python/python_test.go | 19 ++++++++++--- gazelle/python/std_modules.go | 5 ++-- 10 files changed, 42 insertions(+), 24 deletions(-) mode change 100755 => 100644 gazelle/python/parse.py diff --git a/CHANGELOG.md b/CHANGELOG.md index be69f5e8d0..1629e1e708 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ A brief description of the categories of changes: * Make `//python/pip_install:pip_repository_bzl` `bzl_library` target internal as all of the publicly available symbols (etc. `package_annotation`) are re-exported via `//python:pip_bzl` `bzl_library`. +* Gazelle Python extension no longer have runtime dependencies. ### Fixed diff --git a/examples/build_file_generation/BUILD.bazel b/examples/build_file_generation/BUILD.bazel index 79f62519df..a03af54a1a 100644 --- a/examples/build_file_generation/BUILD.bazel +++ b/examples/build_file_generation/BUILD.bazel @@ -6,7 +6,6 @@ load("@bazel_gazelle//:def.bzl", "gazelle") load("@pip//:requirements.bzl", "all_whl_requirements") load("@rules_python//python:defs.bzl", "py_binary", "py_library", "py_test") load("@rules_python//python:pip.bzl", "compile_pip_requirements") -load("@rules_python_gazelle_plugin//:def.bzl", "GAZELLE_PYTHON_RUNTIME_DEPS") load("@rules_python_gazelle_plugin//manifest:defs.bzl", "gazelle_python_manifest") load("@rules_python_gazelle_plugin//modules_mapping:def.bzl", "modules_mapping") @@ -56,7 +55,6 @@ gazelle_python_manifest( # See https://github.com/bazelbuild/bazel-gazelle/blob/master/extend.rst#example gazelle( name = "gazelle", - data = GAZELLE_PYTHON_RUNTIME_DEPS, gazelle = "@rules_python_gazelle_plugin//python:gazelle_binary", ) diff --git a/examples/bzlmod_build_file_generation/BUILD.bazel b/examples/bzlmod_build_file_generation/BUILD.bazel index 9b2e5bdce4..67288d6f43 100644 --- a/examples/bzlmod_build_file_generation/BUILD.bazel +++ b/examples/bzlmod_build_file_generation/BUILD.bazel @@ -9,7 +9,6 @@ load("@bazel_gazelle//:def.bzl", "gazelle") load("@pip//:requirements.bzl", "all_whl_requirements") load("@rules_python//python:defs.bzl", "py_binary", "py_library", "py_test") load("@rules_python//python:pip.bzl", "compile_pip_requirements") -load("@rules_python_gazelle_plugin//:def.bzl", "GAZELLE_PYTHON_RUNTIME_DEPS") load("@rules_python_gazelle_plugin//manifest:defs.bzl", "gazelle_python_manifest") load("@rules_python_gazelle_plugin//modules_mapping:def.bzl", "modules_mapping") @@ -70,7 +69,6 @@ gazelle_python_manifest( # See: https://github.com/bazelbuild/bazel-gazelle#fix-and-update gazelle( name = "gazelle", - data = GAZELLE_PYTHON_RUNTIME_DEPS, gazelle = "@rules_python_gazelle_plugin//python:gazelle_binary", ) diff --git a/gazelle/README.md b/gazelle/README.md index b8be32ff44..fe275e97c9 100644 --- a/gazelle/README.md +++ b/gazelle/README.md @@ -125,7 +125,6 @@ with the rules_python extension included. This typically goes in your root ```starlark load("@bazel_gazelle//:def.bzl", "gazelle") -load("@rules_python_gazelle_plugin//:def.bzl", "GAZELLE_PYTHON_RUNTIME_DEPS") # Our gazelle target points to the python gazelle binary. # This is the simple case where we only need one language supported. @@ -134,7 +133,6 @@ load("@rules_python_gazelle_plugin//:def.bzl", "GAZELLE_PYTHON_RUNTIME_DEPS") # See https://github.com/bazelbuild/bazel-gazelle/blob/master/extend.rst#example gazelle( name = "gazelle", - data = GAZELLE_PYTHON_RUNTIME_DEPS, gazelle = "@rules_python_gazelle_plugin//python:gazelle_binary", ) ``` diff --git a/gazelle/python/BUILD.bazel b/gazelle/python/BUILD.bazel index ca3944e658..507d69e9d7 100644 --- a/gazelle/python/BUILD.bazel +++ b/gazelle/python/BUILD.bazel @@ -58,10 +58,12 @@ go_test( srcs = ["python_test.go"], data = [ ":gazelle_binary", + ":helper", ] + glob(["testdata/**"]), deps = [ "@bazel_gazelle//testtools:go_default_library", "@com_github_ghodss_yaml//:yaml", + "@io_bazel_rules_go//go/runfiles:go_default_library", "@io_bazel_rules_go//go/tools/bazel:go_default_library", ], ) diff --git a/gazelle/python/lifecycle.go b/gazelle/python/lifecycle.go index 910763c8dc..6d628e9137 100644 --- a/gazelle/python/lifecycle.go +++ b/gazelle/python/lifecycle.go @@ -24,22 +24,28 @@ import ( var ( //go:embed helper.zip - pythonZip []byte - pyzPath string + helperZip []byte + helperPath string ) type LifeCycleManager struct { language.BaseLifecycleManager + pyzFilePath string } func (l *LifeCycleManager) Before(ctx context.Context) { - pyzFile, err := os.CreateTemp("", "python_zip_") - if err != nil { - log.Fatalf("failed to write parser zip: %v", err) - } - pyzPath = pyzFile.Name() - if _, err := pyzFile.Write(pythonZip); err != nil { - log.Fatalf("cannot write %q: %v", pyzPath, err) + helperPath = os.Getenv("GAZELLE_PYTHON_HELPER") + if helperPath == "" { + pyzFile, err := os.CreateTemp("", "python_zip_") + if err != nil { + log.Fatalf("failed to write parser zip: %v", err) + } + defer pyzFile.Close() + helperPath = pyzFile.Name() + l.pyzFilePath = helperPath + if _, err := pyzFile.Write(helperZip); err != nil { + log.Fatalf("cannot write %q: %v", helperPath, err) + } } startParserProcess(ctx) startStdModuleProcess(ctx) @@ -51,5 +57,7 @@ func (l *LifeCycleManager) DoneGeneratingRules() { func (l *LifeCycleManager) AfterResolvingDeps(ctx context.Context) { shutdownStdModuleProcess() - os.Remove(pyzPath) + if l.pyzFilePath != "" { + os.Remove(l.pyzFilePath) + } } diff --git a/gazelle/python/parse.py b/gazelle/python/parse.py old mode 100755 new mode 100644 diff --git a/gazelle/python/parser.go b/gazelle/python/parser.go index 91c5ea928a..ad55e03a01 100644 --- a/gazelle/python/parser.go +++ b/gazelle/python/parser.go @@ -38,8 +38,9 @@ var ( ) func startParserProcess(ctx context.Context) { - cmd := exec.CommandContext(ctx, "python3", pyzPath, "parse") - + // due to #691, we need a system interpreter to boostrap, part of which is + // to locate the hermetic interpreter. + cmd := exec.CommandContext(ctx, "python3", helperPath, "parse") cmd.Stderr = os.Stderr stdin, err := cmd.StdinPipe() diff --git a/gazelle/python/python_test.go b/gazelle/python/python_test.go index 23225c15a7..74bd85bce6 100644 --- a/gazelle/python/python_test.go +++ b/gazelle/python/python_test.go @@ -21,15 +21,19 @@ package python_test import ( "bytes" + "context" "errors" - "github.com/bazelbuild/bazel-gazelle/testtools" - "github.com/bazelbuild/rules_go/go/tools/bazel" - "github.com/ghodss/yaml" "os" "os/exec" "path/filepath" "strings" "testing" + "time" + + "github.com/bazelbuild/bazel-gazelle/testtools" + "github.com/bazelbuild/rules_go/go/runfiles" + "github.com/bazelbuild/rules_go/go/tools/bazel" + "github.com/ghodss/yaml" ) const ( @@ -149,11 +153,18 @@ func testPath(t *testing.T, name string, files []bazel.RunfileEntry) { args := []string{"-build_file_name=BUILD,BUILD.bazel"} - cmd := exec.Command(gazellePath, args...) + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + t.Cleanup(cancel) + cmd := exec.CommandContext(ctx, gazellePath, args...) var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr cmd.Dir = workspaceRoot + helperScript, err := runfiles.Rlocation("rules_python_gazelle_plugin/python/helper") + if err != nil { + t.Fatalf("failed to initialize Python heler: %v", err) + } + cmd.Env = append(os.Environ(), "GAZELLE_PYTHON_HELPER="+helperScript) if err := cmd.Run(); err != nil { var e *exec.ExitError if !errors.As(err, &e) { diff --git a/gazelle/python/std_modules.go b/gazelle/python/std_modules.go index 5aa2f62222..dd59cd8832 100644 --- a/gazelle/python/std_modules.go +++ b/gazelle/python/std_modules.go @@ -38,8 +38,9 @@ var ( func startStdModuleProcess(ctx context.Context) { stdModulesSeen = make(map[string]struct{}) - cmd := exec.CommandContext(ctx, "python3", pyzPath, "std_modules") - + // due to #691, we need a system interpreter to boostrap, part of which is + // to locate the hermetic interpreter. + cmd := exec.CommandContext(ctx, "python3", helperPath, "std_modules") cmd.Stderr = os.Stderr // All userland site-packages should be ignored. cmd.Env = []string{"PYTHONNOUSERSITE=1"} From a81ddaf892789e9b8fd3603bdc81a2794470a329 Mon Sep 17 00:00:00 2001 From: Zhongpeng Lin <zplin@uber.com> Date: Mon, 16 Oct 2023 08:42:28 -0700 Subject: [PATCH 6/8] Update CHANGELOG.md Co-authored-by: Ignas Anikevicius <240938+aignas@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1629e1e708..7cd292d227 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,7 @@ A brief description of the categories of changes: * Make `//python/pip_install:pip_repository_bzl` `bzl_library` target internal as all of the publicly available symbols (etc. `package_annotation`) are re-exported via `//python:pip_bzl` `bzl_library`. -* Gazelle Python extension no longer have runtime dependencies. +* Gazelle Python extension no longer has runtime dependencies. Using `GAZELLE_PYTHON_RUNTIME_DEPS` from `@rules_python_gazelle_plugin//:def.bzl` is no longer necessary. ### Fixed From e444f682e398a240546ce2a768318bffe8a14d5b Mon Sep 17 00:00:00 2001 From: Zhongpeng Lin <zplin@uber.com> Date: Mon, 16 Oct 2023 09:19:27 -0700 Subject: [PATCH 7/8] document Python version --- gazelle/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gazelle/README.md b/gazelle/README.md index fe275e97c9..a57fa7393e 100644 --- a/gazelle/README.md +++ b/gazelle/README.md @@ -7,7 +7,7 @@ Gazelle may be run by Bazel using the gazelle rule, or it may be installed and r This directory contains a plugin for [Gazelle](https://github.com/bazelbuild/bazel-gazelle) -that generates BUILD files content for Python code. +that generates BUILD files content for Python code. When Gazelle is run as a command line tool with this plugin, it embeds with a Python interpreter, which is the one Bazel resolves to when it is building the plugin. The behavior of the plugin is different with different version of the interpreter. Distributors of Gazelle binaries need to build a Gazelle binary for each OS+CPU architecture+Python version combination they are targeting. The following instructions are for when you use [bzlmod](https://docs.bazel.build/versions/5.0.0/bzlmod.html). Please refer to older documentation that includes instructions on how to use Gazelle From 03e89f33b1bf2786e2722f5996c25ebec49c77bf Mon Sep 17 00:00:00 2001 From: Ignas Anikevicius <240938+aignas@users.noreply.github.com> Date: Tue, 17 Oct 2023 08:48:32 +0900 Subject: [PATCH 8/8] Update gazelle/README.md --- gazelle/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gazelle/README.md b/gazelle/README.md index a57fa7393e..c32f0d8258 100644 --- a/gazelle/README.md +++ b/gazelle/README.md @@ -7,7 +7,9 @@ Gazelle may be run by Bazel using the gazelle rule, or it may be installed and r This directory contains a plugin for [Gazelle](https://github.com/bazelbuild/bazel-gazelle) -that generates BUILD files content for Python code. When Gazelle is run as a command line tool with this plugin, it embeds with a Python interpreter, which is the one Bazel resolves to when it is building the plugin. The behavior of the plugin is different with different version of the interpreter. Distributors of Gazelle binaries need to build a Gazelle binary for each OS+CPU architecture+Python version combination they are targeting. +that generates BUILD files content for Python code. When Gazelle is run as a command line tool with this plugin, it embeds a Python interpreter resolved during the plugin build. +The behavior of the plugin is slightly different with different version of the interpreter as the Python `stdlib` changes with every minor version release. +Distributors of Gazelle binaries should, therefore, build a Gazelle binary for each OS+CPU architecture+Minor Python version combination they are targeting. The following instructions are for when you use [bzlmod](https://docs.bazel.build/versions/5.0.0/bzlmod.html). Please refer to older documentation that includes instructions on how to use Gazelle