Skip to content

Commit

Permalink
python: support platform-specific sources
Browse files Browse the repository at this point in the history
Summary:
Adds a parameter which pulls in the given sources based on the python
platform used (analogous to C/C++'s platform-specific sources).

Test Plan:
- added unittests
- loaded docs locally in browser
  • Loading branch information
andrewjcg authored and sdwilsh committed Oct 2, 2015
1 parent e7edff6 commit efaf4a5
Show file tree
Hide file tree
Showing 18 changed files with 526 additions and 250 deletions.
65 changes: 65 additions & 0 deletions docs/__python_common.soy
@@ -0,0 +1,65 @@
{namespace python_common}

/***/
{template .srcs_arg}
{call buck.arg}
{param name: 'srcs' /}
{param default : '[]' /}
{param desc}
The set of <code>.py</code> files included in this library.
{/param}
{/call}
{/template}

/***/
{template .platform_srcs_arg}
{call buck.arg}
{param name : 'platform_srcs' /}
{param default : '[]' /}
{param desc}
Python-platform-specific source files. These should be specified as a list of pairs where the first
element is an un-anchored regex (in java.util.regex.Pattern syntax) against which the platform name
is matched (as defined in the `python#name` section of `.buckconfig`), and the second element is
a list of source files.
{/param}
{/call}
{/template}

/***/
{template .resources_arg}
{call buck.arg}
{param name: 'resources' /}
{param default : '[]' /}
{param desc}
Static files to be packaged along with the python sources. These resources can be
accessed at runtime using the <a href="https://pythonhosted.org/setuptools/pkg_resources.html">pkg_resources</a> API.
{/param}
{/call}
{/template}

/***/
{template .platform_resources_arg}
{call buck.arg}
{param name : 'platform_resources' /}
{param default : '[]' /}
{param desc}
Python-platform-specific resource files. These should be specified as a list of pairs where the first
element is an un-anchored regex (in java.util.regex.Pattern syntax) against which the platform name
is matched (as defined in the `python#name` section of `.buckconfig`), and the second element is a
list of resource files.
{/param}
{/call}
{/template}

/***/
{template .base_module_arg}
{call buck.arg}
{param name: 'base_module' /}
{param default : 'None' /}
{param desc}
The package for which the given specified sources and resources should reside in their final
location in the top-level binary. If unset, the project relative directory that houses the
BUCK file is used.
{/param}
{/call}
{/template}
58 changes: 34 additions & 24 deletions docs/rule/python_library.soy
Expand Up @@ -27,32 +27,15 @@ and resources to be packaged into a top-level {call buck.python_binary /} rule.
{/param}
{/call}

{call buck.arg}
{param name: 'srcs' /}
{param default : '[]' /}
{param desc}
The set of <code>.py</code> files included in this library.
{/param}
{/call}
{call python_common.srcs_arg /}

{call buck.arg}
{param name: 'resources' /}
{param default : '[]' /}
{param desc}
Static files to be packaged along with the python sources. These resources can be
accessed at runtime using the <a href="https://pythonhosted.org/setuptools/pkg_resources.html">pkg_resources</a> API.
{/param}
{/call}
{call python_common.platform_srcs_arg /}

{call buck.arg}
{param name: 'base_module' /}
{param default : 'None' /}
{param desc}
The package for which the given specified sources and resources should reside in their final
location in the top-level binary. If unset, the project relative directory that houses the
BUCK file is used.
{/param}
{/call}
{call python_common.resources_arg /}

{call python_common.platform_resources_arg /}

{call python_common.base_module_arg /}

{call buck.arg}
{param name: 'deps' /}
Expand Down Expand Up @@ -90,6 +73,33 @@ python_library(
],
)
</pre>{/literal}
<p>
Here is an example of using the `platform_srcs` and `platform_resources`
parameters to pull in sources/resources only when building for a specific
Python platform:
</p>
{literal}<pre class="prettyprint lang-ini">
; .buckconfig
[python#py2]
interpreter = /usr/bin/python2.7
[python#py3]
interpreter = /usr/bin/python3.4
</pre>{/literal}

{literal}<pre class="prettyprint lang-py">
# BUCK
python_library(
name = 'utils',
platform_srcs = [
('py2', ['foo.py']),
('py3', ['bar.py']),
],
platform_resources = [
('py2', ['foo.dat']),
('py3', ['bar.dat']),
],
)
</pre>{/literal}
{/param}

{/call} // close buck.rule
Expand Down
60 changes: 35 additions & 25 deletions docs/rule/python_test.soy
Expand Up @@ -27,22 +27,15 @@ files that contain tests to run via the <a href="https://docs.python.org/2/libra
{/param}
{/call}

{call buck.arg}
{param name: 'srcs' /}
{param default : '[]' /}
{param desc}
The set of <code>.py</code> files that contain tests.
{/param}
{/call}
{call python_common.srcs_arg /}

{call buck.arg}
{param name: 'resources' /}
{param default : '[]' /}
{param desc}
Static files to be packaged along with the python sources. These resources can be
accessed at runtime using the <a href="https://pythonhosted.org/setuptools/pkg_resources.html">pkg_resources</a> API.
{/param}
{/call}
{call python_common.platform_srcs_arg /}

{call python_common.resources_arg /}

{call python_common.platform_resources_arg /}

{call python_common.base_module_arg /}

{call buck.arg}
{param name: 'env' /}
Expand All @@ -61,16 +54,6 @@ files that contain tests to run via the <a href="https://docs.python.org/2/libra
{/param}
{/call}

{call buck.arg}
{param name: 'base_module' /}
{param default : 'None' /}
{param desc}
The package for which the given specified sources and resources should reside in their final
location in the top-level binary. If unset, the project relative directory that houses the
BUCK file is used.
{/param}
{/call}

{call buck.arg}
{param name: 'deps' /}
{param default : '[]' /}
Expand Down Expand Up @@ -133,6 +116,33 @@ python_library(
],
)
</pre>{/literal}
<p>
Here is an example of using the `platform_srcs` and `platform_resources`
parameters to pull in sources/resources only when building for a specific
Python platform:
</p>
{literal}<pre class="prettyprint lang-ini">
; .buckconfig
[python#py2]
interpreter = /usr/bin/python2.7
[python#py3]
interpreter = /usr/bin/python3.4
</pre>{/literal}

{literal}<pre class="prettyprint lang-py">
# BUCK
python_test(
name = 'test',
platform_srcs = [
('py2', ['foo.py']),
('py3', ['bar.py']),
],
platform_resources = [
('py2', ['foo.dat']),
('py3', ['bar.dat']),
],
)
</pre>{/literal}
{/param}

{/call} // close buck.rule
Expand Down
22 changes: 14 additions & 8 deletions src/com/facebook/buck/python/PythonLibrary.java
Expand Up @@ -25,7 +25,9 @@
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.rules.SourcePathResolver;
import com.facebook.buck.rules.TargetGraph;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;

Expand All @@ -35,15 +37,15 @@ public class PythonLibrary extends NoopBuildRule implements PythonPackagable {

private static final BuildableProperties OUTPUT_TYPE = new BuildableProperties(LIBRARY);

private final ImmutableMap<Path, SourcePath> srcs;
private final ImmutableMap<Path, SourcePath> resources;
private final Function<? super PythonPlatform, ImmutableMap<Path, SourcePath>> srcs;
private final Function<? super PythonPlatform, ImmutableMap<Path, SourcePath>> resources;
private final Optional<Boolean> zipSafe;

public PythonLibrary(
BuildRuleParams params,
SourcePathResolver resolver,
ImmutableMap<Path, SourcePath> srcs,
ImmutableMap<Path, SourcePath> resources,
Function<? super PythonPlatform, ImmutableMap<Path, SourcePath>> srcs,
Function<? super PythonPlatform, ImmutableMap<Path, SourcePath>> resources,
Optional<Boolean> zipSafe) {
super(params, resolver);
this.srcs = srcs;
Expand All @@ -57,8 +59,8 @@ public PythonPackageComponents getPythonPackageComponents(
PythonPlatform pythonPlatform,
CxxPlatform cxxPlatform) {
return PythonPackageComponents.of(
srcs,
resources,
Preconditions.checkNotNull(srcs.apply(pythonPlatform)),
Preconditions.checkNotNull(resources.apply(pythonPlatform)),
ImmutableMap.<Path, SourcePath>of(),
ImmutableSet.<SourcePath>of(),
zipSafe);
Expand All @@ -69,8 +71,12 @@ public BuildableProperties getProperties() {
return OUTPUT_TYPE;
}

public ImmutableMap<Path, SourcePath> getSrcs() {
return srcs;
public ImmutableMap<Path, SourcePath> getSrcs(PythonPlatform pythonPlatform) {
return Preconditions.checkNotNull(srcs.apply(pythonPlatform));
}

public ImmutableMap<Path, SourcePath> getResources(PythonPlatform pythonPlatform) {
return Preconditions.checkNotNull(resources.apply(pythonPlatform));
}

}
70 changes: 54 additions & 16 deletions src/com/facebook/buck/python/PythonLibraryDescription.java
Expand Up @@ -22,11 +22,15 @@
import com.facebook.buck.rules.BuildRuleResolver;
import com.facebook.buck.rules.BuildRuleType;
import com.facebook.buck.rules.Description;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.rules.SourcePathResolver;
import com.facebook.buck.rules.TargetGraph;
import com.facebook.buck.rules.coercer.PatternMatchedCollection;
import com.facebook.buck.rules.coercer.SourceList;
import com.facebook.infer.annotation.SuppressFieldNotInitialized;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedSet;

import java.nio.file.Path;
Expand All @@ -38,7 +42,9 @@ public class PythonLibraryDescription implements Description<Arg> {
@SuppressFieldNotInitialized
public static class Arg {
public Optional<SourceList> srcs;
public Optional<PatternMatchedCollection<SourceList>> platformSrcs;
public Optional<SourceList> resources;
public Optional<PatternMatchedCollection<SourceList>> platformResources;
public Optional<ImmutableSortedSet<BuildTarget>> deps;
public Optional<String> baseModule;
public Optional<Boolean> zipSafe;
Expand All @@ -57,26 +63,58 @@ public Arg createUnpopulatedConstructorArg() {
@Override
public <A extends Arg> PythonLibrary createBuildRule(
TargetGraph targetGraph,
BuildRuleParams params,
final BuildRuleParams params,
BuildRuleResolver resolver,
A args) {
SourcePathResolver pathResolver = new SourcePathResolver(resolver);
Path baseModule = PythonUtil.getBasePath(params.getBuildTarget(), args.baseModule);
final A args) {
final SourcePathResolver pathResolver = new SourcePathResolver(resolver);
final Path baseModule = PythonUtil.getBasePath(params.getBuildTarget(), args.baseModule);
return new PythonLibrary(
params,
pathResolver,
PythonUtil.toModuleMap(
params.getBuildTarget(),
pathResolver,
"srcs",
baseModule,
args.srcs),
PythonUtil.toModuleMap(
params.getBuildTarget(),
pathResolver,
"resources",
baseModule,
args.resources),
new Function<PythonPlatform, ImmutableMap<Path, SourcePath>>() {
@Override
public ImmutableMap<Path, SourcePath> apply(PythonPlatform pythonPlatform) {
return ImmutableMap.<Path, SourcePath>builder()
.putAll(
PythonUtil.toModuleMap(
params.getBuildTarget(),
pathResolver,
"srcs",
baseModule,
args.srcs.asSet()))
.putAll(
PythonUtil.toModuleMap(
params.getBuildTarget(),
pathResolver,
"platformSrcs",
baseModule,
args.platformSrcs.get()
.getMatchingValues(pythonPlatform.getFlavor().toString())))
.build();
}
},
new Function<PythonPlatform, ImmutableMap<Path, SourcePath>>() {
@Override
public ImmutableMap<Path, SourcePath> apply(PythonPlatform pythonPlatform) {
return ImmutableMap.<Path, SourcePath>builder()
.putAll(
PythonUtil.toModuleMap(
params.getBuildTarget(),
pathResolver,
"resources",
baseModule,
args.resources.asSet()))
.putAll(
PythonUtil.toModuleMap(
params.getBuildTarget(),
pathResolver,
"platformResources",
baseModule,
args.platformResources.get()
.getMatchingValues(pythonPlatform.getFlavor().toString())))
.build();
}
},
args.zipSafe);
}

Expand Down

0 comments on commit efaf4a5

Please sign in to comment.