| /* |
| * Copyright (c) 2012, the Dart project authors. |
| * |
| * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except |
| * in compliance with the License. You may obtain a copy of the License at |
| * |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Unless required by applicable law or agreed to in writing, software distributed under the License |
| * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
| * or implied. See the License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package com.google.dart.engine.sdk; |
| |
| import com.google.dart.engine.AnalysisEngine; |
| import com.google.dart.engine.context.AnalysisContext; |
| import com.google.dart.engine.context.ChangeSet; |
| import com.google.dart.engine.internal.context.InternalAnalysisContext; |
| import com.google.dart.engine.internal.context.SdkAnalysisContext; |
| import com.google.dart.engine.internal.sdk.LibraryMap; |
| import com.google.dart.engine.internal.sdk.SdkLibrariesReader; |
| import com.google.dart.engine.source.DartUriResolver; |
| import com.google.dart.engine.source.FileBasedSource; |
| import com.google.dart.engine.source.Source; |
| import com.google.dart.engine.source.SourceFactory; |
| import com.google.dart.engine.utilities.io.FileUtilities; |
| import com.google.dart.engine.utilities.os.OSUtilities; |
| import com.google.dart.engine.utilities.translation.DartBlockBody; |
| import com.google.dart.engine.utilities.translation.DartOmit; |
| import com.google.dart.engine.utilities.translation.DartOptional; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| |
| /** |
| * Instances of the class {@code DirectoryBasedDartSdk} represent a Dart SDK installed in a |
| * specified directory. Typical Dart SDK layout is something like... |
| * |
| * <pre> |
| * dart-sdk/ |
| * bin/ |
| * dart[.exe] <-- VM |
| * lib/ |
| * core/ |
| * core.dart |
| * ... other core library files ... |
| * ... other libraries ... |
| * util/ |
| * ... Dart utilities ... |
| * Chromium/ <-- Dartium typically exists in a sibling directory |
| * </pre> |
| * |
| * @coverage dart.engine.sdk |
| */ |
| public class DirectoryBasedDartSdk implements DartSdk { |
| /** |
| * The {@link AnalysisContext} which is used for all of the sources in this {@link DartSdk}. |
| */ |
| private InternalAnalysisContext analysisContext; |
| |
| /** |
| * The directory containing the SDK. |
| */ |
| private final File sdkDirectory; |
| |
| /** |
| * The revision number of this SDK, or {@code "0"} if the revision number cannot be discovered. |
| */ |
| private String sdkVersion; |
| |
| /** |
| * The file containing the dart2js executable. |
| */ |
| private File dart2jsExecutable; |
| |
| /** |
| * The file containing the dart formatter executable. |
| */ |
| private File dartFmtExecutable; |
| |
| /** |
| * The file containing the Dartium executable. |
| */ |
| private File dartiumExecutable; |
| |
| /** |
| * The file containing the pub executable. |
| */ |
| private File pubExecutable; |
| |
| /** |
| * The file containing the VM executable. |
| */ |
| private File vmExecutable; |
| |
| /** |
| * A mapping from Dart library URI's to the library represented by that URI. |
| */ |
| private LibraryMap libraryMap; |
| |
| /** |
| * The default SDK, or {@code null} if the default SDK either has not yet been created or cannot |
| * be created for some reason. |
| */ |
| private static DirectoryBasedDartSdk DEFAULT_SDK; |
| |
| /** |
| * The name of the directory within the SDK directory that contains executables. |
| */ |
| private static final String BIN_DIRECTORY_NAME = "bin"; //$NON-NLS-1$ |
| |
| /** |
| * The name of the directory on non-Mac that contains dartium. |
| */ |
| private static final String DARTIUM_DIRECTORY_NAME = "chromium"; //$NON-NLS-1$ |
| |
| /** |
| * The name of the dart2js executable on non-windows operating systems. |
| */ |
| private static final String DART2JS_EXECUTABLE_NAME = "dart2js"; //$NON-NLS-1$ |
| |
| /** |
| * The name of the file containing the dart2js executable on Windows. |
| */ |
| private static final String DART2JS_EXECUTABLE_NAME_WIN = "dart2js.bat"; //$NON-NLS-1$ |
| |
| /** |
| * The name of the dart formatter executable on non-windows operating systems. |
| */ |
| private static final String DARTFMT_EXECUTABLE_NAME = "dartfmt"; //$NON-NLS-1$ |
| |
| /** |
| * The name of the dart formatter executable on windows operating systems. |
| */ |
| private static final String DARTFMT_EXECUTABLE_NAME_WIN = "dartfmt.bat"; //$NON-NLS-1$ |
| |
| /** |
| * The name of the file containing the Dartium executable on Linux. |
| */ |
| private static final String DARTIUM_EXECUTABLE_NAME_LINUX = "chrome"; //$NON-NLS-1$ |
| |
| /** |
| * The name of the file containing the Dartium executable on Macintosh. |
| */ |
| private static final String DARTIUM_EXECUTABLE_NAME_MAC = "Chromium.app/Contents/MacOS/Chromium"; //$NON-NLS-1$ |
| |
| /** |
| * The name of the file containing the Dartium executable on Windows. |
| */ |
| private static final String DARTIUM_EXECUTABLE_NAME_WIN = "Chrome.exe"; //$NON-NLS-1$ |
| |
| /** |
| * The name of the {@link System} property whose value is the path to the default Dart SDK |
| * directory. |
| */ |
| private static final String DEFAULT_DIRECTORY_PROPERTY_NAME = "com.google.dart.sdk"; //$NON-NLS-1$ |
| |
| /** |
| * The name of the directory within the SDK directory that contains documentation for the |
| * libraries. |
| */ |
| private static final String DOCS_DIRECTORY_NAME = "docs"; //$NON-NLS-1$ |
| |
| /** |
| * The suffix added to the name of a library to derive the name of the file containing the |
| * documentation for that library. |
| */ |
| private static final String DOC_FILE_SUFFIX = "_api.json"; //$NON-NLS-1$ |
| |
| /** |
| * The name of the directory within the SDK directory that contains the libraries file. |
| */ |
| private static final String INTERNAL_DIR = "_internal"; //$NON-NLS-1$ |
| |
| /** |
| * The name of the directory within the SDK directory that contains the libraries. |
| */ |
| private static final String LIB_DIRECTORY_NAME = "lib"; //$NON-NLS-1$ |
| |
| /** |
| * The name of the libraries file. |
| */ |
| private static final String LIBRARIES_FILE = "libraries.dart"; //$NON-NLS-1$ |
| |
| /** |
| * The name of the pub executable on windows. |
| */ |
| private static final String PUB_EXECUTABLE_NAME_WIN = "pub.bat"; //$NON-NLS-1$ |
| |
| /** |
| * The name of the pub executable on non-windows operating systems. |
| */ |
| private static final String PUB_EXECUTABLE_NAME = "pub"; //$NON-NLS-1$ |
| |
| /** |
| * The name of the file within the SDK directory that contains the version number of the SDK. |
| */ |
| private static final String VERSION_FILE_NAME = "version"; //$NON-NLS-1$ |
| |
| /** |
| * The name of the file containing the VM executable on the Windows operating system. |
| */ |
| private static final String VM_EXECUTABLE_NAME_WIN = "dart.exe"; //$NON-NLS-1$ |
| |
| /** |
| * The name of the file containing the VM executable on non-Windows operating systems. |
| */ |
| private static final String VM_EXECUTABLE_NAME = "dart"; //$NON-NLS-1$ |
| |
| /** |
| * Return the default Dart SDK, or {@code null} if the directory containing the default SDK cannot |
| * be determined (or does not exist). |
| * |
| * @return the default Dart SDK |
| */ |
| public static DirectoryBasedDartSdk getDefaultSdk() { |
| if (DEFAULT_SDK == null) { |
| File sdkDirectory = getDefaultSdkDirectory(); |
| if (sdkDirectory == null) { |
| return null; |
| } |
| DEFAULT_SDK = new DirectoryBasedDartSdk(sdkDirectory); |
| } |
| return DEFAULT_SDK; |
| } |
| |
| /** |
| * Return the default directory for the Dart SDK, or {@code null} if the directory cannot be |
| * determined (or does not exist). The default directory is provided by a {@link System} property |
| * named {@code com.google.dart.sdk}. |
| * |
| * @return the default directory for the Dart SDK |
| */ |
| public static File getDefaultSdkDirectory() { |
| String sdkProperty = System.getProperty(DEFAULT_DIRECTORY_PROPERTY_NAME); |
| if (sdkProperty == null) { |
| return null; |
| } |
| File sdkDirectory = new File(sdkProperty); |
| if (!sdkDirectory.exists()) { |
| return null; |
| } |
| return sdkDirectory; |
| } |
| |
| /** |
| * Initialize a newly created SDK to represent the Dart SDK installed in the given directory. |
| * |
| * @param sdkDirectory the directory containing the SDK |
| */ |
| @DartOmit |
| public DirectoryBasedDartSdk(File sdkDirectory) { |
| this(sdkDirectory, false); |
| } |
| |
| /** |
| * Initialize a newly created SDK to represent the Dart SDK installed in the given directory. |
| * |
| * @param sdkDirectory the directory containing the SDK |
| * @param useDart2jsPaths {@code true} if the dart2js path should be used when it is available |
| */ |
| public DirectoryBasedDartSdk(File sdkDirectory, |
| @DartOptional(defaultValue = "false") boolean useDart2jsPaths) { |
| this.sdkDirectory = sdkDirectory.getAbsoluteFile(); |
| libraryMap = initialLibraryMap(useDart2jsPaths); |
| } |
| |
| @Override |
| public Source fromFileUri(URI uri) { |
| File file = new File(uri); |
| String filePath = file.getAbsolutePath(); |
| String libPath = getLibraryDirectory().getAbsolutePath(); |
| if (!filePath.startsWith(libPath + File.separator)) { |
| return null; |
| } |
| filePath = filePath.substring(libPath.length() + 1); |
| for (SdkLibrary library : libraryMap.getSdkLibraries()) { |
| String libraryPath = library.getPath(); |
| if (filePath.replace('\\', '/').equals(libraryPath)) { |
| String path = library.getShortName(); |
| try { |
| return new FileBasedSource(new URI(path), file); |
| } catch (URISyntaxException exception) { |
| AnalysisEngine.getInstance().getLogger().logInformation( |
| "Failed to create URI: " + path, |
| exception); |
| return null; |
| } |
| } |
| libraryPath = new File(libraryPath).getParent(); |
| if (filePath.startsWith(libraryPath + File.separator)) { |
| String path = library.getShortName() + "/" + filePath.substring(libraryPath.length() + 1); |
| try { |
| return new FileBasedSource(new URI(path), file); |
| } catch (URISyntaxException exception) { |
| AnalysisEngine.getInstance().getLogger().logInformation( |
| "Failed to create URI: " + path, |
| exception); |
| return null; |
| } |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public AnalysisContext getContext() { |
| if (analysisContext == null) { |
| analysisContext = new SdkAnalysisContext(); |
| SourceFactory factory = new SourceFactory(new DartUriResolver(this)); |
| analysisContext.setSourceFactory(factory); |
| String[] uris = getUris(); |
| ChangeSet changeSet = new ChangeSet(); |
| for (String uri : uris) { |
| changeSet.addedSource(factory.forUri(uri)); |
| } |
| analysisContext.applyChanges(changeSet); |
| } |
| return analysisContext; |
| } |
| |
| /** |
| * Return the file containing the dart2js executable, or {@code null} if it does not exist. |
| * |
| * @return the file containing the dart2js executable |
| */ |
| public File getDart2JsExecutable() { |
| synchronized (this) { |
| if (dart2jsExecutable == null) { |
| dart2jsExecutable = FileUtilities.verifyExecutable(new File(new File( |
| sdkDirectory, |
| BIN_DIRECTORY_NAME), OSUtilities.isWindows() ? DART2JS_EXECUTABLE_NAME_WIN |
| : DART2JS_EXECUTABLE_NAME)); |
| } |
| } |
| return dart2jsExecutable; |
| } |
| |
| /** |
| * Return the file containing the dart formatter executable, or {@code null} if it does not exist. |
| * |
| * @return the file containing the dart formatter executable |
| */ |
| public File getDartFmtExecutable() { |
| synchronized (this) { |
| if (dartFmtExecutable == null) { |
| dartFmtExecutable = FileUtilities.verifyExecutable(new File(new File( |
| sdkDirectory, |
| BIN_DIRECTORY_NAME), OSUtilities.isWindows() ? DARTFMT_EXECUTABLE_NAME_WIN |
| : DARTFMT_EXECUTABLE_NAME)); |
| } |
| } |
| return dartFmtExecutable; |
| } |
| |
| /** |
| * Return the file containing the Dartium executable, or {@code null} if it does not exist. |
| * |
| * @return the file containing the Dartium executable |
| */ |
| public File getDartiumExecutable() { |
| synchronized (this) { |
| if (dartiumExecutable == null) { |
| dartiumExecutable = FileUtilities.verifyExecutable(new File( |
| getDartiumWorkingDirectory(), |
| getDartiumBinaryName())); |
| } |
| } |
| return dartiumExecutable; |
| } |
| |
| /** |
| * Return the directory where dartium can be found (the directory that will be the working |
| * directory is Dartium is invoked without changing the default). |
| * |
| * @return the directory where dartium can be found |
| */ |
| public File getDartiumWorkingDirectory() { |
| return getDartiumWorkingDirectory(sdkDirectory.getParentFile()); |
| } |
| |
| /** |
| * Return the directory where dartium can be found (the directory that will be the working |
| * directory is Dartium is invoked without changing the default). |
| * |
| * @param installDir the installation directory |
| * @return the directory where dartium can be found |
| */ |
| public File getDartiumWorkingDirectory(File installDir) { |
| return new File(installDir, DARTIUM_DIRECTORY_NAME); |
| } |
| |
| /** |
| * Return the directory containing the SDK. |
| * |
| * @return the directory containing the SDK |
| */ |
| public File getDirectory() { |
| return sdkDirectory; |
| } |
| |
| /** |
| * Return the directory containing documentation for the SDK. |
| * |
| * @return the SDK's documentation directory |
| */ |
| public File getDocDirectory() { |
| return new File(sdkDirectory, DOCS_DIRECTORY_NAME); |
| } |
| |
| /** |
| * Return the auxiliary documentation file for the given library, or {@code null} if no such file |
| * exists. |
| * |
| * @param libraryName the name of the library associated with the documentation file to be |
| * returned |
| * @return the auxiliary documentation file for the library |
| */ |
| public File getDocFileFor(String libraryName) { |
| File dir = getDocDirectory(); |
| if (!dir.exists()) { |
| return null; |
| } |
| File libDir = new File(dir, libraryName); |
| File docFile = new File(libDir, libraryName + DOC_FILE_SUFFIX); |
| if (docFile.exists()) { |
| return docFile; |
| } |
| return null; |
| } |
| |
| /** |
| * Return the directory within the SDK directory that contains the libraries. |
| * |
| * @return the directory that contains the libraries |
| */ |
| public File getLibraryDirectory() { |
| return new File(sdkDirectory, LIB_DIRECTORY_NAME); |
| } |
| |
| /** |
| * Return the file containing the Pub executable, or {@code null} if it does not exist. |
| * |
| * @return the file containing the Pub executable |
| */ |
| public File getPubExecutable() { |
| synchronized (this) { |
| if (pubExecutable == null) { |
| pubExecutable = FileUtilities.verifyExecutable(new File(new File( |
| sdkDirectory, |
| BIN_DIRECTORY_NAME), OSUtilities.isWindows() ? PUB_EXECUTABLE_NAME_WIN |
| : PUB_EXECUTABLE_NAME)); |
| } |
| } |
| return pubExecutable; |
| } |
| |
| @Override |
| public SdkLibrary[] getSdkLibraries() { |
| return libraryMap.getSdkLibraries(); |
| } |
| |
| @Override |
| public SdkLibrary getSdkLibrary(String dartUri) { |
| return libraryMap.getLibrary(dartUri); |
| } |
| |
| /** |
| * Return the revision number of this SDK, or {@code "0"} if the revision number cannot be |
| * discovered. |
| * |
| * @return the revision number of this SDK |
| */ |
| @Override |
| public String getSdkVersion() { |
| synchronized (this) { |
| if (sdkVersion == null) { |
| sdkVersion = DEFAULT_VERSION; |
| File revisionFile = new File(sdkDirectory, VERSION_FILE_NAME); |
| try { |
| String revision = FileUtilities.getContents(revisionFile); |
| if (revision != null) { |
| sdkVersion = revision.trim(); |
| } |
| } catch (IOException exception) { |
| // Fall through to return the default. |
| } |
| } |
| } |
| return sdkVersion; |
| } |
| |
| /** |
| * Return an array containing the library URI's for the libraries defined in this SDK. |
| * |
| * @return the library URI's for the libraries defined in this SDK |
| */ |
| @Override |
| public String[] getUris() { |
| return libraryMap.getUris(); |
| } |
| |
| /** |
| * Return the file containing the VM executable, or {@code null} if it does not exist. |
| * |
| * @return the file containing the VM executable |
| */ |
| public File getVmExecutable() { |
| synchronized (this) { |
| if (vmExecutable == null) { |
| vmExecutable = FileUtilities.verifyExecutable(new File(new File( |
| sdkDirectory, |
| BIN_DIRECTORY_NAME), getVmBinaryName())); |
| } |
| } |
| return vmExecutable; |
| } |
| |
| /** |
| * Return {@code true} if this SDK includes documentation. |
| * |
| * @return {@code true} if this installation of the SDK has documentation |
| */ |
| public boolean hasDocumentation() { |
| return getDocDirectory().exists(); |
| } |
| |
| /** |
| * Return {@code true} if the Dartium binary is available. |
| * |
| * @return {@code true} if the Dartium binary is available |
| */ |
| public boolean isDartiumInstalled() { |
| return getDartiumExecutable() != null; |
| } |
| |
| @Override |
| public Source mapDartUri(String dartUri) { |
| String libraryName; |
| String relativePath; |
| int index = dartUri.indexOf('/'); |
| if (index >= 0) { |
| libraryName = dartUri.substring(0, index); |
| relativePath = dartUri.substring(index + 1); |
| } else { |
| libraryName = dartUri; |
| relativePath = ""; |
| } |
| SdkLibrary library = getSdkLibrary(libraryName); |
| if (library == null) { |
| return null; |
| } |
| try { |
| File file = new File(getLibraryDirectory(), library.getPath()); |
| if (!relativePath.isEmpty()) { |
| file = file.getParentFile(); |
| file = new File(file, relativePath); |
| } |
| return new FileBasedSource(new URI(dartUri), file); |
| } catch (URISyntaxException exception) { |
| return null; |
| } |
| } |
| |
| /** |
| * Read all of the configuration files to initialize the library maps. |
| * |
| * @param useDart2jsPaths {@code true} if the dart2js path should be used when it is available |
| * @return the initialized library map |
| */ |
| protected LibraryMap initialLibraryMap(boolean useDart2jsPaths) { |
| File librariesFile = new File(new File(getLibraryDirectory(), INTERNAL_DIR), LIBRARIES_FILE); |
| try { |
| String contents = FileUtilities.getContents(librariesFile); |
| return new SdkLibrariesReader(useDart2jsPaths).readFromFile(librariesFile, contents); |
| } catch (Exception exception) { |
| AnalysisEngine.getInstance().getLogger().logError( |
| "Could not initialize the library map from " + librariesFile.getAbsolutePath(), |
| exception); |
| return new LibraryMap(); |
| } |
| } |
| |
| /** |
| * Ensure that the dart VM is executable. If it is not, make it executable and log that it was |
| * necessary for us to do so. |
| */ |
| @DartBlockBody({}) |
| private void ensureVmIsExecutable() { |
| File dartVm = getVmExecutable(); |
| if (dartVm != null) { |
| if (!dartVm.canExecute()) { |
| FileUtilities.makeExecutable(dartVm); |
| AnalysisEngine.getInstance().getLogger().logError(dartVm.getPath() + " was not executable"); |
| } |
| } |
| } |
| |
| /** |
| * Return the name of the file containing the Dartium executable. |
| * |
| * @return the name of the file containing the Dartium executable |
| */ |
| private String getDartiumBinaryName() { |
| if (OSUtilities.isWindows()) { |
| return DARTIUM_EXECUTABLE_NAME_WIN; |
| } else if (OSUtilities.isMac()) { |
| return DARTIUM_EXECUTABLE_NAME_MAC; |
| } else { |
| return DARTIUM_EXECUTABLE_NAME_LINUX; |
| } |
| } |
| |
| /** |
| * Return the name of the file containing the VM executable. |
| * |
| * @return the name of the file containing the VM executable |
| */ |
| private String getVmBinaryName() { |
| if (OSUtilities.isWindows()) { |
| return VM_EXECUTABLE_NAME_WIN; |
| } else { |
| return VM_EXECUTABLE_NAME; |
| } |
| } |
| |
| } |