Search code examples
pythonscons

SCons is trying to validate arguments when it is not needed


Below is the simple code snippet that illustrates the problem:

def external_dependencies(url, destination):
           # this never gets called
           print 'whatever!'
           # if isinstance(url, basestring):
           #            urllib.urlretrieve(url, destination)
           # else:
           #            for a, b in map(None, url, destination):
           #                       urllib.urlretrieve(a, b)
           return None

env = Environment()
env.Command(['http://archive.apache.org/dist/xmlgraphics/batik/batik-1.6.zip',
             'http://archive.apache.org/dist/commons/collections/binaries/commons-collections-3.0.tar.gz',
             'http://archive.apache.org/dist/commons/logging/binaries/commons-logging-1.0.4.tar.gz'],
            ['./thirdparty/batik/batik-1.6.zip',
             './thirdparty/commons-collections-3.0.tar.gz',
             './thirdparty/commons-logging-1.0.4.tar.gz'],
            external_dependencies)

When I'm trying to execute this, I get the following error:

scons: *** [http:/archive.apache.org/dist/commons/collections/binaries/commons-
collections-3.0.tar.gz] Source `thirdparty/batik/batik-1.6.zip' not found, 
needed by target `http:/archive.apache.org/dist/xmlgraphics/batik/batik-1.6.zip'.

(line breaks added for readability)

Obviously the destination cannot be found because it has not been downloaded yet, and the whole purpose of this operation is to download it.

How to override this behaviour? Validating arguments here is absolutely counter-productive.

EDIT:

A tiny update: I could get it to work in this way, but it feels wrong / hackish:

def external_dependencies(dummy, url, destination):
           if isinstance(url, basestring):
                      urllib.urlretrieve(url, destination)
           else:
                      for a, b in map(None, url, destination):
                                 urllib.urlretrieve(a, b)
           return None

env = Environment()
env.AddMethod(external_dependencies, 'ExternalDependencies')

env.ExternalDependencies(
           ['http://archive.apache.org/dist/xmlgraphics/batik/batik-1.6.zip',
            'http://archive.apache.org/dist/commons/collections/binaries/commons-collections-3.0.tar.gz',
            'http://archive.apache.org/dist/commons/logging/binaries/commons-logging-1.0.4.tar.gz'],
           ['./thirdparty/batik/batik-1.6.zip',
            './thirdparty/commons-collections-3.0.tar.gz',
            './thirdparty/commons-logging-1.0.4.tar.gz'])

Note the dummy argument in the external_dependencies - for some reason SCons will call this function passing the number of arguments as the first argument. So, it looks like the intended use was different.


Solution

  • The definition of the Command() builder is as follows:

    Command(target, source, action, [key=val, ...])
    

    So it seems like you ordered your parameters incorrectly. Im assuming the URL list is the source and the file list is the target, right?

    If this is the case, you could either reorder the args, or just do the following:

    Command(source=['http://archive.apache.org/dist/xmlgraphics/batik/batik-1.6.zip',
                    'http://archive.apache.org/dist/commons/collections/binaries/commons-collections-3.0.tar.gz',
                    'http://archive.apache.org/dist/commons/logging/binaries/commons-logging-1.0.4.tar.gz'],
            target=['./thirdparty/batik/batik-1.6.zip',
                    './thirdparty/commons-collections-3.0.tar.gz',
                    './thirdparty/commons-logging-1.0.4.tar.gz'],
            action=external_dependencies)
    

    Im still not convinced this will work though, since SCons will probably assume that the url list is actually a list of file names and it may try to find them anyways, you'll have to test it.

    The second option you tried isnt actually a builder, but just simply a function call, so the dependency checking probably wont be as you expect. As for the dummy argument you mention, Im pretty sure that will be the env that the function was called on, not the number of args.