File Coverage

blib/lib/Sys/OsRelease.pm
Criterion Covered Total %
statement 162 180 90.0
branch 53 76 69.7
condition 8 12 66.6
subroutine 34 37 91.8
pod 13 17 76.4
total 270 322 83.8


line stmt bran cond sub pod time code
1             # Sys::OsRelease
2             # ABSTRACT: read operating system details from standard /etc/os-release file
3             # Copyright (c) 2022 by Ian Kluft
4             # Open Source license Perl's Artistic License 2.0:
5             # SPDX-License-Identifier: Artistic-2.0
6              
7             # This module must be maintained for minimal dependencies so it can be used to build systems and containers.
8              
9             ## no critic (Modules::RequireExplicitPackage)
10             # This resolves conflicting Perl::Critic rules which want package and strictures each before the other
11 4     4   325940 use strict;
  4         6  
  4         126  
12 4     4   27 use warnings;
  4         7  
  4         213  
13 4     4   2340 use utf8;
  4         1022  
  4         24  
14             ## use critic (Modules::RequireExplicitPackage)
15              
16             package Sys::OsRelease;
17             $Sys::OsRelease::VERSION = '0.3.1';
18             BEGIN {
19 4     4   1272 use version;
  4         5610  
  4         25  
20 4 50   4   294 if ( $^V >= version->declare("v5.16.0")) {
  0         0  
21 4     4   389 use feature qw(fc);
  4         8  
  4         479  
22             }
23             }
24 4     4   24 use feature qw(say);
  4         7  
  4         404  
25 4     4   23 use Config;
  4         6  
  4         235  
26 4     4   24 use Carp qw(carp croak);
  4         5  
  4         2417  
