Skip to content

Commit

Permalink
v3.1 diff-add-keep etc
Browse files Browse the repository at this point in the history
  • Loading branch information
tomchen committed Apr 1, 2020
1 parent 0245b64 commit 3a8fcf1
Show file tree
Hide file tree
Showing 10 changed files with 168 additions and 107 deletions.
20 changes: 14 additions & 6 deletions MMArchCompare.pas
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ procedure generateScript(deletedFolderList, deletedNonResFileList, deletedResFil
var
scriptString, elTemp, strTemp: string;
tslTemp: TStringList;
noRes: boolean;

begin

Expand All @@ -269,6 +270,8 @@ procedure generateScript(deletedFolderList, deletedNonResFileList, deletedResFil
deletedResFileList.Sort;
modifiedArchiveList.Sort;

noRes := (deletedResFileList.Count = 0) and (modifiedArchiveList.Count = 0);

if isNsis then // NSIS
begin

Expand Down Expand Up @@ -314,9 +317,12 @@ procedure generateScript(deletedFolderList, deletedNonResFileList, deletedResFil
#13#10 +
';-----FILE COPYING (MODIFYING, DELETING) STARTS HERE-----'#13#10 +
#13#10 +
' SetOutPath $INSTDIR'#13#10 +
' File mmarch.exe'#13#10 +
#13#10;
' SetOutPath $INSTDIR'#13#10;

if not noRes then
scriptString := scriptString + ' File mmarch.exe'#13#10;

scriptString := scriptString + #13#10;

if deletedFolderList.Count > 0 then
begin
Expand All @@ -327,7 +333,7 @@ procedure generateScript(deletedFolderList, deletedNonResFileList, deletedResFil
scriptString := scriptString + #13#10;
end;

scriptString := scriptString +' File /r /x *' + ToDeleteExt + ' ' + withTrailingSlash(beautifyPath(diffFileFolderName)) + '*.*'#13#10 +
scriptString := scriptString +' File /r /x *' + ToDeleteExt + ' /x *' + EmptyFolderKeep + ' ' + withTrailingSlash(beautifyPath(diffFileFolderName)) + '*.*'#13#10 +
#13#10;

if deletedNonResFileList.Count > 0 then
Expand Down Expand Up @@ -364,8 +370,10 @@ procedure generateScript(deletedFolderList, deletedNonResFileList, deletedResFil
scriptString := scriptString + #13#10;
end;

if not noRes then
scriptString := scriptString + ' Delete "mmarch.exe"'#13#10;

scriptString := scriptString +
' Delete "mmarch.exe"'#13#10 +
#13#10 +
';-----FILE COPYING (MODIFYING, DELETING) ENDS HERE-----'#13#10 +
#13#10 +
Expand All @@ -385,7 +393,7 @@ procedure generateScript(deletedFolderList, deletedNonResFileList, deletedResFil
scriptString := scriptString + #13#10;

scriptString := scriptString +
'echo ' + ToDeleteExt + '>excludelist.txt'#13#10 +
'(echo ' + ToDeleteExt + ' && echo ' + EmptyFolderKeep + ')>excludelist.txt'#13#10 +
'Xcopy files . /s /e /y /EXCLUDE:excludelist.txt'#13#10 +
'del excludelist.txt'#13#10 +
#13#10;
Expand Down
111 changes: 83 additions & 28 deletions MMArchPath.pas
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ function getAllFilesInFolder(path: string; ext: string = '*'; isDir: boolean = f

procedure addAllFilesToFileList(var fileList: TStringList; path: string; recursive: integer; isDir: boolean; usePathFilenamePair: boolean; extList: TStringList); overload;
procedure addAllFilesToFileList(var fileList: TStringList; path: string; recursive: integer; isDir: boolean; usePathFilenamePair: boolean); overload;
procedure addKeepToAllEmptyFoldersRecur(folder: string);

function beautifyPath(oldStr: String): string;
function withTrailingSlash(path: string): string;
Expand All @@ -33,13 +34,16 @@ procedure createDirRecur(dir: string);
procedure copyFile0(oldFile, newFile: string);
function createEmptyFile(filePath: string): boolean;
procedure StrToFile(filePath, SourceString: string);
function isSubfolder(folder, potentialSubfolder: string): boolean;
function moveDir(folderFrom, folderTo: string): Boolean;
procedure delDir(folder: string);

const
nameValSeparator: char = ':';
archResSeparator: char = ':';

EmptyFolderKeep: string = '.mmarchkeep';

supportedExts: array[0..7] of string = ('.lod', '.pac', '.snd', '.vid', '.lwd', '.mm7', '.dod', '.mm6');

{$IFDEF MSWINDOWS}
Expand Down Expand Up @@ -219,18 +223,24 @@ function getAllFilesInFolder(path: string; ext: string = '*'; isDir: boolean = f
if findfirst(fileMask, attr, searchResult) = 0 then
begin
repeat
if ( (
(not isDir) and
FileExists(searchResult.Name)
) or (
isDir and
( (searchResult.attr and faDirectory) = faDirectory ) and
(searchResult.Name <> '.') and
(searchResult.Name <> '..')
) ) and (
if (
(
(not isDir) and
FileExists(searchResult.Name)
) or (
isDir and
( (searchResult.attr and faDirectory) = faDirectory ) and
(searchResult.Name <> '.') and
(searchResult.Name <> '..')
)
)
and
(
(fileMask <> '*.') or
( (fileMask = '*.') and (ExtractFileExt(searchResult.Name) = '') )
)
and
(searchResult.Name <> EmptyFolderKeep) // special: ignore all .mmarchkeep file
then
Result.Add(searchResult.Name);
until FindNext(searchResult) <> 0;
Expand All @@ -247,10 +257,10 @@ procedure addAllFilesToFileListNonRecur(var fileList: TStringList; path: string;
begin
for ext in extList do
for fileName in getAllFilesInFolder(path, ext, isDir) do
if usePathFilenamePair then
fileList.Add(fileName + nameValSeparator + beautifyPath(path))
else
fileList.Add(withTrailingSlash(beautifyPath(path)) + fileName);
if usePathFilenamePair then
fileList.Add(fileName + nameValSeparator + beautifyPath(path))
else
fileList.Add(withTrailingSlash(beautifyPath(path)) + fileName);
end;


Expand All @@ -261,7 +271,10 @@ procedure addAllFilesToFileListNonRecur(var fileList: TStringList; path: string;
begin
extList := TStringList.Create;
extList.Add('*');

addAllFilesToFileListNonRecur(fileList, path, isDir, usePathFilenamePair, extList);

extList.Free;
end;


Expand Down Expand Up @@ -307,6 +320,29 @@ procedure addAllFilesToFileList(var fileList: TStringList; path: string; recursi
extList.Add('*');

addAllFilesToFileList(fileList, path, recursive, isDir, usePathFilenamePair, extList);

extList.Free;
end;


procedure addKeepToAllEmptyFoldersRecur(folder: string);
var
allFolders: TStringList;
elTemp: string;

begin
folder := trimCharsRight(beautifyPath(folder), '\', '/');

allFolders := TStringList.Create;
allFolders.Add(folder);
addAllFilesToFileList(allFolders, folder, 1, true, false);

for elTemp in allFolders do
if (getAllFilesInFolder(elTemp, '*', true).Count = 0)
and (getAllFilesInFolder(elTemp, '*', false).Count = 0) then // folder is empty (but maybe contain .mmarchkeep)
createEmptyFile(withTrailingSlash(elTemp) + EmptyFolderKeep);

allFolders.Free;
end;


Expand Down Expand Up @@ -415,6 +451,20 @@ procedure StrToFile(filePath, SourceString: string);
end;


function isSubfolder(folder, potentialSubfolder: string): boolean;
var
parentFolder, lastParentFolder: string;
begin
parentFolder := trimCharsRight(beautifyPath(potentialSubfolder), '\', '/');
folder := trimCharsRight(beautifyPath(folder), '\', '/');
repeat
lastParentFolder := parentFolder;
parentFolder := trimCharsRight(ExtractFilePath(parentFolder), '\', '/');
Result := (parentFolder = folder);
until (parentFolder = lastParentFolder) or (parentFolder = '') or Result;
end;


function moveDir(folderFrom, folderTo: string): Boolean;
// folderFrom, folderTo cannot be current folder or ancestor folder
var
Expand All @@ -423,24 +473,29 @@ function moveDir(folderFrom, folderTo: string): Boolean;
folderFrom := trimCharsRight(beautifyPath(folderFrom), '\', '/');
folderTo := trimCharsRight(beautifyPath(folderTo), '\', '/');

if folderFrom <> folderTo then
if isSubfolder(folderFrom, folderTo) then
begin
createDirRecur(ExtractFilePath(folderTo));
ZeroMemory(@fos, SizeOf(fos));
with fos do
begin
wFunc := FO_MOVE;
fFlags := FOF_FILESONLY;
pFrom := PChar(folderFrom + #0);
pTo := PChar(folderTo);
end;
Result := (0 = ShFileOperation(fos));
Result := moveDir(folderFrom, folderFrom + '.mmarchtmp');
Result := Result and moveDir(folderFrom + '.mmarchtmp', folderTo);
end
else
begin
Result := false;
end;

if folderFrom <> folderTo then
begin
createDirRecur(ExtractFilePath(folderTo));
ZeroMemory(@fos, SizeOf(fos));
with fos do
begin
wFunc := FO_MOVE;
fFlags := FOF_FILESONLY;
pFrom := PChar(folderFrom + #0);
pTo := PChar(folderTo);
end;
Result := (0 = ShFileOperation(fos));
end
else
begin
Result := false;
end;
end;


Expand Down
54 changes: 20 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

Command line tool to handle (extract, replace, compare resources and more) Heroes of Might and Magic 3 and Might and Magic 6, 7, 8 resource archive files (e.g. lod files) for Windows.

[Download mmarch v3.0](https://github.com/might-and-magic/mmarch/releases/download/v3.0/mmarch.zip)
[Download mmarch v3.1](https://github.com/might-and-magic/mmarch/releases/download/v3.1/mmarch.zip)

Based on [GrayFace's MMArchive](https://grayface.github.io/mm/#MMArchive) ([repo](https://github.com/GrayFace/Misc/)) (mmarch is actually kind of a wrapper of MMArchive). If you need a graphical user interface tool, use MMArchive.
Based on [GrayFace's MMArchive](https://grayface.github.io/mm/#MMArchive) ([repo](https://github.com/GrayFace/Misc/)). If you need a graphical user interface tool, use MMArchive.

## Summary & Table of Contents

Expand Down Expand Up @@ -186,6 +186,8 @@ mmarch merge events.lod events2.lod

Compare two archive files, or two folders containing archive files and/or files of any other type.

`mmarch compare` and all related commands and features (incl. NSIS/batch script generation) work totally even if your folders do not contain any MM archive files at all. Therefore, you can use **mmarch** as a general file comparison and diff generation tool.

(`k` is short for `compare`)

The fourth parameter, `[OPTION]`, can be:
Expand Down Expand Up @@ -232,20 +234,28 @@ Copy all diff files (i.e. non-resource file and extract in-archive resource file

Note that if `DIFF_FOLDER` exsits, it will perform a merger of old diff files and new diff files by cleaning up old diff files. Therefore, you can do: `mmarch compare VERSION_1 VERSION_2 filesonly diff_folder` and then `mmarch compare VERSION_2 VERSION_3 filesonly diff_folder`. It's OK to do VER1 -> VER2 then VER2 -> VER3, or VER1 -> VER3 then VER2 -> VER3. But VER1 -> VER2 then VER1 -> VER3 will cause problem ([image demo](tutorial/img/multi_version.png)). This merger (cleanup) is only performed in `filesonly` command, and not in `nsis` or `batch`.

### `compare-files-to-nsis`/`-batch`
### `diff-files-to-nsis`/`-batch`, `diff-add-keep`

There are also two special commands:
There are also 3 special commands related to `compare`:

```
mmarch compare-files-to-nsis <OLD_DIFF_FOLDER> <SCRIPT_FILE> <DIFF_FOLDER_NAME>
or
mmarch compare-files-to-batch <OLD_DIFF_FOLDER> <SCRIPT_FILE> <DIFF_FOLDER_NAME>
mmarch diff-files-to-nsis <OLD_DIFF_FOLDER> <SCRIPT_FILE> <DIFF_FOLDER_NAME>
OR
mmarch diff-files-to-batch <OLD_DIFF_FOLDER> <SCRIPT_FILE> <DIFF_FOLDER_NAME>
```

(`cf2n` is short for `compare-files-to-nsis`; `cf2b` is short for `compare-files-to-batch`)
(`df2n` is short for `diff-files-to-nsis`; `df2b` is short for `diff-files-to-batch`)

The former command generates a .nsi script file, while the later command generates a .bat (Window Batch) file `SCRIPT_FILE`, according to the files in `[OLD_DIFF_FOLDER]` that you get using `filesonly` option of `mmarch compare`. `[OLD_DIFF_FOLDER]` will then be moved to `SCRIPT_FILE`'s folder (becoming its subfolder) and renamed with `DIFF_FOLDER_NAME`.

```
mmarch diff-add-keep <DIFF_FOLDER>
```

(`dak` is short for `diff-add-keep`)

This is for developers using Git. It will add an empty file `.mmarchkeep` to every empty folder in `DIFF_FOLDER`, so that Git can keep the empty folders tracked. `diff-files-to-nsis`/`-batch` ignore `.mmarchkeep` files.

**`compare` mixed examples:**
```
mmarch compare game_folder_old game_folder_new nsis nsis_folder/script.nsi files
Expand All @@ -255,7 +265,7 @@ mmarch compare game_folder_old game_folder_new nsis nsis_folder/script.nsi files

```
mmarch compare game_folder_old game_folder_new filesonly diff_folder_temp
mmarch compare-files-to-nsis diff_folder_temp nsis_folder/script.nsi files
mmarch diff-files-to-nsis diff_folder_temp nsis_folder/script.nsi files
```

## `optimize`
Expand Down Expand Up @@ -455,31 +465,6 @@ A user may:

The batch file will not perform a self-deletion, users have to delete .bat, mmarch.exe and `DIFF_FOLDER` manually.

### Other Batch scripts

Simple demostration of some non-straightforward, advanced usages of batch file:

Save the resource list (one file name per line) in an archive as a txt file:

```
mmarch list events.lod> events_temp_list.txt
```

Save the resource list in an archive as a txt file, with `|` as leading, trailing character and separators. Then search to see if `D17.STR` file exists in the archive:

```
@echo|set /p="|"> events_temp_list.txt
mmarch list events.loD "|">> events_temp_list.txt
@echo|set /p="|">> events_temp_list.txt
findstr "|D17.STR|" events_temp_list.txt
IF %errorlevel% == 0 (
echo Found!
) ELSE (
echo Not found!
)
```

## Compilation

How to compile the source of **mmarch**:
Expand All @@ -494,6 +479,7 @@ How to compile the source of **mmarch**:
* [2020-03-11] v1.0: initial release
* [2020-03-18] v2.0: support palette; support `*.EXT` and batch archive extraction; deal with in-archive & extracted file extension differences and the "cannot find the path specified" problem caused by it
* [2020-03-31] v3.0: add `compare` method that can compare two dir and generate NSIS/Batch installer; tutorial
* [2020-04-02] v3.1: diff-files-to-* instead of compare-files-to-*; diff-add-keep; fix problem moving to subfolder

## License

Expand Down
6 changes: 3 additions & 3 deletions mmarch.bdsproj
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@
<VersionInfo Name="IncludeVerInfo">True</VersionInfo>
<VersionInfo Name="AutoIncBuild">False</VersionInfo>
<VersionInfo Name="MajorVer">3</VersionInfo>
<VersionInfo Name="MinorVer">0</VersionInfo>
<VersionInfo Name="MinorVer">1</VersionInfo>
<VersionInfo Name="Release">0</VersionInfo>
<VersionInfo Name="Build">0</VersionInfo>
<VersionInfo Name="Debug">False</VersionInfo>
Expand All @@ -157,13 +157,13 @@
<VersionInfoKeys>
<VersionInfoKeys Name="CompanyName">Tom CHEN</VersionInfoKeys>
<VersionInfoKeys Name="FileDescription">Command line tool to handle Heroes 3 &amp; Might and Magic 678 archive</VersionInfoKeys>
<VersionInfoKeys Name="FileVersion">3.0.0.0</VersionInfoKeys>
<VersionInfoKeys Name="FileVersion">3.1.0.0</VersionInfoKeys>
<VersionInfoKeys Name="InternalName"></VersionInfoKeys>
<VersionInfoKeys Name="LegalCopyright">MIT License (c) 2020 Tom CHEN</VersionInfoKeys>
<VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys>
<VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys>
<VersionInfoKeys Name="ProductName">mmarch</VersionInfoKeys>
<VersionInfoKeys Name="ProductVersion">3.0.0.0</VersionInfoKeys>
<VersionInfoKeys Name="ProductVersion">3.1.0.0</VersionInfoKeys>
<VersionInfoKeys Name="Comments"></VersionInfoKeys>
</VersionInfoKeys>
</Delphi.Personality>
Expand Down
Loading

0 comments on commit 3a8fcf1

Please sign in to comment.