377 lines
9.7 KiB
Lua
377 lines
9.7 KiB
Lua
|
|
task("check-files")
|
|
|
|
set_menu({
|
|
-- Settings menu usage
|
|
usage = "xmake check-files [options]",
|
|
description = "Check every file for consistency (can fix some errors)",
|
|
options =
|
|
{
|
|
-- Set k mode as key-only bool parameter
|
|
{'f', "fix", "k", nil, "Attempt to automatically fix files." }
|
|
}
|
|
})
|
|
|
|
local function CompareLines(referenceLines, lines, firstLine, lineCount)
|
|
firstLine = firstLine or 1
|
|
lineCount = lineCount or (#lines - firstLine + 1)
|
|
if lineCount ~= #referenceLines then
|
|
return false
|
|
end
|
|
|
|
for i = 1, lineCount do
|
|
if lines[firstLine + i - 1] ~= referenceLines[i] then
|
|
print(lines[firstLine + i])
|
|
print(referenceLines[i])
|
|
return false
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
on_run(function ()
|
|
import("core.base.option")
|
|
|
|
local modules = os.dirs("include/Nazara/*")
|
|
|
|
local fileLines = {}
|
|
local updatedFiles = {}
|
|
local function GetFile(filePath)
|
|
filePath = path.translate(filePath)
|
|
|
|
local lines = fileLines[filePath]
|
|
if not lines then
|
|
lines = table.to_array(io.lines(filePath))
|
|
if not lines then
|
|
os.raise("failed to open " .. filePath)
|
|
end
|
|
|
|
fileLines[filePath] = lines
|
|
end
|
|
|
|
return lines
|
|
end
|
|
|
|
local function UpdateFile(filePath, lines)
|
|
filePath = path.translate(filePath)
|
|
|
|
if lines then
|
|
fileLines[filePath] = lines
|
|
end
|
|
|
|
updatedFiles[filePath] = true
|
|
end
|
|
|
|
local checks = {}
|
|
|
|
table.insert(checks, {
|
|
Name = "remove empty lines at the beginning",
|
|
Check = function (moduleName)
|
|
local files = table.join(
|
|
os.files("include/Nazara/" .. moduleName .. "/**.hpp"),
|
|
os.files("include/Nazara/" .. moduleName .. "/**.inl"),
|
|
os.files("src/Nazara/" .. moduleName .. "/**.hpp"),
|
|
os.files("src/Nazara/" .. moduleName .. "/**.inl"),
|
|
os.files("src/Nazara/" .. moduleName .. "/**.cpp")
|
|
)
|
|
|
|
local fixes = {}
|
|
|
|
for _, filePath in pairs(files) do
|
|
local lines = GetFile(filePath)
|
|
|
|
for i = 1, #lines do
|
|
if not lines[i]:match("^%s*$") then
|
|
if i ~= 1 then
|
|
print(filePath .. " starts with empty lines")
|
|
|
|
table.insert(fixes, {
|
|
File = filePath,
|
|
Func = function (lines)
|
|
for j = 1, i - 1 do
|
|
table.remove(lines, 1)
|
|
end
|
|
|
|
UpdateFile(filePath, lines)
|
|
end
|
|
})
|
|
end
|
|
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
return fixes
|
|
end
|
|
})
|
|
|
|
table.insert(checks, {
|
|
Name = "copyright",
|
|
Check = function (moduleName)
|
|
local files = table.join(
|
|
os.files("include/Nazara/" .. moduleName .. "/**.hpp|Config.hpp"),
|
|
os.files("include/Nazara/" .. moduleName .. "/**.inl"),
|
|
os.files("src/Nazara/" .. moduleName .. "/**.hpp"),
|
|
os.files("src/Nazara/" .. moduleName .. "/**.inl"),
|
|
os.files("src/Nazara/" .. moduleName .. "/**.cpp")
|
|
)
|
|
|
|
local currentYear = os.date("%Y")
|
|
local engineAuthor = "Jérôme \"Lynix\" Leclercq (lynix680@gmail.com)"
|
|
local prevAuthor = "Jérôme Leclercq"
|
|
local fixes = {}
|
|
|
|
local moduleDesc
|
|
if #moduleName > 8 and moduleName:endswith("Renderer") then
|
|
moduleDesc = moduleName:sub(1, -9) .. " renderer"
|
|
else
|
|
moduleDesc = moduleName .. " module"
|
|
end
|
|
|
|
-- Config
|
|
do
|
|
local configFilePath = path.translate("include/Nazara/" .. moduleName .. "/Config.hpp")
|
|
local lines = GetFile(configFilePath)
|
|
local pragmaLine
|
|
for i = 1, #lines do
|
|
if lines[i] == "#pragma once" then
|
|
pragmaLine = i
|
|
break
|
|
end
|
|
end
|
|
|
|
local canFix = true
|
|
|
|
repeat
|
|
if not pragmaLine then
|
|
print(configFilePath .. ": pragma once not found")
|
|
canFix = false
|
|
break
|
|
end
|
|
|
|
local licenseText = [[
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
this software and associated documentation files (the "Software"), to deal in
|
|
the Software without restriction, including without limitation the rights to
|
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
of the Software, and to permit persons to whom the Software is furnished to do
|
|
so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
*/
|
|
|
|
#pragma once]]
|
|
|
|
local licenseLines = licenseText:split("\r?\n", { strict = true })
|
|
local shouldFix = false
|
|
|
|
-- Try to retrieve year and authors
|
|
if lines[1] ~= "/*" then
|
|
print(configFilePath .. ": file doesn't begin with block comment")
|
|
break
|
|
end
|
|
|
|
|
|
if lines[2]:match("\tNazara Engine - " .. moduleDesc) then
|
|
print(configFilePath .. ": module description doesn't match")
|
|
shouldFix = true
|
|
end
|
|
|
|
if lines[3] ~= "" then
|
|
-- Not really empty because of space characters? Not a big deal
|
|
if lines[3]:match("^%s*$") then
|
|
shouldFix = true
|
|
else
|
|
print(configFilePath .. ": expected space after project name")
|
|
break
|
|
end
|
|
end
|
|
|
|
local year, moduleAuthor = lines[4]:match("^\tCopyright %(C%) (Y?E?A?R?%d*) (.+)$")
|
|
if not year then
|
|
print(configFilePath .. ": couldn't parse copyright date and author")
|
|
break
|
|
end
|
|
|
|
if year ~= currentYear then
|
|
print(configFilePath .. ": incorrect copyright year")
|
|
shouldFix = true
|
|
end
|
|
|
|
local additionalAuthors = {}
|
|
for i = 5, #lines do
|
|
if lines[i]:match("^%s*$") then
|
|
-- Empty line
|
|
if not CompareLines(licenseLines, lines, i, pragmaLine - i + 1) then
|
|
shouldFix = true
|
|
end
|
|
|
|
break
|
|
end
|
|
|
|
if lines[i]:match("%s*Permission is hereby granted") then
|
|
print(configFilePath .. ": missing empty line before licence text")
|
|
shouldFix = true
|
|
break
|
|
end
|
|
|
|
table.insert(additionalAuthors, lines[i]:match("%s*(.+)"))
|
|
end
|
|
|
|
if shouldFix then
|
|
table.insert(fixes, {
|
|
File = configFilePath,
|
|
Func = function (lines)
|
|
local newLines = {
|
|
"/*",
|
|
"\tNazara Engine - " .. moduleDesc,
|
|
"",
|
|
}
|
|
|
|
local copyrightNotice = "Copyright (C) " .. currentYear
|
|
table.insert(newLines, "\t" .. copyrightNotice .. " " .. moduleAuthor)
|
|
|
|
for _, author in ipairs(additionalAuthors) do
|
|
table.insert(newLines, "\t" .. string.rep(" ", #copyrightNotice) .. " " .. author)
|
|
end
|
|
|
|
for _, line in ipairs(licenseLines) do
|
|
table.insert(newLines, line)
|
|
end
|
|
|
|
for i = pragmaLine + 1, #lines do
|
|
table.insert(newLines, lines[i])
|
|
end
|
|
|
|
UpdateFile(configFilePath, newLines)
|
|
end
|
|
})
|
|
end
|
|
until true
|
|
|
|
if not canFix then
|
|
print(configFilePath .. ": header couldn't be parsed, no automated fix will be done")
|
|
end
|
|
end
|
|
|
|
-- Headers
|
|
for _, filePath in pairs(files) do
|
|
local lines = GetFile(filePath)
|
|
|
|
local hasCopyright
|
|
local shouldFix = false
|
|
|
|
if lines[1]:lower():match("^// this file was automatically generated") then
|
|
goto skip
|
|
end
|
|
|
|
local year, authors = lines[1]:match("^// Copyright %(C%) (Y?E?A?R?%d*) (.+)$")
|
|
hasCopyright = year ~= nil
|
|
|
|
if authors == "AUTHORS" then
|
|
authors = engineAuthor
|
|
else
|
|
local fixedAuthors = authors:gsub(prevAuthor, engineAuthor)
|
|
if fixedAuthors ~= authors then
|
|
authors = fixedAuthors
|
|
shouldFix = true
|
|
end
|
|
end
|
|
|
|
if hasCopyright then
|
|
if year ~= currentYear then
|
|
print(filePath .. ": copyright year error")
|
|
shouldFix = true
|
|
end
|
|
|
|
local copyrightModule = lines[2]:match("^// This file is part of the \"Nazara Engine %- (.+)\"$")
|
|
if copyrightModule ~= moduleDesc then
|
|
print(filePath .. ": copyright module error")
|
|
shouldFix = true
|
|
end
|
|
|
|
if lines[3] ~= "// For conditions of distribution and use, see copyright notice in Config.hpp" then
|
|
print(filePath .. ": copyright file reference error")
|
|
shouldFix = true
|
|
end
|
|
else
|
|
print(filePath .. ": copyright not found")
|
|
shouldFix = true
|
|
end
|
|
|
|
if shouldFix then
|
|
table.insert(fixes, {
|
|
File = filePath,
|
|
Func = function(lines)
|
|
local copyrightLines = {
|
|
"// Copyright (C) " .. currentYear .. " " .. (authors or engineAuthor),
|
|
"// This file is part of the \"Nazara Engine - " .. moduleDesc .. "\"",
|
|
"// For conditions of distribution and use, see copyright notice in Config.hpp"
|
|
}
|
|
|
|
if hasCopyright then
|
|
for i, line in ipairs(copyrightLines) do
|
|
lines[i] = line
|
|
end
|
|
else
|
|
for i, line in ipairs(copyrightLines) do
|
|
table.insert(lines, i, line)
|
|
end
|
|
table.insert(lines, #copyrightLines + 1, "")
|
|
end
|
|
|
|
UpdateFile(filePath, lines)
|
|
end
|
|
})
|
|
end
|
|
|
|
::skip::
|
|
end
|
|
|
|
return fixes
|
|
end
|
|
})
|
|
|
|
local shouldFix = option.get("fix") or false
|
|
|
|
for _, check in pairs(checks) do
|
|
print("Running " .. check.Name .. " check...")
|
|
|
|
local fixes = {}
|
|
for _, modulePath in pairs(modules) do
|
|
local moduleName = modulePath:match(".*[\\/](.*)")
|
|
|
|
table.join2(fixes, check.Check(moduleName))
|
|
end
|
|
|
|
if shouldFix then
|
|
for _, fix in pairs(fixes) do
|
|
print("Fixing " .. fix.File)
|
|
fix.Func(assert(fileLines[fix.File]))
|
|
end
|
|
|
|
for filePath, _ in pairs(updatedFiles) do
|
|
local lines = assert(fileLines[filePath])
|
|
if lines[#lines] ~= "" then
|
|
table.insert(lines, "")
|
|
end
|
|
|
|
print("Saving changes to " .. filePath)
|
|
io.writefile(filePath, table.concat(lines, "\n"))
|
|
end
|
|
end
|
|
end
|
|
end)
|