#endif
using namespace simgear;
+using namespace std;
const char* rsync_cmd =
"rsync --verbose --archive --delete --perms --owner --group";
const char* svn_options =
"checkout -q";
+namespace UpdateInterval
+{
+ // interval in seconds to allow an update to repeat after a successful update (=daily)
+ static const double SuccessfulAttempt = 24*60*60;
+ // interval in seconds to allow another update after a failed attempt (10 minutes)
+ static const double FailedAttempt = 10*60;
+};
+
typedef map<string,time_t> CompletedTiles;
+///////////////////////////////////////////////////////////////////////////////
+// helper functions ///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+string stripPath(string path)
+{
+ // svn doesn't like trailing white-spaces or path separators - strip them!
+ path = simgear::strutils::strip(path);
+ int slen = path.length();
+ while ((slen>0)&&
+ ((path[slen-1]=='/')||(path[slen-1]=='\\')))
+ {
+ slen--;
+ }
+ return path.substr(0,slen);
+}
+
+bool hasWhitespace(string path)
+{
+ return path.find(' ')!=string::npos;
+}
+
///////////////////////////////////////////////////////////////////////////////
// WaitingTile ////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool hasNewTiles() { return !_freshTiles.empty();}
WaitingTile getNewTile() { return _freshTiles.pop_front();}
- void setSvnServer(string server) { _svn_server = simgear::strutils::strip(server);}
+ void setSvnServer(string server) { _svn_server = stripPath(server);}
void setExtSvnUtility(string svn_util) { _svn_command = simgear::strutils::strip(svn_util);}
void setRsyncServer(string server) { _rsync_server = simgear::strutils::strip(server);}
- void setLocalDir(string dir) { _local_dir = simgear::strutils::strip(dir);}
+ void setLocalDir(string dir) { _local_dir = stripPath(dir);}
string getLocalDir() { return _local_dir;}
void setUseSvn(bool use_svn) { _use_svn = use_svn;}
_stalled = true;
return false;
}
+
#ifdef HAVE_SVN_CLIENT_H
_use_svn |= _use_built_in;
#endif
_stalled = true;
return false;
}
-
if ((!_use_svn)&&(_rsync_server==""))
{
SG_LOG(SG_TERRAIN,SG_ALERT,
return false;
}
- char command[512];
- char dest_base_dir[512];
- snprintf( command, 512,
- "%s/%s", _svn_server.c_str(), dir);
- snprintf( dest_base_dir, 512,
- "%s/%s", _local_dir.c_str(), dir);
+ ostringstream command;
+ command << _svn_server << "/" << dir;
+
+ ostringstream dest_base_dir;
+ dest_base_dir << _local_dir << "/" << dir;
apr_pool_t *subpool = svn_pool_create(_svn_pool);
svn_error_t *err = NULL;
#if (SVN_VER_MINOR >= 5)
err = svn_client_checkout3(NULL,
- command,
- dest_base_dir,
+ command.str().c_str(),
+ dest_base_dir.str().c_str(),
_svn_rev_peg,
_svn_rev,
svn_depth_infinity,
#else
// version 1.4 API
err = svn_client_checkout2(NULL,
- command,
- dest_base_dir,
+ command.str().c_str(),
+ dest_base_dir.str().c_str(),
_svn_rev_peg,
_svn_rev,
1, // recurse=true - same as svn_depth_infinity for checkout3 above
err->message << " (code " << err->apr_err << ").");
svn_error_clear(err);
// try to clean up
- err = svn_client_cleanup(dest_base_dir,
+ err = svn_client_cleanup(dest_base_dir.str().c_str(),
_svn_ctx,subpool);
if (!err)
{
bool SGTerraSync::SvnThread::syncTreeExternal(const char* dir)
{
- int rc;
- char command[512];
+ ostringstream buf;
+ SGPath localPath( _local_dir );
+ localPath.append( dir );
+
if (_use_svn)
{
- snprintf( command, 512,
- "\"%s\" %s %s/%s \"%s/%s\"", _svn_command.c_str(), svn_options,
- _svn_server.c_str(), dir,
- _local_dir.c_str(), dir );
+ buf << "\"" << _svn_command << "\" "
+ << svn_options << " "
+ << "\"" << _svn_server << "/" << dir << "\" "
+ << "\"" << localPath.str_native() << "\"";
} else {
- snprintf( command, 512,
- "%s %s/%s/ \"%s/%s/\"", rsync_cmd,
- _rsync_server.c_str(), dir,
- _local_dir.c_str(), dir );
+ buf << rsync_cmd << " "
+ << "\"" << _rsync_server << "/" << dir << "/\" "
+ << "\"" << localPath.str_native() << "/\"";
}
+
+ string command;
+#ifdef SG_WINDOWS
+ // windows command line parsing is just lovely...
+ // to allow white spaces, the system call needs this:
+ // ""C:\Program Files\something.exe" somearg "some other arg""
+ // Note: whitespace strings quoted by a pair of "" _and_ the
+ // entire string needs to be wrapped by "" too.
+ // The svn url needs forward slashes (/) as a path separator while
+ // the local path needs windows-native backslash as a path separator.
+ command = "\"" + buf.str() + "\"";
+#else
+ command = buf.str();
+#endif
SG_LOG(SG_TERRAIN,SG_DEBUG, "sync command '" << command << "'");
- rc = system( command );
+ int rc = system( command.c_str() );
if (rc)
{
SG_LOG(SG_TERRAIN,SG_ALERT,
_completedTiles.find( next._dir );
time_t now = time(0);
if ((ii == _completedTiles.end())||
- ((ii->second + 60*60*24) < now ))
+ (ii->second < now ))
{
bool isNewDirectory = false;
{
_consecutive_errors++;
_fail_count++;
+ _completedTiles[ next._dir ] = now + UpdateInterval::FailedAttempt;
}
else
{
_is_dirty = true;
}
}
+ _completedTiles[ next._dir ] = now + UpdateInterval::SuccessfulAttempt;
}
_busy = false;
- _completedTiles[ next._dir ] = now;
}
if (_consecutive_errors >= 5)
// not supported under msvc 7.1 ( code inside svn_cmdline_init )
if (svn_cmdline_init("terrasync", 0) != EXIT_SUCCESS)
return EXIT_FAILURE;
+
+ // revert locale setting
+ setlocale(LC_ALL,"C");
#else
+ /* svn_cmdline_init configures the locale. Setup environment to ensure the
+ * default "C" locale remains active, since fgfs isn't locale aware - especially
+ * requires "." as decimal point in strings containing floating point varibales. */
+ setenv("LC_ALL", "C", 1);
+
if (svn_cmdline_init("terrasync", stderr) != EXIT_SUCCESS)
return EXIT_FAILURE;
#endif
- /* Oh no! svn_cmdline_init configures the locale - affecting numeric output
- * formats (i.e. sprintf("%f", ...)). fgfs relies on "C" locale in many places
- * (including assumptions on required sprintf buffer sizes). Things go horribly
- * wrong when the locale is changed to anything else but "C". Might be enough to
- * revert LC_NUMERIC locale - but we'll do a complete revert for now...*/
- setlocale(LC_ALL,"C");
apr_pool_t *pool;
apr_pool_create(&pool, NULL);
void SGTerraSync::syncAirportsModels()
{
- char synced_other;
- for ( synced_other = 'K'; synced_other <= 'Z'; synced_other++ )
- {
- char dir[512];
- snprintf( dir, 512, "Airports/%c", synced_other );
- WaitingTile w(dir,false);
- _svnThread->request( w );
- }
- for ( synced_other = 'A'; synced_other <= 'J'; synced_other++ )
+ static const char bounds[] = "KZAJ";
+ for( unsigned i = 0; i < sizeof(bounds)/sizeof(bounds[0])/2; i+= 2 )
{
- char dir[512];
- snprintf( dir, 512, "Airports/%c", synced_other );
- WaitingTile w(dir,false);
- _svnThread->request( w );
+ for ( char synced_other = bounds[i]; synced_other <= bounds[i+1]; synced_other++ )
+ {
+ ostringstream dir;
+ dir << "Airports/" << synced_other;
+ WaitingTile w(dir.str(),false);
+ _svnThread->request( w );
+ }
}
WaitingTile w("Models",false);
_svnThread->request( w );
bool refresh=true;
for (const char** tree = &terrainobjects[0]; *tree; tree++)
{
- char dir[512];
- snprintf( dir, 512, "%s/%c%03d%c%02d/%c%03d%c%02d",
- *tree,
- EW, abs(baselon), NS, abs(baselat),
- EW, abs(lon), NS, abs(lat) );
- WaitingTile w(dir,refresh);
+ ostringstream dir;
+ dir << *tree << "/" << setfill('0')
+ << EW << setw(3) << abs(baselon) << NS << setw(2) << abs(baselat) << "/"
+ << EW << setw(3) << abs(lon) << NS << setw(2) << abs(lat);
+ WaitingTile w(dir.str(),refresh);
_svnThread->request( w );
refresh=false;
}