<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Olivier “Ölbaum” Scherler</title>
    <description>The latest articles on DEV Community by Olivier “Ölbaum” Scherler (@oscherler).</description>
    <link>https://dev.to/oscherler</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2239%2F695742.png</url>
      <title>DEV Community: Olivier “Ölbaum” Scherler</title>
      <link>https://dev.to/oscherler</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/oscherler"/>
    <language>en</language>
    <item>
      <title>I’m Looking for a Web UI for a Static Site Generator</title>
      <dc:creator>Olivier “Ölbaum” Scherler</dc:creator>
      <pubDate>Fri, 19 Jul 2019 22:25:37 +0000</pubDate>
      <link>https://dev.to/oscherler/i-m-looking-for-a-web-ui-for-a-static-site-generator-49a5</link>
      <guid>https://dev.to/oscherler/i-m-looking-for-a-web-ui-for-a-static-site-generator-49a5</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;I’m looking for a web interface to manage content for a static site generator for web sites (not blogs), and I’d love your help to find one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Story
&lt;/h2&gt;

&lt;p&gt;When I started blogging, WordPress didn’t exist. I used Movable Type, a blogging engine written in Perl, that had the interesting property that while the admin backend was dynamic (CGI), the public front end was all static files, generated or updated as necessary when you posted or someone commented, resulting in a fast web site that could handle a lot of traffic (that’s right, it was a static site generator, over five years before the term started trending.)&lt;/p&gt;

&lt;p&gt;Today I would like the same type of software but for simple web sites, not only a blog. A backend that lets people edit the contents with a nice web interface, and and engine that generates static pages out of it, with templates, navigation, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  My wish list
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The programming language doesn’t matter, I intend to run in in Docker;&lt;/li&gt;
&lt;li&gt;The backend and the site generator don’t need to be the same product, as long as I can get the content from the former to the latter;&lt;/li&gt;
&lt;li&gt;I want to host it on my own server;&lt;/li&gt;
&lt;li&gt;I would like to make web sites, with hierarchical pages, not only a blog (hierarchical pages to control how the navigation is displayed);&lt;/li&gt;
&lt;li&gt;A WYSIWYG editor is preferred;&lt;/li&gt;
&lt;li&gt;Web-based, so different people can edit the site without sending each other the source files;&lt;/li&gt;
&lt;li&gt;Since I’m going to use it to make small web sites for friends, I’d rather the solution to be free and/or open source. At least not a per-site license. Definitely not a SaaS. DEFINITELY not $499 per year.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I tried
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ghost: Very nice interface, but only for blogging. Regular pages are too basic;&lt;/li&gt;
&lt;li&gt;Jekyll Admin: Only works with the Jekyll debug web server, not really suited for production;&lt;/li&gt;
&lt;li&gt;Grav: exactly the opposite of what I’m looking for: you have to edit static files and they are served dynamically;&lt;/li&gt;
&lt;li&gt;Netlify CMS: seems to have a very convoluted ways of doing simple things.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If anyone has suggestions for me to try, I would be very grateful. Thanks in advance.&lt;/p&gt;

</description>
      <category>help</category>
      <category>cms</category>
      <category>ssg</category>
    </item>
    <item>
      <title>Are login forms that ask for your username and password on two different pages more secure?</title>
      <dc:creator>Olivier “Ölbaum” Scherler</dc:creator>
      <pubDate>Mon, 25 Feb 2019 12:18:31 +0000</pubDate>
      <link>https://dev.to/oscherler/are-login-forms-that-ask-for-your-username-and-password-on-two-different-pages-more-secure-4jjf</link>
      <guid>https://dev.to/oscherler/are-login-forms-that-ask-for-your-username-and-password-on-two-different-pages-more-secure-4jjf</guid>
      <description>&lt;p&gt;It’s becoming more and more common: instead of a login form where you fill your e-mail or username and your password, you first have to fill your username and submit the form a first time for the password field to appear on the second page (which is often loaded via Ajax, but the fact that the URL doesn’t change doesn’t make the problem disappear).&lt;/p&gt;

&lt;p&gt;There is no need to discuss the fact that it’s annoying, but it seems that companies choose to do so because they believe it’s more secure. Is it really? And if so, why?&lt;/p&gt;

