Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 311253
Collapse All | Expand All

(-)a/bin/quickpkg (-135 / +179 lines)
Lines 7-12 from __future__ import print_function Link Here
7
import errno
7
import errno
8
import signal
8
import signal
9
import sys
9
import sys
10
import tarfile
10
11
11
try:
12
try:
12
	import portage
13
	import portage
Lines 16-37 except ImportError: Link Here
16
	import portage
17
	import portage
17
18
18
from portage import os
19
from portage import os
20
from portage import catsplit, flatten, isvalidatom, xpak
21
from portage.dbapi.dep_expand import dep_expand
22
from portage.dep import use_reduce, paren_reduce
23
from portage.exception import InvalidAtom, InvalidData, InvalidDependString, PackageSetNotFound
24
from portage.util import ConfigProtect, ensure_dirs
25
from portage.dbapi.vartree import dblink, tar_contents
26
from portage.checksum import perform_md5
27
from portage.sets import load_default_config, SETPREFIX
28
	
29
def quickpkg_atom(options, infos, arg, eout):
30
	root = portage.settings["ROOT"]
31
	trees = portage.db[root]
32
	vartree = trees["vartree"]
33
	vardb = vartree.dbapi
34
	bintree = trees["bintree"]
35
	
36
	include_config = options.include_config == "y"
37
	include_unmodified_config = options.include_unmodified_config == "y"
38
	fix_metadata_keys = ["PF", "CATEGORY"]
39
	
40
	try:
41
		atom = dep_expand(arg, mydb=vardb, settings=vartree.settings)
42
	except ValueError as e:
43
		# Multiple matches thrown from cpv_expand
44
		eout.eerror("Please use a more specific atom: %s" % \
45
			" ".join(e.args[0]))
46
		del e
47
		infos["missing"].append(arg)
48
		return
49
	except (InvalidAtom, InvalidData):
50
		eout.eerror("Invalid atom: %s" % (arg,))
51
		infos["missing"].append(arg)
52
		return
53
	if atom[:1] == '=' and arg[:1] != '=':
54
		# dep_expand() allows missing '=' but it's really invalid
55
		eout.eerror("Invalid atom: %s" % (arg,))
56
		infos["missing"].append(arg)
57
		return
58
59
	matches = vardb.match(atom)
60
	pkgs_for_arg = 0
61
	for cpv in matches:
62
		excluded_config_files = []
63
		bintree.prevent_collision(cpv)
64
		cat, pkg = catsplit(cpv)
65
		dblnk = dblink(cat, pkg, root,
66
			vartree.settings, treetype="vartree",
67
			vartree=vartree)
68
		dblnk.lockdb()
69
		try:
70
			if not dblnk.exists():
71
				# unmerged by a concurrent process
72
				continue
73
			iuse, use, restrict = vardb.aux_get(cpv,
74
				["IUSE","USE","RESTRICT"])
75
			iuse = [ x.lstrip("+-") for x in iuse.split() ]
76
			use = use.split()
77
			try:
78
				restrict = flatten(use_reduce(
79
					paren_reduce(restrict), uselist=use))
80
			except InvalidDependString as e:
81
				eout.eerror("Invalid RESTRICT metadata " + \
82
					"for '%s': %s; skipping" % (cpv, str(e)))
83
				del e
84
				continue
85
			if "bindist" in iuse and "bindist" not in use:
86
				eout.ewarn("%s: package was emerged with USE=-bindist!" % cpv)
87
				eout.ewarn("%s: it may not be legal to redistribute this." % cpv)
88
			elif "bindist" in restrict:
89
				eout.ewarn("%s: package has RESTRICT=bindist!" % cpv)
90
				eout.ewarn("%s: it may not be legal to redistribute this." % cpv)
91
			eout.ebegin("Building package for %s" % cpv)
92
			pkgs_for_arg += 1
93
			contents = dblnk.getcontents()
94
			protect = None
95
			if not include_config:
