aboutsummaryrefslogblamecommitdiff
path: root/src/bin/paku
blob: e4f0b834a862b5a47ba0ea5db54dc24ccb6982aa (plain) (tree)



















                                         
 









                                                                            
 
 





                           

 







                              
 
 



                                           

 



                      

 





























































                                                                                

 


















































































                                                                                  

 
































































                                                                                     
                         



















                                                                                     



                                                                     


                                   
                         







                              

 
 







                                                
 
                 
 

                                                   

                                                                                                    
 
                                      











                                                                                                         
 
                                                           





                                                                                                                        





                                                                                                                
                                      











































                                                                                                                                                          






































                                                                                       
#!/usr/bin/env perl

# FIXME: add html output

use v5.34;
use warnings;
use feature 'signatures';
no warnings ('experimental::signatures');
use Getopt::Std ();
use JSON ();
use MIME::Base64 ();
use open IN => ':encoding(UTF-8)';

sub usage($fh) {
	print $fh <<~'EOF'
		Usage:
		  paku [-f FILE] FIXME
		  paku -h
		EOF
}

sub help($fh) {
	print $fh <<~'EOF'


		Options:
		  -f FILE       use data from FILE (default: paku.json)
		  -h, --help    show this message


		Generate package definitions for different package managers.


		Examples:

		  FIXME:

		    $ FIXME
		EOF
}


for (@ARGV) {
	last if $_ eq '--';
	if ($_ eq '--help') {
		usage *STDOUT;
		help *STDOUT;
		exit;
	}
}

my %opts;
if (!Getopt::Std::getopts('f:h', \%opts)) {
	usage *STDERR;
	exit 2;
}

if ($opts{h}) {
	usage *STDOUT;
	help *STDOUT;
	exit;
}


my $dir = '.paku'; # FIXME: parameterize
my $fname = $opts{f} || 'paku.lock';
my $json_str = do {
	open my $fh, $fname or die "Failed opening \"$fname\"";
	local $/;
	<$fh>;
};
my $json = JSON::decode_json($json_str);

my $action = $ARGV[0];



use Data::Dumper;
use POSIX qw();
use File::Basename ();
use Digest::MD5 ();
use Digest::SHA ();


# FIXME
my $base_url_prefix = 'https://euandre.org/s';

if ($action eq 'release') {
	my $f = $ARGV[1];
	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;
}

if ($action eq 'nix') {
	my $ns = 'org-euandre'; # FIXME
	print <<~EOF;
		{ pkgs }:
		self: super: {
		  $ns = rec {
		EOF
	for my $package (@{$json->{packages}}) {
		for my $version (@{$package->{versions}}) {
			my $ver = $version->{name};
			$ver =~ s/^v//;
			$ver =~ s/\./-/g;
			if ($version->{type} eq 'latest') {
				$ver = 'latest';
				print <<~EOF;
				    $package->{name} = $package->{name}-latest;
				EOF
			}

			my $long = $version->{'long-description'};
			$long =~ s/^(.)/          $1/gm;

			my $base_url = $base_url_prefix . '/' . $package->{name};

			print <<~EOF;
			    $package->{name}-$ver = pkgs.stdenv.mkDerivation rec {
			      name = "$package->{name}";
			      version = "$version->{name}";

			      src = fetchTarball {
			        url =
			          "$version->{url}";
			        sha256 = "$version->{sha256}";
			      };

			      nativeBuildInputs = with pkgs; [
			EOF

			for my $input (@{$version->{'native-inputs'}}) {
				print <<~EOF;
				        $input
				EOF
			}
			print <<~EOF;
			      ];

			      buildInputs = with pkgs; [
			EOF
			for my $input (@{$version->{inputs}}) {
				print <<~EOF;
				        $input
				EOF
			}
			print <<~EOF;
			      ];

			      makeFlags = [ "PREFIX=\$(out)" ];

			      doCheck = true;
			      enableParallelBuilding = true;

			      meta = with pkgs.lib; {
			        description = "$version->{description}";
			        longDescription = ''
			$long
			        '';
			        homepage = "$base_url/";
			        changelog = "$base_url/CHANGELOG.html";
			        downloadPage = "$base_url/#releases";
			        license = licenses.agpl3;
			        platforms = platforms.unix;
			      };
			    };
			EOF
			# FIXME: escape quotes in description
			# FIXME: parameterize license
		}
	}
	print <<~EOF;
	  };
	}
	EOF
	exit;
}


