|
| 1 | +#!/usr/bin/perl |
| 2 | + |
| 3 | +# Copyright (c) F5, Inc. |
| 4 | +# |
| 5 | +# This source code is licensed under the Apache License, Version 2.0 license |
| 6 | +# found in the LICENSE file in the root directory of this source tree. |
| 7 | + |
| 8 | +# Find, download or build letsencrypt/pebble of at least the specified version. |
| 9 | + |
| 10 | +############################################################################### |
| 11 | + |
| 12 | +use strict; |
| 13 | +use warnings; |
| 14 | +use utf8; |
| 15 | + |
| 16 | +use Cwd qw/ realpath /; |
| 17 | +use Digest::SHA; |
| 18 | +use File::Copy qw/ copy /; |
| 19 | +use File::Path qw/ rmtree /; |
| 20 | +use File::Spec; |
| 21 | +use File::Temp; |
| 22 | +use IPC::Open3; |
| 23 | +use POSIX qw/ uname waitpid /; |
| 24 | + |
| 25 | +BEGIN { use FindBin; chdir($FindBin::Bin) } |
| 26 | + |
| 27 | +############################################################################### |
| 28 | + |
| 29 | +my $GO = $ENV{GO} // 'go'; |
| 30 | +my $NAME = 'pebble'; |
| 31 | +my $TARGET = File::Spec->join( realpath('..'), 'bin', $NAME ); |
| 32 | +my $URL = 'https://github.com/letsencrypt/pebble'; |
| 33 | +my $VERSION = '2.8.0'; |
| 34 | + |
| 35 | +my %PREBUILT = ( |
| 36 | + linux => { |
| 37 | + amd64 => |
| 38 | + '34595d915bbc2fc827affb3f58593034824df57e95353b031c8d5185724485ce', |
| 39 | + arm64 => |
| 40 | + '0e70f2537353f61cbf06aa54740bf7f7bb5f963ba00e909f23af5f85bc13fd1a', |
| 41 | + }, |
| 42 | + darwin => { |
| 43 | + amd64 => |
| 44 | + '9b9625651f8ce47706235179503fec149f8f38bce2b2554efe8c0f2a021f877c', |
| 45 | + arm64 => |
| 46 | + '39e07d63dc776521f2ffe0584e5f4f081c984ac02742c882b430891d89f0c866', |
| 47 | + }, |
| 48 | +); |
| 49 | + |
| 50 | +my %ARCH = ( |
| 51 | + aarch64 => 'arm64', |
| 52 | + x86_64 => 'amd64', |
| 53 | +); |
| 54 | + |
| 55 | +############################################################################### |
| 56 | + |
| 57 | +my ( $bin, $version ) = do_check(); |
| 58 | +if ( defined $version ) { |
| 59 | + print STDERR "found pebble $version at $bin\n"; |
| 60 | + print $bin; |
| 61 | + exit 0; |
| 62 | +} |
| 63 | + |
| 64 | +my $arch = ( uname() )[4]; |
| 65 | +$arch = $ARCH{$arch} if defined $ARCH{$arch}; |
| 66 | + |
| 67 | +my $tempdir = File::Temp->newdir( 'get-pebble-XXXXXXXXXX', TMPDIR => 1 ) |
| 68 | + or die "Can't create temp directory: $!\n"; |
| 69 | + |
| 70 | +if ( my $hash = $PREBUILT{$^O}{$arch} ) { |
| 71 | + print STDERR "downloading pebble $VERSION for $^O $arch\n"; |
| 72 | + print do_download( $^O, $arch, $hash ); |
| 73 | +} |
| 74 | +else { |
| 75 | + print STDERR "building pebble $VERSION\n"; |
| 76 | + print do_compile(); |
| 77 | +} |
| 78 | + |
| 79 | +############################################################################### |
| 80 | + |
| 81 | +sub do_check { |
| 82 | + my @names = which($NAME); |
| 83 | + unshift @names, $TARGET; |
| 84 | + |
| 85 | + BIN: foreach my $bin (@names) { |
| 86 | + my $version; |
| 87 | + $version = $1 |
| 88 | + if qx{ $bin -version 2>/dev/null } =~ /version:\s+v?(\d[\d\.]+)/; |
| 89 | + next unless $version; |
| 90 | + |
| 91 | + my @v = split /\./, $version; |
| 92 | + foreach my $n ( split /\./, $VERSION ) { |
| 93 | + my $v = shift @v || 0; |
| 94 | + last if $v > $n; |
| 95 | + next BIN if $v < $n; |
| 96 | + } |
| 97 | + |
| 98 | + return ( $bin, $version ); |
| 99 | + } |
| 100 | +} |
| 101 | + |
| 102 | +sub do_compile { |
| 103 | + my @GO = which($GO) or die "Can't find Go toolchain: $!\n"; |
| 104 | + |
| 105 | + my $repo = $ENV{PEBBLE_SOURCE_DIR} |
| 106 | + // File::Spec->join( $tempdir, 'pebble' ); |
| 107 | + |
| 108 | + run( 'git', 'clone', '--depth=1', '-b', "v${VERSION}", $URL, $repo ) |
| 109 | + unless -d File::Spec->join( $repo, '.git' ); |
| 110 | + |
| 111 | + chdir($repo) or die "chdir failed: $!\n"; |
| 112 | + |
| 113 | + run( 'git', 'fetch', '--depth=1', 'origin', 'tag', "v${VERSION}" ); |
| 114 | + run( 'git', 'checkout', "v${VERSION}" ); |
| 115 | + |
| 116 | + my $commit = run( 'git', 'rev-parse', 'HEAD' ); |
| 117 | + my $ldflags = "-X 'main.version=v${VERSION} ($commit)'"; |
| 118 | + |
| 119 | + run( $GO[0], 'build', '-ldflags=' . $ldflags, './cmd/pebble' ); |
| 120 | + |
| 121 | + chdir($FindBin::Bin); |
| 122 | + return copy_binary( File::Spec->join( $repo, 'pebble' ) ); |
| 123 | +} |
| 124 | + |
| 125 | +sub do_download { |
| 126 | + my ( $os, $arch, $hash ) = @_; |
| 127 | + |
| 128 | + chdir($tempdir) or die "chdir failed: $!\n"; |
| 129 | + |
| 130 | + my $archive = "pebble-$os-$arch.tar.gz"; |
| 131 | + run( 'curl', '--fail', '--silent', '-L', '-o', $archive, |
| 132 | + "$URL/releases/download/v${VERSION}/${archive}" ); |
| 133 | + die "Checksum verification failed\n" if sha256sum($archive) ne $hash; |
| 134 | + |
| 135 | + run( 'tar', 'xzf', $archive ); |
| 136 | + |
| 137 | + chdir($FindBin::Bin); |
| 138 | + return copy_binary( |
| 139 | + File::Spec->join( $tempdir, "pebble-$os-$arch", $os, $arch, 'pebble' ) |
| 140 | + ); |
| 141 | +} |
| 142 | + |
| 143 | +sub copy_binary { |
| 144 | + my ($src) = @_; |
| 145 | + mkdir dirname($TARGET); |
| 146 | + copy $src, $TARGET or die "copy $src, $TARGET: $!\n"; |
| 147 | + chmod 0755, $TARGET or die "chmod $TARGET: $!\n"; |
| 148 | + return $TARGET; |
| 149 | +} |
| 150 | + |
| 151 | +sub dirname { |
| 152 | + my ($filename) = @_; |
| 153 | + my ( $vol, $dir ) = File::Spec->splitpath($filename); |
| 154 | + return File::Spec->catpath( $vol, $dir, '' ); |
| 155 | +} |
| 156 | + |
| 157 | +sub run { |
| 158 | + my $pid = open3( undef, my $fh, '>&STDERR', @_ ); |
| 159 | + waitpid( $pid, 0 ); |
| 160 | + die "$_[0] failed: $! $?\n" unless $? == 0; |
| 161 | + |
| 162 | + $fh->read( my $out, 32768 ); |
| 163 | + chomp($out); |
| 164 | + return $out; |
| 165 | +} |
| 166 | + |
| 167 | +sub sha256sum { |
| 168 | + my ($filename) = @_; |
| 169 | + my $sha = Digest::SHA->new('SHA-256'); |
| 170 | + $sha->addfile( $filename, 'b' ); |
| 171 | + return lc( $sha->hexdigest() ); |
| 172 | +} |
| 173 | + |
| 174 | +sub which { |
| 175 | + my ($name) = @_; |
| 176 | + my @paths = File::Spec->path(); |
| 177 | + return grep { -x } map { File::Spec->join( $_, $name ) } @paths; |
| 178 | +} |
| 179 | + |
| 180 | +############################################################################### |
0 commit comments