Commit d2ce9d4f authored by Greg Ward's avatar Greg Ward

Added 'ready' flag and 'ensure_ready()' method to Command: together

  they make sure that 'set_final_options()' has been called, but isn't
  called redundantly.
Changed Distribution to call 'ensure_ready()' where it used to call
  'set_final_options()', and in a few extra places as well.
Lots of comment/docstring revisions and additions in both classes.
New one-liner utility methods in Command: 'find_peer()', 'spawn()'.
parent 366fb471
...@@ -416,30 +416,25 @@ class Distribution: ...@@ -416,30 +416,25 @@ class Distribution:
Then invoke 'run()' on that command object (or an existing Then invoke 'run()' on that command object (or an existing
one).""" one)."""
# XXX currently, this is the only place where we invoke a
# command object's 'run()' method -- so it might make sense to
# put the 'set_final_options()' call here, too, instead of
# requiring every command's 'run()' to call it first.
# Already been here, done that? then return silently. # Already been here, done that? then return silently.
if self.have_run.get (command): if self.have_run.get (command):
return return
self.announce ("running " + command) self.announce ("running " + command)
cmd_obj = self.find_command_obj (command) cmd_obj = self.find_command_obj (command)
cmd_obj.ensure_ready ()
cmd_obj.run () cmd_obj.run ()
self.have_run[command] = 1 self.have_run[command] = 1
def get_command_option (self, command, option): def get_command_option (self, command, option):
"""Create a command object for 'command' if necessary, finalize """Create a command object for 'command' if necessary, ensure that
its option values by invoking its 'set_final_options()' its option values are all set to their final values, and return
method, and return the value of its 'option' option. Raise the value of its 'option' option. Raise DistutilsOptionError if
DistutilsOptionError if 'option' is not known for 'option' is not known for that 'command'."""
that 'command'."""
cmd_obj = self.find_command_obj (command) cmd_obj = self.find_command_obj (command)
cmd_obj.set_final_options () cmd_obj.ensure_ready ()
return cmd_obj.get_option (option) return cmd_obj.get_option (option)
try: try:
return getattr (cmd_obj, option) return getattr (cmd_obj, option)
...@@ -449,14 +444,14 @@ class Distribution: ...@@ -449,14 +444,14 @@ class Distribution:
def get_command_options (self, command, *options): def get_command_options (self, command, *options):
"""Create a command object for 'command' if necessary, finalize """Create a command object for 'command' if necessary, ensure that
its option values by invoking its 'set_final_options()' its option values are all set to their final values, and return
method, and return the values of all the options listed in a tuple containing the values of all the options listed in
'options' for that command. Raise DistutilsOptionError if 'options' for that command. Raise DistutilsOptionError if any
'option' is not known for that 'command'.""" invalid option is supplied in 'options'."""
cmd_obj = self.find_command_obj (command) cmd_obj = self.find_command_obj (command)
cmd_obj.set_final_options () cmd_obj.ensure_ready ()
values = [] values = []
try: try:
for opt in options: for opt in options:
...@@ -474,14 +469,14 @@ class Command: ...@@ -474,14 +469,14 @@ class Command:
"""Abstract base class for defining command classes, the "worker bees" """Abstract base class for defining command classes, the "worker bees"
of the Distutils. A useful analogy for command classes is to of the Distutils. A useful analogy for command classes is to
think of them as subroutines with local variables called think of them as subroutines with local variables called
"options". The options are "declared" in 'set_initial_options()' "options". The options are "declared" in 'set_default_options()'
and "initialized" (given their real values) in and "initialized" (given their real values) in
'set_final_options()', both of which must be defined by every 'set_final_options()', both of which must be defined by every
command class. The distinction between the two is necessary command class. The distinction between the two is necessary
because option values might come from the outside world (command because option values might come from the outside world (command
line, option file, ...), and any options dependent on other line, option file, ...), and any options dependent on other
options must be computed *after* these outside influences have options must be computed *after* these outside influences have
been processed -- hence 'set_final_values()'. The "body" of the been processed -- hence 'set_final_options()'. The "body" of the
subroutine, where it does all its work based on the values of its subroutine, where it does all its work based on the values of its
options, is the 'run()' method, which must also be implemented by options, is the 'run()' method, which must also be implemented by
every command class.""" every command class."""
...@@ -502,8 +497,21 @@ class Command: ...@@ -502,8 +497,21 @@ class Command:
self.distribution = dist self.distribution = dist
self.set_default_options () self.set_default_options ()
# 'ready' records whether or not 'set_final_options()' has been
# called. 'set_final_options()' itself should not pay attention to
# this flag: it is the business of 'ensure_ready()', which always
# calls 'set_final_options()', to respect/update it.
self.ready = 0
# end __init__ () # end __init__ ()
def ensure_ready (self):
if not self.ready:
self.set_final_options ()
self.ready = 1
# Subclasses must define: # Subclasses must define:
# set_default_options() # set_default_options()
# provide default values for all options; may be overridden # provide default values for all options; may be overridden
...@@ -664,22 +672,32 @@ class Command: ...@@ -664,22 +672,32 @@ class Command:
def set_peer_option (self, command, option, value): def set_peer_option (self, command, option, value):
"""Attempt to simulate a command-line override of some option """Attempt to simulate a command-line override of some option
value in another command. Creates a command object for value in another command. Finds the command object for
'command' if necessary, sets 'option' to 'value', and invokes 'command', sets its 'option' to 'value', and unconditionally
'set_final_options()' on that command object. This will only calls 'set_final_options()' on it: this means that some command
have the desired effect if the command object for 'command' objects may have 'set_final_options()' invoked more than once.
has not previously been created. Generally this is used to Even so, this is not entirely reliable: the other command may
ensure that the options in 'command' dependent on 'option' already be initialized to its satisfaction, in which case the
are computed, hopefully (but not necessarily) deriving from second 'set_final_options()' invocation will have little or no
'value'. It might be more accurate to call this method effect."""
'influence_dependent_peer_options()'."""
cmd_obj = self.distribution.find_command_obj (command) cmd_obj = self.distribution.find_command_obj (command)
cmd_obj.set_option (option, value) cmd_obj.set_option (option, value)
cmd_obj.set_final_options () cmd_obj.set_final_options ()
def find_peer (self, command, create=1):
"""Wrapper around Distribution's 'find_command_obj()' method:
find (create if necessary and 'create' is true) the command
object for 'command'.."""
return self.distribution.find_command_obj (command, create)
def get_peer_option (self, command, option): def get_peer_option (self, command, option):
"""Find or create the command object for 'command', and return
its 'option' option."""
cmd_obj = self.distribution.find_command_obj (command) cmd_obj = self.distribution.find_command_obj (command)
return cmd_obj.get_option (option) return cmd_obj.get_option (option)
...@@ -762,6 +780,13 @@ class Command: ...@@ -762,6 +780,13 @@ class Command:
self.distribution.dry_run) self.distribution.dry_run)
def spawn (self, cmd, search_path=1, level=1):
from distutils.spawn import spawn
spawn (cmd, search_path,
self.distribution.verbose >= level,
self.distribution.dry_run)
def make_file (self, infiles, outfile, func, args, def make_file (self, infiles, outfile, func, args,
exec_msg=None, skip_msg=None, level=1): exec_msg=None, skip_msg=None, level=1):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment