用 lua 写 VisualSvn Server 的 hook

VisualSvn 的 Repositories 下面,每个库都有hooks目录这里存放9种hook.

我比较关心post-commit,要限制文件扩展名,采用白名单.


hooks支持批处理和EXE,比如post-commit.bat或post-commit.exe放在Repositories\code\hooks下面,在提交后,svn server会自动调用,

如果程序返回0表示成功,返回1表示失败. 可以把错误信息写到stderr,server会把错误信息推送到客户端


批处理语法难懂,喜欢用lua.所以写个exe,转调到lua中,在lua中实现主要判断逻辑.


下面是c++代码

#define CP_GBK      (936)       // 简体中文code page

void Unicode_to_GBK(const wchar_t* in, size_t len, std::string& out)
{
	int bufferlen = (int)::WideCharToMultiByte(CP_GBK,0,in,(int)len,NULL,0,NULL,NULL);
	char* pBuffer = new char[bufferlen + 4];
	if ( NULL == pBuffer )
	{
		return;
	}
	int out_len = ::WideCharToMultiByte(CP_GBK,0,in,(int)len,pBuffer,bufferlen+2,NULL,NULL);   
	pBuffer[bufferlen] = '\0';
	out.assign( pBuffer, out_len );
	delete[] pBuffer;

}

static int getShortPathName(lua_State* L)
{
	const char* lpFullPath = luaL_checkstring(L, 1);
	char strShortPath[MAX_PATH] = {0};
	GetShortPathNameA(lpFullPath, strShortPath, MAX_PATH);
	lua_pushstring(L, strShortPath);
	return 1;
}

static int pathFindExtension(lua_State* L)
{
	lua_pushstring(L, PathFindExtensionA(luaL_checkstring(L, 1)));
	return 1;
}

int MainImpl()
{
	int argc = 0;
	LPWSTR * argv = CommandLineToArgvW(GetCommandLine(), &argc);

	wchar_t* lpLuaFile = StrDup(argv[0]);
	PathRenameExtension(lpLuaFile, L".lua") ;

	int ret = 0;

	if (PathFileExists(lpLuaFile) && argv[1] && argv[2])
	{
		std::string strLuaFile;
		Unicode_to_GBK(lpLuaFile, wcslen(lpLuaFile), strLuaFile);

		lua_State* L = luaL_newstate();
		luaL_openlibs(L);
		lua_pushcfunction(L, getShortPathName);
		lua_setglobal(L, "getShortPathName");
		lua_pushcfunction(L, pathFindExtension);
		lua_setglobal(L, "pathFindExtension");

		if (luaL_dofile(L, strLuaFile.c_str()) == 0)
		{
			lua_getglobal(L, "MainCheck");
			if(!lua_isfunction(L, -1))
			{
				fprintf(stderr, "could not find MainCheck function");
				return ret;
			}

			std::string strDir, strTxn;
			Unicode_to_GBK(argv[1], wcslen(argv[1]), strDir);
			Unicode_to_GBK(argv[2], wcslen(argv[2]), strTxn);

			lua_pushstring(L, strDir.c_str());
			lua_pushstring(L, strTxn.c_str());

			if (lua_pcall(L, 2, 1, 0) == 0)
			{
				ret = lua_tointeger(L, -1);
			}
			else
			{
				fprintf(stderr, "%s", lua_tostring(L, -1));
			}
		}

		lua_close(L);
	}

	LocalFree(lpLuaFile);
	LocalFree(argv);
	return ret;
}

int main()
{
	return MainImpl();
}

int __stdcall WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd )
{
	return MainImpl();	
}

下面是lua代码

local svn_look = [[C:\Program Files\VisualSVN Server\bin\svnlook.exe]] -- 通过svn_look返回提交的所有文件列表

print = function(...)
	log = log or io.open([[D:\Repositories\code\hooks\pre-commit.log]], "w")
	for k, v in ipairs(arg) do
		log:write(tostring(v), "\t")
	end
	log:write("\n")
end

-- 白名单
local allow_list = {
	-- c,c++
	[".c"] = true,
	[".cpp"] = true,
	[".h"] = true,
	[".cxx"] = true,
	[".hpp"] = true,
	[".aps"] = true,	
	[".idl"] = true,
	
	-- vs
	[".sln"] = true,
	[".vcproj"] = true,
	[".dsw"] = true,
	
	-- other
	[".html"] = true,
	[".htm"] = true,
	[".xml"] = true,
	[".lua"] = true,
	[".txt"] = true,
	[".bat"] = true,
	
	-- res
	[".ico"] = true,
	[".rc"] = true,
	
	-- office
	[".doc"] = true,
	[".docx"] = true,
	[".ppt"] = true,
	[".pptx"] = true,
	
	--image
	[".jpg"] = true,
	[".png"] = true,
	[".gif"] = true,
	[".bmp"] = true,
	
	--xar
	[".cfg"] = true,
	
}

function MainCheck(dir, txn)
	print("MainCheck", dir, txn)

	local cmd = string.format("%s changed \"%s\" -t \"%s\"", getShortPathName(svn_look), dir, txn)
	print(cmd)
	
	local p = io.popen(cmd)
	for line in p:lines() do
		print(line, line:sub(4), pathFindExtension(line:sub(4)))
		
		local ext = pathFindExtension(line:sub(4))
		if ext:len() ~= 0 and not allow_list[ext:lower()] then
			io.stderr:write(ext:lower().. " 不允许提交")
			return 1
		end
	end
	
	log:close()
	
	return 0
end


用法:把生成的exe,改名为9中hook的任意一种,然后lua文件与exe同名,放在hooks目录下.


有编译好的文件,依赖vc2005和vc2008的运行时.

http://download.csdn.net/detail/gushiaoke/4341686

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值