~ubuntu-branches/debian/sid/bzr-builddeb/sid

« back to all changes in this revision

Viewing changes to upstream/__init__.py

  • Committer: Bazaar Package Importer
  • Author(s): Jelmer Vernooij, Jelmer Vernooij, Jonathan Riddell, Scott Kitterman
  • Date: 2011-07-15 12:15:22 UTC
  • Revision ID: james.westby@ubuntu.com-20110715121522-avtc0uc3uuzcg7zn
Tags: 2.7.5
[ Jelmer Vernooij ]
* New 'bzr dep3-patch' subcommand that can generate DEP-3 compliant
  patches. LP: #460576

[ Jonathan Riddell ]
* Use new set_commit_message() hook in bzr to set the commit
  message from debian/changelog and set fixed bugs in tags. LP: #707274

[ Jelmer Vernooij ]
* Add dependency on devscripts >= 2.10.59, required now that 'dch --
  package' is used. LP: #783122
* Fix support for native packages with dashes in their version in
  sources.list. LP: #796853
* Fix deprecation warnings for TestCase.failUnlessExists and
  TestCase.failIfExists in bzr 2.4.

[ Scott Kitterman ]
* Delete debian/bzr-builddeb.dirs so the long obsolete and empty
  /usr/lib/python2.4/site-packages/bzrlib/plugins/bzr-builddeb/ is no
  longer created. Closes: #631564

[ Jelmer Vernooij ]
* Add support for xz and lzma tarballs. LP: #553668
* When importing upstream component tarballs, don't repack bz2/lzma
  tarballs to gz if the package is in v3 source format. LP: #810531

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
import tarfile
26
26
import tempfile
27
27
 
28
 
from base64 import (
29
 
    standard_b64decode,
30
 
    )
31
 
 
32
 
 
33
28
try:
34
29
    from debian.changelog import Version
35
30
except ImportError:
36
31
    # Prior to 0.1.15 the debian module was called debian_bundle
37
32
    from debian_bundle.changelog import Version
38
33
 
39
 
from bzrlib.errors import (
40
 
    NoSuchRevision,
41
 
    NoSuchTag,
42
 
    )
 
