eggs/infrae.subversion-1.4.5-py2.6.egg/infrae/subversion/Common.py
changeset 69 c6bca38c1cbf
equal deleted inserted replaced
68:5ff1fc726848 69:c6bca38c1cbf
       
     1 # Copyright (c) 2007-2008 Infrae. All rights reserved.
       
     2 # $Id: Common.py 33243 2009-01-29 10:59:47Z sylvain $
       
     3 
       
     4 from sets import Set            # For python 2.3 compatibility
       
     5 import os.path
       
     6 import os
       
     7 import re
       
     8 
       
     9 
       
    10 import zc.buildout
       
    11 
       
    12 
       
    13 def ignoredFile(file):
       
    14     """Return true if the file should be ignored while checking for
       
    15     added/changed/modified files.
       
    16     """
       
    17     for suffix in ['.pyc', '.pyo', '.egg-info']:
       
    18         if file.endswith(suffix):
       
    19             return True
       
    20     return False
       
    21 
       
    22 
       
    23 def reportInvalidFiles(path, name, badfiles):
       
    24     """Report invalid files.
       
    25     """
       
    26     badfiles = [file for file in badfiles if not ignoredFile(file)]
       
    27     if not badfiles:
       
    28         return
       
    29     raise ValueError("""\
       
    30 In '%s':
       
    31 local modifications detected while uninstalling %r: Uninstall aborted!
       
    32 
       
    33 Please check for local modifications and make sure these are checked
       
    34 in.
       
    35 
       
    36 If you sure that these modifications can be ignored, remove the
       
    37 checkout manually:
       
    38 
       
    39   rm -rf %s
       
    40 
       
    41 Or if applicable, add the file to the 'svn:ignore' property of the
       
    42 file's container directory.  Alternatively, add an ignore glob pattern
       
    43 to your subversion client's 'global-ignores' configuration variable.
       
    44 """ % (path, name, """
       
    45   rm -rf """.join(badfiles)))
       
    46 
       
    47 
       
    48 def checkExistPath(path, warning=True):
       
    49     """Check that a path exist.
       
    50     """
       
    51     status = os.path.exists(path)
       
    52     if not status and warning:
       
    53         print "-------- WARNING --------"
       
    54         print "Directory %s have been removed." % os.path.abspath(path)
       
    55         print "Changes might be lost."
       
    56         print "-------- WARNING --------"
       
    57     return status
       
    58 
       
    59 
       
    60 def checkAddedPaths(location, urls):
       
    61     """Check that no path have been added to that location.
       
    62     """
       
    63     current_paths = Set([os.path.join(location, s) for s in
       
    64                          os.listdir(location)])
       
    65     recipe_paths = Set(urls.keys())
       
    66     added_paths = list(current_paths - recipe_paths)
       
    67     for path in added_paths[:]:
       
    68         if path.endswith('.svn'):
       
    69             added_paths.remove(path)
       
    70     if added_paths:
       
    71         msg = "New path have been added to the location: %s."
       
    72         raise ValueError(msg % ', '.join(added_paths))
       
    73 
       
    74 
       
    75 def prepareURLs(location, urls):
       
    76     """Given a list of urls/path, and a location, prepare a list of
       
    77     tuple with url, full path.
       
    78     """
       
    79 
       
    80     def prepareEntry(line):
       
    81         link, path = line.split()
       
    82         return os.path.join(location, path), link
       
    83 
       
    84     return dict([prepareEntry(l) for l in urls.splitlines() if l.strip()])
       
    85 
       
    86 
       
    87 def extractNames(urls):
       
    88     """Return just the target names of the urls (used for egg names)"""
       
    89 
       
    90     def extractName(line):
       
    91         link, name = line.split()
       
    92         return name
       
    93 
       
    94     return [extractName(line) for line in urls.splitlines() if line.strip()]
       
    95 
       
    96 
       
    97 class BaseRecipe(object):
       
    98     """infrae.subversion recipe. Base class.
       
    99     """
       
   100 
       
   101     def __init__(self, buildout, name, options):
       
   102         self.buildout = buildout
       
   103         self.name = name
       
   104         self.options = options
       
   105         # location is overridable if desired.
       
   106         location = options.get('location', None)
       
   107         if location:
       
   108             self.location = os.path.abspath(os.path.join(
       
   109                 buildout['buildout']['directory'], location))
       
   110         else:
       
   111             self.location = os.path.join(
       
   112                 buildout['buildout']['parts-directory'], self.name)
       
   113         options['location'] = self.location
       
   114         self.revisions = {} # Store revision information for each link
       
   115         self.updated = []   # Store updated links
       
   116         self.urls = prepareURLs(self.location, options['urls'])
       
   117         self.export = options.get('export')
       
   118         self.offline = buildout['buildout'].get('offline', 'false') == 'true'
       
   119         self.eggify = options.get('as_eggs', False)
       
   120         self.eggs = self.eggify and extractNames(options['urls']) or []
       
   121         self.newest = (
       
   122             not self.offline and
       
   123             buildout['buildout'].get('newest', 'true') == 'true'
       
   124             )
       
   125         self.verbose = buildout['buildout'].get('verbosity', 0)
       
   126         self.warning = not (options.get('no_warnings', 'false') == 'true')
       
   127 
       
   128     def _exportInformationToOptions(self):
       
   129         """Export revision and changed information to options.
       
   130 
       
   131         Options can only contains strings.
       
   132         """
       
   133         if self.options.get('export_info', False):
       
   134             self.options['updated'] = str('\n'.join(self.updated))
       
   135             str_revisions = ['%s %s' % r for r in self.revisions.items()
       
   136                              if r[1]]
       
   137             self.options['revisions'] = str('\n'.join(sorted(str_revisions)))
       
   138         # Always export egg list
       
   139         self.options['eggs'] = '\n'.join(sorted(self.eggs))
       
   140 
       
   141     def _updateAllRevisionInformation(self):
       
   142         """Update all revision information for defined urls.
       
   143         """
       
   144         for path, link in self.urls.items():
       
   145             if os.path.exists(path):
       
   146                 self._updateRevisionInformation(link, path)
       
   147 
       
   148     def _updateRevisionInformation(self, link, revision):
       
   149         """Update revision information on a path.
       
   150         """
       
   151         old_revision = self.revisions.get(link, None)
       
   152         self.revisions[link] = revision
       
   153         if not (old_revision is None):
       
   154             self.updated.append(link)
       
   155 
       
   156     def _updatePath(self, link, path):
       
   157         """Update a single path.
       
   158         """
       
   159         raise NotImplementedError
       
   160 
       
   161     def _updateAllPaths(self):
       
   162         """Update the checkouts.
       
   163         """
       
   164         ignore = self.options.get('ignore_updates', False) or self.export
       
   165 
       
   166         num_release = re.compile('.*@[0-9]+$')
       
   167         for path, link in self.urls.items():
       
   168             if not checkExistPath(path, warning=self.warning):
       
   169                 if self.verbose:
       
   170                     print "Entry %s missing, checkout a new version ..." % link
       
   171                 self._installPath(link, path)
       
   172                 continue
       
   173 
       
   174             if ignore:
       
   175                 continue
       
   176 
       
   177             if num_release.match(link):
       
   178                 if self.verbose:
       
   179                     print "Given num release for %s, skipping." % link
       
   180                 continue
       
   181 
       
   182             if self.verbose:
       
   183                 print "Updating %s" % path
       
   184             self._updatePath(link, path)
       
   185 
       
   186     def update(self):
       
   187         """Update the recipe.
       
   188 
       
   189         Does not update SVN path if the buildout is in offline mode,
       
   190         but still eggify and export information.
       
   191         """
       
   192         if self.newest:
       
   193             self._updateAllPaths()
       
   194 
       
   195         if self.eggify:
       
   196             self._eggify()
       
   197         self._exportInformationToOptions()
       
   198         return self.location
       
   199 
       
   200     def _installPath(self, link, path):
       
   201         """Checkout a single entry.
       
   202         """
       
   203         raise NotImplementedError
       
   204 
       
   205     def _installPathVerbose(self, link, path):
       
   206         """Checkout a single entry with verbose.
       
   207         """
       
   208         if self.verbose:
       
   209             print "%s %s to %s" % (self.export and 'Export' or 'Fetch',
       
   210                                    link, path)
       
   211         self._installPath(link, path)
       
   212 
       
   213     def _eggify(self):
       
   214         """Install everything as development eggs if eggs=true"""
       
   215         if self.eggify:
       
   216             target = self.buildout['buildout']['develop-eggs-directory']
       
   217             for path in self.urls.keys():
       
   218                 # If we update the recipe, and we don't have newest,
       
   219                 # and that some path have been deleted, all of them
       
   220                 # might not be there.
       
   221                 if checkExistPath(path, warning=self.warning):
       
   222                     zc.buildout.easy_install.develop(path, target)
       
   223 
       
   224     def install(self):
       
   225         """Checkout the checkouts.
       
   226 
       
   227         Fails if buildout is running in offline mode.
       
   228         """
       
   229 
       
   230         for path, link in self.urls.items():
       
   231             self._installPathVerbose(link, path)
       
   232         installed = [self.location]
       
   233 
       
   234         if self.eggify:
       
   235             self._eggify()
       
   236             # And also return the develop-eggs/*.egg-link files that are
       
   237             # ours so that an uninstall automatically zaps them.
       
   238             dev_dir = self.buildout['buildout']['develop-eggs-directory']
       
   239             egg_links = ['%s.egg-link' % egg for egg in self.eggs]
       
   240             egg_links = [os.path.join(dev_dir, link) for link in egg_links]
       
   241             installed += egg_links
       
   242         self._exportInformationToOptions()
       
   243 
       
   244         return installed