96
				confprot = ConfigProtect(root,
97
					portage.settings.get("CONFIG_PROTECT","").split(),
98
					portage.settings.get("CONFIG_PROTECT_MASK","").split())
99
				def protect(filename):
100
					if not confprot.isprotected(filename):
101
						return False
102
					if include_unmodified_config:
103
						file_data = contents[filename]
104
						if file_data[0] == "obj":
105
							orig_md5 = file_data[2].lower()
106
							cur_md5 = perform_md5(filename, calc_prelink=1)
107
							if orig_md5 == cur_md5:
108
								return False
109
					excluded_config_files.append(filename)
110
					return True
111
			existing_metadata = dict(zip(fix_metadata_keys,
112
				vardb.aux_get(cpv, fix_metadata_keys)))
113
			category, pf = portage.catsplit(cpv)
114
			required_metadata = {}
115
			required_metadata["CATEGORY"] = category
116
			required_metadata["PF"] = pf
117
			update_metadata = {}
118
			for k, v in required_metadata.items():
119
				if v != existing_metadata[k]:
120
					update_metadata[k] = v
121
			if update_metadata:
122
				vardb.aux_update(cpv, update_metadata)
123
			xpdata = xpak.xpak(dblnk.dbdir)
124
			binpkg_tmpfile = os.path.join(bintree.pkgdir,
125
				cpv + ".tbz2." + str(os.getpid()))
126
			ensure_dirs(os.path.dirname(binpkg_tmpfile))
127
			tar = tarfile.open(binpkg_tmpfile, "w:bz2")
128
			tar_contents(contents, root, tar, protect=protect)
129
			tar.close()
130
			xpak.tbz2(binpkg_tmpfile).recompose_mem(xpdata)
131
		finally:
132
			dblnk.unlockdb()
133
		bintree.inject(cpv, filename=binpkg_tmpfile)
134
		binpkg_path = bintree.getname(cpv)
135
		try:
136
			s = os.stat(binpkg_path)
137
		except OSError as e:
138
			# Sanity check, shouldn't happen normally.
139
			eout.eend(1)
140
			eout.eerror(str(e))
141
			del e
142
			eout.eerror("Failed to create package: '%s'" % binpkg_path)
143
		else:
144
			eout.eend(0)
145
			infos["successes"].append((cpv, s.st_size))
146
			infos["config_files_excluded"] += len(excluded_config_files)
147
			for filename in excluded_config_files:
148
				eout.ewarn("Excluded config: '%s'" % filename)
149
	if not pkgs_for_arg:
150
		eout.eerror("Could not find anything " + \
151
			"to match '%s'; skipping" % arg)
152
		infos["missing"].append(arg)
153
154
def quickpkg_set(options, infos, arg, eout):
155
	root = portage.settings["ROOT"]
156
	trees = portage.db[root]
157
	vartree = trees["vartree"]
158
	
159
	settings = vartree.settings
160
	settings._init_dirs()
161
	setconfig = load_default_config(settings, trees)
162
	sets = setconfig.getSets()
163
	
164
	set = arg[1:]
165
	if not set in sets:
166
		eout.eerror("Package set not found: '%s'; skipping" % (arg,))
167
		infos["missing"].append(arg)
168
		return
169
	
170
	try:
171
		atoms = setconfig.getSetAtoms(set)
172
	except PackageSetNotFound as e:
173
		eout.eerror("Failed to process package set '%s' because " % set +
174
			"it contains the non-existent package set '%s'; skipping" % e)
175
		infos["missing"].append(arg)
176
		return
177
		
178
	for atom in atoms:
179
		quickpkg_atom(options, infos, atom, eout)
19
180
20
def quickpkg_main(options, args, eout):
181
def quickpkg_main(options, args, eout):
21
	from portage import catsplit, flatten, isvalidatom, xpak
22
	from portage.dbapi.dep_expand import dep_expand
23
	from portage.dep import use_reduce, paren_reduce
24
	from portage.util import ConfigProtect, ensure_dirs
