From d8a72ee125aa0acfa8d43b910572edfcc61cd434 Mon Sep 17 00:00:00 2001 From: mpeterv Date: Fri, 3 Apr 2015 16:45:26 +0300 Subject: Add support for git submodules When fetching rock sources using git, run `git submodule update --init --recursive` after cloning. When using git >= 1.8.4, also pass `--depth=1` to fetch only the last commit of each submodule. --- src/luarocks/fetch/git.lua | 54 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/luarocks/fetch/git.lua b/src/luarocks/fetch/git.lua index e540d696..0847f735 100644 --- a/src/luarocks/fetch/git.lua +++ b/src/luarocks/fetch/git.lua @@ -7,20 +7,48 @@ local unpack = unpack or table.unpack local fs = require("luarocks.fs") local dir = require("luarocks.dir") +local deps = require("luarocks.deps") local util = require("luarocks.util") +local cached_git_version + +--- Get git version. +-- @param git_cmd string: name of git command. +-- @return table: git version as returned by luarocks.deps.parse_version. +local function git_version(git_cmd) + if not cached_git_version then + local version_line = io.popen(fs.Q(git_cmd)..' --version'):read() + local version_string = version_line:match('%d-%.%d+%.?%d*') + cached_git_version = deps.parse_version(version_string) + end + + return cached_git_version +end + +--- Check if git satisfies version requirement. +-- @param git_cmd string: name of git command. +-- @param version string: required version. +-- @return boolean: true if git matches version or is newer, false otherwise. +local function git_is_at_least(git_cmd, version) + return git_version(git_cmd) >= deps.parse_version(version) +end + --- 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. +-- @param git_cmd string: name of git command. -- @return boolean: Whether Git can clone by tag. local function git_can_clone_by_tag(git_cmd) - local version_string = io.popen(fs.Q(git_cmd)..' --version'):read() - local major, minor, tiny = version_string:match('(%d-)%.(%d+)%.?(%d*)') - major, minor, tiny = tonumber(major), tonumber(minor), tonumber(tiny) or 0 - local 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 value + return git_is_at_least(git_cmd, "1.7.10") +end + +--- Git >= 1.8.4 can fetch submodules shallowly, saving bandwidth and time for +-- submodules with large history. +-- @param git_cmd string: name of git command. +-- @return boolean: Whether Git can fetch submodules shallowly. +local function git_supports_shallow_submodules(git_cmd) + return git_is_at_least(git_cmd, "1.8.4") end --- Download sources for building a rock, using git. @@ -77,12 +105,22 @@ function git.get_sources(rockspec, extract, dest_dir, depth) ok, err = fs.change_dir(module) if not ok then return nil, err end if tag_or_branch and not git_can_clone_by_tag() then - local checkout_command = {fs.Q(git_cmd), "checkout", tag_or_branch} - if not fs.execute(unpack(checkout_command)) then + if not fs.execute(fs.Q(git_cmd), "checkout", tag_or_branch) then return nil, 'Failed to check out the "' .. tag_or_branch ..'" tag or branch.' end end + command = {fs.Q(git_cmd), "submodule", "update", "--init", "--recursive"} + + if git_supports_shallow_submodules(git_cmd) then + -- Fetch only the last commit of each submodule. + table.insert(command, 5, "--depth=1") + end + + if not fs.execute(unpack(command)) then + return nil, 'Failed to fetch submodules.' + end + fs.delete(dir.path(store_dir, module, ".git")) fs.delete(dir.path(store_dir, module, ".gitignore")) fs.pop_dir() -- cgit v1.2.3-55-g6feb From 1e9edc66b768ad9e78401cf51931967430de1f7b Mon Sep 17 00:00:00 2001 From: mpeterv Date: Thu, 25 Jun 2015 14:14:16 +0300 Subject: Check that rockspec format is at least 3.0 before fetching submodules For utility, add deps.format_is_at_least(rockspec, version) function. --- src/luarocks/deps.lua | 9 +++++++++ src/luarocks/fetch/git.lua | 17 ++++++++++------- 2 files changed, 19 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/luarocks/deps.lua b/src/luarocks/deps.lua index 0e3265b5..f6c86d1c 100644 --- a/src/luarocks/deps.lua +++ b/src/luarocks/deps.lua @@ -159,6 +159,15 @@ function deps.compare_versions(a, b) return deps.parse_version(a) > deps.parse_version(b) end +--- Check if rockspec format version satisfies version requirement. +-- @param rockspec table: The rockspec table. +-- @param version string: required version. +-- @return boolean: true if rockspec format matches version or is newer, false otherwise. +function deps.format_is_at_least(rockspec, version) + local rockspec_format = rockspec.rockspec_format or "1.0" + return deps.parse_version(rockspec_format) >= deps.parse_version(version) +end + --- Consumes a constraint from a string, converting it to table format. -- For example, a string ">= 1.0, > 2.0" is converted to a table in the -- format {op = ">=", version={1,0}} and the rest, "> 2.0", is returned diff --git a/src/luarocks/fetch/git.lua b/src/luarocks/fetch/git.lua index 0847f735..ce41659b 100644 --- a/src/luarocks/fetch/git.lua +++ b/src/luarocks/fetch/git.lua @@ -110,15 +110,18 @@ function git.get_sources(rockspec, extract, dest_dir, depth) end end - command = {fs.Q(git_cmd), "submodule", "update", "--init", "--recursive"} + -- Fetching git submodules is supported only when rockspec format is >= 3.0. + if deps.format_is_at_least(rockspec, "3.0") then + command = {fs.Q(git_cmd), "submodule", "update", "--init", "--recursive"} - if git_supports_shallow_submodules(git_cmd) then - -- Fetch only the last commit of each submodule. - table.insert(command, 5, "--depth=1") - end + if git_supports_shallow_submodules(git_cmd) then + -- Fetch only the last commit of each submodule. + table.insert(command, 5, "--depth=1") + end - if not fs.execute(unpack(command)) then - return nil, 'Failed to fetch submodules.' + if not fs.execute(unpack(command)) then + return nil, 'Failed to fetch submodules.' + end end fs.delete(dir.path(store_dir, module, ".git")) -- cgit v1.2.3-55-g6feb