pacman.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. # Copyright (c) 2022, Open Source Robotics Foundation
  2. # All rights reserved.
  3. #
  4. # Redistribution and use in source and binary forms, with or without
  5. # modification, are permitted provided that the following conditions are met:
  6. #
  7. # * Redistributions of source code must retain the above copyright
  8. # notice, this list of conditions and the following disclaimer.
  9. # * Redistributions in binary form must reproduce the above copyright
  10. # notice, this list of conditions and the following disclaimer in the
  11. # documentation and/or other materials provided with the distribution.
  12. # * Neither the name of the Willow Garage, Inc. nor the names of its
  13. # contributors may be used to endorse or promote products derived from
  14. # this software without specific prior written permission.
  15. #
  16. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  17. # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19. # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  20. # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  21. # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  22. # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  23. # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  24. # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  25. # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  26. # POSSIBILITY OF SUCH DAMAGE.
  27. import os
  28. import tarfile
  29. from . import open_gz_url
  30. from . import PackageEntry
  31. from . import RepositoryCacheCollection
  32. def replace_tokens(string, repo_name, os_arch):
  33. """Replace pacman-specific tokens in the repository base URL."""
  34. for key, value in {
  35. '$arch': os_arch,
  36. '$repo': repo_name,
  37. }.items():
  38. string = string.replace(key, value)
  39. return string
  40. def enumerate_descs(url):
  41. """
  42. Enumerate desc files from a pacman db.
  43. :param url: the URL of the pacman db.
  44. :returns: an enumeration of desc file contents.
  45. """
  46. with open_gz_url(url) as f:
  47. with tarfile.open(mode='r|', fileobj=f) as tf:
  48. for ti in tf:
  49. if ti.name.endswith('/desc'):
  50. yield tf.extractfile(ti)
  51. def enumerate_blocks(url):
  52. """
  53. Enumerate blocks of mapped data from a pacman db.
  54. :param url: the URL of the pacman db.
  55. :returns: an enumeration of mappings.
  56. """
  57. for desc in enumerate_descs(url):
  58. block = {}
  59. while True:
  60. k = desc.readline()
  61. if not k:
  62. break
  63. k = k.strip().decode()
  64. if not k:
  65. continue
  66. v = []
  67. while True:
  68. line = desc.readline().strip().decode()
  69. if not line:
  70. break
  71. v.append(line)
  72. block[k] = v
  73. if block:
  74. yield block
  75. def enumerate_pacman_packages(base_url, repo_name, os_arch):
  76. """
  77. Enumerate pacman packages in a repository.
  78. :param base_url: the pacman repository base URL.
  79. :param repo_name: the name of the repository to enumerate.
  80. :param os_arch: the system architecture associated with the repository.
  81. :returns: an enumeration of package entries.
  82. """
  83. base_url = replace_tokens(base_url, repo_name, os_arch)
  84. db_url = os.path.join(base_url, repo_name + '.db.tar.gz')
  85. print('Reading pacman package metadata from ' + db_url)
  86. for block in enumerate_blocks(db_url):
  87. pkg_url = os.path.join(base_url, block['%FILENAME%'][0])
  88. pkg_name = block['%NAME%'][0]
  89. pkg_ver = block['%VERSION%'][0]
  90. yield PackageEntry(pkg_name, pkg_ver, pkg_url)
  91. for pkg_prov in block.get('%PROVIDES%', ()):
  92. yield PackageEntry(pkg_prov, pkg_ver, pkg_url, pkg_name, pkg_name)
  93. def pacman_base_url(base_url, repo_name):
  94. """
  95. Create an enumerable cache for a pacman repository.
  96. :param base_url: the URL of the pacman repository.
  97. :param repo_name: the name of the repository to enumerate.
  98. :returns: an enumerable repository cache instance.
  99. """
  100. return RepositoryCacheCollection(
  101. lambda os_name, os_code_name, os_arch:
  102. enumerate_pacman_packages(base_url, repo_name, os_arch))