Fix bug in storage test where it wasn't properly checking for invalid results.

/**
 Duration 10s
 Scene.db:
    *Ent 1: Anything.

 Tests:
   -system.storageBeginTransaction
   -system.storageCommit
   -system.storageErase
   -system.storageRead
   -system.storageWrite
   -system.storageCount
   -serialization
   -timeout
   -killEntity
 */

system.require('emUtil/util.em');
mTest = new UnitTest('storageTest.em');
var toSerialize = {'x':1,'y':2};

//incremented once for each test that we run.  in wrapUp, we compare
//to NUM_TESTS to ensure that we actually got to all the tests.
var numCallbacks = 0;
var NUM_TESTS    = 8;

//used by testWrite and write field and erase written
var fieldKey = 'mFieldKey';

//if we don't finish all these tests in 10 seconds, then we'll consider this a failure
system.timeout(10, wrapUp);

//read unknown field
system.storageRead('noExist', function (success, val)
                   {
                       ++numCallbacks;
                       if (success)
                           mTest.fail('Got successful read for imaginary data');
                       if (typeof(val) !== 'undefined')
                           mTest.fail('Got non-undefined read for imaginary data');
                       testWrite();
                   });

//write toSerialize
function testWrite()
{
    var serialized = system.serialize(toSerialize);
    system.storageWrite(fieldKey,serialized,
                        function(success)
                        {
                            ++numCallbacks;
                            if (typeof(success) !== 'boolean')
                                mTest.fail('Did not receive boolean argument success in testWrite');
                            if (!success)
                                mTest.fail('Failed to write in testWrite');

                            testReadWrittenField();
                        }
                       );
}

//checks if the field written in testWrite actually was written correctly.
function testReadWrittenField()
{
    system.storageRead(fieldKey,
                       function(success,val)
                       {
                           ++numCallbacks;
                           if (typeof(success) !== 'boolean')
                               mTest.fail('Did not receive boolean argument success in testReadWrittenField');
                           if (!success)
                               mTest.fail('Failed to read in testReadWrittenField');
                           else
                           {
                               if (typeof(val) !== 'object')
                               {
                                   mTest.fail('Error in testReadWrittenField.  Should have received an object back from storage system.');
                               }
                               else if (!(fieldKey in val))
                               {
                                   mTest.fail('Error in testReadWrittenField.  Returned value should have a field named by fieldKey');
                               }
                               else
                               {
                                   compareTwoBasicObjects(system.deserialize(val[fieldKey]),toSerialize,'testReadWrittenField');
                               }

                           }
                           testEraseUnknown();
                       }
                      );
}

//tries to erase a field that doesn't exist
function testEraseUnknown()
{
    system.storageBeginTransaction();
    system.storageErase('noExist');
    system.storageCommit( function (success)
                   {
                       ++numCallbacks;
                       if (!success)
                           mTest.fail('Erasing non-existant data failed: ' + success);

                       testEraseWrittenField();
                   });
}

//tries to erase field that was written with key fieldKey in testWrite
function testEraseWrittenField()
{
    system.storageBeginTransaction();
    system.storageErase(fieldKey);

    system.storageCommit( function (success)
                   {
                       ++numCallbacks;
                       if (!success)
                           mTest.fail('Error in testEraseWrittenField: did not erase data that was written.');

                       testReadErased();
                   });
}

//tries to read the field that was erased in testEraseWrittenField
function testReadErased()
{
    system.storageRead(fieldKey,
                       function(success,val)
                       {
                           ++numCallbacks;
                           if (typeof(success) !== 'boolean')
                               mTest.fail('Did not receive boolean argument success in testReadErased');
                           if (success)
                               mTest.fail('Error in testReadErased: could read a field that had been erased.');

                           if (typeof(val) !== 'undefined')
                               mTest.fail('Error in testReadErased: should have received an undefined value');

                           testBasicTransaction();
                       }
                      );
}

//Inside of a transaction, reads an unknown field and writes a field.
//If transactions, are working correctly
function testBasicTransaction()
{
    system.storageBeginTransaction();
    system.storageRead('noExist');
    system.storageWrite(fieldKey,system.serialize(toSerialize));
    system.storageCommit(function(success,readVal)
                         {
                             ++numCallbacks;

                             if (success)
                                 mTest.fail('Error in testBasicTransaction.  Read should have failed.');

                             if (typeof(readVal) !== 'undefined')
                                 mTest.fail('Error in testBasicTransaction.  Read should have failed, which implies we should not have gotten an object back');

                             //try reading the key that shouldn't have been written
                             system.storageRead(fieldKey,
                                                function (success,val)
                                                {
                                                    if (success)
                                                        mTest.fail('Error in testBasicTransaction.  Transaction should have failed, and value should not have been written.');

                                                    if (typeof(val) !== 'undefined')
                                                        mTest.fail('Error in testBasicTransaction.  Transaction should have failed, and should not get data back in val.');

                                                    testTwoOperationTransaction();
                                                }
                                               );
                         }
    );
}

function testTwoOperationTransaction()
{
    //do two writes first
    system.storageBeginTransaction();
    var fieldKey2 = fieldKey + '2';
    system.storageWrite(fieldKey,system.serialize(toSerialize));
    system.storageWrite(fieldKey2,system.serialize(toSerialize));

    system.storageCommit(function(success)
                        {
                           ++numCallbacks;

                            if (!success)
                                mTest.fail('Error in testTwoOperationTransactions when writing initial values.  Should have been written.');

                            system.storageBeginTransaction();
                            system.storageRead(fieldKey);
                            system.storageRead(fieldKey2);
                            system.storageCommit(
                                function (success, val)
                                {
                                    if (!success)
                                        mTest.fail('Error in testTwoOperationTransactions when reading written values.  Got no success');

                                    if (typeof(val) !== 'object')
                                        mTest.fail('Error in testTwoOperationTransactions: did not get an object back.');
                                    else
                                    {
                                        if (!(fieldKey in val) ||
                                            !(fieldKey2 in val) ||
                                            val[fieldKey] === undefined ||
                                            val[fieldKey2] === undefined)
                                            mTest.fail('Error in testTwoOperaionTransactions: returned object does not have correct keys');
                                        else
                                        {
                                            compareTwoBasicObjects(system.deserialize(val[fieldKey]), toSerialize,'testTwoOperationTransaction');
                                            compareTwoBasicObjects(system.deserialize(val[fieldKey2]), toSerialize,'testTwoOerationTransaction 2');
                                        }
                                    }
                                    testCount();
                                }
                            );

                        });

}