&lt;p&gt;(Cover image by &lt;a href="https://www.flickr.com/photos/delsblog/"&gt;Del&lt;/a&gt;.)&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>security</category>
    </item>
    <item>
      <title>Changing the MySQL root User from auth_socket to Password Authentication Using Ansible</title>
      <dc:creator>Olivier “Ölbaum” Scherler</dc:creator>
      <pubDate>Tue, 19 Feb 2019 20:55:26 +0000</pubDate>
      <link>https://dev.to/oscherler/changing-the-mysql-root-user-from-authsocket-to-password-authentication-using-ansible-3l5m</link>
      <guid>https://dev.to/oscherler/changing-the-mysql-root-user-from-authsocket-to-password-authentication-using-ansible-3l5m</guid>
      <description>&lt;p&gt;MySQL 5.7 introduced a change in which at install time, the root user is configured using the &lt;code&gt;auth_socket&lt;/code&gt; authentication plugin. It means that if you start the MySQL client from the shell as root (connecting through the socket, as the name of the plugin implies,) then you’re automatically authenticated, without a password, based on your user ID on the system. It’s a good thing, because it’s secure out of the box and there’s no root password to set.&lt;/p&gt;

&lt;p&gt;But sometimes you have a setup where you need an old-style password on the root user. In my case, I wanted to replace a Ubuntu development machine with an up-to-date one, and I wanted to provision it with Ansible. We had a lot of PHP projects in development running on the old machine, and they all connected to MySQL using the root user, so it wasn’t very practical to create a new user to work around the new plugin set-up. Unfortunately, at the time of this writing, the Ansible &lt;code&gt;mysql_user&lt;/code&gt; module does not support authentication plugins, and will fail if you try to set a password on the root user.&lt;/p&gt;

&lt;p&gt;Updating the Ansible &lt;code&gt;mysql_user&lt;/code&gt; module to support the new plugin seemed the right thing to do, but it turned out to be more complicated than I expected. Authentication plugins were introduced in MariaDB, then found their way into MySQL, and the plugin and column names, as well as the syntax to some commands &lt;a href="https://github.com/oscherler/ansible-mysql-fix#versions-tested"&gt;changed a lot&lt;/a&gt; between flavours and versions. Thus it’s hard to test your changes, &lt;a href="https://github.com/oscherler/ansible-mysql-fix"&gt;even with the help of Docker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I finally found a pretty decent workaround using the unaltered Ansible &lt;code&gt;mysql_user&lt;/code&gt; module and some SQL commands, and I want to share it here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This method has not been extensively tested, and although it work for the author, is likely to be insecure. Use it only on development VMs or in other non-critical situations.&lt;/p&gt;

&lt;p&gt;The concept is to first create a new &lt;code&gt;auth_socket&lt;/code&gt; user for Ansible to use, and to delete and recreate the root user with a password if it’s using the &lt;code&gt;auth_socket&lt;/code&gt; plugin.&lt;/p&gt;

&lt;p&gt;At the base of our trick is a task file that we are going to import for all the users we want to alter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# mysql_setup_user.yml&lt;/span&gt;
&lt;span class="c1"&gt;# &lt;/span&gt;
&lt;span class="c1"&gt;# Setup a MySQL user, supporting both the mysql_native_password&lt;/span&gt;
&lt;span class="c1"&gt;# and auth_socket plugins.&lt;/span&gt;
&lt;span class="c1"&gt;# &lt;/span&gt;
&lt;span class="c1"&gt;# Variables used:&lt;/span&gt;
&lt;span class="c1"&gt;# - login_user: auth_socket user to invoke the MySQL client with (default: root)&lt;/span&gt;
&lt;span class="c1"&gt;# - username: user to configure&lt;/span&gt;
&lt;span class="c1"&gt;# - plugin: authentication plugin for username (default: mysql_native_password)&lt;/span&gt;
&lt;span class="c1"&gt;# - password: password for username&lt;/span&gt;
&lt;span class="c1"&gt;# - priv: privileges to grant&lt;/span&gt;
&lt;span class="c1"&gt;# - host: host to grant privileges for&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Apply default values&lt;/span&gt;
  &lt;span class="na"&gt;set_fact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;actual_login_user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;login_user&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;default("root")&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
    &lt;span class="na"&gt;actual_plugin&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;plugin&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;default("mysql_native_password")&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
    &lt;span class="na"&gt;actual_host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;host&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;default("localhost")&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;

