git-off

git off handles large files in git repos
git clone https://noulin.net/git/git-off.git
Log | Files | Refs | README

commit b39122164a6531ed2ce655246dbbfe6b8485bc27
parent e58a7c2b8a0faa0c261a3b7fefe626186362abd9
Author: Remy Noulin <loader2x@gmail.com>
Date:   Sun, 18 Dec 2016 16:47:15 +0100

add git-off c version, delete git off cache completely

gitoff c is equivalent to git-off coffescript.
The performance is better with the c version.

README.md    |   10 +
c/gitoff     |    2 +
c/gitoff.c   | 2519 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
package.json |    2 +-
4 files changed, 2532 insertions(+), 1 deletion(-)

Diffstat:
MREADME.md | 10++++++++++
Ac/gitoff | 2++
Ac/gitoff.c | 2519+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpackage.json | 2+-
4 files changed, 2532 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md @@ -27,6 +27,16 @@ for help. [https://www.npmjs.com/package/git-off](https://www.npmjs.com/package/git-off) +## C Version + +There is a git-off written in C in the c directory. To use it do the following step: + +``` +apt-get install tcc +cd DIRECTORY_IN_$PATH +ln -s $PATH_TO_GITOFF_GIT/c/gitoff git-off +``` + # Quick Start Setup: diff --git a/c/gitoff b/c/gitoff @@ -0,0 +1,2 @@ +#!/usr/bin/tcc -run +#include "/home/remy/git/sw/gitoff/c/gitoff.c" diff --git a/c/gitoff.c b/c/gitoff.c @@ -0,0 +1,2519 @@ +// TODO +// remove prints +// use the path function +// handle wrong config like getLog +// check parameters from CLI +// +// parse params +// use logger +// +// How to add a new config +// add variable in runtimeConfig +// add default settings in offDEFAULTS +// add a helper in offHelpers +// add setting of default in offCommands.install +// add a command for setting value in offCommands +// print value in offCommands.env +// add command in CLI parser +// update help +// +// How to add a new transport +// add transport functions in offHelpers.setTransport +// add transport in offHelpers.mkdirStore and offHelpers.rmAllStore +// add transport in offCommands.clearAll +// update git off mode help +// if needed, add store creation in offCommands.install +// +// How to add a new command +// add command in offCommands +// add command in CLI parser +// update help +// +////// +// CODE +// +// modules +// defaults +// helpers +// core +// main +// +// +// modules +// all dependencies +// +// defaults +// objInfo fields: for indexing cat-diff response in push command +// externalHelpers: shell commands to be used with the exec function +// runtimeConfig: config built by offHelpers +// offDEFAULTS: default configuration for first time install +// +// helpers +// expandHome: expands ~/ +// gitConfig: handles global git config +// offLog: appends log to git config off.log +// offLogRepo: log for commands run in git repo +// exec: runs an externalHelpers with parameters +// mkdirParents: recursive mkdir +// rmAll: delete recursively files and directories +// copy: copies files +// offHelpers: git-off helpers +// +// core +// transport: transport functions for git off store +// offCommands: command line functions +// +// main +// parse CLI arguments +////// + +////// +// modules +////// +// includes and function prototypes +typedef void (*gConfig_set_t)(char*, char*); +typedef void (*cmdSetF_t)(gConfig_set_t); + +#define internal static + +#include <sys/stat.h> +#include <inttypes.h> +#include <stdio.h> +#include <dirent.h> +#include <libgen.h> +#include <wordexp.h> +#include <stdbool.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdint.h> + +char *expandHome(char *p); +void offLog(char* s); +void offLogRepo(char* s); +char *exec(int cmdName, char* paramsArray); +void gitConfig_set(char* key, char* value); +void gitConfig_setLocal(char* key, char* value); +void gitConfig_setThisRepo(char* key, char* value); +char *gitConfig_getDefault(char* key); +char *gitConfig_get(char *key); +void mkdirParents(char* p); +void rmAll(char* p); +void copy(char* src, char* dst); +char **execOut(char *cmd); +char **walkDir(char* dir); +void freeList(void **list); +char **split(char *string, char* delim); +char *join(char **list, char* delim); +char *offHelpers_gitRepoRoot(); +char *offHelpers_objectPath(); +char *offHelpers_offStore(); +char *offHelpers_offHttp(); +char *offHelpers_offCurlOptions(); +char *offHelpers_offMode(); +char *offHelpers_offIntegrity(); +char *offHelpers_offPem(); +char *offHelpers_offSshOptions(); +char *offHelpers_offScpOptions(); +char *offHelpers_offScp(); +char *offHelpers_offScpUser(); +char *offHelpers_log(); +char *offHelpers_getLog(); +char *offHelpers_offConfigAlways(); +char *offHelpers_s3Region(); +char *offHelpers_s3Bucket(); +char *offHelpers_transform(); +char *offHelpers_transformTo(); +char *offHelpers_transformFrom(); +char *offHelpers_userAt(); +char **offHelpers_getSSHConfig(); +void offHelpers_mkdirStore(char *p); +void offHelpers_rmAllStore(char *p); +void offHelpers_copyTo(); +bool offHelpers_checkIntegrity(char *p); +void transportCopySend(char *file); +void transportCopyReceive(char *file); +void transportScpSend(char *file); +void transportScpReceive(char *file); +void transportHttpSend(char *file); +void transportHttpReceive(char *file); +void offHelpers_setTransport(char *mode ); +#define offHelpers_setTransport_mode() offHelpers_setTransport( "config") +char **offHelpers_getOffFilePath(char *offFile); +void send(char *src); +void receive(char *src); +void transport_transformFrom(char *file); +void thisrepo(cmdSetF_t cmd); +int findCommand(char *p); +void showAllCommandsHelp(); +void offCommands_localSetup(); +void offCommands_install(gConfig_set_t setF ); +#define offCommands_install_setF() offCommands_install( gitConfig_set) +void offCommands_track(); +void offCommands_configAlways(); +void offCommands_setGetGitConfig(gConfig_set_t setF); +void offCommands_clean(); +void offCommands_prepush(); +void offCommands_push(char *line); +void offCommands_smudge(); +void offCommands_copyTo(); +void offCommands_clearAll(); +void offCommands_clearCache(); +void offCommands_clearStore(); +void offCommands_defaults(); +void offCommands_env(); +void offCommands_help(); +void installF(); +void modeF(); +void storeF(); +void scpF(); +void httpF(); +void curlF(); +void integrityF(); +void pemF(); +void sshoptionsF(); +void scpoptionsF(); +void scpuserF(); +void trackF(); +void configAlwaysF(); +void s3regionF(); +void s3bucketF(); +void transformF(); +void transformToF(); +void transformFromF(); +void cleanF(); +void prepushF(); +void smudgeF(); +void copyToF(); +void clearAllF(); +void caF(); +void clearCacheF(); +void ccF(); +void clearStoreF(); +void csF(); +void defaultsF(); +void envF(); +void helpF(); +void initCOMMAND_FUNC(); + +int argc; char **argv; + + +////// +// defaults +////// + +// objInfo fields for indexing cat-diff response in push command +#define oiPREVIOUSPERMISSIONS 0 +#define oiPERMISSIONS 1 +#define oiPREVIOUSOID 2 +#define oiOID 3 +#define oiNAME 4 + +// shell commands to be used with the exec function +// example: exec 'gitRepoRoot' +enum { gitConfigGlobal, gitConfig, gitRepoRoot, gitList, gitDff, gitCat, sha, listAttr, ssh, scp, curl, mv, mkdirE, cp, rm }; +char* externalHelpers[15] = { "git config --global", "git config", "git rev-parse --show-toplevel", "git rev-list", "git diff-tree -r", "git cat-file -p", "git hash-object --no-filters", "git check-attr -a", "ssh", "scp", "curl", "mv", "mkdir -p", "cp", "rm -rf" }; + +// config built by offHelpers +// use offHelpers to access runtimeConfig +enum { currentRepoRoot, objectPath, offStore, offHttp, offMode, offIntegrity, offScp, offScpUser, offPem, offSshOptions, offScpOptions, offCurlOptions, log, offConfigAlways, s3Region, s3Bucket, transform, transformTo, transformFrom, scpHost, scpPath, scpPort }; +char* runtimeConfig[22] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +// default configuration for first time install +// objectPath is git off cache in repo +enum { objectPathD, modeD, integrityD, pemD, scpHostD, scpUserD, sshOptionsD, scpOptionsD, storeD, httpD, curlOptionsD, logD, configAlwaysD, s3RegionD, s3BucketD, transformD, transformToD, transformFromD, prePushD, offSignatureD, lastD }; +char* offDEFAULTS[21] = { "/.git/off/objects", "copy", "disable", "offNoValue", "offNoValue", "", "-C -o StrictHostKeyChecking=no -o ConnectTimeout=3", "-C -o StrictHostKeyChecking=no -o ConnectTimeout=3 -p", "~/.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" }; + +#define offDEFAULTS_shaLength 40 + +////// +// helpers +////// + +// expands ~/ +char *expandHome(char *p) { + wordexp_t exp_result; + size_t len; + + wordexp(p, &exp_result, 0); + p = realloc(p, strlen(exp_result.we_wordv[0])+1); + strcpy(p, exp_result.we_wordv[0]); + wordfree(&exp_result); + return(p); +} + + +// appends log to git config off.log +void offLog(char* s) { + char* r = NULL; + char* dirName = NULL; + DIR* d = NULL; + FILE* f = NULL; + + if (runtimeConfig[log] == NULL) { + // set runtimeConfig.log and get config in git + r = exec(gitConfigGlobal, "off.log"); + r = expandHome(r); + runtimeConfig[log] = r; + // error handling + if (r == NULL) { + printf("Missing off.log config. Run \"git config --global off.log ~/.git-off/log\"."); + printf("\n"); + exit(EXIT_FAILURE); + } + } + dirName = strdup(runtimeConfig[log]); + dirname(dirName); + d = opendir(dirName); + if (d == NULL) { + mkdirParents(dirName); + } + free(dirName); + free(d); + + f = fopen(runtimeConfig[log], "a"); + fprintf(f, "%s\n", s); + fclose(f); +} + +// log for commands run in git repo +// adds current repo path to string s in log +void offLogRepo(char* s) { + // depends on offHelpers + char* ss = NULL; + + ss = malloc(strlen(offHelpers_gitRepoRoot()) + strlen(s) + 1 + 12); + sprintf(ss, "REPO path: %s %s", offHelpers_gitRepoRoot(), s); + offLog(ss); + free(ss); +} + + +// runs an externalHelpers with parameters +// cmdName is string +// paramsArray is an array of strings +// returns line +char *exec(int cmdName, char* paramsArray) { + char* cmd = NULL; + FILE* fp = NULL; + size_t len; + char* line = NULL; + ssize_t read; + + cmd = malloc(strlen(externalHelpers[cmdName]) + strlen(paramsArray) + 1 + 1); + sprintf(cmd, "%s %s", externalHelpers[cmdName], paramsArray); + //print cmd + + fp = popen(cmd, "r"); + if (fp == NULL) { + exit(EXIT_FAILURE); + } + free(cmd); + + read = getline(&line, &len, fp); + fclose(fp); + + if (read == -1) { + // nothing was read + return(NULL); + } + + { + char* pos = NULL; + pos = strchr(line, '\n'); + if (pos != NULL) + *pos = '\0'; + } + //print line + return(line); +} + + +// handles global git config +void gitConfig_set(char* key, char* value) { + char* p = NULL; + char* r = NULL; + + p = malloc(strlen(key) + strlen(value) + 1 + 5); + sprintf(p, "%s \"%s\"", key, value); + r = exec(gitConfigGlobal, p); + free(p); + free(r); +} + +void gitConfig_setLocal(char* key, char* value) { + char* p = NULL; + char* r = NULL; + + p = malloc(strlen(key) + strlen(value) + 1 + 5); + sprintf(p, "%s \"%s\"", key, value); + r = exec(gitConfig, p); + free(p); + free(r); +} + +void gitConfig_setThisRepo(char* key, char* value) { + char* p = NULL; + char* r = NULL; + + p = malloc(strlen(offHelpers_gitRepoRoot()) + strlen(key) + strlen(value) + 1 + 22); + sprintf(p, "--file %s/.git-off %s \"%s\"", offHelpers_gitRepoRoot() , key, value); + r = exec(gitConfig, p); + free(p); + free(r); +} + +char *gitConfig_getDefault(char* key) { + + return(exec(gitConfig, key)); +} + +char *gitConfig_get(char *key) { + // use configAlways setting or + // return value from + // GIT_OFF_CONFIG if found + // repo config if found + // global config + char* r = NULL; + char* p = NULL; + char* gitOffConfigEnv = NULL; + + // configAlways + if (strcmp(offHelpers_offConfigAlways(), "GIT_OFF_CONFIG") == 0) { + gitOffConfigEnv = getenv("GIT_OFF_CONFIG"); + if ((gitOffConfigEnv != NULL) && (access(gitOffConfigEnv, F_OK) != -1)) { + p = malloc(strlen(gitOffConfigEnv) + strlen(key) + 1 + 8); + sprintf(p, "--file %s %s", gitOffConfigEnv, key); + r = exec(gitConfig, p); + free(p); + } + return(r); + } + if (strcmp(offHelpers_offConfigAlways(), "repo") == 0) { + p = malloc(strlen(offHelpers_gitRepoRoot()) + 1 + 9); + sprintf(p, "%s/.git-off", offHelpers_gitRepoRoot()); + if (access(p, F_OK) != -1) { + free(p); + p = malloc(strlen(offHelpers_gitRepoRoot()) + strlen(key) + 1 + 17); + sprintf(p, "--file %s/.git-off %s", offHelpers_gitRepoRoot() , key); + r = exec(gitConfig, p); + } + free(p); + return(r); + } + if (strcmp(offHelpers_offConfigAlways(), "global") == 0) { + r = gitConfig_getDefault(key); + return(r); + } + + // interpolate + gitOffConfigEnv = getenv("GIT_OFF_CONFIG"); + if ((gitOffConfigEnv != NULL) && (access(gitOffConfigEnv, F_OK) != -1)) { + p = malloc(strlen(gitOffConfigEnv) + strlen(key) + 1 + 8); + sprintf(p, "--file %s %s", gitOffConfigEnv, key); + r = exec(gitConfig, p); + free(p); + if (r != NULL) { + return(r); + } + } + + p = malloc(strlen(offHelpers_gitRepoRoot()) + 1 + 9); + sprintf(p, "%s/.git-off", offHelpers_gitRepoRoot()); + if (access(p, F_OK) != -1) { + free(p); + p = malloc(strlen(offHelpers_gitRepoRoot()) + strlen(key) + 1 + 17); + sprintf(p, "--file %s/.git-off %s", offHelpers_gitRepoRoot() , key); + r = exec(gitConfig, p); + if (r != NULL) { + free(p); + return(r); + } + } + free(p); + r = gitConfig_getDefault(key); + return(r); +} + + +// recursive mkdir +void mkdirParents(char* p) { + char* r = NULL; + + r = exec(mkdirE, p); + free(r); +} + +// delete recursively files and directories +void rmAll(char* p) { + char* r = NULL; + + r = exec(rm, p); + free(r); +} + +// copies files +// file modes are not kept +void copy(char* src, char* dst) { + char* r = NULL; + char* p = NULL; + + p = malloc(strlen(src) + strlen(dst) + 1 + 1); + sprintf(p, "%s %s", src, dst); + r = exec(cp, p); + free(p); + free(r); +} + +// exec +// return stdout from cmd +char **execOut(char *cmd) { + FILE* fp = NULL; + size_t len; + char* line = NULL; + ssize_t read; + char **list = NULL; + int count = 0;; + + //print cmd + + fp = popen(cmd, "r"); + if (fp == NULL) { + exit(EXIT_FAILURE); + } + + read = getline(&line, &len, fp); + while (read != -1) { + { + char* pos = NULL; + pos = strchr(line, '\n'); + if (pos != NULL) + *pos = '\0'; + } + if (list == NULL) { + list = malloc(2 * sizeof(int *)); + list[1] = NULL; + } + else { + list = realloc(list, (count+2) * sizeof(int *)); + list[count+1] = NULL; + } + list[count] = strdup(line); + read = getline(&line, &len, fp); + count++; + } + + fclose(fp); + return(list); +} + +// List all files in a directory +char **walkDir(char* dir) { + char* cmd = NULL; + char **list = NULL; + + cmd = malloc(strlen(dir) + 1 + 13); + sprintf(cmd, "find %s -type f", dir); + list = execOut(cmd); + free(cmd); + return(list); +} + +void freeList(void **list) { + int i = 0;; + + if (list != NULL) { + while (list[i] != NULL) { + free(list[i]); + i++; + } + free(list); +} + } + + +char **split(char *string, char* delim) { + char *startString = NULL; + char *workingString = NULL; + char *line = NULL; + char *token = NULL; + int count = 0;; + char **r = NULL; + + startString = strdup(string); + workingString = startString; + while (strlen(workingString) != 0) { + line = workingString; + token = strtok_r(line, delim, &workingString); + if (r == NULL) { + r = malloc(2 * sizeof(int *)); + r[1] = NULL; + } + else { + r = realloc(r, (count+2) * sizeof(int *)); + r[count+1] = NULL; + } + r[count] = strdup(token); + count++; + } + + free(startString); + return(r); +} + +char *join(char **list, char* delim) { + char *r = NULL; + + while (*list != NULL) { + if (r == NULL) { + r = strdup(*list); + } + else { + char *tmp; + tmp = realloc(r, strlen(r) + strlen(delim) + 1); + if (tmp == NULL) { + exit(EXIT_FAILURE); + } + r = tmp; + strcat(r, delim); + tmp = realloc(r, strlen(r) + strlen(*list) + 1); + if (tmp == NULL) { + exit(EXIT_FAILURE); + } + r = tmp; + strcat(r, *list); + } + list++; + } + return(r); +} + + +// transport + +typedef void (*transportSend_t)(char *); +typedef void (*transportReceive_t)(char *); +typedef struct {transportSend_t send; transportReceive_t receive;} transport_t; +transport_t transport; + +// git-off helpers +// gitRepoRoot: sets and returns runtimeConfig.currentRepoRoot +// objectPath: sets and returns runtimeConfig.objectPath +// offStore: sets and returns runtimeConfig.offStore +// offMode: sets and returns runtimeConfig.offMode +// offIntegrity sets and returns runtimeConfig.offIntegrity +// offScp: sets and returns runtimeConfig.offScp +// offScpUser: sets and returns runtimeConfig.offScpUser +// log: sets and returns runtimeConfig.log +// getLog: sets and returns runtimeConfig.log with error checking +// userAt: returns user@ or '' +// getSSHConfig extracts host, port and path from off.sshhost +// mkdirStore mkdir in remote store +// rmAllStore rm in remote store +// checkIntegrity check integrity of files coming from the store +// setTransport: set send and receive functions for transport +// getOffFilePath: creates path for offFile + +char *offHelpers_gitRepoRoot() { + + if (runtimeConfig[currentRepoRoot] == NULL) { + runtimeConfig[currentRepoRoot] = exec(gitRepoRoot, ""); + } + return(runtimeConfig[currentRepoRoot]); +} + +char *offHelpers_objectPath() { + + if (runtimeConfig[objectPath] == NULL) { + runtimeConfig[objectPath] = malloc(strlen(offHelpers_gitRepoRoot()) + strlen(offDEFAULTS[objectPathD]) + 1 + 0); + sprintf(runtimeConfig[objectPath], "%s%s", offHelpers_gitRepoRoot(), offDEFAULTS[objectPathD]); + } + return(runtimeConfig[objectPath]); +} + +char *offHelpers_offStore() { + + if (runtimeConfig[offStore] == NULL) { + runtimeConfig[offStore] = gitConfig_get("off.store"); + } + return(runtimeConfig[offStore]); +} + +char *offHelpers_offHttp() { + + if (runtimeConfig[offHttp] == NULL) { + runtimeConfig[offHttp] = gitConfig_get("off.http"); + } + return(runtimeConfig[offHttp]); +} + +char *offHelpers_offCurlOptions() { + + if (runtimeConfig[offCurlOptions] == NULL) { + runtimeConfig[offCurlOptions] = gitConfig_get("off.curloptions"); + } + return(runtimeConfig[offCurlOptions]); +} + +char *offHelpers_offMode() { + + if (runtimeConfig[offMode] == NULL) { + runtimeConfig[offMode] = gitConfig_get("off.mode"); + } + return(runtimeConfig[offMode]); +} + +char *offHelpers_offIntegrity() { + + if (runtimeConfig[offIntegrity] == NULL) { + runtimeConfig[offIntegrity] = gitConfig_get("off.integrity"); + } + return(runtimeConfig[offIntegrity]); +} + +char *offHelpers_offPem() { + + if (runtimeConfig[offPem] == NULL) { + runtimeConfig[offPem] = gitConfig_get("off.pem"); + } + return(runtimeConfig[offPem]); +} + +char *offHelpers_offSshOptions() { + + if (runtimeConfig[offSshOptions] == NULL) { + runtimeConfig[offSshOptions] = gitConfig_get("off.sshoptions"); + } + return(runtimeConfig[offSshOptions]); +} + +char *offHelpers_offScpOptions() { + + if (runtimeConfig[offScpOptions] == NULL) { + runtimeConfig[offScpOptions] = gitConfig_get("off.scpoptions"); + } + return(runtimeConfig[offScpOptions]); +} + +char *offHelpers_offScp() { + + if (runtimeConfig[offScp] == NULL) { + runtimeConfig[offScp] = gitConfig_get("off.scphost"); + } + return(runtimeConfig[offScp]); +} + +char *offHelpers_offScpUser() { + + if (runtimeConfig[offScpUser] == NULL) { + runtimeConfig[offScpUser] = gitConfig_get("off.scpuser"); + } + return(runtimeConfig[offScpUser]); +} + +char *offHelpers_log() { + + if (runtimeConfig[log] == NULL) { + runtimeConfig[log] = gitConfig_getDefault("off.log"); + runtimeConfig[log] = expandHome(runtimeConfig[log]); + } + return(runtimeConfig[log]); +} + +char *offHelpers_getLog() { + + offHelpers_log(); + // error handling + if (runtimeConfig[log] == NULL) { + printf("Missing off.log config. Run \"git config --global off.log ~/.git-off/log\"."); + printf("\n"); + exit(EXIT_FAILURE); + } + return(runtimeConfig[log]); +} + +char *offHelpers_offConfigAlways() { + + if (runtimeConfig[offConfigAlways] == NULL) { + runtimeConfig[offConfigAlways] = gitConfig_getDefault("off.configAlways"); + } + return(runtimeConfig[offConfigAlways]); +} + +char *offHelpers_s3Region() { + + if (runtimeConfig[s3Region] == NULL) { + runtimeConfig[s3Region] = gitConfig_get("off.s3Region"); + } + return(runtimeConfig[s3Region]); +} + +char *offHelpers_s3Bucket() { + + if (runtimeConfig[s3Bucket] == NULL) { + runtimeConfig[s3Bucket] = gitConfig_get("off.s3Bucket"); + } + return(runtimeConfig[s3Bucket]); +} + +char *offHelpers_transform() { + + if (runtimeConfig[transform] == NULL) { + runtimeConfig[transform] = gitConfig_get("off.transform"); + } + return(runtimeConfig[transform]); +} + +char *offHelpers_transformTo() { + + if (runtimeConfig[transformTo] == NULL) { + runtimeConfig[transformTo] = gitConfig_get("off.transformTo"); + } + return(runtimeConfig[transformTo]); +} + +char *offHelpers_transformFrom() { + + if (runtimeConfig[transformFrom] == NULL) { + runtimeConfig[transformFrom] = gitConfig_get("off.transformFrom"); + } + return(runtimeConfig[transformFrom]); +} + +char *offHelpers_userAt() { + + if ((offHelpers_offScpUser() != NULL) && (strcmp(offHelpers_offScpUser(), "") != 0)) { + char *u; + u = malloc(strlen(offHelpers_offScpUser()) + 1 + 1); + sprintf(u, "%s@", offHelpers_offScpUser()); + return(u); + } + else { + return ""; +} + } + +char **offHelpers_getSSHConfig() { + char *user = NULL; + char **h_l = NULL; + char *port = NULL; + char *host = NULL; + char *storePath = NULL; + char **portAndPath_l = NULL; + char **r = NULL; + + // extract host, port and path from off.sshhost + + user = offHelpers_userAt(); + h_l = split(offHelpers_offScp(), ":"); + host = strdup(h_l[0]); + if (h_l[1] != NULL) { + int i; + + portAndPath_l = split(h_l[1], "/"); + i = strtoumax(portAndPath_l[0], NULL, 10); + if (i != 0) { + port = strdup(portAndPath_l[0]); + } + } + if (port == NULL) { + // use default port + storePath = strdup(h_l[1]); + } + else { + storePath = strdup("/"); + char *tmp; + tmp = join(portAndPath_l + 1, "/"); + char *tmpr; + tmpr = realloc(storePath, strlen(storePath) + strlen(tmp) + 1); + if (tmpr == NULL) { + exit(EXIT_FAILURE); + } + storePath = tmpr; + strcat(storePath, tmp); + free(tmp); + } + freeList((void **) h_l); + freeList((void **) portAndPath_l); + + // result [user + host, storePath, port] + r = malloc(4 * sizeof(int *)); + r[3] = NULL; + r[0] = strdup(user); + char *t; + t = realloc(r[0], strlen(r[0]) + strlen(host) + 1); + if (t == NULL) { + exit(EXIT_FAILURE); + } + r[0] = t; + strcat(r[0], host); + r[1] = storePath; + r[2] = port; + free(host); + return(r); +} + + +void offHelpers_mkdirStore(char *p) { + // mkdir in remote store + char *params = NULL; + char *sshCmd = NULL; + char *pem = NULL; + char **h_l = NULL; + + // TODO handle multiple transports + h_l = offHelpers_getSSHConfig(); + + sshCmd = malloc(strlen(h_l[1]) + strlen(p) + 1 + 10); + sprintf(sshCmd, "mkdir -p %s/%s", h_l[1], p); + + // setup ssh/scp private key + if ((offHelpers_offPem() == NULL) || (strcmp(offHelpers_offPem(), "offNoValue") == 0)) { + pem = strdup(""); + } + else { + pem = malloc(strlen(offHelpers_offPem()) + 1 + 3); + sprintf(pem, "-i %s", offHelpers_offPem()); + } + + // ignore error from mkdir for already existing store + if (h_l[2] == NULL) { + params = malloc(strlen(offHelpers_offSshOptions()) + strlen(pem) + strlen(h_l[0]) + strlen(sshCmd) + 1 + 7); + sprintf(params, "%s %s %s \"%s\"", offHelpers_offSshOptions(), pem, h_l[0], sshCmd); + } + else { + params = malloc(strlen(offHelpers_offSshOptions()) + strlen(pem) + strlen(h_l[2]) + strlen(h_l[0]) + strlen(sshCmd) + 1 + 11); + sprintf(params, "%s %s -p %s %s \"%s\"", offHelpers_offSshOptions(), pem, h_l[2], h_l[0], sshCmd); + } + + freeList((void **) h_l); + free(sshCmd); + free(pem); + exec(ssh, params); + free(params); +} + + +void offHelpers_rmAllStore(char *p) { + // rm in remote store + char *params = NULL; + char *sshCmd = NULL; + char *pem = NULL; + char **h_l = NULL; + + // setup ssh/scp private key + if ((offHelpers_offPem() == NULL) || (strcmp(offHelpers_offPem(), "offNoValue") == 0)) { + pem = strdup(""); + } + else { + pem = malloc(strlen(offHelpers_offPem()) + 1 + 3); + sprintf(pem, "-i %s", offHelpers_offPem()); + } + + // scphost format is host:path + h_l = offHelpers_getSSHConfig(); + + sshCmd = malloc(strlen(h_l[1]) + strlen(p) + 1 + 8); + sprintf(sshCmd, "rm -rf %s/%s", h_l[1], p); + + // ignore error from rm + if (h_l[2] == NULL) { + params = malloc(strlen(offHelpers_offSshOptions()) + strlen(pem) + strlen(h_l[0]) + strlen(sshCmd) + 1 + 7); + sprintf(params, "%s %s %s \"%s\"", offHelpers_offSshOptions(), pem, h_l[0], sshCmd); + } + else { + params = malloc(strlen(offHelpers_offSshOptions()) + strlen(pem) + strlen(h_l[2]) + strlen(h_l[0]) + strlen(sshCmd) + 1 + 11); + sprintf(params, "%s %s -p %s %s \"%s\"", offHelpers_offSshOptions(), pem, h_l[2], h_l[0], sshCmd); + } + + freeList((void **) h_l); + free(sshCmd); + free(pem); + exec(ssh, params); + free(params); +} + +void offHelpers_copyTo() { + // list file in cache + // copy to store + char **files = NULL; + int i; + + // list file in cache + + files = walkDir(offHelpers_objectPath()); + if (files == NULL) { + return; + } + + i = 0; + while (files[i] != NULL) { + char *tmp; + tmp = strdup(files[i] + strlen(offHelpers_objectPath()) + 1); + free(files[i]); + files[i] = tmp; + i++; + } + + // copy to store + + i = 0; + while (files[i] != NULL) { + transport.send(files[i]); + i++; + } + freeList((void **) files); +} + +bool offHelpers_checkIntegrity(char *p) { + // check integrity of files coming from the store + bool result = true;; + char *receivedSha = NULL; + char *base = NULL; + + if (strcmp(offHelpers_offIntegrity(), "disable") == 0) { + return(true); + } + + receivedSha = exec(sha, p); + + base = strdup(basename(p)); + if (strcmp(base, receivedSha) != 0) { + // the file received is different from the one that was sent. + printf("git-off: The file %s differs from the one that was pushed.", p); { + printf("\n"); + result = false; + } + } + free(base); + + return(result); +} + +void transportCopySend(char *file) { + // create file directories in store + char **f_l = NULL; + char *p = NULL; + DIR *d = NULL; + + f_l = split(file, "/"); + p = malloc(strlen(offHelpers_offStore()) + strlen(f_l[0]) + strlen(f_l[1]) + 1 + 2); + sprintf(p, "%s/%s/%s", offHelpers_offStore(), f_l[0], f_l[1]); + d = opendir(p);; + if (d == NULL) { + mkdirParents(p); + } + free(p); + + p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); + sprintf(p, "%s/%s", offHelpers_objectPath(), file); + char *dest; + dest = malloc(strlen(offHelpers_offStore()) + strlen(file) + 1 + 1); + sprintf(dest, "%s/%s", offHelpers_offStore(), file); + copy(p, dest); + free(dest); + free(p); + freeList((void **)f_l); +} + +void transportCopyReceive(char *file) { + // transfer and transform + char *p = NULL; + int sR; + char b[1024]; + FILE *f = NULL; + + if ((strcmp(offHelpers_transform(), "enable") == 0) && (offHelpers_transformFrom() != NULL)) { + // create file directories in objectPath + char **f_l; + DIR *d; + f_l = split(file, "/"); + p = malloc(strlen(offHelpers_objectPath()) + strlen(f_l[0]) + strlen(f_l[1]) + 1 + 2); + sprintf(p, "%s/%s/%s", offHelpers_objectPath(), f_l[0], f_l[1]); + d = opendir(p);; + if (d == NULL) { + mkdirParents(p); + } + free(p); + + p = malloc(strlen(offHelpers_offStore()) + strlen(file) + 1 + 1); + sprintf(p, "%s/%s", offHelpers_offStore(), file); + char *dest; + dest = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); + sprintf(dest, "%s/%s", offHelpers_objectPath(), file); + copy(p, dest); + + transport_transformFrom(file); + + free(p); + p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 8); + sprintf(p, "%s/../tmp/%s", offHelpers_objectPath(), file); + if (offHelpers_checkIntegrity(p)) { + f = fopen(p, "r"); + sR = fread(b, 1, 1024, f); + while (sR != 0) { + fwrite(b, 1, sR, stdout); + sR = fread(b, 1, 1024, f); + } + fclose(f); + } + + free(dest); + freeList((void **)f_l); + } + else { + p = malloc(strlen(offHelpers_offStore()) + strlen(file) + 1 + 1); + sprintf(p, "%s/%s", offHelpers_offStore(), file); + if (offHelpers_checkIntegrity(p)) { + f = fopen(p, "r"); + sR = fread(b, 1, 1024, f); + while (sR != 0) { + fwrite(b, 1, sR, stdout); + sR = fread(b, 1, 1024, f); + } + fclose(f); + } + } + + free(p); +} + + +void transportScpSend(char *file) { + // create file directories in store + char **f_l = NULL; + char *p = NULL; + char *pem = NULL; + char *params = NULL; + char **h_l = NULL; + + f_l = split(file, "/"); + p = malloc(strlen(f_l[0]) + strlen(f_l[1]) + 1 + 1); + sprintf(p, "%s/%s", f_l[0], f_l[1]); + offHelpers_mkdirStore(p); + free(p); + + h_l = offHelpers_getSSHConfig(); + + // setup ssh/scp private key + if ((offHelpers_offPem() == NULL) || (strcmp(offHelpers_offPem(), "offNoValue") == 0)) { + pem = strdup(""); + } + else { + pem = malloc(strlen(offHelpers_offPem()) + 1 + 3); + sprintf(pem, "-i %s", offHelpers_offPem()); + } + + char *dest; + + p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); + sprintf(p, "%s/%s", offHelpers_objectPath(), file); + dest = malloc(strlen(h_l[0]) + strlen(h_l[1]) + strlen(file) + 1 + 2); + sprintf(dest, "%s:%s/%s", h_l[0], h_l[1], file); + + if (h_l[2] == NULL) { + params = malloc(strlen(offHelpers_offScpOptions()) + strlen(pem) + strlen(p) + strlen(dest) + 1 + 3); + sprintf(params, "%s %s %s %s", offHelpers_offScpOptions(), pem, p, dest); + } + else { + params = malloc(strlen(offHelpers_offScpOptions()) + strlen(pem) + strlen(h_l[2]) + strlen(p) + strlen(dest) + 1 + 7); + sprintf(params, "%s %s -P %s %s %s", offHelpers_offScpOptions(), pem, h_l[2], p, dest); + } + + exec(scp, params); + + free(p); + free(dest); + freeList((void **) h_l); + free(pem); + free(params); +} + +void transportScpReceive(char *file) { + char *p = NULL; + char **f_l = NULL; + DIR *d = NULL; + char **h_l = NULL; + char *pem = NULL; + char *params = NULL; + + // create file directories in cache + f_l = split(file, "/"); + p = malloc(strlen(offHelpers_objectPath()) + strlen(f_l[0]) + strlen(f_l[1]) + 1 + 2); + sprintf(p, "%s/%s/%s", offHelpers_objectPath(), f_l[0], f_l[1]); + d = opendir(p);; + if (d == NULL) { + mkdirParents(p); + } + free(p); + freeList((void **)f_l); + + h_l = offHelpers_getSSHConfig(); + + // setup ssh/scp private key + if ((offHelpers_offPem() == NULL) || (strcmp(offHelpers_offPem(), "offNoValue") == 0)) { + pem = strdup(""); + } + else { + pem = malloc(strlen(offHelpers_offPem()) + 1 + 3); + sprintf(pem, "-i %s", offHelpers_offPem()); + } + + char *dest; + + dest = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); + sprintf(dest, "%s/%s", offHelpers_objectPath(), file); + p = malloc(strlen(h_l[0]) + strlen(h_l[1]) + strlen(file) + 1 + 2); + sprintf(p, "%s:%s/%s", h_l[0], h_l[1], file); + + if (h_l[2] == NULL) { + params = malloc(strlen(offHelpers_offScpOptions()) + strlen(pem) + strlen(p) + strlen(dest) + 1 + 3); + sprintf(params, "%s %s %s %s", offHelpers_offScpOptions(), pem, p, dest); + } + else { + params = malloc(strlen(offHelpers_offScpOptions()) + strlen(pem) + strlen(h_l[2]) + strlen(p) + strlen(dest) + 1 + 7); + sprintf(params, "%s %s -P %s %s %s", offHelpers_offScpOptions(), pem, h_l[2], p, dest); + } + + exec(scp, params); + + free(p); + free(dest); + freeList((void **) h_l); + free(pem); + free(params); + + // transform + int sR; + char b[1024]; + FILE *f; + + if ((strcmp(offHelpers_transform(), "enable") == 0) && (offHelpers_transformFrom() != NULL)) { + transport_transformFrom(file); + p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 8); + sprintf(p, "%s/../tmp/%s", offHelpers_objectPath(), file); + if (offHelpers_checkIntegrity(p)) { + f = fopen(p, "r"); + sR = fread(b, 1, 1024, f); + while (sR != 0) { + fwrite(b, 1, sR, stdout); + sR = fread(b, 1, 1024, f); + } + fclose(f); + } + } + else { + p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); + sprintf(p, "%s/%s", offHelpers_objectPath(), file); + if (offHelpers_checkIntegrity(p)) { + f = fopen(p, "r"); + sR = fread(b, 1, 1024, f); + while (sR != 0) { + fwrite(b, 1, sR, stdout); + sR = fread(b, 1, 1024, f); + } + fclose(f); + } + } + + free(p); +} + + +void transportHttpSend(char *file) { + char *p = NULL; + + p = malloc(strlen(file) + 1 + 48); + sprintf(p, "Http mode is read-only: %s is stored in cache only", file); + offLogRepo(p); + free(p); +} + +void transportHttpReceive(char *file) { + char *p = NULL; + char **f_l = NULL; + DIR *d = NULL; + + // create file directories in cache + f_l = split(file, "/"); + p = malloc(strlen(offHelpers_objectPath()) + strlen(f_l[0]) + strlen(f_l[1]) + 1 + 2); + sprintf(p, "%s/%s/%s", offHelpers_objectPath(), f_l[0], f_l[1]); + d = opendir(p);; + if (d == NULL) { + mkdirParents(p); + } + free(p); + freeList((void **)f_l); + + p = malloc(strlen(offHelpers_offCurlOptions()) + strlen(offHelpers_objectPath()) + strlen(file) + strlen(offHelpers_offHttp()) + strlen(file) + 1 + 4); + sprintf(p, "%s %s/%s %s/%s", offHelpers_offCurlOptions(), offHelpers_objectPath(), file, offHelpers_offHttp(), file); + exec(curl, p); + free(p); + + // transform + int sR; + char b[1024]; + FILE *f; + + if ((strcmp(offHelpers_transform(), "enable") == 0) && (offHelpers_transformFrom() != NULL)) { + transport_transformFrom(file); + p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 8); + sprintf(p, "%s/../tmp/%s", offHelpers_objectPath(), file); + if (offHelpers_checkIntegrity(p)) { + f = fopen(p, "r"); + sR = fread(b, 1, 1024, f); + while (sR != 0) { + fwrite(b, 1, sR, stdout); + sR = fread(b, 1, 1024, f); + } + fclose(f); + } + } + else { + p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); + sprintf(p, "%s/%s", offHelpers_objectPath(), file); + if (offHelpers_checkIntegrity(p)) { + f = fopen(p, "r"); + sR = fread(b, 1, 1024, f); + while (sR != 0) { + fwrite(b, 1, sR, stdout); + sR = fread(b, 1, 1024, f); + } + fclose(f); + } + } + + free(p); +} + +void offHelpers_setTransport(char *mode ) { + + // set send and receive functions for transport + // copy, scp + + // use mode from config or from parameter + if (strcmp(mode, "config") == 0) { + mode = strdup(offHelpers_offMode()); + } + + // copy mode + if (strcmp(mode, "copy") == 0) { + transport.send = transportCopySend; + transport.receive = transportCopyReceive; + } + + // scp mode + else if (strcmp(mode, "scp") == 0) { + transport.send = transportScpSend; + transport.receive = transportScpReceive; + } + + // http mode + else if (strcmp(mode, "http") == 0) { + transport.send = transportHttpSend; + transport.receive = transportHttpReceive; +} + } + +// +// // s3 mode +// else if mode == 's3' +// transport['send'] = (file) -> +// AWS = require 'aws-sdk' +// s3 = new AWS.S3({region: offHelpers.s3Region(), signatureVersion: 'v4'}) +// +// // upload to s3 +// upParams = {Bucket: offHelpers.s3Bucket(), Key: file, Body: ''} +// fileStream = fs.createReadStream(offHelpers.objectPath() + '/' + file) +// upParams.Body = fileStream +// s3.upload(upParams, (err, data) -> +// // TODO log eventual error +// return +// ) +// +// return +// transport['receive'] = (file) -> +// AWS = require 'aws-sdk' +// s3 = new AWS.S3({region: offHelpers.s3Region(), signatureVersion: 'v4'}) +// +// // create file directories in cache +// f_l = file.split '/' +// if fs.existsSync(offHelpers.objectPath() + '/' + f_l[0] + '/' + f_l[1]) == false +// mkdirParents offHelpers.objectPath() + '/' + f_l[0] + '/' + f_l[1] +// +// // download from s3 +// dlParams = {Bucket: offHelpers.s3Bucket(), Key: file} +// fileStream = fs.createWriteStream(offHelpers.objectPath() + '/' + file) +// fileStream.on('finish', -> +// // transfer is finished, the complete file is in the cache +// // transform +// if offHelpers.transform() == 'enable' and offHelpers.transformFrom() != '' +// transport['transformFrom'](file) +// if offHelpers.checkIntegrity offHelpers.objectPath() + '/../tmp/' + file +// readStream = fs.createReadStream(offHelpers.objectPath() + '/../tmp/' + file) +// readStream.pipe(process.stdout) +// else +// if offHelpers.checkIntegrity offHelpers.objectPath() + '/' + file +// readStream = fs.createReadStream(offHelpers.objectPath() + '/' + file) +// readStream.pipe(process.stdout) +// return +// ) +// s3.getObject(dlParams, (err, data) -> +// // TODO log eventual error +// return +// ).on('httpData', (chunk) -> +// fileStream.write chunk +// return +// ).on('httpDone', -> +// fileStream.end() +// return +// ) +// return +// return + +char **offHelpers_getOffFilePath(char *offFile) { + char **r = NULL; + char tmp[6]; + + tmp[0] = offFile[0]; + tmp[1] = offFile[1]; + tmp[2] = '/'; + tmp[3] = offFile[2]; + tmp[4] = offFile[3]; + tmp[5] = 0; + + // [offFile.slice(0,2) + '/' + offFile.slice(2,4) + '/' + offFile, offFile.slice(0,2) + '/' + offFile.slice(2,4)] + r = malloc(3 * sizeof(int *)); + r[2] = NULL; + r[0] = malloc(strlen(tmp) + strlen(offFile) + 1 + 1); + sprintf(r[0], "%s/%s", tmp, offFile); + r[1] = strdup(tmp); + return(r); +} + + + +////// +// core +////// + +// transport functions + +void send(char *src) { + + // to be initialized by setTransport + printf("SEND %s", src); + printf("\n"); +} + +void receive(char *src) { + + // to be initialized by setTransport + printf("RECEIVE %s", src); + printf("\n"); +} + +void transport_transformFrom(char *file) { + // transform file in objectPath to objectPath/../tmp/file + // create directories in tmp + char *offFile = NULL; + char **offFilePath = NULL; + char *tmp = NULL; + DIR *d = NULL; + char *cmd = NULL; + char *cmd2 = NULL; + char *p1 = NULL; + char *p2 = NULL; + + offFile = strdup(basename(file)); + offFilePath = offHelpers_getOffFilePath(offFile); + + tmp = malloc(strlen(offHelpers_objectPath()) + strlen(offFilePath[1]) + 1 + 8); + sprintf(tmp, "%s/../tmp/%s", offHelpers_objectPath(), offFilePath[1]); + d = opendir(tmp); + if (d == NULL) { + // create the file directory + mkdirParents(tmp); + } + free(tmp); + + cmd = strdup(offHelpers_transformFrom()); + + p1 = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); + sprintf(p1, "%s/%s", offHelpers_objectPath(), file); + // find _1 index in cmd + tmp = strstr(cmd, " _1"); + if (tmp != NULL) { + tmp[1] = 0; + } + cmd2 = malloc(strlen(cmd) + strlen(p1) + strlen(tmp+3) + 1 + 0); + sprintf(cmd2, "%s%s%s", cmd, p1, tmp+3); + free(p1); + free(cmd); + + p2 = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 8); + sprintf(p2, "%s/../tmp/%s", offHelpers_objectPath(), file); + // find _2 and replace + tmp = strstr(cmd2, " _2"); + if (tmp != NULL) { + tmp[1] = 0; + } + cmd = malloc(strlen(cmd2) + strlen(p2) + strlen(tmp+3) + 1 + 0); + sprintf(cmd, "%s%s%s", cmd2, p2, tmp+3); + free(p2); + //print cmd + freeList((void **)offFilePath); + offFilePath = execOut(cmd); + freeList((void **)offFilePath); + free(offFile); + free(cmd); +} + + + + + + + + + +void thisrepo(cmdSetF_t cmd) { + + if ((argc > 2) && (strcmp(argv[2], "thisrepo") == 0)) { + cmd(gitConfig_setThisRepo); + return; + } + cmd(gitConfig_set); +} + + + +enum { installH, modeH, storeH, scpH, httpH, curlH, integrityH, pemH, sshoptionsH, scpoptionsH, scpuserH, trackH, configAlwaysH, s3regionH, s3bucketH, transformH, transformToH, transformFromH, cleanH, prepushH, smudgeH, copyToH, clearAllH, caH, clearCacheH, ccH, clearStoreH, csH, defaultsH, envH, helpH, lastH }; +char* COMMAND_HELP[32] = { "git off install [thisrepo]\n setup git config (default global)\n thisrepo sets up config in current repo", "git off mode [thisrepo] [copy|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 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|scp|s3]\n copy cache to store for specified 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 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" }; + +enum { installC, modeC, storeC, scpC, httpC, curlC, integrityC, pemC, sshoptionsC, scpoptionsC, scpuserC, trackC, configAlwaysC, s3regionC, s3bucketC, transformC, transformToC, transformFromC, cleanC, prepushC, smudgeC, copyToC, clearAllC, caC, clearCacheC, ccC, clearStoreC, csC, defaultsC, envC, helpC, lastC }; +char* COMMAND_MAP[32] = { "install", "mode", "store", "scp", "http", "curl", "integrity", "pem", "sshoptions", "scpoptions", "scpuser", "track", "configAlways", "s3region", "s3bucket", "transform", "transformTo", "transformFrom", "clean", "pre-push", "smudge", "copyTo", "clearAll", "ca", "clearCache", "cc", "clearStore", "cs", "defaults", "env", "help", "not a command" }; + +enum { installG, modeG, storeG, scpG, httpG, curlG, integrityG, pemG, sshoptionsG, scpoptionsG, scpuserG, trackG, configAlwaysG, s3regionG, s3bucketG, transformG, transformToG, transformFromG, cleanG, prepushG, smudgeG, copyToG, clearAllG, caG, clearCacheG, ccG, clearStoreG, csG, defaultsG, envG, helpG, lastG }; +char* COMMAND_GITCONFIG[32] = { "empty", "off.mode", "off.store", "off.scp", "off.http", "off.curloptions", "off.integrity", "off.pem", "off.sshoptions", "off.scpoptions", "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", "not a command" }; + +// functions called for commands +typedef void (*cmdF_t)(); + +// lastC is the index of last element +cmdF_t COMMAND_FUNC[lastC + 1 ]; + +// helpers called for commands that read a git config +typedef char *(*cmdH_t)(); +cmdH_t COMMAND_HELPERS[lastC + 1 ]; + +int findCommand(char *p) { + int i; + + for (i=0; i < lastC ;i++) { + if (strcmp(p, COMMAND_MAP[i]) == 0) { + break; + } + } + if (i == lastC) { + i = -1; + } + return(i); +} + +void showAllCommandsHelp() { + int i; + + for (i=0; i < lastH ;i++) { + printf("%s\n", COMMAND_HELP[i]); +} + } + + + + +// command line functions +// localSetup: setup current git +// install: setup git config (default global) +// mode: set/show git off mode +// scp: setup scp config +// scpuser: setup scp username config +// track: setup gitattribute filters +// clean: replace files handled by git off with reference +// prepush: read stdin and calls push +// push: copy objects to off.store +// smudge: copy objects from off.store for files handled by git off +// clearAll: delete store, cache in current git and log +// clearCache: delete cache in current git +// clearStore: delete store +// defaults: show first time config (offDEFAULTS) +// env: show config +void offCommands_localSetup() { + // setup current git + // create off directories in current .git + // install pre-push hooks + char *hook = NULL; + + mkdirParents(offHelpers_objectPath()); + + hook = malloc(strlen(offHelpers_gitRepoRoot()) + 1 + 20); + sprintf(hook, "%s/.git/hooks/pre-push", offHelpers_gitRepoRoot()); + if (access(hook, F_OK) == -1) { + FILE *f; + f = fopen(hook, "w"); + fprintf(f, "%s\n", offDEFAULTS[prePushD]); + fclose(f); + chmod(hook, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + } + // error disabled because localSetup is run many times (called from clean and smudge) + // else + // console.error hook.red.bold + ' already exists. Skipping pre-push hook setup.'.red.bold + // process.exit(1) + free(hook); +} + +void offCommands_install(gConfig_set_t setF ) { + + // setup git config + // create off.store + + offCommands_localSetup(); + + // setup config only if not already set + if ((gitConfig_get("filter.off.clean") == NULL) || (setF != gitConfig_set)) { + if (setF == gitConfig_setThisRepo) { + gitConfig_setLocal("filter.off.clean","git off clean %f"); + } + else { + setF("filter.off.clean","git off clean %f"); + } + } + if ((gitConfig_get("filter.off.smudge") == NULL) || (setF != gitConfig_set)) { + if (setF == gitConfig_setThisRepo) { + gitConfig_setLocal("filter.off.smudge","git off smudge %f"); + } + else { + setF("filter.off.smudge","git off smudge %f"); + } + } + if ((offHelpers_log() == NULL) || (setF != gitConfig_set)) { + // log always in global config + gitConfig_set("off.log",offDEFAULTS[logD]); + } + + if ((offHelpers_offMode() == NULL) || (setF != gitConfig_set)) { + setF("off.mode", offDEFAULTS[modeD]); + } + if ((offHelpers_offIntegrity() == NULL) || (setF != gitConfig_set)) { + setF("off.integrity", offDEFAULTS[integrityD]); + } + if ((offHelpers_offPem() == NULL) || (setF != gitConfig_set)) { + setF("off.pem", offDEFAULTS[pemD]); + } + if ((offHelpers_offScp() == NULL) || (setF != gitConfig_set)) { + setF("off.scphost", offDEFAULTS[scpHostD]); + } + if ((offHelpers_offScpUser() == NULL) || (setF != gitConfig_set)) { + setF("off.scpuser", offDEFAULTS[scpUserD]); + } + if ((offHelpers_offSshOptions() == NULL) || (setF != gitConfig_set)) { + setF("off.sshoptions", offDEFAULTS[sshOptionsD]); + } + if ((offHelpers_offScpOptions() == NULL) || (setF != gitConfig_set)) { + setF("off.scpoptions", offDEFAULTS[scpOptionsD]); + } + if ((offHelpers_offStore() == NULL) || (setF != gitConfig_set)) { + setF("off.store", offDEFAULTS[storeD]); + } + if ((offHelpers_offHttp() == NULL) || (setF != gitConfig_set)) { + setF("off.http", offDEFAULTS[httpD]); + } + if ((offHelpers_offCurlOptions() == NULL) || (setF != gitConfig_set)) { + setF("off.curloptions", offDEFAULTS[curlOptionsD]); + } + if ((offHelpers_offConfigAlways() == NULL) || (setF != gitConfig_set)) { + setF("off.configAlways", offDEFAULTS[configAlwaysD]); + } + if ((offHelpers_s3Region() == NULL) || (setF != gitConfig_set)) { + setF("off.s3Region", offDEFAULTS[s3RegionD]); + } + if ((offHelpers_s3Bucket() == NULL) || (setF != gitConfig_set)) { + setF("off.s3Bucket", offDEFAULTS[s3BucketD]); + } + if ((offHelpers_transform() == NULL) || (setF != gitConfig_set)) { + setF("off.transform", offDEFAULTS[transformD]); + } + if ((offHelpers_transformTo() == NULL) || (setF != gitConfig_set)) { + setF("off.transformTo", offDEFAULTS[transformToD]); + } + if ((offHelpers_transformFrom() == NULL) || (setF != gitConfig_set)) { + setF("off.transformFrom", offDEFAULTS[transformFromD]); + } + + // create off.store + + if (strcmp(runtimeConfig[offMode], "copy") == 0) { + mkdirParents(runtimeConfig[offStore]); + } + + if (strcmp(runtimeConfig[offMode], "scp") == 0) { + offHelpers_mkdirStore(""); +} + } + +void offCommands_track() { + FILE* f = NULL; + + // setup gitattribute filters in current folder + // list current git off attributes when there is no parameter + if (argc > 2) { + char *fileName; + char *line; + offCommands_install_setF(); + fileName = malloc(strlen(offHelpers_gitRepoRoot()) + 1 + 15); + sprintf(fileName, "%s/.gitattributes", offHelpers_gitRepoRoot()); + f = fopen(fileName, "a"); + free(fileName); + line = malloc(strlen(argv[2]) + 1 + 17); + sprintf(line, "%s filter=off -text", argv[2]); + fprintf(f, "%s\n", line); + free(line); + fclose(f); + } + else { + // list current git off attributes + char *cmd; + char **list; + int i; + + cmd = malloc(strlen(externalHelpers[listAttr]) + strlen(offHelpers_gitRepoRoot()) + 1 + 20); + sprintf(cmd, "%s `cd %s; git ls-files`", externalHelpers[listAttr], offHelpers_gitRepoRoot()); + list = execOut(cmd); + free(cmd); + + // gff/b.bin: filter: off + if (list != NULL) { + i = 0; + while (list[i] != NULL) { + // find string + if (strstr(list[i], ": filter: off") != NULL) { + printf("%s\n", list[i]); + } + i++; + } + } + freeList((void **)list); +} + } + +void offCommands_configAlways() { + + if (strcmp(argv[argc-1], "configAlways") != 0) { + gitConfig_set(COMMAND_GITCONFIG[configAlwaysC], argv[argc-1]); + } + else { + printf("%s %s", COMMAND_GITCONFIG[configAlwaysC], COMMAND_HELPERS[configAlwaysC]); + printf("\n"); +} + } + +void offCommands_setGetGitConfig(gConfig_set_t setF) { + int i; + + i = findCommand(argv[1]); + if ((argc > 2) && (strcmp(argv[argc-1], "thisrepo") != 0)) { + setF(COMMAND_GITCONFIG[i], argv[argc-1]); + } + else { + printf("%s %s", COMMAND_GITCONFIG[i], COMMAND_HELPERS[i]()); + printf("\n"); +} + } + +void offCommands_clean() { + char *file = NULL; + uint64_t size; + char **offFilePath = NULL; + char *offFile = NULL; + char *fileDir = NULL; + char *filePath = NULL; + DIR *d = NULL; + char b[1024]; + FILE *f = NULL; + int sR; + + // replace files handled by git off with reference + // stdin is data from the working directory file + // + // create local setup in case the repo is freshly cloned + // create file information (size, sha = git off filename) + // copy stdin to git off cache in current git + // transform input file + // print git off ref to stdout for git + + // create local setup in case the repo is freshly cloned + offCommands_localSetup(); + + // create file information (size, sha) + file = argv[2]; + //print file + struct stat st; + stat(file, &st); + size = st.st_size; + offFile = exec(sha, file); + offFilePath = offHelpers_getOffFilePath(offFile); + + fileDir = malloc(strlen(offHelpers_objectPath()) + strlen(offFilePath[1]) + 1 + 1); + sprintf(fileDir, "%s/%s", offHelpers_objectPath(), offFilePath[1]); + d = opendir(fileDir); + if (d == NULL) { + // create the file directory + mkdirParents(fileDir); + } + + // copy stdin to git off cache in current git + // clean runs during git add and git commit, do work only once + filePath = malloc(strlen(offHelpers_objectPath()) + strlen(offFilePath[0]) + 1 + 1); + sprintf(filePath, "%s/%s", offHelpers_objectPath(), offFilePath[0]); + if (access(filePath, F_OK) == -1) { + // stream stdin to sha in git off cache + f = fopen(filePath, "w"); + + sR = fread(b, 1, 1024, stdin); + while (sR != 0) { + fwrite(b, 1, sR, f); + sR = fread(b, 1, 1024, stdin); + } + fclose(f); + + // all objects in cache are read-only + chmod(filePath, S_IRUSR | S_IRGRP | S_IROTH); + + // transform input file + if ((strcmp(offHelpers_transform(), "enable") == 0) && (offHelpers_transformTo() != NULL)) { + char *tmpDir; + tmpDir = malloc(strlen(offHelpers_objectPath()) + strlen(offFilePath[1]) + 1 + 8); + sprintf(tmpDir, "%s/../tmp/%s", offHelpers_objectPath(), offFilePath[1]); + d = opendir(tmpDir); + if (d == NULL) { + // create the file directory + mkdirParents(tmpDir); + } + + // original file is moved to tmp + // transformed file is stored in objectPath under the same name + char *p; + p = malloc(strlen(filePath) + strlen(offHelpers_objectPath()) + strlen(offFilePath[0]) + 1 + 9); + sprintf(p, "%s %s/../tmp/%s", filePath, offHelpers_objectPath(), offFilePath[0]); + exec(mv, p); + free(p); + + char *cmd; + char *cmd2; + char *p1; + char *tmp; + + cmd = strdup(offHelpers_transformTo()); + + p1 = malloc(strlen(offHelpers_objectPath()) + strlen(offFilePath[0]) + 1 + 8); + sprintf(p1, "%s/../tmp/%s", offHelpers_objectPath(), offFilePath[0]); + // find _1 index in cmd + tmp = strstr(cmd, " _1"); + if (tmp != NULL) { + tmp[1] = 0; + } + cmd2 = malloc(strlen(cmd) + strlen(p1) + strlen(tmp+3) + 1 + 0); + sprintf(cmd2, "%s%s%s", cmd, p1, tmp+3); + free(p1); + free(cmd); + + // find _2 and replace + tmp = strstr(cmd2, " _2"); + if (tmp != NULL) { + tmp[1] = 0; + } + cmd = malloc(strlen(cmd2) + strlen(filePath) + strlen(tmp+3) + 1 + 0); + sprintf(cmd, "%s%s%s", cmd2, filePath, tmp+3); + freeList((void **)offFilePath); + offFilePath = execOut(cmd); + free(cmd); + free(tmpDir); + } + } + else { + // file already exists, discard data + f = fopen("/dev/null", "w"); + + sR = fread(b, 1, 1024, stdin); + while (sR != 0) { + fwrite(b, 1, sR, f); + sR = fread(b, 1, 1024, stdin); + } + fclose(f); + } + + free(fileDir); + free(filePath); + + // print git off ref to stdout for git + // ### git-off v1 sha:be3e02b60effe3eab232d5590a6a2e2c2c2f443b size:119 + char sst[20]; + sprintf(sst,"%d", size); + char *tmp; + tmp = malloc(strlen(offDEFAULTS[offSignatureD]) + strlen(offFile) + strlen(sst) + 1 + 6); + sprintf(tmp, "%s%s size:%s", offDEFAULTS[offSignatureD], offFile, sst); + printf("%s\n", tmp); + free(tmp); + freeList((void **)offFilePath); + free(offFile); + sR = 0; +} + +void offCommands_prepush() { + size_t len; + char* line = NULL; + ssize_t read; + char **list = NULL; + int count = 0;; + + // add offCommands_push function + // read stdin and calls push + // stdin (data from git) is a line with remoteName url localRef localSha remoteRef remoteSha + + offHelpers_setTransport_mode(); + + read = getline(&line, &len, stdin); + while (read != -1) { + { + char* pos = NULL; + pos = strchr(line, '\n'); + if (pos != NULL) + *pos = '\0'; + } + if (list == NULL) { + list = malloc(2 * sizeof(int *)); + list[1] = NULL; + } + else { + list = realloc(list, (count+2) * sizeof(int *)); + list[count+1] = NULL; + } + list[count] = strdup(line); + read = getline(&line, &len, stdin); + count++; + } + + count = 0; + while (list[count] != NULL) { + offCommands_push(list[count]); + count++; + } + free(line); + freeList((void **)list); + count = 0; +} + +void offCommands_push(char *line) { + // copy objects to off.store + // + // set remoteName url localRef localSha remoteRef remoteSha + // list missing commits in remote + // list changed objects in missing commits + // check header with git cat + // copy git off objects to off.store + char *remoteName = NULL; + char *url = NULL; + char *localRef = NULL; + char *localSha = NULL; + char *remoteRef = NULL; + char *remoteSha = NULL; + char **line_l = NULL; + char **commitListToPush = NULL; + char *cmd = NULL; + int i; + + // set remoteName url localRef localSha remoteRef remoteSha + remoteName = argv[argc-2]; + url = argv[argc-1]; + + line_l = split(line, " "); + localRef = line_l[0]; + localSha = line_l[1]; + remoteRef = line_l[2]; + remoteSha = line_l[3]; + + // list missing commits in remote + cmd = malloc(strlen(externalHelpers[gitList]) + strlen(localSha) + strlen(remoteSha) + 1 + 3); + sprintf(cmd, "%s %s ^%s", externalHelpers[gitList], localSha, remoteSha); + commitListToPush = execOut(cmd); + free(cmd); + + // list changed objects in missing commits + int commitListIndex = 0; + while (commitListToPush[commitListIndex] != NULL) { + + // list changes for commit sha + char **objInfoList; + cmd = malloc(strlen(externalHelpers[gitDff]) + strlen(commitListToPush[commitListIndex]) + 1 + 1); + sprintf(cmd, "%s %s", externalHelpers[gitDff], commitListToPush[commitListIndex]); + objInfoList = execOut(cmd); + free(cmd); + // :000000 100644 0000000000000000000000000000000000000000 23636079ef005f53e81066aaf092521d8f2346df A dsd + // TODO filter according to .gitattributes, check files in filter only + + int oi = 0; + while (objInfoList[oi] != NULL) { + char **objInfo; + objInfo = split(objInfoList[oi], " "); + + // only lines starting with : (the first line from git diff-tree is the sha) + // dont consider deleted files + if ((objInfoList[oi][0] == ':') && (objInfo[oiNAME][0] != 'D')) { + + // check header with git cat + + char *offRef; + offRef = exec(gitCat, objInfo[oiOID]); + + if (strstr(offRef, offDEFAULTS[offSignatureD]) != NULL) { + + // copy git off objects to off.store + // found an off reference + // ### git-off v1 sha:be3e02b60effe3eab232d5590a6a2e2c2c2f443b size:119 b.bin + + char **offRefS1; + char **offRefS2; + char *offFile; + char **offFilePath; + offRefS1 = split(offRef, ":"); + offRefS2 = split(offRefS1[1], " "); + offFile = offRefS2[0]; + offFilePath = offHelpers_getOffFilePath(offFile); + + transport.send(offFilePath[0]); + freeList((void **)offFilePath); + freeList((void **)offRefS1); + freeList((void **)offRefS2); + } + free(offRef); + } + freeList((void **)objInfo); + oi++; + } + freeList((void **)objInfoList); + commitListIndex++; + } + + freeList((void **)commitListToPush); + freeList((void **)line_l); + + // test prevent push by issuing an error + //exit(EXIT_FAILURE); +} + +void offCommands_smudge() { + + // copy objects from off.store for files handled by git off + // stdin is the data from the git repo + // + // load header + // for git off object, replace git off reference with data from cache or off.store + // for normal object, copy data from repo to stdout + + offHelpers_setTransport_mode(); + offCommands_localSetup(); + + // load header + char b[1024]; + int sR; + sR = fread(b, 1, strlen(offDEFAULTS[offSignatureD]) + offDEFAULTS_shaLength, stdin); + if (sR == 0) { + // error no data + offLogRepo("smudge error: cant get data from stdin."); + exit(EXIT_FAILURE); + } + + if (strncmp(b, offDEFAULTS[offSignatureD], strlen(offDEFAULTS[offSignatureD])) == 0) { + // for git off object, replace git off reference with data from cache or off.store + + b[strlen(offDEFAULTS[offSignatureD]) + offDEFAULTS_shaLength] = 0; + char **header_l; + char *offFile; + char **offFilePath; + header_l = split(b, ":"); + offFile = header_l[1]; + offFilePath = offHelpers_getOffFilePath(offFile); + + // detect if file is already in cache + char *filePath; + filePath = malloc(strlen(offHelpers_objectPath()) + strlen(offFilePath[0]) + 1 + 1); + sprintf(filePath, "%s/%s", offHelpers_objectPath(), offFilePath[0]); + if (access(filePath, F_OK) != -1) { + // copy from cache + FILE *fCache; + if ((strcmp(offHelpers_transform(), "enable") == 0) && (offHelpers_transformFrom() != NULL)) { + // transform file + + transport_transformFrom(offFilePath[0]); + + char *p; + p = malloc(strlen(offHelpers_objectPath()) + strlen(offFilePath[0]) + 1 + 8); + sprintf(p, "%s/../tmp/%s", offHelpers_objectPath(), offFilePath[0]); + + fCache = fopen(p, "r"); + + free(p); + } + else { + fCache = fopen(filePath, "r"); + } + + sR = fread(b, 1, 1024, fCache); + while (sR != 0) { + fwrite(b, 1, sR, stdout); + sR = fread(b, 1, 1024, fCache); + } + fclose(fCache); + } + else { + // copy from off.store + transport.receive(offFilePath[0]); + } + + free(filePath); + freeList((void **)header_l); + freeList((void **)offFilePath); + } + else { + // for normal object, copy data from repo to stdout + + //store header + fwrite(b, 1, sR, stdout); + + sR = fread(b, 1, 1024, stdin); + while (sR != 0) { + fwrite(b, 1, sR, stdout); + sR = fread(b, 1, 1024, stdin); + } + } + sR = 0; +} + +void offCommands_copyTo() { + + // copy cache to store for argv[2] mode + if (argc < 3) { + printf("Choose a mode where to copy the cache"); + printf("\n"); + return; + } + + offHelpers_setTransport(argv[2]); + offHelpers_copyTo(); +} + +void offCommands_clearAll() { + + // delete store, cache in current git and log + offCommands_clearStore(); + offCommands_clearCache(); + rmAll(offHelpers_getLog()); +} + +void offCommands_clearCache() { + char *p = NULL; + + // delete cache in current git + p = malloc(strlen(offHelpers_gitRepoRoot()) + 1 + 9); + sprintf(p, "%s/.git/off", offHelpers_gitRepoRoot()); + rmAll(p); + free(p); +} + +void offCommands_clearStore() { + + // delete store + if (strcmp(offHelpers_offMode(), "copy") == 0) { + rmAll(offHelpers_offStore()); + } + if (strcmp(offHelpers_offMode(), "scp") == 0) { + offHelpers_rmAllStore(""); +} + } + +void offCommands_defaults() { + int i; + + // TODO add default key strings + // show first time config (offDEFAULTS) + for (i=0; i < lastD ; i++) { + printf("%s\n", offDEFAULTS[i]); +} + } + +void offCommands_env() { + + printf("off.mode %s", offHelpers_offMode()); + printf("\n"); + printf("off.integrity %s", offHelpers_offIntegrity()); + printf("\n"); + printf("off.pem %s", offHelpers_offPem()); + printf("\n"); + printf("off.sshoptions %s", offHelpers_offSshOptions()); + printf("\n"); + printf("off.scpoptions %s", offHelpers_offScpOptions()); + printf("\n"); + printf("off.store %s", offHelpers_offStore()); + printf("\n"); + printf("off.http %s", offHelpers_offHttp()); + printf("\n"); + printf("off.curloptions %s", offHelpers_offCurlOptions()); + printf("\n"); + printf("off.scphost %s", offHelpers_offScp()); + printf("\n"); + printf("off.scpuser %s", offHelpers_offScpUser()); + printf("\n"); + printf("off.log %s", offHelpers_getLog()); + printf("\n"); + printf("off.configAlways %s", offHelpers_offConfigAlways()); + printf("\n"); + printf("off.s3region %s", offHelpers_s3Region()); + printf("\n"); + printf("off.s3bucket %s", offHelpers_s3Bucket()); + printf("\n"); + printf("off.transform %s", offHelpers_transform()); + printf("\n"); + printf("off.transformTo %s", offHelpers_transformTo()); + printf("\n"); + printf("off.transformFrom %s", offHelpers_transformFrom()); + printf("\n"); +} + +void offCommands_help() { + + printf("git-off help\n"); + printf("\n"); + if (argc < 3) { + printf("# Quick Start"); + printf("\n"); + printf("Setup:"); + printf("\n"); + printf("git off track '*.bin'"); + printf("\n"); + printf("git add ."); + printf("\n"); + printf("git commit"); + printf("\n"); + printf("git push"); + printf("\n"); + printf("git checkout master"); + printf("\n"); + printf("\n# Other"); + printf("\n"); + printf("git off install"); + printf("\n"); + printf("git off mode scp"); + printf("\n"); + printf("git off scp localhost:/tmp/offStore"); + printf("\n"); + printf("git off scpuser username"); + printf("\n"); + printf("git off cc"); + printf("\n"); + printf("git off ca"); + printf("\n"); + printf("git off env"); + printf("\n"); + printf("git off defaults\n"); + printf("\n"); + + showAllCommandsHelp(); + + printf("More information at"); + printf("\n"); + } + else { + int cmd; + cmd = findCommand(argv[2]); + if (cmd == -1) { + // show help for help + printf("git-off command \"%s\" not found.\n", argv[2]); + printf("\n"); + printf("%s\n", COMMAND_HELP[helpC]); + } + else { + printf("%s\n", COMMAND_HELP[cmd]); +} + } + } + +// -------------------------------------------------------------------------------------------- +void installF() { + + thisrepo(offCommands_install); +} + +void modeF() { + + thisrepo(offCommands_setGetGitConfig); +} + +void storeF() { + + thisrepo(offCommands_setGetGitConfig); +} + +void scpF() { + + thisrepo(offCommands_setGetGitConfig); +} + +void httpF() { + + thisrepo(offCommands_setGetGitConfig); +} + +void curlF() { + + thisrepo(offCommands_setGetGitConfig); +} + +void integrityF() { + + thisrepo(offCommands_setGetGitConfig); +} + +void pemF() { + + thisrepo(offCommands_setGetGitConfig); +} + +void sshoptionsF() { + + thisrepo(offCommands_setGetGitConfig); +} + +void scpoptionsF() { + + thisrepo(offCommands_setGetGitConfig); +} + +void scpuserF() { + + thisrepo(offCommands_setGetGitConfig); +} + +void trackF() { + + offCommands_track(); +} + +void configAlwaysF() { + + offCommands_configAlways(); +} + +void s3regionF() { + + thisrepo(offCommands_setGetGitConfig); +} + +void s3bucketF() { + + thisrepo(offCommands_setGetGitConfig); +} + +void transformF() { + + thisrepo(offCommands_setGetGitConfig); +} + +void transformToF() { + + thisrepo(offCommands_setGetGitConfig); +} + +void transformFromF() { + + thisrepo(offCommands_setGetGitConfig); +} + +void cleanF() { + + offCommands_clean(); +} + +void prepushF() { + + offCommands_prepush(); +} + +void smudgeF() { + + offCommands_smudge(); +} + +void copyToF() { + + offCommands_copyTo(); +} + +void clearAllF() { + + offCommands_clearAll(); +} + +void caF() { + + offCommands_clearAll(); +} + +void clearCacheF() { + + offCommands_clearCache(); +} + +void ccF() { + + offCommands_clearCache(); +} + +void clearStoreF() { + + offCommands_clearStore(); +} + +void csF() { + + offCommands_clearStore(); +} + +void defaultsF() { + + offCommands_defaults(); +} + +void envF() { + + offCommands_env(); +} + +void helpF() { + + offCommands_help(); +} + +// Initialize commands +void initCOMMAND_FUNC() { + + COMMAND_FUNC[0] = installF; + COMMAND_FUNC[1] = modeF; + COMMAND_FUNC[2] = storeF; + COMMAND_FUNC[3] = scpF; + COMMAND_FUNC[4] = httpF; + COMMAND_FUNC[5] = curlF; + COMMAND_FUNC[6] = integrityF; + COMMAND_FUNC[7] = pemF; + COMMAND_FUNC[8] = sshoptionsF; + COMMAND_FUNC[9] = scpoptionsF; + COMMAND_FUNC[10] = scpuserF; + COMMAND_FUNC[11] = trackF; + COMMAND_FUNC[12] = configAlwaysF; + COMMAND_FUNC[13] = s3regionF; + COMMAND_FUNC[14] = s3bucketF; + COMMAND_FUNC[15] = transformF; + COMMAND_FUNC[16] = transformToF; + COMMAND_FUNC[17] = transformFromF; + COMMAND_FUNC[18] = cleanF; + COMMAND_FUNC[19] = prepushF; + COMMAND_FUNC[20] = smudgeF; + COMMAND_FUNC[21] = copyToF; + COMMAND_FUNC[22] = clearAllF; + COMMAND_FUNC[23] = caF; + COMMAND_FUNC[24] = clearCacheF; + COMMAND_FUNC[25] = ccF; + COMMAND_FUNC[26] = clearStoreF; + COMMAND_FUNC[27] = csF; + COMMAND_FUNC[28] = defaultsF; + COMMAND_FUNC[29] = envF; + COMMAND_FUNC[30] = helpF; + COMMAND_FUNC[lastC] = NULL; + + COMMAND_HELPERS[0] = NULL; + COMMAND_HELPERS[1] = offHelpers_offMode; + COMMAND_HELPERS[2] = offHelpers_offStore; + COMMAND_HELPERS[3] = offHelpers_offScp; + COMMAND_HELPERS[4] = offHelpers_offHttp; + COMMAND_HELPERS[5] = offHelpers_offCurlOptions; + COMMAND_HELPERS[6] = offHelpers_offIntegrity; + COMMAND_HELPERS[7] = offHelpers_offPem; + COMMAND_HELPERS[8] = offHelpers_offSshOptions; + COMMAND_HELPERS[9] = offHelpers_offScpOptions; + COMMAND_HELPERS[10] = offHelpers_offScpUser; + COMMAND_HELPERS[11] = NULL; + COMMAND_HELPERS[12] = offHelpers_offConfigAlways; + COMMAND_HELPERS[13] = offHelpers_s3Region; + COMMAND_HELPERS[14] = offHelpers_s3Bucket; + COMMAND_HELPERS[15] = offHelpers_transform; + COMMAND_HELPERS[16] = offHelpers_transformTo; + COMMAND_HELPERS[17] = offHelpers_transformFrom; + COMMAND_HELPERS[18] = NULL; + COMMAND_HELPERS[19] = NULL; + COMMAND_HELPERS[20] = NULL; + COMMAND_HELPERS[21] = NULL; + COMMAND_HELPERS[22] = NULL; + COMMAND_HELPERS[23] = NULL; + COMMAND_HELPERS[24] = NULL; + COMMAND_HELPERS[25] = NULL; + COMMAND_HELPERS[26] = NULL; + COMMAND_HELPERS[27] = NULL; + COMMAND_HELPERS[28] = NULL; + COMMAND_HELPERS[29] = NULL; + COMMAND_HELPERS[30] = NULL; + COMMAND_HELPERS[lastC] = NULL; +} + +int main(int ARGC, char** ARGV) { + int dummy; + char **test = NULL; + // TODO remove dummy + + argc = ARGC; argv = ARGV; + // init transport functions + transport.send = send; + transport.receive = receive; + initCOMMAND_FUNC(); + + // parse CLI arguments + + // TODO remove argv prints + //dummy = 0 + //while dummy < argc + // print argv[dummy] + // dummy++; + + + // TODO remove offHelpers_getOffFilePath test + //transport_transformFrom("12/34/1234WERWER"); + //test = offHelpers_getOffFilePath("1234WERWER") + //dummy = 0 + //while test[dummy] != NULL + // print test[dummy] + // dummy++; + + if (argc == 1) { + offCommands_help(); + } + else { + // call argv[1] command + int i; + i = findCommand(argv[1]); + if (i == -1) { + offCommands_help(); + } + else { + COMMAND_FUNC[i](); +} + } + } diff --git a/package.json b/package.json @@ -1,6 +1,6 @@ { "name": "git-off", - "version": "0.0.10", + "version": "0.0.11", "description": "large file handler for git", "bin": "./src/git-off", "scripts": {