def __init__(self, address, payload=None, sources=None, include_relpath=None, lib_relpath=None, native_lib_names=None, **kwargs): """ :param sources: Files owned by this target. :param str include_relpath: The path where C/C++ headers are located, relative to this target's directory. Libraries depending on this target will be able to #include files relative to this directory. :param str lib_relpath: The path where native libraries are located, relative to this target's directory. :param list native_lib_names: Strings containing the libraries to add to the linker command line. These libraries become `-l<name>` arguments, so they must exist and be named `lib<name>.so` (or `lib<name>.dylib` depending on the platform) or the linker will exit with an error. This field may also be a dict mapping the OS name ('darwin' or 'linux') to a list of such strings. """ if not payload: payload = Payload() payload.add_fields({ 'sources': self.create_sources_field(sources, address.spec_path, key_arg='sources'), 'include_relpath': PrimitiveField(include_relpath), 'lib_relpath': PrimitiveField(lib_relpath), 'native_lib_names': PrimitiveField(native_lib_names), }) super().__init__(address=address, payload=payload, **kwargs)
class ManifestEntries(FingerprintedMixin): """Describes additional items to add to the app manifest.""" class ExpectedDictionaryError(Exception): pass def __init__(self, entries=None): """ :param entries: Additional headers, value pairs to add to the MANIFEST.MF. You can just add fixed string header / value pairs. :type entries: dictionary of string : string """ self.payload = Payload() if entries: if not isinstance(entries, dict): raise self.ExpectedDictionaryError( "entries must be a dictionary of strings.") for key in entries.keys(): if not isinstance(key, string_types): raise self.ExpectedDictionaryError( "entries must be dictionary of strings, got key {} type {}" .format(key, type(key).__name__)) self.payload.add_fields({ 'entries': PrimitiveField(entries or {}), }) def fingerprint(self): return self.payload.fingerprint() @property def entries(self): return self.payload.entries
class ManifestEntries(FingerprintedMixin): """Describes additional items to add to the app manifest.""" class ExpectedDictionaryError(Exception): pass def __init__(self, entries=None): """ :param entries: Additional headers, value pairs to add to the MANIFEST.MF. You can just add fixed string header / value pairs. :type entries: dictionary of string : string """ self.payload = Payload() if entries: if not isinstance(entries, dict): raise self.ExpectedDictionaryError("entries must be a dictionary of strings.") for key in entries.keys(): if not isinstance(key, string_types): raise self.ExpectedDictionaryError( "entries must be dictionary of strings, got key {} type {}" .format(key, type(key).__name__)) self.payload.add_fields({ 'entries' : PrimitiveField(entries or {}), }) def fingerprint(self): return self.payload.fingerprint() @property def entries(self): return self.payload.entries
def __init__(self, address, sources, copied=None, **kwargs): self.copied = copied payload = Payload() payload.add_fields({ 'sources': self.create_sources_field(sources, address.spec_path, key_arg='sources'), }) super(DummyTargetBase, self).__init__(address=address, payload=payload, **kwargs)
def __init__(self, address, payload=None, sources=None, ctypes_native_library=None, strict_deps=None, fatal_warnings=None, **kwargs): if not payload: payload = Payload() sources_field = self.create_sources_field(sources, address.spec_path, key_arg='sources') payload.add_fields({ 'sources': sources_field, 'ctypes_native_library': ctypes_native_library, 'strict_deps': PrimitiveField(strict_deps), 'fatal_warnings': PrimitiveField(fatal_warnings), }) if ctypes_native_library and not isinstance(ctypes_native_library, NativeArtifact): raise TargetDefinitionException( "Target must provide a valid pants '{}' object. Received an object with type '{}' " "and value: {}.".format(NativeArtifact.alias(), type(ctypes_native_library).__name__, ctypes_native_library)) super(NativeLibrary, self).__init__(address=address, payload=payload, **kwargs)
def __init__(self, prefixes=None, provides=None, *args, **kwargs): payload = Payload() payload.add_fields({ 'prefixes': prefixes, 'provides': provides, }) super(PomTarget, self).__init__(payload=payload, *args, **kwargs)
def __init__(self, zip_url, rev='', **kwargs): """ :param str zip_url: - Any URL from which a zipfile can be downloaded containing the source code of the remote library. - Can be a template string using variables {host}, {id}, {rev}. Example: "{host}/{id}/{rev}.zip" - {host} The host address to download zip files from. Specified by an option to GoFetch, '--remote-lib-host'. - {id} The global import identifier of the library, which is specified by the path to the BUILD file relative to the source root of all 3rd party Go libraries. For example, If the 3rd party source root is "3rdparty/go", a target at "3rdparty/go/github.com/user/lib" would have an {id} of "github.com/user/lib". - {rev} See :param rev: - The zip file is expected to have zipped the library directory itself, and NOT the direct contents of the library. Expected: `zip -r mylib.zip mylib/` Not: `zip -r mylib.zip mylib/*` :param str rev: Identifies which version of the remote library to download. This could be a commit SHA (git), node id (hg), etc. """ payload = Payload() payload.add_fields({ 'rev': PrimitiveField(rev), 'zip_url': PrimitiveField(zip_url) }) super(GoRemoteLibrary, self).__init__(payload=payload, **kwargs)
def __init__(self, binary=None, handler=None, **kwargs): """ :param string binary: Target spec of the ``python_binary`` that contains the handler. :param string handler: Lambda handler entrypoint (module.dotted.name:handler_func). """ payload = Payload() payload.add_fields({"binary": PrimitiveField(binary), "handler": PrimitiveField(handler)}) super().__init__(payload=payload, **kwargs)
def __init__(self, distribution_fingerprint=None, *args, **kwargs): """Synthetic target that represents a resolved webpack distribution.""" # Creating the synthetic target lets us avoid any special casing in regards to build order or cache invalidation. payload = Payload() payload.add_fields({ 'distribution_fingerprint': PrimitiveField(distribution_fingerprint), }) super(ResolvedWebPackDistribution, self).__init__(payload=payload, *args, **kwargs)
def __init__(self, distribution_fingerprint=None, *args, **kwargs): """Synthetic target that represents a resolved webpack distribution.""" # Creating the synthetic target lets us avoid any special casing in regards to build order or cache invalidation. payload = Payload() payload.add_fields({ 'distribution_fingerprint': PrimitiveField(distribution_fingerprint), }) super(WebPackDistribution, self).__init__(payload=payload, *args, **kwargs)
def __init__(self, address, sources, *args, **kwargs): payload = Payload() payload.add_fields({ "sources": self.create_sources_field(sources=sources, sources_rel_path=address.spec_path) }) super().__init__(address=address, payload=payload, *args, **kwargs)
def __init__(self, libraries=None, *args, **kwargs): """ :param libraries: Libraries that this target depends on that are not pants targets. For example, 'm' or 'rt' that are expected to be installed on the local system. :type libraries: List of libraries to link against. """ payload = Payload() payload.add_fields({'libraries': PrimitiveField(libraries)}) super(CppBinary, self).__init__(payload=payload, **kwargs)
def __init__(self, deferred_sources_address=None, *args, **kwargs): payload = Payload() payload.add_fields({ 'def_sources': DeferredSourcesField(ref_address=deferred_sources_address), }) super(TestDeferredSourcesTarget, self).__init__(payload=payload, *args, **kwargs)
def __init__(self, address, sources, copied=None, **kwargs): self.copied = copied payload = Payload() payload.add_fields({ "sources": self.create_sources_field(sources, address.spec_path, key_arg="sources") }) super().__init__(address=address, payload=payload, **kwargs)
def __init__(self, address, sources, *args, **kwargs): payload = Payload() payload.add_fields({ 'sources': self.create_sources_field(sources=sources, sources_rel_path=address.spec_path) }) super(DummyCacheLibrary, self).__init__(address=address, payload=payload, *args, **kwargs)
def __init__(self, package=None, **kwargs): """ :param str package: Optional name of the package (i.e. "network" or "containers"). Defaults to `name` if omitted """ self.package = package or kwargs['name'] payload = Payload() payload.add_fields({ 'package': PrimitiveField(self.package), }) super(HaskellStackagePackage, self).__init__(payload = payload, **kwargs)
def __init__(self, apply_pattern, action): """Creates a rule for handling duplicate jar entries. :param string apply_pattern: A regular expression that matches duplicate jar entries this rule applies to. :param action: An action to take to handle one or more duplicate entries. Must be one of: ``Duplicate.SKIP``, ``Duplicate.REPLACE``, ``Duplicate.CONCAT``, ``Duplicate.CONCAT_TEXT``, or ``Duplicate.FAIL``. """ payload = Payload() payload.add_fields({"action": PrimitiveField(self.validate_action(action))}) super(Duplicate, self).__init__(apply_pattern, payload=payload)
def __init__(self, package=None, **kwargs): """ :param str package: Optional name of the package (i.e. "network" or "containers"). Defaults to `name` if omitted """ self.package = package or kwargs['name'] payload = Payload() payload.add_fields({ 'package': PrimitiveField(self.package), }) super(HaskellStackagePackage, self).__init__(payload=payload, **kwargs)
def __init__(self, resolver, **kwargs): """ :param str resolver: The `stack` resolver (i.e. "lts-3.1" or "nightly-2015-08-29") """ self.resolver = resolver payload = Payload() payload.add_fields({ 'resolver': PrimitiveField(self.resolver), }) super(HaskellProject, self).__init__(payload = payload, **kwargs)
def __init__(self, apply_pattern, action): """Creates a rule for handling duplicate jar entries. :param string apply_pattern: A regular expression that matches duplicate jar entries this rule applies to. :param action: An action to take to handle one or more duplicate entries. Must be one of: ``Duplicate.SKIP``, ``Duplicate.REPLACE``, ``Duplicate.CONCAT``, ``Duplicate.CONCAT_TEXT``, or ``Duplicate.FAIL``. """ payload = Payload() payload.add_fields( {"action": PrimitiveField(self.validate_action(action))}) super().__init__(apply_pattern, payload=payload)
def __init__(self, version, package=None, **kwargs): """ :param str version: The package version string (i.e. "0.4.3.0" or "1.0.0") :param str package: Optional name of the package (i.e. "network" or "containers"). Defaults to `name` if omitted """ self.version = version self.package = package or kwargs['name'] payload = Payload() payload.add_fields({ 'version': PrimitiveField(self.version), 'package': PrimitiveField(self.package), }) super(HaskellHackagePackage, self).__init__(**kwargs)
def __init__(self, libraries=None, *args, **kwargs): """ :param libraries: Libraries that this target depends on that are not pants targets. For example, 'm' or 'rt' that are expected to be installed on the local system. :type libraries: List of libraries to link against. """ payload = Payload() payload.add_fields({ 'libraries': PrimitiveField(libraries) }) super(CppBinary, self).__init__(payload=payload, **kwargs)
def __init__(self, binary=None, handler=None, **kwargs): """ :param string binary: Target spec of the ``python_binary`` that contains the handler. :param string handler: Lambda handler entrypoint (module.dotted.name:handler_func). """ payload = Payload() payload.add_fields({ 'binary': PrimitiveField(binary), 'handler': PrimitiveField(handler), }) super(PythonAWSLambda, self).__init__(payload=payload, **kwargs)
def __init__(self, package=None, path=None, **kwargs): """ :param str package: Optional name of the package (i.e. "network" or "containers"). Defaults to `name` if omitted :param str path: Optional path to a remote source archive in TAR or ZIP format. """ self.package = package or kwargs['name'] self.path = path payload = Payload() payload.add_fields({ 'package': PrimitiveField(self.package), 'path': PrimitiveField(self.path), }) super(HaskellSourcePackage, self).__init__(payload=payload, **kwargs)
def __init__(self, package=None, path=None, **kwargs): """ :param str package: Optional name of the package (i.e. "network" or "containers"). Defaults to `name` if omitted :param str path: Optional path to a remote source archive in TAR or ZIP format. """ self.package = package or kwargs['name'] self.path = path payload = Payload() payload.add_fields({ 'package': PrimitiveField(self.package), 'path': PrimitiveField(self.path), }) super(HaskellSourcePackage, self).__init__(payload = payload, **kwargs)
def __init__(self, sources=None, address=None, **kwargs): payload = Payload() payload.add_fields({ 'sources': self.create_sources_field( sources, address.spec_path, key_arg='sources' ) }) super(Dockerfile, self).__init__( address=address, payload=payload, **kwargs )
def __init__(self, address, payload=None, sources=None, ctypes_native_library=None, strict_deps=None, fatal_warnings=None, compiler_option_sets=None, toolchain_variant=None, **kwargs): if not payload: payload = Payload() sources_field = self.create_sources_field(sources, address.spec_path, key_arg="sources") payload.add_fields({ "sources": sources_field, "ctypes_native_library": ctypes_native_library, "strict_deps": PrimitiveField(strict_deps), "fatal_warnings": PrimitiveField(fatal_warnings), "compiler_option_sets": PrimitivesSetField(compiler_option_sets), "toolchain_variant": PrimitiveField(toolchain_variant), }) if ctypes_native_library and not isinstance(ctypes_native_library, NativeArtifact): raise TargetDefinitionException( "Target must provide a valid pants '{}' object. Received an object with type '{}' " "and value: {}.".format( NativeArtifact.alias(), type(ctypes_native_library).__name__, ctypes_native_library, )) super().__init__(address=address, payload=payload, **kwargs)
def create_synthetic_target(cls, options, address_mapper, build_graph, discovered_targets): """Create a synthetic target that depends on the set of jar_library_targets. The created target is injected into the build graph as an unconnected target with a payload of a JarsField populated by the JarDependencies implied by the jar_library_targets. :param `pants.option.options.Option` options: The Task's scoped options. :param `pants.build_graph.AddressMapper` address_mapper: Populated build_graph instance. :param `pants.build_graph.BuildGraph` build_graph: Populated build_graph instance :param collection[`pants.target.Target`] discovered_targets: Targets newly injected into build graph but possibly not in the context of any target_root. :returns synthetic target: :rtype subclass of `pants.target.Target`: """ synthetic_address = cls.get_synthetic_address() # JarLibrary targets have a unique attribute called `managed_dependencies`, which holds a spec of a # `managed_jar_dependency` target. That will not be inserted along with the rest of the jar_library's closure # since at address_mapping time it is not a dependency. We could take care to track them down and insert them # but it looks to me like this handling is already wired into the JarDependency and JarLibrary pipeline. If we # end up seeing misses, we can add the logic to insert them as a special case, but for now I hope to hand that # special casing off. jar_library_targets = [ t for t in discovered_targets if isinstance(t, JarLibrary) ] all_jar_deps = JarLibrary.to_jar_dependencies( synthetic_address, [t.address.spec for t in jar_library_targets], build_graph, ) payload = Payload() payload.add_fields({ 'jars': JarsField(sorted(all_jar_deps)), }) synthetic_target = cls.inject_synthetic_target( build_graph, synthetic_address, payload=payload, dependencies=[j.address for j in jar_library_targets], ) return synthetic_target
def __init__(self, address, payload=None, sources=None, ctypes_native_library=None, strict_deps=None, fatal_warnings=None, **kwargs): if not payload: payload = Payload() sources_field = self.create_sources_field(sources, address.spec_path, key_arg='sources') payload.add_fields({ 'sources': sources_field, 'ctypes_native_library': ctypes_native_library, 'strict_deps': PrimitiveField(strict_deps), 'fatal_warnings': PrimitiveField(fatal_warnings), }) if ctypes_native_library and not isinstance(ctypes_native_library, NativeArtifact): raise TargetDefinitionException( "Target must provide a valid pants '{}' object. Received an object with type '{}' " "and value: {}." .format(NativeArtifact.alias(), type(ctypes_native_library).__name__, ctypes_native_library)) super(NativeLibrary, self).__init__(address=address, payload=payload, **kwargs)
class JarRules(FingerprintedMixin): """A set of rules for packaging up a deploy jar. Deploy jars are executable jars with fully self-contained classpaths and as such, assembling them presents problems given jar semantics. One issue is signed jars that must be included on the classpath. These have a signature that depends on the jar contents and assembly of the deploy jar changes the content of the jar, breaking the signatures. For cases like these the signed jars must be verified and then the signature information thrown away. The `Skip <#Skip>`_ rule supports this sort of issue by allowing outright entry exclusion in the final deploy jar. Another issue is duplicate jar entries. Although the underlying zip format supports these, the java jar tool and libraries do not. As such some action must be taken for each duplicate entry such that there are no duplicates in the final deploy jar. The four `Duplicate <#Duplicate>`_ rules support resolution of these cases by allowing 1st wins, last wins, concatenation of the duplicate entry contents or raising an exception. """ @classmethod def skip_signatures_and_duplicates_concat_well_known_metadata( cls, default_dup_action=None, additional_rules=None): """Produces a rule set useful in many deploy jar creation contexts. The rule set skips duplicate entries by default, retaining the 1st encountered. In addition it has the following special handling: - jar signature metadata is dropped - jar indexing files INDEX.LIST are dropped - ``java.util.ServiceLoader`` provider-configuration files are concatenated in the order encountered :param default_dup_action: An optional default action to take for duplicates. Defaults to `Duplicate.SKIP` if not specified. :param additional_rules: Optionally one or more jar rules to add to those described above. :returns: JarRules """ default_dup_action = Duplicate.validate_action(default_dup_action or Duplicate.SKIP) additional_rules = assert_list(additional_rules, expected_type=(Duplicate, Skip)) rules = [ Skip(r'^META-INF/[^/]+\.SF$'), # signature file Skip(r'^META-INF/[^/]+\.DSA$'), # default signature alg. file Skip(r'^META-INF/[^/]+\.RSA$'), # default signature alg. file Skip(r'^META-INF/INDEX.LIST$' ), # interferes with Class-Path: see man jar for i option Duplicate(r'^META-INF/services/', Duplicate.CONCAT) ] # 1 svc fqcn per line return JarRules(rules=rules + additional_rules, default_dup_action=default_dup_action) _DEFAULT = None @classmethod def default(cls): """Returns the default set of jar rules. Can be set with `set_default` but otherwise defaults to `skip_signatures_and_duplicates_concat_well_known_metadata`. """ if cls._DEFAULT is None: cls._DEFAULT = cls.skip_signatures_and_duplicates_concat_well_known_metadata( ) return cls._DEFAULT @classmethod def set_default(cls, rules): """Sets the default site-wide jar rules.""" if not isinstance(rules, JarRules): raise ValueError('The default rules must be a JarRules instance.') cls._DEFAULT = rules def __init__(self, rules=None, default_dup_action=Duplicate.SKIP): """Creates a new set of jar rules with the default duplicate action of ``Duplicate.SKIP``. :param rules: One or more rules that will be applied in order to jar entries being packaged in a deploy jar. `Skip <#Skip>`_ rules can go here. :param default_dup_action: The default action to take when a duplicate entry is encountered and no explicit rules apply to the entry. """ self.payload = Payload() self.payload.add_fields({ 'default_dup_action': PrimitiveField(Duplicate.validate_action(default_dup_action)) }) self._rules = assert_list(rules, expected_type=JarRule, key_arg="rules") @property def default_dup_action(self): """The default action to take when a duplicate jar entry is encountered.""" return self.payload.default_dup_action @property def rules(self): """A copy of the list of explicit entry rules in effect.""" return list(self._rules) def fingerprint(self): hasher = sha1() hasher.update(self.payload.fingerprint()) for rule in self.rules: hasher.update(rule.fingerprint()) return hasher.hexdigest() @property def value(self): return self._jar_rules
def __init__(self, address, source, *args, **kwargs): payload = Payload() payload.add_fields({'sources': self.create_sources_field(sources=[source], sources_rel_path=address.spec_path)}) self.source = source super(DummyLibrary, self).__init__(address=address, payload=payload, *args, **kwargs)
def __init__(self, sources=None, entry_point=None, inherit_path=False, # pex option zip_safe=True, # pex option always_write_cache=False, # pex option repositories=None, # pex option indices=None, # pex option ignore_errors=False, # pex option shebang=None, # pex option emit_warnings=None, # pex option platforms=(), **kwargs): """ :param string entry_point: the default entry point for this binary. if None, drops into the entry point that is defined by source. Something like "pants.bin.pants_exe:main", where "pants.bin.pants_exe" is the package name and "main" is the function name (if ommitted, the module is executed directly, presuming it has a ``__main.py__``). :param sources: Zero or one source files. If more than one file is required, it should be put in a python_library which should be added to dependencies. :param inherit_path: inherit the sys.path of the environment that this binary runs in :param zip_safe: whether or not this binary is safe to run in compacted (zip-file) form :param always_write_cache: whether or not the .deps cache of this PEX file should always be written to disk. :param repositories: a list of repositories to query for dependencies. :param indices: a list of indices to use for packages. :param ignore_errors: should we ignore inability to resolve dependencies? :param str shebang: Use this shebang for the generated pex. :param bool emit_warnings: Whether or not to emit pex warnings. :param platforms: extra platforms to target when building this binary. If this is, e.g., ``['current', 'linux-x86_64', 'macosx-10.4-x86_64']``, then when building the pex, then for any platform-dependent modules, Pants will include ``egg``\\s for Linux (64-bit Intel), Mac OS X (version 10.4 or newer), and the current platform (whatever is being used when making the PEX). """ if inherit_path is False: inherit_path = "false" payload = Payload() payload.add_fields({ 'entry_point': PrimitiveField(entry_point), 'inherit_path': PrimitiveField(inherit_path), 'zip_safe': PrimitiveField(bool(zip_safe)), 'always_write_cache': PrimitiveField(bool(always_write_cache)), 'repositories': PrimitiveField(maybe_list(repositories or [])), 'indices': PrimitiveField(maybe_list(indices or [])), 'ignore_errors': PrimitiveField(bool(ignore_errors)), 'platforms': PrimitiveField(tuple(maybe_list(platforms or []))), 'shebang': PrimitiveField(shebang), 'emit_warnings': PrimitiveField(self.Defaults.should_emit_warnings(emit_warnings)), }) super(PythonBinary, self).__init__(sources=sources, payload=payload, **kwargs) if (not sources or not sources.files) and entry_point is None: raise TargetDefinitionException(self, 'A python binary target must specify either a single source or entry_point.') if not isinstance(platforms, (list, tuple)) and not isinstance(platforms, string_types): raise TargetDefinitionException(self, 'platforms must be a list, tuple or string.') if sources and sources.files and entry_point: entry_point_module = entry_point.split(':', 1)[0] entry_source = list(self.sources_relative_to_source_root())[0] source_entry_point = self._translate_to_entry_point(entry_source) if entry_point_module != source_entry_point: raise TargetDefinitionException(self, 'Specified both source and entry_point but they do not agree: {} vs {}'.format( source_entry_point, entry_point_module))
def __init__( self, source=None, entry_point=None, inherit_path=False, # pex option zip_safe=True, # pex option always_write_cache=False, # pex option repositories=None, # pex option indices=None, # pex option ignore_errors=False, # pex option platforms=(), **kwargs): """ :param source: relative path to one python source file that becomes this binary's __main__. If None specified, drops into an interpreter by default. :param string entry_point: the default entry point for this binary. if None, drops into the entry point that is defined by source. Something like "pants.bin.pants_exe:main", where "pants.bin.pants_exe" is the package name and "main" is the function name (if ommitted, the module is executed directly, presuming it has a ``__main.py__``). :param sources: Overridden by source. To specify more than one source file, use a python_library and have the python_binary depend on that library. :param inherit_path: inherit the sys.path of the environment that this binary runs in :param zip_safe: whether or not this binary is safe to run in compacted (zip-file) form :param always_write_cache: whether or not the .deps cache of this PEX file should always be written to disk. :param repositories: a list of repositories to query for dependencies. :param indices: a list of indices to use for packages. :param ignore_errors: should we ignore inability to resolve dependencies? :param platforms: extra platforms to target when building this binary. If this is, e.g., ``['current', 'linux-x86_64', 'macosx-10.4-x86_64']``, then when building the pex, then for any platform-dependent modules, Pants will include ``egg``\s for Linux (64-bit Intel), Mac OS X (version 10.4 or newer), and the current platform (whatever is being used when making the PEX). :param compatibility: either a string or list of strings that represents interpreter compatibility for this target, using the Requirement-style format, e.g. ``'CPython>=3', or just ['>=2.7','<3']`` for requirements agnostic to interpreter class. """ payload = Payload() payload.add_fields({ 'entry_point': PrimitiveField(entry_point), 'inherit_path': PrimitiveField(bool(inherit_path)), 'zip_safe': PrimitiveField(bool(zip_safe)), 'always_write_cache': PrimitiveField(bool(always_write_cache)), 'repositories': PrimitiveField(maybe_list(repositories or [])), 'indices': PrimitiveField(maybe_list(indices or [])), 'ignore_errors': PrimitiveField(bool(ignore_errors)), 'platforms': PrimitiveField(tuple(maybe_list(platforms or []))), }) sources = [] if source is None else [source] super(PythonBinary, self).__init__(sources=sources, payload=payload, **kwargs) if source is None and entry_point is None: raise TargetDefinitionException( self, 'A python binary target must specify either source or entry_point.' ) if not isinstance(platforms, (list, tuple)) and not isinstance( platforms, string_types): raise TargetDefinitionException( self, 'platforms must be a list, tuple or string.') if source and entry_point: entry_point_module = entry_point.split(':', 1)[0] entry_source = list(self.sources_relative_to_source_root())[0] source_entry_point = self._translate_to_entry_point(entry_source) if entry_point_module != source_entry_point: raise TargetDefinitionException( self, 'Specified both source and entry_point but they do not agree: {} vs {}' .format(source_entry_point, entry_point_module))
def __init__( self, sources=None, entry_point=None, inherit_path=False, # pex option zip_safe=True, # pex option always_write_cache=False, # pex option ignore_errors=False, # pex option shebang=None, # pex option emit_warnings=None, # pex option platforms=(), **kwargs): """ :param string entry_point: the default entry point for this binary. if None, drops into the entry point that is defined by source. Something like "pants.bin.pants_exe:main", where "pants.bin.pants_exe" is the package name and "main" is the function name (if omitted, the module is executed directly, presuming it has a ``__main.py__``). :param sources: Zero or one source files. If more than one file is required, it should be put in a python_library which should be added to dependencies. :param inherit_path: inherit the sys.path of the environment that this binary runs in :param zip_safe: whether or not this binary is safe to run in compacted (zip-file) form :param always_write_cache: whether or not the .deps cache of this PEX file should always be written to disk. :param ignore_errors: should we ignore inability to resolve dependencies? :param str shebang: Use this shebang for the generated pex. :param bool emit_warnings: Whether or not to emit pex warnings. :param platforms: extra platforms to target when building this binary. If this is, e.g., ``['current', 'linux-x86_64', 'macosx-10.4-x86_64']``, then when building the pex, then for any platform-dependent modules, Pants will include ``egg``\\s for Linux (64-bit Intel), Mac OS X (version 10.4 or newer), and the current platform (whatever is being used when making the PEX). """ if inherit_path is False: inherit_path = "false" payload = Payload() payload.add_fields({ "entry_point": PrimitiveField(entry_point), "inherit_path": PrimitiveField(inherit_path), "zip_safe": PrimitiveField(bool(zip_safe)), "always_write_cache": PrimitiveField(bool(always_write_cache)), "ignore_errors": PrimitiveField(bool(ignore_errors)), "platforms": PrimitiveField( tuple(ensure_str_list(platforms or [], allow_single_str=True))), "shebang": PrimitiveField(shebang), "emit_warnings": PrimitiveField(self.Defaults.should_emit_warnings(emit_warnings)), }) super().__init__(sources=sources, payload=payload, **kwargs) if (not sources or not sources.files) and entry_point is None: raise TargetDefinitionException( self, "A python binary target must specify either a single source or entry_point." ) if not isinstance(platforms, (list, tuple)) and not isinstance(platforms, str): raise TargetDefinitionException( self, "platforms must be a list, tuple or str.") if sources and sources.files and entry_point: entry_point_module = entry_point.split(":", 1)[0] entry_source = list(self.sources_relative_to_source_root())[0] source_entry_point = self.translate_source_path_to_py_module_specifier( entry_source) if entry_point_module != source_entry_point: raise TargetDefinitionException( self, "Specified both source and entry_point but they do not agree: {} vs {}" .format(source_entry_point, entry_point_module), )
class JarRules(FingerprintedMixin): """A set of rules for packaging up a deploy jar. Deploy jars are executable jars with fully self-contained classpaths and as such, assembling them presents problems given jar semantics. One issue is signed jars that must be included on the classpath. These have a signature that depends on the jar contents and assembly of the deploy jar changes the content of the jar, breaking the signatures. For cases like these the signed jars must be verified and then the signature information thrown away. The `Skip <#Skip>`_ rule supports this sort of issue by allowing outright entry exclusion in the final deploy jar. Another issue is duplicate jar entries. Although the underlying zip format supports these, the java jar tool and libraries do not. As such some action must be taken for each duplicate entry such that there are no duplicates in the final deploy jar. The four `Duplicate <#Duplicate>`_ rules support resolution of these cases by allowing 1st wins, last wins, concatenation of the duplicate entry contents or raising an exception. """ @classmethod def skip_signatures_and_duplicates_concat_well_known_metadata(cls, default_dup_action=None, additional_rules=None): """Produces a rule set useful in many deploy jar creation contexts. The rule set skips duplicate entries by default, retaining the 1st encountered. In addition it has the following special handling: - jar signature metadata is dropped - ``java.util.ServiceLoader`` provider-configuration files are concatenated in the order encountered :param default_dup_action: An optional default action to take for duplicates. Defaults to `Duplicate.SKIP` if not specified. :param additional_rules: Optionally one or more jar rules to add to those described above. :returns: JarRules """ default_dup_action = Duplicate.validate_action(default_dup_action or Duplicate.SKIP) additional_rules = assert_list(additional_rules, expected_type=(Duplicate, Skip)) rules = [Skip(r'^META-INF/[^/]+\.SF$'), # signature file Skip(r'^META-INF/[^/]+\.DSA$'), # default signature alg. file Skip(r'^META-INF/[^/]+\.RSA$'), # default signature alg. file Duplicate(r'^META-INF/services/', Duplicate.CONCAT)] # 1 svc fqcn per line return JarRules(rules=rules + additional_rules, default_dup_action=default_dup_action) _DEFAULT = None @classmethod def default(cls): """Returns the default set of jar rules. Can be set with `set_default` but otherwise defaults to `skip_signatures_and_duplicates_concat_well_known_metadata`. """ if cls._DEFAULT is None: cls._DEFAULT = cls.skip_signatures_and_duplicates_concat_well_known_metadata() return cls._DEFAULT @classmethod def set_default(cls, rules): """Sets the default site-wide jar rules.""" if not isinstance(rules, JarRules): raise ValueError('The default rules must be a JarRules instance.') cls._DEFAULT = rules def __init__(self, rules=None, default_dup_action=Duplicate.SKIP): """Creates a new set of jar rules with the default duplicate action of ``Duplicate.SKIP``. :param rules: One or more rules that will be applied in order to jar entries being packaged in a deploy jar. `Skip <#Skip>`_ rules can go here. :param default_dup_action: The default action to take when a duplicate entry is encountered and no explicit rules apply to the entry. """ self.payload = Payload() self.payload.add_fields({ 'default_dup_action' : PrimitiveField(Duplicate.validate_action(default_dup_action)) }) self._rules = assert_list(rules, expected_type=JarRule) @property def default_dup_action(self): """The default action to take when a duplicate jar entry is encountered.""" return self.payload.default_dup_action @property def rules(self): """A copy of the list of explicit entry rules in effect.""" return list(self._rules) def fingerprint(self): hasher = sha1() hasher.update(self.payload.fingerprint()) for rule in self.rules: hasher.update(rule.fingerprint()) return hasher.hexdigest() @property def value(self): return self._jar_rules
def __init__(self, source=None, entry_point=None, inherit_path=False, # pex option zip_safe=True, # pex option always_write_cache=False, # pex option repositories=None, # pex option indices=None, # pex option ignore_errors=False, # pex option shebang=None, # pex option platforms=(), **kwargs): """ :param source: relative path to one python source file that becomes this binary's __main__. If None specified, drops into an interpreter by default. :param string entry_point: the default entry point for this binary. if None, drops into the entry point that is defined by source. Something like "pants.bin.pants_exe:main", where "pants.bin.pants_exe" is the package name and "main" is the function name (if ommitted, the module is executed directly, presuming it has a ``__main.py__``). :param sources: Overridden by source. To specify more than one source file, use a python_library and have the python_binary depend on that library. :param inherit_path: inherit the sys.path of the environment that this binary runs in :param zip_safe: whether or not this binary is safe to run in compacted (zip-file) form :param always_write_cache: whether or not the .deps cache of this PEX file should always be written to disk. :param repositories: a list of repositories to query for dependencies. :param indices: a list of indices to use for packages. :param ignore_errors: should we ignore inability to resolve dependencies? :param platforms: extra platforms to target when building this binary. If this is, e.g., ``['current', 'linux-x86_64', 'macosx-10.4-x86_64']``, then when building the pex, then for any platform-dependent modules, Pants will include ``egg``\s for Linux (64-bit Intel), Mac OS X (version 10.4 or newer), and the current platform (whatever is being used when making the PEX). :param compatibility: either a string or list of strings that represents interpreter compatibility for this target, using the Requirement-style format, e.g. ``'CPython>=3', or just ['>=2.7','<3']`` for requirements agnostic to interpreter class. """ if inherit_path is False: inherit_path = "false" payload = Payload() payload.add_fields({ 'entry_point': PrimitiveField(entry_point), 'inherit_path': PrimitiveField(inherit_path), 'zip_safe': PrimitiveField(bool(zip_safe)), 'always_write_cache': PrimitiveField(bool(always_write_cache)), 'repositories': PrimitiveField(maybe_list(repositories or [])), 'indices': PrimitiveField(maybe_list(indices or [])), 'ignore_errors': PrimitiveField(bool(ignore_errors)), 'platforms': PrimitiveField(tuple(maybe_list(platforms or []))), 'shebang': PrimitiveField(shebang), }) sources = [] if source is None else [source] super(PythonBinary, self).__init__(sources=sources, payload=payload, **kwargs) if source is None and entry_point is None: raise TargetDefinitionException(self, 'A python binary target must specify either source or entry_point.') if not isinstance(platforms, (list, tuple)) and not isinstance(platforms, string_types): raise TargetDefinitionException(self, 'platforms must be a list, tuple or string.') if source and entry_point: entry_point_module = entry_point.split(':', 1)[0] entry_source = list(self.sources_relative_to_source_root())[0] source_entry_point = self._translate_to_entry_point(entry_source) if entry_point_module != source_entry_point: raise TargetDefinitionException(self, 'Specified both source and entry_point but they do not agree: {} vs {}'.format( source_entry_point, entry_point_module))