use strict; use warnings; my $jdkconfig = $ENV{HOME}.'/.idea/config/options/jdk.table.xml'; # Default skeleton my $default = <<EOF; <?xml version="1.0" encoding="UTF-8"?> <!-- generated by $0 --> <application> <component name="ProjectJdkTable"> </component> </application> EOF # Genrate config skeleton, or read existing config file sub readconfig { my $input; open ($input, '<'.$jdkconfig) ? map { chop; $_ } <$input> : split (/\n/, $default); } # Genrate config skeleton, or read existing config file sub writeconfig { my $output; open ($output, '>'.$jdkconfig) or die $!; print $output join ("\n", @_); } # List of installed JDK roots sub jdkhomes { my $alter; open ($alter, 'alternatives --display javac |'); return grep { not /gcj/ } map { /^(\/\S+)\/bin\/javac/ ? $1 : () } <$alter>; } # Craft a nice name for JDK sub jdkname { my $jdkhome = shift; my $jdkname; my %jdknames = ( '/java-1\.(\d+)\.\d+-openjdk' => 'OpenJDK', '/java-1\.(\d+)\.\d+-sun' => 'Sun JDK', '/java-([\.\d]+)-ibm' => 'IBM Java', '/java-([\.\d]+)-bea' => 'BEA Java', '/java-([\.\d]+)-gcj' => 'GNU Compiler for Java', ); foreach (keys %jdknames) { $jdkhome =~ /$_/ and $jdkname = "$jdknames{$_} $1" and last; } ($jdkname) = $jdkhome =~ /([^\/]*)$/ unless $jdkname; return $jdkname; } # Get JDK libraries # Mocking findClasses (File, boolean) of # java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java sub jdkcp { my $jdkhome = shift; my @jars = map { <$jdkhome/jre/$_/*.jar> } ('lib', 'lib/ext', 'lib/endorsed'); } # Get JDK version sub jdkver { my $jdkhome = shift; my $version = [ `$jdkhome/bin/java -version 2>&1` ]->[0]; chomp $version; $version =~ s/\"/"/g; return $version; } # Generate XML config file chunk for a JDK directory sub jdkconfig { my $jdkhome = shift; return ( map { " $_" } '<jdk version="2">', ' <name value="'.jdkname ($jdkhome).'" />', ' <type value="JavaSDK" />', ' <version value="'.jdkver ($jdkhome).'" />', ' <homePath value="'.$jdkhome.'" />', ' <roots>', ' <annotationsPath>', ' <root type="composite" />', ' </annotationsPath>', ' <classPath>', ' <root type="composite">', (map { ' <root type="simple" url="jar://'.$_.'!/" />' } jdkcp ($jdkhome)), ' </root>', ' </classPath>', ' <javadocPath>', ' <root type="composite" />', ' </javadocPath>', ' <sourcePath>', ' <root type="composite" />', ' </sourcePath>', ' </roots>', ' <additional />', '</jdk>', ); } # Process the configuration and construct a new one my @sourceconfig = readconfig; my @targetconfig = (); my @jdks = (); my $thisjdk; my $component = ''; foreach (@sourceconfig) { if (/<\/jdk/ and defined $thisjdk) { undef $thisjdk; next; } elsif (defined $thisjdk) { /<(\w+) value="([^"]*)" \/>/ and $thisjdk->{$1} = $2; push @{$thisjdk->{lines}}, $_; next; } elsif (/<jdk version="2"/ and $component eq 'ProjectJdkTable') { $thisjdk = { lines => [] }; push @jdks, $thisjdk; next; } elsif (/<component name="([^"]*)"/) { $component = $1; } elsif (/<\/component/ and $component eq 'ProjectJdkTable') { push @targetconfig, # Generated configs for system-wide JVMs (map { jdkconfig ($_) } jdkhomes), # Already-defined JVMs, sans system-wide (map { $_->{homePath} =~ /^\/usr\/lib\/jvm/ ? () : @{$_->{lines}} } @jdks); @jdks = (); } push @targetconfig, $_; } # Rewrite the configuration writeconfig (@targetconfig);