From a6f6ed715416b734f6fe6c5bfc7dfa306a0e95e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Lampron?= Date: Mon, 27 Apr 2026 22:24:46 -0400 Subject: [PATCH 1/5] feat: support opening builds from builds folder via command line argument --- src/Modules/Main.lua | 47 +++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/src/Modules/Main.lua b/src/Modules/Main.lua index 9905923bb..febf808f1 100644 --- a/src/Modules/Main.lua +++ b/src/Modules/Main.lua @@ -60,19 +60,26 @@ function main:Init() self.gameAccounts = { } local ignoreBuild + local pendingBuildName if arg[1] then - local importLink = buildSites.ParseImportLinkFromURI(arg[1]) - buildSites.DownloadBuild(arg[1], nil, function(isSuccess, data, importLink) - if not isSuccess then - self:SetMode("BUILD", false, data) - else - local xmlText = Inflate(common.base64.decode(data:gsub("-","+"):gsub("_","/"))) - self:SetMode("BUILD", false, "Imported Build", xmlText, false, importLink) - self.newModeChangeToTree = true - end - end) + if arg[1]:lower():match("%.xml$") then + -- Build name passed as argument, resolved against buildPath after settings load + pendingBuildName = arg[1]:gsub("\\", "/") + ignoreBuild = true + else + local importLink = buildSites.ParseImportLinkFromURI(arg[1]) + buildSites.DownloadBuild(arg[1], nil, function(isSuccess, data, importLink) + if not isSuccess then + self:SetMode("BUILD", false, data) + else + local xmlText = Inflate(common.base64.decode(data:gsub("-","+"):gsub("_","/"))) + self:SetMode("BUILD", false, "Imported Build", xmlText, false, importLink) + self.newModeChangeToTree = true + end + end) + ignoreBuild = true + end arg[1] = nil -- Protect against downloading again this session. - ignoreBuild = true end if not ignoreBuild then @@ -143,6 +150,24 @@ function main:Init() self:ChangeUserPath(self.userPath, ignoreBuild) end + -- Open a build by name from the builds folder (passed via command line) + if pendingBuildName and self.buildPath then + -- Ensure it ends with .xml and resolve relative to buildPath + local fileName = pendingBuildName:match("([^/]+)$") + if fileName then + local buildFile = self.buildPath .. fileName + if not buildFile:lower():match("%.xml$") then + buildFile = buildFile .. ".xml" + end + local file = io.open(buildFile, "r") + if file then + file:close() + local buildName = fileName:gsub("%.xml$", "") + self:SetMode("BUILD", buildFile, buildName) + end + end + end + self.uniqueDB = { list = { }, loading = true } self.rareDB = { list = { }, loading = true } From fef422f60ed3b79e107b769e16f4e34e790cbb04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Lampron?= Date: Mon, 27 Apr 2026 22:40:50 -0400 Subject: [PATCH 2/5] Handle subfolders --- src/Modules/Main.lua | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Modules/Main.lua b/src/Modules/Main.lua index febf808f1..40290ec99 100644 --- a/src/Modules/Main.lua +++ b/src/Modules/Main.lua @@ -152,17 +152,17 @@ function main:Init() -- Open a build by name from the builds folder (passed via command line) if pendingBuildName and self.buildPath then - -- Ensure it ends with .xml and resolve relative to buildPath - local fileName = pendingBuildName:match("([^/]+)$") - if fileName then - local buildFile = self.buildPath .. fileName - if not buildFile:lower():match("%.xml$") then - buildFile = buildFile .. ".xml" + -- Reject path traversal attempts + if not pendingBuildName:match("%.%.") then + local relativePath = pendingBuildName + if not relativePath:lower():match("%.xml$") then + relativePath = relativePath .. ".xml" end + local buildFile = self.buildPath .. relativePath local file = io.open(buildFile, "r") if file then file:close() - local buildName = fileName:gsub("%.xml$", "") + local buildName = relativePath:match("([^/]+)%.xml$") or relativePath self:SetMode("BUILD", buildFile, buildName) end end From e90573f01082f3eecc4fff3afd7d4c9644b953d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Lampron?= Date: Mon, 27 Apr 2026 22:45:56 -0400 Subject: [PATCH 3/5] Simplify the logic --- src/Modules/Main.lua | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/src/Modules/Main.lua b/src/Modules/Main.lua index 40290ec99..653ced8a5 100644 --- a/src/Modules/Main.lua +++ b/src/Modules/Main.lua @@ -60,11 +60,10 @@ function main:Init() self.gameAccounts = { } local ignoreBuild - local pendingBuildName + local pendingBuildFile if arg[1] then if arg[1]:lower():match("%.xml$") then - -- Build name passed as argument, resolved against buildPath after settings load - pendingBuildName = arg[1]:gsub("\\", "/") + pendingBuildFile = arg[1]:gsub("\\", "/") ignoreBuild = true else local importLink = buildSites.ParseImportLinkFromURI(arg[1]) @@ -150,21 +149,14 @@ function main:Init() self:ChangeUserPath(self.userPath, ignoreBuild) end - -- Open a build by name from the builds folder (passed via command line) - if pendingBuildName and self.buildPath then - -- Reject path traversal attempts - if not pendingBuildName:match("%.%.") then - local relativePath = pendingBuildName - if not relativePath:lower():match("%.xml$") then - relativePath = relativePath .. ".xml" - end - local buildFile = self.buildPath .. relativePath - local file = io.open(buildFile, "r") - if file then - file:close() - local buildName = relativePath:match("([^/]+)%.xml$") or relativePath - self:SetMode("BUILD", buildFile, buildName) - end + -- Open a build file from the builds folder (passed via command line) + if pendingBuildFile and self.buildPath and not pendingBuildFile:match("%.%.") then + local buildFile = self.buildPath .. pendingBuildFile + local file = io.open(buildFile, "r") + if file then + file:close() + local buildName = pendingBuildFile:match("([^/]+)%.xml$") or pendingBuildFile + self:SetMode("BUILD", buildFile, buildName) end end From 5c07df022d7e24db5b05d993eb00923810a76070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Lampron?= Date: Tue, 28 Apr 2026 00:22:55 -0400 Subject: [PATCH 4/5] handle full file path --- src/Modules/Main.lua | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Modules/Main.lua b/src/Modules/Main.lua index 653ced8a5..77c760920 100644 --- a/src/Modules/Main.lua +++ b/src/Modules/Main.lua @@ -150,14 +150,24 @@ function main:Init() end -- Open a build file from the builds folder (passed via command line) - if pendingBuildFile and self.buildPath and not pendingBuildFile:match("%.%.") then - local buildFile = self.buildPath .. pendingBuildFile - local file = io.open(buildFile, "r") + if pendingBuildFile and not pendingBuildFile:match("%.%.") then + local buildFile + -- Check if it's an absolute path (drive letter on Windows or / on Unix) + if pendingBuildFile:match("^%a:/") or pendingBuildFile:match("^/") then + buildFile = pendingBuildFile + elseif self.buildPath then + buildFile = self.buildPath .. pendingBuildFile + end + local file = buildFile and io.open(buildFile, "r") if file then file:close() local buildName = pendingBuildFile:match("([^/]+)%.xml$") or pendingBuildFile self:SetMode("BUILD", buildFile, buildName) + else + self:SetMode("BUILD", false, "Unnamed build") end + elseif pendingBuildFile then + self:SetMode("BUILD", false, "Unnamed build") end self.uniqueDB = { list = { }, loading = true } From 43603e52d82e3c93db2cc08f6cc11d6b85701e5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Lampron?= Date: Tue, 28 Apr 2026 00:34:07 -0400 Subject: [PATCH 5/5] Remove Unnamed build --- src/Modules/Main.lua | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Modules/Main.lua b/src/Modules/Main.lua index 77c760920..68654e356 100644 --- a/src/Modules/Main.lua +++ b/src/Modules/Main.lua @@ -163,11 +163,7 @@ function main:Init() file:close() local buildName = pendingBuildFile:match("([^/]+)%.xml$") or pendingBuildFile self:SetMode("BUILD", buildFile, buildName) - else - self:SetMode("BUILD", false, "Unnamed build") end - elseif pendingBuildFile then - self:SetMode("BUILD", false, "Unnamed build") end self.uniqueDB = { list = { }, loading = true }