diff --git a/src/_manifest.lua b/src/_manifest.lua index 4b5acc624..93cae0422 100644 --- a/src/_manifest.lua +++ b/src/_manifest.lua @@ -1,7 +1,7 @@ -- -- _manifest.lua -- Manage the list of built-in Premake scripts. --- Copyright (c) 2002-2015 Jason Perkins and the Premake project +-- Copyright (c) 2002-2024 Jason Perkins and the Premake project -- -- The master list of built-in scripts. Order is important! If you want to @@ -55,6 +55,7 @@ "base/validation.lua", "base/premake.lua", "base/help.lua", + 'base/git_integration.lua', -- tool APIs "tools/dotnet.lua", diff --git a/src/_premake_main.lua b/src/_premake_main.lua index a19fcbe64..3dcd33625 100644 --- a/src/_premake_main.lua +++ b/src/_premake_main.lua @@ -1,7 +1,7 @@ -- -- _premake_main.lua -- Script-side entry point for the main program logic. --- Copyright (c) 2002-2015 Jason Perkins and the Premake project +-- Copyright (c) 2002-2024 Jason Perkins and the Premake project -- local shorthelp = "Type 'premake5 --help' for help" @@ -333,6 +333,13 @@ end end +--- +-- Run git integration part. +--- + + function m.gitHookInstallation() + p.git_integration.gitHookInstallation() + end --- -- Override point, for logic that should run after validation and @@ -387,6 +394,7 @@ m.bake, m.postBake, m.validate, + m.gitHookInstallation, m.preAction, m.callAction, m.postAction, diff --git a/src/base/git_integration.lua b/src/base/git_integration.lua new file mode 100644 index 000000000..ea5f158bf --- /dev/null +++ b/src/base/git_integration.lua @@ -0,0 +1,93 @@ +-- +-- git_integration.lua +-- +-- Code for git integration. +-- +-- Copyright (c) 2024 Jason Perkins and the Premake project +-- + +local p = premake +local api = p.api +p.git_integration = {} +local m = p.git_integration + +----------------------------------------------------------------------------- +-- +-- Register gitintegration. +-- +----------------------------------------------------------------------------- + +api.register { + name = "gitintegration", + scope = "global", + kind = "string", + allowed = { + "Off", + "Always", + "OnNewFiles" + } +} + +--- +-- Find root directory (directory containing '.git' directory). +--- +local function find_git_root(current_path) + current_path = path.getabsolute(current_path or _MAIN_SCRIPT_DIR) + + while not os.isdir(path.join(current_path, ".git")) do + current_path = path.getdirectory(current_path) + if current_path == "" then + error("No git root path") + end + end + return current_path +end + +--- +-- Write git post-checkout content +--- +local function print_git_post_checkout_hooks(root_path, mode) + local args = {} + for _, arg in ipairs(_ARGV) do + if not (arg:startswith("--file") or arg:startswith("/file")) then + table.insert(args, arg); + end + end + + local indent = '' + p.outln('#!/bin/sh') + if mode == 'OnNewFiles' then + p.outln('count=`git diff --compact-summary $1 $2 | grep -E "( \\(new\\)| \\(gone\\)|premake)" | wc -l`') + p.outln('if [ $count -ne 0 ]') + p.outln('then') + indent = ' ' + end + p.outln(indent .. p.esc(path.getrelative(root_path, _PREMAKE_COMMAND)) .. ' --file=' .. p.esc(path.getrelative(root_path, _MAIN_SCRIPT)) .. ' ' .. table.concat(p.esc(args), ' ')) + if mode == 'OnNewFiles' then + p.outln('fi') + end + p.outln('') +end + +--- +-- Generate .git/hooks/post-checkout according to mode +--- +function m.gitHookInstallation() + local git_integration_mode = p.api.rootContainer().gitintegration or "Off" + if git_integration_mode == "Off" then + return + end + local root_path = find_git_root() + + local content = p.capture(function () print_git_post_checkout_hooks(root_path, git_integration_mode) end) + local res, err = os.writefile_ifnotequal(content, path.join(root_path, '.git', 'hooks', 'post-checkout')) + + if (res == 0) then -- file not modified + return + elseif (res < 0) then + error(err, 0) + elseif (res > 0) then -- file modified + printf("Generated %s...", path.getrelative(os.getcwd(), path.join(root_path, '.git', 'hooks', 'post-checkout'))) + return + end +end diff --git a/website/docs/gitintegration.md b/website/docs/gitintegration.md new file mode 100644 index 000000000..068fe1745 --- /dev/null +++ b/website/docs/gitintegration.md @@ -0,0 +1,66 @@ +Enable git integration to run premake on checkout. + +```lua +gitintegration ("value") +``` + +### Parameters ### + +| Action | Description | +|-----------------|----------------------------------------------------------------------------------| +| Off | Disable git integration. | +| Always | Run premake on checkout. | +| OnNewFiles | Run premake only when files are added/removed or if premake script has changed. | + +### Applies To ### + +Global scope. + +### Availability ### + +Premake 5.0.0 beta 3 or later. + +### Examples ### + +Regenerate autoversion.h with git tag when checkout to another branch. + +```lua +gitintegration "Always" + +local locationDir = _OPTIONS["to"] + +local function autoversion_h() + local git_tag, errorCode = os.outputof("git describe --tag --always") + if errorCode == 0 then + print("git description: ", git_tag) + local content = io.readfile("src/autoversion.h.in") + content = content:gsub("${GIT_DESC}", git_tag) + + os.mkdir(locationDir) + local f, err = os.writefile_ifnotequal(content, path.join(locationDir, "autoversion.h")) + + if (f == 0) then -- file not modified + elseif (f < 0) then + error(err, 0) + return false + elseif (f > 0) then + print("Generated autoversion.h...") + end + + return true + else + print("`git describe --tag` failed with error code", errorCode, git_tag) + return false + end +end + +local have_autoversion_h = autoversion_h() + +workspace "MyProject" + location(locationDir) + + if have_autoversion_h then + includedirs { locationDir } -- for generated file (autoversion.h) + end + -- [..] +``` diff --git a/website/sidebars.js b/website/sidebars.js index 7f0e169c6..b9e819693 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -307,6 +307,14 @@ module.exports = { 'xcodesystemcapabilities' ] }, + { + collapsed: true, + type: 'category', + label: 'Global Settings', + items: [ + 'gitintegration' + ] + }, { collapsed: true, type: 'category',