--- deliantra/server/lib/cf.pm 2007/06/10 04:24:50 1.277 +++ deliantra/server/lib/cf.pm 2007/06/11 21:38:14 1.278 @@ -945,48 +945,76 @@ }, ); -sub load_extension { - my ($path) = @_; +sub load_extensions { + cf::sync_job { + my %todo; - $path =~ /([^\/\\]+)\.ext$/ or die "$path"; - my $base = $1; - my $pkg = $1; - $pkg =~ s/[^[:word:]]/_/g; - $pkg = "ext::$pkg"; - - warn "... loading '$path' into '$pkg'\n"; - - open my $fh, "<:utf8", $path - or die "$path: $!"; - - my $source = - "package $pkg; use strict; use utf8;\n" - . "#line 1 \"$path\"\n{\n" - . (do { local $/; <$fh> }) - . "\n};\n1"; - - unless (eval $source) { - my $msg = $@ ? "$path: $@\n" - : "extension disabled.\n"; - if ($source =~ /^#!.*perl.*#.*MANDATORY/m) { # ugly match - warn $@; - warn "mandatory extension failed to load, exiting.\n"; - exit 1; - } - die $@; - } + for my $path (<$LIBDIR/*.ext>) { + next unless -r $path; - push @EXTS, $pkg; -} + $path =~ /([^\/\\]+)\.ext$/ or die "$path"; + my $base = $1; + my $pkg = $1; + $pkg =~ s/[^[:word:]]/_/g; + $pkg = "ext::$pkg"; + + open my $fh, "<:utf8", $path + or die "$path: $!"; + + my $source = do { local $/; <$fh> }; + + my %ext = ( + path => $path, + base => $base, + pkg => $pkg, + ); + + $ext{meta} = { map { split /=/, $_, 2 } split /\s+/, $1 } + if $source =~ /^#!.*?perl.*?#\s*(.*)$/; + + $ext{source} = + "package $pkg; use strict; use utf8;\n" + . "#line 1 \"$path\"\n{\n" + . $source + . "\n};\n1"; -sub load_extensions { - for my $ext (<$LIBDIR/*.ext>) { - next unless -r $ext; - eval { - load_extension $ext; - 1 - } or warn "$ext not loaded: $@"; - } + $todo{$base} = \%ext; + } + + my %done; + while (%todo) { + my $progress; + + while (my ($k, $v) = each %todo) { + for (split /,\s*/, $ext{meta}{depends}) { + goto skip + unless exists $done{$_}; + } + + warn "... loading '$k' into '$v->{pkg}'\n"; + + unless (eval $v->{source}) { + my $msg = $@ ? "$v->{path}: $@\n" + : "extension disabled.\n"; + + if (exists $v->{meta}{mandatory}) { + warn $msg; + warn "mandatory extension failed to load, exiting.\n"; + exit 1; + } + + die $msg; + } + + $done{$k} = delete $todo{$k}; + push @EXTS, $v->{pkg}; + } + + skip: + die "cannot load " . (join ", ", keys %todo) . ": unable to resolve dependencies\n" + unless $progress; + } + }; } #############################################################################