//write toSerialize
function testCount()
{
    // Write some new data, within a range, we can
    // count. Values don't matter. Clear out all other data first to
    // make sure we won't conflict with other tests.
    system.storageRangeErase(
        'a', 'z',
        function(success) {
            if (!success)
                mTest.fail('Failed to clear data testCount');

            system.storageBeginTransaction();
            system.storageWrite('ddd',system.serialize(toSerialize));
            system.storageWrite('xxx',system.serialize(toSerialize));
            system.storageCommit(
                function(success) {
                    if (!success)
                        mTest.fail('Failed to write data for testCount');

                    // Now perform the count
                    system.storageCount(
                        'a', 'z',
                        function(success, count) {
                            if (!success)
                                mTest.fail('Failed to execute count request');
                            if (count !== 2)
                                mTest.fail('Incorrect number of objects returned: ' + count + ' instead of 2');

                            system.storageRangeErase(
                                'a', 'z',
                                function(success) {
                                    if (!success)
                                        mTest.fail('Failed to clear data after testCount');
                                    wrapUp();
                                }
                            );
                        }
                    );
                }
            );
        }
    );
}

//prints success if haven't gotten any failures. Checks that we hit all the callbacks, kills entity.
function wrapUp()
{
    if (numCallbacks != NUM_TESTS)
        mTest.fail('Error in wrapup.  Did not execute to completion.');

    if (! mTest.hasFailed)
        mTest.success('Successfully completed all storageTests.');

    system.killEntity();
}

//returns true if the objects match up (have same fields and same data in fields).
function compareTwoBasicObjects(obj1,obj2,where)
{
    return (compareFieldsInOneToTwo(obj1, obj2, where) &&
            compareFieldsInOneToTwo(obj2, obj1, where));
}

function compareFieldsInOneToTwo(obj1, obj2, where)
{
    if ((typeof(obj1) !== 'object') || (typeof(obj2) !== 'object'))
    {
        mTest.fail('in ' + where + ' .  Did not get two objects to compare');
        return false;
    }

    for (var s in obj1)
    {
        if (! (s in obj2))
        {
            mTest.fail('error in ' + where + ' field mismatch.');
            system.__debugPrint('\n\nField name ' + s.toString() + ' is missing.');
            system.__debugPrint('\n\n');
            system.prettyprint(obj2);
            system.__debugPrint('\n\n');
            system.prettyprint(obj1);
            system.__debugPrint('\n\n');
            return false;
        }
        else
        {
            if (obj1[s] !== obj2[s])
            {
                mTest.fail('error in ' + where + ' data mismatch.');
                return false;
            }
        }
    }

    return true;
}

/**
 Duration 10s
 Scene.db:
    *Ent 1: Anything.

 Tests:
   -system.storageBeginTransaction
   -system.storageCommit
   -system.storageErase
   -system.storageRead
   -system.storageWrite
   -system.storageCount
   -serialization
   -timeout
   -killEntity
 */

system.require('emUtil/util.em');
mTest = new UnitTest('storageTest.em');
var toSerialize = {'x':1,'y':2};

//incremented once for each test that we run.  in wrapUp, we compare
//to NUM_TESTS to ensure that we actually got to all the tests.
var numCallbacks = 0;
var NUM_TESTS    = 8;

//used by testWrite and write field and erase written
var fieldKey = 'mFieldKey';

//if we don't finish all these tests in 10 seconds, then we'll consider this a failure
system.timeout(10, wrapUp);

//read unknown field
system.storageRead('noExist', function (success, val)
                   {
                       ++numCallbacks;
                       if (success)
                           mTest.fail('Got successful read for imaginary data');
                       if (typeof(val) !== 'undefined')
                           mTest.fail('Got non-undefined read for imaginary data');
                       testWrite();
                   });

//write toSerialize
function testWrite()
{
    var serialized = system.serialize(toSerialize);
    system.storageWrite(fieldKey,serialized,
                        function(success)
                        {
                            ++numCallbacks;
                            if (typeof(success) !== 'boolean')
                                mTest.fail('Did not receive boolean argument success in testWrite');
                            if (!success)
                                mTest.fail('Failed to write in testWrite');

                            testReadWrittenField();
                        }
                       );
}

//checks if the field written in testWrite actually was written correctly.
function testReadWrittenField()
{
    system.storageRead(fieldKey,
                       function(success,val)
                       {
                           ++numCallbacks;
                           if (typeof(success) !== 'boolean')
                               mTest.fail('Did not receive boolean argument success in testReadWrittenField');
                           if (!success)
                               mTest.fail('Failed to read in testReadWrittenField');
                           else
                           {
                               if (typeof(val) !== 'object')
                               {
                                   mTest.fail('Error in testReadWrittenField.  Should have received an object back from storage system.');
                               }
                               else if (!(fieldKey in val))
                               {
                                   mTest.fail('Error in testReadWrittenField.  Returned value should have a field named by fieldKey');
                               }
                               else
                               {
                                   compareTwoBasicObjects(system.deserialize(val[fieldKey]),toSerialize,'testReadWrittenField');
                               }

                           }
                           testEraseUnknown();
                       }
                      );
}

//tries to erase a field that doesn't exist
function testEraseUnknown()
{
    system.storageBeginTransaction();
    system.storageErase('noExist');
    system.storageCommit( function (success)
                   {
                       ++numCallbacks;
                       if (!success)
                           mTest.fail('Erasing non-existant data failed: ' + success);

                       testEraseWrittenField();
                   });
}

//tries to erase field that was written with key fieldKey in testWrite
function testEraseWrittenField()
{
    system.storageBeginTransaction();
    system.storageErase(fieldKey);

    system.storageCommit( function (success)
                   {
                       ++numCallbacks;
                       if (!success)
                           mTest.fail('Error in testEraseWrittenField: did not erase data that was written.');

                       testReadErased();
                   });
}