27              
28             # the instance - use Sys::OsRelease->instance() to get it
29             my %_instances = ();
30              
31             # default search path and file name for os-release file
32             my @std_search_path = qw(/etc /usr/lib /run/host);
33             my $std_file_name = "os-release";
34              
35             # defined attributes from FreeDesktop's os-release standard - this needs to be kept up-to-date with the standard
36             my @std_attrs = qw(NAME ID ID_LIKE PRETTY_NAME CPE_NAME VARIANT VARIANT_ID VERSION VERSION_ID VERSION_CODENAME
37             BUILD_ID IMAGE_ID IMAGE_VERSION RELEASE_TYPE HOME_URL DOCUMENTATION_URL SUPPORT_URL BUG_REPORT_URL
38             PRIVACY_POLICY_URL SUPPORT_END LOGO ANSI_COLOR ANSI_COLOR_REVERSE VENDOR_NAME VENDOR_URL EXPERIMENT
39             EXPERIMENT_URL DEFAULT_HOSTNAME ARCHITECTURE SYSEXT_LEVEL CONFEXT_LEVEL SYSEXT_SCOPE CONFEXT_SCOPE
40             PORTABLE_PREFIXES PORTABLE_SCOPE);
41              
42             # OS ID strings which are preferred as common if found in ID_LIKE
43             my %common_id = (
44             alpine => 1,
45             arch => 1,
46             fedora => 1,
47             debian => 1,
48             opensuse => 1,
49             );
50              
51             # call destructor when program ends
52             END {
53 4     4   10015 foreach my $class (keys %_instances) {
54 1         6 $class->clear_instance();
55             }
56 4         62 undef %_instances;
57             }
58              
59             #
60             # singleton management methods
61             # These can be imported by another class by using the import_singleton() method. That was done for Sys::OsPackage,
62             # to avoid copying those methods. But other classes with a similar need to minimize module dependencies which already
63             # use Sys::OsRelease can do this too.
64             #
65              
66             # alternative method to initiate initialization without returning a value
67             sub init
68             {
69 0     0 1 0 my ($class, @params) = @_;
70 0         0 $class->instance(@params);
71 0         0 return;
72             }
73              
74             # new method calls instance
75             sub new
76             {
77 0     0 1 0 my ($class, @params) = @_;
78 0         0 return $class->instance(@params);
79             }
80              
81             # singleton class instance
82             sub instance
83             {
84 31     31 1 459861 my ($class, @params) = @_;
85              
86             # initialize if not already done
87 31 100       106 if (not $class->defined_instance()) {
88 12         60 $_instances{$class} = $class->_new_instance(@params);
89             }
90              
91             # return singleton instance
92 31         141 return $_instances{$class};
93             }
94              
95             # test if instance is defined for testing
96             sub defined_instance
97             {
98 45     45 1 1759 my $class = shift;
99 45 100 66     515 return ((exists $_instances{$class}) and $_instances{$class}->isa($class)) ? 1 : 0;
100             }
101              
102             # clear instance for exit-cleanup or for re-use in testing
103             sub clear_instance
104             {
105 12     12 1 45554 my $class = shift;
106 12 50       56 if ($class->defined_instance()) {
107             # clean up anything that the destructor will miss, such as auto-generated methods
108 12 50       128 if ($class->can("_cleanup_instance")) {
109 12         75 $class->_cleanup_instance();
110             }
111              
112             # dereferencing will destroy singleton instance
113 12         55 delete $_instances{$class};
114             }
115 12         229 return;
116             }
117              
118             # allow other classes which cooperate with Sys::OsRelease to import our singleton-management methods
119             # This helps maintain minimal prerequisites among modules working to set up Perl on containers or new systems.
120             sub import_singleton
121             {
122 1     1 1 221031 my $class = shift;
123 1         9 my $caller_class = caller;
124              
125             # export singleton-management methods to caller class
126 1         4 foreach my $method_name (qw(init new instance defined_instance clear_instance)) {
127             ## no critic (TestingAndDebugging::ProhibitNoStrict)
128 4     4   41 no strict 'refs';
  4         10  
  4         9019  
129 5         10 *{$caller_class."::".$method_name} = \&{$class."::".$method_name};
  5         17  
  5         18  
130             }
131 1         9 return;
132             }
133              
134             #
135             # os-release data access methods
136             #
137              
138             # access module constants
139 1     1 0 1123 sub std_search_path { return @std_search_path; }
140 1     1 0 336414 sub std_attrs { return @std_attrs; }
141              
142             # fold case for case-insensitive matching
143             my $can_fc = CORE->can("fc"); # test fc() once and save result
144             sub fold_case
145             {
146 768     768 0 1331 my $str = shift;
147              
148             # use fc if available, otherwise lc to support older Perls
149 768 50       4816 return $can_fc ? $can_fc->($str) : lc($str);
150             }
151              
152             # initialize a new instance
153             sub _new_instance
154             {
155 12     12   45 my ($class, @params) = @_;
156              
157             # enforce class lineage - _new_instance() should be overloaded by other classes that import singleton methods
158 12 50       78 if (not $class->isa(__PACKAGE__)) {
159 0 0       0 croak "_new_instance() should be overloaded by calling class: "
160             .(ref $class ? ref $class : $class)." is not a ".__PACKAGE__;
161             }
162              
163             # obtain parameters from array or hashref
164 12         27 my %obj;
165 12 100       52 if (scalar @params > 0) {
166 10 50       43 if (ref $params[0] eq 'HASH') {
167 0         0 $obj{_config} = $params[0];
168             } else {
169 10         55 $obj{_config} = {@params};
170             }
171             }
172              
173             # locate os-release file in standard places
174 12         24 my $osrelease_path;
175 12 100       56 my @search_path = ((exists $obj{_config}{search_path}) ? @{$obj{_config}{search_path}} : @std_search_path);
  10         33  
176 12 100       50 my $file_name = ((exists $obj{_config}{file_name}) ? $obj{_config}{file_name} : $std_file_name);
177 12         34 foreach my $search_dir (@search_path) {
178 11 50       3401 if (-r "$search_dir/$file_name") {
179 11         61 $osrelease_path = $search_dir."/".$file_name;
180 11         38 last;
181             }
182             }
183              
184             # If we found os-release on this system, read it
185             # otherwise leave everything empty and platform() method will use Perl's $Config{osname} as a summary value
186 12 100       44 if (defined $osrelease_path) {
187             # save os-release file path
188 11         49 $obj{_config}{osrelease_path} = $osrelease_path;
189              
190             # read os-release file
191             ## no critic (InputOutput::RequireBriefOpen)
192 11 50       939 if (open my $fh, "<", $osrelease_path) {
193 11         850 while (my $line = <$fh>) {
194 134         269 chomp $line; # remove trailing nl
195 134 50       335 if (substr($line, -1, 1) eq "\r") {
196 0         0 $line = substr($line, 0, -1); # remove trailing cr
197             }
198              
199             # skip comments and blank lines
200 134 50 33     755 if ($line =~ /^ \s+ #/x or $line =~ /^ \s+ $/x) {
201 0         0 next;
202             }
203              
204             # read attribute assignment lines
205 134 100 66     715 if ($line =~ /^ ([A-Z0-9_]+) = "(.*)" $/x
      100        
206             or $line =~ /^ ([A-Z0-9_]+) = '(.*)' $/x
207             or $line =~ /^ ([A-Z0-9_]+) = (.*) $/x)
208             {
209 132 50       329 next if $1 eq "_config"; # don't overwrite _config
210 132         235 $obj{fold_case($1)} = $2;
211             }
212             }
213 11         227 close $fh;
214             }
215             }
216              
217             # bless instance and generate accessor methods
218 12         96 my $obj_ref = bless \%obj, $class;
219 12         72 $obj_ref->_gen_accessors();
220              
221             # instantiate object
222 12         70 return $obj_ref;
223             }
224              
225             # helper function to allow methods to get the instance ref when called via the class name
226             sub class_or_obj
227             {
228 1116     1116 0 1760 my $coo = shift;
229              
230             # return the instance
231 1116 100       2737 return ((ref $coo) ? $coo : $coo->instance());
232             }
233              
234             # clean up data in an instance before feeding it to the destructor
235             sub _cleanup_instance
236             {
237 12     12   51 my ($class_or_obj) = @_;
238 12         39 my $self = class_or_obj($class_or_obj);
239              
240             # enforce class lineage - _cleanup_instance() should be overloaded by other classes that import singleton methods
241 12 50       58 if (not $self->isa(__PACKAGE__)) {
242 0         0 croak "_new_instance() should be overloaded by calling class: "
243             .(ef $self)." is not a ".__PACKAGE__;
244             }
245              
246             # clear accessor functions
247 12         28 foreach my $acc (keys %{$self->{_config}{accessor}}) {
  12         206  
248 420         752 $self->_clear_accessor($acc);
249             }
250 12         58 return;
251             }
252              
253             # determine platform type
254             sub platform
255             {
256 4     4 1 2492 my ($class_or_obj) = @_;
257 4         13 my $self = class_or_obj($class_or_obj);
258            
259             # if we haven't already saved this result, compute and save it
260 4 100       14 if (not $self->has_config("platform")) {
261 2 100       12 if ($self->has_attr("id")) {
262 1         7 $self->config("platform", $self->id);
263             }
264 2 100       9 if ($self->has_attr("id_like")) {
265             # check if the configuration has additional common IDs which should be recognized if seen in ID_LIKE
266 1 50       4 if ($self->has_config("common_id")) {
267 0         0 my $cids = $self->config("common_id");
268 0 0       0 my @cids = (ref $cids eq "ARRAY") ? (@{$cids}) : (split /\s+/x, $cids);
  0         0  
269 0         0 foreach my $cid (@cids) {
270 0         0 $common_id{$cid} = 1;
271             }
272             }
273              
274             # check ID_LIKE for more common names which should be used instead of ID
275 1         5 foreach my $like (split /\s+/x, $self->id_like) {
276 1 50       10 if (exists $common_id{$like}) {
277 1         5 $self->config("platform", $like);
278 1         5 last;
279             }
280             }
281             }
282              
283             # if platform is still not set, use Perl's osname config as a summary value
284 2 100       13 if (not $self->has_config("platform")) {
285 1         11 $self->config("platform", $Config{osname});
286             }
287             }
288 4         12 return $self->config("platform");
289             }
290              
291             # get location of the os-release file found on this system
292             # return undef if the file was not found
293             sub osrelease_path
294             {
295 1     1 1 10 my ($class_or_obj) = @_;
296 1         3 my $self = class_or_obj($class_or_obj);
297 1 50       5 if (exists $self->{_config}{osrelease_path}) {
298 1         7 return $self->{_config}{osrelease_path};
299             }
300 0         0 return;
301             }
302              
303             # return list of attributes found in os-release file
304             sub found_attrs
305             {
306 13     13 1 7670 my ($class_or_obj) = @_;
307 13         47 my $self = class_or_obj($class_or_obj);
308 13         106 return grep { $_ ne "_config" } keys %$self;
  145         383  
309             }
310              
311             # attribute existence checker
312             sub has_attr
313             {
314 110     110 1 92283 my ($class_or_obj, $key) = @_;
315 110         277 my $self = class_or_obj($class_or_obj);
316 110 100       332 return ((exists $self->{fold_case($key)}) ? 1 : 0);
317             }
318              
319             # attribute read-only accessor
320             sub get
321             {
322 106     106 1 289 my ($class_or_obj, $key) = @_;
323 106         228 my $self = class_or_obj($class_or_obj);
324 106         234 return $self->{fold_case($key)};
325             }
326              
327             # attribute existence checker
328             sub has_config
329             {
330 11     11 1 27134 my ($class_or_obj, $key) = @_;
331 11         31 my $self = class_or_obj($class_or_obj);
332 11 100       62 return ((exists $self->{_config}{$key}) ? 1 : 0);
333             }
334              
335             # config read/write accessor
336             sub config
337             {
338 7     7 1 37 my ($class_or_obj, $key, $value) = @_;
339 7         16 my $self = class_or_obj($class_or_obj);
340 7 100       21 if (defined $value) {
341 3         9 $self->{_config}{$key} = $value;
342             }
343 7         46 return $self->{_config}{$key};
344             }
345              
346             # generate accessor methods for all defined and standardized attributes
347             # private internal method
348             sub _gen_accessors
349             {
350 12     12   31 my ($class_or_obj) = @_;
351 12         60 my $self = class_or_obj($class_or_obj);
352              
353             # generate accessors for standardized attributes whether or not they were not found in os-release
354             # for attributes which exist, it makes a read-only accessor
355             # for attributes which don't exist, it makes an undef accessor
356 12         44 foreach my $std_attr (@std_attrs) {
357 420 50       877 next if $std_attr eq "_config"; # protect special/reserved attribute
358 420         706 my $fc_attr = fold_case($std_attr);
359 420         855 $self->_gen_accessor($fc_attr);
360             }
361 12         27 return;
362             }
363              
364             # generate accessor
365             # private internal method
366             sub _gen_accessor
367             {
368 420     420   772 my ($class_or_obj, $name) = @_;
369 420         758 my $self = class_or_obj($class_or_obj);
370 420 50       868 my $class = (ref $self) ? (ref $self) : $self;
371 420         701 my $method_name = $class."::".$name;
372              
373             # mark accessor flag in configuration so it can be deleted for cleanup (mainly for testing)
374 420 100       1581 if (not exists $self->{_config}{accessor}) {
375 12         38 $self->{_config}{accessor} = {};
376             }
377              
378             # generate accessor as read-only or undef depending whether it exists in the running system
379 420 100       930 if (exists $self->{$name}) {
380             # generate read-only accessor for attribute which was found in os-release
381 119     3   1041 $self->{_config}{accessor}{$name} = sub { return $self->{$name} };
  3         18  
382             } else {
383             # generate undef accessor for standard attribute which was not found in os-release
384 301     0   1215 $self->{_config}{accessor}{$name} = sub { return; };
  0         0  
385             }
386              
387             ## no critic (TestingAndDebugging::ProhibitNoStrict)
388 4     4   32 no strict 'refs';
  4         7  
  4         739  
389 420         801 *{$method_name} = $self->{_config}{accessor}{$name};
  420         1336  
390 420         1037 return;
391             }
392              
393             # clean up accessor
394             # private internal method
395             sub _clear_accessor
396             {
397 420     420   754 my ($class_or_obj, $name) = @_;
398 420         727 my $self = class_or_obj($class_or_obj);
399 420 50       839 my $class = (ref $self) ? (ref $self) : $self;
400 420 50       952 if (exists $self->{_config}{accessor}{$name}) {
401 420         657 my $method_name = $class."::".$name;
402             ## no critic (TestingAndDebugging::ProhibitNoStrict)
403 4     4   26 no strict 'refs';
  4         6  
  4         883  
404 420         591 undef *{$method_name};
  420         1343  
405 420         2139 delete $self->{_config}{accessor}{$name};
406             }
407 420         832 return;
408             }
409              
410             1;
411              
412             =pod
413              
414             =encoding UTF-8
415              
416             =head1 NAME
417              
418             Sys::OsRelease - read operating system details from standard /etc/os-release file
419              
420             =head1 VERSION
421              
422             version 0.3.1
423              
424             =head1 SYNOPSIS
425              
426             non-object-oriented:
427              
428             Sys::OsRelease->init();
429             my $id = Sys::OsRelease->id();
430             my $id_like = Sys::OsRelease->id_like();
431              
432             object-oriented:
433              
434             my $osrelease = Sys::OsRelease->instance();
435             my $id = $osrelease->id();
436             my $id_like = $osrelease->id_like();
437              
438             =head1 DESCRIPTION
439              
440             Sys::OsRelease is a helper library to read the /etc/os-release file, as defined by FreeDesktop.Org.
441             The os-release file is used to define an operating system environment.
442             It has been in widespread use among Linux distributions since 2017 and BSD variants since 2020.
443             It was started on Linux systems which use the systemd software, but then spread to other Linux, BSD and
444             Unix-based systems.
445             Its purpose is to identify the system to any software which needs to know.
446             It differentiates between Unix-based operating systems and even between Linux distributions.
447              
448             Sys::OsRelease is implemented with a singleton model, meaning there is only one instance of the class.
449             Instead of instantiating an object with new(), the instance() class method returns the one and only instance.
450             The first time it's called, it instantiates it.
451             On following calls, it returns a reference to the singleton instance.
452              
453             This module maintains minimal prerequisites, and only those which are usually included with Perl.
454             (Suggestions of new features and code will have to follow this rule.)
455             That is intended to be acceptable for establishing system or container environments which contain Perl programs.
456             It can also be used for installing or configuring software that needs to know about the system environment.
457              
458             =head2 The os-release Standard
459              
460             FreeDesktop.Org's os-release standard is at L.
461              
462             Current attributes recognized by Sys::OsRelease are:
463             NAME ID ID_LIKE PRETTY_NAME CPE_NAME VARIANT VARIANT_ID VERSION VERSION_ID VERSION_CODENAME BUILD_ID IMAGE_ID
464             IMAGE_VERSION HOME_URL DOCUMENTATION_URL SUPPORT_URL BUG_REPORT_URL PRIVACY_POLICY_URL LOGO ANSI_COLOR
465             DEFAULT_HOSTNAME SYSEXT_LEVEL
466              
467             If other attributes are found in the os-release file, they will be accepted.
468             Folded to lower case, the attribute names are used as keys in an internal hash structure.
469              
470             =head1 METHODS
471              
472             =head2 Class methods
473              
474             I uses a singleton model. So there is only one instance.
475             Class methods manage the singleton instance, or import those methods to another cooperating class' namespace.
476              
477             Class methods must be called using the class name, like Cinstance()> .
478              
479             =over 1
480              
481             =item init([key => value, ...])
482              
483             initializes the singleton instance without returning a value.
484             Parameters are passed to the instance() method.
485             This method is for cases where method calls will be via the class name, and the program
486             doesn't need a reference to the instance.
487              
488             Under normal circumstances no parameters are needed. See instance() for possible parameters.
489              
490             =item new([key => value, ...])
491              
492             initializes the singleton instance and returns a reference to it.
493             Parameters are passed to the instance() method.
494             This is equivalent to using the instance() method, made available if new() sounds more comfortable.
495              
496             Under normal circumstances no parameters are needed. See instance() for possible parameters.
497              
498             =item instance([key => value, ...])
499              
500             initializes the singleton instance and returns a reference to it.
501              
502             Under normal circumstances no parameters are needed. Possible optional parameters are as follows:
503              
504             =over 1
505              
506             =item common_id
507              
508             supplies an arrayref to use as a list of additional common strings which should be recognized by the platform()
509             method, if they occur in the ID_LIKE attribute in the os-release file. By default, "debian" and "fedora" are
510             regonized by platform() as common names and it will return them instead of the system's ID attribute.
511              
512             =item search_path
513              
514             supplies an arrayref of strings with directories to use as the search path for the os-release file.
515              
516             =item file_name
517              
518             supplies a string with the basename of the file to look for the os-release file.
519             Obviously the default file name is "os-release".
520             Under normal circumstances there is no need to set this.
521             Currently this is only used for testing, where suffixes are added for copies of various different systems'
522             os-release files, to indicate which system they came from.
523              
524             =back
525              
526             =item defined_instance()
527              
528             returns true if the singleton instance is defined, false if it is not yet defined or has been cleared.
529              
530             =item clear_instance()
531              
532             removes the singleton instance of the class if it was defined.
533             Under normal circumstances it is not necessary to call this since the class destructor will call it automatically.
534             It is currently only used for testing, where it is necessary to clear the instance before loading a new one with
535             different parameters.
536              
537             Since this class is based on the singleton model, there is only one instance.
538             The instance(), new() and init() methods will only initialize the instance if it is not already initialized.
539              
540             =item import_singleton()
541              
542             The singleton-management methods I, I, I, I and I
543             can be imported by another class by using the import_singleton() method.
544             That was done for L, to allow it to avoid copying those methods.
545             But other classes with a similar need to minimize module dependencies which already
546             use I can do this too.
547             This helps maintain minimal prerequisites among modules working to set up Perl on containers or new systems.
548              
549             =back
550              
551             =head2 Instance methods
552              
553             Object methods, including auto-generated accessors described above, access the data from the singleton instance,
554             either read from an os-release file or empty to indicate no os-release file was found on the system.
555              
556             Instance methods may be called either via the class name or a reference to the singleton instance.
557             Each of these functions can determine whether they were called as a class or object method, and obtain the
558             reference to the singleton instance if needed.
559              
560             =over 1
561              
562             =item platform()
563              
564             returns a string with the platform type. On systems with /etc/os-release (or os-release in any location
565             from the standard) this is usually from the ID field.
566             On systems that use the ID_LIKE field, systems that claim to be like "debian" or "fedora" (always in lower case)
567             will return those names for the platform.
568              
569             The list of recognized common platforms can be modified by passing a "common_id" parameter to instance()/new()
570             with an arrayref containing additional names to recognize as common. For example, "centos" is another possibility.
571             It was not included in the default because CentOS is discontinued. Both Rocky Linux and Alma Linux have
572             ID_LIKE fields of "rhel centos fedora", which will match "fedora" with the default setting, but could be configured
573             via "common_id" to recognize "centos" since it's listed first in ID_LIKE.
574              
575             On systems where an os-release file doesn't exist or isn't found, the platform string will fall back to Perl's
576             $Config{osname} setting for the system.
577              
578             =item osrelease_path()
579              
580             returns the path where os-release was found.
581              
582             The default search path is /etc, /usr/lib and /run/host as defined by the standard.
583             The search path can be replaced by providing a "search_path" parameter to instance()/new() with an arrayref
584             containing the directories to search. This feature is currently only used for testing purposes.
585              
586             =item found_attrs()
587              
588             returns a list of attribute names found in the os-release file, empty if os-release doesn't exist on the platform.
589              
590             =item has_attr(name)
591              
592             returns a boolean which is true if the attribute named by the string parameter exists in the os-release data for the
593             current system.
594             The attribute name is case insensitive.
595              
596             =item get(name)
597              
598             is a read-only accessor which returns the value of the os-release attribute named by the string parameter,
599             or undef if it doesn't exist.
600              
601             =item has_config(name)
602              
603             returns a boolean which is true if Sys::OsRelease contains a configuration setting named by the string parameter.
604              
605             =item config(name, [value])
606              
607             is a read/write accessor for the configuration setting named by the string parameter "name".
608             If no value parameter is provided, it returns the value of the parameter, or undef if it doesn't exist.
609             If a value parameter is provided, it assigns that to the configuration setting and returns the same value.
610              
611             =back
612              
613             =head2 Auto-generated Accessor Methods
614              
615             For convenience, I generates read-only accessor methods for each of the standard
616             attribute names, converted to lower case. For example, from the list above they are I, I,
617             I, etc. The auto-generated methods do not require any parameters, and ignore any if provided.
618              
619             Accessor methods are not generated for non-standard atttributes because it would be unreliable to try to
620             call methods named for transient data that may or may not exist on a given platform, and for the possibility
621             they could conflict with existing functions in the I namespace. Use the I,
622             I and I methods to detect and access non-standard attributes.
623              
624             The current full list is at the os-release standard
625             L
626             which includes descriptions of each attribute.
627              
628             =over 1
629              
630             =item name()
631              
632             =item id()
633              
634             =item id_like()
635              
636             =item pretty_name()
637              
638             =item cpe_name()
639              
640             =item variant()
641              
642             =item variant_id()
643              
644             =item version()
645              
646             =item version_id()
647              
648             =item version_codename()
649              
650             =item build_id()
651              
652             =item image_id()
653              
654             =item image_version()
655              
656             =item release_type()
657              
658             =item home_url()
659              
660             =item documentation_url()
661              
662             =item support_url()
663              
664             =item bug_report_url()
665              
666             =item privacy_policy_url()
667              
668             =item support_end()
669              
670             =item logo()
671              
672             =item ansi_color()
673              
674             =item ansi_color_reverse()
675              
676             =item vendor_name()
677              
678             =item vendor_url()
679              
680             =item experiment()
681              
682             =item experiment_url()
683              
684             =item default_hostname()
685              
686             =item architecture()
687              
688             =item sysext_level()
689              
690             =item confext_level()
691              
692             =item sysext_scope()
693              
694             =item confext_scope()
695              
696             =item portable_prefixes()
697              
698             =item portable_scope()
699              
700             =back
701              
702             =head1 SEE ALSO
703              
704             FreeDesktop.Org's os-release standard: L
705              
706             GitHub repository for Sys::OsRelease: L
707              
708             Related modules:
709              
710             =over 1
711              
712             =item L
713              
714             installs Perl modules, for example as dependencies of a script, via OS packages if available or otherwise via CPAN -
715             uses Sys::OsRelease to determine OS type
716              
717             =item L
718              
719             system information collected from multiple sources including system architecture, hardware, OS release data
720              
721             =back
722              
723             =head1 BUGS AND LIMITATIONS
724              
725             Please report bugs via GitHub at L
726              
727             Patches and enhancements may be submitted via a pull request at L
728              
729             =head1 LICENSE INFORMATION
730              
731             Copyright (c) 2022 by Ian Kluft
732              
733             This module is distributed in the hope that it will be useful, but it is provided “as is” and without any express or implied warranties. For details, see the full text of the license in the file LICENSE or at L.
734              
735             =head1 AUTHOR
736              
737             Ian Kluft
738              
739             =head1 COPYRIGHT AND LICENSE
740              
741             This software is Copyright (c) 2022-2026 by Ian Kluft.
742              
743             This is free software, licensed under:
744              
745             The Artistic License 2.0 (GPL Compatible)
746              
747             =cut
748              
749             __END__