Search in sources :

Example 86 with Version

use of io.fabric8.api.Version in project fabric8 by jboss-fuse.

the class GitPatchManagementServiceImpl method updateOverrides.

/**
 * <p>Updates existing <code>etc/overrides.properties</code> after installing single {@link PatchKind#NON_ROLLUP}
 * patch.</p>
 * @param workTree
 * @param patchData
 */
private void updateOverrides(File workTree, PatchData patchData) throws IOException {
    File overrides = new File(workTree, "etc/overrides.properties");
    List<String> currentOverrides = overrides.isFile() ? FileUtils.readLines(overrides) : new LinkedList<String>();
    for (String bundle : patchData.getBundles()) {
        Artifact artifact = mvnurlToArtifact(bundle, true);
        if (artifact == null) {
            continue;
        }
        // Compute patch bundle version and range
        VersionRange range;
        Version oVer = Utils.getOsgiVersion(artifact.getVersion());
        String vr = patchData.getVersionRange(bundle);
        String override;
        if (vr != null && !vr.isEmpty()) {
            override = bundle + ";range=" + vr;
            range = new VersionRange(vr);
        } else {
            override = bundle;
            Version v1 = new Version(oVer.getMajor(), oVer.getMinor(), 0);
            Version v2 = new Version(oVer.getMajor(), oVer.getMinor() + 1, 0);
            range = new VersionRange(VersionRange.LEFT_CLOSED, v1, v2, VersionRange.RIGHT_OPEN);
        }
        // Process overrides.properties
        boolean matching = false;
        boolean added = false;
        for (int i = 0; i < currentOverrides.size(); i++) {
            String line = currentOverrides.get(i).trim();
            if (!line.isEmpty() && !line.startsWith("#")) {
                Artifact overrideArtifact = mvnurlToArtifact(line, true);
                if (overrideArtifact != null) {
                    Version ver = Utils.getOsgiVersion(overrideArtifact.getVersion());
                    if (isSameButVersion(artifact, overrideArtifact) && range.includes(ver)) {
                        matching = true;
                        if (ver.compareTo(oVer) < 0) {
                            // Replace old override with the new one
                            currentOverrides.set(i, override);
                            added = true;
                        }
                    }
                }
            }
        }
        // If there was not matching bundles, add it
        if (!matching) {
            currentOverrides.add(override);
        }
    }
    FileUtils.writeLines(overrides, currentOverrides, IOUtils.LINE_SEPARATOR_UNIX);
}
Also used : Version(org.osgi.framework.Version) Artifact.isSameButVersion(io.fabric8.patch.management.Artifact.isSameButVersion) VersionRange(org.osgi.framework.VersionRange) ZipFile(org.apache.commons.compress.archivers.zip.ZipFile) File(java.io.File) Artifact(io.fabric8.patch.management.Artifact)

Example 87 with Version

use of io.fabric8.api.Version in project fabric8 by jboss-fuse.

the class GitPatchManagementServiceImpl method commitInstallation.

