Getting a list of `PackageDescriptions` from the local database - haskell

Is there anyway, presumably using the Cabal package, to get a list of PackageDesciptions in the current local database?

I don't know if there's a "built-in"-way of doing this, but I've used this
ghc-pkg list | grep -v "\(^/\|^$\|(\)" | xargs cabal info | grep "\(^\*\|License\)"
to extract "License" info for all installed packages.
If you use stack or cabal-sandbox - the first command needs to be replaced by either stack exec -- ghc-pkg list or cabal sandbox hc-pkg list.
the (first) regex removes the path-lines like /opt/ghc/8.0.2/lib/ghc-8.0.2/package.conf.d, empty lines and lines starting with ( - somehow the colored lines produced by ghc-pkg like ghc-8.0.2 end up with starting ( in my terminal when grepping.
"map cabal info over all packages"
[optional] extracting the package information for the package itself (starting with * and the License field.
I hope this is what you were looking for. Another way, I think, would be writing a haskell program and use Cabal as a library.

Related

Freezing all dependencies when building executables with `cabal v2-install`

I am building a Docker image in which I want to bundle multiple executables. Each executable is defined in a different package, in my case pandoc, pandoc-citeproc, and pandoc-crossref. The build should be as reproducible as reasonably possible on a Debian/Ubuntu based system.
What I'd like to do is use (something like) a cabal.project.freeze file to ensure that all subsequent builds will use the same packages.
I'm aware that I can fix the version of the executables:
cabal v2-install pandoc-2.7.3 pandoc-citeproc-0.16.2 pandoc-crossref-0.3.4.1
But this will not fix the versions of transitive dependencies, so rebuilding at different times may lead to subtly different build results. Can I somehow create and use a freeze file in this setup? Using v2-freeze seems to be of no use here:
$ cabal new-freeze pandoc-2.7.3 pandoc-citeproc-0.16.2 pandoc-crossref-0.3.4.1
cabal: 'freeze' doesn't take any extra arguments: pandoc-2.7.3
pandoc-citeproc-0.16.2 pandoc-crossref-0.3.4.1
Okay, there might be a better built-in way to do this kind of thing, but here's a hacky workaround that might be suitable for you until a real cabal expert comes along.
The basic plan will be this: temporarily create a project with the three packages you care about -- just long enough to get a freeze file -- then use some simple text-editor macros to turn the freeze file into a v2-install command. So:
% cabal unpack pandoc-2.7.3 pandoc-citeproc-0.16.2 pandoc-crossref-0.3.4.1
% echo >cabal.project packages: pandoc-2.7.3 pandoc-citeproc-0.16.2 pandoc-crossref-0.3.4.1
% cabal v2-freeze
% sed "s/^constraints: /cabal v2-install pandoc-2.7.3 pandoc-citeproc-0.16.2 pandoc-crossref-0.3.4.1 --constraint '/;s/^ \+/--constraint '/;s/,\$/' \\\\/;\$s/\$/'/" cabal.project.freeze >cabal-v2-install.sh
Woof, that last one is a mouthful. It says:
# Replace the starting "constraints" stanza with the v2-install command we want to
# run. The first line of the stanza includes a constraint, so prefix it with
# --constraint and start a quote.
s/^constraints: /cabal v2-install pandoc-2.7.3 pandoc-citeproc-0.16.2 pandoc-crossref-0.3.4.1 --constraint '/
# The line we just produced doesn't start with spaces, so this only fires on the
# remaining lines. On those lines, it prefixes --constraint and starts a quote.
s/^ \+/--constraint '/
# Close the quote begun on each line, and replace cabal's line-continuation
# character (,) with a shell's line-continuation character (\). The $ and \ are
# escaped because we are inside the current shell's ""-quoted string.
s/,\$/' \\\\/
# The last line doesn't have a line-continuation character, but still needs its
# quote closed. The two occurrences of $ are escaped because we are inside the
# current shell's ""-quoted string.
\$s/\$/'/
You could also do these manually in an editor if you wanted. At the end of this process, which you can run in a temporary directory to ease cleanup afterwards, you should have a file named cabal-v2-install.sh with a command that will select the exact same versions and flags for all packages involved, including dependencies.

Can I print the "description" field of an RPM package info in one line only

I need to get info of some RPM package and then parse them, so I use the rpm -q --qf [FORMAT] [PACKAGE] command.
It is working fine but the description field of the package is always on multiple lines and it is making my job more difficult for parsing. Is there a way to get this field on one line only with a specific format?
Here is my current format string: Name:%{NAME}\nVersion:%{VERSION}\nRelease:%{RELEASE}\nArchitecture:%{ARCHITECTURE}\nInstall Date:%{INSTALLTIME:date}\nDescription:%{DESCRIPTION}\n
I am afraid that the answer is no, you cannot have it on one line. The description is multiline text and the new line characters are put there by package maintainers.

How to replace paths to executables in source code with Nix that are not in PATH

I wish to write some Haskell that calls an executable as part of its work; and install this on a nixOS host. I don't want the executable to be in my PATH (and to rely on that would disrupt the beautiful dependency model of nix).
If this were, say, a Perl script, I would have a simple builder that looked for strings of a certain format, and replaced them with the executable names, based upon dependencies declared in the .nix file. But that seems somewhat harder with the cabal-based building common to haskell.
Is there a standard idiom for encoding the paths to executables at build time (including during development, as well as at install time) within Haskell code on nix?
For the sake of a concrete example, here is a trivial "script":
import System.Process ( readProcess )
main = do
stdout <- readProcess "hostname" [] ""
putStrLn $ "Hostname: " ++ stdout
I would like to be able to compile run this (in principle) without relying on hostname being in the PATH, but rather replacing hostname with the full /nix/store/-inetutils-/bin/hostname path, and thus also gaining the benefits of dependency management under nix.
This could possibly be managed by using a shell (or similar) script, built using a replacement scheme as defined above, that sets up an environment that the haskell executable expects; but still that would need some bootstrapping via the cabal.mkDerivation, and since I'm a lover of OptParse-Applicative's bash completion, I'm loathe to slow that down with another script to fire up every time I hit the tab key. But if that's what's needed, fair enough.
I did look through cabal.mkDerivation for some sort of pre-build step, but if it's there I'm not seeing it.
Thanks,
Assuming you're building the Haskell app in Nix, you can patch a configuration file via your Nix expression. For an example of how to do this, have a look at this small project.
The crux is that you can define a postConfigure hook like this:
pkgs.haskell.lib.overrideCabal yourProject (old: {
postConfigure = ''
substituteInPlace src/Configuration.hs --replace 'helloPrefix = Nothing' 'helloPrefix = Just "${pkgs.hello}"'
'';
})
What I do with my xmonad build in nix1 is refer to executable paths as things like ##compton##/bin/compton. Then I use a script like this to generate my default.nix file:
#!/usr/bin/env bash
set -eu
packages=($(grep '##[^#]*##' src/Main.hs | sed -e 's/.*##\(.*\)##.*/\1/' | sort -u))
extra_args=()
for p in "${packages[#]}"; do
extra_args+=(--extra-arguments "$p")
done
cabal2nix . "${extra_args[#]}" \
| head -n-1
echo " patchPhase = ''";
echo " substituteInPlace src/Main.hs \\"
for p in "${packages[#]}"; do
echo " --replace '##$p##' '\${$p}' \\"
done
echo " '';"
echo "}"
What it does is grep through src/Main.hs (could easily be changed to find all haskell files, or to some specific configuration module) and pick out all the tags surrounded by## like ##some-package-name##. It then does 2 things with them:
passes them to cabal2nix as extra arguments for the nix expression it generates
post-processes nix expression output from cabal2nix to add a patch phase, which replaces the ##some-package-name## tag in the Haskell source file with the actual path to the derivation.2
This generates a nix-expression like this:
{ mkDerivation, base, compton, networkmanagerapplet, notify-osd
, powerline, setxkbmap, stdenv, synapse, system-config-printer
, taffybar, udiskie, unix, X11, xmonad, xmonad-contrib
}:
mkDerivation {
pname = "xmonad-custom";
version = "0.0.0.0";
src = ./.;
isLibrary = false;
isExecutable = true;
executableHaskellDepends = [
base taffybar unix X11 xmonad xmonad-contrib
];
description = "My XMonad build";
license = stdenv.lib.licenses.bsd3;
patchPhase = ''
substituteInPlace src/Main.hs \
--replace '##compton##' '${compton}' \
--replace '##networkmanagerapplet##' '${networkmanagerapplet}' \
--replace '##notify-osd##' '${notify-osd}' \
--replace '##powerline##' '${powerline}' \
--replace '##setxkbmap##' '${setxkbmap}' \
--replace '##synapse##' '${synapse}' \
--replace '##system-config-printer##' '${system-config-printer}' \
--replace '##udiskie##' '${udiskie}' \
'';
}
The net result is I can just write Haskell code and a cabal package file; I don't have to worry much about maintaining the nix package file as well, only re-running my generate-nix script if my dependencies change.
In my Haskell code I just write paths to executables as if ##the-nix-package-name## was an absolute path to a folder where that package is installed, and everything magically works.
The installed xmonad binary ends up containing hardcoded references to the absolute paths to the executables I call, which is how nix likes to work (this means it automatically knows about the dependency during garbage collection, for example). And I don't have to worry about keeping the things I called in my interactive environment's PATH, or maintaining a wrapper that sets up PATH just for this executable.
1 I have it set up as a cabal project that gets built and installed into the nix store, rather than having it dynamically recompile itself from ~/.xmonad/xmonad.hs
2 Step 2 is a little meta, since I'm using a bash script to generate nix code with an embedded bash script in it
This is not indented to be the answer but if I post this in comment section it would turn out to be ugly formatted.
Also I am not sure if this hack is the right way to do the job.
I notice that if I use nix-shell I can get full path to nix store
Assume hash is always the same, AFAIK I believe it is, you can use it to hard-coded in build recipe.
$ which bash
/run/current-system/sw/bin/bash
[wizzup# ~]
$ nix-shell -p bash
[nix-shell:~]$ which bash
/nix/store/wb34dgkpmnssjkq7yj4qbjqxpnapq0lw-bash-4.4-p12/bin/bash
Lastly, I doubt if you have to to any of this if you use buildInput, it should be the same path.

how to generate documentations with haddock?

The project I am using does not have docs on Stackage (they're out of date). Here is the original one which is on verson 0.3
https://hackage.haskell.org/package/reflex-dom-0.3/docs/Reflex-Dom-Widget-Basic.html
I was told I could generate docs with haddock. I have the source code on my computer (using git clone) version 0.4
The haddock web page was way too advanced.
For the beginner, once I am in my directory, how do I generate docs?
Thanks to one of the answer I made come progress, but here is an error message:
src/Reflex/Dom/Xhr.hs:154:0:
error: missing binary operator before token "("
#if MIN_VERSION_aeson(1,0,0)
^
cabal haddock or stack haddock.
Once you have installed haddock, you can run it as follows:
haddock --html -o <haddock-folder> <list-of-haskell-files>
So for instance:
haddock --html -o the_documentation *.hs
will generate the documentation of all the Haskell files in that directory (not any subdirectories) in a directory named the_documentation.
Some shells allow **.hs to look for all .hs files (subdirectories included). So you might try:
haddock --html -o the_documentation **.hs
If the shell does not suport that, you can of course use a combination of find and xargs, like:
find -iname '*.hs' | xargs haddock --html -o the_documentation
Here find will generate a list of all files that end with .hs, and xargs will write all these files as parameters to haddock --html ....

extracting version string in shell script

I've a progam installed in my linux box called my-scheduler-1.1.0-1112
When I do rpm -qa | grep my, it lists as shown below:
my-scheduler-1.1.0-1112
I want a command which will extract 1.1.0-1112 which is version part in my shell script.
what would be the command to extract it in shell script?
For this question you can try the --queryformat parameter for rpm.
like:
rpm -qa --queryformat '%{NAME}' | grep my
should print
my-scheduler
without the version string... What is much better as mugling it with sed or like. Because you can get something like package-1.0.3-rc2 or soo..
For version-release: use:
--queryformat "%{VERSION}-%{RELEASE}"
and maybe will be useful read http://www.rpm.org/max-rpm/ch-queryformat-tags.html - here is many useful query format tags, so you can directly can get what you want and in what format you want, without scripting...
Not sure what other version strings you may encounter, but you can try:
sed -e 's/^[^0-9]*-//g'
This is a sed replace. It's matching the regular expression ^[^0-9]*-, which is:
starting from the beginning of the String
match as many non-numbers as there are
then the very next character is a -
And it replaces everything that matched with a blank, essentially removing it. This should leave everything after that which is the version string.

Resources