# # patch "ChangeLog" # from [1ca0c140585eb24f3192496cb9194d1cde27c84b] # to [8263954b8157f8429b731690a4f44795114d3caf] # # patch "commands.cc" # from [42a9854e615fff7b96075632e07cb88a6d12ae29] # to [5c9d5557618af9fc3447467688a61189c4727014] # # patch "manifest.cc" # from [aefd8d086360ea7349a541e2dfc0f4f7c28d9913] # to [e42a9ec927beb106fe6c251005eb6901a552199e] # # patch "manifest.hh" # from [2665667c3cf960e64f39301fea45d1e4e67e5dba] # to [32ecf7dfe6decb959f38856418e5e572afa82cd2] # # patch "revision.hh" # from [95b50ede90037557fd0fbbfad6a9fdd67b0bf413] # to [9600fe27d3ee00d922d158b0fe2e3abb6a1a56fb] # # patch "tests/t_status_missing.at" # from [b4a0e1fa174b845f6e58c10db2fcf38ffbcc14ab] # to [72d595bef8c751173ddf45eeaae5083e97cb1dc1] # --- ChangeLog +++ ChangeLog @@ -1,3 +1,13 @@ +2005-04-22 Derek Scherger + + * manifest.{cc,hh} (build_restricted_manifest_map): keep and + return a set of missing files rather than failing on first missing + file + * commands.cc (calculate_restricted_revision): handle set of + missing files + * revision.hh: update comment on the format of a revision + * tests/t_status_missing.at: un-XFAIL and add a few tests + 2005-04-21 Jeremy Cowgar * tests/t_multiple_heads_msg.at: Now checks to ensure 'multiple head' --- commands.cc +++ commands.cc @@ -538,6 +538,7 @@ revision_set & rev, manifest_map & m_old, manifest_map & m_new, + path_set & missing_files, change_set::path_rearrangement & restricted_work) { manifest_id old_manifest_id; @@ -570,7 +571,7 @@ cs->rearrangement = included; restricted_work = excluded; - build_restricted_manifest_map(new_paths, m_old, m_new, app); + build_restricted_manifest_map(new_paths, m_old, m_new, missing_files, app); complete_change_set(m_old, m_new, *cs); calculate_ident(m_new, rev.new_manifest); @@ -578,6 +579,7 @@ rev.edges.insert(make_pair(old_revision_id, make_pair(old_manifest_id, cs))); + } static void @@ -585,6 +587,27 @@ vector const & args, revision_set & rev, manifest_map & m_old, + manifest_map & m_new, + change_set::path_rearrangement & restricted_work) +{ + path_set missing_files; + calculate_restricted_revision(app, args, rev, m_old, m_new, missing_files, restricted_work); + + for (path_set::const_iterator i = missing_files.begin(); + i != missing_files.end(); ++i) + { + W(F("missing %s") % (*i)()); + } + + N(missing_files.size() == 0, + F("%d missing files\n") % missing_files.size()); +} + +static void +calculate_restricted_revision(app_state & app, + vector const & args, + revision_set & rev, + manifest_map & m_old, manifest_map & m_new) { change_set::path_rearrangement work; --- manifest.cc +++ manifest.cc @@ -63,19 +63,25 @@ build_restricted_manifest_map(path_set const & paths, manifest_map const & m_old, manifest_map & m_new, + path_set & missing_files, app_state & app) { m_new.clear(); inodeprint_map ipm; + if (in_inodeprints_mode()) { data dat; read_inodeprints(dat); read_inodeprint_map(dat, ipm); } + for (path_set::const_iterator i = paths.begin(); i != paths.end(); ++i) { - if (app.restriction_includes(*i)) + bool exists = fs::exists(mkpath((*i)())); + bool included = app.restriction_includes(*i); + + if (included && exists) { // compute the current sha1 id for included files // we might be able to avoid it, if we have an inode fingerprint... @@ -94,12 +100,20 @@ } } // ...ah, well, no good fingerprint, just check directly. - N(fs::exists(mkpath((*i)())), - F("file disappeared but exists in new manifest: %s") % (*i)()); hexenc ident; calculate_ident(*i, ident, app.lua); m_new.insert(manifest_entry(*i, file_id(ident))); } + else if (included && !exists) + { + missing_files.insert(*i); + + // copy the old manifest entry for missing files + manifest_map::const_iterator old = m_old.find(*i); + N(old != m_old.end(), + F("file missing but does not exist in old manifest: %s") % *i); + m_new.insert(*old); + } else { // copy the old manifest entry for excluded files --- manifest.hh +++ manifest.hh @@ -77,6 +77,7 @@ void build_restricted_manifest_map(path_set const & paths, manifest_map const & m_old, manifest_map & m_new, + path_set & missing_files, app_state & app); void read_manifest_map(data const & dat, --- revision.hh +++ revision.hh @@ -20,37 +20,31 @@ // sub-components are separately serialized (they could be but there is no // call for it). a grammar (aside from the parsing code) for the serialized // form will show up here eventually. until then, here is an example. +// form will show up here eventually. until then, here is an example. // -// revision: -// { -// new_manifest: [71e0274f16cd68bdf9a2bf5743b86fcc1e597cdc] -// edge: -// { -// old_revision: [71e0274f16cd68bdf9a2bf5743b86fcc1e597cdc] -// old_manifest: [71e0274f16cd68bdf9a2bf5743b86fcc1e597cdc] -// change_set: -// { -// paths: -// { -// rename_file: -// { -// src: "usr/bin/sh" -// dst: "usr/bin/foo" -// } -// delete_dir: "usr/bin" -// add_file: "tmp/foo/bar.txt" -// } -// deltas: -// { -// delta: -// { -// path: "tmp/foo/bar.txt" -// src: [71e0274f16cd68bdf9a2bf5743b86fcc1e597cdc] -// dst: [71e0274f16cd68bdf9a2bf5743b86fcc1e597cdc] -// } -// } -// } -// } +// new_manifest [16afa28e8783987223993d67f54700f0ecfedfaa] +// +// old_revision [d023242b16cbdfd46686a5d217af14e3c339f2b4] +// old_manifest [2dc4a99e27a0026395fbd4226103614928c55c77] +// +// delete_file "deleted-file.cc" +// +// rename_file "old-file.cc" +// to "new-file.cc" +// +// add_file "added-file.cc" +// +// patch "added-file.cc" +// from [] +// to [da39a3ee5e6b4b0d3255bfef95601890afd80709] +// +// patch "changed-file.cc" +// from [588fd8a7bcde43a46f0bde1dd1d13e9e77cf25a1] +// to [559133b166c3154c864f912e9f9452bfc452dfdd] +// +// patch "new-file.cc" +// from [95b50ede90037557fd0fbbfad6a9fdd67b0bf413] +// to [bd39086b9da776fc22abd45734836e8afb59c8c0] extern std::string revision_file_name; --- tests/t_status_missing.at +++ tests/t_status_missing.at @@ -1,19 +1,24 @@ AT_SETUP([(normal) status with missing files]) MONOTONE_SETUP -# This test is a bug report. -AT_XFAIL_IF(true) - -ADD_FILE(testfile, [foo +ADD_FILE(testfile1, [foo ]) +ADD_FILE(testfile2, [bar +]) COMMIT(testbranch) -AT_CHECK(rm -f testfile) +AT_CHECK(rm -f testfile1) +AT_CHECK(rm -f testfile2) # status should successfully report on the status of things regardless # of the status of those things -- i.e. it should report missing files # as such rather than failing on them. -AT_CHECK(MONOTONE status, [0], [ignore], [ignore]) +# status should list all missing files before failing +# if/when there are missing files +AT_CHECK(MONOTONE status, [1], [ignore], [stderr]) +AT_CHECK(grep testfile1 stderr, [], [ignore], [ignore]) +AT_CHECK(grep testfile2 stderr, [], [ignore], [ignore]) + AT_CLEANUP