# # patch "ChangeLog" # from [ac05412182119677d3c15007216968d129a477a3] # to [d5cdabdc96bae23dfa3127be81f64cdc11cf8f6f] # # patch "automate.cc" # from [104a3a0307c16c724da0fed33f087175aaaba5bf] # to [6e3b8cec00c8f4d0d91d8d9fd14c4d06e8f0eef0] # # patch "manifest.cc" # from [cfa44e867c9068323e6cfe566b69d2e84f103264] # to [2d4e047a2587f9b379fad559d192b317d6e2b47e] # # patch "manifest.hh" # from [d96380ff7a7e4e2cef53ad864608b6e97e484207] # to [d86a3fe804cf18e9e31af16401dcda6391225288] # # patch "monotone.texi" # from [1043aaa99cad1d0060f75058661a71ad85c12ac5] # to [9f2c6606e84058bb985b759da3da959f94696ab0] # # patch "tests/t_automate_inventory.at" # from [81165e26ca6a1c4c1310a8f2d1ad28feab636ea9] # to [109af5a233e8700e3d11694aefc5f03ddc84107e] # --- ChangeLog +++ ChangeLog @@ -1,3 +1,17 @@ +2005-05-12 Derek Scherger + + * automate.cc: bump version number to 1.0 + (struct inventory_item): add pre/post states + (inventory_paths): remove obsolete function + (inventory_pre_state, inventory_post_state, inventory_file_state, + inventory_renames): add fancy new functions + (automate_inventory): rework for new output format + * manifest.{cc,hh} (classify_paths): rename to ... + (classify_manifest_paths): ... this and work solely from manifest + * monotone.texi: (Automation): update inventory docs + * tests/t_automate_inventory.at: update for new format and add + some more tests + 2005-05-11 Timothy Brownawell * revision.cc (expand_dominators): Fix bitmap size-matching. --- automate.cc +++ automate.cc @@ -15,9 +15,10 @@ #include "commands.hh" #include "restrictions.hh" #include "revision.hh" +#include "transforms.hh" #include "vocab.hh" -static std::string const interface_version = "0.2"; +static std::string const interface_version = "1.0"; // Name: interface_version // Arguments: none @@ -452,102 +453,158 @@ output << *i << std::endl; } +// consider a changeset with the following +// +// deletions +// renames from to +// additions +// +// pre-state corresponds to deletions and the "from" side of renames +// post-state corresponds to the "to" side of renames and additions +// file-state corresponds to the state of the file with the given name +// +// pre and post state are related to the path rearrangement specified in MT/work +// file state is related to the details of the resulting file + struct inventory_item { - enum pstat - { UNCHANGED_PATH, ADDED_PATH, DROPPED_PATH, RENAMED_PATH, UNKNOWN_PATH, IGNORED_PATH } - path_status; + enum pstate + { KNOWN_PATH, ADDED_PATH, DROPPED_PATH, RENAMED_PATH } + pre_state, post_state; - enum dstat - { UNCHANGED_DATA, PATCHED_DATA, MISSING_DATA } - data_status; + enum fstate + { KNOWN_FILE, PATCHED_FILE, MISSING_FILE, UNKNOWN_FILE, IGNORED_FILE } + file_state; enum ptype { FILE, DIRECTORY } path_type; - file_path old_path; + size_t pre_id, post_id; inventory_item(): - path_status(UNCHANGED_PATH), data_status(UNCHANGED_DATA), path_type(FILE), old_path() {} + pre_state(KNOWN_PATH), post_state(KNOWN_PATH), + file_state(KNOWN_FILE), + path_type(FILE), + pre_id(0), post_id(0) {} }; typedef std::map inventory_map; static void -inventory_paths(inventory_map & inventory, - path_set const & paths, - inventory_item::pstat path_status, - inventory_item::ptype path_type = inventory_item::FILE) +inventory_pre_state(inventory_map & inventory, + path_set const & paths, + inventory_item::pstate pre_state, + size_t id = 0, + inventory_item::ptype path_type = inventory_item::FILE) { for (path_set::const_iterator i = paths.begin(); i != paths.end(); i++) { - L(F("%d %d %s\n") % inventory[*i].path_status % path_status % *i); - I(inventory[*i].path_status == inventory_item::UNCHANGED_PATH); - inventory[*i].path_status = path_status; + L(F("%d %d %s\n") % inventory[*i].pre_state % pre_state % *i); + I(inventory[*i].pre_state == inventory_item::KNOWN_PATH); + inventory[*i].pre_state = pre_state; inventory[*i].path_type = path_type; + if (id != 0) + { + I(inventory[*i].pre_id == 0); + inventory[*i].pre_id = id; + } } } static void -inventory_paths(inventory_map & inventory, - path_set const & paths, - inventory_item::dstat data_status) +inventory_post_state(inventory_map & inventory, + path_set const & paths, + inventory_item::pstate post_state, + size_t id = 0, + inventory_item::ptype path_type = inventory_item::FILE) { for (path_set::const_iterator i = paths.begin(); i != paths.end(); i++) { - L(F("%d %d %s\n") % inventory[*i].data_status % data_status % *i); - I(inventory[*i].data_status == inventory_item::UNCHANGED_DATA); - inventory[*i].data_status = data_status; + L(F("%d %d %s\n") % inventory[*i].post_state % post_state % *i); + I(inventory[*i].post_state == inventory_item::KNOWN_PATH); + inventory[*i].post_state = post_state; + inventory[*i].path_type = path_type; + if (id != 0) + { + I(inventory[*i].post_id == 0); + inventory[*i].post_id = id; + } } } static void -inventory_paths(inventory_map & inventory, - std::map const & renames, - inventory_item::pstat path_status, - inventory_item::ptype path_type = inventory_item::FILE) +inventory_file_state(inventory_map & inventory, + path_set const & paths, + inventory_item::fstate file_state) { + for (path_set::const_iterator i = paths.begin(); i != paths.end(); i++) + { + L(F("%d %d %s\n") % inventory[*i].file_state % file_state % *i); + I(inventory[*i].file_state == inventory_item::KNOWN_FILE); + inventory[*i].file_state = file_state; + } +} + +static void +inventory_renames(inventory_map & inventory, + std::map const & renames, + inventory_item::ptype path_type = inventory_item::FILE) +{ + path_set old_name; + path_set new_name; + + static size_t id = 1; + for (std::map::const_iterator i = renames.begin(); i != renames.end(); i++) { - L(F("%d %d %s %s\n") % inventory[i->second].path_status % path_status % i->first % i->second); - I(inventory[i->second].path_status == inventory_item::UNCHANGED_PATH); - inventory[i->second].path_status = inventory_item::RENAMED_PATH; - inventory[i->second].path_type = path_type; - inventory[i->second].old_path = i->first; + old_name.insert(i->first); + new_name.insert(i->second); + + inventory_pre_state(inventory, old_name, inventory_item::RENAMED_PATH, id, path_type); + inventory_post_state(inventory, new_name, inventory_item::RENAMED_PATH, id, path_type); + + id++; + + old_name.clear(); + new_name.clear(); } } // Name: inventory // Arguments: none -// Added in: 0.2 -// Purpose: Prints all the files found in a working copy or current manifest -// prefixed by 2 status code characters. The first status code character -// indicates the status of the path itsself and is drawn from the following -// set: +// Added in: 1.0 +// Purpose: Prints a summary of every file found in the working copy or its +// associated base manifest. Each unique path is listed on a line prefixed by +// three status characters and two numeric values used for identifying +// renames. The three status characters are as follows. // -// ' ' the path is unchanged from the current manifest -// '+' the path has been added to the current manifest -// '-' the path has been dropped from the current manifest -// '%' the path has been renamed in the current manifest, both the old and new name are listed -// '?' the path is unknown, it exists in the working copy but not in the current manifest -// '~' the path is ignored by the current ignore_file lua hook setting -// -// The second status code character indicates the status of the data associated -// with the path and is drawn from the following set: +// column 1 pre-state +// ' ' the path was unchanged in the pre-state +// 'D' the path was deleted from the pre-state +// 'R' the path was renamed from the pre-state name +// column 2 post-state +// ' ' the path was unchanged in the post-state +// 'R' the path was renamed to the post-state name +// 'A' the path was added to the post-state +// column 3 file-state +// ' ' the file is known and unchanged from the current manifest version +// 'P' the file is patched to a new version +// 'U' the file is unknown and not included in the current manifest +// 'I' the file is ignored and not included in the current manifest +// 'M' the file is missing but is included in the current manifest // -// ' ' the data is unchanged, its sha1 version matches the version in the base manifest -// '#' the data is changed, its sha1 version differs from the version in the base manifest -// '!' the data is missing and its sha1 version cannot be computed +// Output format: Each path is printed on its own line, prefixed by three status +// characters as described above. The status is followed by a single space and +// two numbers, each separated by a single space, used for identifying renames. +// The numbers are followed by a single space and then the pathname, which +// includes the rest of the line. Directory paths are identified as ending with +// the "/" character, file paths do not end in this character. // -// Output format: Each file is printed on its own line, prefixed by a -// two character status code and a single space character. All filenames are -// quoted with double quotes (") to support filenames containg spaces. Intervening quotes -// are escaped with \". Directories are identified by paths ending with '/' characters. -// Rename lines list the old name first, followed by the new name. // Error conditions: If no working copy book keeping MT directory is found, // prints an error message to stderr, and exits with status 1. + static void automate_inventory(std::vector args, std::string const & help_name, @@ -559,12 +616,12 @@ manifest_id old_manifest_id; revision_id old_revision_id; - manifest_map m_old; + manifest_map m_old, m_new; path_set old_paths, new_paths, empty; change_set::path_rearrangement included, excluded; + change_set cs; path_set missing, changed, unchanged, unknown, ignored; inventory_map inventory; - app.require_working_copy(); calculate_restricted_rearrangement(app, args, @@ -572,74 +629,111 @@ m_old, old_paths, new_paths, included, excluded); - file_itemizer u(app, new_paths, unknown, ignored); - walk_tree(u); + // this is a bit screwey. we need to rearrange the old manifest + // according to the included rearrangement and for that we need + // a complete changeset, which is normally obtained from both + // the old and the new manifest. we can't do that because there + // may be missing files, so instead we add our own set of deltas + // below. - // remove deleted paths from the set of unknown paths + // we have the rearrangement of the changeset from above + // now we need to build up the deltas for the added files - for (path_set::const_iterator i = included.deleted_files.begin(); - i != included.deleted_files.end(); ++i) - unknown.erase(*i); + cs.rearrangement = included; - for (path_set::const_iterator i = included.deleted_dirs.begin(); - i != included.deleted_dirs.end(); ++i) - unknown.erase(*i); + hexenc null_ident; - classify_paths(app, new_paths, m_old, missing, changed, unchanged); + for (path_set::const_iterator + i = included.added_files.begin(); + i != included.added_files.end(); ++i) + { + if (file_exists(*i)) + { + // add path from [] to [xxx] + hexenc ident; + calculate_ident(*i, ident, app.lua); + cs.deltas.insert(std::make_pair(*i,std::make_pair(null_ident, ident))); + } + else + { + // remove missing files from the added list since they have not deltas + missing.insert(*i); + cs.rearrangement.added_files.erase(*i); + } + } - inventory_paths(inventory, missing, inventory_item::MISSING_DATA); + apply_change_set(m_old, cs, m_new); - inventory_paths(inventory, included.deleted_files, inventory_item::DROPPED_PATH); - inventory_paths(inventory, included.deleted_dirs, inventory_item::DROPPED_PATH, inventory_item::DIRECTORY); + classify_manifest_paths(app, m_new, missing, changed, unchanged); - inventory_paths(inventory, included.renamed_files, inventory_item::RENAMED_PATH); - inventory_paths(inventory, included.renamed_dirs, inventory_item::RENAMED_PATH, inventory_item::DIRECTORY); + // remove the remaining added files from the unchanged set since they have been + // changed in the deltas construction above. also, only consider the file as + // changed if its not missing - inventory_paths(inventory, included.added_files, inventory_item::ADDED_PATH); - inventory_paths(inventory, changed, inventory_item::PATCHED_DATA); - - inventory_paths(inventory, unchanged, inventory_item::UNCHANGED_DATA); - inventory_paths(inventory, unknown, inventory_item::UNKNOWN_PATH); - inventory_paths(inventory, ignored, inventory_item::IGNORED_PATH); + for (path_set::const_iterator + i = included.added_files.begin(); + i != included.added_files.end(); ++i) + { + unchanged.erase(*i); + if (missing.find(*i) == missing.end()) + changed.insert(*i); + } + file_itemizer u(app, new_paths, unknown, ignored); + walk_tree(u); + + inventory_file_state(inventory, missing, inventory_item::MISSING_FILE); + + inventory_pre_state(inventory, included.deleted_files, inventory_item::DROPPED_PATH); + inventory_pre_state(inventory, included.deleted_dirs, + inventory_item::DROPPED_PATH, inventory_item::DIRECTORY); + + inventory_renames(inventory, included.renamed_files); + inventory_renames(inventory, included.renamed_dirs, inventory_item::DIRECTORY); + + inventory_post_state(inventory, included.added_files, inventory_item::ADDED_PATH); + + inventory_file_state(inventory, changed, inventory_item::PATCHED_FILE); + inventory_file_state(inventory, unchanged, inventory_item::KNOWN_FILE); + inventory_file_state(inventory, unknown, inventory_item::UNKNOWN_FILE); + inventory_file_state(inventory, ignored, inventory_item::IGNORED_FILE); + for (inventory_map::const_iterator i = inventory.begin(); i != inventory.end(); ++i) { - switch (inventory[i->first].path_status) + switch (inventory[i->first].pre_state) { - case inventory_item::UNCHANGED_PATH: output << " "; break; - case inventory_item::ADDED_PATH: output << "+"; break; - case inventory_item::DROPPED_PATH: output << "-"; break; - case inventory_item::RENAMED_PATH: output << "%"; break; - case inventory_item::UNKNOWN_PATH: output << "?"; break; - case inventory_item::IGNORED_PATH: output << "~"; break; + case inventory_item::KNOWN_PATH: output << " "; break; + case inventory_item::DROPPED_PATH: output << "D"; break; + case inventory_item::RENAMED_PATH: output << "R"; break; + default: I(false); // invalid pre_state } - switch (inventory[i->first].data_status) + switch (inventory[i->first].post_state) { - case inventory_item::UNCHANGED_DATA: output << " "; break; - case inventory_item::PATCHED_DATA: output << "#"; break; - case inventory_item::MISSING_DATA: output << "!"; break; + case inventory_item::KNOWN_PATH: output << " "; break; + case inventory_item::RENAMED_PATH: output << "R"; break; + case inventory_item::ADDED_PATH: output << "A"; break; + default: I(false); // invalid post_state } - output << " "; - - switch (inventory[i->first].path_type) + switch (inventory[i->first].file_state) { - case inventory_item::FILE: - if (inventory[i->first].path_status == inventory_item::RENAMED_PATH) - output << basic_io::escape(inventory[i->first].old_path()) << " "; - - output << basic_io::escape(i->first()); - break; + case inventory_item::KNOWN_FILE: output << " "; break; + case inventory_item::PATCHED_FILE: output << "P"; break; + case inventory_item::UNKNOWN_FILE: output << "U"; break; + case inventory_item::IGNORED_FILE: output << "I"; break; + case inventory_item::MISSING_FILE: output << "M"; break; + } - case inventory_item::DIRECTORY: - if (inventory[i->first].path_status == inventory_item::RENAMED_PATH) - output << basic_io::escape(inventory[i->first].old_path() + "/") << " "; - - output << basic_io::escape(i->first() + "/"); - break; - } - + // need directory indicators + + output << " " << inventory[i->first].pre_id + << " " << inventory[i->first].post_id + << " " << i->first; + + if (inventory[i->first].path_type == inventory_item::DIRECTORY) + output << "/"; + output << std::endl; } --- manifest.cc +++ manifest.cc @@ -84,12 +84,11 @@ } void -classify_paths(app_state & app, - path_set const & paths, - manifest_map const & m_old, - path_set & missing, - path_set & changed, - path_set & unchanged) +classify_manifest_paths(app_state & app, + manifest_map const & man, + path_set & missing, + path_set & changed, + path_set & unchanged) { inodeprint_map ipm; @@ -103,48 +102,41 @@ // this code is speed critical, hence the use of inode fingerprints so be // careful when making changes in here and preferably do some timing tests - for (path_set::const_iterator i = paths.begin(); i != paths.end(); ++i) + for (manifest_map::const_iterator i = man.begin(); i != man.end(); ++i) { - if (app.restriction_includes(*i)) + if (app.restriction_includes(i->first)) { // compute the current sha1 id for included files // we might be able to avoid it, if we have an inode fingerprint... - if (inodeprint_unchanged(ipm, *i)) + if (inodeprint_unchanged(ipm, i->first)) { // the inode fingerprint hasn't changed, so we assume the file // hasn't either. - manifest_map::const_iterator k = m_old.find(*i); - I(k != m_old.end()); - unchanged.insert(*i); + manifest_map::const_iterator k = man.find(i->first); + I(k != man.end()); + unchanged.insert(i->first); continue; } // ...ah, well, no good fingerprint, just check directly. - if (file_exists(*i)) + if (file_exists(i->first)) { hexenc ident; - calculate_ident(*i, ident, app.lua); - manifest_map::const_iterator k = m_old.find(*i); + calculate_ident(i->first, ident, app.lua); - if (k != m_old.end()) - { - if (ident == k->second.inner()) - unchanged.insert(*i); - else - changed.insert(*i); - } + if (ident == i->second.inner()) + unchanged.insert(i->first); + else + changed.insert(i->first); - // if the path was not found in the old manifest it must have - // been added or renamed ad it's ignored here - } else - missing.insert(*i); + missing.insert(i->first); } else { // changes to excluded files are ignored - unchanged.insert(*i); + unchanged.insert(i->first); } } } --- manifest.hh +++ manifest.hh @@ -76,12 +76,11 @@ void extract_path_set(manifest_map const & man, path_set & paths); -void classify_paths(app_state & app, - path_set const & paths, - manifest_map const & m_old, - path_set & missing, - path_set & changed, - path_set & unchanged); +void classify_manifest_paths(app_state & app, + manifest_map const & man, + path_set & missing, + path_set & changed, + path_set & unchanged); void build_restricted_manifest_map(path_set const & paths, manifest_map const & m_old, --- monotone.texi +++ monotone.texi @@ -4778,63 +4778,111 @@ @item Added in: -0.2 +1.0 @item Purpose: -Prints the inventory of all files found in the current working copy -prefixed by 2 status code characters. +Prints the inventory of every file found in the working copy or its +associated base manifest. Each unique path is listed on a line prefixed by +three status characters and two numeric values used for identifying +renames. @item Sample output: @verbatim -+ "added-file" -+! "added-and-missing-file" -- "dropped-file" - # "edited-file" -% "file-before-rename" "file-after-rename" -%# "file-before-rename" "file-after-rename-and-edit" -~ "ignored-file" - ! "missing-file" - "unchanged-file" -? "unknown-file" address@hidden verbatim + M 0 0 missing + AP 0 0 added patched +D 0 0 dropped +R 1 0 renamed-from-this + R 0 1 renamed-to-this + P 0 0 patched + 0 0 unchanged + U 0 0 unknown + I 0 0 ignored address@hidden Output format: +# swapped but not moved -Each file is printed on its own line, prefixed by a two character status -code characters and a single space character. All filenames are quoted -with double quotes (") to support filenames containg spaces. Intervening -quotes are escaped with \". Directories are identified by paths ending -with '/' characters. Rename lines list the old name first, followed by -the new name. Lines are ordered by their pathname, with renames using -the new name is used for ordering. +RRP 1 2 unchanged +RRP 2 1 original -The first status character indicates the status of the path itsself and -may be one of the following: +# swapped and moved address@hidden address@hidden ' ' the path is unchanged from the current manifest address@hidden '+' the path has been added to the current manifest address@hidden '-' the path has been dropped from the current manifest address@hidden '%' the path has been renamed in the current manifest, both the old and new name are listed address@hidden '?' the path is unknown, it exists in the working copy but not in the current manifest address@hidden '~' the path is ignored by the current ignore_file lua hook setting address@hidden itemize +RR 1 2 unchanged +RR 2 1 original -The second status character indicates the status of the data associated -witth the path and may be one of the following: +# rename foo bar; add foo address@hidden address@hidden ' ' the data is unchanged, its sha1 version matches the version in the base manifest address@hidden '#' the data is changed, its sha1 version differs from the version in the base manifest address@hidden '!' the data is missing and its sha1 version cannot be computed address@hidden itemize +RAP 1 0 foo + R 0 1 bar +# rotated but not moved dropped -> missing -> original -> dropped + +RRP 1 3 dropped +RRP 2 1 missing +RRP 3 2 original + +# rotated and moved + +RR 1 3 dropped +RR 2 1 missing +RR 3 2 original + +# dropped but not removed and thus unknown + +D U 0 0 dropped + +# added but removed and thus missing + + AM 0 0 added + +# renamed but not moved and thus unknown source and missing target + +R U 1 0 original + RM 0 1 renamed + +# moved but not renamed and thus missing source and unknown target + + M 0 0 original + U 0 0 renamed + +# renamed and patched + +R 1 0 original + RP 0 1 renamed + address@hidden verbatim + address@hidden Output format: + +Each path is printed on its own line, prefixed by three status +characters described below. The status is followed by a single space and +two numbers, each separated by a single space, used for identifying renames. +The numbers are followed by a single space and then the pathname, which +includes the rest of the line. Directory paths are identified as ending with +the "/" character, file paths do not end in this character. + +The three status characters are as follows. + address@hidden +column 1 pre-state + ' ' the path was unchanged in the pre-state + 'D' the path was deleted from the pre-state + 'R' the path was renamed from the pre-state name +column 2 post-state + ' ' the path was unchanged in the post-state + 'R' the path was renamed to the post-state name + 'A' the path was added to the post-state +column 3 file-state + ' ' the file is known and unchanged from the current manifest version + 'P' the file is patched to a new version + 'U' the file is unknown and not included in the current manifest + 'I' the file is ignored and not included in the current manifest + 'M' the file is missing but is included in the current manifest address@hidden verbatim + Full support for versioned directories is not yet complete and the inventory will only list entries for renamed or dropped -directories. Directory entries are designated by pathnames ending with -"/" characters. +directories. @item Error conditions: --- tests/t_automate_inventory.at +++ tests/t_automate_inventory.at @@ -18,11 +18,13 @@ ADD_FILE(unchanged, [unchanged ]) -ADD_FILE(changed, [changed +ADD_FILE(patched, [patched ]) COMMIT(testbranch) +# single status changes + ADD_FILE(added, [added ]) AT_DATA(unknown, [unknown @@ -31,9 +33,9 @@ ]) AT_CHECK(rm missing) - +AT_CHECK(rm dropped) AT_CHECK(mv original renamed) -AT_DATA(changed, [something has changed +AT_DATA(patched, [something has changed ]) AT_CHECK(MONOTONE add added, [], [ignore], [ignore]) @@ -41,35 +43,131 @@ AT_CHECK(MONOTONE drop dropped, [], [ignore], [ignore]) AT_CHECK(MONOTONE automate inventory --rcfile=inventory_hooks.lua, [], [stdout], [ignore]) +AT_CHECK(grep '^ M 0 0 missing$' stdout, [], [ignore], [ignore]) +AT_CHECK(grep '^ AP 0 0 added$' stdout, [], [ignore], [ignore]) +AT_CHECK(grep '^D 0 0 dropped$' stdout, [], [ignore], [ignore]) +AT_CHECK(grep '^R 1 0 original$' stdout, [], [ignore], [ignore]) +AT_CHECK(grep '^ R 0 1 renamed$' stdout, [], [ignore], [ignore]) +AT_CHECK(grep '^ P 0 0 patched$' stdout, [], [ignore], [ignore]) +AT_CHECK(grep '^ 0 0 unchanged$' stdout, [], [ignore], [ignore]) +AT_CHECK(grep '^ U 0 0 unknown$' stdout, [], [ignore], [ignore]) +AT_CHECK(grep '^ I 0 0 ignored~$' stdout, [], [ignore], [ignore]) -AT_CHECK(grep '^ ! "missing"' stdout, [], [ignore], [ignore]) -AT_CHECK(grep '^+ "added"' stdout, [], [ignore], [ignore]) -AT_CHECK(grep '^- "dropped"' stdout, [], [ignore], [ignore]) -AT_CHECK(grep '^% "original" "renamed"' stdout, [], [ignore], [ignore]) -AT_CHECK(grep '^ . "changed"' stdout, [], [ignore], [ignore]) -AT_CHECK(grep '^ "unchanged"' stdout, [], [ignore], [ignore]) -AT_CHECK(grep '^? "unknown"' stdout, [], [ignore], [ignore]) -AT_CHECK(grep '^~ "ignored~"' stdout, [], [ignore], [ignore]) +# swapped but not moved -# renamed and changed +AT_CHECK(MONOTONE revert, [], [ignore], [ignore]) -AT_DATA(renamed, [renamed and changed -]) +AT_CHECK(MONOTONE rename unchanged temporary, [], [ignore], [ignore]) +AT_CHECK(MONOTONE rename original unchanged, [], [ignore], [ignore]) +AT_CHECK(MONOTONE rename temporary original, [], [ignore], [ignore]) -AT_CHECK(MONOTONE automate inventory, [], [stdout], [ignore]) +AT_CHECK(MONOTONE automate inventory --rcfile=inventory_hooks.lua, [], [stdout], [ignore]) +AT_CHECK(grep '^RRP 1 2 original$' stdout, [], [ignore], [ignore]) +AT_CHECK(grep '^RRP 2 1 unchanged$' stdout, [], [ignore], [ignore]) -AT_CHECK(grep '^%. "renamed"' stdout, [1], [ignore], [ignore]) -AT_CHECK(grep '^% "original" "renamed"' stdout, [], [ignore], [ignore]) +# swapped and moved -# missing renamed and added files +AT_CHECK(mv unchanged temporary) +AT_CHECK(mv original unchanged) +AT_CHECK(mv temporary original) -AT_CHECK(rm renamed added) +AT_CHECK(MONOTONE automate inventory --rcfile=inventory_hooks.lua, [], [stdout], [ignore]) +AT_CHECK(grep '^RR 1 2 original$' stdout, [], [ignore], [ignore]) +AT_CHECK(grep '^RR 2 1 unchanged$' stdout, [], [ignore], [ignore]) -AT_CHECK(MONOTONE automate inventory, [], [stdout], [ignore]) +# rename foo bar; add foo -AT_CHECK(grep '^+! "added"' stdout, [], [ignore], [ignore]) -AT_CHECK(grep '^%! "original" "renamed"' stdout, [], [ignore], [ignore]) +AT_CHECK(MONOTONE revert, [], [ignore], [ignore]) +AT_CHECK(MONOTONE rename original renamed, [], [ignore], [ignore]) +AT_CHECK(MONOTONE add original, [], [ignore], [ignore]) + +AT_CHECK(MONOTONE automate inventory --rcfile=inventory_hooks.lua, [], [stdout], [ignore]) +AT_CHECK(grep '^RAP 1 0 original$' stdout, [], [ignore], [ignore]) +AT_CHECK(grep '^ R 0 1 renamed$' stdout, [], [ignore], [ignore]) + +# rotated but not moved +# - note that things are listed and numbered in path collating order +# dropped -> missing -> original -> dropped + +AT_CHECK(MONOTONE revert, [], [ignore], [ignore]) + +AT_CHECK(MONOTONE rename original temporary, [], [ignore], [ignore]) +AT_CHECK(MONOTONE rename missing original, [], [ignore], [ignore]) +AT_CHECK(MONOTONE rename dropped missing, [], [ignore], [ignore]) +AT_CHECK(MONOTONE rename temporary dropped, [], [ignore], [ignore]) + +AT_CHECK(MONOTONE automate inventory --rcfile=inventory_hooks.lua, [], [stdout], [ignore]) +AT_CHECK(grep '^RRP 1 3 dropped$' stdout, [], [ignore], [ignore]) +AT_CHECK(grep '^RRP 2 1 missing$' stdout, [], [ignore], [ignore]) +AT_CHECK(grep '^RRP 3 2 original$' stdout, [], [ignore], [ignore]) + +# rotated and moved + +AT_CHECK(mv original temporary) +AT_CHECK(mv missing original) +AT_CHECK(mv dropped missing) +AT_CHECK(mv temporary dropped) + +AT_CHECK(MONOTONE automate inventory --rcfile=inventory_hooks.lua, [], [stdout], [ignore]) +AT_CHECK(grep '^RR 1 3 dropped$' stdout, [], [ignore], [ignore]) +AT_CHECK(grep '^RR 2 1 missing$' stdout, [], [ignore], [ignore]) +AT_CHECK(grep '^RR 3 2 original$' stdout, [], [ignore], [ignore]) + +# dropped but not removed and thus unknown + +AT_CHECK(MONOTONE revert, [], [ignore], [ignore]) + +AT_CHECK(MONOTONE drop dropped, [], [ignore], [ignore]) + +AT_CHECK(MONOTONE automate inventory --rcfile=inventory_hooks.lua, [], [stdout], [ignore]) +AT_CHECK(grep '^D U 0 0 dropped$' stdout, [], [ignore], [ignore]) + +# added but removed and thus missing + +AT_CHECK(MONOTONE revert, [], [ignore], [ignore]) + +AT_CHECK(MONOTONE add added, [], [ignore], [ignore]) +AT_CHECK(rm added, [], [ignore], [ignore]) + +AT_CHECK(MONOTONE automate inventory --rcfile=inventory_hooks.lua, [], [stdout], [ignore]) +AT_CHECK(grep '^ AM 0 0 added$' stdout, [], [ignore], [ignore]) + +# renamed but not moved and thus unknown source and missing target + +AT_CHECK(MONOTONE revert, [], [ignore], [ignore]) + +AT_CHECK(rm renamed) +AT_CHECK(MONOTONE rename original renamed, [], [ignore], [ignore]) + +AT_CHECK(MONOTONE automate inventory --rcfile=inventory_hooks.lua, [], [stdout], [ignore]) +AT_CHECK(grep '^R U 1 0 original$' stdout, [], [ignore], [ignore]) +AT_CHECK(grep '^ RM 0 1 renamed$' stdout, [], [ignore], [ignore]) + +# moved but not renamed and thus missing source and unknown target + +AT_CHECK(MONOTONE revert, [], [ignore], [ignore]) + +AT_CHECK(mv original renamed, [], [ignore], [ignore]) + +AT_CHECK(MONOTONE automate inventory --rcfile=inventory_hooks.lua, [], [stdout], [ignore]) +AT_CHECK(grep '^ M 0 0 original$' stdout, [], [ignore], [ignore]) +AT_CHECK(grep '^ U 0 0 renamed$' stdout, [], [ignore], [ignore]) + +# renamed and patched + +AT_CHECK(MONOTONE revert, [], [ignore], [ignore]) + +AT_DATA(renamed, [renamed and patched +]) +AT_CHECK(rm original, [], [ignore], [ignore]) + +AT_CHECK(MONOTONE rename original renamed, [], [ignore], [ignore]) +AT_CHECK(MONOTONE automate inventory --rcfile=inventory_hooks.lua, [], [stdout], [ignore]) + +AT_CHECK(grep '^R 1 0 original$' stdout, [], [ignore], [ignore]) +AT_CHECK(grep '^ RP 0 1 renamed$' stdout, [], [ignore], [ignore]) + # need tests for deleted and renamed directories, once these actually work! AT_CLEANUP