Open3

Git-LFSのファイルをローカルから拾ってくるtransfer agentの試作

okuokuokuoku

...標準でできても良くない。。?

Git-LFSにはcustom transfer agent https://github.com/git-lfs/git-lfs/blob/main/docs/custom-transfers.md の仕組みがあり、Jsonlでやりとりするタイプのエージェントを実装することで特定のAPI serverをインターセプトする形で動作できる。

単純にローカルに置くだけで良ければ、 lfs-foldershare がある。ただし、これはファイルのパスフォーマットをこちらから指定することができない。

https://github.com/sinbad/lfs-folderstore

prev

https://zenn.dev/okuoku/scraps/43e6dda6e75752

okuokuokuoku

単純にcloneして失敗させてみる

$ git clone ~/repos/photos.git
Cloning into 'photos'...
done.
Updating files: 100% (2222/2222), done.
Downloading sync/DCIM/Camera/PXL_20221231_213514986.jpg (2.9 MB)
Error downloading object: sync/DCIM/Camera/PXL_20221231_213514986.jpg (85e1b3d):
 Smudge error: Error downloading sync/DCIM/Camera/PXL_20221231_213514986.jpg (85
e1b3d01ca1b4eb7bb6aa665a7bda6ea148e350225258998952a29e2863271a): batch request:
missing protocol: "/home/oku/repos/photos.git/info/lfs"

Errors logged to F:\lfswork\photos\.git\lfs\objects\logs\20230326T170959.3959247
.log
Use `git lfs logs last` to view the log.
error: external filter 'git-lfs filter-process' failed
error: git-lfs filter-process died of signal 15
fatal: sync/DCIM/Camera/PXL_20221231_213514986.jpg: smudge filter lfs failed
warning: Clone succeeded, but checkout failed.
You can inspect what was checked out with 'git status'
and retry with 'git restore --source=HEAD :/'

この写真は実際には //drobo/gitlfs/85/e1/b3d01ca1b4eb7bb6aa665a7bda6ea148e350225258998952a29e2863271a にある。

$ sha256sum //drobo/gitlfs/lfs/85/e1/b3d01ca1b4eb7bb6aa665a7bda6ea148e350225258998952a29e2863271a
85e1b3d01ca1b4eb7bb6aa665a7bda6ea148e350225258998952a29e2863271a *//drobo/gitlfs/lfs/85/e1/b3d01ca1b4eb7bb6aa665a7bda6ea148e350225258998952a29e2863271a

custom transfer agentはoid (= SHA256)を受けとってパスを変換、内容をファイルにコピーすることになる。

okuokuokuoku

とりあえずエラーにする

@node %~dp0lfslocal.mjs
@exit /b %ERRORLEVEL%
import * as readline from "node:readline";
import {stdin, stdout} from "node:process";
import fs from "node:fs";

const rl = readline.createInterface({input: stdin, terminal: false});

function say(obj){
    fs.writeSync(1, JSON.stringify(obj) + "\n");
}

rl.on("line", (l) => {
    let obj = JSON.parse(l);
    if(obj.event == "init"){
        // Ack
        say({});
    }else if(obj.event == "terminate"){
        // Do nothing, wait for termination
    }else if(obj.event == "upload"){
        say({ "event": "complete", "oid":obj.oid, "error": {"code":1, "message": "Upload is not supported"}});
    }else if(obj.event == "download"){
        say({ "event": "complete", "oid":obj.oid, "error": {"code":1, "message": JSON.stringify(obj)}});
    }
});

WindowsにはShebangとか無いんで。。

$ git config --add lfs.customtransfer.lfslocal.path c:/cygwin64/home/oku/repos/lfslocal/lfslocal.cmd
$ git config --add lfs.customtransfer.lfslocal.concurrent false

のようにパスを設定して git reset --hard すると、

$ git reset --hard
Updating files: 100% (2222/2222), done.
Downloading sync/DCIM/Camera/PXL_20221231_213514986.jpg (2.9 MB)
Error downloading object: sync/DCIM/Camera/PXL_20221231_213514986.jpg (85e1b3d):
 Smudge error: Error downloading sync/DCIM/Camera/PXL_20221231_213514986.jpg (85
e1b3d01ca1b4eb7bb6aa665a7bda6ea148e350225258998952a29e2863271a): Error transferr
ing "85e1b3d01ca1b4eb7bb6aa665a7bda6ea148e350225258998952a29e2863271a": [1] {"ev
ent":"download","oid":"85e1b3d01ca1b4eb7bb6aa665a7bda6ea148e350225258998952a29e2
863271a","size":2877852,"action":null}

Errors logged to F:\lfswork\photos\.git\lfs\objects\logs\20230326T212739.9270121
.log
Use `git lfs logs last` to view the log.
error: external filter 'git-lfs filter-process' failed
error: git-lfs filter-process died of signal 15
fatal: sync/DCIM/Camera/PXL_20221231_213514986.jpg: smudge filter lfs failed

のようになる。何故か stderr がリダイレクトされてこなくてデバッグが超面倒。。

あとは適当にテンポラリディレクトリのパスを受けとり、downloadリクエストを実装すればOKなはず。

テンポラリディレクトリのパスは args でコマンドラインから受けとるしか無さそうだ。。じゃぁgitのrootを渡してもらってgit configから追加で入手するのが簡単かな。。

転送は適当なディレクトリにコピーして終わり。今回の場合はマウントされたファイルシステムのパスに変換して返却するだけ ...だと消されちゃうからコピーが必要なはず。