34
from bzrlib import osutils
43
35
from bzrlib.trace import (
44
36
    note,
45
37
    warning,
48
40
from bzrlib.plugins.builddeb.errors import (
49
41
    MissingUpstreamTarball,
50
42
    PackageVersionNotPresent,
51
 
    PerFileTimestampsNotSupported,
52
 
    PristineTarError,
53
43
    WatchFileMissing,
54
44
    )
55
 
from bzrlib.plugins.builddeb.repack_tarball import repack_tarball
 
45
from bzrlib.plugins.builddeb.repack_tarball import (
 
46
    get_filetype,
 
47
    repack_tarball,
 
48
    )
56
49
from bzrlib.plugins.builddeb.util import (
 
50
    component_from_orig_tarball,
57
51
    export,
58
 
    reconstruct_pristine_tar,
59
52
    tarball_name,
60
53
    )
61
54
 
62
55
 
 
56
def new_tarball_name(package, version, old_name):
 
57
    """Determine new tarball name based on the package name and the old name.
 
58
    """
 
59
    old_format = get_filetype(old_name)
 
60
    if old_format in ("gz", "bz2", "xz"):
 
61
        return tarball_name(package, version, None, old_format)
 
62
    # Unknown target format, repack to .tar.gz
 
63
    return tarball_name(package, version, None, "gz")
 
64
 
 
65
 
63
66
class UpstreamSource(object):
64
67
    """A source for upstream versions (uscan, get-orig-source, etc)."""
65
68
 
91
94
        """
92
95
        raise NotImplementedError(self.has_version)
93
96
 
94
 
    def fetch_tarball(self, package, version, target_dir):
 
97
    def fetch_tarballs(self, package, version, target_dir):
95
98
        """Fetch the source tarball for a particular version.
96
99
 
97
100
        :param package: Name of the package
98
101
        :param version: Version string of the version to fetch
99
102
        :param target_dir: Directory in which to store the tarball
100
 
        :return: Path of the fetched tarball
 
103
        :return: Paths of the fetched tarballs
101
104
        """
102
 
        raise NotImplementedError(self.fetch_tarball)
 
105
        raise NotImplementedError(self.fetch_tarballs)
103
106
 
104
 
    def _tarball_path(self, package, version, target_dir, format=None):
105
 
        return os.path.join(target_dir, tarball_name(package, version,
 
107
    def _tarball_path(self, package, version, component, target_dir, format=None):
 
108
        return os.path.join(target_dir, tarball_name(package, version, component,
106
109
                    format=format))
107
110
 
108
111
 
109
 
class PristineTarSource(UpstreamSource):
110
 
    """Source that uses the pristine-tar revisions in the packaging branch."""
111
 
 
112
 
    def __init__(self, tree, branch):
113
 
        self.branch = branch
114
 
        self.tree = tree
115
 
 
116
 
    def tag_name(self, version, distro=None):
117
 
        """Gets the tag name for the upstream part of version.
118
 
 
119
 
        :param version: the Version object to extract the upstream
120
 
            part of the version number from.
121
 
        :return: a String with the name of the tag.
122
 
        """
123
 
        assert isinstance(version, str)
124
 
        if distro is None:
125
 
            return "upstream-" + version
126
 
        return "upstream-%s-%s" % (distro, version)
127
 
 
128
 
    def fetch_tarball(self, package, version, target_dir):
129
 
        revid = self.version_as_revision(package, version)
130
 
        try:
131
 
            rev = self.branch.repository.get_revision(revid)
132
 
        except NoSuchRevision:
133
 
            raise PackageVersionNotPresent(package, version, self)
134
 
        note("Using pristine-tar to reconstruct the needed tarball.")
135
 
        if self.has_pristine_tar_delta(rev):
136
 
            format = self.pristine_tar_format(rev)
137
 
        else:
138
 
            format = 'gz'
139
 
        target_filename = self._tarball_path(package, version,
140
 
                                             target_dir, format=format)
141
 
        try:
142
 
            self.reconstruct_pristine_tar(revid, package, version, target_filename)
143
 
        except PristineTarError:
144
 
            raise PackageVersionNotPresent(package, version, self)
145
 
        except PerFileTimestampsNotSupported:
146
 
            raise PackageVersionNotPresent(package, version, self)
147
 
        return target_filename
148
 
 
149
 
    def _has_version(self, tag_name, md5=None):
150
 
        if not self.branch.tags.has_tag(tag_name):
151
 
            return False
152
 
        revid = self.branch.tags.lookup_tag(tag_name)
153
 
        self.branch.lock_read()
154
 
        try:
155
 
            graph = self.branch.repository.get_graph()
156
 
            if not graph.is_ancestor(revid, self.branch.last_revision()):
157
 
                return False
158
 
        finally:
159
 
            self.branch.unlock()
160
 
        if md5 is None:
161
 
            return True
162
 
        rev = self.branch.repository.get_revision(revid)
163
 
        try:
164
 
            return rev.properties['deb-md5'] == md5
165
 
        except KeyError:
166
 
            warning("tag %s present in branch, but there is no "
167
 
                "associated 'deb-md5' property" % tag_name)
168
 
            return True
169
 
 
170
 
    def version_as_revision(self, package, version):
171
 
        assert isinstance(version, str)
172
 
        for tag_name in self.possible_tag_names(version):
173
 
            if self._has_version(tag_name):
174
 
                return self.branch.tags.lookup_tag(tag_name)
175
 
        tag_name = self.tag_name(version)
176
 
        try:
177
 
            return self.branch.tags.lookup_tag(tag_name)
178
 
        except NoSuchTag:
179
 
            raise PackageVersionNotPresent(package, version, self)
180
 
 
181
 
    def has_version(self, package, version, md5=None):
182
 
        assert isinstance(version, str), str(type(version))
183
 
        for tag_name in self.possible_tag_names(version):
184
 
            if self._has_version(tag_name, md5=md5):
185
 
                return True
186
 
        return False
187
 
 
188
 
    def possible_tag_names(self, version):
189
 
        assert isinstance(version, str)
190
 
        tags = [self.tag_name(version),
191
 
                self.tag_name(version, distro="debian"),
192
 
                self.tag_name(version, distro="ubuntu"),
193
 
                "upstream/%s" % version]
194
 
        return tags
195
 
 
196
 
    def has_pristine_tar_delta(self, rev):
197
 
        return ('deb-pristine-delta' in rev.properties
198
 
                or 'deb-pristine-delta-bz2' in rev.properties)
199
 
 
200
 
    def pristine_tar_format(self, rev):
201
 
        if 'deb-pristine-delta' in rev.properties:
202
 
            return 'gz'
203
 
        elif 'deb-pristine-delta-bz2' in rev.properties:
204
 
            return 'bz2'
205
 
        assert self.has_pristine_tar_delta(rev)
206
 
        raise AssertionError("Not handled new delta type in "
207
 
                "pristine_tar_format")
208
 
 
209
 
    def pristine_tar_delta(self, rev):
210
 
        if 'deb-pristine-delta' in rev.properties:
211
 
            uuencoded = rev.properties['deb-pristine-delta']
212
 
        elif 'deb-pristine-delta-bz2' in rev.properties:
213
 
            uuencoded = rev.properties['deb-pristine-delta-bz2']
214
 
        else:
215
 
            assert self.has_pristine_tar_delta(rev)
216
 
            raise AssertionError("Not handled new delta type in "
217
 
                    "pristine_tar_delta")
218
 
        return standard_b64decode(uuencoded)
219
 
 
220
 
    def reconstruct_pristine_tar(self, revid, package, version,
221
 
            dest_filename):
222
 
        """Reconstruct a pristine-tar tarball from a bzr revision."""
223
 
        tree = self.branch.repository.revision_tree(revid)
224
 
        tmpdir = tempfile.mkdtemp(prefix="builddeb-pristine-")
225
 
        try:
226
 
            dest = os.path.join(tmpdir, "orig")
227
 
            rev = self.branch.repository.get_revision(revid)
228
 
            if self.has_pristine_tar_delta(rev):
229
 
                export(tree, dest, format='dir')
230
 
                delta = self.pristine_tar_delta(rev)
231
 
                reconstruct_pristine_tar(dest, delta, dest_filename)
232
 
            else:
233
 
                export(tree, dest_filename, require_per_file_timestamps=True)
234
 
        finally:
235
 
            shutil.rmtree(tmpdir)
236
 
 
237
 
 
238
112
class AptSource(UpstreamSource):
239
113
    """Upstream source that uses apt-source."""
240
114
 
241
 
    def fetch_tarball(self, package, upstream_version, target_dir, 
 
115
    def fetch_tarballs(self, package, upstream_version, target_dir,
242
116
            _apt_pkg=None):
243
117
        if _apt_pkg is None:
244
118
            import apt_pkg
267
141
        lookup = get_fn(sources, 'lookup', 'Lookup')
268
142
        while lookup(package):
269
143
            version = get_fn(sources, 'version', 'Version')
270
 
            if upstream_version == Version(version).upstream_version:
 
144
            filenames = []
 
145
            for (checksum, size, filename, filekind) in sources.files:
 
146
                if filekind != "tar":
 
147
                    continue
 
148
                filename = os.path.basename(filename)
 
149
                if filename.startswith("%s_%s.orig" % (package, upstream_version)):
 
150
                    filenames.append(filename)
 
151
            if filenames:
271
152
                if self._run_apt_source(package, version, target_dir):
272
 
                    return self._tarball_path(package, version, target_dir)
273
 
                break
 
153
                    return [os.path.join(target_dir, filename)
 
154
                            for filename in filenames]
274
155
        note("apt could not find the needed tarball.")
275
156
        raise PackageVersionNotPresent(package, upstream_version, self)
276
157
 
294
175
        self.tree = tree
295
176
        self.larstiq = larstiq
296
177
 
297
 
    def _get_orig_source(self, source_dir, desired_tarball_names,
298
 
                        target_dir):
 
178
    def _get_orig_source(self, source_dir, prefix, target_dir):
299
179
        note("Trying to use get-orig-source to retrieve needed tarball.")
300
180
        command = ["make", "-f", "debian/rules", "get-orig-source"]
301
181
        proc = subprocess.Popen(command, cwd=source_dir)
303
183
        if ret != 0:
304
184
            note("Trying to run get-orig-source rule failed")
305
185
            return None
306
 
        for desired_tarball_name in desired_tarball_names:
307
 
            fetched_tarball = os.path.join(source_dir, desired_tarball_name)
 
186
        filenames = []
 
187
        for filename in os.listdir(source_dir):
 
188
            if not filename.startswith(prefix):
 
189
                continue
 
190
            fetched_tarball = os.path.join(source_dir, filename)
308
191
            if os.path.exists(fetched_tarball):
309
 
                repack_tarball(fetched_tarball, desired_tarball_name,
310
 
                               target_dir=target_dir, force_gz=False)
311
 
                return fetched_tarball
312
 
        note("get-orig-source did not create %s", desired_tarball_name)
 
192
                repack_tarball(fetched_tarball, filename,
 
193
                               target_dir=target_dir)
 
194
                filenames.append(os.path.join(target_dir, filename))
 
195
        if filenames:
 
196
            return filenames
 
197
        note("get-orig-source did not create file with prefix %s", prefix)
313
198
        return None
314
199
 
315
 
    def fetch_tarball(self, package, version, target_dir):
 
200
    def fetch_tarballs(self, package, version, target_dir):
316
201
        if self.larstiq:
317
202
            rules_name = 'rules'
318
203
        else:
319
204
            rules_name = 'debian/rules'
320
205
        rules_id = self.tree.path2id(rules_name)
321
206
        if rules_id is not None:
322
 
            desired_tarball_names = [tarball_name(package, version),
323
 
                    tarball_name(package, version, 'bz2'),
324
 
                    tarball_name(package, version, 'lzma')]
325
207
            tmpdir = tempfile.mkdtemp(prefix="builddeb-get-orig-source-")
326
208
            try:
327
209
                base_export_dir = os.path.join(tmpdir, "export")
330
212
                    os.mkdir(export_dir)
331
213
                    export_dir = os.path.join(export_dir, "debian")
332
214
                export(self.tree, export_dir, format="dir")
333
 
                tarball_path = self._get_orig_source(base_export_dir,
334
 
                        desired_tarball_names, target_dir)
335
 
                if tarball_path is None:
 
215
                tarball_paths = self._get_orig_source(base_export_dir,
 
216
                        "%s_%s.orig" % (package, version), target_dir)
 
217
                if tarball_paths is None:
336
218
                    raise PackageVersionNotPresent(package, version, self)
337
 
                return tarball_path
 
219
                return tarball_paths
338
220
            finally:
339
221
                shutil.rmtree(tmpdir)
340
222
        note("No debian/rules file to try and use for a get-orig-source rule")
397
279
            os.unlink(tempfilename)
398
280
        return self._xml_report_extract_upstream_version(stdout)
399
281
 
400
 
    def fetch_tarball(self, package, version, target_dir):
 
282
    def fetch_tarballs(self, package, version, target_dir):
401
283
        note("Using uscan to look for the upstream tarball.")
402
284
        try:
403
285
            tempfilename = self._export_watchfile()
409
291
                "--upstream-version=%s" % version,
410
292
                "--force-download", "--rename", "--package=%s" % package,
411
293
                "--check-dirname-level=0",
412
 
                "--download", "--repack", "--destdir=%s" % target_dir,
 
294
                "--download", "--destdir=%s" % target_dir,
413
295
                "--download-version=%s" % version])
414
296
        finally:
415
297
            os.unlink(tempfilename)
416
298
        if r != 0:
417
299
            note("uscan could not find the needed tarball.")
418
300
            raise PackageVersionNotPresent(package, version, self)
419
 
        return self._tarball_path(package, version, target_dir)
 
301
        return gather_orig_files(package, version, target_dir)
420
302
 
421
303
 
422
304
class SelfSplitSource(UpstreamSource):
439
321
        finally:
440
322
            shutil.rmtree(tmpdir)
441
323
 
442
 
    def fetch_tarball(self, package, version, target_dir):
 
324
    def fetch_tarballs(self, package, version, target_dir):
443
325
        note("Using the current branch without the 'debian' directory "
444
326
                "to create the tarball")
445
 
        tarball_path = self._tarball_path(package, version, target_dir)
 
327
        tarball_path = self._tarball_path(package, version, None, target_dir)
446
328
        self._split(package, version, tarball_path)
447
 
        return tarball_path
 
329
        return [tarball_path]
448
330
 
449
331
 
450
332
class StackedUpstreamSource(UpstreamSource):
451
333
    """An upstream source that checks a list of other upstream sources.
452
334
 
453
 
    The first source that can provide a tarball, wins. 
 
335
    The first source that can provide a tarball, wins.
454
336
    """
455
337
 
456
338
    def __init__(self, sources):
459
341
    def __repr__(self):
460
342
        return "%s(%r)" % (self.__class__.__name__, self._sources)
461
343
 
462
 
    def fetch_tarball(self, package, version, target_dir):
 
344
    def fetch_tarballs(self, package, version, target_dir):
463
345
        for source in self._sources:
464
346
            try:
465
 
                path = source.fetch_tarball(package, version, target_dir)
 
347
                paths = source.fetch_tarballs(package, version, target_dir)
466
348
            except PackageVersionNotPresent:
467
349
                pass
468
350
            else:
469
 
                assert isinstance(path, basestring)
470
 
                return path
 
351
                return paths
471
352
        raise PackageVersionNotPresent(package, version, self)
472
353
 
473
354
    def get_latest_version(self, package, version):
481
362
        return None
482
363
 
483
364
 
 
365
def gather_orig_files(package, version, path):
 
366
    prefix = "%s_%s.orig" % (package, version)
 
367
    ret = []
 
368
    path = os.path.abspath(path)
 
369
    if not os.path.isdir(path):
 
370
        return None
 
371
    for filename in os.listdir(path):
 
372
        if filename.startswith(prefix):
 
373
            ret.append(os.path.join(path, filename))
 
374
    if ret:
 
375
        return ret
 
376
    return None
 
377
 
 
378
 
484
379
class UpstreamProvider(object):
485
380
    """An upstream provider can provide the upstream source for a package.
486
381
 
501
396
        self.source = StackedUpstreamSource(sources)
502
397
 
503
398
    def provide(self, target_dir):
504
 
        """Provide the upstream tarball any way possible.
 
399
        """Provide the upstream tarball(s) any way possible.
505
400
 
506
401
        Call this to place the correctly named tarball in to target_dir,
507
402
        through means possible.
528
423
        if in_target is not None:
529
424
            note("Upstream tarball already exists in build directory, "
530
425
                    "using that")
531
 
            return in_target
 
426
            return [(p, component_from_orig_tarball(p,
 
427
                self.package, self.version)) for p in in_target]
532
428
        if self.already_exists_in_store() is None:
533
429
            if not os.path.exists(self.store_dir):
534
430
                os.makedirs(self.store_dir)
535
431
            try:
536
 
                path = self.source.fetch_tarball(self.package,
 
432
                paths = self.source.fetch_tarballs(self.package,
537
433
                    self.version, self.store_dir)
538
434
            except PackageVersionNotPresent:
539
 
                raise MissingUpstreamTarball(self._tarball_names()[0])
540
 
            assert isinstance(path, basestring)
 
435
                raise MissingUpstreamTarball(self.package, self.version)
 
436
            assert isinstance(paths, list)
541
437
        else:
542
438
            note("Using the upstream tarball that is present in %s" %
543
439
                 self.store_dir)
544
 
        path = self.provide_from_store_dir(target_dir)
545
 
        assert path is not None
546
 
        return path
 
440
        paths = self.provide_from_store_dir(target_dir)
 
441
        assert paths is not None
 
442
        return [(p, component_from_orig_tarball(p, self.package, self.version))
 
443
                for p in paths]
547
444
 
548
445
    def already_exists_in_target(self, target_dir):
549
 
        for tarball_name in self._tarball_names():
550
 
            path = os.path.join(target_dir, tarball_name)
551
 
            if os.path.exists(path):
552
 
                return path
553
 
        return None
 
446
        return gather_orig_files(self.package, self.version, target_dir)
554
447
 
555
448
    def already_exists_in_store(self):
556
 
        for tarball_name in self._tarball_names():
557
 
            path = os.path.join(self.store_dir, tarball_name)
558
 
            if os.path.exists(path):
559
 
                return path
560
 
        return None
 
449
        return gather_orig_files(self.package, self.version, self.store_dir)
561
450
 
562
451
    def provide_from_store_dir(self, target_dir):
563
 
        path = self.already_exists_in_store()
564
 
        if path is not None:
 
452
        paths = self.already_exists_in_store()
 
453
        if paths is None:
 
454
            return None
 
455
        for path in paths:
565
456
            repack_tarball(path, os.path.basename(path),
566
 
                    target_dir=target_dir, force_gz=False)
567
 
            return path
568
 
        return path
569
 
 
570
 
    def _tarball_names(self):
571
 
        return [tarball_name(self.package, self.version),
572
 
                tarball_name(self.package, self.version, format='bz2'),
573
 
                tarball_name(self.package, self.version, format='lzma')]
 
457
                    target_dir=target_dir)
 
458
        return paths
574
459
 
575
460
 
576
461
def extract_tarball_version(path, packagename):
580
465
    :param packagename: Name of the package (e.g. "bzr-builddeb")
581
466
    """
582
467
    basename = os.path.basename(path)
583
 
    for extension in [".tar.gz", ".tgz", ".tar.bz2", ".zip"]:
 
468
    for extension in [".tar.gz", ".tgz", ".tar.bz2", ".tar.lzma", ".tar.xz",
 
469
            ".zip"]:
584
470
        if basename.endswith(extension):
585
471
            basename = basename[:-len(extension)]
586
472
            break
605
491
        self.path = path
606
492
        self.version = version
607
493
 
608
 
    def fetch_tarball(self, package, version, target_dir):
 
494
    def fetch_tarballs(self, package, version, target_dir):
609
495
        if version != self.version:
610
496
            raise PackageVersionNotPresent(package, version, self)
611
 
        dest_name = tarball_name(package, version)
612
 
        repack_tarball(self.path, dest_name, target_dir=target_dir, force_gz=True)
613
 
        return os.path.join(target_dir, dest_name)
 
497
        dest_name = new_tarball_name(package, version, self.path)
 
498
        repack_tarball(self.path, dest_name, target_dir=target_dir)
 
499
        return [os.path.join(target_dir, dest_name)]
614
500
 
615
501
    def get_latest_version(self, package, version):
616
502
        if self.version is not None:
617
503
            return self.version
618
504
        return extract_tarball_version(self.path, package)
 
505
 
 
506
 
 
507
class LaunchpadReleaseFileSource(UpstreamSource):
 
508
    """Source that retrieves release files from Launchpad."""
 
509
 
 
510
    @classmethod
 
511
    def from_package(cls, distribution_name, distroseries_name, package):
 
512
        """Create a LaunchpadReleaseFileSource from a distribution package.
 
513
 
 
514
        :param distribution_name: Name of the distribution (e.g. "Ubuntu")
 
515
        :param distroseries_name: Name of the distribution series
 
516
            (e.g. "oneiric")
 
517
        :param package: Package name
 
518
        :return: A `LaunchpadReleaseFileSource`
 
519
        """
 
520
        from bzrlib.plugins.builddeb.launchpad import (
 
521
            get_upstream_projectseries_for_package,
 
522
            )
 
523
        project_series = get_upstream_projectseries_for_package(
 
524
            package, distribution_name, distroseries_name)
 
525
        if project_series is None:
 
526
            return None
 
527
        return cls(project_series=project_series)
 
528
 
 
529
    def __init__(self, project=None, project_series=None):
 
530
        if project_series is None:
 
531
            self.project_series = project.development_focus
 
532
        else:
 
533
            self.project_series = project_series
 
534
        if project is None:
 
535
            self.project = project_series.project
 
536
        else:
 
537
            self.project = project
 
538
 
 
539
    def fetch_tarballs(self, package, version, target_dir):
 
540
        release = self.project.getRelease(version=version)
 
541
        if release is None:
 
542
            raise PackageVersionNotPresent(package, version, self)
 
543
        release_files = []
 
544
        for f in release.files:
 
545
            if f.file_type == "Code Release Tarball":
 
546
                release_files.append(f.file)
 
547
        if len(release_files) == 0:
 
548
            warning("Release %s for package %s found on Launchpad but no "
 
549
                    "associated tarballs.", version, package)
 
550
            raise PackageVersionNotPresent(package, version, self)
 
551
        elif len(release_files) > 1:
 
552
            warning("More than one release file for release %s of package %s"
 
553
                    "found on Launchpad. Using the first.", version, package)
 
554
        hosted_file = release_files[0]
 
555
        tmpdir = tempfile.mkdtemp(prefix="builddeb-get-orig-source-")
 
556
        try:
 
557
            inf = hosted_file.open()
 
558
            try:
 
559
                note("Downloading upstream tarball %s from Launchpad",
 
560
                     inf.filename)
 
561
                filename = inf.filename.encode(osutils._fs_enc)
 
562
                filename = filename.replace("/", "")
 
563
                tmppath = os.path.join(tmpdir, filename)
 
564
                outf = open(tmppath, 'wb')
 
565
                try:
 
566
                    outf.write(inf.read())
 
567
                finally:
 
568
                    outf.close()
 
569
            finally:
 
570
                inf.close()
 
571
            dest_name = new_tarball_name(package, version, filename)
 
572
            repack_tarball(tmppath, dest_name, target_dir=target_dir)
 
573
            return os.path.join(target_dir, dest_name)
 
574
        finally:
 
575
            shutil.rmtree(tmpdir)
 
576
 
 
577
    def get_latest_version(self, package, version):
 
578
        versions = []
 
579
        for release in self.project_series.releases:
 
580
            versions.append((release.date_released, release.version))
 
581
        versions.sort()
 
582
        return versions[-1][1].encode("utf-8")