File Coverage

blib/lib/NVMPL/Remote.pm
Criterion Covered Total %
statement 68 68 100.0
branch 16 18 88.8
condition 2 2 100.0
subroutine 10 10 100.0
pod 0 2 0.0
total 96 100 96.0


line stmt bran cond sub pod time code
1             package NVMPL::Remote;
2 3     3   64012 use strict;
  3         15  
  3         136  
3 3     3   19 use warnings;
  3         6  
  3         223  
4 3     3   21 use feature 'say';
  3         33  
  3         404  
5 3     3   25 use HTTP::Tiny;
  3         6  
  3         179  
6 3     3   21 use JSON::PP qw(decode_json);
  3         5  
  3         225  
7 3     3   20 use File::Spec;
  3         5  
  3         122  
8 3     3   16 use NVMPL::Config;
  3         6  
  3         113  
9 3     3   16 use NVMPL::Utils qw(log_info log_warn log_error);
  3         5  
  3         2883  
10              
11              
12             # ---------------------------------------------------------
13             # Fetch and cache remote Node.js version list
14             # ---------------------------------------------------------
15              
16             sub fetch_remote_list {
17 4     4 0 27028 my $cfg = NVMPL::Config->load();
18 4         36 my $mirror = $cfg->{mirror_url};
19 4         11 my $install_dir = $cfg->{install_dir};
20 4         59 my $cachefile = File::Spec->catfile($install_dir, 'node_index_cache.json');
21 4         13 my $ttl = $cfg->{cache_ttl};
22              
23 4         24 my $json_data;
24 4         9 my $use_cache = 0;
25              
26 4 100       139 if (-f $cachefile) {
27 2         24 my $age = time - (stat($cachefile))[9];
28 2 100       9 if ($age < $ttl) {
29 1         2 $use_cache = 1;
30 1         7 log_info("Using cached node index ($cachefile)");
31 1 50       44 open my $fh, '<', $cachefile or die "Cannot read cache: $!";
32 1         6 local $/;
33 1         37 $json_data = <$fh>;
34 1         18 close $fh;
35             }
36             }
37              
38 4 100       16 unless ($use_cache) {
39 3         8 my $url = "$mirror/index.json";
40 3         18 log_info("Fetching remote version list from $url");
41              
42 3         31 my $ua = HTTP::Tiny->new(timeout => 10);
43 3         514 my $resp = $ua->get($url);
44 3 100       32 unless ($resp->{success}) {
45 1         10 log_error("Failed to fetch index.json: $resp->{status} $resp->{reason}");
46 1         20 die "Network error while fetching index.json\n";
47             }
48 2         6 $json_data = $resp->{content};
49              
50 2 50       309 open my $fh, '>', $cachefile or log_warn("Could not write cache: $!");
51 2         36 print $fh $json_data;
52 2         158 close $fh;
53             }
54              
55 3         20 my $releases = decode_json($json_data);
56 3         3426 return $releases;
57             }
58              
59             # ---------------------------------------------------------
60             # List remote Node versions (optionally filtered)
61             # ---------------------------------------------------------
62              
63             sub list_remote_versions {
64 2     2 0 11378 my (%opts) = @_;
65 2         7 my $releases = fetch_remote_list();
66              
67 2         88 my @filtered;
68 2 100       10 if ($opts{lts}) {
69 1         4 @filtered = grep { $_->{lts} } @$releases;
  4         11  
70             } else {
71 1         5 @filtered = @$releases;
72             }
73              
74 2   100     11 my $limit = $opts{limit} // 20;
75 2 100       10 splice(@filtered, $limit) if @filtered > $limit;
76              
77 2         9 say "[nvm-pl] Available Node.js versions:";
78 2         6 foreach my $r (@filtered) {
79 8         14 my $v = $r->{version};
80 8 100       21 my $lts = $r->{lts} ? "(LTS: $r->{lts})" : "";
81 8         43 say " $v $lts";
82             }
83             }
84              
85             1;