Imported from SVN by Bitbucket
This commit is contained in:
417
PasteScript-1.7.4.2-py2.6.egg/paste/script/create_distro.py
Executable file
417
PasteScript-1.7.4.2-py2.6.egg/paste/script/create_distro.py
Executable file
@@ -0,0 +1,417 @@
|
||||
# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
|
||||
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
import pkg_resources
|
||||
from command import Command, BadCommand
|
||||
import copydir
|
||||
import pluginlib
|
||||
import fnmatch
|
||||
try:
|
||||
set
|
||||
except NameError:
|
||||
from sets import Set as set
|
||||
|
||||
class CreateDistroCommand(Command):
|
||||
|
||||
usage = 'PACKAGE_NAME [VAR=VALUE VAR2=VALUE2 ...]'
|
||||
summary = "Create the file layout for a Python distribution"
|
||||
short_description = summary
|
||||
|
||||
description = """\
|
||||
Create a new project. Projects are typically Python packages,
|
||||
ready for distribution. Projects are created from templates, and
|
||||
represent different kinds of projects -- associated with a
|
||||
particular framework for instance.
|
||||
"""
|
||||
|
||||
parser = Command.standard_parser(
|
||||
simulate=True, no_interactive=True, quiet=True, overwrite=True)
|
||||
parser.add_option('-t', '--template',
|
||||
dest='templates',
|
||||
metavar='TEMPLATE',
|
||||
action='append',
|
||||
help="Add a template to the create process")
|
||||
parser.add_option('-o', '--output-dir',
|
||||
dest='output_dir',
|
||||
metavar='DIR',
|
||||
default='.',
|
||||
help="Write put the directory into DIR (default current directory)")
|
||||
parser.add_option('--svn-repository',
|
||||
dest='svn_repository',
|
||||
metavar='REPOS',
|
||||
help="Create package at given repository location (this will create the standard trunk/ tags/ branches/ hierarchy)")
|
||||
parser.add_option('--list-templates',
|
||||
dest='list_templates',
|
||||
action='store_true',
|
||||
help="List all templates available")
|
||||
parser.add_option('--list-variables',
|
||||
dest="list_variables",
|
||||
action="store_true",
|
||||
help="List all variables expected by the given template (does not create a package)")
|
||||
parser.add_option('--inspect-files',
|
||||
dest='inspect_files',
|
||||
action='store_true',
|
||||
help="Show where the files in the given (already created) directory came from (useful when using multiple templates)")
|
||||
parser.add_option('--config',
|
||||
action='store',
|
||||
dest='config',
|
||||
help="Template variables file")
|
||||
|
||||
_bad_chars_re = re.compile('[^a-zA-Z0-9_]')
|
||||
|
||||
default_verbosity = 1
|
||||
default_interactive = 1
|
||||
|
||||
def command(self):
|
||||
if self.options.list_templates:
|
||||
return self.list_templates()
|
||||
asked_tmpls = self.options.templates or ['basic_package']
|
||||
templates = []
|
||||
for tmpl_name in asked_tmpls:
|
||||
self.extend_templates(templates, tmpl_name)
|
||||
if self.options.list_variables:
|
||||
return self.list_variables(templates)
|
||||
if self.verbose:
|
||||
print 'Selected and implied templates:'
|
||||
max_tmpl_name = max([len(tmpl_name) for tmpl_name, tmpl in templates])
|
||||
for tmpl_name, tmpl in templates:
|
||||
print ' %s%s %s' % (
|
||||
tmpl_name, ' '*(max_tmpl_name-len(tmpl_name)),
|
||||
tmpl.summary)
|
||||
print
|
||||
if not self.args:
|
||||
if self.interactive:
|
||||
dist_name = self.challenge('Enter project name')
|
||||
else:
|
||||
raise BadCommand('You must provide a PACKAGE_NAME')
|
||||
else:
|
||||
dist_name = self.args[0].lstrip(os.path.sep)
|
||||
|
||||
templates = [tmpl for name, tmpl in templates]
|
||||
output_dir = os.path.join(self.options.output_dir, dist_name)
|
||||
|
||||
pkg_name = self._bad_chars_re.sub('', dist_name.lower())
|
||||
vars = {'project': dist_name,
|
||||
'package': pkg_name,
|
||||
'egg': pluginlib.egg_name(dist_name),
|
||||
}
|
||||
vars.update(self.parse_vars(self.args[1:]))
|
||||
if self.options.config and os.path.exists(self.options.config):
|
||||
for key, value in self.read_vars(self.options.config).items():
|
||||
vars.setdefault(key, value)
|
||||
|
||||
if self.verbose: # @@: > 1?
|
||||
self.display_vars(vars)
|
||||
|
||||
if self.options.inspect_files:
|
||||
self.inspect_files(
|
||||
output_dir, templates, vars)
|
||||
return
|
||||
if not os.path.exists(output_dir):
|
||||
# We want to avoid asking questions in copydir if the path
|
||||
# doesn't exist yet
|
||||
copydir.all_answer = 'y'
|
||||
|
||||
if self.options.svn_repository:
|
||||
self.setup_svn_repository(output_dir, dist_name)
|
||||
|
||||
# First we want to make sure all the templates get a chance to
|
||||
# set their variables, all at once, with the most specialized
|
||||
# template going first (the last template is the most
|
||||
# specialized)...
|
||||
for template in templates[::-1]:
|
||||
vars = template.check_vars(vars, self)
|
||||
|
||||
# Gather all the templates egg_plugins into one var
|
||||
egg_plugins = set()
|
||||
for template in templates:
|
||||
egg_plugins.update(template.egg_plugins)
|
||||
egg_plugins = list(egg_plugins)
|
||||
egg_plugins.sort()
|
||||
vars['egg_plugins'] = egg_plugins
|
||||
|
||||
for template in templates:
|
||||
self.create_template(
|
||||
template, output_dir, vars)
|
||||
|
||||
found_setup_py = False
|
||||
paster_plugins_mtime = None
|
||||
if os.path.exists(os.path.join(output_dir, 'setup.py')):
|
||||
# Grab paster_plugins.txt's mtime; used to determine if the
|
||||
# egg_info command wrote to it
|
||||
try:
|
||||
egg_info_dir = pluginlib.egg_info_dir(output_dir, dist_name)
|
||||
except IOError:
|
||||
egg_info_dir = None
|
||||
if egg_info_dir is not None:
|
||||
plugins_path = os.path.join(egg_info_dir, 'paster_plugins.txt')
|
||||
if os.path.exists(plugins_path):
|
||||
paster_plugins_mtime = os.path.getmtime(plugins_path)
|
||||
|
||||
self.run_command(sys.executable, 'setup.py', 'egg_info',
|
||||
cwd=output_dir,
|
||||
# This shouldn't be necessary, but a bug in setuptools 0.6c3 is causing a (not entirely fatal) problem that I don't want to fix right now:
|
||||
expect_returncode=True)
|
||||
found_setup_py = True
|
||||
elif self.verbose > 1:
|
||||
print 'No setup.py (cannot run egg_info)'
|
||||
|
||||
package_dir = vars.get('package_dir', None)
|
||||
if package_dir:
|
||||
output_dir = os.path.join(output_dir, package_dir)
|
||||
|
||||
# With no setup.py this doesn't make sense:
|
||||
if found_setup_py:
|
||||
# Only write paster_plugins.txt if it wasn't written by
|
||||
# egg_info (the correct way). leaving us to do it is
|
||||
# deprecated and you'll get warned
|
||||
egg_info_dir = pluginlib.egg_info_dir(output_dir, dist_name)
|
||||
plugins_path = os.path.join(egg_info_dir, 'paster_plugins.txt')
|
||||
if len(egg_plugins) and (not os.path.exists(plugins_path) or \
|
||||
os.path.getmtime(plugins_path) == paster_plugins_mtime):
|
||||
if self.verbose:
|
||||
print >> sys.stderr, \
|
||||
('Manually creating paster_plugins.txt (deprecated! '
|
||||
'pass a paster_plugins keyword to setup() instead)')
|
||||
for plugin in egg_plugins:
|
||||
if self.verbose:
|
||||
print 'Adding %s to paster_plugins.txt' % plugin
|
||||
if not self.simulate:
|
||||
pluginlib.add_plugin(egg_info_dir, plugin)
|
||||
|
||||
if self.options.svn_repository:
|
||||
self.add_svn_repository(vars, output_dir)
|
||||
|
||||
if self.options.config:
|
||||
write_vars = vars.copy()
|
||||
del write_vars['project']
|
||||
del write_vars['package']
|
||||
self.write_vars(self.options.config, write_vars)
|
||||
|
||||
def create_template(self, template, output_dir, vars):
|
||||
if self.verbose:
|
||||
print 'Creating template %s' % template.name
|
||||
template.run(self, output_dir, vars)
|
||||
|
||||
def setup_svn_repository(self, output_dir, dist_name):
|
||||
# @@: Use subprocess
|
||||
svn_repos = self.options.svn_repository
|
||||
svn_repos_path = os.path.join(svn_repos, dist_name).replace('\\','/')
|
||||
svn_command = 'svn'
|
||||
if sys.platform == 'win32':
|
||||
svn_command += '.exe'
|
||||
# @@: The previous method of formatting this string using \ doesn't work on Windows
|
||||
cmd = '%(svn_command)s mkdir %(svn_repos_path)s' + \
|
||||
' %(svn_repos_path)s/trunk %(svn_repos_path)s/tags' + \
|
||||
' %(svn_repos_path)s/branches -m "New project %(dist_name)s"'
|
||||
cmd = cmd % {
|
||||
'svn_repos_path': svn_repos_path,
|
||||
'dist_name': dist_name,
|
||||
'svn_command':svn_command,
|
||||
}
|
||||
if self.verbose:
|
||||
print "Running:"
|
||||
print cmd
|
||||
if not self.simulate:
|
||||
os.system(cmd)
|
||||
svn_repos_path_trunk = os.path.join(svn_repos_path,'trunk').replace('\\','/')
|
||||
cmd = svn_command+' co "%s" "%s"' % (svn_repos_path_trunk, output_dir)
|
||||
if self.verbose:
|
||||
print "Running %s" % cmd
|
||||
if not self.simulate:
|
||||
os.system(cmd)
|
||||
|
||||
ignore_egg_info_files = [
|
||||
'top_level.txt',
|
||||
'entry_points.txt',
|
||||
'requires.txt',
|
||||
'PKG-INFO',
|
||||
'namespace_packages.txt',
|
||||
'SOURCES.txt',
|
||||
'dependency_links.txt',
|
||||
'not-zip-safe']
|
||||
|
||||
def add_svn_repository(self, vars, output_dir):
|
||||
svn_repos = self.options.svn_repository
|
||||
egg_info_dir = pluginlib.egg_info_dir(output_dir, vars['project'])
|
||||
svn_command = 'svn'
|
||||
if sys.platform == 'win32':
|
||||
svn_command += '.exe'
|
||||
self.run_command(svn_command, 'add', '-N', egg_info_dir)
|
||||
paster_plugins_file = os.path.join(
|
||||
egg_info_dir, 'paster_plugins.txt')
|
||||
if os.path.exists(paster_plugins_file):
|
||||
self.run_command(svn_command, 'add', paster_plugins_file)
|
||||
self.run_command(svn_command, 'ps', 'svn:ignore',
|
||||
'\n'.join(self.ignore_egg_info_files),
|
||||
egg_info_dir)
|
||||
if self.verbose:
|
||||
print ("You must next run 'svn commit' to commit the "
|
||||
"files to repository")
|
||||
|
||||
def extend_templates(self, templates, tmpl_name):
|
||||
if '#' in tmpl_name:
|
||||
dist_name, tmpl_name = tmpl_name.split('#', 1)
|
||||
else:
|
||||
dist_name, tmpl_name = None, tmpl_name
|
||||
if dist_name is None:
|
||||
for entry in self.all_entry_points():
|
||||
if entry.name == tmpl_name:
|
||||
tmpl = entry.load()(entry.name)
|
||||
dist_name = entry.dist.project_name
|
||||
break
|
||||
else:
|
||||
raise LookupError(
|
||||
'Template by name %r not found' % tmpl_name)
|
||||
else:
|
||||
dist = pkg_resources.get_distribution(dist_name)
|
||||
entry = dist.get_entry_info(
|
||||
'paste.paster_create_template', tmpl_name)
|
||||
tmpl = entry.load()(entry.name)
|
||||
full_name = '%s#%s' % (dist_name, tmpl_name)
|
||||
for item_full_name, item_tmpl in templates:
|
||||
if item_full_name == full_name:
|
||||
# Already loaded
|
||||
return
|
||||
for req_name in tmpl.required_templates:
|
||||
self.extend_templates(templates, req_name)
|
||||
templates.append((full_name, tmpl))
|
||||
|
||||
def all_entry_points(self):
|
||||
if not hasattr(self, '_entry_points'):
|
||||
self._entry_points = list(pkg_resources.iter_entry_points(
|
||||
'paste.paster_create_template'))
|
||||
return self._entry_points
|
||||
|
||||
def display_vars(self, vars):
|
||||
vars = vars.items()
|
||||
vars.sort()
|
||||
print 'Variables:'
|
||||
max_var = max([len(n) for n, v in vars])
|
||||
for name, value in vars:
|
||||
print ' %s:%s %s' % (
|
||||
name, ' '*(max_var-len(name)), value)
|
||||
|
||||
def list_templates(self):
|
||||
templates = []
|
||||
for entry in self.all_entry_points():
|
||||
try:
|
||||
templates.append(entry.load()(entry.name))
|
||||
except Exception, e:
|
||||
# We will not be stopped!
|
||||
print 'Warning: could not load entry point %s (%s: %s)' % (
|
||||
entry.name, e.__class__.__name__, e)
|
||||
max_name = max([len(t.name) for t in templates])
|
||||
templates.sort(lambda a, b: cmp(a.name, b.name))
|
||||
print 'Available templates:'
|
||||
for template in templates:
|
||||
# @@: Wrap description
|
||||
print ' %s:%s %s' % (
|
||||
template.name,
|
||||
' '*(max_name-len(template.name)),
|
||||
template.summary)
|
||||
|
||||
def inspect_files(self, output_dir, templates, vars):
|
||||
file_sources = {}
|
||||
for template in templates:
|
||||
self._find_files(template, vars, file_sources)
|
||||
self._show_files(output_dir, file_sources)
|
||||
self._show_leftovers(output_dir, file_sources)
|
||||
|
||||
def _find_files(self, template, vars, file_sources):
|
||||
tmpl_dir = template.template_dir()
|
||||
self._find_template_files(
|
||||
template, tmpl_dir, vars, file_sources)
|
||||
|
||||
def _find_template_files(self, template, tmpl_dir, vars,
|
||||
file_sources, join=''):
|
||||
full_dir = os.path.join(tmpl_dir, join)
|
||||
for name in os.listdir(full_dir):
|
||||
if name.startswith('.'):
|
||||
continue
|
||||
if os.path.isdir(os.path.join(full_dir, name)):
|
||||
self._find_template_files(
|
||||
template, tmpl_dir, vars, file_sources,
|
||||
join=os.path.join(join, name))
|
||||
continue
|
||||
partial = os.path.join(join, name)
|
||||
for name, value in vars.items():
|
||||
partial = partial.replace('+%s+' % name, value)
|
||||
if partial.endswith('_tmpl'):
|
||||
partial = partial[:-5]
|
||||
file_sources.setdefault(partial, []).append(template)
|
||||
|
||||
_ignore_filenames = ['.*', '*.pyc', '*.bak*']
|
||||
_ignore_dirs = ['CVS', '_darcs', '.svn']
|
||||
|
||||
def _show_files(self, output_dir, file_sources, join='', indent=0):
|
||||
pad = ' '*(2*indent)
|
||||
full_dir = os.path.join(output_dir, join)
|
||||
names = os.listdir(full_dir)
|
||||
dirs = [n for n in names
|
||||
if os.path.isdir(os.path.join(full_dir, n))]
|
||||
fns = [n for n in names
|
||||
if not os.path.isdir(os.path.join(full_dir, n))]
|
||||
dirs.sort()
|
||||
names.sort()
|
||||
for name in names:
|
||||
skip_this = False
|
||||
for ext in self._ignore_filenames:
|
||||
if fnmatch.fnmatch(name, ext):
|
||||
if self.verbose > 1:
|
||||
print '%sIgnoring %s' % (pad, name)
|
||||
skip_this = True
|
||||
break
|
||||
if skip_this:
|
||||
continue
|
||||
partial = os.path.join(join, name)
|
||||
if partial not in file_sources:
|
||||
if self.verbose > 1:
|
||||
print '%s%s (not from template)' % (pad, name)
|
||||
continue
|
||||
templates = file_sources.pop(partial)
|
||||
print '%s%s from:' % (pad, name)
|
||||
for template in templates:
|
||||
print '%s %s' % (pad, template.name)
|
||||
for dir in dirs:
|
||||
if dir in self._ignore_dirs:
|
||||
continue
|
||||
print '%sRecursing into %s/' % (pad, dir)
|
||||
self._show_files(
|
||||
output_dir, file_sources,
|
||||
join=os.path.join(join, dir),
|
||||
indent=indent+1)
|
||||
|
||||
def _show_leftovers(self, output_dir, file_sources):
|
||||
if not file_sources:
|
||||
return
|
||||
print
|
||||
print 'These files were supposed to be generated by templates'
|
||||
print 'but were not found:'
|
||||
file_sources = file_sources.items()
|
||||
file_sources.sort()
|
||||
for partial, templates in file_sources:
|
||||
print ' %s from:' % partial
|
||||
for template in templates:
|
||||
print ' %s' % template.name
|
||||
|
||||
def list_variables(self, templates):
|
||||
for tmpl_name, tmpl in templates:
|
||||
if not tmpl.read_vars():
|
||||
if self.verbose > 1:
|
||||
self._show_template_vars(
|
||||
tmpl_name, tmpl, 'No variables found')
|
||||
continue
|
||||
self._show_template_vars(tmpl_name, tmpl)
|
||||
|
||||
def _show_template_vars(self, tmpl_name, tmpl, message=None):
|
||||
title = '%s (from %s)' % (tmpl.name, tmpl_name)
|
||||
print title
|
||||
print '-'*len(title)
|
||||
if message is not None:
|
||||
print ' %s' % message
|
||||
print
|
||||
return
|
||||
tmpl.print_vars(indent=2)
|
||||
Reference in New Issue
Block a user