stdout: never write to std::cout directly (MB #5041)
Cmdline and SyncContext standard output should always go through a variable that can be pointed towards the actual output channel. Cmdline already had m_out for that, but it wasn't used everywhere. Fixed. SyncContext now has setOutput()/getOutput() and that is used in SyncContext.cpp. It is not set anywhere yet. To catch incorrect use of cout or cerr inside SyncEvolution, the SyncEvo namespace defines its own cout and cerr which cannot be used like std::cout/cerr, thus triggering compiler errors. Use "std::cout/cerr" when necessary.
This commit is contained in:
parent
c2633cf5d2
commit
c7aa99e5b2
|
@ -604,13 +604,13 @@ bool Cmdline::run() {
|
|||
if (first) {
|
||||
first = false;
|
||||
} else if(!m_quiet) {
|
||||
cout << endl;
|
||||
m_out << endl;
|
||||
}
|
||||
cout << dir << endl;
|
||||
m_out << dir << endl;
|
||||
if (!m_quiet) {
|
||||
SyncReport report;
|
||||
context->readSessionInfo(dir, report);
|
||||
cout << report;
|
||||
m_out << report;
|
||||
}
|
||||
}
|
||||
} else if (!m_restore.empty()) {
|
||||
|
@ -2516,7 +2516,7 @@ private:
|
|||
success = m_cmdline->parse() &&
|
||||
m_cmdline->run();
|
||||
if (m_err.str().size()) {
|
||||
cout << endl << m_err.str();
|
||||
m_out << endl << m_err.str();
|
||||
}
|
||||
CPPUNIT_ASSERT(success);
|
||||
}
|
||||
|
|
|
@ -147,8 +147,14 @@ SyncContext::SyncContext(const string &server,
|
|||
m_doLogging = doLogging;
|
||||
}
|
||||
|
||||
void SyncContext::setOutput(ostream *out)
|
||||
{
|
||||
m_out = out ? out : &std::cout;
|
||||
}
|
||||
|
||||
void SyncContext::init()
|
||||
{
|
||||
m_out = &std::cout;
|
||||
m_doLogging = false;
|
||||
m_quiet = false;
|
||||
m_dryrun = false;
|
||||
|
@ -1174,6 +1180,7 @@ public:
|
|||
m_logdir.previousLogdirs(dirs);
|
||||
}
|
||||
|
||||
ostream &out = m_client.getOutput();
|
||||
BOOST_FOREACH(SyncSource *source, *this) {
|
||||
if ((!excludeSource.empty() && excludeSource != source->getName()) ||
|
||||
(newSuffix == "after" && m_prepared.find(source->getName()) == m_prepared.end())) {
|
||||
|
@ -1182,7 +1189,7 @@ public:
|
|||
|
||||
// dump only if not done before or changed
|
||||
if (m_intro != intro) {
|
||||
cout << intro;
|
||||
m_client.getOutput() << intro;
|
||||
m_intro = intro;
|
||||
}
|
||||
|
||||
|
@ -1209,22 +1216,22 @@ public:
|
|||
oldDir = databaseName(*source, oldSuffix, oldSession);
|
||||
}
|
||||
string newDir = databaseName(*source, newSuffix);
|
||||
cout << "*** " << source->getName() << " ***\n" << flush;
|
||||
out << "*** " << source->getName() << " ***\n" << flush;
|
||||
string cmd = string("env CLIENT_TEST_COMPARISON_FAILED=10 " + config + " synccompare 2>/dev/null '" ) +
|
||||
oldDir + "' '" + newDir + "'";
|
||||
int ret = system(cmd.c_str());
|
||||
switch (ret == -1 ? ret : WEXITSTATUS(ret)) {
|
||||
case 0:
|
||||
cout << "no changes\n";
|
||||
out << "no changes\n";
|
||||
break;
|
||||
case 10:
|
||||
break;
|
||||
default:
|
||||
cout << "Comparison was impossible.\n";
|
||||
out << "Comparison was impossible.\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
cout << "\n";
|
||||
out << "\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1276,28 +1283,28 @@ public:
|
|||
m_reportTodo = false;
|
||||
|
||||
string logfile = m_logdir.getLogfile();
|
||||
cout << flush;
|
||||
cerr << flush;
|
||||
cout << "\n";
|
||||
ostream &out = m_client.getOutput();
|
||||
out << flush;
|
||||
out << "\n";
|
||||
if (status == STATUS_OK) {
|
||||
cout << "Synchronization successful.\n";
|
||||
out << "Synchronization successful.\n";
|
||||
} else if (logfile.size()) {
|
||||
cout << "Synchronization failed, see "
|
||||
<< logfile
|
||||
<< " for details.\n";
|
||||
out << "Synchronization failed, see "
|
||||
<< logfile
|
||||
<< " for details.\n";
|
||||
} else {
|
||||
cout << "Synchronization failed.\n";
|
||||
out << "Synchronization failed.\n";
|
||||
}
|
||||
|
||||
// pretty-print report
|
||||
if (m_logLevel > LOGGING_QUIET) {
|
||||
cout << "\nChanges applied during synchronization:\n";
|
||||
out << "\nChanges applied during synchronization:\n";
|
||||
}
|
||||
if (m_logLevel > LOGGING_QUIET && report) {
|
||||
cout << *report;
|
||||
out << *report;
|
||||
std::string slowSync = report->slowSyncExplanation(m_client.getPeer());
|
||||
if (!slowSync.empty()) {
|
||||
cout << endl << slowSync;
|
||||
out << endl << slowSync;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3575,9 +3582,10 @@ void SyncContext::status()
|
|||
Exception::handle();
|
||||
}
|
||||
} else {
|
||||
cout << "Previous log directory not found.\n";
|
||||
ostream &out = getOutput();
|
||||
out << "Previous log directory not found.\n";
|
||||
if (!getLogDir() || !getLogDir()[0]) {
|
||||
cout << "Enable the 'logdir' option and synchronize to use this feature.\n";
|
||||
out << "Enable the 'logdir' option and synchronize to use this feature.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -178,6 +178,13 @@ class SyncContext : public SyncConfig, public ConfigUserInterface {
|
|||
bool doLogging = false);
|
||||
~SyncContext();
|
||||
|
||||
/**
|
||||
* Output channel to be used by this context. NULL means "use std::cout", the default.
|
||||
* Owned by caller, must remain valid as long as SyncContext exists.
|
||||
*/
|
||||
void setOutput(ostream *out);
|
||||
ostream &getOutput() const { return *m_out; }
|
||||
|
||||
bool getQuiet() { return m_quiet; }
|
||||
void setQuiet(bool quiet) { m_quiet = quiet; }
|
||||
|
||||
|
@ -733,6 +740,9 @@ class SyncContext : public SyncConfig, public ConfigUserInterface {
|
|||
//It can be used to report infomation about a sync is successfully started.
|
||||
bool m_firstSourceAccess;
|
||||
|
||||
// output stream to be used by this context, never NULL (uses cout as fallback)
|
||||
ostream *m_out;
|
||||
|
||||
public:
|
||||
static bool transport_cb (void *data);
|
||||
void setTransportCallback(int seconds);
|
||||
|
|
|
@ -28,4 +28,21 @@
|
|||
#define SE_BEGIN_CXX namespace SyncEvo {
|
||||
#define SE_END_CXX }
|
||||
|
||||
SE_BEGIN_CXX
|
||||
/*
|
||||
* SyncEvolution should never use standard IO directly. Either use the
|
||||
* logging facilities or use variables that point towards the real
|
||||
* output channels. In particular the command line code then can be
|
||||
* run as pointing towards real std::cout, a string stream, or redirected
|
||||
* via D-Bus.
|
||||
*
|
||||
* These dummy declarations trip up code inside SyncEvo namespace or using it
|
||||
* which use plain "cout << something" after a "using namespace std".
|
||||
* They don't help catching code which references std::cout.
|
||||
*/
|
||||
struct DontUseStandardIO;
|
||||
extern DontUseStandardIO *cout;
|
||||
extern DontUseStandardIO *cerr;
|
||||
SE_END_CXX
|
||||
|
||||
#endif /** INCL_DECLARATIONS */
|
||||
|
|
|
@ -138,7 +138,7 @@ int main( int argc, char **argv )
|
|||
* libs, therefore it would get suppressed (logged at
|
||||
* level DEVELOPER, while output is at most INFO)
|
||||
*/
|
||||
KeyringSyncCmdline cmdline(argc, argv, cout, cout);
|
||||
KeyringSyncCmdline cmdline(argc, argv, std::cout, std::cout);
|
||||
if (cmdline.parse() &&
|
||||
cmdline.run()) {
|
||||
return 0;
|
||||
|
|
|
@ -125,7 +125,7 @@ public:
|
|||
|
||||
void startTest (CppUnit::Test *test) {
|
||||
m_currentTest = test->getName();
|
||||
cerr << m_currentTest;
|
||||
std::cerr << m_currentTest;
|
||||
string logfile = m_currentTest + ".log";
|
||||
simplifyFilename(logfile);
|
||||
m_logger.reset(new LoggerStdout(logfile));
|
||||
|
@ -190,9 +190,9 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
cerr << " " << result << "\n";
|
||||
std::cerr << " " << result << "\n";
|
||||
if (!failure.empty()) {
|
||||
cerr << failure << "\n";
|
||||
std::cerr << failure << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue