Пример #1
0
def freeze(dist):
    """Freeze the given distribution data using py2exe."""
    includes = dist.includes
    excludes = dist.excludes
    options = dist.freezer_options
    #  Merge in any encludes/excludes given in freezer_options
    includes.append("esky")
    for inc in options.pop("includes", ()):
        includes.append(inc)
    for exc in options.pop("excludes", ()):
        excludes.append(exc)
    if "pypy" not in includes and "pypy" not in excludes:
        excludes.append("pypy")
    #  py2exe expects some arguments on the main distribution object.
    #  We handle data_files ourselves, so fake it out for py2exe.
    if getattr(dist.distribution, "console", None):
        msg = "don't call setup(console=[...]) with esky;"
        msg += " use setup(scripts=[...]) instead"
        raise RuntimeError(msg)
    if getattr(dist.distribution, "windows", None):
        msg = "don't call setup(windows=[...]) with esky;"
        msg += " use setup(scripts=[...]) instead"
        raise RuntimeError(msg)
    dist.distribution.console = []
    dist.distribution.windows = []
    my_data_files = dist.distribution.data_files
    dist.distribution.data_files = []
    for exe in dist.get_executables():
        #  Pass any executable kwds through to py2exe.
        #  We handle "icon" and "gui_only" ourselves.
        s = exe._kwds.copy()
        s["script"] = exe.script
        s["dest_base"] = exe.name[:-4]
        if exe.icon is not None and "icon_resources" not in s:
            s["icon_resources"] = [(1, exe.icon)]
        if exe.gui_only:
            dist.distribution.windows.append(s)
        else:
            dist.distribution.console.append(s)
    if "zipfile" in options:
        dist.distribution.zipfile = options.pop("zipfile")
    #  Create the py2exe cmd and adjust its options
    cmd = custom_py2exe(dist.distribution)
    cmd.includes = includes
    cmd.excludes = excludes
    if "bundle_files" in options:
        if options["bundle_files"] < 3 and dist.compile_bootstrap_exes:
            err = "can't compile bootstrap exes when bundle_files < 3"
            raise RuntimeError(err)
    for (nm, val) in options.iteritems():
        setattr(cmd, nm, val)
    cmd.dist_dir = dist.freeze_dir
    cmd.finalize_options()
    #  Actually run the freeze process
    cmd.run()
    #  Copy data files into the freeze dir
    dist.distribution.data_files = my_data_files
    for (src, dst) in dist.get_data_files():
        dst = os.path.join(dist.freeze_dir, dst)
        dstdir = os.path.dirname(dst)
        if not os.path.isdir(dstdir):
            dist.mkpath(dstdir)
        dist.copy_file(src, dst)
    #  Place a marker file so we know how it was frozen
    os.mkdir(os.path.join(dist.freeze_dir, ESKY_CONTROL_DIR))
    marker_file = os.path.join(ESKY_CONTROL_DIR,
                               "f-py2exe-%d%d.txt") % sys.version_info[:2]
    open(os.path.join(dist.freeze_dir, marker_file), "w").close()
    #  Copy package data into the library.zip
    #  For now, we don't try to put package data into a bundled zipfile.
    dist_zipfile = dist.distribution.zipfile
    if dist_zipfile is None:
        for (src, arcnm) in dist.get_package_data():
            err = "zipfile=None can't be used with package_data (yet...)"
            raise RuntimeError(err)
    elif not cmd.skip_archive:
        lib = zipfile.ZipFile(os.path.join(dist.freeze_dir, dist_zipfile), "a")
        for (src, arcnm) in dist.get_package_data():
            lib.write(src, arcnm)
        lib.close()
    else:
        for (src, arcnm) in dist.get_package_data():
            lib = os.path.join(dist.freeze_dir, os.path.dirname(dist_zipfile))
            dest = os.path.join(lib, os.path.dirname(src))
            f = os.path.basename(src)
            if not os.path.isdir(dest):
                dist.mkpath(dest)
            dist.copy_file(src, os.path.join(dest, f))
    #  There's no need to copy library.zip into the bootstrap env, as the
    #  chainloader will run before py2exe goes looking for it.
    pass
    #  Create the bootstraping code, using custom code if specified.
    #  It gets stored as a marshalled list of code objects directly in the exe.
    esky_name = dist.distribution.get_name()
    code_source = ["__esky_name__ = %r" % (esky_name, )]
    code_source.append(inspect.getsource(esky.bootstrap))
    if dist.compile_bootstrap_exes:
        from esky.bdist_esky import pypy_libpython
        from esky.bdist_esky import pypy_winres
        code_source.append(inspect.getsource(pypy_libpython))
        code_source.append(inspect.getsource(pypy_winres))
        code_source.append(_CUSTOM_PYPY_CHAINLOADER)
        code_source.append(dist.get_bootstrap_code())
        code_source = "\n".join(code_source)
        for exe in dist.get_executables(normalise=False):
            if not exe.include_in_bootstrap_env:
                continue
            fexe = os.path.join(dist.freeze_dir, exe.name)
            bsexe = dist.compile_to_bootstrap_exe(exe, code_source)
            winres.copy_safe_resources(fexe, bsexe)
        #  We may also need the bundled MSVCRT libs
        for nm in os.listdir(dist.freeze_dir):
            if is_core_dependency(nm) and nm.startswith("Microsoft"):
                dist.copy_to_bootstrap_env(nm)
    else:
        code_source.append(_FAKE_ESKY_BOOTSTRAP_MODULE)
        code_source.append(_CUSTOM_WIN32_CHAINLOADER)
        code_source.append(dist.get_bootstrap_code())
        code_source.append("bootstrap()")
        code_source = "\n".join(code_source)
        code = marshal.dumps([compile(code_source, "__main__.py", "exec")])
        #  Copy any core dependencies into the bootstrap env.
        for nm in os.listdir(dist.freeze_dir):
            if is_core_dependency(nm):
                dist.copy_to_bootstrap_env(nm)
        #  Copy the loader program for each script into the bootstrap env.
        for exe in dist.get_executables(normalise=False):
            if not exe.include_in_bootstrap_env:
                continue
            exepath = dist.copy_to_bootstrap_env(exe.name)
            #  Read the py2exe metadata from the frozen exe.  We will
            #  need to duplicate some of these fields when to rewrite it.
            coderes = winres.load_resource(exepath, u"PYTHONSCRIPT", 1, 0)
            headsz = struct.calcsize("iiii")
            (magic, optmz, unbfrd,
             codesz) = struct.unpack("iiii", coderes[:headsz])
            assert magic == 0x78563412
            #  Insert the bootstrap code into the exe as a resource.
            #  This appears to have the happy side-effect of stripping any
            #  extra data from the end of the exe, which is exactly what we
            #  want when zipfile=None is specified; otherwise each bootstrap
            #  exe would also contain the whole bundled zipfile.
            coderes = struct.pack(
                "iiii",
                magic,  # magic value used for integrity checking,
                optmz,  # optimization level to enable
                unbfrd,  # whether to use unbuffered output
                len(code),
            ) + b"\x00" + code + b"\x00\x00"
            winres.add_resource(exepath, coderes, u"PYTHONSCRIPT", 1, 0)
        #  If the python dll hasn't been copied into the bootstrap env,
        #  make sure it's stored in each bootstrap dll as a resource.
        pydll = u"python%d%d.dll" % sys.version_info[:2]
        if not os.path.exists(os.path.join(dist.bootstrap_dir, pydll)):
            buf = ctypes.create_string_buffer(3000)
            GetModuleFileNameA = ctypes.windll.kernel32.GetModuleFileNameA
            if not GetModuleFileNameA(sys.dllhandle, ctypes.byref(buf), 3000):
                raise ctypes.WinError()
            with open(buf.value, "rb") as f:
                pydll_bytes = f.read()
            for exe in dist.get_executables(normalise=False):
                if not exe.include_in_bootstrap_env:
                    continue
                exepath = os.path.join(dist.bootstrap_dir, exe.name)
                try:
                    winres.load_resource(exepath, pydll.upper(), 1, 0)
                except EnvironmentError:
                    winres.add_resource(exepath, pydll_bytes, pydll.upper(), 1,
                                        0)
