| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521 | {$mode objfpc}{$H+}program svn2cvs;uses Classes,sysutils,process,DOM,xmlread,custapp,IniFiles;Const  SGlobal       = 'Global';  KeyCVSBin     = 'CVSBinary';  KeySVNBin     = 'SVNBinary';  KeySVNURL     = 'SVNURL';  KeyCVSROOT    = 'CVSROOT';  KeyRepository = 'CVSRepository';  KeyRevision   = 'Revision';  KeyWorkDir    = 'WorkingDir';Resourcestring  SErrFailedToCheckOut     = 'Failed to check out SVN repository';  SErrFailedToInitCVS      = 'Failed to initialize CVS: ';  SErrNoRepository         = 'Cannot initialize CVS: no CVS Repository specified';  SErrDirectoryFailed      = 'Failed to create directory : %s';  SErrFailedToGetVersions  = 'Failed to retrieve SVN versions';  SErrInValidSVNLog        = 'Invalid SVN log.';  SErrUpdateFailed         = 'Update to revision %d failed.';  SErrFailedToCommit       = 'Failed to commit to CVS.';  SErrFailedToRemove       = 'Failed to remove file: %s';  SErrFailedToAddDirectory = 'Failed to add directory to CVS: %s';  SErrFailedToAddFile      = 'Failed to add file to CVS: %s';  SErrDirectoryNotInCVS    = 'Directory not in CVS: %s';  SLogRevision             = 'Revision %s by %s :';  SConvertingRevision      = 'Converting revision : %d';  SWarnUnknownAction       = 'Warning: Unknown action: "%s" for filename : "%s"';  SWarnErrorInLine         = 'Warning: Erroneous file line : %s';  SExecuting               = 'Executing: %s';  Type { TSVN2CVSApp } TVersion = Class(TCollectionItem) private   FAuthor: String;   FDate: string;   FLogMessage: String;   FRevision: Integer; Public   Property Revision : Integer read FRevision;   Property LogMessage : String Read FLogMessage;   Property Date : string Read FDate;   Property Author : String Read FAuthor; end;  { TVersions } TVersions = Class(TCollection) private   function GetVersion(Index : INteger): TVersion;   procedure SetVersion(Index : INteger; const AValue: TVersion); Protected   procedure ConvertLogEntry(E : TDomElement); public   Procedure LoadFromXML(Doc : TXMlDocument);   property Versions[Index : INteger] : TVersion Read GetVersion Write SetVersion; Default; end; { TSVN2CVSApp } TSVN2CVSApp = Class(TCustomApplication) Public   SVNBin : String;   CVSBin : String;   versions : TVersions;   WorkingDir : String;   StartRevision : Integer;   SVNURL : String;   CVSROOT : String;   CVSRepository : String;   Function RunCmd(Cmd: String; CmdOutput: TStream): Boolean;   Function RunSVN(Cmd : String; CmdOutput : TStream) : Boolean;   Function RunCVS(Cmd : String; CmdOutput : TStream) : Boolean;   Function UpdateSVN(Version : TVersion; Files : TStrings) : Boolean;   Procedure WriteLogMessage(Version : TVersion);   Procedure UpdateEntry(AFileName : String);   Procedure DeleteEntry(AFileName : String);   Procedure DoCVSEntries(Version : TVersion;Files : TStrings);   procedure CheckInCVS;   procedure CheckOutSVN(Files : TStrings);   Procedure ConvertVersion(Version : TVersion);   Procedure ConvertRepository;   procedure GetVersions;   procedure ProcessConfigFile;   Function  ProcessArguments : Boolean;   Procedure DoRun; override; end; AppError = Class(Exception);{ TVersions }function TVersions.GetVersion(Index : INteger): TVersion;begin  Result:=Items[Index] as Tversion;end;procedure TVersions.SetVersion(Index : INteger; const AValue: TVersion);begin  Items[Index]:=AValue;end;procedure TVersions.ConvertLogEntry(E : TDomElement);  Function GetNodeText(N : TDomNode) : String;    begin    N:=N.FirstChild;    If N<>Nil then      Result:=N.NodeValue;  end;Var  N : TDomNode;  V : TVersion;begin  V:=Add as TVersion;  V.FRevision:=StrToIntDef(E['revision'],-1);  N:=E.FirstChild;  While (N<>Nil) do    begin    If (N.NodeType=ELEMENT_NODE) then      begin      if (N.NodeName='author') then        V.FAuthor:=GetNodeText(N)      else If (N.NodeName='date') then        V.FDate:=GetNodeText(N)      else If (N.NodeName='msg') then        V.FLogMessage:=GetNodeText(N);      end;    N:=N.NextSibling;    end;end;procedure TVersions.LoadFromXML(Doc: TXMlDocument);var  L : TDomNode;  E : TDomElement;begin  L:=Doc.FirstChild;  While (L<>Nil) and not ((L.NodeType=ELEMENT_NODE) and (L.NodeName='log')) do    L:=L.NextSibling;  if (L=Nil) then    Raise AppError.Create(SErrInValidSVNLog);  L:=L.FirstChild;  While (L<>Nil) do    begin    If (L.NodeType=ELEMENT_NODE) and (L.NodeName='logentry') then      E:=TDomElement(L);    ConvertLogEntry(E);    L:=L.NextSibling;    end;end; { TSVN2CVSApp }function TSVN2CVSApp.RunCmd(Cmd: String; CmdOutput: TStream): Boolean;Var  Buf : Array[1..4096] of Byte;  Count : Integer;begin  With TProcess.Create(Self) do    Try      CommandLine:=cmd;      Writeln(Format(SExecuting,[CommandLine]));      if (CmdOutput<>Nil) then        Options:=[poUsePipes];      Execute;      If (CmdOutPut=Nil) then        WaitOnExit      else        Repeat          Count:=Output.Read(Buf,SizeOf(Buf));          If (Count>0) then            cmdOutput.Write(Buf,Count);        Until (Count=0);      Result:=(ExitStatus=0);    finally      Free;    end;end;function TSVN2CVSApp.RunSVN(Cmd: String; CmdOutput: TStream): Boolean;begin  Result:=RunCmd(SVNbin+' '+Cmd,CmdOutput);end;function TSVN2CVSApp.RunCVS(Cmd: String; CmdOutput: TStream): Boolean;begin  Result:=RunCmd(CVSbin+' '+Cmd,CmdOutput);end;procedure TSVN2CVSApp.CheckOutSVN(Files : TStrings);Var  S : TStringStream;begin  S:=TStringStream.Create('');  Try    if not RunSVN(Format('co -r %d %s .',[StartRevision,SVNURL]),S) then      Raise AppError.Create(SErrFailedToCheckOut);    Files.Text:=S.DataString;  Finally    FreeAndNil(S);  end;end;procedure TSVN2CVSApp.CheckInCVS;Var  F : Text;begin  If not ForceDirectories(WorkingDir+'CVS') then  Try    AssignFile(F,WorkingDir+'CVS/Root');    Rewrite(F);    Try      Writeln(F,CVSRoot);    Finally      CloseFile(F);    end;    AssignFile(F,WorkingDir+'CVS/Repository');    Rewrite(F);    Try      Writeln(F,CVSRepository);    Finally      Close(F);    end;    AssignFile(F,WorkingDir+'CVS/Entries');    Rewrite(F);    Try      // Do nothing.    Finally      Close(F);    end;  except    On E : Exception do      begin      E.Message:=SErrFailedToInitCVS+E.Message;      Raise;      end;  end;end;procedure TSVN2CVSApp.Convertrepository;Var  InitCVS,INITSVN : Boolean;  I : Integer;  Files : TStringList;begin  If Not DirectoryExists(WorkingDir) then    begin    if Not ForceDirectories(WorkingDir) then      Raise AppError.CreateFmt(SErrDirectoryFailed,[WorkingDir]);    InitSVN:=True;    InitCVS:=true;    end  else    begin    if Not DirectoryExists(WorkingDir+'.svn') then      InitSVN:=True;    if Not DirectoryExists(WorkingDir+'CVS') then      InitCVS:=True;    end;  ChDir(WorkingDir);  if InitCVS and (CVSRepository='') then    Raise AppError.Create(SErrNoRepository);  if InitSVN then    begin    Files:=TStringList.Create;    Try      CheckoutSVN(Files);      if InitCVS then        begin        CheckinCVS;        DoCVSEntries(Nil,Files);        end      else        DoCVSEntries(Nil,Files);    finally      FreeAndNil(Files);    end;    end;  GetVersions;  For I:=0 to Versions.Count-1 do    ConvertVersion(Versions[i]);end;procedure TSVN2CVSApp.GetVersions;Var  S : TStringStream;  Doc : TXMLDocument;begin  Versions:=TVersions.Create(TVersion);  S:=TStringStream.Create('');  Try    if not RunSVN(Format('log --xml -r %d:HEAD',[StartRevision]),S) then      Raise AppError(SErrFailedToGetVersions);    S.Position:=0;    ReadXMLFile(Doc,S);    Try      Versions.LoadFromXML(Doc);    finally      Doc.Free;    end;  Finally    S.Free;  end;end;procedure TSVN2CVSApp.ConvertVersion(Version: TVersion);Var  Files : TStringList;begin  Writeln(Format(SConvertingRevision,[Version.revision]));  Files:=TStringList.Create;  Try    If Not UpdateSVN(Version,Files) then      Raise AppError.CreateFmt(SErrUpdateFailed,[Version.Revision]);    DoCVSEntries(Version,Files);  Finally    Files.Free;  end;end;Function TSVN2CVSApp.UpdateSVN(Version : TVersion; Files : TStrings) : Boolean;Var  S : TStringStream;begin  S:=TStringStream.Create('');  Try    Result:=RunSVN(Format('up -r %d',[version.revision]),S);    if Result then      Files.Text:=S.DataString;  Finally    S.Free;  end;end;Procedure TSVN2CVSApp.WriteLogMessage(Version : TVersion);Var  F : Text;  begin  AssignFile(F,'logmsg.txt');  Rewrite(F);  Try    Writeln(F,Format(SLogRevision,[Version.Revision,Version.Author]));    Writeln(F, Version.LogMessage);  Finally    CloseFile(F);  end;end;Procedure TSVN2CVSApp.DoCVSEntries(Version : TVersion;Files : TStrings);Var  I,P        : Integer;  Action   : Char;  FileName : String;begin  For I:=0 to Files.Count-1 do   begin   FileName:=trim(Files[i]);   P:=Pos(' ',FileName);   if (P=0) then     Writeln(StdErr,Format(SWarnErrorInLine,[FileName]))   else     begin     Action:=FileName[1];     system.Delete(FileName,1,P);     FileName:=Trim(FileName);     end;   Case UpCase(action) of     'U' : UpdateEntry(FileName);     'D' : DeleteEntry(FileName);   else      Writeln(stdErr,Format(SWarnUnknownAction,[Action,FileName]));   end;   end; WriteLogMessage(version); Try   If not RunCVS('commit -m -F logmsg.txt .',Nil) then     Raise AppError.Create(SErrFailedToCommit); Finally   if not DeleteFile('logmsg.txt') then     Writeln(StdErr,'Warning: failed to remove log message file.'); end;end;Procedure TSVN2CVSApp.UpdateEntry(AFileName : String);Var  FD : String;  L : TStringList;  I : Integer;  Found : Boolean;  begin  If ((FileGetAttr(AFileName) and faDirectory)<>0) then    begin    if Not RunCVS('add '+AFileName,Nil) then      Raise AppError.CreateFmt(SErrFailedToAddDirectory,[AFileName]);    end  else // Check if file is under CVS control by checking the Entries file.    begin    FD:=ExtractFilePath(AFileName);    If not DirectoryExists(FD+'Entries') then      Raise AppError.CreateFmt(SErrDirectoryNotInCVS,[FD]);    Found:=False;    L:=TStringList.Create;    Try      L.LoadFromFile(FD+'Entries');      Found:=False;      I:=0;      While (not found) and (I<L.Count) do        begin        Inc(I);        end;      if not found then       if Not RunCVS('add '+AFileName,Nil) then         Raise AppError.CreateFmt(SErrFailedToAddFile,[AFileName]);    finally      L.Free;    end;    end;end;Procedure TSVN2CVSApp.DeleteEntry(AFileName : String);begin  If ((FileGetAttr(AFileName) and faDirectory)=0) then    if Not RunCVS('rm '+AFileName,Nil) then      Raise AppError.CreateFmt(SErrFailedToRemove,[AFileName]);end;procedure TSVN2CVSApp.DoRun;begin  If Not ProcessArguments then    exit;  ConvertRepository;end;procedure TSVN2CVSApp.ProcessConfigFile;begin  With TMemIniFile.Create(GetAppConfigFile(False)) do    try      SVNURL:=ReadString(SGlobal,KeySVNURL,'');      CVSROOT:=ReadString(SGlobal,KeyCVSROOT,'');      CVSRepository:=ReadString(SGlobal,KeyRepository,'');      WorkingDir:=ReadString(SGLobal,KeyWorkDir,'');      StartRevision:=ReadInteger(SGlobal,KeyRevision,-1)+1;      SVNBin:=ReadString(SGlobal,KeySVNBin,'svn');      CVSBin:=ReadString(SGlobal,KeyCVSBin,'cvs');    finally      Free;    end;end;function TSVN2CVSApp.ProcessArguments: Boolean;begin  ProcessConfigFile;  if HasOption('s','svn-repository') then    SVNURL:=GetOptionValue('s','svn-repository');  if HasOption('c','cvsroot') then    CVSROOT:=GetOptionValue('c','cvsroot');  if HasOption('c','cvsrepository') then    CVSROOT:=GetOptionValue('p','cvsrepository');  if HasOption('r','revision') then    StartRevision:=StrToIntDef(GetOptionValue('c'),0);  if HasOption('d','directory') then    WorkingDir:=GetOptionValue('d','directory');  Result:=(SVNUrl<>'') and (CVSROOT<>'');  If Result then    begin    If (WorkingDir='') then      WorkingDir:=GetCurrentDir;    WorkingDir:=IncludeTrailingPathDelimiter(WorkingDir);    end;end;begin  With TSVN2CVSApp.Create(Nil) do    try      Initialize;      Run;    Finally      free;    end;  end.
 |