# # # patch "configure.ac" # from [2261e729b116835118ea1c0adf6270a5264ea0a8] # to [84e91854f0143c8124dba0004976c0b8b1740a2a] # # patch "paths.cc" # from [8367c798e233a2dd623e832c5e041dc8e896530e] # to [82b53f74ecd9edcb052df8984a563159f0a28cc9] # # patch "tester.cc" # from [e41c1170a163dbd12343e68444132e768da083ca] # to [1c43edd1b4336076897ec0208b6cad4a12919800] # # patch "tests/diffing_a_file_within_revision_outside_a_workspace/__driver__.lua" # from [37a11a3d4bfc9e8834027965eb7c17dfe9441ba6] # to [b6b86da2a8eaec31c668e1ffa438d80e82982752] # # patch "tests/logging_a_file_within_revision_outside_a_workspace/__driver__.lua" # from [435a5c8c6dc10d39d0aa3e655640ac4048143dc8] # to [2f16087b6cfdba6e097f3a0f27918c64332ea4a7] # ============================================================ --- configure.ac 2261e729b116835118ea1c0adf6270a5264ea0a8 +++ configure.ac 84e91854f0143c8124dba0004976c0b8b1740a2a @@ -120,7 +120,7 @@ AC_CHECK_FUNCS([atexit memset mkstemp st AC_FUNC_ICONV_TRANSLIT AC_CHECK_FUNCS([atexit memset mkstemp strptime lrint \ __cxa_current_exception_type __cxa_demangle \ - putenv setenv unsetenv dirfd fstatat]) + putenv setenv unsetenv dirfd fstatat mkdtemp]) # simple library checks AC_SEARCH_LIBS([deflate], [z], , AC_MSG_FAILURE([zlib is required])) ============================================================ --- paths.cc 8367c798e233a2dd623e832c5e041dc8e896530e +++ paths.cc 82b53f74ecd9edcb052df8984a563159f0a28cc9 @@ -517,9 +517,19 @@ any_path::dirname() const string::size_type sep = s.rfind('/'); if (sep == string::npos) return any_path(); - if (sep == s.size() - 1) // dirname() of the root directory is itself + + // dirname() of the root directory is itself + if (sep == s.size() - 1) return *this; + // dirname() of a direct child of the root is the root + if (sep == 0 || (sep == 1 && s[1] == '/') +#ifdef WIN32 + || (sep == 2 && s[1] == ':') +#endif + ) + return any_path(s, 0, sep+1); + return any_path(s, 0, sep); } @@ -540,11 +550,20 @@ system_path::dirname() const { string const & s = data; string::size_type sep = s.rfind('/'); - if (sep == string::npos) - return system_path(); - if (sep == s.size() - 1) // dirname() of the root directory is itself + I(sep != string::npos); + + // dirname() of the root directory is itself + if (sep == s.size() - 1) return *this; + // dirname() of a direct child of the root is the root + if (sep == 0 || (sep == 1 && s[1] == '/') +#ifdef WIN32 + || (sep == 2 && s[1] == ':') +#endif + ) + return system_path(s, 0, sep+1); + return system_path(s, 0, sep); } @@ -1304,6 +1323,33 @@ UNIT_TEST(paths, basename) % p->in % pc % p->out); } + // any_path::basename() should return exactly the same thing that + // the corresponding specialized basename() does, but with type any_path. + UNIT_TEST_CHECKPOINT("any_path basenames"); + for (struct t const *p = fp_cases; p->in; p++) + { + any_path ap(file_path_internal(p->in)); + path_component pc(ap.basename()); + UNIT_TEST_CHECK_MSG(pc == path_component(p->out), + FL("basename('%s') = '%s' (expect '%s')") + % p->in % pc % p->out); + } + for (struct t const *p = bp_cases; p->in; p++) + { + any_path ap(bookkeeping_path(p->in)); + path_component pc(ap.basename()); + UNIT_TEST_CHECK_MSG(pc == path_component(p->out), + FL("basename('%s') = '%s' (expect '%s')") + % p->in % pc % p->out); + } + for (struct t const *p = sp_cases; p->in; p++) + { + any_path ap(system_path(p->in)); + path_component pc(ap.basename()); + UNIT_TEST_CHECK_MSG(pc == path_component(p->out), + FL("basename('%s') = '%s' (expect '%s')") + % p->in % pc % p->out); + } initial_abs_path.unset(); } @@ -1317,13 +1363,45 @@ UNIT_TEST(paths, dirname) }; // file_paths cannot be absolute, but may be the empty string. struct t const fp_cases[] = { - { "", "" }, - { "foo", "" }, - { "foo/bar", "foo" }, + { "", "" }, + { "foo", "" }, + { "foo/bar", "foo" }, { "foo/bar/baz", "foo/bar" }, { 0, 0 } }; + // system_paths must be absolute. this relies on the setting of + // initial_abs_path below. + struct t const sp_cases[] = { + { "/", "/" }, + { "//", "//" }, + { "foo", "/a/b" }, + { "/foo", "/" }, + { "//foo", "//" }, + { "~/foo", "~" }, + { "foo/bar", "/a/b/foo" }, + { "/foo/bar", "/foo" }, + { "//foo/bar", "//foo" }, + { "~/foo/bar", "~/foo" }, +#ifdef WIN32 + { "c:", "c:" }, + { "c:foo", "c:" }, + { "c:/", "c:/" }, + { "c:/foo", "c:/" }, + { "c:/foo/bar", "c:/foo/bar" }, +#else + { "c:", "/a/b" }, + { "c:foo", "/a/b" }, + { "c:/", "/a/b" }, + { "c:/foo", "/a/b/c:" }, + { "c:/foo/bar", "/a/b/c:/foo" }, +#endif + { 0, 0 } + }; + + initial_abs_path.unset(); + + UNIT_TEST_CHECKPOINT("file_path dirnames"); for (struct t const *p = fp_cases; p->in; p++) { file_path fp = file_path_internal(p->in); @@ -1332,6 +1410,43 @@ UNIT_TEST(paths, dirname) FL("dirname('%s') = '%s' (expect '%s')") % p->in % dn % p->out); } + + + initial_abs_path.set(system_path("/a/b"), true); + UNIT_TEST_CHECKPOINT("system_path dirnames"); + for (struct t const *p = sp_cases; p->in; p++) + { + system_path fp(p->in); + system_path dn(fp.dirname()); + + UNIT_TEST_CHECK_MSG(dn == system_path(p->out), + FL("dirname('%s') = '%s' (expect '%s')") + % p->in % dn % p->out); + } + + // any_path::dirname() should return exactly the same thing that + // the corresponding specialized dirname() does, but with type any_path. + UNIT_TEST_CHECKPOINT("any_path dirnames"); + for (struct t const *p = fp_cases; p->in; p++) + { + any_path ap(file_path_internal(p->in)); + any_path dn(ap.dirname()); + any_path rf(file_path_internal(p->out)); + UNIT_TEST_CHECK_MSG(dn.as_internal() == rf.as_internal(), + FL("dirname('%s') = '%s' (expect '%s')") + % p->in % dn % p->out); + } + for (struct t const *p = sp_cases; p->in; p++) + { + any_path ap(system_path(p->in)); + any_path dn(ap.dirname()); + any_path rf(system_path(p->out)); + UNIT_TEST_CHECK_MSG(dn.as_internal() == rf.as_internal(), + FL("dirname('%s') = '%s' (expect '%s')") + % p->in % dn % p->out); + } + + initial_abs_path.unset(); } UNIT_TEST(paths, depth) ============================================================ --- tester.cc e41c1170a163dbd12343e68444132e768da083ca +++ tester.cc 1c43edd1b4336076897ec0208b6cad4a12919800 @@ -242,6 +242,29 @@ string dirname(string const & s) return s.substr(0, sep); } +char * do_mkdtemp(char const * parent) +{ +#ifdef WIN32 +#error do_mkdtemp needs to be ported to Windows +#elif defined HAVE_MKDTEMP + + char * tmpdir = new char[strlen(parent) + sizeof "/mtXXXXXX"]; + + strcpy(tmpdir, parent); + strcat(tmpdir, "/mtXXXXXX"); + + char * result = mkdtemp(tmpdir); + + E(result != 0, + F("mkdtemp(%s) failed: %s") % tmpdir % os_strerror(errno)); + I(result == tmpdir); + return tmpdir; + +#else +#error do_mkdtemp needs to be ported to this platform +#endif +} + map orig_env_vars; string source_dir; @@ -550,6 +573,32 @@ LUAEXT(mkdir, ) } } +LUAEXT(make_temp_dir, ) +{ + try + { + char const * parent; + parent = getenv("TMPDIR"); + if (parent == 0) + parent = getenv("TEMP"); + if (parent == 0) + parent = getenv("TMP"); + if (parent == 0) + parent = "/tmp"; + + char * tmpdir = do_mkdtemp(parent); + lua_pushstring(L, tmpdir); + delete [] tmpdir; + return 1; + } + catch(informative_failure & e) + { + lua_pushnil(L); + return 1; + } +} + + LUAEXT(mtime, ) { try ============================================================ --- tests/diffing_a_file_within_revision_outside_a_workspace/__driver__.lua 37a11a3d4bfc9e8834027965eb7c17dfe9441ba6 +++ tests/diffing_a_file_within_revision_outside_a_workspace/__driver__.lua b6b86da2a8eaec31c668e1ffa438d80e82982752 @@ -16,3 +16,61 @@ check(mtn("diff", "--revision", parent, check(mtn("diff", "--revision", parent, "--revision", second), 0, false, false) -- check it works when specifying files check(mtn("diff", "--revision", parent, "--revision", second, "foo2"), 0, false, false) + +-- should work without any --root argument, too. we do this in a +-- special temporary directory to ensure no risk to a higher-level +-- workspace. + +tmpdir = make_temp_dir() +copy(test.root .. "/test.db", tmpdir) +copy(test.root .. "/keys", tmpdir) + +check(indir(tmpdir, + { monotone_path, "--norc", + "--db="..tmpdir.."/test.db", + "--confdir="..tmpdir, + "--keydir="..tmpdir.."/keys", + "diff", "--revision", parent, "--revision", second }), + 0, false, false) + +check(indir(tmpdir, + { monotone_path, "--norc", "--root="..tmpdir, + "--db="..tmpdir.."/test.db", + "--confdir="..tmpdir, + "--keydir="..tmpdir.."/keys", + "diff", "--revision", parent, "--revision", second }), + 0, false, false) + +check(indir(tmpdir, + { monotone_path, "--norc", "--root=.", + "--db="..tmpdir.."/test.db", + "--confdir="..tmpdir, + "--keydir="..tmpdir.."/keys", + "diff", "--revision", parent, "--revision", second }), + 0, false, false) + +check(indir(tmpdir, + { monotone_path, "--norc", + "--db="..tmpdir.."/test.db", + "--confdir="..tmpdir, + "--keydir="..tmpdir.."/keys", + "diff", "--revision", parent, "--revision", second, "foo2" }), + 0, false, false) + +check(indir(tmpdir, + { monotone_path, "--norc", "--root="..tmpdir, + "--db="..tmpdir.."/test.db", + "--confdir="..tmpdir, + "--keydir="..tmpdir.."/keys", + "diff", "--revision", parent, "--revision", second, "foo2" }), + 0, false, false) + +check(indir(tmpdir, + { monotone_path, "--norc", "--root=.", + "--db="..tmpdir.."/test.db", + "--confdir="..tmpdir, + "--keydir="..tmpdir.."/keys", + "diff", "--revision", parent, "--revision", second, "foo2" }), + 0, false, false) + +remove(tmpdir) ============================================================ --- tests/logging_a_file_within_revision_outside_a_workspace/__driver__.lua 435a5c8c6dc10d39d0aa3e655640ac4048143dc8 +++ tests/logging_a_file_within_revision_outside_a_workspace/__driver__.lua 2f16087b6cfdba6e097f3a0f27918c64332ea4a7 @@ -10,3 +10,37 @@ check(mtn("log", "--from", rev, "foo1"), remove("_MTN") check(mtn("log", "--from", rev, "foo1"), 0, false, false) + +-- should work without any --root argument, too. we do this in a +-- special temporary directory to ensure no risk to a higher-level +-- workspace. + +tmpdir = make_temp_dir() +copy(test.root .. "/test.db", tmpdir) +copy(test.root .. "/keys", tmpdir) + +check(indir(tmpdir, + { monotone_path, "--norc", + "--db="..tmpdir.."/test.db", + "--confdir="..tmpdir, + "--keydir="..tmpdir.."/keys", + "log", "--from", rev, "foo1" }), + 0, false, false) + +check(indir(tmpdir, + { monotone_path, "--norc", "--root="..tmpdir, + "--db="..tmpdir.."/test.db", + "--confdir="..tmpdir, + "--keydir="..tmpdir.."/keys", + "log", "--from", rev, "foo1" }), + 0, false, false) + +check(indir(tmpdir, + { monotone_path, "--norc", "--root=.", + "--db="..tmpdir.."/test.db", + "--confdir="..tmpdir, + "--keydir="..tmpdir.."/keys", + "log", "--from", rev, "foo1" }), + 0, false, false) + +remove(tmpdir)