Hello from WordCamp Vienna, and ddev in fish

I’m…kind of late mentioning that I’m at WordCamp Vienna. The day of sessions was fun and the people were great.

I’m at the Contributor Day now setting up my site in ddev.  I use the Fish Shell, so sometimes I have to run commands a bit differently.

After I imported my database, ddev reminded me to properly search-replace the WordPress URL, as one does. It told me:

WordPress sites require a search/replace of the database when the URL is changed. You can run “ddev exec ‘wp search-replace [http://www.myproductionsite.example] http://wizonesolutions.com.ddev.local'” to update the URLs across your database. For more information, see http://wp-cli.org/commands/search-replace/

However, I got errors when trying to do that:

Failed to execute command [wp search-replace http://local.wizonesolutions.com http://wizonesolutions.com.ddev.local]: Failed to run docker-compose [-f /Users/kevin/vhosts/ws/wizonesolutions.com/.ddev/docker-compose.yaml exec -T web wp search-replace http://local.wizonesolutions.com http://wizonesolutions.com.ddev.local], err='exit status 126', stdout='OCI runtime exec failed: exec failed: container_linux.go:348: starting container process caused "exec: \"wp search-replace http://local.wizonesolutions.com http://wizonesolutions.com.ddev.local\": stat wp search-replace http://local.wizonesolutions.com http://wizonesolutions.com.ddev.local: no such file or directory": unknown
', stderr=''

This was weird. I could see that it was misinterpreting my command and trying to use it as a working directory or something. That made sense.

I started to think: is Fish processing my command inside the single quotes before it sends to ddev, maybe? I’m not sure if that was the exact cause, but it lead me to running the command this way:

ddev exec ''wp search-replace http://local.wizonesolutions.com http://wizonesolutions.com.ddev.local''

It worked after that!

Posted in DevOps, Toolbox | Tagged | Leave a comment

How to fix nokogiri errors caused by Vagrant 2.0.3 plugins

The short version: vagrant plugin expunge --reinstall

The long version:

Vagrant 2.0.3 seems to have changed something from 2.0.2 in terms of its embedded version of nokogiri. This causes errors when running commands such as vagrant status.

Here’s an example of the kind of error you may see:

/opt/vagrant/embedded/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:in `require': incompatible library version - /Users/kevin/.vagrant.d/gems/2.4.3/gems/nokogiri-1.8.2/lib/nokogiri/nokogiri.bundle (LoadError)
from /opt/vagrant/embedded/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from /Users/kevin/.vagrant.d/gems/2.4.3/gems/nokogiri-1.8.2/lib/nokogiri.rb:32:in `rescue in <top (required)>'
from /Users/kevin/.vagrant.d/gems/2.4.3/gems/nokogiri-1.8.2/lib/nokogiri.rb:28:in `<top (required)>'
from /opt/vagrant/embedded/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from /opt/vagrant/embedded/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from /Users/kevin/.vagrant.d/gems/2.4.3/gems/vagrant-parallels-1.7.8/lib/vagrant-parallels/driver/base.rb:2:in `<top (required)>'
from /Users/kevin/.vagrant.d/gems/2.4.3/gems/vagrant-parallels-1.7.8/lib/vagrant-parallels/driver/meta.rb:4:in `require_relative'
from /Users/kevin/.vagrant.d/gems/2.4.3/gems/vagrant-parallels-1.7.8/lib/vagrant-parallels/driver/meta.rb:4:in `<top (required)>'
from /opt/vagrant/embedded/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from /opt/vagrant/embedded/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from /Users/kevin/.vagrant.d/gems/2.4.3/gems/vagrant-parallels-1.7.8/lib/vagrant-parallels/provider.rb:16:in `usable?'
from /opt/vagrant/embedded/gems/2.0.3/gems/vagrant-2.0.3/lib/vagrant/vagrantfile.rb:138:in `machine_config'
from /opt/vagrant/embedded/gems/2.0.3/gems/vagrant-2.0.3/lib/vagrant/vagrantfile.rb:45:in `machine'
from /opt/vagrant/embedded/gems/2.0.3/gems/vagrant-2.0.3/lib/vagrant/environment.rb:694:in `machine'
from /Users/kevin/.vagrant.d/gems/2.4.3/gems/vagrant-auto_network-1.0.2/lib/auto_network/action/filter_networks.rb:38:in `block in machines_for_env'
from /Users/kevin/.vagrant.d/gems/2.4.3/gems/vagrant-auto_network-1.0.2/lib/auto_network/action/filter_networks.rb:36:in `map'
from /Users/kevin/.vagrant.d/gems/2.4.3/gems/vagrant-auto_network-1.0.2/lib/auto_network/action/filter_networks.rb:36:in `machines_for_env'
from /Users/kevin/.vagrant.d/gems/2.4.3/gems/vagrant-auto_network-1.0.2/lib/auto_network/action/filter_networks.rb:30:in `filter'
from /Users/kevin/.vagrant.d/gems/2.4.3/gems/vagrant-auto_network-1.0.2/lib/auto_network/action/filter_networks.rb:18:in `call'
from /opt/vagrant/embedded/gems/2.0.3/gems/vagrant-2.0.3/lib/vagrant/action/warden.rb:34:in `call'
from /Users/kevin/.vagrant.d/gems/2.4.3/gems/vagrant-auto_network-1.0.2/lib/auto_network/action/load_pool.rb:19:in `call'
from /opt/vagrant/embedded/gems/2.0.3/gems/vagrant-2.0.3/lib/vagrant/action/warden.rb:34:in `call'
from /Users/kevin/.vagrant.d/gems/2.4.3/gems/vagrant-triggers-0.5.3/lib/vagrant-triggers/action/trigger.rb:17:in `call'
from /opt/vagrant/embedded/gems/2.0.3/gems/vagrant-2.0.3/lib/vagrant/action/warden.rb:34:in `call'
from /Users/kevin/.vagrant.d/gems/2.4.3/gems/vagrant-triggers-0.5.3/lib/vagrant-triggers/action/trigger.rb:17:in `call'
from /opt/vagrant/embedded/gems/2.0.3/gems/vagrant-2.0.3/lib/vagrant/action/warden.rb:34:in `call'
from /Users/kevin/.vagrant.d/gems/2.4.3/gems/vagrant-triggers-0.5.3/lib/vagrant-triggers/action/trigger.rb:17:in `call'
from /opt/vagrant/embedded/gems/2.0.3/gems/vagrant-2.0.3/lib/vagrant/action/warden.rb:34:in `call'
from /opt/vagrant/embedded/gems/2.0.3/gems/vagrant-2.0.3/lib/vagrant/action/builder.rb:116:in `call'
from /opt/vagrant/embedded/gems/2.0.3/gems/vagrant-2.0.3/lib/vagrant/action/runner.rb:66:in `block in run'
from /opt/vagrant/embedded/gems/2.0.3/gems/vagrant-2.0.3/lib/vagrant/util/busy.rb:19:in `busy'
from /opt/vagrant/embedded/gems/2.0.3/gems/vagrant-2.0.3/lib/vagrant/action/runner.rb:66:in `run'
from /opt/vagrant/embedded/gems/2.0.3/gems/vagrant-2.0.3/lib/vagrant/environment.rb:504:in `hook'
from /opt/vagrant/embedded/gems/2.0.3/gems/vagrant-2.0.3/lib/vagrant/environment.rb:165:in `initialize'
from /opt/vagrant/embedded/gems/2.0.3/gems/vagrant-2.0.3/bin/vagrant:131:in `new'
from /opt/vagrant/embedded/gems/2.0.3/gems/vagrant-2.0.3/bin/vagrant:131:in `<main>'

 

The most likely reason this happens is that plugins using Nokogiri have to build what are called native extensions each time. That means that the end result of that building is specific to your computer and various things on it. If those things change (e.g. Vagrant changes its version of Nokogiri), then the build becomes invalid and has to be redone.

In this case, it has to be redone across the board, and the easiest way is just to reinstall all plugins.

For that, you can use the vagrant plugin expunge --reinstall command.

You can then get back to developing!

 

(It’s worth noting that the command didn’t work on my older macOS computer, but it did work on my newer one. I’m not really sure why, since they have the same version of Vagrant. I just left the old computer as-was since I didn’t really need to fix it at the time.)

 

Source: https://github.com/hashicorp/vagrant/issues/9599

Posted in DevOps, Technology, Vagrant | Leave a comment

WizOne Solutions will be at Drupaldelphia and Drupal Dev Days Lisbon (so far)

I wasn’t planning on Drupaldelphia OR Drupal Dev Days this year, but I’ll be going to both. If you are too, and want to meet up or talk, get in touch via my contact form above or on Twitter.

 

P.S. I’m strongly considering going to DrupalCamp Nordics in Stockholm early September and Drupal Iron Camp in/near Belgrade mid-to-late October. Playing with the idea of WordCamp Vienna, too, but that’s much less likely :)

Posted in Uncategorized | Leave a comment

I’ve been busy!

You may notice that I haven’t blogged in quite some time. I was busy with a long-term client, so I was focusing more on that than this website. Things changed a bit, and I’ve decided to be more active here.

I have a couple blog posts in the pipeline, one on avoiding a nasty issue when PHPUnit in Drupal 8 to test an API powered by another Drupal 8 site.

I also want to give my impressions of DrupalCamp London 2018, which I attended.

Meanwhile, I’ve updated the site a bit. The old Services page is now the Solutions page. There is also a new Pricing page, which is still in progress.

I plan to make it easy to book time with me over the coming months.

Posted in Uncategorized | Leave a comment

Regular expressions: positive and negative lookaheads and lookbehinds

Do you work with regular expressions sometimes? If you do, and you don’t know about lookbehinds and lookaheads, you are missing out on a fantastic feature. I’m just pasting in something I said to some colleagues. Use your imagination and Google to extract the rest of the blog post 😉

[10/30/14, 10:11:44 PM] Kevin Kaland: man
[10/30/14, 10:11:53 PM] Kevin Kaland: lookaheads and lookbehinds in regex are awesome
[10/30/14, 10:11:58 PM] Kevin Kaland: I can’t believe I survived so long without them
[10/30/14, 10:12:46 PM] Kevin Kaland: you ever done a find/replace to change stuff like

nav.create
nav.formats-pricing

to

site.nav.create
site.nav.formats-pricing

and wound up accidentally with stuff like site.site.nav.create because you double-replaced?
[10/30/14, 10:13:07 PM] Kevin Kaland: if you use the regex (?<!site\.)nav\. for your find then this can’t happen
[10/30/14, 10:13:52 PM] Kevin Kaland: it won’t match it if it already has the site. in front. it’s called a negative lookbehind. negative meaning “it is not there” and lookbehind meaning that it checks before a particular string. there’s also positive look(ahead|behind)s, which make sure things are there.
[10/30/14, 10:14:08 PM] Kevin Kaland: but that text doesn’t become part of the actual match, which is the nice thing

Posted in Life of a Web Developer, Regex, Tips | Tagged , , , , , , , , , , | Leave a comment

I’ve open-sourced Spendflow; it’s a Meteor.js application

Spendflow, an application I’ve been developing on and off over the past year, is now open-source. What is perhaps more interesting is that it’s a Meteor application developed in CoffeeScript. Although Meteor is gaining traction and nearing 1.0, there are still not that many published applications built in Meteor.

I hope Spendflow will be a good example of how to structure a Meteor application of its kind (or that community feedback will soon make it so).

Get the code on GitHub: https://github.com/spendflow/spendflow

Read the full post on the Spendflow blog.

Posted in Meteor, News, Technology, Updates | Tagged , , , , , , , | Leave a comment

Disabling default rsync of the Vagrant Docker provider

Discovered today that Vagrant automatically rsyncs files to the Host VM when the Docker provider is used on a system that doesn’t natively support Docker.

Sometimes, though, one wants to sync the files to a custom location, and might get errors when trying to sync them to two locations on the Host VM (as I was).

To turn off Vagrant’s default sync, use the same syntax you would to turn off the /vagrant shared folder otherwise:

config.vm.synced_folder ".", "/vagrant", disabled: true

Thanks to @adamjt on GitHub for the tip: https://github.com/mitchellh/vagrant/issues/3680#issuecomment-42482434

Posted in DevOps, Life of a Web Developer, Technology, Vagrant | Tagged , , , , , | Leave a comment

lefnire.js: the weirdest Node.js API consumer ever

It must have all started with a joke on iRC that my friend lefnire, creator of HabitRPG, might just be an advanced Node.js program.

A few weeks later, a buddy and I took this to its logical conclusion.

But even with novelty projects, there are things to be learned, and this project has exposed me to npm modules I probably otherwise never would have used. I’m going to go over a few of the architectural highlights (npm and not) in no particular order.

Startup

After you npm install lefnire, typing lefnire runs him.

screenshot of lefnire.js

If you said, “ASCII art?” you would be correct. This was a friend’s idea, and it’s become a staple of the application.

API integration with the superagent and github modules

Currently, lefnire.js is lightly integrated with the HabitRPG and GitHub APIs. The HabitRPG API integration uses straight superagent requests. The GitHub API calls use github.

When you say something containing “habit down,” he makes an API call to https://habitrpg.com/api/v1/status to check.

When you ask him by his IRC name (I’ll be getting to IRC stuff in a second), he queries the GitHub API to find out the number of issues labeled “critical” for HabitRPG on GitHub.

IRC integration with the node-irc module

What would an automaton be without being able to log on to IRC and interact? lefnire.js uses node-irc to accomplish this. The library is pretty robust and follows Node.js patterns well. This is a fantastic example of an application that thrives on asynchronous execution. When you ask him if “habit is down,” and it is, that thread of execution will block. However, it won’t stop the bot from responding, thanks to the event listener model implemented by node-irc.

Mood and the Sentimental module

Another interesting feature is a rudimentary implementation of mood, which is basically just a number between 0 and 30 (0’s the best). This doesn’t do too much yet. It affects his behavior a little bit. The number of GitHub criticals is the baseline metric.

This is then adjusted up or down by how positive or negative Sentimental analyzes the up to the 30 most recent GitHub Events from lefnire to be. This is mostly issue comments, pull requests comments, and commit messages.

When lefnire is in-channel, it also adjusts mood based on Sentimental text analysis of what he says.

No database yet, so everything except what I can retrieve again through API calls is lost if I ctrl-C the bot and stop it.

Wrap-up

Those are the main highlights of the current implementation. A lot of things are planned. I doubt anyone would want to contribute to this, but I’d certainly be excited to receive some pull requests.

GitHub repository: https://github.com/litenull/lefnire.js

 

Posted in APIs, Life of a Web Developer, Node.js, Projects, Technology | Leave a comment