2012-04-20

Konwersja repozytorium SVN Codeplex na Mercurial

Ciąg dalszy zabawy. Wszelkie polecenia i rozszerzenia (hgsubversion, svn dump, svnrdump, hg convert) zawiodły. Pozostało napisanie kodu który ręcznie wyciąga dane z SVN rewizja po rewizji, kopiuje do katalogu repozytorium HG i zatwierdza z odpowiednim użytkownikiem, datą, komentarzem.

Pierwszy problem to kodowanie znaków. Moja aplikacja to konsola napisana w C#. Kodowanie znaków w konsoli to jakiś dos-owy standard. Polecenie svn log wywołane bezpośrednio z przekierowaniem strumienia do pliku zakoduje go w windows-1252, jeśli wywołam je z kodu to otrzymam strumień UTF-8, gdyż takie kodowanie ustawiłem dla strumieni output i error wywoływanego procesu.

Rozpoznawanie jak plik jest zakodowany nie ma sensu i jest bardzo trudne. Tak więc najlepiej zachować tutaj dyscyplinę.

Poza tym polecenie svn log wywoływane z kodu bardzo często kończy się błędem - za często. Tak więc wywołuje je osobno z svnlog.cmd na początku klikając w ten plik dwa razy.

Polecenie svn log potrafi zwrócić xml, w przypadku Codeplex nie zawiera on nic więcej informacji. a powinien. Atrybut kind powinien nam powiedzieć czy mamy do czynienia z plikiem czy z katalogiem. Taka informacja bardzo uprościła by mi pracę.

Co do wiarygodności svn log. Nie możemy ufać zawartym tam informacją. Po pierwsze są ewidentne błędy - svn log twierdzi, że coś się zmieniło, ale update nie i na odwrót. I nieścisłości. Dodajemy katalog z plikiem, ale svn log twierdzi, że zmodyfikowaliśmy lub dodaliśmy tylko plik. Bardzo często zmiany nazwy pliku i przeniesienie go w inne miejsce jest oznaczana za pomocą modyfikacji nowego pliku, a powinna być para A/D. SVN nie obsługuje zmiany nazwy pliku. Już nie mówiąc o tym, że pliki te różnią się.

No i jeszcze jeden kwiatek: zarówno svn log jak i update, potrafi zwrócić informację typu:

A /amiemu_lib/Savest/CPUState.cs (from /amiemu_lib/Savestate/CPUState.cs:82577)

Części w nawiasach pozbywam się z wyrażeniem regularnym. Mojego testowego serwera nie udało mi się zmusić do wygenerowania takiej informacji. A oznacza ona, z tego co mi się wydaje, że plik został usunięty i ponownie dodany.

Po wykonaniu update, muszę zamienić ścieżki bezwzględne na względne, slashe na backslashe, dodać backslashe na początek, zamienić U na M. I najważniejsze, w przypadku kasowania katalogu svn log podaje pliki i katalog, update tylko katalog.

Później porównuje stan svn log z update i decyduję o tym, czy potrzebny jest pełny checkout.

Ostatecznie mam stan SVN na daną rewizję. Kasuje zawartość HG, kopiuje tam dane z SVN.

I wykonuje polecenie hg status by zobaczyć co się zmieniło. Konfrontuje je z svn log. Jak dotąd wszystkie błędy tutaj pokazywane są także wykazywane wcześniej na etapie update. HG w przeciwieństwie do SVN nie zarządza katalogami. Udało mi się wyeliminować tutaj wszelkie raportowane różnice. Pozostała tylko jedna. Kasowany pusty katalog w SVN. Skasowanie takiego katalogu po stronie HG nic nie znaczy, gdyż został on niejako usunięty z repozytorium wraz z ostatnim plikiem. Raportuje tutaj błąd by uniknąć false negative. Żadne błędy na tym etapie nie wywołują powrotu do checkout.

Zatwierdzam zmiany do HG. Kopiuje zawartość HG z powrotem do SVN i przechodzę do następnej rewizji.

Odpukać, jeszcze nie pobrałem wszystkich rewizji. Nie wiem czy się uda, czy nie będzie nowych błędów, czy nie będę musiał jakoś znacząco rozbudować kodu.

Jak je pobiorę to pozostanie etap, w którym będę starał się pobrać wszystkie rewizje za pomocą checkout i porównać pliki binarnie z rewizją w HG. Cały proces będzie się starał wybierać zawsze rewizję środkową w największej dziurze, czyli zawsze checkouty będą równo rozmieszczone. Rewizji mam jakieś 600, tak więc po zrobieniu z 60 checkoutów powinienem chyba być spokojny o spójność danych.

Na końcu i to już ręcznie postaram się wybrać rewizje w HG wokół, których działy się dziwne rzeczy, i skompilować dla nich kod. I ocenić ewentualne błędy kompilacji.