From: Tobias Ulmer Date: Tue, 24 Jan 2017 13:40:43 +0000 (+0100) Subject: Move fetch/update/prepare from scm to source classes X-Git-Tag: e2factory-2.3.17~44 X-Git-Url: https://git.e2factory.org/?a=commitdiff_plain;h=8e8315c4233c2671bc5e8c4612eb317347938f0a;p=e2factory.git Move fetch/update/prepare from scm to source classes Signed-off-by: Tobias Ulmer --- diff --git a/plugins/cvs.lua b/plugins/cvs.lua index 4a868ff..8a7b06b 100644 --- a/plugins/cvs.lua +++ b/plugins/cvs.lua @@ -58,7 +58,38 @@ plugin_descriptor = { exit = function (ctx) return true end, } -cvs.cvs_source = class("cvs_source", source.basic_source) +-------------------------------------------------------------------------------- + +--- Build the cvsroot string. +-- @param src Source object. +-- @return CVSROOT string or false on error. +-- @return Error object on failure. +local function mkcvsroot(src) + local cvsroot, surl, u, re + + surl, re = cache.remote_url(cache.cache(), src:get_server(), src:get_cvsroot()) + if not surl then + return false, e:cat(re) + end + + u, re = url.parse(surl) + if not u then + return false, e:cat(re) + end + + if u.transport == "file" then + cvsroot = string.format("/%s", u.path) + elseif (u.transport == "ssh") or (u.transport == "rsync+ssh") or + u.transport == "scp" then + cvsroot = string.format("%s:/%s", u.server, u.path) + elseif u.transport == "cvspserver" then + cvsroot = string.format(":pserver:%s:/%s", u.server, u.path) + else + return false, err.new("cvs: unhandled transport: %s", u.transport) + end + + return cvsroot +end local function cvs_tool(argv, workdir) local rc, re, cvscmd, cvsflags, rsh @@ -80,6 +111,10 @@ local function cvs_tool(argv, workdir) return e2lib.callcmd_log(cvscmd, workdir, { CVS_RSH=rsh }) end +-------------------------------------------------------------------------------- + +cvs.cvs_source = class("cvs_source", source.basic_source) + function cvs.cvs_source.static:is_scm_source_class() return true end @@ -293,75 +328,39 @@ function cvs.cvs_source:check_workingcopy() return true end --------------------------------------------------------------------------------- - ---- Build the cvsroot string. --- @param sourcename Source name. --- @return CVSROOT string or false on error. --- @return Error object on failure. -local function mkcvsroot(sourcename) - local cvsroot, src, surl, u, re +function cvs.cvs_source:fetch_source() + local rc, re, e, cvsroot, workdir, argv - src = source.sources[sourcename] + e = err.new("fetching source failed: %s", self._name) - surl, re = cache.remote_url(cache.cache(), src:get_server(), src:get_cvsroot()) - if not surl then - return false, e:cat(re) - end - - u, re = url.parse(surl) - if not u then - return false, e:cat(re) - end - - if u.transport == "file" then - cvsroot = string.format("/%s", u.path) - elseif (u.transport == "ssh") or (u.transport == "rsync+ssh") or - u.transport == "scp" then - cvsroot = string.format("%s:/%s", u.server, u.path) - elseif u.transport == "cvspserver" then - cvsroot = string.format(":pserver:%s:/%s", u.server, u.path) - else - return false, err.new("cvs: unhandled transport: %s", u.transport) - end - - return cvsroot -end - -function cvs.fetch_source(info, sourcename) - local rc, re, e, src, cvsroot, workdir, argv - - e = err.new("fetching source failed: %s", sourcename) - src = source.sources[sourcename] - - if src:working_copy_available() then + if self:working_copy_available() then return true end - cvsroot, re = mkcvsroot(sourcename) + cvsroot, re = mkcvsroot(self) if not cvsroot then return false, e:cat(re) end -- split the working directory into dirname and basename as some cvs clients -- don't like slashes (e.g. in/foo) in their checkout -d argument - workdir = e2lib.dirname(e2lib.join(e2tool.root(), src:get_working())) + workdir = e2lib.dirname(e2lib.join(e2tool.root(), self:get_working())) argv = { "-d", cvsroot, "checkout", "-R", - "-d", e2lib.basename(src:get_working()), + "-d", e2lib.basename(self:get_working()), } -- always fetch the configured branch, as we don't know the build mode here. -- HEAD has special meaning to cvs - if src:get_branch() ~= "HEAD" then + if self:get_branch() ~= "HEAD" then table.insert(argv, "-r") - table.insert(argv, src:get_branch()) + table.insert(argv, self:get_branch()) end - table.insert(argv, src:get_module()) + table.insert(argv, self:get_module()) rc, re = cvs_tool(argv, workdir) if not rc or rc ~= 0 then @@ -370,13 +369,12 @@ function cvs.fetch_source(info, sourcename) return true end -function cvs.prepare_source(info, sourcename, sourceset, buildpath) - local rc, re, e, src, cvsroot, argv +function cvs.cvs_source:prepare_source(sourceset, buildpath) + local rc, re, e, cvsroot, argv e = err.new("cvs.prepare_source failed") - src = source.sources[sourcename] - cvsroot, re = mkcvsroot(sourcename) + cvsroot, re = mkcvsroot(self) if not cvsroot then return false, re end @@ -385,29 +383,29 @@ function cvs.prepare_source(info, sourcename, sourceset, buildpath) argv = { "-d", cvsroot, "export", "-R", - "-d", src:get_name(), + "-d", self:get_name(), "-r", } if sourceset == "branch" or - (sourceset == "lazytag" and src:get_tag() == "^") then - table.insert(argv, src:get_branch()) + (sourceset == "lazytag" and self:get_tag() == "^") then + table.insert(argv, self:get_branch()) elseif (sourceset == "tag" or sourceset == "lazytag") and - src:get_tag() ~= "^" then - table.insert(argv, src:get_tag()) + self:get_tag() ~= "^" then + table.insert(argv, self:get_tag()) else return false, e:cat(err.new("source set not allowed")) end - table.insert(argv, src:get_module()) + table.insert(argv, self:get_module()) rc, re = cvs_tool(argv, buildpath) if not rc or rc ~= 0 then return false, e:cat(re) end elseif sourceset == "working-copy" then - rc, re = e2lib.cp(e2lib.join(e2tool.root(), src:get_working()), - e2lib.join(buildpath, src:get_name()), true) + rc, re = e2lib.cp(e2lib.join(e2tool.root(), self:get_working()), + e2lib.join(buildpath, self:get_name()), true) if not rc then return false, e:cat(re) end @@ -417,18 +415,17 @@ function cvs.prepare_source(info, sourcename, sourceset, buildpath) return true, nil end -function cvs.update(info, sourcename) - local rc, re, e, src, workdir, argv +function cvs.cvs_source:update_source() + local rc, re, e, workdir, argv - e = err.new("updating source '%s' failed", sourcename) - src = source.sources[sourcename] + e = err.new("updating source '%s' failed", self._name) - rc, re = src:working_copy_available() + rc, re = self:working_copy_available() if not rc then return false, e:cat(re) end - workdir = e2lib.join(e2tool.root(), src:get_working()) + workdir = e2lib.join(e2tool.root(), self:get_working()) argv = { "update", "-R" } rc, re = cvs_tool(argv, workdir) @@ -439,6 +436,8 @@ function cvs.update(info, sourcename) return true end +-------------------------------------------------------------------------------- + function cvs.toresult(info, sourcename, sourceset, directory) -- /source/.tar.gz -- /makefile @@ -476,7 +475,7 @@ function cvs.toresult(info, sourcename, sourceset, directory) return false, re end - rc, re = cvs.prepare_source(info, sourcename, sourceset, tmpdir) + rc, re = src:prepare_source(sourceset, tmpdir) if not rc then return false, e:cat(re) end diff --git a/plugins/files.lua b/plugins/files.lua index 98c67d3..ab13a7a 100644 --- a/plugins/files.lua +++ b/plugins/files.lua @@ -59,6 +59,147 @@ plugin_descriptor = { exit = function (ctx) return true end, } +-------------------------------------------------------------------------------- + +--- Generates the command to unpack an archive file. +-- @param physpath Current location and filename to be unpacked later. +-- @param virtpath Location and name of the file at the time of unpacking. +-- @param destdir Path where the unpacked files shall be put. +-- @return Tool name (string), or false on error. +-- @return Argument vector table for the tool, or an error object on failure. +local function gen_unpack_command(physpath, virtpath, destdir) + + --- Determine archive type by looking at the file extension. + -- @param filename File name (string). + -- @return String constant describing archive, + -- or false if archive suffix is unknown. + -- @return Error object on failure. + local function archive_by_suffix(filename) + local name = filename:lower() -- case insensitive matching + local atype + + if name:match("%.tar$") then + atype = "TAR" + elseif name:match("%.tgz") or name:match("%.tar%.gz$") then + atype = "TAR_GZ" + elseif name:match("%.tar%.bz2$") then + atype = "TAR_BZIP2" + elseif name:match("%.tar%.xz$") then + atype = "TAR_XZ" + elseif name:match("%.zip$") then + atype = "ZIP" + else + return false, err.new("can not determine archive type of '%s'", + filename) + end + + return atype + end + + local tool + local toolargv = {} + + local atype, re = archive_by_suffix(physpath) + if not atype then + return false, re + end + + if atype == "ZIP" then + tool = "unzip" + table.insert(toolargv, virtpath) + table.insert(toolargv, "-d") + table.insert(toolargv, destdir) + elseif atype == "TAR" then + tool = "tar" + table.insert(toolargv, "-C") + table.insert(toolargv, destdir) + table.insert(toolargv, "-xf") + table.insert(toolargv, virtpath) + elseif atype == "TAR_GZ" then + tool = "tar" + table.insert(toolargv, "-z") + table.insert(toolargv, "-C") + table.insert(toolargv, destdir) + table.insert(toolargv, "-xf") + table.insert(toolargv, virtpath) + elseif atype == "TAR_BZIP2" then + tool = "tar" + table.insert(toolargv, "-j") + table.insert(toolargv, "-C") + table.insert(toolargv, destdir) + table.insert(toolargv, "-xf") + table.insert(toolargv, virtpath) + elseif atype == "TAR_XZ" then + tool = "tar" + table.insert(toolargv, "--xz") + table.insert(toolargv, "-C") + table.insert(toolargv, destdir) + table.insert(toolargv, "-xf") + table.insert(toolargv, virtpath) + else + return false, err.new("unhandled archive type") + end + + return tool, toolargv +end + +--- Handle file:copy() in a way that appears intuitive to the user. Returns +-- a directory and filename that can be passed to eg. mkdir -p and cp. +-- @param buildpath Base build path (string). +-- @param sourcename Name of the source (string). +-- @param copypath Directory or file name where the source file should be +-- copied to (string). +-- @param location Soure file location (string). +-- @param dircheck Check for destination (copypath) being an existing directory. +-- "yes" enables checking (default), "no" disables the check, and "isdir" +-- pretends destination is a directory. This flag is useful for collect_project, +-- where we don't build the source, but just look at its config. +-- @return Destination directory (string). +-- @return Destination file name (string). +local function gen_dest_dir_name(buildpath, sourcename, copypath, location, + dircheck) + + dircheck = dircheck or "yes" + local destdir, destname + local destination = e2lib.join(buildpath, sourcename, copypath) + + -- It may look like ending in a file name ("/foo/bar") - but if + -- bar is a directory, we have to copy the file into the + -- directory. It's not always possible to check for the destination + -- directory. dircheck therefore allows to skip the isdir check, so the + -- reults can still be used for code generation. + + if dircheck == "isdir" or + (dircheck == "yes" and e2lib.isdir(destination)) then + destdir = destination + destname = e2lib.basename(location) + else + -- '.' and '..' are not path components as such, but refer + -- to the current and previous directory instead. + -- Fixup path by appending a harmless slash, to simplify + -- the logic below. + local last = e2lib.basename(destination) + if last == "." or last == ".." then + destination = e2lib.join(destination, "") + end + + if string.sub(destination, -1) == "/" then + -- destination refers to a directory, indicated by the / at the end + -- use destname from location. + destdir = destination + destname = e2lib.basename(location) + else + -- destination (potentially) ends with a file name + destdir = e2lib.dirname(destination) + destname = e2lib.basename(destination) + end + end + + return destdir, destname +end + +-------------------------------------------------------------------------------- + files.files_source = class("files_source", source.basic_source) function files.files_source.static:is_selected_source_class(opts) @@ -301,14 +442,11 @@ function files.files_source:check_workingcopy() return true end --------------------------------------------------------------------------------- - -function files.fetch_source(info, sourcename) +function files.files_source:fetch_source() local rc, re - local src = source.sources[sourcename] - local e = err.new("fetching source failed: %s", sourcename) + local e = err.new("fetching source failed: %s", self._name) - for file in src:file_iter() do + for file in self:file_iter() do if cache.cache_enabled(cache.cache(), file:server()) then e2lib.logf(3, "files.fetch_source: caching file %s", file:servloc()) rc, re = cache.fetch_file_path(cache.cache(), file:server(), file:location()) @@ -323,165 +461,16 @@ function files.fetch_source(info, sourcename) return true end ---- Handle file:copy() in a way that appears intuitive to the user. Returns --- a directory and filename that can be passed to eg. mkdir -p and cp. --- @param buildpath Base build path (string). --- @param sourcename Name of the source (string). --- @param copypath Directory or file name where the source file should be --- copied to (string). --- @param location Soure file location (string). --- @param dircheck Check for destination (copypath) being an existing directory. --- "yes" enables checking (default), "no" disables the check, and "isdir" --- pretends destination is a directory. This flag is useful for collect_project, --- where we don't build the source, but just look at its config. --- @return Destination directory (string). --- @return Destination file name (string). -local function gen_dest_dir_name(buildpath, sourcename, copypath, location, - dircheck) - - dircheck = dircheck or "yes" - local destdir, destname - local destination = e2lib.join(buildpath, sourcename, copypath) - - -- It may look like ending in a file name ("/foo/bar") - but if - -- bar is a directory, we have to copy the file into the - -- directory. It's not always possible to check for the destination - -- directory. dircheck therefore allows to skip the isdir check, so the - -- reults can still be used for code generation. - - if dircheck == "isdir" or - (dircheck == "yes" and e2lib.isdir(destination)) then - destdir = destination - destname = e2lib.basename(location) - else - -- '.' and '..' are not path components as such, but refer - -- to the current and previous directory instead. - -- Fixup path by appending a harmless slash, to simplify - -- the logic below. - local last = e2lib.basename(destination) - if last == "." or last == ".." then - destination = e2lib.join(destination, "") - end - - if string.sub(destination, -1) == "/" then - -- destination refers to a directory, indicated by the / at the end - -- use destname from location. - destdir = destination - destname = e2lib.basename(location) - else - -- destination (potentially) ends with a file name - destdir = e2lib.dirname(destination) - destname = e2lib.basename(destination) - end - end - - return destdir, destname -end - ---- Determine archive type by looking at the file extension. --- @param filename File name (string). --- @return String constant describing archive, --- or false if archive suffix is unknown. --- @return Error object on failure. -local function archive_by_suffix(filename) - local name = filename:lower() -- case insensitive matching - local atype - - if name:match("%.tar$") then - atype = "TAR" - elseif name:match("%.tgz") or name:match("%.tar%.gz$") then - atype = "TAR_GZ" - elseif name:match("%.tar%.bz2$") then - atype = "TAR_BZIP2" - elseif name:match("%.tar%.xz$") then - atype = "TAR_XZ" - elseif name:match("%.zip$") then - atype = "ZIP" - else - return false, err.new("can not determine archive type of '%s'", - filename) - end - - return atype -end - ---- Generates the command to unpack an archive file. --- @param physpath Current location and filename to be unpacked later. --- @param virtpath Location and name of the file at the time of unpacking. --- @param destdir Path where the unpacked files shall be put. --- @return Tool name (string), or false on error. --- @return Argument vector table for the tool, or an error object on failure. -local function gen_unpack_command(physpath, virtpath, destdir) - local tool - local toolargv = {} - - local atype, re = archive_by_suffix(physpath) - if not atype then - return false, re - end - - if atype == "ZIP" then - tool = "unzip" - table.insert(toolargv, virtpath) - table.insert(toolargv, "-d") - table.insert(toolargv, destdir) - elseif atype == "TAR" then - tool = "tar" - table.insert(toolargv, "-C") - table.insert(toolargv, destdir) - table.insert(toolargv, "-xf") - table.insert(toolargv, virtpath) - elseif atype == "TAR_GZ" then - tool = "tar" - table.insert(toolargv, "-z") - table.insert(toolargv, "-C") - table.insert(toolargv, destdir) - table.insert(toolargv, "-xf") - table.insert(toolargv, virtpath) - elseif atype == "TAR_BZIP2" then - tool = "tar" - table.insert(toolargv, "-j") - table.insert(toolargv, "-C") - table.insert(toolargv, destdir) - table.insert(toolargv, "-xf") - table.insert(toolargv, virtpath) - elseif atype == "TAR_XZ" then - tool = "tar" - table.insert(toolargv, "--xz") - table.insert(toolargv, "-C") - table.insert(toolargv, destdir) - table.insert(toolargv, "-xf") - table.insert(toolargv, virtpath) - else - return false, err.new("unhandled archive type") - end - - return tool, toolargv -end - ---- Call the patch command --- @param argv Vector of arguments supplied to patch tool. --- @return True on success, false on error. --- @return Error object on failure. -local function patch_tool(argv) - return e2lib.call_tool_argv("patch", argv) +function files.files_source:update_source() + return true, nil end ---- Prepare a files source. --- @param info The info table. --- @param sourcename The source name (string) --- @param sourceset Unused. --- @param buildpath Base path of the build directory ($T/build) (string). --- @see toresult --- @return bool --- @return nil, maybe an error string on error -function files.prepare_source(info, sourcename, sourceset, buildpath) +function files.files_source:prepare_source(sourceset, buildpath) local rc, re - local e = err.new("error preparing source: %s", sourcename) + local e = err.new("error preparing source: %s", self._name) local symlink = nil - local src = source.sources[sourcename] - for file in src:file_iter() do + for file in self:file_iter() do rc, re = file:checksum_verify() if not rc then return false, e:cat(re) @@ -512,8 +501,8 @@ function files.prepare_source(info, sourcename, sourceset, buildpath) end if not symlink then - symlink = buildpath .. "/" .. sourcename - if file:unpack() ~= sourcename then + symlink = buildpath .. "/" .. self._name + if file:unpack() ~= self._name then rc, re = e2lib.symlink(file:unpack(), symlink) if not rc then return false, e:cat(re) @@ -524,7 +513,7 @@ function files.prepare_source(info, sourcename, sourceset, buildpath) end else if not symlink then - symlink = buildpath .. "/" .. sourcename + symlink = buildpath .. "/" .. self._name rc, re = e2lib.mkdir_recursive(symlink) if not rc then return false, e:cat(re) @@ -537,14 +526,14 @@ function files.prepare_source(info, sourcename, sourceset, buildpath) return false, e:append(re) end local argv = { "-p", file:patch(), "-d", symlink, "-i", path } - rc, re = patch_tool(argv) + rc, re = e2lib.call_tool_argv("patch", argv) if not rc then e:append("applying patch: \"%s\"", file:servloc()) return false, e:cat(re) end elseif file:copy() then local destdir, destname - destdir, destname = gen_dest_dir_name(buildpath, sourcename, + destdir, destname = gen_dest_dir_name(buildpath, self._name, file:copy(), file:location()) rc, re = e2lib.mkdir_recursive(destdir) @@ -567,6 +556,9 @@ function files.prepare_source(info, sourcename, sourceset, buildpath) return true, nil end + +-------------------------------------------------------------------------------- + --- Create a source result containing the generated Makefile and files -- belonging to the source, for use with collect_project. -- Result refers to a collection of files to recreate an e2source for @@ -708,15 +700,6 @@ function files.toresult(info, sourcename, sourceset, directory) return true end ---- Update the source. --- @param info The info table. --- @param sourcename The name of the source (string). --- @return Boolean, true on success. --- @return An error object on failure. -function files.update(info, sourcename) - return true, nil -end - strict.lock(files) -- vim:sw=4:sts=4:et: diff --git a/plugins/git.lua b/plugins/git.lua index 44c51d6..aa860ff 100644 --- a/plugins/git.lua +++ b/plugins/git.lua @@ -376,88 +376,64 @@ function git.git_source:check_workingcopy() return true end --------------------------------------------------------------------------------- +function git.git_source:fetch_source() + local e, rc, re, git_dir, work_tree, id ---- Return the git commit ID of the specified source configuration. Specific to --- sources of type git, useful for writing plugins. --- @param info Info table. --- @param sourcename Source name. --- @param sourceset string: the sourceset --- @param check_remote bool: in tag mode: make sure the tag is available remote --- @return True on success, false on error. --- @return Error object on failure. --- @return Commit ID (string) on success. -function git.git_commit_id(info, sourcename, sourceset, check_remote) - local rc, re, e, src, id, fr, gitdir, ref + e = err.new("fetching source failed: %s", self._name) - e = err.new("getting commit ID failed for source: %s", sourcename) - src = source.sources[sourcename] + if self:working_copy_available() then + return true + end - rc, re = src:working_copy_available() + work_tree = e2lib.join(e2tool.root(), self:get_working()) + git_dir = e2lib.join(work_tree, ".git") + + e2lib.logf(2, "cloning %s:%s [%s]", self:get_server(), self:get_location(), + self:get_branch()) + + rc, re = generic_git.git_clone_from_server(cache.cache(), self:get_server(), + self:get_location(), work_tree, false --[[always checkout]]) if not rc then return false, e:cat(re) end - rc, re = src:check_workingcopy() + rc, re, id = generic_git.lookup_id(git_dir, false, + "refs/heads/" .. self:get_branch()) if not rc then return false, e:cat(re) - end - - gitdir = e2lib.join(e2tool.root(), src:get_working(), ".git") - - if sourceset == "branch" or (sourceset == "lazytag" and src:get_tag() == "^") then - ref = string.format("refs/heads/%s", src:get_branch()) - - rc, re, id = generic_git.lookup_id(gitdir, false, ref) + elseif not id then + rc, re = generic_git.git_branch_new1(work_tree, true, self:get_branch(), + "origin/" .. self:get_branch()) if not rc then return false, e:cat(re) end - elseif sourceset == "tag" or (sourceset == "lazytag" and src:get_tag() ~= "^") then - ref = string.format("refs/tags/%s", src:get_tag()) - rc, re, id = generic_git.lookup_id(gitdir, false, ref) + rc, re = generic_git.git_checkout1(work_tree, + "refs/heads/" .. self:get_branch()) if not rc then return false, e:cat(re) end - - if id and check_remote then - rc, re = generic_git.verify_remote_tag(gitdir, src:get_tag()) - if not rc then - return false, e:cat(re) - end - end - else - return false, err.new("not an scm sourceset: %s", sourceset) end - if not id then - re = err.new("can't get git commit ID for ref %q from repository %q", - ref, src:get_working()) - return false, e:cat(re) - end - - return true, nil, id + return true end --- update a working copy --- @param info the info structure --- @param sourcename string -- @return bool -- @return an error object -function git.update(info, sourcename) - local e, rc, re, src, gitwc, gitdir, argv, id, branch, remote +function git.git_source:update_source() + local e, rc, re, gitwc, gitdir, argv, id, branch, remote - src = source.sources[sourcename] - e = err.new("updating source '%s' failed", sourcename) + e = err.new("updating source '%s' failed", self._name) - rc, re = src:working_copy_available() + rc, re = self:working_copy_available() if not rc then return false, e:cat(re) end - e2lib.logf(2, "updating %s [%s]", src:get_working(), src:get_branch()) + e2lib.logf(2, "updating %s [%s]", self:get_working(), self:get_branch()) - gitwc = e2lib.join(e2tool.root(), src:get_working()) + gitwc = e2lib.join(e2tool.root(), self:get_working()) gitdir = e2lib.join(gitwc, ".git") argv = generic_git.git_new_argv(gitdir, gitwc, "fetch") @@ -488,20 +464,20 @@ function git.update(info, sourcename) return true end - if branch ~= "refs/heads/" .. src:get_branch() then + if branch ~= "refs/heads/" .. self:get_branch() then e2lib.warnf("WOTHER", "not on configured branch. Skipping.") return true end remote, re = generic_git.git_config( - gitdir, "branch."..src:get_branch()..".remote") + gitdir, "branch."..self:get_branch()..".remote") if not remote or string.len(remote) == 0 then e2lib.warnf("WOTHER", "no remote configured for branch %q. Skipping.", - src:get_branch()) + self:get_branch()) return true end - branch = remote .. "/" .. src:get_branch() + branch = remote .. "/" .. self:get_branch() argv = generic_git.git_new_argv(gitdir, gitwc, "merge", "--ff-only", branch) rc, re = generic_git.git(argv) if not rc then @@ -511,75 +487,20 @@ function git.update(info, sourcename) return true end ---- fetch a git source --- @param info the info structure --- @param sourcename string --- @return bool --- @return nil on success, an error string on error -function git.fetch_source(info, sourcename) - local e, rc, re, src, git_dir, work_tree, id - - src = source.sources[sourcename] - e = err.new("fetching source failed: %s", sourcename) - - if src:working_copy_available() then - return true - end - - work_tree = e2lib.join(e2tool.root(), src:get_working()) - git_dir = e2lib.join(work_tree, ".git") - - e2lib.logf(2, "cloning %s:%s [%s]", src:get_server(), src:get_location(), - src:get_branch()) - - rc, re = generic_git.git_clone_from_server(cache.cache(), src:get_server(), - src:get_location(), work_tree, false --[[always checkout]]) - if not rc then - return false, e:cat(re) - end - - rc, re, id = generic_git.lookup_id(git_dir, false, - "refs/heads/" .. src:get_branch()) - if not rc then - return false, e:cat(re) - elseif not id then - rc, re = generic_git.git_branch_new1(work_tree, true, src:get_branch(), - "origin/" .. src:get_branch()) - if not rc then - return false, e:cat(re) - end - - rc, re = generic_git.git_checkout1(work_tree, - "refs/heads/" .. src:get_branch()) - if not rc then - return false, e:cat(re) - end - end - - return true -end - ---- prepare a git source --- @param info the info structure --- @param sourcename string --- @param sourceset --- @param buildpath --- @return bool --- @return nil on success, an error string on error -function git.prepare_source(info, sourcename, sourceset, buildpath) +function git.git_source:prepare_source(sourceset, buildpath) local rc, re, e - local src, srcdir, destdir + local srcdir, destdir, info - e = err.new("preparing git source %s failed", sourcename) - src = source.sources[sourcename] + e = err.new("preparing git source %s failed", self._name) - rc, re = scm.generic_source_check(info, sourcename, true) + info = e2tool.info() + rc, re = scm.generic_source_check(info, self._name, true) if not rc then return false, e:cat(re) end - srcdir = e2lib.join(e2tool.root(), src:get_working()) - destdir = e2lib.join(buildpath, sourcename) + srcdir = e2lib.join(e2tool.root(), self:get_working()) + destdir = e2lib.join(buildpath, self._name) rc, re = e2lib.mkdir_recursive(destdir) if not rc then @@ -589,7 +510,7 @@ function git.prepare_source(info, sourcename, sourceset, buildpath) if sourceset == "working-copy" then local empty - srcdir = e2lib.join(e2tool.root(), src:get_working()) + srcdir = e2lib.join(e2tool.root(), self:get_working()) empty = true for f, re in e2lib.directory(srcdir, true) do @@ -610,7 +531,7 @@ function git.prepare_source(info, sourcename, sourceset, buildpath) end if empty then - e2lib.warnf("WOTHER", "in result: %s", sourcename) + e2lib.warnf("WOTHER", "in result: %s", self._name) e2lib.warnf("WOTHER", "working copy seems empty") end @@ -623,7 +544,7 @@ function git.prepare_source(info, sourcename, sourceset, buildpath) gitdir = e2lib.join(srcdir, ".git") - rc, re = git.git_commit_id(info, sourcename, sourceset) + rc, re = git.git_commit_id(info, self._name, sourceset) if not rc then return false, e:cat(re) end @@ -632,11 +553,11 @@ function git.prepare_source(info, sourcename, sourceset, buildpath) table.insert(git_argv, "--format=tar") if sourceset == "branch" or - (sourceset == "lazytag" and src:get_tag() == "^") then - table.insert(git_argv, "refs/heads/" .. src:get_branch()) + (sourceset == "lazytag" and self:get_tag() == "^") then + table.insert(git_argv, "refs/heads/" .. self:get_branch()) elseif sourceset == "tag" or - (sourceset == "lazytag" and src:get_tag() ~= "^") then - table.insert(git_argv, "refs/tags/" .. src:get_tag()) + (sourceset == "lazytag" and self:get_tag() ~= "^") then + table.insert(git_argv, "refs/tags/" .. self:get_tag()) else error(err.new("invalid sourceset: %s", sourceset)) end @@ -723,6 +644,70 @@ function git.prepare_source(info, sourcename, sourceset, buildpath) return true end + +-------------------------------------------------------------------------------- + +--- Return the git commit ID of the specified source configuration. Specific to +-- sources of type git, useful for writing plugins. +-- @param info Info table. +-- @param sourcename Source name. +-- @param sourceset string: the sourceset +-- @param check_remote bool: in tag mode: make sure the tag is available remote +-- @return True on success, false on error. +-- @return Error object on failure. +-- @return Commit ID (string) on success. +function git.git_commit_id(info, sourcename, sourceset, check_remote) + local rc, re, e, src, id, fr, gitdir, ref + + e = err.new("getting commit ID failed for source: %s", sourcename) + src = source.sources[sourcename] + + rc, re = src:working_copy_available() + if not rc then + return false, e:cat(re) + end + + rc, re = src:check_workingcopy() + if not rc then + return false, e:cat(re) + end + + gitdir = e2lib.join(e2tool.root(), src:get_working(), ".git") + + if sourceset == "branch" or (sourceset == "lazytag" and src:get_tag() == "^") then + ref = string.format("refs/heads/%s", src:get_branch()) + + rc, re, id = generic_git.lookup_id(gitdir, false, ref) + if not rc then + return false, e:cat(re) + end + elseif sourceset == "tag" or (sourceset == "lazytag" and src:get_tag() ~= "^") then + ref = string.format("refs/tags/%s", src:get_tag()) + + rc, re, id = generic_git.lookup_id(gitdir, false, ref) + if not rc then + return false, e:cat(re) + end + + if id and check_remote then + rc, re = generic_git.verify_remote_tag(gitdir, src:get_tag()) + if not rc then + return false, e:cat(re) + end + end + else + return false, err.new("not an scm sourceset: %s", sourceset) + end + + if not id then + re = err.new("can't get git commit ID for ref %q from repository %q", + ref, src:get_working()) + return false, e:cat(re) + end + + return true, nil, id +end + function git.toresult(info, sourcename, sourceset, directory) local rc, re, argv local e = err.new("converting result") diff --git a/plugins/gitrepo.lua b/plugins/gitrepo.lua index 21af90b..4b4e80e 100644 --- a/plugins/gitrepo.lua +++ b/plugins/gitrepo.lua @@ -31,6 +31,7 @@ local hash = require("hash") local licence = require("licence") local scm = require("scm") local source = require("source") +local strict = require("strict") local url = require("url") local gitrepo_source = class("gitrepo_source", source.basic_source) @@ -319,51 +320,40 @@ function gitrepo_source:check_workingcopy() return true end --------------------------------------------------------------------------------- +function gitrepo_source:fetch_source() + local e, rc, re, git_dir, work_tree, id ---- Fetch a gitrepo source. Adapted from git plugin. --- @param info the info structure --- @param sourcename string --- @return bool --- @return true on success, an error string on error -function gitrepo.fetch_source(info, sourcename) - assertIsTable(info) - assertIsStringN(sourcename) - - local e, rc, re, src, git_dir, work_tree, id - - src = source.sources[sourcename] - e = err.new("fetching source failed: %s", sourcename) + e = err.new("fetching source failed: %s", self._name) - if src:working_copy_available() then + if self:working_copy_available() then return true end - work_tree = e2lib.join(e2tool.root(), src:get_working()) + work_tree = e2lib.join(e2tool.root(), self:get_working()) git_dir = e2lib.join(work_tree, ".git") - e2lib.logf(2, "cloning %s:%s [%s]", src:get_server(), src:get_location(), - src:get_branch()) + e2lib.logf(2, "cloning %s:%s [%s]", self:get_server(), self:get_location(), + self:get_branch()) - rc, re = generic_git.git_clone_from_server(cache.cache(), src:get_server(), - src:get_location(), work_tree, false --[[always checkout]]) + rc, re = generic_git.git_clone_from_server(cache.cache(), self:get_server(), + self:get_location(), work_tree, false --[[always checkout]]) if not rc then return false, e:cat(re) end rc, re, id = generic_git.lookup_id(git_dir, false, - "refs/heads/" .. src:get_branch()) + "refs/heads/" .. self:get_branch()) if not rc then return false, e:cat(re) elseif not id then - rc, re = generic_git.git_branch_new1(work_tree, true, src:get_branch(), - "origin/" .. src:get_branch()) + rc, re = generic_git.git_branch_new1(work_tree, true, self:get_branch(), + "origin/" .. self:get_branch()) if not rc then return false, e:cat(re) end rc, re = generic_git.git_checkout1(work_tree, - "refs/heads/" .. src:get_branch()) + "refs/heads/" .. self:get_branch()) if not rc then return false, e:cat(re) end @@ -372,9 +362,76 @@ function gitrepo.fetch_source(info, sourcename) return true end ---- prepare a git source --- @param info the info structure --- @param sourcename string +--- update a working copy +-- @return bool +-- @return an error object +function gitrepo_source:update_source() + local e, rc, re, gitwc, gitdir, argv, id, branch, remote + + e = err.new("updating source '%s' failed", self._name) + + rc, re = scm.generic_source_check(e2tool.info(), self._name, true) + if not rc then + return false, e:cat(re) + end + + e2lib.logf(2, "updating %s [%s]", self:get_working(), self:get_branch()) + + gitwc = e2lib.join(e2tool.root(), self:get_working()) + gitdir = e2lib.join(gitwc, ".git") + + argv = generic_git.git_new_argv(gitdir, gitwc, "fetch") + rc, re = generic_git.git(argv) + if not rc then + return false, e:cat(re) + end + + argv = generic_git.git_new_argv(gitdir, gitwc, "fetch", "--tags") + rc, re = generic_git.git(argv) + if not rc then + return false, e:cat(re) + end + + -- Use HEAD commit ID to find the branch we're on + rc, re, id = generic_git.lookup_id(gitdir, false, "HEAD") + if not rc then + return false, e:cat(re) + elseif not id then + return false, e:cat(err.new("can not find commit ID for HEAD")) + end + + rc, re, branch = generic_git.lookup_ref(gitdir, false, id, "refs/heads/") + if not rc then + return false, e:cat(re) + elseif not branch then + e2lib.warnf("WOTHER", "HEAD is not on a branch (detached?). Skipping") + return true + end + + if branch ~= "refs/heads/" .. self:get_branch() then + e2lib.warnf("WOTHER", "not on configured branch. Skipping.") + return true + end + + remote, re = generic_git.git_config( + gitdir, "branch."..self:get_branch()..".remote") + if not remote or string.len(remote) == 0 then + e2lib.warnf("WOTHER", "no remote configured for branch %q. Skipping.", + self:get_branch()) + return true + end + + branch = remote .. "/" .. self:get_branch() + argv = generic_git.git_new_argv(gitdir, gitwc, "merge", "--ff-only", branch) + rc, re = generic_git.git(argv) + if not rc then + return false, e:cat(re) + end + + return true +end + +--- prepare source for building. -- @param sourceset can be either: -- "tag": the git repository will be checked out to the tag -- "branch": the git repository will be checked out to the branch @@ -382,31 +439,28 @@ end -- @param buildpath the path where the source will be created -- @return True on success, false on failure. -- @return Error object on failure. -function gitrepo.prepare_source(info, sourcename, sourceset, buildpath) - assertIsTable(info) - assertIsStringN(sourcename) +function gitrepo_source:prepare_source(sourceset, buildpath) assertIsStringN(sourceset) assertIsStringN(buildpath) local rc, re, e - local src, argv, destdir, worktree, ref + local argv, destdir, worktree, ref - e = err.new("preparing source failed: %s", sourcename) - src = source.sources[sourcename] + e = err.new("preparing source failed: %s", self._name) - rc, re = scm.generic_source_check(info, sourcename, true) + rc, re = scm.generic_source_check(e2tool.info(), self._name, true) if not rc then return false, e:cat(re) end if sourceset == "tag" or sourceset == "branch" then - destdir = e2lib.join(buildpath, sourcename, ".git") + destdir = e2lib.join(buildpath, self._name, ".git") rc, re = e2lib.mkdir_recursive(destdir) if not rc then return false, e:cat(re) end - worktree = e2lib.join(e2tool.root(), src:get_working()) + worktree = e2lib.join(e2tool.root(), self:get_working()) argv = generic_git.git_new_argv(false, false, "clone", "--mirror", worktree, destdir) rc, re = generic_git.git(argv) @@ -420,9 +474,9 @@ function gitrepo.prepare_source(info, sourcename, sourceset, buildpath) end if sourceset == "tag" then - ref = string.format("refs/tags/%s", src:get_tag()) + ref = string.format("refs/tags/%s", self:get_tag()) else - ref = string.format("refs/heads/%s", src:get_branch()) + ref = string.format("refs/heads/%s", self:get_branch()) end rc, re = generic_git.git_checkout1(e2lib.join(destdir, ".."), ref) @@ -432,8 +486,8 @@ function gitrepo.prepare_source(info, sourcename, sourceset, buildpath) elseif sourceset == "working-copy" then local argv = { "-a", - e2lib.join(e2tool.root(), src:get_working(), ""), - e2lib.join(buildpath, sourcename), + e2lib.join(e2tool.root(), self:get_working(), ""), + e2lib.join(buildpath, self._name), } rc, re = e2lib.rsync(argv) if not rc then @@ -441,83 +495,13 @@ function gitrepo.prepare_source(info, sourcename, sourceset, buildpath) end else return false, err.new("preparing source failed, not a valid type: %s, %s", - sourcename, sourceset) + self._name, sourceset) end return true end ---- update a working copy. from git plugin --- @param info the info structure --- @param sourcename string --- @return bool --- @return an error object -function gitrepo.update(info, sourcename) - local e, rc, re, src, gitwc, gitdir, argv, id, branch, remote - - src = source.sources[sourcename] - e = err.new("updating source '%s' failed", sourcename) - - rc, re = scm.generic_source_check(info, sourcename, true) - if not rc then - return false, e:cat(re) - end - - e2lib.logf(2, "updating %s [%s]", src:get_working(), src:get_branch()) - - gitwc = e2lib.join(e2tool.root(), src:get_working()) - gitdir = e2lib.join(gitwc, ".git") - - argv = generic_git.git_new_argv(gitdir, gitwc, "fetch") - rc, re = generic_git.git(argv) - if not rc then - return false, e:cat(re) - end - - argv = generic_git.git_new_argv(gitdir, gitwc, "fetch", "--tags") - rc, re = generic_git.git(argv) - if not rc then - return false, e:cat(re) - end - - -- Use HEAD commit ID to find the branch we're on - rc, re, id = generic_git.lookup_id(gitdir, false, "HEAD") - if not rc then - return false, e:cat(re) - elseif not id then - return false, e:cat(err.new("can not find commit ID for HEAD")) - end - - rc, re, branch = generic_git.lookup_ref(gitdir, false, id, "refs/heads/") - if not rc then - return false, e:cat(re) - elseif not branch then - e2lib.warnf("WOTHER", "HEAD is not on a branch (detached?). Skipping") - return true - end - - if branch ~= "refs/heads/" .. src:get_branch() then - e2lib.warnf("WOTHER", "not on configured branch. Skipping.") - return true - end - - remote, re = generic_git.git_config( - gitdir, "branch."..src:get_branch()..".remote") - if not remote or string.len(remote) == 0 then - e2lib.warnf("WOTHER", "no remote configured for branch %q. Skipping.", - src:get_branch()) - return true - end - - branch = remote .. "/" .. src:get_branch() - argv = generic_git.git_new_argv(gitdir, gitwc, "merge", "--ff-only", branch) - rc, re = generic_git.git(argv) - if not rc then - return false, e:cat(re) - end - - return true -end +-------------------------------------------------------------------------------- --- Archives the source and prepares the necessary files outside the archive -- @param info the info structure @@ -672,6 +656,6 @@ plugin_descriptor = { -------------------------------------------------------------------------------- -return gitrepo +return strict.lock(gitrepo) -- vim:sw=4:sts=4:et: diff --git a/plugins/svn.lua b/plugins/svn.lua index 550073c..2bd753b 100644 --- a/plugins/svn.lua +++ b/plugins/svn.lua @@ -397,15 +397,10 @@ function svn.svn_source:check_workingcopy() return true end --------------------------------------------------------------------------------- - -function svn.fetch_source(info, sourcename) +function svn.svn_source:fetch_source() local rc, re - local e = err.new("fetching source failed: %s", sourcename) - local src = source.sources[sourcename] - local location = src:get_location() - local server = src:get_server() - local surl, re = cache.remote_url(cache.cache(), server, location) + local e = err.new("fetching source failed: %s", self._name) + local surl, re = cache.remote_url(cache.cache(), self._server, self._location) if not surl then return false, e:cat(re) end @@ -414,11 +409,11 @@ function svn.fetch_source(info, sourcename) return false, e:cat(re) end - if src:working_copy_available() then + if self:working_copy_available() then return true end - local argv = { "checkout", svnurl, e2tool.root() .. "/" .. src:get_working() } + local argv = { "checkout", svnurl, e2tool.root() .. "/" .. self:get_working() } rc, re = svn_tool(argv) if not rc then @@ -427,13 +422,21 @@ function svn.fetch_source(info, sourcename) return true end -function svn.prepare_source(info, sourcename, sourceset, build_path) +function svn.svn_source:update_source() local rc, re - local e = err.new("svn.prepare_source failed") - local src = source.sources[sourcename] - local location = src:get_location() - local server = src:get_server() - local surl, re = cache.remote_url(cache.cache(), server, location) + local e = err.new("updating source '%s' failed", self._name) + local workdir = e2lib.join(e2tool.root(), self:get_working()) + rc, re = svn_tool({ "update" }, workdir) + if not rc then + return false, e:cat(re) + end + return true +end + +function svn.svn_source:prepare_source(sourceset, buildpath) + local rc, re + local e = err.new("preparing source for build failed: %s", self._name) + local surl, re = cache.remote_url(cache.cache(), self._server, self._location) if not surl then return false, e:cat(re) end @@ -444,21 +447,20 @@ function svn.prepare_source(info, sourcename, sourceset, build_path) if sourceset == "tag" or sourceset == "branch" then local rev if sourceset == "tag" then - rev = src:get_tag() + rev = self._tag else -- sourceset == "branch" - rev = src:get_branch() + rev = self._branch end local argv = { "export", svnurl .. "/" .. rev, - build_path .. "/" .. sourcename } + buildpath .. "/" .. self._name } rc, re = svn_tool(argv) if not rc then return false, e:cat(re) end elseif sourceset == "working-copy" then - -- cp -R e2tool.root()/src.working/src.workingcopy_subdir build_path - local s = e2lib.join(e2tool.root(), src:get_working(), - src:get_workingcopy_subdir()) - local d = e2lib.join(build_path, src:get_name()) + local s = e2lib.join(e2tool.root(), self:get_working(), + self:get_workingcopy_subdir()) + local d = e2lib.join(buildpath, self._name) rc, re = e2lib.cp(s, d, true) if not rc then return false, e:cat(re) @@ -466,9 +468,11 @@ function svn.prepare_source(info, sourcename, sourceset, build_path) else return false, e:cat("invalid source set") end - return true, nil + return true end +-------------------------------------------------------------------------------- + function svn.toresult(info, sourcename, sourceset, directory) -- /source/.tar.gz -- /makefile @@ -501,7 +505,7 @@ function svn.toresult(info, sourcename, sourceset, directory) return false, e:cat(re) end - rc, re = svn.prepare_source(info, sourcename, sourceset, tmpdir) + rc, re = src:prepare_source(sourceset, tmpdir) if not rc then return false, e:cat(re) end @@ -529,18 +533,6 @@ function svn.toresult(info, sourcename, sourceset, directory) return true, nil end -function svn.update(info, sourcename) - local rc, re - local e = err.new("updating source '%s' failed", sourcename) - local src = source.sources[sourcename] - local workdir = e2lib.join(e2tool.root(), src:get_working()) - rc, re = svn_tool({ "update" }, workdir) - if not rc then - return false, e:cat(re) - end - return true -end - strict.lock(svn) -- vim:sw=4:sts=4:et: