setup.py
author Thomas Waldmann <tw AT waldmann-edv DOT de>
Wed, 03 Aug 2011 00:07:16 +0200
changeset 5788 89882824b375
parent 5219 ae076c4adfda
child 5920 fe7003b1cc4d
permissions -rw-r--r--
avoid strange exception in zipfile.py for pre-1980 timestamps
     1 #!/usr/bin/env python
     2 # -*- coding: iso-8859-1 -*-
     3 """
     4     MoinMoin installer
     5 
     6     @copyright: 2001-2005 by Jürgen Hermann <jh@web.de>,
     7                 2006-2007 by MoinMoin:ThomasWaldmann
     8     @license: GNU GPL, see COPYING for details.
     9 """
    10 
    11 import os, sys, glob
    12 
    13 import distutils
    14 from distutils.core import setup
    15 from distutils.command.build_scripts import build_scripts
    16 
    17 from MoinMoin.version import release, revision
    18 
    19 
    20 #############################################################################
    21 ### Helpers
    22 #############################################################################
    23 
    24 def isbad(name):
    25     """ Whether name should not be installed """
    26     return (name.startswith('.') or
    27             name.startswith('#') or
    28             name.endswith('.pickle') or
    29             name == 'CVS')
    30 
    31 def isgood(name):
    32     """ Whether name should be installed """
    33     return not isbad(name)
    34 
    35 def makeDataFiles(prefix, dir):
    36     """ Create distutils data_files structure from dir
    37 
    38     distutil will copy all file rooted under dir into prefix, excluding
    39     dir itself, just like 'ditto src dst' works, and unlike 'cp -r src
    40     dst, which copy src into dst'.
    41 
    42     Typical usage:
    43         # install the contents of 'wiki' under sys.prefix+'share/moin'
    44         data_files = makeDataFiles('share/moin', 'wiki')
    45 
    46     For this directory structure:
    47         root
    48             file1
    49             file2
    50             dir
    51                 file
    52                 subdir
    53                     file
    54 
    55     makeDataFiles('prefix', 'root')  will create this distutil data_files structure:
    56         [('prefix', ['file1', 'file2']),
    57          ('prefix/dir', ['file']),
    58          ('prefix/dir/subdir', ['file'])]
    59 
    60     """
    61     # Strip 'dir/' from of path before joining with prefix
    62     dir = dir.rstrip('/')
    63     strip = len(dir) + 1
    64     found = []
    65     os.path.walk(dir, visit, (prefix, strip, found))
    66     return found
    67 
    68 def visit((prefix, strip, found), dirname, names):
    69     """ Visit directory, create distutil tuple
    70 
    71     Add distutil tuple for each directory using this format:
    72         (destination, [dirname/file1, dirname/file2, ...])
    73 
    74     distutil will copy later file1, file2, ... info destination.
    75     """
    76     files = []
    77     # Iterate over a copy of names, modify names
    78     for name in names[:]:
    79         path = os.path.join(dirname, name)
    80         # Ignore directories -  we will visit later
    81         if os.path.isdir(path):
    82             # Remove directories we don't want to visit later
    83             if isbad(name):
    84                 names.remove(name)
    85             continue
    86         elif isgood(name):
    87             files.append(path)
    88     destination = os.path.join(prefix, dirname[strip:])
    89     found.append((destination, files))
    90 
    91 def make_filelist(dir, strip_prefix=''):
    92     """ package_data is pretty stupid: if the globs that can be given there
    93         match a directory, then setup.py install will fall over that later,
    94         because it expects only files.
    95         Use make_filelist(dir, strip) to create a list of all FILES below dir,
    96         stripping off the strip_prefix at the left side.
    97     """
    98     found = []
    99     def _visit((found, strip), dirname, names):
   100         files = []
   101         for name in names:
   102             path = os.path.join(dirname, name)
   103             if os.path.isfile(path):
   104                 if path.startswith(strip):
   105                     path = path[len(strip):]
   106                 files.append(path)
   107         found.extend(files)
   108 
   109     os.path.walk(dir, _visit, (found, strip_prefix))
   110     return found
   111 
   112 #############################################################################
   113 ### Build script files
   114 #############################################################################
   115 
   116 class build_scripts_create(build_scripts):
   117     """ Overload the build_scripts command and create the scripts
   118         from scratch, depending on the target platform.
   119 
   120         You have to define the name of your package in an inherited
   121         class (due to the delayed instantiation of command classes
   122         in distutils, this cannot be passed to __init__).
   123 
   124         The scripts are created in an uniform scheme: they start the
   125         run() function in the module
   126 
   127             <packagename>.script.<mangled_scriptname>
   128 
   129         The mangling of script names replaces '-' and '/' characters
   130         with '-' and '.', so that they are valid module paths.
   131     """
   132     package_name = None
   133 
   134     def copy_scripts(self):
   135         """ Create each script listed in 'self.scripts'
   136         """
   137         if not self.package_name:
   138             raise Exception("You have to inherit build_scripts_create and"
   139                 " provide a package name")
   140 
   141         self.mkpath(self.build_dir)
   142         for script in self.scripts:
   143             outfile = os.path.join(self.build_dir, os.path.basename(script))
   144 
   145             #if not self.force and not newer(script, outfile):
   146             #    self.announce("not copying %s (up-to-date)" % script)
   147             #    continue
   148 
   149             if self.dry_run:
   150                 self.announce("would create %s" % outfile)
   151                 continue
   152 
   153             module = os.path.splitext(os.path.basename(script))[0]
   154             module = module.replace('-', '_').replace('/', '.')
   155             script_vars = {
   156                 'python': os.path.normpath(sys.executable),
   157                 'package': self.package_name,
   158                 'module': module,
   159                 'package_location': '/usr/lib/python/site-packages', # FIXME: we need to know the correct path
   160             }
   161 
   162             self.announce("creating %s" % outfile)
   163             file = open(outfile, 'w')
   164 
   165             try:
   166                 if sys.platform == "win32":
   167                     file.write('@echo off\n'
   168                         'if NOT "%%_4ver%%" == "" %(python)s -c "from %(package)s.script.%(module)s import run; run()" %%$\n'
   169                         'if     "%%_4ver%%" == "" %(python)s -c "from %(package)s.script.%(module)s import run; run()" %%*\n'
   170                         % script_vars)
   171                 else:
   172                     file.write("#! %(python)s\n"
   173                         "#Fix and uncomment those 2 lines if your moin command doesn't find the MoinMoin package:\n"
   174                         "#import sys\n"
   175                         "#sys.path.insert(0, '%(package_location)s')\n"
   176                         "from %(package)s.script.%(module)s import run\n"
   177                         "run()\n"
   178                         % script_vars)
   179             finally:
   180                 file.close()
   181                 os.chmod(outfile, 0755)
   182 
   183 
   184 class build_scripts_moin(build_scripts_create):
   185     package_name = 'MoinMoin'
   186 
   187 
   188 def scriptname(path):
   189     """ Helper for building a list of script names from a list of
   190         module files.
   191     """
   192     script = os.path.splitext(os.path.basename(path))[0]
   193     script = script.replace('_', '-')
   194     if sys.platform == "win32":
   195         script = script + ".bat"
   196     return script
   197 
   198 # build list of scripts from their implementation modules
   199 moin_scripts = [scriptname(fn) for fn in glob.glob('MoinMoin/script/[!_]*.py')]
   200 
   201 
   202 #############################################################################
   203 ### Call setup()
   204 #############################################################################
   205 
   206 setup_args = {
   207     'name': "moin",
   208     'version': release,
   209     'description': "MoinMoin %s is an easy to use, full-featured and extensible wiki software package" % (release, ),
   210     'author': "Juergen Hermann et al.",
   211     'author_email': "moin-user@lists.sourceforge.net",
   212     # maintainer(_email) not active because distutils/register can't handle author and maintainer at once
   213     'download_url': 'http://static.moinmo.in/files/moin-%s.tar.gz' % (release, ),
   214     'url': "http://moinmo.in/",
   215     'license': "GNU GPL",
   216     'long_description': """
   217     MoinMoin is an easy to use, full-featured and extensible wiki software
   218     package written in Python. It can fulfill a wide range of roles, such as
   219     a personal notes organizer deployed on a laptop or home web server,
   220     a company knowledge base deployed on an intranet, or an Internet server
   221     open to individuals sharing the same interests, goals or projects.""",
   222     'classifiers': """Development Status :: 5 - Production/Stable
   223 Environment :: No Input/Output (Daemon)
   224 Environment :: Web Environment
   225 Environment :: Win32 (MS Windows)
   226 Intended Audience :: Customer Service
   227 Intended Audience :: Developers
   228 Intended Audience :: Education
   229 Intended Audience :: End Users/Desktop
   230 Intended Audience :: Financial and Insurance Industry
   231 Intended Audience :: Healthcare Industry
   232 Intended Audience :: Information Technology
   233 Intended Audience :: Legal Industry
   234 Intended Audience :: Manufacturing
   235 Intended Audience :: Other Audience
   236 Intended Audience :: Religion
   237 Intended Audience :: Science/Research
   238 Intended Audience :: System Administrators
   239 Intended Audience :: Telecommunications Industry
   240 License :: OSI Approved :: GNU General Public License (GPL)
   241 Natural Language :: Chinese (Simplified)
   242 Natural Language :: Chinese (Traditional)
   243 Natural Language :: Danish
   244 Natural Language :: Dutch
   245 Natural Language :: English
   246 Natural Language :: French
   247 Natural Language :: German
   248 Natural Language :: Hebrew
   249 Natural Language :: Hungarian
   250 Natural Language :: Italian
   251 Natural Language :: Javanese
   252 Natural Language :: Korean
   253 Natural Language :: Norwegian
   254 Natural Language :: Russian
   255 Natural Language :: Serbian
   256 Natural Language :: Spanish
   257 Natural Language :: Vietnamese
   258 Operating System :: MacOS :: MacOS X
   259 Operating System :: Microsoft :: Windows
   260 Operating System :: Microsoft :: Windows :: Windows 95/98/2000
   261 Operating System :: Microsoft :: Windows :: Windows NT/2000
   262 Operating System :: OS Independent
   263 Operating System :: POSIX
   264 Operating System :: POSIX :: BSD :: FreeBSD
   265 Operating System :: POSIX :: Linux
   266 Operating System :: Unix
   267 Programming Language :: Python
   268 Topic :: Communications :: Conferencing
   269 Topic :: Internet :: WWW/HTTP :: Dynamic Content
   270 Topic :: Office/Business :: Groupware
   271 Topic :: Text Processing :: Markup""".splitlines(),
   272 
   273     'packages': [
   274         'jabberbot',
   275         'MoinMoin',
   276         'MoinMoin.action',
   277         'MoinMoin.auth',
   278         'MoinMoin.auth.openidrp_ext',
   279         'MoinMoin.config',
   280         'MoinMoin.converter',
   281         'MoinMoin.datastruct',
   282         'MoinMoin.datastruct.backends',
   283         'MoinMoin.events',
   284         'MoinMoin.filter',
   285         'MoinMoin.formatter',
   286         'MoinMoin.i18n',
   287         'MoinMoin.i18n.tools',
   288         'MoinMoin.logfile',
   289         'MoinMoin.macro',
   290         'MoinMoin.mail',
   291         'MoinMoin.parser',
   292         'MoinMoin.script',
   293         'MoinMoin.script.account',
   294         'MoinMoin.script.cli',
   295         'MoinMoin.script.export',
   296         'MoinMoin.script.import',
   297         'MoinMoin.script.index',
   298         'MoinMoin.script.maint',
   299         'MoinMoin.script.migration',
   300         'MoinMoin.script.old',
   301         'MoinMoin.script.old.migration',
   302         'MoinMoin.script.old.xmlrpc-tools',
   303         'MoinMoin.script.server',
   304         'MoinMoin.script.xmlrpc',
   305         'MoinMoin.search',
   306         'MoinMoin.search.Xapian',
   307         'MoinMoin.search.queryparser',
   308         'MoinMoin.security',
   309         'MoinMoin.stats',
   310         'MoinMoin.support',
   311         'MoinMoin.support.flup',
   312         'MoinMoin.support.flup.client',
   313         'MoinMoin.support.flup.server',
   314         'MoinMoin.support.pygments',
   315         'MoinMoin.support.pygments.filters',
   316         'MoinMoin.support.pygments.formatters',
   317         'MoinMoin.support.pygments.lexers',
   318         'MoinMoin.support.pygments.styles',
   319         'MoinMoin.support.werkzeug',
   320         'MoinMoin.support.werkzeug.contrib',
   321         'MoinMoin.support.werkzeug.debug',
   322         'MoinMoin.support.xappy',
   323         'MoinMoin.support.parsedatetime',
   324         'MoinMoin.theme',
   325         'MoinMoin.userform',
   326         'MoinMoin.userprefs',
   327         'MoinMoin.util',
   328         'MoinMoin.web',
   329         'MoinMoin.web.static',
   330         'MoinMoin.widget',
   331         'MoinMoin.wikixml',
   332         'MoinMoin.xmlrpc',
   333 
   334         # all other _tests are missing here, either we have all or nothing:
   335         #'MoinMoin._tests',
   336     ],
   337 
   338     'package_dir': {'MoinMoin.i18n': 'MoinMoin/i18n',
   339                     'MoinMoin.web.static': 'MoinMoin/web/static',
   340                    },
   341     'package_data': {'MoinMoin.i18n': ['README', 'Makefile', 'MoinMoin.pot', 'POTFILES.in',
   342                                        '*.po',
   343                                        'tools/*',
   344                                        'jabberbot/*',
   345                                       ],
   346                      'MoinMoin.web.static': make_filelist('MoinMoin/web/static/htdocs',
   347                                                           strip_prefix='MoinMoin/web/static/'),
   348                     },
   349 
   350     # Override certain command classes with our own ones
   351     'cmdclass': {
   352         'build_scripts': build_scripts_moin,
   353     },
   354 
   355     'scripts': moin_scripts,
   356 
   357     # This copies the contents of wiki dir under sys.prefix/share/moin
   358     # Do not put files that should not be installed in the wiki dir, or
   359     # clean the dir before you make the distribution tarball.
   360     'data_files': makeDataFiles('share/moin', 'wiki')
   361 }
   362 
   363 if hasattr(distutils.dist.DistributionMetadata, 'get_keywords'):
   364     setup_args['keywords'] = "wiki web"
   365 
   366 if hasattr(distutils.dist.DistributionMetadata, 'get_platforms'):
   367     setup_args['platforms'] = "any"
   368 
   369 
   370 if __name__ == '__main__':
   371     try:
   372         setup(**setup_args)
   373     except distutils.errors.DistutilsPlatformError, ex:
   374         print
   375         print str(ex)
   376 
   377         print """
   378 POSSIBLE CAUSE
   379 
   380 "distutils" often needs developer support installed to work
   381 correctly, which is usually located in a separate package
   382 called "python%d.%d-dev(el)".
   383 
   384 Please contact the system administrator to have it installed.
   385 """ % sys.version_info[:2]
   386         sys.exit(1)
   387