1 # vim:fileencoding=utf-8:et:ts=4:sw=4:sts=4
3 # Copyright (C) 2013 Intel Corporation <markus.lehtonen@linux.intel.com>
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (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., 51 Franklin Street, Fifth Floor, Boston,
19 """The git-buildpackage source service for OBS"""
25 from ConfigParser import SafeConfigParser
27 from gbp.rpm import guess_spec, NoSpecError
28 from gbp.scripts.buildpackage import main as gbp_deb
29 from gbp.scripts.buildpackage_rpm import main as gbp_rpm
31 from obs_service_gbp import LOGGER, gbplog
32 from obs_service_gbp_utils import GbpServiceError, fork_call, sanitize_uid_gid
33 from obs_service_gbp_utils import write_treeish_meta
34 from gbp_repocache import CachedRepo, CachedRepoError
37 def have_spec(directory):
38 """Find if the package has spec files"""
40 guess_spec(directory, recursive=True)
41 except NoSpecError as err:
42 if str(err).startswith('No spec file'):
46 def construct_gbp_args(args, config, outdir):
47 """Construct args list for git-buildpackage-rpm"""
48 # Args common to deb and rpm
49 argv_common = ['--git-ignore-branch',
51 '--git-export-dir=%s' % outdir,
52 '--git-tmp-dir=%s' % config['gbp-tmp-dir']]
54 argv_common.append('--git-export=%s' % args.revision)
55 if args.verbose == 'yes':
56 argv_common.append('--git-verbose')
58 # Dermine deb and rpm specific args
59 argv_rpm = ['git-buildpackage-rpm'] + argv_common
60 argv_rpm.extend(['--git-builder=osc',
62 '--git-ignore-branch'])
64 argv_rpm.append('--git-spec-vcs-tag=%s' % args.spec_vcs_tag)
66 # We need to build this way (i.e. run outside the sources directory)
67 # because if run with '-b .' dpkg-source will put it's output to different
68 # directory, depending on the version of dpkg
69 deb_builder_script = 'cd ..; dpkg-source -b $GBP_BUILD_DIR'
70 argv_deb = ['git-buildpackage'] + argv_common
71 argv_deb.extend(['--git-purge',
72 '--git-builder=%s' % deb_builder_script])
73 return (argv_rpm, argv_deb)
75 def read_config(filenames):
76 '''Read configuration file(s)'''
77 defaults = {'repo-cache-dir': '/var/cache/obs/git-buildpackage-repos/',
78 'gbp-tmp-dir': '/tmp/obs-service-gbp/',
82 filenames = [os.path.expanduser(fname) for fname in filenames]
83 LOGGER.debug('Trying %s config files: %s', len(filenames), filenames)
84 parser = SafeConfigParser(defaults=defaults)
85 read = parser.read(filenames)
86 LOGGER.debug('Read %s config files: %s', len(read), read)
88 # Add our one-and-only section, if it does not exist
89 if not parser.has_section('general'):
90 parser.add_section('general')
92 # Read overrides from environment
93 for key in defaults.keys():
94 envvar ='OBS_GIT_BUILDPACKAGE_%s' % key.replace('-', '_').upper()
95 if envvar in os.environ:
96 parser.set('general', key, os.environ[envvar])
98 # We only use keys from one section, for now
99 return dict(parser.items('general'))
101 def gbp_export(repo, args, config):
102 """Export sources with GBP"""
103 # Create output directories
105 if not os.path.exists(args.outdir):
106 os.makedirs(args.outdir)
107 tmp_out = tempfile.mkdtemp(dir=args.outdir)
108 except OSError as err:
109 LOGGER.error('Failed to create output directory: %s', err)
113 uid, gid = sanitize_uid_gid(config['gbp-user'], config['gbp-group'])
114 except GbpServiceError as err:
117 # Make temp outdir accessible to the GBP UID/GID
118 os.chown(tmp_out, uid, gid)
121 rpm_args, deb_args = construct_gbp_args(args, config, tmp_out)
122 orig_dir = os.path.abspath(os.curdir)
124 os.chdir(repo.repodir)
125 specs_found = have_spec('.')
126 if args.rpm == 'yes' or (args.rpm == 'auto' and specs_found):
127 LOGGER.info('Exporting RPM packaging files with GBP')
128 LOGGER.debug('git-buildpackage-rpm args: %s', ' '.join(rpm_args))
129 ret = fork_call(uid, gid, gbp_rpm, rpm_args)
131 LOGGER.error('Git-buildpackage-rpm failed, unable to export '
132 'RPM packaging files')
134 if args.deb == 'yes' or (args.deb== 'auto' and os.path.isdir('debian')):
135 LOGGER.info('Exporting Debian source package with GBP')
136 LOGGER.debug('git-buildpackage args: %s', ' '.join(deb_args))
137 ret = fork_call(uid, gid, gbp_deb, deb_args)
139 LOGGER.error('Git-buildpackage failed, unable to export Debian '
140 'sources package files')
142 for fname in os.listdir(tmp_out):
143 shutil.move(os.path.join(tmp_out, fname),
144 os.path.join(args.outdir, fname))
145 except GbpServiceError as err:
146 LOGGER.error('Internal service error when trying to run GBP: %s', err)
147 LOGGER.error('This is most likely a configuration error (or a BUG)!')
151 shutil.rmtree(tmp_out)
154 def parse_args(argv):
155 """Argument parser"""
156 default_configs = ['/etc/obs/services/git-buildpackage',
157 '~/.obs/git-buildpackage']
159 parser = argparse.ArgumentParser()
160 parser.add_argument('--url', help='Remote repository URL', required=True)
161 parser.add_argument('--outdir', default='.', help='Output direcory')
162 parser.add_argument('--revision', help='Remote repository URL',
164 parser.add_argument('--rpm', choices=['auto', 'yes', 'no'], default='auto',
165 help='Export RPM packaging files')
166 parser.add_argument('--deb', choices=['auto', 'yes', 'no'], default='auto',
167 help='Export Debian packaging files')
168 parser.add_argument('--verbose', '-v', help='Verbose output',
169 choices=['yes', 'no'])
170 parser.add_argument('--spec-vcs-tag', help='Set/update the VCS tag in the'
172 parser.add_argument('--config', default=default_configs, action='append',
173 help='Config file to use, can be given multiple times')
174 parser.add_argument('--git-meta', metavar='FILENAME',
175 help='Write data about the exported revision into '
176 'FILENAME in json format')
177 args = parser.parse_args(argv)
178 args.outdir = os.path.abspath(args.outdir)
184 args = parse_args(argv)
186 LOGGER.info('Starting git-buildpackage source service')
187 if args.verbose == 'yes':
188 gbplog.setup(color='auto', verbose=True)
189 LOGGER.setLevel(gbplog.DEBUG)
190 gbp_repocache.LOGGER.setLevel(gbplog.DEBUG)
192 config = read_config(args.config)
194 # Create / update cached repository
196 repo = CachedRepo(config['repo-cache-dir'], args.url)
197 args.revision = repo.update_working_copy(args.revision)
198 except CachedRepoError as err:
199 LOGGER.error('RepoCache: %s', str(err))
203 ret = gbp_export(repo, args, config)
205 # Write git meta file
206 if not ret and args.git_meta:
208 write_treeish_meta(repo.repo, args.revision, args.outdir,
210 except GbpServiceError as err: