# # # add_file "git_change.cc" # content [36ac90ebc9c461622315a75e53f3d3e2f31b69cb] # # add_file "git_change.hh" # content [031cc2efb3ffba1a881f22b485f9ad039e70e56a] # # add_file "unit-tests/git_change.cc" # content [dae7215d87f93975a61caacce1c8214dea75b9c0] # # patch "Makefile.am" # from [71dc300612ac5a26edff2f9643a19209e0c50968] # to [33969621e13d4b468317ed05fc7b0b479391d1f0] # # patch "cmd_othervcs.cc" # from [ca6b1401a25aefc8d105c34875e3c12b7de7a770] # to [9e422824e408cc244da6b40156e03b0bf769d4eb] # # patch "git_export.cc" # from [d5b856f5f9138740e1b796fd5844f97e53656dd2] # to [86a71cc98ad6b77161b79a057f5b5edabc6761a0] # # patch "git_export.hh" # from [fd36f0dab149c0e0f7d047b89f873abb3fcd2069] # to [7a82929d4b697da2668cf766734fea3febf065e2] # ============================================================ --- git_change.cc 36ac90ebc9c461622315a75e53f3d3e2f31b69cb +++ git_change.cc 36ac90ebc9c461622315a75e53f3d3e2f31b69cb @@ -0,0 +1,189 @@ +// Copyright (C) 2009 Derek Scherger +// +// This program is made available under the GNU GPL version 2.0 or +// greater. See the accompanying file COPYING for details. +// +// This program is distributed WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. + +#include "base.hh" +#include "git_change.hh" +#include "parallel_iter.hh" +#include "roster.hh" + +#include + +using std::make_pair; +using std::map; +using std::stack; +using std::string; +using std::vector; + +void +get_change(roster_t const & left, roster_t const & right, + git_change & change) +{ + typedef full_attr_map_t::const_iterator attr_iterator; + static attr_key exe_attr("mtn:execute"); + + parallel::iter i(left.all_nodes(), right.all_nodes()); + while (i.next()) + { + MM(i); + switch (i.state()) + { + case parallel::invalid: + I(false); + + case parallel::in_left: + // deleted + if (is_file_t(i.left_data())) + { + file_path path; + left.get_name(i.left_key(), path); + change.deletions.push_back(path); + } + break; + + case parallel::in_right: + // added + if (is_file_t(i.right_data())) + { + file_t file = downcast_to_file_t(i.right_data()); + + attr_iterator exe = file->attrs.find(exe_attr); + + string mode = "100644"; + if (exe != file->attrs.end() && + exe->second.first && // live attr + exe->second.second() == "true") + mode = "100755"; + + file_path path; + right.get_name(i.right_key(), path); + change.additions.push_back(git_add(path, + file->content, + mode)); + } + break; + + case parallel::in_both: + // moved/renamed/patched/attribute changes + if (is_file_t(i.left_data())) + { + file_t left_file = downcast_to_file_t(i.left_data()); + file_t right_file = downcast_to_file_t(i.right_data()); + + attr_iterator left_attr = left_file->attrs.find(exe_attr); + attr_iterator right_attr = right_file->attrs.find(exe_attr); + + string left_mode = "100644"; + string right_mode = "100644"; + + if (left_attr != left_file->attrs.end() && + left_attr->second.first && // live attr + left_attr->second.second() == "true") + left_mode = "100755"; + + if (right_attr != right_file->attrs.end() && + right_attr->second.first && // live attr + right_attr->second.second() == "true") + right_mode = "100755"; + + file_path left_path, right_path; + left.get_name(i.left_key(), left_path); + right.get_name(i.right_key(), right_path); + + if (left_path != right_path) + change.renames.push_back(make_pair(left_path, + right_path)); + + // git handles content changes as additions + if (left_file->content != right_file->content || + left_mode != right_mode) + change.additions.push_back(git_add(right_path, + right_file->content, + right_mode)); + } + break; + } + } +} + +// re-order renames so that they occur in the correct order +// i.e. rename a->b + rename b->c will be re-ordered as +// rename b->c + rename a->b +// this will also insert temporary names to resolve circular +// renames and name swaps: +// i.e. rename a->b + rename b->a will be re-ordered as +// rename a->tmp + rename b->a + rename tmp->b +void +reorder_renames(vector const & renames, + vector & reordered_renames) +{ + typedef map map_type; + + map_type rename_map; + + for (rename_iterator i = renames.begin(); i != renames.end(); ++i) + rename_map.insert(*i); + + while (!rename_map.empty()) + { + map_type::iterator i = rename_map.begin(); + I(i != rename_map.end()); + git_rename base(*i); + rename_map.erase(i); + + map_type::iterator next = rename_map.find(base.second); + stack rename_stack; + + // stack renames so their order can be reversed + while (next != rename_map.end()) + { + git_rename rename(*next); + rename_stack.push(rename); + rename_map.erase(next); + next = rename_map.find(rename.second); + } + + // break rename loops + if (!rename_stack.empty()) + { + git_rename const & top = rename_stack.top(); + // if there is a loop push another rename onto the stack that + // renames the old base to a temporary and adjust the base + // rename to account for this + if (base.first == top.second) + { + // the temporary path introduced here is pretty weak in + // terms of random filenames but should suffice for the + // already rare situations where any of this is required. + string path = top.second.as_internal(); + path += ".tmp.break-rename-loop"; + file_path tmp = file_path_internal(path); + rename_stack.push(git_rename(base.first, tmp)); + base.first = tmp; + } + } + + // insert the stacked renames in reverse order + while (!rename_stack.empty()) + { + git_rename rename = rename_stack.top(); + rename_stack.pop(); + reordered_renames.push_back(rename); + } + + reordered_renames.push_back(base); + } +} + +// Local Variables: +// mode: C++ +// fill-column: 76 +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s: ============================================================ --- git_change.hh 031cc2efb3ffba1a881f22b485f9ad039e70e56a +++ git_change.hh 031cc2efb3ffba1a881f22b485f9ad039e70e56a @@ -0,0 +1,55 @@ +#ifndef __GIT_CHANGE_HH__ +#define __GIT_CHANGE_HH__ + +// Copyright (C) 2009 Derek Scherger +// +// This program is made available under the GNU GPL version 2.0 or +// greater. See the accompanying file COPYING for details. +// +// This program is distributed WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. + +#include "paths.hh" +#include "vocab.hh" + +#include + +typedef file_path git_delete; +typedef std::pair git_rename; + +struct git_add +{ + file_path path; + file_id content; + std::string mode; + git_add(file_path path, file_id content, std::string mode) : + path(path), content(content), mode(mode) {} +}; + +typedef std::vector::const_iterator delete_iterator; +typedef std::vector::const_iterator rename_iterator; +typedef std::vector::const_iterator add_iterator; + +struct git_change +{ + std::vector deletions; + std::vector renames; + std::vector additions; +}; + +void get_change(roster_t const & left, roster_t const & right, + git_change & change); + +void reorder_renames(std::vector const & renames, + std::vector & reordered_renames); + +// Local Variables: +// mode: C++ +// fill-column: 76 +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s: + +#endif // __GIT_CHANGE_HH__ ============================================================ --- unit-tests/git_change.cc dae7215d87f93975a61caacce1c8214dea75b9c0 +++ unit-tests/git_change.cc dae7215d87f93975a61caacce1c8214dea75b9c0 @@ -0,0 +1,117 @@ +// Copyright (C) 2009 Derek Scherger +// +// This program is made available under the GNU GPL version 2.0 or +// greater. See the accompanying file COPYING for details. +// +// This program is distributed WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. + +#include "base.hh" +#include "unit_tests.hh" +#include "git_change.hh" + +using std::make_pair; +using std::vector; + +UNIT_TEST(reorder_chained_renames) +{ + vector renames, reordered_renames; + renames.push_back(make_pair(file_path_internal("a"), file_path_internal("b"))); + renames.push_back(make_pair(file_path_internal("b"), file_path_internal("c"))); + renames.push_back(make_pair(file_path_internal("c"), file_path_internal("d"))); + + // these should be reordered from a->b b->c c->d to c->d b->c a->b + reorder_renames(renames, reordered_renames); + rename_iterator rename = reordered_renames.begin(); + UNIT_TEST_CHECK(rename->first == file_path_internal("c")); + UNIT_TEST_CHECK(rename->second == file_path_internal("d")); + ++rename; + UNIT_TEST_CHECK(rename->first == file_path_internal("b")); + UNIT_TEST_CHECK(rename->second == file_path_internal("c")); + ++rename; + UNIT_TEST_CHECK(rename->first == file_path_internal("a")); + UNIT_TEST_CHECK(rename->second == file_path_internal("b")); + ++rename; + UNIT_TEST_CHECK(rename == reordered_renames.end()); +} + +UNIT_TEST(reorder_swapped_renames) +{ + vector renames, reordered_renames; + renames.push_back(make_pair(file_path_internal("a"), file_path_internal("b"))); + renames.push_back(make_pair(file_path_internal("b"), file_path_internal("a"))); + + // these should be reordered from a->b b->a to a->tmp b->a tmp->b + reorder_renames(renames, reordered_renames); + rename_iterator rename = reordered_renames.begin(); + UNIT_TEST_CHECK(rename->first == file_path_internal("a")); + UNIT_TEST_CHECK(rename->second == file_path_internal("a.tmp.break-rename-loop")); + ++rename; + UNIT_TEST_CHECK(rename->first == file_path_internal("b")); + UNIT_TEST_CHECK(rename->second == file_path_internal("a")); + ++rename; + UNIT_TEST_CHECK(rename->first == file_path_internal("a.tmp.break-rename-loop")); + UNIT_TEST_CHECK(rename->second == file_path_internal("b")); + ++rename; + UNIT_TEST_CHECK(rename == reordered_renames.end()); +} + +UNIT_TEST(reorder_rename_loop) +{ + vector renames, reordered_renames; + renames.push_back(make_pair(file_path_internal("a"), file_path_internal("b"))); + renames.push_back(make_pair(file_path_internal("b"), file_path_internal("c"))); + renames.push_back(make_pair(file_path_internal("c"), file_path_internal("a"))); + + // these should be reordered from a->b b->c c->a to a->tmp c->a b->c a->b tmp->b + reorder_renames(renames, reordered_renames); + rename_iterator rename = reordered_renames.begin(); + UNIT_TEST_CHECK(rename->first == file_path_internal("a")); + UNIT_TEST_CHECK(rename->second == file_path_internal("a.tmp.break-rename-loop")); + ++rename; + UNIT_TEST_CHECK(rename->first == file_path_internal("c")); + UNIT_TEST_CHECK(rename->second == file_path_internal("a")); + ++rename; + UNIT_TEST_CHECK(rename->first == file_path_internal("b")); + UNIT_TEST_CHECK(rename->second == file_path_internal("c")); + ++rename; + UNIT_TEST_CHECK(rename->first == file_path_internal("a.tmp.break-rename-loop")); + UNIT_TEST_CHECK(rename->second == file_path_internal("b")); + ++rename; + UNIT_TEST_CHECK(rename == reordered_renames.end()); +} + +UNIT_TEST(reorder_reversed_rename_loop) +{ + vector renames, reordered_renames; + renames.push_back(make_pair(file_path_internal("z"), file_path_internal("y"))); + renames.push_back(make_pair(file_path_internal("y"), file_path_internal("x"))); + renames.push_back(make_pair(file_path_internal("x"), file_path_internal("z"))); + + // assuming that the x->z rename gets pulled from the rename map first + // these should be reordered from z->y y->x x->z to x->tmp y->x z->y tmp->z + reorder_renames(renames, reordered_renames); + rename_iterator rename = reordered_renames.begin(); + UNIT_TEST_CHECK(rename->first == file_path_internal("x")); + UNIT_TEST_CHECK(rename->second == file_path_internal("x.tmp.break-rename-loop")); + ++rename; + UNIT_TEST_CHECK(rename->first == file_path_internal("y")); + UNIT_TEST_CHECK(rename->second == file_path_internal("x")); + ++rename; + UNIT_TEST_CHECK(rename->first == file_path_internal("z")); + UNIT_TEST_CHECK(rename->second == file_path_internal("y")); + ++rename; + UNIT_TEST_CHECK(rename->first == file_path_internal("x.tmp.break-rename-loop")); + UNIT_TEST_CHECK(rename->second == file_path_internal("z")); + ++rename; + UNIT_TEST_CHECK(rename == reordered_renames.end()); +} + +// Local Variables: +// mode: C++ +// fill-column: 76 +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s: ============================================================ --- Makefile.am 71dc300612ac5a26edff2f9643a19209e0c50968 +++ Makefile.am 33969621e13d4b468317ed05fc7b0b479391d1f0 @@ -53,7 +53,7 @@ MOST_SOURCES = \ merkle_tree.cc merkle_tree.hh \ lcs.cc lcs.hh \ rcs_import.cc rcs_import.hh \ - git_export.cc git_export.hh \ + git_change.cc git_change.hh git_export.cc git_export.hh \ revision.cc ancestry.cc revision.hh \ cset.cc cset.hh \ roster.cc roster.hh \ @@ -299,7 +299,8 @@ UNIT_TESTEES = \ # these files (part of the main program) contain code subject to unit testing UNIT_TESTEES = \ - basic_io.cc charset.cc commands.cc cset.cc globish.cc graph.cc \ + basic_io.cc charset.cc commands.cc cset.cc \ + git_change.cc globish.cc graph.cc \ merge_3way.cc merge_roster.cc netcmd.cc netxx_pipe.cc \ option.cc outdated_indicator.cc refiner.cc restrictions.cc \ revision.cc simplestring_xform.cc transforms.cc uri.cc \ @@ -311,6 +312,7 @@ UNIT_TESTERS = \ UNIT_TESTERS = \ unit-tests/basic_io.cc unit-tests/charset.cc \ unit-tests/commands.cc unit-tests/cset.cc \ + unit-tests/git_change.cc \ unit-tests/globish.cc unit-tests/graph.cc \ unit-tests/merge_3way.cc unit-tests/merge_roster.cc \ unit-tests/netcmd.cc unit-tests/netxx_pipe.cc \ ============================================================ --- cmd_othervcs.cc ca6b1401a25aefc8d105c34875e3c12b7de7a770 +++ cmd_othervcs.cc 9e422824e408cc244da6b40156e03b0bf769d4eb @@ -12,6 +12,7 @@ #include "cmd.hh" #include "app_state.hh" #include "database.hh" +#include "git_change.hh" #include "git_export.hh" #include "project.hh" #include "rcs_import.hh" @@ -115,7 +116,7 @@ CMD(git_export, "git_export", "", CMD_RE vector revisions; toposort(db, revision_set, revisions); - map change_map; + map change_map; load_changes(db, revisions, change_map); ============================================================ --- git_export.cc d5b856f5f9138740e1b796fd5844f97e53656dd2 +++ git_export.cc 86a71cc98ad6b77161b79a057f5b5edabc6761a0 @@ -12,9 +12,9 @@ #include "database.hh" #include "dates.hh" #include "file_io.hh" +#include "git_change.hh" #include "git_export.hh" #include "outdated_indicator.hh" -#include "parallel_iter.hh" #include "revision.hh" #include "roster.hh" #include "simplestring_xform.hh" @@ -23,15 +23,12 @@ #include #include -#include using std::cout; using std::istringstream; -using std::make_pair; using std::map; using std::ostringstream; using std::set; -using std::stack; using std::string; using std::vector; @@ -56,173 +53,6 @@ namespace return quoted; } - - typedef vector::const_iterator delete_iterator; - typedef vector::const_iterator rename_iterator; - typedef vector::const_iterator add_iterator; - - attr_key exe_attr("mtn:execute"); - - void - get_changes(roster_t const & left, roster_t const & right, - file_changes & changes) - { - - typedef full_attr_map_t::const_iterator attr_iterator; - - parallel::iter i(left.all_nodes(), right.all_nodes()); - while (i.next()) - { - MM(i); - switch (i.state()) - { - case parallel::invalid: - I(false); - - case parallel::in_left: - // deleted - if (is_file_t(i.left_data())) - { - file_path path; - left.get_name(i.left_key(), path); - changes.deletions.push_back(file_delete(path)); - } - break; - - case parallel::in_right: - // added - if (is_file_t(i.right_data())) - { - file_t file = downcast_to_file_t(i.right_data()); - - attr_iterator exe = file->attrs.find(exe_attr); - - string mode = "100644"; - if (exe != file->attrs.end() && - exe->second.first && // live attr - exe->second.second() == "true") - mode = "100755"; - - file_path path; - right.get_name(i.right_key(), path); - changes.additions.push_back(file_add(path, - file->content, - mode)); - } - break; - - case parallel::in_both: - // moved/renamed/patched/attribute changes - if (is_file_t(i.left_data())) - { - file_t left_file = downcast_to_file_t(i.left_data()); - file_t right_file = downcast_to_file_t(i.right_data()); - - attr_iterator left_attr = left_file->attrs.find(exe_attr); - attr_iterator right_attr = right_file->attrs.find(exe_attr); - - string left_mode = "100644"; - string right_mode = "100644"; - - if (left_attr != left_file->attrs.end() && - left_attr->second.first && // live attr - left_attr->second.second() == "true") - left_mode = "100755"; - - if (right_attr != right_file->attrs.end() && - right_attr->second.first && // live attr - right_attr->second.second() == "true") - right_mode = "100755"; - - file_path left_path, right_path; - left.get_name(i.left_key(), left_path); - right.get_name(i.right_key(), right_path); - - if (left_path != right_path) - changes.renames.push_back(file_rename(left_path, - right_path)); - - // git handles content changes as additions - if (left_file->content != right_file->content || - left_mode != right_mode) - changes.additions.push_back(file_add(right_path, - right_file->content, - right_mode)); - } - break; - } - } - } - - // re-order renames so that they occur in the correct order - // i.e. rename a->b + rename b->c will be re-ordered as - // rename b->c + rename a->b - // this will also insert temporary names to resolve circular - // renames and name swaps: - // i.e. rename a->b + rename b->a will be re-ordered as - // rename a->tmp + rename b->a + rename tmp->b - void - reorder_renames(vector const & renames, - vector & reordered_renames) - { - typedef map map_type; - - map_type rename_map; - - for (rename_iterator i = renames.begin(); i != renames.end(); ++i) - rename_map.insert(make_pair(i->old_path, i->new_path)); - - while (!rename_map.empty()) - { - map_type::iterator i = rename_map.begin(); - I(i != rename_map.end()); - file_rename base(i->first, i->second); - rename_map.erase(i); - - map_type::iterator next = rename_map.find(base.new_path); - stack rename_stack; - - // stack renames so their order can be reversed - while (next != rename_map.end()) - { - file_rename rename(next->first, next->second); - rename_stack.push(rename); - rename_map.erase(next); - next = rename_map.find(rename.new_path); - } - - // break rename loops - if (!rename_stack.empty()) - { - file_rename const & top = rename_stack.top(); - // if there is a loop push another rename onto the stack that - // renames the old base to a temporary and adjust the base - // rename to account for this - if (base.old_path == top.new_path) - { - // the temporary path introduced here is pretty weak in - // terms of random filenames but should suffice for the - // already rare situations where any of this is required. - string path = top.new_path.as_internal(); - path += ".tmp.break-rename-loop"; - file_path tmp = file_path_internal(path); - rename_stack.push(file_rename(base.old_path, tmp)); - base.old_path = tmp; - } - } - - // insert the stacked renames in reverse order - while (!rename_stack.empty()) - { - file_rename rename = rename_stack.top(); - rename_stack.pop(); - reordered_renames.push_back(rename); - } - - reordered_renames.push_back(base); - } - } - }; void @@ -301,7 +131,7 @@ load_changes(database & db, void load_changes(database & db, vector const & revisions, - map & change_map) + map & change_map) { // process revisions in reverse order and calculate the file changes for // each revision. these are cached in a map for use in the export phase @@ -342,8 +172,8 @@ load_changes(database & db, db.get_roster(parent1, old_roster); db.get_roster(*r, new_roster); - file_changes changes; - get_changes(old_roster, new_roster, changes); + git_change changes; + get_change(old_roster, new_roster, changes); change_map[*r] = changes; ++loaded; @@ -356,7 +186,7 @@ export_changes(database & db, map & marked_revs, map const & author_map, map const & branch_map, - map const & change_map, + map const & change_map, bool log_revids, bool log_certs) { size_t revnum = 0; @@ -498,17 +328,17 @@ export_changes(database & db, else I(false); - map::const_iterator f = change_map.find(*r); + map::const_iterator f = change_map.find(*r); I(f != change_map.end()); - file_changes const & changes = f->second; + git_change const & change = f->second; - vector reordered_renames; - reorder_renames(changes.renames, reordered_renames); + vector reordered_renames; + reorder_renames(change.renames, reordered_renames); // emit file data blobs for modified and added files for (add_iterator - i = changes.additions.begin(); i != changes.additions.end(); ++i) + i = change.additions.begin(); i != change.additions.end(); ++i) { if (marked_files.find(i->content) == marked_files.end()) { @@ -572,17 +402,17 @@ export_changes(database & db, cout << "merge :" << marked_revs[parent2] << "\n"; for (delete_iterator - i = changes.deletions.begin(); i != changes.deletions.end(); ++i) - cout << "D " << quote_path(i->path) << "\n"; + i = change.deletions.begin(); i != change.deletions.end(); ++i) + cout << "D " << quote_path(*i) << "\n"; for (rename_iterator i = reordered_renames.begin(); i != reordered_renames.end(); ++i) cout << "R " - << quote_path(i->old_path) << " " - << quote_path(i->new_path) << "\n"; + << quote_path(i->first) << " " + << quote_path(i->second) << "\n"; for (add_iterator - i = changes.additions.begin(); i != changes.additions.end(); ++i) + i = change.additions.begin(); i != change.additions.end(); ++i) cout << "M " << i->mode << " :" << marked_files[i->content] << " " << quote_path(i->path) << "\n"; @@ -643,7 +473,6 @@ export_root_refs(database & db, << "from :" << marked_revs[*i] << "\n"; } - void export_leaf_refs(database & db, map & marked_revs) @@ -656,106 +485,6 @@ export_leaf_refs(database & db, << "from :" << marked_revs[*i] << "\n"; } -#ifdef BUILD_UNIT_TESTS - -#include "unit_tests.hh" - -UNIT_TEST(git_rename_reordering, reorder_chained_renames) -{ - vector renames, reordered_renames; - renames.push_back(file_rename(file_path_internal("a"), file_path_internal("b"))); - renames.push_back(file_rename(file_path_internal("b"), file_path_internal("c"))); - renames.push_back(file_rename(file_path_internal("c"), file_path_internal("d"))); - - // these should be reordered from a->b b->c c->d to c->d b->c a->b - reorder_renames(renames, reordered_renames); - rename_iterator rename = reordered_renames.begin(); - UNIT_TEST_CHECK(rename->old_path == file_path_internal("c")); - UNIT_TEST_CHECK(rename->new_path == file_path_internal("d")); - ++rename; - UNIT_TEST_CHECK(rename->old_path == file_path_internal("b")); - UNIT_TEST_CHECK(rename->new_path == file_path_internal("c")); - ++rename; - UNIT_TEST_CHECK(rename->old_path == file_path_internal("a")); - UNIT_TEST_CHECK(rename->new_path == file_path_internal("b")); - ++rename; - UNIT_TEST_CHECK(rename == reordered_renames.end()); -} - -UNIT_TEST(git_rename_reordering, reorder_swapped_renames) -{ - vector renames, reordered_renames; - renames.push_back(file_rename(file_path_internal("a"), file_path_internal("b"))); - renames.push_back(file_rename(file_path_internal("b"), file_path_internal("a"))); - - // these should be reordered from a->b b->a to a->tmp b->a tmp->b - reorder_renames(renames, reordered_renames); - rename_iterator rename = reordered_renames.begin(); - UNIT_TEST_CHECK(rename->old_path == file_path_internal("a")); - UNIT_TEST_CHECK(rename->new_path == file_path_internal("a.tmp.break-rename-loop")); - ++rename; - UNIT_TEST_CHECK(rename->old_path == file_path_internal("b")); - UNIT_TEST_CHECK(rename->new_path == file_path_internal("a")); - ++rename; - UNIT_TEST_CHECK(rename->old_path == file_path_internal("a.tmp.break-rename-loop")); - UNIT_TEST_CHECK(rename->new_path == file_path_internal("b")); - ++rename; - UNIT_TEST_CHECK(rename == reordered_renames.end()); -} - -UNIT_TEST(git_rename_reordering, reorder_rename_loop) -{ - vector renames, reordered_renames; - renames.push_back(file_rename(file_path_internal("a"), file_path_internal("b"))); - renames.push_back(file_rename(file_path_internal("b"), file_path_internal("c"))); - renames.push_back(file_rename(file_path_internal("c"), file_path_internal("a"))); - - // these should be reordered from a->b b->c c->a to a->tmp c->a b->c a->b tmp->b - reorder_renames(renames, reordered_renames); - rename_iterator rename = reordered_renames.begin(); - UNIT_TEST_CHECK(rename->old_path == file_path_internal("a")); - UNIT_TEST_CHECK(rename->new_path == file_path_internal("a.tmp.break-rename-loop")); - ++rename; - UNIT_TEST_CHECK(rename->old_path == file_path_internal("c")); - UNIT_TEST_CHECK(rename->new_path == file_path_internal("a")); - ++rename; - UNIT_TEST_CHECK(rename->old_path == file_path_internal("b")); - UNIT_TEST_CHECK(rename->new_path == file_path_internal("c")); - ++rename; - UNIT_TEST_CHECK(rename->old_path == file_path_internal("a.tmp.break-rename-loop")); - UNIT_TEST_CHECK(rename->new_path == file_path_internal("b")); - ++rename; - UNIT_TEST_CHECK(rename == reordered_renames.end()); -} - -UNIT_TEST(git_rename_reordering, reorder_reversed_rename_loop) -{ - vector renames, reordered_renames; - renames.push_back(file_rename(file_path_internal("z"), file_path_internal("y"))); - renames.push_back(file_rename(file_path_internal("y"), file_path_internal("x"))); - renames.push_back(file_rename(file_path_internal("x"), file_path_internal("z"))); - - // assuming that the x->z rename gets pulled from the rename map first - // these should be reordered from z->y y->x x->z to x->tmp y->x z->y tmp->z - reorder_renames(renames, reordered_renames); - rename_iterator rename = reordered_renames.begin(); - UNIT_TEST_CHECK(rename->old_path == file_path_internal("x")); - UNIT_TEST_CHECK(rename->new_path == file_path_internal("x.tmp.break-rename-loop")); - ++rename; - UNIT_TEST_CHECK(rename->old_path == file_path_internal("y")); - UNIT_TEST_CHECK(rename->new_path == file_path_internal("x")); - ++rename; - UNIT_TEST_CHECK(rename->old_path == file_path_internal("z")); - UNIT_TEST_CHECK(rename->new_path == file_path_internal("y")); - ++rename; - UNIT_TEST_CHECK(rename->old_path == file_path_internal("x.tmp.break-rename-loop")); - UNIT_TEST_CHECK(rename->new_path == file_path_internal("z")); - ++rename; - UNIT_TEST_CHECK(rename == reordered_renames.end()); -} - -#endif // BUILD_UNIT_TESTS - // Local Variables: // mode: C++ // fill-column: 76 ============================================================ --- git_export.hh fd36f0dab149c0e0f7d047b89f873abb3fcd2069 +++ git_export.hh 7a82929d4b697da2668cf766734fea3febf065e2 @@ -10,38 +10,6 @@ // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. -struct file_delete -{ - file_path path; - file_delete(file_path path) : - path(path) {} -}; - -struct file_rename -{ - file_path old_path; - file_path new_path; - file_rename(file_path old_path, file_path new_path) : - old_path(old_path), new_path(new_path) {} -}; - -struct file_add -{ - file_path path; - file_id content; - std::string mode; - file_add(file_path path, file_id content, std::string mode) : - path(path), content(content), mode(mode) {} -}; - -struct file_changes -{ - std::vector deletions; - std::vector renames; - std::vector additions; -}; - - void read_mappings(system_path const & path, std::map & mappings); @@ -53,16 +21,16 @@ void load_changes(database & db, void load_changes(database & db, std::vector const & revisions, - std::map & change_map); + std::map & change_map); void export_changes(database & db, std::vector const & revisions, std::map & marked_revs, std::map const & author_map, std::map const & branch_map, - std::map const & change_map, + std::map const & change_map, bool log_revids, bool log_certs); - + void export_rev_refs(std::vector const & revisions, std::map & marked_revs); @@ -80,4 +48,4 @@ void export_leaf_refs(database & db, // End: // vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s: -#endif // __RCS_IMPORT_HH__ +#endif // __GIT_EXPORT_HH__