仕事で使っているアプリケーションがExeName_YYYYMMDDHHNNSS.Logのような
ログファイルを一杯作るので、消してくれという依頼があった。
ただし、このフォルダには、上記のログを作るファイルがいくつかああって
3世代程度は残してくれという依頼があった。
昔、仕事で触ってたOpenVmsのファイルシステムにはバージョンというのが
あって、古いバージョンのファイルを消すPurgeコマンドがあり
これとにたようなものが欲しいなということで、とりあえず作ってみた。
(本家には似ても似つかぬ、あくまでももどきですが。)
使い方は、
PurgeMock "パージファイルマスク" /D:パージファイルがあるフォルダ /G:残す世代数
で、/R: を指定することで、パージファイルマスクに正規表現が使用できます。
また、ファイルの更新日時を基準に/G:で指定した数だけ残るよう古い日付のものを
削除しますが、 /T:を指定することでファイルの作成日時を基準にPurgeすることが
できます。
なお、パージファイルマスクにより、複数の異なるファイル名のファイルが削除対象
となりえますが、このツールでは、このような場合のことを想定しておりません。
(/G:で指定した数になるようにばっさり消します。)
以下、ソース(delphi Xeがあればコンパイル可能です。)を置いておきます。
ライセンスは、MITライセンスとします。
ソース使用は自由ですが、無保証とします。
まずはメイン。
- program PurgeMock;
-
- {$APPTYPE CONSOLE}
-
- uses
- SysUtils,
- PurgeMockImp in 'PurgeMockImp.pas',
- MidasLib
- ;
-
- function CreatePurgeMockParams : TPurgeMockParams;
- var
- PurgeMockParams : TPurgeMockParams;
- i : Integer;
- begin
-
- PurgeMockParams := TPurgeMockParams.Create;
- try
- try
- PurgeMockParams.Init(Paramstr(0));
- for i := 1 to ParamCount -1 do
- begin
- PurgeMockParams.SetPurgeParam(Paramstr(i));
- end;
- except
- PurgeMockParams.Free;
- PurgeMockParams := nil;
- end;
-
- finally
- Result := PurgeMockParams;
- end;
-
- end;
-
- var
- PurgeMockParams : TPurgeMockParams;
- DoPurgeMock : TPuregMock;
- Ret : Integer;
-
- begin
- try
-
- PurgeMockParams := CreatePurgeMockParams;
- if Assigned(PurgeMockParams) then
- begin
- DoPurgeMock := TPuregMock.Create(PurgeMockParams);
- try
- Ret := DoPurgeMock.Purge;
- finally
- DoPurgeMock.Free;
- end;
- PurgeMockParams.Free;
- end;
-
-
- except
- on E: Exception do
- Writeln(E.ClassName, ': ', E.Message);
- end;
- end.
program PurgeMock;
{$APPTYPE CONSOLE}
uses
SysUtils,
PurgeMockImp in 'PurgeMockImp.pas',
MidasLib
;
function CreatePurgeMockParams : TPurgeMockParams;
var
PurgeMockParams : TPurgeMockParams;
i : Integer;
begin
PurgeMockParams := TPurgeMockParams.Create;
try
try
PurgeMockParams.Init(Paramstr(0));
for i := 1 to ParamCount -1 do
begin
PurgeMockParams.SetPurgeParam(Paramstr(i));
end;
except
PurgeMockParams.Free;
PurgeMockParams := nil;
end;
finally
Result := PurgeMockParams;
end;
end;
var
PurgeMockParams : TPurgeMockParams;
DoPurgeMock : TPuregMock;
Ret : Integer;
begin
try
{ TODO -oUser -cConsole メイン : ここにコードを記述してください }
PurgeMockParams := CreatePurgeMockParams;
if Assigned(PurgeMockParams) then
begin
DoPurgeMock := TPuregMock.Create(PurgeMockParams);
try
Ret := DoPurgeMock.Purge;
finally
DoPurgeMock.Free;
end;
PurgeMockParams.Free;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
次に、パージコマンドの本体
- unit PurgeMockImp;
-
- interface
-
- uses
- SysUtils
- ,DB
- ,DBClient
- ;
-
- type
- TPurgeTimeStamp = (ptCreate, ptUpdate);
-
- TPurgeMockParams = class
- private
- FTargetDir: String;
- FUseRegularExpression: Boolean;
- FFileMask: String;
- FLeavingGenerations: Integer;
- FPurgeTimeStamp: TPurgeTimeStamp;
- procedure SetTargetDir(val: String);
- procedure SetUseRegularExpression(val: Boolean);
- procedure SetFileMask(val: String);
- procedure SetLeavingGenerations(val: Integer);
- procedure SetPurgeTimeStamp(val: TPurgeTimeStamp);
- public
- property TargetDir: String read FTargetDir write SetTargetDir;
- property UseRegularExpression: Boolean read FUseRegularExpression
- write SetUseRegularExpression;
- property FileMask: String read FFileMask write SetFileMask;
- property LeavingGenerations: Integer read FLeavingGenerations
- write SetLeavingGenerations;
- property PurgeTimeStamp: TPurgeTimeStamp read FPurgeTimeStamp
- write SetPurgeTimeStamp;
- procedure Init(ExePath: String);
- procedure SetPurgeParam(PurgeParam : String);
- end;
-
- TPuregMock = class
- public
- constructor Create(Params: TPurgeMockParams);
- function Purge: Integer;
- destructor Destroy; override;
- strict private
- FPurgeMockParams: TPurgeMockParams;
- FPurgeMockDataSet : TClientDataSet;
- function MakePurgeFileList: Integer;
- function ExecPurge: Integer;
- function CreatePurgeDataSet : TClientDataSet;
- end;
-
- function TryParseCmdLineSw(ParameterString : String; Sw : Array of String; var ParamValue : String; IgnoreCase: Boolean = true) : boolean;
-
- implementation
-
- Uses
- StrUtils
- ,IOUtils
- ,Types
- ,RegularExpressionsCore
- ;
-
- procedure TPurgeMockParams.SetTargetDir(val: String);
- begin
- FTargetDir := val;
- end;
-
- procedure TPurgeMockParams.SetUseRegularExpression(val: Boolean);
- begin
- FUseRegularExpression := val;
- end;
-
- procedure TPurgeMockParams.Init(ExePath: String);
- begin
-
- FTargetDir := ExtractFileDir(ExePath);
- FUseRegularExpression := false;
- FileMask := '*.*';
- FLeavingGenerations := 1;
- FPurgeTimeStamp := ptUpdate;
-
- end;
-
- procedure TPurgeMockParams.SetFileMask(val: String);
- begin
- FFileMask := val
- end;
-
- procedure TPurgeMockParams.SetLeavingGenerations(val: Integer);
- begin
- if Val >= 0 then
- begin
- FLeavingGenerations := val;
- end
- else
- begin
- FLeavingGenerations := 0;
- end;
- end;
-
- procedure TPurgeMockParams.SetPurgeParam(PurgeParam: String);
- var
- ValueStr : String;
- begin
-
- if TryParseCmdLineSw(PurgeParam,['/D:','-D:'],ValueStr) then
- begin
- FTargetDir := ValueStr;
- Exit;
- end;
-
- if TryParseCmdLineSw(PurgeParam,['/U:','-U:'],ValueStr) then
- begin
- FUseRegularExpression := true;
- Exit;
- end;
-
- if TryParseCmdLineSw(PurgeParam,['/G:','-G:'],ValueStr) then
- begin
- LeavingGenerations := StrToIntDef(ValueStr,1);
- Exit;
- end;
-
- if TryParseCmdLineSw(PurgeParam,['/T:','-T:'],ValueStr) then
- begin
- FPurgeTimeStamp := ptCreate;
- Exit;
- end;
-
- if TryParseCmdLineSw(PurgeParam,[],ValueStr) then
- begin
- FFileMask := ValueStr;
- Exit;
- end;
-
- end;
-
- procedure TPurgeMockParams.SetPurgeTimeStamp(val: TPurgeTimeStamp);
- begin
- FPurgeTimeStamp := val;
- end;
-
- constructor TPuregMock.Create(Params: TPurgeMockParams);
- begin
- inherited Create;
- FPurgeMockParams := Params;
- end;
-
- function TPuregMock.Purge: Integer;
- begin
-
- Result := -1;
-
- FPurgeMockDataSet := CreatePurgeDataSet;
- if Assigned(FPurgeMockDataSet) then
- begin
- if MakePurgeFileList > 0 then
- begin
- Result := ExecPurge;
- end;
- FPurgeMockDataSet.EmptyDataSet;
- FPurgeMockDataSet.Active := false;
- FPurgeMockDataSet.Free;
- end;
-
- end;
-
- function TPuregMock.CreatePurgeDataSet: TClientDataSet;
- var
- PurgeDataSet : TClientDataSet;
- FD : TFieldDef;
- begin
- PurgeDataSet := TClientDataSet.Create(nil);
- try
- try
- FD := PurgeDataSet.FieldDefs.AddFieldDef;
- FD.Name := 'FileName';
- FD.DataType := ftString;
- FD.Size := 1024;
-
- FD := PurgeDataSet.FieldDefs.AddFieldDef;
- FD.Name := 'TimeStamp';
- FD.DataType := ftDatetime;
-
- PurgeDataSet.CreateDataSet;
- PurgeDataSet.AddIndex('Purge_Idx','TimeStamp;FileName',[]);
- PurgeDataSet.IndexName := 'Purge_Idx';
-
- Except
- if Assigned(PurgeDataSet) then PurgeDataSet.Free;
- PurgeDataSet := nil;
- end;
- finally
- Result := PurgeDataSet;
- end;
- end;
-
- destructor TPuregMock.Destroy;
- begin
- if Assigned(FPurgeMockParams) then
- begin
- FPurgeMockParams := nil;
- end;
-
- inherited Destroy;
- end;
-
- function TPuregMock.MakePurgeFileList: Integer;
- var
- SearchOption: TSearchOption;
- SearchDir : TDirectory;
- SearchFileMask : String;
- LList: TStringDynArray;
- FileFullName,FileName : String;
- CanAddList : Boolean;
- PerlRegEx: TPerlRegEx;
- PurgeFile : TFile;
-
- begin
-
- Result := 0;
-
-
- PerlRegEx:= TPerlRegEx.Create;
- try
- SearchOption := TSearchOption.soTopDirectoryOnly;
- SearchFileMask := FPurgeMockParams.FileMask;
-
-
- if FPurgeMockParams.UseRegularExpression then
- begin
- PerlRegEx.RegEx := SearchFileMask;
- SearchFileMask := '*.*';
- end;
-
- try
- LList := SearchDir.GetFiles(FPurgeMockParams.FTargetDir,SearchFileMask, SearchOption);
- FPurgeMockDataSet.Active := true;
- for FileFullName in LList do
- begin
- CanAddList := true;
- if FPurgeMockParams.UseRegularExpression then
- begin
- FileName := ExtractFileName(FileFullName);
- PerlRegEx.Subject := FileName;
- CanAddList := PerlRegEx.Match;
- end;
-
- if CanAddList then
- begin
-
- FPurgeMockDataSet.Append;
- FPurgeMockDataSet.FieldByName('FileName').AsString := FileFullName;
- if FPurgeMockParams.FPurgeTimeStamp = ptCreate then
- begin
- FPurgeMockDataSet.FieldByName('TimeStamp').AsDateTime := PurgeFile.GetCreationTime(FileFullName);
- end
- else
- begin
- FPurgeMockDataSet.FieldByName('TimeStamp').AsDateTime := PurgeFile.GetLastAccessTime(FileFullName);
- end;
- FPurgeMockDataSet.Post;
- end;
- end;
- Result := FPurgeMockDataSet.RecordCount;
-
- except
- Result := -1;
- end;
- finally
- if Assigned(PerlRegEx) then PerlRegEx.Free;
-
- end;
- end;
-
- function TPuregMock.ExecPurge: Integer;
- var
- DeleteCount : integer;
- DeleteFileName : string;
- PurgeFile : TFile;
- begin
- DeleteCount := 0;
-
- try
- FPurgeMockDataSet.Active := true;
- FPurgeMockDataSet.First;
-
- while not(FPurgeMockDataSet.Eof) do
- begin
- DeleteFileName := FPurgeMockDataSet.FieldByName('FileName').AsString;
- PurgeFile.Delete(DeleteFileName);
- inc(DeleteCount);
-
-
- FPurgeMockDataSet.Delete;
- if FPurgeMockDataSet.RecordCount <= FPurgeMockParams.LeavingGenerations then Break;
- end;
- Result := DeleteCount;
-
- Except
- Result := -1;
- end;
- end;
-
- function TryParseCmdLineSw(ParameterString : String;
- Sw : Array of String;
- var ParamValue : String;
- IgnoreCase: Boolean) : boolean;
- var
- i : integer;
- begin
-
- Result := false;
-
- if Length(Sw) = 0 then
- begin
-
- ParamValue := ParameterString;
- Result := true;
- end
- else
- begin
- for i := low(Sw) to high(Sw) do
- begin
- if IgnoreCase then
- begin
- if StartsText(Sw[i],ParameterString) then
- begin
- Result := true;
- ParamValue := ReplaceText(ParameterString,Sw[i],'');
- Break;
- end;
- end
- else
- begin
- if StartsStr(Sw[i],ParameterString) then
- begin
- Result := true;
- ParamValue := ReplaceStr(ParameterString,Sw[i],'');
- Break;
- end;
- end;
- end;
- end;
-
- end;
-
- end.
unit PurgeMockImp;
interface
uses
SysUtils
,DB
,DBClient
;
type
TPurgeTimeStamp = (ptCreate, ptUpdate);
TPurgeMockParams = class
private
FTargetDir: String;
FUseRegularExpression: Boolean;
FFileMask: String;
FLeavingGenerations: Integer;
FPurgeTimeStamp: TPurgeTimeStamp;
procedure SetTargetDir(val: String);
procedure SetUseRegularExpression(val: Boolean);
procedure SetFileMask(val: String);
procedure SetLeavingGenerations(val: Integer);
procedure SetPurgeTimeStamp(val: TPurgeTimeStamp);
public
property TargetDir: String read FTargetDir write SetTargetDir;
property UseRegularExpression: Boolean read FUseRegularExpression
write SetUseRegularExpression;
property FileMask: String read FFileMask write SetFileMask;
property LeavingGenerations: Integer read FLeavingGenerations
write SetLeavingGenerations;
property PurgeTimeStamp: TPurgeTimeStamp read FPurgeTimeStamp
write SetPurgeTimeStamp;
procedure Init(ExePath: String);
procedure SetPurgeParam(PurgeParam : String);
end;
TPuregMock = class
public
constructor Create(Params: TPurgeMockParams);
function Purge: Integer;
destructor Destroy; override;
strict private
FPurgeMockParams: TPurgeMockParams;
FPurgeMockDataSet : TClientDataSet;
function MakePurgeFileList: Integer;
function ExecPurge: Integer;
function CreatePurgeDataSet : TClientDataSet;
end;
function TryParseCmdLineSw(ParameterString : String; Sw : Array of String; var ParamValue : String; IgnoreCase: Boolean = true) : boolean;
implementation
Uses
StrUtils
,IOUtils
,Types
,RegularExpressionsCore
;
procedure TPurgeMockParams.SetTargetDir(val: String);
begin
FTargetDir := val;
end;
procedure TPurgeMockParams.SetUseRegularExpression(val: Boolean);
begin
FUseRegularExpression := val;
end;
procedure TPurgeMockParams.Init(ExePath: String);
begin
FTargetDir := ExtractFileDir(ExePath);
FUseRegularExpression := false;
FileMask := '*.*';
FLeavingGenerations := 1;
FPurgeTimeStamp := ptUpdate;
end;
procedure TPurgeMockParams.SetFileMask(val: String);
begin
FFileMask := val
end;
procedure TPurgeMockParams.SetLeavingGenerations(val: Integer);
begin
if Val >= 0 then
begin
FLeavingGenerations := val;
end
else
begin
FLeavingGenerations := 0;
end;
end;
procedure TPurgeMockParams.SetPurgeParam(PurgeParam: String);
var
ValueStr : String;
begin
if TryParseCmdLineSw(PurgeParam,['/D:','-D:'],ValueStr) then
begin
FTargetDir := ValueStr;
Exit;
end;
if TryParseCmdLineSw(PurgeParam,['/U:','-U:'],ValueStr) then
begin
FUseRegularExpression := true;
Exit;
end;
if TryParseCmdLineSw(PurgeParam,['/G:','-G:'],ValueStr) then
begin
LeavingGenerations := StrToIntDef(ValueStr,1);
Exit;
end;
if TryParseCmdLineSw(PurgeParam,['/T:','-T:'],ValueStr) then
begin
FPurgeTimeStamp := ptCreate;
Exit;
end;
if TryParseCmdLineSw(PurgeParam,[],ValueStr) then
begin
FFileMask := ValueStr;
Exit;
end;
end;
procedure TPurgeMockParams.SetPurgeTimeStamp(val: TPurgeTimeStamp);
begin
FPurgeTimeStamp := val;
end;
constructor TPuregMock.Create(Params: TPurgeMockParams);
begin
inherited Create;
FPurgeMockParams := Params;
end;
function TPuregMock.Purge: Integer;
begin
Result := -1;
FPurgeMockDataSet := CreatePurgeDataSet;
if Assigned(FPurgeMockDataSet) then
begin
if MakePurgeFileList > 0 then
begin
Result := ExecPurge;
end;
FPurgeMockDataSet.EmptyDataSet;
FPurgeMockDataSet.Active := false;
FPurgeMockDataSet.Free;
end;
end;
function TPuregMock.CreatePurgeDataSet: TClientDataSet;
var
PurgeDataSet : TClientDataSet;
FD : TFieldDef;
begin
PurgeDataSet := TClientDataSet.Create(nil);
try
try
FD := PurgeDataSet.FieldDefs.AddFieldDef;
FD.Name := 'FileName';
FD.DataType := ftString;
FD.Size := 1024;
FD := PurgeDataSet.FieldDefs.AddFieldDef;
FD.Name := 'TimeStamp';
FD.DataType := ftDatetime;
PurgeDataSet.CreateDataSet;
PurgeDataSet.AddIndex('Purge_Idx','TimeStamp;FileName',[]);
PurgeDataSet.IndexName := 'Purge_Idx';
Except
if Assigned(PurgeDataSet) then PurgeDataSet.Free;
PurgeDataSet := nil;
end;
finally
Result := PurgeDataSet;
end;
end;
destructor TPuregMock.Destroy;
begin
if Assigned(FPurgeMockParams) then
begin
FPurgeMockParams := nil;
end;
inherited Destroy;
end;
function TPuregMock.MakePurgeFileList: Integer;
var
SearchOption: TSearchOption;
SearchDir : TDirectory;
SearchFileMask : String;
LList: TStringDynArray;
FileFullName,FileName : String;
CanAddList : Boolean;
PerlRegEx: TPerlRegEx;
PurgeFile : TFile;
begin
Result := 0;
//使っても使わなくても正規表現用のクラスをオープンしておく。
PerlRegEx:= TPerlRegEx.Create;
try
SearchOption := TSearchOption.soTopDirectoryOnly;
SearchFileMask := FPurgeMockParams.FileMask;
if FPurgeMockParams.UseRegularExpression then
begin
PerlRegEx.RegEx := SearchFileMask;
SearchFileMask := '*.*';
end;
try
LList := SearchDir.GetFiles(FPurgeMockParams.FTargetDir,SearchFileMask, SearchOption);
FPurgeMockDataSet.Active := true;
for FileFullName in LList do
begin
CanAddList := true;
if FPurgeMockParams.UseRegularExpression then
begin
FileName := ExtractFileName(FileFullName);
PerlRegEx.Subject := FileName;
CanAddList := PerlRegEx.Match;
end;
if CanAddList then
begin
//パージ対象リストに追加
FPurgeMockDataSet.Append;
FPurgeMockDataSet.FieldByName('FileName').AsString := FileFullName;
if FPurgeMockParams.FPurgeTimeStamp = ptCreate then
begin
FPurgeMockDataSet.FieldByName('TimeStamp').AsDateTime := PurgeFile.GetCreationTime(FileFullName);
end
else
begin
FPurgeMockDataSet.FieldByName('TimeStamp').AsDateTime := PurgeFile.GetLastAccessTime(FileFullName);
end;
FPurgeMockDataSet.Post;
end;
end;
Result := FPurgeMockDataSet.RecordCount;
except
Result := -1;
end;
finally
if Assigned(PerlRegEx) then PerlRegEx.Free;
end;
end;
function TPuregMock.ExecPurge: Integer;
var
DeleteCount : integer;
DeleteFileName : string;
PurgeFile : TFile;
begin
DeleteCount := 0;
try
FPurgeMockDataSet.Active := true;
FPurgeMockDataSet.First;
while not(FPurgeMockDataSet.Eof) do
begin
DeleteFileName := FPurgeMockDataSet.FieldByName('FileName').AsString;
PurgeFile.Delete(DeleteFileName);
inc(DeleteCount);
//レコードをDeleteした場合は、Next不要なので注意
FPurgeMockDataSet.Delete;
if FPurgeMockDataSet.RecordCount <= FPurgeMockParams.LeavingGenerations then Break;
end;
Result := DeleteCount;
Except
Result := -1;
end;
end;
function TryParseCmdLineSw(ParameterString : String;
Sw : Array of String;
var ParamValue : String;
IgnoreCase: Boolean) : boolean;
var
i : integer;
begin
Result := false;
if Length(Sw) = 0 then
begin
//SW指定がない場合はそのままの文字列を返す
ParamValue := ParameterString;
Result := true;
end
else
begin
for i := low(Sw) to high(Sw) do
begin
if IgnoreCase then
begin
if StartsText(Sw[i],ParameterString) then
begin
Result := true;
ParamValue := ReplaceText(ParameterString,Sw[i],'');
Break;
end;
end
else
begin
if StartsStr(Sw[i],ParameterString) then
begin
Result := true;
ParamValue := ReplaceStr(ParameterString,Sw[i],'');
Break;
end;
end;
end;
end;
end;
end.