77use JSON::PP;
88use HTTP::Tiny;
99use File::Spec;
10+ use Getopt::Long;
1011
11- @ARGV == 1 or @ARGV == 2 or die <<EOU ;
12- usage:
12+ my $NO_GITHUB_PATH ;
13+ GetOptions(' p|dont-alter-github-path' => \$NO_GITHUB_PATH )
14+ and (@ARGV == 1 or @ARGV == 2)
15+ or die <<EOU ;
16+ usage: $0 [-p|--dont-alter-github-path] GO_VERSION [INSTALL_DIR]
1317 $0 1.14 [installation_directory/]
1418 $0 1.9.2 [installation_directory/]
1519 $0 1.15.x [installation_directory/]
1620 $0 tip [installation_directory/]
1721
18- installation_directory/ defaults to .
22+ INSTALL_DIR defaults to .
23+
24+ By default, if GITHUB_PATH environment variable exists *AND*
25+ references a writable file, INSTALL_DIR/go/bin is automatically
26+ appended to this file.
27+ -p or --dont-alter-github-path option disables this behavior.
1928EOU
2029
2130
6271 if ($goroot )
6372 {
6473 install_tip(" $goroot /bin/go" , $DESTDIR );
74+ export_path(" $DESTDIR /go/bin" );
6575 exit 0;
6676 }
6777
6878 $TARGET = ' 1.15.x' ;
6979 $TIP = 1;
7080}
7181
72- my $HTTP = HTTP::Tiny::-> new;
7382
7483# 1.12.3 -> (1.12.3, undef)
7584# 1.15.x -> (1.15, 4)
7887link_go_if_available($TARGET , $last_minor , $DESTDIR )
7988 or install_go(get_url($TARGET , $last_minor ), $DESTDIR , $TIP );
8089
90+ export_path(" $DESTDIR /go/bin" );
91+
8192exit 0;
8293
8394
@@ -102,7 +113,7 @@ sub resolve_target
102113 }
103114 $vreg = qr / ^go$vreg \z / ;
104115
105- my $r = $HTTP -> get (' https://go.googlesource.com/go/+refs/tags?format=JSON' );
116+ my $r = http_get (' https://go.googlesource.com/go/+refs/tags?format=JSON' );
106117 $r -> {success } or die " Cannot retrieve tags: $r ->{status} $r ->{reason}\n $r ->{content}\n " ;
107118
108119 my $found ;
@@ -144,11 +155,14 @@ sub link_go_if_available
144155 my $vreg = qr , go[\\ /]\Q $full \E [\\ /]x64\z , ;
145156 while (my ($var , $value ) = each %ENV )
146157 {
147- if ($var =~ / ^GOROOT(?:_\d +_\d +_X64)?\z / and $value =~ $vreg )
158+ if ($var =~ / ^GOROOT(?:_\d +_\d +_X64)?\z /
159+ and $value =~ $vreg
160+ and -f -x " $value /bin/go" )
148161 {
149162 say " Find already installed go version $full " ;
150163 rmdir " $dest_dir /go" ;
151164 symlink ($value , " $dest_dir /go" ) or die " symlink($value , $dest_dir /go): $! \n " ;
165+ say " go version $full symlinked and available as $dest_dir /go/bin/go" ;
152166 return 1;
153167 }
154168 }
@@ -167,8 +181,8 @@ sub get_url
167181 $full .= " .$last_minor " if defined $last_minor ;
168182
169183 say " Check https://golang.org/dl/go$full .$OS -$ARCH .$EXT " ;
170- my $r = $HTTP -> head (" https://golang.org/dl/go$full .$OS -$ARCH .$EXT " );
171- return $r -> {url } if $r -> {success };
184+ my $r = http_head (" https://golang.org/dl/go$full .$OS -$ARCH .$EXT " );
185+ return ( $r -> {url }, $full ) if $r -> {success };
172186 say " => $r ->{status}" ;
173187
174188 if ($r -> {status } == 404)
@@ -188,7 +202,7 @@ sub get_url
188202
189203sub install_go
190204{
191- my ($url , $dest_dir , $tip ) = @_ ;
205+ my ($url , $version , $ dest_dir , $tip ) = @_ ;
192206
193207 chdir $dest_dir or die " Cannot chdir to $dest_dir : $! \n " ;
194208
@@ -203,7 +217,14 @@ sub install_go
203217 exe(" curl -s \Q $url \E | tar zxf - go/bin go/pkg go/src" );
204218 }
205219
206- install_tip(" $dest_dir /go/bin/go" , $dest_dir ) if $tip ;
220+ if ($tip )
221+ {
222+ install_tip(" $dest_dir /go/bin/go" , $dest_dir );
223+ }
224+ else
225+ {
226+ say " go $version installed as $dest_dir /go/bin/go" ;
227+ }
207228}
208229
209230sub install_tip
@@ -224,7 +245,6 @@ sub install_tip
224245 my $final_go = " $dest_dir /go/bin/go" ;
225246 if (-e $final_go )
226247 {
227- say " rename($final_go , $final_go .orig)" ;
228248 rename $final_go , " $final_go .orig"
229249 or die " rename($final_go , $final_go .orig): $! \n " ;
230250 }
@@ -233,9 +253,20 @@ sub install_tip
233253 mkdir_p(" $dest_dir /go/bin" );
234254 }
235255
236- say " symlink($gotip , $final_go )" ;
237256 symlink ($gotip , $final_go ) or die " symlink($gotip , $final_go ): $! \n " ;
238- # rename $gotip, $final_go or die "rename($gotip, $final_go): $!\n";
257+
258+ say " go tip installed as $final_go " ;
259+ }
260+
261+ sub export_path
262+ {
263+ if (not $NO_GITHUB_PATH
264+ and $ENV {GITHUB_PATH }
265+ and open (my $fh , ' >>' , $ENV {GITHUB_PATH }))
266+ {
267+ say $fh shift ;
268+ close $fh ;
269+ }
239270}
240271
241272sub exe
@@ -257,3 +288,94 @@ sub mkdir_p
257288
258289 mkdir $dir or d $dir or die " Cannot create $dir : $! \n " ;
259290}
291+
292+ my $use_curl ;
293+
294+ sub http_get
295+ {
296+ my $url = shift ;
297+
298+ if ($use_curl )
299+ {
300+ my %r ;
301+ open (my $fh , ' -|' , curl => -sLD => ' /dev/fd/1' , $url )
302+ or die " Cannot fork: $! \n " ;
303+
304+ for (;;)
305+ {
306+ my $status_line = <$fh >;
307+ unless (defined $status_line )
308+ {
309+ return {
310+ status => 599,
311+ reason => ' EOF' ,
312+ content => ' ' ,
313+ };
314+ }
315+
316+ (undef , $r {status }, $r {reason }) = split (' ' , $status_line , 3);
317+ $r {success } = $r {status } < 400;
318+
319+ # Consume headers
320+ { local $/ = " \r\n\r\n " ; <$fh > }
321+
322+ # Redirect -> new header
323+ last if $r {status } != 302 and $r {status } != 307;
324+ }
325+
326+ local $/ ;
327+ $r {content } = <$fh >;
328+ close $fh ;
329+ return \%r ;
330+ }
331+
332+ my $r = HTTP::Tiny::-> new-> get($url );
333+ if (not $r -> {success }
334+ and $r -> {status } == 599
335+ and $r -> {content } =~ / must be installed for https support/ )
336+ {
337+ $use_curl = 1;
338+ return http_get($url )
339+ }
340+ return $r ;
341+ }
342+
343+ sub http_head
344+ {
345+ my $url = shift ;
346+
347+ if ($use_curl )
348+ {
349+ my %r = (url => $url );
350+ open (my $fh , ' -|' , curl => ' --head' => -sL => $url )
351+ or die " Cannot fork: $! \n " ;
352+
353+ for (;;)
354+ {
355+ my $status_line = <$fh >;
356+ unless (defined $status_line )
357+ {
358+ return {
359+ status => 599,
360+ reason => ' EOF' ,
361+ content => ' ' ,
362+ };
363+ }
364+
365+ (undef , $r {status }, $r {reason }) = split (' ' , $status_line , 3);
366+ $r {success } = $r {status } < 400;
367+
368+ # Redirect -> new header
369+ last if $r {status } != 302 and $r {status } != 307;
370+
371+ # Consume headers and catch location header
372+ local $/ = " \r\n\r\n " ;
373+ $r {url } = $1 if <$fh > =~ / ^location:\s *([^\r\n ]+)/mi ;
374+ }
375+
376+ close $fh ;
377+ return \%r ;
378+ }
379+
380+ return HTTP::Tiny::-> new-> head($url );
381+ }
0 commit comments