Burak Gürsoy avatar Burak Gürsoy committed 680b619

Improve sysctl parsers

Comments (0)

Files changed (5)

 
 0.794 Thu May 12 05:48:29 2011
     => Implement install date.
+    => Improve sysctl parsers.
 
 0.793 Tue May 10 03:02:09 2011
     => sysctl parser regex fix.
 lib/Sys/Info/Driver/OSX/Device.pm
 lib/Sys/Info/Driver/OSX/OS.pm
 lib/Sys/Info/Driver/OSX/Device/CPU.pm
+t/01-parsers.t
 t/03-basic.t
 Build.PL
 Changes

lib/Sys/Info/Driver/OSX.pm

     qr{second \s level \s name .+? in .+? is \s invalid}xms,
     qr{name                    .+? in .+? is \s unknown}xms,
 ;
-use constant RE_SYSCTL_SPLIT => qr{\n+}xms;
-use constant RE_SYSCTL_ROW   => qr{:(?:\s)+?}xms;
+use constant RE_SYSCTL_SPLIT   => qr{\n+}xms;
+use constant RE_SYSCTL_ROW     => qr{:(?:\s)+?}xms;
+use constant RE_OLD_SYSCTL_ROW => qr{(?:\s)+?=(?:\s)+?}xms;
 
 use Capture::Tiny qw( capture );
 use Carp          qw( croak   );
         foreach my $row ( split RE_SYSCTL_SPLIT, $out ) {
             chomp $row;
             next if ! $row;
-            my($name, $value) = split RE_SYSCTL_ROW, $row, 2;
-            if ( ! $value && $value ne '0' ) {
-                croak sprintf q(Can't happen: No value in output for property )
-                            . q('%s' inside row '%s' collected from key '%s'),
-                                $name || q([no name]),
-                                $row,
-                                $key;
-            }
+            my($name, $value) = _parse_sysctl_row( $row, $key );
             $rv{ $name } = $value;
         }
     }
     };
 }
 
+sub _parse_sysctl_row {
+    my($row, $key, $major) = @_;
+    $major ||= do {
+        my %sw_vers = sw_vers();
+        (split m{[.]}xms, $sw_vers{ProductVersion} || q{})[0] || 0;
+    };
+    my $re_row = $major == 10 ? RE_SYSCTL_ROW : RE_OLD_SYSCTL_ROW;
+    my($name, $value) = split $re_row, $row, 2;
+    if ( ! $value && ( ! defined $value || $value ne '0' ) ) {
+        croak sprintf q(Can't happen: No value in output for property )
+                    . q('%s' inside row '%s' collected from key '%s'),
+                        $name || q([no name]),
+                        $row,
+                        $key;
+    }
+    return $name, $value;
+}
+
 sub _sysctl_not_exists {
     my($error) = @_;
     return if ! $error;

lib/Sys/Info/Driver/OSX/OS.pm

 package Sys::Info::Driver::OSX::OS;
 use strict;
 use warnings;
+
+our $VERSION = '0.73';
+
 use base qw( Sys::Info::Base );
 use Carp qw( croak );
 use Cwd;
 use Sys::Info::Constants qw( LIN_REAL_NAME_FIELD );
 use Sys::Info::Driver::OSX;
 
-our $VERSION = '0.73';
+use constant RE_DATE_STAMP => qr{
+    \A
+     [a-z]{3}  \s                       # Thu
+    ([a-z]{3}) \s                       # May
+    ([0-9]{2}) \s                       # 12
+    ([0-9]{2} : [0-9]{2} : [0-9]{2}) \s # 00:51:29
+    ([0-9]{4})                          # 2011
+    \z
+}xmsi;
+
+my %MONTH_TO_ID = do {
+    my $c = 0;
+    map { $_ => $c++ }
+        qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec );
+};
 
 my %OSVERSION;
 
 sub uptime {
     my $key   = 'kern.boottime';
     my $value = fsysctl $key;
-    if ( $value =~ m<\A[{](.+?)[}]\s+?(.+?)\z>xms ) {
-        my($data, $stamp) = ($1, $2);
+    my $sec   = _parse_uptime( $value, $key );
+    croak "Bogus data returned from $key: $value" if ! $sec;
+    return $sec;
+}
+
+sub _parse_uptime {
+    my($value, $key) = @_;
+
+    if ( my @m = $value =~ m<\A[{](.+?)[}]\s+?(.+?)\z>xms ) {
+        my($data, $stamp) = @m;
         my %data = map {
                         map {
                             __PACKAGE__->trim($_)
         croak "sec key does not exist in $key" if ! exists $data{sec};
         return $data{sec};
     }
-    croak "Bogus data returned from $key: $value";
+
+    if ( my @m = $value =~ RE_DATE_STAMP ) {
+        my($mon_name, $mday, $hms, $year) = @m;
+        my $mon = $MONTH_TO_ID{ $mon_name }
+                    || croak "Unable to gather month from $mon_name";
+        my($hour, $min, $sec) = split m{:}xms, $hms;
+
+        require Time::Local;
+        return Time::Local::timelocal(
+            $sec, $min, $hour, $mday, $mon, $year
+        );
+    }
+
+    return;
 }
 
 # user methods
+#!/usr/bin/env perl -w
+use strict;
+use warnings;
+use Test::More qw( no_plan );
+
+use Sys::Info::Driver::OSX;
+use Sys::Info::Driver::OSX::OS;
+
+SYSCTL_ROW: {
+    my $p     = \&Sys::Info::Driver::OSX::_parse_sysctl_row;
+
+    my $kb_10 = q~kern.boottime: { sec = 1305150689, usec = 0 } Thu May 12 00:51:29 2011~;
+    my $kb_08 = q~kern.boottime = Thu Mar 31 17:43:09 2011~;
+
+    my($name_10, $value_10) = $p->( $kb_10, 'kern.boottime', 10 );
+    my($name_08, $value_08) = $p->( $kb_08, 'kern.boottime',  8 );
+
+    ok( $name_10,  'Got a name for v10'  );
+    ok( $value_10, 'Got a value for v10' );
+    ok( $name_08,  'Got a name for v8'  );
+    ok( $value_08, 'Got a value for v8' );
+
+    is( $name_10, 'kern.boottime', 'Name for v10' );
+    is( $value_10, '{ sec = 1305150689, usec = 0 } Thu May 12 00:51:29 2011',
+        'Value for v10' );
+    is( $name_08,  'kern.boottime',            'Name for v8'  );
+    is( $value_08, 'Thu Mar 31 17:43:09 2011', 'Value for v8' );
+
+}
+
+UPTIME: {
+    my $p     = \&Sys::Info::Driver::OSX::OS::_parse_uptime;
+
+    my $stamp = q~Thu May 12 00:51:29 2011~;
+    my $up_10 = $p->( q~{ sec = 1305150689, usec = 0 } Thu May 12 00:51:29 2011~,
+                        'kern.boottime' );
+    my $up_08 = $p->( $stamp , 'kern.boottime' );
+
+    ok( $up_10, 'Got uptime for v10' );
+    ok( $up_08, 'Got uptime for v8'  );
+
+    is( scalar localtime $up_10, $stamp, 'Correct uptime for v10');
+    is( scalar localtime $up_08, $stamp, 'Correct uptime for v8' );
+}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.