@Override
public void commitInstallation(String transaction) {
    transactionIsValid(transaction, null);
    Git fork = pendingTransactions.get(transaction);
    try {
        switch(pendingTransactionsTypes.get(transaction)) {
            case ROLLUP:
                {
                    // hard reset of main patch branch to point to transaction branch + apply changes to ${karaf.home}
                    gitPatchRepository.checkout(fork).setName(gitPatchRepository.getMainBranchName()).call();
                    // before we reset main patch branch to originate from new baseline, let's find previous baseline
                    RevTag baseline = gitPatchRepository.findCurrentBaseline(fork);
                    RevCommit c1 = new RevWalk(fork.getRepository()).parseCommit(fork.getRepository().resolve(baseline.getTagName() + "^{commit}"));
                    // hard reset of main patch branch - to point to other branch, originating from new baseline
                    fork.reset().setMode(ResetCommand.ResetType.HARD).setRef(transaction).call();
                    gitPatchRepository.push(fork);
                    RevCommit c2 = new RevWalk(fork.getRepository()).parseCommit(fork.getRepository().resolve("HEAD"));
                    // apply changes from single range of commits
                    // applyChanges(fork, c1, c2);
                    applyChanges(fork, false);
                    break;
                }
            case NON_ROLLUP:
                {
                    // fast forward merge of main patch branch with transaction branch
                    gitPatchRepository.checkout(fork).setName(gitPatchRepository.getMainBranchName()).call();
                    // current version of ${karaf.home}
                    RevCommit c1 = new RevWalk(fork.getRepository()).parseCommit(fork.getRepository().resolve("HEAD"));
                    // fast forward over patch-installation branch - possibly over more than 1 commit
                    fork.merge().setFastForward(MergeCommand.FastForwardMode.FF_ONLY).include(fork.getRepository().resolve(transaction)).call();
                    gitPatchRepository.push(fork);
                    // apply a change from commits of all installed patches
                    RevCommit c2 = new RevWalk(fork.getRepository()).parseCommit(fork.getRepository().resolve("HEAD"));
                    applyChanges(fork, c1, c2);
                    // applyChanges(fork);
                    break;
                }
        }
        gitPatchRepository.push(fork);
    } catch (GitAPIException | IOException e) {
        throw new PatchException(e.getMessage(), e);
    } finally {
        gitPatchRepository.closeRepository(fork, true);
    }
    pendingTransactions.remove(transaction);
    pendingTransactionsTypes.remove(transaction);
}
Also used : GitAPIException(org.eclipse.jgit.api.errors.GitAPIException) Git(org.eclipse.jgit.api.Git) RevTag(org.eclipse.jgit.revwalk.RevTag) IOException(java.io.IOException) PatchException(io.fabric8.patch.management.PatchException) RevWalk(org.eclipse.jgit.revwalk.RevWalk) RevCommit(org.eclipse.jgit.revwalk.RevCommit)

Example 88 with Version

use of io.fabric8.api.Version in project fabric8 by jboss-fuse.

the class GitPatchManagementServiceImpl method handleConflict.

