# 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