Skip to content

Commit

Permalink
Various fixes to make more Windows CI tests pass
Browse files Browse the repository at this point in the history
* Try to address the OpenEXR thread pool hanging when we call exit().

    * Strive to remove all exit() calls after any file reads happen,
      in oiiotool, iconvert, and idiff.

    * This does not stop all hanging.

    * Temp workaround: for the Windows CI tests, use ctest commands to
      allow each test to timeout 3 times before giving up. To be clear,
      this does not solve the problem, it only masks it. But it helps
      us "pass" those tests, exposing any other problems occurring with
      them, and we will return later to find the source of any residual
      timeouts.

* Update ref output for several tests where the differ slightly under Windows.

* Make runtest.py convert text output line endings cr-lf -> lf before
  comparing to reference output. (This eliminates unnecessary diffs.)

* Update many tests' run.py file to use double quotes instead of single
  quotes for arguments containing some characters -- looks like the Windows
  shell invoked by Python system() does not handle the single quotes quite
  the same way as Unix shells.

* Helper: ArgParse: add abort() method, lets you stop command line parsing.

* Helper: Filesystem::generic_filepath. Similar to C++17
  std::filesystem::path::generic_string(), but for a filepath sent as
  string_view.

  While I was there, I noticed that a few Filesystem functions that I
  declared as `noexcept` actually call things that can throw, so I put a
  few try/catch in stratgic spots. Nobody had reported a problem with
  this, and maybe it would be fine, but it's the right thing to do.

* oiiotool: when printing the command line after errors, genericize
  identifiable filenames so they render the same on Windows and POSIX,
  and strip directory name from the oiiotool filepath. This makes
  error output comparison more equal between Windows and POSIX, making
  several more tests pass.

In total, this seems to get us down to failing only 7 tests (not counting
spurious timeouts that cause failures).
  • Loading branch information
lgritz committed Jan 8, 2021
1 parent 7e565f7 commit 1d8948c
Show file tree
Hide file tree
Showing 20 changed files with 231 additions and 85 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ jobs:
PYTHON_VERSION: 3.7
CMAKE_GENERATOR: "Visual Studio 16 2019"
OPENEXR_VERSION: v2.4.1
OIIO_CTEST_FLAGS: "--timeout 120 --repeat after-timeout:4"
run: |
source src/build-scripts/ci-startup.bash
source src/build-scripts/gh-win-installdeps.bash
Expand All @@ -348,6 +349,7 @@ jobs:
PYTHON_VERSION: 3.7
CMAKE_GENERATOR: "Visual Studio 15 2017 Win64"
OPENEXR_VERSION: v2.4.1
OIIO_CTEST_FLAGS: "--timeout 120 --repeat after-timeout:4"
run: |
source src/build-scripts/ci-startup.bash
source src/build-scripts/gh-win-installdeps.bash
Expand Down
27 changes: 20 additions & 7 deletions src/iconvert/iconvert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ static int orientation = 0;
static bool rotcw = false, rotccw = false, rot180 = false;
static bool sRGB = false;
static bool separate = false, contig = false;
static bool noclobber = false;
static bool noclobber = false;
static int return_code = EXIT_SUCCESS;
static ArgParse ap;



Expand All @@ -63,7 +65,6 @@ static void
getargs(int argc, char* argv[])
{
bool help = false;
ArgParse ap;
// clang-format off
ap.options ("iconvert -- copy images with format conversions and other alterations\n"
OIIO_INTRO_STRING "\n"
Expand Down Expand Up @@ -103,29 +104,39 @@ getargs(int argc, char* argv[])
if (ap.parse(argc, (const char**)argv) < 0) {
std::cerr << ap.geterror() << std::endl;
ap.usage();
exit(EXIT_FAILURE);
ap.abort();
return_code = EXIT_FAILURE;
return;
}
if (help) {
ap.usage();
exit(EXIT_SUCCESS);
ap.abort();
return_code = EXIT_SUCCESS;
return;
}

if (filenames.size() != 2 && !inplace) {
std::cerr
<< "iconvert: Must have both an input and output filename specified.\n";
ap.usage();
exit(EXIT_FAILURE);
ap.abort();
return_code = EXIT_FAILURE;
return;
}
if (filenames.size() == 0 && inplace) {
std::cerr << "iconvert: Must have at least one filename\n";
ap.usage();
exit(EXIT_FAILURE);
ap.abort();
return_code = EXIT_FAILURE;
return;
}
if (((int)rotcw + (int)rotccw + (int)rot180 + (orientation > 0)) > 1) {
std::cerr
<< "iconvert: more than one of --rotcw, --rotccw, --rot180, --orientation\n";
ap.usage();
exit(EXIT_FAILURE);
ap.abort();
return_code = EXIT_FAILURE;
return;
}
}

Expand Down Expand Up @@ -485,6 +496,8 @@ main(int argc, char* argv[])

Filesystem::convert_native_arguments(argc, (const char**)argv);
getargs(argc, argv);
if (ap.aborted())
return return_code;

OIIO::attribute("threads", nthreads);

Expand Down
2 changes: 1 addition & 1 deletion src/idiff/idiff.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ main(int argc, char* argv[])
std::cerr << "idiff: Must have two input filenames.\n";
std::cout << "> " << Strutil::join(filenames, ", ") << "\n";
ap.usage();
exit(EXIT_FAILURE);
return EXIT_FAILURE;
}
bool verbose = ap["v"].get<int>();
bool quiet = ap["q"].get<int>();
Expand Down
8 changes: 8 additions & 0 deletions src/include/OpenImageIO/argparse.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,14 @@ class OIIO_API ArgParse {
/// `parse_args()` and responding appropriately.
ArgParse& exit_on_error(bool exit_on_error);

/// If called by an argument's action, halts the rest of the command
/// line from continuing to be processed. Call with `aborted = false` to
/// unabort and restore operations.
void abort(bool aborted = true);

/// Reveal whether the current state is aborted.
bool aborted() const;

/// @}

// ------------------------------------------------------------------
Expand Down
3 changes: 3 additions & 0 deletions src/include/OpenImageIO/filesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ OIIO_API std::string parent_path (const std::string &filepath) noexcept;
OIIO_API std::string replace_extension (const std::string &filepath,
const std::string &new_extension) noexcept;

/// Return the filepath in generic format, not any OS-specific conventions.
OIIO_API std::string generic_filepath (string_view filepath) noexcept;

/// Turn a searchpath (multiple directory paths separated by ':' or ';')
/// into a vector<string> containing each individual directory. If
/// validonly is true, only existing and readable directories will end
Expand Down
27 changes: 24 additions & 3 deletions src/libutil/argparse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ class ArgParse::Impl {
bool m_print_defaults = false;
bool m_add_help = true;
bool m_exit_on_error = true;
bool m_aborted = false;
std::vector<std::unique_ptr<ArgOption>> m_option;
callback_t m_preoption_help = [](const ArgParse&, std::ostream&) {};
callback_t m_postoption_help = [](const ArgParse&, std::ostream&) {};
Expand Down Expand Up @@ -294,7 +295,7 @@ ArgOption::initialize()
std::cerr << "Programmer error: Unknown option ";
std::cerr << "type string \"" << *s << "\""
<< "\n";
abort();
return 0;
}
}

