blob: ac058658953712b5c691777e52eb7bf83be2d762 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2010, 2020 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.internal.rhelp.core;
import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
import static org.eclipse.statet.internal.rhelp.core.RHelpCoreInternals.DEBUG;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.jcommons.status.InfoStatus;
import org.eclipse.statet.internal.rhelp.core.index.REnvIndexWriter;
import org.eclipse.statet.rhelp.core.REnvHelp;
import org.eclipse.statet.rhelp.core.REnvHelpConfiguration;
import org.eclipse.statet.rhelp.core.RHelpCore;
import org.eclipse.statet.rhelp.core.RHelpManager;
import org.eclipse.statet.rhelp.core.RPkgHelp;
import org.eclipse.statet.rj.renv.core.RPkgBuilt;
@NonNullByDefault
public class REnvHelpIndexChecker {
private static boolean equalVersion(final RPkgBuilt pkg1, final @Nullable RPkgBuilt pkg2) {
return (pkg2 != null
&& pkg1.getVersion().equals(pkg2.getVersion())
&& pkg1.getBuilt().equals(pkg2.getBuilt()) );
}
private final RHelpManager rHelpManager;
private final REnvHelpConfiguration rEnvConfig;
private int newPkg;
private int changedPkg;
private int newChange= -1;
private Map<String, RPkgBuilt> needUpdate= new HashMap<>();
private Map<String, RPkgBuilt> needUpdatePrevious= new HashMap<>();
private @Nullable Object indexLock;
private @Nullable REnvHelp rEnvHelp;
private boolean rEnvHelpLock;
private boolean inPackageCheck;
public REnvHelpIndexChecker(final RHelpManager rHelpManager,
final REnvHelpConfiguration rEnvConfig) {
this.rHelpManager= nonNullAssert(rHelpManager);
this.rEnvConfig= nonNullAssert(rEnvConfig);
try {
final Path directory= SerUtil.getIndexDirectoryPath(this.rEnvConfig);
if (directory != null) {
try {
// directory writable?
if (!isWritable(directory)) {
if (DEBUG) {
RHelpCoreInternals.log(new InfoStatus(RHelpCore.BUNDLE_ID,
String.format("The index directory '%1$s' is not writable.", //$NON-NLS-1$
directory.toString() ),
null));
}
return;
}
}
catch (final IOException e) {
RHelpCoreInternals.log(new InfoStatus(RHelpCore.BUNDLE_ID,
String.format("The index directory '%1$s' is not accessible.", //$NON-NLS-1$
directory.toString() ),
e));
}
}
}
catch (final Exception e) {}
}
private boolean isWritable(final Path directory) throws IOException {
final Path testFile= directory.resolve("test" + System.nanoTime()); //$NON-NLS-1$
try {
if (!Files.isDirectory(directory)) {
Files.createDirectories(directory);
}
Files.createFile(testFile);
Files.delete(testFile);
}
catch (final IOException e) {
return false;
}
return true;
}
public boolean beginCheck() {
this.newChange= (this.newChange < 0) ? 1 : 0;
if (this.rEnvConfig == null) {
return false;
}
final REnvHelp envHelp= this.rHelpManager.getHelp(this.rEnvConfig.getREnv());
if ((envHelp != null) ? (this.rEnvHelp == null) : this.rEnvHelp != null) {
this.newChange= 1;
}
this.rEnvHelp= envHelp;
this.rEnvHelpLock= (this.rEnvHelp != null);
if (!this.rEnvConfig.equals(this.rEnvConfig.getREnv().get(REnvHelpConfiguration.class))) {
return false;
}
this.indexLock= this.rHelpManager.beginIndexCheck(this.rEnvConfig.getREnv());
return (this.indexLock != null);
}
public void beginPackageCheck() {
this.inPackageCheck= true;
final Map<String, RPkgBuilt> tmp= this.needUpdate;
this.needUpdate= this.needUpdatePrevious;
this.needUpdatePrevious= tmp;
this.newPkg= 0;
this.changedPkg= 0;
this.newChange= 0;
}
public void checkPackage(final RPkgBuilt pkgInfo) {
if (!REnvIndexWriter.IGNORE_PKG_NAMES.contains(pkgInfo.getName())) {
final RPkgHelp pkgHelp= this.rEnvHelp.getPkgHelp(pkgInfo.getName());
if (pkgHelp == null) {
this.newPkg++;
this.needUpdate.put(pkgInfo.getName(), pkgInfo);
if (this.newChange == 0 && !equalVersion(pkgInfo, this.needUpdatePrevious.get(pkgInfo.getName()))) {
this.newChange= 1;
}
}
else if (!RPkgBuilt.equalsBuilt(pkgInfo, pkgHelp.getPkgDescription())) {
this.changedPkg++;
this.needUpdate.put(pkgInfo.getName(), pkgInfo);
if (this.newChange == 0 && !equalVersion(pkgInfo, this.needUpdatePrevious.get(pkgInfo.getName()))) {
this.newChange= 1;
}
}
}
}
public void endPackageCheck() {
this.inPackageCheck= false;
this.needUpdatePrevious.clear();
}
public void cancelCheck() {
if (this.inPackageCheck) {
final Map<String, RPkgBuilt> tmp= this.needUpdate;
this.needUpdate= this.needUpdatePrevious;
this.needUpdatePrevious= tmp;
}
this.needUpdatePrevious.clear();
unlock();
}
public void finalCheck() {
unlock();
}
private void unlock() {
if (this.rEnvHelpLock) {
this.rEnvHelpLock= false;
this.rEnvHelp.unlock();
}
}
public void release() {
if (this.indexLock != null) {
this.rHelpManager.endIndexCheck(this.indexLock);
this.indexLock= null;
}
}
public boolean hasNewChanges() {
return (this.newChange > 0);
}
public boolean needsComplete() {
return (this.rEnvHelp == null);
}
public boolean hasPackageChanges() {
return (this.newPkg > 0 || this.changedPkg > 0);
}
public int getNewPackageCount() {
return this.newPkg;
}
public int getChangedPackageCount() {
return this.changedPkg;
}
}