//tries to read the field that was erased in testEraseWrittenField
function testReadErased()
{
    system.storageRead(fieldKey,
                       function(success,val)
                       {
                           ++numCallbacks;
                           if (typeof(success) !== 'boolean')
                               mTest.fail('Did not receive boolean argument success in testReadErased');
                           if (success)
                               mTest.fail('Error in testReadErased: could read a field that had been erased.');

                           if (typeof(val) !== 'undefined')
                               mTest.fail('Error in testReadErased: should have received an undefined value');

                           testBasicTransaction();
                       }
                      );
}

//Inside of a transaction, reads an unknown field and writes a field.
//If transactions, are working correctly
function testBasicTransaction()
{
    system.storageBeginTransaction();
    system.storageRead('noExist');
    system.storageWrite(fieldKey,system.serialize(toSerialize));
    system.storageCommit(function(success,readVal)
                         {
                             ++numCallbacks;

                             if (success)
                                 mTest.fail('Error in testBasicTransaction.  Read should have failed.');

                             if (typeof(readVal) !== 'undefined')
                                 mTest.fail('Error in testBasicTransaction.  Read should have failed, which implies we should not have gotten an object back');

                             //try reading the key that shouldn't have been written
                             system.storageRead(fieldKey,
                                                function (success,val)
                                                {
                                                    if (success)
                                                        mTest.fail('Error in testBasicTransaction.  Transaction should have failed, and value should not have been written.');

                                                    if (typeof(val) !== 'undefined')
                                                        mTest.fail('Error in testBasicTransaction.  Transaction should have failed, and should not get data back in val.');

                                                    testTwoOperationTransaction();
                                                }
                                               );
                         }
    );
}

function testTwoOperationTransaction()
{
    //do two writes first
    system.storageBeginTransaction();
    var fieldKey2 = fieldKey + '2';
    system.storageWrite(fieldKey,system.serialize(toSerialize));
    system.storageWrite(fieldKey2,system.serialize(toSerialize));

    system.storageCommit(function(success)
                        {
                           ++numCallbacks;

                            if (!success)
                                mTest.fail('Error in testTwoOperationTransactions when writing initial values.  Should have been written.');

                            system.storageBeginTransaction();
                            system.storageRead(fieldKey);
                            system.storageRead(fieldKey2);
                            system.storageCommit(
                                function (success, val)
                                {
                                    if (!success)
                                        mTest.fail('Error in testTwoOperationTransactions when reading written values.  Got no success');

                                    if (typeof(val) !== 'object')
                                        mTest.fail('Error in testTwoOperationTransactions: did not get an object back.');
                                    else
                                    {
                                        if ((!(fieldKey in val)) && (!(fieldKey2 in val)))
                                            mTest.fail('Error in testTwoOperaionTransactions: returned object does not have correct keys');
                                        else
                                        {
                                            compareTwoBasicObjects(system.deserialize(val[fieldKey]), toSerialize,'testTwoOperationTransaction');
                                            compareTwoBasicObjects(system.deserialize(val[fieldKey2]), toSerialize,'testTwoOerationTransaction 2');
                                        }
                                    }
                                    testCount();
                                }
                            );

                        });

}

//write toSerialize
function testCount()
{
    // Write some new data, within a range, we can
    // count. Values don't matter. Clear out all other data first to
    // make sure we won't conflict with other tests.
    system.storageRangeErase(
        'a', 'z',
        function(success) {
            if (!success)
                mTest.fail('Failed to clear data testCount');

            system.storageBeginTransaction();
            system.storageWrite('ddd',system.serialize(toSerialize));
            system.storageWrite('xxx',system.serialize(toSerialize));
            system.storageCommit(
                function(success) {
                    if (!success)
                        mTest.fail('Failed to write data for testCount');

                    // Now perform the count
                    system.storageCount(
                        'a', 'z',
                        function(success, count) {
                            if (!success)
                                mTest.fail('Failed to execute count request');
                            if (count !== 2)
                                mTest.fail('Incorrect number of objects returned: ' + count + ' instead of 2');

                            system.storageRangeErase(
                                'a', 'z',
                                function(success) {
                                    if (!success)
                                        mTest.fail('Failed to clear data after testCount');
                                    wrapUp();
                                }
                            );
                        }
                    );
                }
            );
        }
    );
}

//prints success if haven't gotten any failures. Checks that we hit all the callbacks, kills entity.
function wrapUp()
{
    if (numCallbacks != NUM_TESTS)
        mTest.fail('Error in wrapup.  Did not execute to completion.');

    if (! mTest.hasFailed)
        mTest.success('Successfully completed all storageTests.');

    system.killEntity();
}

//returns true if the objects match up (have same fields and same data in fields).
function compareTwoBasicObjects(obj1,obj2,where)
{
    return (compareFieldsInOneToTwo(obj1, obj2, where) &&
            compareFieldsInOneToTwo(obj2, obj1, where));
}

function compareFieldsInOneToTwo(obj1, obj2, where)
{
    if ((typeof(obj1) !== 'object') || (typeof(obj2) !== 'object'))
    {
        mTest.fail('in ' + where + ' .  Did not get two objects to compare');
        return false;
    }

    for (var s in obj1)
    {
        if (! (s in obj2))
        {
            mTest.fail('error in ' + where + ' field mismatch.');
            system.__debugPrint('\n\nField name ' + s.toString() + ' is missing.');
            system.__debugPrint('\n\n');
            system.prettyprint(obj2);
            system.__debugPrint('\n\n');
            system.prettyprint(obj1);
            system.__debugPrint('\n\n');
            return false;
        }
        else
        {
            if (obj1[s] !== obj2[s])
            {
                mTest.fail('error in ' + where + ' data mismatch.');
                return false;
            }
        }
    }

    return true;
}


Fixes js error on new game submission

Fixes js error on new game submission

class QuizBuzz.GameNewController extends Ember.ObjectController

  init: ()->
    @_super()
    @model = @store.createRecord('game')

  actions:
    createGame: ()->
      if @name? && !isNaN(@seconds_remaining)
        @model.seconds_remaining = parseInt(@model.seconds_remaining)
        @model.save().then ()=>
          @model = @store.createRecord('game')

      false

class QuizBuzz.GameNewController extends Ember.ObjectController

  init: ()->
    @_super()
    @model = @store.createRecord('game')

  actions:
    createGame: ()->
      if @name? && !isNaN(@seconds_remaining)
        @model.seconds_remaining = parseInt(@model.seconds_remaining)
        @model.save().then ()->
          @model = @store.createRecord('game')

      false