if ($action eq 'guix') {
	my @pkgs = ();
	my $ns = 'org euandre'; # FIXME
	print <<~EOF;
	(define-module ($ns packages)
	EOF
	for my $module (@{$json->{guix}{'module-use'}}) {
		print <<~EOF;
		  #:use-module (gnu packages $module)
		EOF
	}
	# FIXME: rename to 'licenses:'
	print <<~EOF;
	  #:use-module ((guix licenses) #:prefix license:)
	  #:use-module (guix gexp)
	  #:use-module (guix packages)
	  #:use-module (guix download)
	  #:use-module (guix build-system gnu))

	EOF

	for my $package (@{$json->{packages}}) {
		for my $version (@{$package->{versions}}) {
			my $ver = $version->{name};
			$ver =~ s/^v//;
			$ver =~ s/\./-/g;
			if ($version->{type} eq 'latest') {
				push @pkgs, "$package->{name}";
				$ver = 'latest';
			}

			my $long = $version->{'long-description'};
			$long =~ s/^(.)/          $1/gm;

			my $base_url = $base_url_prefix . '/' . $package->{name};

			push @pkgs, "$package->{name}-$ver";
			# FIXME: indentation of (source ...)
			print <<~EOF;
			(define-public $package->{name}-$ver
			  (package
			    (name "$package->{name}-$ver")
			    (version "$version->{name}")
			    (source (origin
			              (method url-fetch)
			              (uri "$version->{url}")
			              (sha256
			                (base32 "$version->{sha256FIXME}"))))
			    (build-system gnu-build-system)
			    (native-inputs
			EOF

			print '      (list';
			for my $input (@{$version->{'native-inputs'}}) {
				my $name = $json->{mappings}{$input}{guix} || $input;
				print "\n       $name";
			}
			print "))\n";

			print "    (inputs\n";
			print '      (list';
			for my $input (@{$version->{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 "$version->{description}")
			    (description
			      "$version->{'long-description'}")
			    (home-page "$base_url/")
			    (license license:agpl3+)))

			EOF
			# FIXME: escape quotes in description
			# FIXME: parameterize license
			if ($version->{type} eq 'latest') {
				print <<~EOF;
				(define-public $package->{name}
				  (package
				    (inherit $package->{name}-latest)
				    (name "$package->{name}")))


				EOF
			}
		}
	}
	print '(list';
	for (@pkgs) {
		print "\n $_";
	}
	print ")\n";
	exit;
}


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 $package (@{$json->{packages}}) {
	for my $version (@{$package->{versions}}) {
		push @{$vars{tarballs}},  "\t$dir/tarballs/$version->{fname} \\\n";
		push @{$vars{checkouts}}, "\t$dir/checkouts/$package->{name}-$version->{name} \\\n";

		push @targets, <<~EOF;
			$dir/tarballs/$version->{fname}:
				mkdir -p \$(\@D)
				wget -O \$\@ \\
					'$version->{url}'

			$dir/checkouts/$package->{name}-$version->{name}: $dir/tarballs/$version->{fname}
				mkdir -p \$(\@D)
				tar -C $dir/checkouts/ -xf $dir/tarballs/$version->{fname}
				touch \$\@

			EOF


		next if $version->{architectures} ne 'any';

		push @{$vars{destdirs}},  "\t$dir/debian-destdir/$package->{name}-$version->{name}/DEBIAN \\\n";
		push @{$vars{ctrlfiles}}, "\t$dir/debian-destdir/$package->{name}-$version->{name}/DEBIAN/control \\\n";
		push @{$vars{destdebs}},  "\t$dir/debian-destdir/$package->{name}-$version->{name}.deb \\\n";
		push @{$vars{debs}},      "\t$dir/debian/$package->{name}_$version->{name}_all.deb \\\n";

		my $ver = $version->{type} eq 'latest' ? '0.' . $version->{name} . '.latest' : $version->{name};
		$ver =~ s/^v//;
		my $maintainer_b64 = MIME::Base64::encode_base64 $version->{maintainer}, '';
		my $desc_b64       = MIME::Base64::encode_base64 $version->{description}, '';
		my $long_desc_b64  = MIME::Base64::encode_base64 $version->{'long-description'}, '';

		push @targets, <<~EOF;
			$dir/debian-destdir/$package->{name}-$version->{name}/DEBIAN: $dir/checkouts/$package->{name}-$version->{name}
				\$(MAKE) \\
					-C $dir/checkouts/$package->{name}-$version->{name} \\
					install \\
					PREFIX=/usr \\
					DESTDIR="\$\$PWD"/$dir/debian-destdir/$package->{name}-$version->{name}
				mkdir -p \$\@
				touch \$\@

			$dir/debian-destdir/$package->{name}-$version->{name}/DEBIAN/control: $dir/debian-destdir/$package->{name}-$version->{name}/DEBIAN
				printf '' > \$\@
				printf 'Package: $package->{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 '$maintainer_b64' | base64 -d  >> \$\@
				printf '\\n'                           >> \$\@

				printf 'Description: '                >> \$\@
				printf '$desc_b64' | base64 -d >> \$\@
				printf '\\n'                           >> \$\@

				printf '$long_desc_b64' | \\
					base64 -d |    \\
					sed 's|^\$\$|.|' | \\
					sed 's|^| |'                        >> \$\@
				printf '\\n'                           >> \$\@

			$dir/debian-destdir/$package->{name}-$version->{name}.deb: $dir/debian-destdir/$package->{name}-$version->{name}/DEBIAN/control
				dpkg-deb --build $dir/debian-destdir/$package->{name}-$version->{name}

			$dir/debian/$package->{name}_$version->{name}_all.deb: $dir/debian-destdir/$package->{name}-$version->{name}.deb
				mkdir -p \$(\@D)
				cp $dir/debian-destdir/$package->{name}-$version->{name}.deb \$\@


			EOF
	}
}


print
	@{$vars{tarballs}},  "\n",
	@{$vars{checkouts}}, "\n",
	@{$vars{destdirs}},  "\n",
	@{$vars{ctrlfiles}}, "\n",
	@{$vars{destdebs}},  "\n",
	@{$vars{debs}},      "\n";

print <<~EOF;
	FIXME = eu\@euandre.org


	all: $dir/debian/InRelease $dir/debian/Release.gpg $dir/debian/public-key.asc

	public-dir:
		\@printf '$dir/debian'


	$dir/debian/Packages: \$(debs)
		cd \$(\@D) && dpkg-scanpackages -m . > \$(\@F)

	$dir/debian/Release: $dir/debian/Packages
		perl src/bin/paku 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 \$(FIXME) -a --clear-sign -o \$\@ $dir/debian/Release

	$dir/debian/public-key.asc: $dir/debian/Release
		gpg --armour --export \$(FIXME) > \$\@


	EOF

print @targets;