<sect1 id='package-ebuild-eapi-2'>
<title>EAPI 2_pre0</title>
+ <sect2 id='package-ebuild-eapi-2-helpers'>
+ <title>Helpers</title>
+ <sect3 id='package-ebuild-eapi-2-helpers-doman'>
+ <title>doman</title>
+ <para>
+ Language codes in file names are now used for path translation.
+ </para>
+ <table><title>Man Page Path Translation</title>
+ <tgroup cols='2' align='left' >
+ <colspec colname='source'/>
+ <colspec colname='destination'/>
+ <thead>
+ <row>
+ <entry>Source</entry>
+ <entry>Destination</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>foo.1</entry>
+ <entry>/usr/share/man/man1/foo.1</entry>
+ </row>
+ <row>
+ <entry>foo.lang.1</entry>
+ <entry>/usr/share/man/lang/man1/foo.1</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect3>
+ </sect2>
<sect2 id='package-ebuild-eapi-2-use-deps'>
<title>USE Dependencies</title>
+ <sect3 id='package-ebuild-eapi-2-use-deps-unconditional'>
+ <title>Unconditional USE Dependencies</title>
+ <table><title>Syntax Examples</title>
+ <tgroup cols='2' align='left' >
+ <colspec colname='example'/>
+ <colspec colname='meaning'/>
+ <thead>
+ <row>
+ <entry>Example</entry>
+ <entry>Meaning</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>foo[bar]</entry>
+ <entry>foo must have bar enabled</entry>
+ </row>
+ <row>
+ <entry>foo[bar,baz]</entry>
+ <entry>foo must have both bar and baz enabled</entry>
+ </row>
+ <row>
+ <entry>foo[-bar,baz]</entry>
+ <entry>foo must have bar disabled and baz enabled</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect3>
<sect3 id='package-ebuild-eapi-2-use-deps-conditional'>
<title>Conditional USE Dependencies</title>
<table><title>Syntax Examples</title>
<tbody>
<row>
<entry>foo[bar?]</entry>
- <entry>foo bar? ( foo[bar] )</entry>
+ <entry>bar? ( foo[bar] ) !bar? ( foo )</entry>
</row>
<row>
<entry>foo[-bar?]</entry>
- <entry>foo !bar? ( foo[-bar] )</entry>
+ <entry>bar? ( foo ) !bar? ( foo[-bar] )</entry>
</row>
<row>
<entry>foo[bar=]</entry>
- <entry>foo bar? ( foo[bar] ) !bar? ( foo[-bar] )</entry>
+ <entry>bar? ( foo[bar] ) !bar? ( foo[-bar] )</entry>
</row>
<row>
<entry>foo[bar!=]</entry>
- <entry>foo bar? ( foo[-bar] ) !bar? ( foo[bar] )</entry>
+ <entry>bar? ( foo[-bar] ) !bar? ( foo[bar] )</entry>
</row>
</tbody>
</tgroup>
__slots__ = ("args_set", "background", "find_blockers",
"ldpath_mtimes", "logger", "opts", "pkg", "pkg_count",
"prefetcher", "settings", "world_atom") + \
- ("_build_dir", "_buildpkg", "_ebuild_path", "_tree")
+ ("_build_dir", "_buildpkg", "_ebuild_path", "_issyspkg", "_tree")
def _start(self):
logger.log(msg, short_msg=short_msg)
#buildsyspkg: Check if we need to _force_ binary package creation
- issyspkg = "buildsyspkg" in features and \
+ self._issyspkg = "buildsyspkg" in features and \
system_set.findAtomForPackage(pkg) and \
not opts.buildpkg
- if opts.buildpkg or issyspkg:
+ if opts.buildpkg or self._issyspkg:
self._buildpkg = True
- if issyspkg:
- portage.writemsg_stdout(">>> This is a system package, " + \
- "let's pack a rescue tarball.\n", noiselevel=-1)
msg = " === (%s of %s) Compiling/Packaging (%s::%s)" % \
(pkg_count.curval, pkg_count.maxval, pkg.cpv, ebuild_path)
self.wait()
return
+ if self._issyspkg:
+ msg = ">>> This is a system package, " + \
+ "let's pack a rescue tarball.\n"
+
+ log_path = self.settings.get("PORTAGE_LOG_FILE")
+ if log_path is not None:
+ log_file = open(log_path, 'a')
+ try:
+ log_file.write(msg)
+ finally:
+ log_file.close()
+
+ if not self.background:
+ portage.writemsg_stdout(msg, noiselevel=-1)
+
packager = EbuildBinpkg(background=self.background, pkg=self.pkg,
scheduler=self.scheduler, settings=self.settings)
"FILE" : os.path.basename(pkg_path)
}
- fetch_env = dict((k, settings[k]) for k in settings)
+ fetch_env = dict(settings.iteritems())
fetch_args = [portage.util.varexpand(x, mydict=fcmd_vars) \
for x in shlex.split(fcmd)]
if task.poll() is not None:
state_changed = True
- while task_queue and (len(running_tasks) < max_jobs):
+ while task_queue and \
+ (max_jobs is True or len(running_tasks) < max_jobs):
task = task_queue.popleft()
cancelled = getattr(task, "cancelled", None)
if not cancelled:
max_jobs = self._max_jobs
max_load = self._max_load
- if self._running_job_count() >= self._max_jobs:
+ if self._max_jobs is not True and \
+ self._running_job_count() >= self._max_jobs:
return False
- if max_load is not None and max_jobs > 1 and \
+ if max_load is not None and \
+ (max_jobs is True or max_jobs > 1) and \
self._running_job_count() > 1:
try:
avg1, avg5, avg15 = os.getloadavg()
self._max_load = myopts.get("--load-average")
+ # The load average takes some time to respond when new
+ # jobs are added, so we need to limit the rate of adding
+ # new jobs.
+ self._job_delay_factor = 0.5
+ self._previous_job_start_time = None
+
self._set_digraph(digraph)
# This is used to memoize the _choose_pkg() result when
@rtype: bool
@returns: True if background mode is enabled, False otherwise.
"""
- background = (self._max_jobs > 1 or "--quiet" in self.myopts) and \
+ background = (self._max_jobs is True or \
+ self._max_jobs > 1 or "--quiet" in self.myopts) and \
not bool(self._opts_no_background.intersection(self.myopts))
self._status_display.quiet = \
return background
def _set_digraph(self, digraph):
- if self._max_jobs < 2:
+ if self._max_jobs is not True and \
+ self._max_jobs < 2:
# save some memory
self._digraph = None
return
if self._choose_pkg_return_early:
return None
- if self._max_jobs < 2 or self._jobs == 0:
+ if self._digraph is None:
+ if self._jobs or self._task_queues.merge:
+ self._choose_pkg_return_early = True
+ return None
return self._pkg_queue.pop(0)
self._prune_digraph()
self._poll_loop()
while self._jobs or merge_queue:
+ if merge_queue.schedule() and \
+ not self._poll_event_handlers:
+ continue
self._poll_loop()
def _schedule_tasks(self):
self._status_display.display()
return remaining
+ def _job_delay(self):
+ """
+ @rtype: bool
+ @returns: True if job scheduling should be delayed, False otherwise.
+ """
+
+ if self._jobs and self._max_load is not None:
+
+ current_time = time.time()
+
+ if current_time - self._previous_job_start_time < \
+ self._job_delay_factor * self._jobs:
+ return True
+
+ return False
+
def _schedule_tasks_imp(self):
"""
@rtype: bool
return (False, state_change)
if self._choose_pkg_return_early or \
- not self._can_add_job():
+ not self._can_add_job() or \
+ self._job_delay():
return (True, state_change)
pkg = self._choose_pkg()
elif pkg.built:
self._jobs += 1
+ self._previous_job_start_time = time.time()
self._status_display.running = self._jobs
task.addExitListener(self._extract_exit)
self._task_queues.jobs.add(task)
else:
self._jobs += 1
+ self._previous_job_start_time = time.time()
self._status_display.running = self._jobs
task.addExitListener(self._build_exit)
self._task_queues.jobs.add(task)
sys.stderr.write("!!! '%s' or '%s'\n\n" % (action1, action2))
sys.exit(1)
+def insert_optional_args(args):
+ """
+ Parse optional arguments and insert a value if one has
+ not been provided. This is done before feeding the args
+ to the optparse parser since that parser does not support
+ this feature natively.
+ """
+
+ new_args = []
+ jobs_opts = ("-j", "--jobs")
+ arg_stack = args[:]
+ arg_stack.reverse()
+ while arg_stack:
+ arg = arg_stack.pop()
+
+ short_job_opt = bool("j" in arg and arg[:1] == "-" and arg[:2] != "--")
+ if not (short_job_opt or arg in jobs_opts):
+ new_args.append(arg)
+ continue
+
+ # Insert an empty placeholder in order to
+ # satisfy the requirements of optparse.
+
+ new_args.append("--jobs")
+ job_count = None
+ saved_opts = None
+ if short_job_opt and len(arg) > 2:
+ if arg[:2] == "-j":
+ try:
+ job_count = int(arg[2:])
+ except ValueError:
+ saved_opts = arg[2:]
+ else:
+ job_count = "True"
+ saved_opts = arg[1:].replace("j", "")
+
+ if job_count is None and arg_stack:
+ try:
+ job_count = int(arg_stack[-1])
+ except ValueError:
+ pass
+ else:
+ # Discard the job count from the stack
+ # since we're consuming it here.
+ arg_stack.pop()
+
+ if job_count is None:
+ # unlimited number of jobs
+ new_args.append("True")
+ else:
+ new_args.append(str(job_count))
+
+ if saved_opts is not None:
+ new_args.append("-" + saved_opts)
+
+ return new_args
+
def parse_opts(tmpcmdline, silent=False):
myaction=None
myopts = {}
parser.add_option(myopt,
dest=myopt.lstrip("--").replace("-", "_"), **kwargs)
+ tmpcmdline = insert_optional_args(tmpcmdline)
+
myoptions, myargs = parser.parse_args(args=tmpcmdline)
if myoptions.jobs:
- try:
- jobs = int(myoptions.jobs)
- except ValueError:
- jobs = 0
+ jobs = None
+ if myoptions.jobs == "True":
+ jobs = True
+ else:
+ try:
+ jobs = int(myoptions.jobs)
+ except ValueError:
+ jobs = -1
- if jobs < 1:
+ if jobs is not True and \
+ jobs < 1:
jobs = None
if not silent:
writemsg("!!! Invalid --jobs parameter: '%s'\n" % \