package org.eclipse.dltk.tcl.indexing; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileInfo; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.dltk.ast.declarations.ModuleDeclaration; import org.eclipse.dltk.compiler.SourceElementRequestVisitor; import org.eclipse.dltk.compiler.problem.ProblemCollector; import org.eclipse.dltk.compiler.util.Util; import org.eclipse.dltk.core.DLTKContentTypeManager; import org.eclipse.dltk.core.caching.ArchiveCacheIndexBuilder; import org.eclipse.dltk.core.caching.ArchiveIndexContentChecker; import org.eclipse.dltk.core.caching.MixinModelCollector; import org.eclipse.dltk.core.caching.StructureModelCollector; import org.eclipse.dltk.core.search.indexing.SourceIndexerRequestor; import org.eclipse.dltk.tcl.ast.TclModule; import org.eclipse.dltk.tcl.core.TclLanguageToolkit; import org.eclipse.dltk.tcl.internal.core.TclASTCache; import org.eclipse.dltk.tcl.internal.core.TclSourceIndexerRequestor; import org.eclipse.dltk.tcl.internal.core.search.mixin.TclMixinBuildVisitor; import org.eclipse.dltk.tcl.internal.core.serialization.TclASTSaver; import org.eclipse.dltk.tcl.internal.parser.NewTclSourceParser; import org.eclipse.dltk.tcl.internal.parser.TclSourceElementRequestVisitor; import org.eclipse.dltk.tcl.parser.TclErrorCollector; import org.eclipse.dltk.tcl.parser.TclParser; import org.eclipse.dltk.tcl.parser.definitions.DefinitionManager; import org.eclipse.dltk.utils.TextUtils; /** * @since 2.0 */ public class DLTKEFSTclIndexer { private long totalSize = 0; private long totalIndexesSize = 0; private long totalASTIndexesSize = 0; public final static long VERSION = 200905291444l; public boolean isForceRebuild() { return false; } public void buildIndexFor(IFileStore folder, boolean recursive) { IFileInfo folderInfo = folder.fetchInfo(); if (!folderInfo.isDirectory()) { return; } IFileStore[] files; try { files = folder.childStores(EFS.NONE, new NullProgressMonitor()); } catch (CoreException e1) { e1.printStackTrace(); return; } List<IFileStore> toIndex = new ArrayList<IFileStore>(); for (IFileStore file : files) { IFileInfo fileInfo = file.fetchInfo(); if (fileInfo.isDirectory() && recursive) { buildIndexFor(file, recursive); } else if (needIndexing(file)) { toIndex.add(file); } } boolean readonly = folderInfo.getAttribute(EFS.ATTRIBUTE_READ_ONLY); if (readonly) { logReadonlyFolder(folder); } if (!toIndex.isEmpty() && !readonly) { // Check required rebuild or not boolean buildRequired = isForceRebuild(); IFileStore indexFile = folder.getChild(".dltk.index"); IFileStore astIndexFile = folder.getChild(".dltk.index.ast"); IFileInfo indexFileInfo = indexFile.fetchInfo(); IFileInfo astIndexFileInfo = astIndexFile.fetchInfo(); if (!buildRequired && !indexFileInfo.exists()) { buildRequired = true; } if (!buildRequired && !astIndexFileInfo.exists()) { buildRequired = true; } if (!buildRequired) { // Check for existing index files File indexFileLocal; try { indexFileLocal = indexFile.toLocalFile(EFS.CACHE, new NullProgressMonitor()); ArchiveIndexContentChecker checker = new ArchiveIndexContentChecker( indexFileLocal, VERSION, TclLanguageToolkit .getDefault()); if (checker.containChanges(indexFile)) { buildRequired = true; } } catch (CoreException e) { e.printStackTrace(); } } if (!buildRequired) { File astIndexFileLocal; try { astIndexFileLocal = indexFile.toLocalFile(EFS.CACHE, new NullProgressMonitor()); ArchiveIndexContentChecker astChecker = new ArchiveIndexContentChecker( astIndexFileLocal, VERSION, TclLanguageToolkit .getDefault()); if (astChecker.containChanges(astIndexFile)) { buildRequired = true; } } catch (CoreException e) { e.printStackTrace(); } } if (!buildRequired) { logIndexConsistent(folder); return; } logBeginOfFolder(folder); deleteIndexFiles(indexFile, astIndexFile); long filesSize = 0; try { ArchiveCacheIndexBuilder builder = new ArchiveCacheIndexBuilder( indexFile.openOutputStream(EFS.NONE, new NullProgressMonitor()), VERSION); ArchiveCacheIndexBuilder astIndexBuilder = new ArchiveCacheIndexBuilder( astIndexFile.openOutputStream(EFS.NONE, new NullProgressMonitor()), VERSION); for (IFileStore file : toIndex) { filesSize += indexFile(builder, astIndexBuilder, file); } builder.done(); astIndexBuilder.done(); logEntry(indexFile, filesSize); totalSize += filesSize; indexFileInfo = indexFile.fetchInfo(); astIndexFileInfo = astIndexFile.fetchInfo(); totalIndexesSize += indexFileInfo.getLength(); totalASTIndexesSize += astIndexFileInfo.getLength(); } catch (FileNotFoundException e) { // e.printStackTrace(); deleteIndexFiles(indexFile, astIndexFile); } catch (IOException e) { // e.printStackTrace(); deleteIndexFiles(indexFile, astIndexFile); } catch (Exception e) { reportUnknownError(folder); deleteIndexFiles(indexFile, astIndexFile); } } } public void logReadonlyFolder(IFileStore folder) { } private long indexFile(ArchiveCacheIndexBuilder builder, ArchiveCacheIndexBuilder astIndexBuilder, IFileStore file) throws CoreException, IOException, Exception { String content = new String(Util.getFileByteContent(file)); ProblemCollector dltkProblems = new ProblemCollector(); TclModule module = makeModule(content, dltkProblems); IFileInfo fileInfo = file.fetchInfo(); long timestamp = fileInfo.getLastModified(); if (fileInfo.getAttribute(EFS.ATTRIBUTE_SYMLINK)) { String target = fileInfo .getStringAttribute(EFS.ATTRIBUTE_LINK_TARGET); IFileStore linkTarget = file.getFileStore(new Path(target)); IFileInfo info = linkTarget.fetchInfo(); timestamp = info.getLastModified(); } ByteArrayOutputStream bout = new ByteArrayOutputStream(); TclASTSaver saver = new TclASTSaver(); saver.save(module, dltkProblems, bout); astIndexBuilder.addEntry(file.getName(), timestamp, TclASTCache.TCL_AST_ATTRIBUTE, new ByteArrayInputStream(bout .toByteArray())); // Store indexing information. SourceIndexerRequestor req = new TclSourceIndexerRequestor(); req.setIndexer(new NullIndexer()); StructureModelCollector collector = new StructureModelCollector(req); NewTclSourceParser parser = new NewTclSourceParser(); ModuleDeclaration ast = parser.parse(null, module, null); SourceElementRequestVisitor requestor = new TclSourceElementRequestVisitor( collector, null); ast.traverse(requestor); byte[] structure_index = collector.getBytes(); builder.addEntry(file.getName(), timestamp, TclASTCache.TCL_STRUCTURE_INDEX, new ByteArrayInputStream( structure_index)); // Store mixin index information. MixinModelCollector mixinCollector = new MixinModelCollector(); TclMixinBuildVisitor mixinVisitor = new TclMixinBuildVisitor(ast, null, false, mixinCollector); ast.traverse(mixinVisitor); byte[] mixin_index = mixinCollector.getBytes(); builder.addEntry(file.getName(), timestamp, TclASTCache.TCL_MIXIN_INDEX, new ByteArrayInputStream( mixin_index)); return content.length(); } private void deleteIndexFiles(IFileStore indexFile, IFileStore astIndexFile) { try { IFileInfo indexFileInfo = indexFile.fetchInfo(); if (indexFileInfo.exists()) { indexFile.delete(EFS.NONE, new NullProgressMonitor()); } IFileInfo astIndexFileInfo = astIndexFile.fetchInfo(); if (astIndexFileInfo.exists()) { astIndexFile.delete(EFS.NONE, new NullProgressMonitor()); } } catch (Exception e) { } } protected void logIndexConsistent(IFileStore folder) { } public void logBeginOfFolder(IFileStore folder) { } public void logEntry(IFileStore indexFile, long filesSize) { } protected void reportUnknownError(IFileStore folder) { } private TclModule makeModule(String content, ProblemCollector dltkProblems) { TclParser parser = new TclParser(); TclErrorCollector collector = new TclErrorCollector(); TclModule module = parser.parseModule(content, collector, DefinitionManager.getInstance().createProcessor()); if (dltkProblems != null) { collector.reportAll(dltkProblems, TextUtils .createLineTracker(content)); } return module; } private boolean needIndexing(IFileStore file) { IFileInfo fileInfo = file.fetchInfo(); if (fileInfo.isDirectory()) { return false; } return DLTKContentTypeManager.isValidFileNameForContentType( TclLanguageToolkit.getDefault(), file.getName()); } public long getTotalSize() { return this.totalSize; } public long getTotalIndexesSize() { return this.totalIndexesSize + this.totalASTIndexesSize; } public long getBasicIndexesSize() { return this.totalIndexesSize; } public long getASTIndexesSize() { return this.totalASTIndexesSize; } }