25
	from portage.exception import InvalidAtom, InvalidData, InvalidDependString
26
	from portage.dbapi.vartree import dblink, tar_contents
27
	from portage.checksum import perform_md5
28
	import tarfile
29
	import portage
30
	root = portage.settings["ROOT"]
182
	root = portage.settings["ROOT"]
31
	trees = portage.db[root]
183
	trees = portage.db[root]
32
	vartree = trees["vartree"]
184
	vartree = trees["vartree"]
33
	vardb = vartree.dbapi
185
	vardb = vartree.dbapi
34
	bintree = trees["bintree"]
186
	bintree = trees["bintree"]
187
	
35
	try:
188
	try:
36
		ensure_dirs(bintree.pkgdir)
189
		ensure_dirs(bintree.pkgdir)
37
	except portage.exception.PortageException:
190
	except portage.exception.PortageException:
Lines 39-165 def quickpkg_main(options, args, eout): Link Here
39
	if not os.access(bintree.pkgdir, os.W_OK):
192
	if not os.access(bintree.pkgdir, os.W_OK):
40
		eout.eerror("No write access to '%s'" % bintree.pkgdir)
193
		eout.eerror("No write access to '%s'" % bintree.pkgdir)
41
		return errno.EACCES
194
		return errno.EACCES
42
	successes = []
195
	
43
	missing = []
196
	infos = {}
44
	config_files_excluded = 0
197
	infos["successes"] = []
45
	include_config = options.include_config == "y"
198
	infos["missing"] = []
46
	include_unmodified_config = options.include_unmodified_config == "y"
199
	infos["config_files_excluded"] = 0
47
	fix_metadata_keys = ["PF", "CATEGORY"]
48
	for arg in args:
200
	for arg in args:
49
		try:
201
		if arg[0] == SETPREFIX:
50
			atom = dep_expand(arg, mydb=vardb, settings=vartree.settings)
202
			quickpkg_set(options, infos, arg, eout)
51
		except ValueError as e:
203
		else:
52
			# Multiple matches thrown from cpv_expand
204
			quickpkg_atom(options, infos, arg, eout)
53
			eout.eerror("Please use a more specific atom: %s" % \
205
	
54
				" ".join(e.args[0]))
206
	if not infos["successes"]:
55
			del e
56
			missing.append(arg)
57
			continue
58
		except (InvalidAtom, InvalidData):
59
			eout.eerror("Invalid atom: %s" % (arg,))
60
			missing.append(arg)
61
			continue
62
		if atom[:1] == '=' and arg[:1] != '=':
63
			# dep_expand() allows missing '=' but it's really invalid
64
			eout.eerror("Invalid atom: %s" % (arg,))
65
			missing.append(arg)
66
			continue
67
68
		matches = vardb.match(atom)
69
		pkgs_for_arg = 0
70
		for cpv in matches:
71
			excluded_config_files = []
72
			bintree.prevent_collision(cpv)
73
			cat, pkg = catsplit(cpv)
74
			dblnk = dblink(cat, pkg, root,
75
				vartree.settings, treetype="vartree",
76
				vartree=vartree)
77
			dblnk.lockdb()
78
			try:
79
				if not dblnk.exists():
80
					# unmerged by a concurrent process
81
					continue
82
				iuse, use, restrict = vardb.aux_get(cpv,
83
					["IUSE","USE","RESTRICT"])
84
				iuse = [ x.lstrip("+-") for x in iuse.split() ]
85
				use = use.split()
86
				try:
87
					restrict = flatten(use_reduce(
88
						paren_reduce(restrict), uselist=use))
89
				except InvalidDependString as e:
90
					eout.eerror("Invalid RESTRICT metadata " + \
91
						"for '%s': %s; skipping" % (cpv, str(e)))
92
					del e
93
					continue
94
				if "bindist" in iuse and "bindist" not in use:
95
					eout.ewarn("%s: package was emerged with USE=-bindist!" % cpv)
96
					eout.ewarn("%s: it may not be legal to redistribute this." % cpv)