private void handleConflict(File patchDirectory, Git fork, boolean preferNew, String cpPrefix, boolean performBackup, String choose, String backup, boolean rollback) throws GitAPIException, IOException {
    Map<String, IndexDiff.StageState> conflicts = fork.status().call().getConflictingStageState();
    DirCache cache = fork.getRepository().readDirCache();
    // path -> [oursObjectId, baseObjectId, theirsObjectId]
    Map<String, ObjectId[]> threeWayMerge = new HashMap<>();
    // collect conflicts info
    for (int i = 0; i < cache.getEntryCount(); i++) {
        DirCacheEntry entry = cache.getEntry(i);
        if (entry.getStage() == DirCacheEntry.STAGE_0) {
            continue;
        }
        if (!threeWayMerge.containsKey(entry.getPathString())) {
            threeWayMerge.put(entry.getPathString(), new ObjectId[] { null, null, null });
        }
        if (entry.getStage() == DirCacheEntry.STAGE_1) {
            // base
            threeWayMerge.get(entry.getPathString())[1] = entry.getObjectId();
        }
        if (entry.getStage() == DirCacheEntry.STAGE_2) {
            // ours
            threeWayMerge.get(entry.getPathString())[0] = entry.getObjectId();
        }
        if (entry.getStage() == DirCacheEntry.STAGE_3) {
            // theirs
            threeWayMerge.get(entry.getPathString())[2] = entry.getObjectId();
        }
    }
    // resolve conflicts
    ObjectReader objectReader = fork.getRepository().newObjectReader();
    for (Map.Entry<String, ObjectId[]> entry : threeWayMerge.entrySet()) {
        if (entry.getKey().equals("patch-info.txt")) {
            fork.rm().addFilepattern(entry.getKey()).call();
            continue;
        }
        Resolver resolver = conflictResolver.getResolver(entry.getKey());
        // resolved version - either by custom resolved or using automatic algorithm
        String resolved = null;
        if (resolver != null && entry.getValue()[0] != null && entry.getValue()[2] != null) {
            // custom conflict resolution (don't expect DELETED_BY_X kind of conflict, only BOTH_MODIFIED)
            String message = String.format(" - %s (%s): %s", entry.getKey(), conflicts.get(entry.getKey()), "Using " + resolver.getClass().getName() + " to resolve the conflict");
            Activator.log2(LogService.LOG_INFO, message);
            // when doing custom resolution of conflict, we know that both user and patch has changed the file
            // in non-mergeable way.
            // If there was no resolver, we simply check what to choose by "preferNew" flag
            // But because we have custom resolver, we use "preferNew" flag to check which STAGE points to patch'
            // version and we select this patch' version of conflicting file as less important file inside
            // custom resolver
            File base = null, first = null, second = null;
            try {
                ObjectLoader loader = null;
                if (entry.getValue()[1] != null) {
                    base = new File(fork.getRepository().getWorkTree(), entry.getKey() + ".1");
                    loader = objectReader.open(entry.getValue()[1]);
                    try (FileOutputStream fos = new FileOutputStream(base)) {
                        loader.copyTo(fos);
                    }
                }
                // if preferNew == true (P patch) then "first" file (less important) will be file
                // provided by patch ("theirs", STAGE_3)
                first = new File(fork.getRepository().getWorkTree(), entry.getKey() + ".2");
                loader = objectReader.open(entry.getValue()[preferNew ? 2 : 0]);
                try (FileOutputStream fos = new FileOutputStream(first)) {
                    loader.copyTo(fos);
                }
                // "second", more important file will be user change
                second = new File(fork.getRepository().getWorkTree(), entry.getKey() + ".3");
                loader = objectReader.open(entry.getValue()[preferNew ? 0 : 2]);
                try (FileOutputStream fos = new FileOutputStream(second)) {
                    loader.copyTo(fos);
                }
                // resolvers treat patch change as less important - user lines overwrite patch lines
                if (resolver instanceof PropertiesFileResolver) {
                    // TODO: use options from patch:install / patch:fabric-install command
                    // by default we use a file that comes from patch and we may add property changes
                    // from user
                    // in R patch, preferNew == false, because patch comes first
                    // in P patch, preferNew == true, because patch comes last
                    // in R patch + fabric mode, preferNew == true, because we *merge* patch branch into version
                    // branch
                    boolean useFirstChangeAsBase = true;
                    if (entry.getKey().startsWith("etc/")) {
                        // as base
                        if (rollback) {
                            useFirstChangeAsBase = true;
                        } else {
                            useFirstChangeAsBase = false;
                        }
                    }
                    resolved = ((ResolverEx) resolver).resolve(first, base, second, useFirstChangeAsBase, rollback);
                } else {
                    resolved = resolver.resolve(first, base, second);
                }
                if (resolved != null) {
                    FileUtils.write(new File(fork.getRepository().getWorkTree(), entry.getKey()), resolved);
                    fork.add().addFilepattern(entry.getKey()).call();
                }
            } finally {
                if (base != null) {
                    base.delete();
                }
                if (first != null) {
                    first.delete();
                }
                if (second != null) {
                    second.delete();
                }
            }
        }
        if (resolved == null) {
            // automatic conflict resolution
            String message = String.format(" - %s (%s): Choosing %s", entry.getKey(), conflicts.get(entry.getKey()), choose);
            ObjectLoader loader = null;
            ObjectLoader loaderForBackup = null;
            // longer code, but more readable then series of elvis operators (?:)
            if (preferNew) {
                switch(conflicts.get(entry.getKey())) {
                    case BOTH_ADDED:
                    case BOTH_MODIFIED:
                        loader = objectReader.open(entry.getValue()[2]);
                        loaderForBackup = objectReader.open(entry.getValue()[0]);
                        break;
                    case BOTH_DELETED:
                        break;
                    case DELETED_BY_THEM:
                        // ENTESB-6003: special case: when R patch removes something and we've modified it
                        // let's preserve our version
                        message = String.format(" - %s (%s): Keeping custom change", entry.getKey(), conflicts.get(entry.getKey()));
                        loader = objectReader.open(entry.getValue()[0]);
                        break;
                    case DELETED_BY_US:
                        loader = objectReader.open(entry.getValue()[2]);
                        break;
                }
            } else {
                switch(conflicts.get(entry.getKey())) {
                    case BOTH_ADDED:
                    case BOTH_MODIFIED:
                        loader = objectReader.open(entry.getValue()[0]);
                        loaderForBackup = objectReader.open(entry.getValue()[2]);
                        break;
                    case DELETED_BY_THEM:
                        loader = objectReader.open(entry.getValue()[0]);
                        break;
                    case BOTH_DELETED:
                    case DELETED_BY_US:
                        break;
                }
            }
            Activator.log2(LogService.LOG_WARNING, message);
            if (loader != null) {
                try (FileOutputStream fos = new FileOutputStream(new File(fork.getRepository().getWorkTree(), entry.getKey()))) {
                    loader.copyTo(fos);
                }
                fork.add().addFilepattern(entry.getKey()).call();
            } else {
                fork.rm().addFilepattern(entry.getKey()).call();
            }
            if (performBackup) {
                // the other entry should be backed up
                if (loaderForBackup != null) {
                    File target = new File(patchDirectory.getParent(), patchDirectory.getName() + ".backup");
                    if (isStandaloneChild()) {
                        target = new File(patchDirectory.getParent(), patchDirectory.getName() + "." + System.getProperty("karaf.name") + ".backup");
                    }
                    if (cpPrefix != null) {
                        target = new File(target, cpPrefix);
                    }
                    File file = new File(target, entry.getKey());
                    message = String.format("Backing up %s to \"%s\"", backup, file.getCanonicalPath());
                    Activator.log2(LogService.LOG_DEBUG, message);
                    file.getParentFile().mkdirs();
                    try (FileOutputStream fos = new FileOutputStream(file)) {
                        loaderForBackup.copyTo(fos);
                    }
                }
            }
        }
    }
}
Also used : DirCacheEntry(org.eclipse.jgit.dircache.DirCacheEntry) ConflictResolver(io.fabric8.patch.management.conflicts.ConflictResolver) PropertiesFileResolver(io.fabric8.patch.management.conflicts.PropertiesFileResolver) Resolver(io.fabric8.patch.management.conflicts.Resolver) HashMap(java.util.HashMap) DirCache(org.eclipse.jgit.dircache.DirCache) PropertiesFileResolver(io.fabric8.patch.management.conflicts.PropertiesFileResolver) EOLFixingFileOutputStream(io.fabric8.patch.management.io.EOLFixingFileOutputStream) FileOutputStream(java.io.FileOutputStream) ObjectReader(org.eclipse.jgit.lib.ObjectReader) ObjectLoader(org.eclipse.jgit.lib.ObjectLoader) Map(java.util.Map) TreeMap(java.util.TreeMap) HashMap(java.util.HashMap) ZipFile(org.apache.commons.compress.archivers.zip.ZipFile) File(java.io.File)

