Search in sources :

Example 11 with Patch

use of org.jboss.fuse.patch.management.Patch in project fuse-karaf by jboss-fuse.

the class GitPatchManagementServiceImpl method loadPatch.

@Override
public Patch loadPatch(PatchDetailsRequest request) throws PatchException {
    File descriptor = new File(patchesDir, request.getPatchId() + ".patch");
    try {
        Patch patch = loadPatch(descriptor, true);
        if (patch == null) {
            return null;
        }
        Git repo = gitPatchRepository.findOrCreateMainGitRepository();
        List<DiffEntry> diff = null;
        if (request.isFiles() || request.isDiff()) {
            // fetch the information from git
            ObjectId commitId = repo.getRepository().resolve(patch.getManagedPatch().getCommitId());
            RevCommit commit = new RevWalk(repo.getRepository()).parseCommit(commitId);
            diff = gitPatchRepository.diff(repo, commit.getParent(0), commit);
        }
        if (request.isBundles()) {
        // it's already in PatchData
        }
        if (request.isFiles() && diff != null) {
            for (DiffEntry de : diff) {
                DiffEntry.ChangeType ct = de.getChangeType();
                String newPath = de.getNewPath();
                String oldPath = de.getOldPath();
                switch(ct) {
                    case ADD:
                        patch.getManagedPatch().getFilesAdded().add(newPath);
                        break;
                    case MODIFY:
                        patch.getManagedPatch().getFilesModified().add(newPath);
                        break;
                    case DELETE:
                        patch.getManagedPatch().getFilesRemoved().add(oldPath);
                        break;
                    default:
                        break;
                }
            }
        }
        if (request.isDiff() && diff != null) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            DiffFormatter formatter = new DiffFormatter(baos);
            formatter.setContext(4);
            formatter.setRepository(repo.getRepository());
            for (DiffEntry de : diff) {
                formatter.format(de);
            }
            formatter.flush();
            patch.getManagedPatch().setUnifiedDiff(new String(baos.toByteArray(), "UTF-8"));
        }
        return patch;
    } catch (IOException | GitAPIException e) {
        throw new PatchException(e.getMessage(), e);
    }
}
Also used : ObjectId(org.eclipse.jgit.lib.ObjectId) ByteArrayOutputStream(org.apache.commons.io.output.ByteArrayOutputStream) IOException(java.io.IOException) RevWalk(org.eclipse.jgit.revwalk.RevWalk) GitAPIException(org.eclipse.jgit.api.errors.GitAPIException) Git(org.eclipse.jgit.api.Git) PatchException(org.jboss.fuse.patch.management.PatchException) DiffFormatter(org.eclipse.jgit.diff.DiffFormatter) ZipFile(org.apache.commons.compress.archivers.zip.ZipFile) File(java.io.File) Patch(org.jboss.fuse.patch.management.Patch) ManagedPatch(org.jboss.fuse.patch.management.ManagedPatch) DiffEntry(org.eclipse.jgit.diff.DiffEntry) RevCommit(org.eclipse.jgit.revwalk.RevCommit)

Example 12 with Patch

use of org.jboss.fuse.patch.management.Patch in project fuse-karaf by jboss-fuse.

the class GitPatchManagementServiceImpl method loadPatch.

/**
 * Retrieves patch information from existing file
 * @param patchDescriptor existing file with patch descriptor (<code>*.patch</code> file)
 * @param details whether the returned {@link Patch} should contain {@link ManagedPatch} information
 * @return
 * @throws IOException
 */
