bldsystemtools/commonbldutils/make_directory_tree.pl
changeset 0 83f4b4db085c
child 1 d4b442d23379
equal deleted inserted replaced
-1:000000000000 0:83f4b4db085c
       
     1 #! perl
       
     2 # Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 # All rights reserved.
       
     4 # This component and the accompanying materials are made available
       
     5 # under the terms of "Eclipse Public License v1.0"
       
     6 # which accompanies this distribution, and is available
       
     7 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 #
       
     9 # Initial Contributors:
       
    10 # Nokia Corporation - initial contribution.
       
    11 #
       
    12 # Contributors:
       
    13 #
       
    14 # Description:
       
    15 #
       
    16 
       
    17 use strict;
       
    18 use Getopt::Long;
       
    19 
       
    20 sub Usage(;$)
       
    21 	{
       
    22 	my ($errmsg) = @_;
       
    23 	print "\nERROR: $errmsg\n" if (defined $errmsg);
       
    24 	print <<'EOF';
       
    25 
       
    26 perl make_directory_tree.pl [options] specfile
       
    27 perl make_directory_tree.pl [options] -check specfile 
       
    28  
       
    29 Create a tree of empty directories, specified in specfile.
       
    30 The specification is one or more lines of the form
       
    31 
       
    32    path/name/separated/by/forward/slash   # optional comment
       
    33 
       
    34 Paths should not contain "." or "..". Paths ending in "*"
       
    35 imply that other subdirectories are permitted by the -check
       
    36 option, but ignored.
       
    37 
       
    38 If no specfile is given on the command line, the tool will
       
    39 read from standard input.
       
    40 
       
    41 The -check option compares an existing directory tree
       
    42 with the one which would have been created, and reports 
       
    43 differences.
       
    44 
       
    45 Options:
       
    46 
       
    47 -r rootdir           root of the directory tree 
       
    48 -o newspecfile       specfile describing the new tree, 
       
    49                      mostly for use with the -check option
       
    50 -fix                 attempt to correct directory names which 
       
    51                      have the wrong case - used with -check
       
    52 
       
    53 If no rootdir is specified, the tree will be assumed to start
       
    54 in the current directory. 
       
    55 
       
    56 EOF
       
    57 	exit 1;
       
    58 	}
       
    59 
       
    60 my $rootdir;
       
    61 my $check;
       
    62 my $fix;
       
    63 my $newspecfile;
       
    64 my $help;
       
    65 my $verbose;
       
    66 
       
    67 Usage() if !GetOptions(
       
    68 	'r=s' => \$rootdir,
       
    69 	'o=s' => \$newspecfile,
       
    70 	'check' => \$check,
       
    71 	'fix' => \$fix,
       
    72 	'h' => \$help,
       
    73 	'v' => \$verbose,
       
    74 	);
       
    75 
       
    76 Usage() if ($help);
       
    77 
       
    78 my $line;
       
    79 my %dirnames;		# actual capitalisation
       
    80 my %lc_dirnames;	# forced to lowercase
       
    81 my %wilddirs;
       
    82 
       
    83 while ($line=<>)
       
    84 	{
       
    85 	chomp $line;
       
    86 	$line =~ s/\s*#.*$//;	# hash is comment to end of line
       
    87 	$line =~ s/^\s*//;		# remove leading whitespace
       
    88 	$line =~ s/\s*$//;		# remove trailing whitespace
       
    89 	
       
    90 	# also accepts the output of "p4 have"
       
    91 	if ($line =~ /^\/\/epoc\/master\/(.*)\/[^\/]+$/i)
       
    92 		{
       
    93 		# output of p4 have
       
    94 		$line = $1;
       
    95 		}
       
    96 		
       
    97 	next if ($line eq "");	# ignore blanks
       
    98 
       
    99 	# tolerate some minor errors in the input format
       
   100 	$line =~ s/\\/\//g;	# convert any \ to /
       
   101 	$line =~ s/^\///;	# remove leading /, if present
       
   102 	
       
   103 	my $wilddir = 0;
       
   104 	if ($line =~ /\/\*$/)
       
   105 		{
       
   106 		$line = substr $line, 0, -2;	# cut off last two characters
       
   107 		$wilddir = 1;
       
   108 		}
       
   109 	
       
   110 	my @dirs = split /\//, $line;
       
   111 	my $path = "";
       
   112 	my $lc_path = lc $path;
       
   113 	foreach my $subdir (@dirs)
       
   114 		{
       
   115 		my $parent = $path;
       
   116 		$path .= "/$subdir";
       
   117 		$lc_path .= lc "/$subdir";
       
   118 		
       
   119 		next if (defined $dirnames{$path});	# already seen this one
       
   120 		if (defined $lc_dirnames{$lc_path})
       
   121 			{
       
   122 			my $fixed_path = $lc_dirnames{$lc_path};
       
   123 			print "WARNING: input file has ambiguous case for $path (should be $fixed_path)\n";
       
   124 			$path = $fixed_path;	# recover by using the earlier entry?
       
   125 			next;
       
   126 			}
       
   127 		# found a new directory
       
   128 		@{$dirnames{$path}} = ();	# empty list of subdirs
       
   129 		$lc_dirnames{$lc_path} = $path;
       
   130 		push @{$dirnames{$parent}}, $subdir;
       
   131 		next;
       
   132 		}
       
   133 	$wilddirs{$path} = 1 if ($wilddir);		
       
   134 	}
       
   135 
       
   136 print "* Processed input file\n";
       
   137 Usage("No directories specified") if (scalar keys %dirnames == 0);
       
   138 
       
   139 # %dirnames now contains all of the approved names as keys
       
   140 # The associated value is the list of subdirectories (if any)
       
   141 
       
   142 # Subroutine to create a completely new directory tree
       
   143 sub make_new_tree($)
       
   144 	{
       
   145 	my ($root) = @_;
       
   146 	
       
   147 	my $errors = 0;
       
   148 	foreach my $path (sort keys %dirnames)
       
   149 		{
       
   150 		next if ($path eq "");	# root directory already exists
       
   151 		print "** mkdir $root$path\n" if ($verbose);
       
   152 		if (!mkdir $root.$path)
       
   153 			{
       
   154 			print "ERROR: failed to make $root$path: $!\n";
       
   155 			$errors++;
       
   156 			}
       
   157 		}
       
   158 	
       
   159 	return ($errors == 0);
       
   160 	}
       
   161 
       
   162 # recursive routine to remove a subtree from %dirnames
       
   163 sub remove_subtree($);
       
   164 sub remove_subtree($)
       
   165 	{
       
   166 	my ($subdir) = @_;
       
   167 	my @absent = @{$dirnames{$subdir}};
       
   168 	delete $dirnames{$subdir};	# delete the parent
       
   169 	if (defined $wilddirs{$subdir})
       
   170 		{
       
   171 		# Remove from %wilddirs as well - directory should exist
       
   172 		delete $wilddirs{$subdir};
       
   173 		}
       
   174 	
       
   175 	foreach my $dir (@absent)
       
   176 		{
       
   177 		remove_subtree("$subdir/$dir");	# recursively delete the children
       
   178 		}
       
   179 	}
       
   180 
       
   181 # recursive routine to check a subtree against %dirnames
       
   182 sub check_subtree($$$);
       
   183 sub check_subtree($$$)
       
   184 	{
       
   185 	my ($root,$subdir,$expected) = @_;
       
   186 	
       
   187 	my $currentdir = $root.$subdir;
       
   188 	opendir DIR, $currentdir;
       
   189 	my @contents = grep !/^\.\.?$/, readdir DIR;
       
   190 	closedir DIR;
       
   191 
       
   192 	printf ("** checking $currentdir - %d entries\n", scalar @contents) if ($verbose);
       
   193 
       
   194 	my @confirmed = ();
       
   195 	foreach my $expected (@{$dirnames{$subdir}})
       
   196 		{
       
   197 		push @confirmed,$expected;
       
   198 		if (!-d "$currentdir/$expected")
       
   199 			{
       
   200 			# Note: this does not check the correctness of the case,
       
   201 			# that comes in the scan through @contents
       
   202 			print "REMARK: cannot find expected directory $currentdir/$expected\n";
       
   203 			if ($fix && defined $newspecfile)
       
   204 				{
       
   205 				print "** removing $currentdir/$expected/... from specification\n";
       
   206 				remove_subtree("$subdir/$expected");
       
   207 				pop @confirmed;	
       
   208 				}
       
   209 			}
       
   210 		}
       
   211 	@{$dirnames{$subdir}} = @confirmed;	# update the description of the tree
       
   212 
       
   213 	foreach my $name (@contents)
       
   214 		{
       
   215 		if (!-d "$currentdir/$name")
       
   216 			{
       
   217 			next; # ignore files
       
   218 			}
       
   219 		
       
   220 		my $newpath = "$subdir/$name";
       
   221 		if ($expected)
       
   222 			{
       
   223 			if (defined $dirnames{$newpath})
       
   224 				{
       
   225 				# we expected this one, and it has the correct case
       
   226 				check_subtree($root,$newpath,1);
       
   227 				next;
       
   228 				}
       
   229 			
       
   230 			my $lc_newpath = lc $newpath;
       
   231 			if (defined $lc_dirnames{$lc_newpath})
       
   232 				{
       
   233 				# expected directory, but wrong name
       
   234 				$newpath = $lc_dirnames{$lc_newpath};	# get the correct name
       
   235 				if ($fix && rename("$currentdir/$name","$root$newpath"))
       
   236 					{
       
   237 					print "* corrected $currentdir/$name to $root$newpath\n";
       
   238 					}
       
   239 				else
       
   240 					{
       
   241 				    print "ERROR: $currentdir/$name should be $root$newpath\n";
       
   242 				    }
       
   243 				check_subtree($root,$newpath,1);
       
   244 				next;
       
   245 				}
       
   246 			}
       
   247 
       
   248 		# unexpected subdirectory
       
   249 		
       
   250 		if ($wilddirs{$subdir})
       
   251 			{
       
   252 			# unexpected directory in a directory which allows "extras"
       
   253 			next;
       
   254 			}
       
   255 		
       
   256 		print "REMARK: New subtree found: $newpath\n" if ($expected);
       
   257 		
       
   258 		# add unexpected subtrees to the $dirnames structure
       
   259 		
       
   260 		@{$dirnames{$newpath}} = ();	# empty list of subdirs
       
   261 		push @{$dirnames{$subdir}}, $name;
       
   262 		# no %lc_dirnames entry required
       
   263 		
       
   264 		check_subtree($root,$newpath,0);
       
   265 		}
       
   266 	
       
   267 	}
       
   268 
       
   269 # subroutine to generate a new input file
       
   270 sub print_leaf_dirs($)
       
   271 	{
       
   272 	my ($filename) = @_;
       
   273 	
       
   274 	open FILE, ">$filename" or die "Cannot write to $filename: $!\n";
       
   275 	
       
   276 	foreach my $path (sort keys %dirnames)
       
   277 		{
       
   278 		my @subdirs = @{$dirnames{$path}};
       
   279 
       
   280 		if (defined $wilddirs{$path})
       
   281 			{
       
   282 			print FILE "$path/*\n";	# always print wildcard directories
       
   283 			next;
       
   284 			}
       
   285 					
       
   286 		next if (scalar @subdirs != 0);	# ignore interior directories
       
   287 		print FILE "$path\n";
       
   288 		}
       
   289 
       
   290 	close FILE;
       
   291 	}
       
   292 
       
   293 
       
   294 $rootdir =~ s/\\/\//g if (defined $rootdir);	# convert rootdir to forward slashes
       
   295 
       
   296 if ($check)
       
   297 	{
       
   298 	$rootdir = "." if (!defined $rootdir);
       
   299 	print "* checking $rootdir ...\n";
       
   300 	check_subtree($rootdir,"",1);
       
   301 
       
   302 	}
       
   303 else
       
   304 	{
       
   305 	if (defined $rootdir && !-d $rootdir)
       
   306 		{
       
   307 		Usage("Cannot create $rootdir: $!") if (!mkdir $rootdir);
       
   308 		print "* created root directory $rootdir\n";
       
   309 		}
       
   310 	else
       
   311 		{
       
   312 		$rootdir = ".";
       
   313 		}
       
   314 	
       
   315 	print "* creating directory tree in $rootdir\n";
       
   316 	make_new_tree($rootdir);
       
   317 	}
       
   318 
       
   319 if (defined $newspecfile)
       
   320 	{
       
   321 	print_leaf_dirs($newspecfile);
       
   322 	print "* created $newspecfile\n";
       
   323 	}