Home | History | Annotate | Download | only in py2
      1 # -*- coding: ascii -*-
      2 #
      3 # Copyright 2007, 2008, 2009, 2010, 2011
      4 # Andr\xe9 Malo or his licensors, as applicable
      5 #
      6 # Licensed under the Apache License, Version 2.0 (the "License");
      7 # you may not use this file except in compliance with the License.
      8 # You may obtain a copy of the License at
      9 #
     10 #     http://www.apache.org/licenses/LICENSE-2.0
     11 #
     12 # Unless required by applicable law or agreed to in writing, software
     13 # distributed under the License is distributed on an "AS IS" BASIS,
     14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15 # See the License for the specific language governing permissions and
     16 # limitations under the License.
     17 """
     18 ===================
     19  Data distribution
     20 ===================
     21 
     22 This module provides tools to simplify data distribution.
     23 """
     24 __author__ = u"Andr\xe9 Malo"
     25 __docformat__ = "restructuredtext en"
     26 
     27 from distutils import filelist as _filelist
     28 import os as _os
     29 import posixpath as _posixpath
     30 import sys as _sys
     31 
     32 from _setup import commands as _commands
     33 
     34 
     35 def splitpath(path):
     36     """ Split a path """
     37     drive, path = '', _os.path.normpath(path)
     38     try:
     39         splitunc = _os.path.splitunc
     40     except AttributeError:
     41         pass
     42     else:
     43         drive, path = splitunc(path)
     44     if not drive:
     45         drive, path = _os.path.splitdrive(path)
     46     elems = []
     47     try:
     48         sep = _os.path.sep
     49     except AttributeError:
     50         sep = _os.path.join('1', '2')[1:-1]
     51     while 1:
     52         prefix, path = _os.path.split(path)
     53         elems.append(path)
     54         if prefix in ('', sep):
     55             drive = _os.path.join(drive, prefix)
     56             break
     57         path = prefix
     58     elems.reverse()
     59     return drive, elems
     60 
     61 
     62 def finalizer(installer):
     63     """ Finalize install_data """
     64     data_files = []
     65     for item in installer.data_files:
     66         if not isinstance(item, Data):
     67             data_files.append(item)
     68             continue
     69         data_files.extend(item.flatten(installer))
     70     installer.data_files = data_files
     71 
     72 
     73 class Data(object):
     74     """ File list container """
     75 
     76     def __init__(self, files, target=None, preserve=0, strip=0,
     77                  prefix=None):
     78         """ Initialization """
     79         self._files = files
     80         self._target = target
     81         self._preserve = preserve
     82         self._strip = strip
     83         self._prefix = prefix
     84         self.fixup_commands()
     85 
     86     def fixup_commands(self):
     87         pass
     88 
     89     def from_templates(cls, *templates, **kwargs):
     90         """ Initialize from template """
     91         files = _filelist.FileList()
     92         for tpl in templates:
     93             for line in tpl.split(';'):
     94                 files.process_template_line(line.strip())
     95         files.sort()
     96         files.remove_duplicates()
     97         result = []
     98         for filename in files.files:
     99             _, elems = splitpath(filename)
    100             if '.svn' in elems or '.git' in elems:
    101                 continue
    102             result.append(filename)
    103         return cls(result, **kwargs)
    104     from_templates = classmethod(from_templates)
    105 
    106     def flatten(self, installer):
    107         """ Flatten the file list to (target, file) tuples """
    108         # pylint: disable = W0613
    109         if self._prefix:
    110             _, prefix = splitpath(self._prefix)
    111             telems = prefix
    112         else:
    113             telems = []
    114 
    115         tmap = {}
    116         for fname in self._files:
    117             (_, name), target = splitpath(fname), telems
    118             if self._preserve:
    119                 if self._strip:
    120                     name = name[max(0, min(self._strip, len(name) - 1)):]
    121                 if len(name) > 1:
    122                     target = telems + name[:-1]
    123             tmap.setdefault(_posixpath.join(*target), []).append(fname)
    124         return tmap.items()
    125 
    126 
    127 class Documentation(Data):
    128     """ Documentation container """
    129 
    130     def fixup_commands(self):
    131         _commands.add_option('install_data', 'without-docs',
    132             help_text='Do not install documentation files',
    133             inherit='install',
    134         )
    135         _commands.add_finalizer('install_data', 'documentation', finalizer)
    136 
    137     def flatten(self, installer):
    138         """ Check if docs should be installed at all """
    139         if installer.without_docs:
    140             return []
    141         return Data.flatten(self, installer)
    142 
    143 
    144 class Manpages(Documentation):
    145     """ Manpages container """
    146 
    147     def dispatch(cls, files):
    148         """ Automatically dispatch manpages to their target directories """
    149         mpmap = {}
    150         for manpage in files:
    151             normalized = _os.path.normpath(manpage)
    152             _, ext = _os.path.splitext(normalized)
    153             if ext.startswith(_os.path.extsep):
    154                 ext = ext[len(_os.path.extsep):]
    155             mpmap.setdefault(ext, []).append(manpage)
    156         return [cls(manpages, prefix=_posixpath.join(
    157             'share', 'man', 'man%s' % section,
    158         )) for section, manpages in mpmap.items()]
    159     dispatch = classmethod(dispatch)
    160 
    161     def flatten(self, installer):
    162         """ Check if manpages are suitable """
    163         if _sys.platform == 'win32':
    164             return []
    165         return Documentation.flatten(self, installer)
    166