Update xunit plugin version in template. (#872)

@{
# for backward compatibility only
if 'types' not in vars() and 'pattern' in vars():
    types = [('GoogleTestType', pattern)]
}@
    <xunit plugin="xunit@@2.4.0">
      <types>
@[for type_tag_and_pattern in types]@
@{
# expanding these within the for statement leads to a TypeError in empy version 3.3.4 and older
type_tag, pattern = type_tag_and_pattern
assert type_tag in ('CTestType', 'GoogleTestType', 'JUnitType'), 'Unsupported test type tag: ' + type_tag
}@
        <@(type_tag)>
          <pattern>@ESCAPE(pattern)</pattern>
          <skipNoTestFiles>true</skipNoTestFiles>
          <failIfNotNew>true</failIfNotNew>
          <deleteOutputFiles>true</deleteOutputFiles>
          <stopProcessingIfError>true</stopProcessingIfError>
        </@(type_tag)>
@[end for]@
      </types>
      <thresholds>
        <org.jenkinsci.plugins.xunit.threshold.FailedThreshold>
          <unstableThreshold>0</unstableThreshold>
          <unstableNewThreshold/>
          <failureThreshold/>
          <failureNewThreshold/>
        </org.jenkinsci.plugins.xunit.threshold.FailedThreshold>
        <org.jenkinsci.plugins.xunit.threshold.SkippedThreshold>
          <unstableThreshold/>
          <unstableNewThreshold/>
          <failureThreshold/>
          <failureNewThreshold/>
        </org.jenkinsci.plugins.xunit.threshold.SkippedThreshold>
      </thresholds>
      <thresholdMode>1</thresholdMode>
      <extraConfiguration>
        <testTimeMargin>3000</testTimeMargin>
      </extraConfiguration>
    </xunit>

@{
# for backward compatibility only
if 'types' not in vars() and 'pattern' in vars():
    types = [('GoogleTestType', pattern)]
}@
    <xunit plugin="xunit@@2.3.9">
      <types>
@[for type_tag_and_pattern in types]@
@{
# expanding these within the for statement leads to a TypeError in empy version 3.3.4 and older
type_tag, pattern = type_tag_and_pattern
assert type_tag in ('CTestType', 'GoogleTestType', 'JUnitType'), 'Unsupported test type tag: ' + type_tag
}@
        <@(type_tag)>
          <pattern>@ESCAPE(pattern)</pattern>
          <skipNoTestFiles>true</skipNoTestFiles>
          <failIfNotNew>true</failIfNotNew>
          <deleteOutputFiles>true</deleteOutputFiles>
          <stopProcessingIfError>true</stopProcessingIfError>
        </@(type_tag)>
@[end for]@
      </types>
      <thresholds>
        <org.jenkinsci.plugins.xunit.threshold.FailedThreshold>
          <unstableThreshold>0</unstableThreshold>
          <unstableNewThreshold/>
          <failureThreshold/>
          <failureNewThreshold/>
        </org.jenkinsci.plugins.xunit.threshold.FailedThreshold>
        <org.jenkinsci.plugins.xunit.threshold.SkippedThreshold>
          <unstableThreshold/>
          <unstableNewThreshold/>
          <failureThreshold/>
          <failureNewThreshold/>
        </org.jenkinsci.plugins.xunit.threshold.SkippedThreshold>
      </thresholds>
      <thresholdMode>1</thresholdMode>
      <extraConfiguration>
        <testTimeMargin>3000</testTimeMargin>
      </extraConfiguration>
    </xunit>


fix trigger devel jobs groovy script

fix trigger devel jobs groovy script

<project>
	<actions/>
	<description>Generated at @ESCAPE(now_str) from template '@ESCAPE(template_name)'</description>
@(SNIPPET(
    'log-rotator',
    days_to_keep=365,
    num_to_keep=10,
))@
	<keepDependencies>false</keepDependencies>
	<properties>
@(SNIPPET(
    'property_job-priority',
    priority=2,
))@
		<hudson.model.ParametersDefinitionProperty>
			<parameterDefinitions>
				<hudson.model.ChoiceParameterDefinition>
					<name>filter</name>
					<description/>
					<choices class="java.util.Arrays$ArrayList">
						<a class="string-array">
							<string>not_stable</string>
							<string>worse_than_unstable</string>
							<string>all</string>
							<string>stable</string>
							<string>unstable</string>
							<string>failure</string>
							<string>aborted</string>
							<string>not_built</string>
							</a>
					</choices>
				</hudson.model.ChoiceParameterDefinition>
				</parameterDefinitions>
		</hudson.model.ParametersDefinitionProperty>
	</properties>
@(SNIPPET(
    'scm_null',
))@
	<assignedNode>master</assignedNode>
	<canRoam>false</canRoam>
	<disabled>false</disabled>
	<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
	<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
	<triggers/>
	<concurrentBuild>false</concurrentBuild>
	<builders>
@(SNIPPET(
    'builder_system-groovy',
    command=
"""
import java.util.regex.Matcher
import java.util.regex.Pattern
import hudson.model.AbstractProject
import hudson.model.Result

build = Thread.currentThread().executable
resolver = build.buildVariableResolver
filter = resolver.resolve("filter")
println "Filter: " + filter

pattern = Pattern.compile("%s")
for (p in hudson.model.Hudson.instance.getAllItems(AbstractProject)) {
    if (!pattern.matcher(p.name).matches()) continue
    if (p.isDisabled()) continue
    if (p.isBuilding()) continue
    if (p.isInQueue()) continue

    if (filter != "all") {
        def lb = p.lastBuild
        if (!lb) {
            // job has never been built
            if (filter != "not_built" && filter != "not_stable" && filter != "worse_than_unstable") continue
        } else {
            def r = lb.result
            def pb = lb
            while (!r) {
              pb = pb.previousBuild
              if (!pb) {
                // no finished build yet
                break
              }
              r = pb.result
            }
            if (r == Result.SUCCESS) {
                if (filter != "stable") continue
            } else if (r == Result.UNSTABLE) {
                if (filter != "unstable" && filter != "not_stable") continue
            } else if (r == Result.FAILURE) {
                if (filter != "failure" && filter != "not_stable" && filter != "worse_than_unstable") continue
            } else if (r == Result.ABORTED) {
                if (filter != "aborted" && filter != "not_stable" && filter != "worse_than_unstable") continue
            } else if (!r) {
                if (filter != "not_built" && filter != "not_stable" && filter != "worse_than_unstable") continue
            } else if (r == Result.NOT_BUILT) {
              // this should never happen for the result of a build
              assert false
            } else {
              // unknown result value
              println("Job '" + p.name + "'' has unknown result: " + r)
              assert false
            }
        }
    }
    println p.name
    p.scheduleBuild()
}
""" % project_name_pattern,
))@
	</builders>
	<publishers>
@(SNIPPET(
    'publisher_mailer',
    recipients=recipients,
    dynamic_recipients=[],
    send_to_individuals=False,
))@
	</publishers>
	<buildWrappers>
@(SNIPPET(
    'build-wrapper_timestamper',
))@
	</buildWrappers>
</project>

<project>
	<actions/>
	<description>Generated at @ESCAPE(now_str) from template '@ESCAPE(template_name)'</description>
@(SNIPPET(
    'log-rotator',
    days_to_keep=365,
    num_to_keep=10,
))@
	<keepDependencies>false</keepDependencies>
	<properties>
@(SNIPPET(
    'property_job-priority',
    priority=2,
))@
		<hudson.model.ParametersDefinitionProperty>
			<parameterDefinitions>
				<hudson.model.ChoiceParameterDefinition>
					<name>filter</name>
					<description/>
					<choices class="java.util.Arrays$ArrayList">
						<a class="string-array">
							<string>not_stable</string>
							<string>worse_than_unstable</string>
							<string>all</string>
							<string>stable</string>
							<string>unstable</string>
							<string>failure</string>
							<string>aborted</string>
							<string>not_built</string>
							</a>
					</choices>
				</hudson.model.ChoiceParameterDefinition>
				</parameterDefinitions>
		</hudson.model.ParametersDefinitionProperty>
	</properties>
@(SNIPPET(
    'scm_null',
))@
	<assignedNode>master</assignedNode>
	<canRoam>false</canRoam>
	<disabled>false</disabled>
	<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
	<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
	<triggers/>
	<concurrentBuild>false</concurrentBuild>
	<builders>
@(SNIPPET(
    'builder_system-groovy',
    command=
"""
import java.util.regex.Matcher
import java.util.regex.Pattern
import hudson.model.AbstractProject
import hudson.model.Result

build = Thread.currentThread().executable
resolver = build.buildVariableResolver
filter = resolver.resolve("filter")
println "Filter: " + filter

pattern = Pattern.compile("%s")
for (p in hudson.model.Hudson.instance.getAllItems(AbstractProject)) {
    if (!pattern.matcher(p.name).matches()) continue
    if (p.isDisabled()) continue
    if (p.isBuilding()) continue
    if (p.isInQueue()) continue

    if (filter != "all") {
        def lb = p.lastBuild
        if (!lb) {
            // job has never been built
            if (filter != "not_built" && filter != "not_stable" && filter != "worse_than_unstable")) continue
        } else {
            def r = lb.result
            def pb = lb
            while (!r) {
              pb = pb.previousBuild
              if (!pb) {
                // no finished build yet
                break
              }
              r = pb.result
            }
            if (r == Result.SUCCESS) {
                if (filter != "stable") continue
            } else if (r == Result.UNSTABLE) {
                if (filter != "unstable" && filter != "not_stable") continue
            } else if (r == Result.FAILURE) {
                if (filter != "failure" && filter != "not_stable" && filter != "worse_than_unstable") continue
            } else if (r == Result.ABORTED) {
                if (filter != "aborted" && filter != "not_stable" && filter != "worse_than_unstable") continue
            } else if (!r) {
                if (filter != "not_built" && filter != "not_stable" && filter != "worse_than_unstable") continue
            } else if (r == Result.NOT_BUILT) {
              // this should never happen for the result of a build
              assert false
            } else {
              // unknown result value
              println("Job '" + p.name + "'' has unknown result: " + r)
              assert false
            }
        }
    }
    println p.name
    p.scheduleBuild()
}
""" % project_name_pattern,
))@
	</builders>
	<publishers>
@(SNIPPET(
    'publisher_mailer',
    recipients=recipients,
    dynamic_recipients=[],
    send_to_individuals=False,
))@
	</publishers>
	<buildWrappers>
@(SNIPPET(
    'build-wrapper_timestamper',
))@
	</buildWrappers>
</project>


fix broken assertion (#159)

fix broken assertion (#159)

// generated from rosidl_generator_py/resource/_msg_support.c.em
// generated code does not contain a copyright notice

#include <Python.h>

#include <@(spec.base_type.pkg_name)/@(subfolder)/@(module_name)__struct.h>
#include <@(spec.base_type.pkg_name)/@(subfolder)/@(module_name)__functions.h>

@{
have_not_included_primitive_arrays = True
have_not_included_string = True
nested_array_dict = {}
}@
@[for field in spec.fields]@
@[  if field.type.is_array and have_not_included_primitive_arrays]@
@{have_not_included_primitive_arrays = False}@
#include <rosidl_generator_c/primitives_array.h>
#include <rosidl_generator_c/primitives_array_functions.h>

@[  end if]@
@[  if field.type.type == 'string' and have_not_included_string]@
@{have_not_included_string = False}@
#include <rosidl_generator_c/string.h>
#include <rosidl_generator_c/string_functions.h>

@[  end if]@
@{
if not field.type.is_primitive_type() and field.type.is_array:
    if field.type.type not in nested_array_dict:
        nested_array_dict[field.type.type] = field.type.pkg_name
}@
@[end for]@
@[if nested_array_dict != {}]@
// Nested array functions includes
@[  for key in nested_array_dict]@
#include <@(nested_array_dict[key])/@(subfolder)/@convert_camel_case_to_lower_case_underscore(key)__functions.h>
@[  end for]@
// end nested array functions include
@[end if]@
@{
msg_typename = '%s__%s__%s' % (spec.base_type.pkg_name, subfolder, spec.base_type.type)
}@

void * @(spec.base_type.pkg_name)_@(module_name)__convert_from_py(PyObject * _pymsg)
{
  @(msg_typename) * ros_message = @(msg_typename)__create();
  (void)ros_message;
@{
full_classname = "@(spec.base_type.pkg_name).@(subfolder)._@(module_name).@(spec.base_type.type)"
}@
  char full_classname_dest[@(len(full_classname) + 1)];

  char * class_name = (char *)PyUnicode_1BYTE_DATA(
    PyObject_GetAttrString(PyObject_GetAttrString(_pymsg, "__class__"), "__name__"));
  char * module_name = (char *)PyUnicode_1BYTE_DATA(
    PyObject_GetAttrString(PyObject_GetAttrString(_pymsg, "__class__"), "__module__"));

  snprintf(full_classname_dest, sizeof(full_classname_dest), "%s.%s", module_name, class_name);

  assert(strncmp(
      "@(spec.base_type.pkg_name).@(subfolder)._@(module_name).@(spec.base_type.type)",
      full_classname_dest, @(len(full_classname))) == 0);

@[for field in spec.fields]@
  PyObject * py@(field.name) = PyObject_GetAttrString(_pymsg, "@(field.name)");
@[  if not field.type.is_primitive_type()]@
@{
nested_type = '%s__%s__%s' % (field.type.pkg_name, 'msg', field.type.type)
}@
  PyObject * py@(field.name)_msg_module = PyImport_ImportModule("@(field.type.pkg_name).msg._@convert_camel_case_to_lower_case_underscore(field.type.type)");
  PyObject * py@(field.name)_msg_class = PyObject_GetAttrString(py@(field.name)_msg_module, "@(field.type.type)");
  PyObject * py@(field.name)_msg_metaclass = PyObject_GetAttrString(py@(field.name)_msg_class,"__class__");
  PyObject * py@(field.name)_convert_from_py = PyObject_GetAttrString(py@(field.name)_msg_metaclass, "_CONVERT_FROM_PY");
  typedef PyObject *(* convert_from_py_signature)(void *);
  convert_from_py_signature convert_from_py_@(field.name) = (convert_from_py_signature)PyCapsule_GetPointer(py@(field.name)_convert_from_py, NULL);
@[    if field.type.is_array]@
  assert(PySequence_Check(py@(field.name)));
  PyObject * seq@(field.name) = PySequence_Fast(py@(field.name), "expected a sequence");
  @(nested_type) * item@(field.name);
@[      if field.type.array_size is None or field.type.is_upper_bound]@
  size_t size@(field.name) = PySequence_Size(py@(field.name));
  if (!@(nested_type)__Array__init(&(ros_message->@(field.name)), size@(field.name))) {
    PyErr_SetString(PyExc_RuntimeError, "unable to create @(nested_type)__Array ros_message");
  }
  @(nested_type) * dest@(field.name) = ros_message->@(field.name).data;
@[      else]@
  size_t size@(field.name) = @(field.type.array_size);
  @(nested_type) * dest@(field.name) = ros_message->@(field.name);
@[      end if]@
  size_t idx@(field.name);
  for (idx@(field.name) = 0; idx@(field.name) < size@(field.name); idx@(field.name)++) {
    item@(field.name) = (@(nested_type) *) convert_from_py_@(field.name)(
      PySequence_Fast_GET_ITEM(seq@(field.name), idx@(field.name)));
    memcpy(&dest@(field.name)[idx@(field.name)], item@(field.name), sizeof(@(nested_type)));
  }
@[    else]@
  @(nested_type) * tmp@(field.name) = (@(nested_type) *) convert_from_py_@(field.name)(py@(field.name));
  ros_message->@(field.name) = *tmp@(field.name);
@[    end if]@
@[  elif field.type.is_array]@
  assert(PySequence_Check(py@(field.name)));
  PyObject * seq@(field.name) = PySequence_Fast(py@(field.name), "expected a sequence");
  PyObject * item@(field.name);
@[    if field.type.array_size is None or field.type.is_upper_bound]@
  size_t size@(field.name) = PySequence_Size(py@(field.name));
@[      if field.type.type == 'string']@
  if (!rosidl_generator_c__String__Array__init(&(ros_message->@(field.name)), size@(field.name))) {
    PyErr_SetString(PyExc_RuntimeError, "unable to create String__Array ros_message");
  }
@[      else]@
  if (!rosidl_generator_c__@(field.type.type)__Array__init(&(ros_message->@(field.name)), size@(field.name))) {
    PyErr_SetString(PyExc_RuntimeError, "unable to create @(field.type.type)__Array ros_message");
  }
@[      end if]@
  @primitive_msg_type_to_c(field.type.type) * dest@(field.name) = ros_message->@(field.name).data;
@[    else]@
  size_t size@(field.name) = @(field.type.array_size);
  @primitive_msg_type_to_c(field.type.type) * dest@(field.name) = ros_message->@(field.name);
@[    end if]@
@[    if field.type.type != 'string']@
  @primitive_msg_type_to_c(field.type.type) tmp@(field.name);
@[    end if]@
  size_t idx@(field.name);
  for (idx@(field.name) = 0; idx@(field.name) < size@(field.name); idx@(field.name)++) {
    item@(field.name) = PySequence_Fast_GET_ITEM(seq@(field.name), idx@(field.name));
@[    if field.type.type == 'char']@
    assert(PyUnicode_Check(item@(field.name)));
    tmp@(field.name) = PyUnicode_1BYTE_DATA(item@(field.name))[0];
@[    elif field.type.type == 'byte']@
    assert(PyBytes_Check(item@(field.name)));
    tmp@(field.name) = PyBytes_AS_STRING(item@(field.name))[0];
@[    elif field.type.type == 'string']@
    assert(PyUnicode_Check(item@(field.name)));
    rosidl_generator_c__String__assign(
      &dest@(field.name)[idx@(field.name)], (char *)PyUnicode_1BYTE_DATA(item@(field.name)));
@[    elif field.type.type == 'bool']@
    assert(PyBool_Check(item@(field.name)));
    tmp@(field.name) = (item@(field.name) == Py_True);
@[    elif field.type.type in ['float32', 'float64']]@
    assert(PyFloat_Check(item@(field.name)));
@[      if field.type.type == 'float32']@
    tmp@(field.name) = (float)PyFloat_AS_DOUBLE(item@(field.name));
@[      else]@
    tmp@(field.name) = PyFloat_AS_DOUBLE(item@(field.name));
@[      end if]@
@[    elif field.type.type in [
        'int8',
        'int16',
        'int32',
    ]]@
    assert(PyLong_Check(item@(field.name)));
    tmp@(field.name) = (@(primitive_msg_type_to_c(field.type.type)))PyLong_AsLong(item@(field.name));
@[    elif field.type.type in [
        'uint8',
        'uint16',
        'uint32',
    ]]@
    assert(PyLong_Check(item@(field.name)));
@[      if field.type.type == 'uint32']@
    tmp@(field.name) = PyLong_AsUnsignedLong(item@(field.name));
@[      else]@
    tmp@(field.name) = (@(primitive_msg_type_to_c(field.type.type)))PyLong_AsUnsignedLong(item@(field.name));
@[      end if]
@[    elif field.type.type == 'int64']@
    assert(PyLong_Check(item@(field.name)));
    tmp@(field.name) = PyLong_AsLongLong(item@(field.name));
@[    elif field.type.type == 'uint64']@
    assert(PyLong_Check(item@(field.name)));
    tmp@(field.name) = PyLong_AsUnsignedLongLong(item@(field.name));
@[    end if]@
@[    if field.type.type != 'string']@
    memcpy(&dest@(field.name)[idx@(field.name)], &tmp@(field.name), sizeof(@primitive_msg_type_to_c(field.type.type)));
@[    end if]@
  }
@[  elif field.type.type == 'char']@
  assert(PyUnicode_Check(py@(field.name)));
  ros_message->@(field.name) = PyUnicode_1BYTE_DATA(py@(field.name))[0];
@[  elif field.type.type == 'byte']@
  assert(PyBytes_Check(py@(field.name)));
  ros_message->@(field.name) = PyBytes_AS_STRING(py@(field.name))[0];
@[  elif field.type.type == 'string']@
  assert(PyUnicode_Check(py@(field.name)));
  rosidl_generator_c__String__assign(
    &ros_message->@(field.name), (char *)PyUnicode_1BYTE_DATA(py@(field.name)));
@[  elif field.type.type == 'bool']@
  assert(PyBool_Check(py@(field.name)));
  ros_message->@(field.name) = (Py_True == py@(field.name));
@[  elif field.type.type in ['float32', 'float64']]@
  assert(PyFloat_Check(py@(field.name)));
@[    if field.type.type == 'float32']@
  ros_message->@(field.name) = (float)PyFloat_AS_DOUBLE(py@(field.name));
@[    else]@
  ros_message->@(field.name) = PyFloat_AS_DOUBLE(py@(field.name));
@[    end if]@
@[  elif field.type.type in [
        'int8',
        'int16',
        'int32',
    ]]@
  assert(PyLong_Check(py@(field.name)));
  ros_message->@(field.name) = (@(primitive_msg_type_to_c(field.type.type)))PyLong_AsLong(py@(field.name));
@[  elif field.type.type in [
        'uint8',
        'uint16',
        'uint32',
    ]]@
  assert(PyLong_Check(py@(field.name)));
@[    if field.type.type == 'uint32']@
  ros_message->@(field.name) = PyLong_AsUnsignedLong(py@(field.name));
@[    else]@
  ros_message->@(field.name) = (@(primitive_msg_type_to_c(field.type.type)))PyLong_AsUnsignedLong(py@(field.name));
@[    end if]@
@[  elif field.type.type == 'int64']@
  assert(PyLong_Check(py@(field.name)));
  ros_message->@(field.name) = PyLong_AsLongLong(py@(field.name));
@[  elif field.type.type == 'uint64']@
  assert(PyLong_Check(py@(field.name)));
  ros_message->@(field.name) = PyLong_AsUnsignedLongLong(py@(field.name));
@[  else]@
  assert(false);
@[  end if]@
@[end for]@

  assert(ros_message != NULL);
  return ros_message;
}

PyObject * @(spec.base_type.pkg_name)_@(module_name)__convert_to_py(void * raw_ros_message)
{
  @(msg_typename) * ros_message = (@(msg_typename) *)raw_ros_message;
  (void)ros_message;

  PyObject * pymessage_module = PyImport_ImportModule("@(spec.base_type.pkg_name).@(subfolder)._@(module_name)");
  PyObject * pymessage_class = PyObject_GetAttrString(pymessage_module, "@(spec.base_type.type)");

  /* NOTE(esteve): Call constructor of @(spec.base_type.type) */
  PyObject * _pymessage = NULL;
  _pymessage = PyObject_CallObject(pymessage_class, NULL);
  assert(_pymessage != NULL);

@[for field in spec.fields]@
  PyObject * py@(field.name) = NULL;
@[  if not field.type.is_primitive_type()]@
@{
nested_type = '%s__%s__%s' % (field.type.pkg_name, 'msg', field.type.type)
}@
  PyObject * py@(field.name)_msg_module = PyImport_ImportModule("@(field.type.pkg_name).msg._@convert_camel_case_to_lower_case_underscore(field.type.type)");
  PyObject * py@(field.name)_msg_class = PyObject_GetAttrString(py@(field.name)_msg_module, "@(field.type.type)");
  PyObject * py@(field.name)_msg_metaclass = PyObject_GetAttrString(py@(field.name)_msg_class,"__class__");
  PyObject * py@(field.name)_convert_to_py = PyObject_GetAttrString(py@(field.name)_msg_metaclass, "_CONVERT_TO_PY");
  typedef PyObject *(* convert_to_py_signature)(void *);
  convert_to_py_signature convert_to_py_@(field.name) = (convert_to_py_signature)PyCapsule_GetPointer(py@(field.name)_convert_to_py, NULL);
@[    if field.type.is_array]@
@[      if field.type.array_size is None or field.type.is_upper_bound]@
  size_t size@(field.name) = ros_message->@(field.name).size;
@[      else]@
  size_t size@(field.name) = @(field.type.array_size);
@[      end if]@
  py@(field.name) = PyList_New(size@(field.name));
  @(nested_type) item@(field.name);
  size_t idx@(field.name);
  for (idx@(field.name) = 0; idx@(field.name) < size@(field.name); idx@(field.name)++) {
@[      if field.type.array_size is None or field.type.is_upper_bound]@
    item@(field.name) = ros_message->@(field.name).data[idx@(field.name)];
@[      else]@
    item@(field.name) = ros_message->@(field.name)[idx@(field.name)];
@[      end if]@
    PyList_SetItem(py@(field.name), idx@(field.name), convert_to_py_@(field.name)(&item@(field.name)));
  }
  assert(PySequence_Check(py@(field.name)));
@[    else]@
  @(nested_type) pytmp@(field.name) = ros_message->@(field.name);
  py@(field.name) = convert_to_py_@(field.name)(&pytmp@(field.name));
@[    end if]@
@[  elif field.type.is_array]@
@[    if field.type.array_size is None or field.type.is_upper_bound]@
  size_t size@(field.name) = ros_message->@(field.name).size;
  @primitive_msg_type_to_c(field.type.type) * tmpmessagedata@(field.name) = ros_message->@(field.name).data;
@[    else]@
  size_t size@(field.name) = @(field.type.array_size);
  @primitive_msg_type_to_c(field.type.type) * tmpmessagedata@(field.name) = ros_message->@(field.name);
@[    end if]@
  py@(field.name) = PyList_New(size@(field.name));
  size_t idx@(field.name);
  for (idx@(field.name) = 0; idx@(field.name) < size@(field.name); idx@(field.name)++) {
@[    if field.type.type == 'char']@
    PyList_SetItem(py@(field.name), idx@(field.name),
      Py_BuildValue("C", tmpmessagedata@(field.name)[idx@(field.name)]));
@[    elif field.type.type == 'byte']@
    PyList_SetItem(py@(field.name), idx@(field.name),
      PyBytes_FromStringAndSize((const char *)&tmpmessagedata@(field.name)[idx@(field.name)], 1));
@[    elif field.type.type == 'string']@
    PyList_SetItem(py@(field.name), idx@(field.name), PyUnicode_FromString(tmpmessagedata@(field.name)[idx@(field.name)].data));
@[    elif field.type.type == 'bool']@
    PyList_SetItem(py@(field.name), idx@(field.name), tmpmessagedata@(field.name)[idx@(field.name)] ? Py_True : Py_False);
@[    elif field.type.type in ['float32', 'float64']]@
    PyList_SetItem(py@(field.name), idx@(field.name), PyFloat_FromDouble(tmpmessagedata@(field.name)[idx@(field.name)]));
@[    elif field.type.type in [
        'int8',
        'int16',
        'int32',
    ]]@
    PyList_SetItem(py@(field.name), idx@(field.name), PyLong_FromLong(tmpmessagedata@(field.name)[idx@(field.name)]));
@[    elif field.type.type in [
        'uint8',
        'uint16',
        'uint32',
    ]]@
    PyList_SetItem(py@(field.name), idx@(field.name), PyLong_FromUnsignedLong(tmpmessagedata@(field.name)[idx@(field.name)]));
@[    elif field.type.type == 'int64']@
    PyList_SetItem(py@(field.name), idx@(field.name), PyLong_FromLongLong(tmpmessagedata@(field.name)[idx@(field.name)]));
@[    elif field.type.type == 'uint64']@
    PyList_SetItem(py@(field.name), idx@(field.name), PyLong_FromUnsignedLongLong(tmpmessagedata@(field.name)[idx@(field.name)]));
@[    end if]@
  }
  assert(PySequence_Check(py@(field.name)));
@[  elif field.type.type == 'char']@
  py@(field.name) = Py_BuildValue("C", ros_message->@(field.name));
@[  elif field.type.type == 'byte']@
  py@(field.name) = PyBytes_FromStringAndSize((const char *)&ros_message->@(field.name), 1);
@[  elif field.type.type == 'string']@
  py@(field.name) = PyUnicode_FromString(ros_message->@(field.name).data);
@[  elif field.type.type == 'bool']@
  py@(field.name) = ros_message->@(field.name) ? Py_True : Py_False;
@[  elif field.type.type in ['float32', 'float64']]@
  py@(field.name) = PyFloat_FromDouble(ros_message->@(field.name));
@[  elif field.type.type in [
        'int8',
        'int16',
        'int32',
    ]]@
  py@(field.name) = PyLong_FromLong(ros_message->@(field.name));
@[  elif field.type.type in [
        'uint8',
        'uint16',
        'uint32',
    ]]@
  py@(field.name) = PyLong_FromUnsignedLong(ros_message->@(field.name));
@[  elif field.type.type == 'int64']@
  py@(field.name) = PyLong_FromLongLong(ros_message->@(field.name));
@[  elif field.type.type == 'uint64']@
  py@(field.name) = PyLong_FromUnsignedLongLong(ros_message->@(field.name));
@[  else]@
  assert(false);
@[  end if]@
  assert(py@(field.name) != NULL);
  Py_INCREF(py@(field.name));
  PyObject_SetAttrString(_pymessage, "@(field.name)", py@(field.name));
@[end for]@
  assert(_pymessage != NULL);
  return _pymessage;
}

// generated from rosidl_generator_py/resource/_msg_support.c.em
// generated code does not contain a copyright notice

#include <Python.h>

#include <@(spec.base_type.pkg_name)/@(subfolder)/@(module_name)__struct.h>
#include <@(spec.base_type.pkg_name)/@(subfolder)/@(module_name)__functions.h>

@{
have_not_included_primitive_arrays = True
have_not_included_string = True
nested_array_dict = {}
}@
@[for field in spec.fields]@
@[  if field.type.is_array and have_not_included_primitive_arrays]@
@{have_not_included_primitive_arrays = False}@
#include <rosidl_generator_c/primitives_array.h>
#include <rosidl_generator_c/primitives_array_functions.h>

@[  end if]@
@[  if field.type.type == 'string' and have_not_included_string]@
@{have_not_included_string = False}@
#include <rosidl_generator_c/string.h>
#include <rosidl_generator_c/string_functions.h>

@[  end if]@
@{
if not field.type.is_primitive_type() and field.type.is_array:
    if field.type.type not in nested_array_dict:
        nested_array_dict[field.type.type] = field.type.pkg_name
}@
@[end for]@
@[if nested_array_dict != {}]@
// Nested array functions includes
@[  for key in nested_array_dict]@
#include <@(nested_array_dict[key])/@(subfolder)/@convert_camel_case_to_lower_case_underscore(key)__functions.h>
@[  end for]@
// end nested array functions include
@[end if]@
@{
msg_typename = '%s__%s__%s' % (spec.base_type.pkg_name, subfolder, spec.base_type.type)
}@

void * @(spec.base_type.pkg_name)_@(module_name)__convert_from_py(PyObject * _pymsg)
{
  @(msg_typename) * ros_message = @(msg_typename)__create();
  (void)ros_message;
@{
full_classname = "@(spec.base_type.pkg_name).@(subfolder)._@(module_name).@(spec.base_type.type)"
}@
  char full_classname_dest[@(len(full_classname) + 1)];

  char * class_name = (char *)PyUnicode_1BYTE_DATA(
    PyObject_GetAttrString(PyObject_GetAttrString(_pymsg, "__class__"), "__name__"));
  char * module_name = (char *)PyUnicode_1BYTE_DATA(
    PyObject_GetAttrString(PyObject_GetAttrString(_pymsg, "__class__"), "__module__"));

  snprintf(full_classname_dest, sizeof(full_classname_dest), "%s.%s", class_name, module_name);

  // TODO(dirk-thomas) The check seems to be wrong, asserting that the strings are not equal?
  assert(strncmp(
      "@(spec.base_type.pkg_name).@(subfolder)._@(module_name).@(spec.base_type.type)",
      full_classname_dest, @(len(full_classname))));

@[for field in spec.fields]@
  PyObject * py@(field.name) = PyObject_GetAttrString(_pymsg, "@(field.name)");
@[  if not field.type.is_primitive_type()]@
@{
nested_type = '%s__%s__%s' % (field.type.pkg_name, 'msg', field.type.type)
}@
  PyObject * py@(field.name)_msg_module = PyImport_ImportModule("@(field.type.pkg_name).msg._@convert_camel_case_to_lower_case_underscore(field.type.type)");
  PyObject * py@(field.name)_msg_class = PyObject_GetAttrString(py@(field.name)_msg_module, "@(field.type.type)");
  PyObject * py@(field.name)_msg_metaclass = PyObject_GetAttrString(py@(field.name)_msg_class,"__class__");
  PyObject * py@(field.name)_convert_from_py = PyObject_GetAttrString(py@(field.name)_msg_metaclass, "_CONVERT_FROM_PY");
  typedef PyObject *(* convert_from_py_signature)(void *);
  convert_from_py_signature convert_from_py_@(field.name) = (convert_from_py_signature)PyCapsule_GetPointer(py@(field.name)_convert_from_py, NULL);
@[    if field.type.is_array]@
  assert(PySequence_Check(py@(field.name)));
  PyObject * seq@(field.name) = PySequence_Fast(py@(field.name), "expected a sequence");
  @(nested_type) * item@(field.name);
@[      if field.type.array_size is None or field.type.is_upper_bound]@
  size_t size@(field.name) = PySequence_Size(py@(field.name));
  if (!@(nested_type)__Array__init(&(ros_message->@(field.name)), size@(field.name))) {
    PyErr_SetString(PyExc_RuntimeError, "unable to create @(nested_type)__Array ros_message");
  }
  @(nested_type) * dest@(field.name) = ros_message->@(field.name).data;
@[      else]@
  size_t size@(field.name) = @(field.type.array_size);
  @(nested_type) * dest@(field.name) = ros_message->@(field.name);
@[      end if]@
  size_t idx@(field.name);
  for (idx@(field.name) = 0; idx@(field.name) < size@(field.name); idx@(field.name)++) {
    item@(field.name) = (@(nested_type) *) convert_from_py_@(field.name)(
      PySequence_Fast_GET_ITEM(seq@(field.name), idx@(field.name)));
    memcpy(&dest@(field.name)[idx@(field.name)], item@(field.name), sizeof(@(nested_type)));
  }
@[    else]@
  @(nested_type) * tmp@(field.name) = (@(nested_type) *) convert_from_py_@(field.name)(py@(field.name));
  ros_message->@(field.name) = *tmp@(field.name);
@[    end if]@
@[  elif field.type.is_array]@
  assert(PySequence_Check(py@(field.name)));
  PyObject * seq@(field.name) = PySequence_Fast(py@(field.name), "expected a sequence");
  PyObject * item@(field.name);
@[    if field.type.array_size is None or field.type.is_upper_bound]@
  size_t size@(field.name) = PySequence_Size(py@(field.name));
@[      if field.type.type == 'string']@
  if (!rosidl_generator_c__String__Array__init(&(ros_message->@(field.name)), size@(field.name))) {
    PyErr_SetString(PyExc_RuntimeError, "unable to create String__Array ros_message");
  }
@[      else]@
  if (!rosidl_generator_c__@(field.type.type)__Array__init(&(ros_message->@(field.name)), size@(field.name))) {
    PyErr_SetString(PyExc_RuntimeError, "unable to create @(field.type.type)__Array ros_message");
  }
@[      end if]@
  @primitive_msg_type_to_c(field.type.type) * dest@(field.name) = ros_message->@(field.name).data;
@[    else]@
  size_t size@(field.name) = @(field.type.array_size);
  @primitive_msg_type_to_c(field.type.type) * dest@(field.name) = ros_message->@(field.name);
@[    end if]@
@[    if field.type.type != 'string']@
  @primitive_msg_type_to_c(field.type.type) tmp@(field.name);
@[    end if]@
  size_t idx@(field.name);
  for (idx@(field.name) = 0; idx@(field.name) < size@(field.name); idx@(field.name)++) {
    item@(field.name) = PySequence_Fast_GET_ITEM(seq@(field.name), idx@(field.name));
@[    if field.type.type == 'char']@
    assert(PyUnicode_Check(item@(field.name)));
    tmp@(field.name) = PyUnicode_1BYTE_DATA(item@(field.name))[0];
@[    elif field.type.type == 'byte']@
    assert(PyBytes_Check(item@(field.name)));
    tmp@(field.name) = PyBytes_AS_STRING(item@(field.name))[0];
@[    elif field.type.type == 'string']@
    assert(PyUnicode_Check(item@(field.name)));
    rosidl_generator_c__String__assign(
      &dest@(field.name)[idx@(field.name)], (char *)PyUnicode_1BYTE_DATA(item@(field.name)));
@[    elif field.type.type == 'bool']@
    assert(PyBool_Check(item@(field.name)));
    tmp@(field.name) = (item@(field.name) == Py_True);
@[    elif field.type.type in ['float32', 'float64']]@
    assert(PyFloat_Check(item@(field.name)));
@[      if field.type.type == 'float32']@
    tmp@(field.name) = (float)PyFloat_AS_DOUBLE(item@(field.name));
@[      else]@
    tmp@(field.name) = PyFloat_AS_DOUBLE(item@(field.name));
@[      end if]@
@[    elif field.type.type in [
        'int8',
        'int16',
        'int32',
    ]]@
    assert(PyLong_Check(item@(field.name)));
    tmp@(field.name) = (@(primitive_msg_type_to_c(field.type.type)))PyLong_AsLong(item@(field.name));
@[    elif field.type.type in [
        'uint8',
        'uint16',
        'uint32',
    ]]@
    assert(PyLong_Check(item@(field.name)));
@[      if field.type.type == 'uint32']@
    tmp@(field.name) = PyLong_AsUnsignedLong(item@(field.name));
@[      else]@
    tmp@(field.name) = (@(primitive_msg_type_to_c(field.type.type)))PyLong_AsUnsignedLong(item@(field.name));
@[      end if]
@[    elif field.type.type == 'int64']@
    assert(PyLong_Check(item@(field.name)));
    tmp@(field.name) = PyLong_AsLongLong(item@(field.name));
@[    elif field.type.type == 'uint64']@
    assert(PyLong_Check(item@(field.name)));
    tmp@(field.name) = PyLong_AsUnsignedLongLong(item@(field.name));
@[    end if]@
@[    if field.type.type != 'string']@
    memcpy(&dest@(field.name)[idx@(field.name)], &tmp@(field.name), sizeof(@primitive_msg_type_to_c(field.type.type)));
@[    end if]@
  }
@[  elif field.type.type == 'char']@
  assert(PyUnicode_Check(py@(field.name)));
  ros_message->@(field.name) = PyUnicode_1BYTE_DATA(py@(field.name))[0];
@[  elif field.type.type == 'byte']@
  assert(PyBytes_Check(py@(field.name)));
  ros_message->@(field.name) = PyBytes_AS_STRING(py@(field.name))[0];
@[  elif field.type.type == 'string']@
  assert(PyUnicode_Check(py@(field.name)));
  rosidl_generator_c__String__assign(
    &ros_message->@(field.name), (char *)PyUnicode_1BYTE_DATA(py@(field.name)));
@[  elif field.type.type == 'bool']@
  assert(PyBool_Check(py@(field.name)));
  ros_message->@(field.name) = (Py_True == py@(field.name));
@[  elif field.type.type in ['float32', 'float64']]@
  assert(PyFloat_Check(py@(field.name)));
@[    if field.type.type == 'float32']@
  ros_message->@(field.name) = (float)PyFloat_AS_DOUBLE(py@(field.name));
@[    else]@
  ros_message->@(field.name) = PyFloat_AS_DOUBLE(py@(field.name));
@[    end if]@
@[  elif field.type.type in [
        'int8',
        'int16',
        'int32',
    ]]@
  assert(PyLong_Check(py@(field.name)));
  ros_message->@(field.name) = (@(primitive_msg_type_to_c(field.type.type)))PyLong_AsLong(py@(field.name));
@[  elif field.type.type in [
        'uint8',
        'uint16',
        'uint32',
    ]]@
  assert(PyLong_Check(py@(field.name)));
@[    if field.type.type == 'uint32']@
  ros_message->@(field.name) = PyLong_AsUnsignedLong(py@(field.name));
@[    else]@
  ros_message->@(field.name) = (@(primitive_msg_type_to_c(field.type.type)))PyLong_AsUnsignedLong(py@(field.name));
@[    end if]@
@[  elif field.type.type == 'int64']@
  assert(PyLong_Check(py@(field.name)));
  ros_message->@(field.name) = PyLong_AsLongLong(py@(field.name));
@[  elif field.type.type == 'uint64']@
  assert(PyLong_Check(py@(field.name)));
  ros_message->@(field.name) = PyLong_AsUnsignedLongLong(py@(field.name));
@[  else]@
  assert(false);
@[  end if]@
@[end for]@

  assert(ros_message != NULL);
  return ros_message;
}

PyObject * @(spec.base_type.pkg_name)_@(module_name)__convert_to_py(void * raw_ros_message)
{
  @(msg_typename) * ros_message = (@(msg_typename) *)raw_ros_message;
  (void)ros_message;

  PyObject * pymessage_module = PyImport_ImportModule("@(spec.base_type.pkg_name).@(subfolder)._@(module_name)");
  PyObject * pymessage_class = PyObject_GetAttrString(pymessage_module, "@(spec.base_type.type)");

  /* NOTE(esteve): Call constructor of @(spec.base_type.type) */
  PyObject * _pymessage = NULL;
  _pymessage = PyObject_CallObject(pymessage_class, NULL);
  assert(_pymessage != NULL);

@[for field in spec.fields]@
  PyObject * py@(field.name) = NULL;
@[  if not field.type.is_primitive_type()]@
@{
nested_type = '%s__%s__%s' % (field.type.pkg_name, 'msg', field.type.type)
}@
  PyObject * py@(field.name)_msg_module = PyImport_ImportModule("@(field.type.pkg_name).msg._@convert_camel_case_to_lower_case_underscore(field.type.type)");
  PyObject * py@(field.name)_msg_class = PyObject_GetAttrString(py@(field.name)_msg_module, "@(field.type.type)");
  PyObject * py@(field.name)_msg_metaclass = PyObject_GetAttrString(py@(field.name)_msg_class,"__class__");
  PyObject * py@(field.name)_convert_to_py = PyObject_GetAttrString(py@(field.name)_msg_metaclass, "_CONVERT_TO_PY");
  typedef PyObject *(* convert_to_py_signature)(void *);
  convert_to_py_signature convert_to_py_@(field.name) = (convert_to_py_signature)PyCapsule_GetPointer(py@(field.name)_convert_to_py, NULL);
@[    if field.type.is_array]@
@[      if field.type.array_size is None or field.type.is_upper_bound]@
  size_t size@(field.name) = ros_message->@(field.name).size;
@[      else]@
  size_t size@(field.name) = @(field.type.array_size);
@[      end if]@
  py@(field.name) = PyList_New(size@(field.name));
  @(nested_type) item@(field.name);
  size_t idx@(field.name);
  for (idx@(field.name) = 0; idx@(field.name) < size@(field.name); idx@(field.name)++) {
@[      if field.type.array_size is None or field.type.is_upper_bound]@
    item@(field.name) = ros_message->@(field.name).data[idx@(field.name)];
@[      else]@
    item@(field.name) = ros_message->@(field.name)[idx@(field.name)];
@[      end if]@
    PyList_SetItem(py@(field.name), idx@(field.name), convert_to_py_@(field.name)(&item@(field.name)));
  }
  assert(PySequence_Check(py@(field.name)));
@[    else]@
  @(nested_type) pytmp@(field.name) = ros_message->@(field.name);
  py@(field.name) = convert_to_py_@(field.name)(&pytmp@(field.name));
@[    end if]@
@[  elif field.type.is_array]@
@[    if field.type.array_size is None or field.type.is_upper_bound]@
  size_t size@(field.name) = ros_message->@(field.name).size;
  @primitive_msg_type_to_c(field.type.type) * tmpmessagedata@(field.name) = ros_message->@(field.name).data;
@[    else]@
  size_t size@(field.name) = @(field.type.array_size);
  @primitive_msg_type_to_c(field.type.type) * tmpmessagedata@(field.name) = ros_message->@(field.name);
@[    end if]@
  py@(field.name) = PyList_New(size@(field.name));
  size_t idx@(field.name);
  for (idx@(field.name) = 0; idx@(field.name) < size@(field.name); idx@(field.name)++) {
@[    if field.type.type == 'char']@
    PyList_SetItem(py@(field.name), idx@(field.name),
      Py_BuildValue("C", tmpmessagedata@(field.name)[idx@(field.name)]));
@[    elif field.type.type == 'byte']@
    PyList_SetItem(py@(field.name), idx@(field.name),
      PyBytes_FromStringAndSize((const char *)&tmpmessagedata@(field.name)[idx@(field.name)], 1));
@[    elif field.type.type == 'string']@
    PyList_SetItem(py@(field.name), idx@(field.name), PyUnicode_FromString(tmpmessagedata@(field.name)[idx@(field.name)].data));
@[    elif field.type.type == 'bool']@
    PyList_SetItem(py@(field.name), idx@(field.name), tmpmessagedata@(field.name)[idx@(field.name)] ? Py_True : Py_False);
@[    elif field.type.type in ['float32', 'float64']]@
    PyList_SetItem(py@(field.name), idx@(field.name), PyFloat_FromDouble(tmpmessagedata@(field.name)[idx@(field.name)]));
@[    elif field.type.type in [
        'int8',
        'int16',
        'int32',
    ]]@
    PyList_SetItem(py@(field.name), idx@(field.name), PyLong_FromLong(tmpmessagedata@(field.name)[idx@(field.name)]));
@[    elif field.type.type in [
        'uint8',
        'uint16',
        'uint32',
    ]]@
    PyList_SetItem(py@(field.name), idx@(field.name), PyLong_FromUnsignedLong(tmpmessagedata@(field.name)[idx@(field.name)]));
@[    elif field.type.type == 'int64']@
    PyList_SetItem(py@(field.name), idx@(field.name), PyLong_FromLongLong(tmpmessagedata@(field.name)[idx@(field.name)]));
@[    elif field.type.type == 'uint64']@
    PyList_SetItem(py@(field.name), idx@(field.name), PyLong_FromUnsignedLongLong(tmpmessagedata@(field.name)[idx@(field.name)]));
@[    end if]@
  }
  assert(PySequence_Check(py@(field.name)));
@[  elif field.type.type == 'char']@
  py@(field.name) = Py_BuildValue("C", ros_message->@(field.name));
@[  elif field.type.type == 'byte']@
  py@(field.name) = PyBytes_FromStringAndSize((const char *)&ros_message->@(field.name), 1);
@[  elif field.type.type == 'string']@
  py@(field.name) = PyUnicode_FromString(ros_message->@(field.name).data);
@[  elif field.type.type == 'bool']@
  py@(field.name) = ros_message->@(field.name) ? Py_True : Py_False;
@[  elif field.type.type in ['float32', 'float64']]@
  py@(field.name) = PyFloat_FromDouble(ros_message->@(field.name));
@[  elif field.type.type in [
        'int8',
        'int16',
        'int32',
    ]]@
  py@(field.name) = PyLong_FromLong(ros_message->@(field.name));
@[  elif field.type.type in [
        'uint8',
        'uint16',
        'uint32',
    ]]@
  py@(field.name) = PyLong_FromUnsignedLong(ros_message->@(field.name));
@[  elif field.type.type == 'int64']@
  py@(field.name) = PyLong_FromLongLong(ros_message->@(field.name));
@[  elif field.type.type == 'uint64']@
  py@(field.name) = PyLong_FromUnsignedLongLong(ros_message->@(field.name));
@[  else]@
  assert(false);
@[  end if]@
  assert(py@(field.name) != NULL);
  Py_INCREF(py@(field.name));
  PyObject_SetAttrString(_pymessage, "@(field.name)", py@(field.name));
@[end for]@
  assert(_pymessage != NULL);
  return _pymessage;
}


use galactic for source image

use galactic for source image

Signed-off-by: Mikael Arguedas <a16f295d1139a1392bb19262902c32cf3e999ce4@gmail.com>

%YAML 1.1
# ROS2 Dockerfile database
---
images:
    devel:
        base_image: @(os_name):@(os_code_name)
        maintainer_name: @(maintainer_name)
        template_name: docker_images_ros2/devel/create_ros_image.Dockerfile.em
        entrypoint_name: docker_images_ros2/devel/ros_entrypoint.sh
        template_packages:
            - docker_templates
        upstream_packages:
            - bash-completion
        pip3_install:
            - argcomplete
            - flake8
            - flake8-blind-except
            - flake8-builtins
            - flake8-class-newline
            - flake8-comprehensions
            - flake8-deprecated
            - flake8-docstrings
            - flake8-import-order
            - flake8-quotes
            - pytest-repeat
            - pytest-rerunfailures
        ws: /opt/ros2_ws
    source:
        maintainer_name: @(maintainer_name)
        template_name: docker_images_ros2/source/create_ros_image.Dockerfile.em
        template_packages:
            - docker_templates
        upstream_packages:
            - libasio-dev
            - libssl-dev
            - libtinyxml2-dev
        ros2_distro: galactic
        ws: /opt/ros2_ws
        colcon_args:
            - build
            - --symlink-install
            - --mixin
                build-testing-on
                release
            - --cmake-args
                --no-warn-unused-cli
        rosdep:
            install:
                - --from-paths src
                - --ignore-src
                - --skip-keys "console_bridge fastcdr fastrtps libopensplice69 rti-connext-dds-5.3.1 urdfdom_headers"
        vcs:
            imports:
                repos:

%YAML 1.1
# ROS2 Dockerfile database
---
images:
    devel:
        base_image: @(os_name):@(os_code_name)
        maintainer_name: @(maintainer_name)
        template_name: docker_images_ros2/devel/create_ros_image.Dockerfile.em
        entrypoint_name: docker_images_ros2/devel/ros_entrypoint.sh
        template_packages:
            - docker_templates
        upstream_packages:
            - bash-completion
        pip3_install:
            - argcomplete
            - flake8
            - flake8-blind-except
            - flake8-builtins
            - flake8-class-newline
            - flake8-comprehensions
            - flake8-deprecated
            - flake8-docstrings
            - flake8-import-order
            - flake8-quotes
            - pytest-repeat
            - pytest-rerunfailures
        ws: /opt/ros2_ws
    source:
        maintainer_name: @(maintainer_name)
        template_name: docker_images_ros2/source/create_ros_image.Dockerfile.em
        template_packages:
            - docker_templates
        upstream_packages:
            - libasio-dev
            - libssl-dev
            - libtinyxml2-dev
        ros2_distro: foxy
        ws: /opt/ros2_ws
        colcon_args:
            - build
            - --symlink-install
            - --mixin
                build-testing-on
                release
            - --cmake-args
                --no-warn-unused-cli
        rosdep:
            install:
                - --from-paths src
                - --ignore-src
                - --skip-keys "console_bridge fastcdr fastrtps libopensplice69 rti-connext-dds-5.3.1 urdfdom_headers"
        vcs:
            imports:
                repos:


fix legacy

fix legacy

@(TEMPLATE(
    'snippet/add_generated_comment.Dockerfile.em',
    user_name=user_name,
    tag_name=tag_name,
    source_template_name=template_name,
))@
@(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_name=maintainer_name,
))@

@(TEMPLATE(
    'snippet/old_release_set.Dockerfile.em',
    template_packages=template_packages,
    os_name=os_name,
    os_code_name=os_code_name,
))@

@[if 'packages' in locals()]@
@[  if packages]@

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

@[  end if]@
@[end if]@
@
@(TEMPLATE(
    'snippet/setup_ros_sources.Dockerfile.em',
    os_name=os_name,
    os_code_name=os_code_name,
    rosdistro_name=rosdistro_name,
    ros_version=ros_version,
))@

# setup environment
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8

# install ros packages
ENV ROS_DISTRO @rosdistro_name
RUN apt-get update && apt-get install -y \
    @(' \\\n    '.join('{name}{version}'.format(**p) for p in ros_packages))@  \
    && rm -rf /var/lib/apt/lists/* \
    && mkdir /var/lib/apt/lists/partial

@[if 'entrypoint_name' in locals()]@
@[  if entrypoint_name]@
@{
entrypoint_file = entrypoint_name.split('/')[-1]
}@
# setup entrypoint
COPY ./@entrypoint_file /ros_entrypoint.sh

ENTRYPOINT ["/ros_entrypoint.sh"]
@[  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,
))@
@(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_name=maintainer_name,
))@

@(TEMPLATE(
    'snippet/old_release_set.Dockerfile.em',
    template_packages=template_packages,
    os_name=os_name,
    os_code_name=os_code_name,
))@

@[if 'packages' in locals()]@
@[  if packages]@

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

@[  end if]@
@[end if]@
@
@(TEMPLATE(
    'snippet/setup_ros_sources.Dockerfile.em',
    os_name=os_name,
    os_code_name=os_code_name,
    rosdistro_name=rosdistro_name,
    ros_version=ros_version,
))@

# setup environment
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8

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

@[if 'entrypoint_name' in locals()]@
@[  if entrypoint_name]@
@{
entrypoint_file = entrypoint_name.split('/')[-1]
}@
# setup entrypoint
COPY ./@entrypoint_file /ros_entrypoint.sh

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


update print statements in sample template

#! $Id: //projects/empy/sample.em#50 $ $Date: 2003/10/27 $
@# Bangpaths are handled properly (the above line will not appear).
#! This line however will appear (not the first line in the script).
@# This is a comment.  This should not appear in the processed output.
This is text.  It should appear in the processed output.
This is a literal at sign: @@.
This is a line continuation; @
this will appear on the same line.
Note that it will actually eat any white@ space (one word).
@{
# The em.py script has to be somewhere in sys.path!
import em
}@

@# Escape codes.
This will appear on one line.@\nThis will appear on a separate line.
This is separated by a tab:@\tSee?
These are uppercase As (presuming ASCII): A, @\q1001, @\o101, @\d065, @\x41.
@{
import sys
# This is just a normal Python comment.
print("This is more text.")
}@
@# Note the @{ ... }@ convention to suppress the newline following the }.
@# Also note that comments are completely tossed: This is not expanded: @(x).

@# The basics.
@{
import sys, math, string
x = 4
s = 'alpha'
word = "book"
l = [3, 2, 1]
def square(n):
    return n**2
friends = ['Albert', 'Betty', 'Charles', 'Donald']
}@
The basics: The square of @(x) is @(x**2), or @(square(x)).
Internal whitespace is fine: @( x ) squared is @( square(x) ).
Statements: @{sys.stdout.write("%d**2 = %d" % (x, square(x)))}.
Whitespace too: @{ sys.stdout.write("%d**2 = %d (still)" % (x, square(x))) }.
@{
print("But only on single-line statement expansions.")
if 1:
    print("Internal whitespace on multi-line statements is significant.")
for i in range(2):
    print("Normal Python indentation rules must be followed here.")
}@
Simple expressions: x is @x, l is @l, s is "@s," and @x squared is @square(x).
Literals too: x is @x, but would be written @@x.
Trailing dots are ignored: The value of x is @x.
Quotes outside of expansions are also ignored: This is quoted: "x is @x."
@# Whitespace is important in simple expressions.
Array subscription: The first element of l is @l[0].
But this is not: The first element of l is not @l [0].
That was equivalent to: @(l) and then [0], not @l[0].
But whitespace can go inside the brackets: @l[0] is @l[ 0 ].
Same with functions: @square(x) is @square( x ).
The same applies to the other forms.
Involved: The legal digits are @string.digits.
More involved: The names of my friends are @string.join(friends, ', ').
Following expressions: Pluralize "@word" as "@(word)s," or maybe "@word@ s."
By default str is used (@s), but you can use repr if you want (@`s`).
Conditional expressions: @(x ? "x is true" ! "x is false").
Pluralization: How many words? @x word@(x != 1 ? 's').
Protected expressions: @(foo $ "foo is not defined").
Also here, whitespace isn't important: @(bar$"bar isn't defined either").
The math module has @(math ? "been imported" $ "not been imported").
The re module has @(re ? "been imported" $ "not been imported").
Division by zero is @(x/0 $ "illegal").
To swallow errors, use None: @(buh $ None) [two spaces].
This is self-expanding: @:2 + 2:(this will get replaced with 4):
You can expand multiple times: @
@empy.expand("@empy.expand('@:2 + 2:hugalugahglughalug:')")

@# More complex examples, including classes.
@{
class C:
    def __init__(self, name):
        self.name = name

    def greetString(self):
        return "Hello, %s" % self.name

    def printGreeting(self):
        sys.stdout.write("Hello, %s" % self.name) # implicit None return

c = C("empy")
}@
c's class is @c.__class__.__name__.
c's name is @c.name.
Method call: @c.greetString().
Note that None is not expanded: @(None) [two spaces].
But the string 'None' is, of course, printed fine: @('None').
So a function can return None for side effects only: @c.printGreeting().

@# Control.
@{
a = 5 # something positive
b = -3 # something negative
z = 0 # zero
}@
If: a is @[if a > 0]positive@[end if].
If/else: b is @[if b > 0]positive@[else]negative@[end if].
If/elif/else: cmp(a, b) is @
@[if a < b]negative@[elif a > b]positive@[else]zero@[end if].
Numbers:@
@[for i in range(10)] @i@[end for].
Evens:@
@[for i in range(10)]@[if i % 2 == 1]@[continue]@[end if] @i@[end for].
Integers less than 5:@
@[for i in range(10)]@[if i >= 5]@[break]@[end if] @i@[end for].
Countdown:@
@{j = 10}@[while j >= 0] @j@{j = j - 1}@[end while].
While/else: @[while z]shouldn't get here@[else]works@[end while].
For/else:@
@[for i in range(3)] @i@[else] also works@[end for].
Tuple unpacking:@[for x in [1, 2, 3, 4]] <@x>@[end for].
Tuple unpacking:@[for x, in [[1], [2], [3], [4]]] <@x>@[end for].
Tuple unpacking:@[for (x,) in [[1], [2], [3], [4]]] <@x>@[end for].
Tuple unpacking:@[for x, y in [[1, 2], [3, 4]]] <@x, @y>@[end for].
Tuple unpacking:@[for (x), (y) in [[1, 2], [3, 4]]] <@x, @y>@[end for].
Tuple unpacking:@[for (x, y) in [[1, 2], [3, 4]]] <@x, @y>@[end for].
Tuple unpacking:@[for x, (y) in [[1, 2], [3, 4]]] <@x, @y>@[end for].
Tuple unpacking:@[for x, (y,) in [[1, [2]], [3, [4]]]] <@x, @y>@[end for].
Tuple unpacking:@[for (x), y in [[1, 2], [3, 4]]] <@x, @y>@[end for].
Tuple unpacking:@[for (x,), y in [[[1], 2], [[3], 4]]] <@x, @y>@[end for].
Tuple unpacking:@[for (x,), (y,) in [[[1], [2]], [[3], [4]]]] <@x, @y>@[end for].
More tuple unpacking:@[for (((x))), ((y),) in [[1, [2]], [3, [4]]]] <@x, @y>@[end for].
Garbage is @[try]@hglhagulahguha@[except NameError]not defined@[end try].
Division by zero is @[try]@(a/z)@[except ZeroDivisionError]illegal@[end try].
Catch all: @[try]@ghlaghlhagl@[except]something happened@[end try].
Finally works: @
@[try]@[try]@(1/0)@[finally]finally, @[end try]@[except]and caught@[end try].
@[def sign(x)]@x is @[if x > 0]positive@[elif x < 0]negative@[else]zero@[end if]@[end def]@
Define: @sign(a), @sign(b), @sign(z).

@# Diversions.  Again, a trailing @ is used to suppress the following newline.
A. This text is undiverted.
@empy.startDiversion(1)@
C. This text is diverted.
@empy.stopDiverting()@
B. This text is also undiverted.
@empy.playDiversion(1)@
D. Again, this text is undiverted.
@empy.startDiversion('a')@
E. This text is diverted and then undiverted@
@empy.stopDiverting()@
@empy.replayDiversion('a').
@empy.playDiversion('a') (this should appear twice).
@empy.startDiversion('q')@
F. This text is diverted and then cancelled.
@empy.playDiversion('q')@
G. This text is again undiverted.
@empy.startDiversion('x')@
X. This text will be purged and should not appear!
@empy.stopDiverting()@
H. There should be one remaining diversion: @empy.getAllDiversions().
@empy.purgeDiversion('x')@
I. But not after purging it: @empy.getAllDiversions().
@{
# Finally, make a manual diversion and manipulate it.
empy.createDiversion('z')
zDiversion = empy.retrieveDiversion('z')
zDiversion.write("J. This should be the final diversion, created manually.\n")
empy.playDiversion('z')
}@

@# Parsing checks.
Blanks: @(''), @(""), @(''''''), @("""""").
Single quotes: @('\''), @("'"), @("""'""").
Double quotes: @("\""), @('"'), @('''"''').
Triple quotes: @("\"\"\""), @('"""'), @('\'\'\''), @("'''").
Quotes surrounded by spaces: @(""" " """), @(''' ' ''').
At signs: @('@'), @("@"), @('''@'''), @("""@""").
Close parentheses: @(')'), @(")"), @((")")), @((')')).
Close parentheses in quotes: @("')'"), @('\')\'').
Close braces with an intervening space: @
@{sys.stdout.write("}")} @{sys.stdout.write('}')}.
Repr of a backquote: @`'`'`.
Exes: @("?"?'x'), @(0?"!"!'x'), @(0?":":'x'), @("]"?'x'), @(1?"x"!"]").
Dollar signs: @("$"$None), @(asdf?"$"$"$"), @(1?asdf$"$").
These are strings:
@'single quoted string'
@"double quoted string"
@'single quoted string with escaped \'single quotes\''
@"double quoted string with escaped \"double quotes\""
@'''triple single quoted string'''
@"""triple double quoted string"""
@'single quoted string with "double quotes"'
@"double quoted string with 'single quotes'"
@'''triple single quoted continued \
string'''
@"""triple double quoted continued \
string"""
@'''triple single quoted
...multi-line string'''
@"""triple double quoted
... multi-line string"""

@# Significators.
@%a
@%b
@%c "x"
@%d "x"
@%e "x y"
@%f "x y"
Encountered significators:
a and b should be None: @`__a__`, @`__b__`
c and d should be 'x': @`__c__`, @`__d__`
e and f should be 'x y': @`__e__`, @`__f__`

@# Filters.
@{import string}@
This line should be in mixed case.
@empy.setFilter(string.lower)@
This line should be all lowercase.
@empy.setFilter(string.upper)@
This line should be all uppercase (how gauche).
@empy.setFilter([em.LineBufferedFilter(), lambda x: '[%s]\n' % x[:-1]])@
This line should be bracketed.
So should this line.
@empy.setFilter([em.SizeBufferedFilter(5), lambda x: '*' + x])@
There should be stars every five characters on this line.
@empy.nullFilter()@
This line should not appear at all!
@empy.resetFilter()@
This line should be back to mixed case.
@empy.attachFilter(string.upper)@
@empy.attachFilter(em.LineBufferedFilter())@
@empy.attachFilter(lambda x: '[%s]\n' % x[:-1])@
This line should be all uppercase with brackets.
@empy.resetFilter()@
This line should be back to mixed case (again).

@# Contexts, metaoperations.
@{
import StringIO
def context():
    return "%s:%d" % empy.identify()
stringFile = StringIO.StringIO("2 + 2 = @(2 + 2) [@context()].\n")
}@
The new context is @context().
File inclusion [@context()]: @empy.include(stringFile)@
Expansion [@context()]: @
@empy.expand("This should be appear [@context()]") @
on the same line as this [@context()].
More expansion [@context()]: @
@{sys.stdout.write(empy.expand("Another expansion [@context()]"))}.
This is the next line [@context()].
Quoting: @empy.quote("x when quoted would be '@x' or @x").
More quoting: @empy.quote("This will be @doubled but '''@this is not'''").
Here's the last view of the old context: @context().
Creating a new context ...
@empy.pushContext()@
The current context is: @context().
@?NewName
The context name should now be 'NewName': @context().
@!1000
The line number should now be 1000: @context().
@empy.popContext()@
Back to the old context: @context().

@# Embedded interpreters and standalone expansion.
@{
q = 1
}@
Interpreter's q is @q.
@{
try:
    i = em.Interpreter()
    i.string("@{q = 10}")
    i.string("Embedded interpreter's q is @q.\n")
finally:
    i.shutdown()
}@
Interpreter's q is still @q; the embedded interpreter had no effect.
Standalone expansion: @em.expand("1 + 1 is @(1 + 1).")
With locals: @em.expand("@x + @y is @(x + y).", x=2, y=3)
@{
g = {}
}@
With globals: @em.expand("@{x = 10}g's x is @x.", g)
Still with globals: @em.expand("g's x + 1 is @(x + 1).", g)
g's x is still @g['x'].

@# Hooks.
@{
class SampleHook(em.Hook):
    def null(self):
        self.interpreter.write('[SampleHook.null invoked]')

sampleHook = SampleHook()
empy.addHook(sampleHook)
}@
Invoking the sample hook: @empy.invokeHook('null').
@{
empy.removeHook(sampleHook)
}@

@# Custom.
@{
def customCallback(contents, empy=empy):
    empy.write('[%s]' % contents)
empy.registerCallback(customCallback)
}@
Using a custom markup: @<This appears in brackets>.
Again: @<<There are angle brackets in this one>>.
Once more: @<This is a right angle bracket in quotes: ">">.
@{
empy.deregisterCallback()
}@

@# Finals; note these are evaluated in reverse order.
@empy.atExit(lambda: empy.string("Version: @empy.VERSION.\n"))@
@empy.atExit(lambda: empy.write("This is the penultimate line.\n"))@

#! $Id: //projects/empy/sample.em#50 $ $Date: 2003/10/27 $
@# Bangpaths are handled properly (the above line will not appear).
#! This line however will appear (not the first line in the script).
@# This is a comment.  This should not appear in the processed output.
This is text.  It should appear in the processed output.
This is a literal at sign: @@.
This is a line continuation; @
this will appear on the same line.
Note that it will actually eat any white@ space (one word).
@{
# The em.py script has to be somewhere in sys.path!
import em
}@

@# Escape codes.
This will appear on one line.@\nThis will appear on a separate line.
This is separated by a tab:@\tSee?
These are uppercase As (presuming ASCII): A, @\q1001, @\o101, @\d065, @\x41.
@{
import sys
# This is just a normal Python comment.
print "This is more text."
}@
@# Note the @{ ... }@ convention to suppress the newline following the }.
@# Also note that comments are completely tossed: This is not expanded: @(x).

@# The basics.
@{
import sys, math, string
x = 4
s = 'alpha'
word = "book"
l = [3, 2, 1]
def square(n):
    return n**2
friends = ['Albert', 'Betty', 'Charles', 'Donald']
}@
The basics: The square of @(x) is @(x**2), or @(square(x)).
Internal whitespace is fine: @( x ) squared is @( square(x) ).
Statements: @{sys.stdout.write("%d**2 = %d" % (x, square(x)))}.
Whitespace too: @{ sys.stdout.write("%d**2 = %d (still)" % (x, square(x))) }.
@{
print "But only on single-line statement expansions."
if 1:
    print "Internal whitespace on multi-line statements is significant."
for i in range(2):
    print "Normal Python indentation rules must be followed here."
}@
Simple expressions: x is @x, l is @l, s is "@s," and @x squared is @square(x).
Literals too: x is @x, but would be written @@x.
Trailing dots are ignored: The value of x is @x.
Quotes outside of expansions are also ignored: This is quoted: "x is @x."
@# Whitespace is important in simple expressions.
Array subscription: The first element of l is @l[0].
But this is not: The first element of l is not @l [0].
That was equivalent to: @(l) and then [0], not @l[0].
But whitespace can go inside the brackets: @l[0] is @l[ 0 ].
Same with functions: @square(x) is @square( x ).
The same applies to the other forms.
Involved: The legal digits are @string.digits.
More involved: The names of my friends are @string.join(friends, ', ').
Following expressions: Pluralize "@word" as "@(word)s," or maybe "@word@ s."
By default str is used (@s), but you can use repr if you want (@`s`).
Conditional expressions: @(x ? "x is true" ! "x is false").
Pluralization: How many words? @x word@(x != 1 ? 's').
Protected expressions: @(foo $ "foo is not defined").
Also here, whitespace isn't important: @(bar$"bar isn't defined either").
The math module has @(math ? "been imported" $ "not been imported").
The re module has @(re ? "been imported" $ "not been imported").
Division by zero is @(x/0 $ "illegal").
To swallow errors, use None: @(buh $ None) [two spaces].
This is self-expanding: @:2 + 2:(this will get replaced with 4):
You can expand multiple times: @
@empy.expand("@empy.expand('@:2 + 2:hugalugahglughalug:')")

@# More complex examples, including classes.
@{
class C:
    def __init__(self, name):
        self.name = name

    def greetString(self):
        return "Hello, %s" % self.name

    def printGreeting(self):
        sys.stdout.write("Hello, %s" % self.name) # implicit None return

c = C("empy")
}@
c's class is @c.__class__.__name__.
c's name is @c.name.
Method call: @c.greetString().
Note that None is not expanded: @(None) [two spaces].
But the string 'None' is, of course, printed fine: @('None').
So a function can return None for side effects only: @c.printGreeting().

@# Control.
@{
a = 5 # something positive
b = -3 # something negative
z = 0 # zero
}@
If: a is @[if a > 0]positive@[end if].
If/else: b is @[if b > 0]positive@[else]negative@[end if].
If/elif/else: cmp(a, b) is @
@[if a < b]negative@[elif a > b]positive@[else]zero@[end if].
Numbers:@
@[for i in range(10)] @i@[end for].
Evens:@
@[for i in range(10)]@[if i % 2 == 1]@[continue]@[end if] @i@[end for].
Integers less than 5:@
@[for i in range(10)]@[if i >= 5]@[break]@[end if] @i@[end for].
Countdown:@
@{j = 10}@[while j >= 0] @j@{j = j - 1}@[end while].
While/else: @[while z]shouldn't get here@[else]works@[end while].
For/else:@
@[for i in range(3)] @i@[else] also works@[end for].
Tuple unpacking:@[for x in [1, 2, 3, 4]] <@x>@[end for].
Tuple unpacking:@[for x, in [[1], [2], [3], [4]]] <@x>@[end for].
Tuple unpacking:@[for (x,) in [[1], [2], [3], [4]]] <@x>@[end for].
Tuple unpacking:@[for x, y in [[1, 2], [3, 4]]] <@x, @y>@[end for].
Tuple unpacking:@[for (x), (y) in [[1, 2], [3, 4]]] <@x, @y>@[end for].
Tuple unpacking:@[for (x, y) in [[1, 2], [3, 4]]] <@x, @y>@[end for].
Tuple unpacking:@[for x, (y) in [[1, 2], [3, 4]]] <@x, @y>@[end for].
Tuple unpacking:@[for x, (y,) in [[1, [2]], [3, [4]]]] <@x, @y>@[end for].
Tuple unpacking:@[for (x), y in [[1, 2], [3, 4]]] <@x, @y>@[end for].
Tuple unpacking:@[for (x,), y in [[[1], 2], [[3], 4]]] <@x, @y>@[end for].
Tuple unpacking:@[for (x,), (y,) in [[[1], [2]], [[3], [4]]]] <@x, @y>@[end for].
More tuple unpacking:@[for (((x))), ((y),) in [[1, [2]], [3, [4]]]] <@x, @y>@[end for].
Garbage is @[try]@hglhagulahguha@[except NameError]not defined@[end try].
Division by zero is @[try]@(a/z)@[except ZeroDivisionError]illegal@[end try].
Catch all: @[try]@ghlaghlhagl@[except]something happened@[end try].
Finally works: @
@[try]@[try]@(1/0)@[finally]finally, @[end try]@[except]and caught@[end try].
@[def sign(x)]@x is @[if x > 0]positive@[elif x < 0]negative@[else]zero@[end if]@[end def]@
Define: @sign(a), @sign(b), @sign(z).

@# Diversions.  Again, a trailing @ is used to suppress the following newline.
A. This text is undiverted.
@empy.startDiversion(1)@
C. This text is diverted.
@empy.stopDiverting()@
B. This text is also undiverted.
@empy.playDiversion(1)@
D. Again, this text is undiverted.
@empy.startDiversion('a')@
E. This text is diverted and then undiverted@
@empy.stopDiverting()@
@empy.replayDiversion('a').
@empy.playDiversion('a') (this should appear twice).
@empy.startDiversion('q')@
F. This text is diverted and then cancelled.
@empy.playDiversion('q')@
G. This text is again undiverted.
@empy.startDiversion('x')@
X. This text will be purged and should not appear!
@empy.stopDiverting()@
H. There should be one remaining diversion: @empy.getAllDiversions().
@empy.purgeDiversion('x')@
I. But not after purging it: @empy.getAllDiversions().
@{
# Finally, make a manual diversion and manipulate it.
empy.createDiversion('z')
zDiversion = empy.retrieveDiversion('z')
zDiversion.write("J. This should be the final diversion, created manually.\n")
empy.playDiversion('z')
}@

@# Parsing checks.
Blanks: @(''), @(""), @(''''''), @("""""").
Single quotes: @('\''), @("'"), @("""'""").
Double quotes: @("\""), @('"'), @('''"''').
Triple quotes: @("\"\"\""), @('"""'), @('\'\'\''), @("'''").
Quotes surrounded by spaces: @(""" " """), @(''' ' ''').
At signs: @('@'), @("@"), @('''@'''), @("""@""").
Close parentheses: @(')'), @(")"), @((")")), @((')')).
Close parentheses in quotes: @("')'"), @('\')\'').
Close braces with an intervening space: @
@{sys.stdout.write("}")} @{sys.stdout.write('}')}.
Repr of a backquote: @`'`'`.
Exes: @("?"?'x'), @(0?"!"!'x'), @(0?":":'x'), @("]"?'x'), @(1?"x"!"]").
Dollar signs: @("$"$None), @(asdf?"$"$"$"), @(1?asdf$"$").
These are strings:
@'single quoted string'
@"double quoted string"
@'single quoted string with escaped \'single quotes\''
@"double quoted string with escaped \"double quotes\""
@'''triple single quoted string'''
@"""triple double quoted string"""
@'single quoted string with "double quotes"'
@"double quoted string with 'single quotes'"
@'''triple single quoted continued \
string'''
@"""triple double quoted continued \
string"""
@'''triple single quoted
...multi-line string'''
@"""triple double quoted
... multi-line string"""

@# Significators.
@%a
@%b
@%c "x"
@%d "x"
@%e "x y"
@%f "x y"
Encountered significators:
a and b should be None: @`__a__`, @`__b__`
c and d should be 'x': @`__c__`, @`__d__`
e and f should be 'x y': @`__e__`, @`__f__`

@# Filters.
@{import string}@
This line should be in mixed case.
@empy.setFilter(string.lower)@
This line should be all lowercase.
@empy.setFilter(string.upper)@
This line should be all uppercase (how gauche).
@empy.setFilter([em.LineBufferedFilter(), lambda x: '[%s]\n' % x[:-1]])@
This line should be bracketed.
So should this line.
@empy.setFilter([em.SizeBufferedFilter(5), lambda x: '*' + x])@
There should be stars every five characters on this line.
@empy.nullFilter()@
This line should not appear at all!
@empy.resetFilter()@
This line should be back to mixed case.
@empy.attachFilter(string.upper)@
@empy.attachFilter(em.LineBufferedFilter())@
@empy.attachFilter(lambda x: '[%s]\n' % x[:-1])@
This line should be all uppercase with brackets.
@empy.resetFilter()@
This line should be back to mixed case (again).

@# Contexts, metaoperations.
@{
import StringIO
def context():
    return "%s:%d" % empy.identify()
stringFile = StringIO.StringIO("2 + 2 = @(2 + 2) [@context()].\n")
}@
The new context is @context().
File inclusion [@context()]: @empy.include(stringFile)@
Expansion [@context()]: @
@empy.expand("This should be appear [@context()]") @
on the same line as this [@context()].
More expansion [@context()]: @
@{sys.stdout.write(empy.expand("Another expansion [@context()]"))}.
This is the next line [@context()].
Quoting: @empy.quote("x when quoted would be '@x' or @x").
More quoting: @empy.quote("This will be @doubled but '''@this is not'''").
Here's the last view of the old context: @context().
Creating a new context ...
@empy.pushContext()@
The current context is: @context().
@?NewName
The context name should now be 'NewName': @context().
@!1000
The line number should now be 1000: @context().
@empy.popContext()@
Back to the old context: @context().

@# Embedded interpreters and standalone expansion.
@{
q = 1
}@
Interpreter's q is @q.
@{
try:
    i = em.Interpreter()
    i.string("@{q = 10}")
    i.string("Embedded interpreter's q is @q.\n")
finally:
    i.shutdown()
}@
Interpreter's q is still @q; the embedded interpreter had no effect.
Standalone expansion: @em.expand("1 + 1 is @(1 + 1).")
With locals: @em.expand("@x + @y is @(x + y).", x=2, y=3)
@{
g = {}
}@
With globals: @em.expand("@{x = 10}g's x is @x.", g)
Still with globals: @em.expand("g's x + 1 is @(x + 1).", g)
g's x is still @g['x'].

@# Hooks.
@{
class SampleHook(em.Hook):
    def null(self):
        self.interpreter.write('[SampleHook.null invoked]')

sampleHook = SampleHook()
empy.addHook(sampleHook)
}@
Invoking the sample hook: @empy.invokeHook('null').
@{
empy.removeHook(sampleHook)
}@

@# Custom.
@{
def customCallback(contents, empy=empy):
    empy.write('[%s]' % contents)
empy.registerCallback(customCallback)
}@
Using a custom markup: @<This appears in brackets>.
Again: @<<There are angle brackets in this one>>.
Once more: @<This is a right angle bracket in quotes: ">">.
@{
empy.deregisterCallback()
}@

@# Finals; note these are evaluated in reverse order.
@empy.atExit(lambda: empy.string("Version: @empy.VERSION.\n"))@
@empy.atExit(lambda: empy.write("This is the penultimate line.\n"))@


Fix bug in where axes visible is stored, remove some debug printouts.

/* axes.em
 *
 * Author: Will Monroe
 *
 * Restrict an object's motion to take place along a certain axis while
 * dragging.
 *
 * [currently: creates a single axis as its own entity, which can be dragged
 * in any direction and is not attached to another presence]
 */
system.require('std/graphics/graphics.em');

(function() {

     var redAxisMesh = 'meerkat:///wmonroe4/red_axis.dae/optimized/red_axis.dae';

     function axesScript(args) {
         system.require('std/movement/movableremote.em');
         system.require('std/movement/units.em');
         system.require('std/core/repeatingTimer.em');

         var moveMeshes = {x: 'meerkat:///wmonroe4/red_axis.dae/optimized/red_axis.dae',
                           y: 'meerkat:///wmonroe4/green_axis.dae/optimized/green_axis.dae',
                           z: 'meerkat:///wmonroe4/blue_axis.dae/optimized/blue_axis.dae'};
         var rotateMeshes = {x: 'meerkat:///wmonroe4/red_gimbal.dae/optimized/red_gimbal.dae',
                           y: 'meerkat:///wmonroe4/green_gimbal.dae/optimized/green_gimbal.dae',
                           z: 'meerkat:///wmonroe4/blue_gimbal.dae/optimized/blue_gimbal.dae'};
         var orientations = {x: new util.Quaternion(<0, 0, -1>, Math.PI / 2),
                             y: new util.Quaternion(),
                             z: new util.Quaternion(<1, 0, 0>, Math.PI / 2)};
         var axisMeshes = moveMeshes;
         var mode = 'move';
         var axes = {};
         var axisIDs = {};
         var movable = null;
         var updateTimer;
         var UPDATE_PERIOD = 1 * u.s;
         var ROTATE_FACTOR = 0.02;

         function onPresenceConnected(presence) {
             if(presence.mesh.slice(-12) != 'red_axis.dae')
                 return;

             setPosition << [{'request':'movable':},
                             {'position'::}];
             setOrientation << [{'request':'movable':},
                                {'orient'::}];
             setScale << [{'request':'movable':},
                          {'scale'::}];

             follow << [{'request':'axes':},
                               {'id'::}];
             toggleRotateMode << [{'request':'axes':},
                                  {'mode':'toggle':}];
             snapLocal << [{'request':'axes':},
                           {'snap':'local':}];
             snapGlobal << [{'request':'axes':},
                           {'snap':'global':}];
             forwardScriptRequest << [{'request':'script':}];
             onRedConnected(presence);
         }

         function onRedConnected(presence) {
             presence.modelOrientation = orientations.x;
             axes.x = presence;
             axisIDs[presence.toString()] = true;
             system.createPresence('meerkat:///wmonroe4/green_axis.dae/optimized/green_axis.dae',
                                   onGreenConnected);
         }

         function onGreenConnected(presence) {
             presence.modelOrientation = orientations.y;
             axes.y = presence;
             axisIDs[presence.toString()] = true;
             system.createPresence('meerkat:///wmonroe4/blue_axis.dae/optimized/blue_axis.dae',
                                   onBlueConnected);
         }

         function onBlueConnected(presence) {
             presence.modelOrientation = orientations.z;
             axes.z = presence;
             axisIDs[presence.toString()] = true;
             follow();
             updateTimer = new std.core.RepeatingTimer(UPDATE_PERIOD,
                                                       function() { follow(); });
             {axes: 'created'} >> args.avatar >> [];
         }

         function setPosition(msg, sender) {
             var axis = system.self.orientation.mul(
                     system.self.modelOrientation.mul(<0, 1, 0>));
             var delta = axis.scale(axis.dot(msg.position - system.self.position));
             if(mode == 'move') {
                 system.self.position = system.self.position + delta;

                 for(var a in axes)
                     axes[a].position = system.self.position;
                 if(movable)
                     movable.setPosition(system.self.position);
             } else /* mode == 'rotate' */ {
                 var quatDelta = new util.Quaternion(delta.normal(),
                                                     delta.length() * ROTATE_FACTOR /
                                                     system.self.scale);

                 system.self.orientation = quatDelta.mul(system.self.orientation);

                 for(var a in axes)
                     axes[a].orientation = system.self.orientation;
                 if(movable)
                     movable.setOrientation(system.self.orientation);
             }
             msg.makeReply({}) >> [];
         }

         function setOrientation(msg, sender) {
             /* Quaternions mess everything up!  By all means, try to fix this
              * code if you're brave.  Right now I've just made moving become
              * rotating when in rotate mode. (See above).
              */
             /*
             var axis = system.self.orientation.mul(
                     system.self.modelOrientation.mul(<0, 1, 0>));
             //system.__debugPrint('axis: ' + std.core.pretty(axis) + '\n');
             var target = msg.orient.mul(<0, 1, 0>);
             //system.__debugPrint('target: ' + std.core.pretty(target) + '\n');
             var corrAxis = target.cross(axis);
             //system.__debugPrint('corr: ' + std.core.pretty(corrAxis) + '\n');
             var correction = (new util.Quaternion(corrAxis.x, corrAxis.y,
                                                  corrAxis.z, 1 +
                                                  target.dot(axis))).normal();
             var newOrient = correction.mul(msg.orient);
             //system.__debugPrint('new y: ' + std.core.pretty(newOrient.mul(<0, 1, 0>)) + '\n\n');
             system.self.orientation = newOrient.mul(system.self.
                                       modelOrientation.inverse());
              */

             system.self.orientation = msg.orient.mul(system.self.
                                       modelOrientation.inverse());
             for(a in axes)
                 axes[a].orientation = system.self.orientation;
             if(movable)
                 movable.setOrientation(system.self.orientation);

             msg.makeReply({}) >> [];
         }

         function setScale(msg, sender) {
             system.self.scale = msg.scale;
             for(var a in axes)
                 axes[a].scale = system.self.scale;
             if(movable)
                 movable.setScale(system.self.scale / 2);
             msg.makeReply({}) >> [];
         }

         function follow(msg, sender) {
             if(typeof(msg) === 'undefined') {
                 if(movable) {
                     msg = {id: movable._remote.toString()};
                 } else {
                     msg = {id: ''};
                 }
             }

             if(msg.id !== '') {
                 if(msg.id in axisIDs)
                     // selecting an axis shouldn't make it follow itself!
                     return;

                 if(!movable || movable._remote.toString() != msg.id)
                     movable = new std.movement.MovableRemote(
                             system.createVisible(msg.id));

                 for(var a in axes) {
                     axes[a].mesh = axisMeshes[a];
                     axes[a].position = movable.getPosition();
                     axes[a].orientation = movable.getOrientation();
                     axes[a].scale = movable.getScale() * 2;
                 }
             } else {
                 movable = null;
                 for(var a in axes) {
                     axes[a].mesh = '';
                 }
             }
         }

         function toggleRotateMode(msg, sender) {
             mode = (mode == 'move' ? 'rotate' : 'move');
             axisMeshes = (mode == 'move' ? moveMeshes : rotateMeshes);
             for(var a in axes)
                 if(axes[a].mesh != '')
                     axes[a].mesh = axisMeshes[a];
         }

         function snapLocal(msg, sender) {
             for(var a in axes)
                 axes[a].modelOrientation = orientations[a];

             follow();
         }

         function snapGlobal(msg, sender) {
             if(!movable)
                 return;

             for(var a in axes)
                 axes[a].modelOrientation = movable.getOrientation().inverse().
                                            mul(orientations[a]);

             follow();
         }

         function forwardScriptRequest(msg, sender) {
             if(!movable)
                 return;

             msg >> movable._remote >> [];
         }

         system.onPresenceConnected(onPresenceConnected);
     }

     std.graphics.Graphics.prototype.onAxesCreated = function(msg, sender) {
         this._axes._axesVisible = sender;
     };

     std.graphics.Graphics.prototype.createAxes = function(self) {
         std.core.bind(this.onAxesCreated, this) << [{'axes':'created':}];

         system.createEntityScript(<0, 0, 0>, axesScript,
                                   {avatar: self},
                                   self.queryAngle, redAxisMesh, 1);
     };

     std.graphics.Graphics.prototype._axes = {};

     std.graphics.Graphics.prototype._axes.follow = function(vis) {
         if (!this._axesVisible) return;
         if(vis)
             {request: 'axes', id: vis.toString()} >> this._axesVisible >> [];
         else
             {request: 'axes', id: ''} >> this._axesVisible >> [];
     };

     std.graphics.Graphics.prototype._axes.toggleRotateMode = function() {
         if (!this._axesVisible) return;
         {request: 'axes', mode: 'toggle'} >> this._axesVisible >> [];
     };

     std.graphics.Graphics.prototype._axes.snapLocal = function() {
         if (!this._axesVisible) return;
         {request: 'axes', snap: 'local'} >> this._axesVisible >> [];
     }

     std.graphics.Graphics.prototype._axes.snapGlobal = function() {
         if (!this._axesVisible) return;
         {request: 'axes', snap: 'global'} >> this._axesVisible >> [];
     }

})();

/* axes.em
 *
 * Author: Will Monroe
 *
 * Restrict an object's motion to take place along a certain axis while
 * dragging.
 *
 * [currently: creates a single axis as its own entity, which can be dragged
 * in any direction and is not attached to another presence]
 */
system.require('std/graphics/graphics.em');

(function() {

     var redAxisMesh = 'meerkat:///wmonroe4/red_axis.dae/optimized/red_axis.dae';

     function axesScript(args) {
         system.require('std/movement/movableremote.em');
         system.require('std/movement/units.em');
         system.require('std/core/repeatingTimer.em');

         var moveMeshes = {x: 'meerkat:///wmonroe4/red_axis.dae/optimized/red_axis.dae',
                           y: 'meerkat:///wmonroe4/green_axis.dae/optimized/green_axis.dae',
                           z: 'meerkat:///wmonroe4/blue_axis.dae/optimized/blue_axis.dae'};
         var rotateMeshes = {x: 'meerkat:///wmonroe4/red_gimbal.dae/optimized/red_gimbal.dae',
                           y: 'meerkat:///wmonroe4/green_gimbal.dae/optimized/green_gimbal.dae',
                           z: 'meerkat:///wmonroe4/blue_gimbal.dae/optimized/blue_gimbal.dae'};
         var orientations = {x: new util.Quaternion(<0, 0, -1>, Math.PI / 2),
                             y: new util.Quaternion(),
                             z: new util.Quaternion(<1, 0, 0>, Math.PI / 2)};
         var axisMeshes = moveMeshes;
         var mode = 'move';
         var axes = {};
         var axisIDs = {};
         var movable = null;
         var updateTimer;
         var UPDATE_PERIOD = 1 * u.s;
         var ROTATE_FACTOR = 0.02;

         function onPresenceConnected(presence) {
             if(presence.mesh.slice(-12) != 'red_axis.dae')
                 return;

             setPosition << [{'request':'movable':},
                             {'position'::}];
             setOrientation << [{'request':'movable':},
                                {'orient'::}];
             setScale << [{'request':'movable':},
                          {'scale'::}];

             follow << [{'request':'axes':},
                               {'id'::}];
             toggleRotateMode << [{'request':'axes':},
                                  {'mode':'toggle':}];
             snapLocal << [{'request':'axes':},
                           {'snap':'local':}];
             snapGlobal << [{'request':'axes':},
                           {'snap':'global':}];
             forwardScriptRequest << [{'request':'script':}];
             onRedConnected(presence);
         }

         function onRedConnected(presence) {
             presence.modelOrientation = orientations.x;
             axes.x = presence;
             axisIDs[presence.toString()] = true;
             system.createPresence('meerkat:///wmonroe4/green_axis.dae/optimized/green_axis.dae',
                                   onGreenConnected);
         }

         function onGreenConnected(presence) {
             presence.modelOrientation = orientations.y;
             axes.y = presence;
             axisIDs[presence.toString()] = true;
             system.createPresence('meerkat:///wmonroe4/blue_axis.dae/optimized/blue_axis.dae',
                                   onBlueConnected);
         }

         function onBlueConnected(presence) {
             presence.modelOrientation = orientations.z;
             axes.z = presence;
             axisIDs[presence.toString()] = true;
             follow();
             updateTimer = new std.core.RepeatingTimer(UPDATE_PERIOD,
                                                       function() { follow(); });
             {axes: 'created'} >> args.avatar >> [];
         }

         function setPosition(msg, sender) {
             var axis = system.self.orientation.mul(
                     system.self.modelOrientation.mul(<0, 1, 0>));
             var delta = axis.scale(axis.dot(msg.position - system.self.position));
             if(mode == 'move') {
                 system.self.position = system.self.position + delta;

                 for(var a in axes)
                     axes[a].position = system.self.position;
                 if(movable)
                     movable.setPosition(system.self.position);
             } else /* mode == 'rotate' */ {
                 var quatDelta = new util.Quaternion(delta.normal(),
                                                     delta.length() * ROTATE_FACTOR /
                                                     system.self.scale);

                 system.self.orientation = quatDelta.mul(system.self.orientation);

                 for(var a in axes)
                     axes[a].orientation = system.self.orientation;
                 if(movable)
                     movable.setOrientation(system.self.orientation);
             }
             msg.makeReply({}) >> [];
         }

         function setOrientation(msg, sender) {
             /* Quaternions mess everything up!  By all means, try to fix this
              * code if you're brave.  Right now I've just made moving become
              * rotating when in rotate mode. (See above).
              */
             /*
             var axis = system.self.orientation.mul(
                     system.self.modelOrientation.mul(<0, 1, 0>));
             system.__debugPrint('axis: ' + std.core.pretty(axis) + '\n');
             var target = msg.orient.mul(<0, 1, 0>);
             system.__debugPrint('target: ' + std.core.pretty(target) + '\n');
             var corrAxis = target.cross(axis);
             system.__debugPrint('corr: ' + std.core.pretty(corrAxis) + '\n');
             var correction = (new util.Quaternion(corrAxis.x, corrAxis.y,
                                                  corrAxis.z, 1 +
                                                  target.dot(axis))).normal();
             var newOrient = correction.mul(msg.orient);
             system.__debugPrint('new y: ' + std.core.pretty(newOrient.mul(<0, 1, 0>)) + '\n\n');
             system.self.orientation = newOrient.mul(system.self.
                                       modelOrientation.inverse());
              */

             system.self.orientation = msg.orient.mul(system.self.
                                       modelOrientation.inverse());
             for(a in axes)
                 axes[a].orientation = system.self.orientation;
             if(movable)
                 movable.setOrientation(system.self.orientation);

             msg.makeReply({}) >> [];
         }

         function setScale(msg, sender) {
             system.self.scale = msg.scale;
             for(var a in axes)
                 axes[a].scale = system.self.scale;
             if(movable)
                 movable.setScale(system.self.scale / 2);
             msg.makeReply({}) >> [];
         }

         function follow(msg, sender) {
             if(typeof(msg) === 'undefined') {
                 if(movable) {
                     msg = {id: movable._remote.toString()};
                 } else {
                     msg = {id: ''};
                 }
             }

             if(msg.id !== '') {
                 if(msg.id in axisIDs)
                     // selecting an axis shouldn't make it follow itself!
                     return;

                 if(!movable || movable._remote.toString() != msg.id)
                     movable = new std.movement.MovableRemote(
                             system.createVisible(msg.id));

                 for(var a in axes) {
                     axes[a].mesh = axisMeshes[a];
                     axes[a].position = movable.getPosition();
                     axes[a].orientation = movable.getOrientation();
                     axes[a].scale = movable.getScale() * 2;
                 }
             } else {
                 movable = null;
                 for(var a in axes) {
                     axes[a].mesh = '';
                 }
             }
         }

         function toggleRotateMode(msg, sender) {
             mode = (mode == 'move' ? 'rotate' : 'move');
             axisMeshes = (mode == 'move' ? moveMeshes : rotateMeshes);
             for(var a in axes)
                 if(axes[a].mesh != '')
                     axes[a].mesh = axisMeshes[a];
         }

         function snapLocal(msg, sender) {
             for(var a in axes)
                 axes[a].modelOrientation = orientations[a];

             follow();
         }

         function snapGlobal(msg, sender) {
             if(!movable)
                 return;

             for(var a in axes)
                 axes[a].modelOrientation = movable.getOrientation().inverse().
                                            mul(orientations[a]);

             follow();
         }

         function forwardScriptRequest(msg, sender) {
             if(!movable)
                 return;

             msg >> movable._remote >> [];
         }

         system.onPresenceConnected(onPresenceConnected);
     }

     std.graphics.Graphics.prototype.onAxesCreated = function(msg, sender) {
         this._axesVisible = sender;
     };

     std.graphics.Graphics.prototype.createAxes = function(self) {
         std.core.bind(this.onAxesCreated, this) << [{'axes':'created':}];

         system.createEntityScript(<0, 0, 0>, axesScript,
                                   {avatar: self},
                                   self.queryAngle, redAxisMesh, 1);
     };

     std.graphics.Graphics.prototype._axes = {};

     std.graphics.Graphics.prototype._axes.follow = function(vis) {
         if (!this._axesVisible) return;
         if(vis)
             {request: 'axes', id: vis.toString()} >> this._axesVisible >> [];
         else
             {request: 'axes', id: ''} >> this._axesVisible >> [];
     };

     std.graphics.Graphics.prototype._axes.toggleRotateMode = function() {
         if (!this._axesVisible) return;
         {request: 'axes', mode: 'toggle'} >> this._axesVisible >> [];
     };

     std.graphics.Graphics.prototype._axes.snapLocal = function() {
         if (!this._axesVisible) return;
         {request: 'axes', snap: 'local'} >> this._axesVisible >> [];
     }

     std.graphics.Graphics.prototype._axes.snapGlobal = function() {
         if (!this._axesVisible) return;
         {request: 'axes', snap: 'global'} >> this._axesVisible >> [];
     }

})();


keep many more build logs for import-package jobs

<project>
  <actions/>
  <description>Generated at @ESCAPE(now_str) from template '@ESCAPE(template_name)'</description>
@(SNIPPET(
    'log-rotator',
    days_to_keep=30,
    num_to_keep=10000,
))@
  <keepDependencies>false</keepDependencies>
  <properties>
@(SNIPPET(
    'property_parameters-definition',
    parameters=[
        {
            'type': 'string',
            'name': 'subfolder',
        },
        {
            'type': 'string',
            'name': 'debian_package_name',
        },
    ],
))@
@(SNIPPET(
    'property_requeue-job',
))@
@(SNIPPET(
    'property_disk-usage',
))@
  </properties>
@(SNIPPET(
    'scm_git',
    url='https://github.com/ros-infrastructure/reprepro-updater.git',
    branch_name='refactor',
    relative_target_dir='reprepro-updater',
    refspec=None,
))@
  <assignedNode>building_repository</assignedNode>
  <canRoam>false</canRoam>
  <disabled>false</disabled>
  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
  <triggers/>
  <concurrentBuild>false</concurrentBuild>
  <builders>
@(SNIPPET(
    'builder_shell',
    script='\n'.join([
        'echo "# BEGIN SECTION: import debian package"',
        'export PYTHONPATH=$WORKSPACE/reprepro-updater/src:$PYTHONPATH',
        'python -u $WORKSPACE/reprepro-updater/scripts/include_folder.py --folder /var/repos/ubuntu/building/queue/$subfolder --package $debian_package_name --delete-folder --commit',
        'echo "# END SECTION"',
    ]),
))@
  </builders>
  <publishers>
@(SNIPPET(
    'publisher_description-setter',
    regexp='Importing package: (\S+)',
    # to prevent overwriting the description of failed builds
    regexp_for_failed='ThisRegExpShouldNeverMatch',
))@
@(SNIPPET(
    'publisher_mailer',
    recipients=notify_emails,
    dynamic_recipients=[],
    send_to_individuals=False,
))@
  </publishers>
  <buildWrappers>
@(SNIPPET(
    'build-wrapper_timestamper',
))@
@(SNIPPET(
    'build-wrapper_disk-check',
))@
  </buildWrappers>
</project>

<project>
  <actions/>
  <description>Generated at @ESCAPE(now_str) from template '@ESCAPE(template_name)'</description>
@(SNIPPET(
    'log-rotator',
    days_to_keep=100,
    num_to_keep=100,
))@
  <keepDependencies>false</keepDependencies>
  <properties>
@(SNIPPET(
    'property_parameters-definition',
    parameters=[
        {
            'type': 'string',
            'name': 'subfolder',
        },
        {
            'type': 'string',
            'name': 'debian_package_name',
        },
    ],
))@
@(SNIPPET(
    'property_requeue-job',
))@
@(SNIPPET(
    'property_disk-usage',
))@
  </properties>
@(SNIPPET(
    'scm_git',
    url='https://github.com/ros-infrastructure/reprepro-updater.git',
    branch_name='refactor',
    relative_target_dir='reprepro-updater',
    refspec=None,
))@
  <assignedNode>building_repository</assignedNode>
  <canRoam>false</canRoam>
  <disabled>false</disabled>
  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
  <triggers/>
  <concurrentBuild>false</concurrentBuild>
  <builders>
@(SNIPPET(
    'builder_shell',
    script='\n'.join([
        'echo "# BEGIN SECTION: import debian package"',
        'export PYTHONPATH=$WORKSPACE/reprepro-updater/src:$PYTHONPATH',
        'python -u $WORKSPACE/reprepro-updater/scripts/include_folder.py --folder /var/repos/ubuntu/building/queue/$subfolder --package $debian_package_name --delete-folder --commit',
        'echo "# END SECTION"',
    ]),
))@
  </builders>
  <publishers>
@(SNIPPET(
    'publisher_description-setter',
    regexp='Importing package: (\S+)',
    # to prevent overwriting the description of failed builds
    regexp_for_failed='ThisRegExpShouldNeverMatch',
))@
@(SNIPPET(
    'publisher_mailer',
    recipients=notify_emails,
    dynamic_recipients=[],
    send_to_individuals=False,
))@
  </publishers>
  <buildWrappers>
@(SNIPPET(
    'build-wrapper_timestamper',
))@
@(SNIPPET(
    'build-wrapper_disk-check',
))@
  </buildWrappers>
</project>