COOPY » Guide  version 0.6.5
/home/paulfitz/cvs/coopy_scm/coopy/src/widesheet/WideSheetManager.cpp
Go to the documentation of this file.
00001 #include "WideSheetManager.h"
00002 
00003 #include <stdio.h>
00004 #include <stdlib.h>
00005 #include "sqlite3.h"
00006 
00007 #include <string>
00008 
00009 #include <coopy/PolyBook.h>
00010 #include <coopy/MergeOutputTdiff.h>
00011 #include <coopy/BookCompare.h>
00012 #include <coopy/SheetPatcher.h>
00013 
00014 #ifndef WIN32
00015 #include <unistd.h>
00016 #else
00017 #include <io.h>
00018 #define access(f,a) _access(f,a)
00019 #endif
00020 #ifndef F_OK
00021 #define F_OK 0
00022 #endif
00023 
00024 using namespace std;
00025 using namespace coopy::store;
00026 using namespace coopy::cmp;
00027 
00028 static bool sql_enact(sqlite3 *db, const char *cmd) {
00029     int result = sqlite3_exec(db, cmd, NULL, NULL, NULL);
00030     if (result!=SQLITE_OK) {
00031         const char *msg = sqlite3_errmsg(db);
00032         if (msg!=NULL) {
00033             fprintf(stderr,"Database error: %s\n", msg);
00034         }
00035         sqlite3_close(db);
00036         fprintf(stderr,"Failed to set up database tables\n");
00037         exit(1);
00038     }
00039     return true;
00040 }
00041 
00042 WideSheetManager::~WideSheetManager() {
00043   disconnect();
00044 }
00045 
00046 bool WideSheetManager::connect(bool create, const char *fname) {
00047   disconnect();
00048 
00049   const char *filename = (fname!=NULL)?fname:"widesheet.sqlite";
00050   int result = sqlite3_open_v2(filename,
00051                                &db,
00052                                SQLITE_OPEN_READWRITE|
00053                                (create?SQLITE_OPEN_CREATE:0)|
00054                                SQLITE_OPEN_NOMUTEX,
00055                                NULL);
00056   if (result!=SQLITE_OK) {
00057     fprintf(stderr,"Failed to open database %s\n", filename);
00058     if (db!=NULL) {
00059       sqlite3_close(db);
00060     }
00061     db = NULL;
00062     return false;
00063   }
00064 
00065   string create_main_table = "CREATE TABLE IF NOT EXISTS widesheet_links (\n\
00066         filename TEXT,\n\
00067         key TEXT);";
00068 
00069   result = sqlite3_exec(db, create_main_table.c_str(), NULL, NULL, NULL);
00070   if (result!=SQLITE_OK) {
00071     const char *msg = sqlite3_errmsg(db);
00072     if (msg!=NULL) {
00073       fprintf(stderr,"Error in %s: %s\n", filename, msg);
00074     }
00075     sqlite3_close(db);
00076     db = NULL;
00077     fprintf(stderr,"Failed to set up database tables\n");
00078     return false;
00079   }
00080 
00081   string create_prop_table = "CREATE TABLE IF NOT EXISTS widesheet_props (\n\
00082         key TEXT PRIMARY KEY,\n\
00083         val TEXT);";
00084 
00085   result = sqlite3_exec(db, create_prop_table.c_str(), NULL, NULL, NULL);
00086   if (result!=SQLITE_OK) {
00087     const char *msg = sqlite3_errmsg(db);
00088     if (msg!=NULL) {
00089       fprintf(stderr,"Error in %s: %s\n", filename, msg);
00090     }
00091     sqlite3_close(db);
00092     db = NULL;
00093     fprintf(stderr,"Failed to set up database tables\n");
00094     return false;
00095   }
00096   return true;
00097 }
00098 
00099 
00100 bool WideSheetManager::disconnect() {
00101   if (db!=NULL) {
00102     sqlite3_close(db);
00103     db = NULL;
00104   }
00105   return true;
00106 }
00107 
00108 bool WideSheetManager::setProperty(const char *key, const char *val) {
00109   char *query = NULL;
00110   query = sqlite3_mprintf("INSERT OR REPLACE INTO widesheet_props (key,val) VALUES(%Q,%Q)",
00111                           key, val);
00112   sql_enact(db,query);
00113   sqlite3_free(query);
00114   return true;
00115 }
00116 
00117 
00118 std::string WideSheetManager::getProperty(const char *key) {
00119   char *query = NULL;
00120   string out;
00121   query = sqlite3_mprintf("SELECT val FROM widesheet_props WHERE key = %Q",
00122                           key);
00123   
00124   sqlite3_stmt *statement = NULL;
00125   int result = sqlite3_prepare_v2(db,query,-1,&statement,NULL);
00126   if (result!=SQLITE_OK) {
00127     printf("Error in query\n");
00128   }
00129   if (result == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW) {
00130     out = (char *)sqlite3_column_text(statement,0);
00131   }
00132   sqlite3_finalize(statement);
00133   sqlite3_free(query);
00134   return out;
00135 }
00136 
00137 
00138 std::string WideSheetManager::getPropertyWithDefault(const char *key) {
00139   string result = getProperty(key);
00140   if (result!="") return result;
00141   string str(key);
00142   if (str=="remote") {
00143     return "remote.csvs";
00144   }
00145   if (str=="pivot") {
00146     return "pivot.csvs";
00147   }
00148   return "";
00149 }
00150 
00151 
00152 bool WideSheetManager::exportSheet() {
00153   string local = getProperty("local");
00154   if (local=="") {
00155     fprintf(stderr,"No local file.\n");
00156     return false;
00157   }
00158   string remote = getPropertyWithDefault("remote");
00159 
00160   PolyBook src;
00161   if (!src.read(local.c_str())) {
00162     fprintf(stderr,"Failed to read %s\n", local.c_str());
00163     return false;
00164   } 
00165   if (!src.write(remote.c_str())) {
00166     fprintf(stderr,"Failed to write %s\n", remote.c_str());
00167     return false;
00168   } 
00169   printf("%s -> %s\n", local.c_str(), remote.c_str());
00170   return true;
00171 }
00172 
00173 bool WideSheetManager::acceptSheet() {
00174   string pivot = getPropertyWithDefault("pivot");
00175   string remote = getPropertyWithDefault("remote");
00176 
00177   // THIS IS JUST A COPY OPERATION!
00178   // Massively inefficient right now, replace with a file copy.
00179 
00180   PolyBook src;
00181   if (!src.read(remote.c_str())) {
00182     fprintf(stderr,"Failed to read %s\n", remote.c_str());
00183     return false;
00184   } 
00185   if (!src.write(pivot.c_str())) {
00186     fprintf(stderr,"Failed to write %s\n", pivot.c_str());
00187     return false;
00188   } 
00189   printf("%s -> %s\n", remote.c_str(), pivot.c_str());
00190   return true;
00191 }
00192 
00193 
00194 bool WideSheetManager::diffSheet() {
00195   string local = getProperty("local");
00196   if (local=="") {
00197     fprintf(stderr,"No local file.\n");
00198     return false;
00199   }
00200   string pivot = getPropertyWithDefault("pivot");
00201   string remote = getPropertyWithDefault("remote");
00202 
00203   int result = access(pivot.c_str(),F_OK);
00204   if (result!=0) {
00205     fprintf(stderr,"Pivot not present, please offer/accept first.\n");
00206     return false;
00207   }
00208 
00209   MergeOutputTdiff diff;
00210   CompareFlags flags;
00211   flags.out = stdout;
00212   PolyBook p,l,r;
00213   if (!p.read(pivot.c_str())) {
00214     fprintf(stderr,"Failed to read %s\n", pivot.c_str());
00215     return false;
00216   } 
00217   if (!l.read(local.c_str())) {
00218     fprintf(stderr,"Failed to read %s\n", local.c_str());
00219     return false;
00220   } 
00221   if (!r.read(remote.c_str())) {
00222     fprintf(stderr,"Failed to read %s\n", remote.c_str());
00223     return false;
00224   } 
00225   BookCompare cmp;
00226   cmp.compare(p,l,r,diff,flags);
00227 
00228   return true;
00229 }
00230 
00231 
00232 
00233 bool WideSheetManager::setFile(const char *key, const char *val) {
00234   char *query = NULL;
00235 
00236   query = sqlite3_mprintf("DELETE FROM widesheet_links WHERE key = %Q",
00237                           key);
00238   sql_enact(db,query);
00239   sqlite3_free(query);
00240   query = NULL;
00241 
00242   query = sqlite3_mprintf("INSERT OR REPLACE INTO widesheet_links (filename,key) VALUES(%Q,%Q)",
00243                           val, key);
00244   sql_enact(db,query);
00245   sqlite3_free(query);
00246   return true;
00247 }
00248 
00249 std::string WideSheetManager::getFile(const char *key) {
00250   char *query = NULL;
00251   string out;
00252   query = sqlite3_mprintf("SELECT filename FROM widesheet_links WHERE key = %Q",
00253                           key);
00254   
00255   sqlite3_stmt *statement = NULL;
00256   int result = sqlite3_prepare_v2(db,query,-1,&statement,NULL);
00257   if (result!=SQLITE_OK) {
00258     printf("Error in query\n");
00259   }
00260   if (result == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW) {
00261     out = (char *)sqlite3_column_text(statement,0);
00262   }
00263   sqlite3_finalize(statement);
00264   sqlite3_free(query);
00265   return out;
00266 }
00267 
00268 bool WideSheetManager::setDirectory(const char *dir, const char *sep) {
00269   this->dir = dir;
00270   this->sep = sep;
00271 }
00272 
00273 
00274 bool WideSheetManager::exportSheet(const char *key, bool reverse) {
00275   //printf("Export key %s direction %s\n", key, reverse?"reversed":"forward");
00276   string remote = getFile(key);
00277   if (remote=="") {
00278     return false;
00279   }
00280   string local = dir + sep + key + ".csvs";
00281 
00282   if (reverse) {
00283     string tmp = local;
00284     local = remote;
00285     remote = tmp;
00286   }
00287 
00288   PolyBook src;
00289   if (!src.read(local.c_str())) {
00290     fprintf(stderr,"Failed to read %s\n", local.c_str());
00291     return false;
00292   } 
00293   if (!src.write(remote.c_str())) {
00294     fprintf(stderr,"Failed to write %s\n", remote.c_str());
00295     return false;
00296   } 
00297   printf("%s -> %s\n", local.c_str(), remote.c_str());
00298   return true;
00299 }
00300 
00301 static void start_output2(string output, CompareFlags& flags) {
00302   if (output=="" || output=="-") {
00303     flags.out = stdout;
00304     return;
00305   }
00306   FILE *fout = fopen(output.c_str(),"wb");
00307   if (fout==NULL) {
00308     fprintf(stderr,"Could not open %s for writing\n", output.c_str());
00309     exit(1);
00310   }
00311   flags.out = fout;
00312 }
00313 
00314 static void stop_output2(string output, CompareFlags& flags) {
00315   if (flags.out!=stdout) {
00316     fclose(flags.out);
00317     flags.out = stdout;
00318   }
00319 }
00320 
00321 bool WideSheetManager::mergeToLocal(const char *localName,
00322                                     const char *remoteName,
00323                                     const char *pivotName,
00324                                     const char *logName) {
00325   printf("merging...\n");
00326   PolyBook _pivot;
00327   PolyBook *pivot;
00328   PolyBook _local;
00329   PolyBook *local = &_local;
00330   PolyBook _remote;
00331   PolyBook *remote = &_remote;
00332   
00333   if (!_local.read(localName)) {
00334     fprintf(stderr,"Failed to read %s\n", localName);
00335     return false;
00336   }
00337   if (!_remote.read(remoteName)) {
00338     fprintf(stderr,"Failed to read %s\n", remoteName);
00339     return 1;
00340   }
00341   if (pivotName!=NULL) {
00342     if (!_pivot.read(pivotName)) {
00343       fprintf(stderr,"Failed to read %s\n", pivotName);
00344       return false;
00345     }
00346     pivot = &_pivot;
00347   } else {
00348     pivot = &_local;
00349   }
00350 
00351   SheetPatcher *diff = SheetPatcher::createForMerge();
00352   COOPY_ASSERT(diff);
00353   MergeOutputTdiff nested_diff;
00354   diff->attachBook(*local);
00355   diff->showSummary(&nested_diff,false);
00356   BookCompare cmp;
00357   CompareFlags flags;
00358   string output = logName;
00359   start_output2(output,flags);
00360   nested_diff.setFlags(flags);
00361   int r = cmp.compare(*pivot,*local,*remote,*diff,flags);
00362   int cc = diff->getChangeCount();
00363   stop_output2(output,flags);
00364   delete diff;  diff = NULL;
00365 
00366   if (r<0) {
00367     return false;
00368   }
00369   if (cc>0) {
00370     if (!local->inplace()) {
00371       if (!local->write(localName)) {
00372         fprintf(stderr,"Failed to write %s\n", localName);
00373         return false;
00374       }
00375     }
00376   }
00377   return true;
00378 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines