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