如何设置TeamCity CI,使其解压Xamarin组件?

如何设置TeamCity CI,使其解压Xamarin组件?,teamcity,xamarin,mvvmcross,Teamcity,Xamarin,Mvvmcross,在VisualStudio中,一切工作正常,并使用适当的DLL创建组件目录。但是,TeamCity无法检索Android支持库DLL,因为还原的触发器是加载解决方案时运行的Xamarin VS插件。Xamarin的nuget包还原的等价物是。我已将xamarin-component.exe放在我的C:\Windows目录中。为了配置TeamCity,我用 Command executable: xamarin-component Command parameters: restore myso

在VisualStudio中,一切工作正常,并使用适当的DLL创建组件目录。但是,TeamCity无法检索Android支持库DLL,因为还原的触发器是加载解决方案时运行的Xamarin VS插件。Xamarin的nuget包还原的等价物是。我已将xamarin-component.exe放在我的C:\Windows目录中。为了配置TeamCity,我用

Command executable: xamarin-component 
Command parameters: restore mysolution.sln
TeamCity作为NT Authority\System运行。所以使用PsExec

psexec -i -s %SystemRoot%\system32\cmd.exe
如果我运行“xamarin组件登录”

INFO (login): Computed cookie jar path: C:\Windows\system32\config\systemprofile\.xamarin-credentials 
INFO (login): Computed cookie jar path: C:\Windows\system32\config\systemprofile\.xamarin-credentials 
INFO (login): Credentials successfully stored.
当我在cmd中找到我的解决方案并尝试恢复时,我尝试下载组件,然后出现Json解析错误。这和我在TeamCity遇到的错误是一样的

如果我使用“Administrator”(将凭据存储在C:\Users\Administrator中),则会出现错误。早些时候,当我使用我的个人帐户时,它确实有效。但是,一旦我删除了C:\Users\tim\AppData\Local\Xamarin\Cache\Components,同样的问题就会出现。Fiddler显示了这一点,而不是恢复Json(当我们输入一个无效的令牌时)我们得到了一个302重定向,表示对象移动到了这里 登录页面-显然不是Json

尝试过。 1.将COOKIE\u JAR\u路径设置为C:\Users\tim.xamarin-credentials-xpkg拾取,但出现相同错误 2.将.xamarin凭据从Config\system32复制到D:\,将COOKIE\u JAR\u路径设置为D:.xamarin凭据-xpkg将拾取,但出现相同错误 3.将.xamarin凭据移动到C:\,设置COOKIE\u JAR\u路径-相同错误 4.使用COOKIE_JAR_路径重新登录NT Authority到C:.xamarin凭据-相同错误

我现在的临时想法是找出NT Authority xamarin组件在哪里查找缓存并将文件放在那里

C:\Windows\system32\config\systemprofile\AppData\Local\Xamarin\Cache\Components\xamandroidsupportv4-18-4.18.1.xam

我的xamarin组件的版本是0.99-对于100,我们会更加努力…

我在从system32路径正确加载cookie jar时遇到了问题。我认为这是一个路径虚拟化问题,我只是不太了解,无法理解

最后,我添加了一个环境变量,该工具将从中读取(我是Xamarin的主要作者:-),它指定了要读取的cookie jar路径,这解决了使用TeamCity的其他人的问题。环境变量是
cookie\u jar\u path


您可以从TeamCity的环境设置中将其设置为指向system32概要文件目录之外的cookie jar路径(我认为在我最初的测试中,我将其放在C:驱动器的根目录中,但实际上它可以在任何地方)。

作为黑客,我从

C:\Users\tim\AppData\Local\Xamarin 

这绕过了与Xamarin服务器的通信

更新。我怀疑可能是服务器端的链接或设置错误。调用xamarin组件还原时,会调用

GET /api/available_versions?alias=xamandroidsupportv4-18 HTTP/1.1
它返回“objectmovedthere”,其中“here”不存在

如果在删除缓存和组件文件夹(位于解决方案旁边)后启动Visual Studio,Xamarin将调用

GET /api/download/xamandroidsupportv4-18/4.18.1 HTTP/1.0
它移动了一个外观类似的对象,但这次它将引导您访问xamarin-components.s3.amazonaws.com/

GET /fdca922d2b77799fe208a08c9f3444fe/xamandroidsupportv4-18-4.18.1.xam HTTP/1.0


可能是发生了变化,或者可用的\u版本API发生了变化。

非常感谢您的提问和回答。我不太喜欢在构建节点上存储身份验证cookie或手动复制缓存的想法,所以我想出了自己的解决方案,所以我用一个快速的Powershell脚本解决了这个问题模拟
xamarin-component.exe还原操作的行为:

param
(
    [Parameter(Mandatory=$true)]
    $authCookie,

    [Parameter(Mandatory=$true)]
    $componentDirectory,

    [Parameter(Mandatory=$true)]
    $project
)

