initial import of fpsvnsync

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@122 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
vsnijders
2007-03-08 21:10:28 +00:00
parent dd83bd49fe
commit d50e06a2e8
2 changed files with 548 additions and 0 deletions

View File

@ -0,0 +1,203 @@
<?xml version="1.0"?>
<CONFIG>
<ProjectOptions>
<PathDelim Value="\"/>
<Version Value="5"/>
<General>
<MainUnit Value="0"/>
<IconPath Value="./"/>
<TargetFileExt Value=".exe"/>
<ActiveEditorIndexAtStart Value="0"/>
</General>
<VersionInfo>
<ProjectVersion Value=""/>
<Language Value=""/>
<CharSet Value=""/>
</VersionInfo>
<PublishOptions>
<Version Value="2"/>
<IgnoreBinaries Value="False"/>
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
<ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
</PublishOptions>
<RunParams>
<local>
<FormatVersion Value="1"/>
<LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
</local>
</RunParams>
<RequiredPackages Count="2">
<Item1>
<PackageName Value="svnpkg"/>
</Item1>
<Item2>
<PackageName Value="FCL"/>
</Item2>
</RequiredPackages>
<Units Count="21">
<Unit0>
<Filename Value="fpsvnsync.lpr"/>
<IsPartOfProject Value="True"/>
<UnitName Value="fpsvnsync"/>
<CursorPos X="30" Y="33"/>
<TopLine Value="307"/>
<EditorIndex Value="0"/>
<UsageCount Value="133"/>
<Loaded Value="True"/>
</Unit0>
<Unit1>
<Filename Value="..\..\..\..\fpc\2.1\fcl\inc\custapp.pp"/>
<UnitName Value="CustApp"/>
<CursorPos X="3" Y="166"/>
<TopLine Value="188"/>
<UsageCount Value="62"/>
</Unit1>
<Unit2>
<Filename Value="..\test\testsvncommand.pas"/>
<UnitName Value="TestSvnCommand"/>
<CursorPos X="15" Y="9"/>
<TopLine Value="1"/>
<UsageCount Value="9"/>
</Unit2>
<Unit3>
<Filename Value="..\svncommand.pas"/>
<UnitName Value="SvnCommand"/>
<CursorPos X="58" Y="96"/>
<TopLine Value="76"/>
<UsageCount Value="67"/>
</Unit3>
<Unit4>
<Filename Value="..\svnclasses.pas"/>
<UnitName Value="SvnClasses"/>
<CursorPos X="35" Y="476"/>
<TopLine Value="541"/>
<UsageCount Value="67"/>
</Unit4>
<Unit5>
<Filename Value="..\..\..\..\fpc\2.1\fcl\xml\xmlread.pp"/>
<UnitName Value="XMLRead"/>
<CursorPos X="16" Y="886"/>
<TopLine Value="866"/>
<UsageCount Value="61"/>
</Unit5>
<Unit6>
<Filename Value="..\..\..\..\fpc\2.1\fcl\inc\process.pp"/>
<UnitName Value="process"/>
<CursorPos X="1" Y="186"/>
<TopLine Value="153"/>
<UsageCount Value="9"/>
</Unit6>
<Unit7>
<Filename Value="..\..\..\..\lazarus\lcl\stringhashlist.pas"/>
<UnitName Value="StringHashList"/>
<CursorPos X="1" Y="1"/>
<TopLine Value="1"/>
<UsageCount Value="55"/>
</Unit7>
<Unit8>
<Filename Value="..\..\..\..\lazarus\lcl\fpcadds.pas"/>
<UnitName Value="FPCAdds"/>
<CursorPos X="1" Y="75"/>
<TopLine Value="46"/>
<UsageCount Value="61"/>
</Unit8>
<Unit9>
<Filename Value="..\..\..\..\fpc\2.1\rtl\win\sysutils.pp"/>
<UnitName Value="sysutils"/>
<CursorPos X="3" Y="333"/>
<TopLine Value="329"/>
<UsageCount Value="55"/>
</Unit9>
<Unit10>
<Filename Value="..\..\..\..\fpc\2.1\fcl\inc\contnrs.pp"/>
<UnitName Value="contnrs"/>
<CursorPos X="34" Y="61"/>
<TopLine Value="42"/>
<UsageCount Value="22"/>
</Unit10>
<Unit11>
<Filename Value="..\..\..\..\fpc\2.1\rtl\objpas\classes\classesh.inc"/>
<CursorPos X="64" Y="147"/>
<TopLine Value="128"/>
<UsageCount Value="22"/>
</Unit11>
<Unit12>
<Filename Value="..\..\..\..\fpc\2.1\rtl\objpas\sysutils\filutilh.inc"/>
<CursorPos X="10" Y="85"/>
<TopLine Value="62"/>
<UsageCount Value="15"/>
</Unit12>
<Unit13>
<Filename Value="..\..\..\..\fpc\2.1\compiler\aasmtai.pas"/>
<UnitName Value="aasmtai"/>
<CursorPos X="30" Y="176"/>
<TopLine Value="156"/>
<UsageCount Value="8"/>
</Unit13>
<Unit14>
<Filename Value="..\..\..\..\fpc\2.1\compiler\cgbase.pas"/>
<UnitName Value="cgbase"/>
<CursorPos X="7" Y="177"/>
<TopLine Value="157"/>
<UsageCount Value="8"/>
</Unit14>
<Unit15>
<Filename Value="..\..\..\..\lazarus\lcl\fileutil.pas"/>
<UnitName Value="FileUtil"/>
<CursorPos X="10" Y="111"/>
<TopLine Value="91"/>
<UsageCount Value="13"/>
</Unit15>
<Unit16>
<Filename Value="..\..\..\..\lazarus\lcl\include\fileutil.inc"/>
<CursorPos X="3" Y="1194"/>
<TopLine Value="1186"/>
<UsageCount Value="13"/>
</Unit16>
<Unit17>
<Filename Value="..\..\..\..\fpc\2.1\rtl\win32\initc.pp"/>
<UnitName Value="initc"/>
<CursorPos X="6" Y="18"/>
<TopLine Value="1"/>
<UsageCount Value="11"/>
</Unit17>
<Unit18>
<Filename Value="..\..\..\..\fpc\2.1\rtl\inc\ctypes.pp"/>
<UnitName Value="ctypes"/>
<CursorPos X="1" Y="1"/>
<TopLine Value="1"/>
<UsageCount Value="11"/>
</Unit18>
<Unit19>
<Filename Value="..\..\..\..\fpc\2.1\rtl\win\wininc\messages.inc"/>
<CursorPos X="54" Y="1165"/>
<TopLine Value="1138"/>
<UsageCount Value="10"/>
</Unit19>
<Unit20>
<Filename Value="..\..\..\..\fpc\2.1\rtl\inc\objpash.inc"/>
<CursorPos X="8" Y="264"/>
<TopLine Value="254"/>
<UsageCount Value="9"/>
</Unit20>
</Units>
<JumpHistory Count="0" HistoryIndex="-1"/>
</ProjectOptions>
<CompilerOptions>
<Version Value="5"/>
<PathDelim Value="\"/>
<CodeGeneration>
<Generate Value="Faster"/>
</CodeGeneration>
<Linking>
<Debugging>
<GenerateDebugInfo Value="True"/>
</Debugging>
</Linking>
<Other>
<CustomOptions Value="-Faheaptrc
"/>
<CompilerPath Value="$(CompPath)"/>
</Other>
</CompilerOptions>
</CONFIG>