Adding entrypoint script to core template

@(TEMPLATE(
    'snippet/add_generated_comment.Dockerfile.em',
    user_name=user_name,
    tag_name=tag_name,
    source_template_name=template_name,
    now_str=now_str,
))@
@(TEMPLATE(
    'snippet/from_base_image.Dockerfile.em',
    template_packages=template_packages,
    os_name=os_name,
    os_code_name=os_code_name,
    arch=arch,
    base_image=base_image,
))@
MAINTAINER Dirk Thomas dthomas+buildfarm@@osrfoundation.org

# setup environment
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
@[if 'packages' in locals()]@
@[if packages]@

# install packages
RUN apt-get update && apt-get install -y \
    @(' \\\n    '.join(packages))@  \
    && rm -rf /var/lib/apt/lists/*

@[end if]@
@[end if]@

# setup keys
RUN apt-key adv --keyserver ha.pool.sks-keyservers.net --recv-keys 421C365BD9FF1F717815A3895523BAEEB01FA116

# setup sources.list
RUN echo "deb http://packages.ros.org/ros/@os_name @os_code_name main" > /etc/apt/sources.list.d/ros-latest.list

# install bootstrap tools
ENV ROS_DISTRO @rosdistro_name
RUN apt-get update && apt-get install --no-install-recommends -y \
    python-rosdep \
    python-rosinstall \
    python-vcstools \
    && rm -rf /var/lib/apt/lists/*

# bootstrap rosdep
RUN rosdep init \
    && rosdep update

# install ros packages
RUN apt-get update && apt-get install -y \
    @(' \\\n    '.join(ros_packages))@  \
    && rm -rf /var/lib/apt/lists/*

# setup entrypoint
COPY ./ros_entrypoint.sh /
RUN chmod +x ./ros_entrypoint.sh

@[if 'entrypoint_name' in locals()]@
@[if entrypoint_name]@
@{
entrypoint_file = entrypoint_name.split('/')[-1]
}@
# install packages
ENTRYPOINT ["/@entrypoint_file"]
@[end if]@
@[end if]@

@{
cmds = [
'bash',
]
}@
CMD ["@(' && '.join(cmds))"]

@(TEMPLATE(
    'snippet/add_generated_comment.Dockerfile.em',
    user_name=user_name,
    tag_name=tag_name,
    source_template_name=template_name,
    now_str=now_str,
))@
@(TEMPLATE(
    'snippet/from_base_image.Dockerfile.em',
    template_packages=template_packages,
    os_name=os_name,
    os_code_name=os_code_name,
    arch=arch,
    base_image=base_image,
))@
MAINTAINER Dirk Thomas dthomas+buildfarm@@osrfoundation.org

# setup environment
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
@[if 'packages' in locals()]@
@[if packages]@

# install packages
RUN apt-get update && apt-get install -y \
    @(' \\\n    '.join(packages))@  \
    && rm -rf /var/lib/apt/lists/*

@[end if]@
@[end if]@

# setup keys
RUN apt-key adv --keyserver ha.pool.sks-keyservers.net --recv-keys 421C365BD9FF1F717815A3895523BAEEB01FA116

# setup sources.list
RUN echo "deb http://packages.ros.org/ros/@os_name @os_code_name main" > /etc/apt/sources.list.d/ros-latest.list

# install bootstrap tools
ENV ROS_DISTRO @rosdistro_name
RUN apt-get update && apt-get install --no-install-recommends -y \
    python-rosdep \
    python-rosinstall \
    python-vcstools \
    && rm -rf /var/lib/apt/lists/*

# bootstrap rosdep
RUN rosdep init \
    && rosdep update

# install ros packages
RUN apt-get update && apt-get install -y \
    @(' \\\n    '.join(ros_packages))@  \
    && rm -rf /var/lib/apt/lists/*

# setup entrypoint
COPY ./ros_entrypoint.sh /
RUN chmod +x ./ros_entrypoint.sh

ENTRYPOINT ["/ros_entrypoint.sh"]
@{
cmds = [
'bash',
]
}@
CMD ["@(' && '.join(cmds))"]


Sort CI job plot groups in Jenkins job XML (#773)

The order of these key/value pairs gets lost when the YAML is
deserialized. Enforce alphabetical order based on the group name so that
the order is consistent across runs.

@{
import html
}@
    <hudson.plugins.plot.PlotPublisher plugin="plot@@2.1.3">
      <plots>
@[for plot_group, plot_list in sorted(plots.items())]@
@[for plot in plot_list]@
        <hudson.plugins.plot.Plot>
          <description>@(html.escape(plot.description))</description>
          <title>@(plot.title)</title>
          <yaxis>@(plot.y_axis_label)</yaxis>
          <series>
@[for series in plot.data_series]@
            <hudson.plugins.plot.CSVSeries>
              <file>@(series.data_file)</file>
              <label />
              <fileType>@(series.data_type)</fileType>
              <colExclusionSet>
                <int>@(series.selection_value)</int>
              </colExclusionSet>
              <inclusionFlag>@(series.selection_flag)</inclusionFlag>
              <exclusionValues>@(series.selection_value)</exclusionValues>
              <exclusionValuesList class="java.util.Arrays$ArrayList">
                <a class="string-array">
                  <string>@(series.selection_value)</string>
                </a>
              </exclusionValuesList>
              <url>@(series.url)</url>
              <displayTableFlag>true</displayTableFlag>
            </hudson.plugins.plot.CSVSeries>
@[end for]@
          </series>
          <group>@(plot_group)</group>
          <numBuilds>@(plot.num_builds or '')</numBuilds>
          <csvFileName>@(plot.master_csv_name)</csvFileName>
          <csvLastModification>0</csvLastModification>
          <style>@(plot.style)</style>
          <useDescr>false</useDescr>
          <keepRecords>false</keepRecords>
          <exclZero>@('true' if plot.y_axis_exclude_zero else 'false')</exclZero>
          <logarithmic>false</logarithmic>
@[if plot.y_axis_minimum is not None]@
          <yaxisMinimum>@(plot.y_axis_minimum)</yaxisMinimum>
@[else]@
          <yaxisMinimum />
@[end if]@
@[if plot.y_axis_maximum is not None]@
          <yaxisMaximum>@(plot.y_axis_maximum)</yaxisMaximum>
@[else]@
          <yaxisMaximum />
@[end if]@
        </hudson.plugins.plot.Plot>
@[end for]@
@[end for]@
      </plots>
    </hudson.plugins.plot.PlotPublisher>

@{
import html
}@
    <hudson.plugins.plot.PlotPublisher plugin="plot@@2.1.3">
      <plots>
@[for plot_group, plot_list in plots.items()]@
@[for plot in plot_list]@
        <hudson.plugins.plot.Plot>
          <description>@(html.escape(plot.description))</description>
          <title>@(plot.title)</title>
          <yaxis>@(plot.y_axis_label)</yaxis>
          <series>
@[for series in plot.data_series]@
            <hudson.plugins.plot.CSVSeries>
              <file>@(series.data_file)</file>
              <label />
              <fileType>@(series.data_type)</fileType>
              <colExclusionSet>
                <int>@(series.selection_value)</int>
              </colExclusionSet>
              <inclusionFlag>@(series.selection_flag)</inclusionFlag>
              <exclusionValues>@(series.selection_value)</exclusionValues>
              <exclusionValuesList class="java.util.Arrays$ArrayList">
                <a class="string-array">
                  <string>@(series.selection_value)</string>
                </a>
              </exclusionValuesList>
              <url>@(series.url)</url>
              <displayTableFlag>true</displayTableFlag>
            </hudson.plugins.plot.CSVSeries>
@[end for]@
          </series>
          <group>@(plot_group)</group>
          <numBuilds>@(plot.num_builds or '')</numBuilds>
          <csvFileName>@(plot.master_csv_name)</csvFileName>
          <csvLastModification>0</csvLastModification>
          <style>@(plot.style)</style>
          <useDescr>false</useDescr>
          <keepRecords>false</keepRecords>
          <exclZero>@('true' if plot.y_axis_exclude_zero else 'false')</exclZero>
          <logarithmic>false</logarithmic>
@[if plot.y_axis_minimum is not None]@
          <yaxisMinimum>@(plot.y_axis_minimum)</yaxisMinimum>
@[else]@
          <yaxisMinimum />
@[end if]@
@[if plot.y_axis_maximum is not None]@
          <yaxisMaximum>@(plot.y_axis_maximum)</yaxisMaximum>
@[else]@
          <yaxisMaximum />
@[end if]@
        </hudson.plugins.plot.Plot>
@[end for]@
@[end for]@
      </plots>
    </hudson.plugins.plot.PlotPublisher>


fix the bug for none of recv_topics

fix the bug for none of recv_topics

@###############################################
@#
@# EmPy template for generating microRTPS_agent.cpp file
@#
@###############################################
@# Start of Template
@#
@# Context:
@#  - msgs (List) list of all msg files
@#  - multi_topics (List) list of all multi-topic names
@#  - ids (List) list of all RTPS msg ids
@###############################################
@{
import genmsg.msgs

from px_generate_uorb_topic_helper import * # this is in Tools/
from px_generate_uorb_topic_files import MsgScope # this is in Tools/

send_topics = [(alias[idx] if alias[idx] else s.short_name) for idx, s in enumerate(spec) if scope[idx] == MsgScope.SEND]
recv_topics = [(alias[idx] if alias[idx] else s.short_name) for idx, s in enumerate(spec) if scope[idx] == MsgScope.RECEIVE]
}@
/****************************************************************************
 *
 * Copyright 2017 Proyectos y Sistemas de Mantenimiento SL (eProsima).
 * Copyright (c) 2018-2019 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors
 * may be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

#include <thread>
#include <atomic>
#include <unistd.h>
#include <poll.h>
#include <chrono>
#include <ctime>
#include <csignal>
#include <termios.h>
#include <condition_variable>
#include <queue>

#include <fastcdr/Cdr.h>
#include <fastcdr/FastCdr.h>
#include <fastcdr/exceptions/Exception.h>
#include <fastrtps/utils/eClock.h>
#include <fastrtps/Domain.h>

#include "microRTPS_transport.h"
#include "RtpsTopics.h"

#define BUFFER_SIZE 1024

// Default values
#define DEVICE "/dev/ttyACM0"
#define SLEEP_US 1
#define BAUDRATE 460800
#define POLL_MS 0
#define WAIT_CNST 2
#define DEFAULT_RECV_PORT 2020
#define DEFAULT_SEND_PORT 2019
#define DEFAULT_IP "127.0.0.1"

using namespace eprosima;
using namespace eprosima::fastrtps;

volatile sig_atomic_t running = 1;
Transport_node *transport_node = nullptr;
RtpsTopics topics;
uint32_t total_sent = 0, sent = 0;

struct options {
    enum class eTransports
    {
        UART,
        UDP
    };
    eTransports transport = options::eTransports::UART;
    char device[64] = DEVICE;
    int sleep_us = SLEEP_US;
    uint32_t baudrate = BAUDRATE;
    int poll_ms = POLL_MS;
    uint16_t recv_port = DEFAULT_RECV_PORT;
    uint16_t send_port = DEFAULT_SEND_PORT;
    char ip[16] = DEFAULT_IP;
} _options;

static void usage(const char *name)
{
    printf("usage: %s [options]\n\n"
             "  -t <transport>          [UART|UDP] Default UART\n"
             "  -d <device>             UART device. Default /dev/ttyACM0\n"
             "  -w <sleep_time_us>      Time in us for which each iteration sleep. Default 1ms\n"
             "  -b <baudrate>           UART device baudrate. Default 460800\n"
             "  -p <poll_ms>            Time in ms to poll over UART. Default 1ms\n"
             "  -r <reception port>     UDP port for receiving. Default 2019\n"
             "  -s <sending port>       UDP port for sending. Default 2020\n"
             "  -i <ip_address>         Target IP for UDP. Default 127.0.0.1\n",
             name);
}

static int parse_options(int argc, char **argv)
{
    int ch;

    while ((ch = getopt(argc, argv, "t:d:w:b:p:r:s:i:")) != EOF)
    {
        switch (ch)
        {
            case 't': _options.transport      = strcmp(optarg, "UDP") == 0?
                                                 options::eTransports::UDP
                                                :options::eTransports::UART;  break;
            case 'd': if (nullptr != optarg) strcpy(_options.device, optarg); break;
            case 'w': _options.sleep_us       = strtol(optarg, nullptr, 10);  break;
            case 'b': _options.baudrate       = strtoul(optarg, nullptr, 10); break;
            case 'p': _options.poll_ms        = strtol(optarg, nullptr, 10);  break;
            case 'r': _options.recv_port      = strtoul(optarg, nullptr, 10); break;
            case 's': _options.send_port      = strtoul(optarg, nullptr, 10); break;
            case 'i': if (nullptr != optarg) strcpy(_options.ip, optarg); break;
            default:
                usage(argv[0]);
            return -1;
        }
    }

    if (optind < argc)
    {
        usage(argv[0]);
        return -1;
    }

    return 0;
}

void signal_handler(int signum)
{
   printf("Interrupt signal (%d) received.\n", signum);
   running = 0;
   transport_node->close();
}

@[if recv_topics]@
std::atomic<bool> exit_sender_thread(false);
std::condition_variable t_send_queue_cv;
std::mutex t_send_queue_mutex;
std::queue<uint8_t> t_send_queue;

void t_send(void*)
{
    char data_buffer[BUFFER_SIZE] = {};
    uint32_t length = 0;

    while (running && !exit_sender_thread.load())
    {
        std::unique_lock<std::mutex> lk(t_send_queue_mutex);
        while (t_send_queue.empty() && !exit_sender_thread.load())
        {
            t_send_queue_cv.wait(lk);
        }
        uint8_t topic_ID = t_send_queue.front();
        t_send_queue.pop();
        lk.unlock();

        size_t header_length = transport_node->get_header_length();
        /* make room for the header to fill in later */
        eprosima::fastcdr::FastBuffer cdrbuffer(&data_buffer[header_length], sizeof(data_buffer)-header_length);
        eprosima::fastcdr::Cdr scdr(cdrbuffer);
        if (topics.getMsg(topic_ID, scdr))
        {
            length = scdr.getSerializedDataLength();
            if (0 < (length = transport_node->write(topic_ID, data_buffer, length)))
            {
                total_sent += length;
                ++sent;
            }
        }
    }
}
@[end if]@

