Search code examples
homebrewfile-permissionsautomake

automake correctly setting +x bit on dist_bin_SCRIPTS except when installed from a brew formula


I have a few scripts to setup my tmux development environment and I'm trying to packaging them up into a brew formula but I've hit a snag.

Locally running:

% ./configure
% make install

produces two scripts from *.in and runs chmod +x on each one successfully. The files it generates are both executable (0755).

The output of ls in the project folder after manually running ./configure && make is:

~/repositories/tmuxide/scripts on :master? (2895bf9) tracking origin/master
****@****(ttys002)[1062] % ls
total 104
drwxr-xr-x   9 frankjmattia  staff   306B Jun 16 22:10 .
drwxr-xr-x  24 frankjmattia  staff   816B Jun 16 22:10 ..
-rw-r--r--   1 frankjmattia  staff    14K Jun 16 22:09 Makefile
-rw-r--r--   1 frankjmattia  staff   405B Jun 16 22:08 Makefile.am
-rw-r--r--   1 frankjmattia  staff    14K Jun 16 22:09 Makefile.in
-rwxr-xr-x   1 frankjmattia  staff   1.7K Jun 16 22:10 log-pane
-rw-r--r--   1 frankjmattia  staff   1.7K Jun 12 20:35 log-pane.in
-rwxr-xr-x   1 frankjmattia  staff   2.1K Jun 16 22:10 tmuxide
-rw-r--r--   1 frankjmattia  staff   2.1K Jun 16 22:04 tmuxide.in

And the output of ls in the folder where homebrew installs it is:

/usr/local/Cellar/tmuxide/0.0.3.j/bin on :master (3fec4c9)
*****@****(ttys002)[1056] % ls
total 16
drwxr-xr-x  4 frankjmattia  admin   136B Jun 16 22:11 .
drwxr-xr-x  6 frankjmattia  admin   204B Jun 16 22:11 ..
-r--r--r--  1 frankjmattia  admin   1.7K Jun 16 22:11 log-pane
-r--r--r--  1 frankjmattia  admin   2.1K Jun 16 22:11 tmuxide

Here are the important parts of the files at play:

configure.ac

AC_PREREQ([2.69])
AC_INIT([tmuxide], [0.0.3.j], [[email protected]])
AM_INIT_AUTOMAKE
AC_OUTPUT(Makefile man/Makefile scripts/Makefile)
AC_OUTPUT

scripts/Makefile.am

dist_bin_SCRIPTS = tmuxide log-pane
CLEANFILES = $(dist_bin_SCRIPTS)

EXTRA_DIST = tmuxide.in log-pane.in

do_subst = sed \
    -e 's,[@]PACKAGE[@],$(PACKAGE),g' \
    -e 's,[@]PACKAGE_VERSION[@],$(PACKAGE_VERSION),g'

tmuxide: tmuxide.in Makefile
    $(do_subst) < $(srcdir)/tmuxide.in > tmuxide
    chmod +x tmuxide

log-pane: log-pane.in Makefile
    $(do_subst) < $(srcdir)/log-pane.in > log-pane
    chmod +x log-pane

However, when I wrap this in a brew formula, the generated files are only readable (0444).

homebrew/tmuxide.rb

require "formula"

class Tmuxide < Formula
  homepage 'https://github.com/frankjmattia/tmuxide'
  url 'https://frankjmattia.github.io/tmuxide/tmuxide-0.0.3.j.tar.gz'
  sha1 '5e51b66013a4afd60c362ce448b7e976cf7d6d6e'

  depends_on 'gnu-getopt'

  def install
    system './configure', '--disable-silent-rules',
                          "--prefix=#{prefix}"

    system 'make', 'install'
  end
end

I can't figure out where things are going wrong and any suggestions would be greatly appreciated.

You can find the complete source at github.com/frankjmattia/tmuxide


Solution

  • Finally got it to work.

    I ran brew install tmuxide -vd and at the end of the run I noticed this gem

    ==> Cleaning
    Fixing /usr/local/Cellar/tmuxide/0.0.3.k/bin/log-pane permissions from 755 to 444
    Fixing /usr/local/Cellar/tmuxide/0.0.3.k/bin/tmuxide permissions from 755 to 444
    

    Digging into the homebrew source I found this:

    [@f.bin, @f.sbin, @f.lib].select{ |d| d.exist? }.each{ |d| clean_dir d }
    

    clean_dir basically goes through each file and if it's a binary executable or text executable file it adjusts the execute bit accordingly. If it's not, it removes the execute bit.

    Then I stumbled up this stack overflow question which led me to believe I should have been using libexec to distribute these files. the clean_dir method didn't change anything in libexec so my file permissions were preserved but my journey was far from over.

    After getting this to work I then had to symlink these to /usr/local/bin because libexec isn't in path. So I added bin.install_symlink "#{libexec}/tmuxide" to the formula. That worked - but it wasn't the right solution. After putzing around I went back and looked at the clean_dir method again to see what constituted a text_executable? pathname.

    def text_executable?
      %r[^#!\s*\S+] === open('r') { |f| f.read(1024) }
    end
    

    I went back to my script (because I knew I had a shebang in there) and realized my shebang line wasn't properly formed. I made it an ordinary comment # /usr/bin/env zsh. After correcting that to #!/usr/bin/env zsh everything proceeded as normal.

    @ldav1s Thanks for the good tips on automake. Your help was appreciated.