1 |
Author: zmedico |
2 |
Date: 2008-12-25 00:31:45 +0000 (Thu, 25 Dec 2008) |
3 |
New Revision: 12303 |
4 |
|
5 |
Modified: |
6 |
main/trunk/pym/_emerge/__init__.py |
7 |
Log: |
8 |
Add support for synchronizing ebuild and eclass timestamps with the metadata |
9 |
cache timestamps which emerge --sync operates on a git repository. This is |
10 |
necessary since git doesn't preserve timestamps. It is assumed that the |
11 |
timestamps should be synchronized if the relevant ebuilds and eclasses are |
12 |
unmodified relative to the HEAD commit (as reported by git-ls-files). This |
13 |
feature was requested by Daniel Robbins, so that it's possible for the funtoo |
14 |
git repository to distribute pre-generated metadata. |
15 |
|
16 |
|
17 |
Modified: main/trunk/pym/_emerge/__init__.py |
18 |
=================================================================== |
19 |
--- main/trunk/pym/_emerge/__init__.py 2008-12-24 22:49:37 UTC (rev 12302) |
20 |
+++ main/trunk/pym/_emerge/__init__.py 2008-12-25 00:31:45 UTC (rev 12303) |
21 |
@@ -11803,6 +11803,7 @@ |
22 |
vcs_dirs = vcs_dirs.intersection(os.listdir(myportdir)) |
23 |
|
24 |
os.umask(0022) |
25 |
+ dosyncuri = syncuri |
26 |
updatecache_flg = False |
27 |
if myaction == "metadata": |
28 |
print "skipping sync" |
29 |
@@ -11825,7 +11826,9 @@ |
30 |
msg = ">>> Git pull in %s successful" % myportdir |
31 |
emergelog(xterm_titles, msg) |
32 |
writemsg_level(msg + "\n") |
33 |
- return exitcode |
34 |
+ exitcode = git_sync_timestamps(settings, myportdir) |
35 |
+ if exitcode == os.EX_OK: |
36 |
+ updatecache_flg = True |
37 |
elif syncuri[:8]=="rsync://": |
38 |
for vcs_dir in vcs_dirs: |
39 |
writemsg_level(("!!! %s appears to be under revision " + \ |
40 |
@@ -12248,6 +12251,138 @@ |
41 |
display_news_notification(root_config, myopts) |
42 |
return os.EX_OK |
43 |
|
44 |
+def git_sync_timestamps(settings, portdir): |
45 |
+ """ |
46 |
+ Since git doesn't preserve timestamps, synchronize timestamps between |
47 |
+ entries and ebuilds/eclasses. Assume the cache has the correct timestamp |
48 |
+ for a given file as long as the file in the working tree is not modified |
49 |
+ (relative to HEAD). |
50 |
+ """ |
51 |
+ cache_dir = os.path.join(portdir, "metadata", "cache") |
52 |
+ if not os.path.isdir(cache_dir): |
53 |
+ return os.EX_OK |
54 |
+ writemsg_level(">>> Synchronizing timestamps...\n") |
55 |
+ |
56 |
+ from portage.cache.cache_errors import CacheError |
57 |
+ try: |
58 |
+ cache_db = settings.load_best_module("portdbapi.metadbmodule")( |
59 |
+ portdir, "metadata/cache", portage.auxdbkeys[:], readonly=True) |
60 |
+ except CacheError, e: |
61 |
+ writemsg_level("!!! Unable to instantiate cache: %s\n" % (e,), |
62 |
+ level=logging.ERROR, noiselevel=-1) |
63 |
+ return 1 |
64 |
+ |
65 |
+ ec_dir = os.path.join(portdir, "eclass") |
66 |
+ try: |
67 |
+ ec_names = set(f[:-7] for f in os.listdir(ec_dir) \ |
68 |
+ if f.endswith(".eclass")) |
69 |
+ except OSError, e: |
70 |
+ writemsg_level("!!! Unable to list eclasses: %s\n" % (e,), |
71 |
+ level=logging.ERROR, noiselevel=-1) |
72 |
+ return 1 |
73 |
+ |
74 |
+ args = [portage.const.BASH_BINARY, "-c", |
75 |
+ "cd %s && git ls-files -m --with-tree=HEAD" % \ |
76 |
+ portage._shell_quote(portdir)] |
77 |
+ import subprocess |
78 |
+ proc = subprocess.Popen(args, stdout=subprocess.PIPE) |
79 |
+ modified_files = set(l.rstrip("\n") for l in proc.stdout) |
80 |
+ rval = proc.wait() |
81 |
+ if rval != os.EX_OK: |
82 |
+ return rval |
83 |
+ |
84 |
+ modified_eclasses = set(ec for ec in ec_names \ |
85 |
+ if os.path.join("eclass", ec + ".eclass") in modified_files) |
86 |
+ |
87 |
+ updated_ec_mtimes = {} |
88 |
+ |
89 |
+ for cpv in cache_db: |
90 |
+ cpv_split = portage.catpkgsplit(cpv) |
91 |
+ if cpv_split is None: |
92 |
+ writemsg_level("!!! Invalid cache entry: %s\n" % (cpv,), |
93 |
+ level=logging.ERROR, noiselevel=-1) |
94 |
+ continue |
95 |
+ |
96 |
+ cat, pn, ver, rev = cpv_split |
97 |
+ cat, pf = portage.catsplit(cpv) |
98 |
+ relative_eb_path = os.path.join(cat, pn, pf + ".ebuild") |
99 |
+ if relative_eb_path in modified_files: |
100 |
+ continue |
101 |
+ |
102 |
+ try: |
103 |
+ cache_entry = cache_db[cpv] |
104 |
+ eb_mtime = cache_entry.get("_mtime_") |
105 |
+ ec_mtimes = cache_entry.get("_eclasses_") |
106 |
+ except KeyError: |
107 |
+ writemsg_level("!!! Missing cache entry: %s\n" % (cpv,), |
108 |
+ level=logging.ERROR, noiselevel=-1) |
109 |
+ continue |
110 |
+ except CacheError, e: |
111 |
+ writemsg_level("!!! Unable to access cache entry: %s %s\n" % \ |
112 |
+ (cpv, e), level=logging.ERROR, noiselevel=-1) |
113 |
+ continue |
114 |
+ |
115 |
+ if eb_mtime is None: |
116 |
+ writemsg_level("!!! Missing ebuild mtime: %s\n" % (cpv,), |
117 |
+ level=logging.ERROR, noiselevel=-1) |
118 |
+ continue |
119 |
+ |
120 |
+ try: |
121 |
+ eb_mtime = long(eb_mtime) |
122 |
+ except ValueError: |
123 |
+ writemsg_level("!!! Invalid ebuild mtime: %s %s\n" % \ |
124 |
+ (cpv, eb_mtime), level=logging.ERROR, noiselevel=-1) |
125 |
+ continue |
126 |
+ |
127 |
+ if ec_mtimes is None: |
128 |
+ writemsg_level("!!! Missing eclass mtimes: %s\n" % (cpv,), |
129 |
+ level=logging.ERROR, noiselevel=-1) |
130 |
+ continue |
131 |
+ |
132 |
+ if modified_eclasses.intersection(ec_mtimes): |
133 |
+ continue |
134 |
+ |
135 |
+ missing_eclasses = set(ec_mtimes).difference(ec_names) |
136 |
+ if missing_eclasses: |
137 |
+ writemsg_level("!!! Non-existent eclass(es): %s %s\n" % \ |
138 |
+ (cpv, sorted(missing_eclasses)), level=logging.ERROR, |
139 |
+ noiselevel=-1) |
140 |
+ continue |
141 |
+ |
142 |
+ eb_path = os.path.join(portdir, relative_eb_path) |
143 |
+ try: |
144 |
+ current_eb_mtime = os.stat(eb_path) |
145 |
+ except OSError: |
146 |
+ writemsg_level("!!! Missing ebuild: %s\n" % \ |
147 |
+ (cpv,), level=logging.ERROR, noiselevel=-1) |
148 |
+ continue |
149 |
+ |
150 |
+ inconsistent = False |
151 |
+ for ec, (ec_path, ec_mtime) in ec_mtimes.iteritems(): |
152 |
+ updated_mtime = updated_ec_mtimes.get(ec) |
153 |
+ if updated_mtime is not None and updated_mtime != ec_mtime: |
154 |
+ writemsg_level("!!! Inconsistend eclass mtime: %s %s\n" % \ |
155 |
+ (cpv, ec), level=logging.ERROR, noiselevel=-1) |
156 |
+ inconsistent = True |
157 |
+ break |
158 |
+ |
159 |
+ if inconsistent: |
160 |
+ continue |
161 |
+ |
162 |
+ if current_eb_mtime != eb_mtime: |
163 |
+ os.utime(eb_path, (eb_mtime, eb_mtime)) |
164 |
+ |
165 |
+ for ec, (ec_path, ec_mtime) in ec_mtimes.iteritems(): |
166 |
+ if ec in updated_ec_mtimes: |
167 |
+ continue |
168 |
+ ec_path = os.path.join(ec_dir, ec + ".eclass") |
169 |
+ current_mtime = long(os.stat(ec_path).st_mtime) |
170 |
+ if current_mtime != ec_mtime: |
171 |
+ os.utime(ec_path, (ec_mtime, ec_mtime)) |
172 |
+ updated_ec_mtimes[ec] = ec_mtime |
173 |
+ |
174 |
+ return os.EX_OK |
175 |
+ |
176 |
def action_metadata(settings, portdb, myopts): |
177 |
portage.writemsg_stdout("\n>>> Updating Portage cache: ") |
178 |
old_umask = os.umask(0002) |