48
40
from bzrlib.plugins.builddeb.errors import (
49
41
MissingUpstreamTarball,
50
42
PackageVersionNotPresent,
51
PerFileTimestampsNotSupported,
55
from bzrlib.plugins.builddeb.repack_tarball import repack_tarball
45
from bzrlib.plugins.builddeb.repack_tarball import (
56
49
from bzrlib.plugins.builddeb.util import (
50
component_from_orig_tarball,
58
reconstruct_pristine_tar,
56
def new_tarball_name(package, version, old_name):
57
"""Determine new tarball name based on the package name and the old name.
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")
63
66
class UpstreamSource(object):
64
67
"""A source for upstream versions (uscan, get-orig-source, etc)."""
92
95
raise NotImplementedError(self.has_version)
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.
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
102
raise NotImplementedError(self.fetch_tarball)
105
raise NotImplementedError(self.fetch_tarballs)
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,
109
class PristineTarSource(UpstreamSource):
110
"""Source that uses the pristine-tar revisions in the packaging branch."""
112
def __init__(self, tree, branch):
116
def tag_name(self, version, distro=None):
117
"""Gets the tag name for the upstream part of version.
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.
123
assert isinstance(version, str)
125
return "upstream-" + version
126
return "upstream-%s-%s" % (distro, version)
128
def fetch_tarball(self, package, version, target_dir):
129
revid = self.version_as_revision(package, version)
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)
139
target_filename = self._tarball_path(package, version,
140
target_dir, format=format)
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
149
def _has_version(self, tag_name, md5=None):
150
if not self.branch.tags.has_tag(tag_name):
152
revid = self.branch.tags.lookup_tag(tag_name)
153
self.branch.lock_read()
155
graph = self.branch.repository.get_graph()
156
if not graph.is_ancestor(revid, self.branch.last_revision()):
162
rev = self.branch.repository.get_revision(revid)
164
return rev.properties['deb-md5'] == md5
166
warning("tag %s present in branch, but there is no "
167
"associated 'deb-md5' property" % tag_name)
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)
177
return self.branch.tags.lookup_tag(tag_name)
179
raise PackageVersionNotPresent(package, version, self)
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):
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]
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)
200
def pristine_tar_format(self, rev):
201
if 'deb-pristine-delta' in rev.properties:
203
elif 'deb-pristine-delta-bz2' in rev.properties:
205
assert self.has_pristine_tar_delta(rev)
206
raise AssertionError("Not handled new delta type in "
207
"pristine_tar_format")
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']
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)
220
def reconstruct_pristine_tar(self, revid, package, version,
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-")
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)
233
export(tree, dest_filename, require_per_file_timestamps=True)
235
shutil.rmtree(tmpdir)
238
112
class AptSource(UpstreamSource):
239
113
"""Upstream source that uses apt-source."""
241
def fetch_tarball(self, package, upstream_version, target_dir,
115
def fetch_tarballs(self, package, upstream_version, target_dir,
243
117
if _apt_pkg is None:
304
184
note("Trying to run get-orig-source rule failed")
306
for desired_tarball_name in desired_tarball_names:
307
fetched_tarball = os.path.join(source_dir, desired_tarball_name)
187
for filename in os.listdir(source_dir):
188
if not filename.startswith(prefix):
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))
197
note("get-orig-source did not create file with prefix %s", prefix)
315
def fetch_tarball(self, package, version, target_dir):
200
def fetch_tarballs(self, package, version, target_dir):
317
202
rules_name = 'rules'
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-")
327
209
base_export_dir = os.path.join(tmpdir, "export")
528
423
if in_target is not None:
529
424
note("Upstream tarball already exists in build directory, "
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)
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)
542
438
note("Using the upstream tarball that is present in %s" %
544
path = self.provide_from_store_dir(target_dir)
545
assert path is not None
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))
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):
446
return gather_orig_files(self.package, self.version, target_dir)
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):
449
return gather_orig_files(self.package, self.version, self.store_dir)
562
451
def provide_from_store_dir(self, target_dir):
563
path = self.already_exists_in_store()
452
paths = self.already_exists_in_store()
565
456
repack_tarball(path, os.path.basename(path),
566
target_dir=target_dir, force_gz=False)
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)
576
461
def extract_tarball_version(path, packagename):
606
492
self.version = version
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)]
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)
507
class LaunchpadReleaseFileSource(UpstreamSource):
508
"""Source that retrieves release files from Launchpad."""
511
def from_package(cls, distribution_name, distroseries_name, package):
512
"""Create a LaunchpadReleaseFileSource from a distribution package.
514
:param distribution_name: Name of the distribution (e.g. "Ubuntu")
515
:param distroseries_name: Name of the distribution series
517
:param package: Package name
518
:return: A `LaunchpadReleaseFileSource`
520
from bzrlib.plugins.builddeb.launchpad import (
521
get_upstream_projectseries_for_package,
523
project_series = get_upstream_projectseries_for_package(
524
package, distribution_name, distroseries_name)
525
if project_series is None:
527
return cls(project_series=project_series)
529
def __init__(self, project=None, project_series=None):
530
if project_series is None:
531
self.project_series = project.development_focus
533
self.project_series = project_series
535
self.project = project_series.project
537
self.project = project
539
def fetch_tarballs(self, package, version, target_dir):
540
release = self.project.getRelease(version=version)
542
raise PackageVersionNotPresent(package, version, self)
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-")
557
inf = hosted_file.open()
559
note("Downloading upstream tarball %s from Launchpad",
561
filename = inf.filename.encode(osutils._fs_enc)
562
filename = filename.replace("/", "")
563
tmppath = os.path.join(tmpdir, filename)
564
outf = open(tmppath, 'wb')
566
outf.write(inf.read())
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)
575
shutil.rmtree(tmpdir)
577
def get_latest_version(self, package, version):
579
for release in self.project_series.releases:
580
versions.append((release.date_released, release.version))
582
return versions[-1][1].encode("utf-8")