# from [3a12551766a64a6c4b0d6777dd2dae50a07ea209]
# to [8bdcc08f32aec97ddb7d31f11229d1503d542f61]
#
# patch "mtn_cvs/mtn_pipe.cc"
# from [ad7b9a7bdb821f697701f9fd066c28a3ea2b2dcc]
# to [f1ade36969990ae78b7f3dcbd75b3452aa6b5bd6]
#
# patch "mtn_cvs/mtn_pipe.hh"
# from [e724a7fe7e4b1ec29c5a99ef983b2d02411561f2]
# to [04c479ea3866e9a5107f25b8bf1f48d10d4eb2d3]
---
+++
@@ -0,0 +1,41 @@
+AM_CXXFLAGS=-I. -I.. -DLIBMTN_COMPILE -I../lua $(intl_CFLAGS) $(pcre_CFLAGS) $(botan_CFLAGS) \
+ $(lua_CFLAGS) $(idn_CFLAGS)
+
+noinst_LIBRARIES=libmtn.a
+
+libmtn_a_SOURCES=../netxx_pipe.cc ../sanity.cc ../ui.cc \
+ ../transforms.cc ../vocab.cc ../paths.cc ../charset.cc \
+ ../simplestring_xform.cc ../constants.cc ../xdelta.cc \
+ ../commands.cc ../basic_io.cc piece_table.cc \
+ ../mtn-sanity.cc ../package_revision.cc ../option.cc \
+ ../file_io.cc ../ssh_agent.cc ../specialized_lexical_cast.cc \
+ ../gzip.cc ../lua.cc ../globish.cc ../pcrewrap.cc ../dates.cc
+
+bin_PROGRAMS = mtn_cvs
+
+mtn_cvs_SOURCES = options.cc cvs_sync.cc cvs_client.cc mtn_cvs.cc \
+ mtn_pipe.cc mtn_automate.cc mtncvs_state.cc \
+ cvs_revision_nr.cc cvs_edge.cc ../unix/main.cc \
+ cvs_sync_pull.cc cvs_sync_push.cc cvs_sync_takeover.cc ../package_full_revision.cc
+
+AM_LDFLAGS = -L. -L..
+mtn_cvs_LDADD = -lmtn -lplatform -l3rdparty $(intl_LIBS) $(pcre_LIBS) \
+ $(botan_LIBS) $(lua_LIBS) $(sqlite_LIBS) $(idn_LIBS)
+
+pipetest: mtn_pipe.cc
+ $(CXX) $(CXXFLAGS) $(AM_CXXFLAGS) $(AM_LDFLAGS) $(LIBS) \
+ -o $@ -DTEST_MAIN $^ $(mtn_cvs_LDADD)
+
+testlinks:
+ cd tests ; ln -sf ../../tests/common ../../tests/min_hooks.lua \
+ ../../tests/test_hooks.lua ../../tests/test_keys .
+
+TESTS = run_lua_tests
+TESTS_ENVIRONMENT=AUTOTEST_PATH="."
+
+run_lua_tests: Makefile
+ echo '#!/bin/sh' > $@ ; \
+ echo 'PATH=$(top_builddir):$$PATH' >> $@ ; \
+ echo 'exec $(top_builddir)/tester $(srcdir)/lua-testsuite.lua "$$@"' >> $@ ; \
+ chmod 755 $@
+
--- mtn_cvs/mtn_pipe.cc
+++ mtn_cvs/mtn_pipe.cc
@@ -0,0 +1,197 @@
+// -*- mode: C++; c-file-style: "gnu"; indent-tabs-mode: nil -*-
+// copyright (C) 2006 Christof Petig
+// all rights reserved.
+// licensed to the public under the terms of the GNU GPL (>= 2)
+// see the file COPYING for details
+
+#include "../base.hh"
+#include "mtn_pipe.hh"
+#include
+#include
+#include "stringtok.hh"
+#include
+
+#ifndef TEST_MAIN
+#include
+#endif
+
+void mtn_pipe::open(std::string const& command, std::vector const& options)
+{ std::vector args;
+// args.push_back("--db="+database);
+ std::copy(options.begin(),options.end(),std::back_inserter(args));
+ args.push_back("automate");
+ args.push_back("stdio");
+ first_reaction=true;
+ pipe=new Netxx::PipeStream(command,args);
+}
+
+void mtn_pipe::close()
+{ if (pipe)
+ { delete pipe;
+ pipe=0;
+ }
+}
+
+// I hate C interfaces !
+Netxx::PipeStream &operator<<(Netxx::PipeStream &s, char c)
+{ s.write(&c,1);
+ return s;
+}
+
+Netxx::PipeStream &operator<<(Netxx::PipeStream &s, std::string const &t)
+{ s.write(t.data(),t.size());
+ return s;
+}
+
+Netxx::PipeStream &operator<<(Netxx::PipeStream &s, char const x[])
+{ s.write(x,strlen(x));
+ return s;
+}
+
+template
+ Netxx::PipeStream &operator<<(Netxx::PipeStream &s, T const& i)
+{ return s << boost::lexical_cast(i);
+}
+
+#ifdef TEST_MAIN
+#include
+#undef I
+#define I(x) assert(x)
+#endif
+
+static unsigned count_colons(char const* s, unsigned len)
+{ unsigned res=0;
+ for (unsigned i=0;i const& v)
+{ for (std::vector::const_iterator i=v.begin();i!=v.end();++i)
+ os << *i << ',';
+ return os;
+}
+
+std::string mtn_pipe::automate(std::string const& command,
+ std::vector const& args) throw (std::runtime_error)
+{ L(FL("mtn automate: %s %s") % command % args);
+ std::string s_cmdnum=boost::lexical_cast(cmdnum);
+ (*pipe) << 'l' << command.size() << ':' << command;
+ for (std::vector::const_iterator i=args.begin();i!=args.end();++i)
+ (*pipe) << i->size() << ':' << *i;
+ (*pipe) << "e\n";
+ std::string result;
+ Netxx::PipeCompatibleProbe probe;
+ probe.add(*pipe, Netxx::Probe::ready_read);
+again:
+ char buf[1024];
+ // at least we can expect 8 bytes
+
+ int baselen= format_version==1 ? 7 : 5;
+ int read=blocking_read(*pipe,probe,buf,baselen+s_cmdnum.size());
+ E(read==baselen+s_cmdnum.size(), origin::internal, F("mtn pipe failure\n"));
+ if (first_reaction)
+ {
+ first_reaction=false;
+ if (!strncmp(buf,"format-v",8))
+ { read+=blocking_read(*pipe,probe,buf+read,19-read);
+ I(read==19);
+ I(!strncmp(buf,"format-version: 2\n\n",19));
+ format_version=2;
+ goto again;
+ }
+ }
+ int colons=0;
+ int cmdresult=0;
+ if (format_version==1)
+ {
+ while ((colons=count_colons(buf,read))<4 && read+(4-colons)<=sizeof(buf))
+ { int res=blocking_read(*pipe,probe,buf+read,4-colons);
+ I(res==4-colons);
+ read+=res;
+ }
+ I(colons==4);
+ std::vector results;
+ stringtok(results,std::string(buf,buf+read),":");
+ I(results.size()==4);
+ I(results[0]==s_cmdnum);
+ cmdresult=boost::lexical_cast(results[1]);
+ I(results[2].size()==1);
+ unsigned chars=boost::lexical_cast(results[3]);
+ while (chars)
+ { unsigned toread=chars<=sizeof(buf)?chars:sizeof(buf);
+ int res=blocking_read(*pipe,probe,buf,toread);
+ I(res==toread);
+ result+=std::string(buf,buf+toread);
+ chars-=toread;
+ }
+ if (results[2]=="m") goto again;
+ I(results[2]=="l");
+ }
+ else // format version: 2
+ {
+ while ((colons=count_colons(buf,read))<3 && read+(3-colons)<=sizeof(buf))
+ { int res=blocking_read(*pipe,probe,buf+read,3-colons);
+ I(res==3-colons);
+ read+=res;
+ }
+ I(colons==3);
+ std::vector results;
+ stringtok(results,std::string(buf,buf+read),":");
+ I(results.size()==3);
+ I(results[0]==s_cmdnum);
+ unsigned chars=boost::lexical_cast(results[2]);
+ std::string stringresult;
+ while (chars)
+ { unsigned toread=chars<=sizeof(buf)?chars:sizeof(buf);
+ int res=blocking_read(*pipe,probe,buf,toread);
+ I(res==toread);
+ if (results[1]=="m")
+ result+=std::string(buf,buf+toread);
+ else if (results[1]=="l")
+ stringresult+=std::string(buf,buf+toread);
+ chars-=toread;
+ }
+ if (results[1]!="l") goto again;
+ cmdresult= boost::lexical_cast(stringresult);
+ }
+ ++cmdnum;
+ if (cmdresult)
+ { L(FL("mtn returned %d %s") % cmdresult % result);
+ throw std::runtime_error(result);
+ }
+ L(FL("automate result %s") % result);
+ return result;
+}
+
+#ifdef TEST_MAIN
+#include
+
+int main(int argc, char **argv)
+{ mtn_pipe p;
+ if (argc==1 && std::string(argv[0])=="--help")
+ { std::cerr << "USAGE: " << argv[0] << " [binary [options]]\n";
+ return 0;
+ }
+ std::vector args;
+ std::string cmd="mtn";
+ if (argc>1) cmd=argv[1];
+ for (unsigned i=2;i
+//
+// This program is made available under the GNU GPL version 2.0 or
+// greater. See the accompanying file COPYING for details.
+//
+// This program is distributed WITHOUT ANY WARRANTY; without even the
+// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+// PURPOSE.
+
+#include "netxx_pipe.hh"
+
+class mtn_pipe
+{ Netxx::PipeStream *pipe;
+ int cmdnum;
+ bool first_reaction;
+ int format_version;
+
+public:
+ mtn_pipe() : pipe(),cmdnum(),first_reaction(),format_version(1) {}
+ ~mtn_pipe() { close(); }
+ void open(std::string const& command="mtn",
+ std::vector const& options=std::vector());
+ void close();
+ std::string automate(std::string const& command,
+ std::vector const& args=std::vector())
+ throw (std::runtime_error);
+ bool is_open() { return pipe; }
+};
+#endif