Initial commit
This commit is contained in:
		
						commit
						103d08f96a
					
				
							
								
								
									
										164
									
								
								cfgparser.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								cfgparser.pm
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,164 @@ | |||
| package cfgparser; | ||||
| 
 | ||||
| use strict; | ||||
| 
 | ||||
| require Exporter; | ||||
| @cfgparser::ISA = qw(Exporter); | ||||
| @cfgparser::EXPORT = qw( | ||||
| 	parse_structure | ||||
| 	parse_cfg_file | ||||
| ); | ||||
| 
 | ||||
| use logging; | ||||
| use JSON; | ||||
| use Data::Dumper; | ||||
| 
 | ||||
| sub check_structure ($$$); | ||||
| 
 | ||||
| sub check_structure ($$$) | ||||
| { | ||||
| 	my ($label, $structure, $grammar) = @_; | ||||
| 
 | ||||
| 	my $stype = ref($structure); | ||||
| 	my $gtype = $$grammar{Type}; | ||||
| 	if ($gtype eq 'or') { | ||||
| 		my $options = $$grammar{Options}; | ||||
| 		if ($stype eq 'LIST') { | ||||
| 			foreach my $subgrammar (@$options) { | ||||
| 				my $gtype = $$subgrammar{Type}; | ||||
| 				if ($gtype eq 'list') { | ||||
| 					return check_structure($label, $structure, $subgrammar); | ||||
| 				} | ||||
| 			} | ||||
| 			print_log('config', ERROR, 'Found LIST, not expecting this at %s', $label); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		elsif ($stype eq 'HASH') { | ||||
| 			foreach my $subgrammar (@$options) { | ||||
| 				my $gtype = $$subgrammar{Type}; | ||||
| 				if ($gtype eq 'map' || $gtype eq 'struct') { | ||||
| 					return check_structure($label, $structure, $subgrammar); | ||||
| 				} | ||||
| 			} | ||||
| 			print_log('config', ERROR, 'Found HASH, not expecting this at %s', $label); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		elsif ($stype eq '') { | ||||
| 			foreach my $subgrammar (@$options) { | ||||
| 				my $gtype = $$subgrammar{Type}; | ||||
| 				if ($gtype eq 'string' || $gtype eq 'integer') { | ||||
| 					return check_structure($label, $structure, $subgrammar); | ||||
| 				} | ||||
| 			} | ||||
| 			print_log('config', ERROR, 'Found SCALAR, not expecting this at %s', $label); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		else { | ||||
| 			print_log('config', ERROR, 'Found %s, not expecting this at %s', $stype, $label); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 	if ($gtype eq 'map') { | ||||
| 		if ($stype ne 'HASH') { | ||||
| 			print_log('config', ERROR, 'Expecting HASH, found %s at %s', $stype, $label); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		my $sublabel = $label; | ||||
| 		$sublabel .= '/' unless $sublabel eq '/'; | ||||
| 		foreach my $key (keys %$structure) { | ||||
| 			return 0 unless check_structure($sublabel.$key, $$structure{$key}, $$grammar{Elements}); | ||||
| 		} | ||||
| 		return 1; | ||||
| 	} | ||||
| 	if ($gtype eq 'struct') { | ||||
| 		if ($stype ne 'HASH') { | ||||
| 			print_log('config', ERROR, 'Expecting HASH, found %s at %s', $stype, $label); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		my $sublabel = $label; | ||||
| 		$sublabel .= '/' unless $sublabel eq '/'; | ||||
| 		my $keywords = $$grammar{Keywords}; | ||||
| 		foreach my $key (keys %$structure) { | ||||
| 			my $kw = $$keywords{$key}; | ||||
| 			if (! defined $kw) { | ||||
| 				print_log('config', ERROR, 'Unknown keyword %s at %s', $key, $label); | ||||
| 				return 0; | ||||
| 			} | ||||
| 			return 0 unless check_structure($sublabel.$key, $$structure{$key}, $kw); | ||||
| 		} | ||||
| 		foreach my $key (keys %$keywords) { | ||||
| 			my $kw = $$keywords{$key}; | ||||
| 			next unless defined $$kw{Mandatory} && $$kw{Mandatory}; | ||||
| 			if (! defined $$structure{$key}) { | ||||
| 				print_log('config', ERROR, 'Missing mandatory keyword %s at %s', $key, $label); | ||||
| 				return 0; | ||||
| 			} | ||||
| 		} | ||||
| 		my $checkfunc = $$grammar{Check}; | ||||
| 		return 0 if defined $checkfunc && ! &{$checkfunc}($structure, $label); | ||||
| 		return 1; | ||||
| 	} | ||||
| 	if ($gtype eq 'list') { | ||||
| 		if ($stype ne 'ARRAY') { | ||||
| 			print_log('config', ERROR, 'Expecting ARRAY, found %s at %s', $stype, $label); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		my $index = 0; | ||||
| 		foreach my $element (@$structure) { | ||||
| 			$index++; | ||||
| 			return 0 unless check_structure($label.'['.$index.']', $element, $$grammar{Elements}); | ||||
| 		} | ||||
| 		return 1; | ||||
| 	} | ||||
| 	if ($stype ne '') { | ||||
| 		print_log('config', ERROR, 'Expecting SCALAR, found %s at %s', $stype, $label); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	if ($gtype eq 'string') { | ||||
| 		print_log('config', DEBUG2, 'Found string value %s at %s', $structure, $label); | ||||
| 	} | ||||
| 	elsif ($gtype eq 'integer') { | ||||
| 		if ($structure !~ /^\d+$/o) { | ||||
| 			print_log('config', ERROR, 'Expecting integer value, found %s at %s', $structure, $label); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		print_log('config', DEBUG2, 'Found integer value %s at %s', $structure, $label); | ||||
| 	} | ||||
| 	else { | ||||
| 		print_log('config', ERROR, 'Unknown grammar element type: %s', $gtype); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| sub parse_structure ($$$) | ||||
| { | ||||
| 	my ($path, $contents, $grammar) = @_; | ||||
| 
 | ||||
| 	my $structure = eval { decode_json($contents) }; | ||||
| 	if (! defined $structure) { | ||||
| 		my $error = $@; | ||||
| 		print_log('config', ERROR, 'Cannot parse config file %s: %s', $path, $error); | ||||
| 		return undef; | ||||
| 	} | ||||
| 	return undef unless check_structure('/', $structure, $grammar); | ||||
| 	return $structure; | ||||
| } | ||||
| 
 | ||||
| sub parse_cfg_file ($$) | ||||
| { | ||||
| 	my ($path, $grammar) = @_; | ||||
| 
 | ||||
| 	if (! open(FILE, '<', $path)) { | ||||
| 		print_log('config', ERROR, 'Cannot open file %s: %s', $path, $!); | ||||
| 		return undef; | ||||
| 	} | ||||
| 	my $contents = ''; | ||||
| 	while (<FILE>) { | ||||
| 		$contents .= $_; | ||||
| 	} | ||||
| 	close(FILE); | ||||
| 	return parse_structure($path, $contents, $grammar); | ||||
| } | ||||
| 
 | ||||
| 1; | ||||
							
								
								
									
										230
									
								
								cmdline.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										230
									
								
								cmdline.pm
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,230 @@ | |||
| package cmdline; | ||||
| 
 | ||||
| use strict; | ||||
| 
 | ||||
| require Exporter; | ||||
| @cmdline::ISA = qw(Exporter); | ||||
| @cmdline::EXPORT = qw( | ||||
| 	parse_cmdline | ||||
| 	print_usage | ||||
| ); | ||||
| 
 | ||||
| use logging; | ||||
| 
 | ||||
| sub store_option_value ($$$) | ||||
| { | ||||
| 	my ($spec, $arg, $value) = @_; | ||||
| 	 | ||||
| 	my $storeinto = $$spec{StoreInto}; | ||||
| 	if (defined $storeinto && ref($storeinto) eq 'SCALAR') { | ||||
| 		print_log('global', DEBUG1, 'Storing option %s value: %s', $arg, $value); | ||||
| 		$$storeinto = $value; | ||||
| 	} | ||||
| 	my $storefunc = $$spec{StoreFunc}; | ||||
| 	if (defined $storefunc && ref($storefunc) eq 'CODE') { | ||||
| 		print_log('global', DEBUG1, 'Storing option %s value: %s', $arg, $value); | ||||
| 		&{$storefunc}($value); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| sub check_option_value ($$$) | ||||
| { | ||||
| 	my ($spec, $arg, $value) = @_; | ||||
| 
 | ||||
| 	my $type = $$spec{Type}; | ||||
| 	if ($type eq 'integer') { | ||||
| 		if ($value !~ /^\d+$/o) { | ||||
| 			print STDERR 'Invalid integer parameter for option '.$arg.': '.$value."\n"; | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 	if ($type eq 'keyvalue') { | ||||
| 		if ($value !~ /^[^=]+=/o) { | ||||
| 			print STDERR 'Invalid key=value parameter syntax for option '.$arg.': '.$value."\n"; | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| sub parse_cmdline ($) | ||||
| { | ||||
| 	my ($specs) = @_; | ||||
| 
 | ||||
| 	my $general = 0; | ||||
| 	my $found = {}; | ||||
| 	my $shorts = {}; | ||||
| 	my $longs = {}; | ||||
| 	foreach my $spec (@$specs) { | ||||
| 		$general++ if defined $$spec{General}; | ||||
| 		my $short = $$spec{Short}; | ||||
| 		my $long = $$spec{Long}; | ||||
| 		$$shorts{$short} = $spec if defined $short; | ||||
| 		$$longs{$long} = $spec if defined $long; | ||||
| 	} | ||||
| 
 | ||||
| 	my $left = []; | ||||
| 
 | ||||
| 	my $i = 0; | ||||
| 	my $options = 1; | ||||
| 	while (1) { | ||||
| 		my $arg = $ARGV[$i++]; | ||||
| 		last unless defined $arg; | ||||
| 		print_log('global', DEBUG2, 'Checking argument %s', $arg); | ||||
| 
 | ||||
| 		if ($options && $arg =~ /^--(.*)$/o) { | ||||
| 			my $long = $1; | ||||
| 			if ($long eq '') { | ||||
| 				print_log('global', DEBUG2, 'No more options'); | ||||
| 				$options = 0; | ||||
| 				next; | ||||
| 			} | ||||
| 			my $spec = $$longs{$long}; | ||||
| 			if (! defined $spec) { | ||||
| 				print STDERR 'Unknown long option: '.$arg."\n"; | ||||
| 				return undef; | ||||
| 			} | ||||
| 			print_log('global', DEBUG2, 'Found long option: %s', $long); | ||||
| 			my $param; | ||||
| 			if ($$spec{Type} eq 'flag') { | ||||
| 				$param = 1; | ||||
| 			} | ||||
| 			else { | ||||
| 				$param = $ARGV[$i++]; | ||||
| 				if (! defined $param) { | ||||
| 					print STDERR 'Missing parameter for long option: '.$arg."\n"; | ||||
| 					return undef; | ||||
| 				} | ||||
| 				return undef unless check_option_value($spec, $arg, $param); | ||||
| 			} | ||||
| 			$$found{$arg} = 1; | ||||
| 			store_option_value($spec, $arg, $param); | ||||
| 			next; | ||||
| 		} | ||||
| 		if ($options && $arg =~ /^-(.*)$/o) { | ||||
| 			my $list = $1; | ||||
| 			my $j = 0; | ||||
| 			while ($j < length($list)) { | ||||
| 				my $short = substr($list, $j++, 1); | ||||
| 				if ($short eq '-') { | ||||
| 					print_log('global', DEBUG2, 'No more options'); | ||||
| 					$options = 0; | ||||
| 					next; | ||||
| 				} | ||||
| 				my $opt = '-'.$short; | ||||
| 				my $spec = $$shorts{$short}; | ||||
| 				if (! defined $spec) { | ||||
| 					print STDERR 'Unknown short option: '.$opt."\n"; | ||||
| 					return undef; | ||||
| 				} | ||||
| 				print_log('global', DEBUG2, 'Found short option: %s', $short); | ||||
| 				my $param; | ||||
| 				if ($$spec{Type} eq 'flag') { | ||||
| 					$param = 1; | ||||
| 				} | ||||
| 				else { | ||||
| 					$param = $ARGV[$i++]; | ||||
| 					if (! defined $param) { | ||||
| 						print STDERR 'Missing parameter for short option: '.$opt."\n"; | ||||
| 						return undef; | ||||
| 					} | ||||
| 					return undef unless check_option_value($spec, $opt, $param); | ||||
| 				} | ||||
| 				$$found{$opt} = 1; | ||||
| 				store_option_value($spec, $opt, $param); | ||||
| 			} | ||||
| 			next; | ||||
| 		} | ||||
| 		if (! $general) { | ||||
| 			print STDERR 'Unexpected general parameter: '.$arg."\n"; | ||||
| 			return undef; | ||||
| 		} | ||||
| 		print_log('global', DEBUG1, 'Adding general cli parameter %s', $arg); | ||||
| 		push @$left, $arg; | ||||
| 	} | ||||
| 
 | ||||
| 	foreach my $spec (@$specs) { | ||||
| 		next if defined $$spec{General}; | ||||
| 		my $default = $$spec{Default}; | ||||
| 		next unless defined $default; | ||||
| 		my $arg; | ||||
| 		my $long = $$spec{Long}; | ||||
| 		if (defined $long) { | ||||
| 			$arg = '--'.$long; | ||||
| 			next if defined $$found{$arg}; | ||||
| 		} | ||||
| 		my $short = $$spec{Short}; | ||||
| 		if (defined $short) { | ||||
| 			$arg = '-'.$short; | ||||
| 			next if defined $$found{$arg}; | ||||
| 		} | ||||
| 		print_log('global', DEBUG1, 'Using default for option %s: %s', $arg, $default); | ||||
| 		store_option_value($spec, $arg, $default); | ||||
| 	} | ||||
| 
 | ||||
| 	return $left; | ||||
| } | ||||
| 
 | ||||
| sub print_usage ($) | ||||
| { | ||||
| 	my ($specs) = @_; | ||||
| 
 | ||||
| 	my $general = ''; | ||||
| 	my $longest = 0; | ||||
| 	foreach my $spec (@$specs) { | ||||
| 		my $len = 0; | ||||
| 		if (defined $$spec{General}) { | ||||
| 			my $option = $$spec{Option}; | ||||
| 			my $optional = $$spec{Optional}; | ||||
| 			$optional = defined $optional && $optional; | ||||
| 			$len = length($option); | ||||
| 			$general .= ' '.($optional ? '[' : '').$option.($optional ? ']' : '') | ||||
| 				if $len > 0; | ||||
| 		} | ||||
| 		else { | ||||
| 			my $short = $$spec{Short}; | ||||
| 			my $long = $$spec{Long}; | ||||
| 			my $shortlen = defined $short ? length($short) + 1 : 0; | ||||
| 			my $longlen = defined $long ? length($long) + 2 : 0; | ||||
| 			$len = $shortlen + $longlen; | ||||
| 			$len += 2 if $shortlen > 0 && $longlen > 0; | ||||
| 		} | ||||
| 		$longest = $len if $len > $longest; | ||||
| 	} | ||||
| 
 | ||||
| 	print STDERR 'Usage: '.$0.' [<options>]'.$general."\n"; | ||||
| 	foreach my $spec (@$specs) { | ||||
| 		my $buffer = ''; | ||||
| 		my $desc = $$spec{Description}; | ||||
| 		if (defined $$spec{General}) { | ||||
| 			my $option = $$spec{Option}; | ||||
| 
 | ||||
| 			$buffer .= $option; | ||||
| 		} | ||||
| 		else { | ||||
| 			my $short = $$spec{Short}; | ||||
| 			my $long = $$spec{Long}; | ||||
| 			my $type = $$spec{Type}; | ||||
| 			$type = '['.$type.']' if defined $type; | ||||
| 			$desc = $desc.' '.$type if defined $type; | ||||
| 			my $default = $$spec{Default}; | ||||
| 			$default = 'set' if $type eq 'Flag' && defined $default && $default; | ||||
| 			$default = '(Default:'.$default.')' if defined $default; | ||||
| 			$desc = $desc.' '.$default if defined $default; | ||||
| 			$short = '-'.$short if defined $short; | ||||
| 			$long = '--'.$long if defined $long; | ||||
| 
 | ||||
| 			$buffer .= $short if defined $short; | ||||
| 			$buffer .= ', ' if defined $short && defined $long; | ||||
| 			$buffer .= $long if defined $long; | ||||
| 		} | ||||
| 
 | ||||
| 		$buffer .= ' ' x ($longest - length($buffer)) if length($buffer) < $longest; | ||||
| 		$buffer = '  '.$buffer; | ||||
| 		$buffer .= $longest + 4 + length($desc) < 80 ? | ||||
| 			'  '.$desc."\n" : "\n".'      '.$desc."\n"; | ||||
| 		print STDERR $buffer | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 1; | ||||
							
								
								
									
										627
									
								
								logging.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										627
									
								
								logging.pm
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,627 @@ | |||
| package logging; | ||||
| 
 | ||||
| use strict; | ||||
| 
 | ||||
| require Exporter; | ||||
| @logging::ISA = qw(Exporter); | ||||
| @logging::EXPORT = qw( | ||||
| 	VARIABLE | ||||
| 	FATAL | ||||
| 	ERROR | ||||
| 	WARNING | ||||
| 	INFO | ||||
| 	DEBUG1 | ||||
| 	DEBUG2 | ||||
| 	DEBUG3 | ||||
| 	DEBUG4 | ||||
| 	DEBUG5 | ||||
| 	DEBUG | ||||
| 	set_pkgtool_dir | ||||
| 	set_verbose_flag | ||||
| 	set_log_level | ||||
| 	set_log_base_dir | ||||
| 	set_current_pkg_name | ||||
| 	get_win_version | ||||
| 	get_default_vars | ||||
| 	set_datetime_vars | ||||
| 	compare_versions | ||||
| 	substitute_variables | ||||
| 	close_all_log_files | ||||
| 	print_log | ||||
| 	set_log_defs | ||||
| ); | ||||
| 
 | ||||
| use POSIX; | ||||
| use File::Spec; | ||||
| require Win32; | ||||
| 
 | ||||
| sub print_stderr_log ($$); | ||||
| sub print_to_log_file ($$); | ||||
| 
 | ||||
| my $orig_stdout; | ||||
| my $orig_stderr; | ||||
| 
 | ||||
| if (! open($orig_stdout, '>&STDOUT')) { | ||||
| 	print STDERR 'Cannot dup STDOUT: '.$!."\n"; | ||||
| 	exit(1); | ||||
| } | ||||
| if (! open($orig_stderr, '>&', \*STDERR)) { | ||||
| 	print STDERR 'Cannot dup STDERR: '.$!."\n"; | ||||
| 	exit(1); | ||||
| } | ||||
| 
 | ||||
| sub VARIABLE { return -99; } | ||||
| sub FATAL { return -3; } | ||||
| sub ERROR { return -2; } | ||||
| sub WARNING { return -1; } | ||||
| sub INFO { return 0; } | ||||
| sub DEBUG1 { return 1; } | ||||
| sub DEBUG2 { return 2; } | ||||
| sub DEBUG3 { return 3; } | ||||
| sub DEBUG4 { return 4; } | ||||
| sub DEBUG5 { return 5; } | ||||
| sub DEBUG { return 99; } | ||||
| 
 | ||||
| my $pkgtool_dir; | ||||
| my $verbose_flag; | ||||
| my $log_level; | ||||
| my $log_base_dir; | ||||
| my $fallback_log_def = { | ||||
| 	type => 'stderr', | ||||
| 	channel => { | ||||
| 		global => 'variable' | ||||
| 	} | ||||
| }; | ||||
| my $fallback_log_file = { | ||||
| 	Definition => $fallback_log_def, | ||||
| 	LogFunc => \&print_stderr_log, | ||||
| 	Channels => { | ||||
| 		global => VARIABLE, | ||||
| 		config => VARIABLE, | ||||
| 		pkg => VARIABLE | ||||
| 	} | ||||
| }; | ||||
| my $log_defs = []; | ||||
| my $current_pkg_name; | ||||
| my $global_log_files = {}; | ||||
| my $package_log_files = {}; | ||||
| 
 | ||||
| sub set_pkgtool_dir ($) | ||||
| { | ||||
| 	my ($dir) = @_; | ||||
| 
 | ||||
| 	$pkgtool_dir = $dir; | ||||
| } | ||||
| 
 | ||||
| sub set_verbose_flag ($) | ||||
| { | ||||
| 	my ($verbose) = @_; | ||||
| 
 | ||||
| 	$verbose_flag = $verbose; | ||||
| } | ||||
| 
 | ||||
| sub set_log_level ($) | ||||
| { | ||||
| 	my ($level) = @_; | ||||
| 
 | ||||
| 	$log_level = $level; | ||||
| } | ||||
| 
 | ||||
| sub set_log_base_dir ($) | ||||
| { | ||||
| 	my ($dir) = @_; | ||||
| 
 | ||||
| 	$log_base_dir = $dir; | ||||
| } | ||||
| 
 | ||||
| sub level2str ($) | ||||
| { | ||||
| 	my ($level) = @_; | ||||
| 
 | ||||
| 	return 'VARIABLE' if ($level == VARIABLE); | ||||
| 	return 'FATAL' if ($level == FATAL); | ||||
| 	return 'ERROR' if ($level == ERROR); | ||||
| 	return 'WARNING' if ($level == WARNING); | ||||
| 	return 'INFO' if ($level == INFO); | ||||
| 	return 'DEBUG1' if ($level == DEBUG1); | ||||
| 	return 'DEBUG2' if ($level == DEBUG2); | ||||
| 	return 'DEBUG3' if ($level == DEBUG3); | ||||
| 	return 'DEBUG4' if ($level == DEBUG4); | ||||
| 	return 'DEBUG5' if ($level == DEBUG5); | ||||
| 	return 'DEBUG' if ($level == DEBUG); | ||||
| 	return $level; | ||||
| } | ||||
| 
 | ||||
| sub str2level ($) | ||||
| { | ||||
| 	my ($level) = @_; | ||||
| 
 | ||||
| 	return $level if $level =~ /^-?\d+$/o; | ||||
| 	return VARIABLE if $level =~ /^variable$/io; | ||||
| 	return FATAL if $level =~ /^fatal$/io; | ||||
| 	return ERROR if $level =~ /^error$/io; | ||||
| 	return WARNING if $level =~ /^warning$/io; | ||||
| 	return INFO if $level =~ /^info$/io; | ||||
| 	return DEBUG1 if $level =~ /^debug1$/io; | ||||
| 	return DEBUG2 if $level =~ /^debug2$/io; | ||||
| 	return DEBUG3 if $level =~ /^debug3$/io; | ||||
| 	return DEBUG4 if $level =~ /^debug4$/io; | ||||
| 	return DEBUG5 if $level =~ /^debug5$/io; | ||||
| 	return DEBUG if $level =~ /^debug$/io; | ||||
| 	return VARIABLE; | ||||
| } | ||||
| 
 | ||||
| sub compare_levels ($$) | ||||
| { | ||||
| 	my ($reference, $level) = @_; | ||||
| 
 | ||||
| 	if ($reference == VARIABLE) { | ||||
| 		$reference = defined $log_level && $log_level > 0 ? $log_level : | ||||
| 			defined $verbose_flag && $verbose_flag ? INFO : WARNING; | ||||
| 	} | ||||
| 	elsif ($reference == DEBUG) { | ||||
| 		$reference = defined $log_level && $log_level > 0 ? $log_level : INFO; | ||||
| 	} | ||||
| 	return $level <=> $reference; | ||||
| } | ||||
| 
 | ||||
| sub compare_versions ($$) | ||||
| { | ||||
| 	my ($a, $b) = @_; | ||||
| 
 | ||||
| 	my $alist = [split(/\./, $a)]; | ||||
| 	my $blist = [split(/\./, $b)]; | ||||
| 	while (1) { | ||||
| 		my $acomponent = shift @$alist; | ||||
| 		my $bcomponent = shift @$blist; | ||||
| 		if (defined $acomponent) { | ||||
| 			return 1 unless defined $acomponent; | ||||
| 			my $rc; | ||||
| 			if ($acomponent =~ /^\d+$/o && $bcomponent =~ /^\d+$/o) { | ||||
| 				$rc = $acomponent <=> $bcomponent; | ||||
| 			} | ||||
| 			else { | ||||
| 				$rc = $acomponent cmp $bcomponent; | ||||
| 			} | ||||
| 			return $rc if $rc; | ||||
| 		} | ||||
| 		else { | ||||
| 			return 0 unless defined $bcomponent; | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| sub get_win_version () | ||||
| { | ||||
| 	my ($osver, $osmajor, $osminor, $osbuild) = Win32::GetOSVersion(); | ||||
| 
 | ||||
| 	return $osmajor.'.'.$osminor; | ||||
| } | ||||
| 
 | ||||
| sub get_default_vars (;$) | ||||
| { | ||||
| 	my ($config) = @_; | ||||
| 
 | ||||
| 	my $genericvars = defined $config ? $$config{'generic-variables'} : undef; | ||||
| 	my $globals = defined $config ? $$config{'global-variables'} : undef; | ||||
| 
 | ||||
| 	my $arch = $ENV{'PROCESSOR_ARCHITECTURE'} =~ /AMD64/io ? 'x64' : ''; | ||||
| 	my $xarch = $ENV{'PROCESSOR_ARCHITECTURE'} =~ /AMD64/io ? 'x64' : 'x86'; | ||||
| 	my $programfiles = $ENV{'ProgramFiles'}; | ||||
| 	my $programfiles32 = $ENV{'ProgramFiles(x86)'}; | ||||
| 	$programfiles32 = $programfiles unless defined $programfiles32; | ||||
| 	 | ||||
| 	my $vars = {}; | ||||
| 	foreach my $key (keys %ENV) { | ||||
| 		$$vars{lc($key)} = $ENV{$key}; | ||||
| 	} | ||||
| 	$$vars{arch} = $arch; | ||||
| 	$$vars{xarch} = $xarch; | ||||
| 	$$vars{osversion} = get_win_version(); | ||||
| 	$$vars{programfiles32} = $programfiles32; | ||||
| 	$$vars{pkgtooldir} = $pkgtool_dir; | ||||
| 	$$vars{logdir} = $log_base_dir if defined $log_base_dir; | ||||
| 
 | ||||
| 	if (defined $genericvars) { | ||||
| 		foreach my $genvar (@$genericvars) { | ||||
| 			my $varname = $$genvar{variable}; | ||||
| 			my $expression = $$genvar{expression}; | ||||
| 
 | ||||
| 			my $value = eval $expression; | ||||
| 			my $error = $@; | ||||
| 			next if defined $error && $error ne ''; | ||||
| 			$$vars{$varname} = $value; | ||||
| 		} | ||||
| 	} | ||||
| 	if (defined $globals) { | ||||
| 		foreach my $varname (keys %$globals) { | ||||
| 			my $value = $$globals{$varname}; | ||||
| 			$$vars{$varname} = $value; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return $vars; | ||||
| } | ||||
| 
 | ||||
| sub set_datetime_vars ($;$) | ||||
| { | ||||
| 	my ($vars, $now) = @_; | ||||
| 
 | ||||
| 	$now = time() unless defined $now; | ||||
| 	my $date = strftime('%Y%m%d', localtime($now)); | ||||
| 	my $time = strftime('%H%M%S', localtime($now)); | ||||
| 	my $datetime = $date.'-'.$time; | ||||
| 	$$vars{date} = $date; | ||||
| 	$$vars{time} = $time; | ||||
| 	$$vars{datetime} = $datetime; | ||||
| } | ||||
| 
 | ||||
| sub substitute_variables ($$$;$$) | ||||
| { | ||||
| 	my ($vars, $expr, $ispath, $basedir, $channel) = @_; | ||||
| 
 | ||||
| 	print_log($channel, DEBUG3, 'Substitute_variables for: %s', $expr) if defined $channel; | ||||
| 
 | ||||
| 	$expr =~ s/\//\\/go if $ispath; | ||||
| 	$expr =~ s/%([^%]+)%/defined $$vars{lc($1)} ? $$vars{lc($1)} : ''/ge; | ||||
| 	$expr =~ s/%%/%/go; | ||||
| 	if ($ispath && defined $basedir && $expr !~ /^[^:]:/o) { | ||||
| 		print_log($channel, DEBUG3, 'Basedir: %s  expr: %s', $basedir, $expr) if defined $channel; | ||||
| 		if ($expr =~ /^\\/o) { | ||||
| 			if ($basedir =~ /^([^:]:)/o) { | ||||
| 				my $drive = $1; | ||||
| 				$expr = $drive.$expr; | ||||
| 			} | ||||
| 		} | ||||
| 		else { | ||||
| 			$basedir .= '\\' unless $basedir =~ /\\$/o; | ||||
| 			$expr = $basedir.$expr; | ||||
| 		} | ||||
| 	} | ||||
| 	print_log($channel, DEBUG3, 'Result: %s', $expr) if defined $channel; | ||||
| 	return $expr; | ||||
| } | ||||
| 
 | ||||
| sub init_log_file ($) | ||||
| { | ||||
| 	my ($logdef) = @_; | ||||
| 
 | ||||
| 	my $ispkg = 0; | ||||
| 	my $spec; | ||||
| 	my $func; | ||||
| 	my $type = $$logdef{type}; | ||||
| 	if ($type eq 'stderr') { | ||||
| 		$spec = '<STDERR>'; | ||||
| 		$func = \&print_stderr_log; | ||||
| 	} | ||||
| 	elsif ($type eq 'file') { | ||||
| 		$spec = $$logdef{path}; | ||||
| 		$func = \&print_to_log_file; | ||||
| 		$ispkg = is_pkg_only_path($spec); | ||||
| 	} | ||||
| 	else { | ||||
| 		print_log('global', ERROR, 'Unknown log type %s', $type); | ||||
| 		return undef; | ||||
| 	} | ||||
| 
 | ||||
| 	if ($ispkg) { | ||||
| 		return undef unless defined $current_pkg_name; | ||||
| 	} | ||||
| 
 | ||||
| 	my $log_file_registry; | ||||
| 	if ($ispkg) { | ||||
| 		$log_file_registry = $package_log_files; | ||||
| 	} | ||||
| 	else { | ||||
| 		$log_file_registry = $global_log_files; | ||||
| 	} | ||||
| 
 | ||||
| 	my $lfchan = {}; | ||||
| 	my $channels = $$logdef{channel}; | ||||
| 	foreach my $ch (keys %$channels) { | ||||
| 		$$lfchan{$ch} = str2level($$channels{$ch}); | ||||
| 	} | ||||
| 
 | ||||
| 	if (defined $$log_file_registry{$spec}) { | ||||
| 		print_log('global', ERROR, 'Trying to reinitialize %s log type %s%s', | ||||
| 			$type, (defined $ispkg ? 'application '.$current_pkg_name : 'global'), | ||||
| 			($type eq 'file' ? ' path '.$$logdef{path} : '')); | ||||
| 		return undef; | ||||
| 	} | ||||
| 	my $lf = { | ||||
| 		Definition => $logdef, | ||||
| 		LogFunc => $func, | ||||
| 		Channels => $lfchan | ||||
| 	}; | ||||
| 	$$lf{PackageName} = $current_pkg_name if defined $current_pkg_name; | ||||
| 	$$log_file_registry{$spec} = $lf; | ||||
| 	$$logdef{Initialized} = 1; | ||||
| 	return $lf; | ||||
| } | ||||
| 
 | ||||
| sub close_all_log_files ($) | ||||
| { | ||||
| 	my ($pkgonly) = @_; | ||||
| 
 | ||||
| 	my $speclist = [keys %$package_log_files]; | ||||
| 	foreach my $spec (@$speclist) { | ||||
| 		my $lf = $$package_log_files{$spec}; | ||||
| 		delete $$package_log_files{$spec}; | ||||
| 		my $def = $$lf{Definition}; | ||||
| 		delete $$def{Initialized} if defined $def; | ||||
| 		close_log_file($lf); | ||||
| 	} | ||||
| 	return if $pkgonly; | ||||
| 	$speclist = [keys %$global_log_files]; | ||||
| 	foreach my $spec (@$speclist) { | ||||
| 		my $lf = $$global_log_files{$spec}; | ||||
| 		delete $$global_log_files{$spec}; | ||||
| 		my $def = $$lf{Definition}; | ||||
| 		delete $$def{Initialized} if defined $def; | ||||
| 		close_log_file($lf); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| sub init_log_files () | ||||
| { | ||||
| 	foreach my $def (@$log_defs) { | ||||
| 		next if defined $$def{Initialized}; | ||||
| 		init_log_file($def); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| sub is_pkg_only_path ($) | ||||
| { | ||||
| 	my ($path) = @_; | ||||
| 
 | ||||
| 	return $path =~ /%(pkgname)%/io; | ||||
| } | ||||
| 
 | ||||
| sub is_timebased_path ($) | ||||
| { | ||||
| 	my ($path) = @_; | ||||
| 
 | ||||
| 	return $path =~ /%(date|time|datetime)%/io; | ||||
| } | ||||
| 
 | ||||
| sub set_current_pkg_name ($) | ||||
| { | ||||
| 	my ($pkgname) = @_; | ||||
| 
 | ||||
| 	if (defined $current_pkg_name) { | ||||
| 		return if defined $pkgname && $current_pkg_name eq $pkgname; | ||||
| 		close_all_log_files(1); | ||||
| 	} | ||||
| 	$current_pkg_name = $pkgname; | ||||
| 	init_log_files(); | ||||
| } | ||||
| 
 | ||||
| sub get_log_file_name ($$) | ||||
| { | ||||
| 	my ($pkgname, $path) = @_; | ||||
| 
 | ||||
| 	my $vars = get_default_vars(); | ||||
| 	set_datetime_vars($vars); | ||||
| 	$$vars{pkgname} = $pkgname if defined $pkgname; | ||||
| 	return substitute_variables($vars, $path, 1, $log_base_dir); | ||||
| } | ||||
| 
 | ||||
| sub get_log_template_name ($$) | ||||
| { | ||||
| 	my ($pkgname, $path) = @_; | ||||
| 
 | ||||
| 	my $vars = get_default_vars(); | ||||
| 	$$vars{date} = '????????'; | ||||
| 	$$vars{time} = '??????'; | ||||
| 	$$vars{datetime} = '????????-??????'; | ||||
| 	$$vars{pkgname} = $pkgname if defined $pkgname; | ||||
| 	return substitute_variables($vars, $path, 1, $log_base_dir); | ||||
| } | ||||
| 
 | ||||
| sub generate_log_file_name ($) | ||||
| { | ||||
| 	my ($lf) = @_; | ||||
| 
 | ||||
| 	if (! defined $$lf{CurrentFileName}) { | ||||
| 		my $def = $$lf{Definition}; | ||||
| 		$$lf{CurrentFileName} = get_log_file_name($$lf{PackageName}, $$def{path}); | ||||
| 	} | ||||
| 	return $$lf{CurrentFileName}; | ||||
| } | ||||
| 
 | ||||
| sub open_log_file ($) | ||||
| { | ||||
| 	my ($lf) = @_; | ||||
| 
 | ||||
| 	return 1 if defined $$lf{Handle}; | ||||
| 	my $path = generate_log_file_name($lf); | ||||
| 	local *LH; | ||||
| 	return 0 unless open(LH, '>>', $path); | ||||
| 	LH->autoflush(1); | ||||
| 	$$lf{Handle} = *LH; | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| sub close_log_file ($) | ||||
| { | ||||
| 	my ($lf) = @_; | ||||
| 
 | ||||
| 	if (defined $$lf{Handle}) { | ||||
| 		close($$lf{Handle}); | ||||
| 		delete $$lf{Handle}; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| sub rotate_log_file ($) | ||||
| { | ||||
| 	my ($lf) = @_; | ||||
| 
 | ||||
| 	return unless defined $$lf{Handle}; | ||||
| 	my $def = $$lf{Definition}; | ||||
| 	return unless defined $def && defined $$def{type} && $$def{type} eq 'file'; | ||||
| 
 | ||||
| 	my $rotate = $$def{rotate}; | ||||
| 	return unless defined $rotate; | ||||
| 	my $template = $$rotate{name}; | ||||
| 	next unless defined $template; | ||||
| 	$template = File::Spec->canonpath($template); | ||||
| 	my $maxsize = $$rotate{'max-kb'}; | ||||
| 	return unless defined $maxsize && $maxsize > 0; | ||||
| 	$maxsize *= 1024; | ||||
| 	my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size) = | ||||
| 		stat($$lf{Handle}); | ||||
| 	return unless defined $size && $size >= $maxsize; | ||||
| 	close_log_file($lf); | ||||
| 
 | ||||
| 	if (! is_timebased_path($$def{path})) { | ||||
| 		my $newname = get_log_file_name($$lf{PackageName}, $template); | ||||
| 		my $oldname = $$lf{CurrentFileName}; | ||||
| 		rename($oldname, $newname); | ||||
| 	} | ||||
| 	delete $$lf{CurrentFileName}; | ||||
| 
 | ||||
| 	my $maxhist = $$rotate{'max-num'}; | ||||
| 	if (defined $maxhist && $maxhist > 0) { | ||||
| 		my ($vol, $dir, $file) = File::Spec->splitpath(get_log_template_name($$lf{PackageName}, $template)); | ||||
| 		$dir = $vol.$dir; | ||||
| 		return if $dir =~ /\?/o; | ||||
| 		if (opendir(DIR, $dir)) { | ||||
| 			$dir .= '\\' unless $dir =~ /\\$/o; | ||||
| 			$file =~ s/\./\\./go; | ||||
| 			$file =~ s/\?/[0-9]/go; | ||||
| 			my $list = []; | ||||
| 			while (1) { | ||||
| 				my $entry = readdir(DIR); | ||||
| 				last unless defined $entry; | ||||
| 				next if $entry eq '.' || $entry eq '..'; | ||||
| 				next unless $entry =~ /^$file$/; | ||||
| 				push @$list, $entry; | ||||
| 			} | ||||
| 			closedir(DIR); | ||||
| 			if (scalar @$list > $maxhist) { | ||||
| 				$list = [sort @$list]; | ||||
| 				while (1) { | ||||
| 					my $filename = $dir; | ||||
| 					$filename .= shift @$list; | ||||
| 					unlink($filename); | ||||
| 					last if scalar @$list <= $maxhist; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	open_log_file($lf); | ||||
| } | ||||
| 
 | ||||
| sub setup_log_msg_prefix ($) | ||||
| { | ||||
| 	my ($msg) = @_; | ||||
| 
 | ||||
| 	return if defined $$msg{Prefix}; | ||||
| 	my $levelstr = $$msg{LevelStr}; | ||||
| 	$levelstr = $$msg{LevelStr} = level2str($$msg{Level}) unless defined $levelstr; | ||||
| 	$$msg{Prefix} = strftime('%Y-%m-%d %H:%M:%S', localtime($$msg{TimeStamp})). | ||||
| 		' ['.$$msg{Channel}.'/'.$levelstr.'] '; | ||||
| } | ||||
| 
 | ||||
| sub process_log_msg ($) | ||||
| { | ||||
| 	my ($msg) = @_; | ||||
| 
 | ||||
| 	return if defined $$msg{Output}; | ||||
| 	$$msg{Output} = sprintf($$msg{Message}, @{$$msg{Parameters}}); | ||||
| } | ||||
| 
 | ||||
| sub print_to_log_file ($$) | ||||
| { | ||||
| 	my ($lf, $msg) = @_; | ||||
| 
 | ||||
| 	return 0 unless open_log_file($lf); | ||||
| 	rotate_log_file($lf); | ||||
| 	setup_log_msg_prefix($msg); | ||||
| 	process_log_msg($msg); | ||||
| 	print { $$lf{Handle} } $$msg{Prefix}.$$msg{Output}."\n"; | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| sub print_stderr_log ($$) | ||||
| { | ||||
| 	my ($lf, $msg) = @_; | ||||
| 
 | ||||
| 	process_log_msg($msg); | ||||
| 	print $orig_stderr $$msg{Output}."\n"; | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| sub print_log_into_logfile ($$) | ||||
| { | ||||
| 	my ($lf, $msg) = @_; | ||||
| 
 | ||||
| 	my $func = $$lf{LogFunc}; | ||||
| 	return 0 unless defined $func; | ||||
| 	my $channels = $$lf{Channels}; | ||||
| 	return 0 unless defined $channels; | ||||
| 	my $minlevel = $$channels{$$msg{Channel}}; | ||||
| 	return 0 unless defined $minlevel; | ||||
| 	return 1 unless compare_levels($minlevel, $$msg{Level}) <= 0; | ||||
| 	return &{$func}($lf, $msg); | ||||
| } | ||||
| 
 | ||||
| sub print_log ($$$@) | ||||
| { | ||||
| 	my ($channel, $level, $message, @params) = @_; | ||||
| 
 | ||||
| 	my $msg = { | ||||
| 		TimeStamp => time(), | ||||
| 		Channel => $channel, | ||||
| 		Level => $level, | ||||
| 		Message => $message, | ||||
| 		Parameters => [@params] | ||||
| 	}; | ||||
| 
 | ||||
| 	my $list = [values %$global_log_files]; | ||||
| 	push @$list, values %$package_log_files if $channel eq 'pkg'; | ||||
| 	my $ok = 0; | ||||
| 	foreach my $lf (@$list) { | ||||
| 		$ok = 1 if print_log_into_logfile($lf, $msg); | ||||
| 	} | ||||
| 	return if $ok; | ||||
| 	print_log_into_logfile($fallback_log_file, $msg); | ||||
| } | ||||
| 
 | ||||
| sub set_log_defs ($) | ||||
| { | ||||
| 	my ($defs) = @_; | ||||
| 
 | ||||
| 	$log_defs = $defs; | ||||
| 	init_log_files(); | ||||
| } | ||||
| 
 | ||||
| use Carp; | ||||
| 
 | ||||
| $SIG{__DIE__} = sub { | ||||
| 	die @_ unless defined $^S && $^S == 0 && defined Carp::longmess; | ||||
| 	print_log('global', FATAL, '%s', | ||||
| 		join(', ', map { | ||||
| 			my $x = $_; | ||||
| 			$x =~ s/\r?\n[ \t]*$//os; | ||||
| 			$x =~ s/\.\r?\n[ \t]*/. /gos; | ||||
| 			$x =~ s/\r?\n[ \t]*/, /gos; | ||||
| 			$x =~ s/^ +//o; | ||||
| 			$x | ||||
| 		} Carp::longmess(@_))); | ||||
| 	die 'Fatal error: exiting'."\n"; | ||||
| }; | ||||
| $SIG{__WARN__} = sub { | ||||
| 	print_log('global', WARNING, '%s', | ||||
| 		join(', ', map { | ||||
| 			my $x = $_; | ||||
| 			$x =~ s/\r?\n[ \t]*$//os; | ||||
| 			$x =~ s/\.\r?\n[ \t]*/. /gos; | ||||
| 			$x =~ s/\r?\n[ \t]*/, /gos; | ||||
| 			$x =~ s/^ +//o; | ||||
| 			$x | ||||
| 		} @_)); | ||||
| }; | ||||
| 
 | ||||
| 1; | ||||
							
								
								
									
										274
									
								
								pkgtool.pl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										274
									
								
								pkgtool.pl
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,274 @@ | |||
| #!perl -w | ||||
| 
 | ||||
| use strict; | ||||
| 
 | ||||
| my $DEFAULT_DOMAIN_NAME = 'karinthy.hu'; | ||||
| my $DEFAULT_CONFIG_FILE_NAME = 'pkgtool.cfg'; | ||||
| 
 | ||||
| my $base_directory; | ||||
| 
 | ||||
| BEGIN { | ||||
| 	$base_directory = $0; | ||||
| 	if ($^O eq 'MSWin32') { | ||||
| 		if ($base_directory =~ /^(.*[\/\\])[^\/\\]*$/o) { | ||||
| 			$base_directory = $1; | ||||
| 		} | ||||
| 		else { | ||||
| 			$base_directory = '.'; | ||||
| 		} | ||||
| 	} | ||||
| 	else { | ||||
| 		if ($base_directory =~ /^(.*\/)[^\/]*$/o) { | ||||
| 			$base_directory = $1; | ||||
| 		} | ||||
| 		else { | ||||
| 			$base_directory = '.'; | ||||
| 		} | ||||
| 	} | ||||
| 	push @INC, $base_directory if -d $base_directory; | ||||
| } | ||||
| 
 | ||||
| use logging; | ||||
| use cmdline; | ||||
| use cfgparser; | ||||
| use pkgtool; | ||||
| 
 | ||||
| my $print_help; | ||||
| my $config_file_name; | ||||
| my $proxycmd = $base_directory.'\\install.cmd'; | ||||
| my $standalone = 0; | ||||
| my $globals = {}; | ||||
| 
 | ||||
| sub set_standalone_flag ($) | ||||
| { | ||||
| 	my ($param) = @_; | ||||
| 
 | ||||
| 	$standalone = $param; | ||||
| } | ||||
| 
 | ||||
| sub set_global ($) | ||||
| { | ||||
| 	my ($param) = @_; | ||||
| 
 | ||||
| 	if ($param =~ /^([^=]+)=(.*)$/o) { | ||||
| 		my $key = $1; | ||||
| 		my $value = $2; | ||||
| 		$$globals{$key} = $value; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| my $CONFIG_OPTIONS = [{ | ||||
| 	General => 1, | ||||
| 	Option => '<command>', | ||||
| 	Description => 'Command: list, status, update' | ||||
| }, { | ||||
| 	Short => 'c', | ||||
| 	Long => 'config', | ||||
| 	Description => 'Config file name', | ||||
| 	Type => 'string', | ||||
| 	Default => $DEFAULT_CONFIG_FILE_NAME, | ||||
| 	StoreInto => \$config_file_name | ||||
| }, { | ||||
| 	Short => 'd', | ||||
| 	Long => 'debug', | ||||
| 	Description => 'Debug log level (0=off)', | ||||
| 	Type => 'integer', | ||||
| 	Default => 0, | ||||
| 	StoreFunc => \&set_log_level | ||||
| }, { | ||||
| 	Short => 'g', | ||||
| 	Long => 'global', | ||||
| 	Description => 'Set generic variable (key=value)', | ||||
| 	Type => 'keyvalue', | ||||
| 	StoreFunc => \&set_global | ||||
| }, { | ||||
| 	Short => 'h', | ||||
| 	Long => 'help', | ||||
| 	Description => 'Print usage', | ||||
| 	Type => 'flag', | ||||
| 	Default => 0, | ||||
| 	StoreInto => \$print_help | ||||
| }, { | ||||
| 	Short => 's', | ||||
| 	Long => 'standalone', | ||||
| 	Description => 'Skip accessing install server', | ||||
| 	Type => 'flag', | ||||
| 	StoreFunc => \&set_standalone_flag | ||||
| }, { | ||||
| 	Short => 'v', | ||||
| 	Long => 'verbose', | ||||
| 	Description => 'Verbose logging', | ||||
| 	Type => 'flag', | ||||
| 	Default => 0, | ||||
| 	StoreFunc => \&set_verbose_flag | ||||
| }]; | ||||
| 
 | ||||
| set_pkgtool_dir($base_directory); | ||||
| my $commands = parse_cmdline($CONFIG_OPTIONS); | ||||
| if (! defined $commands || scalar @$commands < 1 || $print_help) { | ||||
| 	print_usage($CONFIG_OPTIONS); | ||||
| 	exit(1); | ||||
| } | ||||
| my $cmd = $$commands[0]; | ||||
| if ($cmd ne 'list' && $cmd ne 'status' && $cmd ne 'update') { | ||||
| 	print_log('global', ERROR, 'Unknown command: %s', $cmd); | ||||
| 	print_usage($CONFIG_OPTIONS); | ||||
| 	exit(1); | ||||
| } | ||||
| 
 | ||||
| my $dns_domain = get_default_dnsdomain(); | ||||
| $dns_domain = $DEFAULT_DOMAIN_NAME unless defined $dns_domain; | ||||
| my $install_host = 'install.'.$dns_domain; | ||||
| 
 | ||||
| my $config = parse_cfg_file(substitute_variables({}, $config_file_name, | ||||
| 	1, $base_directory, 'global'), get_cfg_syntax()); | ||||
| exit(1) unless defined $config; | ||||
| $$config{'generic-variables'} = [] unless defined $$config{'generic-variables'}; | ||||
| $$config{'proxy-command'} = $proxycmd; | ||||
| $$config{'install-host'} = $install_host; | ||||
| set_log_base_dir(substitute_variables(get_default_vars(), | ||||
| 	$$config{'log-directory'}, 1, $base_directory, 'global')); | ||||
| set_log_defs($$config{logging}) if defined $$config{logging}; | ||||
| if ($standalone) { | ||||
| 	print_log('global', INFO, 'Skipping install server'); | ||||
| } | ||||
| else { | ||||
| 	print_log('global', INFO, 'Install server: %s', $install_host); | ||||
| 	my $error = get_install_sets($config); | ||||
| 	exit(1) if defined $error; | ||||
| } | ||||
| my $error = scan_package_dirs($config, $base_directory); | ||||
| exit(1) if defined $error; | ||||
| $$config{'package-def'} = {} unless defined $$config{'package-def'}; | ||||
| $$config{'global-variables'} = $globals; | ||||
| 
 | ||||
| my $db = {}; | ||||
| read_installed_packages($db); | ||||
| read_installed_patches($db); | ||||
| 
 | ||||
| my $counters = { | ||||
| 	RebootFlag => 0, | ||||
|         InstalledList => [], | ||||
|         InstalledCount => 0, | ||||
|         RemovedList => [], | ||||
|         RemovedCount => 0, | ||||
| 	FailList => [], | ||||
| 	FailCount => 0, | ||||
| 	SkipList => [], | ||||
| 	SkipCount => 0, | ||||
| 	ToInstallList => [], | ||||
| 	ToInstallCount => 0, | ||||
| 	ToRemoveList => [], | ||||
| 	ToRemoveCount => 0 | ||||
| }; | ||||
| 
 | ||||
| my $stats; | ||||
| my $results; | ||||
| if ($cmd eq 'list') { | ||||
| 	print_log('global', INFO, '== Listing packages'); | ||||
| 	my $pkgdefs = $$config{'package-def'}; | ||||
| 	foreach my $key (sort keys %$pkgdefs) { | ||||
| 		my $def = $$pkgdefs{$key}; | ||||
| 		next unless defined $def; | ||||
| 		print_log('global', INFO, 'Definition: %s "%s"', $key, $$def{description}); | ||||
| 	} | ||||
| 	my $installed = $$db{Installed}; | ||||
| 	foreach my $instname (sort keys %$installed) { | ||||
| 		my $inst = $$installed{$instname}; | ||||
| 		next unless defined $inst && defined $$inst{DisplayName} && defined $$inst{DisplayVersion}; | ||||
| 		print_log('global', INFO, 'Installed: %s "%s" "%s" "%s"', | ||||
| 			$$inst{UserPackage} ? 'user' : 'global', $instname, $$inst{DisplayName}, $$inst{DisplayVersion}); | ||||
| 	} | ||||
| 	$installed = $$db{InstalledSpec}; | ||||
| 	foreach my $instname (sort keys %$installed) { | ||||
| 		my $inst = $$installed{$instname}; | ||||
| 		next unless defined $inst && defined $$inst{DisplayName} && defined $$inst{DisplayVersion}; | ||||
| 		print_log('global', INFO, 'Installed: %s "%s" "%s" "%s"', | ||||
| 			$$inst{UserPackage} ? 'user' : 'global', $instname, $$inst{DisplayName}, $$inst{DisplayVersion}); | ||||
| 	} | ||||
| 	print_log('global', INFO, '== Listing patches'); | ||||
| 	my $patches = $$db{Patches}; | ||||
| 	foreach my $kb (sort { ${$$patches{$a}}{Number} <=> ${$$patches{$b}}{Number} } keys %$patches) { | ||||
| 		my $patch = $$patches{$kb}; | ||||
| 		next unless defined $patch; | ||||
| 		print_log('global', INFO, 'Installed: %s %s %s %s', | ||||
| 			$$patch{KB}, | ||||
| 			($$patch{Type} eq 'OS' ? 'OS' : 'Packages('.join(',', sort keys %{$$patch{Packages}}).')'), | ||||
| 			($$patch{Original} ? 'original' : 'update'), | ||||
| 			($$patch{Current} ? 'current' : 'obsoleted')); | ||||
| 	} | ||||
| } | ||||
| elsif ($cmd eq 'status') { | ||||
| 	print_log('global', INFO, '== Displaying package status'); | ||||
| 	my $pkgdefs = $$config{'package-def'}; | ||||
| 	my $pkgs = $$config{'packages'}; | ||||
| 	foreach my $pkg (@$pkgs) { | ||||
| 		handle_pkg($config, $base_directory, $db, $pkg, $counters, 0); | ||||
| 	} | ||||
| 	$stats = ''; | ||||
| } | ||||
| elsif ($cmd eq 'update') { | ||||
| 	my $pkgname = $$commands[1]; | ||||
| 	print_log('global', INFO, '== Updating packages/patches: %s', defined $pkgname ? $pkgname : 'all'); | ||||
| 	my $pkgdefs = $$config{'package-def'}; | ||||
| 	my $pkgs = $$config{'packages'}; | ||||
| 	foreach my $pkg (@$pkgs) { | ||||
| 		my $name = $$pkg{name}; | ||||
| 		next if defined $pkgname && $name ne $pkgname; | ||||
| 		handle_pkg($config, $base_directory, $db, $pkg, $counters, 1); | ||||
| 	} | ||||
| 	$stats = ''; | ||||
| } | ||||
| if (defined $stats) { | ||||
| 	$results = ''; | ||||
| 	if ($$counters{SkipCount} > 0) { | ||||
| 		$stats .= $stats eq '' ? 'S' : ', s'; | ||||
| 		$stats .= sprintf('kipping %d', $$counters{SkipCount}); | ||||
| 		$results .= $results eq '' ? 'S' : ', s'; | ||||
| 		$results .= 'kipping: '.join(',', @{$$counters{SkipList}}); | ||||
| 	}	 | ||||
| 	if ($$counters{FailCount} > 0) { | ||||
| 		$stats .= $stats eq '' ? 'F' : ', f'; | ||||
| 		$stats .= sprintf('ailed %d', $$counters{FailCount}); | ||||
| 		$results .= $results eq '' ? 'F' : ', f'; | ||||
| 		$results .= 'ailed: '.join(',', @{$$counters{FailList}}); | ||||
| 	}	 | ||||
| 	if ($$counters{ToInstallCount} > 0) { | ||||
| 		$stats .= $stats eq '' ? 'To ' : ', to '; | ||||
| 		$stats .= sprintf('install %d', $$counters{ToInstallCount}); | ||||
| 		$results .= $results eq '' ? 'To ' : ', to '; | ||||
| 		$results .= 'install: '.join(',', @{$$counters{ToInstallList}}); | ||||
| 	}	 | ||||
| 	if ($$counters{ToRemoveCount} > 0) { | ||||
| 		$stats .= $stats eq '' ? 'To ' : ', to '; | ||||
| 		$stats .= sprintf('remove %d', $$counters{ToRemoveCount}); | ||||
| 		$results .= $results eq '' ? 'To ' : ', to '; | ||||
| 		$results .= 'remove: '.join(',', @{$$counters{ToRemoveList}}); | ||||
| 	} | ||||
| 	if ($cmd eq 'update') { | ||||
| 		$stats .= $stats eq '' ? 'I' : ', i'; | ||||
| 		$stats .= sprintf('nstalled %d, removed %d', $$counters{InstalledCount}, $$counters{RemovedCount}); | ||||
| 		$results .= $results eq '' ? 'I' : ', i'; | ||||
| 		if (scalar @{$$counters{InstalledList}} > 0) { | ||||
| 			$results .= 'nstalled: '.join(',', @{$$counters{InstalledList}}); | ||||
| 		} | ||||
| 		else { | ||||
| 			$results .= 'nstalled: -'; | ||||
| 		} | ||||
| 		if (scalar @{$$counters{RemovedList}} > 0) { | ||||
| 			$results .= ', removed: '.join(',', @{$$counters{RemovedList}}); | ||||
| 		} | ||||
| 		else { | ||||
| 			$results .= ', removed: -'; | ||||
| 		} | ||||
| 	} | ||||
| 	if ($$counters{RebootFlag}) { | ||||
| 		$stats .= $stats eq '' ? 'R' : ', r'; | ||||
| 		$stats .= sprintf('eboot needed!'); | ||||
| 	}	 | ||||
| } | ||||
| print_log('global', WARNING, 'Package/patch statistics: %s', $stats) if defined $stats; | ||||
| print_log('global', INFO, '%s', $results) if defined $results; | ||||
| 
 | ||||
| close_all_log_files(0); | ||||
| exit(0); | ||||
							
								
								
									
										2851
									
								
								pkgtool.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2851
									
								
								pkgtool.pm
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
		Loading…
	
		Reference in a new issue