Changeset 9


Ignore:
Timestamp:
Aug 21, 2022, 7:07:10 PM (21 months ago)
Author:
chronos
Message:
  • Modified: Restore pristine files for deleted files with using information from subversion SQLite3 database.
Location:
trunk
Files:
5 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/Install/deb/debian/control

    r2 r9  
    55Standards-Version: 1.0.0
    66#Build-Depends: fpc, lazarus, lcl, lcl-utils, debhelper (>= 8)
    7 Build-Depends: fpc-laz, lazarus-project, debhelper (>= 8)
     7Build-Depends: fpc-laz, lazarus-project, libsqlite3-dev, debhelper (>= 8)
    88
    99Package: svnzero
    1010Architecture: any
    11 Depends: ${shlibs:Depends}, ${misc:Depends},
     11Depends: ${shlibs:Depends}, ${misc:Depends}, libsqlite3
    1212Description: Subversion zero pristine wrapper.
    1313HomePage: https://app.zdechov.net/svnzero
  • trunk/Languages/svnzero.cs.po

    r6 r9  
    1111"Language: cs\n"
    1212"X-Generator: Poedit 3.0\n"
     13
     14#: sqlite3wrap.sdatabasenotconnected
     15msgid "SQLite3 error: database is not connected."
     16msgstr ""
     17
     18#: sqlite3wrap.serrormessage
     19#, object-pascal-format
     20msgid "SQLite3 error: %s"
     21msgstr ""
     22
     23#: sqlite3wrap.snotransactionopen
     24msgid "No transaction is open"
     25msgstr ""
     26
     27#: sqlite3wrap.stransactionalreadyopen
     28msgid "Transaction is already opened."
     29msgstr ""
    1330
    1431#: usvnzero.spristinerecoveryfail
  • trunk/Languages/svnzero.pot

    r6 r9  
    11msgid ""
    22msgstr "Content-Type: text/plain; charset=UTF-8"
     3
     4#: sqlite3wrap.sdatabasenotconnected
     5msgid "SQLite3 error: database is not connected."
     6msgstr ""
     7
     8#: sqlite3wrap.serrormessage
     9#, object-pascal-format
     10msgid "SQLite3 error: %s"
     11msgstr ""
     12
     13#: sqlite3wrap.snotransactionopen
     14msgid "No transaction is open"
     15msgstr ""
     16
     17#: sqlite3wrap.stransactionalreadyopen
     18msgid "Transaction is already opened."
     19msgstr ""
    320
    421#: usvnzero.spristinerecoveryfail
  • trunk/SVNZero.lpi

    r6 r9  
    2828          <SearchPaths>
    2929            <IncludeFiles Value="$(ProjOutDir)"/>
     30            <OtherUnitFiles Value="SQLite3"/>
    3031            <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)-$(BuildMode)"/>
    3132          </SearchPaths>
     
    9192        <IsPartOfProject Value="True"/>
    9293      </Unit>
     94      <Unit>
     95        <Filename Value="UExecute.pas"/>
     96        <IsPartOfProject Value="True"/>
     97      </Unit>
     98      <Unit>
     99        <Filename Value="SQLite3/SQLite3.pas"/>
     100        <IsPartOfProject Value="True"/>
     101      </Unit>
     102      <Unit>
     103        <Filename Value="SQLite3/SQLite3Utils.pas"/>
     104        <IsPartOfProject Value="True"/>
     105      </Unit>
     106      <Unit>
     107        <Filename Value="SQLite3/SQLite3Wrap.pas"/>
     108        <IsPartOfProject Value="True"/>
     109      </Unit>
    93110    </Units>
    94111  </ProjectOptions>
     
    100117    <SearchPaths>
    101118      <IncludeFiles Value="$(ProjOutDir)"/>
     119      <OtherUnitFiles Value="SQLite3"/>
    102120      <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)-$(BuildMode)"/>
    103121    </SearchPaths>
  • trunk/SVNZero.lpr

    r8 r9  
    55  cthreads,
    66  {$ENDIF}
    7   Classes, SysUtils, CustApp, USubversion, UTest, USvnZero, UTestCases
     7  Classes, SysUtils, CustApp, USubversion, UTest, USvnZero, UTestCases, UExecute
    88  { you can add units after this };
    99
     
    2727
    2828procedure TSvnZeroApp.DoRun;
     29var
     30  I: Integer;
    2931begin
     32  if HasOption('print') then begin
     33    SvnZero.PrintOutput := True;
     34  end;
    3035  if HasOption('t', 'test') then begin
    3136    with TTestCases.Create do
     
    3742      AddNew('Merge', TTestCaseMerge);
    3843      AddNew('Update multiple', TTestCaseUpdateMultiple);
     44      AddNew('Delete update', TTestCaseDeleteUpdate);
     45      AddNew('Delete update duplicate files', TTestCaseDeleteUpdateDuplicateFiles);
     46      for I := 0 to Count - 1 do
     47      if Items[I] is TTestCaseSvn then begin
     48        TTestCaseSvn(Items[I]).Subversion.PrintOutput := SvnZero.PrintOutput;
     49        TTestCaseSvn(Items[I]).Subversion.PrintCommand := SvnZero.PrintOutput;
     50      end;
    3951      Run;
    4052    finally
     
    6981  Params: TStringArray;
    7082  I: Integer;
     83  J: Integer;
    7184begin
    7285  Params := Default(TStringArray);
    7386  SetLength(Params, ParamCount);
    74   for I := 0 to ParamCount - 1 do
    75     Params[I] := GetParams(I + 1);
     87  J := 0;
     88  for I := 0 to ParamCount - 1 do begin
     89    if GetParams(I + 1) <> '--print' then begin
     90      Params[J] := GetParams(I + 1);
     91      Inc(J);
     92    end;
     93  end;
     94  SetLength(Params, J);
    7695
    7796  SVNZero.ExecuteOutput(Params);
  • trunk/USubversion.pas

    r5 r9  
    44
    55uses
    6   Classes, SysUtils, Process, FileUtil
     6  Classes, SysUtils, Process, FileUtil, UExecute
    77  {$IFDEF UNIX}, baseunix{$ENDIF};
    88
     
    1515  end;
    1616
    17   { TExecute }
    18 
    19   TExecute = class
    20   protected
    21     function GetExecutable: string; virtual;
    22   public
    23     StandardOutput: string;
    24     ErrorOutput: string;
    25     procedure Execute(Parameters: array of string); virtual;
    26     procedure ExecuteOutput(Parameters: array of string);
    27     function GetInfo(Text: string): TSubversionInfo;
    28   end;
    29 
    3017  { TSubversion }
    3118
     
    3522    function GetExecutable: string; override;
    3623  public
     24    function GetInfo(Text: string): TSubversionInfo;
    3725  end;
    3826
     
    5038implementation
    5139
    52 { TExecute }
    53 
    54 function TExecute.GetExecutable: string;
    55 begin
    56   Result := '';
    57 end;
    58 
    59 procedure TExecute.Execute(Parameters: array of string);
    60 var
    61   Process: TProcess;
    62   I: Integer;
    63   Buffer: string;
    64   Count: Integer;
    65 begin
    66   StandardOutput := '';
    67   ErrorOutput := '';
    68   Buffer := '';
    69   try
    70     Process := TProcess.Create(nil);
    71     Process.Executable := GetExecutable;
    72     for I := 0 to Length(Parameters) - 1 do
    73       Process.Parameters.Add(Parameters[I]);
    74     Process.Options := [poUsePipes, poNoConsole];
    75     Process.Execute;
    76     while Process.Running or (Process.Output.NumBytesAvailable > 0) or
    77     (Process.Stderr.NumBytesAvailable > 0) do
    78     begin
    79       if Process.Output.NumBytesAvailable > 0 then begin
    80         SetLength(Buffer, 1000);
    81         Count := Process.Output.Read(Buffer[1], Length(Buffer));
    82         SetLength(Buffer, Count);
    83         StandardOutput := StandardOutput + Buffer;
    84       end;
    85       if Process.Stderr.NumBytesAvailable > 0 then begin
    86         SetLength(Buffer, 1000);
    87         Count := Process.Stderr.Read(Buffer[1], Length(Buffer));
    88         SetLength(Buffer, Count);
    89         ErrorOutput := ErrorOutput + Buffer;
    90       end;
    91       Sleep(1);
    92     end;
    93   finally
    94     Process.Free;
    95   end;
    96 end;
    97 
    98 procedure TExecute.ExecuteOutput(Parameters: array of string);
    99 begin
    100   Execute(Parameters);
    101   if StandardOutput <> '' then Write(StandardOutput);
    102   if ErrorOutput <> '' then Write(ErrorOutput);
    103 end;
    104 
    105 function TExecute.GetInfo(Text: string): TSubversionInfo;
     40function TSubversion.GetInfo(Text: string): TSubversionInfo;
    10641var
    10742  Index: Integer;
  • trunk/USvnZero.pas

    r8 r9  
    1717    function GetWorkingCopyRootPath(FileName: string): string;
    1818    function CheckErrorOutput(Text: string): Boolean;
     19    function GetFileInfoByMd5(Md5Hash: string): TSubversionInfo;
    1920    procedure ZeroPristine;
    2021    procedure RestorePristine;
     
    3334implementation
    3435
     36uses
     37  SQLite3, SQLite3Wrap;
     38
    3539const
    3640  SvnBaseExt = '.svn-base';
     
    130134  LastErrorOutput: string;
    131135begin
     136  Subversion.PrintOutput := PrintOutput;
     137  Subversion.PrintCommand := PrintCommand;
    132138  LastErrorOutput := '';
    133139  StandardOutputMerged := '';
     
    176182  PristineFileName: string;
    177183  Info: TSubversionInfo;
     184  Md5Hash: string;
     185const
     186  StartText = 'expected:';
    178187begin
    179188  Result := False;
    180189  if Pos(': Checksum mismatch', Text) > 0 then begin
    181     I := Pos('''', Text);
     190    I := Pos(StartText, Text);
     191    if I > 0 then begin
     192      Md5Hash := Copy(Text, I + Length(StartText), MaxInt);
     193      I := Pos(#10, Md5Hash);
     194      if I > 0 then
     195        Delete(Md5Hash, I, MaxInt);
     196      Md5Hash := Trim(Md5Hash);
     197      Info := GetFileInfoByMd5(Md5Hash);
     198      ExportedFileName := GetSvnDir('.') + DirectorySeparator + 'tmp' +
     199        DirectorySeparator + 'ExportedFile.bin';
     200      PristineFileName := GetPristineDir('.') + DirectorySeparator + Copy(Info.Checksum, 1, 2) +
     201        DirectorySeparator + Info.Checksum + '.svn-base';
     202      Subversion.Execute(['export', '-r', Info.Revision, '--force', Info.URL, ExportedFileName]);
     203      MakeFileWriteable(PristineFileName);
     204      CopyFile(ExportedFileName, PristineFileName);
     205      Subversion.Execute(['cleanup']);
     206      Result := True;
     207    end;
     208
     209 {   I := Pos('''', Text);
    182210    if I > 0 then begin
    183211      FileName := Copy(Text, I + 1, MaxInt);
     
    198226      Result := True;
    199227    end;
     228    }
     229  end;
     230end;
     231
     232function TSvnZero.GetFileInfoByMd5(Md5Hash: string): TSubversionInfo;
     233var
     234  Database: TSQLite3Database;
     235  Statement: TSQLite3Statement;
     236begin
     237  Database := TSQLite3Database.Create;
     238  try
     239    Database.Open(GetSvnDir('.') + DirectorySeparator + 'wc.db');
     240    Statement := Database.Prepare('SELECT checksum FROM PRISTINE WHERE md5_checksum=''$md5 $' + Md5Hash + '''');
     241    try
     242      while Statement.Step = SQLITE_ROW do begin
     243        Result.Checksum := Statement.ColumnText(0);
     244      end;
     245    finally
     246      Statement.Free;
     247    end;
     248
     249    Statement := Database.Prepare('SELECT repos_path,changed_revision FROM NODES WHERE checksum="' + Result.Checksum + '" LIMIT 1');
     250    try
     251      while Statement.Step = SQLITE_ROW do begin
     252        Result.Path := Statement.ColumnText(0);
     253        Result.Revision := Statement.ColumnText(1);
     254      end;
     255    finally
     256      Statement.Free;
     257    end;
     258
     259    Statement := Database.Prepare('SELECT root FROM REPOSITORY LIMIT 1');
     260    try
     261      while Statement.Step = SQLITE_ROW do begin
     262        Result.URL := Statement.ColumnText(0) + '/' + Result.Path;
     263      end;
     264    finally
     265      Statement.Free;
     266    end;
     267
     268    if Result.Checksum.StartsWith('$sha1$') then
     269      Result.Checksum := Copy(Result.Checksum, 7);
     270  finally
     271    Database.Free;
    200272  end;
    201273end;
  • trunk/UTest.pas

    r8 r9  
    4545procedure Translate;
    4646procedure SaveStringToFile(S, FileName: string);
     47function LoadFileToStr(const FileName: TFileName): AnsiString;
    4748
    4849
     
    7071end;
    7172
     73function LoadFileToStr(const FileName: TFileName): AnsiString;
     74var
     75  FileStream: TFileStream;
     76  Read: Integer;
     77begin
     78  Result := '';
     79  FileStream := TFileStream.Create(FileName, fmOpenRead);
     80  try
     81    if FileStream.Size > 0 then begin
     82      SetLength(Result, FileStream.Size);
     83      Read := FileStream.Read(Pointer(Result)^, FileStream.Size);
     84      SetLength(Result, Read);
     85    end;
     86  finally
     87    FileStream.Free;
     88  end;
     89end;
     90
    7291{ TTestCase }
    7392
    7493procedure TTestCase.Initialize;
    7594begin
     95  TestResult := trNone;
    7696end;
    7797
     
    119139  Failed: Integer;
    120140begin
     141  Passed := 0;
     142  Failed := 0;
    121143  for I := 0 to Count - 1 do
    122144  with Items[I] do begin
     
    125147    Run;
    126148    Finalize;
     149    if TestResult = trPassed then Inc(Passed);
     150    if TestResult = trFailed then Inc(Failed);
    127151  end;
    128152
    129   Passed := 0;
    130   Failed := 0;
    131153  for I := 0 to Count - 1 do
    132154  with Items[I] do begin
    133155    WriteLn(Name + ': ' + ResultText[TestResult]);
    134     if TestResult = trPassed then Inc(Passed);
    135     if TestResult = trFailed then Inc(Failed);
    136156  end;
    137157  WriteLn('Total: ' + IntToStr(Count) + ', Passed: ' + IntToStr(Passed) +
  • trunk/UTestCases.pas

    r8 r9  
    1111  TTestCaseSvn = class(TTestCase)
    1212  private
    13     Subversion: TExecute;
    14     SubversionAdmin: TSubversionAdmin;
    1513    function CheckError(Text: string): Boolean;
    1614  protected
     
    2220    procedure SvnAdmin(Parameters: array of string);
    2321  public
     22    Subversion: TSubversion;
     23    SubversionAdmin: TSubversionAdmin;
    2424    procedure Initialize; override;
    2525    procedure Run; override;
     
    5353  end;
    5454
     55  { TTestCaseDeleteUpdate }
     56
     57  TTestCaseDeleteUpdate = class(TTestCaseSvn)
     58    procedure Run; override;
     59  end;
     60
    5561  { TTestCaseMerge }
    5662
     
    6268
    6369  TTestCaseUpdateMultiple = class(TTestCaseSvn)
     70    procedure Run; override;
     71  end;
     72
     73  { TTestCaseDeleteUpdateDuplicateFiles }
     74
     75  TTestCaseDeleteUpdateDuplicateFiles = class(TTestCaseSvn)
    6476    procedure Run; override;
    6577  end;
     
    6981uses
    7082  USvnZero;
     83
     84{ TTestCaseDeleteUpdateDuplicateFiles }
     85
     86procedure TTestCaseDeleteUpdateDuplicateFiles.Run;
     87var
     88  TestFile: string;
     89  TestFile2: string;
     90const
     91  TestText = 'Some text';
     92begin
     93  TestFile := 'TestFile.txt';
     94  TestFile2 := 'TestFile2.txt';
     95  SaveStringToFile(TestText, TestFile);
     96  SaveStringToFile(TestText, TestFile2);
     97  Svn(['add', TestFile]);
     98  Svn(['add', TestFile2]);
     99  Svn(['commit', '-m', '"Commit message"']);
     100  Svn(['delete', TestFile]);
     101  Svn(['commit', '-m', '"Commit message 2"']);
     102  Svn(['update', '-r', '1']);
     103  Evaluate(LoadFileToStr(TestFile) = TestText);
     104end;
     105
     106{ TTestCaseDeleteUpdate }
     107
     108procedure TTestCaseDeleteUpdate.Run;
     109var
     110  TestFile: string;
     111  TestFile2: string;
     112begin
     113  TestFile := 'TestFile.txt';
     114  TestFile2 := 'TestFile2.txt';
     115  SaveStringToFile('Some text', TestFile);
     116  Svn(['add', TestFile]);
     117  Svn(['commit', '-m', '"Commit message"']);
     118  Svn(['delete', TestFile]);
     119  SaveStringToFile('File2 test', TestFile2);
     120  Svn(['add', TestFile2]);
     121  Svn(['commit', '-m', '"Commit message 2"']);
     122  Svn(['delete', TestFile2]);
     123  Svn(['commit', '-m', '"Commit message 3"']);
     124  Svn(['update', '-r', '1']);
     125  Svn(['update', '-r', '2']);
     126  Svn(['update', '-r', '3']);
     127  Svn(['update']);
     128  Evaluate(True);
     129end;
    71130
    72131{ TTestCaseSvn }
Note: See TracChangeset for help on using the changeset viewer.