/** * Copyright (c) 2009--2015 Red Hat, Inc. * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or * implied, including the implied warranties of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 * along with this software; if not, see * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. * * Red Hat trademarks are not licensed under GPLv2. No permission is * granted to use or replicate Red Hat trademarks that are incorporated * in this software or its documentation. */ package com.redhat.rhn.taskomatic.task.repomd; import com.redhat.rhn.common.conf.ConfigDefaults; import com.redhat.rhn.domain.channel.Channel; import com.redhat.rhn.frontend.dto.PackageCapabilityDto; import com.redhat.rhn.frontend.dto.PackageDto; import com.redhat.rhn.manager.rhnpackage.PackageManager; import com.redhat.rhn.manager.task.TaskManager; import com.redhat.rhn.taskomatic.task.TaskConstants; import org.apache.commons.lang.StringUtils; import org.xml.sax.SAXException; import java.io.ByteArrayOutputStream; import java.io.Writer; import java.util.Collection; import java.util.HashMap; import java.util.Map; /** * Primary.xml writer class * @version $Rev $ * */ public class PrimaryXmlWriter extends RepomdWriter { /** * * @param writer The writer object for primary xml */ public PrimaryXmlWriter(Writer writer) { super(writer, false); } /** * end xml metadata generation */ @Override public void end() { try { handler.endElement("metadata"); handler.endDocument(); } catch (SAXException e) { throw new RepomdRuntimeException(e); } } /** * Start xml metadata generation * @param channel channel data */ @Override public void begin(Channel channel) { SimpleAttributesImpl attr = new SimpleAttributesImpl(); attr.addAttribute("xmlns", "http://linux.duke.edu/metadata/common"); attr.addAttribute("xmlns:rpm", "http://linux.duke.edu/metadata/rpm"); attr.addAttribute("packages", Integer.toString(channel.getPackageCount())); try { handler.startElement("metadata", attr); } catch (SAXException e) { throw new RepomdRuntimeException(e); } } /** * * @param pkgDto pkg info to add to xml */ public void addPackage(PackageDto pkgDto) { try { String xml = pkgDto.getPrimaryXml(); if (ConfigDefaults.get().useDBRepodata() && !StringUtils.isEmpty(xml)) { if (xml != null) { handler.addCharacters(xml); return; } } ByteArrayOutputStream st = new ByteArrayOutputStream(); SimpleContentHandler tmpHandler = getTemporaryHandler(st); SimpleAttributesImpl attr = new SimpleAttributesImpl(); attr.addAttribute("type", "rpm"); tmpHandler.startDocument(); tmpHandler.startElement("package", attr); addBasicPackageDetails(pkgDto, tmpHandler); addPackageFormatDetails(pkgDto, tmpHandler); tmpHandler.endElement("package"); tmpHandler.endDocument(); String pkg = st.toString(); PackageManager.updateRepoPrimary(pkgDto.getId(), pkg); handler.addCharacters(pkg); } catch (SAXException e) { throw new RepomdRuntimeException(e); } } /** * * @param pkgDto pkg info to add to xml * @throws SAXException sax exception */ private void addPackageFormatDetails(PackageDto pkgDto, SimpleContentHandler localHandler) throws SAXException { long pkgId = pkgDto.getId().longValue(); localHandler.startElement("format"); localHandler.addElementWithCharacters("rpm:license", sanitize(pkgId, pkgDto .getCopyright())); localHandler.addElementWithCharacters("rpm:vendor", sanitize(pkgId, pkgDto .getVendor())); localHandler.addElementWithCharacters("rpm:group", sanitize(pkgId, pkgDto .getPackageGroupName())); localHandler.addElementWithCharacters("rpm:buildhost", sanitize(pkgId, pkgDto.getBuildHost())); localHandler.addElementWithCharacters("rpm:sourcerpm", sanitize(pkgId, pkgDto.getSourceRpm())); SimpleAttributesImpl attr = new SimpleAttributesImpl(); attr.addAttribute("start", pkgDto.getHeaderStart().toString()); attr.addAttribute("end", pkgDto.getHeaderEnd().toString()); localHandler.startElement("rpm:header-range", attr); localHandler.endElement("rpm:header-range"); addPackagePrcoData(pkgDto, localHandler); addEssentialPackageFiles(pkgId, localHandler); localHandler.endElement("format"); } /** * * @param pkgDto pkg info to add to xml * @throws SAXException sax exception */ private void addBasicPackageDetails(PackageDto pkgDto, SimpleContentHandler localHandler) throws SAXException { long pkgId = pkgDto.getId().longValue(); localHandler.addElementWithCharacters("name", sanitize(pkgId, pkgDto .getName())); localHandler.addElementWithCharacters("arch", sanitize(pkgId, pkgDto .getArchLabel())); SimpleAttributesImpl attr = new SimpleAttributesImpl(); attr.addAttribute("ver", sanitize(pkgId, pkgDto.getVersion())); attr.addAttribute("rel", sanitize(pkgId, pkgDto.getRelease())); attr.addAttribute("epoch", sanitize(pkgId, getPackageEpoch(pkgDto .getEpoch()))); localHandler.startElement("version", attr); localHandler.endElement("version"); attr.clear(); attr.addAttribute("type", sanitize(pkgId, pkgDto.getChecksumType())); attr.addAttribute("pkgid", "YES"); localHandler.startElement("checksum", attr); localHandler.addCharacters(sanitize(pkgId, pkgDto.getChecksum())); localHandler.endElement("checksum"); localHandler.addElementWithCharacters("summary", sanitize(pkgId, pkgDto .getSummary())); localHandler.addElementWithCharacters("description", sanitize(pkgId, pkgDto .getDescription())); localHandler.addEmptyElement("packager"); localHandler.addEmptyElement("url"); attr.clear(); attr.addAttribute("file", Long .toString(pkgDto.getBuildTime().getTime() / 1000)); attr.addAttribute("build", Long.toString(pkgDto.getBuildTime() .getTime() / 1000)); localHandler.startElement("time", attr); localHandler.endElement("time"); attr.clear(); attr.addAttribute("package", pkgDto.getPackageSize().toString()); attr.addAttribute("archive", pkgDto.getPayloadSize().toString()); if (pkgDto.getInstalledSize() != null) { attr.addAttribute("installed", pkgDto.getInstalledSize().toString()); } else { /* set something for "installed" so anaconda doesn't die */ attr.addAttribute("installed", pkgDto.getPayloadSize().toString()); } localHandler.startElement("size", attr); localHandler.endElement("size"); String pkgFile = sanitize(pkgId, getProxyFriendlyFilename(pkgDto)); attr.clear(); attr.addAttribute("href", "getPackage/" + pkgFile); localHandler.startElement("location", attr); localHandler.endElement("location"); } /** * * @param pkgDto pkg info to add to xml * @throws SAXException */ private void addPackagePrcoData(PackageDto pkgDto, SimpleContentHandler localHandler) throws SAXException { addPackageDepData( TaskConstants.TASK_QUERY_REPOMD_GENERATOR_CAPABILITY_PROVIDES, pkgDto.getId(), "provides", localHandler); addPackageDepData( TaskConstants.TASK_QUERY_REPOMD_GENERATOR_CAPABILITY_REQUIRES, pkgDto.getId(), "requires", localHandler); addPackageDepData( TaskConstants.TASK_QUERY_REPOMD_GENERATOR_CAPABILITY_CONFLICTS, pkgDto.getId(), "conflicts", localHandler); addPackageDepData( TaskConstants.TASK_QUERY_REPOMD_GENERATOR_CAPABILITY_OBSOLETES, pkgDto.getId(), "obsoletes", localHandler); addPackageDepData( TaskConstants.TASK_QUERY_REPOMD_GENERATOR_CAPABILITY_RECOMMENDS, pkgDto.getId(), "recommends", localHandler); addPackageDepData( TaskConstants.TASK_QUERY_REPOMD_GENERATOR_CAPABILITY_SUGGESTS, pkgDto.getId(), "suggests", localHandler); addPackageDepData( TaskConstants.TASK_QUERY_REPOMD_GENERATOR_CAPABILITY_SUPPLEMENTS, pkgDto.getId(), "supplements", localHandler); addPackageDepData( TaskConstants.TASK_QUERY_REPOMD_GENERATOR_CAPABILITY_ENHANCES, pkgDto.getId(), "enhances", localHandler); } /** * * @param pkgCapIter pkg capability info * @param pkgId package Id to set * @param dep dependency info * @throws SAXException sax exception */ private void addPackageDepData(String query, Long pkgId, String dep, SimpleContentHandler localHandler) throws SAXException { Collection<PackageCapabilityDto> capabilities = TaskManager .getPackageCapabilityDtos(pkgId, query); localHandler.startElement("rpm:" + dep); for (PackageCapabilityDto capability : capabilities) { SimpleAttributesImpl attr = new SimpleAttributesImpl(); attr.addAttribute("name", sanitize(pkgId, capability.getName())); Map<String, String> evrMap = parseEvr(sanitize(pkgId, capability.getVersion())); if (evrMap.get("epoch") != null || evrMap.get("version") != null || evrMap.get("release") != null) { attr.addAttribute("flags", getSenseAsString(capability.getSense())); } if (evrMap.get("epoch") != null) { attr.addAttribute("epoch", evrMap.get("epoch")); } else if (evrMap.get("version") != null) { attr.addAttribute("epoch", "0"); } if (evrMap.get("version") != null) { attr.addAttribute("ver", evrMap.get("version")); } if (evrMap.get("release") != null) { attr.addAttribute("rel", evrMap.get("release")); } if (hasPreFlag(capability.getSense())) { attr.addAttribute("pre", "1"); } localHandler.startElement("rpm:entry", attr); localHandler.endElement("rpm:entry"); } localHandler.endElement("rpm:" + dep); } /** * * @param evr package evr info * @return package evr object */ private static Map<String, String> parseEvr(String evr) { Map<String, String> map = new HashMap<String, String>(); map.put("epoch", null); map.put("version", null); map.put("release", null); if (evr != null) { String[] parts = evr.split(":"); String vr; if (parts.length != 1) { map.put("epoch", parts[0]); vr = parts[1]; } else { vr = parts[0]; } int dash = vr.indexOf('-'); if (dash == -1) { map.put("version", vr); } else { map.put("version", vr.substring(0, dash)); map.put("release", vr.substring(dash + 1)); } } return map; } /** * * @param pkgId package Id info * @throws SAXException sax exception */ private void addEssentialPackageFiles(long pkgId, SimpleContentHandler hndlr) throws SAXException { String regex = ".*bin/.*|^/etc/.*|^/usr/lib.sendmail$"; Collection<PackageCapabilityDto> files = TaskManager .getPackageCapabilityDtos( pkgId, TaskConstants.TASK_QUERY_REPOMD_GENERATOR_CAPABILITY_FILES); for (PackageCapabilityDto file : files) { String path = sanitize(pkgId, file.getName()); if (path.matches(regex)) { hndlr.addElementWithCharacters("file", path); } } } /** * * @param pkgDto package info * @return package filename */ private String getProxyFriendlyFilename(PackageDto pkgDto) { String[] parts = StringUtils.split(pkgDto.getPath(), '/'); if (parts != null && parts.length > 0) { return parts[parts.length - 1]; } return pkgDto.getName() + "-" + pkgDto.getVersion() + "-" + pkgDto.getRelease() + "." + pkgDto.getArchLabel() + ".rpm"; } /** * @param senseIn package sense * @return a human readable representation of the sense */ private String getSenseAsString(long senseIn) { long sense = senseIn & 0xf; if (sense == 2) { return "LT"; } else if (sense == 4) { return "GT"; } else if (sense == 8) { return "EQ"; } else if (sense == 10) { return "LE"; } else { // 12 return "GE"; } } /** * Checks if a sense flag indicate a pre-requirement * * The flags that are taken into account are: * * RPMSENSE_PREREQ (1 << 6) * RPMSENSE_SCRIPT_PRE (1 << 9) * RPMSENSE_SCRIPT_POST (1 << 10) * RPMSENSE_RPMLIB (1 << 24) * * (from rpmds.h) * * @param senseIn package sense * @return true in case any of the sense flags that indicate a pre-requirement * are enabled, otherwise false. */ private boolean hasPreFlag(long senseIn) { return (senseIn & ((1 << 6) | (1 << 9) | (1 << 10) | (1 << 24))) > 0; } }