Search code examples
windowsvisual-studioxamarinchef-infrawindows-server-2012

How to install Xamarin on Windows using Chef


I configure my TeamCity build agents (Windows Server 2012 VMs) using Chef, and I have a need to install Xamarin for an Visual Studio/Android build. For other installers I usually play around with invoking it with /h, /help, /?, -?, -h and --help until I get a usage dialog that tells me the command-line parameters. I have not been able to figure out the command-line parameters for the XamarinInstaller.exe, however, and when I launch it like this:

XamarinInstaller.exe /quiet /norestart

since those are common conventions, it seems that it just sits there and doesn't do anything. It should be downloaded stuff (that's what it does when I launch it with the GUI) but when I look at the Ethernet usage in the task manager, nothing much is happening. I don't know where it writes it logs or how to know if it has failed. It doesn't seem to quit when it has failed.

Here is my Chef code:

xamarinTargets = 'C:\\Program Files (x86)\\MSBuild\\Xamarin\\Android\\Xamarin.Android.CSharp.targets'

xamarinInstaller = 'C:\\Repo\\Xamarin\\XamarinInstaller.exe'

execute "Xamarin" do
  command "#{xamarinInstaller} /quiet /norestart"
  not_if { ::File.exist?(xamarinTargets) }
end

How do I invoke the Xamarin installer headlessly? How do I install it with Chef?


Solution

  • Here's what I had to do, and some of it is kind of wonky.

    1. Install android-sdk and xamarin-visualstudio via Chocolatey using the chocolatey_package resource from the chocolatey cookbook.
    2. Verify the Xamarin install worked as expected.
    3. Unzip a prefabbed android-sdk.zip into $HOME\AppData\Local\Android in order to get everything I need installed in the Android SDK*
    4. Verify the Android SDK install worked as expected.
    5. Create a registry key to point Xamarin's Visual Studio integration to the appropriate Android SDK.

    Here it is in Chef code:

    xamarinTargets = 'C:\\Program Files (x86)\\MSBuild\\Xamarin\\Android\\Xamarin.Android.CSharp.targets'
    
    chocolatey_package 'android-sdk'
    chocolatey_package 'xamarin-visualstudio'
    
    ruby_block "Verify Xamarin MSBuild targets exist" do
        block do
            if not ::File.exist?(xamarinTargets)
                raise "Did not find #{xamarinTargets} which was supposed to have been created by the Xamarin install"
            end
        end
    end
    
    homeDir = "C:\\Users\\#{ENV['User']}"
    androidDir = "#{homeDir}\\AppData\\Local\\Android"
    androidSdk = "#{androidDir}\\android-sdk"
    androidSdkZip = "C:\\Repo\\Android\\android-sdk.zip"
    adbExe = "#{androidSdk}\\platform-tools\\adb.exe"
    
    seven_zip_archive "Android SDK API level 15" do
        path androidDir
        source androidSdkZip
        overwrite true
        not_if { ::File.exist?(adbExe) }
    end
    
    ruby_block "Verify Android adb.exe exists" do
        block do
            if not ::File.exist?(adbExe)
                raise "Did not find #{adbExe} which was supposed to have been created by the Android SDK install"
            end
        end
    end
    
    registry_key 'HKEY_USERS\\S-1-5-18\\Software\\Novell\\Mono\ for\ Android' do
      values [{
        :name => "AndroidSdkDirectory",
        :type => :string,
        :data => androidSdk
      }]
      recursive true
      action :create
    end
    

    *I could not for the life of me get android update sdk to work when invoked through Chef. It seems that the Android SDK Manager won't run even nongraphically unless it can detect that it is being run by a user?! Not sure, but finally in desperation, I ran the command manually to install the necessary SDK (I need API level 15) and build tools:

    android update sdk --no-ui --all --filter "tools,platform-tools,build-tools-23.0.3,android-15"
    

    I then took the resulting $HOME\AppData\Local\Android\android-sk directory and zipped it to produce the "prefabbed android-sdk.zip" mentioned above.