PageRenderTime 24ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/PackageKit-0.8.2/backends/ports/portsBackend.rb

#
Ruby | 956 lines | 839 code | 68 blank | 49 comment | 133 complexity | 0139d723a81650897cc5955630add35f MD5 | raw file
Possible License(s): GPL-2.0, CC-BY-SA-4.0, LGPL-2.1
  1. #!/usr/local/bin/ruby
  2. # -*- ruby -*-
  3. # Copyright (C) 2009 Anders F Bjorklund <afb@users.sourceforge.net>
  4. #
  5. # Licensed under the GNU General Public License Version 2
  6. #
  7. # This program is free software; you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation; either version 2 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program; if not, write to the Free Software
  19. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  20. require 'pkgtools'
  21. require 'open3' # ignores exitcodes
  22. PROGRAM_DIR=File.dirname(File.expand_path($PROGRAM_NAME))
  23. $LOAD_PATH.unshift PROGRAM_DIR
  24. require 'ruby_packagekit/backend'
  25. require 'ruby_packagekit/enums'
  26. require 'ruby_packagekit/prints'
  27. def init_global
  28. $pkg_arch = PkgConfig::OS_PLATFORM
  29. end
  30. class PackageKitPortsBackend < PackageKitBaseBackend
  31. # maps Ports group to PackageKit group
  32. GROUPS = {
  33. "accessibility" => GROUP_ACCESSIBILITY,
  34. "arabic" => GROUP_LOCALIZATION,
  35. "archivers" => GROUP_UNKNOWN,
  36. "astro" => GROUP_UNKNOWN,
  37. "audio" => GROUP_MULTIMEDIA, # ???
  38. "benchmarks" => GROUP_UNKNOWN,
  39. "biology" => GROUP_SCIENCE,
  40. "cad" => GROUP_UNKNOWN,
  41. "chinese" => GROUP_LOCALIZATION,
  42. "comms" => GROUP_COMMUNICATION,
  43. "converters" => GROUP_UNKNOWN,
  44. "databases" => GROUP_SERVERS,
  45. "deskutils" => GROUP_ACCESSORIES,
  46. "devel" => GROUP_PROGRAMMING,
  47. "dns" => GROUP_INTERNET,
  48. "editors" => GROUP_UNKNOWN,
  49. "emulators" => GROUP_VIRTUALIZATION, # ???
  50. "finance" => GROUP_UNKNOWN,
  51. "french" => GROUP_LOCALIZATION,
  52. "ftp" => GROUP_INTERNET,
  53. "games" => GROUP_GAMES,
  54. "german" => GROUP_LOCALIZATION,
  55. "graphics" => GROUP_GRAPHICS,
  56. "hebrew" => GROUP_LOCALIZATION,
  57. "hungarian" => GROUP_LOCALIZATION,
  58. "irc" => GROUP_INTERNET,
  59. "japanese" => GROUP_LOCALIZATION,
  60. "java" => GROUP_UNKNOWN,
  61. "korean" => GROUP_LOCALIZATION,
  62. "lang" => GROUP_UNKNOWN,
  63. "mail" => GROUP_INTERNET,
  64. "math" => GROUP_SCIENCE,
  65. "mbone" => GROUP_UNKNOWN,
  66. "misc" => GROUP_OTHER,
  67. "multimedia" => GROUP_MULTIMEDIA,
  68. "net" => GROUP_NETWORK,
  69. "net-im" => GROUP_NETWORK,
  70. "net-mgmt" => GROUP_NETWORK,
  71. "net-p2p" => GROUP_NETWORK,
  72. "news" => GROUP_INTERNET,
  73. "palm" => GROUP_UNKNOWN,
  74. "polish" => GROUP_LOCALIZATION,
  75. "ports-mgmt" => GROUP_ADMIN_TOOLS,
  76. "portuguese" => GROUP_LOCALIZATION,
  77. "print" => GROUP_PUBLISHING,
  78. "russian" => GROUP_LOCALIZATION,
  79. "science" => GROUP_SCIENCE,
  80. "security" => GROUP_SECURITY,
  81. "shells" => GROUP_SYSTEM, # ???
  82. "spanish" => GROUP_LOCALIZATION,
  83. "sysutils" => GROUP_SYSTEM,
  84. "textproc" => GROUP_UNKNOWN,
  85. "ukrainian" => GROUP_LOCALIZATION,
  86. "vietnamese" => GROUP_LOCALIZATION,
  87. "www" => GROUP_INTERNET,
  88. "x11" => GROUP_DESKTOP_OTHER,
  89. "x11-clocks" => GROUP_DESKTOP_OTHER,
  90. "x11-drivers" => GROUP_DESKTOP_OTHER,
  91. "x11-fm" => GROUP_DESKTOP_OTHER,
  92. "x11-fonts" => GROUP_FONTS,
  93. "x11-servers" => GROUP_DESKTOP_OTHER,
  94. "x11-themes" => GROUP_DESKTOP_OTHER,
  95. "x11-toolkits" => GROUP_DESKTOP_OTHER,
  96. "x11-wm" => GROUP_DESKTOP_OTHER,
  97. ### virtual categories
  98. "afterstep" => GROUP_DESKTOP_OTHER,
  99. "docs" => GROUP_DOCUMENTATION,
  100. "elisp" => GROUP_UNKNOWN,
  101. "geography" => GROUP_UNKNOWN,
  102. "gnome" => GROUP_DESKTOP_GNOME,
  103. "gnustep" => GROUP_DESKTOP_OTHER,
  104. "hamradio" => GROUP_COMMUNICATION,
  105. "haskell" => GROUP_UNKNOWN,
  106. "ipv6" => GROUP_NETWORK,
  107. "kde" => GROUP_DESKTOP_KDE,
  108. "kld" => GROUP_SYSTEM,
  109. "linux" => GROUP_VIRTUALIZATION, # ???
  110. "lisp" => GROUP_UNKNOWN,
  111. "parallel" => GROUP_UNKNOWN,
  112. "pear" => GROUP_UNKNOWN,
  113. "perl5" => GROUP_UNKNOWN,
  114. "plan9" => GROUP_UNKNOWN,
  115. "python" => GROUP_UNKNOWN,
  116. "ruby" => GROUP_UNKNOWN,
  117. "rubygems" => GROUP_UNKNOWN,
  118. "scheme" => GROUP_UNKNOWN,
  119. "tcl" => GROUP_UNKNOWN,
  120. "tk" => GROUP_UNKNOWN,
  121. "windowmaker" => GROUP_UNKNOWN,
  122. "xfce" => GROUP_DESKTOP_XFCE,
  123. "zope" => GROUP_UNKNOWN,
  124. }
  125. def get_packages(filters)
  126. status(STATUS_QUERY)
  127. filterlist = filters.split(';')
  128. begin
  129. $portsdb.each do |portinfo|
  130. port = PortInfo.new(portinfo)
  131. pkg = PkgInfo.new(port.pkgname)
  132. installed = pkg.installed?
  133. if filterlist.include? FILTER_NOT_INSTALLED and installed:
  134. next
  135. elsif filterlist.include? FILTER_INSTALLED and !installed:
  136. next
  137. end
  138. data = installed ? "installed" : "ports"
  139. package_id = get_package_id(pkg.name, pkg.version, $pkg_arch, data)
  140. status = installed ? INFO_INSTALLED : INFO_AVAILABLE
  141. summary = port.comment
  142. if summary
  143. summary.chomp.chomp
  144. summary = summary.gsub(/\n\n/, ';')
  145. summary = summary.gsub(/\n/, ' ')
  146. summary = summary.gsub(/\t/, ' ')
  147. end
  148. package(package_id, status, summary)
  149. end
  150. rescue => e
  151. STDERR.puts e.message
  152. exit 1
  153. end
  154. rescue PortsDB::IndexFileError
  155. error(ERROR_INTERNAL_ERROR, "Error reading the ports INDEX.", false)
  156. rescue PortsDB::DBError
  157. error(ERROR_INTERNAL_ERROR, "Error reading the ports database.", false)
  158. end
  159. def get_repo_list(filters)
  160. status(STATUS_INFO)
  161. repo_detail("ports", "FreeBSD Ports", enabled=true)
  162. end
  163. def resolve(filters, packages)
  164. status(STATUS_QUERY)
  165. _resolve(filters, packages)
  166. end
  167. def _resolve(filters, packages)
  168. filterlist = filters.split(';')
  169. packages.each do |package|
  170. portnames = $portsdb.glob(package)
  171. if portnames
  172. portnames.each do |port|
  173. pkg = PkgInfo.new(port.pkgname)
  174. installed = pkg.installed?
  175. if filterlist.include? FILTER_NOT_INSTALLED and installed:
  176. next
  177. elsif filterlist.include? FILTER_INSTALLED and !installed:
  178. next
  179. end
  180. data = installed ? "installed" : "ports"
  181. package_id = get_package_id(pkg.name, pkg.version, $pkg_arch, data)
  182. status = installed ? INFO_INSTALLED : INFO_AVAILABLE
  183. summary = port.comment
  184. if summary
  185. summary.chomp.chomp
  186. summary = summary.gsub(/\n/, ';')
  187. summary = summary.gsub(/\t/, ' ')
  188. end
  189. package(package_id, status, summary)
  190. end
  191. else
  192. error(ERROR_PACKAGE_NOT_FOUND, "Package #{package} was not found")
  193. end
  194. end
  195. end
  196. def search_group(filters, key)
  197. status(STATUS_QUERY)
  198. filterlist = filters.split(';')
  199. if key == GROUP_NEWEST
  200. portmodified = Hash.new do |modified, portinfo|
  201. modified[portinfo] = File.mtime(File.join(portinfo.portdir, 'Makefile')) if portinfo
  202. end
  203. ports = $portsdb.origins.sort { |a, b| portmodified[$portsdb.port(b)] \
  204. <=> portmodified[$portsdb.port(a)] }
  205. else
  206. category = GROUPS.invert[key] || GROUP_UNKNOWN
  207. ports = $portsdb.origins(category)
  208. end
  209. begin
  210. ports.each do |origin|
  211. port = $portsdb.port(origin)
  212. pkg = PkgInfo.new(port.pkgname)
  213. installed = pkg.installed?
  214. if filterlist.include? FILTER_NOT_INSTALLED and installed:
  215. next
  216. elsif filterlist.include? FILTER_INSTALLED and !installed:
  217. next
  218. end
  219. data = installed ? "installed" : "ports"
  220. package_id = get_package_id(pkg.name, pkg.version, $pkg_arch, data)
  221. status = installed ? INFO_INSTALLED : INFO_AVAILABLE
  222. summary = port.comment
  223. if summary
  224. summary.chomp.chomp
  225. summary = summary.gsub(/\n\n/, ';')
  226. summary = summary.gsub(/\n/, ' ')
  227. summary = summary.gsub(/\t/, ' ')
  228. end
  229. package(package_id, status, summary)
  230. end
  231. end
  232. end
  233. def search_name(filters, key)
  234. status(STATUS_QUERY)
  235. filterlist = filters.split(';')
  236. name = key
  237. begin
  238. $portsdb.glob("*#{name}*").each do |port|
  239. pkg = PkgInfo.new(port.pkgname)
  240. installed = pkg.installed?
  241. data = installed ? "installed" : "ports"
  242. package_id = get_package_id(pkg.name, pkg.version, $pkg_arch, data)
  243. status = installed ? INFO_INSTALLED : INFO_AVAILABLE
  244. summary = port.comment
  245. if summary
  246. summary.chomp.chomp
  247. summary = summary.gsub(/\n/, ' ')
  248. summary = summary.gsub(/\t/, ' ')
  249. end
  250. package(package_id, status, summary)
  251. end
  252. end
  253. end
  254. def search_details(filters, key)
  255. status(STATUS_QUERY)
  256. filterlist = filters.split(';')
  257. begin
  258. $portsdb.each do |portinfo|
  259. port = PortInfo.new(portinfo)
  260. pkg = PkgInfo.new(port.pkgname)
  261. if port.comment and port.comment.match(key)
  262. installed = pkg.installed?
  263. data = installed ? "installed" : "ports"
  264. package_id = get_package_id(pkg.name, pkg.version, $pkg_arch, data)
  265. status = installed ? INFO_INSTALLED : INFO_AVAILABLE
  266. summary = pkg.comment
  267. if summary
  268. summary.chomp.chomp
  269. summary = summary.gsub(/\n/, ' ')
  270. summary = summary.gsub(/\t/, ' ')
  271. end
  272. package(package_id, status, summary)
  273. end
  274. end
  275. end
  276. end
  277. def search_file(filters, key)
  278. status(STATUS_QUERY)
  279. filterlist = filters.split(';')
  280. if filterlist.include? FILTER_NOT_INSTALLED
  281. error(ERROR_CANNOT_GET_FILELIST, "Only available for installed packages", false)
  282. return
  283. end
  284. if key[0,1] == '/':
  285. packages = $pkgdb.which_m(key)
  286. if packages
  287. packages.each do |pkgname|
  288. pkg = $pkgdb.pkg(pkgname)
  289. installed = true
  290. data = installed ? "installed" : "ports"
  291. package_id = get_package_id(pkg.name, pkg.version, $pkg_arch, data)
  292. status = installed ? INFO_INSTALLED : INFO_AVAILABLE
  293. summary = pkg.comment
  294. if summary
  295. summary.chomp.chomp
  296. summary = summary.gsub(/\n/, ' ')
  297. summary = summary.gsub(/\t/, ' ')
  298. end
  299. package(package_id, status, summary)
  300. end
  301. end
  302. else
  303. $pkgdb.each do |pkg|
  304. match = false
  305. pkg.files.each do |file|
  306. match = true if file.match(key)
  307. end
  308. next unless match
  309. installed = true
  310. data = installed ? "installed" : "ports"
  311. package_id = get_package_id(pkg.name, pkg.version, $pkg_arch, data)
  312. status = installed ? INFO_INSTALLED : INFO_AVAILABLE
  313. summary = pkg.comment
  314. if summary
  315. summary.chomp.chomp
  316. summary = summary.gsub(/\n/, ' ')
  317. summary = summary.gsub(/\t/, ' ')
  318. end
  319. package(package_id, status, summary)
  320. end
  321. end
  322. end
  323. def get_depends(filters, package_ids, recursive)
  324. status(STATUS_INFO)
  325. filterlist = filters.split(';')
  326. package_ids.each do |package|
  327. name, version, arch, data = split_package_id(package)
  328. pkgnames = $portsdb.glob(name)
  329. if pkgnames
  330. pkgnames.each do |port|
  331. pkg = PkgInfo.new(port.pkgname)
  332. next if pkg.version != version
  333. if pkg.pkgdep
  334. pkg.pkgdep.each do |dep|
  335. _resolve(filters, dep)
  336. end
  337. elsif port.all_depends
  338. port.all_depends.each do |dep|
  339. _resolve(filters, dep)
  340. end
  341. end
  342. end
  343. else
  344. error(ERROR_PACKAGE_NOT_FOUND, "Package #{package} was not found")
  345. end
  346. end
  347. end
  348. def _distsize(origin)
  349. portdir = $portsdb.portdir(origin)
  350. file = $portsdb.make_var('MD5_FILE', portdir) # 'distinfo'
  351. dist_dir = $portsdb.make_var('DISTDIR', $portsdb.my_portdir)
  352. distsize = 0
  353. open(file) do |f|
  354. f.each do |line|
  355. if /^SIZE \((.*)\) = ([0-9]+)/ =~ line
  356. if not File.exist?(File.join(dist_dir, $1))
  357. distsize += $2.to_i
  358. end
  359. end
  360. end
  361. end
  362. return distsize
  363. end
  364. def get_details(package_ids)
  365. status(STATUS_INFO)
  366. package_ids.each do |package|
  367. name, version, arch, data = split_package_id(package)
  368. pkgnames = $portsdb.glob(name)
  369. if pkgnames
  370. pkgnames.each do |port|
  371. pkg = PkgInfo.new(port.pkgname)
  372. next if pkg.version != version
  373. license = 'unknown'
  374. portgroup = port.category()
  375. group = GROUPS[portgroup] || GROUP_UNKNOWN
  376. descr_file = File.join($portsdb.ports_dir, port.descr_file)
  377. www = ""
  378. if descr_file
  379. desc = IO.read(descr_file)
  380. desc.chomp.chomp
  381. www = $~[1] if desc =~ /WWW:\s+(.*)/
  382. desc = desc.sub(/WWW:\s+(.*)/, "")
  383. license = $~[1] if desc =~ /LICENSE:\s+(.*)/
  384. license = license.gsub(/\s/, ' ')
  385. desc = desc.gsub(/\n/, ';')
  386. desc = desc.gsub(/\t/, ' ')
  387. end
  388. size = pkg.totalsize || _distsize(port.origin)
  389. details(package, license, group, desc, www, size)
  390. end
  391. else
  392. error(ERROR_PACKAGE_NOT_FOUND, "Package #{package} was not found")
  393. end
  394. end
  395. end
  396. def get_files(package_ids)
  397. status(STATUS_INFO)
  398. package_ids.each do |package|
  399. name, version, arch, data = split_package_id(package)
  400. pkgnames = $portsdb.glob(name)
  401. if pkgnames
  402. pkgnames.each do |port|
  403. pkg = PkgInfo.new(port.pkgname)
  404. next if pkg.version != version
  405. if !pkg.installed?
  406. error(ERROR_CANNOT_GET_FILELIST, "Only available for installed packages", false)
  407. end
  408. file_list = pkg.files.join(';')
  409. files(package, file_list)
  410. end
  411. else
  412. error(ERROR_PACKAGE_NOT_FOUND, "Package #{package} was not found")
  413. end
  414. end
  415. end
  416. def get_requires(filters, package_ids, recursive)
  417. status(STATUS_INFO)
  418. package_ids.each do |package|
  419. name, version, arch, data = split_package_id(package)
  420. pkgnames = $portsdb.glob(name)
  421. if pkgnames
  422. pkgnames.each do |port|
  423. pkg = PkgInfo.new(port.pkgname)
  424. next if pkg.version != version
  425. if pkg.required_by
  426. pkg.required_by.each do |dep|
  427. resolve(FILTER_INSTALLED, dep)
  428. end
  429. end
  430. end
  431. else
  432. error(ERROR_PACKAGE_NOT_FOUND, "Package #{package} was not found")
  433. end
  434. end
  435. end
  436. # (ports-mgmt/portaudit)
  437. PORTAUDIT="#{PREFIX}/sbin/portaudit"
  438. def refresh_cache(force)
  439. percentage(0)
  440. status(STATUS_DOWNLOAD_PACKAGELIST)
  441. system "cd #{$portsdb.abs_ports_dir} && make update"
  442. if File.exist?(PORTAUDIT)
  443. status(STATUS_DOWNLOAD_UPDATEINFO)
  444. system(PORTAUDIT, '-q', '-F')
  445. end
  446. percentage(50)
  447. status(STATUS_REFRESH_CACHE)
  448. $portsdb.update_db(force)
  449. percentage(100)
  450. end
  451. # (security/vxquery)
  452. VXQUERY = "#{PREFIX}/bin/vxquery"
  453. # http://www.vuxml.org
  454. VULN_XML = 'vuln.xml'
  455. def _match_range(range, version)
  456. cmp = PkgVersion.new(version.to_s) <=> PkgVersion.new(range.text)
  457. return true if range.name == 'lt' && cmp < 0
  458. return true if range.name == 'le' && cmp <= 0
  459. return true if range.name == 'eq' && cmp == 0
  460. return true if range.name == 'ge' && cmp >= 0
  461. return true if range.name == 'gt' && cmp > 0
  462. return false
  463. end
  464. def _vuxml(name, oldversion=nil, newversion=nil)
  465. vulnxml = File.join($portsdb.portdir('security/vuxml'), VULN_XML)
  466. vulns = []
  467. if File.exist?(VXQUERY) and File.exist?(vulnxml)
  468. require 'rexml/document'
  469. vuxml = `#{VXQUERY} -t 'vuxml' #{vulnxml} '#{name}'`
  470. doc = REXML::Document.new vuxml
  471. doc.root.each_element('//vuln') do |vuln|
  472. match = false
  473. vuln.each_element('affects/package') do |package|
  474. package.elements['name'].each do |element|
  475. if element == name
  476. match = true
  477. break
  478. end
  479. end
  480. next unless match
  481. if oldversion and newversion
  482. match = false
  483. package.elements['range'].each do |element|
  484. if _match_range(element, oldversion) and
  485. not _match_range(element, newversion)
  486. match = true
  487. break
  488. end
  489. end
  490. end
  491. end
  492. vulns << vuln if match
  493. end
  494. end
  495. return vulns
  496. end
  497. def get_updates(filters)
  498. status(STATUS_DEP_RESOLVE)
  499. filterlist = filters.split(';')
  500. list = []
  501. $pkgdb.glob.each do |pkgname|
  502. list |= $pkgdb.recurse(pkgname)
  503. end
  504. status(STATUS_INFO)
  505. list.each do |pkg|
  506. pkgname = pkg.fullname
  507. if origin = pkg.origin
  508. if portinfo = $portsdb[origin]
  509. newpkg = portinfo.pkgname
  510. elsif $portsdb.exist?(origin, quick = true)
  511. pkgname = $portsdb.exist?(origin) or next
  512. newpkg = PkgInfo.new(pkgname)
  513. else
  514. # pkg's port is not in portsdb
  515. next
  516. end
  517. if newpkg.version > pkg.version
  518. data = "ports"
  519. package_id = get_package_id(pkg.name, pkg.version, $pkg_arch, data)
  520. status = INFO_NORMAL
  521. if File.exist?(PORTAUDIT)
  522. system("PATH=/sbin:$PATH #{PORTAUDIT} -q '#{pkg.fullname}'") # /sbin/md5
  523. status = INFO_SECURITY if ($? != 0)
  524. end
  525. summary = pkg.comment
  526. if summary
  527. summary.chomp.chomp
  528. summary = summary.gsub(/\n/, ' ')
  529. summary = summary.gsub(/\t/, ' ')
  530. end
  531. package(package_id, status, summary)
  532. end
  533. end
  534. end
  535. end
  536. def get_update_detail(package_ids)
  537. status(STATUS_INFO)
  538. package_ids.each do |package|
  539. name, version, arch, data = split_package_id(package)
  540. pkgnames = $portsdb.glob(name)
  541. if pkgnames
  542. pkgnames.each do |port|
  543. pkg = PkgInfo.new(port.pkgname)
  544. updates = ''
  545. obsoletes = ''
  546. oldpkg = $pkgdb.glob(port.origin).first
  547. next if pkg == oldpkg
  548. if oldpkg
  549. next if oldpkg.version != version
  550. data = 'ports'
  551. package = get_package_id(pkg.name, pkg.version, $pkg_arch, data)
  552. data = oldpkg.installed? ? 'installed' : 'ports'
  553. updates = get_package_id(oldpkg.name, oldpkg.version, $pkg_arch, data)
  554. else
  555. pkgnames = $portsdb.glob(name)
  556. pkgnames.each do |oldport|
  557. oldpkg = PkgInfo.new(oldport.pkgname)
  558. next if oldpkg.version != version
  559. end
  560. data = oldpkg.installed? ? 'installed' : 'ports'
  561. obsoletes = get_package_id(oldpkg.name, oldpkg.version, $pkg_arch, data)
  562. end
  563. state = UPDATE_STATE_STABLE
  564. vendor_urls = []
  565. bugzilla_urls = []
  566. cve_urls = []
  567. description = ''
  568. issued = ''
  569. updated = ''
  570. vulns = _vuxml(pkg.name, oldpkg.version, pkg.version)
  571. vulns.each do |vuln|
  572. if topic = vuln.elements['topic']
  573. description += topic.text
  574. end
  575. if vid = vuln.attributes["vid"]
  576. vendor_urls << "http://vuxml.freebsd.org/#{vid}.html"
  577. end
  578. vuln.each_element('references/cvename') do |cve|
  579. cve_urls << "http://cve.mitre.org/cgi-bin/cvename.cgi?name=#{cve.text}"
  580. end
  581. vuln.each_element('references/url') do |element|
  582. url = element.text.chomp
  583. if url.match(/bugzilla/)
  584. bugzilla_urls << url
  585. end
  586. end
  587. if date = vuln.elements['dates/entry']
  588. issued = date.text
  589. end
  590. if date = vuln.elements['dates/modified']
  591. updated = date.text
  592. end
  593. end
  594. vendor_urls = vendor_urls.join(';')
  595. bugzilla_urls = bugzilla_urls.join(';')
  596. cve_urls = cve_urls.join(';')
  597. reboot = 'none'
  598. changelog = ''
  599. update_detail(package,
  600. updates, obsoletes, vendor_urls, bugzilla_urls, cve_urls,
  601. reboot, description, changelog, state, issued, updated)
  602. break
  603. end
  604. else
  605. error(ERROR_PACKAGE_NOT_FOUND, "Package #{package} was not found")
  606. end
  607. end
  608. end
  609. # (ports-mgmt/portupgrade)
  610. PORTUPGRADE="#{PREFIX}/sbin/portupgrade"
  611. # use a non-interactive (default) dialog program
  612. DIALOG="#{PROGRAM_DIR}/helpers/default-dialog"
  613. # Here are the extra subphases used, when:
  614. # ---> Using the port instead of a package
  615. # ---> Building '#{portdir}'
  616. # ===> Cleaning for #{pkgname}
  617. # [fetch distfiles]
  618. # ===> Extracting for #{pkgname}
  619. # [fetch patchfiles]
  620. # ===> Patching for #{pkgname}
  621. # ===> Configuring for #{pkgname}
  622. # ===> Building for #{pkgname}
  623. # ===> Installing for #{pkgname}
  624. # ===> Building package for #{pkgname}
  625. # ===> Cleaning for #{pkgname}
  626. # use packages
  627. USE_PKG = true
  628. # build packages
  629. BIN_PKG = true
  630. def update_system(only_trusted)
  631. if only_trusted
  632. error(ERROR_MISSING_GPG_SIGNATURE, "Trusted packages not available.")
  633. return
  634. end
  635. args = ['-M', 'DIALOG='+DIALOG]
  636. args << '-P' if USE_PKG
  637. args << '-p' if BIN_PKG
  638. args << '-a' # all installed
  639. status(STATUS_DEP_RESOLVE)
  640. stdin, stdout, stderr = Open3.popen3(PORTUPGRADE, *args)
  641. stdout.each_line do |line|
  642. if line.match(/^\=+\>/)
  643. message(MESSAGE_UNKNOWN, line.chomp)
  644. elsif line.match(/^\-\-\-\>/)
  645. if line.match(/Upgrading '(.*)\-(.*)' to '(.*)\-(.*)'/)
  646. status(STATUS_UPDATE)
  647. _resolve(FILTER_NONE, $1)
  648. elsif line.match(/Fetching (.*)\-(.*)/)
  649. status(STATUS_DOWNLOAD)
  650. _resolve(FILTER_NONE, $1)
  651. elsif line.match(/SECURITY REPORT/)
  652. # important safety tip
  653. end
  654. message(MESSAGE_UNKNOWN, line.chomp)
  655. end
  656. end
  657. stderr.each_line do |line|
  658. if line.match(/\[Updating the pkgdb.*\]/)
  659. status(STATUS_WAIT)
  660. elsif line.match(/^\*\* Command failed \[exit code (\d)\]: (.*)/)
  661. error(ERROR_TRANSACTION_ERROR, $2)
  662. elsif not line.match(/\[Gathering depends.*\]/) \
  663. and not line.match(/^\*\* Could not find the latest version/)
  664. message(MESSAGE_BACKEND_ERROR, line.chomp)
  665. end
  666. end
  667. end
  668. def download_packages(directory, package_ids)
  669. pkgnames = []
  670. package_ids.each do |package|
  671. name, version, arch, data = split_package_id(package)
  672. if not $portsdb.glob(name)
  673. error(ERROR_PACKAGE_NOT_FOUND, "Package #{name} was not found", exit=false)
  674. next
  675. end
  676. pkgname = "#{name}-#{version}"
  677. pkgnames << pkgname
  678. end
  679. args = [ '-f' ] # download even if installed
  680. args.concat pkgnames
  681. packages = ENV['PACKAGES']
  682. pkgname = nil
  683. status(STATUS_DEP_RESOLVE)
  684. ENV['PACKAGES'] = directory
  685. stdin, stdout, stderr = Open3.popen3(PkgDB::command(:pkg_fetch), *args)
  686. stdout.each_line do |line|
  687. if line.match(/^\-\-\-\>/)
  688. if line.match(/Fetching (.*)\-(.*)/)
  689. status(STATUS_DOWNLOAD)
  690. _resolve(FILTER_NONE, $1)
  691. pkgname = "#{$1}-#{$2}"
  692. elsif line.match(/Saved as (.*)/)
  693. next unless pkgname
  694. pkg = PkgInfo.new(pkgname)
  695. file_list = $1
  696. data = pkg.installed? ? "installed" : "ports"
  697. package_id = get_package_id(pkg.name, pkg.version, $pkg_arch, data)
  698. files(package_id, file_list)
  699. pkgname = nil
  700. end
  701. message(MESSAGE_UNKNOWN, line.chomp)
  702. end
  703. end
  704. stderr.each_line do |line|
  705. if line.match(/\*\* Failed to fetch (.*)\-(.*)/)
  706. pkgname = "#{$1}-#{$2}"
  707. next unless pkgnames.include?(pkgname)
  708. message(ERROR_PACKAGE_DOWNLOAD_FAILED, "Failed to fetch #{pkgname}")
  709. else
  710. message(MESSAGE_BACKEND_ERROR, line.chomp)
  711. end
  712. end
  713. ENV['PACKAGES'] = packages
  714. end
  715. def install_files(only_trusted, inst_files)
  716. if only_trusted
  717. error(ERROR_MISSING_GPG_SIGNATURE, "Trusted packages not available.")
  718. return
  719. end
  720. pkg_path = ENV['PKG_PATH']
  721. path = []
  722. pkgnames = []
  723. inst_files.each do |file|
  724. begin
  725. pkg = PkgFileInfo.new(file)
  726. pkgname = pkg.fullname
  727. if pkg.installed?
  728. error(ERROR_PACKAGE_ALREADY_INSTALLED, "The package #{pkgname} is already installed")
  729. elsif $portsdb.glob(pkgname).empty?
  730. # portinstall is a little picky about installing packages for mismatched ports
  731. error(ERROR_PACKAGE_NOT_FOUND, "Port for #{pkgname} was not found", exit=true)
  732. else
  733. pkgnames << pkgname
  734. end
  735. rescue ArgumentError
  736. error(ERROR_INVALID_PACKAGE_FILE, "File #{file} is not a package")
  737. next
  738. end
  739. path << File.dirname(file)
  740. end
  741. path << $packages_dir # add default dir for depends
  742. ENV['PKG_PATH'] = path.join(':')
  743. _install(pkgnames)
  744. ENV['PKG_PATH'] = pkg_path
  745. end
  746. def install_packages(only_trusted, package_ids)
  747. if only_trusted
  748. error(ERROR_MISSING_GPG_SIGNATURE, "Trusted packages not available.")
  749. return
  750. end
  751. pkgnames = []
  752. package_ids.each do |package|
  753. name, version, arch, data = split_package_id(package)
  754. if $portsdb.glob(name)
  755. pkgname = "#{name}-#{version}"
  756. pkg = PkgInfo.new(pkgname)
  757. if pkg.installed?
  758. error(ERROR_PACKAGE_ALREADY_INSTALLED, "The package #{pkgname} is already installed")
  759. else
  760. pkgnames << pkg.fullname
  761. end
  762. else
  763. error(ERROR_PACKAGE_NOT_FOUND, "Package #{name} was not found", exit=false)
  764. next
  765. end
  766. end
  767. _install(pkgnames)
  768. end
  769. def _install(pkgnames)
  770. return if pkgnames.empty?
  771. args = ['-M', 'DIALOG='+DIALOG]
  772. args << '-P' if USE_PKG
  773. args << '-p' if BIN_PKG
  774. args.concat pkgnames
  775. status(STATUS_DEP_RESOLVE)
  776. stdin, stdout, stderr = Open3.popen3(PkgDB::command(:portinstall), *args)
  777. stdout.each_line do |line|
  778. if line.match(/^\=+\>/)
  779. message(MESSAGE_UNKNOWN, line.chomp)
  780. elsif line.match(/^\-\-\-\>/)
  781. if line.match(/Installing '(.*)\-(.*)'/)
  782. status(STATUS_INSTALL)
  783. _resolve(FILTER_NONE, $1)
  784. elsif line.match(/Fetching (.*)\-(.*)/)
  785. status(STATUS_DOWNLOAD)
  786. _resolve(FILTER_NONE, $1)
  787. elsif line.match(/SECURITY REPORT/)
  788. # important safety tip
  789. end
  790. message(MESSAGE_UNKNOWN, line.chomp)
  791. end
  792. end
  793. stderr.each_line do |line|
  794. if line.match(/\[Updating the pkgdb.*\]/)
  795. status(STATUS_WAIT)
  796. elsif line.match(/^\*\* Command failed \[exit code (\d)\]: (.*)/)
  797. error(ERROR_TRANSACTION_ERROR, $2)
  798. elsif not line.match(/\[Gathering depends.*\]/) \
  799. and not line.match(/^\*\* Could not find the latest version/)
  800. message(MESSAGE_BACKEND_ERROR, line.chomp)
  801. end
  802. end
  803. pkgnames.each do |pkgname|
  804. _resolve(FILTER_INSTALLED, pkgname)
  805. end
  806. end
  807. def remove_packages(allowdep, autoremove, package_ids)
  808. if autoremove
  809. error(ERROR_NOT_SUPPORTED, "Automatic removal not available.", exit=false)
  810. end
  811. pkgnames = []
  812. package_ids.each do |package|
  813. name, version, arch, data = split_package_id(package)
  814. if not $portsdb.glob(name)
  815. error(ERROR_PACKAGE_NOT_FOUND, "Package #{name} was not found", exit=false)
  816. next
  817. end
  818. pkgname = "#{name}-#{version}"
  819. pkg = PkgInfo.new(pkgname)
  820. if not pkg.installed?
  821. error(ERROR_PACKAGE_NOT_INSTALLED, "The package #{pkgname} is not installed")
  822. else
  823. pkgnames << pkgname
  824. end
  825. end
  826. return if pkgnames.empty?
  827. status(STATUS_DEP_RESOLVE)
  828. args = []
  829. args << '--recursive' if allowdep
  830. args.concat pkgnames
  831. stdin, stdout, stderr = Open3.popen3(PkgDB::command(:pkg_deinstall), *args)
  832. stdout.each_line do |line|
  833. if line.match(/^\=+\>/)
  834. message(MESSAGE_UNKNOWN, line.chomp)
  835. elsif line.match(/^\-\-\-\>/)
  836. if line.match(/Deinstalling '(.*)\-(.*)'/)
  837. status(STATUS_REMOVE)
  838. _resolve(FILTER_NONE, $1)
  839. end
  840. message(MESSAGE_UNKNOWN, line.chomp)
  841. end
  842. end
  843. stderr.each_line do |line|
  844. if line.match(/\[Updating the pkgdb.*\]/)
  845. status(STATUS_WAIT)
  846. elsif line.match(/^\*\* Command failed \[exit code (\d)\]: (.*)/)
  847. error(ERROR_TRANSACTION_ERROR, $2)
  848. elsif not line.match(/\[Gathering depends.*\]/) \
  849. and not line.match(/^\*\* Could not find the latest version/)
  850. message(MESSAGE_BACKEND_ERROR, line.chomp)
  851. end
  852. end
  853. package_ids.each do |package|
  854. name, version, arch, data = split_package_id(package)
  855. pkgname = "#{name}-#{version}"
  856. _resolve(FILTER_NOT_INSTALLED, pkgname)
  857. end
  858. end
  859. protected :_resolve, :_match_range, :_vuxml, :_install
  860. end
  861. #######################################################################
  862. def to_b(string)
  863. return true if string == true || string =~ /^true$/i
  864. return false if string == false || string.nil? || string =~ /^false$/i
  865. return true if string == "yes"
  866. return false if string == "no"
  867. raise ArgumentError.new("invalid value for bool: \"#{string}\"")
  868. end
  869. # Returns a package id.
  870. def get_package_id(name, version, arch, data)
  871. return [name, version, arch, data].join(';')
  872. end
  873. # Returns an array with the name, version, arch, data of a package id.
  874. def split_package_id(id)
  875. return id.split(';', 4)
  876. end
  877. #######################################################################
  878. def main(argv)
  879. init_global
  880. init_pkgtools_global
  881. backend = PackageKitPortsBackend.new
  882. backend.dispatcher(argv)
  883. 0
  884. end
  885. if $0 == __FILE__
  886. set_signal_handlers
  887. exit(main(ARGV) || 1)
  888. end