Plone技术论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 活动 交友 discuz
查看: 4101|回复: 0

自动配置开发环境脚本赏析

[复制链接]
发表于 2012-3-11 08:25:07 | 显示全部楼层 |阅读模式
这是Martin Aspeli 的最新贡献,目前支持Plone4.1,不久将支持Plone4.2,
下载网址: https://github.com/plone/plone-devstart/raw/master/plone-devstart.py

  1. #!/usr/bin/python
  2. """Create a "safe" Plone development environment starting from nothing but
  3. Python.

  4. Usage::

  5.     $ python plone-devstart <dirname>

  6. If directory name is omitted, the current directory is used.

  7. This will:

  8. * Download ``virtualenv.py`` and ``bootstrap.py``
  9. * Run it with the current interpreter to create an isolated development
  10.   environment
  11. * Create and bootstrap a new buildout for Plone using this interpreter

  12. You will be asked several questions along the way
  13. """

  14. import optparse
  15. import os
  16. import os.path
  17. import sys
  18. import httplib
  19. import urlparse
  20. import urllib2
  21. import subprocess
  22. import zipfile
  23. import tempfile
  24. import distutils.ccompiler
  25. import distutils.sysconfig

  26. # Version of this script
  27. devstart_version = "0.1"

  28. # Base Python version and skeleton location for each base Plone version (to minor version)
  29. plone_versions = {
  30.     '4.1' : {
  31.         'python_version': '2.6',
  32.         'skeleton_url': 'https://github.com/plone/plone-devstart/raw/master/closet/plone-4.1.zip',
  33.     },
  34. }
  35. default_version = '4.1'

  36. config = {
  37.     'virtualenv_url': "https://raw.github.com/pypa/virtualenv/master/virtualenv.py",
  38.     'bootstrap_url' : "http://python-distribute.org/bootstrap.py",
  39.     'plone_kgs_url' : "http://dist.plone.org/release/%(plone_version)s/versions.cfg",
  40.     'pilcheck':
  41. """
  42. #include <stdio.h>
  43. #include <jpeglib.h>
  44. #include <zlib.h>
  45. int main(void) {}
  46. """,
  47. }

  48. is_windows = sys.platform[:3] == 'win'

  49. # Utilities

  50. def download(url, directory, filename):
  51.     """Download the given file into the given (or current) directory
  52.     """

  53.     # Thanks to http://stackoverflow.com/questions/22676/how-do-i-download-a-file-over-http-using-python
  54.     u = urllib2.urlopen(url)
  55.     f = open(os.path.join(directory, filename), 'wb')
  56.     meta = u.info()
  57.     file_size = int(meta.getheaders("Content-Length")[0])
  58.     print "> Downloading: %s (%d bytes)" % (filename, file_size)

  59.     file_size_dl = 0
  60.     block_sz = 8192
  61.     while True:
  62.         buffer = u.read(block_sz)
  63.         if not buffer:
  64.             break

  65.         file_size_dl += len(buffer)
  66.         f.write(buffer)
  67.         status = r"%10d  [%3.2f%%]" % (file_size_dl, file_size_dl * 100. / file_size)
  68.         status = status + chr(8)*(len(status)+1)
  69.         print status,
  70.     print
  71.     f.close()

  72. def run(command, *args, **kw):
  73.     """Run the given command
  74.     """
  75.     print "> Running:", command, ' '.join(args)
  76.     try:
  77.         return subprocess.call([command] + list(args), stdout=kw.get('stdout'), stderr=kw.get('stderr')) == 0
  78.     except OSError:
  79.         return False

  80. def ask(prompt, default=None):
  81.     """Ask a question and return the response entered by the user
  82.     """
  83.     if default:
  84.         prompt = prompt + " [%s] " % default
  85.     answer = raw_input(prompt)
  86.     if not answer and default:
  87.         answer = default
  88.     return answer

  89. def check_url(url):
  90.     """Check to see if the given URL exists
  91.     """

  92.     split = urlparse.urlsplit(url)
  93.     connection = httplib.HTTPConnection(split.netloc, port=split.port)
  94.     connection.request('HEAD', split.path)
  95.     response = connection.getresponse()
  96.     return response.status == 200

  97. def get_base_version(version):
  98.     """Turn a specific Plone or Python version into a base version
  99.     """
  100.     return '.'.join(version.split('.')[:2])

  101. # Verification

  102. def check_python(version_config):
  103.     """Given an intended Plone version, determine if the current Python version
  104.     is acceptable
  105.     """

  106.     python_version = version_config['python_version'].split('.')
  107.     for i, e in enumerate(python_version):
  108.         if i >= len(sys.version_info) or str(sys.version_info[i]) != e:
  109.             return False
  110.     return True

  111. def check_python_headers(version_config):
  112.     """Validate if Python header files are installed
  113.     """
  114.     directory = distutils.sysconfig.get_python_inc()
  115.     python_header = os.path.join(directory, 'Python.h')
  116.     return os.path.isfile(python_header)

  117. def check_compiler():
  118.     """Check if there is a usable compiler installed
  119.     """
  120.     compilers = distutils.ccompiler.new_compiler().compiler
  121.     if not compilers:
  122.         return False

  123.     return run(compilers[0], '--version')

  124. def check_zlib():
  125.     """Check if zlib is installed
  126.     """
  127.     try:
  128.         import zlib
  129.         return True
  130.     except ImportError:
  131.         return False

  132. def check_ssl():
  133.     """Check if Pyton has SSL support
  134.     """
  135.     try:
  136.         import _ssl
  137.         return True
  138.     except ImportError:
  139.         return False

  140. def check_pil_libraries():
  141.     """Check if the appropriate header files exist for PIL
  142.     """
  143.     c_fd, c_name = tempfile.mkstemp(suffix='.c')
  144.     a_fd, a_name = tempfile.mkstemp(suffix='.out')

  145.     try:
  146.         c_file = os.fdopen(c_fd, 'w')
  147.         c_file.write(config['pilcheck'])
  148.         c_file.close()

  149.         return run('cc', '-o', a_name, c_name)
  150.     finally:
  151.         os.unlink(c_name)
  152.         os.unlink(a_name)

  153. # Execution

  154. def main():

  155.     parser = optparse.OptionParser()
  156.     parser.add_option("-v", "--version", dest="version",
  157.         help="Use the given Plone version", metavar="VERSION"
  158.     )
  159.     parser.add_option("-f", "--force", action="store_true", dest="force", default=False,
  160.         help="Force creation of files even if they appear to exist already"
  161.     )

  162.     options, args = parser.parse_args()

  163.     directory =  os.getcwd()
  164.     if len(args) > 0:
  165.         directory = args[0]
  166.     directory = os.path.abspath(directory)

  167.     print
  168.     print "Welcome to plone-devstart (version %s)" % devstart_version
  169.     print "Press Ctrl+C any time to abort"
  170.     print

  171.     version = options.version

  172.     if not version:
  173.         print "Please enter the Plone version you would like to start with."
  174.         print "Version numbers can be found at http://dist.plone.org/release"
  175.         print
  176.         print "plone-devstart knows about the following base versions:"
  177.         print
  178.         print "  ", ", ".join(sorted(plone_versions.keys()))
  179.         print
  180.         print "You can use a more specific revision of any of these, e.g. 4.1.2"
  181.         print

  182.         version = ask("Enter a Plone version number", default_version)

  183.     base_version = get_base_version(version)
  184.     while base_version not in plone_versions:
  185.         print
  186.         print "plone-devstart does not know what to do with this version."
  187.         print "Known versions start with one of:", ", ".join(sorted(plone_versions.keys()))
  188.         print "Please try again or press Ctrl+C to abort."
  189.         print

  190.         version = ask("Enter a Plone version number", default_version)
  191.         base_version = get_base_version(version)

  192.     version_config = plone_versions[base_version]

  193.     kgs_url = config['plone_kgs_url'] % {'plone_version': version}
  194.     print
  195.     print "* Checking for known good versions set at"
  196.     print "  ", kgs_url, "..."
  197.     if not check_url(kgs_url):
  198.         print
  199.         print "** WARNING: No known good set found at"
  200.         print kgs_url
  201.         print "Plone build will likely fail."
  202.         print
  203.         ask("Press Enter to continue, or Ctrl+C to abort")
  204.     else:
  205.         print "Done"

  206.     print
  207.     print "* Checking Python version compatibility"
  208.     if not check_python(version_config):
  209.         print
  210.         print "** WARNING: The current Python version is not known to work with Plone", version
  211.         print "The expected Python version is", version_config['python_version'], "but this script is being run with Python"
  212.         print "version", '.'.join([str(s) for s in sys.version_info]) + '.', "Plone build may fail."
  213.         print
  214.         ask("Press Enter to continue, or Ctrl+C to abort")

  215.     if not is_windows:

  216.         print
  217.         print "* Checking for a viable C compiler"
  218.         if not check_compiler():
  219.             print
  220.             print "** WARNING: Unable to find a C compiler (``cc``). Building Python packages with"
  221.             print "C extensions is likely to fail. You may need to install an operating system"
  222.             print "package like ``gcc``."
  223.             print
  224.             ask("Press Enter to continue, or Ctrl+C to abort")
  225.         else:
  226.             print "Done"

  227.         print
  228.         print "* Checking for Python header files"
  229.         if not check_python_headers(version_config):
  230.             print
  231.             print "** WARNING: Unable to find Python header files. Building Python packages with"
  232.             print "C extensions is likely to fail. You may need to install an operating system"
  233.             print "package like ``python-dev`` or ``python-devel``, or compile Python from source."
  234.             print
  235.             ask("Press Enter to continue, or Ctrl+C to abort")
  236.         else:
  237.             print "Done"

  238.         print
  239.         print "* Checking if image libraries are installed"
  240.         if not check_pil_libraries():
  241.             print
  242.             print "** WARNING: Unable to find ``libjpeg`` and ``zlib`` header files. Building"
  243.             print "PIL mail fail. You may need to install an operating system package like"
  244.             print "``jpeglib-dev`` or ``jpeglib-devel``."
  245.             print
  246.             ask("Press Enter to continue, or Ctrl+C to abort")
  247.         else:
  248.             print "Done"

  249.     print
  250.     print "* Checking for zlib support"
  251.     if not check_zlib():
  252.         print
  253.         print "** WARNING: Python does not have zlib support. Some Plone funtions may not work."
  254.         print "You may need to install an operating system package like ``zlib-dev`` or"
  255.         print "``zlib-devel`` and then reinstall or recompile Python."
  256.         print
  257.         ask("Press Enter to continue, or Ctrl+C to abort")
  258.     else:
  259.         print "Done"

  260.     print
  261.     print "* Checking for SSL support"
  262.     if not check_ssl():
  263.         print
  264.         print "** WARNING: Python does not have SSL support. Downloading of some packages may"
  265.         print "fail. You may need to install an operating system package like ``openssl-dev``"
  266.         print "or ``openssl-devel`` and then reinstall or recompile Python."
  267.         print
  268.         ask("Press Enter to continue, or Ctrl+C to abort")
  269.     else:
  270.         print "Done"

  271.     print
  272.     print "* Creating build in directory", directory
  273.     if not options.force:
  274.         print
  275.         ask("Press Enter to continue, or Ctrl+C to abort")
  276.     create_directory(directory)
  277.     print "Done"

  278.     print
  279.     print "* Creating virtual Python environment"
  280.     create_virtualenv(directory)
  281.     print "Done"

  282.     print
  283.     print "* Installing PIL"
  284.     install_pil(directory)
  285.     print "Done"

  286.     print
  287.     print "* Obtaining skeleton buildout"
  288.     if not options.force and os.path.exists(os.path.join(directory, 'buildout.cfg')):
  289.         print
  290.         print "** WARNING: It looks like there is already a buildout.cfg file here."
  291.         print "plone-devstart will not overwrite it or recreate any other files. Use the"
  292.         print "--force command line option if you want to overwrite files."
  293.     else:
  294.         create_buildout(directory, version, version_config, options)
  295.         print "Done"

  296.     print
  297.     print "* Bootstrapping buildout"
  298.     bootstrap(directory)
  299.     print "Done"

  300.     print
  301.     print "All done!"
  302.     print
  303.     print "To build Plone, inspect and modify the generated ``buildout.cfg`` as necessary,"
  304.     print "then run ``bin/buildout`` in the directory", directory


  305. def create_directory(directory):
  306.     """Create the build directory if necessary
  307.     """
  308.     if not os.path.exists(directory):
  309.         os.mkdir(directory)

  310. def create_virtualenv(directory):
  311.     """Create a virtualenv in the given directory
  312.     """
  313.     download(config['virtualenv_url'], directory, 'virtualenv.py')
  314.     run(sys.executable, os.path.join(directory, 'virtualenv.py'), directory)

  315. def install_pil(directory):
  316.     """Install PIL in the virtualenv
  317.     """
  318.     run(os.path.join(directory, 'bin', 'pip'), 'install', 'PIL')

  319. def create_buildout(directory, plone_version, version_config, options):
  320.     """Create a new buildout in the given directory
  321.     """

  322.     # Download
  323.     download(version_config['skeleton_url'], directory, 'buildout-skeleton.zip')

  324.     # Unzip
  325.     skeleton_file = os.path.join(directory, 'buildout-skeleton.zip')
  326.     zf = zipfile.ZipFile(skeleton_file)

  327.     for name in zf.namelist():
  328.         f = zf.open(name)

  329.         target_name = os.path.join(directory, name)
  330.         target_directory = os.path.dirname(target_name)

  331.         if not os.path.exists(target_directory):
  332.             os.makedirs(target_directory)

  333.         if not name.endswith('/'):
  334.             with open(target_name, 'w') as f2:
  335.                 data = f.read()

  336.                 # Interpolate variables into buildout cfg files only
  337.                 if target_name.lower().endswith('.cfg'):
  338.                     data = data % {
  339.                         'plone_kgs_url': config['plone_kgs_url'] % {'plone_version': plone_version},
  340.                     }

  341.                 f2.write(data)
  342.         f.close()

  343.     # Delete the zip file
  344.     os.unlink(skeleton_file)


  345. def bootstrap(directory):
  346.     """Bootstrap the buildout in the given directory
  347.     """
  348.     cwd = os.getcwd()
  349.     download(config['bootstrap_url'], directory, 'bootstrap.py')

  350.     os.chdir(directory)
  351.     run(os.path.join(directory, 'bin', 'python'), 'bootstrap.py')
  352.     os.chdir(cwd)

  353. if __name__ == '__main__':
  354.     main()
复制代码



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|Plone技术论坛 ( 湘ICP备07003419

GMT+8, 2017-9-20 06:48 , Processed in 0.131941 second(s), 10 queries , Gzip On, Memcache On.

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表