int main(int argc, char** argv)
{
    if (-1 == parse_options(argc, argv))
    {
        printf("EXITING...\n");
        return -1;
    }

    // register signal SIGINT and signal handler
    signal(SIGINT, signal_handler);

    printf("--- MicroRTPS Agent ---\n");
    printf("- Starting link...\n");

    switch (_options.transport)
    {
        case options::eTransports::UART:
        {
            transport_node = new UART_node(_options.device, _options.baudrate, _options.poll_ms);
            printf("- UART transport: device: %s; baudrate: %d; sleep: %dus; poll: %dms\n",
                   _options.device, _options.baudrate, _options.sleep_us, _options.poll_ms);
        }
        break;
        case options::eTransports::UDP:
        {
            transport_node = new UDP_node(_options.ip, _options.recv_port, _options.send_port);
            printf("- UDP transport: ip address: %s; recv port: %u; send port: %u; sleep: %dus\n",
                    _options.ip, _options.recv_port, _options.send_port, _options.sleep_us);
        }
        break;
        default:
            printf("EXITING...\n");
        return -1;
    }

    if (0 > transport_node->init())
    {
        printf("EXITING...\n");
        return -1;
    }

    sleep(1);

@[if send_topics]@
    char data_buffer[BUFFER_SIZE] = {};
    int received = 0, loop = 0;
    int length = 0, total_read = 0;
    bool receiving = false;
    uint8_t topic_ID = 255;
    std::chrono::time_point<std::chrono::steady_clock> start, end;
@[end if]@

@[if recv_topics]@
    topics.init(&t_send_queue_cv, &t_send_queue_mutex, &t_send_queue);
@[end if]@

    running = true;
@[if recv_topics]@
    std::thread sender_thread(t_send, nullptr);
@[end if]@

    while (running)
    {
@[if send_topics]@
        ++loop;
        if (!receiving) start = std::chrono::steady_clock::now();
        // Publish messages received from UART
        while (0 < (length = transport_node->read(&topic_ID, data_buffer, BUFFER_SIZE)))
        {
            topics.publish(topic_ID, data_buffer, sizeof(data_buffer));
            ++received;
            total_read += length;
            receiving = true;
            end = std::chrono::steady_clock::now();
        }

        if ((receiving && std::chrono::duration<double>(std::chrono::steady_clock::now() - end).count() > WAIT_CNST) ||
            (!running  && loop > 1))
        {
            std::chrono::duration<double>  elapsed_secs = end - start;
            printf("\nSENT:     %lu messages - %lu bytes\n",
                    (unsigned long)sent, (unsigned long)total_sent);
            printf("RECEIVED: %d messages - %d bytes; %d LOOPS - %.03f seconds - %.02fKB/s\n\n",
                    received, total_read, loop, elapsed_secs.count(), (double)total_read/(1000*elapsed_secs.count()));
            received = sent = total_read = total_sent = 0;
            receiving = false;
        }
@[else]@
        usleep(_options.sleep_us);
@[end if]@
    }
@[if recv_topics]@
    exit_sender_thread = true;
    t_send_queue_cv.notify_one();
    sender_thread.join();
@[end if]@
    delete transport_node;
    transport_node = nullptr;

    return 0;
}

