Skip to content

Commit 691a404

Browse files
committed
Converted BSPPak to CommandLineParser and added start of testing for it
1 parent 645bab4 commit 691a404

File tree

5 files changed

+128
-62
lines changed

5 files changed

+128
-62
lines changed

BSPLumpExtract/Program.cs

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System;
22
using System.IO;
3-
using System.Linq;
43
using CommandLine;
54
using LibBSP;
65

BSPPak/FileFinder.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ private static bool HasFilterFile(string dir)
2323
}
2424

2525
/// <summary>
26-
/// Returns an array of files contained in the specified directory and recursively in sub-directories.
26+
/// Returns a collection of files contained in the specified directory and recursively in sub-directories.
2727
/// If the directory has a ".pakfilter" file, it will be used to filter which files to find.
2828
/// The .pakfilter file contains a list of filtering rules with the same syntax as the .gitignore file in Git. However,
2929
/// contrary to the .gitignore file which is a blacklist, the .pakfilter file is a whitelist.

BSPPak/InvalidOptionException.cs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System;
2+
3+
namespace BSPPak
4+
{
5+
public class InvalidOptionException : Exception
6+
{
7+
public InvalidOptionException(string msg) : base(msg)
8+
{
9+
}
10+
}
11+
}

BSPPak/Program.cs

+68-60
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,24 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.IO;
34
using System.IO.Compression;
5+
using CommandLine;
46
using LibBSP;
57

