use of io.fabric8.patch.management.Artifact in project fabric8 by jboss-fuse.
the class DeployToProfileMojoTest method before.
// Fixtures setup
@Before
public void before() {
mojo.fabricServer = mock(Server.class);
project = new MavenProject();
project.setGroupId("io.fabric8");
project.setArtifactId("artifact");
project.setVersion(FABRIC_VERSION);
mojo.project = project;
deployResults = new DeployResults();
deployResults.setProfileId("profileId");
deployResults.setVersionId("versionId");
}
use of io.fabric8.patch.management.Artifact in project fabric8 by jboss-fuse.
the class GitPatchManagementServiceImpl method install.
@Override
public void install(String transaction, Patch patch, List<BundleUpdate> bundleUpdatesInThisPatch) {
transactionIsValid(transaction, patch);
Git fork = pendingTransactions.get(transaction);
try {
switch(pendingTransactionsTypes.get(transaction)) {
case ROLLUP:
{
Activator.log2(LogService.LOG_INFO, String.format("Installing rollup patch \"%s\"", patch.getPatchData().getId()));
// we can install only one rollup patch within single transaction
// and it is equal to cherry-picking all user changes on top of transaction branch
// after cherry-picking the commit from the rollup patch branch
// rollup patches do their own update to startup.properties
// we're operating on patch branch, HEAD of the patch branch points to the baseline
ObjectId since = fork.getRepository().resolve("HEAD^{commit}");
// we'll pick all user changes between baseline and main patch branch without P installations
ObjectId to = fork.getRepository().resolve(gitPatchRepository.getMainBranchName() + "^{commit}");
Iterable<RevCommit> mainChanges = fork.log().addRange(since, to).call();
List<RevCommit> userChanges = new LinkedList<>();
// gather lines of HF patches - patches that have *only* bundle updates
// if any of HF patches provide newer version of artifact than currently installed R patch,
// we will leave the relevant line in etc/overrides.properties
List<String> hfChanges = new LinkedList<>();
for (RevCommit rc : mainChanges) {
if (isUserChangeCommit(rc)) {
userChanges.add(rc);
} else {
String hfPatchId = isHfChangeCommit(rc);
if (hfPatchId != null) {
hfChanges.addAll(gatherOverrides(hfPatchId, patch));
}
}
}
String patchRef = patch.getManagedPatch().getCommitId();
if (env == EnvType.STANDALONE_CHILD) {
// we're in a slightly different situation:
// - patch was patch:added in root container
// - its main commit should be used when patching full Fuse/AMQ container
// - it created "side" commits (with tags) for this case of patching admin:create based containers
// - those tags are stored in special patch-info.txt file within patch' commit
String patchInfo = gitPatchRepository.getFileContent(fork, patchRef, "patch-info.txt");
if (patchInfo != null) {
BufferedReader reader = new BufferedReader(new StringReader(patchInfo));
String line = null;
while ((line = reader.readLine()) != null) {
if (line.startsWith("#")) {
continue;
}
Pattern p = Pattern.compile(env.getBaselineTagFormat().replace("%s", "(.*)"));
if (p.matcher(line).matches()) {
// this means we have another commit/tag that we should chery-pick as a patch
// for this standalone child container
patchRef = line.trim();
}
}
} else {
// hmm, we actually can't patch standalone child container then...
Activator.log2(LogService.LOG_WARNING, String.format("Can't install rollup patch \"%s\" in admin container - no information about admin container patch", patch.getPatchData().getId()));
return;
}
}
if (env == EnvType.STANDALONE) {
// pick the rollup patch
fork.cherryPick().include(fork.getRepository().resolve(patchRef)).setNoCommit(true).call();
gitPatchRepository.prepareCommit(fork, String.format(MARKER_R_PATCH_INSTALLATION_PATTERN, patch.getPatchData().getId())).call();
} else if (env == EnvType.STANDALONE_CHILD) {
// rebase on top of rollup patch
fork.reset().setMode(ResetCommand.ResetType.HARD).setRef("refs/tags/" + patchRef + "^{commit}").call();
}
// next commit - reset overrides.properties - this is 2nd step of installing rollup patch
// we are doing it even if the commit is going to be empty - this is the same step as after
// creating initial baseline
resetOverrides(fork.getRepository().getWorkTree(), hfChanges);
fork.add().addFilepattern("etc/overrides.properties").call();
RevCommit c = gitPatchRepository.prepareCommit(fork, String.format(MARKER_R_PATCH_RESET_OVERRIDES_PATTERN, patch.getPatchData().getId())).call();
if (env == EnvType.STANDALONE) {
// tag the new rollup patch as new baseline
String newFuseVersion = determineVersion(fork.getRepository().getWorkTree(), "fuse");
fork.tag().setName(String.format(EnvType.STANDALONE.getBaselineTagFormat(), newFuseVersion)).setObjectId(c).call();
}
// reapply those user changes that are not conflicting
// for each conflicting cherry-pick we do a backup of user files, to be able to restore them
// when rollup patch is rolled back
ListIterator<RevCommit> it = userChanges.listIterator(userChanges.size());
int prefixSize = Integer.toString(userChanges.size()).length();
int count = 1;
while (it.hasPrevious()) {
RevCommit userChange = it.previous();
String prefix = String.format("%0" + prefixSize + "d-%s", count++, userChange.getName());
CherryPickResult result = fork.cherryPick().include(userChange).setNoCommit(true).call();
// ENTESB-5492: remove etc/overrides.properties if there is such file left from old patch
// mechanism
File overrides = new File(fork.getRepository().getWorkTree(), "etc/overrides.properties");
if (overrides.isFile()) {
// version of some bundles, overrides.properties should be kept
if (!(hfChanges.size() > 0 && overrides.length() > 0)) {
overrides.delete();
fork.rm().addFilepattern("etc/overrides.properties").call();
}
}
// if there's conflict here, prefer patch version (which is "ours" (first) in this case)
handleCherryPickConflict(patch.getPatchData().getPatchDirectory(), fork, result, userChange, false, PatchKind.ROLLUP, prefix, true, false);
// always commit even empty changes - to be able to restore user changes when rolling back
// rollup patch.
// commit has the original commit id appended to the message.
// when we rebase on OLDER baseline (rollback) we restore backed up files based on this
// commit id (from patches/patch-id.backup/number-commit directory)
String newMessage = userChange.getFullMessage() + "\n\n";
newMessage += prefix;
gitPatchRepository.prepareCommit(fork, newMessage).call();
// we may have unadded changes - when file mode is changed
fork.reset().setMode(ResetCommand.ResetType.HARD).call();
}
// finally - let's get rid of all the tags related to non-rollup patches installed between
// previous baseline and previous HEAD, because installing rollup patch makes all previous P
// patches obsolete
RevWalk walk = new RevWalk(fork.getRepository());
RevCommit c1 = walk.parseCommit(since);
RevCommit c2 = walk.parseCommit(to);
Map<String, RevTag> tags = gitPatchRepository.findTagsBetween(fork, c1, c2);
for (Map.Entry<String, RevTag> entry : tags.entrySet()) {
if (entry.getKey().startsWith("patch-")) {
fork.tagDelete().setTags(entry.getKey()).call();
fork.push().setRefSpecs(new RefSpec().setSource(null).setDestination("refs/tags/" + entry.getKey())).call();
}
}
break;
}
case NON_ROLLUP:
{
Activator.log2(LogService.LOG_INFO, String.format("Installing non-rollup patch \"%s\"", patch.getPatchData().getId()));
// simply cherry-pick patch commit to transaction branch
// non-rollup patches require manual change to artifact references in all files
// pick the non-rollup patch
RevCommit commit = new RevWalk(fork.getRepository()).parseCommit(fork.getRepository().resolve(patch.getManagedPatch().getCommitId()));
CherryPickResult result = fork.cherryPick().include(commit).setNoCommit(true).call();
handleCherryPickConflict(patch.getPatchData().getPatchDirectory(), fork, result, commit, true, PatchKind.NON_ROLLUP, null, true, false);
// there are several files in ${karaf.home} that need to be changed together with patch
// commit, to make them reference updated bundles (paths, locations, ...)
updateFileReferences(fork, patch.getPatchData(), bundleUpdatesInThisPatch);
updateOverrides(fork.getRepository().getWorkTree(), patch.getPatchData());
fork.add().addFilepattern(".").call();
// always commit non-rollup patch
RevCommit c = gitPatchRepository.prepareCommit(fork, String.format(MARKER_P_PATCH_INSTALLATION_PATTERN, patch.getPatchData().getId())).call();
// we may have unadded changes - when file mode is changed
fork.reset().setMode(ResetCommand.ResetType.HARD).call();
// tag the installed patch (to easily rollback and to prevent another installation)
String tagName = String.format("patch-%s", patch.getPatchData().getId().replace(' ', '-'));
if (env == EnvType.STANDALONE_CHILD) {
tagName += "-" + gitPatchRepository.getStandaloneChildkarafName();
}
fork.tag().setName(tagName).setObjectId(c).call();
break;
}
}
} catch (IOException | GitAPIException e) {
throw new PatchException(e.getMessage(), e);
}
}
use of io.fabric8.patch.management.Artifact in project fabric8 by jboss-fuse.
the class GitPatchManagementServiceImpl method determineVersion.
/**
* Return version of product (Fuse, Fabric8) used, but probably based on different karafHome
* @param home
* @param product
* @return
*/
private String determineVersion(File home, String product) {
if (env != EnvType.FABRIC_CHILD && env != EnvType.STANDALONE_CHILD) {
File versions = new File(home, "fabric/import/fabric/profiles/default.profile/io.fabric8.version.properties");
if (versions.exists() && versions.isFile()) {
Properties props = new Properties();
FileInputStream fis = null;
try {
fis = new FileInputStream(versions);
props.load(fis);
return props.getProperty(product);
} catch (IOException e) {
Activator.log(LogService.LOG_ERROR, null, e.getMessage(), e, true);
return null;
} finally {
IOUtils.closeQuietly(fis);
}
} else {
Activator.log2(LogService.LOG_ERROR, "Can't find io.fabric8.version.properties file in default profile");
}
} else {
// for child container we have to be more careful and not examine root container's io.fabric8.version.properties!
File startup = new File(home, "etc/startup.properties");
if (startup.exists() && startup.isFile()) {
Properties props = new Properties();
FileInputStream fis = null;
try {
fis = new FileInputStream(startup);
props.load(fis);
for (String key : props.stringPropertyNames()) {
if (key.startsWith("org/apache/karaf/features/org.apache.karaf.features.core")) {
String url = Utils.pathToMvnurl(key);
Artifact artifact = Utils.mvnurlToArtifact(url, true);
if (artifact != null) {
return artifact.getVersion();
}
}
}
} catch (IOException e) {
Activator.log(LogService.LOG_ERROR, null, e.getMessage(), e, true);
return null;
} finally {
IOUtils.closeQuietly(fis);
}
} else {
Activator.log2(LogService.LOG_ERROR, "Can't find etc/startup.properties file in child container");
}
}
return null;
}
use of io.fabric8.patch.management.Artifact in project fabric8 by jboss-fuse.
the class GitPatchManagementServiceImpl method uploadPatchArtifacts.
@Override
public void uploadPatchArtifacts(PatchData patchData, URI uploadAddress, UploadCallback callback) throws PatchException {
try {
Activator.log2(LogService.LOG_INFO, "Uploading artifacts to " + uploadAddress);
List<File> artifacts = new LinkedList<>();
for (String bundle : patchData.getBundles()) {
String newUrl = Utils.mvnurlToPath(bundle);
if (newUrl != null) {
File repoLocation = new File(Utils.getSystemRepository(karafHome, bundleContext), newUrl);
if (repoLocation.isFile()) {
artifacts.add(repoLocation);
}
}
}
for (String featureRepository : patchData.getFeatureFiles()) {
String newUrl = Utils.mvnurlToPath(featureRepository);
if (newUrl != null) {
File repoLocation = new File(Utils.getSystemRepository(karafHome, bundleContext), newUrl);
if (repoLocation.isFile()) {
artifacts.add(repoLocation);
}
}
}
for (String artifact : patchData.getOtherArtifacts()) {
String newUrl = Utils.mvnurlToPath(artifact);
if (newUrl != null) {
File repoLocation = new File(Utils.getSystemRepository(karafHome, bundleContext), newUrl);
if (repoLocation.isFile()) {
artifacts.add(repoLocation);
}
}
}
int delta = artifacts.size() / 10;
int count = 0;
for (File f : artifacts) {
if (++count % delta == 0) {
Activator.log2(LogService.LOG_DEBUG, String.format("Uploaded %d/%d", count, artifacts.size()));
}
String relativeName = Utils.relative(Utils.getSystemRepository(karafHome, bundleContext), f.getCanonicalFile());
relativeName = relativeName.replace('\\', '/');
URL uploadUrl = uploadAddress.resolve(relativeName).toURL();
URLConnection con = uploadUrl.openConnection();
callback.doWithUrlConnection(con);
con.setDoInput(true);
con.setDoOutput(true);
con.connect();
OutputStream os = con.getOutputStream();
InputStream is = new FileInputStream(f);
try {
IOUtils.copy(is, os);
if (con instanceof HttpURLConnection) {
int code = ((HttpURLConnection) con).getResponseCode();
if (code < 200 || code >= 300) {
throw new IOException("Error uploading patched artifacts: " + ((HttpURLConnection) con).getResponseMessage());
}
}
} finally {
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(os);
}
}
Activator.log2(LogService.LOG_DEBUG, String.format("Uploaded %d/%d", count, artifacts.size()));
} catch (Exception e) {
throw new PatchException(e.getMessage(), e);
}
}
use of io.fabric8.patch.management.Artifact in project fabric8 by jboss-fuse.
the class GitPatchManagementServiceImpl method alignTo.
@Override
public boolean alignTo(Map<String, String> versions, List<String> urls, File localMavenRepository, Runnable callback) throws PatchException {
if (aligning.getAndSet(true)) {
return false;
}
try {
if (!env.isFabric()) {
try {
// we probably survived fabric:create without refreshing patch-management bundle
env = envService.determineEnvironmentType();
File patchRepositoryLocation = new File(patchesDir, GitPatchRepositoryImpl.MAIN_GIT_REPO_LOCATION);
getGitPatchRepository().close();
GitPatchRepositoryImpl repository = new GitPatchRepositoryImpl(env, patchRepositoryLocation, karafHome, karafBase, karafData, patchesDir);
setGitPatchRepository(repository);
start();
// let's tweak the configuration when entering fabric mode
// this way we will track other kinds of baselines
ensurePatchManagementInitialized();
if (master) {
// let the caller know that we've configured patch management in "master" container
// this is mainly to push the changes from local to cluster git repository
// so child/ssh containers created in fabric can fetch correct baselines
callback.run();
}
} catch (Exception e) {
throw new PatchException(e.getMessage(), e);
}
}
if (env.isFabric()) {
Git fork = null;
try {
ensuringLock.lock();
String version = versions.get(env.getProductId());
String tagName = String.format(env.getBaselineTagFormat(), version);
// we have to be at that tag
Git mainRepository = gitPatchRepository.findOrCreateMainGitRepository();
fetchFabricPatchData(mainRepository);
fork = gitPatchRepository.cloneRepository(mainRepository, true);
gitPatchRepository.checkout(fork).setName(gitPatchRepository.getMainBranchName()).call();
RevTag tag = gitPatchRepository.findCurrentBaseline(fork);
if (tag != null && tagName.equals(tag.getTagName())) {
if (master) {
// and then to data/git/servlet
try {
gitPatchRepository.pushPatchBranches();
callback.run();
} catch (Exception e) {
Activator.log(LogService.LOG_WARNING, null, e.getMessage(), e, false);
} catch (Error e) {
// in case newer patch management calls agent which is still wired to old patch management
Activator.log(LogService.LOG_WARNING, null, e.getMessage(), e, false);
}
}
return false;
}
boolean baselineSwitched = handleNonCurrentBaseline(fork, version, tagName, false, true);
if (localMavenRepository != null) {
try {
File systemRepo = getSystemRepository(karafHome, systemContext);
// let's copy artifacts referenced in etc/startup.properties from localMavenRepository to system
File etcStartupProperties = new File(karafBase, "etc/startup.properties");
try (FileInputStream fis = new FileInputStream(etcStartupProperties)) {
Properties props = new Properties();
props.load(fis);
for (String artifact : props.stringPropertyNames()) {
File target = new File(systemRepo, artifact);
File src = new File(localMavenRepository, artifact);
if (!target.exists() && src.isFile()) {
FileUtils.copyFile(src, target);
}
}
}
// now the URLs from the passed lis
for (String url : urls) {
String path = Utils.mvnurlToPath(url);
if (path != null) {
File target = new File(systemRepo, path);
File src = new File(localMavenRepository, path);
if (!target.exists() && src.isFile()) {
FileUtils.copyFile(src, target);
}
}
}
} catch (Exception e) {
Activator.log(LogService.LOG_ERROR, null, e.getMessage(), e, false);
}
}
return baselineSwitched;
} catch (Exception e) {
throw new PatchException(e.getMessage(), e);
} finally {
ensuringLock.unlock();
if (fork != null) {
gitPatchRepository.closeRepository(fork, true);
}
}
}
return false;
} finally {
aligning.set(false);
}
}
Aggregations