diff options
author | Richard Maw <richard.maw@gmail.com> | 2013-11-05 20:11:15 +0000 |
---|---|---|
committer | Richard Maw <richard.maw@gmail.com> | 2013-11-05 20:11:15 +0000 |
commit | 13a96bfd7342d01745a8f298d91d2486d0031512 (patch) | |
tree | 787bf9a341a0c3847ddcdfb5264a9ae60c4c581b | |
download | tar-clone-13a96bfd7342d01745a8f298d91d2486d0031512.tar.bz2 |
Add prototypes so they don't get lost
-rwxr-xr-x | tarjoin.lua | 171 | ||||
-rwxr-xr-x | tarjoin.sh | 22 |
2 files changed, 193 insertions, 0 deletions
diff --git a/tarjoin.lua b/tarjoin.lua new file mode 100755 index 0000000..82c0c12 --- /dev/null +++ b/tarjoin.lua @@ -0,0 +1,171 @@ +#!/usr/bin/lua +local basedir, repo, localname = ... + +local luxio = require "luxio" +local sio = require "luxio.simple" +local sp = require "luxio.subprocess" +local archive = require "archive" + +local CONFIG_FORMAT = [[ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +[remote "origin"] + url = %s + fetch = +refs/heads/*:refs/remotes/origin/* +[branch "%s"] + remote = origin + merge = refs/heads/%s +]] +local function get_config(fetch_url, HEAD) + return CONFIG_FORMAT:format(fetch_url, HEAD, HEAD) +end + + +local include_whitelist = { + "./objects", + "./description", +} +local function matches_prefix(path, prefix) + local matched = string.sub(path, 1, string.len(prefix)) == prefix + return matched +end +local function whitelisted(path) + for _, prefix in ipairs(include_whitelist) do + if matches_prefix(path, prefix) then + return true + end + end + return false +end + + +local function copy_file(from, write_all, buffer_size) + -- Default buffer size is 4M, but can be changed + buffer_size = buffer_size or 4 * 1024 * 1024 + local fromfile, emsg = sio.open(from, "r") + if not fromfile then + return false, emsg + end + local write_count + repeat + local ok + local bytes, emsg = fromfile:read(buffer_size) + if not bytes then + fromfile:close() + tofile:close() + return false, emsg + end + ok, write_count, emsg = write_all(bytes) + if not ok then + fromfile:close() + return false, emsg + end + until write_count == 0 + return true +end + + +local function add_dir(writer, basedir, path) + local fspath = basedir..'/'..path + for name, dinfo in sio.opendir(fspath):iterate() do + local fssubpath = fspath..'/'..name + local subpath = path..'/'..name + --io.stderr:write("name:\t", subpath, '\n') + if name ~= '.' and name ~= '..' and whitelisted(subpath) then + dt = dinfo.d_type + dts = (dt == luxio.DT_REG and "Regular") + or (dt == luxio.DT_DIR and "Directory") + or (dt == luxio.DT_LNK and "Symlink") + --io.stderr:write("d_type:\t", dts, '\n') + local entry = archive.entry{ + sourcepath = fssubpath, + pathname = localname..'/.git/'..subpath, + ino = 0, + dev = 0, + uid = 0, + uname = 'root', + gid = 0, + gname = 'root', + atime = {683074800, 683074800}, + ctime = {683074800, 683074800}, + mtime = {683074800, 683074800}, + birthtime = {683074800, 683074800}, + } + if dt == luxio.DT_REG then + writer:header(entry) + copy_file(fssubpath, function(bytes) + writer:data(bytes) + end) + elseif dt == luxio.DT_DIR then + writer:header(entry) + add_dir(writer, basedir, subpath) + elseif dt == luxio.DT_LNK then + writer:header(entry) + end + end + end +end + +local function write_file(writer, path, data) + writer:header(archive.entry{ + pathname = path, + mode = tonumber('100664', 8), + ino = 0, + dev = 0, + uid = 0, + uname = 'root', + gid = 0, + gname = 'root', + atime = {683074800, 683074800}, + ctime = {683074800, 683074800}, + mtime = {683074800, 683074800}, + birthtime = {683074800, 683074800}, + size = #data + }) + writer:data(data) +end + +local function run_git(dir, ...) + proc = sp.spawn_simple{cwd=dir, stdout=sp.PIPE, ...} + output = proc.stdout:read("*a") + how, why = proc:wait() + if how == -1 then + error("run_git failed: "..tostring(why)) + end + return output +end + +local writer = archive.write{ + format = "pax", + writer = function(archive, string) + if string == nil then + -- pass + else + io.stdout:write(string) + return #string + end + end, +} +add_dir(writer, basedir, repo) + +HEAD = run_git(basedir..'/'..repo, "git", "rev-parse", + "--abbrev-ref", "HEAD"):sub(1, -2) +write_file(writer, localname..'/.git/HEAD', + 'ref: refs/heads/'..HEAD..'\n') +config = get_config('git://git@gitserver/repo', HEAD) +write_file(writer, localname..'/.git/config', config) + +for branch, sha1 in run_git(basedir..'/'..repo, 'git', 'for-each-ref', + '--format', '%(refname)%00%(objectname)%00', + 'refs/heads') + :gmatch"refs/heads/([^%z]+)%z([^%z]+)%z\n" do + write_file(writer, localname..'/.git/refs/remotes/origin/'..branch, + sha1..'\n') + if branch == HEAD then + write_file(writer, localname..'/.git/refs/heads/'..branch, + sha1..'\n') + end +end diff --git a/tarjoin.sh b/tarjoin.sh new file mode 100755 index 0000000..481feef --- /dev/null +++ b/tarjoin.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# CPIO passed through env, so busybox CPIO can be used +CPIO=${CPIO-cpio} +REPO=$(readlink -f "${1-foo.bar.baz}") +APPEND=$(readlink -f "${2-append}") +OUTDIR="${3-baz}" +export TMPDIR=`pwd`/tmp +tmp=`mktemp -d` +trap 'rm -rf "$tmp"' INT TERM EXIT + +cd "$tmp" +{ + mkdir -p "$OUTDIR/.git" >&2 + find "$OUTDIR" + rmdir "$OUTDIR/.git" >&2 + ln -sf "$REPO" "$OUTDIR/.git" >&2 + find "$OUTDIR/.git/qux" + rm "$OUTDIR/.git" + ln -sf "$APPEND" "$OUTDIR/.git" >&2 + find "$OUTDIR/.git/zip" +} | ($CPIO -oHnewc) |