Expand Down Expand Up @@ -385,7 +386,7 @@ ArgOption::set_parameter(int i, const char* argv)
case '!': *(bool*)m_param[i] = false; break;

case '*':
default: abort();
default: break;
}
}

Expand Down Expand Up @@ -445,13 +446,19 @@ ArgParse::Impl::parse_args(int xargc, const char** xargv)
m_option[0]->m_help = "Print help message";
m_option[0]->m_action = [&](Arg& arg, cspan<const char*> myarg) {
this->m_argparse.print_help();
exit(EXIT_SUCCESS);
if (m_exit_on_error)
exit(EXIT_SUCCESS);
else {
m_argparse.abort();
}
};
m_option[0]->initialize();
}

bool any_option_encountered = false;
for (int i = 1; i < m_argc; i++) {
if (m_aborted)
break;
if (m_argv[i][0] == '-'
&& (isalpha(m_argv[i][1]) || m_argv[i][1] == '-')) { // flag
any_option_encountered = true;
Expand Down Expand Up @@ -1057,4 +1064,18 @@ ArgParse::set_postoption_help(callback_t callback)



void
ArgParse::abort(bool aborted)
{
m_impl->m_aborted = aborted;
}



bool
ArgParse::aborted() const
{
return m_impl->m_aborted;
}

OIIO_NAMESPACE_END
36 changes: 32 additions & 4 deletions src/libutil/filesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,23 @@ Filesystem::filename(const std::string& filepath) noexcept
{
// To simplify dealing with platform-specific separators and whatnot,
// just use the Boost routines:
return pathstr(u8path(filepath).filename());
try {
return pathstr(u8path(filepath).filename());
} catch (...) {
return filepath;
}
}



std::string
Filesystem::extension(const std::string& filepath, bool include_dot) noexcept
{
std::string s = pathstr(u8path(filepath).extension());
std::string s;
try {
s = pathstr(u8path(filepath).extension());
} catch (...) {
}
if (!include_dot && !s.empty() && s[0] == '.')
s.erase(0, 1); // erase the first character
return s;
Expand All @@ -118,7 +126,11 @@ Filesystem::extension(const std::string& filepath, bool include_dot) noexcept
std::string
Filesystem::parent_path(const std::string& filepath) noexcept
{
return pathstr(u8path(filepath).parent_path());
try {
return pathstr(u8path(filepath).parent_path());
} catch (...) {
return filepath;
}
}


Expand All @@ -127,7 +139,23 @@ std::string
Filesystem::replace_extension(const std::string& filepath,
const std::string& new_extension) noexcept
{
return pathstr(u8path(filepath).replace_extension(new_extension));
try {
return pathstr(u8path(filepath).replace_extension(new_extension));
} catch (...) {
return filepath;
}
}



std::string
Filesystem::generic_filepath(string_view filepath) noexcept
{
try {
return pathstr(u8path(filepath).generic_string());
} catch (...) {
return filepath;
}
}


Expand Down
8 changes: 8 additions & 0 deletions src/libutil/filesystem_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ test_filename_decomposition()
std::cout << "Testing replace_extension\n";
OIIO_CHECK_EQUAL(Filesystem::replace_extension(test, "foo"),
"/directoryA/directory/filename.foo");

std::cout << "Testing generic_string\n";
#if _WIN32
OIIO_CHECK_EQUAL(Filesystem::generic_filepath("\\x\\y"), "/x/y");
OIIO_CHECK_EQUAL(Filesystem::generic_filepath("c:\\x\\y"), "/c/x/y");
#endif
}


Expand Down Expand Up @@ -287,6 +293,8 @@ test_scan_file_seq_with_views(const char* pattern, const char** views_,
Filesystem::scan_for_matching_filenames(normalized_pattern, views,
frame_numbers, frame_views,
frame_names);
for (auto& f : frame_names)
f = Filesystem::generic_filepath(f);
std::string joined = Strutil::join(frame_names, " ");
std::cout << " " << pattern;
std::cout << " -> " << joined << "\n";
Expand Down
Loading

0 comments on commit 1d8948c

Please sign in to comment.