Git / SSH wisi, gdy jest wywoływany z MVC WebApi

Część projektu, nad którym pracuję (Windows, C #, MVC4 WebAPI) wymaga pewnej integracji z git. Żadna z istniejących bibliotek C # git nie obsługiwała zdalnego klonowania, więc zamknąłem portowanie częściJavaGit projekt, którego potrzebowaliśmy (checkout, fetch, status) i sam piszący klon. W rzeczywistości jest to wrapper do wykonywalnego wiersza poleceń git. Odpowiedni kod, który wywołuje, jest tutaj:

public static void RunGitCommand(string repositoryPath, string gitArguments)
{
    // GitCommand is the full path to git.exe (currently using Github for Windows)
    if (null == GitCommand || String.IsNullOrWhiteSpace(GitCommand))
    {
        throw new FileNotFoundException("Unable to find git.exe on your system PATH.");
    }

    // gitArguments contains the command to run (e.g. "clone -- git@repo:projectName c:\repositories\repo_a8c0dd321f")
    var startInfo = new ProcessStartInfo(GitCommand, gitArguments)
    {
        WorkingDirectory = (null != repositoryPath && Directory.Exists(repositoryPath)) ? repositoryPath : String.Empty,
        CreateNoWindow = true,
        UseShellExecute = false,
        RedirectStandardOutput = true,
        RedirectStandardInput = true,
        RedirectStandardError = true
    };

    using (var p = new Process
    {
        EnableRaisingEvents = true,
        StartInfo = startInfo
    })
    {
        p.OutputDataReceived += (sender, args) => Log.Debug(args.Data);

        p.ErrorDataReceived += (sender, args) => Log.Debug(args.Data);

        p.Start();

        p.BeginOutputReadLine();
        p.BeginErrorReadLine();

        p.WaitForExit();
    }
}

Który zostałby nazwany kodem jako:

// names changed to protect the innocent
string localRepo = @"c:\repositories\repo_a8c0dd321f";
string gitArgs = "clone -- git@repo:projectName c:\repositories\repo_a8c0dd321f";

GitConfiguration.RunGitCommand(localRepo, gitArgs);

W interfejsie API MVC używamy personifikacji, aby upewnić się, że działa jako użytkownik z prawidłowym loginem i kluczem git (bez hasła). Powyższe polecenie działa doskonale z linii poleceń jako ja, a także w szybkim teście jednostkowym (wiem, że to naprawdę test integracji).

Jednak gdy jest wywoływany z API, jak pokazano powyżej, zawiesza się. Przeglądanie w Menedżerze zadań pokazuje uruchomiony program git.exe z wierszem poleceń pokazującym pełną ścieżkę do git.exe, a następnie argumenty powyżej. Nie używa żadnego czasu procesora i tylko 2604K pamięci RAM, ale twierdzi, że działa. Podobnie działa proces ssh.exe, również bez użycia procesora, i 1212K pamięci RAM, z linii poleceń:

ssh git@repo "git-upload-pack 'projectName'"

Oba procesy są wymienione jako działające pod moją nazwą użytkownika, więc wygląda na to, że personifikacja działa poprawnie.

Przeglądając katalog localRepo, tworzy katalog .git, a następnie zawiesza się, pozostawiając tam około 13 000 plików git, ale żaden z naszych kodów. Myśląc, że to z powodu ogromnego repo, pozwoliłem mu działać w nocy. Nadal nie ma ruchu od dziś rano.

Wychowany LINQPad, pobiegł:

Process.GetProcessById($gitPID).Dump()

To samo dotyczyło procesu SSH. Wątki pokazały, że są w stanie Wait, a WaitReason był Executive (oczekiwanie na program planujący wątki). Początkowo zakładałem, że czeka na hasło, jak mój klucz miał. Przełączyłem się na klucz roboczy bez hasła, taki sam wynik.

Git/SSH versions (from latest GitHub for Windows):
    git version
        git version 1.7.11.msysgit.1
    ssh -v
        OpenSSH_4.6p1, OpenSSL 0.9.8e 23 Feb 2007

Jedynym pomysłem, jaki mi pozostał, jest to, że może nie może komunikować się z działającym ssh-agentem. Właściwie podszywa się pod mnie, więc nie wiem, dlaczego nie działałby w środowisku WebApi, ale działa dobrze z testu „jednostki” i Git Shell. Próbowałem upewnić się, że zmienne środowiskowe HOME, PLINK_PROTOCOL, TERM, SSH_AUTH_SOCK i SSH_AGENT_PID zostały ustawione po przejrzeniu skryptów instalacyjnych systemu Github, aby upewnić się, że niczego nie brakuje.

Jestem w całkowitej stracie. Oto fragment pliku dziennika z późniejszymi komentarzami:

2012-11-20 13:42:59.5898 Info Initializing repo at path: c:\repositories\repo_a8c0dd321f 
2012-11-20 13:42:59.5898 Debug Working Directory: c:\repositories\repo_a8c0dd321f 
2012-11-20 13:42:59.6053 Debug C:\Users\christian.doggett\AppData\Local\GitHub\PortableGit_8810fd5c2c79c73adcc73fd0825f3b32fdb816e7\bin\git.exe status --branch 
2012-11-20 13:42:59.6209 Debug HOME=H:\ 
2012-11-20 13:42:59.6209 Debug PLINK_PROTOCOL=ssh 
2012-11-20 13:42:59.6365 Debug TERM=msys 
2012-11-20 13:42:59.6365 Debug SSH_AGENT_PID=58416 
2012-11-20 13:42:59.6365 Debug SSH_AUTH_SOCK=/tmp/ssh-IgTHj19056/agent.19056 
2012-11-20 13:42:59.6521 Info git status --branch
Exit code: 128

2012-11-20 13:42:59.6521 Error  
2012-11-20 13:42:59.6677 Info Cloning repo from origin: git@repo:projectName 
2012-11-20 13:43:01.8674 Debug Cloning into 'c:\repositories\repo_a8c0dd321f'... 
2012-11-20 13:43:03.2090 Debug Could not create directory 'h/.ssh'. 
2012-11-20 13:43:03.2870 Debug Warning: Permanently added 'repo,359.33.9.234' (RSA) to the list of known hosts. 
2012-11-20 13:44:41.4593 Debug fatal: The remote end hung up unexpectedly 

I zawsze pobierz „Nie można utworzyć katalogu h / .ssh” i „Ostrzeżenie: na stałe dodano * do listy znanych hostów”. wiadomości, nawet w wierszu poleceń. Mój H: .ssh znane_hosty pozostają puste, ale moje klucze znajdują się w tym katalogu i git znajduje te, które są w porządku. „Zdalny koniec nieoczekiwanie zawiesił się”, gdy zabiłem procesy git i ssh.

Mogę zakończyć przechodzenie do LibGit2Sharp dla większości moich potrzeb, ale to wciąż nie rozwiązuje mojego problemu z klonowaniem. Czy coś jest nie tak z moją konfiguracją klucza, która znowu działa idealnie poza procesem w3wp.exe? Czy musi być w stanie komunikować się z ssh-agent.exe i nie jest w stanie? Czy ktoś sklonował zdalne repozytorium git przez System.Diagnostics.Process i przeżył, aby opowiedzieć historię?

UPDATE (25.11.2012 18:54):

mvp słusznie wskazał, że personifikacja i zmapowane dyski sieciowe nie grają dobrze razem. Dodałem następujące elementy przed rozpoczęciem procesu:

var userProfile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
Environment.SetEnvironmentVariable("HOME", userProfile);

Uruchomiłem go ponownie i przynajmniej widzę nowy proces git w Menedżerze zadań, który zajmuje 0 czasu procesora, ale używa coraz większej ilości pamięci, jak sądzę, jako część procesu klonowania. Wiersz poleceń był:

git index-pack --stdin --fix-thin "--keep=fetch-pack 6024 on MACHINENAME"

W końcu skończyło się po 10 minutach (to ogromne repozytorium) i rzuciło wyjątek:

fatal: git checkout: updating paths is incompatible with switching branches.
Did you intend to checkout 'origin/8b243b8d9a5140673fc552ef7da8f0dfe9039d50' which can not be resolved as commit?

Wygląda jednak na to, że klon działał po zmianie na katalog! Inny problem dotyczy natychmiastowego wywołania kasowania po zakończeniu operacji klonowania, ale nie ma związku z problemem zawieszania.

Po prostu muszę zweryfikować rozwiązanie mojego / mvp na serwerze produkcyjnym, a następnie przyznam nagrodę.

questionAnswers(2)

yourAnswerToTheQuestion