detachRedirOut for Cmd
This commit is contained in:
+23
-18
@@ -7,9 +7,10 @@
|
|||||||
/* All CONST references are used and cast away to allow for taking
|
/* All CONST references are used and cast away to allow for taking
|
||||||
both l and r values without using templates or making copies
|
both l and r values without using templates or making copies
|
||||||
|
|
||||||
implicitly convert to it but not to const char* and we want the
|
char* arg pointers are kept and used NOT COPIED
|
||||||
implicit conversion for quick scripting
|
|
||||||
arg pointers are kept and used not copied */
|
Anything that takes a PendingCmd takes a Cmd as well
|
||||||
|
*/
|
||||||
|
|
||||||
/* A shell command */
|
/* A shell command */
|
||||||
class Cmd
|
class Cmd
|
||||||
@@ -28,9 +29,6 @@ public:
|
|||||||
to redirect err to out by giving err=1 like in shell */
|
to redirect err to out by giving err=1 like in shell */
|
||||||
DeadProc operator()(fd_t in=0, fd_t out=1, fd_t err=2) const;
|
DeadProc operator()(fd_t in=0, fd_t out=1, fd_t err=2) const;
|
||||||
|
|
||||||
/* Run the command, don't wait to return like shell's & */
|
|
||||||
Proc detach(fd_t in=0, fd_t out=1, fd_t err=2) const;
|
|
||||||
|
|
||||||
/* Append arguments */
|
/* Append arguments */
|
||||||
void append_args(std::initializer_list<const char*>);
|
void append_args(std::initializer_list<const char*>);
|
||||||
/* Append an argument and return the new command */
|
/* Append an argument and return the new command */
|
||||||
@@ -52,37 +50,40 @@ public:
|
|||||||
/* Execute the command on destruction */
|
/* Execute the command on destruction */
|
||||||
~PendingCmd();
|
~PendingCmd();
|
||||||
|
|
||||||
/* No copy we use unnamed return value optimization to return PendingCmd without destruction */
|
/* No copy - we use unnamed return value optimization to return PendingCmd without destruction */
|
||||||
PendingCmd(const PendingCmd&) = delete;
|
PendingCmd(const PendingCmd&) = delete;
|
||||||
PendingCmd& operator=(const PendingCmd&) = delete;
|
PendingCmd& operator=(const PendingCmd&) = delete;
|
||||||
|
|
||||||
/* Run the command */
|
/* Run the command */
|
||||||
DeadProc operator()();
|
DeadProc operator()();
|
||||||
|
|
||||||
/* Run the command async
|
|
||||||
shell: cmd &
|
|
||||||
becomes: cmd.detach() */
|
|
||||||
Proc detach();
|
|
||||||
/* Detach but redirect output to a pipe */
|
|
||||||
Proc detachRedirOut();
|
|
||||||
|
|
||||||
/* Prevent a pending command from being executed on destruction */
|
/* Prevent a pending command from being executed on destruction */
|
||||||
void cancel();
|
void cancel();
|
||||||
|
|
||||||
Cmd cmd;
|
const Cmd& cmd;
|
||||||
fd_t in, out, err;
|
fd_t in, out, err;
|
||||||
private:
|
private:
|
||||||
bool execed_;
|
bool execed_;
|
||||||
|
|
||||||
|
friend Proc detach(const PendingCmd&);
|
||||||
|
friend Proc detachRedirOut(const PendingCmd&);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Anything that takes PendingCmd can take Cmd aswell */
|
|
||||||
|
|
||||||
/* Like shell's exec */
|
/* Like shell's exec */
|
||||||
void exec(const Cmd&); /* todo: take Pending? */
|
void exec(const Cmd&); /* todo: take Pending? */
|
||||||
|
|
||||||
/* Execute the command, like the operator() */
|
/* Execute the command, like the operator() */
|
||||||
DeadProc run(const Cmd&);
|
DeadProc run(const PendingCmd&);
|
||||||
|
|
||||||
|
/* Run the command async
|
||||||
|
shell: cmd &
|
||||||
|
becomes: cmd.detach() */
|
||||||
|
Proc detach(const PendingCmd&);
|
||||||
|
|
||||||
|
/* Detach but redirect output to a pipe */
|
||||||
|
Proc detachRedirOut(const PendingCmd&);
|
||||||
|
|
||||||
|
|
||||||
/* Run commands in sequence
|
/* Run commands in sequence
|
||||||
shell:
|
shell:
|
||||||
@@ -164,6 +165,10 @@ PendingCmd operator&(const PendingCmd&, const Cmd&);
|
|||||||
*/
|
*/
|
||||||
std::string $(const PendingCmd&);
|
std::string $(const PendingCmd&);
|
||||||
|
|
||||||
|
/* Read from a file descriptor until it closes
|
||||||
|
can be used on proccess out/err */
|
||||||
|
std::string read_to_end(fd_t);
|
||||||
|
|
||||||
/* Operator<< for printing */
|
/* Operator<< for printing */
|
||||||
std::ostream& operator<<(std::ostream&, const Cmd&);
|
std::ostream& operator<<(std::ostream&, const Cmd&);
|
||||||
|
|
||||||
|
|||||||
+78
-76
@@ -43,11 +43,6 @@ inline DeadProc Cmd::operator()(fd_t in, fd_t out, fd_t err) const
|
|||||||
return wait(p);
|
return wait(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Proc Cmd::detach(fd_t in, fd_t out, fd_t err) const
|
|
||||||
{
|
|
||||||
return createProcess(argv.data(), in, out, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Cmd::append_args(std::initializer_list<const char*> args)
|
inline void Cmd::append_args(std::initializer_list<const char*> args)
|
||||||
{
|
{
|
||||||
argv.reserve(argv.size() + args.size());
|
argv.reserve(argv.size() + args.size());
|
||||||
@@ -100,31 +95,30 @@ inline DeadProc PendingCmd::operator()()
|
|||||||
return cmd(in, out, err);
|
return cmd(in, out, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Proc PendingCmd::detach()
|
|
||||||
{
|
|
||||||
assert(!execed_ && "Executed command twice");
|
|
||||||
execed_ = true;
|
|
||||||
return cmd.detach(in, out, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Proc PendingCmd::detachRedirOut()
|
|
||||||
{
|
|
||||||
assert(!execed_ && "Executed command twice");
|
|
||||||
assert(out==1 && "Capturing redirected proccess");
|
|
||||||
|
|
||||||
execed_ = true;
|
|
||||||
return createCapProcess(cmd.argv.data(), in, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void PendingCmd::cancel()
|
inline void PendingCmd::cancel()
|
||||||
{
|
{
|
||||||
execed_ = true;
|
execed_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string $(const PendingCmd& cmd)
|
inline std::string $(const PendingCmd& c)
|
||||||
{
|
{
|
||||||
Proc p = const_cast<PendingCmd&>(cmd).detachRedirOut();
|
Proc p = detachRedirOut(c);
|
||||||
|
|
||||||
|
std::string output = read_to_end(p.out);
|
||||||
|
|
||||||
|
// Remove trailing newlines
|
||||||
|
int i = output.size() - 1;
|
||||||
|
while(i > 0 && output[i] == '\n')
|
||||||
|
--i;
|
||||||
|
|
||||||
|
// erase the newlines
|
||||||
|
output.erase(i+1, -1); // till the end
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string read_to_end(fd_t fd)
|
||||||
|
{
|
||||||
// write to the string directly, todo: find a better way
|
// write to the string directly, todo: find a better way
|
||||||
std::string output;
|
std::string output;
|
||||||
|
|
||||||
@@ -134,44 +128,53 @@ inline std::string $(const PendingCmd& cmd)
|
|||||||
{
|
{
|
||||||
output.resize(output.size() + PIPE_BUF); // todo: check if we are overallocating
|
output.resize(output.size() + PIPE_BUF); // todo: check if we are overallocating
|
||||||
|
|
||||||
read_count = read(p.out, &output[i], PIPE_BUF); // todo: check errno
|
read_count = read(fd, &output[i], PIPE_BUF); // todo: check errno
|
||||||
if(read_count > 0)
|
if(read_count > 0)
|
||||||
i += read_count;
|
i += read_count;
|
||||||
}
|
}
|
||||||
while(read_count > 0);
|
while(read_count > 0);
|
||||||
// p finished?
|
|
||||||
|
|
||||||
// Remove trailing newlines
|
close(fd);
|
||||||
// i is on the past the end element, go back to end
|
|
||||||
int j = i - 1;
|
|
||||||
|
|
||||||
while(j > 0 && output[j] == '\n')
|
|
||||||
--j;
|
|
||||||
|
|
||||||
i = j + 1;
|
|
||||||
|
|
||||||
// erase the extra elements
|
// erase the extra elements
|
||||||
output.erase(i, -1); // till the end
|
output.erase(i, -1); // till the end
|
||||||
|
|
||||||
close(p.out);
|
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void exec(const Cmd& cmd)
|
inline void exec(const Cmd& c)
|
||||||
{
|
{
|
||||||
exec_or_die(cmd.argv.data());
|
exec_or_die(c.argv.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline DeadProc run(const Cmd& cmd)
|
inline DeadProc run(const PendingCmd& c)
|
||||||
{
|
{
|
||||||
return cmd();
|
return const_cast<PendingCmd&>(c)();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PendingCmd operator,(const PendingCmd& cleft, const Cmd& right)
|
inline Proc detach(const PendingCmd& ccmd)
|
||||||
{
|
{
|
||||||
auto& left = const_cast<PendingCmd&>(cleft);
|
auto& c = const_cast<PendingCmd&>(ccmd);
|
||||||
left();
|
|
||||||
|
assert(!c.execed_ && "Executed command twice");
|
||||||
|
c.execed_ = true;
|
||||||
|
return createProcess(c.cmd.argv.data(), c.in, c.out, c.err);
|
||||||
|
}
|
||||||
|
|
||||||
|
Proc detachRedirOut(const PendingCmd& ccmd)
|
||||||
|
{
|
||||||
|
auto& c = const_cast<PendingCmd&>(ccmd);
|
||||||
|
|
||||||
|
assert(!c.execed_ && "Executed command twice");
|
||||||
|
assert(c.out==1 && "Capturing redirected proccess");
|
||||||
|
|
||||||
|
c.execed_ = true;
|
||||||
|
return createCapProcess(c.cmd.argv.data(), c.in, c.err);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline PendingCmd operator,(const PendingCmd& left, const Cmd& right)
|
||||||
|
{
|
||||||
|
run(left);
|
||||||
return PendingCmd(right);
|
return PendingCmd(right);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,10 +183,9 @@ inline PendingCmd operator,(DeadProc, const Cmd& right)
|
|||||||
return PendingCmd(right);
|
return PendingCmd(right);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PendingCmd operator|(const PendingCmd& cleft, const Cmd& right)
|
inline PendingCmd operator|(const PendingCmd& left, const Cmd& right)
|
||||||
{
|
{
|
||||||
auto& left = const_cast<PendingCmd&>(cleft);
|
fd_t leftOut = detachRedirOut(left).out;
|
||||||
fd_t leftOut = left.detachRedirOut().out;
|
|
||||||
return PendingCmd(right, leftOut);
|
return PendingCmd(right, leftOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,77 +232,77 @@ inline DeadProc operator||(DeadProc p, const Cmd& ccmd)
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PendingCmd& operator>(const PendingCmd& cmd, const char* file)
|
inline PendingCmd& operator>(const PendingCmd& c, const char* file)
|
||||||
{
|
{
|
||||||
fd_t fd = _cppipe::open_or_die(file, O_WRONLY | O_CREAT);
|
fd_t fd = _cppipe::open_or_die(file, O_WRONLY | O_CREAT);
|
||||||
return cmd > fd;
|
return c > fd;
|
||||||
}
|
}
|
||||||
inline PendingCmd& operator>(const PendingCmd& ccmd, fd_t fd)
|
inline PendingCmd& operator>(const PendingCmd& ccmd, fd_t fd)
|
||||||
{
|
{
|
||||||
auto& cmd = const_cast<PendingCmd&>(ccmd);
|
auto& c = const_cast<PendingCmd&>(ccmd);
|
||||||
assert(cmd.out == 1 && "ERROR: Output is already redirected!");
|
assert(c.out == 1 && "ERROR: Output is already redirected!");
|
||||||
|
|
||||||
cmd.out = fd;
|
c.out = fd;
|
||||||
return cmd;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PendingCmd& operator>>(const PendingCmd& cmd, const char* file)
|
inline PendingCmd& operator>>(const PendingCmd& c, const char* file)
|
||||||
{
|
{
|
||||||
fd_t fd = _cppipe::open_or_die(file, O_WRONLY | O_CREAT | O_APPEND);
|
fd_t fd = _cppipe::open_or_die(file, O_WRONLY | O_CREAT | O_APPEND);
|
||||||
return cmd > fd;
|
return c > fd;
|
||||||
}
|
}
|
||||||
inline PendingCmd& operator>>(const PendingCmd& cmd, fd_t fd)
|
inline PendingCmd& operator>>(const PendingCmd& c, fd_t fd)
|
||||||
{
|
{
|
||||||
return cmd > fd;
|
return c > fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PendingCmd& operator>=(const PendingCmd& cmd, const char* file)
|
inline PendingCmd& operator>=(const PendingCmd& c, const char* file)
|
||||||
{
|
{
|
||||||
fd_t fd = _cppipe::open_or_die(file, O_WRONLY | O_CREAT);
|
fd_t fd = _cppipe::open_or_die(file, O_WRONLY | O_CREAT);
|
||||||
return cmd >= fd;
|
return c >= fd;
|
||||||
}
|
}
|
||||||
inline PendingCmd& operator>=(const PendingCmd& ccmd, fd_t fd)
|
inline PendingCmd& operator>=(const PendingCmd& ccmd, fd_t fd)
|
||||||
{
|
{
|
||||||
auto& cmd = const_cast<PendingCmd&>(ccmd);
|
auto& c = const_cast<PendingCmd&>(ccmd);
|
||||||
assert(cmd.err == 2 && "ERROR: Error output is already redirected!");
|
assert(c.err == 2 && "ERROR: Error output is already redirected!");
|
||||||
|
|
||||||
cmd.err = fd;
|
c.err = fd;
|
||||||
return cmd;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PendingCmd& operator>>=(const PendingCmd& cmd, const char* file)
|
inline PendingCmd& operator>>=(const PendingCmd& c, const char* file)
|
||||||
{
|
{
|
||||||
fd_t fd = _cppipe::open_or_die(file, O_WRONLY | O_CREAT | O_APPEND);
|
fd_t fd = _cppipe::open_or_die(file, O_WRONLY | O_CREAT | O_APPEND);
|
||||||
return cmd >= fd;
|
return c >= fd;
|
||||||
}
|
}
|
||||||
inline PendingCmd& operator>>=(const PendingCmd& cmd, fd_t fd)
|
inline PendingCmd& operator>>=(const PendingCmd& c, fd_t fd)
|
||||||
{
|
{
|
||||||
return cmd >= fd;
|
return c >= fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PendingCmd& operator<(const PendingCmd& cmd, const char* file)
|
inline PendingCmd& operator<(const PendingCmd& c, const char* file)
|
||||||
{
|
{
|
||||||
fd_t fd = _cppipe::open_or_die(file, O_RDONLY);
|
fd_t fd = _cppipe::open_or_die(file, O_RDONLY);
|
||||||
return cmd < fd;
|
return c < fd;
|
||||||
}
|
}
|
||||||
inline PendingCmd& operator<(const PendingCmd& ccmd, fd_t fd)
|
inline PendingCmd& operator<(const PendingCmd& ccmd, fd_t fd)
|
||||||
{
|
{
|
||||||
auto& cmd = const_cast<PendingCmd&>(ccmd);
|
auto& c = const_cast<PendingCmd&>(ccmd);
|
||||||
assert(cmd.in == 0 && "ERROR: Input is already redirected!");
|
assert(c.in == 0 && "ERROR: Input is already redirected!");
|
||||||
|
|
||||||
cmd.in = fd;
|
c.in = fd;
|
||||||
return cmd;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PendingCmd operator&(const PendingCmd& cleft, const Cmd& right)
|
inline PendingCmd operator&(const PendingCmd& left, const Cmd& right)
|
||||||
{
|
{
|
||||||
const_cast<PendingCmd&>(cleft).detach();
|
detach(left);
|
||||||
return PendingCmd(right);
|
return PendingCmd(right);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::ostream& operator<<(std::ostream& s, const Cmd& cmd)
|
inline std::ostream& operator<<(std::ostream& s, const Cmd& c)
|
||||||
{
|
{
|
||||||
for(size_t i = 0; i < cmd.argv.size() - 1; ++i)
|
for(size_t i = 0; i < c.argv.size() - 1; ++i)
|
||||||
s << '"' << cmd.argv[i] << '"' << ' ';
|
s << '"' << c.argv[i] << '"' << ' ';
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-1
@@ -243,7 +243,11 @@ optional<fs::path> preprocess_and_compare()
|
|||||||
+= (src_type == SrcType::C ? ".i" : ".ii");
|
+= (src_type == SrcType::C ? ".i" : ".ii");
|
||||||
|
|
||||||
// Result of preprocessing as string
|
// Result of preprocessing as string
|
||||||
string new_pp = $(preprocess);
|
Proc preprocessing = detachRedirOut(preprocess);
|
||||||
|
string new_pp = read_to_end(preprocessing.out);
|
||||||
|
|
||||||
|
if( !wait(preprocessing) ) // preprocessing failed
|
||||||
|
exit(1);
|
||||||
|
|
||||||
if( fs::exists(old_pp_path) ) // todo: clean up if else blocks
|
if( fs::exists(old_pp_path) ) // todo: clean up if else blocks
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
-q only check timestamps
|
||||||
man
|
man
|
||||||
tips (sigaction SIGCHILD, SIG_IGN, SIG_DFL)
|
tips (sigaction SIGCHILD, SIG_IGN, SIG_DFL)
|
||||||
|
- redirected processes block if their output is not read
|
||||||
make sure file descriptors are closed when no longer used
|
make sure file descriptors are closed when no longer used
|
||||||
cppipe compile options from tft
|
cppipe compile options from tft
|
||||||
respect CXXFLAGS LDFLAGS
|
respect CXXFLAGS LDFLAGS
|
||||||
|
|||||||
Reference in New Issue
Block a user