1
2
3
4 __all__ = ['digestgen']
5
6 import errno
7
8 import portage
9 portage.proxy.lazyimport.lazyimport(globals(),
10 'portage.package.ebuild._spawn_nofetch:spawn_nofetch',
11 )
12
13 from portage import os
14 from portage.const import MANIFEST2_REQUIRED_HASH
15 from portage.dbapi.porttree import FetchlistDict
16 from portage.dep import use_reduce
17 from portage.exception import InvalidDependString, FileNotFound, \
18 PermissionDenied, PortagePackageException
19 from portage.localization import _
20 from portage.output import colorize
21 from portage.package.ebuild.fetch import fetch
22 from portage.util import writemsg, writemsg_stdout
23 from portage.versions import catsplit
24
25 -def digestgen(myarchives=None, mysettings=None, myportdb=None):
26 """
27 Generates a digest file if missing. Fetches files if necessary.
28 NOTE: myarchives and mysettings used to be positional arguments,
29 so their order must be preserved for backward compatibility.
30 @param mysettings: the ebuild config (mysettings["O"] must correspond
31 to the ebuild's parent directory)
32 @type mysettings: config
33 @param myportdb: a portdbapi instance
34 @type myportdb: portdbapi
35 @rtype: int
36 @return: 1 on success and 0 on failure
37 """
38 if mysettings is None or myportdb is None:
39 raise TypeError("portage.digestgen(): 'mysettings' and 'myportdb' parameter are required.")
40
41 try:
42 portage._doebuild_manifest_exempt_depend += 1
43 distfiles_map = {}
44 fetchlist_dict = FetchlistDict(mysettings["O"], mysettings, myportdb)
45 for cpv in fetchlist_dict:
46 try:
47 for myfile in fetchlist_dict[cpv]:
48 distfiles_map.setdefault(myfile, []).append(cpv)
49 except InvalidDependString as e:
50 writemsg("!!! %s\n" % str(e), noiselevel=-1)
51 del e
52 return 0
53 mytree = os.path.dirname(os.path.dirname(mysettings["O"]))
54 try:
55 mf = mysettings.repositories.get_repo_for_location(mytree)
56 except KeyError:
57
58 mytree = os.path.realpath(mytree)
59 mf = mysettings.repositories.get_repo_for_location(mytree)
60
61 mf = mf.load_manifest(mysettings["O"], mysettings["DISTDIR"],
62 fetchlist_dict=fetchlist_dict)
63
64 if not mf.allow_create:
65 writemsg_stdout(_(">>> Skipping creating Manifest for %s; "
66 "repository is configured to not use them\n") % mysettings["O"])
67 return 1
68
69
70
71
72
73 required_hash_types = set()
74 required_hash_types.add("size")
75 required_hash_types.add(MANIFEST2_REQUIRED_HASH)
76 dist_hashes = mf.fhashdict.get("DIST", {})
77
78
79
80
81
82
83
84
85 missing_files = []
86 for myfile in distfiles_map:
87 myhashes = dist_hashes.get(myfile)
88 if not myhashes:
89 try:
90 st = os.stat(os.path.join(mysettings["DISTDIR"], myfile))
91 except OSError:
92 st = None
93 if st is None or st.st_size == 0:
94 missing_files.append(myfile)
95 continue
96 size = myhashes.get("size")
97
98 try:
99 st = os.stat(os.path.join(mysettings["DISTDIR"], myfile))
100 except OSError as e:
101 if e.errno != errno.ENOENT:
102 raise
103 del e
104 if size == 0:
105 missing_files.append(myfile)
106 continue
107 if required_hash_types.difference(myhashes):
108 missing_files.append(myfile)
109 continue
110 else:
111 if st.st_size == 0 or size is not None and size != st.st_size:
112 missing_files.append(myfile)
113 continue
114
115 for myfile in missing_files:
116 uris = set()
117 all_restrict = set()
118 for cpv in distfiles_map[myfile]:
119 uris.update(myportdb.getFetchMap(
120 cpv, mytree=mytree)[myfile])
121 restrict = myportdb.aux_get(cpv, ['RESTRICT'], mytree=mytree)[0]
122
123
124
125
126 all_restrict.update(use_reduce(restrict,
127 flat=True, matchnone=True))
128
129
130
131 cat, pf = catsplit(cpv)
132 mysettings["CATEGORY"] = cat
133 mysettings["PF"] = pf
134
135
136
137
138 mysettings["PORTAGE_RESTRICT"] = " ".join(all_restrict)
139
140 try:
141 st = os.stat(os.path.join(mysettings["DISTDIR"], myfile))
142 except OSError:
143 st = None
144
145 if not fetch({myfile : uris}, mysettings):
146 myebuild = os.path.join(mysettings["O"],
147 catsplit(cpv)[1] + ".ebuild")
148 spawn_nofetch(myportdb, myebuild)
149 writemsg(_("!!! Fetch failed for %s, can't update Manifest\n")
150 % myfile, noiselevel=-1)
151 if myfile in dist_hashes and \
152 st is not None and st.st_size > 0:
153
154
155
156 cmd = colorize("INFORM", "ebuild --force %s manifest" %
157 os.path.basename(myebuild))
158 writemsg((_(
159 "!!! If you would like to forcefully replace the existing Manifest entry\n"
160 "!!! for %s, use the following command:\n") % myfile) +
161 "!!! %s\n" % cmd,
162 noiselevel=-1)
163 return 0
164
165 writemsg_stdout(_(">>> Creating Manifest for %s\n") % mysettings["O"])
166 try:
167 mf.create(assumeDistHashesSometimes=True,
168 assumeDistHashesAlways=(
169 "assume-digests" in mysettings.features))
170 except FileNotFound as e:
171 writemsg(_("!!! File %s doesn't exist, can't update Manifest\n")
172 % e, noiselevel=-1)
173 return 0
174 except PortagePackageException as e:
175 writemsg(("!!! %s\n") % (e,), noiselevel=-1)
176 return 0
177 try:
178 mf.write(sign=False)
179 except PermissionDenied as e:
180 writemsg(_("!!! Permission Denied: %s\n") % (e,), noiselevel=-1)
181 return 0
182 if "assume-digests" not in mysettings.features:
183 distlist = list(mf.fhashdict.get("DIST", {}))
184 distlist.sort()
185 auto_assumed = []
186 for filename in distlist:
187 if not os.path.exists(
188 os.path.join(mysettings["DISTDIR"], filename)):
189 auto_assumed.append(filename)
190 if auto_assumed:
191 cp = os.path.sep.join(mysettings["O"].split(os.path.sep)[-2:])
192 pkgs = myportdb.cp_list(cp, mytree=mytree)
193 pkgs.sort()
194 writemsg_stdout(" digest.assumed" + colorize("WARN",
195 str(len(auto_assumed)).rjust(18)) + "\n")
196 for pkg_key in pkgs:
197 fetchlist = myportdb.getFetchMap(pkg_key, mytree=mytree)
198 pv = pkg_key.split("/")[1]
199 for filename in auto_assumed:
200 if filename in fetchlist:
201 writemsg_stdout(
202 " %s::%s\n" % (pv, filename))
203 return 1
204 finally:
205 portage._doebuild_manifest_exempt_depend -= 1
206