def create(self, ebuild_path=None): """Write ebuild and update it after unpacking and examining ${S}""" # Need to write the ebuild first so we can unpack it and check for $S if ebuild_path: self.ebuild_path = ebuild_path if self.write(overwrite=self.options.overwrite): if self.unpacked_dir is None: PortageUtils.unpack_ebuild(self.ebuild_path) self.update_with_s() self.post_unpack() # Write ebuild again after unpacking and adding ${S} self.write(overwrite=True) if self.options.command != 'echo': # apply workflows Metadata(self.options, os.path.dirname(self.ebuild_path))() Echangelog(self.options, os.path.dirname(self.ebuild_path))() Repoman(self.options, os.path.dirname(self.ebuild_path))() log.info("Your ebuild is here: " + self.ebuild_path) # TODO: If ebuild already exists, we don't unpack and get dependencies # because they must exist. # We should add an option to force creating dependencies or should # overwrite be used? return self.requires
def update_with_s(self): """Add ${:term:`S`} to ebuild if needed.""" log.debug("Trying to determine ${S}, unpacking...") if self.unpacked_dir is None: unpacked_dir = PortageUtils.find_s_dir(self['p'], self.options.category) if unpacked_dir == "": self["s"] = "${WORKDIR}" self.unpacked_dir = os.path.join(PortageUtils.get_workdir(self['p'], self.options.category), unpacked_dir) if self.get('my_p', None): self["s"] = "${WORKDIR}/${MY_P}" else: pass # ${WORKDIR}/${P}
def write(self, overwrite=False): """Write ebuild file :param overwrite: Overwrite ebuild if it already exists. :type overwrite: bool """ # get ebuild path if not self.ebuild_path: overlay_name = self.options.overlay overlay_path = PortageUtils.get_overlay_path(overlay_name) self.ebuild_path = self.find_path_to_ebuild(overlay_path) log.debug('Ebuild.write: build_path(%s)', self.ebuild_path) # see if we want to overwrite if (not self.options.command == 'echo') and os.path.exists(self.ebuild_path) and not overwrite: log.warn("Ebuild exists (use -o to overwrite), skipping: %s" % self.ebuild_path) return False # write ebuild out = open(self.ebuild_path, "w") try: out.write(self.render()) finally: out.close() return True
def find_path_to_ebuild(self, overlay_path): """""" ebuild_dir = PortageUtils.make_ebuild_dir(self.options.category, self['pn'], overlay_path) if not os.path.isdir(ebuild_dir or ""): raise GPyPiCouldNotCreateEbuildPath('Couldn not create ebuild directory %s' % ebuild_dir) return os.path.join(ebuild_dir, self['p'] + ".ebuild")
def sync(self): """""" pypi = CheeseShop() for package in pypi.list_packages(): (pn, vers) = pypi.query_versions_pypi(package) for version in vers: # TODO: parse_* will not return anything for correct atoms atom = Enamer.construct_atom(Enamer.parse_pn(pn)[0], self.config.category, Enamer.parse_pv(version[0])) # we skip existing ebuilds if PortageUtils.ebuild_exists(atom): continue try: url = pypi.get_download_urls(pn, version)[0] # TODO: use setuptools way also except IndexError: log.warn('Skipping %s, no download url', atom) else: try: self.config.configs['argparse']['uri'] = url self.config.configs['argparse']['up_pn'] = pn self.config.configs['argparse']['up_pv'] = version gpypi = GPyPI(pn, version, self.config) gpypi.create_ebuilds() except KeyboardInterrupt: raise except: log.exception('Unexpected error occured during ebuild creation:')
def sync(self): """""" pypi = CheeseShop() for package in pypi.list_packages(): (pn, vers) = pypi.query_versions_pypi(package) for version in vers: # TODO: parse_* will not return anything for correct atoms atom = Enamer.construct_atom( Enamer.parse_pn(pn)[0], self.config.category, Enamer.parse_pv(version[0])) # we skip existing ebuilds if PortageUtils.ebuild_exists(atom): continue try: url = pypi.get_download_urls(pn, version)[0] # TODO: use setuptools way also except IndexError: log.warn('Skipping %s, no download url', atom) else: try: self.config.configs['argparse']['uri'] = url self.config.configs['argparse']['up_pn'] = pn self.config.configs['argparse']['up_pv'] = version gpypi = GPyPI(pn, version, self.config) gpypi.create_ebuilds() except KeyboardInterrupt: raise except: log.exception( 'Unexpected error occured during ebuild creation:')
def __init__(self, options): self.setup_keywords = {} self.metadata = {} self.unpacked_dir = None self.ebuild_path = None self.requires = set() self.has_tests = None self.options = options # init stuff self.env = Environment( loader=PackageLoader(self.EBUILD_TEMPLATE_PACKAGE, 'templates'), trim_blocks=True) self.template = self.env.get_template(self.EBUILD_TEMPLATE) # Variables that will be passed to the Jinja template d = { 'python_modname': None, 'rdepend': set(), 'depend': set(), 'use': set(), 'warnings': set(), 'slot': '0', 's': '', 'tests_method': '', 'inherit': set(['distutils']), 'gpypi_version': __version__, 'year': date.today().year, 'gentoo_keywords': PortageUtils.get_keyword(), } super(Ebuild, self).__init__(d) # TODO: use Config rather self.options.configs['setup_py'] = self self.set_ebuild_vars()
def is_valid_portage_license(cls, license): """ Check if license string matches a valid one in ${PORTDIR}/licenses :param license: Portage license name :type license: string :returns: True if license is valid/exists :rtype: bool **Example:** >>> Enamer.is_valid_portage_license("KQEMU") True >>> Enamer.is_valid_portage_license("foobar") False """ return os.path.exists(os.path.join(PortageUtils.get_portdir(), "licenses", license))
def is_valid_portage_license(cls, license): """ Check if license string matches a valid one in ${PORTDIR}/licenses :param license: Portage license name :type license: string :returns: True if license is valid/exists :rtype: bool **Example:** >>> Enamer.is_valid_portage_license("KQEMU") True >>> Enamer.is_valid_portage_license("foobar") False """ return os.path.exists( os.path.join(PortageUtils.get_portdir(), "licenses", license))
def get_vars(cls, uri, up_pn, up_pv, pn="", pv="", my_pn=None, my_pv=None): """ Determine P* and MY_* ebuild variables :param uri: HTTP URL to download link for a package :param up_pn: Upstream package name :param up_pv: Upstream package version :param pn: Converted package name :param pv: Converted package version :param my_pn: Bash substitution for upstream package name :param my_pv: Bash substitution for upstream package version :type uri: string :type up_pn: string :type up_pv: string :type pn: string :type pv: string :type my_pn: list :type my_pv: list :raises: :exc:`GPyPiInvalidAtom` if version/name could not be parsed correctly :returns: * pn -- Ebuild Gentoo package name * pv -- Ebuild Gentoo package version * p -- Ebuild Gentoo package name + version * my_p -- Upstream whole package name (name + version) * my_pn -- Bash substitution for upstream package name * my_pv -- Bash substitution for upstream package version * my_p_raw -- my_p extracted from SRC_URI * src_uri -- Ebuild SRC_URI with MY_P variable :rtype: dict **Examples of what it can detect/convert** (see test_enamer.py for full capabilities) http://www.foo.com/pkgfoo-1.0.tbz2 * PN="pkgfoo" * PV="1.0" * Ebuild name: pkgfoo-1.0.ebuild * SRC_URI="http://www.foo.com/${P}.tbz2" http://www.foo.com/PkgFoo-1.0.tbz2 * PN="pkgfoo" * PV="1.0" * Ebuild name: pkgfoo-1.0.ebuild * MY_P="PkgFoo-${PV}" * SRC_URI="http://www.foo.com/${MY_P}.tbz2" http://www.foo.com/pkgfoo_1.0.tbz2 * PN="pkgfoo" * PV="1.0" * Ebuild name: pkgfoo-1.0.ebuild * MY_P="${PN}_${PV}" * SRC_URI="http://www.foo.com/${MY_P}.tbz2" http://www.foo.com/PKGFOO_1.0.tbz2 * PN="pkgfoo" * PV="1.0" * Ebuild name: pkgfoo-1.0.ebuild * MY_P="PKGFOO_${PV}" * SRC_URI="http://www.foo.com/${MY_P}.tbz2" http://www.foo.com/pkg-foo-1.0_beta1.tbz2 * PN="pkg-foo" * PV="1.0_beta1" * Ebuild name: pkg-foo-1.0_beta1.ebuild * SRC_URI="http://www.foo.com/${P}.tbz2" **Example:** >>> d = Enamer.get_vars('http://www.foo.com/pkg.foo-1.0b1.tbz2', 'pkg.foo', '1.0b1') >>> assert d['pn'] == 'pkg-foo' >>> assert d['pv'] == '1.0_beta1' >>> assert d['p'] == 'pkg-foo-1.0_beta1' >>> assert d['my_pv'] == ['${PV/_beta/b}'] >>> assert d['my_pn'] == ['${PN/-/.}'] >>> assert d['my_p'] == '${MY_PN}-${MY_PV}' >>> assert d['my_p_raw'] == 'pkg.foo-1.0b1' >>> assert d['src_uri'] == 'http://www.foo.com/${MY_P}.tbz2' >>> assert len(d) == 8 """ log.debug("get_vars: %r" % locals()) my_pn = my_pn or [] my_pv = my_pv or [] my_p = "" INVALID_VERSION = False uri = cls.sanitize_uri(uri) # Test for PV with -r1234 suffix # Portage uses -r suffixes for it's own ebuild revisions so # We have to convert it to _pre or _alpha etc. tail = up_pv.split("-")[-1][0] if tail == "r": INVALID_VERSION = True log.debug("We have a version with a -r### suffix") portage_atom = "=dev-python/%s-%s" % (up_pn, up_pv) if not PortageUtils.is_valid_atom(portage_atom): INVALID_VERSION = True log.debug("%s is not valid portage atom", portage_atom) if INVALID_VERSION: pv, my_pv = cls.parse_pv(up_pv, pv, my_pv) pn, my_pn = cls.parse_pn(up_pn, pn, my_pn) # No PN or PV given on command-line, try upstream's name/version if not pn and not pv: log.debug("pn and pv not given, trying upstream") # Try to determine pn and pv from uri parts = cls.split_uri(uri) if parts: # pylint: disable-msg=W0612 # unused variable 'rev' # The 'rev' is never used because these are # new ebuilds being created. pn, pv, rev = parts else: pn = up_pn pv = up_pv # Try upstream's version if it could't be determined from uri or cli option elif pn and not pv: pv = up_pv elif not pn and pv: pn = up_pn p = "%s-%s" % (pn, pv) log.debug("get_vars: p(%s)", p) # Make sure we have a valid P atom = "=dev-python/%s-%s" % (pn, pv) if not PortageUtils.is_valid_atom(atom): log.debug(locals()) raise GPyPiInvalidAtom("%s is not a valid portage atom. " "We could not determine it from upstream pn(%s) and pv(%s)." % (atom, up_pn, up_pv)) # Check if we need to use MY_P based on src's uri src_uri, my_p_raw = cls.get_my_p(uri) log.debug("getting SRC_URI with ${MY_P}: %s %s %s", src_uri, my_p, my_p_raw) if my_p_raw == p: my_pn = [] my_p_raw = '' src_uri = src_uri.replace("${MY_P}", "${P}") elif not (my_pn or my_pv): src_uri, my_p, my_pn, my_p_raw = cls._get_src_uri(uri, my_pn) log.debug("getting SRC_URI: %s %s %s", src_uri, my_p, my_p_raw) log.debug("before MY_P guessing: %r", locals()) if my_pn or my_pv: my_p = "%s-%s" % ("${MY_PN}" if my_pn else "${PN}", "${MY_PV}" if my_pv else "${PV}") return { 'pn': pn, 'pv': pv, 'p': p, 'my_p': my_p, 'my_pn': my_pn, 'my_pv': my_pv, 'my_p_raw': my_p_raw, 'src_uri': src_uri, }
def get_dependencies(self, vanilla_requirements, if_use=None): """ Generate :term:`DEPEND` / :term:`RDEPEND` strings. :param vanilla_requirements: **require_\*** contents from `setup.py` :param if_use: :term:`USE` flag that must be set to download dependencies :type vanilla_requirements: string or list :type if_use: string """ # TODO: DOC: steps to acquire deps requirements = parse_requirements(vanilla_requirements) for req in requirements: extras = req.extras # TODO: extend configuration to support callable configs # TODO: pass metadata from the project_name #category = Enamer.convert_category(req.project_name, {}) category = self.options.category pn = Enamer.parse_pn(req.project_name)[0] or req.project_name # add setuptools dependency for later dependency generating self.add_setuptools_depend(req) log.debug('get_dependencies: pn(%s) category(%s)', pn, category) if not len(req.specs): # No version of requirement was specified so we only add # dev-python/pn self.add_rdepend(Enamer.construct_atom(pn, category, uses=extras, if_use=if_use)) else: comparator, ver = req.specs[0] ver = Enamer.parse_pv(ver)[0] or ver log.debug('get_dependencies: pv(%s)' % ver) if len(req.specs) > 1: # Some packages have more than one comparator, i.e. cherrypy # for turbogears has cherrpy>=2.2,<3.0 which would translate # to portage's =dev-python/cherrypy-2.2* comparator1, ver1 = req.specs[0] comparator2, ver2 = req.specs[1] # TODO: this is a total mess, refactor if comparator1.startswith(">") and \ comparator2.startswith("<"): # we set blocker for <* self.add_rdepend(Enamer.construct_atom(pn, category, ver1, comparator1, uses=extras, if_use=if_use)) self.add_rdepend(Enamer.construct_atom(pn, category, ver2, "!" + comparator2, uses=extras, if_use=if_use)) elif comparator2.startswith(">") and \ comparator1.startswith("<"): self.add_rdepend(Enamer.construct_atom(pn, category, ver2, comparator2, uses=extras, if_use=if_use)) self.add_rdepend(Enamer.construct_atom(pn, category, ver1, "!" + comparator1, uses=extras, if_use=if_use)) else: self['warnings'].add("Couldn't resolve requirements. " "You will need to make sure the RDEPEND for %s is " "correct." % req) self.add_rdepend(Enamer.construct_atom(pn, category, uses=extras, if_use=if_use)) self['warnings'].add("Could not determine dependency: %s" % req) break # Requirement.specs is a list of (comparator,version) tuples if comparator == "==": comparator = "=" atom = Enamer.construct_atom(pn, category, ver, comparator, uses=extras) if PortageUtils.is_valid_atom(atom): self.add_rdepend(Enamer.construct_atom(pn, category, ver, comparator, uses=extras, if_use=if_use)) else: log.debug("Invalid PV in dependency: (Requirement %s) %s", req, atom) installed_pv = PortageUtils.get_installed_ver(Enamer.\ construct_atom(pn, category, uses=extras, if_use=if_use)) if installed_pv: # If we have it installed, use >= installed version self.add_rdepend(Enamer.construct_atom(pn, category, installed_pv, '>=', uses=extras, if_use=if_use)) else: # If package has invalid version and we don't have # an ebuild in portage, just add PN to DEPEND, no # version. self['warnings'].add("Could not determine dependency: %s" % req) self.add_rdepend(Enamer.construct_atom(pn, category, uses=extras, if_use=if_use))
def get_vars(cls, uri, up_pn, up_pv, pn="", pv="", my_pn=None, my_pv=None): """ Determine P* and MY_* ebuild variables :param uri: HTTP URL to download link for a package :param up_pn: Upstream package name :param up_pv: Upstream package version :param pn: Converted package name :param pv: Converted package version :param my_pn: Bash substitution for upstream package name :param my_pv: Bash substitution for upstream package version :type uri: string :type up_pn: string :type up_pv: string :type pn: string :type pv: string :type my_pn: list :type my_pv: list :raises: :exc:`GPyPiInvalidAtom` if version/name could not be parsed correctly :returns: * pn -- Ebuild Gentoo package name * pv -- Ebuild Gentoo package version * p -- Ebuild Gentoo package name + version * my_p -- Upstream whole package name (name + version) * my_pn -- Bash substitution for upstream package name * my_pv -- Bash substitution for upstream package version * my_p_raw -- my_p extracted from SRC_URI * src_uri -- Ebuild SRC_URI with MY_P variable :rtype: dict **Examples of what it can detect/convert** (see test_enamer.py for full capabilities) http://www.foo.com/pkgfoo-1.0.tbz2 * PN="pkgfoo" * PV="1.0" * Ebuild name: pkgfoo-1.0.ebuild * SRC_URI="http://www.foo.com/${P}.tbz2" http://www.foo.com/PkgFoo-1.0.tbz2 * PN="pkgfoo" * PV="1.0" * Ebuild name: pkgfoo-1.0.ebuild * MY_P="PkgFoo-${PV}" * SRC_URI="http://www.foo.com/${MY_P}.tbz2" http://www.foo.com/pkgfoo_1.0.tbz2 * PN="pkgfoo" * PV="1.0" * Ebuild name: pkgfoo-1.0.ebuild * MY_P="${PN}_${PV}" * SRC_URI="http://www.foo.com/${MY_P}.tbz2" http://www.foo.com/PKGFOO_1.0.tbz2 * PN="pkgfoo" * PV="1.0" * Ebuild name: pkgfoo-1.0.ebuild * MY_P="PKGFOO_${PV}" * SRC_URI="http://www.foo.com/${MY_P}.tbz2" http://www.foo.com/pkg-foo-1.0_beta1.tbz2 * PN="pkg-foo" * PV="1.0_beta1" * Ebuild name: pkg-foo-1.0_beta1.ebuild * SRC_URI="http://www.foo.com/${P}.tbz2" **Example:** >>> d = Enamer.get_vars('http://www.foo.com/pkg.foo-1.0b1.tbz2', 'pkg.foo', '1.0b1') >>> assert d['pn'] == 'pkg-foo' >>> assert d['pv'] == '1.0_beta1' >>> assert d['p'] == 'pkg-foo-1.0_beta1' >>> assert d['my_pv'] == ['${PV/_beta/b}'] >>> assert d['my_pn'] == ['${PN/-/.}'] >>> assert d['my_p'] == '${MY_PN}-${MY_PV}' >>> assert d['my_p_raw'] == 'pkg.foo-1.0b1' >>> assert d['src_uri'] == 'http://www.foo.com/${MY_P}.tbz2' >>> assert len(d) == 8 """ log.debug("get_vars: %r" % locals()) my_pn = my_pn or [] my_pv = my_pv or [] my_p = "" INVALID_VERSION = False uri = cls.sanitize_uri(uri) # Test for PV with -r1234 suffix # Portage uses -r suffixes for it's own ebuild revisions so # We have to convert it to _pre or _alpha etc. tail = up_pv.split("-")[-1][0] if tail == "r": INVALID_VERSION = True log.debug("We have a version with a -r### suffix") portage_atom = "=dev-python/%s-%s" % (up_pn, up_pv) if not PortageUtils.is_valid_atom(portage_atom): INVALID_VERSION = True log.debug("%s is not valid portage atom", portage_atom) if INVALID_VERSION: pv, my_pv = cls.parse_pv(up_pv, pv, my_pv) pn, my_pn = cls.parse_pn(up_pn, pn, my_pn) # No PN or PV given on command-line, try upstream's name/version if not pn and not pv: log.debug("pn and pv not given, trying upstream") # Try to determine pn and pv from uri parts = cls.split_uri(uri) if parts: # pylint: disable-msg=W0612 # unused variable 'rev' # The 'rev' is never used because these are # new ebuilds being created. pn, pv, rev = parts else: pn = up_pn pv = up_pv # Try upstream's version if it could't be determined from uri or cli option elif pn and not pv: pv = up_pv elif not pn and pv: pn = up_pn p = "%s-%s" % (pn, pv) log.debug("get_vars: p(%s)", p) # Make sure we have a valid P atom = "=dev-python/%s-%s" % (pn, pv) if not PortageUtils.is_valid_atom(atom): log.debug(locals()) raise GPyPiInvalidAtom( "%s is not a valid portage atom. " "We could not determine it from upstream pn(%s) and pv(%s)." % (atom, up_pn, up_pv)) # Check if we need to use MY_P based on src's uri src_uri, my_p_raw = cls.get_my_p(uri) log.debug("getting SRC_URI with ${MY_P}: %s %s %s", src_uri, my_p, my_p_raw) if my_p_raw == p: my_pn = [] my_p_raw = '' src_uri = src_uri.replace("${MY_P}", "${P}") elif not (my_pn or my_pv): src_uri, my_p, my_pn, my_p_raw = cls._get_src_uri(uri, my_pn) log.debug("getting SRC_URI: %s %s %s", src_uri, my_p, my_p_raw) log.debug("before MY_P guessing: %r", locals()) if my_pn or my_pv: my_p = "%s-%s" % ("${MY_PN}" if my_pn else "${PN}", "${MY_PV}" if my_pv else "${PV}") return { 'pn': pn, 'pv': pv, 'p': p, 'my_p': my_p, 'my_pn': my_pn, 'my_pv': my_pv, 'my_p_raw': my_p_raw, 'src_uri': src_uri, }