nongnu: Add brscan4.

* nongnu/packages/scanner.scm (brscan4): New variable.
This commit is contained in:
Pierre Neidhardt 2020-04-19 18:12:43 +02:00
parent da95ca97d4
commit e199cf436b

210
nongnu/packages/scanner.scm Normal file
View file

@ -0,0 +1,210 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2020 Pierre Neidhardt <mail@ambrevar.xyz>
;;;
;;; This file is not part of GNU Guix.
;;;
;;; GNU Guix is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; GNU Guix is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
(define-module (nongnu packages scanner)
#:use-module (ice-9 match)
#:use-module (guix packages)
#:use-module (nonguix build-system binary)
#:use-module (guix download)
#:use-module (gnu packages avahi)
#:use-module (gnu packages base)
#:use-module (gnu packages cpio)
#:use-module (gnu packages gcc)
#:use-module (gnu packages glib)
#:use-module (gnu packages gtk)
#:use-module (gnu packages package-management)
#:use-module (nonguix licenses))
;; TODO: This packaged should reproduce what NixOS does, but I couldn't get
;; the Brother MFC-J5335DW to work. There may be something wrong with my
;; scanner, or with Guix and Sane, or with this package.
;; See https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=brscan4
;; See https://nixos.wiki/wiki/Scanners
(define brscan4-version "0.4.8")
(define brscan4-i686-archive
(origin
(method url-fetch)
(uri (string-append "https://download.brother.com/welcome/dlf006647/brscan4-"
brscan4-version "-1.i386.rpm"))
(sha256
(base32 "0amp5j1likv1slfvlj2y22dnimljp7pzzg1z94fiwhlvk98m80pz"))))
(define brscan4-x86_64-archive
(origin
(method url-fetch)
(uri (string-append "https://download.brother.com/welcome/dlf006648/brscan4-"
brscan4-version "-1.x86_64.rpm"))
(sha256
(base32 "1bfdpf8z2ijr5gk3njffpy8zxw9fvyfw30ncrz4cfk15md7vwqfd"))))
(define (lib)
(if (string=? (or (%current-target-system) (%current-system)) "x86_64-linux")
"lib64" "lib"))
(define-public brscan4
(package
(name "brscan4")
(version brscan4-version)
(source #f)
(build-system binary-build-system)
(arguments
`(#:patchelf-plan
`(("opt/brother/scanner/brscan4/brsaneconfig4")
("opt/brother/scanner/brscan4/brscan_cnetconfig"
("avahi"))
("opt/brother/scanner/brscan4/brscan_gnetconfig"
("avahi" "glib" "gtk")))
#:install-plan
`((,,(string-append "usr/" (lib) "/sane/libsane-brother4.so.1.0.7") "lib/sane/")
("opt/brother/scanner/brscan4/" "opt/brother/scanner/brscan4/"
#:exclude ("setupSaneScan4" "udev_config.sh")))
#:modules ((guix build utils)
(nonguix build utils)
(nonguix build binary-build-system)
(srfi srfi-1)
(ice-9 regex)
(ice-9 textual-ports))
#:phases
(modify-phases %standard-phases
(replace 'unpack
(lambda* (#:key inputs #:allow-other-keys)
(system (format #f "rpm2cpio ~a | cpio -idmv"
(assoc-ref inputs "archive")))
#t))
(add-after 'install 'symlink-lib
(lambda* (#:key outputs #:allow-other-keys)
(let* ((out (assoc-ref outputs "out"))
(lib (string-append out "/lib/sane/libsane-brother4.so.1.0.7"))
(link (string-append out "/lib/sane/libsane-brother4.so.1.0.7")))
(symlink lib (string-append (dirname lib) "/libsane-brother4.so.1"))
(symlink lib (string-append (dirname lib) "/libsane-brother4.so")))
#t))
(add-after 'install 'set-sane-dll-conf
(lambda* (#:key outputs #:allow-other-keys)
(let* ((out (assoc-ref outputs "out"))
(dll (string-append out "/etc/sane.d/dll.conf")))
(mkdir-p (dirname dll))
(with-output-to-file dll
(lambda ()
(display "brother4"))))
#t))
(add-after 'install 'set-udev-rules
(lambda* (#:key outputs #:allow-other-keys)
(define (file->lines file)
(let ((file-string (call-with-input-file file
(lambda (f)
(get-string-all f)))))
(delete "" (string-split file-string #\newline))))
(define (maybe-print-line line)
(when (string-count line #\,)
(let* ((first-word (first (delete "" (string-split line #\,))))
(id-match (string-match "0[xX]([[:xdigit:]]+)" first-word)))
(when id-match
(format #t
(string-append "ATTR{idProduct}==\"~a\", "
"MODE=\"0664\", GROUP=\"scanner\", "
"ENV{libsane_matched}=\"yes\"~%")
(string-downcase (regexp-substitute #f id-match 1)))))))
(let* ((out (assoc-ref outputs "out"))
(rules (string-append out "/lib/udev/rules.d/49-brother-brscan4-libsane-type1.rules")))
(mkdir-p (dirname rules))
(with-output-to-file rules
(lambda ()
(format #t "~a~%~a~%~a~%"
"ACTION==\"add\", ATTR{idVendor}==\"04f9\", GOTO=\"brscan4\""
"GOTO=\"brscan4_end\""
"LABEL=\"brscan4\"")
(for-each
(lambda (file)
(for-each
maybe-print-line
(file->lines file)))
(cons "opt/brother/scanner/brscan4/Brsane4.ini"
(find-files "opt/brother/scanner/brscan4/models4"
"\\.ini$")))
(format #t "LABEL=\"brscan4_end\"~%"))))
#t))
(add-after 'build 'build-preload
;; Generate an LD_PRELOAD wrapper to redirect execvp(), open() and
;; open64() calls to `/opt/brother/scanner/brscan4`.
(lambda* (#:key inputs outputs system #:allow-other-keys)
(let* ((out (assoc-ref outputs "out"))
(preload-src (assoc-ref inputs "preload"))
(preload (string-append
out "/libexec/brother/scanner/brscan4/libpreload.so")))
(mkdir-p (dirname preload))
(apply invoke "gcc"
(append
(if (string=? system "x86_64-linux")
;; FIXME: For some reason glibc32 has higher
;; priority than the 64-bit version.
(list (string-append "-L" (assoc-ref inputs "glibc64") "/lib"))
'())
(list
"-shared" preload-src "-o" preload "-ldl"
(string-append "-DOUT=\"" out "\"") "-fPIC"))))
#t))
(add-after 'build-preload 'wrap-program
(lambda* (#:key inputs outputs #:allow-other-keys)
(let* ((out (assoc-ref outputs "out"))
(preload (string-append
out "/libexec/brother/scanner/brscan4/libpreload.so"))
(wrapper (string-append out "/bin/brsaneconfig4"))
(bin (string-append out "/opt/brother/scanner/brscan4/brsaneconfig4")))
(mkdir-p (dirname wrapper))
(make-wrapper wrapper bin
`("LD_PRELOAD" ":" prefix ,(list preload))))
#t)))))
(native-inputs
`(("rpm" ,rpm)
("cpio" ,cpio)
("archive"
,(match (or (%current-target-system) (%current-system))
("x86_64-linux" brscan4-x86_64-archive)
(_ brscan4-i686-archive)))
("gcc" ,gcc)
,@(if (string=? (or (%current-target-system) (%current-system)) "x86_64-linux")
`(("glibc64" ,glibc))
'())
("preload"
,(origin
(method url-fetch)
(uri (string-append "https://raw.githubusercontent.com/NixOS/nixpkgs/"
"15b3d9d2773b6ff919b324d756e23f0f8bf9fc3f" ; 2020-05-16
"/pkgs/applications/graphics/sane/backends"
"/brscan4/preload.c"))
(sha256
(base32
"0dgp2qy9j7qjf2ld5hh921iaizwxwyspfjfp5p8p0bd5q0n45g6k"))))))
(inputs
`(("avahi" ,avahi)
("glib" ,glib)
("gtk" ,gtk+-2)))
(home-page "http://support.brother.com/")
(supported-systems '("i686-linux" "x86_64-linux"))
(synopsis "Driver, detection and configuration tool for Brother scanners")
(description "Driver, detection and configuration tool for Brother
scanners. It also supports specifying an alternate file name for
@file{brsanenetdevice4.cfg} via the @command{BRSANENETDEVICE4_CFG_FILENAME}
environment variable, otherwise the file is invariably created at
@file{/etc/opt/brother/scanner/brscan4}.")
(license (nonfree "No URL"))))