Example 89 with Version

use of io.fabric8.api.Version in project fabric8 by jboss-fuse.

the class GitPatchManagementServiceImpl method mergeProfileChanges.

@Override
public void mergeProfileChanges(Patch patch, File gitRepository, String versionBranch, String patchBranch) {
    Git git = null;
    try {
        git = Git.open(gitRepository);
        // merge version branch with patch branch - no fast forward, so we have nice named commit
        git.checkout().setCreateBranch(false).setName(versionBranch).call();
        MergeResult result = git.merge().setFastForward(MergeCommand.FastForwardMode.NO_FF).include(git.getRepository().resolve(patchBranch)).setCommit(false).call();
        boolean commit = true;
        if (result.getMergeStatus() == MergeResult.MergeStatus.CONFLICTING) {
            handleMergeConflict(git, result, versionBranch, patchBranch);
        } else if (result.getMergeStatus() != MergeResult.MergeStatus.MERGED_NOT_COMMITTED) {
            commit = false;
            Activator.log2(LogService.LOG_ERROR, "Can't merge version branch \"" + versionBranch + "\" with" + " patch branch \"" + patchBranch + "\". Resetting the branch.");
            git.reset().setMode(ResetCommand.ResetType.HARD).call();
        }
    // if (commit) {
    // git.commit()
    // .setMessage("Installing rollup patch \"" + patch.getPatchData().getId() + "\"")
    // .call();
    // }
    } catch (Exception e) {
        throw new PatchException(e.getMessage(), e);
    } finally {
        if (git != null) {
            try {
                git.branchDelete().setBranchNames(patchBranch).setForce(true).call();
            } catch (GitAPIException e) {
                Activator.log2(LogService.LOG_ERROR, e.getMessage());
            }
            gitPatchRepository.closeRepository(git, false);
        }
    }
}
Also used : GitAPIException(org.eclipse.jgit.api.errors.GitAPIException) Git(org.eclipse.jgit.api.Git) MergeResult(org.eclipse.jgit.api.MergeResult) PatchException(io.fabric8.patch.management.PatchException) PatchException(io.fabric8.patch.management.PatchException) GitAPIException(org.eclipse.jgit.api.errors.GitAPIException) IOException(java.io.IOException) FileNotFoundException(java.io.FileNotFoundException)

