git-off.c (79791B)
1 #!/usr/bin/tcc -run 2 // TODO 3 // use the path function 4 // handle wrong config like getLog 5 // check parameters from CLI 6 // 7 // parse params 8 // use logger 9 // 10 // How to add a new config 11 // add variable in runtimeConfig 12 // add default settings in offDEFAULTS 13 // add a helper in offHelpers 14 // add setting of default in offCommands.install 15 // add a command for setting value in offCommands 16 // print value in offCommands.env 17 // add command in CLI parser 18 // update help 19 // 20 // How to add a new transport 21 // add transport functions in offHelpers.setTransport 22 // add transport in offHelpers.mkdirStore and offHelpers.rmAllStore 23 // add transport in offCommands.clearAll 24 // update git off mode help 25 // if needed, add store creation in offCommands.install 26 // 27 // How to add a new command 28 // add command in offCommands 29 // add command in CLI parser 30 // update help 31 // 32 ////// 33 // CODE 34 // 35 // modules 36 // defaults 37 // helpers 38 // core 39 // main 40 // 41 // 42 // modules 43 // all dependencies 44 // 45 // defaults 46 // objInfo fields: for indexing cat-diff response in push command 47 // externalHelpers: shell commands to be used with the exec function 48 // runtimeConfig: config built by offHelpers 49 // offDEFAULTS: default configuration for first time install 50 // 51 // helpers 52 // expandHome: expands ~/ 53 // gitConfig: handles global git config 54 // offLog: appends log to git config off.log 55 // offLogRepo: log for commands run in git repo 56 // exec: runs an externalHelpers with parameters 57 // mkdirParents: recursive mkdir 58 // rmAll: delete recursively files and directories 59 // copy: copies files 60 // offHelpers: git-off helpers 61 // 62 // core 63 // transport: transport functions for git off store 64 // offCommands: command line functions 65 // 66 // main 67 // parse CLI arguments 68 ////// 69 70 ////// 71 // modules 72 ////// 73 // includes and function prototypes 74 #ifdef unitTest 75 // gitoff.h is used in unit tests 76 #include "gitoff.h" 77 #else 78 typedef void (*gConfig_set_t)(char*, char*); 79 typedef void (*cmdSetF_t)(gConfig_set_t); 80 #endif 81 82 #define internal static 83 84 #include <sys/stat.h> 85 #include <inttypes.h> 86 #include <stdio.h> 87 #include <dirent.h> 88 #include <libgen.h> 89 #include <wordexp.h> 90 #include <stdbool.h> 91 #include <string.h> 92 #include <stdlib.h> 93 #include <unistd.h> 94 #include <stdint.h> 95 96 char *expandHome(char *p); 97 void offLog(char* s); 98 void offLogRepo(char* s); 99 char *exec(int cmdName, char* paramsArray); 100 bool strEq(char *string1, char *string2); 101 void gitConfig_set(char* key, char* value); 102 void gitConfig_setLocal(char* key, char* value); 103 void gitConfig_setThisRepo(char* key, char* value); 104 char *gitConfig_getDefault(char* key); 105 char *gitConfig_get(char *key); 106 void mkdirParents(char* p); 107 void rmAll(char* p); 108 void copy(char* src, char* dst); 109 char **execOut(char *cmd); 110 char **walkDir(char* dir); 111 void freeList(void **list); 112 char **split(char *string, char* delim); 113 char *join(char **list, char* delim); 114 char *offHelpers_gitRepoRoot(); 115 char *offHelpers_objectPath(); 116 char *offHelpers_offStore(); 117 char *offHelpers_offHttp(); 118 char *offHelpers_offCurlOptions(); 119 char *offHelpers_offMode(); 120 char *offHelpers_offIntegrity(); 121 char *offHelpers_offPem(); 122 char *offHelpers_offSshOptions(); 123 char *offHelpers_offScpOptions(); 124 char *offHelpers_offRsyncOptions(); 125 char *offHelpers_offScp(); 126 char *offHelpers_offScpUser(); 127 char *offHelpers_log(); 128 char *offHelpers_getLog(); 129 char *offHelpers_offConfigAlways(); 130 char *offHelpers_s3Region(); 131 char *offHelpers_s3Bucket(); 132 char *offHelpers_transform(); 133 char *offHelpers_transformTo(); 134 char *offHelpers_transformFrom(); 135 char *offHelpers_userAt(); 136 char **offHelpers_getSSHConfig(); 137 void offHelpers_mkdirStore(char *p); 138 void offHelpers_rmAllStore(char *p); 139 void offHelpers_copyTo(); 140 bool offHelpers_checkIntegrity(char *p); 141 void transportCopySend(char *file); 142 void transportCopyReceive(char *file); 143 void transportRsyncSend(char *file); 144 void transportRsyncReceive(char *file); 145 void transportScpSend(char *file); 146 void transportScpReceive(char *file); 147 void transportHttpSend(char *file); 148 void transportHttpReceive(char *file); 149 void offHelpers_setTransport(char *mode ); 150 #define offHelpers_setTransport_mode() offHelpers_setTransport( "config") 151 char **offHelpers_getOffFilePath(char *offFile); 152 void send(char *src); 153 void receive(char *src); 154 void transport_transformFrom(char *file); 155 void thisrepo(cmdSetF_t cmd); 156 int findCommand(char *p); 157 void showAllCommandsHelp(); 158 void offCommands_localSetup(); 159 void offCommands_install(gConfig_set_t setF ); 160 #define offCommands_install_setF() offCommands_install( gitConfig_set) 161 void offCommands_track(); 162 void offCommands_configAlways(); 163 void offCommands_setGetGitConfig(gConfig_set_t setF); 164 void offCommands_clean(); 165 void offCommands_prepush(); 166 void offCommands_push(char *line); 167 void offCommands_smudge(); 168 void offCommands_copyTo(); 169 void offCommands_pushTo(); 170 void offCommands_clearAll(); 171 void offCommands_clearCache(); 172 void offCommands_clearStore(); 173 void offCommands_clearTmp(); 174 void offCommands_defaults(); 175 void offCommands_env(); 176 void offCommands_help(); 177 void installF(); 178 void modeF(); 179 void storeF(); 180 void scpF(); 181 void httpF(); 182 void curlF(); 183 void integrityF(); 184 void pemF(); 185 void sshoptionsF(); 186 void scpoptionsF(); 187 void rsyncoptionsF(); 188 void scpuserF(); 189 void trackF(); 190 void configAlwaysF(); 191 void s3regionF(); 192 void s3bucketF(); 193 void transformF(); 194 void transformToF(); 195 void transformFromF(); 196 void cleanF(); 197 void prepushF(); 198 void smudgeF(); 199 void copyToF(); 200 void pushF(); 201 void clearAllF(); 202 void caF(); 203 void clearCacheF(); 204 void ccF(); 205 void clearStoreF(); 206 void csF(); 207 void clearTmpF(); 208 void ctF(); 209 void defaultsF(); 210 void envF(); 211 void helpF(); 212 void initCOMMAND_FUNC(); 213 int MAIN(int ARGC, char** ARGV); 214 215 int argc; char **argv; 216 217 ////// 218 // defaults 219 ////// 220 221 // objInfo fields for indexing cat-diff response in push command 222 #define oiPREVIOUSPERMISSIONS 0 223 #define oiPERMISSIONS 1 224 #define oiPREVIOUSOID 2 225 #define oiOID 3 226 #define oiNAME 4 227 228 // shell commands to be used with the exec function 229 // example: exec 'gitRepoRoot' 230 enum { gitConfigGlobal, gitConfig, gitRepoRoot, gitList, gitDff, gitCat, sha, listAttr, ssh, scp, rsync, curl, mv, mkdirE, cp, rm }; 231 char* externalHelpers[16] = { "git config --global", "git config", "git rev-parse --show-toplevel", "git rev-list", "git show --raw --format=\"\" --no-abbrev", "git cat-file -p", "git hash-object --no-filters", "git check-attr -a", "ssh", "scp", "rsync", "curl", "mv", "mkdir -p", "cp -u", "rm -rf" }; 232 233 // config built by offHelpers 234 // use offHelpers to access runtimeConfig 235 enum { currentRepoRoot, objectPath, offStore, offHttp, offMode, offIntegrity, offScp, offScpUser, offPem, offSshOptions, offScpOptions, offRsyncOptions, offCurlOptions, log, offConfigAlways, s3Region, s3Bucket, transform, transformTo, transformFrom, scpHost, scpPath, scpPort }; 236 char* runtimeConfig[23] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; 237 238 // default configuration for first time install 239 // objectPath is git off cache in repo 240 enum { objectPathD, modeD, integrityD, pemD, scpHostD, scpUserD, sshOptionsD, scpOptionsD, rsyncOptionsD, storeD, httpD, curlOptionsD, logD, configAlwaysD, s3RegionD, s3BucketD, transformD, transformToD, transformFromD, prePushD, offSignatureD, lastD }; 241 char* offDEFAULTS[22] = { "/.git/off/objects", "copy", "disable", "offNoValue", "offNoValue", "", "-C -o StrictHostKeyChecking=no -o ConnectTimeout=3", "-C -o StrictHostKeyChecking=no -o ConnectTimeout=3 -p", "-az -e \"ssh -i _i\"", "~/.git-off/offStore", "offNoValue", "-o", "~/.git-off/log", "offNoValue", "offNoValue", "offNoValue", "disable", "pbzip2 -9 -c _1 > _2", "pbzip2 -d -c _1 > _2", "#!/bin/sh\ncommand -v git-off >/dev/null 2>&1 || { echo >&2 \"\\nThis repository is configured for Git off but \"git-off\" was not found on your path. If you no longer wish to use git off, remove this hook by deleting .git/hooks/pre-push.\\n\"; exit 2; }\ngit off pre-push \"$@\"", "### git-off v1 sha:", "not used" }; 242 243 #define offDEFAULTS_shaLength 40 244 245 ////// 246 // helpers 247 ////// 248 249 // expands ~/ 250 char *expandHome(char *p) { 251 wordexp_t exp_result; 252 size_t len; 253 254 if (p == NULL) { 255 return(NULL); 256 } 257 wordexp(p, &exp_result, 0); 258 p = realloc(p, strlen(exp_result.we_wordv[0])+1); 259 strcpy(p, exp_result.we_wordv[0]); 260 wordfree(&exp_result); 261 return(p); 262 } 263 264 265 // appends log to git config off.log 266 void offLog(char* s) { 267 char* r = NULL; 268 char* dirName = NULL; 269 DIR* d = NULL; 270 FILE* f = NULL; 271 272 if (runtimeConfig[log] == NULL) { 273 // set runtimeConfig.log and get config in git 274 r = exec(gitConfigGlobal, "off.log"); 275 r = expandHome(r); 276 runtimeConfig[log] = r; 277 // error handling 278 if (r == NULL) { 279 printf("Missing off.log config. Run \"git config --global off.log ~/.git-off/log\"."); 280 printf("\n"); 281 exit(EXIT_FAILURE); 282 } 283 } 284 dirName = strdup(runtimeConfig[log]); 285 dirname(dirName); 286 d = opendir(dirName); 287 if (d == NULL) { 288 mkdirParents(dirName); 289 } 290 free(dirName); 291 free(d); 292 293 f = fopen(runtimeConfig[log], "a"); 294 fprintf(f, "%s\n", s); 295 fclose(f); 296 } 297 298 // log for commands run in git repo 299 // adds current repo path to string s in log 300 void offLogRepo(char* s) { 301 // depends on offHelpers 302 char* ss = NULL; 303 304 ss = malloc(strlen(offHelpers_gitRepoRoot()) + strlen(s) + 1 + 12); 305 sprintf(ss, "REPO path: %s %s", offHelpers_gitRepoRoot(), s); 306 offLog(ss); 307 free(ss); 308 } 309 310 311 // runs an externalHelpers with parameters 312 // cmdName is string 313 // paramsArray is an array of strings 314 // returns line 315 char *exec(int cmdName, char* paramsArray) { 316 char* cmd = NULL; 317 FILE* fp = NULL; 318 size_t len; 319 char* line = NULL; 320 ssize_t read; 321 322 cmd = malloc(strlen(externalHelpers[cmdName]) + strlen(paramsArray) + 1 + 1); 323 sprintf(cmd, "%s %s", externalHelpers[cmdName], paramsArray); 324 //print cmd 325 326 fp = popen(cmd, "r"); 327 if (fp == NULL) { 328 exit(EXIT_FAILURE); 329 } 330 free(cmd); 331 332 read = getline(&line, &len, fp); 333 pclose(fp); 334 335 if (read == -1) { 336 // nothing was read 337 return(NULL); 338 } 339 340 { 341 char* pos = NULL; 342 pos = strchr(line, '\n'); 343 if (pos != NULL) 344 *pos = '\0'; 345 } 346 //print line 347 return(line); 348 } 349 350 // compare strings 351 bool strEq(char *string1, char *string2) { 352 353 if (string1 == NULL) { 354 return(false); 355 } 356 if (string2 == NULL) { 357 return(false); 358 } 359 return(strcmp(string1,string2) == 0);; 360 } 361 362 363 // handles global git config 364 void gitConfig_set(char* key, char* value) { 365 char* p = NULL; 366 char* r = NULL; 367 368 // dont use double quote, problem with rsyncOptions - p = '%s \"%s\"', key, value 369 p = malloc(strlen(key) + strlen(value) + 1 + 5);; 370 sprintf(p, "%s '%s'", key, value); 371 r = exec(gitConfigGlobal, p); 372 free(p); 373 free(r); 374 } 375 376 void gitConfig_setLocal(char* key, char* value) { 377 char* p = NULL; 378 char* r = NULL; 379 380 p = malloc(strlen(key) + strlen(value) + 1 + 5); 381 sprintf(p, "%s \"%s\"", key, value); 382 r = exec(gitConfig, p); 383 free(p); 384 free(r); 385 } 386 387 void gitConfig_setThisRepo(char* key, char* value) { 388 char* p = NULL; 389 char* r = NULL; 390 391 p = malloc(strlen(offHelpers_gitRepoRoot()) + strlen(key) + strlen(value) + 1 + 22); 392 sprintf(p, "--file %s/.git-off %s \"%s\"", offHelpers_gitRepoRoot() , key, value); 393 r = exec(gitConfig, p); 394 free(p); 395 free(r); 396 } 397 398 char *gitConfig_getDefault(char* key) { 399 400 return(exec(gitConfig, key)); 401 } 402 403 char *gitConfig_get(char *key) { 404 // use configAlways setting or 405 // return value from 406 // GIT_OFF_CONFIG if found 407 // repo config if found 408 // global config 409 char* r = NULL; 410 char* p = NULL; 411 char* gitOffConfigEnv = NULL; 412 413 // configAlways 414 if (strEq(offHelpers_offConfigAlways(), "GIT_OFF_CONFIG")) { 415 gitOffConfigEnv = getenv("GIT_OFF_CONFIG"); 416 if ((gitOffConfigEnv != NULL) && (access(gitOffConfigEnv, F_OK) != -1)) { 417 p = malloc(strlen(gitOffConfigEnv) + strlen(key) + 1 + 8); 418 sprintf(p, "--file %s %s", gitOffConfigEnv, key); 419 r = exec(gitConfig, p); 420 free(p); 421 } 422 return(r); 423 } 424 if (strEq(offHelpers_offConfigAlways(), "repo")) { 425 p = malloc(strlen(offHelpers_gitRepoRoot()) + 1 + 9); 426 sprintf(p, "%s/.git-off", offHelpers_gitRepoRoot()); 427 if (access(p, F_OK) != -1) { 428 free(p); 429 p = malloc(strlen(offHelpers_gitRepoRoot()) + strlen(key) + 1 + 17); 430 sprintf(p, "--file %s/.git-off %s", offHelpers_gitRepoRoot() , key); 431 r = exec(gitConfig, p); 432 } 433 free(p); 434 return(r); 435 } 436 if (strEq(offHelpers_offConfigAlways(), "global")) { 437 r = gitConfig_getDefault(key); 438 return(r); 439 } 440 441 // interpolate 442 gitOffConfigEnv = getenv("GIT_OFF_CONFIG"); 443 if ((gitOffConfigEnv != NULL) && (access(gitOffConfigEnv, F_OK) != -1)) { 444 p = malloc(strlen(gitOffConfigEnv) + strlen(key) + 1 + 8); 445 sprintf(p, "--file %s %s", gitOffConfigEnv, key); 446 r = exec(gitConfig, p); 447 free(p); 448 if (r != NULL) { 449 return(r); 450 } 451 } 452 453 if (offHelpers_gitRepoRoot()) { 454 // skip repo config when running outside a git repo 455 p = malloc(strlen(offHelpers_gitRepoRoot()) + 1 + 9); 456 sprintf(p, "%s/.git-off", offHelpers_gitRepoRoot()); 457 if (access(p, F_OK) != -1) { 458 free(p); 459 p = malloc(strlen(offHelpers_gitRepoRoot()) + strlen(key) + 1 + 17); 460 sprintf(p, "--file %s/.git-off %s", offHelpers_gitRepoRoot() , key); 461 r = exec(gitConfig, p); 462 if (r != NULL) { 463 free(p); 464 return(r); 465 } 466 } 467 free(p); 468 } 469 r = gitConfig_getDefault(key); 470 return(r); 471 } 472 473 474 // recursive mkdir 475 void mkdirParents(char* p) { 476 char* r = NULL; 477 478 r = exec(mkdirE, p); 479 free(r); 480 } 481 482 // delete recursively files and directories 483 void rmAll(char* p) { 484 char* r = NULL; 485 486 r = exec(rm, p); 487 free(r); 488 } 489 490 // copies files 491 // file modes are not kept 492 void copy(char* src, char* dst) { 493 char* r = NULL; 494 char* p = NULL; 495 496 p = malloc(strlen(src) + strlen(dst) + 1 + 1); 497 sprintf(p, "%s %s", src, dst); 498 r = exec(cp, p); 499 free(p); 500 free(r); 501 } 502 503 // exec 504 // return stdout from cmd 505 char **execOut(char *cmd) { 506 FILE* fp = NULL; 507 size_t len; 508 char* line = NULL; 509 ssize_t read; 510 char **list = NULL; 511 int count = 0;; 512 513 //print cmd 514 515 fp = popen(cmd, "r"); 516 if (fp == NULL) { 517 exit(EXIT_FAILURE); 518 } 519 520 read = getline(&line, &len, fp); 521 while (read != -1) { 522 { 523 char* pos = NULL; 524 pos = strchr(line, '\n'); 525 if (pos != NULL) 526 *pos = '\0'; 527 } 528 if (list == NULL) { 529 list = malloc(2 * sizeof(int *)); 530 list[1] = NULL; 531 } 532 else { 533 list = realloc(list, (count+2) * sizeof(int *)); 534 if (list == NULL) { 535 exit(EXIT_FAILURE); 536 } 537 list[count+1] = NULL; 538 } 539 list[count] = strdup(line); 540 read = getline(&line, &len, fp); 541 count++; 542 } 543 544 pclose(fp); 545 return(list); 546 } 547 548 // List all files in a directory 549 char **walkDir(char* dir) { 550 char* cmd = NULL; 551 char **list = NULL; 552 553 cmd = malloc(strlen(dir) + 1 + 13); 554 sprintf(cmd, "find %s -type f", dir); 555 list = execOut(cmd); 556 free(cmd); 557 return(list); 558 } 559 560 void freeList(void **list) { 561 int i = 0;; 562 563 if (list != NULL) { 564 while (list[i] != NULL) { 565 free(list[i]); 566 i++; 567 } 568 free(list); 569 } 570 } 571 572 573 char **split(char *string, char* delim) { 574 char *startString = NULL; 575 char *workingString = NULL; 576 char *line = NULL; 577 char *token = NULL; 578 int count = 0;; 579 char **r = NULL; 580 581 startString = strdup(string); 582 workingString = startString; 583 while (strlen(workingString) != 0) { 584 line = workingString; 585 token = strtok_r(line, delim, &workingString); 586 if (r == NULL) { 587 r = malloc(2 * sizeof(int *)); 588 r[1] = NULL; 589 } 590 else { 591 r = realloc(r, (count+2) * sizeof(int *)); 592 if (r == NULL) { 593 exit(EXIT_FAILURE); 594 } 595 r[count+1] = NULL; 596 } 597 r[count] = strdup(token); 598 count++; 599 // macOS sets workingString to NULL at the end 600 if (!workingString) { 601 break; 602 } 603 } 604 605 free(startString); 606 return(r); 607 } 608 609 char *join(char **list, char* delim) { 610 char *r = NULL; 611 612 while (*list != NULL) { 613 if (r == NULL) { 614 r = strdup(*list); 615 } 616 else { 617 char *tmp; 618 tmp = realloc(r, strlen(r) + strlen(delim) + 1); 619 if (tmp == NULL) { 620 exit(EXIT_FAILURE); 621 } 622 r = tmp; 623 strcat(r, delim); 624 tmp = realloc(r, strlen(r) + strlen(*list) + 1); 625 if (tmp == NULL) { 626 exit(EXIT_FAILURE); 627 } 628 r = tmp; 629 strcat(r, *list); 630 } 631 list++; 632 } 633 return(r); 634 } 635 636 637 // transport 638 639 typedef void (*transportSend_t)(char *); 640 typedef void (*transportReceive_t)(char *); 641 typedef struct {transportSend_t send; transportReceive_t receive;} transport_t; 642 transport_t transport; 643 644 // git-off helpers 645 // gitRepoRoot: sets and returns runtimeConfig.currentRepoRoot 646 // objectPath: sets and returns runtimeConfig.objectPath 647 // offStore: sets and returns runtimeConfig.offStore 648 // offMode: sets and returns runtimeConfig.offMode 649 // offIntegrity sets and returns runtimeConfig.offIntegrity 650 // offScp: sets and returns runtimeConfig.offScp 651 // offScpUser: sets and returns runtimeConfig.offScpUser 652 // log: sets and returns runtimeConfig.log 653 // getLog: sets and returns runtimeConfig.log with error checking 654 // userAt: returns user@ or '' 655 // getSSHConfig extracts host, port and path from off.sshhost 656 // mkdirStore mkdir in remote store 657 // rmAllStore rm in remote store 658 // checkIntegrity check integrity of files coming from the store 659 // setTransport: set send and receive functions for transport 660 // getOffFilePath: creates path for offFile 661 662 char *offHelpers_gitRepoRoot() { 663 664 if (runtimeConfig[currentRepoRoot] == NULL) { 665 runtimeConfig[currentRepoRoot] = exec(gitRepoRoot, ""); 666 } 667 return(runtimeConfig[currentRepoRoot]); 668 } 669 670 char *offHelpers_objectPath() { 671 672 if (runtimeConfig[objectPath] == NULL) { 673 runtimeConfig[objectPath] = malloc(strlen(offHelpers_gitRepoRoot()) + strlen(offDEFAULTS[objectPathD]) + 1 + 0); 674 sprintf(runtimeConfig[objectPath], "%s%s", offHelpers_gitRepoRoot(), offDEFAULTS[objectPathD]); 675 } 676 return(runtimeConfig[objectPath]); 677 } 678 679 char *offHelpers_offStore() { 680 681 if (runtimeConfig[offStore] == NULL) { 682 runtimeConfig[offStore] = gitConfig_get("off.store"); 683 } 684 return(runtimeConfig[offStore]); 685 } 686 687 char *offHelpers_offHttp() { 688 689 if (runtimeConfig[offHttp] == NULL) { 690 runtimeConfig[offHttp] = gitConfig_get("off.http"); 691 } 692 return(runtimeConfig[offHttp]); 693 } 694 695 char *offHelpers_offCurlOptions() { 696 697 if (runtimeConfig[offCurlOptions] == NULL) { 698 runtimeConfig[offCurlOptions] = gitConfig_get("off.curloptions"); 699 } 700 return(runtimeConfig[offCurlOptions]); 701 } 702 703 char *offHelpers_offMode() { 704 705 if (runtimeConfig[offMode] == NULL) { 706 runtimeConfig[offMode] = gitConfig_get("off.mode"); 707 } 708 return(runtimeConfig[offMode]); 709 } 710 711 char *offHelpers_offIntegrity() { 712 713 if (runtimeConfig[offIntegrity] == NULL) { 714 runtimeConfig[offIntegrity] = gitConfig_get("off.integrity"); 715 } 716 return(runtimeConfig[offIntegrity]); 717 } 718 719 char *offHelpers_offPem() { 720 721 if (runtimeConfig[offPem] == NULL) { 722 runtimeConfig[offPem] = gitConfig_get("off.pem"); 723 } 724 return(runtimeConfig[offPem]); 725 } 726 727 char *offHelpers_offSshOptions() { 728 729 if (runtimeConfig[offSshOptions] == NULL) { 730 runtimeConfig[offSshOptions] = gitConfig_get("off.sshoptions"); 731 } 732 return(runtimeConfig[offSshOptions]); 733 } 734 735 char *offHelpers_offScpOptions() { 736 737 if (runtimeConfig[offScpOptions] == NULL) { 738 runtimeConfig[offScpOptions] = gitConfig_get("off.scpoptions"); 739 } 740 return(runtimeConfig[offScpOptions]); 741 } 742 743 char *offHelpers_offRsyncOptions() { 744 745 if (runtimeConfig[offRsyncOptions] == NULL) { 746 runtimeConfig[offRsyncOptions] = gitConfig_get("off.rsyncoptions"); 747 } 748 return(runtimeConfig[offRsyncOptions]); 749 } 750 751 char *offHelpers_offScp() { 752 753 if (runtimeConfig[offScp] == NULL) { 754 runtimeConfig[offScp] = gitConfig_get("off.scphost"); 755 } 756 return(runtimeConfig[offScp]); 757 } 758 759 char *offHelpers_offScpUser() { 760 761 if (runtimeConfig[offScpUser] == NULL) { 762 runtimeConfig[offScpUser] = gitConfig_get("off.scpuser"); 763 } 764 return(runtimeConfig[offScpUser]); 765 } 766 767 char *offHelpers_log() { 768 769 if (runtimeConfig[log] == NULL) { 770 runtimeConfig[log] = gitConfig_getDefault("off.log"); 771 runtimeConfig[log] = expandHome(runtimeConfig[log]); 772 } 773 return(runtimeConfig[log]); 774 } 775 776 char *offHelpers_getLog() { 777 778 offHelpers_log(); 779 // error handling 780 if (runtimeConfig[log] == NULL) { 781 printf("Missing off.log config. Run \"git config --global off.log ~/.git-off/log\"."); 782 printf("\n"); 783 exit(EXIT_FAILURE); 784 } 785 return(runtimeConfig[log]); 786 } 787 788 char *offHelpers_offConfigAlways() { 789 790 if (runtimeConfig[offConfigAlways] == NULL) { 791 runtimeConfig[offConfigAlways] = gitConfig_getDefault("off.configAlways"); 792 } 793 return(runtimeConfig[offConfigAlways]); 794 } 795 796 char *offHelpers_s3Region() { 797 798 if (runtimeConfig[s3Region] == NULL) { 799 runtimeConfig[s3Region] = gitConfig_get("off.s3Region"); 800 } 801 return(runtimeConfig[s3Region]); 802 } 803 804 char *offHelpers_s3Bucket() { 805 806 if (runtimeConfig[s3Bucket] == NULL) { 807 runtimeConfig[s3Bucket] = gitConfig_get("off.s3Bucket"); 808 } 809 return(runtimeConfig[s3Bucket]); 810 } 811 812 char *offHelpers_transform() { 813 814 if (runtimeConfig[transform] == NULL) { 815 runtimeConfig[transform] = gitConfig_get("off.transform"); 816 } 817 return(runtimeConfig[transform]); 818 } 819 820 char *offHelpers_transformTo() { 821 822 if (runtimeConfig[transformTo] == NULL) { 823 runtimeConfig[transformTo] = gitConfig_get("off.transformTo"); 824 } 825 return(runtimeConfig[transformTo]); 826 } 827 828 char *offHelpers_transformFrom() { 829 830 if (runtimeConfig[transformFrom] == NULL) { 831 runtimeConfig[transformFrom] = gitConfig_get("off.transformFrom"); 832 } 833 return(runtimeConfig[transformFrom]); 834 } 835 836 char *offHelpers_userAt() { 837 838 if ((offHelpers_offScpUser() != NULL) && (!strEq(offHelpers_offScpUser(), ""))) { 839 char *u; 840 u = malloc(strlen(offHelpers_offScpUser()) + 1 + 1); 841 sprintf(u, "%s@", offHelpers_offScpUser()); 842 return(u); 843 } 844 else { 845 return ""; 846 } 847 } 848 849 char **offHelpers_getSSHConfig() { 850 char *user = NULL; 851 char **h_l = NULL; 852 char *port = NULL; 853 char *host = NULL; 854 char *storePath = NULL; 855 char **portAndPath_l = NULL; 856 char **r = NULL; 857 858 // extract host, port and path from off.sshhost 859 860 user = offHelpers_userAt(); 861 h_l = split(offHelpers_offScp(), ":"); 862 host = strdup(h_l[0]); 863 if (h_l[1] != NULL) { 864 int i; 865 866 portAndPath_l = split(h_l[1], "/"); 867 i = strtoumax(portAndPath_l[0], NULL, 10); 868 if (i != 0) { 869 port = strdup(portAndPath_l[0]); 870 } 871 } 872 if (port == NULL) { 873 // use default port 874 storePath = strdup(h_l[1]); 875 } 876 else { 877 storePath = strdup("/"); 878 char *tmp; 879 tmp = join(portAndPath_l + 1, "/"); 880 char *tmpr; 881 tmpr = realloc(storePath, strlen(storePath) + strlen(tmp) + 1); 882 if (tmpr == NULL) { 883 exit(EXIT_FAILURE); 884 } 885 storePath = tmpr; 886 strcat(storePath, tmp); 887 free(tmp); 888 } 889 freeList((void **) h_l); 890 freeList((void **) portAndPath_l); 891 892 // result [user + host, storePath, port] 893 r = malloc(4 * sizeof(int *)); 894 r[3] = NULL; 895 r[0] = strdup(user); 896 char *t; 897 t = realloc(r[0], strlen(r[0]) + strlen(host) + 1); 898 if (t == NULL) { 899 exit(EXIT_FAILURE); 900 } 901 r[0] = t; 902 strcat(r[0], host); 903 r[1] = storePath; 904 r[2] = port; 905 free(host); 906 return(r); 907 } 908 909 910 void offHelpers_mkdirStore(char *p) { 911 // mkdir in remote store 912 char *params = NULL; 913 char *sshCmd = NULL; 914 char *pem = NULL; 915 char **h_l = NULL; 916 917 // TODO handle multiple transports 918 h_l = offHelpers_getSSHConfig(); 919 920 sshCmd = malloc(strlen(h_l[1]) + strlen(p) + 1 + 10); 921 sprintf(sshCmd, "mkdir -p %s/%s", h_l[1], p); 922 923 // setup ssh/scp private key 924 if ((offHelpers_offPem() == NULL) || (strEq(offHelpers_offPem(), "offNoValue")) || (offHelpers_offPem() == NULL)) { 925 pem = strdup(""); 926 } 927 else { 928 pem = malloc(strlen(offHelpers_offPem()) + 1 + 3); 929 sprintf(pem, "-i %s", offHelpers_offPem()); 930 } 931 932 // ignore error from mkdir for already existing store 933 if (h_l[2] == NULL) { 934 params = malloc(strlen(offHelpers_offSshOptions()) + strlen(pem) + strlen(h_l[0]) + strlen(sshCmd) + 1 + 7); 935 sprintf(params, "%s %s %s \"%s\"", offHelpers_offSshOptions(), pem, h_l[0], sshCmd); 936 } 937 else { 938 params = malloc(strlen(offHelpers_offSshOptions()) + strlen(pem) + strlen(h_l[2]) + strlen(h_l[0]) + strlen(sshCmd) + 1 + 11); 939 sprintf(params, "%s %s -p %s %s \"%s\"", offHelpers_offSshOptions(), pem, h_l[2], h_l[0], sshCmd); 940 } 941 942 freeList((void **) h_l); 943 free(sshCmd); 944 free(pem); 945 exec(ssh, params); 946 free(params); 947 } 948 949 950 void offHelpers_rmAllStore(char *p) { 951 // rm in remote store 952 char *params = NULL; 953 char *sshCmd = NULL; 954 char *pem = NULL; 955 char **h_l = NULL; 956 957 // setup ssh/scp private key 958 if ((offHelpers_offPem() == NULL) || (strEq(offHelpers_offPem(), "offNoValue")) || (offHelpers_offPem() == NULL)) { 959 pem = strdup(""); 960 } 961 else { 962 pem = malloc(strlen(offHelpers_offPem()) + 1 + 3); 963 sprintf(pem, "-i %s", offHelpers_offPem()); 964 } 965 966 // scphost format is host:path 967 h_l = offHelpers_getSSHConfig(); 968 969 sshCmd = malloc(strlen(h_l[1]) + strlen(p) + 1 + 8); 970 sprintf(sshCmd, "rm -rf %s/%s", h_l[1], p); 971 972 // ignore error from rm 973 if (h_l[2] == NULL) { 974 params = malloc(strlen(offHelpers_offSshOptions()) + strlen(pem) + strlen(h_l[0]) + strlen(sshCmd) + 1 + 7); 975 sprintf(params, "%s %s %s \"%s\"", offHelpers_offSshOptions(), pem, h_l[0], sshCmd); 976 } 977 else { 978 params = malloc(strlen(offHelpers_offSshOptions()) + strlen(pem) + strlen(h_l[2]) + strlen(h_l[0]) + strlen(sshCmd) + 1 + 11); 979 sprintf(params, "%s %s -p %s %s \"%s\"", offHelpers_offSshOptions(), pem, h_l[2], h_l[0], sshCmd); 980 } 981 982 freeList((void **) h_l); 983 free(sshCmd); 984 free(pem); 985 exec(ssh, params); 986 free(params); 987 } 988 989 void offHelpers_copyTo() { 990 // list file in cache 991 // copy to store 992 char **files = NULL; 993 int i; 994 995 // list file in cache 996 997 files = walkDir(offHelpers_objectPath()); 998 if (files == NULL) { 999 return; 1000 } 1001 1002 i = 0; 1003 while (files[i] != NULL) { 1004 char *tmp; 1005 tmp = strdup(files[i] + strlen(offHelpers_objectPath()) + 1); 1006 free(files[i]); 1007 files[i] = tmp; 1008 i++; 1009 } 1010 1011 // copy to store 1012 1013 i = 0; 1014 while (files[i] != NULL) { 1015 transport.send(files[i]); 1016 i++; 1017 } 1018 freeList((void **) files); 1019 } 1020 1021 bool offHelpers_checkIntegrity(char *p) { 1022 // check integrity of files coming from the store 1023 bool result = true;; 1024 char *receivedSha = NULL; 1025 char *base = NULL; 1026 1027 if (strEq(offHelpers_offIntegrity(), "disable")) { 1028 return(true); 1029 } 1030 1031 receivedSha = exec(sha, p); 1032 1033 base = strdup(basename(p)); 1034 if (!strEq(base, receivedSha)) { 1035 // the file received is different from the one that was sent. 1036 printf("git-off: The file %s differs from the one that was pushed.", p); { 1037 printf("\n"); 1038 result = false; 1039 } 1040 } 1041 free(base); 1042 1043 return(result); 1044 } 1045 1046 void transportCopySend(char *file) { 1047 // create file directories in store 1048 char **f_l = NULL; 1049 char *p = NULL; 1050 DIR *d = NULL; 1051 1052 f_l = split(file, "/"); 1053 p = malloc(strlen(offHelpers_offStore()) + strlen(f_l[0]) + strlen(f_l[1]) + 1 + 2); 1054 sprintf(p, "%s/%s/%s", offHelpers_offStore(), f_l[0], f_l[1]); 1055 d = opendir(p);; 1056 if (d == NULL) { 1057 mkdirParents(p); 1058 } 1059 free(p); 1060 1061 p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); 1062 sprintf(p, "%s/%s", offHelpers_objectPath(), file); 1063 char *dest; 1064 dest = malloc(strlen(offHelpers_offStore()) + strlen(file) + 1 + 1); 1065 sprintf(dest, "%s/%s", offHelpers_offStore(), file); 1066 copy(p, dest); 1067 free(dest); 1068 free(p); 1069 freeList((void **)f_l); 1070 } 1071 1072 void transportCopyReceive(char *file) { 1073 // transfer and transform 1074 char *p = NULL; 1075 int sR; 1076 char b[1024]; 1077 FILE *f = NULL; 1078 1079 if ((strEq(offHelpers_transform(), "enable")) && (offHelpers_transformFrom() != NULL)) { 1080 // create file directories in objectPath 1081 char **f_l; 1082 DIR *d; 1083 f_l = split(file, "/"); 1084 p = malloc(strlen(offHelpers_objectPath()) + strlen(f_l[0]) + strlen(f_l[1]) + 1 + 2); 1085 sprintf(p, "%s/%s/%s", offHelpers_objectPath(), f_l[0], f_l[1]); 1086 d = opendir(p);; 1087 if (d == NULL) { 1088 mkdirParents(p); 1089 } 1090 free(p); 1091 1092 p = malloc(strlen(offHelpers_offStore()) + strlen(file) + 1 + 1); 1093 sprintf(p, "%s/%s", offHelpers_offStore(), file); 1094 char *dest; 1095 dest = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); 1096 sprintf(dest, "%s/%s", offHelpers_objectPath(), file); 1097 copy(p, dest); 1098 1099 transport_transformFrom(file); 1100 1101 free(p); 1102 p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 8); 1103 sprintf(p, "%s/../tmp/%s", offHelpers_objectPath(), file); 1104 if (offHelpers_checkIntegrity(p)) { 1105 f = fopen(p, "r"); 1106 sR = fread(b, 1, 1024, f); 1107 while (sR != 0) { 1108 fwrite(b, 1, sR, stdout); 1109 sR = fread(b, 1, 1024, f); 1110 } 1111 fclose(f); 1112 } 1113 1114 free(dest); 1115 freeList((void **)f_l); 1116 } 1117 else { 1118 p = malloc(strlen(offHelpers_offStore()) + strlen(file) + 1 + 1); 1119 sprintf(p, "%s/%s", offHelpers_offStore(), file); 1120 if (offHelpers_checkIntegrity(p)) { 1121 f = fopen(p, "r"); 1122 sR = fread(b, 1, 1024, f); 1123 while (sR != 0) { 1124 fwrite(b, 1, sR, stdout); 1125 sR = fread(b, 1, 1024, f); 1126 } 1127 fclose(f); 1128 } 1129 } 1130 1131 free(p); 1132 } 1133 1134 1135 void transportRsyncSend(char *file) { 1136 // create file directories in store 1137 char **f_l = NULL; 1138 char *p = NULL; 1139 char *pem = NULL; 1140 char *params = NULL; 1141 char *options = NULL; 1142 char *options2 = NULL; 1143 char *tmp = NULL; 1144 1145 f_l = split(file, "/"); 1146 p = malloc(strlen(f_l[0]) + strlen(f_l[1]) + 1 + 1); 1147 sprintf(p, "%s/%s", f_l[0], f_l[1]); 1148 offHelpers_mkdirStore(p); 1149 free(p); 1150 1151 options = strdup(offHelpers_offRsyncOptions()); 1152 1153 // set pem or not? check rsyncoptions 1154 // find _i index in options 1155 tmp = strstr(options, " _i"); 1156 if (tmp != NULL) { 1157 if ((offHelpers_offPem() == NULL) || (strEq(offHelpers_offPem(), "offNoValue"))) { 1158 options2 = strdup(options); 1159 } 1160 else { 1161 tmp[1] = 0; 1162 options2 = malloc(strlen(options) + strlen(offHelpers_offPem()) + strlen(tmp+3) + 1 + 0); 1163 sprintf(options2, "%s%s%s", options, offHelpers_offPem(), tmp+3); 1164 } 1165 } 1166 else { 1167 options2 = strdup(options); 1168 } 1169 1170 char *dest; 1171 1172 p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); 1173 sprintf(p, "%s/%s", offHelpers_objectPath(), file); 1174 dest = malloc(strlen(offHelpers_offScp()) + strlen(file) + 1 + 1); 1175 sprintf(dest, "%s/%s", offHelpers_offScp(), file); 1176 1177 params = malloc(strlen(options2) + strlen(p) + strlen(dest) + 1 + 2); 1178 sprintf(params, "%s %s %s", options2, p, dest); 1179 1180 exec(rsync, params); 1181 1182 free(p); 1183 free(dest); 1184 free(pem); 1185 free(params); 1186 free(options); 1187 free(options2); 1188 } 1189 1190 void transportRsyncReceive(char *file) { 1191 char *p = NULL; 1192 char **f_l = NULL; 1193 DIR *d = NULL; 1194 char *pem = NULL; 1195 char *params = NULL; 1196 char *options = NULL; 1197 char *options2 = NULL; 1198 char *tmp = NULL; 1199 1200 // create file directories in cache 1201 f_l = split(file, "/"); 1202 p = malloc(strlen(offHelpers_objectPath()) + strlen(f_l[0]) + strlen(f_l[1]) + 1 + 2); 1203 sprintf(p, "%s/%s/%s", offHelpers_objectPath(), f_l[0], f_l[1]); 1204 d = opendir(p);; 1205 if (d == NULL) { 1206 mkdirParents(p); 1207 } 1208 free(p); 1209 freeList((void **)f_l); 1210 1211 1212 options = strdup(offHelpers_offRsyncOptions()); 1213 1214 // set pem or not? check rsyncoptions 1215 // find _i index in options 1216 tmp = strstr(options, " _i"); 1217 if (tmp != NULL) { 1218 if ((offHelpers_offPem() == NULL) || (strEq(offHelpers_offPem(), "offNoValue"))) { 1219 options2 = strdup(options); 1220 } 1221 else { 1222 tmp[1] = 0; 1223 options2 = malloc(strlen(options) + strlen(offHelpers_offPem()) + strlen(tmp+3) + 1 + 0); 1224 sprintf(options2, "%s%s%s", options, offHelpers_offPem(), tmp+3); 1225 } 1226 } 1227 else { 1228 options2 = strdup(options); 1229 } 1230 1231 char *dest; 1232 1233 dest = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); 1234 sprintf(dest, "%s/%s", offHelpers_objectPath(), file); 1235 p = malloc(strlen(offHelpers_offScp()) + strlen(file) + 1 + 1); 1236 sprintf(p, "%s/%s", offHelpers_offScp(), file); 1237 1238 params = malloc(strlen(options2) + strlen(p) + strlen(dest) + 1 + 2); 1239 sprintf(params, "%s %s %s", options2, p, dest); 1240 1241 exec(rsync, params); 1242 1243 free(p); 1244 free(dest); 1245 free(pem); 1246 free(params); 1247 free(options); 1248 free(options2); 1249 1250 // transform 1251 int sR; 1252 char b[1024]; 1253 FILE *f; 1254 1255 if ((strEq(offHelpers_transform(), "enable")) && (offHelpers_transformFrom() != NULL)) { 1256 transport_transformFrom(file); 1257 p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 8); 1258 sprintf(p, "%s/../tmp/%s", offHelpers_objectPath(), file); 1259 if (offHelpers_checkIntegrity(p)) { 1260 f = fopen(p, "r"); 1261 sR = fread(b, 1, 1024, f); 1262 while (sR != 0) { 1263 fwrite(b, 1, sR, stdout); 1264 sR = fread(b, 1, 1024, f); 1265 } 1266 fclose(f); 1267 } 1268 } 1269 else { 1270 p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); 1271 sprintf(p, "%s/%s", offHelpers_objectPath(), file); 1272 if (offHelpers_checkIntegrity(p)) { 1273 f = fopen(p, "r"); 1274 sR = fread(b, 1, 1024, f); 1275 while (sR != 0) { 1276 fwrite(b, 1, sR, stdout); 1277 sR = fread(b, 1, 1024, f); 1278 } 1279 fclose(f); 1280 } 1281 } 1282 1283 free(p); 1284 } 1285 1286 1287 void transportScpSend(char *file) { 1288 // create file directories in store 1289 char **f_l = NULL; 1290 char *p = NULL; 1291 char *pem = NULL; 1292 char *params = NULL; 1293 char **h_l = NULL; 1294 1295 f_l = split(file, "/"); 1296 p = malloc(strlen(f_l[0]) + strlen(f_l[1]) + 1 + 1); 1297 sprintf(p, "%s/%s", f_l[0], f_l[1]); 1298 offHelpers_mkdirStore(p); 1299 free(p); 1300 1301 h_l = offHelpers_getSSHConfig(); 1302 1303 // setup ssh/scp private key 1304 if ((offHelpers_offPem() == NULL) || (strEq(offHelpers_offPem(), "offNoValue"))) { 1305 pem = strdup(""); 1306 } 1307 else { 1308 pem = malloc(strlen(offHelpers_offPem()) + 1 + 3); 1309 sprintf(pem, "-i %s", offHelpers_offPem()); 1310 } 1311 1312 char *dest; 1313 1314 p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); 1315 sprintf(p, "%s/%s", offHelpers_objectPath(), file); 1316 dest = malloc(strlen(h_l[0]) + strlen(h_l[1]) + strlen(file) + 1 + 2); 1317 sprintf(dest, "%s:%s/%s", h_l[0], h_l[1], file); 1318 1319 if (h_l[2] == NULL) { 1320 params = malloc(strlen(offHelpers_offScpOptions()) + strlen(pem) + strlen(p) + strlen(dest) + 1 + 3); 1321 sprintf(params, "%s %s %s %s", offHelpers_offScpOptions(), pem, p, dest); 1322 } 1323 else { 1324 params = malloc(strlen(offHelpers_offScpOptions()) + strlen(pem) + strlen(h_l[2]) + strlen(p) + strlen(dest) + 1 + 7); 1325 sprintf(params, "%s %s -P %s %s %s", offHelpers_offScpOptions(), pem, h_l[2], p, dest); 1326 } 1327 1328 exec(scp, params); 1329 1330 free(p); 1331 free(dest); 1332 freeList((void **) h_l); 1333 free(pem); 1334 free(params); 1335 } 1336 1337 void transportScpReceive(char *file) { 1338 char *p = NULL; 1339 char **f_l = NULL; 1340 DIR *d = NULL; 1341 char **h_l = NULL; 1342 char *pem = NULL; 1343 char *params = NULL; 1344 1345 // create file directories in cache 1346 f_l = split(file, "/"); 1347 p = malloc(strlen(offHelpers_objectPath()) + strlen(f_l[0]) + strlen(f_l[1]) + 1 + 2); 1348 sprintf(p, "%s/%s/%s", offHelpers_objectPath(), f_l[0], f_l[1]); 1349 d = opendir(p);; 1350 if (d == NULL) { 1351 mkdirParents(p); 1352 } 1353 free(p); 1354 freeList((void **)f_l); 1355 1356 h_l = offHelpers_getSSHConfig(); 1357 1358 // setup ssh/scp private key 1359 if ((offHelpers_offPem() == NULL) || (strEq(offHelpers_offPem(), "offNoValue"))) { 1360 pem = strdup(""); 1361 } 1362 else { 1363 pem = malloc(strlen(offHelpers_offPem()) + 1 + 3); 1364 sprintf(pem, "-i %s", offHelpers_offPem()); 1365 } 1366 1367 char *dest; 1368 1369 dest = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); 1370 sprintf(dest, "%s/%s", offHelpers_objectPath(), file); 1371 p = malloc(strlen(h_l[0]) + strlen(h_l[1]) + strlen(file) + 1 + 2); 1372 sprintf(p, "%s:%s/%s", h_l[0], h_l[1], file); 1373 1374 if (h_l[2] == NULL) { 1375 params = malloc(strlen(offHelpers_offScpOptions()) + strlen(pem) + strlen(p) + strlen(dest) + 1 + 3); 1376 sprintf(params, "%s %s %s %s", offHelpers_offScpOptions(), pem, p, dest); 1377 } 1378 else { 1379 params = malloc(strlen(offHelpers_offScpOptions()) + strlen(pem) + strlen(h_l[2]) + strlen(p) + strlen(dest) + 1 + 7); 1380 sprintf(params, "%s %s -P %s %s %s", offHelpers_offScpOptions(), pem, h_l[2], p, dest); 1381 } 1382 1383 exec(scp, params); 1384 1385 free(p); 1386 free(dest); 1387 freeList((void **) h_l); 1388 free(pem); 1389 free(params); 1390 1391 // transform 1392 int sR; 1393 char b[1024]; 1394 FILE *f; 1395 1396 if ((strEq(offHelpers_transform(), "enable")) && (offHelpers_transformFrom() != NULL)) { 1397 transport_transformFrom(file); 1398 p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 8); 1399 sprintf(p, "%s/../tmp/%s", offHelpers_objectPath(), file); 1400 if (offHelpers_checkIntegrity(p)) { 1401 f = fopen(p, "r"); 1402 sR = fread(b, 1, 1024, f); 1403 while (sR != 0) { 1404 fwrite(b, 1, sR, stdout); 1405 sR = fread(b, 1, 1024, f); 1406 } 1407 fclose(f); 1408 } 1409 } 1410 else { 1411 p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); 1412 sprintf(p, "%s/%s", offHelpers_objectPath(), file); 1413 if (offHelpers_checkIntegrity(p)) { 1414 f = fopen(p, "r"); 1415 sR = fread(b, 1, 1024, f); 1416 while (sR != 0) { 1417 fwrite(b, 1, sR, stdout); 1418 sR = fread(b, 1, 1024, f); 1419 } 1420 fclose(f); 1421 } 1422 } 1423 1424 free(p); 1425 } 1426 1427 1428 void transportHttpSend(char *file) { 1429 char *p = NULL; 1430 1431 p = malloc(strlen(file) + 1 + 48); 1432 sprintf(p, "Http mode is read-only: %s is stored in cache only", file); 1433 offLogRepo(p); 1434 free(p); 1435 } 1436 1437 void transportHttpReceive(char *file) { 1438 char *p = NULL; 1439 char **f_l = NULL; 1440 DIR *d = NULL; 1441 1442 // create file directories in cache 1443 f_l = split(file, "/"); 1444 p = malloc(strlen(offHelpers_objectPath()) + strlen(f_l[0]) + strlen(f_l[1]) + 1 + 2); 1445 sprintf(p, "%s/%s/%s", offHelpers_objectPath(), f_l[0], f_l[1]); 1446 d = opendir(p);; 1447 if (d == NULL) { 1448 mkdirParents(p); 1449 } 1450 free(p); 1451 freeList((void **)f_l); 1452 1453 p = malloc(strlen(offHelpers_offCurlOptions()) + strlen(offHelpers_objectPath()) + strlen(file) + strlen(offHelpers_offHttp()) + strlen(file) + 1 + 4); 1454 sprintf(p, "%s %s/%s %s/%s", offHelpers_offCurlOptions(), offHelpers_objectPath(), file, offHelpers_offHttp(), file); 1455 exec(curl, p); 1456 free(p); 1457 1458 // transform 1459 int sR; 1460 char b[1024]; 1461 FILE *f; 1462 1463 if ((strEq(offHelpers_transform(), "enable")) && (offHelpers_transformFrom() != NULL)) { 1464 transport_transformFrom(file); 1465 p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 8); 1466 sprintf(p, "%s/../tmp/%s", offHelpers_objectPath(), file); 1467 if (offHelpers_checkIntegrity(p)) { 1468 f = fopen(p, "r"); 1469 sR = fread(b, 1, 1024, f); 1470 while (sR != 0) { 1471 fwrite(b, 1, sR, stdout); 1472 sR = fread(b, 1, 1024, f); 1473 } 1474 fclose(f); 1475 } 1476 } 1477 else { 1478 p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); 1479 sprintf(p, "%s/%s", offHelpers_objectPath(), file); 1480 if (offHelpers_checkIntegrity(p)) { 1481 f = fopen(p, "r"); 1482 sR = fread(b, 1, 1024, f); 1483 while (sR != 0) { 1484 fwrite(b, 1, sR, stdout); 1485 sR = fread(b, 1, 1024, f); 1486 } 1487 fclose(f); 1488 } 1489 } 1490 1491 free(p); 1492 } 1493 1494 void offHelpers_setTransport(char *mode ) { 1495 char *m = NULL; 1496 1497 // set send and receive functions for transport 1498 // copy, scp 1499 1500 // use mode from config or from parameter 1501 if (strEq(mode, "config")) { 1502 m = strdup(offHelpers_offMode()); 1503 } 1504 else { 1505 m = mode; 1506 } 1507 1508 // copy mode 1509 if (strEq(m, "copy")) { 1510 transport.send = transportCopySend; 1511 transport.receive = transportCopyReceive; 1512 } 1513 1514 // rsync mode 1515 else if (strEq(m, "rsync")) { 1516 transport.send = transportRsyncSend; 1517 transport.receive = transportRsyncReceive; 1518 } 1519 1520 // scp mode 1521 else if (strEq(m, "scp")) { 1522 transport.send = transportScpSend; 1523 transport.receive = transportScpReceive; 1524 } 1525 1526 // http mode 1527 else if (strEq(m, "http")) { 1528 transport.send = transportHttpSend; 1529 transport.receive = transportHttpReceive; 1530 } 1531 1532 if (m != mode) { 1533 free(m); 1534 } 1535 } 1536 // 1537 // // s3 mode 1538 // else if mode == 's3' 1539 // transport['send'] = (file) -> 1540 // AWS = require 'aws-sdk' 1541 // s3 = new AWS.S3({region: offHelpers.s3Region(), signatureVersion: 'v4'}) 1542 // 1543 // // upload to s3 1544 // upParams = {Bucket: offHelpers.s3Bucket(), Key: file, Body: ''} 1545 // fileStream = fs.createReadStream(offHelpers.objectPath() + '/' + file) 1546 // upParams.Body = fileStream 1547 // s3.upload(upParams, (err, data) -> 1548 // // TODO log eventual error 1549 // return 1550 // ) 1551 // 1552 // return 1553 // transport['receive'] = (file) -> 1554 // AWS = require 'aws-sdk' 1555 // s3 = new AWS.S3({region: offHelpers.s3Region(), signatureVersion: 'v4'}) 1556 // 1557 // // create file directories in cache 1558 // f_l = file.split '/' 1559 // if fs.existsSync(offHelpers.objectPath() + '/' + f_l[0] + '/' + f_l[1]) == false 1560 // mkdirParents offHelpers.objectPath() + '/' + f_l[0] + '/' + f_l[1] 1561 // 1562 // // download from s3 1563 // dlParams = {Bucket: offHelpers.s3Bucket(), Key: file} 1564 // fileStream = fs.createWriteStream(offHelpers.objectPath() + '/' + file) 1565 // fileStream.on('finish', -> 1566 // // transfer is finished, the complete file is in the cache 1567 // // transform 1568 // if offHelpers.transform() == 'enable' and offHelpers.transformFrom() != '' 1569 // transport['transformFrom'](file) 1570 // if offHelpers.checkIntegrity offHelpers.objectPath() + '/../tmp/' + file 1571 // readStream = fs.createReadStream(offHelpers.objectPath() + '/../tmp/' + file) 1572 // readStream.pipe(process.stdout) 1573 // else 1574 // if offHelpers.checkIntegrity offHelpers.objectPath() + '/' + file 1575 // readStream = fs.createReadStream(offHelpers.objectPath() + '/' + file) 1576 // readStream.pipe(process.stdout) 1577 // return 1578 // ) 1579 // s3.getObject(dlParams, (err, data) -> 1580 // // TODO log eventual error 1581 // return 1582 // ).on('httpData', (chunk) -> 1583 // fileStream.write chunk 1584 // return 1585 // ).on('httpDone', -> 1586 // fileStream.end() 1587 // return 1588 // ) 1589 // return 1590 // return 1591 1592 char **offHelpers_getOffFilePath(char *offFile) { 1593 char **r = NULL; 1594 char tmp[6]; 1595 1596 tmp[0] = offFile[0]; 1597 tmp[1] = offFile[1]; 1598 tmp[2] = '/'; 1599 tmp[3] = offFile[2]; 1600 tmp[4] = offFile[3]; 1601 tmp[5] = 0; 1602 1603 // [offFile.slice(0,2) + '/' + offFile.slice(2,4) + '/' + offFile, offFile.slice(0,2) + '/' + offFile.slice(2,4)] 1604 r = malloc(3 * sizeof(int *)); 1605 r[2] = NULL; 1606 r[0] = malloc(strlen(tmp) + strlen(offFile) + 1 + 1); 1607 sprintf(r[0], "%s/%s", tmp, offFile); 1608 r[1] = strdup(tmp); 1609 return(r); 1610 } 1611 1612 1613 1614 ////// 1615 // core 1616 ////// 1617 1618 // transport functions 1619 1620 void send(char *src) { 1621 1622 // to be initialized by setTransport 1623 printf("SEND %s", src); 1624 printf("\n"); 1625 } 1626 1627 void receive(char *src) { 1628 1629 // to be initialized by setTransport 1630 printf("RECEIVE %s", src); 1631 printf("\n"); 1632 } 1633 1634 void transport_transformFrom(char *file) { 1635 // transform file in objectPath to objectPath/../tmp/file 1636 // create directories in tmp 1637 char *offFile = NULL; 1638 char **offFilePath = NULL; 1639 char *tmp = NULL; 1640 DIR *d = NULL; 1641 char *cmd = NULL; 1642 char *cmd2 = NULL; 1643 char *p1 = NULL; 1644 char *p2 = NULL; 1645 1646 offFile = strdup(basename(file)); 1647 offFilePath = offHelpers_getOffFilePath(offFile); 1648 1649 tmp = malloc(strlen(offHelpers_objectPath()) + strlen(offFilePath[1]) + 1 + 8); 1650 sprintf(tmp, "%s/../tmp/%s", offHelpers_objectPath(), offFilePath[1]); 1651 d = opendir(tmp); 1652 if (d == NULL) { 1653 // create the file directory 1654 mkdirParents(tmp); 1655 } 1656 free(tmp); 1657 1658 cmd = strdup(offHelpers_transformFrom()); 1659 1660 p1 = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); 1661 sprintf(p1, "%s/%s", offHelpers_objectPath(), file); 1662 // find _1 index in cmd 1663 tmp = strstr(cmd, " _1"); 1664 if (tmp != NULL) { 1665 tmp[1] = 0; 1666 } 1667 cmd2 = malloc(strlen(cmd) + strlen(p1) + strlen(tmp+3) + 1 + 0); 1668 sprintf(cmd2, "%s%s%s", cmd, p1, tmp+3); 1669 free(p1); 1670 free(cmd); 1671 1672 p2 = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 8); 1673 sprintf(p2, "%s/../tmp/%s", offHelpers_objectPath(), file); 1674 // find _2 and replace 1675 tmp = strstr(cmd2, " _2"); 1676 if (tmp != NULL) { 1677 tmp[1] = 0; 1678 } 1679 cmd = malloc(strlen(cmd2) + strlen(p2) + strlen(tmp+3) + 1 + 0); 1680 sprintf(cmd, "%s%s%s", cmd2, p2, tmp+3); 1681 free(p2); 1682 //print cmd 1683 free(cmd2); 1684 freeList((void **)offFilePath); 1685 offFilePath = execOut(cmd); 1686 freeList((void **)offFilePath); 1687 free(offFile); 1688 free(cmd); 1689 } 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 void thisrepo(cmdSetF_t cmd) { 1700 1701 if ((argc > 2) && (strEq(argv[2], "thisrepo"))) { 1702 cmd(gitConfig_setThisRepo); 1703 return; 1704 } 1705 cmd(gitConfig_set); 1706 } 1707 1708 1709 1710 enum { installH, modeH, storeH, scpH, httpH, curlH, integrityH, pemH, sshoptionsH, scpoptionsH, rsyncoptionsH, scpuserH, trackH, configAlwaysH, s3regionH, s3bucketH, transformH, transformToH, transformFromH, cleanH, prepushH, smudgeH, copyToH, pushH, clearAllH, caH, clearCacheH, ccH, clearStoreH, csH, clearTmpH, ctH, defaultsH, envH, helpH, lastH }; 1711 char* COMMAND_HELP[36] = { "git off install [thisrepo]\n setup git config (default global)\n thisrepo sets up config in current repo", "git off mode [thisrepo] [copy|rsync|scp|http|s3]\n set/show git off mode", "git off store [thisrepo] [path]\n set/show git off store path for copy mode", "git off scp [thisrepo] [host]\n setup scp config\n host has format host:path, user@host:path, user@host:port/path\n Example: localhost:/tmp/offStore", "git off http [thisrepo] [host]\n setup http config\n host has format http://host/path\n Example http://localhost/offStore", "git off curl [thisrepo] [options]\n setup curl config", "git off integrity [thisrepo] [enable|disable]\n set/show git off integrity.\n when enabled, the SHA of the file received from the store is\n checked again the SHA of the original file", "git off pem [thisrepo] [pathToPrivateKey]\n set/show git off pem.\n off.pem is the private key for ssh and scp\n set \"offNoValue\" to set an empty value (useful when there are multiple configs)", "git off sshoptions [thisrepo] [options]\n set/show git off sshoptions", "git off scpoptions [thisrepo] [options]\n set/show git off scpoptions", "git off rsyncoptions [thisrepo] [options]\n set/show git off rsyncoptions", "git off scpuser [thisrepo] [username]\n setup scp username config", "git off track\n setup gitattribute filters\n example: git off track \"*.bin\"\n without parameter, list git off attributes\n calls git off install", "git off configAlways [\"\"|GIT_OFF_CONFIG|repo|global]\n \"\" disable configAlways\n GIT_OFF_CONFIG load all configurations from $GIT_OFF_CONFIG\n repo load all configurations from current git repo\n global load all configurations from global git config\n set \"offNoValue\" to set an empty value", "git off s3region [thisrepo] [region]\n setup amazon s3 region for the bucket", "git off s3bucket [thisrepo] [bucket]\n setup amazon s3 bucket", "git off transform [thisrepo] [enable|disable]\n enable transform in clean and smudge filters", "git off transformTo [thisrepo] [\"cmd _1 _2\"]\n setup transform command for clear filter\n When the command is empty the regular transport is performed", "git off transformFrom [thisrepo] [\"cmd _1 _2\"]\n setup transform command for smudge filter\n When the command is empty the regular transport is performed", "git off clean\n internal filter\n dont use directly", "git off pre-push\n internal filter\n dont use directly", "git off smudge\n internal filter\n dont use directly", "git off copyTo [copy|rsync|scp|s3]\n copy cache to store for specified mode", "git off push\n copy cache to store for selected mode", "git off clearAll\n delete store, cache and log", "git off ca\n delete store, cache and log", "git off clearCache\n delete cache in current git", "git off cc\n delete cache in current git", "git off clearStore\n delete store", "git off cs\n delete store", "git off clearTmp\n delete tmp in git off cache\n Useful when transform is enabled", "git off ct\n delete tmp in git off cache\n Useful when transform is enabled", "git off defaults\n shows first time config", "git off env\n shows config", "git off help [cmd]\n git off help. Run git off help command to get help for a specific command.", "not a command" }; 1712 1713 enum { installC, modeC, storeC, scpC, httpC, curlC, integrityC, pemC, sshoptionsC, scpoptionsC, rsyncoptionsC, scpuserC, trackC, configAlwaysC, s3regionC, s3bucketC, transformC, transformToC, transformFromC, cleanC, prepushC, smudgeC, copyToC, pushC, clearAllC, caC, clearCacheC, ccC, clearStoreC, csC, clearTmpC, ctC, defaultsC, envC, helpC, lastC }; 1714 char* COMMAND_MAP[36] = { "install", "mode", "store", "scp", "http", "curl", "integrity", "pem", "sshoptions", "scpoptions", "rsyncoptions", "scpuser", "track", "configAlways", "s3region", "s3bucket", "transform", "transformTo", "transformFrom", "clean", "pre-push", "smudge", "copyTo", "push", "clearAll", "ca", "clearCache", "cc", "clearStore", "cs", "clearTmp", "ct", "defaults", "env", "help", "not a command" }; 1715 1716 enum { installG, modeG, storeG, scpG, httpG, curlG, integrityG, pemG, sshoptionsG, scpoptionsG, rsyncoptionsG, scpuserG, trackG, configAlwaysG, s3regionG, s3bucketG, transformG, transformToG, transformFromG, cleanG, prepushG, smudgeG, copyToG, pushG, clearAllG, caG, clearCacheG, ccG, clearStoreG, csG, clearTmpG, ctG, defaultsG, envG, helpG, lastG }; 1717 char* COMMAND_GITCONFIG[36] = { "empty", "off.mode", "off.store", "off.scphost", "off.http", "off.curloptions", "off.integrity", "off.pem", "off.sshoptions", "off.scpoptions", "off.rsyncoptions", "off.scpuser", "empty", "off.configAlways", "off.s3region", "off.s3bucket", "off.transform", "off.transformTo", "off.transformFrom", "empty", "empty", "empty", "empty", "empty", "empty", "empty", "empty", "empty", "empty", "empty", "empty", "empty", "empty", "empty", "empty", "not a command" }; 1718 1719 // functions called for commands 1720 typedef void (*cmdF_t)(); 1721 1722 // lastC is the index of last element 1723 cmdF_t COMMAND_FUNC[lastC + 1 ]; 1724 1725 // helpers called for commands that read a git config 1726 typedef char *(*cmdH_t)(); 1727 cmdH_t COMMAND_HELPERS[lastC + 1 ]; 1728 1729 int findCommand(char *p) { 1730 int i; 1731 1732 for (i=0; i < lastC ;i++) { 1733 if (strEq(p, COMMAND_MAP[i])) { 1734 break; 1735 } 1736 } 1737 if (i == lastC) { 1738 i = -1; 1739 } 1740 return(i); 1741 } 1742 1743 void showAllCommandsHelp() { 1744 int i; 1745 1746 for (i=0; i < lastH ;i++) { 1747 printf("%s\n", COMMAND_HELP[i]); 1748 } 1749 } 1750 1751 1752 1753 1754 // command line functions 1755 // localSetup: setup current git 1756 // install: setup git config (default global) 1757 // mode: set/show git off mode 1758 // scp: setup scp config 1759 // scpuser: setup scp username config 1760 // track: setup gitattribute filters 1761 // clean: replace files handled by git off with reference 1762 // prepush: read stdin and calls push 1763 // push: copy objects to off.store 1764 // smudge: copy objects from off.store for files handled by git off 1765 // clearAll: delete store, cache in current git and log 1766 // clearCache: delete cache in current git 1767 // clearStore: delete store 1768 // defaults: show first time config (offDEFAULTS) 1769 // env: show config 1770 void offCommands_localSetup() { 1771 // setup current git 1772 // create off directories in current .git 1773 // install pre-push hooks 1774 char *hook = NULL; 1775 1776 mkdirParents(offHelpers_objectPath()); 1777 1778 hook = malloc(strlen(offHelpers_gitRepoRoot()) + 1 + 20); 1779 sprintf(hook, "%s/.git/hooks/pre-push", offHelpers_gitRepoRoot()); 1780 if (access(hook, F_OK) == -1) { 1781 FILE *f; 1782 f = fopen(hook, "w"); 1783 fprintf(f, "%s\n", offDEFAULTS[prePushD]); 1784 fclose(f); 1785 chmod(hook, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); 1786 } 1787 // error disabled because localSetup is run many times (called from clean and smudge) 1788 // else 1789 // console.error hook.red.bold + ' already exists. Skipping pre-push hook setup.'.red.bold 1790 // process.exit(1) 1791 free(hook); 1792 } 1793 1794 void offCommands_install(gConfig_set_t setF ) { 1795 1796 // setup git config 1797 // create off.store 1798 1799 offCommands_localSetup(); 1800 1801 // setup config only if not already set 1802 if ((gitConfig_get("filter.off.clean") == NULL) || (setF != gitConfig_set)) { 1803 if (setF == gitConfig_setThisRepo) { 1804 gitConfig_setLocal("filter.off.clean","git off clean %f"); 1805 } 1806 else { 1807 setF("filter.off.clean","git off clean %f"); 1808 } 1809 } 1810 if ((gitConfig_get("filter.off.smudge") == NULL) || (setF != gitConfig_set)) { 1811 if (setF == gitConfig_setThisRepo) { 1812 gitConfig_setLocal("filter.off.smudge","git off smudge %f"); 1813 } 1814 else { 1815 setF("filter.off.smudge","git off smudge %f"); 1816 } 1817 } 1818 if ((offHelpers_log() == NULL) || (setF != gitConfig_set)) { 1819 // log always in global config 1820 gitConfig_set("off.log",offDEFAULTS[logD]); 1821 } 1822 1823 if ((offHelpers_offMode() == NULL) || (setF != gitConfig_set)) { 1824 setF("off.mode", offDEFAULTS[modeD]); 1825 } 1826 if ((offHelpers_offIntegrity() == NULL) || (setF != gitConfig_set)) { 1827 setF("off.integrity", offDEFAULTS[integrityD]); 1828 } 1829 if ((offHelpers_offPem() == NULL) || (setF != gitConfig_set)) { 1830 setF("off.pem", offDEFAULTS[pemD]); 1831 } 1832 if ((offHelpers_offScp() == NULL) || (setF != gitConfig_set)) { 1833 setF("off.scphost", offDEFAULTS[scpHostD]); 1834 } 1835 if ((offHelpers_offScpUser() == NULL) || (setF != gitConfig_set)) { 1836 setF("off.scpuser", offDEFAULTS[scpUserD]); 1837 } 1838 if ((offHelpers_offSshOptions() == NULL) || (setF != gitConfig_set)) { 1839 setF("off.sshoptions", offDEFAULTS[sshOptionsD]); 1840 } 1841 if ((offHelpers_offScpOptions() == NULL) || (setF != gitConfig_set)) { 1842 setF("off.scpoptions", offDEFAULTS[scpOptionsD]); 1843 } 1844 if ((offHelpers_offRsyncOptions() == NULL) || (setF != gitConfig_set)) { 1845 setF("off.rsyncoptions", offDEFAULTS[rsyncOptionsD]); 1846 } 1847 if ((offHelpers_offStore() == NULL) || (setF != gitConfig_set)) { 1848 setF("off.store", offDEFAULTS[storeD]); 1849 } 1850 if ((offHelpers_offHttp() == NULL) || (setF != gitConfig_set)) { 1851 setF("off.http", offDEFAULTS[httpD]); 1852 } 1853 if ((offHelpers_offCurlOptions() == NULL) || (setF != gitConfig_set)) { 1854 setF("off.curloptions", offDEFAULTS[curlOptionsD]); 1855 } 1856 if ((offHelpers_offConfigAlways() == NULL) || (setF != gitConfig_set)) { 1857 setF("off.configAlways", offDEFAULTS[configAlwaysD]); 1858 } 1859 if ((offHelpers_s3Region() == NULL) || (setF != gitConfig_set)) { 1860 setF("off.s3Region", offDEFAULTS[s3RegionD]); 1861 } 1862 if ((offHelpers_s3Bucket() == NULL) || (setF != gitConfig_set)) { 1863 setF("off.s3Bucket", offDEFAULTS[s3BucketD]); 1864 } 1865 if ((offHelpers_transform() == NULL) || (setF != gitConfig_set)) { 1866 setF("off.transform", offDEFAULTS[transformD]); 1867 } 1868 if ((offHelpers_transformTo() == NULL) || (setF != gitConfig_set)) { 1869 setF("off.transformTo", offDEFAULTS[transformToD]); 1870 } 1871 if ((offHelpers_transformFrom() == NULL) || (setF != gitConfig_set)) { 1872 setF("off.transformFrom", offDEFAULTS[transformFromD]); 1873 } 1874 1875 // create off.store 1876 1877 if (strEq(runtimeConfig[offMode], "copy")) { 1878 mkdirParents(runtimeConfig[offStore]); 1879 } 1880 1881 if (strEq(runtimeConfig[offMode], "scp") || strEq(runtimeConfig[offMode], "rsync")) { 1882 offHelpers_mkdirStore(""); 1883 } 1884 } 1885 1886 void offCommands_track() { 1887 FILE* f = NULL; 1888 1889 // setup gitattribute filters in current folder 1890 // list current git off attributes when there is no parameter 1891 if (argc > 2) { 1892 char *fileName; 1893 char *line; 1894 offCommands_install_setF(); 1895 fileName = malloc(strlen(offHelpers_gitRepoRoot()) + 1 + 15); 1896 sprintf(fileName, "%s/.gitattributes", offHelpers_gitRepoRoot()); 1897 f = fopen(fileName, "a"); 1898 free(fileName); 1899 line = malloc(strlen(argv[2]) + 1 + 17); 1900 sprintf(line, "%s filter=off -text", argv[2]); 1901 fprintf(f, "%s\n", line); 1902 free(line); 1903 fclose(f); 1904 } 1905 else { 1906 // list current git off attributes 1907 char *cmd; 1908 char **list; 1909 int i; 1910 1911 cmd = malloc(strlen(externalHelpers[listAttr]) + strlen(offHelpers_gitRepoRoot()) + 1 + 20); 1912 sprintf(cmd, "%s `cd %s; git ls-files`", externalHelpers[listAttr], offHelpers_gitRepoRoot()); 1913 list = execOut(cmd); 1914 free(cmd); 1915 1916 // gff/b.bin: filter: off 1917 if (list != NULL) { 1918 i = 0; 1919 while (list[i] != NULL) { 1920 // find string 1921 if (strstr(list[i], ": filter: off") != NULL) { 1922 printf("%s\n", list[i]); 1923 } 1924 i++; 1925 } 1926 } 1927 freeList((void **)list); 1928 } 1929 } 1930 1931 void offCommands_configAlways() { 1932 1933 if (!strEq(argv[argc-1], "configAlways")) { 1934 gitConfig_set(COMMAND_GITCONFIG[configAlwaysC], argv[argc-1]); 1935 } 1936 else { 1937 if (COMMAND_HELPERS[configAlwaysC]()) { 1938 // print when config is available 1939 printf("%s %s", COMMAND_GITCONFIG[configAlwaysC], COMMAND_HELPERS[configAlwaysC]()); 1940 printf("\n"); 1941 } 1942 else { 1943 printf("Not in config: %s", COMMAND_GITCONFIG[configAlwaysC]); 1944 printf("\n"); 1945 } 1946 } 1947 } 1948 1949 void offCommands_setGetGitConfig(gConfig_set_t setF) { 1950 int i; 1951 1952 i = findCommand(argv[1]); 1953 if ((argc > 2) && (!strEq(argv[argc-1], "thisrepo"))) { 1954 setF(COMMAND_GITCONFIG[i], argv[argc-1]); 1955 } 1956 else { 1957 if (COMMAND_HELPERS[i]()) { 1958 printf("%s %s", COMMAND_GITCONFIG[i], COMMAND_HELPERS[i]()); 1959 printf("\n"); 1960 } 1961 else { 1962 printf("Not in config: %s", COMMAND_GITCONFIG[i]); 1963 printf("\n"); 1964 } 1965 } 1966 } 1967 1968 void offCommands_clean() { 1969 char *file = NULL; 1970 uint64_t size; 1971 char **offFilePath = NULL; 1972 char *offFile = NULL; 1973 char *fileDir = NULL; 1974 char *filePath = NULL; 1975 DIR *d = NULL; 1976 char b[1024]; 1977 FILE *f = NULL; 1978 int sR; 1979 char *quotedFile = NULL; 1980 1981 // replace files handled by git off with reference 1982 // stdin is data from the working directory file 1983 // 1984 // create local setup in case the repo is freshly cloned 1985 // create file information (size, sha = git off filename) 1986 // copy stdin to git off cache in current git 1987 // transform input file 1988 // print git off ref to stdout for git 1989 1990 // create local setup in case the repo is freshly cloned 1991 offCommands_localSetup(); 1992 1993 // create file information (size, sha) 1994 file = argv[2]; 1995 //print file 1996 struct stat st; 1997 stat(file, &st); 1998 size = st.st_size; 1999 quotedFile = malloc(strlen(file) + 1 + 4); 2000 sprintf(quotedFile, "\"%s\"", file); 2001 offFile = exec(sha, quotedFile); 2002 free(quotedFile); 2003 offFilePath = offHelpers_getOffFilePath(offFile); 2004 2005 fileDir = malloc(strlen(offHelpers_objectPath()) + strlen(offFilePath[1]) + 1 + 1); 2006 sprintf(fileDir, "%s/%s", offHelpers_objectPath(), offFilePath[1]); 2007 d = opendir(fileDir); 2008 if (d == NULL) { 2009 // create the file directory 2010 mkdirParents(fileDir); 2011 } 2012 2013 // copy stdin to git off cache in current git 2014 // clean runs during git add and git commit, do work only once 2015 filePath = malloc(strlen(offHelpers_objectPath()) + strlen(offFilePath[0]) + 1 + 1); 2016 sprintf(filePath, "%s/%s", offHelpers_objectPath(), offFilePath[0]); 2017 if (access(filePath, F_OK) == -1) { 2018 // stream stdin to sha in git off cache 2019 f = fopen(filePath, "w"); 2020 2021 sR = fread(b, 1, 1024, stdin); 2022 while (sR != 0) { 2023 fwrite(b, 1, sR, f); 2024 sR = fread(b, 1, 1024, stdin); 2025 } 2026 fclose(f); 2027 2028 // all objects in cache are read-only 2029 chmod(filePath, S_IRUSR | S_IRGRP | S_IROTH); 2030 2031 // transform input file 2032 if ((strEq(offHelpers_transform(), "enable")) && (offHelpers_transformTo() != NULL)) { 2033 char *tmpDir; 2034 tmpDir = malloc(strlen(offHelpers_objectPath()) + strlen(offFilePath[1]) + 1 + 8); 2035 sprintf(tmpDir, "%s/../tmp/%s", offHelpers_objectPath(), offFilePath[1]); 2036 d = opendir(tmpDir); 2037 if (d == NULL) { 2038 // create the file directory 2039 mkdirParents(tmpDir); 2040 } 2041 2042 // original file is moved to tmp 2043 // transformed file is stored in objectPath under the same name 2044 char *p; 2045 p = malloc(strlen(filePath) + strlen(offHelpers_objectPath()) + strlen(offFilePath[0]) + 1 + 9); 2046 sprintf(p, "%s %s/../tmp/%s", filePath, offHelpers_objectPath(), offFilePath[0]); 2047 exec(mv, p); 2048 free(p); 2049 2050 char *cmd; 2051 char *cmd2; 2052 char *p1; 2053 char *tmp; 2054 2055 cmd = strdup(offHelpers_transformTo()); 2056 2057 p1 = malloc(strlen(offHelpers_objectPath()) + strlen(offFilePath[0]) + 1 + 8); 2058 sprintf(p1, "%s/../tmp/%s", offHelpers_objectPath(), offFilePath[0]); 2059 // find _1 index in cmd 2060 tmp = strstr(cmd, " _1"); 2061 if (tmp != NULL) { 2062 tmp[1] = 0; 2063 } 2064 cmd2 = malloc(strlen(cmd) + strlen(p1) + strlen(tmp+3) + 1 + 0); 2065 sprintf(cmd2, "%s%s%s", cmd, p1, tmp+3); 2066 free(p1); 2067 free(cmd); 2068 2069 // find _2 and replace 2070 tmp = strstr(cmd2, " _2"); 2071 if (tmp != NULL) { 2072 tmp[1] = 0; 2073 } 2074 cmd = malloc(strlen(cmd2) + strlen(filePath) + strlen(tmp+3) + 1 + 0); 2075 sprintf(cmd, "%s%s%s", cmd2, filePath, tmp+3); 2076 freeList((void **)offFilePath); 2077 offFilePath = execOut(cmd); 2078 free(cmd); 2079 free(tmpDir); 2080 } 2081 } 2082 else { 2083 // file already exists, discard data 2084 f = fopen("/dev/null", "w"); 2085 2086 sR = fread(b, 1, 1024, stdin); 2087 while (sR != 0) { 2088 fwrite(b, 1, sR, f); 2089 sR = fread(b, 1, 1024, stdin); 2090 } 2091 fclose(f); 2092 } 2093 2094 free(fileDir); 2095 free(filePath); 2096 2097 // print git off ref to stdout for git 2098 // ### git-off v1 sha:be3e02b60effe3eab232d5590a6a2e2c2c2f443b size:119 2099 char sst[20]; 2100 sprintf(sst,"%lu", size); 2101 char *tmp; 2102 tmp = malloc(strlen(offDEFAULTS[offSignatureD]) + strlen(offFile) + strlen(sst) + 1 + 6); 2103 sprintf(tmp, "%s%s size:%s", offDEFAULTS[offSignatureD], offFile, sst); 2104 printf("%s\n", tmp); 2105 free(tmp); 2106 freeList((void **)offFilePath); 2107 free(offFile); 2108 sR = 0; 2109 } 2110 2111 void offCommands_prepush() { 2112 size_t len; 2113 char* line = NULL; 2114 ssize_t read; 2115 char **list = NULL; 2116 int count = 0;; 2117 2118 // add offCommands_push function 2119 // read stdin and calls push 2120 // stdin (data from git) is a line with remoteName url localRef localSha remoteRef remoteSha 2121 2122 offHelpers_setTransport_mode(); 2123 2124 read = getline(&line, &len, stdin); 2125 if (read == -1) { 2126 // exit directly when there is nothing to do 2127 exit(EXIT_SUCCESS); 2128 } 2129 while (read != -1) { 2130 { 2131 char* pos = NULL; 2132 pos = strchr(line, '\n'); 2133 if (pos != NULL) 2134 *pos = '\0'; 2135 } 2136 if (list == NULL) { 2137 list = malloc(2 * sizeof(int *)); 2138 list[1] = NULL; 2139 } 2140 else { 2141 list = realloc(list, (count+2) * sizeof(int *)); 2142 if (list == NULL) { 2143 exit(EXIT_FAILURE); 2144 } 2145 list[count+1] = NULL; 2146 } 2147 list[count] = strdup(line); 2148 read = getline(&line, &len, stdin); 2149 count++; 2150 } 2151 2152 count = 0; 2153 while (list[count] != NULL) { 2154 offCommands_push(list[count]); 2155 count++; 2156 } 2157 free(line); 2158 freeList((void **)list); 2159 count = 0; 2160 } 2161 2162 void offCommands_push(char *line) { 2163 // copy objects to off.store 2164 // 2165 // set remoteName url localRef localSha remoteRef remoteSha 2166 // list missing commits in remote 2167 // list changed objects in missing commits 2168 // check header with git cat 2169 // copy git off objects to off.store 2170 char *remoteName = NULL; 2171 char *url = NULL; 2172 char *localRef = NULL; 2173 char *localSha = NULL; 2174 char *remoteRef = NULL; 2175 char *remoteSha = NULL; 2176 char **line_l = NULL; 2177 char **commitListToPush = NULL; 2178 char *cmd = NULL; 2179 int i; 2180 2181 // set remoteName url localRef localSha remoteRef remoteSha 2182 remoteName = argv[argc-2]; 2183 url = argv[argc-1]; 2184 2185 line_l = split(line, " "); 2186 localRef = line_l[0]; 2187 localSha = line_l[1]; 2188 remoteRef = line_l[2]; 2189 remoteSha = line_l[3]; 2190 2191 // list missing commits in remote 2192 // handle empty cloned repo 2193 if (strEq(remoteSha, "0000000000000000000000000000000000000000")) { 2194 // run git rev-list --max-parents=0 localSha 2195 // when an empty git was cloned. 2196 char *parent = "--max-parents=0";; 2197 cmd = malloc(strlen(externalHelpers[gitList]) + strlen(parent) + strlen(localSha) + 1 + 2); 2198 sprintf(cmd, "%s %s %s", externalHelpers[gitList], parent, localSha); 2199 } 2200 else { 2201 cmd = malloc(strlen(externalHelpers[gitList]) + strlen(localSha) + strlen(remoteSha) + 1 + 3); 2202 sprintf(cmd, "%s %s ^%s", externalHelpers[gitList], localSha, remoteSha); 2203 } 2204 commitListToPush = execOut(cmd); 2205 free(cmd); 2206 2207 // list changed objects in missing commits 2208 int commitListIndex = 0; 2209 while (commitListToPush[commitListIndex] != NULL) { 2210 2211 // list changes for commit sha 2212 char **objInfoList; 2213 cmd = malloc(strlen(externalHelpers[gitDff]) + strlen(commitListToPush[commitListIndex]) + 1 + 1); 2214 sprintf(cmd, "%s %s", externalHelpers[gitDff], commitListToPush[commitListIndex]); 2215 objInfoList = execOut(cmd); 2216 free(cmd); 2217 // :000000 100644 0000000000000000000000000000000000000000 23636079ef005f53e81066aaf092521d8f2346df A dsd 2218 // TODO filter according to .gitattributes, check files in filter only 2219 2220 int oi = 0; 2221 while (objInfoList[oi] != NULL) { 2222 char **objInfo; 2223 objInfo = split(objInfoList[oi], " "); 2224 2225 // only lines starting with : (the first line from git diff-tree is the sha) 2226 // dont consider deleted files 2227 if ((objInfoList[oi][0] == ':') && (objInfo[oiNAME][0] != 'D')) { 2228 2229 // check header with git cat 2230 2231 char *offRef; 2232 offRef = exec(gitCat, objInfo[oiOID]); 2233 2234 if (offRef && (strstr(offRef, offDEFAULTS[offSignatureD]) != NULL)) { 2235 2236 // copy git off objects to off.store 2237 // found an off reference 2238 // ### git-off v1 sha:be3e02b60effe3eab232d5590a6a2e2c2c2f443b size:119 b.bin 2239 2240 char **offRefS1; 2241 char **offRefS2; 2242 char *offFile; 2243 char **offFilePath; 2244 offRefS1 = split(offRef, ":"); 2245 offRefS2 = split(offRefS1[1], " "); 2246 offFile = offRefS2[0]; 2247 offFilePath = offHelpers_getOffFilePath(offFile); 2248 2249 transport.send(offFilePath[0]); 2250 freeList((void **)offFilePath); 2251 freeList((void **)offRefS1); 2252 freeList((void **)offRefS2); 2253 } 2254 free(offRef); 2255 } 2256 freeList((void **)objInfo); 2257 oi++; 2258 } 2259 freeList((void **)objInfoList); 2260 commitListIndex++; 2261 } 2262 2263 freeList((void **)commitListToPush); 2264 freeList((void **)line_l); 2265 2266 // test prevent push by issuing an error 2267 //exit(EXIT_FAILURE); 2268 } 2269 2270 void offCommands_smudge() { 2271 2272 // copy objects from off.store for files handled by git off 2273 // stdin is the data from the git repo 2274 // 2275 // load header 2276 // for git off object, replace git off reference with data from cache or off.store 2277 // for normal object, copy data from repo to stdout 2278 2279 offHelpers_setTransport_mode(); 2280 offCommands_localSetup(); 2281 2282 // load header 2283 char b[1024]; 2284 int sR; 2285 sR = fread(b, 1, strlen(offDEFAULTS[offSignatureD]) + offDEFAULTS_shaLength, stdin); 2286 if (sR == 0) { 2287 // error no data 2288 offLogRepo("smudge error: cant get data from stdin."); 2289 exit(EXIT_FAILURE); 2290 } 2291 2292 if (strncmp(b, offDEFAULTS[offSignatureD], strlen(offDEFAULTS[offSignatureD])) == 0) { 2293 // for git off object, replace git off reference with data from cache or off.store 2294 2295 b[strlen(offDEFAULTS[offSignatureD]) + offDEFAULTS_shaLength] = 0; 2296 char **header_l; 2297 char *offFile; 2298 char **offFilePath; 2299 header_l = split(b, ":"); 2300 offFile = header_l[1]; 2301 offFilePath = offHelpers_getOffFilePath(offFile); 2302 2303 // detect if file is already in cache 2304 char *filePath; 2305 filePath = malloc(strlen(offHelpers_objectPath()) + strlen(offFilePath[0]) + 1 + 1); 2306 sprintf(filePath, "%s/%s", offHelpers_objectPath(), offFilePath[0]); 2307 if (access(filePath, F_OK) != -1) { 2308 // copy from cache 2309 FILE *fCache; 2310 if ((strEq(offHelpers_transform(), "enable")) && (offHelpers_transformFrom() != NULL)) { 2311 // transform file 2312 2313 transport_transformFrom(offFilePath[0]); 2314 2315 char *p; 2316 p = malloc(strlen(offHelpers_objectPath()) + strlen(offFilePath[0]) + 1 + 8); 2317 sprintf(p, "%s/../tmp/%s", offHelpers_objectPath(), offFilePath[0]); 2318 2319 fCache = fopen(p, "r"); 2320 2321 free(p); 2322 } 2323 else { 2324 fCache = fopen(filePath, "r"); 2325 } 2326 2327 sR = fread(b, 1, 1024, fCache); 2328 while (sR != 0) { 2329 fwrite(b, 1, sR, stdout); 2330 sR = fread(b, 1, 1024, fCache); 2331 } 2332 fclose(fCache); 2333 } 2334 else { 2335 // copy from off.store 2336 transport.receive(offFilePath[0]); 2337 } 2338 2339 free(filePath); 2340 freeList((void **)header_l); 2341 freeList((void **)offFilePath); 2342 } 2343 else { 2344 // for normal object, copy data from repo to stdout 2345 2346 //store header 2347 fwrite(b, 1, sR, stdout); 2348 2349 sR = fread(b, 1, 1024, stdin); 2350 while (sR != 0) { 2351 fwrite(b, 1, sR, stdout); 2352 sR = fread(b, 1, 1024, stdin); 2353 } 2354 } 2355 sR = 0; 2356 } 2357 2358 void offCommands_copyTo() { 2359 2360 // copy cache to store for argv[2] mode 2361 if (argc < 3) { 2362 printf("Choose a mode where to copy the cache"); 2363 printf("\n"); 2364 return; 2365 } 2366 2367 offHelpers_setTransport(argv[2]); 2368 offHelpers_copyTo(); 2369 } 2370 2371 void offCommands_pushTo() { 2372 2373 if (offHelpers_offMode() != NULL) { 2374 printf("mode: %s", offHelpers_offMode()); 2375 printf("\n"); 2376 offHelpers_setTransport(offHelpers_offMode()); 2377 offHelpers_copyTo(); 2378 } 2379 } 2380 2381 void offCommands_clearAll() { 2382 2383 // delete store, cache in current git and log 2384 offCommands_clearStore(); 2385 offCommands_clearCache(); 2386 rmAll(offHelpers_getLog()); 2387 } 2388 2389 void offCommands_clearCache() { 2390 char *p = NULL; 2391 2392 // delete cache in current git 2393 p = malloc(strlen(offHelpers_gitRepoRoot()) + 1 + 9); 2394 sprintf(p, "%s/.git/off", offHelpers_gitRepoRoot()); 2395 rmAll(p); 2396 free(p); 2397 } 2398 2399 void offCommands_clearStore() { 2400 2401 // delete store 2402 if (strEq(offHelpers_offMode(), "copy")) { 2403 rmAll(offHelpers_offStore()); 2404 } 2405 if (strEq(offHelpers_offMode(), "scp") || strEq(offHelpers_offMode(), "rsync")) { 2406 offHelpers_rmAllStore(""); 2407 } 2408 } 2409 2410 void offCommands_clearTmp() { 2411 char *p = NULL; 2412 2413 // delete tmp in cache in current git 2414 p = malloc(strlen(offHelpers_gitRepoRoot()) + 1 + 13); 2415 sprintf(p, "%s/.git/off/tmp", offHelpers_gitRepoRoot()); 2416 rmAll(p); 2417 free(p); 2418 } 2419 2420 void offCommands_defaults() { 2421 int i; 2422 2423 // TODO add default key strings 2424 // show first time config (offDEFAULTS) 2425 for (i=0; i < lastD ; i++) { 2426 printf("%s\n", offDEFAULTS[i]); 2427 } 2428 } 2429 2430 void offCommands_env() { 2431 char *s = NULL; 2432 2433 s = offHelpers_offMode(); 2434 if (s != NULL) { 2435 printf("off.mode %s", offHelpers_offMode()); 2436 printf("\n"); 2437 } 2438 s = offHelpers_offIntegrity(); 2439 if (s != NULL) { 2440 printf("off.integrity %s", offHelpers_offIntegrity()); 2441 printf("\n"); 2442 } 2443 s = offHelpers_offPem(); 2444 if (s != NULL) { 2445 printf("off.pem %s", offHelpers_offPem()); 2446 printf("\n"); 2447 } 2448 s = offHelpers_offSshOptions(); 2449 if (s != NULL) { 2450 printf("off.sshoptions %s", offHelpers_offSshOptions()); 2451 printf("\n"); 2452 } 2453 s = offHelpers_offScpOptions(); 2454 if (s != NULL) { 2455 printf("off.scpoptions %s", offHelpers_offScpOptions()); 2456 printf("\n"); 2457 } 2458 s = offHelpers_offRsyncOptions(); 2459 if (s != NULL) { 2460 printf("off.rsyncoptions %s", offHelpers_offRsyncOptions()); 2461 printf("\n"); 2462 } 2463 s = offHelpers_offStore(); 2464 if (s != NULL) { 2465 printf("off.store %s", offHelpers_offStore()); 2466 printf("\n"); 2467 } 2468 s = offHelpers_offHttp(); 2469 if (s != NULL) { 2470 printf("off.http %s", offHelpers_offHttp()); 2471 printf("\n"); 2472 } 2473 s = offHelpers_offCurlOptions(); 2474 if (s != NULL) { 2475 printf("off.curloptions %s", offHelpers_offCurlOptions()); 2476 printf("\n"); 2477 } 2478 s = offHelpers_offScp(); 2479 if (s != NULL) { 2480 printf("off.scphost %s", offHelpers_offScp()); 2481 printf("\n"); 2482 } 2483 s = offHelpers_offScpUser(); 2484 if (s != NULL) { 2485 printf("off.scpuser %s", offHelpers_offScpUser()); 2486 printf("\n"); 2487 } 2488 s = offHelpers_getLog(); 2489 if (s != NULL) { 2490 printf("off.log %s", offHelpers_getLog()); 2491 printf("\n"); 2492 } 2493 s = offHelpers_offConfigAlways(); 2494 if (s != NULL) { 2495 printf("off.configAlways %s", offHelpers_offConfigAlways()); 2496 printf("\n"); 2497 } 2498 s = offHelpers_s3Region(); 2499 if (s != NULL) { 2500 printf("off.s3region %s", offHelpers_s3Region()); 2501 printf("\n"); 2502 } 2503 s = offHelpers_s3Bucket(); 2504 if (s != NULL) { 2505 printf("off.s3bucket %s", offHelpers_s3Bucket()); 2506 printf("\n"); 2507 } 2508 s = offHelpers_transform(); 2509 if (s != NULL) { 2510 printf("off.transform %s", offHelpers_transform()); 2511 printf("\n"); 2512 } 2513 s = offHelpers_transformTo(); 2514 if (s != NULL) { 2515 printf("off.transformTo %s", offHelpers_transformTo()); 2516 printf("\n"); 2517 } 2518 s = offHelpers_transformFrom(); 2519 if (s != NULL) { 2520 printf("off.transformFrom %s", offHelpers_transformFrom()); 2521 printf("\n"); 2522 } 2523 } 2524 2525 void offCommands_help() { 2526 2527 printf("git-off help\n"); 2528 printf("\n"); 2529 if (argc < 3) { 2530 printf("# Quick Start"); 2531 printf("\n"); 2532 printf("Setup:"); 2533 printf("\n"); 2534 printf("git off track '*.bin'"); 2535 printf("\n"); 2536 printf("git add ."); 2537 printf("\n"); 2538 printf("git commit"); 2539 printf("\n"); 2540 printf("git push"); 2541 printf("\n"); 2542 printf("git checkout master"); 2543 printf("\n"); 2544 printf("\n# Other"); 2545 printf("\n"); 2546 printf("git off install"); 2547 printf("\n"); 2548 printf("git off mode scp"); 2549 printf("\n"); 2550 printf("git off scp localhost:/tmp/offStore"); 2551 printf("\n"); 2552 printf("git off scpuser username"); 2553 printf("\n"); 2554 printf("git off cc"); 2555 printf("\n"); 2556 printf("git off ca"); 2557 printf("\n"); 2558 printf("git off env"); 2559 printf("\n"); 2560 printf("git off defaults\n"); 2561 printf("\n"); 2562 2563 showAllCommandsHelp(); 2564 2565 printf("More information at https://noulin.net/git-off/file/README.md.html"); 2566 printf("\n"); 2567 } 2568 else { 2569 int cmd; 2570 cmd = findCommand(argv[2]); 2571 if (cmd == -1) { 2572 // show help for help 2573 printf("git-off command \"%s\" not found.\n", argv[2]); 2574 printf("\n"); 2575 printf("%s\n", COMMAND_HELP[helpC]); 2576 } 2577 else { 2578 printf("%s\n", COMMAND_HELP[cmd]); 2579 } 2580 } 2581 } 2582 2583 // -------------------------------------------------------------------------------------------- 2584 void installF() { 2585 2586 thisrepo(offCommands_install); 2587 } 2588 2589 void modeF() { 2590 2591 thisrepo(offCommands_setGetGitConfig); 2592 } 2593 2594 void storeF() { 2595 2596 thisrepo(offCommands_setGetGitConfig); 2597 } 2598 2599 void scpF() { 2600 2601 thisrepo(offCommands_setGetGitConfig); 2602 } 2603 2604 void httpF() { 2605 2606 thisrepo(offCommands_setGetGitConfig); 2607 } 2608 2609 void curlF() { 2610 2611 thisrepo(offCommands_setGetGitConfig); 2612 } 2613 2614 void integrityF() { 2615 2616 thisrepo(offCommands_setGetGitConfig); 2617 } 2618 2619 void pemF() { 2620 2621 thisrepo(offCommands_setGetGitConfig); 2622 } 2623 2624 void sshoptionsF() { 2625 2626 thisrepo(offCommands_setGetGitConfig); 2627 } 2628 2629 void scpoptionsF() { 2630 2631 thisrepo(offCommands_setGetGitConfig); 2632 } 2633 2634 void rsyncoptionsF() { 2635 2636 thisrepo(offCommands_setGetGitConfig); 2637 } 2638 2639 void scpuserF() { 2640 2641 thisrepo(offCommands_setGetGitConfig); 2642 } 2643 2644 void trackF() { 2645 2646 offCommands_track(); 2647 } 2648 2649 void configAlwaysF() { 2650 2651 offCommands_configAlways(); 2652 } 2653 2654 void s3regionF() { 2655 2656 thisrepo(offCommands_setGetGitConfig); 2657 } 2658 2659 void s3bucketF() { 2660 2661 thisrepo(offCommands_setGetGitConfig); 2662 } 2663 2664 void transformF() { 2665 2666 thisrepo(offCommands_setGetGitConfig); 2667 } 2668 2669 void transformToF() { 2670 2671 thisrepo(offCommands_setGetGitConfig); 2672 } 2673 2674 void transformFromF() { 2675 2676 thisrepo(offCommands_setGetGitConfig); 2677 } 2678 2679 void cleanF() { 2680 2681 offCommands_clean(); 2682 } 2683 2684 void prepushF() { 2685 2686 offCommands_prepush(); 2687 } 2688 2689 void smudgeF() { 2690 2691 offCommands_smudge(); 2692 } 2693 2694 void copyToF() { 2695 2696 offCommands_copyTo(); 2697 } 2698 2699 void pushF() { 2700 2701 offCommands_pushTo(); 2702 } 2703 2704 void clearAllF() { 2705 2706 offCommands_clearAll(); 2707 } 2708 2709 void caF() { 2710 2711 offCommands_clearAll(); 2712 } 2713 2714 void clearCacheF() { 2715 2716 offCommands_clearCache(); 2717 } 2718 2719 void ccF() { 2720 2721 offCommands_clearCache(); 2722 } 2723 2724 void clearStoreF() { 2725 2726 offCommands_clearStore(); 2727 } 2728 2729 void csF() { 2730 2731 offCommands_clearStore(); 2732 } 2733 2734 void clearTmpF() { 2735 2736 offCommands_clearTmp(); 2737 } 2738 2739 void ctF() { 2740 2741 offCommands_clearTmp(); 2742 } 2743 2744 void defaultsF() { 2745 2746 offCommands_defaults(); 2747 } 2748 2749 void envF() { 2750 2751 offCommands_env(); 2752 } 2753 2754 void helpF() { 2755 2756 offCommands_help(); 2757 } 2758 2759 // Initialize commands 2760 void initCOMMAND_FUNC() { 2761 2762 COMMAND_FUNC[0] = installF; 2763 COMMAND_FUNC[1] = modeF; 2764 COMMAND_FUNC[2] = storeF; 2765 COMMAND_FUNC[3] = scpF; 2766 COMMAND_FUNC[4] = httpF; 2767 COMMAND_FUNC[5] = curlF; 2768 COMMAND_FUNC[6] = integrityF; 2769 COMMAND_FUNC[7] = pemF; 2770 COMMAND_FUNC[8] = sshoptionsF; 2771 COMMAND_FUNC[9] = scpoptionsF; 2772 COMMAND_FUNC[10] = rsyncoptionsF; 2773 COMMAND_FUNC[11] = scpuserF; 2774 COMMAND_FUNC[12] = trackF; 2775 COMMAND_FUNC[13] = configAlwaysF; 2776 COMMAND_FUNC[14] = s3regionF; 2777 COMMAND_FUNC[15] = s3bucketF; 2778 COMMAND_FUNC[16] = transformF; 2779 COMMAND_FUNC[17] = transformToF; 2780 COMMAND_FUNC[18] = transformFromF; 2781 COMMAND_FUNC[19] = cleanF; 2782 COMMAND_FUNC[20] = prepushF; 2783 COMMAND_FUNC[21] = smudgeF; 2784 COMMAND_FUNC[22] = copyToF; 2785 COMMAND_FUNC[23] = pushF; 2786 COMMAND_FUNC[24] = clearAllF; 2787 COMMAND_FUNC[25] = caF; 2788 COMMAND_FUNC[26] = clearCacheF; 2789 COMMAND_FUNC[27] = ccF; 2790 COMMAND_FUNC[28] = clearStoreF; 2791 COMMAND_FUNC[29] = csF; 2792 COMMAND_FUNC[30] = clearTmpF; 2793 COMMAND_FUNC[31] = ctF; 2794 COMMAND_FUNC[32] = defaultsF; 2795 COMMAND_FUNC[33] = envF; 2796 COMMAND_FUNC[34] = helpF; 2797 COMMAND_FUNC[lastC] = NULL; 2798 2799 COMMAND_HELPERS[0] = NULL; 2800 COMMAND_HELPERS[1] = offHelpers_offMode; 2801 COMMAND_HELPERS[2] = offHelpers_offStore; 2802 COMMAND_HELPERS[3] = offHelpers_offScp; 2803 COMMAND_HELPERS[4] = offHelpers_offHttp; 2804 COMMAND_HELPERS[5] = offHelpers_offCurlOptions; 2805 COMMAND_HELPERS[6] = offHelpers_offIntegrity; 2806 COMMAND_HELPERS[7] = offHelpers_offPem; 2807 COMMAND_HELPERS[8] = offHelpers_offSshOptions; 2808 COMMAND_HELPERS[9] = offHelpers_offScpOptions; 2809 COMMAND_HELPERS[10] = offHelpers_offRsyncOptions; 2810 COMMAND_HELPERS[11] = offHelpers_offScpUser; 2811 COMMAND_HELPERS[12] = NULL; 2812 COMMAND_HELPERS[13] = offHelpers_offConfigAlways; 2813 COMMAND_HELPERS[14] = offHelpers_s3Region; 2814 COMMAND_HELPERS[15] = offHelpers_s3Bucket; 2815 COMMAND_HELPERS[16] = offHelpers_transform; 2816 COMMAND_HELPERS[17] = offHelpers_transformTo; 2817 COMMAND_HELPERS[18] = offHelpers_transformFrom; 2818 COMMAND_HELPERS[19] = NULL; 2819 COMMAND_HELPERS[20] = NULL; 2820 COMMAND_HELPERS[21] = NULL; 2821 COMMAND_HELPERS[22] = NULL; 2822 COMMAND_HELPERS[23] = NULL; 2823 COMMAND_HELPERS[24] = NULL; 2824 COMMAND_HELPERS[25] = NULL; 2825 COMMAND_HELPERS[26] = NULL; 2826 COMMAND_HELPERS[27] = NULL; 2827 COMMAND_HELPERS[28] = NULL; 2828 COMMAND_HELPERS[29] = NULL; 2829 COMMAND_HELPERS[30] = NULL; 2830 COMMAND_HELPERS[31] = NULL; 2831 COMMAND_HELPERS[32] = NULL; 2832 COMMAND_HELPERS[33] = NULL; 2833 COMMAND_HELPERS[34] = NULL; 2834 COMMAND_HELPERS[lastC] = NULL; 2835 } 2836 2837 #ifndef unitTest 2838 // Remove main when running the unit tests 2839 #define MAIN main 2840 #endif 2841 int MAIN(int ARGC, char** ARGV) { 2842 int dummy; 2843 // TODO remove dummy 2844 2845 argc = ARGC; argv = ARGV;;// init transport functions 2846 transport.send = send; 2847 transport.receive = receive; 2848 initCOMMAND_FUNC(); 2849 2850 // parse CLI arguments 2851 2852 if (argc == 1) { 2853 offCommands_help(); 2854 } 2855 else { 2856 // call argv[1] command 2857 int i; 2858 i = findCommand(argv[1]); 2859 if (i == -1) { 2860 offCommands_help(); 2861 } 2862 else { 2863 COMMAND_FUNC[i](); 2864 } 2865 } 2866 }