]> git.proxmox.com Git - pve-client.git/blob - PVE/APIClient/Helpers.pm
d6d1a176d6d482754fe8313623524d08e7b2b6fa
[pve-client.git] / PVE / APIClient / Helpers.pm
1 package PVE::APIClient::Helpers;
2
3 use strict;
4 use warnings;
5
6 use Storable;
7 use JSON;
8 use PVE::APIClient::Exception qw(raise);
9 use Encode::Locale;
10 use Encode;
11 use HTTP::Status qw(:constants);
12
13 my $pve_api_definition;
14 my $pve_api_path_hash;
15
16 my $pve_api_definition_fn = "/usr/share/pve-client/pve-api-definition.dat";
17
18 my $build_pve_api_path_hash;
19 $build_pve_api_path_hash = sub {
20 my ($tree) = @_;
21
22 my $class = ref($tree);
23 return $tree if !$class;
24
25 if ($class eq 'ARRAY') {
26 foreach my $el (@$tree) {
27 $build_pve_api_path_hash->($el);
28 }
29 } elsif ($class eq 'HASH') {
30 if (defined($tree->{leaf}) && defined(my $path = $tree->{path})) {
31 $pve_api_path_hash->{$path} = $tree;
32 }
33 foreach my $k (keys %$tree) {
34 $build_pve_api_path_hash->($tree->{$k});
35 }
36 }
37 };
38
39 sub get_api_definition {
40
41 if (!defined($pve_api_definition)) {
42 open(my $fh, '<', $pve_api_definition_fn) ||
43 die "unable to open '$pve_api_definition_fn' - $!\n";
44 $pve_api_definition = Storable::fd_retrieve($fh);
45 $build_pve_api_path_hash->($pve_api_definition);
46 }
47
48 return $pve_api_definition;
49 }
50
51 sub lookup_api_method {
52 my ($path, $method, $noerr) = @_;
53
54 get_api_definition(); # make sure API data is loaded
55
56 my $info = $pve_api_path_hash->{$path};
57
58 if (!$info) {
59 return undef if $noerr;
60 die "unable to find API info for path '$path'\n";
61 }
62
63 my $data = $info->{info}->{$method};
64
65 if (!$data) {
66 return undef if $noerr;
67 die "unable to find API method '$method' for path '$path'\n";
68 }
69
70 return $data;
71 }
72
73 sub complete_api_call_options {
74 my ($cmd, $prop, $prev, $cur, $args) = @_;
75
76 my $print_result = sub {
77 foreach my $p (@_) {
78 print "$p\n" if $p =~ m/^$cur/;
79 }
80 };
81
82 my $print_parameter_completion = sub {
83 my ($pname) = @_;
84 my $d = $prop->{$pname};
85 if ($d->{completion}) {
86 my $vt = ref($d->{completion});
87 if ($vt eq 'CODE') {
88 my $res = $d->{completion}->($cmd, $pname, $cur, $args);
89 &$print_result(@$res);
90 }
91 } elsif ($d->{type} eq 'boolean') {
92 &$print_result('0', '1');
93 } elsif ($d->{enum}) {
94 &$print_result(@{$d->{enum}});
95 }
96 };
97
98 my @option_list = ();
99 foreach my $key (keys %$prop) {
100 push @option_list, "--$key";
101 }
102
103 if ($cur =~ m/^-/) {
104 &$print_result(@option_list);
105 return;
106 }
107
108 if ($prev =~ m/^--?(.+)$/ && $prop->{$1}) {
109 my $pname = $1;
110 &$print_parameter_completion($pname);
111 return;
112 }
113
114 &$print_result(@option_list);
115 }
116
117 sub complete_api_path {
118 my ($text) = @_;
119
120 get_api_definition(); # make sure API data is loaded
121
122 $text =~ s!^/!!;
123
124 my ($dir, $rest) = $text =~ m|^(?:(.*)/)?(?:([^/]*))?$|;
125
126 my $info;
127 if (!defined($dir)) {
128 $dir = '';
129 $info = { children => $pve_api_definition };
130 } else {
131 $info = $pve_api_path_hash->{"/$dir"};
132 }
133
134 if ($info) {
135 if (my $children = $info->{children}) {
136 foreach my $c (@$children) {
137 if ($c->{path} =~ m!\Q$dir/$rest!) {
138 print "$c->{path}\n";
139 print "$c->{path}/\n"if $c->{children};
140 }
141 }
142 }
143 }
144 }
145
146 1;