~ubuntu-branches/ubuntu/trusty/germinate/trusty-proposed

« back to all changes in this revision

Viewing changes to Germinate/seeds.py

  • Committer: Package Import Robot
  • Author(s): Colin Watson
  • Date: 2011-12-04 14:16:54 UTC
  • Revision ID: package-import@ubuntu.com-20111204141654-pumqjv3x5x0a4lgi
Tags: 2.0
* Make sure to always close files after finishing with them.  Mostly this
  is done using the 'with' statement in Python 2.6, but pychecker gets
  unhappy with contextlib.closing so I carried on using traditional
  try/finally blocks in cases that would require that.
* Remove all uses of os.system and os.popen, replacing them with uses of
  the better-designed subprocess module.
* Remove all code supporting the germinate -i/--ipv6 option; this has been
  off by default since November 2004, the service behind this was
  discontinued in March 2007
  (http://lists.debian.org/debian-ipv6/2007/02/msg00015.html), and
  germinate was never a great place to track this kind of thing anyway.
* Convert all option parsing to optparse.  Consolidate defaults into a new
  Germinate.defaults module.
* Update copyright dates.
* Move canonical source location from people.canonical.com to a hosted
  branch on Launchpad.
* Slightly modernise use of dh_python2.
* Forbid seed names containing slashes.
* Eliminate most uses of list.sort() in favour of sorted(iterable).
* When promoting dependencies from lesser seeds, remove them from the
  lesser seed lists at output time rather than immediately.  This is
  mostly to make it easier to process multiple seed structures, but also
  fixes a long-standing bug where promoted dependencies were only removed
  from a single arbitrary lesser seed rather than from all possible ones.
* Memoise the results of Germinator's _inner_seeds, _strictly_outer_seeds,
  and _outer_seeds methods.  This saves nearly a third of germinate's
  runtime in common cases.
* Write all output files atomically.
* Change default distribution to precise.
* Update kubuntu-meta example in germinate-update-metapackage(1).
* Refer to versioned GPL file in debian/copyright.
* Policy version 3.9.2: no changes required.

* Massive API cleanup:
  - Move output-writing functions from the top-level germinate program
    into Germinator.
  - Redesign how Germinator gets Packages/Sources sections from the
    archive.  This now works via an abstract interface, which should make
    it easier to plug in alternative archive sources (e.g. a database).
  - Move all apt_pkg interaction into library code.  Germinator.__init__
    now takes an architecture argument so that it can set
    APT::Architecture.
  - Turn open_seed into a Seed class, allowing it to be a context manager.
  - Move code pertaining to the structure of seeds into a SeedStructure
    class, simplifying the interface.
  - Make all module names lower-case, per PEP-8.  Remove the separate
    Germinate.Archive.tagfile module; this is now in germinate.archive
    directly.  Adjust build system and pychecker handling to support this.
  - Remove unnecessary logging helper functions.
  - Don't modify level names on the root logger simply as a result of
    importing germinate.germinator; move this into a function.
  - Prefix all private methods with an underscore.
  - Remove germinate.tsort from germinate's public API.
  - Convert all method names to the PEP-8 preferred style (method_name
    rather than methodName).
  - Introduce wrapper functions for the various uses of write_list and
    write_source_list, and make the underlying methods private.
  - Make most instance variables private by prefixing an underscore,
    adding a few accessor methods.
  - Convert build system to distutils, make the germinate Python package
    public, and create a new python-germinate binary package.
  - Improve the Seed class so that seeds can be read multiple times
    without having to redownload them, and so that they remember which
    branch they came from.
  - Don't modify inner seeds when processing outer ones; filter
    build-dependencies on output instead.
  - Don't plant or grow seeds that have already had functionally-identical
    versions planted or grown respectively.
  - Automatically convert string dists/components/mirrors/source_mirrors
    arguments to lists in TagFile constructor.
  - Make it possible for a single Germinator to process multiple seed
    structures, reusing the work done on common seeds.
  - Canonicalise mirrors (by appending '/' if necessary) in TagFile rather
    than in the main germinate program.
  - Handle the extra seed entirely within Germinator rather than modifying
    SeedStructure (which doesn't fit well with processing the same seed
    structure on multiple architectures).
  - Use module-level loggers.
  - Get rid of the custom PROGRESS log level.
  - Change germinate.archive to use logging rather than print.
  - Add docstrings for all public classes and methods, and tidy up a few
    existing ones per PEP-257.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- coding: UTF-8 -*-
2
 
"""Fetch seeds from a URL collection or from bzr."""
3
 
 
4
 
# Copyright (c) 2004, 2005, 2006, 2008 Canonical Ltd.
5
 
#
6
 
# Germinate is free software; you can redistribute it and/or modify it
7
 
# under the terms of the GNU General Public License as published by the
8
 
# Free Software Foundation; either version 2, or (at your option) any
9
 
# later version.
10
 
#
11
 
# Germinate is distributed in the hope that it will be useful, but
12
 
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 
# General Public License for more details.
15
 
#
16
 
# You should have received a copy of the GNU General Public License
17
 
# along with Germinate; see the file COPYING.  If not, write to the Free
18
 
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19
 
# 02110-1301, USA.
20
 
 
21
 
import os
22
 
import tempfile
23
 
import atexit
24
 
import logging
25
 
import urlparse
26
 
import urllib2
27
 
import shutil
28
 
import re
29
 
 
30
 
bzr_cache_dir = None
31
 
 
32
 
class SeedError(RuntimeError):
33
 
    pass
34
 
 
35
 
def _cleanup_bzr_cache(directory):
36
 
    shutil.rmtree(directory, ignore_errors=True)
37
 
 
38
 
def _open_seed_internal(seed_base, seed_branch, seed_file, bzr=False):
39
 
    seed_path = os.path.join(seed_base, seed_branch)
40
 
    if not seed_path.endswith('/'):
41
 
        seed_path += '/'
42
 
    if bzr:
43
 
        global bzr_cache_dir
44
 
        if bzr_cache_dir is None:
45
 
            bzr_cache_dir = tempfile.mkdtemp(prefix='germinate-')
46
 
            atexit.register(_cleanup_bzr_cache, bzr_cache_dir)
47
 
        seed_checkout = os.path.join(bzr_cache_dir, seed_branch)
48
 
        if not os.path.isdir(seed_checkout):
49
 
            # https://launchpad.net/products/bzr/+bug/39542
50
 
            if seed_path.startswith('http:'):
51
 
                operation = 'branch'
52
 
                logging.info("Fetching branch of %s", seed_path)
53
 
            else:
54
 
                operation = 'checkout --lightweight'
55
 
                logging.info("Checking out %s", seed_path)
56
 
            command = ('bzr %s %s %s' % (operation, seed_path, seed_checkout))
57
 
            status = os.system(command)
58
 
            if status != 0:
59
 
                raise SeedError("Command failed with exit status %d:\n"
60
 
                                "  '%s'" % (status, command))
61
 
        return open(os.path.join(seed_checkout, seed_file))
62
 
    else:
63
 
        url = urlparse.urljoin(seed_path, seed_file)
64
 
        logging.info("Downloading %s", url)
65
 
        req = urllib2.Request(url)
66
 
        req.add_header('Cache-Control', 'no-cache')
67
 
        req.add_header('Pragma', 'no-cache')
68
 
        return urllib2.urlopen(req)
69
 
 
70
 
def open_seed(seed_bases, seed_branches, seed_file, bzr=False):
71
 
    if isinstance(seed_branches, str) or isinstance(seed_branches, unicode):
72
 
        seed_branches = [seed_branches]
73
 
 
74
 
    fd = None
75
 
    seed_ssh_host = None
76
 
    for base in seed_bases:
77
 
        for branch in seed_branches:
78
 
            try:
79
 
                fd = _open_seed_internal(base, branch, seed_file, bzr)
80
 
                break
81
 
            except SeedError:
82
 
                ssh_match = re.match(r'bzr\+ssh://(?:[^/]*?@)?(.*?)(?:/|$)',
83
 
                                     base)
84
 
                if ssh_match:
85
 
                    seed_ssh_host = ssh_match.group(1)
86
 
            except (OSError, IOError, urllib2.URLError):
87
 
                pass
88
 
        if fd is not None:
89
 
            break
90
 
 
91
 
    if fd is None:
92
 
        if bzr:
93
 
            logging.warning("Could not open %s from checkout of (any of):",
94
 
                            seed_file)
95
 
            for base in seed_bases:
96
 
                for branch in seed_branches:
97
 
                    logging.warning('  %s' % os.path.join(base, branch))
98
 
 
99
 
            if seed_ssh_host is not None:
100
 
                logging.error("Do you need to set your user name on %s?",
101
 
                              seed_ssh_host)
102
 
                logging.error("Try a section such as this in ~/.ssh/config:")
103
 
                logging.error("")
104
 
                logging.error("Host %s", seed_ssh_host)
105
 
                logging.error("        User YOUR_USER_NAME")
106
 
        else:
107
 
            logging.warning("Could not open (any of):")
108
 
            for base in seed_bases:
109
 
                for branch in seed_branches:
110
 
                    path = os.path.join(base, branch)
111
 
                    if not path.endswith('/'):
112
 
                        path += '/'
113
 
                    logging.warning('  %s' % urlparse.urljoin(path, seed_file))
114
 
        raise SeedError("Could not open %s" % seed_file)
115
 
 
116
 
    return fd