COOPY » Guide
version 0.6.5
|
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 }