Permalink
Browse files

Add tiny process (#9)

add tiny-process-library as 3rdparty module

git-subtree-dir: keyvi/3rdparty/tiny-process-library
git-subtree-split: e828cba32d5da1c0a661c1fbc8233e8c7d946b01
  • Loading branch information...
hendrikmuhs committed Nov 12, 2017
1 parent dc11842 commit 0549c98e06ff369529f904522bb716ed6b007615
@@ -6,3 +6,4 @@ git remote add rapidjson https://github.com/miloyip/rapidjson.git
git remote add msgpack-c https://github.com/msgpack/msgpack-c.git
git remote add tpie https://github.com/thomasmoelhave/tpie.git
git remote add xchange https://github.com/xpol/xchange.git
git remote add tiny-process-library https://github.com/eidheim/tiny-process-library.git
@@ -0,0 +1,2 @@
#!/bin/sh
git subtree pull --prefix keyvi/3rdparty/tiny-process-library tiny-process-library master --squash
@@ -0,0 +1,47 @@
# https://github.com/github/gitignore/blob/master/CMake.gitignore
CMakeCache.txt
CMakeFiles
CMakeScripts
Makefile
cmake_install.cmake
install_manifest.txt
*.cmake
#Additions to https://github.com/github/gitignore/blob/master/CMake.gitignore
Testing
compile_commands.json
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
examples
open_close_test
multithread_test
io_test
# Commonly used build directory
build
@@ -0,0 +1,18 @@
sudo: required
services:
- docker
script:
- sudo docker run -it -v "$PWD:/repository" eidheim/testing sh -c "
cd /repository && mkdir build && cd build &&
scan-build cmake -DCMAKE_CXX_FLAGS=-Werror .. &&
scan-build --status-bugs make &&
rm -r * &&
CXX=clang++ cmake -DCMAKE_CXX_FLAGS=-Werror .. &&
make &&
rm -r * &&
CXX=g++ cmake -DCMAKE_CXX_FLAGS=-Werror .. &&
make &&
CTEST_OUTPUT_ON_FAILURE=1 make test
"
@@ -0,0 +1,44 @@
cmake_minimum_required(VERSION 2.8)
project(tiny-process-library)
if(MSVC)
add_definitions(_CRT_SECURE_NO_WARNINGS)
else()
add_compile_options(-std=c++11 -Wall -Wextra)
endif()
add_library(tiny-process-library process.cpp)
if(WIN32)
target_sources(tiny-process-library PRIVATE process_win.cpp)
#If compiled using MSYS2, use sh to run commands
if(MSYS)
target_compile_definitions(tiny-process-library PUBLIC MSYS_PROCESS_USE_SH)
endif()
else()
target_sources(tiny-process-library PRIVATE process_unix.cpp)
endif()
find_package(Threads REQUIRED)
target_link_libraries(tiny-process-library ${CMAKE_THREAD_LIBS_INIT})
target_include_directories(tiny-process-library PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
option(BUILD_TESTING OFF)
# if tiny-process-library is not a sub-project:
if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
add_executable(examples examples.cpp)
target_link_libraries(examples tiny-process-library)
set(BUILD_TESTING ON)
install(TARGETS tiny-process-library DESTINATION lib)
install(FILES process.hpp DESTINATION include)
endif()
if(BUILD_TESTING)
enable_testing()
add_subdirectory(tests)
endif()
@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015-2016 Ole Christian Eidheim
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,42 @@
# tiny-process-library [![Build Status](https://travis-ci.org/eidheim/tiny-process-library.svg?branch=master)](https://travis-ci.org/eidheim/tiny-process-library)
A small platform independent library making it simple to create and stop new processes in C++, as well as writing to stdin and reading from stdout and stderr of a new process.
This library was created for, and is used by the C++ IDE project [juCi++](https://github.com/cppit/jucipp).
### Features
* No external dependencies
* Simple to use
* Platform independent
* Creating processes using executables is supported on all platforms
* Creating processes using functions is only possible on Unix-like systems
* Read separately from stdout and stderr using anonymous functions
* Write to stdin
* Kill a running process (SIGTERM is supported on Unix-like systems)
* Correctly closes file descriptors/handles
### Usage
See [examples.cpp](https://github.com/eidheim/tiny-process-library/blob/master/examples.cpp).
### Get, compile and run
#### Unix-like systems
```sh
git clone http://github.com/eidheim/tiny-process-library
cd tiny-process-library
mkdir build
cd build
cmake ..
make
./examples
```
#### Windows with MSYS2 (https://msys2.github.io/)
```sh
git clone http://github.com/eidheim/tiny-process-library
cd tiny-process-library
mkdir build
cd build
cmake -G"MSYS Makefiles" ..
make
./examples
```
@@ -0,0 +1,159 @@
#include "process.hpp"
#include <iostream>
using namespace std;
using namespace TinyProcessLib;
int main() {
#if !defined(_WIN32) || defined(MSYS_PROCESS_USE_SH)
//The following examples are for Unix-like systems and Windows through MSYS2
cout << "Example 1a - the mandatory Hello World through an executable" << endl;
Process process1a("echo Hello World", "", [](const char *bytes, size_t n) {
cout << "Output from stdout: " << string(bytes, n);
});
auto exit_status=process1a.get_exit_status();
cout << "Example 1a process returned: " << exit_status << " (" << (exit_status==0?"success":"failure") << ")" << endl;
this_thread::sleep_for(chrono::seconds(5));
#ifndef _WIN32
cout << endl << "Example 1b - Hello World through a function on Unix-like systems" << endl;
Process process1b([] {
cout << "Hello World" << endl;
exit(0);
}, [](const char *bytes, size_t n) {
cout << "Output from stdout: " << string(bytes, n);
});
exit_status=process1b.get_exit_status();
cout << "Example 1b process returned: " << exit_status << " (" << (exit_status==0?"success":"failure") << ")" << endl;
this_thread::sleep_for(chrono::seconds(5));
#endif
cout << endl << "Example 2 - cd into a nonexistent directory" << endl;
Process process2("cd a_nonexistent_directory", "", [](const char *bytes, size_t n) {
cout << "Output from stdout: " << string(bytes, n);
}, [](const char *bytes, size_t n) {
cout << "Output from stderr: " << string(bytes, n);
//add a newline for prettier output on some platforms:
if(bytes[n-1]!='\n')
cout << endl;
});
exit_status=process2.get_exit_status();
cout << "Example 2 process returned: " << exit_status << " (" << (exit_status==0?"success":"failure") << ")" << endl;
this_thread::sleep_for(chrono::seconds(5));
cout << endl << "Example 3 - async sleep process" << endl;
thread thread3([]() {
Process process3("sleep 5");
auto exit_status=process3.get_exit_status();
cout << "Example 3 process returned: " << exit_status << " (" << (exit_status==0?"success":"failure") << ")" << endl;
});
thread3.detach();
this_thread::sleep_for(chrono::seconds(10));
cout << endl << "Example 4 - killing async sleep process after 5 seconds" << endl;
auto process4=make_shared<Process>("sleep 10");
thread thread4([process4]() {
auto exit_status=process4->get_exit_status();
cout << "Example 4 process returned: " << exit_status << " (" << (exit_status==0?"success":"failure") << ")" << endl;
});
thread4.detach();
this_thread::sleep_for(chrono::seconds(5));
process4->kill();
this_thread::sleep_for(chrono::seconds(5));
cout << endl << "Example 5 - multiple commands, stdout and stderr" << endl;
Process process5("echo Hello && ls an_incorrect_path", "", [](const char *bytes, size_t n) {
cout << "Output from stdout: " << string(bytes, n);
}, [](const char *bytes, size_t n) {
cout << "Output from stderr: " << string(bytes, n);
//add a newline for prettier output on some platforms:
if(bytes[n-1]!='\n')
cout << endl;
});
exit_status=process5.get_exit_status();
cout << "Example 5 process returned: " << exit_status << " (" << (exit_status==0?"success":"failure") << ")" << endl;
this_thread::sleep_for(chrono::seconds(5));
cout << endl << "Example 6 - run bash with input from stdin" << endl;
Process process6("bash", "", [](const char *bytes, size_t n) {
cout << "Output from stdout: " << string(bytes, n);
}, nullptr, true);
process6.write("echo Hello from bash\n");
process6.write("exit\n");
exit_status=process6.get_exit_status();
cout << "Example 6 process returned: " << exit_status << " (" << (exit_status==0?"success":"failure") << ")" << endl;
this_thread::sleep_for(chrono::seconds(5));
cout << endl << "Example 7 - send data to cat through stdin" << endl;
Process process7("cat", "", [](const char *bytes, size_t n) {
cout << "Output from stdout: " << string(bytes, n);
}, nullptr, true);
process7.write("Hello cat\n");
process7.close_stdin();
exit_status=process7.get_exit_status();
cout << "Example 7 process returned: " << exit_status << " (" << (exit_status==0?"success":"failure") << ")" << endl;
this_thread::sleep_for(chrono::seconds(5));
#else
//Examples for Windows without MSYS2
cout << "Example 1 - the mandatory Hello World" << endl;
Process process1("cmd /C echo Hello World", "", [](const char *bytes, size_t n) {
cout << "Output from stdout: " << string(bytes, n);
});
auto exit_status=process1.get_exit_status();
cout << "Example 1 process returned: " << exit_status << " (" << (exit_status==0?"success":"failure") << ")" << endl;
this_thread::sleep_for(chrono::seconds(5));
cout << endl << "Example 2 - cd into a nonexistent directory" << endl;
Process process2("cmd /C cd a_nonexistent_directory", "", [](const char *bytes, size_t n) {
cout << "Output from stdout: " << string(bytes, n);
}, [](const char *bytes, size_t n) {
cout << "Output from stderr: " << string(bytes, n);
//add a newline for prettier output on some platforms:
if(bytes[n-1]!='\n')
cout << endl;
});
exit_status=process2.get_exit_status();
cout << "Example 2 process returned: " << exit_status << " (" << (exit_status==0?"success":"failure") << ")" << endl;
this_thread::sleep_for(chrono::seconds(5));
cout << endl << "Example 3 - async sleep process" << endl;
thread thread3([]() {
Process process3("timeout 5");
auto exit_status=process3.get_exit_status();
cout << "Example 3 process returned: " << exit_status << " (" << (exit_status==0?"success":"failure") << ")" << endl;
});
thread3.detach();
this_thread::sleep_for(chrono::seconds(10));
cout << endl << "Example 4 - killing async sleep process after 5 seconds" << endl;
auto process4=make_shared<Process>("timeout 10");
thread thread4([process4]() {
auto exit_status=process4->get_exit_status();
cout << "Example 4 process returned: " << exit_status << " (" << (exit_status==0?"success":"failure") << ")" << endl;
});
thread4.detach();
this_thread::sleep_for(chrono::seconds(5));
process4->kill();
this_thread::sleep_for(chrono::seconds(5));
#endif
return 0;
}
@@ -0,0 +1,26 @@
#include "process.hpp"
namespace TinyProcessLib {
Process::Process(const string_type &command, const string_type &path,
std::function<void(const char* bytes, size_t n)> read_stdout,
std::function<void(const char* bytes, size_t n)> read_stderr,
bool open_stdin, size_t buffer_size) noexcept:
closed(true), read_stdout(read_stdout), read_stderr(read_stderr), open_stdin(open_stdin), buffer_size(buffer_size) {
open(command, path);
async_read();
}
Process::~Process() noexcept {
close_fds();
}
Process::id_type Process::get_id() const noexcept {
return data.id;
}
bool Process::write(const std::string &data) {
return write(data.c_str(), data.size());
}
} // TinyProsessLib
Oops, something went wrong.

0 comments on commit 0549c98

Please sign in to comment.