View File

@ -0,0 +1,345 @@
{ $Id }
{ svnsync-like utility written with freepascal
fpsvnsync synchronizes two svn repositories without the need to set
revision properties.
Copyright (C) 2007 Vincent Snijders (vincents@freepascal.org)
This source 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; either version 2 of the License, or (at your option)
any later version.
This code 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.
A copy of the GNU General Public License is available on the World Wide Web
at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing
to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
}
program fpsvnsync;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils, CustApp,
FileUtil,
SvnClasses, SvnCommand;
type
{ TSvnMirrorApp }
TSvnMirrorApp = class(TCustomApplication)
private
FSourceWC: string;
FDestWC: string;
function GetRevision(Directory: string): integer;
function GetRepositoryRoot(Directory: string): string;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Run;
end;
{ TSvnMirrorApp }
function TSvnMirrorApp.GetRevision(Directory: string): integer;
var
SvnInfo: TSvnInfo;
begin
SvnInfo := TSvnInfo.Create(Directory);
Result := SvnInfo.Entry.Revision;
SvnInfo.Free;
end;
function TSvnMirrorApp.GetRepositoryRoot(Directory: string): string;
var
SvnInfo: TSvnInfo;
begin
SvnInfo := TSvnInfo.Create(Directory);
Result := SvnInfo.Entry.Repository.Root;
SvnInfo.Free;
end;
procedure TSvnMirrorApp.Run;
var
SourceHead: integer;
Revision: integer;
XmlOutput: TMemoryStream;
SvnResult: LongInt;
SvnLog: TSvnLog;
SubPath: string;
DestRoot: string;
procedure GetLog;
var
Command: string;
begin
writeln('Getting log message for revision ', Revision);
Command := Format('log --xml -v -r%d %s', [Revision,FSourceWC]);
SvnLog.LoadFromCommand(command);
SvnLog.LogEntry[0].SortPaths;
SubPath := SvnLog.LogEntry[0].CommonPath;
writeln('Finding common path from log messages: ', SubPath);
end;
procedure UpdateWC(const WorkingDir, SubPath: string; Revision: integer);
var
Command: string;
UpdatePath: string;
RevisionStr: string;
begin
UpdatePath := WorkingDir+SubPath;
if Revision > 0 then
RevisionStr := IntToStr(Revision)
else
RevisionStr := 'HEAD';
writeln(format('Updating %s to revision %s', [UpdatePath, RevisionStr]));
Command := Format('up -r%s %s', [RevisionStr, UpdatePath]);
writeln('svn ', Command);
SvnResult := ExecuteSvnCommand(Command);
end;
procedure GetDiff;
var
Command: string;
Diff: TStrings;
begin
writeln('Getting diffs between revision ', Revision-1,' and ', Revision);
Command := Format('diff -c%d %s', [Revision, FSourceWC+SubPath]);
writeln('svn ', Command);
XmlOutput.Clear;
SvnResult := ExecuteSvnCommand(Command, XmlOutput);
XmlOutput.Position := 0;
Diff := TStringList.Create;
Diff.LoadFromStream(XmlOutput);
writeln('Diff contains ', Diff.Count, ' lines');
if pos('Property changes on', Diff.Text)>0 then begin
writeln('Properties changed');
writeln(Diff.Text);
Diff.Free;
halt(1);
end;
Diff.Free;
end;
procedure DeleteFiles;
var
LogEntry: TLogEntry;
LogPath: TLogPath;
i: integer;
DestFile: string;
begin
LogEntry := SvnLog.LogEntry[0];
for i := 0 to LogEntry.PathCount-1 do begin
LogPath := LogEntry.Path[i];
if LogPath.Action=caDelete then begin
DestFile := FDestWC + LogPath.Path;
writeln('Deleting ', DestFile);
ExecuteSvnCommand('delete '+DestFile);
end;
end;
end;
procedure CopyChanges;
var
LogEntry: TLogEntry;
LogPath: TLogPath;
i: integer;
SourceFile, DestFile, Command: string;
begin
LogEntry := SvnLog.LogEntry[0];
for i := 0 to LogEntry.PathCount-1 do begin
LogPath := LogEntry.Path[i];
DestFile := FDestWC + LogPath.Path;
if LogPath.Action in [caModify, caAdd] then begin
SourceFile := FSourceWC + LogPath.Path;
if LogPath.CopyFromPath<>'' then begin
Command := format('copy -r%d %s%s %s',
[LogPath.CopyFromRevision,
DestRoot, LogPath.CopyFromPath, DestFile]);
writeln('svn '+ Command);
ExecuteSvnCommand(Command);
end;
writeln('Copy ', SourceFile, ' to ', DestFile);
if DirectoryExists(SourceFile) then
ForceDirectory(DestFile)
else
CopyFile(SourceFile, DestFile, true);
if LogPath.Action=caAdd then begin
writeln('svn add '+ DestFile);
writeln('Result: ',ExecuteSvnCommand('add '+DestFile));
end;
end;
end;
end;
procedure ApplyPropChanges;
var
SourcePropInfo: TSvnPropInfo;
DestPropInfo: TSvnPropInfo;
i: Integer;
function CreatePropInfo(const BaseDir: string): TSvnPropInfo;
var
Files: TStrings;
begin
Result := TSvnPropInfo.Create;
Files := SvnLog.LogEntry[0].GetFileList(BaseDir);
Result.LoadForFiles(Files);
Files.Free;
end;
procedure CopyFileProp(SourceProp, DestProp: TSvnFileProp);
var
j: integer;
Command: string;
begin
if SourceProp.Properties.Text=DestProp.Properties.Text then exit;
writeln('Properties changed for ', DestProp.FileName);
writeln('Source properties');
writeln(SourceProp.Properties.Text);
writeln('Destination properties');
writeln(DestProp.Properties.Text);
for j:=0 to DestProp.Properties.Count-1 do begin
Command := format('propdel %s %s',
[DestProp.Properties.Names[j], DestProp.FileName]);
writeln('svn ', Command);
writeln('svn result: ', ExecuteSvnCommand(Command));
end;
for j:=0 to SourceProp.Properties.Count-1 do begin
Command := format('propset %s "%s" %s',
[SourceProp.Properties.Names[j],
SourceProp.Properties.ValueFromIndex[j],
DestProp.FileName]);
writeln('svn ', Command);
writeln('svn result: ', ExecuteSvnCommand(Command));
end;
end;
begin
SourcePropInfo := CreatePropInfo(FSourceWC);
DestPropInfo := CreatePropInfo(FDestWC);
if SourcePropInfo.FileCount<>DestPropInfo.FileCount then begin
writeln('FileName number mismatch: ',
SourcePropInfo.FileCount, '<>', DestPropInfo.FileCount);
halt(2);
end;
for i := 0 to SourcePropInfo.FileCount-1 do begin
if Copy(SourcePropInfo[i].FileName, length(FSourceWC)+1, 4000) <> Copy(DestPropInfo[i].FileName, Length(FDestWC)+1, 4000) then begin
writeln('FileName mismatch: ',
SourcePropInfo[i].FileName, '<>', DestPropInfo[i].FileName);
halt(3);
end;
CopyFileProp(SourcePropInfo[i], DestPropInfo[i]);
end;
SourcePropInfo.Free;
DestPropInfo.Free;
end;
procedure CommitChanges;
var
Command: string;
MessageFile: string;
Message: TStrings;
LogEntry: TLogEntry;
begin
writeln('Commit to destination');
LogEntry := SvnLog.LogEntry[0];
MessageFile := SysUtils.GetTempFileName;
Message := TStringList.Create;
Message.Add(SvnLog.LogEntry[0].Message);
Message.Add(
Format('Commited by %s at %s', [LogEntry.Author, LogEntry.DisplayDate]));
Message.SaveToFile(MessageFile);
writeln(Message.Text);
Message.Free;
Command := Format('commit -F "%s" %s', [MessageFile, FDestWC+LogEntry.CommonPath]);
writeln('svn ', Command);
writeln('svn commit result: ', ExecuteSvnCommand(Command));
DeleteFile(MessageFile);
end;
begin
SourceHead := GetRevision('-rHEAD '+FSourceWC);
writeln(FSourceWC, ' HEAD at revision ', SourceHead);
Revision := GetRevision('-rHEAD '+FDestWC);
writeln(FDestWC, ' HEAD at revision ', Revision);
DestRoot := GetRepositoryRoot(FDestWC);
writeln('------');
XmlOutput := TMemoryStream.Create;
SvnLog := TSvnLog.Create;
while (Revision<SourceHead) do begin
inc(Revision);
GetLog;
UpdateWC(FDestWC, SvnLog.LogEntry[0].CommonPath, Revision-1);
UpdateWC(FSourceWC, SvnLog.LogEntry[0].CommonPath, Revision);
writeln('Doing adds/deletes');
DeleteFiles;
CopyChanges;
//GetDiff;
ApplyPropChanges;
CommitChanges;
writeln;
//break;
//if Revision>10670 then break;
end;
XmlOutput.Free;
SvnLog.Free;
end;
constructor TSvnMirrorApp.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
if ParamCount=2 then begin
FSourceWC := ParamStr(1);
FDestWC := ParamStr(2);
end
else
begin
FSourceWC := 'd:\lazarus\lazmirror\source';
FDestWC := 'd:\lazarus\lazmirror\dest';
FSourceWC := 'c:\lazarus\lazmirror\source';
FDestWC := 'c:\lazarus\lazmirror\dest';
end;
end;
destructor TSvnMirrorApp.Destroy;
begin
inherited Destroy;
end;
var
SvnMirrorApp: TSvnMirrorApp;
begin
SvnMirrorApp := TSvnMirrorApp.Create(nil);
try
SvnMirrorApp.Run;
finally
SvnMirrorApp.Free;
end;
end.