sub _parse_vim_cmd_output()

in managementnode/lib/VCL/Module/Provisioning/VMware/VIM_SSH.pm [3194:3321]


sub _parse_vim_cmd_output {
	my $self = shift;
	if (ref($self) !~ /VCL::Module/i) {
		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
		return;
	}
	
	my ($argument, $debug) = @_;
	if (!defined($argument)) {
		notify($ERRORS{'WARNING'}, 0, "vim-cmd output argument was not supplied");
		return;
	}
	my @lines;
	if (my $type = ref($argument)) {
		if ($type eq 'ARRAY') {
			@lines = @$argument;
		}
		else {
			notify($ERRORS{'WARNING'}, 0, "argument is a $type reference, only an ARRAY reference or string are supported");
			return;
		}
	}
	elsif (scalar(@_) > 1) {
		@lines = @_;
	}
	else {
		@lines = split("\n", $argument);
	}
	
	my $statement;
	my $numbered_statement;
	my $line_number = 0;
	for my $line (@lines) {
		# Skip blank lines
		if ($line !~ /\S/) {
			next;
		}
		
		# Some commands such as 'vim-cmd vmsvc/get.summary' add this to the beginning:
		# Listsummary:
		if ($line =~ /:$/) {
			notify($ERRORS{'DEBUG'}, 0, "skipping line: $line");
			next;
		}
		
		$line_number++;
		
		my $original_line = $line;
		
		# Remove trailing newlines
		$line =~ s/\n+$//g;
		
		# Remove class names in parenthesis from beginning class name of indented lines
		# '   (vim.vm.device.xxx) {' --> '   {'
		$line =~ s/^(\s+)\([^\)]*\)\s*/$1/g;
		
		# Remove class names at beginning of a line surrounded by parenthesis
		# '(vim.vm.device.VirtualPointingDevice) {' --> 'vim.vm.device.VirtualPointingDevice => {'
		$line =~ s/^\(([^\)]+)\)\s*{/$1 => {/gx;
		
		# Remove class names 
		# '(vim.vm.ConfigOptionDescriptor) ['
		$line =~ s/^\([^\)]+\)\s*(\[)/$1/gx;
		
		# Add comma to lines containing a closing curly bracket
		# '   }' --> '   },'
		$line =~ s/^(\s*)}\s*$/$1},/g;
		
		# Remove class names after an equals sign
		# 'backing = (vim.vm.device.VirtualDevice.BackingInfo) null,' --> 'backing = null'
		$line =~ s/(=\s+)\([^\)]+\)\s*/$1/g;
		
		# Add comma to lines containing = sign which don't end with a comma
		# 'value = xxx' --> 'value = xxx,'
		$line =~ s/(=\s+[^,]+[\w>])$/$1,/g;
		
		# Surround values after equals sign in single quotes
		# value = xxx,   --> value = 'xxx',
		# value = "xxx", --> value = 'xxx',
		$line =~ s/(=\s+)["']?([^"']+)["']?,/$1'$2',/g;
		
		# Surround values before equals sign in single quotes
		$line =~ s/^(\s*)["']?([^\s"']+)["']?(\s*=)/$1'$2'$3/g;
		
		# Change 'null' to undef and add =>
		# 'busSlotOption null,' --> 'busSlotOption => undef,'
		$line =~ s/(\w\s+)null,/$1 => undef,/g;
		
		# Change = to =>
		$line =~ s/=(\s+.+)/=>$1/g;
		
		# Add => before array and hash references
		# 'guestOSDescriptor [' --> 'guestOSDescriptor => ['
		$line =~ s/(\w\s+)([\[{])/$1=>$2/g;
		
		$statement .= "$line\n";
		$numbered_statement .= "$line_number:\n";
		$numbered_statement .= "$original_line\n";
		$numbered_statement .= "$line\n";
	}

	# Enclose the entire statement in curly brackets
	if ($statement =~ /^[^\n]+{/) {
		$statement = "{\n$statement\n}";
	}
	
	if ($debug) {
		print "\n";
		print '.' x 200 . "\n";
		print "Statement:\n$statement\n";
		print '.' x 200 . "\n";
	}
	
	# The statement variable should contain a valid definition
	my $result = eval($statement);
	if ($EVAL_ERROR) {
		notify($ERRORS{'WARNING'}, 0, "failed to parse vim-cmd output, error:\n$EVAL_ERROR\n$numbered_statement");
		return;
	}
	elsif (!defined($result)) {
		notify($ERRORS{'WARNING'}, 0, "failed to parse vim-cmd output:\n$numbered_statement");
		return;
	}
	else {
		#notify($ERRORS{'DEBUG'}, 0, "parsed vim-cmd output:\n" . format_data($result));
		return $result;
	}
}