2 # pylint: disable-msg=C0301,W0613,W0612,C0103,E0611,W0511
10 Command-line code for g-pypi
19 from pkg_resources import Requirement
22 from portage import exception as portage_exception
25 from portage import portage_exception
27 from yolk.pypi import CheeseShop
28 from yolk.yolklib import get_highest_version
29 from yolk.setuptools_support import get_download_uri
30 from g_pypi.config import MyConfig
31 from g_pypi.ebuild import Ebuild
32 from g_pypi.portage_utils import ebuild_exists
33 from g_pypi.__init__ import __version__ as VERSION
36 __docformat__ = 'restructuredtext'
37 __revision__ = '$Revision: 215 $'[11:-1].strip()
45 Filter stdout or stderr from specific modules
46 So far this is just used for pkg_resources
49 def __init__(self, stream, modulenames):
52 self.modulenames = modulenames
54 def __getattr__(self, attribute):
55 if not self.__dict__.has_key(attribute) or attribute == '__doc__':
56 return getattr(self.stdout, attribute)
57 return self.__dict__[attribute]
59 def write(self, inline):
61 Write a line to stdout if it isn't in a blacklist
63 Try to get the name of the calling module to see if we want
64 to filter it. If there is no calling module, use current
65 frame in case there's a traceback before there is any calling module
67 frame = inspect.currentframe().f_back
69 mod = frame.f_globals.get('__name__')
71 mod = sys._getframe(0).f_globals.get('__name__')
72 if not mod in self.modulenames:
73 self.stdout.write(inline)
75 def writelines(self, inline):
76 """Write multiple lines"""
84 Main class for command-line interface
87 def __init__(self, package_name, version, options, logger):
89 @param package_name: case-insensitive package name
90 @type package_name: string
92 @param version: package version
95 @param options: command-line options
96 @type options: OptParser config object
98 @param logger: message logger
99 @type logger: logger object
102 self.package_name = package_name
103 self.version = version
104 self. options = options
106 self.tree = [(package_name, version)]
107 self.pypi = CheeseShop()
108 self.create_ebuilds()
110 def raise_error(self, msg):
112 Cleanup, print error message and raise GPyPiErro
114 @param msg: Error message
118 #XXX: Call function to do 'ebuild pkg-ver.ebuild clean' etc.
119 #to clean up unpacked ebuilds
121 self.logger.error("Error: " + msg)
124 def create_ebuilds(self):
126 Create ebuild for given package_name and any ebuilds for dependencies
127 if needed. If no version is given we use the highest available.
129 #Create first ebuild then turn off overwrite in case a dependency
130 #ebuild already exists
131 #self.logger.debug("Creating dep tree...")
132 while len(self.tree):
133 (project_name, version) = self.tree.pop(0)
134 #self.logger.debug(self.tree)
135 #self.logger.debug("%s %s" % (project_name, version))
136 self.package_name = project_name
137 self.version = version
138 requires = self.do_ebuild()
139 #print "REQUIRES", requires
142 if self.options.no_deps or ebuild_exists("dev-python/%s" % req.project_name.lower()):
143 if not self.options.no_deps:
144 self.logger.info("Skipping dependency (exists): %s" % req.project_name)
146 self.add_dep(req.project_name)
147 self.options.overwrite = False
149 def add_dep(self, project_name):
153 for deps in self.tree:
156 if project_name not in pkgs:
157 self.tree.append((project_name, None))
158 #self.logger.info("Dependency needed: %s" % project_name)
160 def url_from_pypi(self):
162 Query PyPI for package's download URL
164 @returns: source URL string
168 return self.pypi.get_download_urls(self.package_name, self.version, pkg_type="source")[0]
172 def find_uri(self, method="setuptools"):
174 Returns download URI for package
175 If no package version was given it returns highest available
176 Setuptools should find anything xml-rpc can and more.
178 @param method: download method can be 'xml-rpc', 'setuptools', or 'all'
181 @returns download_url string
185 if method == "all" or method == "xml-rpc":
186 download_url = self.url_from_pypi()
188 if (method == "all" or method == "setuptools") and not download_url:
189 #Sometimes setuptools can find a package URI if PyPI doesn't have it
190 download_url = self.uri_from_setuptools()
193 def get_uri(self, svn=False):
195 Attempt to find a package's download URI
197 @returns: download_url string
200 download_url = self.find_uri()
203 self.raise_error("Can't find SRC_URI for '%s'." % self.package_name)
205 self.logger.debug("Package URI: %s " % download_url)
208 def uri_from_setuptools(self):
210 Use setuptools to find a package's URI
214 req = Requirement.parse(self.package_name)
216 self.raise_error("The package seems to have a ridiculous name or version, can't proceed.")
218 if self.options.subversion:
219 src_uri = get_download_uri(self.package_name, "dev", "source")
221 src_uri = get_download_uri(self.package_name, self.version, "source")
223 self.raise_error("The package has no source URI available.")
226 def verify_pkgver(self):
228 Query PyPI to make sure we have correct case for package name
234 Get SRC_URI using PyPI and attempt to create ebuild
236 @returns: tuple with exit code and pkg_resources requirement
239 #Get proper case for project name:
240 (package_name, versions) = self.pypi.query_versions_pypi(self.package_name)
241 if package_name != self.package_name:
242 self.package_name = package_name
245 if self.version and (self.version not in versions):
246 self.logger.error("Can't find package for version:'%s'." % self.version)
249 self.version = get_highest_version(versions)
251 download_url = self.get_uri()
253 ebuild = Ebuild(self.package_name, self.version, download_url)
254 except portage_exception.InvalidVersionString:
255 self.logger.error("Can't determine PV, use -v to set it: %s-%s" % \
256 (self.package_name, self.version))
258 except portage_exception.InvalidPackageName:
259 self.logger.error("Can't determine PN, use -n to set it: %s-%s" % \
260 (self.package_name, self.version))
263 ebuild.set_metadata(self.query_metadata())
266 if self.options.pretend:
268 ebuild.print_ebuild()
270 return ebuild.create_ebuild()
272 def query_metadata(self):
274 Get package metadata from PyPI
276 @returns: metadata text
281 return self.pypi.release_data(self.package_name, self.version)
283 (pn, vers) = self.pypi.query_versions_pypi(self.package_name)
284 return self.pypi.release_data(self.package_name, get_highest_version(vers))
286 def parse_pkg_ver(package_spec):
288 Return tuple with package_name and version from CLI args
290 @param package_spec: pkg_resources package spec
291 @type package_spec: string
293 @returns: tupe with pkg_name and version
297 arg_str = ("").join(package_spec)
298 if "==" not in arg_str:
299 #No version specified
300 package_name = arg_str
303 (package_name, version) = arg_str.split("==")
304 package_name = package_name.strip()
305 version = version.strip()
306 return (package_name, version)
310 Print g-pypi's version
312 print "g-pypi version %s (rev. %s)" % (VERSION, __revision__)
315 """Parse command-line options and do it."""
317 usage = "usage: %prog [options] <package_name[==version]>"
318 opt_parser = optparse.OptionParser(usage=usage)
320 opt_parser.add_option("-p", "--pretend", action='store_true', dest=
321 "pretend", default=False, help=
322 "Print ebuild to stdout, don't write ebuild file, \
323 don't download SRC_URI.")
325 opt_parser.add_option("-o", "--overwrite", action='store_true', dest=
326 "overwrite", default=False, help=
327 "Overwrite existing ebuild.")
329 opt_parser.add_option("--no-deps", action='store_true', dest=
330 "no_deps", default=False, help=
331 "Don't create ebuilds for any needed dependencies.")
333 opt_parser.add_option("-c", "--portage-category", action='store', dest=
334 "category", default="dev-python", help=
335 "Specify category to use when creating ebuild. Default is dev-python")
337 opt_parser.add_option("-n", "--PN", action='store', dest=
338 "pn", default=False, help=
339 "Specify PN to use when naming ebuild.")
341 opt_parser.add_option("-v", "--PV", action='store', dest=
342 "pv", default=False, help=
343 "Specify PV to use when naming ebuild.")
345 opt_parser.add_option("--MY_PV", action='store', dest=
346 "my_pv", default=False, help=
349 opt_parser.add_option("--MY_PN", action='store', dest=
350 "my_pn", default=False, help=
353 opt_parser.add_option("--MY_P", action='store', dest=
354 "my_p", default=False, help=
357 opt_parser.add_option("--format", action='store', dest=
358 "format", default=None, help=
359 "Format when printing to stdout: ansi, html, bbcode, or none")
360 opt_parser.add_option("-s", "--subversion", action='store_true', dest=
361 "subversion", default=False, help=
362 "Create live subversion ebuild if repo is available.")
364 opt_parser.add_option("-V", "--verbose", action='store_true', dest=
365 "verbose", default=False, help=
367 opt_parser.add_option("-q", "--quiet", action='store_true', dest=
368 "quiet", default=False, help=
371 opt_parser.add_option("-d", "--debug", action='store_true', dest=
372 "debug", default=False, help=
373 "Show debug information.")
376 opt_parser.add_option("--version", action='store_true', dest=
377 "version", default=False, help=
378 "Show g-pypi version and exit.")
380 (options, package_spec) = opt_parser.parse_args()
385 #Turn off all output from the pkg_resources module by default
386 sys.stdout = StdOut(sys.stdout, ['distutils.log'])
387 sys.stderr = StdOut(sys.stderr, ['distutils.log'])
390 config.set_options(options)
392 logger = config.get_logger()
395 opt_parser.print_help()
396 logger.error("\nError: You need to specify a package name at least.")
398 (package_name, version) = parse_pkg_ver(package_spec)
399 gpypi = GPyPI(package_name, version, options, logger)
401 if __name__ == "__main__":