# # # add_file "unix/parse_time.cc" # content [32590b4a1e4f2fa9efa0f48f077d47af8f13b431] # # add_file "win32/parse_time.cc" # content [6970babb88f00ec9526d1e4e3585b55dea2e7da2] # # patch "Makefile.am" # from [e956bf588ace925767e267296316a673e7d4761a] # to [6e0664ed9ae020582bc88b50023b44a94a57f474] # # patch "cmd_ws_commit.cc" # from [3ffbaa10b5e4c72028f08fcbf06950e5997b7c69] # to [53480aabfe2e2c66ebedb7c350ec632552dc2614] # # patch "dates.cc" # from [24dd854d8c1be66b65a57d813b756ddf13550848] # to [2413fafb2058055cab18cc8f6787c893f471c214] # # patch "platform.hh" # from [648608271dd6559ba89bc0bb816a3de306c3355f] # to [04a90e564b175d1193c25c2e59e9028ddefcc85d] # # patch "tests/branch_leaves_sync_bug/__driver__.lua" # from [b07136d83463e208ef345d97415e53eafd244203] # to [17b7a2b625a52f0f1e4315c99fb747c4657855e8] # # patch "tests/commit_default_editor/__driver__.lua" # from [8d09d83b970265688cb9825e4e0f78c1db3b52ff] # to [8d2c518dae48558b15227fd42c33831271f42fe6] # # patch "unit-tests/dates.cc" # from [fc614466a2130277bb98e89db1398d6b85cde1a1] # to [be9bcbe238f0221acb2c37f07b78f98b1a52471a] # ============================================================ --- unix/parse_time.cc 32590b4a1e4f2fa9efa0f48f077d47af8f13b431 +++ unix/parse_time.cc 32590b4a1e4f2fa9efa0f48f077d47af8f13b431 @@ -0,0 +1,19 @@ +// Copyright (C) 2010 Stephen Leake +// +// This program is made available under the GNU GPL version 3.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 +#include + +bool parse_date (const std::string s, const std::string fmt, struct tm *tp) +{ + char *p = strptime(s.c_str(), fmt.c_str(), tb); + + return p != 0; +} +// end of file ============================================================ --- win32/parse_time.cc 6970babb88f00ec9526d1e4e3585b55dea2e7da2 +++ win32/parse_time.cc 6970babb88f00ec9526d1e4e3585b55dea2e7da2 @@ -0,0 +1,21 @@ +// Copyright (C) 2010 Stephen Leake +// +// This program is made available under the GNU GPL version 3.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 + +bool parse_date (const std::string s, const std::string fmt, struct tm *tp) +{ + // Apparently the Win32 API does not provide a date parsing function. + // + // So far, parse_date is only used in the changelog processing to + // allow the user to change the date cert. So we just disable that + // on Win32; see cmd_ws_commit.cc get_log_message_interactively. + return false; +} +// end of file ============================================================ --- Makefile.am e956bf588ace925767e267296316a673e7d4761a +++ Makefile.am 6e0664ed9ae020582bc88b50023b44a94a57f474 @@ -145,14 +145,14 @@ UNIX_PLATFORM_SOURCES = \ unix/process.cc unix/terminal.cc unix/inodeprint.cc \ unix/fs.cc unix/make_io_binary.cc unix/os_strerror.cc \ unix/cputime.cc unix/ssh_agent_platform.cc \ - unix/ssh_agent_platform.hh + unix/ssh_agent_platform.hh win32/parse_time.cc WIN32_PLATFORM_SOURCES = \ win32/read_password.cc win32/get_system_flavour.cc \ win32/process.cc win32/terminal.cc win32/inodeprint.cc \ win32/fs.cc win32/make_io_binary.cc win32/os_strerror.cc \ win32/cputime.cc win32/ssh_agent_platform.cc \ - win32/ssh_agent_platform.hh + win32/ssh_agent_platform.hh win32/parse_time.cc # these files (part of the main program) contain code subject to unit testing ============================================================ --- cmd_ws_commit.cc 3ffbaa10b5e4c72028f08fcbf06950e5997b7c69 +++ cmd_ws_commit.cc 53480aabfe2e2c66ebedb7c350ec632552dc2614 @@ -1,3 +1,4 @@ +// Copyright (C) 2010 Stephen Leake // Copyright (C) 2002 Graydon Hoare // // This program is made available under the GNU GPL version 2.0 or @@ -127,6 +128,41 @@ private: size_t offset; }; +static bool +date_fmt_valid (string date_fmt) +{ + if (date_fmt.empty()) + { + return true; + } + else + { + // check that the specified date format can be used to format and + // parse a date + date_t now = date_t::now(); + date_t parsed; + try + { + string formatted = now.as_formatted_localtime(date_fmt); + parsed = date_t::from_formatted_localtime(formatted, date_fmt); + } + catch (recoverable_failure const & e) + { + L(FL("date check failed: %s") % e.what()); + } + + if (parsed != now) + { + L(FL("date check failed: %s != %s") % now % parsed); + return false; + } + else + { + return true; + } + } +} + static void get_log_message_interactively(lua_hooks & lua, workspace & work, project_t & project, @@ -196,12 +232,23 @@ get_log_message_interactively(lua_hooks utf8 header; utf8 summary; - revision_header(rid, rev, author, date, branch, changelog, date_fmt, header); + bool is_date_fmt_valid = date_fmt_valid(date_fmt); + string null_date_fmt(""); + + if (!is_date_fmt_valid) + { + W(F("date format '%s' cannot be used for commit; using default instead") % date_fmt); + revision_header(rid, rev, author, date, branch, changelog, null_date_fmt, header); + } + else + { + revision_header(rid, rev, author, date, branch, changelog, date_fmt, header); + } revision_summary(rev, summary); - utf8 full_message(instructions() + cancel() + header() + notes() + summary(), + utf8 full_message(instructions() + cancel() + header() + notes() + summary(), origin::internal); - + external input_message; external output_message; @@ -276,7 +323,7 @@ get_log_message_interactively(lua_hooks E(!d.empty(), origin::user, F("Commit failed. Date value empty.")); - if (date_fmt.empty()) + if (!is_date_fmt_valid || date_fmt.empty()) date = date_t(d); else date = date_t::from_formatted_localtime(d, date_fmt); @@ -777,28 +824,9 @@ CMD(status, "status", "", CMD_REF(inform app.lua.hook_get_date_format_spec(date_time_long, date_fmt); } - if (!date_fmt.empty()) - { - // check that the specified date format can be parsed (for commit) - date_t now = date_t::now(); - date_t parsed; - try - { - string formatted = now.as_formatted_localtime(date_fmt); - parsed = date_t::from_formatted_localtime(formatted, date_fmt); - } - catch (recoverable_failure const & e) - { - L(FL("date check failed: %s") % e.what()); - } + if (!date_fmt_valid(date_fmt)) + W(F("date format '%s' cannot be used for commit") % date_fmt); - if (parsed != now) - { - L(FL("date check failed: %s != %s") % now % parsed); - W(F("date format '%s' cannot be used for commit") % date_fmt); - } - } - work.get_parent_rosters(db, old_rosters); work.get_current_roster_shape(db, nis, new_roster); @@ -1452,29 +1480,6 @@ CMD(commit, "commit", "ci", CMD_REF(work author = key.official_name(); } - if (!date_fmt.empty()) - { - // check that the current date format can be parsed - date_t parsed; - try - { - string formatted = date.as_formatted_localtime(date_fmt); - parsed = date_t::from_formatted_localtime(formatted, date_fmt); - } - catch (recoverable_failure const & e) - { - L(FL("date check failed: %s") % e.what()); - } - - if (parsed != date) - { - L(FL("date check failed: %s != %s") % date % parsed); - } - - E(parsed == date, origin::user, - F("date format '%s' cannot be used for commit") % date_fmt); - } - if (!log_message_given) { // This call handles _MTN/log. ============================================================ --- dates.cc 24dd854d8c1be66b65a57d813b756ddf13550848 +++ dates.cc 2413fafb2058055cab18cc8f6787c893f471c214 @@ -8,13 +8,14 @@ // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. +#include +#include + #include "base.hh" #include "dates.hh" #include "sanity.hh" +#include "platform.hh" -#include -#include - // Generic date handling routines for Monotone. // // The routines in this file substantively duplicate functionality of the @@ -442,13 +443,9 @@ date_t::from_formatted_localtime(string L(FL("parsing date '%s' with format '%s'") % s % fmt); - char *p = strptime(s.c_str(), fmt.c_str(), &tb); // local timezone values - - E(p, origin::user, // strptime failed to match all of the format string + // get local timezone values + E(parse_date(s, fmt, &tb), origin::user, F("unable to parse date '%s' with format '%s'") % s % fmt); - - E(*p == 0, origin::user, // extraneous characters in input string - F("invalid date '%s' not matched by format '%s'") % s % fmt); // strptime does *not* set the tm_isdst field in the broken down time // struct. setting it to -1 is apparently the way to tell mktime to @@ -494,7 +491,7 @@ date_t::from_formatted_localtime(string tb.tm_wday == check.tm_wday && tb.tm_yday == check.tm_yday && tb.tm_isdst == check.tm_isdst, - origin::user, + origin::user, F("date '%s' is out of range and cannot be parsed") % s); ============================================================ --- platform.hh 648608271dd6559ba89bc0bb816a3de306c3355f +++ platform.hh 04a90e564b175d1193c25c2e59e9028ddefcc85d @@ -15,6 +15,7 @@ #include +#include void read_password(std::string const & prompt, char * buf, size_t bufsz); void get_system_flavour(std::string & ident); @@ -164,6 +165,12 @@ std::string get_locale_dir(); // determine directory to load locale data from std::string get_locale_dir(); +// Fill tp from s, using format fmt. +// Returns false on failure, true on success. +// +// This is strptime on Unix, something else on MinGW. +bool parse_date (const std::string s, const std::string fmt, struct tm *tp); + #endif // __PLATFORM_HH__ // Local Variables: ============================================================ --- tests/branch_leaves_sync_bug/__driver__.lua b07136d83463e208ef345d97415e53eafd244203 +++ tests/branch_leaves_sync_bug/__driver__.lua 17b7a2b625a52f0f1e4315c99fb747c4657855e8 @@ -6,6 +6,12 @@ -- The bug does not occur if the two workspaces use the same author -- name and key. +-- The bug was about logic in the branch leaves cache, not +-- specifically about sync; it's tested adequately on Linux. 'sync +-- file:' doesn't work on Win32, but it's not worth setting up a +-- server for this test. +skip_if(ostype == "Windows") + function abe_mtn(...) return raw_mtn("--rcfile", test.root .. "/min_hooks.lua", "--db=" .. test.root .. "/abe.db", ============================================================ --- tests/commit_default_editor/__driver__.lua 8d09d83b970265688cb9825e4e0f78c1db3b52ff +++ tests/commit_default_editor/__driver__.lua 8d2c518dae48558b15227fd42c33831271f42fe6 @@ -2,6 +2,8 @@ -- which should look for an "editor" executable on the PATH and run it -- if neither $EDITOR nor $VISUAL is set in the environment. We have -- to override the default test hooks, which disable edit_comment. +-- +-- Also test bad --date-format; doesn't fail, just uses the default mtn_setup() addfile("a", "hello there") @@ -9,4 +11,5 @@ check(get("test_hooks.lua")) -- this res check(get("test_hooks.lua")) -- this restores the default edit_comment -- and provides a fake "editor" executable -check(mtn("--branch", "testbranch", "commit"), 0, false, false) +check(mtn("--branch", "testbranch", "commit", "--date-format", "foo"), 0, false, true) +check(qgrep("date format 'foo' cannot be used for commit; using default instead", "stderr")) ============================================================ --- unit-tests/dates.cc fc614466a2130277bb98e89db1398d6b85cde1a1 +++ unit-tests/dates.cc be9bcbe238f0221acb2c37f07b78f98b1a52471a @@ -188,6 +188,8 @@ UNIT_TEST(from_string) #undef NO } +#ifndef WIN32 +// parse_date (used by from_formatted_localtime) not implemented on Win32 UNIT_TEST(roundtrip_localtimes) { #define OK(x) do { \ @@ -213,7 +215,7 @@ UNIT_TEST(roundtrip_localtimes) end += 1000; // these tests run with LANG=C and TZ=UTC so the %c format seems to work - // however strptime does not like the timezone name when %c is used in + // however strptime does not like the timezone name when %c is used in // other locales. with LANG=en_CA.UTF-8 this test fails. if (sizeof(time_t) <= 4) @@ -247,7 +249,10 @@ UNIT_TEST(roundtrip_localtimes) #undef OK } +#endif +#ifndef WIN32 +// parse_date (used by from_formatted_localtime) not implemented on Win32 UNIT_TEST(localtime_formats) { #define OK(d, f) do { \ @@ -309,6 +314,7 @@ UNIT_TEST(localtime_formats) #undef OK } +#endif UNIT_TEST(from_unix_epoch) {