setup.py
branchstable
changeset 42172 71d8b4d91616
parent 42075 456c37433c43
child 42174 bd92dd3eff42
equal deleted inserted replaced
42149:84b5ad5fc2aa 42172:71d8b4d91616
   935 
   935 
   936             data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape))
   936             data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape))
   937             with open(outfile, 'wb') as fp:
   937             with open(outfile, 'wb') as fp:
   938                 fp.write(data)
   938                 fp.write(data)
   939 
   939 
       
   940 # virtualenv installs custom distutils/__init__.py and
       
   941 # distutils/distutils.cfg files which essentially proxy back to the
       
   942 # "real" distutils in the main Python install. The presence of this
       
   943 # directory causes py2exe to pick up the "hacked" distutils package
       
   944 # from the virtualenv and "import distutils" will fail from the py2exe
       
   945 # build because the "real" distutils files can't be located.
       
   946 #
       
   947 # We work around this by monkeypatching the py2exe code finding Python
       
   948 # modules to replace the found virtualenv distutils modules with the
       
   949 # original versions via filesystem scanning. This is a bit hacky. But
       
   950 # it allows us to use virtualenvs for py2exe packaging, which is more
       
   951 # deterministic and reproducible.
       
   952 #
       
   953 # It's worth noting that the common StackOverflow suggestions for this
       
   954 # problem involve copying the original distutils files into the
       
   955 # virtualenv or into the staging directory after setup() is invoked.
       
   956 # The former is very brittle and can easily break setup(). Our hacking
       
   957 # of the found modules routine has a similar result as copying the files
       
   958 # manually. But it makes fewer assumptions about how py2exe works and
       
   959 # is less brittle.
       
   960 
       
   961 # This only catches virtualenvs made with virtualenv (as opposed to
       
   962 # venv, which is likely what Python 3 uses).
       
   963 py2exehacked = py2exeloaded and getattr(sys, 'real_prefix', None) is not None
       
   964 
       
   965 if py2exehacked:
       
   966     from distutils.command.py2exe import py2exe as buildpy2exe
       
   967     from py2exe.mf import Module as py2exemodule
       
   968 
       
   969     class hgbuildpy2exe(buildpy2exe):
       
   970         def find_needed_modules(self, mf, files, modules):
       
   971             res = buildpy2exe.find_needed_modules(self, mf, files, modules)
       
   972 
       
   973             # Replace virtualenv's distutils modules with the real ones.
       
   974             res.modules = {
       
   975                 k: v for k, v in res.modules.items()
       
   976                 if k != 'distutils' and not k.startswith('distutils.')}
       
   977 
       
   978             import opcode
       
   979             distutilsreal = os.path.join(os.path.dirname(opcode.__file__),
       
   980                                          'distutils')
       
   981 
       
   982             for root, dirs, files in os.walk(distutilsreal):
       
   983                 for f in sorted(files):
       
   984                     if not f.endswith('.py'):
       
   985                         continue
       
   986 
       
   987                     full = os.path.join(root, f)
       
   988 
       
   989                     parents = ['distutils']
       
   990 
       
   991                     if root != distutilsreal:
       
   992                         rel = os.path.relpath(root, distutilsreal)
       
   993                         parents.extend(p for p in rel.split(os.sep))
       
   994 
       
   995                     modname = '%s.%s' % ('.'.join(parents), f[:-3])
       
   996 
       
   997                     if modname.startswith('distutils.tests.'):
       
   998                         continue
       
   999 
       
  1000                     if modname.endswith('.__init__'):
       
  1001                         modname = modname[:-len('.__init__')]
       
  1002                         path = os.path.dirname(full)
       
  1003                     else:
       
  1004                         path = None
       
  1005 
       
  1006                     res.modules[modname] = py2exemodule(modname, full,
       
  1007                                                         path=path)
       
  1008 
       
  1009             if 'distutils' not in res.modules:
       
  1010                 raise SystemExit('could not find distutils modules')
       
  1011 
       
  1012             return res
       
  1013 
   940 cmdclass = {'build': hgbuild,
  1014 cmdclass = {'build': hgbuild,
   941             'build_doc': hgbuilddoc,
  1015             'build_doc': hgbuilddoc,
   942             'build_mo': hgbuildmo,
  1016             'build_mo': hgbuildmo,
   943             'build_ext': hgbuildext,
  1017             'build_ext': hgbuildext,
   944             'build_py': hgbuildpy,
  1018             'build_py': hgbuildpy,
   947             'install': hginstall,
  1021             'install': hginstall,
   948             'install_lib': hginstalllib,
  1022             'install_lib': hginstalllib,
   949             'install_scripts': hginstallscripts,
  1023             'install_scripts': hginstallscripts,
   950             'build_hgexe': buildhgexe,
  1024             'build_hgexe': buildhgexe,
   951             }
  1025             }
       
  1026 
       
  1027 if py2exehacked:
       
  1028     cmdclass['py2exe'] = hgbuildpy2exe
   952 
  1029 
   953 packages = ['mercurial',
  1030 packages = ['mercurial',
   954             'mercurial.cext',
  1031             'mercurial.cext',
   955             'mercurial.cffi',
  1032             'mercurial.cffi',
   956             'mercurial.hgweb',
  1033             'mercurial.hgweb',