&lt;span class="c1"&gt;# Check existence and authentication plugin of the user to configure&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Get&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;username&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}@{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;actual_host&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user'&lt;/span&gt;
  &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;mysql -u {{ actual_login_user }} -p'{{ login_password }}' -NBe 'SELECT plugin FROM mysql.user WHERE Host="{{ actual_host }}" AND User = "{{ username }}"'&lt;/span&gt;
  &lt;span class="na"&gt;failed_when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;no&lt;/span&gt;
  &lt;span class="na"&gt;changed_when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;no&lt;/span&gt;
  &lt;span class="na"&gt;register&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql_plugin_output&lt;/span&gt;

&lt;span class="c1"&gt;# User exists if the output of the previous task is not empty&lt;/span&gt;
&lt;span class="c1"&gt;# The auth plugin is the output of the previous task&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Store&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;username&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;info'&lt;/span&gt;
  &lt;span class="na"&gt;set_fact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;user_exists&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;mysql_plugin_output.stdout&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;!=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
    &lt;span class="na"&gt;user_current_plugin&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;mysql_plugin_output.stdout&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;

&lt;span class="c1"&gt;# If the requested user doesn’t exist and the plugin is mysql_native_password,&lt;/span&gt;
&lt;span class="c1"&gt;# create it using the mysql_user module&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Create&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{{ username&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;(if&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;plugin&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;mysql_native_password)'&lt;/span&gt;
  &lt;span class="na"&gt;mysql_user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;login_user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;actual_login_user&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
    &lt;span class="na"&gt;login_password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;login_password&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{ username&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{ actual_host&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
  &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;actual_plugin&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"mysql_native_password"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;not&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user_exists'&lt;/span&gt;

&lt;span class="c1"&gt;# If the requested user doesn’t exist but the plugin is auth_socket,&lt;/span&gt;
&lt;span class="c1"&gt;# then we can’t create it using the mysql_user module, so we resort&lt;/span&gt;
&lt;span class="c1"&gt;# to a shell command&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Create&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{{ username&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;(if&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;plugin&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;auth_socket)'&lt;/span&gt;
  &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;mysql -u {{ actual_login_user }} -p'{{ login_password }}' -NBe 'CREATE USER "{{ username }}"@"{{ actual_host }}" IDENTIFIED WITH auth_socket'&lt;/span&gt;
  &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;actual_plugin&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"auth_socket"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;not&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user_exists'&lt;/span&gt;

&lt;span class="c1"&gt;# Change the plugin if needed, providing the password if the new plugin&lt;/span&gt;
&lt;span class="c1"&gt;# is mysql_native_password.&lt;/span&gt;
&lt;span class="c1"&gt;# It only supports a clear text password, so use a vault.&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Alter&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{{ username&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;use&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;actual_plugin&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
  &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;mysql -u {{ actual_login_user }} -p'{{ login_password }}' -NBe 'ALTER USER "{{ username }}"@"{{ actual_host }}" IDENTIFIED WITH {{ actual_plugin }} {% if actual_plugin == "mysql_native_password" %}BY "{{ password }}"{% endif %}'&lt;/span&gt;
  &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user_current_plugin&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;!=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;actual_plugin'&lt;/span&gt;

&lt;span class="c1"&gt;# If the plugin is mysql_native_password, update the user using Ansible mysql_user,&lt;/span&gt;
&lt;span class="c1"&gt;# to change its password.&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Update&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{{ username&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;(if&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;plugin&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;mysql_native_password)'&lt;/span&gt;
  &lt;span class="na"&gt;mysql_user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;login_user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;actual_login_user&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
    &lt;span class="na"&gt;login_password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;login_password&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{ username&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{ password&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{ actual_host&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
  &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;actual_plugin&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"mysql_native_password"'&lt;/span&gt;

&lt;span class="c1"&gt;# Grant privileges&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Grant&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;privileges&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{{ username&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
  &lt;span class="na"&gt;mysql_user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;login_user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;actual_login_user&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
    &lt;span class="na"&gt;login_password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;login_password&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{ username&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{ actual_host&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
    &lt;span class="na"&gt;priv&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;priv&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are going to use this task file in two plays: one to set-up a new &lt;code&gt;auth_socket&lt;/code&gt; user so we can alter the root user, and the other one to actually alter it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# mysql-root-playbook.yml&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set MySQL root password&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;
  &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yes&lt;/span&gt;

  &lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create user Ansible for MySQL administration with auth_socket&lt;/span&gt;
      &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ansible'&lt;/span&gt;
        &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;present&lt;/span&gt;
        &lt;span class="na"&gt;createhome&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;no&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup ansible user&lt;/span&gt;
      &lt;span class="na"&gt;include_tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql_setup_user.yml&lt;/span&gt;
      &lt;span class="na"&gt;vars&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ansible&lt;/span&gt;
        &lt;span class="na"&gt;login_password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;mysql_root_password&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
        &lt;span class="na"&gt;plugin&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;auth_socket&lt;/span&gt;
        &lt;span class="na"&gt;priv&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;*.*:ALL,GRANT'&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Configure MySQL root user (using user ansible)&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;
  &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yes&lt;/span&gt;
  &lt;span class="na"&gt;become_user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ansible&lt;/span&gt;

  &lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup root user&lt;/span&gt;
      &lt;span class="na"&gt;include_tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql_setup_user.yml&lt;/span&gt;
      &lt;span class="na"&gt;vars&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;login_user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ansible&lt;/span&gt;
        &lt;span class="na"&gt;login_password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;mysql_root_password&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
        &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;root&lt;/span&gt;
        &lt;span class="na"&gt;plugin&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql_native_password&lt;/span&gt;
        &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;mysql_root_password&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
        &lt;span class="na"&gt;priv&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;*.*:ALL,GRANT'&lt;/span&gt;
        &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;item&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
      &lt;span class="na"&gt;with_items&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;localhost'&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1'&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if you set variable &lt;code&gt;mysql_root_password&lt;/code&gt; and run the above playbook with &lt;code&gt;ansible-playbook -i hosts.yml mysql-root-playbook.yml&lt;/code&gt; (replace &lt;code&gt;hosts.yml&lt;/code&gt; with your actual inventory), the following is going to happen:&lt;/p&gt;

&lt;p&gt;The first play, as root, will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new system user, &lt;code&gt;ansible&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Create MySQL user &lt;code&gt;ansible@localhost&lt;/code&gt; with plugin &lt;code&gt;auth_socket&lt;/code&gt; (no password needed) and full privileges, using the current root user with &lt;code&gt;auth_socket&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second play, as user &lt;code&gt;ansible&lt;/code&gt; will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;See that &lt;code&gt;root@localhost&lt;/code&gt; is using plugin &lt;code&gt;auth_socket&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Alter the root user to use &lt;code&gt;mysql_native_password&lt;/code&gt; and the desired password.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you run the playbook again, it will see (as root with the newly set password) that the &lt;code&gt;ansible&lt;/code&gt; user is configured as desired, and them as &lt;code&gt;ansible&lt;/code&gt; with &lt;code&gt;auth_socket&lt;/code&gt; that the root user is configured as desired as well.&lt;/p&gt;

&lt;p&gt;Three drawbacks to this method:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It’s quite verbose;&lt;/li&gt;
&lt;li&gt;It runs shell commands with the MySQL password for root in the command line;&lt;/li&gt;
&lt;li&gt;It will fail if you subsequently change the root password, because it won’t be able to connect as root with a password.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, this is a workaround intended for development machines, so it doesn’t really matter. On a production machine, you should be perfectly happy with using &lt;code&gt;auth_socket&lt;/code&gt; for &lt;code&gt;root@localhost&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>ansible</category>
      <category>mysql</category>
    </item>
    <item>
      <title>Move Android Studio Virtual Devices to Another Hard Drive on a Mac</title>
      <dc:creator>Olivier “Ölbaum” Scherler</dc:creator>
      <pubDate>Wed, 06 Feb 2019 10:08:40 +0000</pubDate>
      <link>https://dev.to/oscherler/move-android-studio-virtual-devices-on-a-mac-5ej5</link>
      <guid>https://dev.to/oscherler/move-android-studio-virtual-devices-on-a-mac-5ej5</guid>
      <description>&lt;p&gt;Imagine you’d like to reclaim space on your Mac’s main hard drive by moving your Android Studio Virtual Devices (the phones and tablets you run in the Android Emulator to test your applications). It’s possible, but if you’re lucky like I am, you might run into some hurdles.&lt;/p&gt;

&lt;p&gt;It’s &lt;a href="https://developer.android.com/studio/command-line/variables"&gt;easy enough to find out&lt;/a&gt; that you should modify either the &lt;code&gt;ANDROID_SDK_ROOT&lt;/code&gt;, &lt;code&gt;ANDROID_EMULATOR_HOME&lt;/code&gt;, or &lt;code&gt;ANDROID_AVD_HOME&lt;/code&gt; environment variables (or even &lt;code&gt;ANDROID_HOME&lt;/code&gt;, if you’re unlucky enough to find some really outdated documents). But if you try to set them under &lt;u&gt;Appearance &amp;amp; Behavior &amp;gt; Path Variables&lt;/u&gt; in the Android Studio Preferences, because you think it would be a reasonable thing to do, then you might waste a lot of time, because it does not work. And of course, the thousands of documents about how to do it in Windows are of no help at all, and the few that are about the Mac are really, really outdated.&lt;/p&gt;

&lt;p&gt;What we want to achieve here is to define the &lt;code&gt;ANDROID_AVD_HOME&lt;/code&gt; environment variable in a way that makes it available to applications launched from the Finder. Starting from Mac OS 10.10 (and working at least until 10.14, at the time of this writing), it can be done with &lt;code&gt;launchctl setenv&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;launchctl setenv ANDROID_AVD_HOME /Volumes/LargeHDD/Android/avd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To test it without starting Android Studio, you can use Apple’s Script Editor and run this script (however, keep in mind that you must relaunch Script Editor after calling &lt;code&gt;launchctl setenv&lt;/code&gt;, in order for it to pick up the changes):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight applescript"&gt;&lt;code&gt;&lt;span class="nb"&gt;do shell script&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"echo $ANDROID_AVD_HOME"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now is a good time to move your Android Virtual Device (AVD) files from &lt;code&gt;~/.android/avd&lt;/code&gt; to their new location (e.g. &lt;code&gt;/Volumes/LargeHDD/Android/avd&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;However&lt;/strong&gt;, you also need to update the &lt;code&gt;.ini&lt;/code&gt; files in that folder, because they reference an absolute path to the old location, and if you don’t update it, Android Studio will complain that the INI file is corrupted. For example if you have a file &lt;code&gt;Nexus_5X_API_26.ini&lt;/code&gt; in your new &lt;code&gt;/Volumes/LargeHDD/Android/avd&lt;/code&gt; folder, edit it (the &lt;code&gt;path&lt;/code&gt; property) from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;avd.ini.encoding&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;UTF-8&lt;/span&gt;
&lt;span class="py"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/Users/olivier/.android/avd/Nexus_5X_API_26.avd&lt;/span&gt;
&lt;span class="py"&gt;path.rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;avd/Nexus_5X_API_26.avd&lt;/span&gt;
&lt;span class="py"&gt;target&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;android-26&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;avd.ini.encoding&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;UTF-8&lt;/span&gt;
&lt;span class="py"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/Volumes/LargeHDD/Android/avd/Nexus_5X_API_26.avd&lt;/span&gt;
&lt;span class="py"&gt;path.rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;avd/Nexus_5X_API_26.avd&lt;/span&gt;
&lt;span class="py"&gt;target&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;android-26&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now launch Android Studio and open the AVD Manager to see that your devices are still there, but we still need to make sure this environment variable is set every time you log in. For that, we are going to create a script, and start it at login using Launchd.&lt;/p&gt;

&lt;p&gt;Create the following script at &lt;code&gt;/Users/[YOUR_USER_NAME]/.android_studio_env_vars&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ANDROID_AVD_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'/Volumes/LargeHDD/Android/avd'&lt;/span&gt;

launchctl setenv ANDROID_AVD_HOME &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ANDROID_AVD_HOME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create the following PList file at &lt;code&gt;~/Library/LaunchAgents/user.AndroidStudioEnvVars.plist&lt;/code&gt; (you can name it however you like):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;plist&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dict&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Label&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;user.AndroidStudioEnvVars&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;ProgramArguments&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/bin/bash&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/Users/[YOUR_USER_NAME]/.android_studio_env_vars&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;RunAtLoad&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;true/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dict&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plist&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could just execute &lt;code&gt;launchctl setenv ANDROID_AVD_HOME /Volumes/LargeHDD/Android/avd&lt;/code&gt; from the PList, but a script allows us to define other variables, like &lt;code&gt;ANDROID_SDK_ROOT&lt;/code&gt; if needed.&lt;/p&gt;

&lt;p&gt;Finally, load the PList with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;launchctl load ~/Library/LaunchAgents/user.AndroidStudioEnvVars.plist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next time you log in or restart, the environment variable should be automatically set, which you can check with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;launchctl getenv ANDROID_SDK_ROOT
&lt;span class="c"&gt;# -&amp;gt; /Volumes/LargeHDD/Android/sdk&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>android</category>
      <category>mac</category>
      <category>avd</category>
    </item>
  </channel>
</rss>