97
				elif "bindist" in restrict:
98
					eout.ewarn("%s: package has RESTRICT=bindist!" % cpv)
99
					eout.ewarn("%s: it may not be legal to redistribute this." % cpv)
100
				eout.ebegin("Building package for %s" % cpv)
101
				pkgs_for_arg += 1
102
				contents = dblnk.getcontents()
103
				protect = None
104
				if not include_config:
105
					confprot = ConfigProtect(root,
106
						portage.settings.get("CONFIG_PROTECT","").split(),
107
						portage.settings.get("CONFIG_PROTECT_MASK","").split())
108
					def protect(filename):
109
						if not confprot.isprotected(filename):
110
							return False
111
						if include_unmodified_config:
112
							file_data = contents[filename]
113
							if file_data[0] == "obj":
114
								orig_md5 = file_data[2].lower()
115
								cur_md5 = perform_md5(filename, calc_prelink=1)
116
								if orig_md5 == cur_md5:
117
									return False
118
						excluded_config_files.append(filename)
119
						return True
120
				existing_metadata = dict(zip(fix_metadata_keys,
121
					vardb.aux_get(cpv, fix_metadata_keys)))
122
				category, pf = portage.catsplit(cpv)
123
				required_metadata = {}
124
				required_metadata["CATEGORY"] = category
125
				required_metadata["PF"] = pf
126
				update_metadata = {}
127
				for k, v in required_metadata.items():
128
					if v != existing_metadata[k]:
129
						update_metadata[k] = v
130
				if update_metadata:
131
					vardb.aux_update(cpv, update_metadata)
132
				xpdata = xpak.xpak(dblnk.dbdir)
133
				binpkg_tmpfile = os.path.join(bintree.pkgdir,
134
					cpv + ".tbz2." + str(os.getpid()))
135
				ensure_dirs(os.path.dirname(binpkg_tmpfile))
136
				tar = tarfile.open(binpkg_tmpfile, "w:bz2")
137
				tar_contents(contents, root, tar, protect=protect)
138
				tar.close()
139
				xpak.tbz2(binpkg_tmpfile).recompose_mem(xpdata)
140
			finally:
141
				dblnk.unlockdb()
142
			bintree.inject(cpv, filename=binpkg_tmpfile)
143
			binpkg_path = bintree.getname(cpv)
144
			try:
145
				s = os.stat(binpkg_path)
146
			except OSError as e:
147
				# Sanity check, shouldn't happen normally.
148
				eout.eend(1)
149
				eout.eerror(str(e))
150
				del e
151
				eout.eerror("Failed to create package: '%s'" % binpkg_path)
152
			else:
153
				eout.eend(0)
154
				successes.append((cpv, s.st_size))
155
				config_files_excluded += len(excluded_config_files)
156
				for filename in excluded_config_files:
157
					eout.ewarn("Excluded config: '%s'" % filename)
158
		if not pkgs_for_arg:
159
			eout.eerror("Could not find anything " + \
160
				"to match '%s'; skipping" % arg)
161
			missing.append(arg)
162
	if not successes:
163
		eout.eerror("No packages found")
207
		eout.eerror("No packages found")
164
		return 1
208
		return 1
165
	print()
209
	print()
Lines 167-173 def quickpkg_main(options, args, eout): Link Here
167
	import math
211
	import math
168
	units = {10:'K', 20:'M', 30:'G', 40:'T',
212
	units = {10:'K', 20:'M', 30:'G', 40:'T',
169
		50:'P', 60:'E', 70:'Z', 80:'Y'}
213
		50:'P', 60:'E', 70:'Z', 80:'Y'}
170
	for cpv, size in successes:
214
	for cpv, size in infos["successes"]:
171
		if not size:
215
		if not size:
172
			# avoid OverflowError in math.log()
216
			# avoid OverflowError in math.log()
173
			size_str = "0"
217
			size_str = "0"
Lines 185-203 def quickpkg_main(options, args, eout): Link Here
185
			else:
