diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml new file mode 100644 index 0000000..ee3d89d --- /dev/null +++ b/.github/workflows/unit-test.yml @@ -0,0 +1,25 @@ +name: unit-test + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + compiler: [g++, clang++] + steps: + - uses: actions/checkout@v4 + - name: Install dependencies + run: sudo apt-get install -y libboost-all-dev + - name: Build + run: | + ./autogen.sh + ./configure CXX=${{ matrix.compiler }} + make + - name: Test + run: make test diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c1695de..0000000 --- a/.travis.yml +++ /dev/null @@ -1,18 +0,0 @@ -language: cpp - -compiler: - - gcc-4.8 - - clang - -install: - - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi - -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-4.8 - - libboost-all-dev - -script: ./autogen.sh && ./configure && make && make test diff --git a/README.md b/README.md index 81a207d..71caf01 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,8 @@ int main(int argc, char *argv[]) { subprocess::popen cmd("ls", {}); - std::cout << cmd.stdout().rdbuf(); - + std::cout << cmd.out().rdbuf(); + return 0; } ``` @@ -51,15 +51,15 @@ main(int argc, char *argv[]) std::ifstream file("inputfile.txt"); std::string line; - + while (std::getline(file, line)) { - cmd.stdin() << line << std::endl; + cmd.in() << line << std::endl; } cmd.close(); - - std::cout << cmd.stdout().rdbuf(); - + + std::cout << cmd.out().rdbuf(); + return 0; } ``` @@ -77,14 +77,14 @@ int main(int argc, char *argv[]) { subprocess::popen sort_cmd("sort", {"-r"}); - subprocess::popen cat_cmd("cat", {}, sort_cmd.stdin()); + subprocess::popen cat_cmd("cat", {}, sort_cmd.in()); - cat_cmd.stdin() << "a" << std::endl; - cat_cmd.stdin() << "b" << std::endl; - cat_cmd.stdin() << "c" << std::endl; + cat_cmd.in() << "a" << std::endl; + cat_cmd.in() << "b" << std::endl; + cat_cmd.in() << "c" << std::endl; cat_cmd.close(); - std::cout << sort_cmd.stdout().rdbuf(); + std::cout << sort_cmd.out().rdbuf(); return 0; } @@ -104,16 +104,16 @@ main(int argc, char *argv[]) subprocess::popen cat_cmd("cat", {}); - cat_cmd.stdin() << "a" << std::endl; - std::getline(cat_cmd.stdout(), buf); + cat_cmd.in() << "a" << std::endl; + std::getline(cat_cmd.out(), buf); std::cout << buf << std::endl; - cat_cmd.stdin() << "b" << std::endl; - std::getline(cat_cmd.stdout(), buf); + cat_cmd.in() << "b" << std::endl; + std::getline(cat_cmd.out(), buf); std::cout << buf << std::endl; - cat_cmd.stdin() << "c" << std::endl; - std::getline(cat_cmd.stdout(), buf); + cat_cmd.in() << "c" << std::endl; + std::getline(cat_cmd.out(), buf); std::cout << buf << std::endl; return 0; diff --git a/include/subprocess.hpp b/include/subprocess.hpp index 1871d83..1413428 100644 --- a/include/subprocess.hpp +++ b/include/subprocess.hpp @@ -23,7 +23,7 @@ namespace subprocess { class popen -{ +{ public: popen(const std::string& cmd, std::vector argv) @@ -65,16 +65,16 @@ class popen delete err_stream; } - std::ostream& stdin() { return *in_stream; }; + std::ostream& in() { return *in_stream; }; - std::istream& stdout() + std::istream& out() { if (out_stream == nullptr) throw std::system_error(EBADF, std::system_category()); return *out_stream; }; - - std::istream& stderr() { return *err_stream; }; - + + std::istream& err() { return *err_stream; }; + int wait() { int status = 0; @@ -86,10 +86,10 @@ class popen { in_filebuf->close(); } - - + + private: - + enum ends_of_pipe { READ = 0, WRITE = 1 }; struct raii_char_str @@ -104,28 +104,28 @@ class popen argv.insert(argv.begin(), cmd); pid = ::fork(); - + if (pid == 0) child(argv); ::close(in_pipe[READ]); ::close(out_pipe[WRITE]); ::close(err_pipe[WRITE]); - + in_filebuf = new __gnu_cxx::stdio_filebuf(in_pipe[WRITE], std::ios_base::out, 1); in_stream = new std::ostream(in_filebuf); - + if (out_pipe[READ] != -1) { out_filebuf = new __gnu_cxx::stdio_filebuf(out_pipe[READ], std::ios_base::in, 1); out_stream = new std::istream(out_filebuf); } - + err_filebuf = new __gnu_cxx::stdio_filebuf(err_pipe[READ], std::ios_base::in, 1); err_stream = new std::istream(err_filebuf); } - + void child(const std::vector& argv) - { + { if (dup2(in_pipe[READ], STDIN_FILENO) == -1 || dup2(out_pipe[WRITE], STDOUT_FILENO) == -1 || dup2(err_pipe[WRITE], STDERR_FILENO) == -1 ) @@ -138,13 +138,13 @@ class popen ::close(in_pipe[WRITE]); if (out_pipe[READ] != -1) ::close(out_pipe[READ]); ::close(out_pipe[WRITE]); - ::close(err_pipe[READ]); + ::close(err_pipe[READ]); ::close(err_pipe[WRITE]); - + std::vector real_args(argv.begin(), argv.end()); std::vector cargs(real_args.begin(), real_args.end()); cargs.push_back(nullptr); - + if (execvp(cargs[0], &cargs[0]) == -1) { std::perror("subprocess: execvp() failed"); @@ -157,7 +157,7 @@ class popen int in_pipe[2]; int out_pipe[2]; int err_pipe[2]; - + __gnu_cxx::stdio_filebuf* in_filebuf; __gnu_cxx::stdio_filebuf* out_filebuf; __gnu_cxx::stdio_filebuf* err_filebuf; diff --git a/tests/test-subprocess.cpp b/tests/test-subprocess.cpp index c59c635..bfe7855 100644 --- a/tests/test-subprocess.cpp +++ b/tests/test-subprocess.cpp @@ -12,7 +12,7 @@ BOOST_AUTO_TEST_CASE(arguments) subprocess::popen cmd("echo", {"foo", "bar", "baz"}); std::string buf; - std::getline(cmd.stdout(), buf); + std::getline(cmd.out(), buf); BOOST_CHECK_EQUAL(buf, "foo bar baz"); BOOST_CHECK_EQUAL(cmd.wait(), 0); @@ -22,12 +22,12 @@ BOOST_AUTO_TEST_CASE(stdio_forwarding) { subprocess::popen cmd("cat", {}); - cmd.stdin() << "Hello world!" << std::endl; + cmd.in() << "Hello world!" << std::endl; cmd.close(); - + std::string buf; - std::getline(cmd.stdout(), buf); - + std::getline(cmd.out(), buf); + BOOST_CHECK_EQUAL(buf, "Hello world!"); BOOST_CHECK_EQUAL(cmd.wait(), 0); } @@ -36,7 +36,7 @@ BOOST_AUTO_TEST_CASE(return_values) { subprocess::popen true_cmd("true", {}); BOOST_CHECK_EQUAL(true_cmd.wait(), 0); - + subprocess::popen false_cmd("false", {}); BOOST_CHECK_EQUAL(false_cmd.wait(), 1); } @@ -50,20 +50,20 @@ BOOST_AUTO_TEST_CASE(bad_command) BOOST_AUTO_TEST_CASE(pipes) { - subprocess::popen sort_cmd("sort", {"-r"}); - subprocess::popen cat_cmd("cat", {}, sort_cmd.stdin()); - - cat_cmd.stdin() << "a" << std::endl; - cat_cmd.stdin() << "b" << std::endl; - cat_cmd.stdin() << "c" << std::endl; + subprocess::popen sort_cmd("sort", {"-r"}); + subprocess::popen cat_cmd("cat", {}, sort_cmd.in()); + + cat_cmd.in() << "a" << std::endl; + cat_cmd.in() << "b" << std::endl; + cat_cmd.in() << "c" << std::endl; cat_cmd.close(); - + std::string line; - std::getline(sort_cmd.stdout(), line); + std::getline(sort_cmd.out(), line); BOOST_CHECK_EQUAL(line, "c"); - std::getline(sort_cmd.stdout(), line); + std::getline(sort_cmd.out(), line); BOOST_CHECK_EQUAL(line, "b"); - std::getline(sort_cmd.stdout(), line); + std::getline(sort_cmd.out(), line); BOOST_CHECK_EQUAL(line, "a"); BOOST_CHECK(cat_cmd.wait() == 0);