summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Maw <richard.maw@gmail.com>2013-11-05 20:11:15 +0000
committerRichard Maw <richard.maw@gmail.com>2013-11-05 20:11:15 +0000
commit13a96bfd7342d01745a8f298d91d2486d0031512 (patch)
tree787bf9a341a0c3847ddcdfb5264a9ae60c4c581b
downloadtar-clone-13a96bfd7342d01745a8f298d91d2486d0031512.tar.bz2
Add prototypes so they don't get lost
-rwxr-xr-xtarjoin.lua171
-rwxr-xr-xtarjoin.sh22
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)