private Patch loadPatch(File patchDescriptor, boolean details) throws IOException {
    Patch p = new Patch();
    if (!patchDescriptor.exists() || !patchDescriptor.isFile()) {
        return null;
    }
    PatchData data = PatchData.load(new FileInputStream(patchDescriptor));
    p.setPatchData(data);
    File patchDirectory = new File(patchesDir, FilenameUtils.getBaseName(patchDescriptor.getName()));
    if (patchDirectory.exists() && patchDirectory.isDirectory()) {
        // not every descriptor downloaded may be a ZIP file, not every patch has content
        data.setPatchDirectory(patchDirectory);
        File featureOverridesLocation = new File(patchDirectory, "org.apache.karaf.features.xml");
        if (featureOverridesLocation.isFile()) {
            // them available during all patch operations
            try {
                FeaturesProcessing featureOverrides = InternalUtils.loadFeatureProcessing(featureOverridesLocation, null);
                List<String> overrides = new LinkedList<>();
                if (featureOverrides.getFeatureReplacements().getReplacements() != null) {
                    featureOverrides.getFeatureReplacements().getReplacements().forEach(of -> overrides.add(of.getFeature().getId()));
                }
                data.setFeatureOverrides(overrides);
            } catch (Exception e) {
                Activator.log(LogService.LOG_WARNING, "Problem loading org.apache.karaf.features.xml from patch " + data.getId() + ": " + e.getMessage());
            }
        }
    }
    data.setPatchLocation(patchesDir);
    File resultFile = new File(patchesDir, FilenameUtils.getBaseName(patchDescriptor.getName()) + ".patch.result");
    if (resultFile.exists() && resultFile.isFile()) {
        PatchResult result = PatchResult.load(data, new FileInputStream(resultFile));
        p.setResult(result);
    }
    if (details) {
        ManagedPatch mp = gitPatchRepository.getManagedPatch(data.getId());
        p.setManagedPatch(mp);
    }
    return p;
}
Also used : ManagedPatch(org.jboss.fuse.patch.management.ManagedPatch) PatchData(org.jboss.fuse.patch.management.PatchData) PatchResult(org.jboss.fuse.patch.management.PatchResult) Patch(org.jboss.fuse.patch.management.Patch) ManagedPatch(org.jboss.fuse.patch.management.ManagedPatch) ZipFile(org.apache.commons.compress.archivers.zip.ZipFile) File(java.io.File) FileInputStream(java.io.FileInputStream) FeaturesProcessing(org.apache.karaf.features.internal.model.processing.FeaturesProcessing) LinkedList(java.util.LinkedList) PatchException(org.jboss.fuse.patch.management.PatchException) GitAPIException(org.eclipse.jgit.api.errors.GitAPIException) IOException(java.io.IOException)

Example 13 with Patch

use of org.jboss.fuse.patch.management.Patch in project fuse-karaf by jboss-fuse.

the class GitPatchManagementServiceImpl method trackPatch.

/**
 * <p>This method turns static information about a patch into managed patch - i.e., patch added to git
 * repository.</p>
 *
 * <p>Such patch has its own branch ready to be merged (when patch is installed). Before installation we can verify
 * the patch,
 * examine the content, check the differences, conflicts and perform simulation (merge to temporary branch created
 * from main patch branch)</p>
 *
 * <p>The strategy is as follows:<ul>
 *     <li><em>main patch branch</em> in git repository tracks all changes (from baselines, patch-management
 *     system, patches and user changes)</li>
 *     <li>Initially there are 3 commits: baseline, patch-management bundle installation in etc/startup.properties,
 *     initial user changes</li>
 *     <li>We always <strong>tag the baseline commit</strong></li>
 *     <li>User changes may be applied each time Framework is restarted</li>
 *     <li>When we add a patch, we create <em>named branch</em> from the <strong>latest baseline</strong></li>
 *     <li>When we install a patch, we <strong>merge</strong> the patch branch with the <em>main patch branch</em>
 *     (that may contain additional user changes)</li>
 *     <li>When patch ZIP contains new baseline distribution, after merging patch branch, we tag the merge commit
 *     in <em>main patch branch</em> branch as new baseline</li>
 *     <li>Branches for new patches will then be created from new baseline commit</li>
 * </ul></p>
 * @param patchData
 * @return
 */
