Convert mtime from a time_t to a struct timespec.
[Samba.git] / buildtools / wafsamba / samba_dist.py
bloba11a37cc1bf7595bddc531587aeebc38b3bd6cf9
1 # customised version of 'waf dist' for Samba tools
2 # uses git ls-files to get file lists
4 import Utils, os, sys, tarfile, stat, Scripting, Logs, Options
5 from samba_utils import *
7 dist_dirs = None
8 dist_blacklist = ""
10 def add_symlink(tar, fname, abspath, basedir):
11 '''handle symlinks to directories that may move during packaging'''
12 if not os.path.islink(abspath):
13 return False
14 tinfo = tar.gettarinfo(name=abspath, arcname=fname)
15 tgt = os.readlink(abspath)
17 if dist_dirs:
18 # we need to find the target relative to the main directory
19 # this is here to cope with symlinks into the buildtools
20 # directory from within the standalone libraries in Samba. For example,
21 # a symlink to ../../builtools/scripts/autogen-waf.sh needs
22 # to be rewritten as a symlink to buildtools/scripts/autogen-waf.sh
23 # when the tarball for talloc is built
25 # the filename without the appname-version
26 rel_fname = '/'.join(fname.split('/')[1:])
28 # join this with the symlink target
29 tgt_full = os.path.join(os.path.dirname(rel_fname), tgt)
31 # join with the base directory
32 tgt_base = os.path.normpath(os.path.join(basedir, tgt_full))
34 # see if this is inside one of our dist_dirs
35 for dir in dist_dirs.split():
36 if dir.find(':') != -1:
37 destdir=dir.split(':')[1]
38 dir=dir.split(':')[0]
39 else:
40 destdir = '.'
41 if dir == basedir:
42 # internal links don't get rewritten
43 continue
44 if dir == tgt_base[0:len(dir)] and tgt_base[len(dir)] == '/':
45 new_tgt = destdir + tgt_base[len(dir):]
46 tinfo.linkname = new_tgt
47 break
49 tinfo.uid = 0
50 tinfo.gid = 0
51 tinfo.uname = 'root'
52 tinfo.gname = 'root'
53 tar.addfile(tinfo)
54 return True
56 def add_tarfile(tar, fname, abspath, basedir):
57 '''add a file to the tarball'''
58 if add_symlink(tar, fname, abspath, basedir):
59 return
60 try:
61 tinfo = tar.gettarinfo(name=abspath, arcname=fname)
62 except OSError:
63 Logs.error('Unable to find file %s - missing from git checkout?' % abspath)
64 sys.exit(1)
65 tinfo.uid = 0
66 tinfo.gid = 0
67 tinfo.uname = 'root'
68 tinfo.gname = 'root'
69 fh = open(abspath)
70 tar.addfile(tinfo, fileobj=fh)
71 fh.close()
74 def vcs_dir_contents(path):
75 """Return the versioned files under a path.
77 :return: List of paths relative to path
78 """
79 repo = path
80 while repo != "/":
81 if os.path.isdir(os.path.join(repo, ".git")):
82 ls_files_cmd = [ 'git', 'ls-files', '--full-name',
83 os_path_relpath(path, repo) ]
84 cwd = None
85 env = dict(os.environ)
86 env["GIT_DIR"] = os.path.join(repo, ".git")
87 break
88 elif os.path.isdir(os.path.join(repo, ".bzr")):
89 ls_files_cmd = [ 'bzr', 'ls', '--recursive', '--versioned',
90 os_path_relpath(path, repo)]
91 cwd = repo
92 env = None
93 break
94 repo = os.path.dirname(repo)
95 if repo == "/":
96 raise Exception("unsupported or no vcs for %s" % path)
97 return Utils.cmd_output(ls_files_cmd, cwd=cwd, env=env).split()
100 def dist(appname='',version=''):
101 if not isinstance(appname, str) or not appname:
102 # this copes with a mismatch in the calling arguments for dist()
103 appname = Utils.g_module.APPNAME
104 version = Utils.g_module.VERSION
105 if not version:
106 version = Utils.g_module.VERSION
108 srcdir = os.path.normpath(os.path.join(os.path.dirname(Utils.g_module.root_path), Utils.g_module.srcdir))
110 if not dist_dirs:
111 Logs.error('You must use samba_dist.DIST_DIRS() to set which directories to package')
112 sys.exit(1)
114 dist_base = '%s-%s' % (appname, version)
116 if Options.options.SIGN_RELEASE:
117 dist_name = '%s.tar' % (dist_base)
118 tar = tarfile.open(dist_name, 'w')
119 else:
120 dist_name = '%s.tar.gz' % (dist_base)
121 tar = tarfile.open(dist_name, 'w:gz')
123 blacklist = dist_blacklist.split()
125 for dir in dist_dirs.split():
126 if dir.find(':') != -1:
127 destdir=dir.split(':')[1]
128 dir=dir.split(':')[0]
129 else:
130 destdir = '.'
131 absdir = os.path.join(srcdir, dir)
132 try:
133 files = vcs_dir_contents(absdir)
134 except Exception, e:
135 Logs.error('unable to get contents of %s: %s' % (absdir, e))
136 sys.exit(1)
137 for f in files:
138 abspath = os.path.join(srcdir, f)
140 if dir != '.':
141 f = f[len(dir)+1:]
143 # Remove files in the blacklist
144 if f in dist_blacklist:
145 continue
146 blacklisted = False
147 # Remove directories in the blacklist
148 for d in blacklist:
149 if f.startswith(d):
150 blacklisted = True
151 if blacklisted:
152 continue
153 if os.path.isdir(abspath):
154 continue
155 if destdir != '.':
156 f = destdir + '/' + f
157 fname = dist_base + '/' + f
158 add_tarfile(tar, fname, abspath, dir)
160 tar.close()
162 if Options.options.SIGN_RELEASE:
163 import gzip
164 try:
165 os.unlink(dist_name + '.asc')
166 except OSError:
167 pass
169 cmd = "gpg --detach-sign --armor " + dist_name
170 os.system(cmd)
171 uncompressed_tar = open(dist_name, 'rb')
172 compressed_tar = gzip.open(dist_name + '.gz', 'wb')
173 while 1:
174 buffer = uncompressed_tar.read(1048576)
175 if buffer:
176 compressed_tar.write(buffer)
177 else:
178 break
179 uncompressed_tar.close()
180 compressed_tar.close()
181 os.unlink(dist_name)
182 Logs.info('Created %s.gz %s.asc' % (dist_name, dist_name))
183 dist_name = dist_name + '.gz'
184 else:
185 Logs.info('Created %s' % dist_name)
187 return dist_name
190 @conf
191 def DIST_DIRS(dirs):
192 '''set the directories to package, relative to top srcdir'''
193 global dist_dirs
194 if not dist_dirs:
195 dist_dirs = dirs
197 @conf
198 def DIST_BLACKLIST(blacklist):
199 '''set the files to exclude from packaging, relative to top srcdir'''
200 global dist_blacklist
201 if not dist_blacklist:
202 dist_blacklist = blacklist
204 Scripting.dist = dist