package org.python.pydev.core; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.io.StringReader; import java.nio.charset.IllegalCharsetNameException; import java.util.zip.ZipFile; import org.eclipse.core.filebuffers.FileBuffers; import org.eclipse.core.filebuffers.ITextFileBuffer; import org.eclipse.core.filebuffers.ITextFileBufferManager; import org.eclipse.core.filebuffers.LocationKind; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.jface.text.IDocument; import org.python.pydev.core.callbacks.ICallback0; import org.python.pydev.core.log.Log; import com.aptana.shared_core.io.FileUtils; import com.aptana.shared_core.string.FastStringBuffer; /** * File utilities that need access to: * - ITextFileBufferManager * - IProject/IResource * * Also, the functions to load documents may suppose they're dealing with Python files (i.e.: * to get the encoding to open the stream properly if we weren't able to get the stream from * the ITextFileBufferManager). */ public class FileUtilsFileBuffer { /** * Characters that files in the filesystem cannot have. */ public static char[] INVALID_FILESYSTEM_CHARS = { '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '[', ']', '{', '}', '=', '+', '.', ' ', '`', '~', '\'', '"', ',', ';' }; /** * Determines if we're in tests: When in tests, some warnings may be supressed. */ public static boolean IN_TESTS = false; /** * @return a valid name for a project so that the returned name can be used to create a file in the filesystem */ public static String getValidProjectName(IProject project) { String name = project.getName(); for (char c : INVALID_FILESYSTEM_CHARS) { name = name.replace(c, '_'); } return name; } public static IDocument getDocFromFile(java.io.File f) throws IOException { return getDocFromFile(f, true); } /** * @return a string with the contents from a path within a zip file. */ public static String getStringFromZip(File f, String pathInZip) throws Exception { return (String) getCustomReturnFromZip(f, pathInZip, String.class); } /** * @return a document with the contents from a path within a zip file. */ public static IDocument getDocFromZip(File f, String pathInZip) throws Exception { return (IDocument) getCustomReturnFromZip(f, pathInZip, IDocument.class); } /** * @param f the zip file that should be opened * @param pathInZip the path within the zip file that should be gotten * @param returnType the class that specifies the return type of this method. * If null, it'll return in the fastest possible way available. * Valid options are: * String.class * IDocument.class * FastStringBuffer.class * * @return an object with the contents from a path within a zip file, having the return type * of the object specified by the parameter returnType. */ public static Object getCustomReturnFromZip(File f, String pathInZip, Class<? extends Object> returnType) throws Exception { ZipFile zipFile = new ZipFile(f, ZipFile.OPEN_READ); try { InputStream inputStream = zipFile.getInputStream(zipFile.getEntry(pathInZip)); try { return FileUtils.getStreamContents(inputStream, null, null, returnType); } finally { inputStream.close(); } } finally { zipFile.close(); } } /** * @return a string with the contents of the passed file */ public static String getStringFromFile(java.io.File f, boolean loadIfNotInWorkspace) throws IOException { return (String) getCustomReturnFromFile(f, loadIfNotInWorkspace, String.class); } /** * @return the document given its 'filesystem' file */ public static IDocument getDocFromFile(java.io.File f, boolean loadIfNotInWorkspace) throws IOException { return (IDocument) getCustomReturnFromFile(f, loadIfNotInWorkspace, IDocument.class); } /** * @param f the file from where we want to get the contents * @param returnType the class that specifies the return type of this method. * If null, it'll return in the fastest possible way available. * Valid options are: * String.class * IDocument.class * FastStringBuffer.class * * * @return an object with the contents from the file, having the return type * of the object specified by the parameter returnType. */ public static Object getCustomReturnFromFile(java.io.File f, boolean loadIfNotInWorkspace, Class<? extends Object> returnType) throws IOException { IPath path = Path.fromOSString(FileUtils.getFileAbsolutePath(f)); IDocument doc = getDocFromPath(path); if (doc != null) { if (returnType == null || returnType == IDocument.class) { return doc; } else if (returnType == String.class) { return doc.get(); } else if (returnType == FastStringBuffer.class) { return new FastStringBuffer(doc.get(), 16); } else { throw new RuntimeException("Don't know how to treat requested return type: " + returnType); } } if (doc == null && loadIfNotInWorkspace) { FileInputStream stream = new FileInputStream(f); try { String encoding = FileUtils.getPythonFileEncoding(f); return FileUtils.getStreamContents(stream, encoding, null, returnType); } finally { try { if (stream != null) stream.close(); } catch (Exception e) { Log.log(e); } } } return doc; } /** * @param path the path we're interested in * @return a file buffer to be used. */ @SuppressWarnings("deprecation") public static ITextFileBuffer getBufferFromPath(IPath path) { try { try { //eclipse 3.3 has a different interface ITextFileBufferManager textFileBufferManager = ITextFileBufferManager.DEFAULT; if (textFileBufferManager != null) {//we don't have it in tests ITextFileBuffer textFileBuffer = textFileBufferManager.getTextFileBuffer(path, LocationKind.LOCATION); if (textFileBuffer != null) { //we don't have it when it is not properly refreshed return textFileBuffer; } } } catch (Throwable e) {//NoSuchMethod/NoClassDef exception if (e instanceof ClassNotFoundException || e instanceof LinkageError || e instanceof NoSuchMethodException || e instanceof NoSuchMethodError || e instanceof NoClassDefFoundError) { ITextFileBufferManager textFileBufferManager = FileBuffers.getTextFileBufferManager(); if (textFileBufferManager != null) {//we don't have it in tests ITextFileBuffer textFileBuffer = textFileBufferManager.getTextFileBuffer(path); if (textFileBuffer != null) { //we don't have it when it is not properly refreshed return textFileBuffer; } } } else { throw e; } } return null; } catch (Throwable e) { //private static final IWorkspaceRoot WORKSPACE_ROOT= ResourcesPlugin.getWorkspace().getRoot(); //throws an error and we don't even have access to the FileBuffers class in tests if (!IN_TESTS) { Log.log("Unable to get doc from text file buffer"); } return null; } } /** * @return null if it was unable to get the document from the path (this may happen if it was not refreshed). * Or the document that represents the file */ public static IDocument getDocFromPath(IPath path) { ITextFileBuffer buffer = getBufferFromPath(path); if (buffer != null) { return buffer.getDocument(); } return null; } public static ICallback0<IDocument> getDocOnCallbackFromResource(final IResource resource) { return new ICallback0<IDocument>() { private IDocument cache; private boolean calledOnce = false; public IDocument call() { if (!calledOnce) { calledOnce = true; cache = getDocFromResource(resource); } return cache; } }; } /** * Returns a document, created with the contents of a resource (first tries to get from the 'FileBuffers', * and if that fails, it creates one reading the file. */ public static IDocument getDocFromResource(IResource resource) { IProject project = resource.getProject(); if (project != null && resource instanceof IFile && resource.exists()) { IFile file = (IFile) resource; try { if (!file.isSynchronized(IResource.DEPTH_ZERO)) { file.refreshLocal(IResource.DEPTH_ZERO, new NullProgressMonitor()); } IPath path = file.getFullPath(); IDocument doc = getDocFromPath(path); if (doc == null) { //can this actually happen?... yeap, it can (if file does not exist) doc = (IDocument) FileUtils.getStreamContents(file.getContents(true), null, null, IDocument.class); } return doc; } catch (CoreException e) { //it may stop existing from the initial exists check to the getContents call return null; } catch (Exception e) { Log.log(e); } } return null; } /** * The encoding declared in the document is returned (according to the PEP: http://www.python.org/doc/peps/pep-0263/) */ public static String getPythonFileEncoding(IDocument doc, String fileLocation) throws IllegalCharsetNameException { Reader inputStreamReader = new StringReader(doc.get()); return FileUtils.getPythonFileEncoding(inputStreamReader, fileLocation); } }