summaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rw-r--r--contrib/buildsystems/Generators.pm42
-rw-r--r--contrib/buildsystems/Generators/QMake.pm189
-rw-r--r--contrib/buildsystems/Generators/Vcproj.pm622
-rw-r--r--contrib/buildsystems/engine.pl353
-rw-r--r--contrib/buildsystems/generate29
-rw-r--r--contrib/buildsystems/parse.pl228
-rwxr-xr-xcontrib/completion/git-completion.bash107
-rw-r--r--contrib/emacs/git.el26
-rwxr-xr-xcontrib/fast-import/git-p4181
-rwxr-xr-xcontrib/fast-import/import-directories.perl416
-rwxr-xr-xcontrib/fast-import/import-tars.perl50
11 files changed, 2111 insertions, 132 deletions
diff --git a/contrib/buildsystems/Generators.pm b/contrib/buildsystems/Generators.pm
new file mode 100644
index 0000000000..408ef714b8
--- /dev/null
+++ b/contrib/buildsystems/Generators.pm
@@ -0,0 +1,42 @@
+package Generators;
+require Exporter;
+
+use strict;
+use File::Basename;
+no strict 'refs';
+use vars qw($VERSION @AVAILABLE);
+
+our $VERSION = '1.00';
+our(@ISA, @EXPORT, @EXPORT_OK, @AVAILABLE);
+@ISA = qw(Exporter);
+
+BEGIN {
+ local(*D);
+ my $me = $INC{"Generators.pm"};
+ die "Couldn't find myself in \@INC, which is required to load the generators!" if ("$me" eq "");
+ $me = dirname($me);
+ if (opendir(D,"$me/Generators")) {
+ foreach my $gen (readdir(D)) {
+ next if ($gen =~ /^\.\.?$/);
+ require "${me}/Generators/$gen";
+ $gen =~ s,\.pm,,;
+ push(@AVAILABLE, $gen);
+ }
+ closedir(D);
+ my $gens = join(', ', @AVAILABLE);
+ }
+
+ push @EXPORT_OK, qw(available);
+}
+
+sub available {
+ return @AVAILABLE;
+}
+
+sub generate {
+ my ($gen, $git_dir, $out_dir, $rel_dir, %build_structure) = @_;
+ return eval("Generators::${gen}::generate(\$git_dir, \$out_dir, \$rel_dir, \%build_structure)") if grep(/^$gen$/, @AVAILABLE);
+ die "Generator \"${gen}\" is not available!\nAvailable generators are: @AVAILABLE\n";
+}
+
+1;
diff --git a/contrib/buildsystems/Generators/QMake.pm b/contrib/buildsystems/Generators/QMake.pm
new file mode 100644
index 0000000000..ff3b657e61
--- /dev/null
+++ b/contrib/buildsystems/Generators/QMake.pm
@@ -0,0 +1,189 @@
+package Generators::QMake;
+require Exporter;
+
+use strict;
+use vars qw($VERSION);
+
+our $VERSION = '1.00';
+our(@ISA, @EXPORT, @EXPORT_OK, @AVAILABLE);
+@ISA = qw(Exporter);
+
+BEGIN {
+ push @EXPORT_OK, qw(generate);
+}
+
+sub generate {
+ my ($git_dir, $out_dir, $rel_dir, %build_structure) = @_;
+
+ my @libs = @{$build_structure{"LIBS"}};
+ foreach (@libs) {
+ createLibProject($_, $git_dir, $out_dir, $rel_dir, %build_structure);
+ }
+
+ my @apps = @{$build_structure{"APPS"}};
+ foreach (@apps) {
+ createAppProject($_, $git_dir, $out_dir, $rel_dir, %build_structure);
+ }
+
+ createGlueProject($git_dir, $out_dir, $rel_dir, %build_structure);
+ return 0;
+}
+
+sub createLibProject {
+ my ($libname, $git_dir, $out_dir, $rel_dir, %build_structure) = @_;
+ print "Generate $libname lib project\n";
+ $rel_dir = "../$rel_dir";
+
+ my $sources = join(" \\\n\t", sort(map("$rel_dir/$_", @{$build_structure{"LIBS_${libname}_SOURCES"}})));
+ my $defines = join(" \\\n\t", sort(@{$build_structure{"LIBS_${libname}_DEFINES"}}));
+ my $includes= join(" \\\n\t", sort(map("$rel_dir/$_", @{$build_structure{"LIBS_${libname}_INCLUDES"}})));
+ my $cflags = join(" ", sort(@{$build_structure{"LIBS_${libname}_CFLAGS"}}));
+
+ my $cflags_debug = $cflags;
+ $cflags_debug =~ s/-MT/-MTd/;
+ $cflags_debug =~ s/-O.//;
+
+ my $cflags_release = $cflags;
+ $cflags_release =~ s/-MTd/-MT/;
+
+ my @tmp = @{$build_structure{"LIBS_${libname}_LFLAGS"}};
+ my @tmp2 = ();
+ foreach (@tmp) {
+ if (/^-LTCG/) {
+ } elsif (/^-L/) {
+ $_ =~ s/^-L/-LIBPATH:$rel_dir\//;
+ }
+ push(@tmp2, $_);
+ }
+ my $lflags = join(" ", sort(@tmp));
+
+ my $target = $libname;
+ $target =~ s/\//_/g;
+ $defines =~ s/-D//g;
+ $defines =~ s/"/\\\\"/g;
+ $includes =~ s/-I//g;
+ mkdir "$target" || die "Could not create the directory $target for lib project!\n";
+ open F, ">$target/$target.pro" || die "Could not open $target/$target.pro for writing!\n";
+ print F << "EOM";
+TEMPLATE = lib
+TARGET = $target
+DESTDIR = $rel_dir
+
+CONFIG -= qt
+CONFIG += static
+
+QMAKE_CFLAGS =
+QMAKE_CFLAGS_RELEASE = $cflags_release
+QMAKE_CFLAGS_DEBUG = $cflags_debug
+QMAKE_LIBFLAGS = $lflags
+
+DEFINES += \\
+ $defines
+
+INCLUDEPATH += \\
+ $includes
+
+SOURCES += \\
+ $sources
+EOM
+ close F;
+}
+
+sub createAppProject {
+ my ($appname, $git_dir, $out_dir, $rel_dir, %build_structure) = @_;
+ print "Generate $appname app project\n";
+ $rel_dir = "../$rel_dir";
+
+ my $sources = join(" \\\n\t", sort(map("$rel_dir/$_", @{$build_structure{"APPS_${appname}_SOURCES"}})));
+ my $defines = join(" \\\n\t", sort(@{$build_structure{"APPS_${appname}_DEFINES"}}));
+ my $includes= join(" \\\n\t", sort(map("$rel_dir/$_", @{$build_structure{"APPS_${appname}_INCLUDES"}})));
+ my $cflags = join(" ", sort(@{$build_structure{"APPS_${appname}_CFLAGS"}}));
+
+ my $cflags_debug = $cflags;
+ $cflags_debug =~ s/-MT/-MTd/;
+ $cflags_debug =~ s/-O.//;
+
+ my $cflags_release = $cflags;
+ $cflags_release =~ s/-MTd/-MT/;
+
+ my $libs;
+ foreach (sort(@{$build_structure{"APPS_${appname}_LIBS"}})) {
+ $_ =~ s/\//_/g;
+ $libs .= " $_";
+ }
+ my @tmp = @{$build_structure{"APPS_${appname}_LFLAGS"}};
+ my @tmp2 = ();
+ foreach (@tmp) {
+ # next if ($_ eq "-NODEFAULTLIB:MSVCRT.lib");
+ if (/^-LTCG/) {
+ } elsif (/^-L/) {
+ $_ =~ s/^-L/-LIBPATH:$rel_dir\//;
+ }
+ push(@tmp2, $_);
+ }
+ my $lflags = join(" ", sort(@tmp));
+
+ my $target = $appname;
+ $target =~ s/\.exe//;
+ $target =~ s/\//_/g;
+ $defines =~ s/-D//g;
+ $defines =~ s/"/\\\\"/g;
+ $includes =~ s/-I//g;
+ mkdir "$target" || die "Could not create the directory $target for app project!\n";
+ open F, ">$target/$target.pro" || die "Could not open $target/$target.pro for writing!\n";
+ print F << "EOM";
+TEMPLATE = app
+TARGET = $target
+DESTDIR = $rel_dir
+
+CONFIG -= qt embed_manifest_exe
+CONFIG += console
+
+QMAKE_CFLAGS =
+QMAKE_CFLAGS_RELEASE = $cflags_release
+QMAKE_CFLAGS_DEBUG = $cflags_debug
+QMAKE_LFLAGS = $lflags
+LIBS = $libs
+
+DEFINES += \\
+ $defines
+
+INCLUDEPATH += \\
+ $includes
+
+win32:QMAKE_LFLAGS += -LIBPATH:$rel_dir
+else: QMAKE_LFLAGS += -L$rel_dir
+
+SOURCES += \\
+ $sources
+EOM
+ close F;
+}
+
+sub createGlueProject {
+ my ($git_dir, $out_dir, $rel_dir, %build_structure) = @_;
+ my $libs = join(" \\ \n", map("\t$_|$_.pro", @{$build_structure{"LIBS"}}));
+ my $apps = join(" \\ \n", map("\t$_|$_.pro", @{$build_structure{"APPS"}}));
+ $libs =~ s/\.a//g;
+ $libs =~ s/\//_/g;
+ $libs =~ s/\|/\//g;
+ $apps =~ s/\.exe//g;
+ $apps =~ s/\//_/g;
+ $apps =~ s/\|/\//g;
+
+ my $filename = $out_dir;
+ $filename =~ s/.*\/([^\/]+)$/$1/;
+ $filename =~ s/\/$//;
+ print "Generate glue project $filename.pro\n";
+ open F, ">$filename.pro" || die "Could not open $filename.pro for writing!\n";
+ print F << "EOM";
+TEMPLATE = subdirs
+CONFIG += ordered
+SUBDIRS += \\
+$libs \\
+$apps
+EOM
+ close F;
+}
+
+1;
diff --git a/contrib/buildsystems/Generators/Vcproj.pm b/contrib/buildsystems/Generators/Vcproj.pm
new file mode 100644
index 0000000000..be94ba18d2
--- /dev/null
+++ b/contrib/buildsystems/Generators/Vcproj.pm
@@ -0,0 +1,622 @@
+package Generators::Vcproj;
+require Exporter;
+
+use strict;
+use vars qw($VERSION);
+
+our $VERSION = '1.00';
+our(@ISA, @EXPORT, @EXPORT_OK, @AVAILABLE);
+@ISA = qw(Exporter);
+
+BEGIN {
+ push @EXPORT_OK, qw(generate);
+}
+
+my $guid_index = 0;
+my @GUIDS = (
+ "{E07B9989-2BF7-4F21-8918-BE22BA467AC3}",
+ "{278FFB51-0296-4A44-A81A-22B87B7C3592}",
+ "{7346A2C4-F0FD-444F-9EBE-1AF23B2B5650}",
+ "{67F421AC-EB34-4D49-820B-3196807B423F}",
+ "{385DCFE1-CC8C-4211-A451-80FCFC31CA51}",
+ "{97CC46C5-D2CC-4D26-B634-E75792B79916}",
+ "{C7CE21FE-6EF8-4012-A5C7-A22BCEDFBA11}",
+ "{51575134-3FDF-42D1-BABD-3FB12669C6C9}",
+ "{0AE195E4-9823-4B87-8E6F-20C5614AF2FF}",
+ "{4B918255-67CA-43BB-A46C-26704B666E6B}",
+ "{18CCFEEF-C8EE-4CC1-A265-26F95C9F4649}",
+ "{5D5D90FA-01B7-4973-AFE5-CA88C53AC197}",
+ "{1F054320-036D-49E1-B384-FB5DF0BC8AC0}",
+ "{7CED65EE-F2D9-4171-825B-C7D561FE5786}",
+ "{8D341679-0F07-4664-9A56-3BA0DE88B9BC}",
+ "{C189FEDC-2957-4BD7-9FA4-7622241EA145}",
+ "{66844203-1B9F-4C53-9274-164FFF95B847}",
+ "{E4FEA145-DECC-440D-AEEA-598CF381FD43}",
+ "{73300A8E-C8AC-41B0-B555-4F596B681BA7}",
+ "{873FDEB1-D01D-40BF-A1BF-8BBC58EC0F51}",
+ "{7922C8BE-76C5-4AC6-8BF7-885C0F93B782}",
+ "{E245D370-308B-4A49-BFC1-1E527827975F}",
+ "{F6FA957B-66FC-4ED7-B260-E59BBE4FE813}",
+ "{E6055070-0198-431A-BC49-8DB6CEE770AE}",
+ "{54159234-C3EB-43DA-906B-CE5DA5C74654}",
+ "{594CFC35-0B60-46F6-B8EF-9983ACC1187D}",
+ "{D93FCAB7-1F01-48D2-B832-F761B83231A5}",
+ "{DBA5E6AC-E7BE-42D3-8703-4E787141526E}",
+ "{6171953F-DD26-44C7-A3BE-CC45F86FC11F}",
+ "{9E19DDBE-F5E4-4A26-A2FE-0616E04879B8}",
+ "{AE81A615-99E3-4885-9CE0-D9CAA193E867}",
+ "{FBF4067E-1855-4F6C-8BCD-4D62E801A04D}",
+ "{17007948-6593-4AEB-8106-F7884B4F2C19}",
+ "{199D4C8D-8639-4DA6-82EF-08668C35DEE0}",
+ "{E085E50E-C140-4CF3-BE4B-094B14F0DDD6}",
+ "{00785268-A9CC-4E40-AC29-BAC0019159CE}",
+ "{4C06F56A-DCDB-46A6-B67C-02339935CF12}",
+ "{3A62D3FD-519E-4EC9-8171-D2C1BFEA022F}",
+ "{3A62D3FD-519E-4EC9-8171-D2C1BFEA022F}",
+ "{9392EB58-D7BA-410B-B1F0-B2FAA6BC89A7}",
+ "{2ACAB2D5-E0CE-4027-BCA0-D78B2D7A6C66}",
+ "{86E216C3-43CE-481A-BCB2-BE5E62850635}",
+ "{FB631291-7923-4B91-9A57-7B18FDBB7A42}",
+ "{0A176EC9-E934-45B8-B87F-16C7F4C80039}",
+ "{DF55CA80-46E8-4C53-B65B-4990A23DD444}",
+ "{3A0F9895-55D2-4710-BE5E-AD7498B5BF44}",
+ "{294BDC5A-F448-48B6-8110-DD0A81820F8C}",
+ "{4B9F66E9-FAC9-47AB-B1EF-C16756FBFD06}",
+ "{72EA49C6-2806-48BD-B81B-D4905102E19C}",
+ "{5728EB7E-8929-486C-8CD5-3238D060E768}"
+);
+
+sub generate {
+ my ($git_dir, $out_dir, $rel_dir, %build_structure) = @_;
+ my @libs = @{$build_structure{"LIBS"}};
+ foreach (@libs) {
+ createLibProject($_, $git_dir, $out_dir, $rel_dir, \%build_structure);
+ }
+
+ my @apps = @{$build_structure{"APPS"}};
+ foreach (@apps) {
+ createAppProject($_, $git_dir, $out_dir, $rel_dir, \%build_structure);
+ }
+
+ createGlueProject($git_dir, $out_dir, $rel_dir, %build_structure);
+ return 0;
+}
+
+sub createLibProject {
+ my ($libname, $git_dir, $out_dir, $rel_dir, $build_structure) = @_;
+ print "Generate $libname vcproj lib project\n";
+ $rel_dir = "..\\$rel_dir";
+ $rel_dir =~ s/\//\\/g;
+
+ my $target = $libname;
+ $target =~ s/\//_/g;
+ $target =~ s/\.a//;
+
+ my $uuid = $GUIDS[$guid_index];
+ $$build_structure{"LIBS_${target}_GUID"} = $uuid;
+ $guid_index += 1;
+
+ my @srcs = sort(map("$rel_dir\\$_", @{$$build_structure{"LIBS_${libname}_SOURCES"}}));
+ my @sources;
+ foreach (@srcs) {
+ $_ =~ s/\//\\/g;
+ push(@sources, $_);
+ }
+ my $defines = join(",", sort(@{$$build_structure{"LIBS_${libname}_DEFINES"}}));
+ my $includes= join(";", sort(map("&quot;$rel_dir\\$_&quot;", @{$$build_structure{"LIBS_${libname}_INCLUDES"}})));
+ my $cflags = join(" ", sort(@{$$build_structure{"LIBS_${libname}_CFLAGS"}}));
+ $cflags =~ s/\"/&quot;/g;
+
+ my $cflags_debug = $cflags;
+ $cflags_debug =~ s/-MT/-MTd/;
+ $cflags_debug =~ s/-O.//;
+
+ my $cflags_release = $cflags;
+ $cflags_release =~ s/-MTd/-MT/;
+
+ my @tmp = @{$$build_structure{"LIBS_${libname}_LFLAGS"}};
+ my @tmp2 = ();
+ foreach (@tmp) {
+ if (/^-LTCG/) {
+ } elsif (/^-L/) {
+ $_ =~ s/^-L/-LIBPATH:$rel_dir\//;
+ }
+ push(@tmp2, $_);
+ }
+ my $lflags = join(" ", sort(@tmp));
+
+ $defines =~ s/-D//g;
+ $defines =~ s/\"/\\&quot;/g;
+ $defines =~ s/\'//g;
+ $includes =~ s/-I//g;
+ mkdir "$target" || die "Could not create the directory $target for lib project!\n";
+ open F, ">$target/$target.vcproj" || die "Could not open $target/$target.pro for writing!\n";
+ binmode F, ":crlf";
+ print F << "EOM";
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9,00"
+ Name="$target"
+ ProjectGUID="$uuid">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$rel_dir"
+ ConfigurationType="4"
+ CharacterSet="0"
+ IntermediateDirectory="\$(ProjectDir)\$(ConfigurationName)"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="$cflags_debug"
+ Optimization="0"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="$includes"
+ PreprocessorDefinitions="WIN32,_DEBUG,$defines"
+ MinimalRebuild="true"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$rel_dir"
+ ConfigurationType="4"
+ CharacterSet="0"
+ WholeProgramOptimization="1"
+ IntermediateDirectory="\$(ProjectDir)\$(ConfigurationName)"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="$cflags_release"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="$includes"
+ PreprocessorDefinitions="WIN32,NDEBUG,$defines"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+EOM
+ foreach(@sources) {
+ print F << "EOM";
+ <File
+ RelativePath="$_"/>
+EOM
+ }
+ print F << "EOM";
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
+EOM
+ close F;
+}
+
+sub createAppProject {
+ my ($appname, $git_dir, $out_dir, $rel_dir, $build_structure) = @_;
+ print "Generate $appname vcproj app project\n";
+ $rel_dir = "..\\$rel_dir";
+ $rel_dir =~ s/\//\\/g;
+
+ my $target = $appname;
+ $target =~ s/\//_/g;
+ $target =~ s/\.exe//;
+
+ my $uuid = $GUIDS[$guid_index];
+ $$build_structure{"APPS_${target}_GUID"} = $uuid;
+ $guid_index += 1;
+
+ my @srcs = sort(map("$rel_dir\\$_", @{$$build_structure{"APPS_${appname}_SOURCES"}}));
+ my @sources;
+ foreach (@srcs) {
+ $_ =~ s/\//\\/g;
+ push(@sources, $_);
+ }
+ my $defines = join(",", sort(@{$$build_structure{"APPS_${appname}_DEFINES"}}));
+ my $includes= join(";", sort(map("&quot;$rel_dir\\$_&quot;", @{$$build_structure{"APPS_${appname}_INCLUDES"}})));
+ my $cflags = join(" ", sort(@{$$build_structure{"APPS_${appname}_CFLAGS"}}));
+ $cflags =~ s/\"/&quot;/g;
+
+ my $cflags_debug = $cflags;
+ $cflags_debug =~ s/-MT/-MTd/;
+ $cflags_debug =~ s/-O.//;
+
+ my $cflags_release = $cflags;
+ $cflags_release =~ s/-MTd/-MT/;
+
+ my $libs;
+ foreach (sort(@{$$build_structure{"APPS_${appname}_LIBS"}})) {
+ $_ =~ s/\//_/g;
+ $libs .= " $_";
+ }
+ my @tmp = @{$$build_structure{"APPS_${appname}_LFLAGS"}};
+ my @tmp2 = ();
+ foreach (@tmp) {
+ if (/^-LTCG/) {
+ } elsif (/^-L/) {
+ $_ =~ s/^-L/-LIBPATH:$rel_dir\//;
+ }
+ push(@tmp2, $_);
+ }
+ my $lflags = join(" ", sort(@tmp)) . " -LIBPATH:$rel_dir";
+
+ $defines =~ s/-D//g;
+ $defines =~ s/\"/\\&quot;/g;
+ $defines =~ s/\'//g;
+ $defines =~ s/\\\\/\\/g;
+ $includes =~ s/-I//g;
+ mkdir "$target" || die "Could not create the directory $target for lib project!\n";
+ open F, ">$target/$target.vcproj" || die "Could not open $target/$target.pro for writing!\n";
+ binmode F, ":crlf";
+ print F << "EOM";
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9,00"
+ Name="$target"
+ ProjectGUID="$uuid">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$rel_dir"
+ ConfigurationType="1"
+ CharacterSet="0"
+ IntermediateDirectory="\$(ProjectDir)\$(ConfigurationName)"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="$cflags_debug"
+ Optimization="0"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="$includes"
+ PreprocessorDefinitions="WIN32,_DEBUG,$defines"
+ MinimalRebuild="true"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="$libs"
+ AdditionalOptions="$lflags"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$rel_dir"
+ ConfigurationType="1"
+ CharacterSet="0"
+ WholeProgramOptimization="1"
+ IntermediateDirectory="\$(ProjectDir)\$(ConfigurationName)"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="$cflags_release"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="$includes"
+ PreprocessorDefinitions="WIN32,NDEBUG,$defines"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="$libs"
+ AdditionalOptions="$lflags"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+EOM
+ foreach(@sources) {
+ print F << "EOM";
+ <File
+ RelativePath="$_"/>
+EOM
+ }
+ print F << "EOM";
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
+EOM
+ close F;
+}
+
+sub createGlueProject {
+ my ($git_dir, $out_dir, $rel_dir, %build_structure) = @_;
+ print "Generate solutions file\n";
+ $rel_dir = "..\\$rel_dir";
+ $rel_dir =~ s/\//\\/g;
+ my $SLN_HEAD = "Microsoft Visual Studio Solution File, Format Version 10.00\n# Visual Studio 2008\n";
+ my $SLN_PRE = "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = ";
+ my $SLN_POST = "\nEndProject\n";
+
+ my @libs = @{$build_structure{"LIBS"}};
+ my @tmp;
+ foreach (@libs) {
+ $_ =~ s/\//_/g;
+ $_ =~ s/\.a//;
+ push(@tmp, $_);
+ }
+ @libs = @tmp;
+
+ my @apps = @{$build_structure{"APPS"}};
+ @tmp = ();
+ foreach (@apps) {
+ $_ =~ s/\//_/g;
+ $_ =~ s/\.exe//;
+ push(@tmp, $_);
+ }
+ @apps = @tmp;
+
+ open F, ">git.sln" || die "Could not open git.sln for writing!\n";
+ binmode F, ":crlf";
+ print F "$SLN_HEAD";
+ foreach (@libs) {
+ my $libname = $_;
+ my $uuid = $build_structure{"LIBS_${libname}_GUID"};
+ print F "$SLN_PRE";
+ print F "\"${libname}\", \"${libname}\\${libname}.vcproj\", \"${uuid}\"";
+ print F "$SLN_POST";
+ }
+ my $uuid_libgit = $build_structure{"LIBS_libgit_GUID"};
+ my $uuid_xdiff_lib = $build_structure{"LIBS_xdiff_lib_GUID"};
+ foreach (@apps) {
+ my $appname = $_;
+ my $uuid = $build_structure{"APPS_${appname}_GUID"};
+ print F "$SLN_PRE";
+ print F "\"${appname}\", \"${appname}\\${appname}.vcproj\", \"${uuid}\"\n";
+ print F " ProjectSection(ProjectDependencies) = postProject\n";
+ print F " ${uuid_libgit} = ${uuid_libgit}\n";
+ print F " ${uuid_xdiff_lib} = ${uuid_xdiff_lib}\n";
+ print F " EndProjectSection";
+ print F "$SLN_POST";
+ }
+
+ print F << "EOM";
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+EOM
+ print F << "EOM";
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+EOM
+ foreach (@libs) {
+ my $libname = $_;
+ my $uuid = $build_structure{"LIBS_${libname}_GUID"};
+ print F "\t\t${uuid}.Debug|Win32.ActiveCfg = Debug|Win32\n";
+ print F "\t\t${uuid}.Debug|Win32.Build.0 = Debug|Win32\n";
+ print F "\t\t${uuid}.Release|Win32.ActiveCfg = Release|Win32\n";
+ print F "\t\t${uuid}.Release|Win32.Build.0 = Release|Win32\n";
+ }
+ foreach (@apps) {
+ my $appname = $_;
+ my $uuid = $build_structure{"APPS_${appname}_GUID"};
+ print F "\t\t${uuid}.Debug|Win32.ActiveCfg = Debug|Win32\n";
+ print F "\t\t${uuid}.Debug|Win32.Build.0 = Debug|Win32\n";
+ print F "\t\t${uuid}.Release|Win32.ActiveCfg = Release|Win32\n";
+ print F "\t\t${uuid}.Release|Win32.Build.0 = Release|Win32\n";
+ }
+
+ print F << "EOM";
+ EndGlobalSection
+EndGlobal
+EOM
+ close F;
+}
+
+1;
diff --git a/contrib/buildsystems/engine.pl b/contrib/buildsystems/engine.pl
new file mode 100644
index 0000000000..20bd061b3e
--- /dev/null
+++ b/contrib/buildsystems/engine.pl
@@ -0,0 +1,353 @@
+#!/usr/bin/perl -w
+######################################################################
+# Do not call this script directly!
+#
+# The generate script ensures that @INC is correct before the engine
+# is executed.
+#
+# Copyright (C) 2009 Marius Storm-Olsen <mstormo@gmail.com>
+######################################################################
+use strict;
+use File::Basename;
+use File::Spec;
+use Cwd;
+use Generators;
+
+my (%build_structure, %compile_options, @makedry);
+my $out_dir = getcwd();
+my $git_dir = $out_dir;
+$git_dir =~ s=\\=/=g;
+$git_dir = dirname($git_dir) while (!-e "$git_dir/git.c" && "$git_dir" ne "");
+die "Couldn't find Git repo" if ("$git_dir" eq "");
+
+my @gens = Generators::available();
+my $gen = "Vcproj";
+
+sub showUsage
+{
+ my $genlist = join(', ', @gens);
+ print << "EOM";
+generate usage:
+ -g <GENERATOR> --gen <GENERATOR> Specify the buildsystem generator (default: $gen)
+ Available: $genlist
+ -o <PATH> --out <PATH> Specify output directory generation (default: .)
+ -i <FILE> --in <FILE> Specify input file, instead of running GNU Make
+ -h,-? --help This help
+EOM
+ exit 0;
+}
+
+# Parse command-line options
+while (@ARGV) {
+ my $arg = shift @ARGV;
+ if ("$arg" eq "-h" || "$arg" eq "--help" || "$arg" eq "-?") {
+ showUsage();
+ exit(0);
+ } elsif("$arg" eq "--out" || "$arg" eq "-o") {
+ $out_dir = shift @ARGV;
+ } elsif("$arg" eq "--gen" || "$arg" eq "-g") {
+ $gen = shift @ARGV;
+ } elsif("$arg" eq "--in" || "$arg" eq "-i") {
+ my $infile = shift @ARGV;
+ open(F, "<$infile") || die "Couldn't open file $infile";
+ @makedry = <F>;
+ close(F);
+ }
+}
+
+# NOT using File::Spec->rel2abs($path, $base) here, as
+# it fails badly for me in the msysgit environment
+$git_dir = File::Spec->rel2abs($git_dir);
+$out_dir = File::Spec->rel2abs($out_dir);
+my $rel_dir = makeOutRel2Git($git_dir, $out_dir);
+
+# Print some information so the user feels informed
+print << "EOM";
+-----
+Generator: $gen
+Git dir: $git_dir
+Out dir: $out_dir
+-----
+Running GNU Make to figure out build structure...
+EOM
+
+# Pipe a make --dry-run into a variable, if not already loaded from file
+@makedry = `cd $git_dir && make -n MSVC=1 V=1 2>/dev/null` if !@makedry;
+
+# Parse the make output into usable info
+parseMakeOutput();
+
+# Finally, ask the generator to start generating..
+Generators::generate($gen, $git_dir, $out_dir, $rel_dir, %build_structure);
+
+# main flow ends here
+# -------------------------------------------------------------------------------------------------
+
+
+# 1) path: /foo/bar/baz 2) path: /foo/bar/baz 3) path: /foo/bar/baz
+# base: /foo/bar/baz/temp base: /foo/bar base: /tmp
+# rel: .. rel: baz rel: ../foo/bar/baz
+sub makeOutRel2Git
+{
+ my ($path, $base) = @_;
+ my $rel;
+ if ("$path" eq "$base") {
+ return ".";
+ } elsif ($base =~ /^$path/) {
+ # case 1
+ my $tmp = $base;
+ $tmp =~ s/^$path//;
+ foreach (split('/', $tmp)) {
+ $rel .= "../" if ("$_" ne "");
+ }
+ } elsif ($path =~ /^$base/) {
+ # case 2
+ $rel = $path;
+ $rel =~ s/^$base//;
+ $rel = "./$rel";
+ } else {
+ my $tmp = $base;
+ foreach (split('/', $tmp)) {
+ $rel .= "../" if ("$_" ne "");
+ }
+ $rel .= $path;
+ }
+ $rel =~ s/\/\//\//g; # simplify
+ $rel =~ s/\/$//; # don't end with /
+ return $rel;
+}
+
+sub parseMakeOutput
+{
+ print "Parsing GNU Make output to figure out build structure...\n";
+ my $line = 0;
+ while (my $text = shift @makedry) {
+ my $ate_next;
+ do {
+ $ate_next = 0;
+ $line++;
+ chomp $text;
+ chop $text if ($text =~ /\r$/);
+ if ($text =~ /\\$/) {
+ $text =~ s/\\$//;
+ $text .= shift @makedry;
+ $ate_next = 1;
+ }
+ } while($ate_next);
+
+ if($text =~ / -c /) {
+ # compilation
+ handleCompileLine($text, $line);
+
+ } elsif ($text =~ / -o /) {
+ # linking executable
+ handleLinkLine($text, $line);
+
+ } elsif ($text =~ /\.o / && $text =~ /\.a /) {
+ # libifying
+ handleLibLine($text, $line);
+#
+# } elsif ($text =~ /^cp /) {
+# # copy file around
+#
+# } elsif ($text =~ /^rm -f /) {
+# # shell command
+#
+# } elsif ($text =~ /^make[ \[]/) {
+# # make output
+#
+# } elsif ($text =~ /^echo /) {
+# # echo to file
+#
+# } elsif ($text =~ /^if /) {
+# # shell conditional
+#
+# } elsif ($text =~ /^tclsh /) {
+# # translation stuff
+#
+# } elsif ($text =~ /^umask /) {
+# # handling boilerplates
+#
+# } elsif ($text =~ /\$\(\:\)/) {
+# # ignore
+#
+# } elsif ($text =~ /^FLAGS=/) {
+# # flags check for dependencies
+#
+# } elsif ($text =~ /^'\/usr\/bin\/perl' -MError -e/) {
+# # perl commands for copying files
+#
+# } elsif ($text =~ /generate-cmdlist\.sh/) {
+# # command for generating list of commands
+#
+# } elsif ($text =~ /^test / && $text =~ /|| rm -f /) {
+# # commands removing executables, if they exist
+#
+# } elsif ($text =~ /new locations or Tcl/) {
+# # command for detecting Tcl/Tk changes
+#
+# } elsif ($text =~ /mkdir -p/) {
+# # command creating path
+#
+# } elsif ($text =~ /: no custom templates yet/) {
+# # whatever
+#
+# } else {
+# print "Unhandled (line: $line): $text\n";
+ }
+ }
+
+# use Data::Dumper;
+# print "Parsed build structure:\n";
+# print Dumper(%build_structure);
+}
+
+# variables for the compilation part of each step
+my (@defines, @incpaths, @cflags, @sources);
+
+sub clearCompileStep
+{
+ @defines = ();
+ @incpaths = ();
+ @cflags = ();
+ @sources = ();
+}
+
+sub removeDuplicates
+{
+ my (%dupHash, $entry);
+ %dupHash = map { $_, 1 } @defines;
+ @defines = keys %dupHash;
+
+ %dupHash = map { $_, 1 } @incpaths;
+ @incpaths = keys %dupHash;
+
+ %dupHash = map { $_, 1 } @cflags;
+ @cflags = keys %dupHash;
+}
+
+sub handleCompileLine
+{
+ my ($line, $lineno) = @_;
+ my @parts = split(' ', $line);
+ my $sourcefile;
+ shift(@parts); # ignore cmd
+ while (my $part = shift @parts) {
+ if ("$part" eq "-o") {
+ # ignore object file
+ shift @parts;
+ } elsif ("$part" eq "-c") {
+ # ignore compile flag
+ } elsif ("$part" eq "-c") {
+ } elsif ($part =~ /^.?-I/) {
+ push(@incpaths, $part);
+ } elsif ($part =~ /^.?-D/) {
+ push(@defines, $part);
+ } elsif ($part =~ /^-/) {
+ push(@cflags, $part);
+ } elsif ($part =~ /\.(c|cc|cpp)$/) {
+ $sourcefile = $part;
+ } else {
+ die "Unhandled compiler option @ line $lineno: $part";
+ }
+ }
+ @{$compile_options{"${sourcefile}_CFLAGS"}} = @cflags;
+ @{$compile_options{"${sourcefile}_DEFINES"}} = @defines;
+ @{$compile_options{"${sourcefile}_INCPATHS"}} = @incpaths;
+ clearCompileStep();
+}
+
+sub handleLibLine
+{
+ my ($line, $lineno) = @_;
+ my (@objfiles, @lflags, $libout, $part);
+ # kill cmd and rm 'prefix'
+ $line =~ s/^rm -f .* && .* rcs //;
+ my @parts = split(' ', $line);
+ while ($part = shift @parts) {
+ if ($part =~ /^-/) {
+ push(@lflags, $part);
+ } elsif ($part =~ /\.(o|obj)$/) {
+ push(@objfiles, $part);
+ } elsif ($part =~ /\.(a|lib)$/) {
+ $libout = $part;
+ $libout =~ s/\.a$//;
+ } else {
+ die "Unhandled lib option @ line $lineno: $part";
+ }
+ }
+# print "LibOut: '$libout'\nLFlags: @lflags\nOfiles: @objfiles\n";
+# exit(1);
+ foreach (@objfiles) {
+ my $sourcefile = $_;
+ $sourcefile =~ s/\.o/.c/;
+ push(@sources, $sourcefile);
+ push(@cflags, @{$compile_options{"${sourcefile}_CFLAGS"}});
+ push(@defines, @{$compile_options{"${sourcefile}_DEFINES"}});
+ push(@incpaths, @{$compile_options{"${sourcefile}_INCPATHS"}});
+ }
+ removeDuplicates();
+
+ push(@{$build_structure{"LIBS"}}, $libout);
+ @{$build_structure{"LIBS_${libout}"}} = ("_DEFINES", "_INCLUDES", "_CFLAGS", "_SOURCES",
+ "_OBJECTS");
+ @{$build_structure{"LIBS_${libout}_DEFINES"}} = @defines;
+ @{$build_structure{"LIBS_${libout}_INCLUDES"}} = @incpaths;
+ @{$build_structure{"LIBS_${libout}_CFLAGS"}} = @cflags;
+ @{$build_structure{"LIBS_${libout}_LFLAGS"}} = @lflags;
+ @{$build_structure{"LIBS_${libout}_SOURCES"}} = @sources;
+ @{$build_structure{"LIBS_${libout}_OBJECTS"}} = @objfiles;
+ clearCompileStep();
+}
+
+sub handleLinkLine
+{
+ my ($line, $lineno) = @_;
+ my (@objfiles, @lflags, @libs, $appout, $part);
+ my @parts = split(' ', $line);
+ shift(@parts); # ignore cmd
+ while ($part = shift @parts) {
+ if ($part =~ /^-IGNORE/) {
+ push(@lflags, $part);
+ } elsif ($part =~ /^-[GRIMDO]/) {
+ # eat compiler flags
+ } elsif ("$part" eq "-o") {
+ $appout = shift @parts;
+ } elsif ("$part" eq "-lz") {
+ push(@libs, "zlib.lib");
+ } elsif ($part =~ /^-/) {
+ push(@lflags, $part);
+ } elsif ($part =~ /\.(a|lib)$/) {
+ $part =~ s/\.a$/.lib/;
+ push(@libs, $part);
+ } elsif ($part =~ /\.(o|obj)$/) {
+ push(@objfiles, $part);
+ } else {
+ die "Unhandled lib option @ line $lineno: $part";
+ }
+ }
+# print "AppOut: '$appout'\nLFlags: @lflags\nLibs : @libs\nOfiles: @objfiles\n";
+# exit(1);
+ foreach (@objfiles) {
+ my $sourcefile = $_;
+ $sourcefile =~ s/\.o/.c/;
+ push(@sources, $sourcefile);
+ push(@cflags, @{$compile_options{"${sourcefile}_CFLAGS"}});
+ push(@defines, @{$compile_options{"${sourcefile}_DEFINES"}});
+ push(@incpaths, @{$compile_options{"${sourcefile}_INCPATHS"}});
+ }
+ removeDuplicates();
+
+ removeDuplicates();
+ push(@{$build_structure{"APPS"}}, $appout);
+ @{$build_structure{"APPS_${appout}"}} = ("_DEFINES", "_INCLUDES", "_CFLAGS", "_LFLAGS",
+ "_SOURCES", "_OBJECTS", "_LIBS");
+ @{$build_structure{"APPS_${appout}_DEFINES"}} = @defines;
+ @{$build_structure{"APPS_${appout}_INCLUDES"}} = @incpaths;
+ @{$build_structure{"APPS_${appout}_CFLAGS"}} = @cflags;
+ @{$build_structure{"APPS_${appout}_LFLAGS"}} = @lflags;
+ @{$build_structure{"APPS_${appout}_SOURCES"}} = @sources;
+ @{$build_structure{"APPS_${appout}_OBJECTS"}} = @objfiles;
+ @{$build_structure{"APPS_${appout}_LIBS"}} = @libs;
+ clearCompileStep();
+}
diff --git a/contrib/buildsystems/generate b/contrib/buildsystems/generate
new file mode 100644
index 0000000000..bc10f25ff2
--- /dev/null
+++ b/contrib/buildsystems/generate
@@ -0,0 +1,29 @@
+#!/usr/bin/perl -w
+######################################################################
+# Generate buildsystem files
+#
+# This script generate buildsystem files based on the output of a
+# GNU Make --dry-run, enabling Windows users to develop Git with their
+# trusted IDE with native projects.
+#
+# Note:
+# It is not meant as *the* way of building Git with MSVC, but merely a
+# convenience. The correct way of building Git with MSVC is to use the
+# GNU Make tool to build with the maintained Makefile in the root of
+# the project. If you have the msysgit environment installed and
+# available in your current console, together with the Visual Studio
+# environment you wish to build for, all you have to do is run the
+# command:
+# make MSVC=1
+#
+# Copyright (C) 2009 Marius Storm-Olsen <mstormo@gmail.com>
+######################################################################
+use strict;
+use File::Basename;
+use Cwd;
+
+my $git_dir = getcwd();
+$git_dir =~ s=\\=/=g;
+$git_dir = dirname($git_dir) while (!-e "$git_dir/git.c" && "$git_dir" ne "");
+die "Couldn't find Git repo" if ("$git_dir" eq "");
+exec join(" ", ("PERL5LIB=${git_dir}/contrib/buildsystems ${git_dir}/contrib/buildsystems/engine.pl", @ARGV));
diff --git a/contrib/buildsystems/parse.pl b/contrib/buildsystems/parse.pl
new file mode 100644
index 0000000000..c9656ece99
--- /dev/null
+++ b/contrib/buildsystems/parse.pl
@@ -0,0 +1,228 @@
+#!/usr/bin/perl -w
+######################################################################
+# Do not call this script directly!
+#
+# The generate script ensures that @INC is correct before the engine
+# is executed.
+#
+# Copyright (C) 2009 Marius Storm-Olsen <mstormo@gmail.com>
+######################################################################
+use strict;
+use File::Basename;
+use Cwd;
+
+my $file = $ARGV[0];
+die "No file provided!" if !defined $file;
+
+my ($cflags, $target, $type, $line);
+
+open(F, "<$file") || die "Couldn't open file $file";
+my @data = <F>;
+close(F);
+
+while (my $text = shift @data) {
+ my $ate_next;
+ do {
+ $ate_next = 0;
+ $line++;
+ chomp $text;
+ chop $text if ($text =~ /\r$/);
+ if ($text =~ /\\$/) {
+ $text =~ s/\\$//;
+ $text .= shift @data;
+ $ate_next = 1;
+ }
+ } while($ate_next);
+
+ if($text =~ / -c /) {
+ # compilation
+ handleCompileLine($text, $line);
+
+ } elsif ($text =~ / -o /) {
+ # linking executable
+ handleLinkLine($text, $line);
+
+ } elsif ($text =~ /\.o / && $text =~ /\.a /) {
+ # libifying
+ handleLibLine($text, $line);
+
+# } elsif ($text =~ /^cp /) {
+# # copy file around
+#
+# } elsif ($text =~ /^rm -f /) {
+# # shell command
+#
+# } elsif ($text =~ /^make[ \[]/) {
+# # make output
+#
+# } elsif ($text =~ /^echo /) {
+# # echo to file
+#
+# } elsif ($text =~ /^if /) {
+# # shell conditional
+#
+# } elsif ($text =~ /^tclsh /) {
+# # translation stuff
+#
+# } elsif ($text =~ /^umask /) {
+# # handling boilerplates
+#
+# } elsif ($text =~ /\$\(\:\)/) {
+# # ignore
+#
+# } elsif ($text =~ /^FLAGS=/) {
+# # flags check for dependencies
+#
+# } elsif ($text =~ /^'\/usr\/bin\/perl' -MError -e/) {
+# # perl commands for copying files
+#
+# } elsif ($text =~ /generate-cmdlist\.sh/) {
+# # command for generating list of commands
+#
+# } elsif ($text =~ /^test / && $text =~ /|| rm -f /) {
+# # commands removing executables, if they exist
+#
+# } elsif ($text =~ /new locations or Tcl/) {
+# # command for detecting Tcl/Tk changes
+#
+# } elsif ($text =~ /mkdir -p/) {
+# # command creating path
+#
+# } elsif ($text =~ /: no custom templates yet/) {
+# # whatever
+
+ } else {
+# print "Unhandled (line: $line): $text\n";
+ }
+}
+close(F);
+
+# use Data::Dumper;
+# print "Parsed build structure:\n";
+# print Dumper(%build_structure);
+
+# -------------------------------------------------------------------
+# Functions under here
+# -------------------------------------------------------------------
+my (%build_structure, @defines, @incpaths, @cflags, @sources);
+
+sub clearCompileStep
+{
+ @defines = ();
+ @incpaths = ();
+ @cflags = ();
+ @sources = ();
+}
+
+sub removeDuplicates
+{
+ my (%dupHash, $entry);
+ %dupHash = map { $_, 1 } @defines;
+ @defines = keys %dupHash;
+
+ %dupHash = map { $_, 1 } @incpaths;
+ @incpaths = keys %dupHash;
+
+ %dupHash = map { $_, 1 } @cflags;
+ @cflags = keys %dupHash;
+
+ %dupHash = map { $_, 1 } @sources;
+ @sources = keys %dupHash;
+}
+
+sub handleCompileLine
+{
+ my ($line, $lineno) = @_;
+ my @parts = split(' ', $line);
+ shift(@parts); # ignore cmd
+ while (my $part = shift @parts) {
+ if ("$part" eq "-o") {
+ # ignore object file
+ shift @parts;
+ } elsif ("$part" eq "-c") {
+ # ignore compile flag
+ } elsif ("$part" eq "-c") {
+ } elsif ($part =~ /^.?-I/) {
+ push(@incpaths, $part);
+ } elsif ($part =~ /^.?-D/) {
+ push(@defines, $part);
+ } elsif ($part =~ /^-/) {
+ push(@cflags, $part);
+ } elsif ($part =~ /\.(c|cc|cpp)$/) {
+ push(@sources, $part);
+ } else {
+ die "Unhandled compiler option @ line $lineno: $part";
+ }
+ }
+ #print "Sources: @sources\nCFlags: @cflags\nDefine: @defines\nIncpat: @incpaths\n";
+ #exit(1);
+}
+
+sub handleLibLine
+{
+ my ($line, $lineno) = @_;
+ my (@objfiles, @lflags, $libout, $part);
+ # kill cmd and rm 'prefix'
+ $line =~ s/^rm -f .* && .* rcs //;
+ my @parts = split(' ', $line);
+ while ($part = shift @parts) {
+ if ($part =~ /^-/) {
+ push(@lflags, $part);
+ } elsif ($part =~ /\.(o|obj)$/) {
+ push(@objfiles, $part);
+ } elsif ($part =~ /\.(a|lib)$/) {
+ $libout = $part;
+ } else {
+ die "Unhandled lib option @ line $lineno: $part";
+ }
+ }
+ #print "LibOut: '$libout'\nLFlags: @lflags\nOfiles: @objfiles\n";
+ #exit(1);
+ removeDuplicates();
+ push(@{$build_structure{"LIBS"}}, $libout);
+ @{$build_structure{"LIBS_${libout}"}} = ("_DEFINES", "_INCLUDES", "_CFLAGS", "_SOURCES",
+ "_OBJECTS");
+ @{$build_structure{"LIBS_${libout}_DEFINES"}} = @defines;
+ @{$build_structure{"LIBS_${libout}_INCLUDES"}} = @incpaths;
+ @{$build_structure{"LIBS_${libout}_CFLAGS"}} = @cflags;
+ @{$build_structure{"LIBS_${libout}_SOURCES"}} = @sources;
+ @{$build_structure{"LIBS_${libout}_OBJECTS"}} = @objfiles;
+ clearCompileStep();
+}
+
+sub handleLinkLine
+{
+ my ($line, $lineno) = @_;
+ my (@objfiles, @lflags, @libs, $appout, $part);
+ my @parts = split(' ', $line);
+ shift(@parts); # ignore cmd
+ while ($part = shift @parts) {
+ if ($part =~ /^-[GRIDO]/) {
+ # eat compiler flags
+ } elsif ("$part" eq "-o") {
+ $appout = shift @parts;
+ } elsif ($part =~ /^-/) {
+ push(@lflags, $part);
+ } elsif ($part =~ /\.(a|lib)$/) {
+ push(@libs, $part);
+ } elsif ($part =~ /\.(o|obj)$/) {
+ push(@objfiles, $part);
+ } else {
+ die "Unhandled lib option @ line $lineno: $part";
+ }
+ }
+ #print "AppOut: '$appout'\nLFlags: @lflags\nLibs : @libs\nOfiles: @objfiles\n";
+ #exit(1);
+ removeDuplicates();
+ push(@{$build_structure{"APPS"}}, $appout);
+ @{$build_structure{"APPS_${appout}"}} = ("_DEFINES", "_INCLUDES", "_CFLAGS", "_LFLAGS",
+ "_SOURCES", "_OBJECTS", "_LIBS");
+ @{$build_structure{"APPS_${appout}_DEFINES"}} = @defines;
+ @{$build_structure{"APPS_${appout}_INCLUDES"}} = @incpaths;
+ @{$build_structure{"APPS_${appout}_CFLAGS"}} = @cflags;
+ @{$build_structure{"APPS_${appout}_LFLAGS"}} = @lflags;
+ @{$build_structure{"APPS_${appout}_SOURCES"}} = @sources;
+ @{$build_structure{"APPS_${appout}_OBJECTS"}} = @objfiles;
+ @{$build_structure{"APPS_${appout}_LIBS"}} = @libs;
+ clearCompileStep();
+}
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 745b5fb78b..4cb89a1256 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -148,11 +148,9 @@ __git_ps1 ()
elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then
if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then
if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then
- git diff --no-ext-diff --ignore-submodules \
- --quiet --exit-code || w="*"
+ git diff --no-ext-diff --quiet --exit-code || w="*"
if git rev-parse --quiet --verify HEAD >/dev/null; then
- git diff-index --cached --quiet \
- --ignore-submodules HEAD -- || i="+"
+ git diff-index --cached --quiet HEAD -- || i="+"
else
i="#"
fi
@@ -318,13 +316,9 @@ __git_remotes ()
echo ${i#$d/remotes/}
done
[ "$ngoff" ] && shopt -u nullglob
- for i in $(git --git-dir="$d" config --list); do
- case "$i" in
- remote.*.url=*)
- i="${i#remote.}"
- echo "${i/.url=*/}"
- ;;
- esac
+ for i in $(git --git-dir="$d" config --get-regexp 'remote\..*\.url' 2>/dev/null); do
+ i="${i#remote.}"
+ echo "${i/.url*/}"
done
}
@@ -500,7 +494,7 @@ __git_all_commands ()
return
fi
local i IFS=" "$'\n'
- for i in $(git help -a|egrep '^ ')
+ for i in $(git help -a|egrep '^ [a-zA-Z0-9]')
do
case $i in
*--*) : helper pattern;;
@@ -605,11 +599,11 @@ __git_porcelain_commandlist="$(__git_porcelain_commands 2>/dev/null)"
__git_aliases ()
{
local i IFS=$'\n'
- for i in $(git --git-dir="$(__gitdir)" config --list); do
+ for i in $(git --git-dir="$(__gitdir)" config --get-regexp "alias\..*" 2>/dev/null); do
case "$i" in
alias.*)
i="${i#alias.}"
- echo "${i/=*/}"
+ echo "${i/ */}"
;;
esac
done
@@ -628,8 +622,8 @@ __git_aliased_command ()
done
}
-# __git_find_subcommand requires 1 argument
-__git_find_subcommand ()
+# __git_find_on_cmdline requires 1 argument
+__git_find_on_cmdline ()
{
local word subcommand c=1
@@ -674,8 +668,9 @@ _git_am ()
--*)
__gitcomp "
--3way --committer-date-is-author-date --ignore-date
+ --ignore-whitespace --ignore-space-change
--interactive --keep --no-utf8 --signoff --utf8
- --whitespace=
+ --whitespace= --scissors
"
return
esac
@@ -695,6 +690,7 @@ _git_apply ()
--stat --numstat --summary --check --index
--cached --index-info --reverse --reject --unidiff-zero
--apply --no-add --exclude=
+ --ignore-whitespace --ignore-space-change
--whitespace= --inaccurate-eof --verbose
"
return
@@ -746,7 +742,7 @@ _git_bisect ()
__git_has_doubledash && return
local subcommands="start bad good skip reset visualize replay log run"
- local subcommand="$(__git_find_subcommand "$subcommands")"
+ local subcommand="$(__git_find_on_cmdline "$subcommands")"
if [ -z "$subcommand" ]; then
__gitcomp "$subcommands"
return
@@ -816,7 +812,21 @@ _git_checkout ()
{
__git_has_doubledash && return
- __gitcomp "$(__git_refs)"
+ local cur="${COMP_WORDS[COMP_CWORD]}"
+ case "$cur" in
+ --conflict=*)
+ __gitcomp "diff3 merge" "" "${cur##--conflict=}"
+ ;;
+ --*)
+ __gitcomp "
+ --quiet --ours --theirs --track --no-track --merge
+ --conflict= --patch
+ "
+ ;;
+ *)
+ __gitcomp "$(__git_refs)"
+ ;;
+ esac
}
_git_cherry ()
@@ -886,6 +896,7 @@ _git_commit ()
__gitcomp "
--all --author= --signoff --verify --no-verify
--edit --amend --include --only --interactive
+ --dry-run
"
return
esac
@@ -918,6 +929,8 @@ __git_diff_common_options="--stat --numstat --shortstat --summary
--inter-hunk-context=
--patience
--raw
+ --dirstat --dirstat= --dirstat-by-file
+ --dirstat-by-file= --cumulative
"
_git_diff ()
@@ -1047,6 +1060,7 @@ _git_grep ()
--extended-regexp --basic-regexp --fixed-strings
--files-with-matches --name-only
--files-without-match
+ --max-depth
--count
--and --or --not --all-match
"
@@ -1170,6 +1184,10 @@ _git_log ()
__gitcomp "$__git_log_date_formats" "" "${cur##--date=}"
return
;;
+ --decorate=*)
+ __gitcomp "long short" "" "${cur##--decorate=}"
+ return
+ ;;
--*)
__gitcomp "
$__git_log_common_options
@@ -1182,7 +1200,7 @@ _git_log ()
--pretty= --format= --oneline
--cherry-pick
--graph
- --decorate
+ --decorate --decorate=
--walk-reflogs
--parents --children
$merge
@@ -1529,13 +1547,14 @@ _git_config ()
url.*.*)
local pfx="${cur%.*}."
cur="${cur##*.}"
- __gitcomp "insteadof" "$pfx" "$cur"
+ __gitcomp "insteadOf pushInsteadOf" "$pfx" "$cur"
return
;;
esac
__gitcomp "
add.ignore-errors
alias.
+ apply.ignorewhitespace
apply.whitespace
branch.autosetupmerge
branch.autosetuprebase
@@ -1753,7 +1772,7 @@ _git_config ()
_git_remote ()
{
local subcommands="add rename rm show prune update set-head"
- local subcommand="$(__git_find_subcommand "$subcommands")"
+ local subcommand="$(__git_find_on_cmdline "$subcommands")"
if [ -z "$subcommand" ]; then
__gitcomp "$subcommands"
return
@@ -1765,13 +1784,9 @@ _git_remote ()
;;
update)
local i c='' IFS=$'\n'
- for i in $(git --git-dir="$(__gitdir)" config --list); do
- case "$i" in
- remotes.*)
- i="${i#remotes.}"
- c="$c ${i/=*/}"
- ;;
- esac
+ for i in $(git --git-dir="$(__gitdir)" config --get-regexp "remotes\..*" 2>/dev/null); do
+ i="${i#remotes.}"
+ c="$c ${i/ */}"
done
__gitcomp "$c"
;;
@@ -1781,6 +1796,11 @@ _git_remote ()
esac
}
+_git_replace ()
+{
+ __gitcomp "$(__git_refs)"
+}
+
_git_reset ()
{
__git_has_doubledash && return
@@ -1788,7 +1808,7 @@ _git_reset ()
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
- __gitcomp "--merge --mixed --hard --soft"
+ __gitcomp "--merge --mixed --hard --soft --patch"
return
;;
esac
@@ -1884,18 +1904,30 @@ _git_show_branch ()
_git_stash ()
{
+ local cur="${COMP_WORDS[COMP_CWORD]}"
+ local save_opts='--keep-index --no-keep-index --quiet --patch'
local subcommands='save list show apply clear drop pop create branch'
- local subcommand="$(__git_find_subcommand "$subcommands")"
+ local subcommand="$(__git_find_on_cmdline "$subcommands")"
if [ -z "$subcommand" ]; then
- __gitcomp "$subcommands"
+ case "$cur" in
+ --*)
+ __gitcomp "$save_opts"
+ ;;
+ *)
+ if [ -z "$(__git_find_on_cmdline "$save_opts")" ]; then
+ __gitcomp "$subcommands"
+ else
+ COMPREPLY=()
+ fi
+ ;;
+ esac
else
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$subcommand,$cur" in
save,--*)
- __gitcomp "--keep-index"
+ __gitcomp "$save_opts"
;;
apply,--*|pop,--*)
- __gitcomp "--index"
+ __gitcomp "--index --quiet"
;;
show,--*|drop,--*|branch,--*)
COMPREPLY=()
@@ -1916,7 +1948,7 @@ _git_submodule ()
__git_has_doubledash && return
local subcommands="add status init update summary foreach sync"
- if [ -z "$(__git_find_subcommand "$subcommands")" ]; then
+ if [ -z "$(__git_find_on_cmdline "$subcommands")" ]; then
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
@@ -1938,7 +1970,7 @@ _git_svn ()
proplist show-ignore show-externals branch tag blame
migrate
"
- local subcommand="$(__git_find_subcommand "$subcommands")"
+ local subcommand="$(__git_find_on_cmdline "$subcommands")"
if [ -z "$subcommand" ]; then
__gitcomp "$subcommands"
else
@@ -2137,6 +2169,7 @@ _git ()
push) _git_push ;;
rebase) _git_rebase ;;
remote) _git_remote ;;
+ replace) _git_replace ;;
reset) _git_reset ;;
revert) _git_revert ;;
rm) _git_rm ;;
diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el
index eace9c18eb..214930a021 100644
--- a/contrib/emacs/git.el
+++ b/contrib/emacs/git.el
@@ -429,16 +429,19 @@ Each entry is a cons of (SHORT-NAME . FULL-NAME)."
(git-get-string-sha1
(git-call-process-string-display-error "write-tree"))))
-(defun git-commit-tree (buffer tree head)
- "Call git-commit-tree with buffer as input and return the resulting commit SHA1."
+(defun git-commit-tree (buffer tree parent)
+ "Create a commit and possibly update HEAD.
+Create a commit with the message in BUFFER using the tree with hash TREE.
+Use PARENT as the parent of the new commit. If PARENT is the current \"HEAD\",
+update the \"HEAD\" reference to the new commit."
(let ((author-name (git-get-committer-name))
(author-email (git-get-committer-email))
(subject "commit (initial): ")
author-date log-start log-end args coding-system-for-write)
- (when head
+ (when parent
(setq subject "commit: ")
(push "-p" args)
- (push head args))
+ (push parent args))
(with-current-buffer buffer
(goto-char (point-min))
(if
@@ -474,7 +477,7 @@ Each entry is a cons of (SHORT-NAME . FULL-NAME)."
(apply #'git-run-command-region
buffer log-start log-end env
"commit-tree" tree (nreverse args))))))
- (when commit (git-update-ref "HEAD" commit head subject))
+ (when commit (git-update-ref "HEAD" commit parent subject))
commit)))
(defun git-empty-db-p ()
@@ -1043,7 +1046,7 @@ The FILES list must be sorted."
(defun git-add-file ()
"Add marked file(s) to the index cache."
(interactive)
- (let ((files (git-get-filenames (git-marked-files-state 'unknown 'ignored))))
+ (let ((files (git-get-filenames (git-marked-files-state 'unknown 'ignored 'unmerged))))
;; FIXME: add support for directories
(unless files
(push (file-relative-name (read-file-name "File to add: " nil nil t)) files))
@@ -1116,15 +1119,6 @@ The FILES list must be sorted."
(when buffer (with-current-buffer buffer (revert-buffer t t t)))))
(git-success-message "Reverted" names))))))
-(defun git-resolve-file ()
- "Resolve conflicts in marked file(s)."
- (interactive)
- (let ((files (git-get-filenames (git-marked-files-state 'unmerged))))
- (when files
- (when (apply 'git-call-process-display-error "update-index" "--" files)
- (git-update-status-files files)
- (git-success-message "Resolved" files)))))
-
(defun git-remove-handled ()
"Remove handled files from the status list."
(interactive)
@@ -1553,7 +1547,6 @@ amended version of it."
(define-key map "P" 'git-prev-unmerged-file)
(define-key map "q" 'git-status-quit)
(define-key map "r" 'git-remove-file)
- (define-key map "R" 'git-resolve-file)
(define-key map "t" toggle-map)
(define-key map "T" 'git-toggle-all-marks)
(define-key map "u" 'git-unmark-file)
@@ -1595,7 +1588,6 @@ amended version of it."
("Merge"
["Next Unmerged File" git-next-unmerged-file t]
["Prev Unmerged File" git-prev-unmerged-file t]
- ["Mark as Resolved" git-resolve-file t]
["Interactive Merge File" git-find-file-imerge t]
["Diff Against Common Base File" git-diff-file-base t]
["Diff Combined" git-diff-file-combined t]
diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
index 342529db30..e710219ca5 100755
--- a/contrib/fast-import/git-p4
+++ b/contrib/fast-import/git-p4
@@ -8,12 +8,10 @@
# License: MIT <http://www.opensource.org/licenses/mit-license.php>
#
-import optparse, sys, os, marshal, popen2, subprocess, shelve
-import tempfile, getopt, sha, os.path, time, platform
+import optparse, sys, os, marshal, subprocess, shelve
+import tempfile, getopt, os.path, time, platform
import re
-from sets import Set;
-
verbose = False
@@ -201,7 +199,7 @@ def isModeExec(mode):
def isModeExecChanged(src_mode, dst_mode):
return isModeExec(src_mode) != isModeExec(dst_mode)
-def p4CmdList(cmd, stdin=None, stdin_mode='w+b'):
+def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None):
cmd = p4_build_cmd("-G %s" % (cmd))
if verbose:
sys.stderr.write("Opening pipe: %s\n" % cmd)
@@ -224,7 +222,10 @@ def p4CmdList(cmd, stdin=None, stdin_mode='w+b'):
try:
while True:
entry = marshal.load(p4.stdout)
- result.append(entry)
+ if cb is not None:
+ cb(entry)
+ else:
+ result.append(entry)
except EOFError:
pass
exitCode = p4.wait()
@@ -861,8 +862,8 @@ class P4Sync(Command):
self.usage += " //depot/path[@revRange]"
self.silent = False
- self.createdBranches = Set()
- self.committedChanges = Set()
+ self.createdBranches = set()
+ self.committedChanges = set()
self.branch = ""
self.detectBranches = False
self.detectLabels = False
@@ -950,10 +951,84 @@ class P4Sync(Command):
return branches
- ## Should move this out, doesn't use SELF.
- def readP4Files(self, files):
+ # output one file from the P4 stream
+ # - helper for streamP4Files
+
+ def streamOneP4File(self, file, contents):
+ if file["type"] == "apple":
+ print "\nfile %s is a strange apple file that forks. Ignoring" % \
+ file['depotFile']
+ return
+
+ relPath = self.stripRepoPath(file['depotFile'], self.branchPrefixes)
+ if verbose:
+ sys.stderr.write("%s\n" % relPath)
+
+ mode = "644"
+ if isP4Exec(file["type"]):
+ mode = "755"
+ elif file["type"] == "symlink":
+ mode = "120000"
+ # p4 print on a symlink contains "target\n", so strip it off
+ last = contents.pop()
+ last = last[:-1]
+ contents.append(last)
+
+ if self.isWindows and file["type"].endswith("text"):
+ mangled = []
+ for data in contents:
+ data = data.replace("\r\n", "\n")
+ mangled.append(data)
+ contents = mangled
+
+ if file['type'] in ('text+ko', 'unicode+ko', 'binary+ko'):
+ contents = map(lambda text: re.sub(r'(?i)\$(Id|Header):[^$]*\$',r'$\1$', text), contents)
+ elif file['type'] in ('text+k', 'ktext', 'kxtext', 'unicode+k', 'binary+k'):
+ contents = map(lambda text: re.sub(r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$\n]*\$',r'$\1$', text), contents)
+
+ self.gitStream.write("M %s inline %s\n" % (mode, relPath))
+
+ # total length...
+ length = 0
+ for d in contents:
+ length = length + len(d)
+
+ self.gitStream.write("data %d\n" % length)
+ for d in contents:
+ self.gitStream.write(d)
+ self.gitStream.write("\n")
+
+ def streamOneP4Deletion(self, file):
+ relPath = self.stripRepoPath(file['path'], self.branchPrefixes)
+ if verbose:
+ sys.stderr.write("delete %s\n" % relPath)
+ self.gitStream.write("D %s\n" % relPath)
+
+ # handle another chunk of streaming data
+ def streamP4FilesCb(self, marshalled):
+
+ if marshalled.has_key('depotFile') and self.stream_have_file_info:
+ # start of a new file - output the old one first
+ self.streamOneP4File(self.stream_file, self.stream_contents)
+ self.stream_file = {}
+ self.stream_contents = []
+ self.stream_have_file_info = False
+
+ # pick up the new file information... for the
+ # 'data' field we need to append to our array
+ for k in marshalled.keys():
+ if k == 'data':
+ self.stream_contents.append(marshalled['data'])
+ else:
+ self.stream_file[k] = marshalled[k]
+
+ self.stream_have_file_info = True
+
+ # Stream directly from "p4 files" into "git fast-import"
+ def streamP4Files(self, files):
filesForCommit = []
filesToRead = []
+ filesToDelete = []
for f in files:
includeFile = True
@@ -967,50 +1042,35 @@ class P4Sync(Command):
filesForCommit.append(f)
if f['action'] not in ('delete', 'purge'):
filesToRead.append(f)
+ else:
+ filesToDelete.append(f)
- filedata = []
- if len(filesToRead) > 0:
- filedata = p4CmdList('-x - print',
- stdin='\n'.join(['%s#%s' % (f['path'], f['rev'])
- for f in filesToRead]),
- stdin_mode='w+')
-
- if "p4ExitCode" in filedata[0]:
- die("Problems executing p4. Error: [%d]."
- % (filedata[0]['p4ExitCode']));
-
- j = 0;
- contents = {}
- while j < len(filedata):
- stat = filedata[j]
- j += 1
- text = ''
- while j < len(filedata) and filedata[j]['code'] in ('text', 'unicode', 'binary'):
- text += filedata[j]['data']
- del filedata[j]['data']
- j += 1
-
- if not stat.has_key('depotFile'):
- sys.stderr.write("p4 print fails with: %s\n" % repr(stat))
- continue
+ # deleted files...
+ for f in filesToDelete:
+ self.streamOneP4Deletion(f)
- if stat['type'] in ('text+ko', 'unicode+ko', 'binary+ko'):
- text = re.sub(r'(?i)\$(Id|Header):[^$]*\$',r'$\1$', text)
- elif stat['type'] in ('text+k', 'ktext', 'kxtext', 'unicode+k', 'binary+k'):
- text = re.sub(r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$\n]*\$',r'$\1$', text)
+ if len(filesToRead) > 0:
+ self.stream_file = {}
+ self.stream_contents = []
+ self.stream_have_file_info = False
- contents[stat['depotFile']] = text
+ # curry self argument
+ def streamP4FilesCbSelf(entry):
+ self.streamP4FilesCb(entry)
- for f in filesForCommit:
- path = f['path']
- if contents.has_key(path):
- f['data'] = contents[path]
+ p4CmdList("-x - print",
+ '\n'.join(['%s#%s' % (f['path'], f['rev'])
+ for f in filesToRead]),
+ cb=streamP4FilesCbSelf)
- return filesForCommit
+ # do the last chunk
+ if self.stream_file.has_key('depotFile'):
+ self.streamOneP4File(self.stream_file, self.stream_contents)
def commit(self, details, files, branch, branchPrefixes, parent = ""):
epoch = details["time"]
author = details["user"]
+ self.branchPrefixes = branchPrefixes
if self.verbose:
print "commit into %s" % branch
@@ -1023,7 +1083,6 @@ class P4Sync(Command):
new_files.append (f)
else:
sys.stderr.write("Ignoring file outside of prefix: %s\n" % path)
- files = self.readP4Files(new_files)
self.gitStream.write("commit %s\n" % branch)
# gitStream.write("mark :%s\n" % details["change"])
@@ -1051,33 +1110,7 @@ class P4Sync(Command):
print "parent %s" % parent
self.gitStream.write("from %s\n" % parent)
- for file in files:
- if file["type"] == "apple":
- print "\nfile %s is a strange apple file that forks. Ignoring!" % file['path']
- continue
-
- relPath = self.stripRepoPath(file['path'], branchPrefixes)
- if file["action"] in ("delete", "purge"):
- self.gitStream.write("D %s\n" % relPath)
- else:
- data = file['data']
-
- mode = "644"
- if isP4Exec(file["type"]):
- mode = "755"
- elif file["type"] == "symlink":
- mode = "120000"
- # p4 print on a symlink contains "target\n", so strip it off
- data = data[:-1]
-
- if self.isWindows and file["type"].endswith("text"):
- data = data.replace("\r\n", "\n")
-
- self.gitStream.write("M %s inline %s\n" % (mode, relPath))
- self.gitStream.write("data %s\n" % len(data))
- self.gitStream.write(data)
- self.gitStream.write("\n")
-
+ self.streamP4Files(new_files)
self.gitStream.write("\n")
change = int(details["change"])
@@ -1627,7 +1660,7 @@ class P4Sync(Command):
if len(self.changesFile) > 0:
output = open(self.changesFile).readlines()
- changeSet = Set()
+ changeSet = set()
for line in output:
changeSet.add(int(line))
diff --git a/contrib/fast-import/import-directories.perl b/contrib/fast-import/import-directories.perl
new file mode 100755
index 0000000000..5782d80e26
--- /dev/null
+++ b/contrib/fast-import/import-directories.perl
@@ -0,0 +1,416 @@
+#!/usr/bin/perl -w
+#
+# Copyright 2008-2009 Peter Krefting <peter@softwolves.pp.se>
+#
+# ------------------------------------------------------------------------
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+# ------------------------------------------------------------------------
+
+=pod
+
+=head1 NAME
+
+import-directories - Import bits and pieces to Git.
+
+=head1 SYNOPSIS
+
+B<import-directories.perl> F<configfile> F<outputfile>
+
+=head1 DESCRIPTION
+
+Script to import arbitrary projects version controlled by the "copy the
+source directory to a new location and edit it there"-version controlled
+projects into version control. Handles projects with arbitrary branching
+and version trees, taking a file describing the inputs and generating a
+file compatible with the L<git-fast-import(1)> format.
+
+=head1 CONFIGURATION FILE
+
+=head2 Format
+
+The configuration file is based on the standard I<.ini> format.
+
+ ; Comments start with semi-colons
+ [section]
+ key=value
+
+Please see below for information on how to escape special characters.
+
+=head2 Global configuration
+
+Global configuration is done in the B<[config]> section, which should be
+the first section in the file. Configuration can be changed by
+repeating configuration sections later on.
+
+ [config]
+ ; configure conversion of CRLFs. "convert" means that all CRLFs
+ ; should be converted into LFs (suitable for the core.autocrlf
+ ; setting set to true in Git). "none" means that all data is
+ ; treated as binary.
+ crlf=convert
+
+=head2 Revision configuration
+
+Each revision that is to be imported is described in three
+sections. Revisions should be defined in topological order, so
+that a revision's parent has always been defined when a new revision
+is introduced. All the sections for one revision must be defined
+before defining the next revision.
+
+Each revision is assigned a unique numerical identifier. The
+numbers do not need to be consecutive, nor monotonically
+increasing.
+
+For instance, if your configuration file contains only the two
+revisions 4711 and 42, where 4711 is the initial commit, the
+only requirement is that 4711 is completely defined before 42.
+
+=pod
+
+=head3 Revision description section
+
+A section whose section name is just an integer gives meta-data
+about the revision.
+
+ [3]
+ ; author sets the author of the revisions
+ author=Peter Krefting <peter@softwolves.pp.se>
+ ; branch sets the branch that the revision should be committed to
+ branch=master
+ ; parent describes the revision that is the parent of this commit
+ ; (optional)
+ parent=1
+ ; merges describes a revision that is merged into this commit
+ ; (optional; can be repeated)
+ merges=2
+ ; selects one file to take the timestamp from
+ ; (optional; if unspecified, the most recent file from the .files
+ ; section is used)
+ timestamp=3/source.c
+
+=head3 Revision contents section
+
+A section whose section name is an integer followed by B<.files>
+describe all the files included in this revision. If a file that
+was available previously is not included in this revision, it will
+be removed.
+
+If an on-disk revision is incomplete, you can point to files from
+a previous revision. There are no restriction as to where the source
+files are located, nor to the names of them.
+
+ [3.files]
+ ; the key is the path inside the repository, the value is the path
+ ; as seen from the importer script.
+ source.c=ver-3.00/source.c
+ source.h=ver-2.99/source.h
+ readme.txt=ver-3.00/introduction to the project.txt
+
+File names are treated as byte strings (but please see below on
+quoting rules), and should be stored in the configuration file in
+the encoding that should be used in the generated repository.
+
+=head3 Revision commit message section
+
+A section whose section name is an integer followed by B<.message>
+gives the commit message. This section is read verbatim, up until
+the beginning of the next section. As such, a commit message may not
+contain a line that begins with an opening square bracket ("[") and
+ends with a closing square bracket ("]"), unless they are surrounded
+by whitespace or other characters.
+
+ [3.message]
+ Implement foobar.
+ ; trailing blank lines are ignored.
+
+=cut
+
+# Globals
+use strict;
+use integer;
+my $crlfmode = 0;
+my @revs;
+my (%revmap, %message, %files, %author, %branch, %parent, %merges, %time, %timesource);
+my $sectiontype = 0;
+my $rev = 0;
+my $mark = 1;
+
+# Check command line
+if ($#ARGV < 1 || $ARGV[0] =~ /^--?h/)
+{
+ exec('perldoc', $0);
+ exit 1;
+}
+
+# Open configuration
+my $config = $ARGV[0];
+open CFG, '<', $config or die "Cannot open configuration file \"$config\": ";
+
+# Open output
+my $output = $ARGV[1];
+open OUT, '>', $output or die "Cannot create output file \"$output\": ";
+binmode OUT;
+
+LINE: while (my $line = <CFG>)
+{
+ $line =~ s/\r?\n$//;
+ next LINE if $sectiontype != 4 && $line eq '';
+ next LINE if $line =~ /^;/;
+ my $oldsectiontype = $sectiontype;
+ my $oldrev = $rev;
+
+ # Sections
+ if ($line =~ m"^\[(config|(\d+)(|\.files|\.message))\]$")
+ {
+ if ($1 eq 'config')
+ {
+ $sectiontype = 1;
+ }
+ elsif ($3 eq '')
+ {
+ $sectiontype = 2;
+ $rev = $2;
+ # Create a new revision
+ die "Duplicate rev: $line\n " if defined $revmap{$rev};
+ print "Reading revision $rev\n";
+ push @revs, $rev;
+ $revmap{$rev} = $mark ++;
+ $time{$revmap{$rev}} = 0;
+ }
+ elsif ($3 eq '.files')
+ {
+ $sectiontype = 3;
+ $rev = $2;
+ die "Revision mismatch: $line\n " unless $rev == $oldrev;
+ }
+ elsif ($3 eq '.message')
+ {
+ $sectiontype = 4;
+ $rev = $2;
+ die "Revision mismatch: $line\n " unless $rev == $oldrev;
+ }
+ else
+ {
+ die "Internal parse error: $line\n ";
+ }
+ next LINE;
+ }
+
+ # Parse data
+ if ($sectiontype != 4)
+ {
+ # Key and value
+ if ($line =~ m"^\s*([^\s].*=.*[^\s])\s*$")
+ {
+ my ($key, $value) = &parsekeyvaluepair($1);
+ # Global configuration
+ if (1 == $sectiontype)
+ {
+ if ($key eq 'crlf')
+ {
+ $crlfmode = 1, next LINE if $value eq 'convert';
+ $crlfmode = 0, next LINE if $value eq 'none';
+ }
+ die "Unknown configuration option: $line\n ";
+ }
+ # Revision specification
+ if (2 == $sectiontype)
+ {
+ my $current = $revmap{$rev};
+ $author{$current} = $value, next LINE if $key eq 'author';
+ $branch{$current} = $value, next LINE if $key eq 'branch';
+ $parent{$current} = $value, next LINE if $key eq 'parent';
+ $timesource{$current} = $value, next LINE if $key eq 'timestamp';
+ push(@{$merges{$current}}, $value), next LINE if $key eq 'merges';
+ die "Unknown revision option: $line\n ";
+ }
+ # Filespecs
+ if (3 == $sectiontype)
+ {
+ # Add the file and create a marker
+ die "File not found: $line\n " unless -f $value;
+ my $current = $revmap{$rev};
+ ${$files{$current}}{$key} = $mark;
+ my $time = &fileblob($value, $crlfmode, $mark ++);
+
+ # Update revision timestamp if more recent than other
+ # files seen, or if this is the file we have selected
+ # to take the time stamp from using the "timestamp"
+ # directive.
+ if ((defined $timesource{$current} && $timesource{$current} eq $value)
+ || $time > $time{$current})
+ {
+ $time{$current} = $time;
+ }
+ }
+ }
+ else
+ {
+ die "Parse error: $line\n ";
+ }
+ }
+ else
+ {
+ # Commit message
+ my $current = $revmap{$rev};
+ if (defined $message{$current})
+ {
+ $message{$current} .= "\n";
+ }
+ $message{$current} .= $line;
+ }
+}
+close CFG;
+
+# Start spewing out data for git-fast-import
+foreach my $commit (@revs)
+{
+ # Progress
+ print OUT "progress Creating revision $commit\n";
+
+ # Create commit header
+ my $mark = $revmap{$commit};
+
+ # Branch and commit id
+ print OUT "commit refs/heads/", $branch{$mark}, "\nmark :", $mark, "\n";
+
+ # Author and timestamp
+ die "No timestamp defined for $commit (no files?)\n" unless defined $time{$mark};
+ print OUT "committer ", $author{$mark}, " ", $time{$mark}, " +0100\n";
+
+ # Commit message
+ die "No message defined for $commit\n" unless defined $message{$mark};
+ my $message = $message{$mark};
+ $message =~ s/\n$//; # Kill trailing empty line
+ print OUT "data ", length($message), "\n", $message, "\n";
+
+ # Parent and any merges
+ print OUT "from :", $revmap{$parent{$mark}}, "\n" if defined $parent{$mark};
+ if (defined $merges{$mark})
+ {
+ foreach my $merge (@{$merges{$mark}})
+ {
+ print OUT "merge :", $revmap{$merge}, "\n";
+ }
+ }
+
+ # Output file marks
+ print OUT "deleteall\n"; # start from scratch
+ foreach my $file (sort keys %{$files{$mark}})
+ {
+ print OUT "M 644 :", ${$files{$mark}}{$file}, " $file\n";
+ }
+ print OUT "\n";
+}
+
+# Create one file blob
+sub fileblob
+{
+ my ($filename, $crlfmode, $mark) = @_;
+
+ # Import the file
+ print OUT "progress Importing $filename\nblob\nmark :$mark\n";
+ open FILE, '<', $filename or die "Cannot read $filename\n ";
+ binmode FILE;
+ my ($size, $mtime) = (stat(FILE))[7,9];
+ my $file;
+ read FILE, $file, $size;
+ close FILE;
+ $file =~ s/\r\n/\n/g if $crlfmode;
+ print OUT "data ", length($file), "\n", $file, "\n";
+
+ return $mtime;
+}
+
+# Parse a key=value pair
+sub parsekeyvaluepair
+{
+=pod
+
+=head2 Escaping special characters
+
+Key and value strings may be enclosed in quotes, in which case
+whitespace inside the quotes is preserved. Additionally, an equal
+sign may be included in the key by preceeding it with a backslash.
+For example:
+
+ "key1 "=value1
+ key2=" value2"
+ key\=3=value3
+ key4=value=4
+ "key5""=value5
+
+Here the first key is "key1 " (note the trailing white-space) and the
+second value is " value2" (note the leading white-space). The third
+key contains an equal sign "key=3" and so does the fourth value, which
+does not need to be escaped. The fifth key contains a trailing quote,
+which does not need to be escaped since it is inside a surrounding
+quote.
+
+=cut
+ my $pair = shift;
+
+ # Separate key and value by the first non-quoted equal sign
+ my ($key, $value);
+ if ($pair =~ /^(.*[^\\])=(.*)$/)
+ {
+ ($key, $value) = ($1, $2)
+ }
+ else
+ {
+ die "Parse error: $pair\n ";
+ }
+
+ # Unquote and unescape the key and value separately
+ return (&unescape($key), &unescape($value));
+}
+
+# Unquote and unescape
+sub unescape
+{
+ my $string = shift;
+
+ # First remove enclosing quotes. Backslash before the trailing
+ # quote leaves both.
+ if ($string =~ /^"(.*[^\\])"$/)
+ {
+ $string = $1;
+ }
+
+ # Second remove any backslashes inside the unquoted string.
+ # For later: Handle special sequences like \t ?
+ $string =~ s/\\(.)/$1/g;
+
+ return $string;
+}
+
+__END__
+
+=pod
+
+=head1 EXAMPLES
+
+B<import-directories.perl> F<project.import>
+
+=head1 AUTHOR
+
+Copyright 2008-2009 Peter Krefting E<lt>peter@softwolves.pp.se>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation.
+
+=cut
diff --git a/contrib/fast-import/import-tars.perl b/contrib/fast-import/import-tars.perl
index 78e40d2a13..7001862bfd 100755
--- a/contrib/fast-import/import-tars.perl
+++ b/contrib/fast-import/import-tars.perl
@@ -8,9 +8,20 @@
## perl import-tars.perl *.tar.bz2
## git whatchanged import-tars
##
+## Use --metainfo to specify the extension for a meta data file, where
+## import-tars can read the commit message and optionally author and
+## committer information.
+##
+## echo 'This is the commit message' > myfile.tar.bz2.msg
+## perl import-tars.perl --metainfo=msg myfile.tar.bz2
use strict;
-die "usage: import-tars *.tar.{gz,bz2,Z}\n" unless @ARGV;
+use Getopt::Long;
+
+my $metaext = '';
+
+die "usage: import-tars [--metainfo=extension] *.tar.{gz,bz2,Z}\n"
+ unless GetOptions('metainfo=s' => \$metaext) && @ARGV;
my $branch_name = 'import-tars';
my $branch_ref = "refs/heads/$branch_name";
@@ -109,12 +120,43 @@ foreach my $tar_file (@ARGV)
$have_top_dir = 0 if $top_dir ne $1;
}
+ my $commit_msg = "Imported from $tar_file.";
+ my $this_committer_name = $committer_name;
+ my $this_committer_email = $committer_email;
+ my $this_author_name = $author_name;
+ my $this_author_email = $author_email;
+ if ($metaext ne '') {
+ # Optionally read a commit message from <filename.tar>.msg
+ # Add a line on the form "Committer: name <e-mail>" to override
+ # the committer and "Author: name <e-mail>" to override the
+ # author for this tar ball.
+ if (open MSG, '<', "${tar_file}.${metaext}") {
+ my $header_done = 0;
+ $commit_msg = '';
+ while (<MSG>) {
+ if (!$header_done && /^Committer:\s+([^<>]*)\s+<(.*)>\s*$/i) {
+ $this_committer_name = $1;
+ $this_committer_email = $2;
+ } elsif (!$header_done && /^Author:\s+([^<>]*)\s+<(.*)>\s*$/i) {
+ $this_author_name = $1;
+ $this_author_email = $2;
+ } elsif (!$header_done && /^$/) { # empty line ends header.
+ $header_done = 1;
+ } else {
+ $commit_msg .= $_;
+ $header_done = 1;
+ }
+ }
+ close MSG;
+ }
+ }
+
print FI <<EOF;
commit $branch_ref
-author $author_name <$author_email> $author_time +0000
-committer $committer_name <$committer_email> $commit_time +0000
+author $this_author_name <$this_author_email> $author_time +0000
+committer $this_committer_name <$this_committer_email> $commit_time +0000
data <<END_OF_COMMIT_MESSAGE
-Imported from $tar_file.
+$commit_msg
END_OF_COMMIT_MESSAGE
deleteall