Merge pull request #19 from dmnks/bz1403015
[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.main()
71
72     def main(self):
73         # Parse the commandline option and setup the basics.
74         try:
75             opts = self.doUtilConfigSetup()
76         except yum.Errors.RepoError, e:
77             self.logger.error("Cannot handle specific enablerepo/disablerepo options.")
78             sys.exit(50)
79
80         # turn of our local gpg checking for opening the srpm if it is turned
81         # off for repos :)
82         if (opts.nogpgcheck or
83             not self.conf.localpkg_gpgcheck or not self.conf.gpgcheck):
84             self.ts.pushVSFlags((rpm._RPMVSF_NOSIGNATURES|rpm._RPMVSF_NODIGESTS))
85
86         # Check if there is anything to do.
87         if len(self.cmds) < 1: 
88             print self.optparser.format_help()
89             sys.exit(0)
90
91         if self.conf.uid != 0:
92             self.logger.error("Error: You must be root to install packages")
93             sys.exit(1)
94
95         if not all(cmd.endswith('.spec') or cmd.endswith('.src.rpm') for cmd in self.cmds):
96             # Use source rpms
97             self.arch.archlist.append('src')
98             self.setupSourceRepos()
99
100         # Setup yum (Ts, RPM db, Repo & Sack)
101         self.doUtilYumSetup()
102         # Do the real action
103         # solve for each srpm and put the pkgs into a ts
104         try:
105             self.get_build_deps(opts)
106         except yum.Errors.MiscError, e:
107             msg = "There was a problem getting the build deps, exiting:\n   %s" % e
108             self.logger.error(msg)
109             sys.exit(1)
110
111         if hasattr(self, 'doUtilBuildTransaction'):
112             errc = self.doUtilBuildTransaction()
113             if errc:
114                 sys.exit(errc)
115         else:
116             try:
117                 self.buildTransaction()
118             except yum.Errors.YumBaseError, e:
119                 self.logger.critical("Error building transaction: %s" % e)
120                 sys.exit(1)
121
122         if len(self.tsInfo) < 1:
123             print 'No uninstalled build requires'
124             sys.exit()
125             
126         sys.exit(self.doUtilTransaction())
127         
128     def setupSourceRepos(self):
129         # enable the -source repos for enabled primary repos
130         for repo in self.repos.listEnabled():
131             issource_repo = repo.id.endswith('-source')
132             if rhn_source_repos and repo.id.endswith('-source-rpms'):
133                 issource_repo = True
134             if rhn_source_repos and (not repo.id.endswith('-source-rpms') and
135                                      repo.id.endswith('-rpms')):
136                 srcrepo = '%s-source,%s-source-rpms' % (repo.id, repo.id[:-5])
137             elif not issource_repo:
138                 srcrepo = '%s-source' % repo.id
139             else:
140                 continue
141             
142             for r in self.repos.findRepos(srcrepo):
143                 if r in self.repos.listEnabled():
144                     continue
145                 self.logger.info('Enabling %s repository' % r.id)
146                 r.enable()
147
148     def install_deps(self, deplist, opts):
149         errors = set()
150         for dep in deplist:
151             self.logger.debug(' REQ:  %s' % dep)                
152             if dep.startswith("rpmlib("): 
153                 continue
154             instreq = self.returnInstalledPackagesByDep(dep)
155             if instreq:
156                 self.logger.info(' --> Already installed : %s'  % instreq[0])                    
157                 continue
158             try:
159                 pkg = self.returnPackageByDep(dep)
160                 self.logger.info(' --> %s' % pkg)
161                 self.install(pkg)
162             except yum.Errors.YumBaseError, e:
163                 errors.add(exception2msg(e))
164
165         if errors:
166             for i in sorted(errors):
167                 self.logger.error("Error: %s" % i)
168             if not opts.tolerant:
169                 sys.exit(1)
170
171     # go through each of the pkgs, figure out what they are/where they are 
172     # if they are not a local package then run
173         # Setup source repos
174         #self.setupSourceRepos()
175     # get all of their deps
176     # throw them into a ts
177     # run the ts
178     
179     def get_build_deps(self,opts):
180         srcnames = []
181         specnames = []
182         srpms = []
183         specworks = False
184         reloadworks = False
185
186         # See if we can use spec files for buildrequires
187         if hasattr(rpm, 'spec') and hasattr(rpm.spec, 'sourceHeader'):
188             specworks = True
189         # See if we can reload rpm configuration
190         if hasattr(rpm, 'reloadConfig'):
191             reloadworks = True
192
193         for arg in self.cmds:
194             if arg.endswith('.src.rpm'):
195                 try:
196                     srpms.append(yum.packages.YumLocalPackage(self.ts, arg))
197                 except yum.Errors.MiscError, e:
198                     self.logger.error("Error: Could not open %s .\nTry" 
199                     " running yum-builddep with the --nogpgcheck option." % arg)
200                     raise
201             elif arg.endswith('.src'):
202                 srcnames.append(arg)
203             elif specworks and arg.endswith('.spec'):
204                 specnames.append(arg)
205             else:
206                 srcnames.append(arg)
207
208         toActOn = []     
209         if srcnames:
210             pkgs = self.pkgSack.returnPackages(patterns=srcnames)
211             exact, match, unmatch = yum.packages.parsePackages(pkgs, srcnames, casematch=1)
212             srpms += exact + match
213             
214             if len(unmatch):
215                 pkgs = self.rpmdb.returnPackages(patterns=unmatch)
216                 exact, match, unmatch = yum.packages.parsePackages(pkgs, unmatch, casematch=1)
217                 if len(unmatch):
218                     self.logger.error("No such package(s): %s" %
219                                       ", ".join(unmatch))
220                     sys.exit(1)
221                     
222         toActOn = []
223         # Get the best matching srpms
224         for newpkg in srpms:
225             srcpkg = _best_convert_pkg2srcpkgs(self, opts, newpkg)
226             toActOn.extend(self.bestPackagesFromList(srcpkg, 'src'))
227
228         for srpm in toActOn:
229             self.logger.info('Getting requirements for %s' % srpm)
230             self.install_deps(srpm.requiresList(), opts)
231     
232         for name in specnames:
233             # (re)load rpm config for target if set
234             if reloadworks and opts.target:
235                 rpm.reloadConfig(opts.target)
236
237             try:
238                 spec = rpm.spec(name)
239             except ValueError:
240                 self.logger.error("Bad spec: %s" % name)
241                 continue
242
243             # reset default rpm config after each parse to avoid side-effects
244             if reloadworks:
245                 rpm.reloadConfig()
246
247             buildreqs = []
248             for d in rpm.ds(spec.sourceHeader, 'requires'):
249                 buildreqs.append(d.DNEVR()[2:])
250                 
251             self.logger.info('Getting requirements for %s' % name)
252             self.install_deps(buildreqs, opts)
253             
254 if __name__ == '__main__':
255     setup_locale()
256     util = YumBuildDep()
257         
258