Example 90 with Version

use of io.fabric8.api.Version in project fabric8 by jboss-fuse.

the class GitPatchManagementServiceIT method rollbackInstalledRollupPatch.

@Test
public void rollbackInstalledRollupPatch() throws IOException, GitAPIException {
    freshKarafStandaloneDistro();
    GitPatchRepository repository = patchManagement();
    PatchManagement management = (PatchManagement) pm;
    preparePatchZip("src/test/resources/content/patch1", "target/karaf/patches/source/patch-1.zip", false);
    preparePatchZip("src/test/resources/content/patch4", "target/karaf/patches/source/patch-4.zip", false);
    List<PatchData> patches = management.fetchPatches(new File("target/karaf/patches/source/patch-1.zip").toURI().toURL());
    Patch patch1 = management.trackPatch(patches.get(0));
    patches = management.fetchPatches(new File("target/karaf/patches/source/patch-4.zip").toURI().toURL());
    Patch patch4 = management.trackPatch(patches.get(0));
    Git fork = repository.cloneRepository(repository.findOrCreateMainGitRepository(), true);
    ObjectId master1 = fork.getRepository().resolve(GitPatchRepository.HISTORY_BRANCH);
    String tx = management.beginInstallation(PatchKind.ROLLUP);
    management.install(tx, patch4, null);
    management.commitInstallation(tx);
    // install P patch to check if rolling back rollup patch will remove P patch's tag
    tx = management.beginInstallation(PatchKind.NON_ROLLUP);
    management.install(tx, patch1, null);
    management.commitInstallation(tx);
    fork = repository.cloneRepository(repository.findOrCreateMainGitRepository(), true);
    assertTrue(repository.containsTag(fork, "patch-my-patch-1"));
    management.rollback(patch4.getPatchData());
    repository.closeRepository(fork, true);
    fork = repository.cloneRepository(repository.findOrCreateMainGitRepository(), true);
    ObjectId master2 = fork.getRepository().resolve(GitPatchRepository.HISTORY_BRANCH);
    assertThat(master1, not(equalTo(master2)));
    assertThat(fork.tagList().call().size(), equalTo(2));
    assertTrue(repository.containsTag(fork, "patch-management"));
    assertTrue(repository.containsTag(fork, "baseline-6.2.0"));
    assertFalse("When rolling back rollup patch, newer P patches' tags should be removed", repository.containsTag(fork, "patch-my-patch-1"));
    assertThat(repository.findCurrentBaseline(fork).getTagName(), equalTo("baseline-6.2.0"));
// TODO: There should be version restored from backed up conflict
// but we've changed the way rolledback R patch handled - we copy entire WC after rollback
// String binStart = FileUtils.readFileToString(new File(karafHome, "bin/start"));
// assertTrue("bin/start should be at previous version",
// binStart.contains("echo \"This is user's change\""));
}
Also used : Git(org.eclipse.jgit.api.Git) ObjectId(org.eclipse.jgit.lib.ObjectId) GitPatchRepository(io.fabric8.patch.management.impl.GitPatchRepository) File(java.io.File) Test(org.junit.Test)

Aggregations

Version (io.fabric8.api.Version)74 Profile (io.fabric8.api.Profile)70 File (java.io.File)52 Test (org.junit.Test)46 IOException (java.io.IOException)41 ArrayList (java.util.ArrayList)36 Container (io.fabric8.api.Container)35 HashMap (java.util.HashMap)34 ProfileService (io.fabric8.api.ProfileService)27 Map (java.util.Map)25 Git (org.eclipse.jgit.api.Git)22 FabricService (io.fabric8.api.FabricService)21 Version (org.osgi.framework.Version)21 ProfileBuilder (io.fabric8.api.ProfileBuilder)18 GitVersion (io.fabric8.api.commands.GitVersion)18 PatchException (io.fabric8.patch.management.PatchException)15 HashSet (java.util.HashSet)15 TreeMap (java.util.TreeMap)14 LinkedList (java.util.LinkedList)13 GitPatchRepository (io.fabric8.patch.management.impl.GitPatchRepository)12