Merge lp:~snappy-dev/snapcraft/more-apt into lp:~snappy-dev/snapcraft/core

Proposed by Sergio Schvezov
Status: Merged
Approved by: Sergio Schvezov
Approved revision: 191
Merged at revision: 186
Proposed branch: lp:~snappy-dev/snapcraft/more-apt
Merge into: lp:~snappy-dev/snapcraft/core
Diff against target: 277 lines (+97/-59)
4 files modified
snapcraft/__init__.py (+5/-1)
snapcraft/manifest.txt (+13/-0)
snapcraft/repo.py (+79/-49)
snapcraft/tests/test_repo.py (+0/-9)
To merge this branch: bzr merge lp:~snappy-dev/snapcraft/more-apt
Reviewer Review Type Date Requested Status
Michael Vogt (community) Approve
Review via email: mp+271817@code.launchpad.net

Commit message

Improving stage-package handling

To post a comment you must log in.
lp:~snappy-dev/snapcraft/more-apt updated
190. By Sergio Schvezov

Remove tests that doesn't make sense as a unit test

191. By Sergio Schvezov

merge trunk

Revision history for this message
Michael Vogt (mvo) wrote :

Good stuff!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'snapcraft/__init__.py'
2--- snapcraft/__init__.py 2015-09-17 14:14:14 +0000
3+++ snapcraft/__init__.py 2015-09-21 15:29:20 +0000
4@@ -31,6 +31,10 @@
5 def PLUGIN_STAGE_PACKAGES(self):
6 return getattr(self, '_PLUGIN_STAGE_PACKAGES', [])
7
8+ @property
9+ def PLUGIN_STAGE_SOURCES(self):
10+ return getattr(self, '_PLUGIN_STAGE_SOURCES', [])
11+
12 def __init__(self, name, options):
13 self.name = name
14 self.options = options
15@@ -99,9 +103,9 @@
16 os.makedirs(d, exist_ok=True)
17
18 def setup_stage_packages(self):
19- ubuntu = snapcraft.repo.Ubuntu(self.ubuntudir)
20 part_stage_packages = getattr(self.options, 'stage_packages', []) or []
21 if self.PLUGIN_STAGE_PACKAGES or part_stage_packages:
22+ ubuntu = snapcraft.repo.Ubuntu(self.ubuntudir, sources=self.PLUGIN_STAGE_SOURCES)
23 ubuntu.get(self.PLUGIN_STAGE_PACKAGES + part_stage_packages)
24 ubuntu.unpack(self.installdir)
25
26
27=== modified file 'snapcraft/manifest.txt'
28--- snapcraft/manifest.txt 2015-09-01 19:04:49 +0000
29+++ snapcraft/manifest.txt 2015-09-21 15:29:20 +0000
30@@ -1,5 +1,6 @@
31 adduser
32 apt
33+apt-utils
34 base-files
35 base-passwd
36 bash
37@@ -7,12 +8,14 @@
38 coreutils
39 dash
40 debconf
41+debconf-i18n
42 debianutils
43 diffutils
44 dmsetup
45 dpkg
46 e2fslibs
47 e2fsprogs
48+file
49 findutils
50 gcc-4.9-base
51 gcc-5-base
52@@ -26,6 +29,8 @@
53 insserv
54 libacl1
55 libapparmor1
56+libapt
57+libapt-inst1.5
58 libapt-pkg4.12
59 libattr1
60 libaudit-common
61@@ -44,8 +49,11 @@
62 libgcc1
63 libgcrypt20
64 libgpg-error0
65+libgpm2
66 libkmod2
67+liblocale-gettext-perl
68 liblzma5
69+libmagic1
70 libmount1
71 libncurses5
72 libncursesw5
73@@ -65,6 +73,9 @@
74 libss2
75 libstdc++6
76 libsystemd0
77+libtext-charwidth-perl
78+libtext-iconv-perl
79+libtext-wrapi18n-perl
80 libtinfo5
81 libudev1
82 libusb-0.1-4
83@@ -74,6 +85,8 @@
84 login
85 lsb-base
86 makedev
87+manpages
88+manpages-dev
89 mawk
90 mount
91 multiarch-support
92
93=== modified file 'snapcraft/repo.py'
94--- snapcraft/repo.py 2015-09-07 20:23:57 +0000
95+++ snapcraft/repo.py 2015-09-21 15:29:20 +0000
96@@ -14,11 +14,28 @@
97 # You should have received a copy of the GNU General Public License
98 # along with this program. If not, see <http://www.gnu.org/licenses/>.
99
100-import apt
101 import glob
102 import itertools
103 import os
104+import string
105 import subprocess
106+import urllib
107+import urllib.request
108+
109+import apt
110+from xml.etree import ElementTree
111+
112+_DEFAULT_SOURCES = '''deb http://${mirror}archive.ubuntu.com/ubuntu/ vivid main restricted
113+deb http://${mirror}archive.ubuntu.com/ubuntu/ vivid-updates main restricted
114+deb http://${mirror}archive.ubuntu.com/ubuntu/ vivid universe
115+deb http://${mirror}archive.ubuntu.com/ubuntu/ vivid-updates universe
116+deb http://${mirror}archive.ubuntu.com/ubuntu/ vivid multiverse
117+deb http://${mirror}archive.ubuntu.com/ubuntu/ vivid-updates multiverse
118+deb http://security.ubuntu.com/ubuntu vivid-security main restricted
119+deb http://security.ubuntu.com/ubuntu vivid-security universe
120+deb http://security.ubuntu.com/ubuntu vivid-security multiverse
121+'''
122+_GEOIP_SERVER = "http://geoip.ubuntu.com/lookup"
123
124
125 class PackageNotFoundError(Exception):
126@@ -43,33 +60,47 @@
127
128 class Ubuntu:
129
130- def __init__(self, download_dir, recommends=False):
131- self.apt_cache = apt.Cache()
132- self.manifest_dep_names = self._manifest_dep_names()
133+ def __init__(self, rootdir, recommends=False, sources=_DEFAULT_SOURCES):
134+ sources = sources or _DEFAULT_SOURCES
135+ self.downloaddir = os.path.join(rootdir, 'download')
136+ self.rootdir = rootdir
137+ self.apt_cache = _setup_apt_cache(rootdir, sources)
138 self.recommends = recommends
139- self.download_dir = download_dir
140
141 def get(self, package_names):
142- # TODO cleanup download_dir for clean gets and unpacks
143- self.all_dep_names = set()
144-
145- all_package_names = self._compute_deps(package_names)
146-
147- for pkg in all_package_names:
148- self.apt_cache[pkg].candidate.fetch_binary(destdir=self.download_dir)
149-
150- return all_package_names
151-
152- def unpack(self, root_dir):
153- pkgs_abs_path = glob.glob(os.path.join(self.download_dir, '*.deb'))
154+ os.makedirs(self.downloaddir, exist_ok=True)
155+
156+ manifest_dep_names = self._manifest_dep_names()
157+
158+ for name in package_names:
159+ try:
160+ self.apt_cache[name].mark_install()
161+ except KeyError:
162+ raise PackageNotFoundError(name)
163+
164+ for pkg in self.apt_cache:
165+ # those should be already on each system, it also prevents
166+ # diving into downloading libc6
167+ if (pkg.candidate.priority in 'essential' and
168+ pkg.name not in package_names):
169+ print('Skipping priority essential/imporant %s' % pkg.name)
170+ continue
171+ if (pkg.name in manifest_dep_names and pkg.name not in package_names):
172+ print('Skipping blacklisted from manifest package %s' % pkg.name)
173+ continue
174+ if pkg.marked_install:
175+ pkg.candidate.fetch_binary(destdir=self.downloaddir)
176+
177+ def unpack(self, rootdir):
178+ pkgs_abs_path = glob.glob(os.path.join(self.downloaddir, '*.deb'))
179 for pkg in pkgs_abs_path:
180 # TODO needs elegance and error control
181 try:
182- subprocess.check_call(['dpkg-deb', '--extract', pkg, root_dir])
183+ subprocess.check_call(['dpkg-deb', '--extract', pkg, rootdir])
184 except subprocess.CalledProcessError:
185 raise UnpackError(pkg)
186
187- _fix_symlinks(root_dir)
188+ _fix_symlinks(rootdir)
189
190 def _manifest_dep_names(self):
191 manifest_dep_names = set()
192@@ -82,36 +113,35 @@
193
194 return manifest_dep_names
195
196- def _compute_deps(self, package_names):
197- self._add_deps(package_names)
198-
199- for pkg in package_names:
200- if pkg not in self.all_dep_names:
201- raise PackageNotFoundError(pkg)
202-
203- return sorted(self.all_dep_names)
204-
205- def _add_deps(self, package_names):
206- def add_deps(packages):
207- for pkg in packages:
208- # Remove the :any in packages
209- # TODO support multiarch
210- pkg = pkg.rsplit(':', 1)[0]
211- if pkg in self.all_dep_names:
212- continue
213- if pkg in self.manifest_dep_names and pkg not in package_names:
214- continue
215- deps = set()
216- try:
217- candidate_pkg = self.apt_cache[pkg].candidate
218- except KeyError:
219- raise PackageNotFoundError(pkg)
220- deps = candidate_pkg.dependencies
221- if self.recommends:
222- deps += candidate_pkg.recommends
223- self.all_dep_names.add(pkg)
224- add_deps([x[0].name for x in deps])
225- add_deps(package_names)
226+
227+def get_geoip_country_code_prefix():
228+ try:
229+ with urllib.request.urlopen(_GEOIP_SERVER) as f:
230+ xml_data = f.read()
231+ et = ElementTree.fromstring(xml_data)
232+ cc = et.find("CountryCode")
233+ if cc is None:
234+ return ""
235+ return cc.text.lower() + "."
236+ except (ElementTree.ParseError, urllib.error.URLError):
237+ pass
238+ return ""
239+
240+
241+def _setup_apt_cache(rootdir, sources):
242+ os.makedirs(os.path.join(rootdir, 'etc', 'apt'), exist_ok=True)
243+ srcfile = os.path.join(rootdir, 'etc', 'apt', 'sources.list')
244+ with open(srcfile, 'w') as f:
245+ mirror_prefix = get_geoip_country_code_prefix()
246+ sources_list = string.Template(sources).substitute(
247+ {"mirror": mirror_prefix})
248+ f.write(sources_list)
249+ progress = apt.progress.text.AcquireProgress()
250+ apt_cache = apt.Cache(rootdir=rootdir, memonly=True)
251+ apt_cache.update(fetch_progress=progress, sources_list=srcfile)
252+ apt_cache.open()
253+
254+ return apt_cache
255
256
257 def _fix_symlinks(debdir):
258
259=== modified file 'snapcraft/tests/test_repo.py'
260--- snapcraft/tests/test_repo.py 2015-09-01 19:04:49 +0000
261+++ snapcraft/tests/test_repo.py 2015-09-21 15:29:20 +0000
262@@ -23,15 +23,6 @@
263
264 class UbuntuTestCase(tests.TestCase):
265
266- def test_unrecognized_package_raises_exception(self):
267- ubuntu = repo.Ubuntu('download_dir')
268-
269- with self.assertRaises(repo.PackageNotFoundError) as raised:
270- ubuntu.get(['test_package'])
271-
272- expected_message = 'The Ubuntu package \'test_package\' was not found'
273- self.assertEqual(raised.exception.message, expected_message)
274-
275 def test_fix_symlinks(self):
276 tempdirObj = tempfile.TemporaryDirectory()
277 self.addCleanup(tempdirObj.cleanup)

Subscribers

People subscribed via source and target branches

to all changes: