From db2ef01fe45bf80a73d273ab90d5ea0a5fc13ea3 Mon Sep 17 00:00:00 2001 From: Norman Clarke Date: Fri, 22 Jun 2012 11:41:56 -0300 Subject: Adjust Git clone command according to Git version. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git 1.7.10 and higher allows a branch or a tag to be passed as an argument to `git clone` along with `--depth=1`, which lets us check out the exact code needed to pack a rockspec without the entire repository's history. This offers a significant performance improvement for large repositories. For Git 1.7.9 and earlier, Luarocks will clone the repository without the branch argument in order to support both branches and tags. This is possible in part because prior to Git 1.7.10, git will clone sufficient repository history to check out any tag, even when the --depth option is passed. After cloning, Luarocks will then perform a `git checkout` prior to packing a rockspec. This is slower but lets Luarocks work consistently on more versions of Git. Resolves #73 Resolves #78 This change was implemented by: * Juan Ramírez (https://github.com/ichramm) * Ignacio Burgueño (https://github.com/ignacio) * Norman Clarke (https://github.com/norman) --- src/luarocks/fetch/git.lua | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/luarocks/fetch/git.lua b/src/luarocks/fetch/git.lua index e5f1ad4d..d643d25d 100644 --- a/src/luarocks/fetch/git.lua +++ b/src/luarocks/fetch/git.lua @@ -6,6 +6,20 @@ local fs = require("luarocks.fs") local dir = require("luarocks.dir") local util = require("luarocks.util") +--- Git >= 1.7.10 can clone a branch **or tag**, < 1.7.10 by branch only. We +-- need to know this in order to build the appropriate command; if we can't +-- clone by tag then we'll have to issue a subsequent command to check out the +-- given tag. +-- @return boolean: Whether Git can clone by tag. +local function git_can_clone_by_tag() + local version_string = io.popen('git --version'):read() + local major, minor, tiny = version_string:match('(%d-)%.(%d+)%.?(%d*)') + major, minor, tiny = tonumber(major), tonumber(minor), tonumber(tiny) or 0 + value = major > 1 or (major == 1 and (minor > 7 or (minor == 7 and tiny >= 10))) + git_can_clone_by_tag = function() return value end + return git_can_clone_by_tag() +end + --- Download sources for building a rock, using git. -- @param rockspec table: The rockspec table -- @param extract boolean: Unused in this module (required for API purposes.) @@ -22,11 +36,7 @@ function get_sources(rockspec, extract, dest_dir) local module = dir.base_name(rockspec.source.url) -- Strip off .git from base name if present module = module:gsub("%.git$", "") - local command = {git_cmd, "clone", "--depth=1", rockspec.source.url, module} - local tag_or_branch = rockspec.source.tag or rockspec.source.branch - if tag_or_branch then - table.insert(command, 4, "--branch=" .. tag_or_branch) - end + local store_dir if not dest_dir then store_dir = fs.make_temp_dir(name_version) @@ -39,14 +49,33 @@ function get_sources(rockspec, extract, dest_dir) end store_dir = fs.absolute_name(store_dir) fs.change_dir(store_dir) + + local command = {git_cmd, "clone", "--depth=1", rockspec.source.url, module} + local tag_or_branch = rockspec.source.tag or rockspec.source.branch + -- If the tag or branch is explicitly set to "master" in the rockspec, then + -- we can avoid passing it to Git since it's the default. + if tag_or_branch == "master" then tag_or_branch = nil end + if tag_or_branch then + if git_can_clone_by_tag() then + -- The argument to `--branch` can actually be a branch or a tag as of + -- Git 1.7.10. + table.insert(command, 4, "--branch=" .. tag_or_branch) + end + end if not fs.execute(unpack(command)) then return nil, "Failed cloning git repository." end fs.change_dir(module) + if tag_or_branch and not git_can_clone_by_tag() then + local checkout_command = {git_cmd, "checkout", tag_or_branch} + if not fs.execute(unpack(checkout_command)) then + return nil, 'Failed to check out the "' .. tag_or_branch ..'" tag or branch.' + end + end + fs.delete(dir.path(store_dir, module, ".git")) fs.delete(dir.path(store_dir, module, ".gitignore")) fs.pop_dir() fs.pop_dir() return module, store_dir end - -- cgit v1.2.3-55-g6feb