From 14d7adc51910f9db8a3ec5a0e8c18455a1a9ef3b Mon Sep 17 00:00:00 2001
From: TSC21 <n.marques21@hotmail.com>
Date: Mon, 28 Jan 2019 15:28:40 +0000
Subject: [PATCH] Jenkins CI: PX4 ROS2: deploy required tools

---
 Jenkinsfile                       |  35 ++++++-
 msg/tools/uorb_to_ros_rtps_ids.py | 158 ++++++++++++++++++++++++++++++
 2 files changed, 192 insertions(+), 1 deletion(-)
 create mode 100644 msg/tools/uorb_to_ros_rtps_ids.py

diff --git a/Jenkinsfile b/Jenkinsfile
index 31042dff2e..2451ab2873 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -484,7 +484,40 @@ pipeline {
               sh("git clone https://${GIT_USER}:${GIT_PASS}@github.com/PX4/px4_msgs.git -b ${BRANCH_NAME}")
               sh('python msg/tools/uorb_to_ros_msgs.py msg/ px4_msgs/msg/')
               sh('cd px4_msgs; git status; git add .; git commit -a -m "Update message definitions `date`" || true')
-              sh('cd px4_msgs; git push origin master || true')
+              sh('cd px4_msgs; git push origin ${BRANCH_NAME} || true')
+              sh('rm -rf px4_msgs')
+            }
+          }
+          when {
+            anyOf {
+              branch 'master'
+              branch 'pr-jenkins' // for testing
+            }
+          }
+          options {
+            skipDefaultCheckout()
+          }
+        }
+
+        stage('PX4 ROS2 bridge') {
+          agent {
+            docker { image 'px4io/px4-dev-base:2019-01-01' }
+          }
+          steps {
+            checkout(scm)
+            sh('export')
+            withCredentials([usernamePassword(credentialsId: 'px4buildbot_github_personal_token', passwordVariable: 'GIT_PASS', usernameVariable: 'GIT_USER')]) {
+              sh("git clone https://${GIT_USER}:${GIT_PASS}@github.com/PX4/px4_ros_com.git -b ${BRANCH_NAME}")
+              // deploy uORB RTPS ID map
+              sh('python msg/tools/uorb_to_ros_rtps_ids.py -i msg/tools/uorb_rtps_message_ids.yaml -o px4_ros_com/templates/uorb_rtps_message_ids.yaml')
+              sh('cd px4_ros_com; git status; git add .; git commit -a -m "Update uORB RTPS ID map `date`" || true')
+              // deploy uORB RTPS required tools
+              sh('cp msg/tools/uorb_rtps_classifier.py px4_ros_com/scripts/uorb_rtps_classifier.py')
+              sh('cp msg/tools/generate_microRTPS_bridge.py px4_ros_com/scripts/generate_microRTPS_bridge.py')
+              sh('cp msg/tools/px_generate_uorb_topic_files.py px4_ros_com/scripts/px_generate_uorb_topic_files.py')
+              sh('cp msg/tools/px_generate_uorb_topic_helper.py px4_ros_com/scripts/px_generate_uorb_topic_helper.py')
+              sh('cd px4_ros_com; git status; git add .; git commit -a -m "Update uORB RTPS script tools `date`" || true')
+              sh('cd px4_ros_com; git push origin ${BRANCH_NAME} || true')
               sh('rm -rf px4_msgs')
             }
           }
diff --git a/msg/tools/uorb_to_ros_rtps_ids.py b/msg/tools/uorb_to_ros_rtps_ids.py
new file mode 100644
index 0000000000..bdbfca788c
--- /dev/null
+++ b/msg/tools/uorb_to_ros_rtps_ids.py
@@ -0,0 +1,158 @@
+#!/usr/bin/env python
+"""
+Script to read an yaml file containing the RTPS message IDs and update the naming convention to PascalCase
+"""
+
+import os
+import yaml
+import sys
+import argparse
+
+__author__ = 'PX4 Development Team'
+__copyright__ = \
+    '''
+     '
+     '   Copyright (C) 2018-2019 PX4 Development Team. All rights reserved.
+     '
+     ' Redistribution and use in source and binary forms, or without
+     ' modification, permitted provided that the following conditions
+     ' are met:
+     '
+     ' 1. Redistributions of source code must retain the above copyright
+     '    notice, list of conditions and the following disclaimer.
+     ' 2. Redistributions in binary form must reproduce the above copyright
+     '    notice, list of conditions and the following disclaimer in
+     '    the documentation and/or other materials provided with the
+     '    distribution.
+     ' 3. Neither the name PX4 nor the names of its contributors may be
+     '    used to endorse or promote products derived from self software
+     '    without specific prior written permission.
+     '
+     ' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+     ' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, NOT
+     ' LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+     ' FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+     ' COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+     ' INCIDENTAL, SPECIAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING,
+     ' BUT NOT LIMITED TO, OF SUBSTITUTE GOODS OR SERVICES; LOSS
+     ' OF USE, DATA, PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+     ' AND ON ANY THEORY OF LIABILITY, IN CONTRACT, STRICT
+     ' LIABILITY, TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+     ' ANY WAY OUT OF THE USE OF THIS SOFTWARE, IF ADVISED OF THE
+     ' POSSIBILITY OF SUCH DAMAGE.
+     '
+    '''
+__credits__ = ['Nuno Marques <nuno.marques@dronesolution.io>']
+__license__ = 'BSD-3-Clause'
+__version__ = '0.1.0'
+__maintainer__ = 'Nuno Marques'
+__email__ = 'nuno.marques@dronesolution.io'
+__status__ = 'Development'
+
+list = []
+in_file = ""
+out_file = ""
+verbose = True
+
+
+class IndenterDumper(yaml.Dumper):
+    """ Custom dumper for yaml files that apply the correct indentation """
+
+    def increase_indent(self, flow=False, indentless=False):
+        return super(IndenterDumper, self).increase_indent(flow, False)
+
+
+def load_yaml_file(file):
+    """
+    Open yaml file and parse the data into a list of dict
+
+    :param file: the yaml file to load
+    :returns: the list of dictionaries that represent the message and respective RTPS IDs
+    :raises IOError: raises and error when the file is not found
+    """
+    try:
+        with open(file, 'r') as f:
+            if verbose:
+                print("--\t[Step 1] %s yaml file loaded!" % file)
+            return yaml.load(f)
+    except OSError as e:
+        if e.errno == errno.ENOENT:
+            raise IOError(errno.ENOENT, os.strerror(errno.ENOENT), file)
+        else:
+            raise
+
+
+def update_dict(list):
+    """
+    Update the message naming on the dictionary to fit the PascalCase convention
+
+    :param file: the list of dicts to be updated
+    """
+    if verbose:
+        num_of_msgs = 0
+    for i, dictionary in enumerate(list["rtps"]):
+        # implementation depends on the Python version being used
+        if sys.version_info[0] < 3:
+            dict = {k: v.title().replace('_', '') if isinstance(
+                v, basestring) else v for k, v in dictionary.iteritems()}
+        else:
+            dict = {k: v.title().replace('_', '') if isinstance(
+                v, str) else v for k, v in dictionary.items()}
+        list["rtps"][i] = dict
+        if verbose:
+            num_of_msgs += 1
+    if verbose:
+        print("--\t[Step 2] List: %d msg names updated!" % num_of_msgs)
+
+
+def update_yaml_file(list, file):
+    """
+    Open the yaml file to dump the new list of dict toself.
+
+    .. note:: Since the the dump method automatically sorts the keys alphabetically,
+    the 'id' fields will appear first than the 'msg' fields.
+
+    :param list: the list of updated dicts
+    :param file: the yaml file to load and write the new data
+    :raises IOError: raises and error when the file is not found
+    """
+    try:
+        with open(file, 'w') as f:
+            yaml.dump(list, f, Dumper=IndenterDumper, default_flow_style=False)
+            if verbose:
+                if in_file == out_file:
+                    print("--\t[Step 3] %s updated!" % in_file)
+                else:
+                    print("--\t[Step 3] %s created!" % out_file)
+
+    except OSError as e:
+        if e.errno == errno.ENOENT:
+            raise IOError(errno.ENOENT, os.strerror(errno.ENOENT), file)
+        else:
+            raise
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(
+        description='Read an yaml file containing the RTPS message IDs and update the naming convention to PascalCase')
+    optional = parser._action_groups.pop()
+    required = parser.add_argument_group('Required')
+    required.add_argument("-i", "--input-file", dest="input_file",
+                          help="Yaml file to read", metavar="INFILE")
+    optional.add_argument("-o", "--output-file", dest="output_file",
+                          help="Yaml file to dump. If not set, it is the same as the input",
+                          metavar="OUTFILE", default="")
+    optional.add_argument("-q", "--quiet", action="store_false", dest="verbose",
+                          default=True, help="Don't print status messages to stdout")
+
+    args = parser.parse_args()
+    verbose = args.verbose
+    in_file = args.input_file
+    out_file = args.output_file if (args.output_file != in_file and args.output_file != "") else in_file
+
+    if verbose:
+        print("-- PX4 to ROS RTPS Ids --")
+
+    list = load_yaml_file(in_file)
+    update_dict(list)
+    update_yaml_file(list, out_file)
-- 
GitLab