The “git archive” man page states:
git archive behaves differently when given a tree ID versus when given a commit ID or tag ID. In the first case the current time is used as the modification time of each file in the archive.
By using the current time in this case, git-archive is dooming all of our tarballs to have constantly changing SHA256 hashes. A lot of build systems, including Fedora’s Koji, rely on source tarballs maintaining a consistent fingerprint. What is a person to do?
Fix it of course! Below is a Python 2 program I wrote that addresses the issue. The code is well-commented (I hope) so you should be able to follow along. You give it the Unix timestamp you want the files to have, the git ref you want baked into the tar header, and the initial tarball. The result is printed to stdout so just redirect that to wherever you please (or pipe it into gzip). It also has some code in there to deal with tarballs created by the maven-assembly plugin, but it doesn’t surface that on the primitive CLI. I’m leaving that as an exercise for the reader I guess.
Recently I noticed that in my IRC client, when I right-click a URL and select “Open Link In Browser”, the system would open a new browser window (or tab if appropriate) but not pointed to the link I wanted to visit. It would just open the home page.
What gives? Well, I happen to know from experience that in Linux most programs that need to use a “default” type service of which there are many implementations (such as a web-browser) use the xdg-open
command. XDG associates different mime-types to default applications. Step one then is to figure out what’s going on with XDG.
% xdg-mime query default text/html
firefox.desktop firefox.desktop
Here I’m asking XDG what applications are associated with the text/html
mime-type. Seeing two firefox.desktop files was a bit of a surprise. Let’s find out more!
% locate firefox.desktop
/usr/share/applications/firefox.desktop
/usr/share/xfce4/helpers/firefox.desktop
So I open up those two files and the first file looks normal and that file actually belongs to the Firefox package according to rpm -qf
. In the second file, I see
X-XFCE-Commands=%B -remote "openURL(about:blank,new-window)";%B;
X-XFCE-CommandsWithParameter=%B -remote "openURL(%s,new-window)";%B "%s";
That looks strange to me. If I want to open a URL from the command line, I don’t use openURL
. Let’s see what happens if I replace that with
X-XFCE-Commands=%B;
X-XFCE-CommandsWithParameter=%B "%s";
Aha! It works! But why? Well, after a little searching I came across Mozilla Bug 1080319. Looks like the openURL
was a legacy thing and got removed in Firefox 36. And a quick rpm -q firefox
confirms that I’m running that version. Firefox 36.0.1 add support for openURL
back in, but my hack will serve until that version hits Fedora.
I wanted to use a Logitech R400 that a friend loaned my in a presentation, but I wanted to tweak the mappings for the buttons a bit. My presentation is done using Reveal.js and uses both left/right and up/down. The R400 has four buttons but two of them are mapped to “go to black screen” and “slideshow mode” neither of which is useful to me. Here is how I fixed it in Fedora 20.
/etc/udev/hwdb.d
/etc/udev/hwdb.d/99-logitech-r400.hwdb
# The lower left button actually emits two
# different scancodes depending on the state of
# the "presentation".
# E.g. one code to start and one to stop.
keyboard:usb:v046DpC538
KEYBOARD_KEY_70029=up
KEYBOARD_KEY_7003E=up
KEYBOARD_KEY_70037=down
KEYBOARD_KEY_7004B=left
KEYBOARD_KEY_7004E=right
This maps the left and right buttons to left and right, the both states of the slideshow button to up, and the blank screen button to down. The 046D
is the Logitech vendor code and the C538
is the model number. Those magic numbers after “KEYBOARD_KEY” are the scancodes associated with the button. Supposedly showkey --scancodes
will display them but I couldn’t get that to work and ended up taking them from another blog post.
# udevadm hwdb --update && udevadm trigger
# xev | grep -A2 --line-buffered '^KeyRelease' | sed -n '/keycode /s/^.*keycode \([0-9]*\).* (.*, \(.*\)).*$/\1 \2/p'
/etc/udev/rules.d/99-logitech-r400.rules
SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c538", IMPORT{builtin}="hwdb 'keyboard:usb:v046DpC538'", RUN{builtin}+="keyboard"
That will import our custom mapping when the USB receiver is plugged in.
Thanks to the following who helped me figure all this out:
In my experience, the best way to learn about how to package RPMs is to look at how other people package RPMs. That means looking at lots of spec files. Sure fedpkg
will let you clone lots of package repos, but what if you only have the SRPM? You can get the spec file out of a SRPM, but it takes a little work with cpio
, a tool with so many options that I can never remember the exact invocation. So I wrote a quick two-liner to save me some aggravation:
#! /bin/sh
spec=$(rpm -qlp $1 | grep -E '\.spec$')
rpm2cpio $1 | cpio -i --to-stdout $spec
And how can you get the SRPM? Simple, install yum-utils
then run
$ yumdownloader --source --downloadonly PACKAGE_NAME
I use mock frequently when I am building packages for Fedora. Koji is great, but mock really shines when you are rapidly iterating over spec file changes. The --no-clean
option keeps the chroot around so you don’t have to download packages repeatedly and you can actually look around inside the chroot to see where a build is going wrong if you need to.
I also use repoquery a lot to see what a package requires or provides. Knowing what a package requires or provides is especially helpful when you’re doing builds. By default repoquery runs against the repos in /etc/yum.repos.d
. Wouldn’t it be nice if we could run repoquery against the repos set up in our mock configs?
It turns out that you can. Repoquery takes a --repofrompath
argument that can be used to create an ad hoc repo to query. The only missing piece is reading the mock config, grabbing the repo URL, and formatting it.
I wrote a little Zsh function to do just that.
#! /bin/zsh
mock-repoquery() {
local profile="$1"
[ -f "$profile" ] || profile="/etc/mock/${1}.cfg"
# Take all baseurls in a file and make them into an array
# See Parameter Expansion Flags section of the zshexpn man page and
# http://unix.stackexchange.com/a/29748
local repo_urls
repo_urls=("${(@f)$(sed -n -r 's/.*baseurl=(.*)(\\n|$)/\1/p' $profile | cut -d'\' -f1)}")
local repo_args
repo_args=()
for ((i=1; i <= ${#repo_urls}; i++)); do
repo_args+="--repofrompath=r${i},$repo_urls[i]"
repo_args+="--repoid=r${i}"
done
repoquery "${repo_args[@]}" "$@[2,-1]"
}
mock-repoquery "$@"
Drop the above code into ~/.zfunc/mock-repoquery
and then add the following to ~/.zshrc
fpath=( ~/.zfunc "${fpath[@]}" )
autoload -Uz mock-repoquery
Then you can use mock-repoquery
by passing a mock profile as the first argument. Any additional arguments will be forwarded to repoquery. For example:
$ mock-repoquery /etc/mock/fedora-20-x86_64.cfg --requires tig
git
libc.so.6(GLIBC_2.15)(64bit)
libncursesw.so.5()(64bit)
libtinfo.so.5()(64bit)
rtld(GNU_HASH)
Note that mock-repoquery
will only work in Zsh due to my usage of Zsh parameter expansion. Converting this function to work in Bash is possible, but I use Zsh so I didn’t bother. Patches will be accepted happily!