Debian – dh_usrlocal: … is not a directory

debianpackage-management

I'm working on a Makefile setup to create a debian package:

.PHONY: package
package: $(PACKAGE_TARGETS)

build/%.changes: ../%.changes
        mkdir -p build
        for f in `<$< awk 'BEGIN { files = 0; } { if (files) print $$5; } /^Files:/ { files = 1; }'`; do \
            test -f build/$$f || mv ../$$f build/; \
        done
        mv $< $@

../%.changes:
        dpkg-buildpackage -rfakeroot -b -uc

Everything was working fine with the build until I made a very small commit. Which adds an executable file at /src/bin/app-cli. Then references that executable in the debian install file debian/app.install:

src/bin/app-cli usr/local/bin

For some reason making that change caused the build system to generate the error:

dh_usrlocal: debian/app/usr/local/bin/app-cli is not a directory
rmdir: failed to remove 'debian/app/usr/local/bin': Directory not empty
dh_usrlocal: rmdir debian/app/usr/local/bin returned exit code 1
make[1]: *** [binary] Error 1
make[1]: Leaving directory `/var/lib/jenkins/data/workspace/app-VBJPWWOTACEEMDGNNWMFS4QU6K4EPG5PJRESMEIZPZL4GAUCKWVQ'
dpkg-buildpackage: error: fakeroot debian/rules binary gave error exit status 2
make: *** [../app_0.0.1-13-master_amd64.changes] Error 2

Does anyone know this new file is being treated as directory by Debian Helper?

Best Answer

The dh_usrlocal manpage might help you understand what’s going on.

Debian packages are allowed to install directories under /usr/local, but the best way to do so is to use maintainer scripts. dh_usrlocal automates this by transforming directories under /usr/local into maintainer script snippets. It assumes these directories are empty, since Debian packages aren’t allowed to install files under /usr/local.

In your package, dh_install follows your instructions and copies app-cli to /usr/local/bin (inside your package). dh_usrlocal then runs, sees the directory, creates the appropriate maintainer script, then tries to delete the directory (so it isn’t shipped as such in the package) — and fails since it contains a file.