@Override
public Patch trackPatch(PatchData patchData) throws PatchException {
    try {
        awaitInitialization();
    } catch (InterruptedException e) {
        throw new PatchException("Patch management system is not ready yet");
    }
    Git fork = null;
    try {
        Git mainRepository = gitPatchRepository.findOrCreateMainGitRepository();
        // prepare single fork for all the below operations
        fork = gitPatchRepository.cloneRepository(mainRepository, true);
        // 1. find current baseline
        RevTag latestBaseline = gitPatchRepository.findCurrentBaseline(fork);
        if (latestBaseline == null) {
            throw new PatchException("Can't find baseline distribution tracked in patch management. Is patch management initialized?");
        }
        // the commit from the patch should be available from main patch branch
        RevCommit commit = new RevWalk(fork.getRepository()).parseCommit(latestBaseline.getObject());
        // create dedicated branch for this patch. We'll immediately add patch content there so we can examine the
        // changes from the latest baseline
        gitPatchRepository.checkout(fork).setCreateBranch(true).setName("patch-" + patchData.getId()).setStartPoint(commit).call();
        // copy patch resources (but not maven artifacts from system/ or repository/) to working copy
        if (patchData.getPatchDirectory() != null) {
            boolean removeTargetDir = patchData.isRollupPatch();
            copyManagedDirectories(patchData.getPatchDirectory(), fork.getRepository().getWorkTree(), removeTargetDir, false, false);
        }
        // add the changes
        fork.add().addFilepattern(".").call();
        // remove the deletes
        for (String missing : fork.status().call().getMissing()) {
            fork.rm().addFilepattern(missing).call();
        }
        // record information about other "patches" included in added patch (e.g., Fuse patch
        // may contain patches to instance:create based containers in standalone mode)
        StringWriter sw = new StringWriter();
        sw.append("# tags for patches included in \"").append(patchData.getId()).append("\"\n");
        for (String bundle : patchData.getBundles()) {
            // containers that want to patch:install patches added in root containers
            if (bundle.contains("mvn:org.apache.karaf.instance/org.apache.karaf.instance.core/")) {
                Artifact a = Utils.mvnurlToArtifact(bundle, true);
                if (a != null) {
                    sw.append(String.format(EnvType.STANDALONE_CHILD.getBaselineTagFormat(), a.getVersion())).append("\n");
                }
                break;
            }
        }
        FileUtils.write(new File(fork.getRepository().getWorkTree(), "patch-info.txt"), sw.toString(), "UTF-8");
        fork.add().addFilepattern(".").call();
        // commit the changes (patch vs. baseline) to patch branch
        gitPatchRepository.prepareCommit(fork, String.format("[PATCH] Tracking patch %s", patchData.getId())).call();
        // push the patch branch
        gitPatchRepository.push(fork, "patch-" + patchData.getId());
        // for instance:create child containers
        trackBaselinesForChildContainers(fork);
        return new Patch(patchData, gitPatchRepository.getManagedPatch(patchData.getId()));
    } catch (IOException | GitAPIException e) {
        throw new PatchException(e.getMessage(), e);
    } finally {
        if (fork != null) {
            gitPatchRepository.closeRepository(fork, true);
        }
    }
}
Also used : RevTag(org.eclipse.jgit.revwalk.RevTag) IOException(java.io.IOException) RevWalk(org.eclipse.jgit.revwalk.RevWalk) Artifact(org.jboss.fuse.patch.management.Artifact) GitAPIException(org.eclipse.jgit.api.errors.GitAPIException) Git(org.eclipse.jgit.api.Git) StringWriter(java.io.StringWriter) PatchException(org.jboss.fuse.patch.management.PatchException) ZipFile(org.apache.commons.compress.archivers.zip.ZipFile) File(java.io.File) Patch(org.jboss.fuse.patch.management.Patch) ManagedPatch(org.jboss.fuse.patch.management.ManagedPatch) RevCommit(org.eclipse.jgit.revwalk.RevCommit)

Example 14 with Patch

use of org.jboss.fuse.patch.management.Patch in project fuse-karaf by jboss-fuse.