@###############################################
@#
@# EmPy template for generating microRTPS_agent.cpp file
@#
@###############################################
@# Start of Template
@#
@# Context:
@#  - msgs (List) list of all msg files
@#  - multi_topics (List) list of all multi-topic names
@#  - ids (List) list of all RTPS msg ids
@###############################################
@{
import genmsg.msgs

from px_generate_uorb_topic_helper import * # this is in Tools/
from px_generate_uorb_topic_files import MsgScope # this is in Tools/

send_topics = [(alias[idx] if alias[idx] else s.short_name) for idx, s in enumerate(spec) if scope[idx] == MsgScope.SEND]
recv_topics = [(alias[idx] if alias[idx] else s.short_name) for idx, s in enumerate(spec) if scope[idx] == MsgScope.RECEIVE]
}@
/****************************************************************************
 *
 * Copyright 2017 Proyectos y Sistemas de Mantenimiento SL (eProsima).
 * Copyright (c) 2018-2019 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors
 * may be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

#include <thread>
#include <atomic>
#include <unistd.h>
#include <poll.h>
#include <chrono>
#include <ctime>
#include <csignal>
#include <termios.h>
#include <condition_variable>
#include <queue>

#include <fastcdr/Cdr.h>
#include <fastcdr/FastCdr.h>
#include <fastcdr/exceptions/Exception.h>
#include <fastrtps/utils/eClock.h>
#include <fastrtps/Domain.h>

#include "microRTPS_transport.h"
#include "RtpsTopics.h"

#define BUFFER_SIZE 1024

// Default values
#define DEVICE "/dev/ttyACM0"
#define SLEEP_US 1
#define BAUDRATE 460800
#define POLL_MS 0
#define WAIT_CNST 2
#define DEFAULT_RECV_PORT 2020
#define DEFAULT_SEND_PORT 2019
#define DEFAULT_IP "127.0.0.1"

using namespace eprosima;
using namespace eprosima::fastrtps;

volatile sig_atomic_t running = 1;
Transport_node *transport_node = nullptr;
RtpsTopics topics;
uint32_t total_sent = 0, sent = 0;

struct options {
    enum class eTransports
    {
        UART,
        UDP
    };
    eTransports transport = options::eTransports::UART;
    char device[64] = DEVICE;
    int sleep_us = SLEEP_US;
    uint32_t baudrate = BAUDRATE;
    int poll_ms = POLL_MS;
    uint16_t recv_port = DEFAULT_RECV_PORT;
    uint16_t send_port = DEFAULT_SEND_PORT;
    char ip[16] = DEFAULT_IP;
} _options;

static void usage(const char *name)
{
    printf("usage: %s [options]\n\n"
             "  -t <transport>          [UART|UDP] Default UART\n"
             "  -d <device>             UART device. Default /dev/ttyACM0\n"
             "  -w <sleep_time_us>      Time in us for which each iteration sleep. Default 1ms\n"
             "  -b <baudrate>           UART device baudrate. Default 460800\n"
             "  -p <poll_ms>            Time in ms to poll over UART. Default 1ms\n"
             "  -r <reception port>     UDP port for receiving. Default 2019\n"
             "  -s <sending port>       UDP port for sending. Default 2020\n"
             "  -i <ip_address>         Target IP for UDP. Default 127.0.0.1\n",
             name);
}

static int parse_options(int argc, char **argv)
{
    int ch;

    while ((ch = getopt(argc, argv, "t:d:w:b:p:r:s:i:")) != EOF)
    {
        switch (ch)
        {
            case 't': _options.transport      = strcmp(optarg, "UDP") == 0?
                                                 options::eTransports::UDP
                                                :options::eTransports::UART;  break;
            case 'd': if (nullptr != optarg) strcpy(_options.device, optarg); break;
            case 'w': _options.sleep_us       = strtol(optarg, nullptr, 10);  break;
            case 'b': _options.baudrate       = strtoul(optarg, nullptr, 10); break;
            case 'p': _options.poll_ms        = strtol(optarg, nullptr, 10);  break;
            case 'r': _options.recv_port      = strtoul(optarg, nullptr, 10); break;
            case 's': _options.send_port      = strtoul(optarg, nullptr, 10); break;
            case 'i': if (nullptr != optarg) strcpy(_options.ip, optarg); break;
            default:
                usage(argv[0]);
            return -1;
        }
    }

    if (optind < argc)
    {
        usage(argv[0]);
        return -1;
    }

    return 0;
}

void signal_handler(int signum)
{
   printf("Interrupt signal (%d) received.\n", signum);
   running = 0;
   transport_node->close();
}

@[if recv_topics]@
std::atomic<bool> exit_sender_thread(false);
std::condition_variable t_send_queue_cv;
std::mutex t_send_queue_mutex;
std::queue<uint8_t> t_send_queue;

void t_send(void*)
{
    char data_buffer[BUFFER_SIZE] = {};
    uint32_t length = 0;

    while (running && !exit_sender_thread.load())
    {
        std::unique_lock<std::mutex> lk(t_send_queue_mutex);
        while (t_send_queue.empty() && !exit_sender_thread.load())
        {
            t_send_queue_cv.wait(lk);
        }
        uint8_t topic_ID = t_send_queue.front();
        t_send_queue.pop();
        lk.unlock();

        size_t header_length = transport_node->get_header_length();
        /* make room for the header to fill in later */
        eprosima::fastcdr::FastBuffer cdrbuffer(&data_buffer[header_length], sizeof(data_buffer)-header_length);
        eprosima::fastcdr::Cdr scdr(cdrbuffer);
        if (topics.getMsg(topic_ID, scdr))
        {
            length = scdr.getSerializedDataLength();
            if (0 < (length = transport_node->write(topic_ID, data_buffer, length)))
            {
                total_sent += length;
                ++sent;
            }
        }
    }
}
@[end if]@

