Sunday, January 31, 2016

Install Ansible on Windows with Cygwin

  1. Install Cygwin with all the items under the categories Devel, Python, plus openssh and wget 

    At the step of "Select Packages", toggle the categories Devel, Python from "Default" to "Install" which selects all the items under the category, and toggle openssh under "Net" and wget under "Web" from "Skip" to each version. Ignore any "Setup Alert" message boxes which say that you should install something else by yourself.
  2. Create Ansible.bat

    You may have Windows-native Python installed on your Windows. In order to prevent it from interfering with Cygwin's python, write the following batch script that clears the Windows PATH. Run this Ansible.bat to enter the sandboxed Ansible environment.
    @path ;
    @C:\cygwin64\Cygwin.bat
    
  3. Install PIP and Ansible through PIP

    At the bash prompt of Ansible.bat, enter the following commands
    $ easy_install-2.7 pip
    $ pip install ansible
    
  4. Add Ansible variables to .bashrc

    Edit ~/.bashrc by adding the following environment variables used by Ansible
    # Ansible settings
    export ANSIBLE_SCP_IF_SSH=y
    export ANSIBLE_SSH_ARGS='-o ControlMaster=no'
    
  5. Install sshpass

    In order to enable Ansible options --ask-pass, --ask-become-pass, you need to install sshpass by yourself. Run the following commands
    $ wget http://downloads.sourceforge.net/project/sshpass/sshpass/1.05/sshpass-1.05.tar.gz
    $ tar -xvf sshpass-1.05.tar.gz
    $ cd sshpass-1.05
    $ ./configure
    $ make install
    
  6. Rerun Ansilbe.bat

    Close the previous Cygwin prompt that you have used for installing and run Ansible.bat again. Now you can run the following command to check if Ansible is installed.
    $ ansible --version
    
    Always run Ansible.bat to use Ansible commands.

Tuesday, January 19, 2016

Add resources from Resources.resx to XAML

You may have tried this technique gleaned from the Internet in order to change your WPF GUI's text at runtime according to the language.
When you write the next snippet in your Window's XAML for adding resources from the Resources.resx file and rebuild and run in Visual Studio 2015,

<Window
    ...
    xmlns:props="clr-namespace:MyProject.Properties" 
    >
    <Window.Resources>
        <props:Resources x:Key="LocalResources" />
    </Window.Resources>
    <Window.BindingGroup>
        <BindingGroup Name="localization"/>
    </Window.BindingGroup>
    <Window.Title>
        <Binding Path="WindowTitleStringName"
                 Source="{StaticResource LocalResources}"
                 BindingGroupName="localization"/>
    </Window.Title>
    <Label Content="{Binding LabelContentStringName,
                             Source={StaticResource LocalResources},
                             BindingGroupName=localization}"
        ...
       />
</Window>
// Change to the default Resources.resx in MyWindow.cs
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture ;
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture ;
BindingGroup.BindingExpressions
    .Where( be => be.BindingGroup.Name=="localization" )
    .ToList().ForEach( be => be.UpdateTarget() );

the next exception is thrown.

System.Windows.Markup.XamlParseException / System.MissingMethodException :
    No matching constructor found on type MyProject.Properties.Resources.
    You can use the Arguments or FactoryMethod directives to construct this type.

If you slightly modify Resources.Designer.cs like adding meaningless spaces and just build(not rebuild) and run, the exception is not thrown any more.

Even so, this can be a problem when this app is built in an automated build system.

In order to solve this problem, derive your own Resources class from MyProject.Properties.Resources  and use it with the already defined "local" namespace in your xaml like the next.
namespace MyProject
{
    public class Resources 
        : Properties.Resources
    {
        public Resources()
        {
        }

    }  // End Of Class
}

<Window
    ...
    xmlns:props="clr-namespace:MyProject.Properties"
    >
    <Window.Resources>
         <local:Resources x:Key="LocalResources" />
    </Window.Resources>
    ...
</Window>