Permission denied errors with HomeBrew & Maven / Could not resolve dependencies with lein

Like so many developers with a Mac I was pleased with the fact that homebrew at last offered package management on OS X that works as easily as it does on linuxes; but never quite managed to deal with all the issues that brew doctor listed.

Which I could ignore until I started using maven and leiningen (which uses maven). Because maven is itself a package manager, so the user id with which you brew installed it may prevent you using it later.

It starts (in my case) with

brew install maven

which failed because I didn't have write access to /usr/local/opt or something.
Undoubtedly the right step in future is to chmod /usr/local/ at this point. But I didn't, instead I

sudo brew install maven

which worked. This might not have mattered but then I also

sudo brew install leiningen

Which installed something or other into my maven repository. As root. I tested my new install with lein new at the command line and that works so I merrily plough ahead with installing clojure and leiningen plugins into my IntelliJ IDE, try the get started project and ... get errors in the ide:
ExceptionInfo: Could not resolve dependencies: Could not resolve dependencies
Back to the command line, and I realise that although lein new works, almost no other lein command does - they all fail with a million lines of output somewhere in which I find some permissions issue when trying to install a different version of clojure to the one I'd already installed:

Downloading: org/clojure/clojure/1.3.0/clojure-1.3.0.pom from repository central at http://repo1.maven.org/maven2
[WARNING] Unable to get resource 'org.clojure:clojure:pom:1.3.0' from repository central (http://repo1.maven.org/maven2): Specified destination directory cannot be created: /Users/myusername/.m2/repository/org/clojure/clojure/1.3.0
Downloading: org/clojure/clojure/1.3.0/clojure-1.3.0.pom from repository clojars at http://clojars.org/repo/
[WARNING] Unable to get resource 'org.clojure:clojure:pom:1.3.0' from repository clojars (http://clojars.org/repo/): Specified destination directory cannot be created: /Users/myusername/.m2/repository/org/clojure/clojure/1.3.0
Downloading: org/clojure/clojure/1.3.0/clojure-1.3.0.jar from repository central at http://repo1.maven.org/maven2
[WARNING] Unable to get resource 'org.clojure:clojure:jar:1.3.0' from repository central (http://repo1.maven.org/maven2): Specified destination directory cannot be created: /Users/myusername/.m2/repository/org/clojure/clojure/1.3.0
Downloading: org/clojure/clojure/1.3.0/clojure-1.3.0.jar from repository clojars at http://clojars.org/repo/
[WARNING] Unable to get resource 'org.clojure:clojure:jar:1.3.0' from repository clojars (http://clojars.org/repo/): Specified destination directory cannot be created: /Users/myusername/.m2/repository/org/clojure/clojure/1.3.0
An error has occurred while processing the Maven artifact tasks.
 Diagnosis:
Unable to resolve artifact: Missing:
----------
1) org.clojure:clojure:jar:1.3.0

  Try downloading the file manually from the project website.
..etc ... etc..

Grr. I suppose I'd better try to fix those brew doctor errors.

Fixing the homebrew brew doctor errors

I decide to ignore the errors the brew doctor gives about other *-config files installed. Why shouldn't I have? I also ignore homebrew's desire to have /usr/local/bin ahead of /usr/bin in my path as I have no idea what the impact of changing it will be. I assume Apple set it that way but then again maybe macPorts did it a decade ago.

But I do want to fix the 'no write permissions issues':

This set of errors:
Warning: /usr/local/etc isn't writable.
You should probably `chown` /usr/local/etc
...
Warning: /usr/local/include isn't writable.
You should probably `chown` /usr/local/include
...
Warning: /usr/local/share isn't writable.
You should probably `chown` /usr/local/share

I fixed this not by chowning but by adding myself to the wheel group, which might or might not have been a bad idea. But I didn't like the idea that the homebrew install on my machine was tied to my login.

# "g+u" copies all the permissions that the user has to the group
sudo chmod -R g+u /usr/local/share/
# add myself to the wheel group so that I have group access to all the stuff that homebrew installed
# actually I could have sworn I already was a member of wheel because of being an admin user but I didn't see wheel when I typed id. 
sudo /usr/sbin/dseditgroup -o edit -a myusername -t user wheel

Fixing the maven repository 'Specified destination directory cannot be created' errors

This isn't too hard. I examine the exact path in the error message and then find that my earlier sudo brew install leiningen has resulted in the org.clojure directory in my maven repository being owned by root, and I have no write permissions to it:

ls -l /user/myusername/.m2/repository/org
# rwxr-xr-x   6 myusername  staff  204 Jan  9 14:59 antlr
# drwxr-xr-x  10 myusername  staff  340 Jan 14 15:37 apache
# drwxr-xr-x   4 myusername  staff  136 Jan  9 14:58 aspectj
# drwxr-xr-x   9 myusername  staff  306 Jan  9 14:59 atmosphere
# drwxr-xr-x   3 root      staff  102 Jan 15 06:59 clojure
# aha. Bits of my repository - the clojure dir -  is owned by root and I don't have write permissions.
#
# This time I'm happy to chown because the repository is in my home directory anyway.
sudo chown -R myusername /Users/myusername/.m2/repository/

If was starting from scratch I'd probably prefer a repository for the machine, but I didn't pay attention to the
=> Caveats
Standalone jar and dependencies installed to:
$HOME/.m2/repository

message when I installed maven. Because of course I just wanted to install maven and get on with using it.

And now leiningen works. Mostly.

Now I try lein again:

lein test

Woohoo. lein can now successfully downloads its dependencies, and it works.
Back to IntelliJ and press the lein go button: that works too. Now I can run and test clojure.
But wait. Now I try to follow the palletOps quickstart instructions and I get error messages again. Eventually I find that there are files in ~/.lean which are also owned by root so I also need:

sudo chown -R myusername /Users/myusername/.lein

Remove HomeBrewed leiningen and download leiningen 2 from Github

By this time I was fed-up. And, homebrew had installed lein 1.7.1 but lein 2 is already mainstream. So I gave up on the homebrew'd install of leiningen and went native as per https://github.com/technomancy/leiningen/wiki/Upgrading. (Give or take the fact that I've got curl on OS X, not wget. Oh wait, there's a brew for that 😉 )

sudo brew uninstall lein
sudo rm -Rf ~/.lein
sudo curl https://raw.github.com/technomancy/leiningen/preview/bin/lein -o /usr/bin/local/lein
lein self-install

There. That's better. Now it works properly.

References

Making TDD even more efficient

Kent Beck is still kind of working on unit testing tools -- a couple of simple but great ideas that are baked into his re-launched JUnitMax:

  1. When running a test suite after a failure, give the most useful feedback first -- by running the failures first before the rest of the suite
  2. Otherwise, run the fastest tests first. This gives you 99% of the feedback as fast as possible
  3. Alas, only currently available for Eclipse.

The Cloud defined in a sentence, 12 bullet points and 3 pictures

Kudos to someone at apps.gov or NIST for a great 2 minute summary of the cloud. My summary of the summary:

Cloud Computing Defined

Cloud computing is a model for enabling convenient, on-demand network access to a shared pool of configurable computing resources e.g., networks, servers, storage, applications, and services that can be rapidly provisioned and released with minimal management effort.
Cloud computing - picture by http://cloudtimes.org

Five Characteristics of Cloud Computing

  • On-demand, self service
  • Wide network access
  • Resources dynamically shared and allocated across customers
  • Elastic rapid provision and release
  • Metered service

Three Main Layers of Service Provided by Cloud Computing

  • Saas: Software as a service, for end-user consumers
  • Paas: Platform as a service, for software developers
  • Iaas: Infrastructure as a service, for system administrators

Two Axes of Choice for Cloud Deployment

  • Public vs Private
  • Outsourced vs In-house

And finally a bonus:

A History of Cloud Computing in Three Sentences

  • It began life as "Grid Computing" - a technology to solve large problems with parallel computing on widely distributed resources.
  • Grid computing matured to be offered as a metered service known as "utility computing".
  • This evolved via packaged solutions and self-service subscription over the internet into what is now known as Cloud Computing.

Condensed from http://info.apps.gov/content/what-cloud

AppleScript : Start a background process and get the pid to kill it

Like so:

do shell script ("cd /Users/myName/Sites/FitNesse ; java -jar fitnesse-standalone.jar -p 5555  &> fitNesse.log & echo $!")
set pid to the result
open location "http://localhost:5555/"
display dialog "Press okay to shutdown FitNesse (" & pid & ")" buttons {"OK"}
do shell script ("kill " & pid)

To see it work, open AppleScript Editor, and paste in the script.
Save it first as a script, then Export it as an Application.

A couple of tricks are involved, the two least well-known are perhaps:

  • $! will return the pid of the most recently started background process
  • You may not need to log output but you still apparently need an output redirection clause such as &> /dev/null". Otherwise AppleScript waits for the stdout / stderr to free up. Which never happens.
  • You usually want to cd to the right directory when you run a shell script from AppleScript