int main(int argc, char** argv)
{
    if (-1 == parse_options(argc, argv))
    {
        printf("EXITING...\n");
        return -1;
    }

    // register signal SIGINT and signal handler
    signal(SIGINT, signal_handler);

    printf("--- MicroRTPS Agent ---\n");
    printf("- Starting link...\n");

    switch (_options.transport)
    {
        case options::eTransports::UART:
        {
            transport_node = new UART_node(_options.device, _options.baudrate, _options.poll_ms);
            printf("- UART transport: device: %s; baudrate: %d; sleep: %dus; poll: %dms\n",
                   _options.device, _options.baudrate, _options.sleep_us, _options.poll_ms);
        }
        break;
        case options::eTransports::UDP:
        {
            transport_node = new UDP_node(_options.ip, _options.recv_port, _options.send_port);
            printf("- UDP transport: ip address: %s; recv port: %u; send port: %u; sleep: %dus\n",
                    _options.ip, _options.recv_port, _options.send_port, _options.sleep_us);
        }
        break;
        default:
            printf("EXITING...\n");
        return -1;
    }

    if (0 > transport_node->init())
    {
        printf("EXITING...\n");
        return -1;
    }

    sleep(1);

@[if send_topics]@
    char data_buffer[BUFFER_SIZE] = {};
    int received = 0, loop = 0;
    int length = 0, total_read = 0;
    bool receiving = false;
    uint8_t topic_ID = 255;
    std::chrono::time_point<std::chrono::steady_clock> start, end;
@[end if]@

    topics.init(&t_send_queue_cv, &t_send_queue_mutex, &t_send_queue);

    running = true;
@[if recv_topics]@
    std::thread sender_thread(t_send, nullptr);
@[end if]@

    while (running)
    {
@[if send_topics]@
        ++loop;
        if (!receiving) start = std::chrono::steady_clock::now();
        // Publish messages received from UART
        while (0 < (length = transport_node->read(&topic_ID, data_buffer, BUFFER_SIZE)))
        {
            topics.publish(topic_ID, data_buffer, sizeof(data_buffer));
            ++received;
            total_read += length;
            receiving = true;
            end = std::chrono::steady_clock::now();
        }

        if ((receiving && std::chrono::duration<double>(std::chrono::steady_clock::now() - end).count() > WAIT_CNST) ||
            (!running  && loop > 1))
        {
            std::chrono::duration<double>  elapsed_secs = end - start;
            printf("\nSENT:     %lu messages - %lu bytes\n",
                    (unsigned long)sent, (unsigned long)total_sent);
            printf("RECEIVED: %d messages - %d bytes; %d LOOPS - %.03f seconds - %.02fKB/s\n\n",
                    received, total_read, loop, elapsed_secs.count(), (double)total_read/(1000*elapsed_secs.count()));
            received = sent = total_read = total_sent = 0;
            receiving = false;
        }
@[else]@
        usleep(_options.sleep_us);
@[end if]@
    }
@[if recv_topics]@
    exit_sender_thread = true;
    t_send_queue_cv.notify_one();
    sender_thread.join();
@[end if]@
    delete transport_node;
    transport_node = nullptr;

    return 0;
}


