Merge pull request #30 from dmnks/bz1349433
[yum-utils.git] / yum-builddep.py
1 #!/usr/bin/python -tt
2
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
17 import sys
18 sys.path.insert(0,'/usr/share/yum-cli')
19
20 import yum
21 from yum.misc import setup_locale
22 from yum.i18n import exception2msg
23 import yum.Errors
24 from utils import YumUtilBase
25
26 import logging
27 import rpmUtils
28 import rpm
29
30 rhn_source_repos = False
31
32 # Copied from yumdownloader (need a yum-utils python module ;)
33 # This is to fix Bug 469
34 # To convert from a pkg to a source pkg, we have a problem in that all we have
35 # is "sourcerpm", which can be a different nevra ... but just to make it fun
36 # the epoch isn't in the name. So we use rpmUtils.miscutils.splitFilename
37 # and ignore the arch/epoch ... and hope we get the right thing.
38 # Eg. run:
39 # for pkg in yb.pkgSack.returnPackages():
40 #     if pkg.version not in pkg.sourcerpm:
41 #         print pkg, pkg.sourcerpm
42 def _best_convert_pkg2srcpkgs(self, opts, pkg):
43     if pkg.arch == 'src':
44         return [pkg]
45
46     (n,v,r,e,a) = rpmUtils.miscutils.splitFilename(pkg.sourcerpm)
47     src = self.pkgSack.searchNevra(name=n, ver=v, rel=r, arch='src')
48     if src == []:
49         self.logger.error('No source RPM found for %s' % str(pkg))
50
51     return src
52
53
54 class YumBuildDep(YumUtilBase):
55     NAME = 'yum-builddep'
56     VERSION = '1.0'
57     USAGE = 'yum-builddep [options] package1 [package2] [package..]'
58     
59     def __init__(self):
60         YumUtilBase.__init__(self,
61                              YumBuildDep.NAME,
62                              YumBuildDep.VERSION,
63                              YumBuildDep.USAGE)
64         self.logger = logging.getLogger("yum.verbose.cli.yumbuildep")                             
65         # Add util commandline options to the yum-cli ones
66         self.optparser = self.getOptionParser() 
67         if hasattr(rpm, 'reloadConfig'):
68             self.optparser.add_option("--target",
69                               help="set target architecture for spec parsing")
70             self.optparser.add_option(
71                 "--define",
72                 action="append",
73                 default=[],
74                 metavar="'MACRO EXPR'",
75                 help="define the rpm MACRO with value EXPR for spec parsing",
76             )
77         self.main()
78
79     def main(self):
80         # Parse the commandline option and setup the basics.
81         try:
82             opts = self.doUtilConfigSetup()
83         except yum.Errors.RepoError, e:
84             self.logger.error("Cannot handle specific enablerepo/disablerepo options.")
85             sys.exit(50)
86
87         # turn of our local gpg checking for opening the srpm if it is turned
88         # off for repos :)
89         if (opts.nogpgcheck or
90             not self.conf.localpkg_gpgcheck or not self.conf.gpgcheck):
91             self.ts.pushVSFlags((rpm._RPMVSF_NOSIGNATURES|rpm._RPMVSF_NODIGESTS))
92
93         # Check if there is anything to do.
94         if len(self.cmds) < 1: 
95             print self.optparser.format_help()
96             sys.exit(0)
97
98         if self.conf.uid != 0:
99             self.logger.error("Error: You must be root to install packages")
100             sys.exit(1)
101
102         if not all(cmd.endswith('.spec') or cmd.endswith('.src.rpm') for cmd in self.cmds):
103             # Use source rpms
104             self.arch.archlist.append('src')
105             self.setupSourceRepos()
106
107         # Setup yum (Ts, RPM db, Repo & Sack)
108         self.doUtilYumSetup()
109         # Do the real action
110         # solve for each srpm and put the pkgs into a ts
111         try:
112             self.get_build_deps(opts)
113         except yum.Errors.MiscError, e:
114             msg = "There was a problem getting the build deps, exiting:\n   %s" % e
115             self.logger.error(msg)
116             sys.exit(1)
117
118         if hasattr(self, 'doUtilBuildTransaction'):
119             errc = self.doUtilBuildTransaction()
120             if errc:
121                 sys.exit(errc)
122         else:
123             try:
124                 self.buildTransaction()
125             except yum.Errors.YumBaseError, e:
126                 self.logger.critical("Error building transaction: %s" % e)
127                 sys.exit(1)
128
129         if len(self.tsInfo) < 1:
130             print 'No uninstalled build requires'
131             sys.exit()
132             
133         sys.exit(self.doUtilTransaction())
134         
135     def setupSourceRepos(self):
136         # enable the -source repos for enabled primary repos
137         for repo in self.repos.listEnabled():
138             issource_repo = repo.id.endswith('-source')
139             if rhn_source_repos and repo.id.endswith('-source-rpms'):
140                 issource_repo = True
141             if rhn_source_repos and (not repo.id.endswith('-source-rpms') and
142                                      repo.id.endswith('-rpms')):
143                 srcrepo = '%s-source,%s-source-rpms' % (repo.id, repo.id[:-5])
144             elif not issource_repo:
145                 srcrepo = '%s-source' % repo.id
146             else:
147                 continue
148             
149             for r in self.repos.findRepos(srcrepo):
150                 if r in self.repos.listEnabled():
151                     continue
152                 self.logger.info('Enabling %s repository' % r.id)
153                 r.enable()
154
155     def install_deps(self, deplist, opts):
156         errors = set()
157         for dep in deplist:
158             self.logger.debug(' REQ:  %s' % dep)                
159             if dep.startswith("rpmlib("): 
160                 continue
161             instreq = self.returnInstalledPackagesByDep(dep)
162             if instreq:
163                 self.logger.info(' --> Already installed : %s'  % instreq[0])                    
164                 continue
165             try:
166                 pkg = self.returnPackageByDep(dep)
167                 self.logger.info(' --> %s' % pkg)
168                 self.install(pkg)
169             except yum.Errors.YumBaseError, e:
170                 errors.add(exception2msg(e))
171
172         if errors:
173             for i in sorted(errors):
174                 self.logger.error("Error: %s" % i)
175             if not opts.tolerant:
176                 sys.exit(1)
177
178     # go through each of the pkgs, figure out what they are/where they are 
179     # if they are not a local package then run
180         # Setup source repos
181         #self.setupSourceRepos()
182     # get all of their deps
183     # throw them into a ts
184     # run the ts
185     
186     def get_build_deps(self,opts):
187         srcnames = []
188         specnames = []
189         srpms = []
190         specworks = False
191         reloadworks = False
192
193         # See if we can use spec files for buildrequires
194         if hasattr(rpm, 'spec') and hasattr(rpm.spec, 'sourceHeader'):
195             specworks = True
196         # See if we can reload rpm configuration
197         if hasattr(rpm, 'reloadConfig'):
198             reloadworks = True
199
200         for arg in self.cmds:
201             if arg.endswith('.src.rpm'):
202                 try:
203                     srpms.append(yum.packages.YumLocalPackage(self.ts, arg))
204                 except yum.Errors.MiscError, e:
205                     self.logger.error("Error: Could not open %s .\nTry" 
206                     " running yum-builddep with the --nogpgcheck option." % arg)
207                     raise
208             elif arg.endswith('.src'):
209                 srcnames.append(arg)
210             elif specworks and arg.endswith('.spec'):
211                 specnames.append(arg)
212             else:
213                 srcnames.append(arg)
214
215         toActOn = []     
216         if srcnames:
217             pkgs = self.pkgSack.returnPackages(patterns=srcnames)
218             exact, match, unmatch = yum.packages.parsePackages(pkgs, srcnames, casematch=1)
219             srpms += exact + match
220             
221             if len(unmatch):
222                 pkgs = self.rpmdb.returnPackages(patterns=unmatch)
223                 exact, match, unmatch = yum.packages.parsePackages(pkgs, unmatch, casematch=1)
224                 if len(unmatch):
225                     self.logger.error("No such package(s): %s" %
226                                       ", ".join(unmatch))
227                     sys.exit(1)
228                     
229         toActOn = []
230         # Get the best matching srpms
231         for newpkg in srpms:
232             srcpkg = _best_convert_pkg2srcpkgs(self, opts, newpkg)
233             toActOn.extend(self.bestPackagesFromList(srcpkg, 'src'))
234
235         for srpm in toActOn:
236             self.logger.info('Getting requirements for %s' % srpm)
237             self.install_deps(srpm.requiresList(), opts)
238     
239         # Parse macro defines
240         macros = []
241         error = False
242         for define in opts.define:
243             words = define.split(None, 1)
244             if len(words) == 1:
245                 self.logger.error('Error: No EXPR given for MACRO %%%s'
246                                   % words[0])
247                 error = True
248                 continue
249             macros.append(words)
250         if error:
251             sys.exit(1)
252
253         for name in specnames:
254             # (re)load rpm config for target if set
255             if reloadworks and opts.target:
256                 rpm.reloadConfig(opts.target)
257
258             for macro in macros:
259                 rpm.addMacro(*macro)
260
261             try:
262                 spec = rpm.spec(name)
263             except ValueError:
264                 self.logger.error("Bad spec: %s" % name)
265                 continue
266
267             # reset default rpm config after each parse to avoid side-effects
268             if reloadworks:
269                 rpm.reloadConfig()
270
271             buildreqs = []
272             for d in rpm.ds(spec.sourceHeader, 'requires'):
273                 buildreqs.append(d.DNEVR()[2:])
274                 
275             self.logger.info('Getting requirements for %s' % name)
276             self.install_deps(buildreqs, opts)
277             
278 if __name__ == '__main__':
279     setup_locale()
280     util = YumBuildDep()
281         
282