package aQute.library.bnd;
import java.io.*;
import java.util.*;
import aQute.bnd.version.*;
import aQute.lib.converter.*;
import aQute.lib.io.*;
import aQute.lib.json.*;
import aQute.libg.reporter.*;
import aQute.service.library.*;
import aQute.service.library.Library.RevisionRef;
import aQute.service.reporter.*;
import aQute.struct.*;
public class Index {
Reporter reporter = new ReporterAdapter(System.out);
static public class Repo extends struct {
public int version;
public List<Library.RevisionRef> revisionRefs = list();
public int increment;
public long date;
public boolean learning = true;
public boolean recurse = true;
// Manually print this so that we
// have 1 line per resource, making it easier on git
// to compare.
void write(Formatter format) throws Exception {
format.format("{\n\"version\" :%s,\n" + "\"increment\" :%s,\n" + "\"date\" :%s,\n"
+ "\"revisionRefs\" : [\n", version, increment, date);
String del = "";
for (Library.RevisionRef resource : revisionRefs) {
format.format(del);
format.flush();
codec.enc().to(format.out()).put(resource);
del = ",\n";
}
format.format("\n]}\n");
format.flush();
}
}
private static final SortedSet<Version> EMPTY_VERSIONS = Collections
.unmodifiableSortedSet(new TreeSet<Version>());
private File indexFile;
private Map<String,SortedMap<Version,Library.RevisionRef>> cache;
private Repo repo;
public Index(File file) {
this.indexFile = file;
}
static final JSONCodec codec = new JSONCodec();
private boolean dirty;
private void init() throws Exception {
if (repo == null) {
cache = new TreeMap<String,SortedMap<Version,Library.RevisionRef>>();
if (indexFile.isFile() && indexFile.length() > 100) {
repo = codec.dec().from(indexFile).get(new TypeReference<Repo>() {});
for (Library.RevisionRef r : repo.revisionRefs) {
SortedMap<Version,Library.RevisionRef> map = cache.get(r.bsn);
if (map == null) {
map = new TreeMap<Version,Library.RevisionRef>(Collections.reverseOrder());
cache.put(r.bsn, map);
}
Version v = toVersion(r.baseline, r.qualifier);
map.put(v, r);
}
} else {
repo = new Repo();
repo.version = 1;
}
}
}
public Set<String> getBsns() throws Exception {
init();
return cache.keySet();
}
public SortedSet<Version> getVersions(String bsn) throws Exception {
init();
Map<Version,Library.RevisionRef> map = cache.get(bsn);
if (map == null)
return EMPTY_VERSIONS;
return (SortedSet<Version>) map.keySet();
}
public boolean addRevision(Library.RevisionRef ref) throws Exception {
init();
Version v = toVersion(ref.baseline, ref.qualifier);
SortedMap<Version,Library.RevisionRef> map = cache.get(ref.bsn);
if (map == null) {
map = new TreeMap<Version,Library.RevisionRef>();
cache.put(ref.bsn, map);
}
boolean result = map.put(v, ref) != null;
repo.increment++;
dirty = true;
return result;
}
public Library.RevisionRef getRevisionRef(String bsn, Version version) throws Exception {
init();
Map<Version,Library.RevisionRef> map = cache.get(bsn);
if (map == null)
return null;
return map.get(version);
}
public boolean delete(String bsn, Version v) throws Exception {
init();
Map<Version,Library.RevisionRef> map = cache.get(bsn);
if (map != null) {
try {
Library.RevisionRef removed = map.remove(v);
if (removed != null) {
for (Iterator<RevisionRef> i = repo.revisionRefs.iterator(); i.hasNext();) {
RevisionRef other = i.next();
if (Arrays.equals(other.revision, removed.revision)) {
i.remove();
}
}
repo.revisionRefs.remove(removed);
repo.increment++;
dirty = true;
return true;
}
}
finally {
if (map.isEmpty())
cache.remove(bsn);
}
}
return false;
}
public void save(Writer out) throws Exception {
init();
repo.date = System.currentTimeMillis();
repo.revisionRefs = getRevisionRefs();
Formatter f = new Formatter(out);
repo.write(f);
}
public void save(OutputStream out) throws Exception {
save(new OutputStreamWriter(out));
}
public void save(File out) throws Exception {
File tmp = IO.createTempFile(out.getParentFile(), out.getName(), ".tmp");
FileWriter fout = new FileWriter(tmp);
try {
save(fout);
tmp.renameTo(out);
}
finally {
fout.close();
}
}
public void save() throws Exception {
if (dirty)
save(indexFile);
dirty = false;
}
static Version toVersion(String baseline, String qualifier) {
if (qualifier == null || qualifier.isEmpty())
return new Version(baseline);
else
return new Version(baseline + "." + qualifier);
}
public static Version toVersion(Library.RevisionRef ref) {
return toVersion(ref.baseline, ref.qualifier);
}
public Library.RevisionRef getRevisionRef(byte[] sha) throws Exception {
init();
for (SortedMap<Version, ? extends RevisionRef> list : cache.values()) {
for (RevisionRef r : list.values()) {
if (Arrays.equals(sha, r.revision))
return r;
}
}
return null;
}
public List<RevisionRef> getRevisionRefs() {
List<RevisionRef> refs = new ArrayList<Library.RevisionRef>();
for (SortedMap<Version, ? extends RevisionRef> list : cache.values()) {
refs.addAll(list.values());
}
return refs;
}
public void setReporter(Reporter reporter) {
this.reporter = reporter;
}
public boolean isLearning() {
return repo.learning;
}
public void setLearning(boolean learning) {
dirty |= repo.learning != learning;
repo.learning = learning;
}
public boolean isRecurse() {
return repo.recurse;
}
public void setRecurse(boolean learning) {
dirty |= repo.recurse != learning;
repo.recurse = learning;
}
}