From 1f272686647486407da698d7b57f1f2410fe906f Mon Sep 17 00:00:00 2001 From: Wolfgang Hess Date: Tue, 10 Jan 2017 12:23:10 +0100 Subject: [PATCH] Add resolution of option types to the documentation script. (#180) --- docs/source/configuration.rst | 44 +++++++-------- scripts/update_configuration_doc.py | 85 +++++++++++++++++++---------- 2 files changed, 77 insertions(+), 52 deletions(-) diff --git a/docs/source/configuration.rst b/docs/source/configuration.rst index 9c4d3e9..e521963 100644 --- a/docs/source/configuration.rst +++ b/docs/source/configuration.rst @@ -62,19 +62,19 @@ cartographer.mapping.proto.MapBuilderOptions bool use_trajectory_builder_2d Not yet documented. -mapping_2d.proto.LocalTrajectoryBuilderOptions trajectory_builder_2d_options +cartographer.mapping_2d.proto.LocalTrajectoryBuilderOptions trajectory_builder_2d_options Not yet documented. bool use_trajectory_builder_3d Not yet documented. -mapping_3d.proto.LocalTrajectoryBuilderOptions trajectory_builder_3d_options +cartographer.mapping_3d.proto.LocalTrajectoryBuilderOptions trajectory_builder_3d_options Not yet documented. int32 num_background_threads Number of threads to use for background computations. -SparsePoseGraphOptions sparse_pose_graph_options +cartographer.mapping.proto.SparsePoseGraphOptions sparse_pose_graph_options Not yet documented. @@ -85,10 +85,10 @@ int32 optimize_every_n_scans Online loop closure: If positive, will run the loop closure while the map is built. -mapping.sparse_pose_graph.proto.ConstraintBuilderOptions constraint_builder_options +cartographer.mapping.sparse_pose_graph.proto.ConstraintBuilderOptions constraint_builder_options Options for the constraint builder. -mapping.sparse_pose_graph.proto.OptimizationProblemOptions optimization_problem_options +cartographer.mapping.sparse_pose_graph.proto.OptimizationProblemOptions optimization_problem_options Options for the optimization problem. int32 max_num_final_iterations @@ -110,7 +110,7 @@ double sampling_ratio double max_constraint_distance Threshold for poses to be considered near a submap. -sensor.proto.AdaptiveVoxelFilterOptions adaptive_voxel_filter_options +cartographer.sensor.proto.AdaptiveVoxelFilterOptions adaptive_voxel_filter_options Voxel filter used to compute a sparser point cloud for matching. double min_score @@ -126,16 +126,16 @@ double lower_covariance_eigenvalue_bound bool log_matches If enabled, logs information of loop-closing constraints for debugging. -mapping_2d.scan_matching.proto.FastCorrelativeScanMatcherOptions fast_correlative_scan_matcher_options +cartographer.mapping_2d.scan_matching.proto.FastCorrelativeScanMatcherOptions fast_correlative_scan_matcher_options Options for the internally used scan matchers. -mapping_2d.scan_matching.proto.CeresScanMatcherOptions ceres_scan_matcher_options +cartographer.mapping_2d.scan_matching.proto.CeresScanMatcherOptions ceres_scan_matcher_options Not yet documented. -mapping_3d.scan_matching.proto.FastCorrelativeScanMatcherOptions fast_correlative_scan_matcher_options_3d +cartographer.mapping_3d.scan_matching.proto.FastCorrelativeScanMatcherOptions fast_correlative_scan_matcher_options_3d Not yet documented. -mapping_3d.scan_matching.proto.CeresScanMatcherOptions ceres_scan_matcher_options_3d +cartographer.mapping_3d.scan_matching.proto.CeresScanMatcherOptions ceres_scan_matcher_options_3d Not yet documented. @@ -160,7 +160,7 @@ double consecutive_scan_rotation_penalty_factor bool log_solver_summary If true, the Ceres solver summary will be logged for every optimization. -common.proto.CeresSolverOptions ceres_solver_options +cartographer.common.proto.CeresSolverOptions ceres_solver_options Not yet documented. @@ -207,16 +207,16 @@ bool use_online_correlative_scan_matching Whether to solve the online scan matching first using the correlative scan matcher to generate a good starting point for Ceres. -sensor.proto.AdaptiveVoxelFilterOptions adaptive_voxel_filter_options +cartographer.sensor.proto.AdaptiveVoxelFilterOptions adaptive_voxel_filter_options Voxel filter used to compute a sparser point cloud for matching. -scan_matching.proto.RealTimeCorrelativeScanMatcherOptions real_time_correlative_scan_matcher_options +cartographer.mapping_2d.scan_matching.proto.RealTimeCorrelativeScanMatcherOptions real_time_correlative_scan_matcher_options Not yet documented. -scan_matching.proto.CeresScanMatcherOptions ceres_scan_matcher_options +cartographer.mapping_2d.scan_matching.proto.CeresScanMatcherOptions ceres_scan_matcher_options Not yet documented. -mapping_3d.proto.MotionFilterOptions motion_filter_options +cartographer.mapping_3d.proto.MotionFilterOptions motion_filter_options Not yet documented. double imu_gravity_time_constant @@ -230,7 +230,7 @@ double imu_gravity_time_constant int32 num_odometry_states Maximum number of previous odometry states to keep. -mapping_2d.proto.SubmapsOptions submaps_options +cartographer.mapping_2d.proto.SubmapsOptions submaps_options Not yet documented. bool use_imu_data @@ -254,7 +254,7 @@ int32 num_laser_fans bool output_debug_images If enabled, submap%d.png images are written for debugging. -LaserFanInserterOptions laser_fan_inserter_options +cartographer.mapping_2d.proto.LaserFanInserterOptions laser_fan_inserter_options Not yet documented. @@ -273,7 +273,7 @@ double rotation_weight double covariance_scale Scale applied to the covariance estimate from Ceres. -common.proto.CeresSolverOptions ceres_solver_options +cartographer.common.proto.CeresSolverOptions ceres_solver_options Configure the Ceres solver. See the Ceres documentation for more information: https://code.google.com/p/ceres-solver/ @@ -318,10 +318,10 @@ bool use_online_correlative_scan_matching Whether to solve the online scan matching first using the correlative scan matcher to generate a good starting point for Ceres. -mapping_2d.scan_matching.proto.RealTimeCorrelativeScanMatcherOptions real_time_correlative_scan_matcher_options +cartographer.mapping_2d.scan_matching.proto.RealTimeCorrelativeScanMatcherOptions real_time_correlative_scan_matcher_options Not yet documented. -kalman_filter.proto.PoseTrackerOptions pose_tracker_options +cartographer.kalman_filter.proto.PoseTrackerOptions pose_tracker_options Not yet documented. double odometer_translational_variance @@ -409,7 +409,7 @@ int32 num_laser_fans number of scans inserted: First for initialization without being matched against, then while being matched. -LaserFanInserterOptions laser_fan_inserter_options +cartographer.mapping_3d.proto.LaserFanInserterOptions laser_fan_inserter_options Not yet documented. @@ -428,7 +428,7 @@ double covariance_scale bool only_optimize_yaw Whether only to allow changes to yaw, keeping roll/pitch constant. -common.proto.CeresSolverOptions ceres_solver_options +cartographer.common.proto.CeresSolverOptions ceres_solver_options Configure the Ceres solver. See the Ceres documentation for more information: https://code.google.com/p/ceres-solver/ diff --git a/scripts/update_configuration_doc.py b/scripts/update_configuration_doc.py index 03a460a..9c52c59 100755 --- a/scripts/update_configuration_doc.py +++ b/scripts/update_configuration_doc.py @@ -48,19 +48,10 @@ SUFFIX = """ NODOC = 'Not yet documented.' -def ForEachProtoFile(root, callback): - for dirpath, dirnames, filenames in os.walk(root): - for name in filenames: - if name.endswith('.proto'): - path = os.path.join(dirpath, name) - print("Found '%s'..." % path) - assert not os.path.islink(path) - callback(io.open(path, encoding='UTF-8')) - - class Message(object): - def __init__(self, name, preceding_comments): + def __init__(self, name, package, preceding_comments): self.name = name + self.package = package self.preceding_comments = preceding_comments self.trailing_comments = None self.options = [] @@ -68,8 +59,8 @@ class Message(object): def AddTrailingComments(self, comments): self.trailing_comments = comments - def AddOption(self, name, comments): - self.options.append((name, comments)) + def AddOption(self, option_type, name, comments): + self.options.append((option_type, name, comments)) def ParseProtoFile(proto_file): @@ -107,7 +98,7 @@ def ParseProtoFile(proto_file): # We reached the end of file. break print(" Found '%s'." % message_name) - message = Message(message_name, message_comments) + message = Message(message_name, package, message_comments) message_list.append(message) # We capture the contents of this message. @@ -135,27 +126,68 @@ def ParseProtoFile(proto_file): if not multiline.endswith(';'): continue assert len(multiline) < 200 - option_name = multiline[8:-1].strip().rstrip('0123456789').strip() - assert option_name.endswith('=') - option_name = option_name[:-1].strip(); + option = multiline[8:-1].strip().rstrip('0123456789').strip() + assert option.endswith('=') + option_type, option_name = option[:-1].strip().split(); print(" Option '%s'." % option_name) multiline = None - message.AddOption(option_name, option_comments) + message.AddOption(option_type, option_name, option_comments) option_comments = [] return message_list -def GenerateDocumentation(output_dict, proto_file): - for message in ParseProtoFile(proto_file): +def ParseProtoFilesRecursively(root): + """Recursively parses all proto files into a list of Message objects.""" + message_list = [] + for dirpath, dirnames, filenames in os.walk(root): + for name in filenames: + if name.endswith('.proto'): + path = os.path.join(dirpath, name) + print("Found '%s'..." % path) + assert not os.path.islink(path) + message_list.extend(ParseProtoFile(io.open(path, encoding='UTF-8'))) + return message_list + + +class ResolutionError(Exception): + """Raised when resolving a message name fails.""" + + +class Resolver(object): + def __init__(self, name_set): + self.name_set = set(iter(name_set)) + + def Resolve(self, message_name, package_name): + if message_name in ('bool', 'double', 'float', 'int32'): + return message_name + if message_name.startswith('.'): + return message_name[1:] + package = package_name.split('.') + for levels in range(len(package), -1, -1): + candidate = '.'.join(package[0:levels]) + '.' + message_name + if candidate in self.name_set: + return candidate + raise ResolutionError( + 'Resolving %s in %s failed.' % (message_name, package_name)) + + +def GenerateDocumentation(output_file, root): + """Recursively generates documentation, sorts and writes it.""" + message_list = ParseProtoFilesRecursively(root) + resolver = Resolver(message.name for message in message_list) + + output_dict = {} + for message in message_list: content = [message.name, '=' * len(message.name), ''] assert message.name not in output_dict output_dict[message.name] = content if message.preceding_comments: content.extend(preceding_comments) content.append('') - for option_name, option_comments in message.options: - content.append(option_name) + for option_type, option_name, option_comments in message.options: + content.append( + resolver.Resolve(option_type, message.package) + ' ' + option_name) if not option_comments: option_comments.append(NODOC) for comment in option_comments: @@ -165,13 +197,6 @@ def GenerateDocumentation(output_dict, proto_file): content.extend(message.trailing_comments) content.append('') - -def GenerateDocumentationRecursively(output_file, root): - """Recursively generates documentation, sorts and writes it.""" - output_dict = {} - def callback(proto_file): - GenerateDocumentation(output_dict, proto_file) - ForEachProtoFile(root, callback) output = ['\n'.join(doc) for key, doc in sorted(list(output_dict.items()))] print('\n\n'.join(output), file=output_file) @@ -181,7 +206,7 @@ def main(): assert not os.path.islink(ROOT) and os.path.isdir(ROOT) output_file = io.open(TARGET, mode='w', encoding='UTF-8', newline='\n') output_file.write(PREFIX) - GenerateDocumentationRecursively(output_file, ROOT) + GenerateDocumentation(output_file, ROOT) output_file.write(SUFFIX) output_file.close()