the class GitPatchManagementServiceImpl method checkPendingPatches.

@Override
public void checkPendingPatches() {
    File[] pendingPatches = patchesDir.listFiles(pathname -> pathname.exists() && pathname.getName().endsWith(".pending"));
    if (pendingPatches == null || pendingPatches.length == 0) {
        return;
    }
    final String dataCache = systemContext.getProperty("org.osgi.framework.storage");
    for (File pending : pendingPatches) {
        try {
            Pending what = Pending.valueOf(FileUtils.readFileToString(pending, "UTF-8"));
            final String prefix = what == Pending.ROLLUP_INSTALLATION ? "install" : "rollback";
            String name = pending.getName().replaceFirst("\\.pending$", "");
            if (isStandaloneChild()) {
                if (name.endsWith("." + System.getProperty("karaf.name") + ".patch")) {
                    name = name.replaceFirst("\\." + System.getProperty("karaf.name"), "");
                } else {
                    continue;
                }
            }
            File patchFile = new File(pending.getParentFile(), name);
            if (!patchFile.isFile()) {
                Activator.log(LogService.LOG_INFO, "Ignoring patch result file: " + patchFile.getName());
                continue;
            }
            PatchData patchData = PatchData.load(new FileInputStream(patchFile));
            Patch patch = loadPatch(new PatchDetailsRequest(patchData.getId()));
            String dataFilesName = patchData.getId() + ".datafiles";
            if (isStandaloneChild()) {
                dataFilesName = patchData.getId() + "." + System.getProperty("karaf.name") + ".datafiles";
            }
            final File dataFilesBackupDir = new File(pending.getParentFile(), dataFilesName);
            final Properties backupProperties = new Properties();
            FileInputStream inStream = new FileInputStream(new File(dataFilesBackupDir, "backup-" + prefix + ".properties"));
            backupProperties.load(inStream);
            Utils.closeQuietly(inStream);
            // maybe one of those bundles has data directory to restore?
            for (Bundle b : systemContext.getBundles()) {
                if (b.getSymbolicName() != null) {
                    String key = String.format("%s$$%s", stripSymbolicName(b.getSymbolicName()), b.getVersion().toString());
                    if (backupProperties.containsKey(key)) {
                        String backupDirName = backupProperties.getProperty(key);
                        File backupDir = new File(dataFilesBackupDir, prefix + "/" + backupDirName + "/data");
                        restoreDataDirectory(dataCache, b, backupDir);
                        // we no longer want to restore this dir
                        backupProperties.remove(key);
                    }
                }
            }
            // 2. We can however have more bundle data backups - we'll restore them after each bundle
            // is INSTALLED and we'll use listener for this
            BundleListener bundleListener = new SynchronousBundleListener() {

                @Override
                public void bundleChanged(BundleEvent event) {
                    Bundle b = event.getBundle();
                    if (event.getType() == BundleEvent.INSTALLED && b.getSymbolicName() != null) {
                        String key = String.format("%s$$%s", stripSymbolicName(b.getSymbolicName()), b.getVersion().toString());
                        if (backupProperties.containsKey(key)) {
                            String backupDirName = backupProperties.getProperty(key);
                            File backupDir = new File(dataFilesBackupDir, prefix + "/" + backupDirName + "/data");
                            restoreDataDirectory(dataCache, b, backupDir);
                        }
                    }
                }
            };
            systemContext.addBundleListener(bundleListener);
            pendingPatchesListeners.put(patchData.getId(), bundleListener);
        } catch (Exception e) {
            Activator.log(LogService.LOG_ERROR, null, e.getMessage(), e, true);
        }
    }
}
Also used : PatchData(org.jboss.fuse.patch.management.PatchData) Bundle(org.osgi.framework.Bundle) Properties(java.util.Properties) PatchDetailsRequest(org.jboss.fuse.patch.management.PatchDetailsRequest) FileInputStream(java.io.FileInputStream) PatchException(org.jboss.fuse.patch.management.PatchException) GitAPIException(org.eclipse.jgit.api.errors.GitAPIException) IOException(java.io.IOException) BundleEvent(org.osgi.framework.BundleEvent) BundleListener(org.osgi.framework.BundleListener) SynchronousBundleListener(org.osgi.framework.SynchronousBundleListener) ZipFile(org.apache.commons.compress.archivers.zip.ZipFile) File(java.io.File) Patch(org.jboss.fuse.patch.management.Patch) ManagedPatch(org.jboss.fuse.patch.management.ManagedPatch) Pending(org.jboss.fuse.patch.management.Pending) SynchronousBundleListener(org.osgi.framework.SynchronousBundleListener)