229
			else:
186
				size_str = str(size)
230
				size_str = str(size)
187
		eout.einfo("%s: %s" % (cpv, size_str))
231
		eout.einfo("%s: %s" % (cpv, size_str))
188
	if config_files_excluded:
232
	if infos["config_files_excluded"]:
189
		print()
233
		print()
190
		eout.ewarn("Excluded config files: %d" % config_files_excluded)
234
		eout.ewarn("Excluded config files: %d" % infos["config_files_excluded"])
191
		eout.ewarn("See --help if you would like to include config files.")
235
		eout.ewarn("See --help if you would like to include config files.")
192
	if missing:
236
	if infos["missing"]:
193
		print()
237
		print()
194
		eout.ewarn("The following packages could not be found:")
238
		eout.ewarn("The following packages could not be found:")
195
		eout.ewarn(" ".join(missing))
239
		eout.ewarn(" ".join(infos["missing"]))
196
		return 2
240
		return 2
197
	return os.EX_OK
241
	return os.EX_OK
198
242
199
if __name__ == "__main__":
243
if __name__ == "__main__":
200
	usage = "quickpkg [options] <list of package atoms>"
244
	usage = "quickpkg [options] <list of package atoms or package sets>"
201
	from optparse import OptionParser
245
	from optparse import OptionParser
202
	parser = OptionParser(usage=usage)
246
	parser = OptionParser(usage=usage)
203
	parser.add_option("--umask",
247
	parser.add_option("--umask",
(-)a/man/quickpkg.1 (-7 / +10 lines)
Lines 2-8 Link Here
2
.SH NAME
2
.SH NAME
3
quickpkg \- creates portage packages
3
quickpkg \- creates portage packages
4
.SH SYNOPSIS
4
.SH SYNOPSIS
5
.B quickpkg <list of pkgs>
5
.B quickpkg <list of packages or package\-sets>
6
.SH DESCRIPTION
6
.SH DESCRIPTION
7
.I quickpkg
7
.I quickpkg
8
can be utilized to quickly create a package for portage by
8
can be utilized to quickly create a package for portage by
Lines 20-32 This variable is defined in \fBmake.conf\fR(5) and defaults to Link Here
20
/usr/portage/packages.
20
/usr/portage/packages.
21
.SH OPTIONS
21
.SH OPTIONS
22
.TP
22
.TP
23
.B <list of packages>
23
.B <list of packages or package\-sets>
24
Each package in the list can be of two forms.  First you can
24
Each package in the list can be of two forms.  First you can
25
give it the full path to the installed entry in the virtual
25
give it the full path to the installed entry in the virtual
26
database.  That is, /var/db/pkg/<CATEGORY>/<PKG-VERSION>/.  
26
database.  That is, /var/db/pkg/<CATEGORY>/<PKG-VERSION>/.
27
The second form is a portage depend atom.  This atom is of
27
The second form is a portage depend atom or a portage package
28
the same form that you would give \fBemerge\fR if you wanted 
28
set.  The atom or set is of the same form that you would give
29
to emerge something.  See \fBebuild\fR(5) for full definition.
29
\fBemerge\fR if you wanted to emerge something.
30
See \fBebuild\fR(5) for full definition.
30
.SH "EXAMPLES"
31
.SH "EXAMPLES"
31
.B quickpkg
32
.B quickpkg
32
/var/db/pkg/dev-python/pyogg-1.1
33
/var/db/pkg/dev-python/pyogg-1.1
Lines 39-44 planeshift Link Here
39
.br
40
.br
40
.B quickpkg
41
.B quickpkg
41
=net-www/apache-2*
42
=net-www/apache-2*
43
.br
44
.B quickpkg
45
@system
42
.SH "REPORTING BUGS"
46
.SH "REPORTING BUGS"
43
Please report bugs via http://bugs.gentoo.org/
47
Please report bugs via http://bugs.gentoo.org/
44
.SH AUTHORS
48
.SH AUTHORS
45
- 

Return to bug 311253