def __init__(self, root_dir, relpath=None, must_exist=True): """Creates a BuildFile object representing the BUILD file set at the specified path. :param string root_dir: The base directory of the project :param string relpath: The path relative to root_dir where the BUILD file is found - this can either point directly at the BUILD file or else to a directory which contains BUILD files :param bool must_exist: If True, the specified BUILD file must exist or else an IOError is thrown :raises IOError: if the root_dir path is not absolute :raises MissingBuildFileError: if the path does not house a BUILD file and must_exist is True """ if not os.path.isabs(root_dir): raise self.InvalidRootDirError('BuildFile root_dir {root_dir} must be an absolute path.' .format(root_dir=root_dir)) path = os.path.join(root_dir, relpath) if relpath else root_dir self._build_basename = BuildFile._BUILD_FILE_PREFIX buildfile = os.path.join(path, self._build_basename) if os.path.isdir(path) else path if must_exist: # If the build file must exist then we want to make sure it's not a dir. # In other cases we are ok with it being a dir, for example someone might have # repo/scripts/build/doit.sh. if os.path.isdir(buildfile): raise self.MissingBuildFileError( 'Path to buildfile ({buildfile}) is a directory, but it must be a file.' .format(buildfile=buildfile)) if not os.path.exists(os.path.dirname(buildfile)): raise self.MissingBuildFileError('Path to BUILD file does not exist at: {path}' .format(path=os.path.dirname(buildfile))) # There is no BUILD file without a prefix so select any viable sibling if not os.path.exists(buildfile) or os.path.isdir(buildfile): for build in BuildFile._get_all_build_files(os.path.dirname(buildfile)): self._build_basename = build buildfile = os.path.join(path, self._build_basename) break if must_exist: if not os.path.exists(buildfile): raise self.MissingBuildFileError('BUILD file does not exist at: {path}' .format(path=buildfile)) if not BuildFile._is_buildfile_name(os.path.basename(buildfile)): raise self.MissingBuildFileError('{path} is not a BUILD file' .format(path=buildfile)) self.root_dir = os.path.realpath(root_dir) self.full_path = os.path.realpath(buildfile) self.name = os.path.basename(self.full_path) self.parent_path = os.path.dirname(self.full_path) self._bytecode_path = os.path.join(self.parent_path, '.{name}.{ident}.pyc'.format(name=self.name, ident=PythonIdentity.get())) self.relpath = os.path.relpath(self.full_path, self.root_dir) self.spec_path = os.path.dirname(self.relpath)
def __init__(self, root_dir, relpath=None, must_exist=True): """Creates a BuildFile object representing the BUILD file set at the specified path. :param string root_dir: The base directory of the project :param string relpath: The path relative to root_dir where the BUILD file is found - this can either point directly at the BUILD file or else to a directory which contains BUILD files :param bool must_exist: If True, the specified BUILD file must exist or else an IOError is thrown :raises IOError: if the root_dir path is not absolute :raises MissingBuildFileError: if the path does not house a BUILD file and must_exist is True """ if not os.path.isabs(root_dir): raise self.InvalidRootDirError( 'BuildFile root_dir {root_dir} must be an absolute path.'. format(root_dir=root_dir)) path = os.path.join(root_dir, relpath) if relpath else root_dir self._build_basename = BuildFile._BUILD_FILE_PREFIX buildfile = os.path.join( path, self._build_basename) if os.path.isdir(path) else path if must_exist: # If the build file must exist then we want to make sure it's not a dir. # In other cases we are ok with it being a dir, for example someone might have # repo/scripts/build/doit.sh. if os.path.isdir(buildfile): raise self.MissingBuildFileError( 'Path to buildfile ({buildfile}) is a directory, but it must be a file.' .format(buildfile=buildfile)) if not os.path.exists(os.path.dirname(buildfile)): raise self.MissingBuildFileError( 'Path to BUILD file does not exist at: {path}'.format( path=os.path.dirname(buildfile))) # There is no BUILD file without a prefix so select any viable sibling if not os.path.exists(buildfile) or os.path.isdir(buildfile): for build in BuildFile._get_all_build_files( os.path.dirname(buildfile)): self._build_basename = build buildfile = os.path.join(path, self._build_basename) break if must_exist: if not os.path.exists(buildfile): raise self.MissingBuildFileError( 'BUILD file does not exist at: {path}'.format( path=buildfile)) if not BuildFile._is_buildfile_name(os.path.basename(buildfile)): raise self.MissingBuildFileError( '{path} is not a BUILD file'.format(path=buildfile)) self.root_dir = os.path.realpath(root_dir) self.full_path = os.path.realpath(buildfile) self.name = os.path.basename(self.full_path) self.parent_path = os.path.dirname(self.full_path) self._bytecode_path = os.path.join( self.parent_path, '.{name}.{ident}.pyc'.format(name=self.name, ident=PythonIdentity.get())) self.relpath = os.path.relpath(self.full_path, self.root_dir) self.spec_path = os.path.dirname(self.relpath)
def main(): parser = optparse.OptionParser(usage="usage: %prog [options] output") parser.add_option("--entry-point", default="__main__") parser.add_option("--directory", action="store_true", default=False) parser.add_option( "--no-zip-safe", action="store_false", dest="zip_safe", default=True ) parser.add_option("--python", default="") parser.add_option("--python-version", default="") parser.add_option("--python-shebang", default=None) parser.add_option("--preload", action="append", default=[]) options, args = parser.parse_args() if len(args) == 1: output = args[0] else: parser.error("'output' positional argument is required") return 1 # The manifest is passed via stdin, as it can sometimes get too large # to be passed as a CLA. manifest = json.load(sys.stdin) # The version of pkg_resources.py (from setuptools) on some distros is # too old for PEX. So we keep a recent version in the buck repo and # force it into the process by constructing a custom PythonInterpreter # instance using it. if not options.python: options.python = sys.executable identity = PythonIdentity.get() elif not options.python_version: # Note: this is expensive (~500ms). prefer passing --python-version when possible. identity = PythonInterpreter.from_binary(options.python).identity else: # Convert "CPython 2.7" to "CPython 2 7 0" python_version = options.python_version.replace(".", " ").split() if len(python_version) == 3: python_version.append("0") identity = PythonIdentity.from_id_string(" ".join(python_version)) interpreter = PythonInterpreter(options.python, identity, extras={}) pex_builder = PEXBuilder( path=output if options.directory else None, interpreter=interpreter ) if options.python_shebang is not None: pex_builder.set_shebang(options.python_shebang) # Set whether this PEX as zip-safe, meaning everything will stayed zipped up # and we'll rely on python's zip-import mechanism to load modules from # the PEX. This may not work in some situations (e.g. native # libraries, libraries that want to find resources via the FS). pex_builder.info.zip_safe = options.zip_safe # Set the starting point for this PEX. pex_builder.info.entry_point = options.entry_point # Copy in our version of `pkg_resources` & `_markerlib`. copy_package(pex_builder, "pkg_resources", prefix=pex_builder.BOOTSTRAP_DIR) copy_package(pex_builder, "_markerlib", prefix=pex_builder.BOOTSTRAP_DIR) # Add the sources listed in the manifest. for dst, src in manifest["modules"].items(): # NOTE(agallagher): calls the `add_source` and `add_resource` below # hard-link the given source into the PEX temp dir. Since OS X and # Linux behave different when hard-linking a source that is a # symbolic link (Linux does *not* follow symlinks), resolve any # layers of symlinks here to get consistent behavior. try: pex_builder.add_source(dereference_symlinks(src), dst) except OSError as e: raise Exception("Failed to add {}: {}".format(src, e)) # Add resources listed in the manifest. for dst, src in manifest["resources"].items(): # NOTE(agallagher): see rationale above. pex_builder.add_resource(dereference_symlinks(src), dst) # Add resources listed in the manifest. for dst, src in manifest["nativeLibraries"].items(): # NOTE(agallagher): see rationale above. pex_builder.add_resource(dereference_symlinks(src), dst) if options.directory: pex_builder.freeze(code_hash=False, bytecode_compile=False) else: pex_builder.build(output)
def main(): parser = optparse.OptionParser(usage="usage: %prog [options] output") parser.add_option("--entry-point", default="__main__") parser.add_option("--directory", action="store_true", default=False) parser.add_option( "--no-zip-safe", action="store_false", dest="zip_safe", default=True ) parser.add_option("--python", default="") parser.add_option("--python-version", default="") parser.add_option("--python-shebang", default=None) parser.add_option("--preload", action="append", default=[]) options, args = parser.parse_args() if len(args) == 1: output = args[0] else: parser.error("'output' positional argument is required") return 1 # The manifest is passed via stdin, as it can sometimes get too large # to be passed as a CLA. manifest = json.load(sys.stdin) # The version of pkg_resources.py (from setuptools) on some distros is # too old for PEX. So we keep a recent version in the buck repo and # force it into the process by constructing a custom PythonInterpreter # instance using it. if not options.python: options.python = sys.executable identity = PythonIdentity.get() elif not options.python_version: # Note: this is expensive (~500ms). prefer passing --python-version when possible. identity = PythonInterpreter.from_binary(options.python).identity else: # Convert "CPython 2.7" to "CPython 2 7 0" python_version = options.python_version.replace(".", " ").split() if len(python_version) == 3: python_version.append("0") identity = PythonIdentity.from_id_string(" ".join(python_version)) interpreter = PythonInterpreter(options.python, identity, extras={}) pex_builder = PEXBuilder( path=output if options.directory else None, interpreter=interpreter ) if options.python_shebang is not None: pex_builder.set_shebang(options.python_shebang) # Set whether this PEX as zip-safe, meaning everything will stayed zipped up # and we'll rely on python's zip-import mechanism to load modules from # the PEX. This may not work in some situations (e.g. native # libraries, libraries that want to find resources via the FS). pex_builder.info.zip_safe = options.zip_safe # Set the starting point for this PEX. pex_builder.info.entry_point = options.entry_point # Copy in our version of `pkg_resources` & `_markerlib`. copy_package(pex_builder, "pkg_resources", prefix=pex_builder.BOOTSTRAP_DIR) copy_package(pex_builder, "_markerlib", prefix=pex_builder.BOOTSTRAP_DIR) # Add the sources listed in the manifest. for dst, src in manifest["modules"].iteritems(): # NOTE(agallagher): calls the `add_source` and `add_resource` below # hard-link the given source into the PEX temp dir. Since OS X and # Linux behave different when hard-linking a source that is a # symbolic link (Linux does *not* follow symlinks), resolve any # layers of symlinks here to get consistent behavior. try: pex_builder.add_source(dereference_symlinks(src), dst) except OSError as e: raise Exception("Failed to add {}: {}".format(src, e)) # Add resources listed in the manifest. for dst, src in manifest["resources"].iteritems(): # NOTE(agallagher): see rationale above. pex_builder.add_resource(dereference_symlinks(src), dst) # Add resources listed in the manifest. for dst, src in manifest["nativeLibraries"].iteritems(): # NOTE(agallagher): see rationale above. pex_builder.add_resource(dereference_symlinks(src), dst) if options.directory: pex_builder.freeze(code_hash=False, bytecode_compile=False) else: pex_builder.build(output)