Пример #2
0
def freeze(dist):
    """Freeze the given distribution data using py2exe."""
    includes = dist.includes
    excludes = dist.excludes
    options = dist.freezer_options
    #  Merge in any encludes/excludes given in freezer_options
    includes.append("esky")
    for inc in options.pop("includes",()):
        includes.append(inc)
    for exc in options.pop("excludes",()):
        excludes.append(exc)
    if "pypy" not in includes and "pypy" not in excludes:
        excludes.append("pypy")
    #  py2exe expects some arguments on the main distribution object.
    #  We handle data_files ourselves, so fake it out for py2exe.
    if getattr(dist.distribution,"console",None):
        msg = "don't call setup(console=[...]) with esky;"
        msg += " use setup(scripts=[...]) instead"
        raise RuntimeError(msg)
    if getattr(dist.distribution,"windows",None):
        msg = "don't call setup(windows=[...]) with esky;"
        msg += " use setup(scripts=[...]) instead"
        raise RuntimeError(msg)
    dist.distribution.console = []
    dist.distribution.windows = []
    my_data_files = dist.distribution.data_files
    dist.distribution.data_files = []
    for exe in dist.get_executables():
        #  Pass any executable kwds through to py2exe.
        #  We handle "icon" and "gui_only" ourselves.
        s = exe._kwds.copy()
        s["script"] = exe.script
        s["dest_base"] = exe.name[:-4]
        if exe.icon is not None and "icon_resources" not in s:
            s["icon_resources"] = [(1,exe.icon)]
        if exe.gui_only:
            dist.distribution.windows.append(s)
        else:
            dist.distribution.console.append(s)
    if "zipfile" in options:
        dist.distribution.zipfile = options.pop("zipfile")
    #  Create the py2exe cmd and adjust its options
    cmd = custom_py2exe(dist.distribution)
    cmd.includes = includes
    cmd.excludes = excludes
    if "bundle_files" in options:
        if options["bundle_files"] < 3 and dist.compile_bootstrap_exes:
             err = "can't compile bootstrap exes when bundle_files < 3"
             raise RuntimeError(err)
    for (nm,val) in options.iteritems():
        setattr(cmd,nm,val)
    cmd.dist_dir = dist.freeze_dir
    cmd.finalize_options()
    #  Actually run the freeze process
    cmd.run()
    #  Copy data files into the freeze dir
    dist.distribution.data_files = my_data_files
    for (src,dst) in dist.get_data_files():
        dst = os.path.join(dist.freeze_dir,dst)
        dstdir = os.path.dirname(dst)
        if not os.path.isdir(dstdir):
            dist.mkpath(dstdir)
        dist.copy_file(src,dst)
    #  Place a marker file so we know how it was frozen
    os.mkdir(os.path.join(dist.freeze_dir,ESKY_CONTROL_DIR))
    marker_file = os.path.join(ESKY_CONTROL_DIR,"f-py2exe-%d%d.txt")%sys.version_info[:2]
    open(os.path.join(dist.freeze_dir,marker_file),"w").close()
    #  Copy package data into the library.zip
    #  For now, we don't try to put package data into a bundled zipfile.
    dist_zipfile = dist.distribution.zipfile
    if dist_zipfile is None:
        for (src,arcnm) in dist.get_package_data():
            err = "zipfile=None can't be used with package_data (yet...)"
            raise RuntimeError(err)
    elif not cmd.skip_archive:
        lib = zipfile.ZipFile(os.path.join(dist.freeze_dir,dist_zipfile),"a")
        for (src,arcnm) in dist.get_package_data():
            lib.write(src,arcnm)
        lib.close()
    else:
        for (src,arcnm) in dist.get_package_data():
            lib = os.path.join(dist.freeze_dir,os.path.dirname(dist_zipfile))
            dest = os.path.join(lib, os.path.dirname(src))
            f = os.path.basename(src)
            if not os.path.isdir(dest):
                dist.mkpath(dest)
            dist.copy_file(src,os.path.join(dest, f))
    #  There's no need to copy library.zip into the bootstrap env, as the
    #  chainloader will run before py2exe goes looking for it.
    pass
    #  Create the bootstraping code, using custom code if specified.
    #  It gets stored as a marshalled list of code objects directly in the exe.
    esky_name = dist.distribution.get_name()
    code_source = ["__esky_name__ = %r" % (esky_name,)]
    code_source.append(inspect.getsource(esky.bootstrap))
    if dist.compile_bootstrap_exes:
        from esky.bdist_esky import pypy_libpython
        from esky.bdist_esky import pypy_winres
        code_source.append(inspect.getsource(pypy_libpython))
        code_source.append(inspect.getsource(pypy_winres))
        code_source.append(_CUSTOM_PYPY_CHAINLOADER)
        code_source.append(dist.get_bootstrap_code())
        code_source = "\n".join(code_source)
        for exe in dist.get_executables(normalise=False):
            if not exe.include_in_bootstrap_env:
                continue
            fexe = os.path.join(dist.freeze_dir,exe.name)
            bsexe = dist.compile_to_bootstrap_exe(exe,code_source)
            winres.copy_safe_resources(fexe,bsexe)
        #  We may also need the bundled MSVCRT libs
        for nm in os.listdir(dist.freeze_dir):
            if is_core_dependency(nm) and nm.startswith("Microsoft"):
                dist.copy_to_bootstrap_env(nm)
    else:
        code_source.append(_FAKE_ESKY_BOOTSTRAP_MODULE)
        code_source.append(_CUSTOM_WIN32_CHAINLOADER)
        code_source.append(dist.get_bootstrap_code())
        code_source.append("bootstrap()")
        code_source = "\n".join(code_source)
        code = marshal.dumps([compile(code_source,"__main__.py","exec")])
        #  Copy any core dependencies into the bootstrap env.
        for nm in os.listdir(dist.freeze_dir):
            if is_core_dependency(nm):
                dist.copy_to_bootstrap_env(nm)
        #  Copy the loader program for each script into the bootstrap env.
        for exe in dist.get_executables(normalise=False):
            if not exe.include_in_bootstrap_env:
                continue
            exepath = dist.copy_to_bootstrap_env(exe.name)
            #  Read the py2exe metadata from the frozen exe.  We will
            #  need to duplicate some of these fields when to rewrite it.
            coderes = winres.load_resource(exepath,u"PYTHONSCRIPT",1,0)
            headsz = struct.calcsize("iiii")
            (magic,optmz,unbfrd,codesz) = struct.unpack("iiii",coderes[:headsz])
            assert magic == 0x78563412
            #  Insert the bootstrap code into the exe as a resource.
            #  This appears to have the happy side-effect of stripping any
            #  extra data from the end of the exe, which is exactly what we
            #  want when zipfile=None is specified; otherwise each bootstrap
            #  exe would also contain the whole bundled zipfile.
            coderes = struct.pack("iiii",
                         magic, # magic value used for integrity checking,
                         optmz, # optimization level to enable
                         unbfrd,  # whether to use unbuffered output
                         len(code),
                      ) + "\x00" + code + "\x00\x00"
            winres.add_resource(exepath,coderes,u"PYTHONSCRIPT",1,0)
        #  If the python dll hasn't been copied into the bootstrap env,
        #  make sure it's stored in each bootstrap dll as a resource.
        pydll = u"python%d%d.dll" % sys.version_info[:2]
        if not os.path.exists(os.path.join(dist.bootstrap_dir,pydll)):
            buf = ctypes.create_string_buffer(3000)
            GetModuleFileNameA = ctypes.windll.kernel32.GetModuleFileNameA
            if not GetModuleFileNameA(sys.dllhandle,ctypes.byref(buf),3000):
                raise ctypes.WinError()
            with open(buf.value,"rb") as f:
                pydll_bytes = f.read()
            for exe in dist.get_executables(normalise=False):
                if not exe.include_in_bootstrap_env:
                    continue
                exepath = os.path.join(dist.bootstrap_dir,exe.name)
                try:
                    winres.load_resource(exepath,pydll.upper(),1,0)
                except EnvironmentError:
                    winres.add_resource(exepath,pydll_bytes,pydll.upper(),1,0)
