diff --git a/ReadMe.md b/ReadMe.md index 2aacab8..8a90798 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -5,13 +5,19 @@ Blue Shiny Rocks, or BSRocks for short serves two purposes: - Lightweight implementation of [LuaRocks](https://luarocks.org/) Most functionality of Lua 5.1 is implemented, with the following caveats: - - The [debug library](http://www.lua.org/manual/5.1/manual.html#5.9) is only partially implemented. + - The [debug library](http://www.lua.org/manual/5.1/manual.html#5.9) is only partially implemented: - `debug.traceback` does not accept threads - `debug.getinfo` only accepts a numeric value - `.getmetatable`, `.setmetatable`, `.getfenv` and `.setfenv` are just their normal versions - Everything else is not implemented - - `string.gmatch` will infinitely loop on the `*` pattern (e.g. `\n*`) - `os` library is only partially implemented + - `io.popen` is not implemented. + - Several LuaJ bugs: + - `\011` is not considered whitespace + - `string.format` floating point specifiers don't work (e.g. `%5.2f`) + - `string.gmatch` will infinitely loop on the `*` pattern (e.g. `\n*`) + - `getmetatable` returns `nil` for strings. + - String's metatable and the `string` library are not the same, so you cannot add string methods. The LuaRocks implementation is very minimal: - Currently only supports downloading GitHub repositories diff --git a/bsrocks/bin/completions.lua b/bsrocks/bin/completions.lua index 09b6179..61e5fb0 100644 --- a/bsrocks/bin/completions.lua +++ b/bsrocks/bin/completions.lua @@ -27,4 +27,6 @@ local function completeBsRocks(shell, index, text, previous) end end -shell.setCompletionFunction(shell.resolve(...), completeBsRocks) +for i = 1, select('#', ...) do + shell.setCompletionFunction(shell.resolve(select(i, ...)), completeBsRocks) +end diff --git a/bsrocks/commands/admin/make.lua b/bsrocks/commands/admin/make.lua index a105966..a8a9f4b 100644 --- a/bsrocks/commands/admin/make.lua +++ b/bsrocks/commands/admin/make.lua @@ -33,8 +33,6 @@ local function execute(...) fileWrapper.assertExists(changed, "changed sources for " .. name, 0) fileWrapper.assertExists(info, "patchspec for " .. name, 0) - fs.delete(patch) - local data = serialize.unserialize(fileWrapper.read(info)) local originalSources = fileWrapper.readDir(original) local changedSources = fileWrapper.readDir(changed) diff --git a/bsrocks/commands/exec.lua b/bsrocks/commands/exec.lua index 2a5b03c..36affe2 100644 --- a/bsrocks/commands/exec.lua +++ b/bsrocks/commands/exec.lua @@ -22,15 +22,21 @@ return { if not loaded then error(msg, 0) end local thisEnv = env()._G - thisEnv.arg = {[0] = fil, ... } + thisEnv.arg = {[-2] = "/" .. shell.getRunningProgram(), [-1] = "exec", [0] = "/" .. file, ... } setfenv(loaded, thisEnv) local args = {...} - xpcall( + local success, msg = xpcall( function() return loaded(unpack(args)) end, function(msg) - printError(env()._G.debug.traceback(msg, 2)) + local code = msg:match("^Exit code: (%d+)") + if code and code == "0" then return "" end + + return env()._G.debug.traceback(msg, 2) end ) + if not success and msg ~= "" then + error(msg, 0) + end end, } diff --git a/bsrocks/env/date.lua b/bsrocks/env/date.lua new file mode 100644 index 0000000..a757d05 --- /dev/null +++ b/bsrocks/env/date.lua @@ -0,0 +1,384 @@ +--[[ +The MIT License (MIT) + +Copyright (c) 2013 Daurnimator + +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. +]] + +local strformat = string.format +local floor = math.floor +local function idiv(n, d) return floor(n / d) end + +local mon_lengths = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } +-- Number of days in year until start of month; not corrected for leap years +local months_to_days_cumulative = { 0 } +for i = 2, 12 do + months_to_days_cumulative [ i ] = months_to_days_cumulative [ i-1 ] + mon_lengths [ i-1 ] +end +-- For Sakamoto's Algorithm (day of week) +local sakamoto = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; + +local function is_leap ( y ) + if (y % 4) ~= 0 then + return false + elseif (y % 100) ~= 0 then + return true + else + return (y % 400) == 0 + end +end + +local function year_length ( y ) + return is_leap ( y ) and 366 or 365 +end + +local function month_length ( m, y ) + if m == 2 then + return is_leap ( y ) and 29 or 28 + else + return mon_lengths [ m ] + end +end + +local function leap_years_since ( year ) + return idiv ( year, 4 ) - idiv ( year, 100 ) + idiv ( year, 400 ) +end + +local function day_of_year ( day, month, year ) + local yday = months_to_days_cumulative [ month ] + if month > 2 and is_leap ( year ) then + yday = yday + 1 + end + return yday + day +end + +local function day_of_week ( day, month, year ) + if month < 3 then + year = year - 1 + end + return ( year + leap_years_since ( year ) + sakamoto[month] + day ) % 7 + 1 +end + +local function borrow ( tens, units, base ) + local frac = tens % 1 + units = units + frac * base + tens = tens - frac + return tens, units +end + +local function carry ( tens, units, base ) + if units >= base then + tens = tens + idiv ( units, base ) + units = units % base + elseif units < 0 then + tens = tens - 1 + idiv ( -units, base ) + units = base - ( -units % base ) + end + return tens, units +end + +-- Modify parameters so they all fit within the "normal" range +local function normalise ( year, month, day, hour, min, sec ) + -- `month` and `day` start from 1, need -1 and +1 so it works modulo + month, day = month - 1, day - 1 + + -- Convert everything (except seconds) to an integer + -- by propagating fractional components down. + year, month = borrow ( year, month, 12 ) + -- Carry from month to year first, so we get month length correct in next line around leap years + year, month = carry ( year, month, 12 ) + month, day = borrow ( month, day, month_length ( floor ( month + 1 ), year ) ) + day, hour = borrow ( day, hour, 24 ) + hour, min = borrow ( hour, min, 60 ) + min, sec = borrow ( min, sec, 60 ) + + -- Propagate out of range values up + -- e.g. if `min` is 70, `hour` increments by 1 and `min` becomes 10 + -- This has to happen for all columns after borrowing, as lower radixes may be pushed out of range + min, sec = carry ( min, sec, 60 ) -- TODO: consider leap seconds? + hour, min = carry ( hour, min, 60 ) + day, hour = carry ( day, hour, 24 ) + -- Ensure `day` is not underflowed + -- Add a whole year of days at a time, this is later resolved by adding months + -- TODO[OPTIMIZE]: This could be slow if `day` is far out of range + while day < 0 do + year = year - 1 + day = day + year_length ( year ) + end + year, month = carry ( year, month, 12 ) + + -- TODO[OPTIMIZE]: This could potentially be slow if `day` is very large + while true do + local i = month_length (month + 1, year) + if day < i then break end + day = day - i + month = month + 1 + if month >= 12 then + month = 0 + year = year + 1 + end + end + + -- Now we can place `day` and `month` back in their normal ranges + -- e.g. month as 1-12 instead of 0-11 + month, day = month + 1, day + 1 + + return year, month, day, hour, min, sec +end + +local function create(ts) + local year, month, day, hour, min, sec = normalise (1970, 1, 1, 0 , 0, ts) + + return { + day = day, + month = month, + year = year, + hour = hour, + min = min, + sec = sec, + yday = day_of_year ( day , month , year ), + wday = day_of_week ( day , month , year ) + } +end + +local leap_years_since_1970 = leap_years_since ( 1970 ) + +local function timestamp(year, month, day, hour, min, sec ) + year, month, day, hour, min, sec = normalise(year, month, day, hour, min, sec) + + local days_since_epoch = day_of_year ( day, month, year ) + + 365 * ( year - 1970 ) + -- Each leap year adds one day + + ( leap_years_since ( year - 1 ) - leap_years_since_1970 ) - 1 + + return days_since_epoch * (60*60*24) + + hour * (60*60) + + min * 60 + + sec +end + +local function timestampTbl(tbl) + return timestamp(tbl.year, tbl.month, tbl.day, tbl.hour or 0, tbl.min or 0, tbl.sec or 0) +end + +local c_locale = { + abday = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" } ; + day = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" } ; + abmon = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" } ; + mon = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" } ; + am_pm = { "AM", "PM" } ; +} + +--- ISO-8601 week logic +-- ISO 8601 weekday as number with Monday as 1 (1-7) +local function iso_8601_weekday ( wday ) + if wday == 1 then + return 7 + else + return wday - 1 + end +end +local iso_8601_week do + -- Years that have 53 weeks according to ISO-8601 + local long_years = { } + for _, v in ipairs { + 4, 9, 15, 20, 26, 32, 37, 43, 48, 54, 60, 65, 71, 76, 82, + 88, 93, 99, 105, 111, 116, 122, 128, 133, 139, 144, 150, 156, 161, 167, + 172, 178, 184, 189, 195, 201, 207, 212, 218, 224, 229, 235, 240, 246, 252, + 257, 263, 268, 274, 280, 285, 291, 296, 303, 308, 314, 320, 325, 331, 336, + 342, 348, 353, 359, 364, 370, 376, 381, 387, 392, 398 + } do + long_years [ v ] = true + end + local function is_long_year ( year ) + return long_years [ year % 400 ] + end + function iso_8601_week ( self ) + local wday = iso_8601_weekday ( self.wday ) + local n = self.yday - wday + local year = self.year + if n < -3 then + year = year - 1 + if is_long_year ( year ) then + return year, 53, wday + else + return year, 52, wday + end + elseif n >= 361 and not is_long_year ( year ) then + return year + 1, 1, wday + else + return year, idiv ( n + 10, 7 ), wday + end + end +end + +--- Specifiers +local t = { } +function t:a ( locale ) + return "%s", locale.abday [ self.wday ] +end +function t:A ( locale ) + return "%s", locale.day [ self.wday ] +end +function t:b ( locale ) + return "%s", locale.abmon [ self.month ] +end +function t:B ( locale ) + return "%s", locale.mon [ self.month ] +end +function t:c ( locale ) + return "%.3s %.3s%3d %.2d:%.2d:%.2d %d", + locale.abday [ self.wday ], locale.abmon [ self.month ], + self.day, self.hour, self.min, self.sec, self.year +end +-- Century +function t:C ( ) + return "%02d", idiv ( self.year, 100 ) +end +function t:d ( ) + return "%02d", self.day +end +-- Short MM/DD/YY date, equivalent to %m/%d/%y +function t:D ( ) + return "%02d/%02d/%02d", self.month, self.day, self.year % 100 +end +function t:e ( ) + return "%2d", self.day +end +-- Short YYYY-MM-DD date, equivalent to %Y-%m-%d +function t:F ( ) + return "%d-%02d-%02d", self.year, self.month, self.day +end +-- Week-based year, last two digits (00-99) +function t:g ( ) + return "%02d", iso_8601_week ( self ) % 100 +end +-- Week-based year +function t:G ( ) + return "%d", iso_8601_week ( self ) +end +t.h = t.b +function t:H ( ) + return "%02d", self.hour +end +function t:I ( ) + return "%02d", (self.hour-1) % 12 + 1 +end +function t:j ( ) + return "%03d", self.yday +end +function t:m ( ) + return "%02d", self.month +end +function t:M ( ) + return "%02d", self.min +end +-- New-line character ('\n') +function t:n ( ) -- luacheck: ignore 212 + return "\n" +end +function t:p ( locale ) + return self.hour < 12 and locale.am_pm[1] or locale.am_pm[2] +end +-- TODO: should respect locale +function t:r ( locale ) + return "%02d:%02d:%02d %s", + (self.hour-1) % 12 + 1, self.min, self.sec, + self.hour < 12 and locale.am_pm[1] or locale.am_pm[2] +end +-- 24-hour HH:MM time, equivalent to %H:%M +function t:R ( ) + return "%02d:%02d", self.hour, self.min +end +function t:s ( ) + return "%d", timestamp(self) +end +function t:S ( ) + return "%02d", self.sec +end +-- Horizontal-tab character ('\t') +function t:t ( ) -- luacheck: ignore 212 + return "\t" +end +-- ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S +function t:T ( ) + return "%02d:%02d:%02d", self.hour, self.min, self.sec +end +function t:u ( ) + return "%d", iso_8601_weekday ( self.wday ) +end +-- Week number with the first Sunday as the first day of week one (00-53) +function t:U ( ) + return "%02d", idiv ( self.yday - self.wday + 7, 7 ) +end +-- ISO 8601 week number (00-53) +function t:V ( ) + return "%02d", select ( 2, iso_8601_week ( self ) ) +end +-- Weekday as a decimal number with Sunday as 0 (0-6) +function t:w ( ) + return "%d", self.wday - 1 +end +-- Week number with the first Monday as the first day of week one (00-53) +function t:W ( ) + return "%02d", idiv ( self.yday - iso_8601_weekday ( self.wday ) + 7, 7 ) +end +-- TODO make t.x and t.X respect locale +t.x = t.D +t.X = t.T +function t:y ( ) + return "%02d", self.year % 100 +end +function t:Y ( ) + return "%d", self.year +end +-- TODO timezones +function t:z ( ) -- luacheck: ignore 212 + return "+0000" +end +function t:Z ( ) -- luacheck: ignore 212 + return "GMT" +end +-- A literal '%' character. +t["%"] = function ( self ) -- luacheck: ignore 212 + return "%%" +end + +local function strftime ( format_string, timetable ) + return ( string.gsub ( format_string, "%%([EO]?)(.)", function ( locale_modifier, specifier ) + local func = t [ specifier ] + if func then + return strformat ( func ( timetable, c_locale ) ) + else + error ( "invalid conversation specifier '%"..locale_modifier..specifier.."'", 3 ) + end + end ) ) +end + +local function asctime ( timetable ) + -- Equivalent to the format string "%c\n" + return strformat ( t.c ( timetable, c_locale ) ) +end + +return { + create = create, + timestamp = timestampTbl, + strftime = strftime, + asctime = asctime, +} diff --git a/bsrocks/env/debug.lua b/bsrocks/env/debug.lua index fb6b44f..03d343a 100644 --- a/bsrocks/env/debug.lua +++ b/bsrocks/env/debug.lua @@ -16,7 +16,7 @@ local function getInfo(thread, func, what) local data = { what = "lua", source = "", - short_source = "", + short_src = "", linedefined = -1, lastlinedefined = -1, currentline = -1, @@ -30,10 +30,13 @@ local function getInfo(thread, func, what) if t == "number" or t == "string" then func = tonumber(func) - local _, name = pcall(error, "", 2 + func) - name = name:gsub(":?[^:]*: *$", "", 1) + local _, source = pcall(error, "", 2 + func) + local name = source:gsub(":?[^:]*: *$", "", 1) data.source = "@" .. name - data.short_source = name + data.short_src = name + + local line = tonumber(source:match("^[^:]+:([%d]+):") or "") + if line then data.currentline = line end elseif t == "function" then -- We really can't do much data.func = func @@ -52,7 +55,7 @@ return function(env) getinfo = getInfo, getlocal = err("getlocal"), gethook = err("gethook"), - getmetatable = getmetatable, + getmetatable = env._G.getmetatable, getregistry = err("getregistry"), setfenv = setfenv, sethook = err("sethook"), diff --git a/bsrocks/env/fixes.lua b/bsrocks/env/fixes.lua new file mode 100644 index 0000000..61fae6a --- /dev/null +++ b/bsrocks/env/fixes.lua @@ -0,0 +1,29 @@ +--- Various patches for LuaJ's + +local type, pairs = type, pairs + +local function copy(tbl) + local out = {} + for k, v in pairs(tbl) do out[k] = v end + return out +end + +local function getmeta(obj) + if type(obj) == "table" then + return getmetatable(obj) + else + return nil + end +end + +return function(env) + env._G.getmetatable = getmeta + + if not table.pack().n then + local table = copy(table) + table.pack = function( ... ) return {n=select('#',...), ... } end + + env._G.table = table + end + +end diff --git a/bsrocks/env/init.lua b/bsrocks/env/init.lua index 1de4257..e69fd11 100644 --- a/bsrocks/env/init.lua +++ b/bsrocks/env/init.lua @@ -1,3 +1,5 @@ +local fileWrapper = require "bsrocks.lib.files" + local function addWithMeta(src, dest) for k, v in pairs(src) do if dest[k] == nil then @@ -48,9 +50,6 @@ return function(options) return path end - -- Copy functions across - addWithMeta(getfenv(), _G) - function _G.load(func, chunk) local cache = {} while true do @@ -76,12 +75,11 @@ return function(options) -- Customised loadfile function to work with relative files function _G.loadfile(path) - local result, message = loadfile(env.resolve(path)) - if result then - return setfenv(result, _G) + if fs.exists(path) then + return load(fileWrapper.read(path), path, "t", _G) + else + return nil, "File not found" end - - return result, message end function _G.dofile(path) @@ -136,6 +134,8 @@ return function(options) end -- Setup other items + require "bsrocks.env.fixes"(env) + require "bsrocks.env.io"(env) require "bsrocks.env.os"(env) @@ -145,5 +145,8 @@ return function(options) require "bsrocks.env.package"(env) + -- Copy functions across + addWithMeta(getfenv(), _G) + return env end diff --git a/bsrocks/env/io.lua b/bsrocks/env/io.lua index b6e9da9..a453b8a 100644 --- a/bsrocks/env/io.lua +++ b/bsrocks/env/io.lua @@ -103,7 +103,7 @@ return function(env) do -- Setup standard outputs local function void() end - local function close() error("cannot close standard file", 3) end + local function close() return nil, "cannot close standard file" end local function read() error("cannot read from output", 3) end env.stdout = setmetatable({ __handle = { diff --git a/bsrocks/env/os.lua b/bsrocks/env/os.lua index 7900ead..092df4e 100644 --- a/bsrocks/env/os.lua +++ b/bsrocks/env/os.lua @@ -2,18 +2,29 @@ -- http://www.lua.org/manual/5.1/manual.html#5.8 local utils = require "bsrocks.lib.utils" +local date = require "bsrocks.env.date" local checkType = utils.checkType return function(env) - local os, shell = _G.os, _G.shell + local os, shell = os, shell env._G.os = { clock = os.clock, date = function(format, time) - format = checkType(format or "*t", "string") + format = checkType(format or "%c", "string") time = checkType(time or os.time(), "number") - -- TODO: Implement this properly - return textutils.formatTime(time) + -- Ignore UTC/CUT + if format:sub(1, 1) == "!" then format = format:sub(2) end + + local d = date.create(time) + + if format == "*t" then + return d + elseif format == "%c" then + return date.asctime(d) + else + return date.strftime(format, d) + end end, @@ -22,8 +33,14 @@ return function(env) return t2 - t1 end, - execute = function(command) return shell.run(command) and 0 or 1 end, - exit = function(code) error("Exit code: " .. (code or 0), 2) end, + execute = function(command) + if shell.run(command) then + return 0 + else + return 1 + end + end, + exit = function(code) error("Exit code: " .. (code or 0), 0) end, getfenv = function(name) -- I <3 ClamShell if shell.getenv then @@ -39,7 +56,12 @@ return function(env) end, setlocale = function() end, -- Technically not - time = os.time, + time = function(tbl) + if not tbl then return os.time() end + + checkType(tbl, "table") + return date.timestamp(tbl) + end, tmpname = utils.tmpName } end diff --git a/bsrocks/env/package.lua b/bsrocks/env/package.lua index ec9d676..74d2d7d 100644 --- a/bsrocks/env/package.lua +++ b/bsrocks/env/package.lua @@ -1,8 +1,9 @@ --- The main package library - a pure lua reimplementation of the package library in lua -- See: http://www.lua.org/manual/5.1/manual.html#5.3 -local utils = require "bsrocks.lib.utils" +local fileWrapper = require "bsrocks.lib.files" local settings = require "bsrocks.lib.settings" +local utils = require "bsrocks.lib.utils" local checkType = utils.checkType return function(env) @@ -70,14 +71,18 @@ return function(env) local filePath = env.resolve(path:sub(pos, start - 1):gsub("%?", name, 1)) pos = start + 1 - local loaded, err = loadfile(filePath) + local loaded, err - if not fs.exists(filePath) then - loaded, err = loadfile(filePath .. ".lua") + if fs.exists(filePath) then + loaded, err = load(fileWrapper.read(filePath), filePath, "t", _G) + elseif fs.exists(filePath .. ".lua") then + loaded, err = load(fileWrapper.read(filePath .. ".lua"), filePath, "t", _G) + else + err = "File not found" end if type(loaded) == "function" then - return setfenv(loaded, _G) + return loaded end errs[#errs + 1] = "'" .. filePath .. "': " .. err @@ -193,28 +198,7 @@ return function(env) module._PACKAGE = name:gsub("%.[^%.]+$", "") or "" -- Everything before the last . end - -- Technically we need to set the environment above to access this. - -- Instead we just set the __newindex functions t o use it - local env = getfenv(2) - - local meta = getmetatable(env) - if meta == nil then - meta = {} - setmetatable(env, meta) - end - - local rawset = rawset - -- Copy all variables over - for k, v in pairs(module) do - rawset(env, k, v) - end - - -- We rawset the current table as well so things like - -- for k, v in pairs(getfenv()) do ... end work - meta.__newindex = function(self, key, value) - rawset(self, key, value) - module[key] = value - end + setfenv(2, module) -- Applies functions. This could be package.seeall or similar for _, modifier in pairs({...}) do diff --git a/bsrocks/lib/utils.lua b/bsrocks/lib/utils.lua index 3e0a1a9..0505fdd 100644 --- a/bsrocks/lib/utils.lua +++ b/bsrocks/lib/utils.lua @@ -16,7 +16,7 @@ end --- Generate a temp name for a file -- Pretty safe, though not 100% accurate local function tmpName() - return "/tmp/" .. os.clock() .. "-" .. math.random(1, 2^32) + return "/tmp/" .. os.clock() .. "-" .. math.random(1, 2^31-1) end local function traceback(thread, message, level) @@ -30,7 +30,7 @@ local function traceback(thread, message, level) local result = {"stack traceback: "} for i = 2, 20 do local _, err = pcall(error, "", i + level) - if err == "" then + if err == "" or err == "nil:" then break end diff --git a/bsrocks/rocks/install.lua b/bsrocks/rocks/install.lua index 20b6993..19bfe2e 100644 --- a/bsrocks/rocks/install.lua +++ b/bsrocks/rocks/install.lua @@ -90,7 +90,7 @@ local function save(rockS, patchS) if build.modules then local moduleDir = fs.combine(installDirectory, "lib") for module, file in pairs(build.modules) do - fileWrapper.write(fs.combine(moduleDir, module:gsub("%.", "/") .. ".lua"), files[file]) + fileWrapper.write(fs.combine(moduleDir, module:gsub("%.", "/") .. ".lua"), downloaded[file]) end end @@ -99,7 +99,7 @@ local function save(rockS, patchS) for name, install in pairs(build.install) do local dir = fs.combine(installDirectory, name) for name, file in pairs(install) do - fileWrapper.write(fs.combine(dir, name .. ".lua"), files[file]) + fileWrapper.write(fs.combine(dir, name .. ".lua"), downloaded[file]) end end end diff --git a/bsrocks/rocks/patchspec.lua b/bsrocks/rocks/patchspec.lua index 40ae287..0e0183c 100644 --- a/bsrocks/rocks/patchspec.lua +++ b/bsrocks/rocks/patchspec.lua @@ -1,9 +1,11 @@ local diff = require "bsrocks.lib.diffmatchpatch" local fileWrapper = require "bsrocks.lib.files" -local log = require "bsrocks.lib.utils".log local manifest = require "bsrocks.rocks.manifest" local patchDirectory = require "bsrocks.lib.settings".patchDirectory local unserialize = require "bsrocks.lib.serialize".unserialize +local utils = require "bsrocks.lib.utils" + +local log, warn = utils.log, utils.warn local patchCache = {} @@ -136,6 +138,7 @@ local function applyPatches(original, files, patches, added, removed) local changed = {} local modified = {} + local issues = false for _, file in ipairs(patches) do local patchContents = files[file .. ".patch"] local originalContents = original[file] @@ -144,7 +147,14 @@ local function applyPatches(original, files, patches, added, removed) if not originalContents then error("Cannot find original " .. file) end local patches = diff.patch_fromText(patchContents) - local changedContent = diff.patch_apply(patches, originalContents) + local changedContent, success = diff.patch_apply(patches, originalContents) + + for k, v in pairs(success) do + if not v then + warn("Cannot apply #" .. k .. " for " .. file) + issues = true + end + end changed[file] = changedContent modified[file] = true @@ -153,6 +163,10 @@ local function applyPatches(original, files, patches, added, removed) coroutine.yield("diff") end + if issues then + error("Issues occured when patching", 0) + end + for _, file in ipairs(removed) do modified[file] = true end