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