Add script allowing to create a clone of MSVS project file

Put under version control an ancient script (created back in ~2012?)
that can be used to create a copy an existing MSVS project file using a
new name and a different UUID.

This is very far from being a replacement for a proper (meta) build
system such as bakefile but still better than nothing at all.
This commit is contained in:
Vadim Zeitlin
2024-02-11 15:58:59 +01:00
parent 50252c9382
commit 63100ff3ae

110
build/vcxproj-clone.pl Executable file
View File

@@ -0,0 +1,110 @@
#!/usr/bin/env perl
use v5.10;
use strict;
use warnings;
use autodie;
use File::Copy qw(copy);
use File::Spec;
use Getopt::Long;
use IO::Handle;
use UUID::Tiny qw(:std);
my $force = 0;
my $verbose = 0;
GetOptions(
'force|f' => \$force,
'verbose|v' => \$verbose,
) and (@ARGV == 2) or die <<EOF
Usage: $0 [options] <existing-project.vcxproj> <new-name>
Clone an existing MSBuild project file with .vcxproj extension by creating a
new project with the given name.
Options:
-f, --force Overwrite the file with the new name even if it exists.
-v, --verbose Show more details about what the program is doing.
EOF
;
# Show progress messages immediately.
STDOUT->autoflush(1) if $verbose;
# Returns just the name of the project, i.e. the part without any path nor
# extension and the full path to it, which will always have .vcxproj extension
# whether it is already present in input or not.
sub get_name_and_project
{
my ($file) = @_;
# If a .filters file was passed on input by mistake, accept it as if the
# project itself was given.
$file =~ s/\.filters$//;
my ($volume, $dir, $name) = File::Spec->splitpath($file);
if ($file !~ /\.vcxproj$/) {
$file .= '.vcxproj';
} else {
$name =~ s/\.vcxproj$//;
}
return ($name, $file)
}
my ($orig_name, $orig_project) = get_name_and_project(shift @ARGV);
my ($new_name, $new_project) = get_name_and_project(shift @ARGV);
if (!$force && -e $new_project) {
die qq{File "$new_project" already exists, not overwriting without -f.\n}
}
open my $fh_in, '<', $orig_project;
open my $fh_out, '>', $new_project;
say "Cloning $orig_project to $new_project" if $verbose;
# Don't bother with parsing XML, just mangle the text directly.
while (<$fh_in>) {
# Note: don't use chomp to preserve the same kind of EOLs.
if (m|
^
(?<leading_space>\s*)
<ProjectGuid>
\{
(?<orig_uuid>[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12})
\}
</ProjectGuid>
(?<trailing_space>\s*)
$
|x) {
my $new_uuid = uc(create_uuid_as_string(UUID_RANDOM));
say qq(Replacing old GUID "$+{orig_uuid}" with "$new_uuid".);
$_ = "$+{leading_space}<ProjectGuid>{$new_uuid}</ProjectGuid>$+{trailing_space}"
} else {
# Replace the project name for the tags that use it.
s@
^
(\s*)
\K
<(?<tag>ProjectName|IntDir|\w+File(?:Name)?)>
(?<before>.*)\Q$orig_name\E(?<after>.*)
</\g{tag}>
(?<trailing_space>\s*)
$
@<$+{tag}>$+{before}$new_name$+{after}</$+{tag}>$+{trailing_space}@ix;
}
print $fh_out $_;
}
close $fh_out;
say "And copying $orig_project.filters to $new_project.filters" if $verbose;
copy("$orig_project.filters", "$new_project.filters") or
die qq{Failed to copy "$orig_project.filters" to "$new_project.filters: $!\n};
exit 0