Combine XPO a poškozené soubory

Před pár dny přestal správně pracovat můj noční build jedné aplikace Dynamics AX 2009. V sestavené vrstvě chyběly některé objekty, což pochopitelně způsobilo spoustu kompilačních chyb.

Ukázalo se, že data byla v pořádku získána ze správy verzí, ale aplikace Combine XPO Tool (CombineXPOs.exe) je nedokázala zpracovat. (Pokud ji neznáte, Combine XPO se používá k sloučení více .xpo souborů do jednoho – typicky (jako v tomto případě) ke zkombinování všech souborů získaných ze správy verzí před importem do AX.)

CombineXPOs.exe vrátila návratový kód -4 a zapsala následující chybovou zprávu do standardního výstupního proudu:

Error [-4] The file is bad: C:\NightBuild\SourceFiles\bus\Data Dictionary\Tables\AddressCountryRegion.xpo.
Exception message: System.ArgumentOutOfRangeException: Length cannot be less than zero.
Parameter name: length

V překladu to znamená toto:

Chyba [-4] Soubor je špatný: C:\NightBuild\SourceFiles\bus\Data Dictionary\Tables\AddressCountryRegion.xpo.
Chybová zpráva: System.ArgumentOutOfRangeException: Délka nesmí být menší než nula.
Jméno parametru: length

Jak můžete očekávat, Combine XPO nezpracovala zbývající soubory, tudíž sloučený .xpo soubor byl nekompletní. Druhá část problému byla v tom, že návratový kód nebyl v sestavovacím skriptu ošetřen.

Ono problematické .xpo obsahovalo toto:

Exportfile for AOT version 1.0 or later
Formatversion: 1

***Element: END

Jak můžete vidět, neobsahuje téměř nic – dokonce ani typ a jméno objektu. A Combine XPO není jediný nástroj, který má s takovým .xpo problémy – porovnání verzí v AX2009 vyhodilo na tomto objektu runtime chybu (zdá se, že v AX2012 to funguje bez problémů).

Verze Combine XPO Tool

Když jsem toto chování testoval, všiml jsem si, že různé verze Combine XPO Tool řeší tuto situaci odlišně:

Verze 1.0.3974.781 (to je verze dostupná na blogu mfp a ta kterou jsem používal v nočních buildech)

Výsledek Zpracování zastaveno na poškozeném .xpo souboru
Návratový kód -4
Standardní výstup Error [-4] The file is bad: C:\NightBuild\SourceFiles\bus\Data Dictionary\Tables\AddressCountryRegi
on.xpo. Exception message: System.ArgumentOutOfRangeException: Length cannot be less than zero.
Parameter name: length

Version 6.0.947.5121 (stažena z InformationSource; oficiální název Microsoft Dynamics AX 2012 Combine XPO Tool Beta 1.0):

Result Zpracovány všechny soubory
Exit code -4
Standardní výstup 1764 XPO files processed
Ok
Standard error CombineXPOs.exe : Warning [-5] CombineXPOs.exe : Error [C:\NightBuild\SourceFiles\bus\Data Dicti
onary\Tables\AddressCountryRegion.xpo] Length cannot be less than zero.
Parameter name: length

Obě verzi  si stěžují na poškozené .xpo, ale ta novější ho zkrátka přeskočí a pokračuje, ta starší se zastaví a vy dostanete .xpo, které nezahrnuje obsah všech vstupních .xpo souborů. Někdo si toho problému asi všiml a to chování změnil. Jedna zajímavá věc je to, že obě verze vrací zcela stejný návratový kód.

Jak vytvořit poškozené .xpo

Vytvoření poškozeného .xpo je překvapivě jednoduché. Například můžete následovat tyto kroky:

  1. Najděte tabulku, která existuje v nižší vrstvě (třeba SYS), ale ne ve vaší vývojové vrstvě.
  2. Přidejte nové pole.
  3. Vložte objekt do zprávy verzí.
  4. Proveďte check in.
  5. Proveďte check out.
  6. Odeberte pole.
  7. Opět proveďte check in.

V bodě 7 v zásadě ukládáte do správy verzí objekt, který už ve vývojové vrstvě neexistuje, protože jste všechny změny (jedno pole) odebrali. AX pak vyexportuje všechny změny (= žádné), čímž vznikne prázdné .xpo popsané výše (testováno v AX2009 + SourceSafe a AX2012 R2 + TFS).

Tato procedura není to, co byste měli použít – chcete-li odebrat všechny změny, fakticky odstraňujete daný objekt, tudíž byste ho měli skutečně odstranit a smazání uložit do správy verzí (smazání je prostě jeden z typů akce ve správě verzí).

Jak zpracovat návratový kód z Combine XPO

Pokud by byl návratový kód řádně zpracován, problém by nezmizel – ale bylo by očividné, co je špatně.

Protože nová verze Combine XPO zkrátka přeskočí poškozená .xpo, můžete mít tendenci celý problém ignorovat. Ale to není správný přístup, protože existují i další důvody proč může Combine XPO selhat. Například pokud zdrojový adresář neexistuje, obdržíte návratový kód -2.

Byla by také chyba ignorovat návratový kód -4 – ten dostanete pro jakoukoli výjimku v jedné části Combine XPO, není nijak svázán s tímto konkrétním problémem.

Mohli byste analyzovat zprávy zapsané do chybové výstupního proudu, ale nejjistější je zastavit zpracování pokaždé, kdy návratový kód není roven nule.

Ukázku najdete v následujícím Powershellovém kódu. Pracuje s oběma verzemi Combine XPO (hledá chybová hlášení jak v chybovém, tak standardním výstupu) a také zpracovává návratové kódy bez chybové zprávy. Kód jednoduše vyhazuje výjimku, protože všechny výjimký jsou zpracovány buildovacím skriptem pomocí příkazu trap (ten zde není ukázán).

$output = & $combineXpoExe -XpoDir $sourceFilesDir -CombinedXpoFile $combinedFile -utf8 2>&1
 
if ($LastExitCode -ne 0)
{
    $err = "CombineXPOs.exe: Exit code $LastExitCode"
    if ($output)
    {
        $err = $output | ?{$_.getType().Name -eq "ErrorRecord"}
        if (!$err)
        {
            $err = $output
        }
    }	
    throw $err
}