1 # vim: set fileencoding=utf-8 :
3 # (C) 2006-2011 Guido Guenther <agx@sigxcpu.org>
4 # (C) 2012 Intel Corporation <markus.lehtonen@linux.intel.com>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 """Common functionality for Debian and RPM buildpackage scripts"""
25 import gbp.tmpfile as tempfile
26 from gbp.command_wrappers import (CatenateTarArchive, CatenateZipArchive)
27 from gbp.git.repository import GitRepository, GitRepositoryError
28 from gbp.errors import GbpError
31 # when we want to reference the index in a treeish context we call it:
33 # when we want to reference the working copy in treeish context we call it:
34 wc_names = {'WC': {'force': True, 'untracked': True},
35 'WC.TRACKED': {'force': False, 'untracked': False},
36 'WC.UNTRACKED': {'force': False, 'untracked': True},
37 'WC.IGNORED': {'force': True, 'untracked': True}}
40 def sanitize_prefix(prefix):
42 Sanitize the prefix used for generating source archives
44 >>> sanitize_prefix('')
46 >>> sanitize_prefix('foo/')
48 >>> sanitize_prefix('/foo/bar')
52 return prefix.strip('/') + '/'
56 def compress(cmd, options, output, input_data=None):
58 Filter data through a compressor cmd.
60 For better performance input_data should feed data in bigger chunks.
62 stdin = subprocess.PIPE if input_data else None
64 with open(output, 'w') as fobj:
65 popen = subprocess.Popen([cmd] + options, stdin=stdin, stdout=fobj)
67 for chunk in input_data:
68 popen.stdin.write(chunk)
71 raise GbpError("Error creating %s: running '%s' failed" %
72 (output, ' '.join([cmd] + options)))
73 except (OSError, IOError) as err:
74 raise GbpError("Error creating %s: %s" % (output, err))
76 def git_archive_submodules(repo, treeish, output, tmpdir_base, prefix,
77 comp_type, comp_level, comp_opts, format='tar'):
79 Create a source tree archive with submodules.
81 Since git-archive always writes an end of tarfile trailer we concatenate
82 the generated archives using tar and compress the result.
84 Exception handling is left to the caller.
86 prefix = sanitize_prefix(prefix)
87 tempdir = tempfile.mkdtemp(dir=tmpdir_base, prefix='git-archive_')
88 main_archive = os.path.join(tempdir, "main.%s" % format)
89 submodule_archive = os.path.join(tempdir, "submodule.%s" % format)
91 # generate main (tmp) archive
92 repo.archive(format=format, prefix=prefix,
93 output=main_archive, treeish=treeish)
95 # generate each submodule's arhive and append it to the main archive
96 for (subdir, commit) in repo.get_submodules(treeish):
97 tarpath = [subdir, subdir[2:]][subdir.startswith("./")]
98 subrepo = GitRepository(os.path.join(repo.path, subdir))
100 gbp.log.debug("Processing submodule %s (%s)" % (subdir, commit[0:8]))
101 subrepo.archive(format=format, prefix='%s%s/' % (prefix, tarpath),
102 output=submodule_archive, treeish=commit)
104 CatenateTarArchive(main_archive)(submodule_archive)
105 elif format == 'zip':
106 CatenateZipArchive(main_archive)(submodule_archive)
108 # compress the output
110 compress(comp_type, ['--stdout', '-%s' % comp_level] + comp_opts +
111 [main_archive], output)
113 shutil.move(main_archive, output)
115 shutil.rmtree(tempdir)
118 def git_archive_single(repo, treeish, output, prefix, comp_type, comp_level,
119 comp_opts, format='tar'):
121 Create an archive without submodules
123 Exception handling is left to the caller.
125 prefix = sanitize_prefix(prefix)
128 opts = ['--stdout', '-%s' % comp_level] + comp_opts
132 input_data = repo.archive(format, prefix, None, treeish)
133 compress(cmd, opts, output, input_data)
135 def untar_data(outdir, data):
136 """Extract tar provided as an iterable"""
137 popen = subprocess.Popen(['tar', '-C', outdir, '-x'],
138 stdin=subprocess.PIPE)
140 popen.stdin.write(chunk)
143 raise GbpError("Error extracting tar to %s" % outdir)
145 #{ Functions to handle export-dir
146 def dump_tree(repo, export_dir, treeish, with_submodules, recursive=True):
147 """Dump a git tree-ish to output_dir"""
148 if not os.path.exists(export_dir):
149 os.makedirs(export_dir)
153 paths = ["'%s'" % nam.decode() for _mod, typ, _sha, nam in
154 repo.list_tree(treeish) if typ == 'blob']
157 data = repo.archive('tar', '', None, treeish, paths)
158 untar_data(export_dir, data)
159 if recursive and with_submodules and repo.has_submodules():
160 repo.update_submodules()
161 for (subdir, commit) in repo.get_submodules(treeish):
162 gbp.log.info("Processing submodule %s (%s)" % (subdir,
164 subrepo = GitRepository(os.path.join(repo.path, subdir))
165 prefix = [subdir, subdir[2:]][subdir.startswith("./")] + '/'
166 data = subrepo.archive('tar', prefix, None, treeish=commit)
167 untar_data(export_dir, data)
168 except GitRepositoryError as err:
169 gbp.log.err("Git error when dumping tree: %s" % err)
175 """Get path of the temporary index file used for exporting working copy"""
176 return os.path.join(repo.git_dir, "gbp_index")
178 def write_wc(repo, force=True, untracked=True):
179 """write out the current working copy as a treeish object"""
181 repo.add_files(repo.path, force=force, untracked=untracked, index_file=wc_index(repo))
182 tree = repo.write_tree(index_file=wc_index(repo))
186 def drop_index(repo):
187 """drop our custom index"""
188 if os.path.exists(wc_index(repo)):
189 os.unlink(wc_index(repo))
191 def clone_index(repo):
192 """Copy the current index file to our custom index file"""
193 indexfn = os.path.join(repo.git_dir, "index")
194 if os.path.exists(indexfn):
195 shutil.copy2(indexfn, wc_index(repo))