git-off

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

commit b126e1dcbf5895404a894d63565d775583ef932d
parent 5c6b2943d020fdae0b33748b2e5a910d6db90e8a
Author: Remy Noulin (Spartatek) <remy.noulin@spartatek.se>
Date:   Mon, 21 Nov 2016 17:06:31 +0100

save files in multiple directories in cache and store

src/gitoff.coffee | 73 ++++++++++++++++++++++++++++++++++++++++---------------
1 file changed, 54 insertions(+), 19 deletions(-)

Diffstat:
Msrc/gitoff.coffee | 73++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 54 insertions(+), 19 deletions(-)

diff --git a/src/gitoff.coffee b/src/gitoff.coffee @@ -266,16 +266,17 @@ copy = (src, dst) -> return # 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 -# 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 '' -# setTransport: set send and receive functions for transport +# gitRepoRoot: sets and returns runtimeConfig.currentRepoRoot +# objectPath: sets and returns runtimeConfig.objectPath +# offStore: sets and returns runtimeConfig.offStore +# offMode: sets and returns runtimeConfig.offMode +# 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 '' +# setTransport: set send and receive functions for transport +# getOffFilePath: creates path for offFile offHelpers = 'gitRepoRoot': (ignoreStderr=false) -> if runtimeConfig.currentRepoRoot == '' @@ -335,8 +336,15 @@ offHelpers = user 'setTransport': -> + # set send and receive functions for transport + # copy, scp if offHelpers.offMode() == 'copy' transport['send'] = (file) -> + # create file directories in store + f_l = file.split '/' + if fs.existsSync(offHelpers.offStore() + '/' + f_l[0] + '/' + f_l[1]) == false + mkdirParents offHelpers.offStore() + '/' + f_l[0] + '/' + f_l[1] + copy offHelpers.objectPath() + '/' + file, offHelpers.offStore() + '/' + file fs.chmodSync offHelpers.offStore() + '/' + file, '444' return @@ -344,18 +352,37 @@ offHelpers = readStream = fs.createReadStream(offHelpers.offStore() + '/' + file) readStream.pipe(process.stdout) return + else if offHelpers.offMode() == 'scp' transport['send'] = (file) -> user = offHelpers.userAt() + + # create file directories in store + h_l = offHelpers.offScp().split(':') + f_l = file.split '/' + # bug in coffeescript - cant have '"mkdir '+ h_l[1] +'"' + sshCmd = '"mkdir -p '+ h_l[1] + '/' + f_l[0] + '/' + f_l[1] + sshCmd += '"' + # ignore error from mkdir for already existing store + exec 'ssh', [user + h_l[0], sshCmd], true + + exec 'scp', [offHelpers.objectPath() + '/' + file, user + offHelpers.offScp() + '/' + file] return transport['receive'] = (file) -> + # 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] + user = offHelpers.userAt() exec 'scp', [user + offHelpers.offScp() + '/' + file, offHelpers.objectPath() + '/' + file] readStream = fs.createReadStream(offHelpers.objectPath() + '/' + file) readStream.pipe(process.stdout) return return + 'getOffFilePath': (offFile) -> + [offFile.slice(0,2) + '/' + offFile.slice(2,4) + '/' + offFile, offFile.slice(0,2) + '/' + offFile.slice(2,4)] # list offHelpers, run 'git off' #console.log Object.keys(offHelpers) @@ -373,6 +400,7 @@ transport = # to be initialized by setTransport return + # command line functions # localSetup: setup current git # install: setup git config (default global) @@ -509,16 +537,21 @@ offCommands = size = fs.statSync(file).size r = exec 'sha', [file] # trim because git hash-object adds \n - offFile = r.stdout.split(' ')[0].trim() + offFile = r.stdout.split(' ')[0].trim() + offFilePath = offHelpers.getOffFilePath(offFile) + if fs.existsSync(offHelpers.objectPath() + '/' + offFilePath[1]) == false + # create the file directory + mkdirParents offHelpers.objectPath() + '/' + offFilePath[1] + offFilePath = offFilePath[0] # copy stdin to git off cache in current git # clean runs during git add and git commit, do work only once - if fs.existsSync(offHelpers.objectPath() + '/' + offFile) == false + if fs.existsSync(offHelpers.objectPath() + '/' + offFilePath) == false # stream stdin to sha in git off cache - writeStream = fs.createWriteStream(offHelpers.objectPath() + '/' + offFile) + writeStream = fs.createWriteStream(offHelpers.objectPath() + '/' + offFilePath) process.stdin.pipe(writeStream) # all objects in cache are read-only - fs.chmodSync offHelpers.objectPath() + '/' + offFile, '444' + fs.chmodSync offHelpers.objectPath() + '/' + offFilePath, '444' else # file already exists, discard data writeStream = fs.createWriteStream('/dev/null') @@ -600,8 +633,9 @@ offCommands = # ### git-off v1 sha:be3e02b60effe3eab232d5590a6a2e2c2c2f443b size:119 b.bin offFile = offRef.split(':')[1].split(' ')[0] + offFilePath = offHelpers.getOffFilePath(offFile)[0] - transport.send offFile + transport.send offFilePath # test prevent push by issuing an error #process.exit(1) @@ -638,15 +672,16 @@ offCommands = if header.slice(0,offDEFAULTS.offSignature.length) == offDEFAULTS.offSignature # for git off object, replace git off reference with data from cache or off.store - offFile = header.split(':')[1] + offFile = header.split(':')[1] + offFilePath = offHelpers.getOffFilePath(offFile)[0] # detect if file is already in cache - if fs.existsSync(offHelpers.objectPath() + '/' + offFile) == true + if fs.existsSync(offHelpers.objectPath() + '/' + offFilePath) == true # copy from cache - readStream = fs.createReadStream(offHelpers.objectPath() + '/' + offFile) + readStream = fs.createReadStream(offHelpers.objectPath() + '/' + offFilePath) readStream.pipe(process.stdout) else # copy from off.store - transport.receive offFile + transport.receive offFilePath else # for normal object, copy data from repo to stdout