aboutsummaryrefslogtreecommitdiff
path: root/src/bin/paku
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/paku')
-rwxr-xr-xsrc/bin/paku726
1 files changed, 0 insertions, 726 deletions
diff --git a/src/bin/paku b/src/bin/paku
deleted file mode 100755
index fcaf1ea..0000000
--- a/src/bin/paku
+++ /dev/null
@@ -1,726 +0,0 @@
-#!/usr/bin/env perl
-
-use v5.34;
-use warnings;
-use feature 'signatures';
-no warnings ('experimental::signatures');
-use Getopt::Std ();
-use JSON ();
-use File::Basename ();
-use Digest::MD5 ();
-use Digest::SHA ();
-
-sub usage($fh) {
- print $fh <<~'EOF'
- Usage:
- paku [-d DIR] [-f FILE] ACTION
- paku -h
- EOF
-}
-
-sub help($fh) {
- print $fh <<~'EOF'
-
-
- Options:
- -d DIR use DIR for intermediary data (default: .paku/)
- -f FILE use data from FILE (default: paku.lock)
- -h, --help show this message
-
- ACTION what to emit, one of:
- - guix
- - debian
- - nix
- - html
-
-
- Generate package definitions for different package managers.
-
-
- Examples:
-
- Emit Guix package definitions using all defaults:
-
- $ paku guix > packages.scm
- $ guix build -f packages.scm
-
-
- Emit Debian build recipes from "debian.json", using
- ".debtmp/" as the temporary directory, and execute them
- as is:
-
- $ paku -d .debtemp/ -f debian.json debian | make -f-
- EOF
-}
-
-
-for (@ARGV) {
- last if $_ eq '--';
- if ($_ eq '--help') {
- usage *STDOUT;
- help *STDOUT;
- exit;
- }
-}
-
-my %opts;
-if (!Getopt::Std::getopts('d:f:h', \%opts)) {
- usage *STDERR;
- exit 2;
-}
-
-if ($opts{h}) {
- usage *STDOUT;
- help *STDOUT;
- exit;
-}
-
-
-my $dir = $opts{d} || '.paku';
-my $fname = $opts{f} || 'paku.lock';
-
-my $action = $ARGV[0] or die "Missing ACTION";
-shift;
-
-sub load_json() {
- my $json_str = do {
- open my $fh, $fname or die "Failed opening \"$fname\"";
- local $/;
- <$fh>;
- };
- return JSON::decode_json($json_str);
-}
-
-my $licenses = {
- guix => {
- 'AGPL-3.0-or-later' => 'agpl3+',
- },
- nix => {
- 'AGPL-3.0-or-later' => 'agpl3Plus',
- },
-};
-sub license_for($target, $id) {
- return $licenses->{$target}->{$id};
-}
-
-sub emit_packages() {
- for (@ARGV) {
- my $fh;
- my $size = (stat($_))[7];
-
- open ($fh, '<', $_) or die "Can't open \"$_\": $!";
- my $md5 = Digest::MD5->new->addfile($fh)->hexdigest;
- close $fh;
-
- open ($fh, '<', $_) or die "Can't open \"$_\": $!";
- my $sha1 = Digest::SHA->new(1)->addfile($fh)->hexdigest;
- close $fh;
-
- open ($fh, '<', $_) or die "Can't open \"$_\": $!";
- my $sha256 = Digest::SHA->new(256)->addfile($fh)->hexdigest;
- close $fh;
-
- open ($fh, '<', $_) or die "Can't open \"$_\": $!";
- my $sha512 = Digest::SHA->new(512)->addfile($fh)->hexdigest;
- close $fh;
-
- print `ar -p $_ control.tar.xz | tar -xJO ./control`;
- say "Filename: ./$_";
- say "Size: $size";
- say "MD5sum: $md5";
- say "SHA1: $sha1";
- say "SHA256: $sha256";
- print "\n";
- }
-}
-
-sub emit_release() {
- my $f = $ARGV[0] or die 'Missing "Packages" file';
- my $name = File::Basename::basename $f;
- my $size = (stat($f))[7];
-
- my $now = `env LANG=POSIX.UTF-8 date -u '+%a, %d %b %Y %H:%M:%S +0000'`;
- chomp $now;
-
- my $fh;
-
- open ($fh, '<', $f) or die "Can't open \"$f\": $!";
- my $md5 = Digest::MD5->new->addfile($fh)->hexdigest;
- close $fh;
-
- open ($fh, '<', $f) or die "Can't open \"$f\": $!";
- my $sha1 = Digest::SHA->new(1)->addfile($fh)->hexdigest;
- close $fh;
-
- open ($fh, '<', $f) or die "Can't open \"$f\": $!";
- my $sha256 = Digest::SHA->new(256)->addfile($fh)->hexdigest;
- close $fh;
-
- open ($fh, '<', $f) or die "Can't open \"$f\": $!";
- my $sha512 = Digest::SHA->new(512)->addfile($fh)->hexdigest;
- close $fh;
-
- print <<~EOF;
- Date: $now
- MD5Sum:
- $md5 $size $name
- SHA1:
- $sha1 $size $name
- SHA256:
- $sha256 $size $name
- SHA512:
- $sha512 $size $name
- EOF
- exit;
-}
-
-sub emit_nix() {
- my $json = load_json();
- my $ns = $json->{namespace};
- $ns =~ s/\./-/g;
- print <<~EOF;
- { pkgs }:
- self: super: {
- $ns = rec {
- EOF
- for my $pkg (@{$json->{packages}}) {
- my $long = $pkg->{'long-description'};
- $long =~ s/^(.)/ $1/gm;
- my $license = license_for 'nix', $pkg->{license};
-
- my $suffix = $pkg->{label} eq 'latest' ? '' : "-$pkg->{label}";
- print <<~EOF;
- $pkg->{name}$suffix = pkgs.stdenv.mkDerivation rec {
- name = "$pkg->{name}";
- version = "$pkg->{version}";
-
- src = fetchTarball {
- url =
- "$pkg->{url}";
- sha256 = "$pkg->{sha256nix}";
- };
-
- nativeBuildInputs = with pkgs; [
- EOF
-
- for my $input (@{$pkg->{'native-inputs'}}) {
- print <<~EOF;
- $input
- EOF
- }
- print <<~EOF;
- ];
-
- buildInputs = with pkgs; [
- EOF
- for my $input (@{$pkg->{inputs}}) {
- print <<~EOF;
- $input
- EOF
- }
- print <<~EOF;
- ];
-
- makeFlags = [ "PREFIX=\$(out)" ];
-
- doCheck = true;
- enableParallelBuilding = true;
-
- meta = with pkgs.lib; {
- description = "$pkg->{description}";
- longDescription = ''
- $long
- '';
- homepage = "$pkg->{homepage}";
- changelog = "$pkg->{changelog}";
- downloadPage = "$pkg->{'downloads-page'}";
- license = licenses.$license;
- platforms = platforms.unix;
- };
- };
- EOF
- }
- print <<~EOF;
- };
- }
- EOF
-}
-
-sub emit_guix() {
- my $json = load_json();
- my $ns = $json->{namespace};
- $ns =~ s/\./ /g;
- print <<~EOF;
- (define-module ($ns packages)
- EOF
- for my $module (@{$json->{guix}{'module-use'}}) {
- print <<~EOF;
- #:use-module (gnu packages $module)
- EOF
- }
- print <<~EOF;
- #:use-module ((guix licenses) #:prefix licenses:)
- #:use-module (guix gexp)
- #:use-module (guix packages)
- #:use-module (guix download)
- #:use-module (guix build-system gnu))
-
- EOF
-
- my @pkgs = ();
- for my $pkg (@{$json->{packages}}) {
- my $long = $pkg->{'long-description'};
- $long =~ s/^(.)/ $1/gm;
- my $ver = $pkg->{version} =~ s/^v//r;
- my $license = license_for 'guix', $pkg->{license};
-
- my $name = $pkg->{name} . (
- $pkg->{label} eq 'latest' ? '' : "-$pkg->{label}"
- );
- push @pkgs, $name;
- print <<~EOF;
- (define-public $name
- (package
- (name "$pkg->{name}")
- (version "$ver")
- (source
- (origin
- (method url-fetch)
- (uri "$pkg->{url}")
- (sha256
- (base32 "$pkg->{sha256guix}"))))
- (build-system gnu-build-system)
- (native-inputs
- EOF
-
- print ' (list';
- for my $input (@{$pkg->{'native-inputs'}}) {
- my $name = $json->{mappings}{$input}{guix} || $input;
- print "\n $name";
- }
- print "))\n";
-
- print " (inputs\n";
- print ' (list';
- for my $input (@{$pkg->{inputs}}) {
- my $name = $json->{mappings}{$input}{guix} || $input;
- print "\n $name";
- }
- print "))\n";
-
- print <<~EOF;
- (arguments
- (list
- #:make-flags '(list (string-append "PREFIX=" %output))
- #:phases
- #~(modify-phases %standard-phases
- (delete 'configure))))
- (synopsis "$pkg->{description}")
- (description
- "$pkg->{'long-description'}")
- (home-page "$pkg->{homepage}")
- (license licenses:$license)))
-
- EOF
- }
- print '(list';
- for (@pkgs) {
- print "\n $_";
- }
- print ")\n";
-}
-
-sub emit_debian() {
- my $json = load_json();
- my %vars = (
- tarballs => ["tarballs = \\\n"],
- checkouts => ["checkouts = \\\n"],
- destdirs => ["debian-destdirs = \\\n"],
- ctrlfiles => ["control-files = \\\n"],
- destdebs => ["destdir-debs = \\\n"],
- debs => ["debs = \\\n"],
- );
-
- my @targets = ();
-
- for my $pkg (@{$json->{packages}}) {
- push @{$vars{tarballs}}, "\t\$(DIR)/tarballs/$pkg->{fname} \\\n";
- push @{$vars{checkouts}}, "\t\$(DIR)/checkouts/$pkg->{name}-$pkg->{version} \\\n";
-
- push @targets, <<~EOF;
- \$(DIR)/tarballs/$pkg->{fname}:
- mkdir -p \$(\@D)
- wget -O \$\@ \\
- '$pkg->{url}'
-
- \$(DIR)/checkouts/$pkg->{name}-$pkg->{version}: \$(DIR)/tarballs/$pkg->{fname}
- mkdir -p \$(\@D)
- tar -C \$(DIR)/checkouts/ -xf \$(DIR)/tarballs/$pkg->{fname}
- touch \$\@
-
- EOF
-
-
- next if $pkg->{architectures} ne 'any';
-
- push @{$vars{destdirs}}, "\t\$(DIR)/debian-destdir/$pkg->{name}-$pkg->{version}/DEBIAN \\\n";
- push @{$vars{ctrlfiles}}, "\t\$(DIR)/debian-destdir/$pkg->{name}-$pkg->{version}/DEBIAN/control \\\n";
- push @{$vars{destdebs}}, "\t\$(DIR)/debian-destdir/$pkg->{name}-$pkg->{version}.deb \\\n";
- push @{$vars{debs}}, "\t\$(DIR)/debian/$pkg->{name}_$pkg->{version}_all.deb \\\n";
-
- my $ver = $pkg->{label} eq 'latest' ? '0.' . $pkg->{version} . '.latest' : $pkg->{version};
- $ver =~ s/^v//;
-
- push @targets, <<~EOF;
- \$(DIR)/debian-destdir/$pkg->{name}-$pkg->{version}/DEBIAN: \$(DIR)/checkouts/$pkg->{name}-$pkg->{version}
- \$(MAKE) \\
- -C \$(DIR)/checkouts/$pkg->{name}-$pkg->{version} \\
- install \\
- PREFIX=/usr \\
- DESTDIR="\$\$PWD"/\$(DIR)/debian-destdir/$pkg->{name}-$pkg->{version}
- mkdir -p \$\@
- touch \$\@
-
- \$(DIR)/debian-destdir/$pkg->{name}-$pkg->{version}/DEBIAN/control: \$(DIR)/debian-destdir/$pkg->{name}-$pkg->{version}/DEBIAN
- printf '' > \$\@
- printf 'Package: $pkg->{name}\\n' >> \$\@
- printf 'Version: $ver\\n' >> \$\@
- printf 'Section: custom\\n' >> \$\@
- printf 'Depends:\\n' >> \$\@
- printf 'Priority: optional\\n' >> \$\@
- printf 'Architecture: all\\n' >> \$\@
- printf 'Essential: no\\n' >> \$\@
-
- printf 'Maintainer: ' >> \$\@
- printf '$pkg->{"maintainer-b64"}' | base64 -d >> \$\@
- printf '\\n' >> \$\@
-
- printf 'Description: ' >> \$\@
- printf '$pkg->{"description-b64"}' | base64 -d >> \$\@
- printf '\\n' >> \$\@
-
- printf '$pkg->{'long-description-b64'}' | \\
- base64 -d | \\
- sed 's|^\$\$|.|' | \\
- sed 's|^| |' >> \$\@
- printf '\\n' >> \$\@
-
- \$(DIR)/debian-destdir/$pkg->{name}-$pkg->{version}.deb: \$(DIR)/debian-destdir/$pkg->{name}-$pkg->{version}/DEBIAN/control
- dpkg-deb --build \$(DIR)/debian-destdir/$pkg->{name}-$pkg->{version}
-
- \$(DIR)/debian/$pkg->{name}_$pkg->{version}_all.deb: \$(DIR)/debian-destdir/$pkg->{name}-$pkg->{version}.deb
- mkdir -p \$(\@D)
- cp \$(DIR)/debian-destdir/$pkg->{name}-$pkg->{version}.deb \$\@
-
-
- EOF
- }
-
-
- print "DIR = $dir\n\n";
-
- print
- @{$vars{tarballs}}, "\n",
- @{$vars{checkouts}}, "\n",
- @{$vars{destdirs}}, "\n",
- @{$vars{ctrlfiles}}, "\n",
- @{$vars{destdebs}}, "\n",
- @{$vars{debs}}, "\n";
-
- print <<~EOF;
- GPGKEY = '$json->{maintainer}'
-
-
- all: \$(DIR)/debian/InRelease \$(DIR)/debian/Release.gpg \$(DIR)/debian/public-key.asc
-
- public-dir:
- \@printf '\$(DIR)/debian'
-
-
- \$(DIR)/debian/Packages: \$(debs)
- cd \$(\@D) && perl \$\$OLDPWD/src/bin/paku debian-packages *.deb > \$(\@F)
-
- \$(DIR)/debian/Release: \$(DIR)/debian/Packages
- perl src/bin/paku debian-release \$(DIR)/debian/Packages > \$\@
-
- \$(DIR)/debian/Release.gpg: \$(DIR)/debian/Release
- gpg -abs -o \$\@ \$(DIR)/debian/Release
-
- \$(DIR)/debian/InRelease: \$(DIR)/debian/Release
- gpg --default-key \$(GPGKEY) -a --clear-sign -o \$\@ \$(DIR)/debian/Release
-
- \$(DIR)/debian/public-key.asc: \$(DIR)/debian/Release
- gpg --armour --export \$(GPGKEY) > \$\@
-
-
- EOF
-
- print @targets;
-}
-
-sub pascal_case($s) {
- return join('', map(ucfirst, split '-', $s))
-}
-
-sub emit_homebrew() {
- my $d = $ARGV[0] or die 'Missing "Formula/" directory';
- my $json = load_json();
- for my $pkg (@{$json->{packages}}) {
- my $name = $pkg->{name} . (
- $pkg->{label} eq 'latest' ? '' : "-$pkg->{label}"
- );
- open(my $fh, '>', "$d/$name.rb");
- my $class_name = pascal_case $name;
- print $fh <<~EOF;
- class $class_name < Formula
- desc '$pkg->{description}'
- homepage '$pkg->{homepage}'
- url '$pkg->{url}'
- sha256 '$pkg->{sha256}'
- license 'AGPL-3.0-or-later'
-
- def install
- system 'make'
- system 'make', 'check'
- system 'make', 'install', "PREFIX=#{prefix}"
- end
-
- test do
- system "#{bin}/$pkg->{name}", '-V'
- end
- end
- EOF
- close $fh;
- }
-}
-
-sub emit_html() {
- my $json = load_json();
- print <<~EOF;
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <link rel="icon" type="image/svg+html" href="favicon.svg" />
- <title>$json->{name} package index</title>
-
- <style>
- body {
- max-width: 800px;
- margin: 0 auto;
- }
-
- ul {
- list-style: none;
- }
-
- li {
- margin-top: 2em;
- }
- </style>
- </head>
- <body>
- <main>
- <h1>
- $json->{name} package index
- </h1>
- <ul>
- EOF
-
- for my $pkg (@{$json->{packages}}) {
- my $guix_suffix = $pkg->{label} eq 'latest' ? '' : '@' . $pkg->{label} =~ s/-/./gr;
- my $suffix = $pkg->{label} eq 'latest' ? '' : "-$pkg->{label}";
- my $apt_suffix = $suffix =~ s/-/=/r;
- my $ver = $pkg->{label} eq 'latest' ? $pkg->{label} : $pkg->{version};
- print <<~EOF;
- <li id="$pkg->{name}-$ver">
- <details>
- <summary>
- <a href="#$pkg->{name}-$ver">$pkg->{name}</a>
- ($ver) - $pkg->{description}
- </summary>
- <p>
- <a href="$pkg->{homepage}/">Homepage</a>
- </p>
- <section>
- <h2>Guix</h2>
- <p>
- After following the
- <a href="#guix-instructions">Guix instructions</a>
- to include this channel, you can launch a shell
- that includes this package:
- </p>
- <pre><code>\$ guix shell $pkg->{name}$guix_suffix</code></pre>
- <p>
- Alternatively, you can install it imperatively:
- </p>
- <pre><code>\$ guix install $pkg->{name}$guix_suffix</code></pre>
- </section>
- <section>
- <h2>Debian</h2>
- <p>
- After following the
- <a href="#debian-instructions">Debian instructions</a>
- to include this repository to
- <code>/etc/apt/sources.list</code>, you can
- install it:
- </p>
- <pre><code># apt install $pkg->{name}$apt_suffix</code></pre>
- </section>
- <section>
- <h2>Nix</h2>
- <p>
- After following the
- <a href="#nix-instructions">Nix instructions</a>
- to include this repository as an overlay, you
- can launch a shell that includes this package:
- </p>
- <pre><code>\$ nix-shell -p $pkg->{name}$suffix</code></pre>
- <p>
- Alternatively, you can install it imperatively:
- </p>
- <pre><code>\$ nix-env -i $pkg->{name}$suffix</code></pre>
- </section>
- <section>
- <h2>Homebrew</h2>
- <p>
- After following the
- <a href="#homebrew-instructions">Homebrew instructions</a>
- to include this repository as a <code>tap</code>, you can
- install it with:
- </p>
- <pre><code>\$ brew install $pkg->{name}$suffix</code></pre>
- </section>
- </details>
- </li>
- EOF
- }
-
- my $channel_name = $json->{namespace} =~ s/\./-/gr;
- my $overlay_name = $json->{namespace} =~ s/\./-/gr;
- my $tap_name = $json->{namespace} =~ s/\./\//gr;
- print <<~EOF;
- </ul>
- <article id="guix-instructions">
- <h2>Guix instructions</h2>
- <p>
- Add this channel to your
- <code>~/.config/guix/channels.scm</code>:
- </p>
- <pre><code>(cons*
- (channel
- (name '$channel_name)
- (url "$json->{vcs}->{git}")
- (branch "main")
- (introduction
- (make-channel-introduction
- "d749e053e6db365069cb9b2ef47a78b06f9e7361"
- (openpgp-fingerprint
- "5BDA E9B8 B2F6 C6BC BB0D 6CE5 81F9 0EC3 CD35 6060"))))
- %default-channels)</code></pre>
- <p>
- Afterwards, do a <code>guix pull</code> to make the
- packages in this channel available to your profile.
- </p>
- <p>
- See also the
- <a href="https://guix.gnu.org/manual/en/guix.html#Channels">Guix manual on channels</a>
- for more information.
- </p>
- </article>
- <article id="debian-instructions">
- <h2>Debian instructions</h2>
- <p>
- Include my public key for validating the repository
- signatures:
- </p>
- <pre><code>\$ wget -qO- $json->{'base-url'}/debian/public-key.asc | sudo tee /etc/apt/trusted.gpg.d/$json->{namespace}.asc</code></pre>
- <p>
- Afterwards, include this repository to the list of
- repositories that <code>apt</code> uses for sources
- by adding its URL to
- <code>/etc/apt/sources.list</code>:
- </p>
- <pre><code>\$ sudo apt-add-repository 'deb $json->{'base-url'}/debian ./'</code></pre>
- <p>
- <code>apt-add-repository</code> will already perform
- an <code>apt update</code>, so the packages from the
- new repository will already be available.
- </p>
- </article>
- <article id="nix-instructions">
- <h2>Nix instructions</h2>
- <p>
- Add this repository as an overlay to your
- <code>/etc/nixos/configuration.nix</code>:
- </p>
- <pre><code> nixpkgs = {
- overlays = [
- (import (fetchTarball {
- url = "$json->{vcs}->{tarball}";
- }) { inherit pkgs; })
- ];
- };</code></pre>
- <p>
- All the packages live under the
- <code>$overlay_name</code> attribute set, like.
- <code>$overlay_name.$json->{packages}[0]->{name}</code>,
- so it can be included in the list of packages:
- </p>
- <pre><code> environment.systemPackages = with pkgs; [
- ...
- $overlay_name.$json->{packages}[0]->{name}
- ];</pre></code>
- <p>
- To make the overlay available outside the system
- environment of
- <code>/etc/nixos/configuration.nix</code>, you need to
- add this overlay to your
- <code>~/.config/nixpkgs/overlays/</code> directory,
- like a
- <code>~/.config/nixpkgs/overlays/$json->{namespace}.nix</code>
- file containing:
- </p>
- <pre><code>import (fetchTarball {
- url = "$json->{vcs}->{tarball}";
- }) { pkgs = import &lt;nixpkgs&gt; {}; }</pre></code>
- <p>
- Then you'd be able to launch a shell with a package
- from this overlay:
- </p>
- <pre><code>\$ nix-shell -p $overlay_name.$json->{packages}[0]->{name}</code></pre>
- </article>
- <article id="homebrew-instructions">
- <h2>Homebrew instructions</h2>
- <p>
- Add this repository as a tap:
- </p>
- <pre><code>\$ brew tap --force-auto-update $tap_name $json->{vcs}->{http}</code></pre>
- <p>
- The explicit <code>--force-auto-update</code> option
- is required, because <code>homebrew(1)</code> will only
- fetch updates automatically for repositories hosted on
- GitHub. With this option, repositories not on GitHub
- are treated equally.
- </p>
- </article>
- </main>
- </body>
- </html>
- EOF
-}
-
-
-my %actions = (
- 'debian-packages' => \&emit_packages,
- 'debian-release' => \&emit_release,
- nix => \&emit_nix,
- guix => \&emit_guix,
- debian => \&emit_debian,
- homebrew => \&emit_homebrew,
- html => \&emit_html,
-);
-
-my $fn = $actions{$action} or die "Unknown ACTION: \"$action\"";
-&$fn;