Skip to content

Commit

Permalink
Lots of small fixes. Now fact classes are loaded. Yay!
Browse files Browse the repository at this point in the history
  • Loading branch information
cosimo committed Nov 28, 2010
1 parent d6c4ed3 commit 5e20701
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 98 deletions.
5 changes: 3 additions & 2 deletions lib/Facter.pm
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ method collection {
$!collection //= Facter::Util::Collection.new $!collection //= Facter::Util::Collection.new
} }


method version () { method version {
return $VERSION $VERSION
} }


method BUILD { method BUILD {
Expand Down Expand Up @@ -146,6 +146,7 @@ method to_hash (*@args) {
method add ($name, Sub $block) { method add ($name, Sub $block) {
# TODO add %options support # TODO add %options support
#multi method add ($name, %options = (), $block) { #multi method add ($name, %options = (), $block) {
Facter.debug("Facter: adding fact $name as " ~ $block.perl);
my $instance = self // Facter.get_instance; my $instance = self // Facter.get_instance;
$instance.collection.add($name, $block); $instance.collection.add($name, $block);
} }
Expand Down
16 changes: 14 additions & 2 deletions lib/Facter/Util/Collection.pm
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@ method add($fact_name, Sub $block) {
# TODO add %options support # TODO add %options support
my %options = (); my %options = ();


Facter.debug("collection.add $fact_name: " ~ $block.perl);

my $name = self.canonize($fact_name); my $name = self.canonize($fact_name);


my $fact = %!facts{$name}; my $fact = %!facts{$name};
unless $fact { unless $fact {
$fact = Facter::Util::Fact.new($name); Facter.debug("new Fact '$name'");
$fact = Facter::Util::Fact.new(name => $name);
Facter.debug("new Fact '$name' created: " ~ $fact.perl);
%!facts{$name} = $fact; %!facts{$name} = $fact;
} }


Expand All @@ -41,6 +45,8 @@ method add($fact_name, Sub $block) {
} }


if $block { if $block {

Facter.debug("Fact " ~ $fact ~ " adding block " ~ $block.perl);
my $resolve = $fact.add($block); my $resolve = $fact.add($block);


# Set any resolve-appropriate options # Set any resolve-appropriate options
Expand Down Expand Up @@ -74,7 +80,13 @@ method each () {
# Return a fact by name. # Return a fact by name.
method fact($name) { method fact($name) {
my $fact_name = self.canonize($name); my $fact_name = self.canonize($name);
self.loader.load($fact_name) unless %!facts{$fact_name}; Facter.debug("self.canonize($name) = $fact_name");

unless %!facts{$fact_name} {
Facter.debug("Loading fact $fact_name through loader");
self.loader.load($fact_name);
}

return %!facts{$fact_name}; return %!facts{$fact_name};
} }


Expand Down
18 changes: 6 additions & 12 deletions lib/Facter/Util/Confine.pm
Original file line number Original file line Diff line number Diff line change
@@ -1,15 +1,9 @@
=begin pod #
# Facter::Util::Confine
=head1 NAME #
# A restricting tag for fact resolution mechanisms. The tag must be true
Facter::Util::Confine # for the resolution mechanism to be suitable.
#
=head1 DESCRIPTION
A restricting tag for fact resolution mechanisms. The tag must be true
for the resolution mechanism to be suitable.
=end pod


class Facter::Util::Confine; class Facter::Util::Confine;


Expand Down
19 changes: 9 additions & 10 deletions lib/Facter/Util/Fact.pm
Original file line number Original file line Diff line number Diff line change
@@ -1,11 +1,6 @@
use v6;

# FIXME Doesn't work because of search_path already defined
#use Facter;

class Facter::Util::Fact; class Facter::Util::Fact;


#se Facter::Util::Resolution; use Facter::Util::Resolution;


our $TIMEOUT = 5; our $TIMEOUT = 5;


Expand Down Expand Up @@ -34,22 +29,26 @@ method initialize($name, %options = ()) {


# Add a new resolution mechanism. This requires a block, which will then # Add a new resolution mechanism. This requires a block, which will then
# be evaluated in the context of the new mechanism. # be evaluated in the context of the new mechanism.
method add(Sub $block) { method add($block) {


#raise ArgumentError, "You must pass a block to Fact<instance>.add" unless block_given? #raise ArgumentError, "You must pass a block to Fact<instance>.add" unless block_given?
if ! $block { if ! $block {
die "You must pass a block to Fact<instance>.add"; die "You must pass a block to Fact<instance>.add";
} }


my $resolve = Facter::Util::Resolution.new($.name); Facter.debug("Fact.add($.name, $block)");
$resolve.instance_eval($block); my $resolve = Facter::Util::Resolution.new(name => $.name);

# ruby: resolve.instance_eval(block);
$block($resolve);

@.resolves.push($resolve); @.resolves.push($resolve);


# Immediately sort the resolutions, so that we always have # Immediately sort the resolutions, so that we always have
# a sorted list for looking up values. # a sorted list for looking up values.
# We always want to look them up in the order of number of # We always want to look them up in the order of number of
# confines, so the most restricted resolution always wins. # confines, so the most restricted resolution always wins.
#@resolves.sort! { |a, b| b.length <=> a.length } @.resolves = sort { $^b.elems <=> $^a.elems }, @.resolves;


return $resolve; return $resolve;
} }
Expand Down
8 changes: 4 additions & 4 deletions lib/Facter/Util/Loader.pm
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ method load($fact) {
my $module = "Facter::$shortname"; my $module = "Facter::$shortname";
try { try {
require $module; require $module;
CATCH { }
warn "Unable to load fact $shortname: $!"; CATCH {
return False; warn "Unable to load fact $shortname: $!";
} return False;
} }


return True; return True;
Expand Down
97 changes: 35 additions & 62 deletions lib/Facter/Util/Resolution.pm
Original file line number Original file line Diff line number Diff line change
@@ -1,41 +1,33 @@
=begin pod #
# Facter::Util::Resolution
=head1 NAME #
# An actual fact resolution mechanism. These are largely just chunks of
Facter::Util::Resolution # code, with optional confinements restricting the mechanisms to only working on
# specific systems. Note that the confinements are always ANDed, so any
=head1 DESCRIPTION # confinements specified must all be true for the resolution to be
# suitable.
An actual fact resolution mechanism. These are largely just chunks of #
code, with optional confinements restricting the mechanisms to only working on
specific systems. Note that the confinements are always ANDed, so any
confinements specified must all be true for the resolution to be
suitable.
=end pod


class Facter::Util::Resolution; class Facter::Util::Resolution;


use Facter::Util::Confine; #equire 'timeout'

#equire 'rbconfig'
#require 'timeout'
#require 'rbconfig'


has $.code is rw; has $.code is rw;
has $.interpreter is rw; has $.interpreter is rw;
has $.name is rw; has $.name is rw;
has $.value is rw; has $!value is rw;
has $.timeout is rw; has $.timeout is rw;
has @.confines is rw; has @.confines is rw;


our $WINDOWS = $*OS ~~ m:i/mswin|win32|dos|mingw|cygwin/; our $WINDOWS = $*OS ~~ m:i/mswin|win32|dos|mingw|cygwin/;
our $INTERPRETER = $WINDOWS ?? 'cmd.exe' :: '/bin/sh' our $INTERPRETER = $WINDOWS ?? 'cmd.exe' !! '/bin/sh';
our $HAVE_WHICH; our $HAVE_WHICH;


method have_which { method have_which {
if ! $HAVE_WHICH.defined { if ! $HAVE_WHICH.defined {
if Facter.value('kernel') == 'windows' { if Facter.value('kernel') eq 'windows' {
$HAVE_WHICH = False $HAVE_WHICH = False;
} else { } else {
$HAVE_WHICH = run('which which >/dev/null 2>&1') == 0; $HAVE_WHICH = run('which which >/dev/null 2>&1') == 0;
} }
Expand All @@ -50,7 +42,7 @@ method have_which {
# #
method exec($code, $interpreter = $INTERPRETER) { method exec($code, $interpreter = $INTERPRETER) {


unless $interpreter == $INTERPRETER { unless $interpreter eq $INTERPRETER {
die "invalid interpreter"; die "invalid interpreter";
} }


Expand All @@ -74,38 +66,37 @@ method exec($code, $interpreter = $INTERPRETER) {
# we don't have the binary necessary # we don't have the binary necessary
return if $path eq "" or $path.match(/Command not found\./); return if $path eq "" or $path.match(/Command not found\./);
} }

return unless $path.IO ~~ :e; return unless $path.IO ~~ :e;
} }


my $out; my $out;


Facter.debug("Running command $code");
try { try {
$out = qx{$code}.chomp; $out = qx{$code}.chomp;
} CATCH {
warn "Command failed: $!";
return;
} }

CATCH {
if $out == "" { Facter.debug("Command failed: $!");
return return;
} }


return if $out eq "";
return $out; return $out;
} }


# Add a new confine to the resolution mechanism. # Add a new confine to the resolution mechanism.
method confine(%confines) { method confine(%confines) {
require Facter::Util::Confine;
for %confines.kv -> $fact, $values { for %confines.kv -> $fact, $values {
@.confines.push(Facter::Util::Confine.new($fact, $values); @.confines.push(Facter::Util::Confine.new($fact, $values));
} }
} }


# Create a new resolution mechanism. # Create a new resolution mechanism.
method initialize($name) { method initialize($name) {
$.name = $name; $.name = $name;
@.confines = (); @.confines = ();
$.value = Mu; $!value = Mu;
$.timeout = 0; $.timeout = 0;
return; return;
} }
Expand All @@ -119,70 +110,52 @@ method length {
# of ruby seem to already have a 'timeout' method and we can't # of ruby seem to already have a 'timeout' method and we can't
# seem to override the instance methods, somehow. # seem to override the instance methods, somehow.
method limit { method limit {
$.timeout $.timeout;
} }


# Set our code for returning a value. # Set our code for returning a value.
method setcode($string = Mu, $interp = Mu, Sub $block) method setcode($string = "", $interp = "", $block) {
if $string { if $string {
$.code = $string; $.code = $string;
$.interpreter = $interp || $INTERPRETER; $.interpreter = $interp || $INTERPRETER;
} elsif $block { } elsif $block {
$.code = $block $.code = $block;
} else { } else {
die "You must pass either code or a block" die "You must pass either code or a block";
} }
} }


# Is this resolution mechanism suitable on the system in question? # Is this resolution mechanism suitable on the system in question?
method suitable method suitable {
unless defined $.suitable { unless defined $.suitable {
$.suitable = ! any(@confines, False); $.suitable = ! (any(@.confines) == False);
} }
return $.suitable; return $.suitable;
} }


method Str { method Str {
return self.value() return self.value;
} }


# How we get a value for our resolution mechanism. # How we get a value for our resolution mechanism.
method value { method value {


if ! $.code and ! $.interpreter { if ! $.code and ! $.interpreter {
Facter.debug("No code and no interpreter. Can't get value of fact $.name");
return; return;
} }


my $result; my $result;
my $starttime = time; my $starttime = time;


=begin ruby Facter.debug("Getting value of fact $.name...");
begin
Timeout.timeout(limit) do
if @code.is_a?(Proc)
result = @code.call()
else
result = Facter::Util::Resolution.exec(@code,@interpreter)
}
}
rescue Timeout::Error => detail
warn "Timed out seeking value for %s" % self.name
# This call avoids zombies -- basically, create a thread that will
# dezombify all of the child processes that we're ignoring because
# of the timeout.
Thread.new { Process.waitall }
return nil
rescue => details
warn "Could not retrieve %s: %s" % [self.name, details]
return nil
}
=end ruby


try { try {
if "Sub()" eq $.code.WHAT { if "Sub()" eq $.code.WHAT {
Facter.debug(" Running block $.code");
$result = $.code(); $result = $.code();
} else { } else {
Facter.debug(" Running command $.code through $.interpreter");
$result = Facter::Util::Resolution.exec($.code, $.interpreter); $result = Facter::Util::Resolution.exec($.code, $.interpreter);
} }
} }
Expand Down
10 changes: 7 additions & 3 deletions lib/Facter/perl6os.pm
Original file line number Original file line Diff line number Diff line change
@@ -1,3 +1,7 @@
Facter.add(<perl6os>, sub { Facter.add("perl6os", sub ($f) {
$*OS.Str; Facter.debug("perl6os fact block running");
}); $f.setcode(block => sub {
$*OS.Str
});
})

3 changes: 3 additions & 0 deletions t/000-load-classes.t
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ use Facter;
use Facter::Util::Fact; use Facter::Util::Fact;
use Facter::Util::Collection; use Facter::Util::Collection;
use Facter::Util::Loader; use Facter::Util::Loader;
use Facter::Util::Resolution;
use Facter::Util::Confine;
use Facter::Util::Values;


ok(1, 'Facter main classes loaded'); ok(1, 'Facter main classes loaded');


Expand Down
15 changes: 12 additions & 3 deletions t/basic.t
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -13,11 +13,20 @@ ok($coll, "Collection object is there");


my $test-fact = 'perl6os'; my $test-fact = 'perl6os';


my $lsbdistname = $facter.fact($test-fact); my $fact = $facter.fact($test-fact);
ok($fact, "test fact is loaded");
ok($fact.^can("value"), "fact object has a value() method");

my $lsbdistname = $facter.fact($test-fact).Str;
ok($lsbdistname, "fact '$test-fact' is loaded"); ok($lsbdistname, "fact '$test-fact' is loaded");
is($lsbdistname, $*OS, "test fact has correct value");

my $same-value = $facter.fact($test-fact).value;
is($lsbdistname, $same-value, "fact.value and fact.Str should yield the same result");


@search_dirs = $facter.search_path; # Unused for now...
ok(@search_dirs.elems > 0, "Search path should be filled now"); #@search_dirs = $facter.search_path;
#ok(@search_dirs.elems > 0, "Search path should be filled now");


diag("Collection object:" ~ $coll.perl); diag("Collection object:" ~ $coll.perl);
diag("Search dirs:" ~ @search_dirs.perl); diag("Search dirs:" ~ @search_dirs.perl);
Expand Down

0 comments on commit 5e20701

Please sign in to comment.