Category: Technology

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

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

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.

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

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

 

Toolbox page launched

You may have noticed there’s a new tab on the site: Toolbox. This is a simple list of various tools I use in my day-to-day work and in running the business. There’s no need to keep the fact that I use them secret, so I thought I’d start maintaining a page of said tools. It will also hopefully help me generate some affiliate income.

So check it out, and if any of the tools on it interest you, check them out!

Joomla!

I’ve been playing around with Joomla! lately, and it seems to have its pros and cons. Compared to Drupal, it seems a little unnecessarily complex at times, and I don’t really understand the naming conventions for its extensions (“modules,” at least – blocks, the Drupal equivalent, is a much clearer term).

The administration interface is worth applause, though…Drupal’s is simpler, although it can be souped up with modules. It seems like Joomla! has more out-of-the-box but that Drupal is easier to get going with and to tailor to one’s needs. I prefer the latter, since it gives more flexibility to the creation and presentation of content.

Drupal’s also got much nicer URLs, and turning on its “Clean URLs” is super-easy.

So I’m still on the Drupal side, but if you think I should reconsider or try to get more into Joomla!, let me know in the comments.

At some point, I’ll do a proper comparison between the two.