chiark / gitweb /
agpl.py: Fix up symbolic links between directories being dumped.
[chopwood] / agpl.py
diff --git a/agpl.py b/agpl.py
index b89330cb56de6e64f66303af0743e7dd184fc819..43eba824d5be38993b17d9cadfd3ff77ec36d6a2 100644 (file)
--- a/agpl.py
+++ b/agpl.py
 ### <http://www.gnu.org/licenses/>.
 
 import contextlib as CTX
+import grp as GR
 import os as OS
+import pwd as PW
 import shlex as SL
 import shutil as SH
 import subprocess as SUB
 import sys as SYS
 import tarfile as TAR
 import tempfile as TF
+import time as T
+
+from cStringIO import StringIO
 
 from auto import PACKAGE, VERSION
 import util as U
@@ -74,9 +79,10 @@ def filez(cmd):
         z = buf.find('\0', i)
         if z < 0: break
         f = buf[i:z]
+        i = z + 1
+        if f == '.': continue
         if f.startswith('./'): f = f[2:]
         yield f
-        i = z + 1
       left = buf[i:]
     if left:
       raise U.ExpectedError, \
@@ -88,16 +94,31 @@ DUMPERS = [
                            filez('find .git -print0')]),
   (lambda d: True, [filez('find . ( ! -perm +004 -prune ) -o -print0')])]
 
-def dump_dir(dir, tf, root):
+def dump_dir(name, dir, dirmap, tf, root):
   for test, listers in DUMPERS:
     if test(dir): break
   else:
     raise U.ExpectedError, (500, "no dumper for `%s'" % dir)
+  tf.add(dir, OS.path.join(root, name), recursive = False)
   for lister in listers:
-    base = OS.path.basename(dir)
     for file in lister(dir):
-      tf.add(OS.path.join(dir, file), OS.path.join(root, base, file),
-             recursive = False)
+      full = OS.path.join(dir, file)
+      tarname = OS.path.join(root, name, file)
+      skip = False
+      if OS.path.islink(full):
+        dest = OS.path.realpath(full)
+        for d, local in dirmap:
+          if dest.startswith(d):
+            fix = OS.path.relpath(OS.path.join('/', local, dest[len(d):]),
+                                  OS.path.join('/', name,
+                                               OS.path.dirname(file)))
+            st = OS.stat(full)
+            ti = tf.gettarinfo(full, tarname)
+            ti.linkname = fix
+            tf.addfile(ti)
+            skip = True
+      if not skip:
+        tf.add(full, tarname, recursive = False)
 
 def source(out):
   if SYS.version_info >= (2, 6):
@@ -105,8 +126,32 @@ def source(out):
   else:
     tf = TAR.open(fileobj = out, mode = 'w|gz')
     tf.posix = True
-  for d in dirs_to_dump():
-    dump_dir(d, tf, '%s-%s' % (PACKAGE, VERSION))
+  root = '%s-%s' % (PACKAGE, VERSION)
+  seen = set()
+  dirmap = []
+  festout = StringIO()
+  for dir in dirs_to_dump():
+    dir = dir.rstrip('/')
+    base = OS.path.basename(dir)
+    if base not in seen:
+      name = base
+    else:
+      for i in I.count():
+        name = '%s.%d' % (base, i)
+        if name not in seen: break
+    dirmap.append((dir + '/', name))
+    festout.write('%s = %s\n' % (name, dir))
+  fest = festout.getvalue()
+  ti = TAR.TarInfo(OS.path.join(root, 'MANIFEST'))
+  ti.size = len(fest)
+  ti.mtime = T.time()
+  ti.mode = 0664
+  ti.type = TAR.REGTYPE
+  uid = OS.getuid(); ti.uid, ti.uname = uid, PW.getpwuid(uid).pw_name
+  gid = OS.getgid(); ti.gid, ti.gname = gid, GR.getgrgid(gid).gr_name
+  tf.addfile(ti, fileobj = StringIO(fest))
+  for dir, name in dirmap:
+    dump_dir(name, dir, dirmap, tf, root)
   tf.close()
 
 ###----- That's all, folks --------------------------------------------------