📄 svn_load_dirs.pl.in
字号:
# Check that the file or directory to be renamed
# has the same file type.
if ($got_line)
{
$add_filename = $add_files[$add_index];
$del_filename = $del_files[$del_index];
if ($add_files{$add_filename}{type} ne
$del_files{$del_filename}{type})
{
print "File types for $del_filename and ",
"$add_filename differ.\n";
$got_line = undef;
}
}
}
} until ($got_line);
if ($line !~ /^F$/i)
{
print "Renaming $del_filename to $add_filename.\n";
$repeat_loop = 1;
# Because subversion cannot rename the same file
# or directory twice, which includes doing a
# rename of a file in a directory that was
# previously renamed, a commit has to be
# performed. Check if the file or directory being
# renamed now would cause such a problem and
# commit if so.
my $do_commit_now = 0;
foreach my $rename_to_filename (keys %rename_to_files)
{
if (contained_in($del_filename,
$rename_to_filename,
$rename_to_files{$rename_to_filename}{type}))
{
$do_commit_now = 1;
last;
}
}
if ($do_commit_now)
{
print "Now committing previously run renames.\n";
&commit_renames($load_dir,
\@renamed_filenames,
\%rename_from_files,
\%rename_to_files);
}
push(@renamed_filenames, $del_filename, $add_filename);
{
my $d = $del_files{$del_filename};
$rename_from_files{$del_filename} = $d;
$rename_to_files{$add_filename} = $d;
}
# Check that any required directories to do the
# rename exist.
my @add_segments = split('/', $add_filename);
pop(@add_segments);
my $add_dir = '';
my @add_dirs;
foreach my $segment (@add_segments)
{
$add_dir = length($add_dir) ? "$add_dir/$segment" :
$segment;
unless (-d $add_dir)
{
push(@add_dirs, $add_dir);
}
}
if (@add_dirs)
{
read_from_process($svn, 'mkdir', @add_dirs);
}
read_from_process($svn, 'mv',
$del_filename, $add_filename);
}
}
} while ($repeat_loop);
}
# If there are any renames that have not been committed, then do
# that now.
if (@renamed_filenames)
{
&commit_renames($load_dir,
\@renamed_filenames,
\%rename_from_files,
\%rename_to_files);
}
# At this point all renames have been performed. Now get the
# final list of files and directories in the working copy
# directory. The %add_files hash will contain the list of files
# and directories to add to the working copy and %del_files starts
# with all the files already in the working copy and gets files
# removed that are in the imported directory, which results in a
# list of files that should be deleted. %upd_files holds the list
# of files that have been updated.
my %add_files;
my %del_files = &recursive_ls_and_hash($wc_import_dir_cwd);
my %upd_files;
# This anonymous subroutine copies files from the source directory
# to the working copy directory.
my $wanted = sub
{
s#^\./##;
return if $_ eq '.';
my $source_path = $_;
my $dest_path = "$wc_import_dir_cwd/$_";
my ($source_type, $source_is_exe) = &file_info($source_path);
my ($dest_type) = &file_info($dest_path);
return if ($source_type ne 'd' and $source_type ne 'f');
# Fail if the destination type exists but is of a different
# type of file than the source type.
if ($dest_type ne '0' and $source_type ne $dest_type)
{
die "$0: does not handle changing source and destination type ",
"for '$source_path'.\n";
}
# Determine if the file is being added or is an update to an
# already existing file using the file's digest.
my $del_info = delete $del_files{$source_path};
if (defined $del_info)
{
if (defined (my $del_digest = $del_info->{digest}))
{
my $new_digest = &digest_hash_file($source_path);
if ($new_digest ne $del_digest)
{
print "U $source_path\n";
$upd_files{$source_path} = $del_info;
}
}
}
else
{
print "A $source_path\n";
$add_files{$source_path}{type} = $source_type;
# Create an array reference to hold the list of properties
# to apply to this object.
unless (defined $add_files{$source_path}{properties})
{
$add_files{$source_path}{properties} = [];
}
# Go through the list of properties for a match on this
# file or directory and if there is a match, then apply
# the property to it.
foreach my $property (@property_settings)
{
my $re = $property->{re};
if ($source_path =~ $re)
{
my $property_name = $property->{name};
my $property_value = $property->{value};
# The property value may not be set in the
# configuration file, since the user may just want
# to set the control flag.
if (defined $property_name and defined $property_value)
{
# Ignore properties that do not apply to
# directories.
if ($source_type eq 'd')
{
if ($property_name eq 'svn:eol-style' or
$property_name eq 'svn:executable' or
$property_name eq 'svn:keywords' or
$property_name eq 'svn:mime-type')
{
next;
}
}
# Ignore properties that do not apply to
# files.
if ($source_type eq 'f')
{
if ($property_name eq 'svn:externals' or
$property_name eq 'svn:ignore')
{
next;
}
}
print "Adding to '$source_path' property ",
"'$property_name' with value ",
"'$property_value'.\n";
push(@{$add_files{$source_path}{properties}},
$property);
}
last if $property->{control} eq 'break';
}
}
}
# Add svn:executable to files that have their executable bit
# set.
if ($source_is_exe)
{
print "Adding to '$source_path' property 'svn:executable' with ",
"value ''.\n";
my $property = {name => 'svn:executable', value => ''};
push (@{$add_files{$source_path}{properties}},
$property);
}
# Now make sure the file or directory in the source directory
# exists in the repository.
if ($source_type eq 'd')
{
if ($dest_type eq '0')
{
mkdir($dest_path)
or die "$0: cannot mkdir '$dest_path': $!\n";
}
}
elsif
($source_type eq 'f') {
# Only copy the file if the digests do not match.
if ($add_files{$source_path} or $upd_files{$source_path})
{
copy($source_path, $dest_path)
or die "$0: copy '$source_path' to '$dest_path': $!\n";
}
}
else
{
die "$0: does not handle copying files of type '$source_type'.\n";
}
};
# Now change into the directory containing the files to load.
# First change to the original directory where this script was run
# so that if the specified directory is a relative directory path,
# then the script can change into it.
chdir($orig_cwd)
or die "$0: cannot chdir '$orig_cwd': $!\n";
chdir($load_dir)
or die "$0: cannot chdir '$load_dir': $!\n";
find({no_chdir => 1,
preprocess => sub { sort { $b cmp $a } @_ },
wanted => $wanted
}, '.');
# The files and directories that are in %del_files are the files
# and directories that need to be deleted. Because svn will
# return an error if a file or directory is deleted in a directory
# that subsequently is deleted, first find all directories and
# remove from the list any files and directories inside those
# directories from this list. Work through the list repeatedly
# working from short to long names so that directories containing
# other files and directories will be deleted first.
my $repeat_loop;
do
{
$repeat_loop = 0;
my @del_files = sort {length($a) <=> length($b) || $a cmp $b}
keys %del_files;
&filter_renamed_files(\@del_files, \%rename_from_files);
foreach my $file (@del_files)
{
if ($del_files{$file}{type} eq 'd')
{
my $dir = "$file/";
my $dir_length = length($dir);
foreach my $f (@del_files)
{
next if $file eq $f;
if (length($f) >= $dir_length and
substr($f, 0, $dir_length) eq $dir)
{
print "d $f\n";
delete $del_files{$f};
$repeat_loop = 1;
}
}
# If there were any deletions of files and/or
# directories inside a directory that will be deleted,
# then restart the entire loop again, because one or
# more keys have been deleted from %del_files.
# Equally important is not to stop this loop if no
# deletions have been done, otherwise later
# directories that may contain files and directories
# to be deleted will not be deleted.
last if $repeat_loop;
}
}
} while ($repeat_loop);
# What is left are files that are not in any directories to be
# deleted and directories to be deleted. To delete the files,
# deeper files and directories must be deleted first. Because we
# have a hash keyed by remaining files and directories to be
# deleted, instead of trying to figure out which directories and
# files are contained in other directories, just reverse sort by
# the path length and then alphabetically.
my @del_files = sort {length($b) <=> length($a) || $a cmp $b }
keys %del_files;
&filter_renamed_files(\@del_files, \%rename_from_files);
foreach my $file (@del_files)
{
print "D $file\n";
}
# Now change back to the trunk directory and run the svn commands.
chdir($wc_import_dir_cwd)
or die "$0: cannot chdir '$wc_import_dir_cwd': $!\n";
# If any of the added files have the svn:eol-style property set,
# then pass -b to diff, otherwise diff may fail because the end of
# lines have changed and the source file and file in the
# repository will not be identical.
my @diff_ignore_space_changes;
if (keys %add_files)
{
my @add_files = sort {length($a) <=> length($b) || $a cmp $b}
keys %add_files;
my $target_filename = &make_targets_file(@add_files);
read_from_process($svn, 'add', '-N', '--targets', $target_filename);
unlink($target_filename);
# Add properties on the added files.
foreach my $add_file (@add_files)
{
foreach my $property (@{$add_files{$add_file}{properties}})
{
my $property_name = $property->{name};
my $property_value = $property->{value};
if ($property_name eq 'svn:eol-style')
{
@diff_ignore_space_changes = ('-b');
}
# Write the value to a temporary file in case it's multi-line
my ($handle, $tmpfile) = tempfile(DIR => $temp_dir);
print $handle $property_value;
close($handle);
read_from_process($svn,
'propset',
$property_name,
'--file',
$tmpfile,
$add_file);
}
}
}
if (@del_files)
{
my $target_filename = &make_targets_file(@del_files);
read_from_process($svn, 'rm', '--targets', $target_filename);
unlink($target_filename);
}
# Go through the list of updated files and check the svn:eol-style
# property. If it is set to native, then convert all CR, CRLF and
# LF's in the file to the native end of line characters. Also,
# modify diff's command line so that it will ignore the change in
# end of line style.
if (keys %upd_files)
{
my @upd_files = sort {length($a) <=> length($b) || $a cmp $b}
keys %upd_files;
foreach my $upd_file (@upd_files)
{
my @command = ($svn, 'propget', 'svn:eol-style', $upd_file);
my @lines = read_from_process(@command);
next unless @lines;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -