From a2e650fd5c4e20dfb6978fc80a0c40c0587a040f Mon Sep 17 00:00:00 2001 From: Jochen Topf Date: Sun, 6 Feb 2022 14:26:20 +0100 Subject: [PATCH] Add options to the "diff" command to ignore certain attributes When the new command line options --ignore-changeset, --ignore-uid, or --ignore-user are used, the respective attributes of OSM objects are ignored when comparing the input files. This is especially useful for user names, because OSM users can change their own user names, which happens often enough to matter. When used with the OPL output format the ignored attributes are not written out to the output. --- man/osmium-diff.md | 15 +++++++- src/command_diff.cpp | 56 +++++++++++++++++++++++++--- src/command_diff.hpp | 8 ++++ test/diff/CMakeLists.txt | 8 ++++ test/diff/input1uid.osm | 4 ++ test/diff/input2.osm | 2 +- test/diff/input2uid.osm | 4 ++ test/diff/output-compact-c-nouid | 7 ++++ test/diff/output-compact-c-nouid-opl | 8 ++++ test/diff/output-empty | 0 zsh_completion/_osmium | 3 ++ 11 files changed, 107 insertions(+), 8 deletions(-) create mode 100644 test/diff/input1uid.osm create mode 100644 test/diff/input2uid.osm create mode 100644 test/diff/output-compact-c-nouid create mode 100644 test/diff/output-compact-c-nouid-opl create mode 100644 test/diff/output-empty diff --git a/man/osmium-diff.md b/man/osmium-diff.md index 25b05d68..0e00e0f9 100644 --- a/man/osmium-diff.md +++ b/man/osmium-diff.md @@ -63,6 +63,19 @@ None of the output formats print the headers of the input files. -f, \--output-format=FORMAT : See the **OUTPUT FORMATS** section. +\--ignore-changeset +: Ignore changeset id on OSM objects when comparing files. When used with + the OPL output format the 'changeset' attribute is not written to the + output. + +\--ignore-uid +: Ignore user id on OSM objects when comparing files. When used with + the OPL output format the 'uid' attribute is not written to the output. + +\--ignore-user +: Ignore user name on OSM objects when comparing files. When used with + the OPL output format the 'user' attribute is not written to the output. + -o, \--output=FILE : Name of the output file. Default is '-' (STDOUT). @@ -107,7 +120,7 @@ None of the output formats print the headers of the input files. # EXAMPLES -Show difference between Nepal files from January 2016 and Febrary 2016 in +Show difference between Nepal files from January 2016 and February 2016 in compact format: osmium diff nepal-20160101.osm.pbf nepal-20160201.osm.pbf diff --git a/src/command_diff.cpp b/src/command_diff.cpp index 89b72e2e..5733c933 100644 --- a/src/command_diff.cpp +++ b/src/command_diff.cpp @@ -52,6 +52,9 @@ along with this program. If not, see . bool CommandDiff::setup(const std::vector& arguments) { po::options_description opts_cmd{"COMMAND OPTIONS"}; opts_cmd.add_options() + ("ignore-changeset", "Ignore changeset id when comparing objects") + ("ignore-uid", "Ignore user id when comparing objects") + ("ignore-user", "Ignore user name when comparing objects") ("object-type,t", po::value>(), "Read only objects of given type (node, way, relation)") ("output,o", po::value(), "Output file") ("output-format,f", po::value(), "Format of output file") @@ -93,6 +96,18 @@ bool CommandDiff::setup(const std::vector& arguments) { throw argument_error("You need exactly two input files for this command."); } + if (vm.count("ignore-changeset")) { + m_ignore_attrs_changeset = true; + } + + if (vm.count("ignore-uid")) { + m_ignore_attrs_uid = true; + } + + if (vm.count("ignore-user")) { + m_ignore_attrs_user = true; + } + if (vm.count("output")) { m_output_filename = vm["output"].as(); } @@ -130,6 +145,18 @@ bool CommandDiff::setup(const std::vector& arguments) { m_output_file = osmium::io::File{m_output_filename, m_output_format}; m_output_file.check(); + std::string metadata{"version+timestamp"}; + if (!m_ignore_attrs_changeset) { + metadata += "+changeset"; + } + if (!m_ignore_attrs_uid) { + metadata += "+uid"; + } + if (!m_ignore_attrs_changeset) { + metadata += "+user"; + } + m_output_file.set("add_metadata", metadata); + auto f = m_output_file.format(); if (f != osmium::io::file_format::opl && f != osmium::io::file_format::debug) { throw argument_error("File format does not support diff output. Use 'compact', 'opl' or 'debug' format."); @@ -248,6 +275,21 @@ class OutputActionOSM : public OutputAction { }; // class OutputActionOSM +void CommandDiff::update_object_crc(osmium::CRC* crc, const osmium::OSMObject &object) { + crc->update_bool(object.visible()); + crc->update(object.timestamp()); + crc->update(object.tags()); + if (!m_ignore_attrs_changeset) { + crc->update_int32(object.changeset()); + } + if (!m_ignore_attrs_uid) { + crc->update_int32(object.uid()); + } + if (!m_ignore_attrs_user) { + crc->update_string(object.user()); + } +} + bool CommandDiff::run() { osmium::io::Reader reader1{m_input_files[0], osm_entity_bits()}; osmium::io::ReaderWithProgressBar reader2{display_progress(), m_input_files[1], osm_entity_bits()}; @@ -298,18 +340,20 @@ bool CommandDiff::run() { } else { /* *it1 == *it2 */ osmium::CRC crc1; osmium::CRC crc2; + update_object_crc(&crc1, *it1); + update_object_crc(&crc2, *it2); switch (it1->type()) { case osmium::item_type::node: - crc1.update(static_cast(*it1)); - crc2.update(static_cast(*it2)); + crc1.update(static_cast(*it1).location()); + crc2.update(static_cast(*it2).location()); break; case osmium::item_type::way: - crc1.update(static_cast(*it1)); - crc2.update(static_cast(*it2)); + crc1.update(static_cast(*it1).nodes()); + crc2.update(static_cast(*it2).nodes()); break; case osmium::item_type::relation: - crc1.update(static_cast(*it1)); - crc2.update(static_cast(*it2)); + crc1.update(static_cast(*it1).members()); + crc2.update(static_cast(*it2).members()); break; default: break; diff --git a/src/command_diff.hpp b/src/command_diff.hpp index 100b8ab3..b5f1779f 100644 --- a/src/command_diff.hpp +++ b/src/command_diff.hpp @@ -25,15 +25,23 @@ along with this program. If not, see . #include "cmd.hpp" // IWYU pragma: export +#include +#include + #include #include class CommandDiff : public CommandWithMultipleOSMInputs, public with_osm_output { std::string m_output_action; + bool m_ignore_attrs_changeset = false; + bool m_ignore_attrs_uid = false; + bool m_ignore_attrs_user = false; bool m_show_summary = false; bool m_suppress_common = false; + void update_object_crc(osmium::CRC* crc, const osmium::OSMObject &object); + public: explicit CommandDiff(const CommandFactory& command_factory) : diff --git a/test/diff/CMakeLists.txt b/test/diff/CMakeLists.txt index 6c251de9..fe37b19d 100644 --- a/test/diff/CMakeLists.txt +++ b/test/diff/CMakeLists.txt @@ -20,4 +20,12 @@ check_diff(opl-c "-f opl -c" input1.osm input2.osm output-c.opl 1) check_diff(same "" input1.osm input1.osm output-same 0) +check_diff(ignore-uid "--ignore-uid -c" input1.osm input2.osm output-compact-c-nouid 1) + +check_diff(ignore-uid-15 "--ignore-uid -c" input1uid.osm input2uid.osm output-empty 0) + +check_diff(ignore-uid-opl "--ignore-uid -f opl -c" input1.osm input2.osm output-compact-c-nouid-opl 1) + +check_diff(ignore-uid-15-opl "--ignore-uid -f opl -c" input1uid.osm input2uid.osm output-empty 0) + #----------------------------------------------------------------------------- diff --git a/test/diff/input1uid.osm b/test/diff/input1uid.osm new file mode 100644 index 00000000..d186bebd --- /dev/null +++ b/test/diff/input1uid.osm @@ -0,0 +1,4 @@ + + + + diff --git a/test/diff/input2.osm b/test/diff/input2.osm index a6d5bcd7..e870c07b 100644 --- a/test/diff/input2.osm +++ b/test/diff/input2.osm @@ -1,5 +1,5 @@ - + diff --git a/test/diff/input2uid.osm b/test/diff/input2uid.osm new file mode 100644 index 00000000..1c71fd1f --- /dev/null +++ b/test/diff/input2uid.osm @@ -0,0 +1,4 @@ + + + + diff --git a/test/diff/output-compact-c-nouid b/test/diff/output-compact-c-nouid new file mode 100644 index 00000000..b9b86d6a --- /dev/null +++ b/test/diff/output-compact-c-nouid @@ -0,0 +1,7 @@ +-n11 v1 ++n11 v2 +-n13 v1 ++n14 v1 +*n16 v1 +-w21 v1 ++w21 v2 diff --git a/test/diff/output-compact-c-nouid-opl b/test/diff/output-compact-c-nouid-opl new file mode 100644 index 00000000..165b06c3 --- /dev/null +++ b/test/diff/output-compact-c-nouid-opl @@ -0,0 +1,8 @@ +-n11 v1 dV c1 t2015-01-01T01:00:00Z utest T x1 y2 ++n11 v2 dV c2 t2015-01-01T02:00:00Z utest T x2 y2 +-n13 v1 dV c1 t2015-01-01T01:00:00Z utest T x1 y4 ++n14 v1 dV c2 t2015-01-01T02:00:00Z utest T x1 y5 +-n16 v1 dV c1 t2015-01-01T02:00:00Z utest T x2 y5 ++n16 v1 dV c1 t2015-01-01T02:00:00Z utest T x1 y5 +-w21 v1 dV c1 t2015-01-01T01:00:00Z utest Txyz=abc Nn12,n13 ++w21 v2 dV c2 t2015-01-01T02:00:00Z utest Txyz=new Nn12,n14 diff --git a/test/diff/output-empty b/test/diff/output-empty new file mode 100644 index 00000000..e69de29b diff --git a/zsh_completion/_osmium b/zsh_completion/_osmium index 7e6878c8..df416e87 100644 --- a/zsh_completion/_osmium +++ b/zsh_completion/_osmium @@ -182,6 +182,9 @@ _osmium-diff() { ${(f)"$(_osmium-multiple-inputs-options)"} \ ${(f)"$(_osmium-diff-output-format-options)"} \ ${(f)"$(_osmium-output-options)"} \ + '--ignore-changeset[ignore changeset id on OSM objects when comparing files]' \ + '--ignore-uid[ignore user id on OSM objects when comparing files]' \ + '--ignore-user[ignore user name on OSM objects when comparing files]' \ '(--quiet)-q[report only when files differ]' \ '(-q)--quiet[report only when files differ]' \ '(--suppress-common)-c[suppress common objects]' \