diff --git a/README.md b/README.md index 57e4e4b..5710c19 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,49 @@ Available as a [LuaRocks][luarocks] [package][package]. ## Features love-release makes your LÖVE game release easier. It can create from your sources Windows executables, MacOS X applications, Debian packages and simple LÖVE files. -love-release creates only one LÖVE file in a release directory and keeps it synced with your sources. +love-release creates only one LÖVE file per release directory and keeps it synced with your sources. love-release can extract its informations from the environment: it guesses your game's title from the directory where it's stored, selects by default the latest LÖVE version from the web or uses its latest bundled LÖVE version, then parses the `conf.lua` file to extract even more informations such as the real LÖVE version your project uses. +### Usage +``` +Usage: love-release [-D] [-M] [-a ] [-b] [-d ] + [-e ] [-l ] [-p ] [-t ] [-u <url>] + [--uti <uti>] [-v <v>] [--version] [-h] [<release>] [<source>] + [-W [32|64]] + +Makes LÖVE games releases easier ! + +Arguments: + release Project release directory. + source Project source directory. + +Options: + -D Debian package. + -M MacOS X application. + -W [32|64] Windows executable. + -a <author>, --author <author> + Author full name. + -b Compile new or updated files to LuaJIT bytecode. + -d <desc>, --desc <desc> + Project description. + -e <email>, --email <email> + Author email. + -l <love>, --love <love> + LÖVE version to use. + -p <package>, --package <package> + Package and command name. + -t <title>, --title <title> + Project title. + -u <url>, --url <url> Project homepage url. + --uti <uti> Project Uniform Type Identifier. + -v <v> Project version. + --version Show love-release version and exit. + -h, --help Show this help message and exit. + +For more info, see https://github.com/MisterDA/love-release +``` + ### Configuration love-release prints to the command-line a Lua table containing the informations it uses to generate your project. These informations can be stored in your `conf.lua` file to be used later. @@ -46,6 +85,7 @@ love-release is only installable through LuaRocks and highly depends on LuaRocks #### Optional - `love` can be used to determine your system LÖVE version. - `fakeroot` and `dpkg-deb` are required to create Debian packages. +- [LuaJIT][luajit] can be used to compile your sources, either with `luarocks-luajit` or if `luajit` is installed. ### Install @@ -77,6 +117,7 @@ Every bug report or feature request is gladly welcome ! [libzip]: http://www.nih.at/libzip/ [love]: https://www.love2d.org/ [lua]: http://www.lua.org/ +[luajit]: http://luajit.org/ [luarocks]: https://luarocks.org/ [lua-zip]: https://github.com/brimworks/lua-zip [loadconf]: https://github.com/Alloyed/loadconf diff --git a/rockspecs/love-release-scm-1.rockspec b/rockspecs/love-release-scm-1.rockspec index 8d6987d..e11f75a 100644 --- a/rockspecs/love-release-scm-1.rockspec +++ b/rockspecs/love-release-scm-1.rockspec @@ -14,6 +14,7 @@ It automates LÖVE Game Distribution. homepage = "https://github.com/MisterDA/love-release", } dependencies = { + "argparse", "loadconf", "lua ~> 5.1", "luafilesystem", @@ -28,6 +29,7 @@ build = { ["love-release.scripts.love"] = "src/scripts/love.lua", ["love-release.scripts.macosx"] = "src/scripts/macosx.lua", ["love-release.scripts.windows"] = "src/scripts/windows.lua", + ["love-release.pipes.args"] = "src/pipes/args.lua", ["love-release.pipes.conf"] = "src/pipes/conf.lua", ["love-release.pipes.env"] = "src/pipes/env.lua", ["love-release.project"] = "src/project.lua", diff --git a/src/main.lua b/src/main.lua index 55b1b3e..eb1b0a4 100644 --- a/src/main.lua +++ b/src/main.lua @@ -1,20 +1,13 @@ --- love-release main. -- @script love-release +local Args = require 'love-release.pipes.args' local conf = require 'love-release.pipes.conf' local env = require 'love-release.pipes.env' local Project = require 'love-release.project' + local p = Project:new() -conf(env(p)) +local args = Args:new() +args(conf(env(args(p)))) -print(p) - -local script -script = require 'love-release.scripts.love' -script(p) -script = require 'love-release.scripts.macosx' -script(p) -script = require 'love-release.scripts.windows' -script(p) -script = require 'love-release.scripts.debian' -script(p) +return 0 diff --git a/src/pipes/args.lua b/src/pipes/args.lua new file mode 100644 index 0000000..5a8722e --- /dev/null +++ b/src/pipes/args.lua @@ -0,0 +1,126 @@ +--- Gather informations from the CLI +-- @module args +-- @usage args(project) + +local argparse = require 'argparse' +local class = require 'middleclass' +local utils = require 'love-release.utils' + +local Args = class('Args') + + +Args.pre = true + +Args.args = nil + +function Args:initialize() + self.pre = Args.pre + + local parser = argparse() + :name "love-release" + :description "Makes LÖVE games releases easier !" + :epilog "For more info, see https://github.com/MisterDA/love-release" + + + parser:argument("release", "Project release directory.") + :args "?" + parser:argument("source", "Project source directory.") + :args "?" + + parser:flag("-D", "Debian package.") + :target "debian" + parser:flag("-M", "MacOS X application.") + :target "macosx" + parser:option("-W", "Windows executable.") + :target "windows" + :args "0-1" + :count "0-2" + :argname "32|64" + + parser:option("-a --author", "Author full name.") + parser:flag("-b", "Compile new or updated files to LuaJIT bytecode.") + :target("compile") + parser:option("-d --desc", "Project description.") + parser:option("-e --email", "Author email.") + parser:option("-l --love", "LÖVE version to use.") + :target("loveVersion") + parser:option("-p --package", "Package and command name.") + parser:option("-t --title", "Project title.") + parser:option("-u --url", "Project homepage url.") + parser:option("--uti", "Project Uniform Type Identifier.") + parser:option("-v", "Project version.") + :target("version") + + parser:flag("--version", "Show love-release version and exit.") + :target("love_release") + + self.args = parser:parse() +end + + +function Args:__call(project) + local out = utils.io.out + local args = self.args + + if self.pre then + if args.source then project:setProjectDirectory(args.source) end + if args.release then project:setReleaseDirectory(args.release) end + if args.love_release then + local show = require 'luarocks.show' + local _, version = show.pick_installed_rock("love-release") + out("love-release "..version.."\n") + os.exit(0) + end + self.pre = false + return project + end + + if args.author then project:setAuthor(args.author) end + if args.compile then project:setCompile(true) end + if args.desc then project:setDescription(args.desc) end + if args.email then project:setEmail(args.email) end + if args.loveVersion then + assert(utils.love.isSupported(args.loveVersion), + "ARGS: "..args.loveVersion.." is not supported.\n") + project:setLoveVersion(args.loveVersion) + end + if args.package then project:setPackage(args.package) end + if args.title then project:setTitle(args.title) end + if args.url then project:setHomepage(args.url) end + if args.uti then project:setIdentifier(args.uti) end + if args.version then project:setVersion(args.version) end + + if project.projectDirectory == project.releaseDirectory then + project:setReleaseDirectory(project.releaseDirectory.."/releases") + end + + print(project) + + local script + script = require 'love-release.scripts.love' + script(project) + if args.macosx then + script = require 'love-release.scripts.macosx' + script(project) + end + if #args.windows > 0 then + local win = args.windows + local win32 = win[1][1] == "32" or (win[2] and win[2][1] == "32") + local win64 = win[1][1] == "64" or (win[2] and win[2][1] == "64") + if not win32 and not win64 then + win32, win64 = true, true + end + script = require 'love-release.scripts.windows' + if win32 then script(project, 32) end + if win64 then script(project, 64) end + end + if args.debian then + script = require 'love-release.scripts.debian' + script(project) + end + + return project +end + + +return Args diff --git a/src/project.lua b/src/project.lua index db2a447..406e710 100644 --- a/src/project.lua +++ b/src/project.lua @@ -43,13 +43,16 @@ Project.projectDirectory = nil --- Project release directory, where to store the releases. Project.releaseDirectory = nil +--- True is the files should be precompiled to LuaJIT bytecode. +Project.compile = false + Project._fileTree = nil Project._fileList = nil function Project:initialize() local defaultDirectory = fs.current_dir() self:setProjectDirectory(defaultDirectory) - self:setReleaseDirectory(defaultDirectory.."/releases") + self:setReleaseDirectory(defaultDirectory) end --- Recursive function used to build the tree. @@ -115,17 +118,29 @@ end --- Excludes files from the LÖVE file. -- @todo This function should be able to parse and use CVS files such as -- gitignore. It should also work on the file tree rather than on the file list. --- For now it only exludes the release directory if it is within the project --- directory and works on the file list. +-- For now it works on the file list and only exludes the release directory if +-- it is within the project directory. function Project:excludeFiles() - local dir = self.releaseDirectory:gsub( + local dir, rm_dir = self.releaseDirectory:gsub( "^"..utils.lua.escape_string_regex(self.projectDirectory).."/", "") - if dir then + if rm_dir > 0 then + rm_dir = true + dir = "^"..dir + else + rm_dir = false + end + + if rm_dir then + local rm = false + local file local n = #self._fileList for i = 1, n do - if self._fileList[i]:find("^"..dir) then + file = self._fileList[i] + if rm_dir then if file:find(dir) then rm = true end end + if rm then self._fileList[i] = nil + rm = false end end end @@ -168,6 +183,7 @@ function Project:__tostring() ' description = '..escape(self.description)..',\n'.. ' homepage = '..escape(self.homepage)..',\n'.. ' identifier = '..escape(self.identifier)..',\n'.. + ' compile = '..escape(self.compile)..',\n'.. ' projectDirectory = '..escape(self.projectDirectory)..',\n'.. ' releaseDirectory = '..escape(self.releaseDirectory)..',\n'.. '}' @@ -268,5 +284,20 @@ function Project:setReleaseDirectory(directory) return self end +--- Sets if Lua files should be precompiled to LuaJIT bytecode. By default they +-- are not compiled. +-- @bool value wether the files should be compiled or not. +-- @treturn project self +function Project:setCompile(value) + if value then + if package.loaded.jit then + self.compile = true + else + assert(fs.is_tool_available("luajit", "LuaJIT", "-v")) + self.compile = true + end + end +end + return Project diff --git a/src/script.lua b/src/script.lua index dfeafc5..1a0ea6a 100644 --- a/src/script.lua +++ b/src/script.lua @@ -60,13 +60,22 @@ function Script:createLoveFile() if attributes.mode == "directory" then ar:add_dir(file) else - ar:add(file, "file", file) + if self.project.compile then + ar:add(file, "string", utils.lua.bytecode(file)) + else + ar:add(file, "file", file) + end end -- file in the filesystem is more recent than in the archive elseif attributes and stat and attributes.modification > stat.mtime + 5 then if attributes.mode == "file" then utils.io.out("Update "..file.."\n") - ar:replace(assert(ar:name_locate(file)), "file", file) + if self.project.compile then + ar:replace(assert(ar:name_locate(file)), "string", + utils.lua.bytecode(file)) + else + ar:replace(assert(ar:name_locate(file)), "file", file) + end end end end diff --git a/src/scripts/windows.lua b/src/scripts/windows.lua index db5ad21..c163c9a 100644 --- a/src/scripts/windows.lua +++ b/src/scripts/windows.lua @@ -68,12 +68,14 @@ local function release(script, project, arch) os.rename(bin, project.title.."-win"..arch..".zip") end -function s.script(project) +function s.script(project, arch) local script = Script:new(project) script:createLoveFile() fs.change_dir(project.releaseDirectory) - release(script, project, 32) - if project.loveVersion >= semver'0.8.0' then + if arch == 32 then + release(script, project, 32) + end + if arch == 64 and project.loveVersion >= semver'0.8.0' then release(script, project, 64) end fs.pop_dir() @@ -81,7 +83,7 @@ end setmetatable(s, { - __call = function(_, project) return s.script(project) end, + __call = function(_, project, arch) return s.script(project, arch) end, }) return s