void split_paths( const filesystem::path& p1, const filesystem::path& p2, filesystem::path& common, filesystem::path& r1, filesystem::path& r2) { assert(common.empty()); assert(r1.empty()); assert(r2.empty()); filesystem::path::const_iterator i1 = p1.begin(); filesystem::path::const_iterator i2 = p2.begin(); while (i1 != p1.end() && i2 != p2.end()) { if (*i1 != *i2) break; if ((p1.has_filename() && succ(i1) == p1.end()) || (p2.has_filename() && succ(i2) == p2.end())) break; common /= *i1; ++i1, ++i2; } while (i1 != p1.end()) r1 /= *i1++; while (i2 != p2.end()) r2 /= *i2++; }
fs::path mpw_path() { static fs::path path; if (path.empty()) { std::error_code ec; const char *cp = getenv("PATH"); if (!cp) cp = _PATH_DEFPATH; std::string s(cp); string_splitter ss(s, ':'); for (; ss; ++ss) { if (ss->empty()) continue; fs::path p(*ss); p /= "mpw"; if (fs::is_regular_file(p, ec)) { path = std::move(p); break; } } //also check /usr/local/bin if (path.empty()) { fs::path p = "/usr/local/bin/mpw"; if (fs::is_regular_file(p, ec)) { path = std::move(p); } } if (path.empty()) { fs::path p = root() / "bin/mpw"; if (fs::is_regular_file(p, ec)) { path = std::move(p); } } if (path.empty()) { fprintf(stderr, "Unable to find mpw executable\n"); fprintf(stderr, "PATH = %s\n", s.c_str()); path = "mpw"; } } return path; }
promise< std::pair< std::int64_t, int > > process::create( const filesystem::path &exe, const std::vector< std::string > &args, const env_t &env, const filesystem::path &working_directory, pid_t &pid, input_f stdin_handler, output_f stdout_handler, output_f stderr_handler ) { auto context = std::unique_ptr< process_s, std::function< void ( process_s* )> >( new process_s(), []( auto handle ) { uv_close( reinterpret_cast< uv_handle_t* >( handle ), []( auto handle ) { auto context = reinterpret_cast< process_s* >( handle ); delete context; } ); } ); #if defined( WIN32 ) auto env_vec = std::vector< std::string >(); #endif auto c_args = std::vector< const char* >(); auto c_env = std::vector< const char* >(); auto ret = promise< std::pair< std::int64_t, int > >(); context->stdin_handler = stdin_handler; context->stdout_handler = stdout_handler; context->stderr_handler = stderr_handler; context->ret = ret; c_args.push_back( exe.c_str() ); for ( auto &arg : args ) { c_args.push_back( arg.c_str() ); } c_args.push_back( nullptr ); context->options.file = exe.c_str(); context->options.args = const_cast< char** >( c_args.data() ); #if defined( WIN32 ) context->options.flags = UV_PROCESS_DETACHED; #endif if ( !env.empty() ) { #if defined( WIN32 ) # undef GetEnvironmentStrings auto strings = GetEnvironmentStrings(); auto prev = 0; for ( auto i = 0; ; i++ ) { if ( strings[ i ] == '\0' ) { env_vec.emplace_back( strings + prev, strings + i ); prev = i; if ( strings[ i + 1 ] == '\0' ) { break; } } } FreeEnvironmentStringsA( strings ); for ( auto &string : env_vec ) { c_env.push_back( string.c_str() ); } #else for ( int i = 0; environ[ i ] != nullptr; i++ ) { c_env.push_back( environ[ i ] ); } #endif for ( auto it = env.begin(); it != env.end(); it++ ) { c_env.push_back( it->c_str() ); } c_env.push_back( nullptr ); context->options.env = const_cast< char** >( c_env.data() ); } if ( !working_directory.empty() ) { context->options.cwd = working_directory.c_str(); } context->options.exit_cb = exit_cb; auto err = uv_spawn( uv_default_loop(), context.get(), &context->options ); ncheck_error_action( err == 0, ret.reject( std::error_code( err, libuv::error_category() ) ), exit ); if ( stdin_handler ) { auto str = stdin_handler(); auto buf = uv_buf_init( const_cast< char* >( str.data() ), str.size() ); auto req = new uv_write_t; auto err = std::error_code( uv_write( req, reinterpret_cast< uv_stream_t* >( context->in ), &buf, 1, on_write ), libuv::error_category() ); } err = uv_read_start( reinterpret_cast< uv_stream_t* >( context->out ), on_alloc_stdout, on_read_stdout ); ncheck_error_action( err == 0, ret.reject( std::error_code( err, libuv::error_category() ) ), exit ); err = uv_read_start( reinterpret_cast< uv_stream_t* >( context->err ), on_alloc_stderr, on_read_stderr ); ncheck_error_action( err == 0, ret.reject( std::error_code( err, libuv::error_category() ) ), exit ); pid = context->pid; context.release(); exit: return ret; }