ultimatepp/uppsrc/ide/SrcUpdater/Updater.cpp
dolik 3ff6060295 theide: improved source updater (batch actions, ignores)
git-svn-id: svn://ultimatepp.org/upp/trunk@3431 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2011-05-17 16:58:59 +00:00

248 lines
7.5 KiB
C++

#include "SrcUpdater.h"
#define LLOG(x) //RLOG(x)
#define LDUMP(x) //RDUMP(x)
//#define IMAGECLASS IdeImg
//#define IMAGEFILE <ide/ide.iml>
//#include <Draw/iml_header.h>
void LoadUpdaterCfg(){
String cfg=ConfigFile("updates.xml");
if(FileExists(cfg)){
LoadFromXMLFile(UpdaterCfg(),cfg);
}else{
UpdaterCfg().method=0;
UpdaterCfg().sync=0;
UpdaterCfg().period=0;
UpdaterCfg().last=Null;
UpdaterCfg().ignored=0;
UpdaterCfg().localsrc=GetHomeDirFile("upp");
UpdaterCfg().svnserver="http://upp-mirror.googlecode.com/svn/trunk/";
UpdaterCfg().svnuser="";
UpdaterCfg().svnpass="";
}
UpdaterCfg().globalsrc=FindGlobalSrc();
UpdaterCfg().available=false;
}
String GetSrcVersion(const char* dir,String& error){
String fn=AppendFileName(dir,"uppsrc/ide/version.h");
String ver=LoadFile(fn);
if(ver.IsVoid()){
error="Can't read file "+fn;
}else{
ver=ver.Mid(ver.Find("IDE_VERSION")+12);
ver=ver.Mid(ver.Find('"')+1);
ver=ver.Left(ver.Find('"'));
}
LLOG("GetSrcVersion("<<dir<<") = "<<ver);
return ver;
}
String GetSvnVersion(const String& server,bool verbose,String& error){
String ver;
LocalProcess p("svn info "+server);
if(verbose){
Progress pi;
pi.SetText("Checking revision at "+server);
while(p.IsRunning()){
if(pi.Canceled()){
p.Detach(); // p.Kill() would be better, but it hangs...
error="CANCEL";
return String::GetVoid();
}
pi.Step();
Sleep(50);
}
pi.Close();
}else{
while(p.IsRunning()){Ctrl::GuiSleep(1000);}
}
int exitcode=p.GetExitCode();
if(exitcode){
error="SVN command 'svn info "+server+"' failed with exit code "+AsString(exitcode)+"&Output:&[l150 "+DeQtf(p.Get());
LDUMP(error);
return String::GetVoid();
}
ver=p.Get();
ver=ver.Mid(ver.Find("Revision: ")+10);
LLOG("GetSvnVersion("<<server<<") = "<<IntStr(ScanInt(ver)));
return IntStr(ScanInt(ver));
}
String FindGlobalSrc(){
#ifdef PLATFORM_POSIX
static const char* dirs[]={"/usr/share/upp","/usr/local/share/upp","/usr/local/lib/upp","/usr/lib/upp"};
int n=4;
#else
static const char* dirs[]={}; // Program Files?
int n=0;
#endif
for(int i=0;i<n;i++){
if(DirectoryExists(dirs[i])) return dirs[i];
}
return "";
}
SourceUpdater::SourceUpdater(){
CtrlLayout(*this,"Updates available");
ignore<<THISBACK(Ignore);
skip<<=THISBACK(Close);
update<<=THISBACK(DoUpdate);
update.SetFocus();
//Icon(IdeImg::Package(), IdeImg::PackageLarge());
}
bool SourceUpdater::NeedsUpdate(bool verbose){
String where;
LLOG("checking for updates");
switch(UpdaterCfg().method){
case 0:{
//copy in /home
local=GetSrcVersion(UpdaterCfg().localsrc,error);
global=GetSrcVersion(UpdaterCfg().globalsrc,error);
where="in "+UpdaterCfg().globalsrc+" (updated by your package manager)";
break;
}
case 2:{
//svn repo
switch(UpdaterCfg().sync){
case 0:{
//always newest
global=GetSvnVersion(UpdaterCfg().svnserver,verbose,error);
break;
}
case 1:{
//sync with the version of theide
global=IDE_VERSION;
break;
}
default: return false;
}
where="in SVN repository ("+DeQtf(UpdaterCfg().svnserver)+")";
local=GetSvnVersion(UpdaterCfg().localsrc,false,error);
break;
}
default: return false;
}
LLOG("NeedsUpdate: local="<<local<<", global="<<global);
if(ScanInt(global)<=UpdaterCfg().ignored || global.IsVoid() || local.IsVoid())
return false;
text<<="[ [ [/ Newer version of U`+`+ sources is available.]&][ &]"
"[ {{5000:5000FNGN@N; [ [1 Curent local version:]]:: [ [1 "+local+"]]:: [ [1 Will update to:]]:: [ [1 "+global+"]]}}][ &&]"
"[1# If you choose to update now, your local sources (directory "+DeQtf(UpdaterCfg().localsrc)+") will be compared to the files "+where+". If you modified the files in your local copy, you will be able to choose appropriate actions for each changed file before writing anything on your hard drive.]";
return UpdaterCfg().available=(ScanInt(local)<ScanInt(global));
}
void SourceUpdater::CheckUpdates(){
if(UpdaterCfg().method==2) {
if(UpdaterCfg().sync==1){
global=IDE_VERSION;
CheckLocalSvn();
} else if(UpdaterCfg().sync==0){
CheckGlobalSvn();
}
return;
}
//else it is fast enough to run without the callback chain
UpdaterCfg().last=GetUtcTime();
StoreAsXMLFile(UpdaterCfg(),"SourceUpdater",ConfigFile("updates.xml"));
LLOG("running needsupdate");
if(NeedsUpdate(false))
WhenUpdateAvailable();
}
void SourceUpdater::CheckLocalSvn(){
if(pl.IsRunning()) return;
LLOG("checking local svn");
pl.Start("svn info "+UpdaterCfg().localsrc);
SetTimeCallback(-50,THISBACK(CheckLocalSvnFinished),1);
}
void SourceUpdater::CheckLocalSvnFinished(){
if(pl.IsRunning()) return;
LLOG("checking local svn finished");
KillTimeCallback(1);
int exitcode=pl.GetExitCode();
if(exitcode){
error="SVN command 'svn info "+UpdaterCfg().localsrc+"' failed with exit code "+AsString(exitcode)+"&Output:&[l150 "+DeQtf(pl.Get());
LDUMP(error);
return;
}
local=pl.Get();
local=local.Mid(local.Find("Revision: ")+10);
local=IntStr(ScanInt(local));
text<<="[ [ [/ Newer version of U`+`+ sources is available.]&][ &]"
"[ {{5000:5000FNGN@N; [ [1 Curent local version:]]:: [ [1 "+local+"]]:: [ [1 Will update to:]]:: [ [1 "+global+"]]}}][ &&]"
"[1# If you choose to update now, your local sources (directory "+DeQtf(UpdaterCfg().localsrc)+") will be compared to the files in SVN repository ("+DeQtf(UpdaterCfg().svnserver)+"). If you modified the files in your local copy, you will be able to choose appropriate actions for each changed file before writing anything on your hard drive.]";
UpdaterCfg().available=(ScanInt(local)<ScanInt(global));
LLOG("Callback chain finished: local="<<local<<", global="<<global);
UpdaterCfg().last=GetUtcTime();
StoreAsXMLFile(UpdaterCfg(),"SourceUpdater",ConfigFile("updates.xml"));
if(UpdaterCfg().available)
WhenUpdateAvailable();
}
void SourceUpdater::CheckGlobalSvn(){
if(pg.IsRunning()) return;
LLOG("checking global svn");
pg.Start("svn info "+UpdaterCfg().svnserver);
SetTimeCallback(-500,THISBACK(CheckGlobalSvnFinished),2);
}
void SourceUpdater::CheckGlobalSvnFinished(){
if(pg.IsRunning()) return;
LLOG("checking global svn finished");
KillTimeCallback(2);
int exitcode=pg.GetExitCode();
if(exitcode){
error="SVN command 'svn info "+UpdaterCfg().svnserver+"' failed with exit code "+AsString(exitcode)+"&Output:&[l150 "+DeQtf(pg.Get());
LLOG(error);
return;
}
global=pg.Get();
global=global.Mid(global.Find("Revision: ")+10);
global=IntStr(ScanInt(global));
if(ScanInt(global)>UpdaterCfg().ignored)
CheckLocalSvn();
}
void SourceUpdater::DoUpdate(){
Close();Hide();
LLOG("DoUpdate");
switch(UpdaterCfg().method){
case 0: {
//copy in /home
LocalSync ls;
if(ls.Execute()==IDOK){
ls.Perform();
//DeleteFile(ConfigFile("md5sums"));
FileCopy(AppendFileName(UpdaterCfg().globalsrc,"uppsrc/ide/version.h"),AppendFileName(UpdaterCfg().localsrc,"uppsrc/ide/version.h"));
}
break;
}
case 2: {
//svn repository
SaveFile(AppendFileName(UpdaterCfg().localsrc,"uppsrc/ide/version.h"),"#define IDE_VERSION \"\"\n");
SvnSync ss;
ss.Dir(UpdaterCfg().localsrc,UpdaterCfg().svnreadonly);
if(UpdaterCfg().sync==1){
ss.FixRevision(UpdaterCfg().localsrc,ScanInt(global));
}
ss.DoSync();
SaveFile(AppendFileName(UpdaterCfg().localsrc,"uppsrc/ide/version.h"),"#define IDE_VERSION \""+global+"\"\n");
break;
}
default: return;
}
UpdaterCfg().available=(ScanInt(global)>ScanInt(GetSrcVersion(UpdaterCfg().localsrc,error)));
}
void SourceUpdater::Ignore(){
UpdaterCfg().ignored=ScanInt(global);
UpdaterCfg().available=false;
Close();
}