get the syntax right and only embed git.py

@{
filename = 'git.py'
wrapper_script = wrapper_scripts[filename]
cmd = 'echo "%s" > wrapper_scripts/%s' % ('\\n'.join(wrapper_script.replace('\\', '\\\\\\\\').replace('"', '\\"').splitlines()), filename)
}@
@(SNIPPET(
    'builder_shell',
    script='\n'.join([
        'echo "# BEGIN SECTION: Embed wrapper scripts"',
        'rm -fr wrapper_scripts',
        'mkdir wrapper_scripts',
        cmd,
        'echo "# END SECTION"',
    ]),
))@
@{
import re
cmds = []
if ros_buildfarm_repository.version and re.match('[0-9a-f]{40}', ros_buildfarm_repository.version):
    # cannot create a shallow clone for hashes
    cmds += [
        'python3 -u wrapper_scripts/git.py clone %s ros_buildfarm' % ros_buildfarm_repository.url,
        'git -C ros_buildfarm checkout %s' % ros_buildfarm_repository.version,
    ]
else:
    # shallow clone when version is a branch or tag
    cmds.append('python3 -u wrapper_scripts/git.py clone --depth 1 %s%s ros_buildfarm' % ('-b %s ' % ros_buildfarm_repository.version if ros_buildfarm_repository.version else '', ros_buildfarm_repository.url))
}@
@(SNIPPET(
    'builder_shell',
    script='\n'.join([
        'echo "# BEGIN SECTION: Clone ros_buildfarm"',
        'rm -fr ros_buildfarm',
    ] + cmds + [
        'git -C ros_buildfarm log -n 1',
        'rm -fr ros_buildfarm/.git',
        'rm -fr ros_buildfarm/doc',
        'echo "# END SECTION"',
    ]),
))@

@{
cmds = []
for filename in sorted(wrapper_scripts.keys())
    cmd.append('\\n'.join(wrapper_scripts[filename].replace('\\', '\\\\\\\\').replace('"', '\\"').splitlines())') > wrapper_scripts/@(filename)
}@
@[]@
RUN echo "@('\\n'.join(wrapper_scripts[filename].replace('\\', '\\\\\\\\').replace('"', '\\"').splitlines()))" > /tmp/wrapper_scripts/@(filename)
@[end for]@
@(SNIPPET(
    'builder_shell',
    script='\n'.join([
        'echo "# BEGIN SECTION: Embed wrapper scripts"',
        'rm -fr wrapper_scripts',
        'mkdir wrapper_scripts',
    ] + cmds + [
        'echo "# END SECTION"',
    ]),
))@
@{
import re
cmds = []
if ros_buildfarm_repository.version and re.match('[0-9a-f]{40}', ros_buildfarm_repository.version):
    # cannot create a shallow clone for hashes
    cmds += [
        'python3 -u wrapper_scripts/git.py clone %s ros_buildfarm' % ros_buildfarm_repository.url,
        'git -C ros_buildfarm checkout %s' % ros_buildfarm_repository.version,
    ]
else:
    # shallow clone when version is a branch or tag
    cmds.append('python3 -u wrapper_scripts/git.py clone --depth 1 %s%s ros_buildfarm' % ('-b %s ' % ros_buildfarm_repository.version if ros_buildfarm_repository.version else '', ros_buildfarm_repository.url))
}@
@(SNIPPET(
    'builder_shell',
    script='\n'.join([
        'echo "# BEGIN SECTION: Clone ros_buildfarm"',
        'rm -fr ros_buildfarm',
    ] + cmds + [
        'git -C ros_buildfarm log -n 1',
        'rm -fr ros_buildfarm/.git',
        'rm -fr ros_buildfarm/doc',
        'echo "# END SECTION"',
    ]),
))@


require_tree argument must be dir

require_tree argument must be dir

#= require ./store
#= require_tree ./mixins
#= require_tree ./initializers
#= require_tree ./models
#= require_tree ./controllers
#= require_tree ./views
#= require_tree ./components
#= require_tree ./templates
#= require_tree ./routes
#= require ./router
#= require_self

#= require ./store
#= require_tree ./mixins
#= require_tree ./initializers
#= require_tree ./models
#= require_tree ./controllers
#= require_tree ./views
#= require_tree ./helpers
#= require_tree ./components
#= require_tree ./templates
#= require_tree ./routes
#= require ./router
#= require_self