1 |
v2: Reformat, add a function to return an appropriate read-only checker |
2 |
for the operating system, so that this can be extended to other OSes. |
3 |
--- |
4 |
pym/portage/dbapi/vartree.py | 32 +++++++++++++++++ |
5 |
pym/portage/util/rochecker.py | 81 +++++++++++++++++++++++++++++++++++++++++++ |
6 |
2 files changed, 113 insertions(+) |
7 |
create mode 100644 pym/portage/util/rochecker.py |
8 |
|
9 |
diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py |
10 |
index ed62323..c77cf07 100644 |
11 |
--- a/pym/portage/dbapi/vartree.py |
12 |
+++ b/pym/portage/dbapi/vartree.py |
13 |
@@ -32,6 +32,7 @@ portage.proxy.lazyimport.lazyimport(globals(), |
14 |
'portage.util.env_update:env_update', |
15 |
'portage.util.listdir:dircache,listdir', |
16 |
'portage.util.movefile:movefile', |
17 |
+ 'portage.util.rochecker:get_ro_checker', |
18 |
'portage.util._dyn_libs.PreservedLibsRegistry:PreservedLibsRegistry', |
19 |
'portage.util._dyn_libs.LinkageMapELF:LinkageMapELF@LinkageMap', |
20 |
'portage.util._async.SchedulerInterface:SchedulerInterface', |
21 |
@@ -3508,6 +3509,8 @@ class dblink(object): |
22 |
|
23 |
This function does the following: |
24 |
|
25 |
+ calls get_ro_checker to retrieve a function for checking whether Portage |
26 |
+ will write to a read-only filesystem, then runs it against the directory list |
27 |
calls self._preserve_libs if FEATURES=preserve-libs |
28 |
calls self._collision_protect if FEATURES=collision-protect |
29 |
calls doebuild(mydo=pkg_preinst) |
30 |
@@ -3685,6 +3688,7 @@ class dblink(object): |
31 |
eagain_error = False |
32 |
|
33 |
myfilelist = [] |
34 |
+ mydirlist = [] |
35 |
mylinklist = [] |
36 |
paths_with_newlines = [] |
37 |
def onerror(e): |
38 |
@@ -3717,6 +3721,9 @@ class dblink(object): |
39 |
unicode_errors.append(new_parent[ed_len:]) |
40 |
break |
41 |
|
42 |
+ relative_path = parent[srcroot_len:] |
43 |
+ mydirlist.append("/" + relative_path) |
44 |
+ |
45 |
for fname in files: |
46 |
try: |
47 |
fname = _unicode_decode(fname, |
48 |
@@ -3829,6 +3836,31 @@ class dblink(object): |
49 |
for other in others_in_slot]) |
50 |
prepare_build_dirs(settings=self.settings, cleanup=cleanup) |
51 |
|
52 |
+ # Check for read-only filesystems |
53 |
+ ro_checker_func = get_ro_checker() |
54 |
+ rofilesystems = ro_checker_func(mydirlist) |
55 |
+ |
56 |
+ if rofilesystems: |
57 |
+ msg = _("One or more files installed to this package are " |
58 |
+ "set to be installed to read-only filesystems. " |
59 |
+ "Please mount the filesystems below read-write " |
60 |
+ "and retry.") |
61 |
+ msg = textwrap.wrap(msg, 70) |
62 |
+ msg.append("") |
63 |
+ for f in rofilesystems: |
64 |
+ msg.append("\t%s" % os.path.join(destroot, |
65 |
+ f.lstrip(os.path.sep))) |
66 |
+ msg.append("") |
67 |
+ self._elog("eerror", "preinst", msg) |
68 |
+ |
69 |
+ msg = _("Package '%s' NOT merged due to read-only file systems.") % \ |
70 |
+ self.settings.mycpv |
71 |
+ msg += _(" If necessary, refer to your elog " |
72 |
+ "messages for the whole content of the above message.") |
73 |
+ msg = textwrap.wrap(msg, 70) |
74 |
+ eerror(msg) |
75 |
+ return 1 |
76 |
+ |
77 |
# check for package collisions |
78 |
blockers = self._blockers |
79 |
if blockers is None: |
80 |
diff --git a/pym/portage/util/rochecker.py b/pym/portage/util/rochecker.py |
81 |
new file mode 100644 |
82 |
index 0000000..67e8131 |
83 |
--- /dev/null |
84 |
+++ b/pym/portage/util/rochecker.py |
85 |
@@ -0,0 +1,81 @@ |
86 |
+#-*- coding:utf-8 -*- |
87 |
+# Copyright 2014 Gentoo Foundation |
88 |
+# Distributed under the terms of the GNU General Public License v2 |
89 |
+""" |
90 |
+Methods to check whether Portage is going to write to read-only filesystems. |
91 |
+Since the methods are not portable across different OSes, each OS needs its |
92 |
+own method. To expand RO checking for different OSes, add a method which |
93 |
+accepts a list of directories and returns a list of mounts which need to be |
94 |
+remounted RW, then add "elif ostype == (the ostype value for your OS)" to |
95 |
+get_ro_checker() |
96 |
+""" |
97 |
+from __future__ import unicode_literals |
98 |
+ |
99 |
+import logging |
100 |
+import re |
101 |
+ |
102 |
+from portage.util import writemsg_level |
103 |
+from portage.localization import _ |
104 |
+from portage.data import ostype |
105 |
+ |
106 |
+ |
107 |
+def get_ro_checker(): |
108 |
+ """ |
109 |
+ Uses the system type to find an appropriate method for testing whether Portage |
110 |
+ is going to write to any read-only filesystems |
111 |
+ |
112 |
+ @return: |
113 |
+ 1. A method for testing for RO filesystems appropriate to the current system |
114 |
+ """ |
115 |
+ if ostype == "Linux": |
116 |
+ return linux_ro_checker |
117 |
+ else: |
118 |
+ return empty_ro_checker |
119 |
+ |
120 |
+ |
121 |
+def linux_ro_checker(dir_list): |
122 |
+ """ |
123 |
+ Use /proc/mounts to check that no directories installed by the ebuild are set |
124 |
+ to be installed to a read-only filesystem |
125 |
+ |
126 |
+ @param dir_list: Directories installed by the ebuild |
127 |
+ @type dir_list: List |
128 |
+ @return: |
129 |
+ 1. A list of filesystems which are both set to be written to and are mounted |
130 |
+ read-only, may be empty. |
131 |
+ """ |
132 |
+ ro_filesystems = set() |
133 |
+ ro_filesystems_written = set() |
134 |
+ |
135 |
+ try: |
136 |
+ with open("/proc/mounts") as f: |
137 |
+ roregex = re.compile(r'(\A|,)ro(\Z|,)') |
138 |
+ for line in f: |
139 |
+ if roregex.search(line.split(" ")[3].strip()) is not None: |
140 |
+ romount = line.split(" ")[1].strip() |
141 |
+ ro_filesystems.add(romount) |
142 |
+ |
143 |
+ # If /proc/mounts can't be read, assume that there are no RO |
144 |
+ # filesystems and return |
145 |
+ except EnvironmentError: |
146 |
+ writemsg_level(_("!!! /proc/mounts cannot be read"), |
147 |
+ level=logging.WARNING, noiselevel=-1) |
148 |
+ return [] |
149 |
+ |
150 |
+ if not ro_filesystems: |
151 |
+ return ro_filesystems |
152 |
+ |
153 |
+ for directory in dir_list: |
154 |
+ for filesystem in ro_filesystems: |
155 |
+ if filesystem == directory: |
156 |
+ ro_filesystems_written.add(filesystem) |
157 |
+ |
158 |
+ return ro_filesystems_written |
159 |
+ |
160 |
+ |
161 |
+def empty_ro_checker(dir_list): |
162 |
+ """ |
163 |
+ Always returns [], this is the fallback function if the system does not have |
164 |
+ an ro_checker method defined |
165 |
+ """ |
166 |
+ return [] |
167 |
-- |
168 |
1.8.5.1 |