Warn if an import contains multiple occurrences of the same UUID (#3560)
This commit is contained in:
@@ -32,6 +32,7 @@
|
|||||||
#include <format.h>
|
#include <format.h>
|
||||||
#include <shared.h>
|
#include <shared.h>
|
||||||
#include <util.h>
|
#include <util.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
CmdImport::CmdImport ()
|
CmdImport::CmdImport ()
|
||||||
@@ -90,6 +91,20 @@ int CmdImport::execute (std::string&)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Context::getContext ().footnote (format ("Imported {1} tasks.", count));
|
Context::getContext ().footnote (format ("Imported {1} tasks.", count));
|
||||||
|
|
||||||
|
// Warn the user about multiple occurrences of the same UUID.
|
||||||
|
auto duplicates = false;
|
||||||
|
for (const auto& [uuid, occurrences] : uuid_occurrences)
|
||||||
|
{
|
||||||
|
if (occurrences > 1)
|
||||||
|
{
|
||||||
|
duplicates = true;
|
||||||
|
Context::getContext ().footnote (format ("Input contains UUID '{1}' {2} times.", uuid, occurrences));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (duplicates)
|
||||||
|
Context::getContext ().footnote ("Tasks with the same UUID have been merged. Please check the results.");
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +201,9 @@ void CmdImport::importSingleTask (json::object* obj)
|
|||||||
|
|
||||||
// Check whether the imported task is new or a modified existing task.
|
// Check whether the imported task is new or a modified existing task.
|
||||||
Task before;
|
Task before;
|
||||||
if (Context::getContext ().tdb2.get (task.get ("uuid"), before))
|
auto uuid = task.get("uuid");
|
||||||
|
uuid_occurrences[uuid]++;
|
||||||
|
if (Context::getContext ().tdb2.get (uuid, before))
|
||||||
{
|
{
|
||||||
// We need to neglect updates from attributes with dynamic defaults
|
// We need to neglect updates from attributes with dynamic defaults
|
||||||
// unless they have been explicitly specified on import.
|
// unless they have been explicitly specified on import.
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ public:
|
|||||||
int execute (std::string&);
|
int execute (std::string&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::unordered_map<std::string, unsigned int> uuid_occurrences;
|
||||||
int import (const std::string&);
|
int import (const std::string&);
|
||||||
void importSingleTask (json::object*);
|
void importSingleTask (json::object*);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -224,6 +224,15 @@ class TestImport(TestCase):
|
|||||||
code, out2, err = self.t("export")
|
code, out2, err = self.t("export")
|
||||||
self.assertEqual(out1, out2)
|
self.assertEqual(out1, out2)
|
||||||
|
|
||||||
|
def test_import_duplicate_uuid_in_input(self):
|
||||||
|
"""Test import warns if input contains the same UUID twice."""
|
||||||
|
_data = """[
|
||||||
|
{"uuid":"a0000000-a000-a000-a000-a00000000000","description":"first description"},
|
||||||
|
{"uuid":"a0000000-a000-a000-a000-a00000000000","description":"second description"}
|
||||||
|
]"""
|
||||||
|
_, _, err = self.t("import", input=_data)
|
||||||
|
self.assertIn("Input contains UUID 'a0000000-a000-a000-a000-a00000000000' 2 times", err)
|
||||||
|
|
||||||
|
|
||||||
class TestImportExportRoundtrip(TestCase):
|
class TestImportExportRoundtrip(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user