2002-2005
Sven Ehrke
Sven
Ehrke
ericb@gobosoft.com 7 July 2005

# copy

## Description

Copy a file or fileset to a new file or directory. Files are only copied if the source file is newer than the destination file, or when the destination file does not exist.

## Parameters

file

  Description: File to be copied

  Domain: Valid filename pointing to existing file

  Default: -

to_file

  Description: File to copy to

  Domain: Valid filename

  Default: -

to_directory

  Description: Directory to which file(s) should be copied to

  Domain: Valid directoryname pointing to existing directory

  Default: -

force

  Description: Copy file even when the possibly existing target file is not out of date.

  Domain: Boolean (true|false)

  Default: false

## RNG Specification

      <define name="copy">
        <element name="copy">
          <ref name="dir_if_unless"/>
            <choice>
              <group>
                <attribute name="file"/>
                <attribute name="to_file"/>
              </group>
              <group>
                <attribute name="file"/>
                <attribute name="to_directory"/>
              </group>
              <group>
                <attribute name="to_directory"/>
                <ref name="fileset"/>
              </group>
            </choice>
          <optional>
            <attribute name="force">
              <!-- runtime evaluation
              <choice>
                <value>true</value>
                <value>false</value>
              </choice>
              -->
            </attribute>
          </optional>
        </element>
      </define>

## Examples

Copy a single file:

      <copy file="readme.txt" to_file="readme1.txt"/>

Copy a single file to a directory:

      <copy file="readme.txt" to_directory="/tmp"/>

Copy a single file even if this would not be necessary:

By default the copy task only copies files if the target file is out of date. With the force flag set to true it is always copied.

      <copy file="readme.txt" to_directory="/tmp" force="true"/>

Copy a directory to another directory:

Let's assume we have the directories 'input' and 'output' under the current directory. If we want to copy the directory 'input' to directory 'output' do it as follows:

      <copy to_directory="output">
        <fileset include="@(input/**/*)"/>
      </copy>

Copy a directory to another directory

Let's assume we have the directories 'input', 'input/1' and 'output' under the current directory. What we want is to copy the directory '1' in directory 'input' to directory 'output'. There are a couple of ways to achieve this from which three are shown here:

Possibility 1 (probably the easiest way):

        <copy to_directory="../output" dir="input">
          <fileset include="@(1/**/*)"/>
        </copy>

Possibility 2:

      <copy to_directory="output">
        <fileset include="@(1/**/*)" filename_directory="input" dir="input"/>
      </copy>

Possibility 3:

      <copy to_directory="output">
        <fileset include="@(input/1/**/*)">
          <map type="glob" from="input/*" to="*"/>
        </fileset>
      </copy>

Description for possibility 1:

The 'copy' task is executed from within the directory 'input'. Therefore the attribute 'to_directory' has to be set to '../output'.

Description for possibility 2:

In a first attempt we might use this approach:

      <copy to_directory="output">
        <fileset include="@(input/1/**/*)"/>
      </copy>

But with this approach we end up with the directory 'output/input/1/...' which is not what we want. We need to get rid of the input in the selected filenames. To achieve this we set the attribute 'dir' of the fileset to the directory 'input' so that for the time the fileset executes it is collecting the appropriate filenames from within the directory 'input':

      <copy to_directory="output">
        <fileset include="@(1/**/*)" dir="input"/>
      </copy>

Now the fileset contains the filenames we want. Unfortunately the 'copy' task cannot work with them since it cannot copy files from '1/**' because they are in the directory 'input'. So what we need is that 'input' is prepended anyway but only to read the files while copying and not for writing. To achieve this we set the attribute 'filename_directory' to 'input'. The value of this attribute ('input' in this case) will be prepended to the source name while the target name remains as is. For example for a matched filename '1/somedir/readme.txt' the source filename will become 'input/1/somedir/readme.txt' but the target filename will still be '1/somedir/readme.txt'. So our working 'copy' task is:

      <copy to_directory="output">
        <fileset include="@(1/**/*)" filename_directory="input" dir="input"/>
      </copy>

Description for possibility 3:

If we start again go back to our first attempt from possibility 2 which produces the undesired 'input' directory:

      <copy to_directory="output">
        <fileset include="@(input/1/**/*)"/>
      </copy>

... it is more natural to come to the conclusion that all that needs to be done is removing that 'input/' from the target filenames. The element 'fileset' provides an attribute called 'mapped_filename_directory' but that is only for prepending and not for removal. But using a nested map does the trick:

      <copy to_directory="output">
        <fileset include="@(input/1/**/*)">
          <map type="glob" from="input/*" to="*"/>
        </fileset>
      </copy>

With this approach all leading 'input/' text is removed from our target filenames.