package org.basex.query.util.pkg;
import static org.basex.query.util.Err.*;
import static org.basex.query.util.pkg.PkgText.*;
import static org.basex.util.Token.*;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.basex.io.IO;
import org.basex.io.IOContent;
import org.basex.io.IOFile;
import org.basex.io.Zip;
import org.basex.query.QueryException;
import org.basex.query.util.pkg.Package.Dependency;
import org.basex.util.InputInfo;
import org.basex.util.Util;
/**
* Repository manager.
*
* @author BaseX Team 2005-12, BSD License
* @author Rositsa Shadura
*/
public final class RepoManager {
/** Repository context. */
private final Repo repo;
/**
* Constructor.
* @param r repository context
*/
public RepoManager(final Repo r) {
repo = r;
}
/**
* Installs a new package.
* @param path package path
* @param ii input info
* @throws QueryException query exception
*/
public void install(final String path, final InputInfo ii)
throws QueryException {
// check if package exists, and cache contents
final IO io = IO.get(path);
IOContent cont = null;
try {
cont = new IOContent(io.read());
} catch(final IOException ex) {
Util.debug(ex);
PKGNOTEXIST.thrw(ii, path);
}
try {
// parse and validate repository
final Zip zip = new Zip(cont);
final byte[] dsc = zip.read(DESCRIPTOR);
final Package pkg = new PkgParser(repo, ii).parse(new IOContent(dsc));
new PkgValidator(repo, ii).check(pkg);
// choose unique directory, unzip files and register repository
final IOFile file = uniqueDir(
string(pkg.uniqueName()).replaceAll("[^\\w.-]+", "-"));
zip.unzip(file);
repo.add(pkg, file.name());
} catch(final FileNotFoundException ex) {
Util.debug(ex);
PKGREADFNF.thrw(ii, io.name(), ex.getMessage());
} catch(final IOException ex) {
Util.debug(ex);
PKGREADFAIL.thrw(ii, io.name(), ex.getMessage());
}
}
/**
* Returns a unique directory for the specified package.
* @param n name
* @return unique directory
*/
private IOFile uniqueDir(final String n) {
String nm = n;
int c = 0;
do {
final IOFile io = repo.path(nm);
if(!io.exists()) return io;
nm = n + '-' + ++c;
} while(true);
}
/**
* Removes a package from package repository.
* @param pkg package
* @param ii input info
* @throws QueryException query exception
*/
public void delete(final String pkg, final InputInfo ii)
throws QueryException {
boolean found = false;
for(final byte[] nextPkg : repo.pkgDict()) {
if(nextPkg == null) continue;
final byte[] dir = repo.pkgDict().get(nextPkg);
if(eq(Package.name(nextPkg), token(pkg)) || eq(dir, token(pkg))) {
// a package can be deleted either by its name or by its directory name
found = true;
// check if package to be deleted participates in a dependency
final byte[] primPkg = primary(nextPkg, ii);
if(primPkg != null) PKGDEP.thrw(ii, string(primPkg), pkg);
// clean package repository
final IOFile f = repo.path(string(dir));
final IOFile desc = new IOFile(f, DESCRIPTOR);
repo.remove(new PkgParser(repo, ii).parse(desc));
// package does not participate in a dependency => delete it
if(!f.delete()) CANNOTDELPKG.thrw(ii);
}
}
if(!found) PKGNOTEXIST.thrw(ii, pkg);
}
/**
* Checks if a package participates in a dependency.
* @param pkgName package
* @param ii input info
* @return package depending on the current one
* @throws QueryException query exception
*/
private byte[] primary(final byte[] pkgName, final InputInfo ii)
throws QueryException {
for(final byte[] nextPkg : repo.pkgDict()) {
if(nextPkg != null && !eq(nextPkg, pkgName)) {
// check only packages different from the current one
final IOFile desc = new IOFile(repo.path(
string(repo.pkgDict().get(nextPkg))), DESCRIPTOR);
final Package pkg = new PkgParser(repo, ii).parse(desc);
final byte[] name = Package.name(pkgName);
for(final Dependency dep : pkg.dep)
// Check only package dependencies
if(dep.pkg != null && eq(dep.pkg, name)) return Package.name(nextPkg);
}
}
return null;
}
}