68
namespace BSPPak
79
{
8-
internal class Program
10+
public class Program
911
{
10-
private static void Main(string[] args)
11-
{
12-
// TODO: use a proper parameter parsing plugin
13-
if (args.Length < 2 || args.Length > 3)
14-
{
15-
Console.WriteLine("Usage: BSPPak \"C:/Path/To/Map.bsp\" \"C:/Path/To/Content/Folder\"");
16-
Console.WriteLine("Usage: BSPPak -d \"C:/Path/To/Map.bsp\" \"C:/Path/To/Content/Folder\"");
17-
Console.WriteLine(
18-
"The content folder can contain a file named \".pakfilter\" which contains .gitignore-like syntax for matching which files to pack. " +
19-
"Remember that the .pakfilter file matches inversely to a regular .gitignore, .gitignore acts as a blacklist while .pakfilter acts as a whitelist.");
20-
Console.WriteLine("Use the -d flag to mark it as a dry run where the bsp will not get edited.");
21-
return;
22-
}
23-
24-
bool isDryRun;
25-
string bspPath;
26-
string contentPath;
27-
if (args.Length == 2)
28-
{
29-
isDryRun = false;
30-
bspPath = args[0];
31-
contentPath = args[1];
32-
}
33-
else
34-
{
35-
isDryRun = true;
36-
bspPath = args[1];
37-
contentPath = args[2];
38-
}
39-
40-
var files = FileFinder.Find(contentPath);
41-
42-
if (isDryRun)
43-
{
44-
foreach (var item in files)
45-
Console.WriteLine(ToRelativePath(item, contentPath));
46-
Console.WriteLine($"Found {files.Count} files matching the filter.");
47-
Console.WriteLine("Finished, dry run");
48-
return;
49-
}
50-
51-
if (files.Count == 0)
52-
{
53-
Console.WriteLine("No files found that matches the filter. Exiting.");
54-
return;
55-
}
12+
public const int ExitFail = 1;
5613

14+
public static void PackFiles(Options opts, IReadOnlyCollection<string> files)
15+
{
5716
Console.WriteLine($"Found {files.Count} files matching the filter.");
5817

59-
if (!File.Exists(bspPath))
60-
{
61-
Console.WriteLine("Invalid bsp specified");
62-
return;
63-
}
18+
Console.WriteLine($"Reading from {Path.GetFileName(opts.BSPPath)}");
19+
var bsp = new BSP(opts.BSPPath);
6420

65-
Console.WriteLine("Reading and parsing BSP");
66-
var bsp = new BSP(bspPath);
67-
68-
var pakLump = (PakfileLump) bsp.Lumps[40];
21+
var pakLump = (PakfileLump) bsp.Lumps[(int) LumpType.Pakfile];
6922
var archive = pakLump.OpenArchiveStream(ZipArchiveMode.Update);
7023

7124
var i = 0;
@@ -74,7 +27,7 @@ private static void Main(string[] args)
7427
if (i % 50 == 0)
7528
Console.WriteLine($"{i}/{files.Count} Zipping files...");
7629

77-
var relPath = ToRelativePath(file, contentPath);
30+
var relPath = ToRelativePath(file, opts.ContentPath);
7831
var entry = archive.GetEntry(relPath);
7932
if (entry != null)
8033
Console.WriteLine($"{relPath} already packed, overwriting...");
@@ -90,18 +43,73 @@ private static void Main(string[] args)
9043

9144
pakLump.CloseArchiveStream();
9245

93-
Console.WriteLine("Writing BSP");
94-
bsp.WriteBSP(bspPath);
46+
Console.WriteLine($"Writing to {Path.GetFileName(opts.BSPPath)}");
47+
bsp.WriteBSP(opts.BSPPath);
9548

9649
Console.WriteLine("Done!");
9750
}
9851

99-
private static string ToRelativePath(string fullPath, string relDir)
52+
public static void PrintFiles(Options opts, IReadOnlyCollection<string> files)
53+
{
54+
foreach (var item in files)
55+
Console.WriteLine(ToRelativePath(item, opts.ContentPath));
56+
Console.WriteLine($"Found {files.Count} files matching the filter.");
57+
}
58+
59+
public static void ValidateOptions(Options opts)
60+
{
61+
if (!File.Exists(opts.BSPPath))
62+
throw new InvalidOptionException("Invalid .bsp file specified.");
63+
64+
if (!Directory.Exists(opts.ContentPath))
65+
throw new InvalidOptionException("Invalid content folder specified.");
66+
}
67+
68+
private static void Main(string[] args)
69+
{
70+
Parser.Default.ParseArguments<Options>(args)
71+
.WithParsed(opts =>
72+
{
73+
try
74+
{
75+
ValidateOptions(opts);
76+
}
77+
catch (InvalidOptionException e)
78+
{
79+
Console.WriteLine(e.Message);
80+
Environment.ExitCode = ExitFail;
81+
return;
82+
}
83+
84+
var files = FileFinder.Find(opts.ContentPath);
85+
86+
if (opts.DryRun)
87+
PrintFiles(opts, files);
88+
else
89+
PackFiles(opts, files);
90+
});
91+
}
92+
93+
public static string ToRelativePath(string fullPath, string relDir)
10094
{
10195
if (!fullPath.StartsWith(relDir))
10296
throw new ArgumentException("relDir is not a parent directory to fullPath!");
10397

10498
return fullPath.Substring(relDir.Length).TrimStart('/', '\\');
10599
}
100+
101+
public class Options
102+
{
103+
[Option('d', "dry-run", Required = false,
104+
HelpText =
105+
"Only output a list of files found in the content folder that passes the filter. The BSP file won't be edited.")]
106+
public bool DryRun { get; set; }
107+
108+
[Value(0, MetaName = "BSP file", HelpText = "The .bsp file to process.", Required = true)]
109+
public string BSPPath { get; set; }
110+
111+
[Value(1, MetaName = "Content path", HelpText = "The path to the content folder.", Required = true)]
112+
public string ContentPath { get; set; }
113+
}
106114
}
107115
}

BSPUtilsTest/BSPPak/AppTest.cs

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using BSPUtilsTest.TestUtil;
5+
using Xunit;
6+
using App = BSPPak;
7+
using Program = BSPPak.Program;
8+
using Options = BSPPak.Program.Options;
9+
10+
namespace BSPUtilsTest.BSPPak
11+
{
12+
public class AppTest
13+
{
14+
[Fact]
15+
public void TestValidateValidOptions()
16+
{
17+
var opts = new Options
18+
{
19+
BSPPath = "testdata/map.bsp",
20+
ContentPath = "testdata"
21+
};
22+
Program.ValidateOptions(opts); // Should not throw anything
23+
}
24+
25+
[Fact]
26+
public void TestValidateInvalidBSPPath()
27+
{
28+
var opts = new Options
29+
{
30+
BSPPath = "testdata/invalidFile.bsp",
31+
ContentPath = "testdata"
32+
};
33+
Assert.Throws<App.InvalidOptionException>(() => Program.ValidateOptions(opts));
34+
}
35+
36+
[Fact]
37+
public void TestValidateInvalidContentPath()
38+
{
39+
var opts = new Options
40+
{
41+
BSPPath = "testdata/map.bsp",
42+
ContentPath = "testdataInvalid"
43+
};
44+
Assert.Throws<App.InvalidOptionException>(() => Program.ValidateOptions(opts));
45+
}
46+
47+
}
48+
}

0 commit comments

Comments
 (0)