[void]([System.Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem'))
$xml = [xml] $(cat $project);
$components = $xml.Project.ItemGroup.XamarinComponentReference | ? { $_.Include.Length -gt 0 } | % { $_.Include };

if (!(test-path $componentDirectory))
{
    echo "$componentDirectory didn't exist, so it was created.";
    [void](mkdir $componentDirectory);
}

foreach ($component in $components)
{
    $source = "http://components.xamarin.com/download/$component";
    $destination = "$componentDirectory\$component.zip";

    if (test-path $destination)
    {
        echo "$destination already exists, skipping...";
        continue;
    }

    echo "Downloading $component from $source to $destination...";

    $client = New-Object System.Net.WebClient
    $client.Headers.Add([System.Net.HttpRequestHeader]::Cookie, "XAM_AUTH=$authCookie");

    try
    {
        $client.DownloadFile($source, $destination);
    }
    catch
    {
        # The error message will be on one of these lines hopefully:
        write-error "Failed to download! Errors are below:";
        write-error $_
        write-error $_.Exception
        write-error $_.Exception.InnerException
        write-error $_.Exception.InnerException.InnerException
        exit 1;
    }

    if (!(test-path $destination))
    {
        write-error "$destination doesn't exist - the download must have failed!";
        exit 1;
    }

    echo "Decompressing $source to $componentDirectory"
    [System.IO.Compression.ZipFile]::ExtractToDirectory($destination, $componentDirectory)
    echo ""
}

echo "Done!";
-authCookie
参数可以从浏览器中的XAM_AUTH cookie或主目录中的.xamarin凭据“cookiejar”中提取。很高兴将其参数化为这样,以便您可以将其作为秘密变量存储在TeamCity中

componentDirectory
参数必须是组件目录的完整路径-如果它不存在,将创建它

project
参数应该是要为其还原包的项目的路径-如果有多个项目需要此路径,则必须为每个项目执行脚本。不要指定解决方案,因为它不起作用


不幸的是,这对Xamarin的突发奇想不是很有弹性-一个简单的API更改可能会使其变得毫无用处,因此显然最好的解决方案是等待Xamarin解决此问题。我通过电子邮件向Xamarin支持部门投诉此问题,但我想我不会得到及时的响应(这些天他们似乎非常忙)。我希望这是有用的!

创建目录并将目录路径放入环境变量XAMARIN\u CACHEPATH中


谢谢你,Bojan。我希望收到你的来信。我会尝试一下。建议在下一个版本中内置警告-或者可以选择指定cookie jar位置。是的,我必须花一些时间改进工具上的错误处理/文档。嗯,指向我个人的C:\Users\tim\。xamarin凭据同样的错误,尽管该工具确实接受了更改。将NT Authority生成的版本从Config\systemprofile复制到D:\,运气不佳。从Fiddler看来,我得到的是重定向,而不是JSON。您可以在另一台机器上创建cookie jar,然后复制它——我不会尝试从Config\systemprofile复制该版本还有。这是一个简单的文本文件,你可以通过记事本创建。好消息!我向Xamarin报告了这个错误,他们已经发现了问题。他们希望修复的API将在本周末可用。
param
(
    [Parameter(Mandatory=$true)]
    $authCookie,

    [Parameter(Mandatory=$true)]
    $componentDirectory,

    [Parameter(Mandatory=$true)]
    $project
)

[void]([System.Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem'))
$xml = [xml] $(cat $project);
$components = $xml.Project.ItemGroup.XamarinComponentReference | ? { $_.Include.Length -gt 0 } | % { $_.Include };

if (!(test-path $componentDirectory))
{
    echo "$componentDirectory didn't exist, so it was created.";
    [void](mkdir $componentDirectory);
}

foreach ($component in $components)
{
    $source = "http://components.xamarin.com/download/$component";
    $destination = "$componentDirectory\$component.zip";

    if (test-path $destination)
    {
        echo "$destination already exists, skipping...";
        continue;
    }

    echo "Downloading $component from $source to $destination...";

    $client = New-Object System.Net.WebClient
    $client.Headers.Add([System.Net.HttpRequestHeader]::Cookie, "XAM_AUTH=$authCookie");

    try
    {
        $client.DownloadFile($source, $destination);
    }
    catch
    {
        # The error message will be on one of these lines hopefully:
        write-error "Failed to download! Errors are below:";
        write-error $_
        write-error $_.Exception
        write-error $_.Exception.InnerException
        write-error $_.Exception.InnerException.InnerException
        exit 1;
    }

    if (!(test-path $destination))
    {
        write-error "$destination doesn't exist - the download must have failed!";
        exit 1;
    }

    echo "Decompressing $source to $componentDirectory"
    [System.IO.Compression.ZipFile]::ExtractToDirectory($destination, $componentDirectory)
    echo ""
}

echo "Done!";