diff --git a/gbp/deb/copyright.py b/gbp/deb/copyright.py new file mode 100644 index 00000000..1feab92a --- /dev/null +++ b/gbp/deb/copyright.py @@ -0,0 +1,70 @@ +# vim: set fileencoding=utf-8 : +# +# (C) 2018 Shengjing Zhu +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, please see +# +"""A Debian Copyright file""" +import email +import os + + +class NoCopyrightError(Exception): + """No copyright found""" + pass + + +class ParseCopyrightError(Exception): + """Problem parsing copyright""" + pass + + +class Copyright(object): + """ + A Debian copyright + """ + def __init__(self, contents=None, filename="debian/copyright"): + """ + Parse an existing copyright file. + + @param contents: content of a control file + @type contents: C{str} + @param filename: name of the control file + @type filename: C{str} + @return: Copyright object + @rtype: C{gbp.deb.copyright.Copyright} object + """ + if contents: + copyright = email.message_from_string(contents) + else: + if not os.access(filename, os.F_OK): + raise NoCopyrightError("Copyright file %s doesn't exist" % filename) + with open(filename) as f: + copyright = email.message_from_file(f) + + if not copyright.items(): + raise ParseCopyrightError("Empty or invalid copyright file or contents") + + self._copyright = copyright + self.filename = filename + + def files_excluded(self, component=None): + """The file list to be excluded""" + if component: + files = self._copyright['Files-Excluded-' + component] + else: + files = self._copyright['Files-Excluded'] + if files: + return files.split() + else: + return [] diff --git a/gbp/deb/git.py b/gbp/deb/git.py index 7e87eda0..38676859 100644 --- a/gbp/deb/git.py +++ b/gbp/deb/git.py @@ -331,7 +331,7 @@ def create_upstream_tarball_via_pristine_tar(self, source, output_dir, comp, com return True def create_upstream_tarball_via_git_archive(self, source, output_dir, treeish, - comp, with_submodules, component=None): + comp, with_submodules, component=None, excludes=None): """ Create a compressed orig tarball in output_dir using git archive @@ -347,6 +347,8 @@ def create_upstream_tarball_via_git_archive(self, source, output_dir, treeish, @type with_submodules: C{bool} @param component: component to add to tarball name @type component: C{str} + @param excludes: files to be excluded from tarball + @type excludes: C{list} Raises GitRepositoryError in case of an error """ @@ -355,11 +357,18 @@ def create_upstream_tarball_via_git_archive(self, source, output_dir, treeish, source.upstream_tarball_name(comp.type, component=component)) prefix = "%s-%s" % (source.name, source.upstream_version) + old_attributes = self.read_git_dir_attributes() + if excludes: + attributes = '\n'.join([f + ' export-ignore' for f in excludes]) + attributes = attributes + '\n' + old_attributes + self.write_git_dir_attributes(attributes) try: if self.has_submodules() and with_submodules: submodules = True self.update_submodules() self.archive_comp(treeish, output, prefix, comp, submodules=submodules) + if excludes: + self.write_git_dir_attributes(old_attributes) except Exception as e: raise GitRepositoryError("Error creating %s: %s" % (output, e)) return True diff --git a/gbp/deb/source.py b/gbp/deb/source.py index f1e2c569..569afd1f 100644 --- a/gbp/deb/source.py +++ b/gbp/deb/source.py @@ -21,6 +21,7 @@ from gbp.deb.format import DebianSourceFormat from gbp.deb.changelog import ChangeLog from gbp.deb.control import Control +from gbp.deb.copyright import Copyright class FileVfs(object): @@ -57,6 +58,7 @@ def __init__(self, vfs): """ self._changelog = None self._control = None + self._copyright = None if isinstance(vfs, str): self._vfs = FileVfs(vfs) @@ -114,6 +116,19 @@ def control(self): raise DebianSourceError('Failed to read control file: %s' % err) return self._control + @property + def copyright(self): + """ + Return the L{gbp.deb.copyright} + """ + if not self._copyright: + try: + with self._vfs.open('debian/copyright', 'rb') as crf: + self._copyright = Copyright(crf.read().decode('utf-8')) + except IOError as err: + raise DebianSourceError('Failed to read copyright file: %s' % err) + return self._copyright + @property def sourcepkg(self): """ diff --git a/gbp/git/repository.py b/gbp/git/repository.py index 6b29f5c4..bb0dd5e4 100644 --- a/gbp/git/repository.py +++ b/gbp/git/repository.py @@ -2096,3 +2096,32 @@ def clone(cls, path, remote, depth=0, recursive=False, mirror=False, % (remote, abspath, err[1])) return None #} + +#{ Attributes in Git_DIR + def read_git_dir_attributes(self): + """ + Get content of $GIT_DIR/info/attributes + + @return: attributes contents + @rtype: C{str} + """ + path = os.path.join(self.git_dir, 'info/attributes') + if not os.path.exists(path): + return '' + with open(path, 'rb') as f: + contents = f.read().decode('utf-8') + return contents + + def write_git_dir_attributes(self, contents): + """ + Write contents to $GIT_DIR/info/attributes + + @param contents: contents to write + @type contents: C{str} + """ + path = os.path.join(self.git_dir, 'info') + if not os.path.isdir(path): + raise GitRepositoryError("Path %s is not directory" % path) + with open(os.path.join(path, 'attributes'), 'w') as f: + f.write(contents) +#} diff --git a/gbp/scripts/buildpackage.py b/gbp/scripts/buildpackage.py index b055f8d5..a0e9764c 100755 --- a/gbp/scripts/buildpackage.py +++ b/gbp/scripts/buildpackage.py @@ -393,6 +393,9 @@ def build_parser(name, prefix=None): help="Compression level, default is '%(compression-level)s'") orig_group.add_config_file_option("component", action="append", metavar='COMPONENT', dest="components") + orig_group.add_config_file_option(option_name="exclude-with-copyright", action="store_true", + dest="exclude_with_copyright", default=False, + help="exclude files in Files-Excluded field set in debian/copyright") branch_group.add_config_file_option(option_name="upstream-branch", dest="upstream_branch") branch_group.add_config_file_option(option_name="debian-branch", dest="debian_branch") branch_group.add_boolean_config_file_option(option_name="ignore-branch", dest="ignore_branch") diff --git a/gbp/scripts/export_orig.py b/gbp/scripts/export_orig.py index 95b83da5..99068484 100755 --- a/gbp/scripts/export_orig.py +++ b/gbp/scripts/export_orig.py @@ -208,7 +208,12 @@ def git_archive_build_origs(repo, source, output_dir, options): upstream_tree)) gbp.log.debug("Building upstream tarball with compression %s" % comp) tree = repo.tree_drop_dirs(upstream_tree, options.components) if options.components else upstream_tree - repo.create_upstream_tarball_via_git_archive(source, output_dir, tree, comp, options.with_submodules) + + excludes = source.copyright.files_excluded() if options.exclude_with_copyright else [] + gbp.log.debug("Excluding these files from archive: %s" % excludes) + + repo.create_upstream_tarball_via_git_archive(source, output_dir, tree, comp, + options.with_submodules, excludes=excludes) for component in options.components: subtree = repo.tree_get_dir(upstream_tree, component) if not subtree: @@ -217,8 +222,11 @@ def git_archive_build_origs(repo, source, output_dir, options): gbp.log.info("Creating additional tarball '%s' from '%s'" % (source.upstream_tarball_name(options.comp_type, component=component), subtree)) + excludes = source.copyright.files_excluded(component) if options.exclude_with_copyright else [] + gbp.log.debug("Excluding these files from archive: %s" % excludes) repo.create_upstream_tarball_via_git_archive(source, output_dir, subtree, comp, - options.with_submodules, component=component) + options.with_submodules, component=component, + excludes=excludes) def guess_comp_type(comp_type, source, repo, tarball_dir): @@ -298,6 +306,9 @@ def build_parser(name): help="Compression level, default is '%(compression-level)s'") orig_group.add_config_file_option("component", action="append", metavar='COMPONENT', dest="components") + orig_group.add_config_file_option(option_name="exclude-with-copyright", action="store_true", + dest="exclude_with_copyright", default=False, + help="exclude files in Files-Excluded field set in debian/copyright") branch_group.add_config_file_option(option_name="upstream-branch", dest="upstream_branch") branch_group.add_boolean_config_file_option(option_name="submodules", dest="with_submodules") return parser