diff options
13 files changed, 532 insertions, 1 deletions
diff --git a/examples/py_native/BUILD b/examples/py_native/BUILD new file mode 100644 index 0000000000..3d8de94251 --- /dev/null +++ b/examples/py_native/BUILD @@ -0,0 +1,10 @@ +py_binary( + name = "bin", + srcs = ["bin.py"], + deps = [":lib"], +) + +py_library( + name = "lib", + srcs = ["lib.py"], +) diff --git a/examples/py_native/bin.py b/examples/py_native/bin.py new file mode 100644 index 0000000000..f79379a237 --- /dev/null +++ b/examples/py_native/bin.py @@ -0,0 +1,4 @@ +"""A tiny example binary for the native Python rules of Bazel.""" +from examples.py_native.lib import GetNumber + +print "The number is %d" % GetNumber() diff --git a/examples/py_native/lib.py b/examples/py_native/lib.py new file mode 100644 index 0000000000..44522e0fe9 --- /dev/null +++ b/examples/py_native/lib.py @@ -0,0 +1,5 @@ +"""A tiny example binary for the native Python rules of Bazel.""" + + +def GetNumber(): + return 42 diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java index 909eec8b20..4ee294d211 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java @@ -44,6 +44,9 @@ import com.google.devtools.build.lib.bazel.rules.java.BazelJavaPluginRule; import com.google.devtools.build.lib.bazel.rules.java.BazelJavaRuleClasses; import com.google.devtools.build.lib.bazel.rules.java.BazelJavaTestRule; import com.google.devtools.build.lib.bazel.rules.objc.BazelIosTestRule; +import com.google.devtools.build.lib.bazel.rules.python.BazelPyBinaryRule; +import com.google.devtools.build.lib.bazel.rules.python.BazelPyLibraryRule; +import com.google.devtools.build.lib.bazel.rules.python.BazelPyRuleClasses; import com.google.devtools.build.lib.bazel.rules.sh.BazelShBinaryRule; import com.google.devtools.build.lib.bazel.rules.sh.BazelShLibraryRule; import com.google.devtools.build.lib.bazel.rules.sh.BazelShRuleClasses; @@ -88,6 +91,8 @@ import com.google.devtools.build.lib.rules.objc.ObjcOptionsRule; import com.google.devtools.build.lib.rules.objc.ObjcProtoLibraryRule; import com.google.devtools.build.lib.rules.objc.ObjcRuleClasses; import com.google.devtools.build.lib.rules.objc.ObjcXcodeprojRule; +import com.google.devtools.build.lib.rules.python.PythonConfigurationLoader; +import com.google.devtools.build.lib.rules.python.PythonOptions; import com.google.devtools.build.lib.rules.workspace.BindRule; import com.google.devtools.build.lib.syntax.Label; import com.google.devtools.build.lib.syntax.SkylarkType; @@ -171,6 +176,7 @@ public class BazelRuleClassProvider { BuildConfiguration.Options.class, CppOptions.class, JavaOptions.class, + PythonOptions.class, ObjcCommandLineOptions.class ); @@ -225,10 +231,14 @@ public class BazelRuleClassProvider { builder.addRuleDefinition(new BazelCppRuleClasses.CcBinaryBaseRule()); builder.addRuleDefinition(new BazelCppRuleClasses.CcBinaryRule()); builder.addRuleDefinition(new BazelCppRuleClasses.CcTestRule()); - builder.addRuleDefinition(new BazelCppRuleClasses.CcLibraryBaseRule()); builder.addRuleDefinition(new BazelCppRuleClasses.CcLibraryRule()); + builder.addRuleDefinition(new BazelPyRuleClasses.PyBaseRule()); + builder.addRuleDefinition(new BazelPyRuleClasses.PyBinaryBaseRule()); + builder.addRuleDefinition(new BazelPyLibraryRule()); + builder.addRuleDefinition(new BazelPyBinaryRule()); + builder.addWorkspaceFile(BazelJavaRuleClasses.getDefaultWorkspace()); builder.addRuleDefinition(new BazelJavaRuleClasses.BaseJavaBinaryRule()); builder.addRuleDefinition(new BazelJavaRuleClasses.IjarBaseRule()); @@ -286,6 +296,7 @@ public class BazelRuleClassProvider { builder.addConfigurationFragment(new BazelConfiguration.Loader()); builder.addConfigurationFragment(new CppConfigurationLoader( Functions.<String>identity())); + builder.addConfigurationFragment(new PythonConfigurationLoader(Functions.<String>identity())); builder.addConfigurationFragment(new JvmConfigurationLoader(JAVA_CPU_SUPPLIER)); builder.addConfigurationFragment(new JavaConfigurationLoader(JAVA_CPU_SUPPLIER)); builder.addConfigurationFragment(new ObjcConfigurationLoader()); diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyBinary.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyBinary.java new file mode 100644 index 0000000000..3186791265 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyBinary.java @@ -0,0 +1,28 @@ +// Copyright 2014 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 com.google.devtools.build.lib.bazel.rules.python; + +import com.google.devtools.build.lib.rules.python.PyBinary; +import com.google.devtools.build.lib.rules.python.PythonSemantics; + +/** + * Implementation of the {@code py_binary} rule for Bazel. + */ +public class BazelPyBinary extends PyBinary { + @Override + protected PythonSemantics createSemantics() { + return new BazelPythonSemantics(); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyBinaryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyBinaryRule.java new file mode 100644 index 0000000000..6d6b2fd1a5 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyBinaryRule.java @@ -0,0 +1,101 @@ +// Copyright 2014 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 com.google.devtools.build.lib.bazel.rules.python; + +import com.google.devtools.build.lib.analysis.RuleDefinition; +import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; +import com.google.devtools.build.lib.bazel.rules.BazelBaseRuleClasses; +import com.google.devtools.build.lib.bazel.rules.python.BazelPyRuleClasses.PyBinaryBaseRule; +import com.google.devtools.build.lib.packages.RuleClass; + +/** + * Rule definition for the {@code py_binary} rule. + */ +public final class BazelPyBinaryRule implements RuleDefinition { + @Override + public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) { + /* <!-- #BLAZE_RULE(py_binary).NAME --> + <br/>If <code>main</code> is unspecified, this should be the same as the name + of the source file that is the main entry point of the application, + minus the extension. For example, if your entry point is called + <code>main.py</code>, then your name should be <code>main</code>. + <!-- #END_BLAZE_RULE.NAME --> */ + return builder + .build(); + } + + @Override + public Metadata getMetadata() { + return RuleDefinition.Metadata.builder() + .name("py_binary") + .ancestors(PyBinaryBaseRule.class, BazelBaseRuleClasses.BinaryBaseRule.class) + .factoryClass(BazelPyBinary.class) + .build(); + } +} + +/*<!-- #BLAZE_RULE (NAME = py_binary, TYPE = BINARY, FAMILY = Python) --> + +${ATTRIBUTE_SIGNATURE} + +<p> + A <code>py_binary</code> is an executable Python program consisting + of a collection of <code>.py</code> source files (possibly belonging + to other <code>py_library</code> rules), a <code>*.runfiles</code> + directory tree containing all the code and data needed by the + program at run-time, and a stub script that starts up the program with + the correct initial environment and data. +</p> + +${IMPLICIT_OUTPUTS} + +${ATTRIBUTE_DEFINITION} + +<h4 id="py_binary_examples">Examples</h4> + +<pre class="code"> +py_binary( + name = "foo", + srcs = ["foo.py"], + data = [":transform"], # a cc_binary which we invoke at run time + deps = [ + "//pyglib", + ":foolib", # a py_library + ], +) +</pre> + +<p>If you want to run a <code>py_binary</code> from within another binary or + test (for example, running a python binary to set up some mock resource from + within a java_test) then the correct approach is to make the other binary or + test depend on the <code>py_binary</code> in its data section. The other + binary can then locate the <code>py_binary</code> relative to the source + directory. +</p> + +<pre class="code"> +py_binary( + name = "test_main", + srcs = ["test_main.py"], + deps = [":testlib"], +) + +java_library( + name = "testing", + srcs = glob(["*.java"]), + data = [":test_main"] +) +</pre> +<!-- #END_BLAZE_RULE -->*/ diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyLibrary.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyLibrary.java new file mode 100644 index 0000000000..5cd9b8fbb3 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyLibrary.java @@ -0,0 +1,28 @@ +// Copyright 2014 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 com.google.devtools.build.lib.bazel.rules.python; + +import com.google.devtools.build.lib.rules.python.PyLibrary; +import com.google.devtools.build.lib.rules.python.PythonSemantics; + +/** + * Implementation of the {@code py_library} rule for Bazel. + */ +public class BazelPyLibrary extends PyLibrary { + @Override + protected PythonSemantics createSemantics() { + return new BazelPythonSemantics(); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyLibraryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyLibraryRule.java new file mode 100644 index 0000000000..bc508960b2 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyLibraryRule.java @@ -0,0 +1,76 @@ +// Copyright 2014 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 com.google.devtools.build.lib.bazel.rules.python; + +import static com.google.devtools.build.lib.packages.Attribute.attr; +import static com.google.devtools.build.lib.packages.Type.LABEL_LIST; + +import com.google.devtools.build.lib.analysis.RuleDefinition; +import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; +import com.google.devtools.build.lib.bazel.rules.python.BazelPyRuleClasses.PyBaseRule; +import com.google.devtools.build.lib.packages.RuleClass; + +/** + * Rule definition for the {@code py_library} rule. + */ +public final class BazelPyLibraryRule implements RuleDefinition { + @Override + public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) { + return builder + /* <!-- #BLAZE_RULE(py_library).ATTRIBUTE(deps) --> + The list of other libraries to be linked in to the library target. + ${SYNOPSIS} + See general comments about <code>deps</code> + at <a href="#common-attributes">Attributes common to all build rules</a>. + In practice, these arguments are treated like those in <code>srcs</code>; + you may move items between these lists willy-nilly. It's probably more + readable to keep your <code>.py</code> files in your <code>srcs</code>. + <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ + + /* <!-- #BLAZE_RULE(py_library).ATTRIBUTE(data) --> + The list of files needed by this library at runtime. + ${SYNOPSIS} + See general comments about <code>data</code> + at <a href="#common-attributes">Attributes common to all build rules</a>. + <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ + + /* <!-- #BLAZE_RULE(py_library).ATTRIBUTE(srcs) --> + The list of source files that are processed to create the target. + ${SYNOPSIS} + This includes all your checked-in code and any generated source files. + <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ + .add(attr("srcs", LABEL_LIST) + .direct_compile_time_input() + .allowedFileTypes(BazelPyRuleClasses.PYTHON_SOURCE)) + .build(); + } + + @Override + public Metadata getMetadata() { + return RuleDefinition.Metadata.builder() + .name("py_library") + .ancestors(PyBaseRule.class) + .factoryClass(BazelPyLibrary.class) + .build(); + } +} + +/*<!-- #BLAZE_RULE (NAME = py_library, TYPE = LIBRARY, FAMILY = Python) --> + +${ATTRIBUTE_SIGNATURE} + +${ATTRIBUTE_DEFINITION} + +<!-- #END_BLAZE_RULE -->*/ diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyRuleClasses.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyRuleClasses.java new file mode 100644 index 0000000000..019170c88f --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyRuleClasses.java @@ -0,0 +1,180 @@ +// Copyright 2014 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 com.google.devtools.build.lib.bazel.rules.python; + +import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.HOST; +import static com.google.devtools.build.lib.packages.Attribute.attr; +import static com.google.devtools.build.lib.packages.Type.LABEL; +import static com.google.devtools.build.lib.packages.Type.LABEL_LIST; +import static com.google.devtools.build.lib.packages.Type.STRING; +import static com.google.devtools.build.lib.packages.Type.TRISTATE; + +import com.google.devtools.build.lib.analysis.BaseRuleClasses; +import com.google.devtools.build.lib.analysis.RuleDefinition; +import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; +import com.google.devtools.build.lib.bazel.rules.cpp.BazelCppRuleClasses; +import com.google.devtools.build.lib.packages.RuleClass; +import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType; +import com.google.devtools.build.lib.packages.TriState; +import com.google.devtools.build.lib.rules.python.PyRuleClasses; +import com.google.devtools.build.lib.rules.python.PythonVersion; +import com.google.devtools.build.lib.util.FileType; + +/** + * Bazel-specific rule definitions for Python rules. + */ +public final class BazelPyRuleClasses { + public static final FileType PYTHON_SOURCE = FileType.of(".py"); + + public static final String[] ALLOWED_RULES_IN_DEPS = new String[] { + "py_binary", + "py_library", + }; + + /** + * Base class for Python rule definitions. + */ + public static final class PyBaseRule implements RuleDefinition { + @Override + public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) { + return builder + /* <!-- #BLAZE_RULE($base_py).ATTRIBUTE(deps) --> + The list of other libraries to be linked in to the binary target. + ${SYNOPSIS} + See general comments about <code>deps</code> + at <a href="#common-attributes">Attributes common to all build rules</a>. + These can be + <a href="#py_binary"><code>py_binary</code></a> rules, + <a href="#py_library"><code>py_library</code></a> rules or + <a href="#cc_library"><code>cc_library</code></a> rules, + <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ + .override(builder.copy("deps") + .allowedRuleClasses(ALLOWED_RULES_IN_DEPS) + .allowedFileTypes()) + /* <!-- #BLAZE_RULE($base_py).ATTRIBUTE(srcs_version) --> + A string specifying the Python major version(s) that the <code>.py</code> source + files listed in the <code>srcs</code> of this rule are compatible with. + ${SYNOPSIS} + Valid values are:<br/> + <code>"PY2ONLY"</code> - + Python 2 code that is <b>not</b> suitable for <code>2to3</code> conversion.<br/> + <code>"PY2"</code> - + Python 2 code that is expected to work when run through <code>2to3</code>.<br/> + <code>"PY2AND3"</code> - + Code that is compatible with both Python 2 and 3 without + <code>2to3</code> conversion.<br/> + <code>"PY3"</code> - + Python 3 code that will not run on Python 2.<br/> + <br/> + <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ + .add(attr("srcs_version", STRING) + .value(PythonVersion.defaultValue().toString())) + // do not depend on lib2to3:2to3 rule, because it creates circular dependencies + // 2to3 is itself written in Python and depends on many libraries. + .add(attr("$python2to3", LABEL).cfg(HOST).exec() + .value(env.getLabel("//tools/python:2to3"))) + .setPreferredDependencyPredicate(PyRuleClasses.PYTHON_SOURCE) + .build(); + } + + @Override + public Metadata getMetadata() { + return RuleDefinition.Metadata.builder() + .name("$base_py") + .type(RuleClassType.ABSTRACT) + .ancestors(BaseRuleClasses.RuleBase.class) + .build(); + } + } + + /** + * Base class for Python rule definitions that produce binaries. + */ + public static final class PyBinaryBaseRule implements RuleDefinition { + @Override + public RuleClass build(RuleClass.Builder builder, final RuleDefinitionEnvironment env) { + return builder + /* <!-- #BLAZE_RULE($base_py_binary).ATTRIBUTE(data) --> + The list of files needed by this binary at runtime. + ${SYNOPSIS} + See general comments about <code>data</code> + at <a href="#common-attributes">Attributes common to all build rules</a>. + Also see the <a href="#py_library.data"><code>data</code></a> argument of + the <a href="#py_library"><code>py_library</code></a> rule for details. + <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ + + /* <!-- #BLAZE_RULE($base_py_binary).ATTRIBUTE(main) --> + The name of the source file that is the main entry point of the application. + ${SYNOPSIS} + This file must also be listed in <code>srcs</code>. If left unspecified, + <code>name</code> is used instead (see above). If <code>name</code> does not + match any filename in <code>srcs</code>, <code>main</code> must be specified. + <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ + .add(attr("main", LABEL).allowedFileTypes(PYTHON_SOURCE)) + /* <!-- #BLAZE_RULE($base_py_binary).ATTRIBUTE(default_python_version) --> + A string specifying the default Python major version to use when building this binary and + all of its <code>deps</code>. + ${SYNOPSIS} + Valid values are <code>"PY2"</code> (default) or <code>"PY3"</code>. + Python 3 support is experimental. + <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ + .add(attr("default_python_version", STRING) + .value(PythonVersion.defaultValue().toString()) + .nonconfigurable("read by PythonUtils.getNewPythonVersion, which doesn't have access" + + " to configuration keys")) + /* <!-- #BLAZE_RULE($base_py_binary).ATTRIBUTE(srcs) --> + The list of source files that are processed to create the target. + ${SYNOPSIS} + This includes all your checked-in code and any + generated source files. The line between <code>srcs</code> and + <code>deps</code> is loose. The <code>.py</code> files + probably belong in <code>srcs</code> and library targets probably belong + in <code>deps</code>, but don't worry about it too much. + <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ + .add(attr("srcs", LABEL_LIST) + .mandatory() + .allowedFileTypes(PYTHON_SOURCE) + .direct_compile_time_input() + .allowedFileTypes(BazelPyRuleClasses.PYTHON_SOURCE)) + /* <!-- #BLAZE_RULE($base_py_binary).ATTRIBUTE(stamp) --> + Enable link stamping. + ${SYNOPSIS} + Whether to encode build information into the binary. Possible values: + <ul> + <li><code>stamp = 1</code>: Stamp the build information into the + binary. Stamped binaries are only rebuilt when their dependencies + change. Use this if there are tests that depend on the build + information.</li> + <li><code>stamp = 0</code>: Always replace build information by constant + values. This gives good build result caching.</li> + <li><code>stamp = -1</code>: Embedding of build information is controlled + by the <a href="blaze-user-manual.html#flag--stamp">--[no]stamp</a> Blaze + flag.</li> + </ul> + <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ + .add(attr("stamp", TRISTATE).value(TriState.AUTO)) + .build(); + } + + @Override + public Metadata getMetadata() { + return RuleDefinition.Metadata.builder() + .name("$base_py_binary") + .type(RuleClassType.ABSTRACT) + .ancestors(PyBaseRule.class, BazelCppRuleClasses.CcLinkingRule.class) + .build(); + } + } +} diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPythonSemantics.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPythonSemantics.java new file mode 100644 index 0000000000..3b249010c1 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPythonSemantics.java @@ -0,0 +1,74 @@ +// Copyright 2014 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 com.google.devtools.build.lib.bazel.rules.python; + +import com.google.common.collect.ImmutableList; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.analysis.Runfiles.Builder; +import com.google.devtools.build.lib.analysis.RunfilesSupport; +import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction; +import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction.Substitution; +import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction.Template; +import com.google.devtools.build.lib.rules.cpp.CcLinkParamsStore; +import com.google.devtools.build.lib.rules.python.PyCommon; +import com.google.devtools.build.lib.rules.python.PythonSemantics; +import com.google.devtools.build.lib.rules.test.InstrumentedFilesCollector.InstrumentationSpec; +import com.google.devtools.build.lib.util.FileTypeSet; + +/** + * Functionality specific to the Python rules in Bazel. + */ +public class BazelPythonSemantics implements PythonSemantics { + private static final Template STUB_TEMPLATE = + Template.forResource(BazelPythonSemantics.class, "stub_template.txt"); + public static final InstrumentationSpec PYTHON_COLLECTION_SPEC = new InstrumentationSpec( + FileTypeSet.of(BazelPyRuleClasses.PYTHON_SOURCE), + "srcs", "deps", "data"); + + @Override + public void validate(RuleContext ruleContext, PyCommon common) { + } + + @Override + public void collectRunfilesForBinary(RuleContext ruleContext, Builder builder, PyCommon common) { + } + + @Override + public void collectDefaultRunfilesForBinary(RuleContext ruleContext, Builder builder) { + } + + @Override + public InstrumentationSpec getCoverageInstrumentationSpec() { + return PYTHON_COLLECTION_SPEC; + } + + @Override + public void createExecutable(RuleContext ruleContext, PyCommon common, + CcLinkParamsStore ccLinkParamsStore) { + String main = common.determineMainExecutableSource(); + + ruleContext.registerAction(new TemplateExpansionAction( + ruleContext.getActionOwner(), + common.getExecutable(), + STUB_TEMPLATE, + ImmutableList.of(Substitution.of("%main%", main)), + true)); + } + + @Override + public void postInitBinary(RuleContext ruleContext, RunfilesSupport runfilesSupport, + PyCommon common) { + } +} diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/stub_template.txt b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/stub_template.txt new file mode 100644 index 0000000000..c285517673 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/stub_template.txt @@ -0,0 +1,5 @@ +#!/bin/bash -eu + +STUBPATH=$(python -c "import os.path; print os.path.realpath('$0');") +export PYTHONPATH=$STUBPATH.runfiles +python ${PYTHONPATH}/%main% diff --git a/tools/python/2to3.sh b/tools/python/2to3.sh new file mode 100755 index 0000000000..d87f29eecf --- /dev/null +++ b/tools/python/2to3.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +exit 1 diff --git a/tools/python/BUILD b/tools/python/BUILD new file mode 100644 index 0000000000..f489fe1d94 --- /dev/null +++ b/tools/python/BUILD @@ -0,0 +1,6 @@ +package(default_visibility = ["//visibility:public"]) + +sh_binary( + name = "2to3", + srcs = ["2to3.sh"], +) |