Пример #3
0
def freeze(dist):
    """Freeze the given distribution data using py2exe."""
    includes = dist.includes
    excludes = dist.excludes
    options = dist.freezer_options
    #  Merge in any encludes/excludes given in freezer_options
    includes.append("esky")
    for inc in options.pop("includes",()):
        includes.append(inc)
    for exc in options.pop("excludes",()):
        excludes.append(exc)
    #  py2exe expects some arguments on the main distribution object.
    #  We handle data_files ourselves, so fake it out for py2exe.
    dist.distribution.console = []
    dist.distribution.windows = []
    my_data_files = dist.distribution.data_files
    dist.distribution.data_files = []
    for exe in dist.get_executables():
        #  Pass any executable kwds through to py2exe.
        #  We handle "icon" and "gui_only" ourselves.
        s = exe._kwds.copy()
        s["script"] = exe.script
        s["dest_base"] = exe.name[:-4]
        if exe.icon is not None and "icon_resources" not in s:
            s["icon_resources"] = [(1,exe.icon)]
        if exe.gui_only:
            dist.distribution.windows.append(s)
        else:
            dist.distribution.console.append(s)
    if "zipfile" in options:
        dist.distribution.zipfile = options.pop("zipfile")
    #  Create the py2exe cmd and adjust its options
    cmd = custom_py2exe(dist.distribution)
    cmd.includes = includes
    cmd.excludes = excludes
    for (nm,val) in options.iteritems():
        setattr(cmd,nm,val)
    cmd.dist_dir = dist.freeze_dir
    cmd.finalize_options()
    #  Actually run the freeze process
    cmd.run()
    #  Copy data files into the freeze dir
    dist.distribution.data_files = my_data_files
    for (src,dst) in dist.get_data_files():
        dst = os.path.join(dist.freeze_dir,dst)
        dstdir = os.path.dirname(dst)
        if not os.path.isdir(dstdir):
            dist.mkpath(dstdir)
        dist.copy_file(src,dst)
    #  Place a marker fileso we know how it was frozen
    os.mkdir(os.path.join(dist.freeze_dir,ESKY_CONTROL_DIR))
    marker_file = os.path.join(ESKY_CONTROL_DIR,"f-py2exe-%d%d.txt")%sys.version_info[:2]
    open(os.path.join(dist.freeze_dir,marker_file),"w").close()
    #  Copy package data into the library.zip
    #  For now, we don't try to put package data into a bundled zipfile.
    if dist.distribution.zipfile is not None:
        lib = zipfile.ZipFile(os.path.join(dist.freeze_dir,"library.zip"),"a")
        for (src,arcnm) in dist.get_package_data():
            lib.write(src,arcnm)
        lib.close()
    else:
        for (src,arcnm) in dist.get_package_data():
            err = "zipfile=None can't be used with package_data (yet...)"
            raise RuntimeError(err)
    #  There's no need to copy library.zip into the bootstrap env, as the
    #  chainloader will run before py2exe goes looking for it.
    pass
    #  Create the bootstraping code, using custom code if specified.
    #  It gets stored as a marshalled list of code objects directly in the exe.
    code_source = [inspect.getsource(esky.bootstrap)]
    code_source.append(_FAKE_ESKY_BOOTSTRAP_MODULE)
    code_source.append(_CUSTOM_WIN32_CHAINLOADER)
    code_source.append("__esky_name__ = '%s'" % (dist.distribution.get_name(),))
    code_source.append(dist.get_bootstrap_code())
    code_source.append("bootstrap()")
    code_source = "\n".join(code_source)
    code = marshal.dumps([compile(code_source,"__main__.py","exec")])
    coderes = struct.pack("iiii",
                     0x78563412, # a magic value used for integrity checking,
                     0, # no optimization
                     False,  # normal buffered output
                     len(code),
                     ) + "\x00" + code + "\x00\x00"
    #  We try to bundle the python DLL into all bootstrap executables, even
    #  if it's not bundled in the frozen distribution.  This helps keep the
    #  bootstrap env small and minimises the chances of something going wrong.
    pydll = u"python%d%d.dll" % sys.version_info[:2]
    frozen_pydll = os.path.join(dist.freeze_dir,pydll)
    if os.path.exists(frozen_pydll):
        for nm in os.listdir(dist.freeze_dir):
            if nm == pydll:
                continue
            if nm.lower().endswith(".pyd") or nm.lower().endswith(".dll"):
                #  There's an unbundled C-extension, so we can't bundle
                #  the DLL or our bootstrapper won't work.
                pydll_bytes = None
                break
        else:
            with open(frozen_pydll,"rb") as f:
                pydll_bytes = f.read()
    else:
        #  They've bundlded the dll into the zipfile.  Rather than parse
        #  it back out, I'm just going to grab it from the filesystem.
        sz = 0
        res = 0
        while res == sz:
            sz += 512
            buf = ctypes.create_string_buffer(sz)
            res = ctypes.windll.kernel32.GetModuleFileNameA(sys.dllhandle,ctypes.byref(buf),sz)
            if not res:
                raise ctypes.WinError()
        with open(buf.value,"rb") as f:
            pydll_bytes = f.read()
    #  Copy any core dependencies into the bootstrap env.
    for nm in os.listdir(dist.freeze_dir):
        if is_core_dependency(nm):
            if nm == pydll and pydll_bytes is not None:
                continue
            dist.copy_to_bootstrap_env(nm)
    #  Copy the loader program for each script into the bootstrap env.
    for exe in dist.get_executables(normalise=False):
        if not exe.include_in_bootstrap_env:
            continue
        exepath = dist.copy_to_bootstrap_env(exe.name)
        #  Insert the bootstrap code into the exe as a resource.
        #  This appears to have the happy side-effect of stripping any extra
        #  data from the end of the exe, which is exactly what we want when
        #  zipfile=None is specified; otherwise each bootstrap EXE would also
        #  contain the whole bundled zipfile.
        winres.add_resource(exepath,coderes,u"PYTHONSCRIPT",1,0)
        #  Inline the pythonXY.dll as a resource in the exe.
        if pydll_bytes is not None:
            winres.add_resource(exepath,pydll_bytes,pydll.upper(),1,0)