2 # pylint: disable-msg=C0301,W0613,W0612,C0103,E0611,W0511
9 Various functions dealing with portage
19 from portage import config as portage_config
20 from portage import settings as portage_settings
24 from portage import dep as portage_dep
25 from portage import doebuild # perhaps this has moved?
26 from portage import config as portage_config # perhaps this has moved?
29 from portage import portage_dep
30 from portage import doebuild
31 from portage import config as portage_config
34 import gentoolkit # gentoolkit since 0.3.0 are installed as usual
35 except ImportError: # earlier versions in '/usr/lib/gentoolkit/pym'
36 sys.path.append(os.path.join('/usr', 'lib', 'gentoolkit', 'pym'))
40 import gentoolkit.query # gentoolkit since 0.3.0
41 def find_packages(key):
42 return gentoolkit.query.Query(cat_pkg).find()
43 except ImportError: # earlier versions
44 from gentoolkit.helpers import find_packages
47 __docformat__ = 'restructuredtext'
49 ENV = portage_config(clone=portage_settings)
50 LOGGER = logging.getLogger('g-pypi')
51 #_L = logging.getLogger('portage_utils)
52 #_L.setLevel(LOGGER.logging.DEBUG)
53 #LOGGER.addHandler(logging.StreamHandler())
55 def get_repo_name(path):
56 """Return the name of the overlay rooted at `path`.
58 @returns: string overlay name
60 repo_name_path = os.path.join(path, 'profiles/repo_name')
62 return open(repo_name_path, 'r').readline().strip()
63 except (OSError,IOError):
64 LOGGER.warn("no profiles/repo_name in %s" % path)
68 Return a dict of overlay names with their paths
70 {'reponame': '/path/to/repo', ...}
72 @returns: dict with repoman/paths
75 porttrees = [ENV['PORTDIR']] + \
76 [os.path.realpath(t) for t in ENV["PORTDIR_OVERLAY"].split()]
78 for path in porttrees:
79 name = get_repo_name(path)
84 def get_installed_ver(cpn):
86 Return PV for installed version of package
88 @param cpn: cat/pkg-ver
91 @returns: string version or None if not pkg installed
95 #Return first version installed
96 #XXX Log warning if more than one installed (SLOT)?
97 pkg = gentoolkit.find_installed_packages(cpn, masked=True)[0]
98 return pkg.get_version()
104 Return True if cpn is valid portage category/pn-pv
106 @param cpn: cat/pkg-ver
109 @returns: True if installed, False if not installed
111 if portage_dep.isvalidatom(cpn):
117 def ebuild_exists(cat_pkg):
120 Checks if an ebuild exists in portage tree or overlay
122 @param cat_pkg: portage category/packagename
123 @type cat_pkg: string
125 @returns: True if ebuild exists, False if no ebuild exists
128 pkgs = find_packages(cat_pkg)
134 #def run_tests(ebuild_path):
136 # Use portage to run tests
138 # Some day I'll figure out how to get portage to do this directly. Some day.
140 # @param ebuild_path: full path to ebuild
141 # @type ebuild_path: string
142 # @returns: None if succeed, raises OSError if fails to unpack
145 # cmd = "/usr/bin/python /usr/bin/ebuild %s test" % ebuild_path
147 # (status, output) = commands.getstatusoutput(cmd)
151 def unpack_ebuild(ebuild_path):
153 Use portage to unpack an ebuild
155 @param ebuild_path: full path to ebuild
156 @type ebuild_path: string
157 @returns: None if succeed, raises OSError if fails to unpack
160 #for phase in ['digest', 'setup', 'clean', 'unpack']:
161 # a = portage.doebuild(
162 # ebuild=ebuild_path, mydo=phase,
163 # mysettings=-!-!-! portage_config)
165 (status, output) = commands.getstatusoutput("ebuild %s digest setup clean unpack" % ebuild_path)
167 #Portage's error message, sometimes.
168 #Couldn't determine PN or PV so we misnamed ebuild
169 if 'does not follow correct package syntax' in output:
171 LOGGER.error("Misnamed ebuild: %s" % ebuild_path)
172 LOGGER.error("Try using -n or -v to force PN or PV")
173 os.unlink(ebuild_path)
178 def find_s_dir(p, cat):
180 Try to get ${S} by determining what directories were unpacked
182 @param p: portage ${P}
185 @param cat: valid portage category
188 @returns: string with directory name if detected, empty string
189 if S=WORKDIR, None if couldn't find S
194 workdir = get_workdir(p, cat)
195 files = os.listdir(workdir)
197 for unpacked in files:
198 if os.path.isdir(os.path.join(workdir, unpacked)):
199 dirs.append(unpacked)
201 #Only one directory, must be it.
207 #XXX Need to search whole tree for setup.py
208 LOGGER.error("Can't determine ${S}")
209 LOGGER.error("Unpacked multiple directories: %s" % dirs)
211 def get_workdir(p, cat):
215 @param p: portage ${P}
218 @param cat: valid portage category
221 @return: string of portage_tmpdir/cp
224 return '%s/portage/%s/%s/work' % (get_portage_tmpdir(), cat, p)
226 def get_portdir_overlay():
227 """Return PORTDIR_OVERLAY from /etc/make.conf"""
228 return ENV['PORTDIR_OVERLAY'].split(" ")[0]
230 def get_portage_tmpdir():
231 """Return PORTAGE_TMPDIR from /etc/make.conf"""
232 return ENV["PORTAGE_TMPDIR"]
235 """Return PORTDIR from /etc/make.conf"""
236 return ENV["PORTDIR"]
239 """Return first ACCEPT_KEYWORDS from /etc/make.conf"""
240 #Choose the first arch they have, in case of multiples.
243 arch = ENV["ACCEPT_KEYWORDS"].split(' ')[0]
245 LOGGER.error("No ACCEPT_KEYWORDS found, using ~x86")
248 #New ebuilds must be ~arch
250 if not arch.startswith('~'):
254 def make_overlay_dir(category, pn, overlay):
256 Create directory(s) in overlay for ebuild
258 @param category: valid portage category
259 @type category: string
261 @param pn: portage ${PN}
264 @param overlay: portage overlay directory
265 @type overlay: string
267 @return: string of full directory name
271 ebuild_dir = os.path.join(overlay, category, pn)
272 if not os.path.isdir(ebuild_dir):
273 os.makedirs(ebuild_dir)
277 def find_egg_info_dir(root):
279 Locate all files matching supplied filename pattern in and below
280 supplied root directory.
282 for path, dirs, files in os.walk(os.path.abspath(root)):
283 for this_dir in dirs:
284 if this_dir.endswith(".egg-info"):
285 return os.path.normpath(os.path.join(path, this_dir, ".."))
287 #Unused as of now. Could be used to find setup.py
288 #def find_files(pattern, root):
290 # Locate all files matching supplied filename pattern in and below
291 # supplied root directory.
293 # for path, dirs, files in os.walk(os.path.abspath(root)):
294 # for filename in fnmatch.filter(dirs, pattern):
295 # yield os.path.join(path, filename)
296 if __name__ == '__main__':
297 print get_repo_names()