Example 15 with Patch

use of org.jboss.fuse.patch.management.Patch in project fuse-karaf by jboss-fuse.

the class DeleteCommand method doExecute.

@Override
protected void doExecute(PatchService service) throws Exception {
    Patch patch = patchManagement.loadPatch(new PatchDetailsRequest(patchId));
    if (patch == null) {
        throw new PatchException("Patch '" + patchId + "' not found");
    }
    if (patch.getResult() != null && patch.getResult().getKarafBases().size() > 0) {
        throw new PatchException("Patch '" + patchId + "' can't be deleted, as it's installed in these containers: " + patch.getResult().getKarafBases().stream().map(kb -> kb.contains("|") ? kb.split("\\s*\\|\\s*")[0] : kb).collect(Collectors.joining(", ")));
    }
    patchManagement.delete(patch);
    System.out.println("Patch '" + patchId + "' was successfully deleted");
}
Also used : UninstallPatchCompleter(org.jboss.fuse.patch.commands.completers.UninstallPatchCompleter) Argument(org.apache.karaf.shell.api.action.Argument) PatchDetailsRequest(org.jboss.fuse.patch.management.PatchDetailsRequest) Collectors(java.util.stream.Collectors) PatchException(org.jboss.fuse.patch.management.PatchException) BundleContext(org.osgi.framework.BundleContext) Command(org.apache.karaf.shell.api.action.Command) Reference(org.apache.karaf.shell.api.action.lifecycle.Reference) Patch(org.jboss.fuse.patch.management.Patch) Service(org.apache.karaf.shell.api.action.lifecycle.Service) PatchService(org.jboss.fuse.patch.PatchService) PatchManagement(org.jboss.fuse.patch.management.PatchManagement) Completion(org.apache.karaf.shell.api.action.Completion) PatchException(org.jboss.fuse.patch.management.PatchException) Patch(org.jboss.fuse.patch.management.Patch) PatchDetailsRequest(org.jboss.fuse.patch.management.PatchDetailsRequest)

Aggregations

Patch (org.jboss.fuse.patch.management.Patch)33 PatchException (org.jboss.fuse.patch.management.PatchException)20 IOException (java.io.IOException)12 PatchResult (org.jboss.fuse.patch.management.PatchResult)11 File (java.io.File)10 ManagedPatch (org.jboss.fuse.patch.management.ManagedPatch)9 PatchData (org.jboss.fuse.patch.management.PatchData)9 Test (org.junit.Test)9 LinkedList (java.util.LinkedList)7 GitAPIException (org.eclipse.jgit.api.errors.GitAPIException)7 PatchDetailsRequest (org.jboss.fuse.patch.management.PatchDetailsRequest)7 HashMap (java.util.HashMap)6 BundleUpdate (org.jboss.fuse.patch.management.BundleUpdate)6 Bundle (org.osgi.framework.Bundle)6 ZipFile (org.apache.commons.compress.archivers.zip.ZipFile)5 RevCommit (org.eclipse.jgit.revwalk.RevCommit)5 RevWalk (org.eclipse.jgit.revwalk.RevWalk)5 GitPatchManagementServiceImpl (org.jboss.fuse.patch.management.impl.GitPatchManagementServiceImpl)5 FileInputStream (java.io.FileInputStream)4 ArrayList (java.util.ArrayList)4