Use ~x86 if absolutely no ACCEPT_KEYWORDS found.
[g-pypi.git] / g_pypi / portage_utils.py
1 #!/usr/bin/env python
2 # pylint: disable-msg=C0301,W0613,W0612,C0103,E0611,W0511
3
4 """
5
6 portage_utils.py
7 ================
8
9 Various functions dealing with portage
10
11 """
12
13 import sys
14 import os
15 import commands
16 import logging
17 #import fnmatch
18
19 import portage
20
21 try:
22     #portage >= 2.2
23     from portage import dep as portage_dep
24 except ImportError:
25     #portage <= 2.1
26     from portage import portage_dep
27
28 sys.path.insert(0, "/usr/lib/gentoolkit/pym")
29 import gentoolkit
30
31
32 __docformat__ = 'restructuredtext'
33
34 ENV = portage.config(clone=portage.settings).environ()
35 LOGGER = logging.getLogger(__name__)
36 LOGGER.setLevel(logging.DEBUG)
37 LOGGER.addHandler(logging.StreamHandler())
38
39
40 def get_installed_ver(cpn):
41     """
42     Return PV for installed version of package
43
44     @param cpn: cat/pkg-ver
45     @type cpn: string
46
47     @returns: string version or None if not pkg installed
48
49     """
50     try:
51         #Return first version installed
52         #XXX Log warning if more than one installed (SLOT)?
53         pkg = gentoolkit.find_installed_packages(cpn, masked=True)[0]
54         return pkg.get_version()
55     except:
56         return
57
58 def valid_cpn(cpn):
59     """
60     Return True if cpn is valid portage category/pn-pv
61
62     @param cpn: cat/pkg-ver
63     @type cpn: string
64
65     @returns: True if installed, False if not installed
66     """
67     if portage_dep.isvalidatom(cpn):
68         return True
69     else:
70         return False
71
72
73 def ebuild_exists(cat_pkg):
74     """
75
76     Checks if an ebuild exists in portage tree or overlay
77
78     @param cat_pkg: portage category/packagename
79     @type cat_pkg: string
80
81     @returns: True if ebuild exists, False if no ebuild exists
82     """
83
84     pkgs = gentoolkit.find_packages(cat_pkg)
85     if len(pkgs):
86         return True
87     else:
88         return False
89
90 #def run_tests(ebuild_path):
91 #    """
92 #    Use portage to run tests
93
94 #    Some day I'll figure out how to get portage to do this directly. Some day.
95
96 #    @param ebuild_path: full path to ebuild
97 #    @type ebuild_path: string
98 #    @returns: None if succeed, raises OSError if fails to unpack
99
100 #    """
101 #    cmd = "/usr/bin/python /usr/bin/ebuild %s test" % ebuild_path
102 #    print cmd
103 #    (status, output) = commands.getstatusoutput(cmd)
104 #    print output
105 #    print status
106
107 def unpack_ebuild(ebuild_path):
108     """
109     Use portage to unpack an ebuild
110
111     Some day I'll figure out how to get portage to do this directly. Some day.
112
113     @param ebuild_path: full path to ebuild
114     @type ebuild_path: string
115     @returns: None if succeed, raises OSError if fails to unpack
116
117     """
118     (status, output) = commands.getstatusoutput("ebuild %s digest setup clean unpack" % ebuild_path)
119     if status:
120         #Portage's error message, sometimes.
121         #Couldn't determine PN or PV so we misnamed ebuild
122         if 'does not follow correct package syntax' in output:
123             LOGGER.error(output)
124             LOGGER.error("Misnamed ebuild: %s" % ebuild_path)
125             LOGGER.error("Try using -n or -v to force PN or PV")
126             os.unlink(ebuild_path)
127         else:
128             LOGGER.error(output)
129             raise OSError
130   
131 def find_s_dir(p, cat):
132     """
133     Try to get ${S} by determining what directories were unpacked
134
135     @param p: portage ${P}
136     @type p: string
137
138     @param cat: valid portage category
139     @type cat: string
140
141     @returns: string with directory name if detected, empty string
142               if S=WORKDIR, None if couldn't find S
143     
144     
145     """
146
147     workdir = get_workdir(p, cat)
148     files = os.listdir(workdir)
149     dirs = []
150     for unpacked in files:
151         if os.path.isdir(os.path.join(workdir, unpacked)):
152             dirs.append(unpacked)
153     if len(dirs) == 1:
154         #Only one directory, must be it.
155         return dirs[0]
156     elif not len(dirs):
157         #Unpacked in cwd
158         return ""
159     else:
160         #XXX Need to search whole tree for setup.py
161         LOGGER.error("Can't determine ${S}")
162         LOGGER.error("Unpacked multiple directories: %s" % dirs)
163  
164 def get_workdir(p, cat):
165     """
166     Return WORKDIR
167
168     @param p: portage ${P}
169     @type p: string
170
171     @param cat: valid portage category
172     @type cat: string
173
174     @return: string of portage_tmpdir/cp
175     """
176
177     return '%s/portage/%s/%s/work' % (get_portage_tmpdir(), cat, p)
178
179 def get_portdir_overlay():
180     """Return PORTDIR_OVERLAY from /etc/make.conf"""
181     return ENV['PORTDIR_OVERLAY'].split(" ")[0]
182
183 def get_portage_tmpdir():
184     """Return PORTAGE_TMPDIR from /etc/make.conf"""
185     return ENV["PORTAGE_TMPDIR"]
186
187 def get_portdir():
188     """Return PORTDIR from /etc/make.conf"""
189     return ENV["PORTDIR"]
190     
191 def get_keyword():
192     """Return first ACCEPT_KEYWORDS from /etc/make.conf"""
193     #Choose the first arch they have, in case of multiples.
194     
195     try:
196         arch = ENV["ACCEPT_KEYWORDS"].split(' ')[0]
197     except KeyError:
198         self.logger.error("No ACCEPT_KEYWORDS found, using ~x86")
199         arch = '~x86'
200
201     #New ebuilds must be ~arch
202
203     if not arch.startswith('~'):
204         arch = "~%s" % arch
205     return arch
206
207 def make_overlay_dir(category, pn, overlay):
208     """
209     Create directory(s) in overlay for ebuild
210     
211     @param category: valid portage category
212     @type category: string
213
214     @param pn: portage ${PN}
215     @type pn: string
216
217     @param overlay: portage overlay directory
218     @type overlay: string
219
220     @return: string of full directory name
221
222     """
223
224     ebuild_dir = os.path.join(overlay, category, pn)
225     if not os.path.isdir(ebuild_dir):
226         try:
227             os.makedirs(ebuild_dir)
228         except OSError, err:
229             #XXX Use logger
230             LOGGER.error(err)
231             sys.exit(2)
232     return ebuild_dir
233
234
235 def find_egg_info_dir(root):
236     """
237     Locate all files matching supplied filename pattern in and below
238     supplied root directory.
239     """
240     for path, dirs, files in os.walk(os.path.abspath(root)):
241         for this_dir in dirs:
242             if this_dir.endswith(".egg-info"):
243                 return os.path.normpath(os.path.join(path, this_dir, ".."))
244
245 #Unused as of now. Could be used to find setup.py
246 #def find_files(pattern, root):
247 #    """
248 #    Locate all files matching supplied filename pattern in and below
249 #    supplied root directory.
250 #    """
251 #    for path, dirs, files in os.walk(os.path.abspath(root)):
252 #        for filename in fnmatch.filter(dirs, pattern):
253 #            yield os.path.join(path, filename)