1 |
On 03/13/14 15:09, Alec Warner wrote: |
2 |
> |
3 |
> |
4 |
> |
5 |
> On Wed, Mar 12, 2014 at 11:10 PM, Pavel Kazakov |
6 |
> <nullishzero@g.o <mailto:nullishzero@g.o>> wrote: |
7 |
> |
8 |
> --- |
9 |
> pym/portage/emaint/main.py | 6 +- |
10 |
> |
11 |
|
12 |
... |
13 |
|
14 |
> Perhaps add an __iter__ function to TrackingFile, that implicitly |
15 |
> calls load? |
16 |
> |
17 |
> Then this can be: |
18 |
> for pkg, mtime in self._tracking_file: |
19 |
> |
20 |
> ? |
21 |
> |
22 |
> Just a thought. |
23 |
|
24 |
That's actually a neat idea. Going to do it. |
25 |
|
26 |
> |
27 |
> |
28 |
> + for pkg, mtime in self._tracking_file.load().items(): |
29 |
> + if pkg not in failed_pkgs: |
30 |
> + failed_pkgs[pkg] = mtime |
31 |
> + return failed_pkgs |
32 |
> + |
33 |
> + |
34 |
> + def _remove_failed_dirs(self, failed_pkgs): |
35 |
> + """ |
36 |
> + Remove the directories of packages that failed to |
37 |
> merge. |
38 |
> + |
39 |
> + @param failed_pkgs: failed packages whose |
40 |
> directories to remove |
41 |
> + @type failed_pkg: dict |
42 |
> + """ |
43 |
> + for failed_pkg in failed_pkgs: |
44 |
> + pkg_path = os.path.join(self._vardb_path, |
45 |
> failed_pkg) |
46 |
> + # delete failed merge directory if it |
47 |
> exists (it might not exist |
48 |
> + # if loaded from tracking file) |
49 |
> + if os.path.exists(pkg_path): |
50 |
> + shutil.rmtree(pkg_path) |
51 |
> + # TODO: try removing package contents to |
52 |
> prevent orphaned |
53 |
> + # files |
54 |
> |
55 |
> |
56 |
> I don't get this TODO, can you elaborate? |
57 |
|
58 |
Right now the current code deletes only the failed merge directory (e.g. |
59 |
/var/db/pkg/app-misc/-MERGING-lsx-0.1/). |
60 |
|
61 |
In /var/db/pkg/app-misc/-MERGING-lsx-0.1/, there should be a file called |
62 |
CONTENTS that records the package contents (e.g. obj |
63 |
/usr/bin/lsx-suckless 478333aa1cb7761bc8e3a400cbd976ab 1394688298). |
64 |
However, during a failed merge, the CONTENTS file may not be there or |
65 |
may be corrupt, so my code doesn't handle removing the contents right |
66 |
now, only the failed merge directory. |
67 |
|
68 |
Any suggestions for better wording? |
69 |
|
70 |
> |
71 |
> |
72 |
> + |
73 |
> + |
74 |
> + def _get_pkg_atoms(self, failed_pkgs, pkg_atoms, pkg_dne): |
75 |
> + """ |
76 |
> + Get the package atoms for the specified failed |
77 |
> packages. |
78 |
> + |
79 |
> + @param failed_pkgs: failed packages to iterate |
80 |
> + @type failed_pkgs: dict |
81 |
> + @param pkg_atoms: append package atoms to this set |
82 |
> + @type pkg_atoms: set |
83 |
> + @param pkg_dne: append any packages atoms that are |
84 |
> invalid to this set |
85 |
> + @type pkg_dne: set |
86 |
> |
87 |
> |
88 |
> Not following what dne means. |
89 |
|
90 |
How about pkg_invalid_entries? And I can change the comment to '@param |
91 |
pkg_invalid_entries: append any packages that are invalid to this set' |
92 |
|
93 |
After looking at the function more, I think it might make sense to |
94 |
instead return pkg_atoms and pkg_invalid_entries as a tuple, instead of |
95 |
having the calling code pass them in. |
96 |
|
97 |
> |
98 |
> |
99 |
> + """ |
100 |
> + |
101 |
> + emerge_config = load_emerge_config() |
102 |
> + portdb = |
103 |
> emerge_config.target_config.trees['porttree'].dbapi |
104 |
> + for failed_pkg in failed_pkgs: |
105 |
> + # validate pkg name |
106 |
> + pkg_name = '%s' % |
107 |
> failed_pkg.replace(MERGING_IDENTIFIER, '') |
108 |
> + pkg_atom = '=%s' % pkg_name |
109 |
> + |
110 |
> + if not isvalidatom(pkg_atom): |
111 |
> + pkg_dne.append( "'%s' is an |
112 |
> invalid package atom." % pkg_atom) |
113 |
> + if not portdb.cpv_exists(pkg_name): |
114 |
> + pkg_dne.append( "'%s' does not |
115 |
> exist in the portage tree." |
116 |
> + % pkg_name) |
117 |
> + pkg_atoms.add(pkg_atom) |
118 |
> + |
119 |
> + |
120 |
> + def _emerge_pkg_atoms(self, module_output, pkg_atoms): |
121 |
> + """ |
122 |
> + Emerge the specified packages atoms. |
123 |
> + |
124 |
> + @param module_output: output will be written to |
125 |
> + @type module_output: Class |
126 |
> + @param pkg_atoms: packages atoms to emerge |
127 |
> + @type pkg_atoms: set |
128 |
> + @rtype: list |
129 |
> + @return: List of results |
130 |
> + """ |
131 |
> + # TODO: rewrite code to use portage's APIs instead |
132 |
> of a subprocess |
133 |
> + env = { |
134 |
> + "FEATURES" : "-collision-detect |
135 |
> -protect-owned", |
136 |
> + "PATH" : os.environ["PATH"] |
137 |
> + } |
138 |
> + emerge_cmd = ( |
139 |
> + portage._python_interpreter, |
140 |
> + '-b', |
141 |
> + os.path.join(PORTAGE_BIN_PATH, 'emerge'), |
142 |
> + '--quiet', |
143 |
> + '--oneshot', |
144 |
> + '--complete-graph=y' |
145 |
> + ) |
146 |
> + results = [] |
147 |
> + msg = 'Re-Emerging packages that failed to merge...\n' |
148 |
> + if module_output: |
149 |
> + module_output.write(msg) |
150 |
> + else: |
151 |
> + module_output = subprocess.PIPE |
152 |
> + results.append(msg) |
153 |
> + proc = subprocess.Popen(emerge_cmd + |
154 |
> tuple(pkg_atoms), env=env, |
155 |
> + stdout=module_output, stderr=sys.stderr) |
156 |
> + output = proc.communicate()[0] |
157 |
> |
158 |
> |
159 |
> This seems sort of weird, perhaps: |
160 |
> |
161 |
> output, _ = proc.communicate() |
162 |
|
163 |
I'll change it, but in fairness 'proc.communicate()[0]' is how both the |
164 |
official python documentation and other areas of portage do it ;) |
165 |
|
166 |
> |
167 |
> |
168 |
> + if output: |
169 |
> + results.append(output) |
170 |
> + if proc.returncode != os.EX_OK: |
171 |
> + emerge_status = "Failed to emerge '%s'" % |
172 |
> (' '.join(pkg_atoms)) |
173 |
> + else: |
174 |
> |
175 |
... |
176 |
|
177 |
I'll incorporate your other changes. |
178 |
|
179 |
Regards, |
180 |
Pavel |