/**
* Copyright (c) 2013-2016 Angelo ZERR.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation
*/
package tern.repository;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import tern.TernException;
import tern.metadata.TernModuleMetadata;
import tern.metadata.TernModuleMetadataManager;
import tern.server.ITernModule;
import tern.server.ITernPlugin;
import tern.server.ModuleType;
import tern.utils.ExtensionUtils;
import tern.utils.IOUtils;
import tern.utils.TernModuleHelper;
import tern.utils.ZipUtils;
/**
* Tern repository implementation.
*
*/
public class TernRepository implements ITernRepository {
private static final String DEFS_FOLDER = "defs";
private static final String PLUGIN_FOLDER = "plugin";
private static final List<String> IGNORE_PLUGINS = Arrays
.asList(new String[] { "commonjs", "modules", "node_resolve" });
private final String name;
private File baseDir;
private File nodeModulesDir;
private File ternBaseDir;
private final boolean defaultRepository;
private Map<String, ITernModule> modules;
private Map<String, ITernModule> modulesByOrigin;
private ITernPlugin[] linters;
private final TernModuleMetadataManager metadataManager;
public TernRepository(String name, File baseDir) {
this(name, baseDir, false);
}
public TernRepository(String name, File baseDir, boolean defaultRepository) {
this.name = name;
this.setBaseDir(baseDir);
this.defaultRepository = defaultRepository;
this.metadataManager = new TernModuleMetadataManager(this);
}
@Override
public String getName() {
return name;
}
@Override
public ITernModule[] getModules() throws TernException {
intializeIfNeeded();
return modules.values().toArray(ITernModule.EMPTY_MODULE);
}
@Override
public ITernModule getModule(String name) {
try {
intializeIfNeeded();
return modules.get(name);
} catch (TernException e) {
return null;
}
}
@Override
public ITernModule getModuleByOrigin(String origin) {
try {
intializeIfNeeded();
return modulesByOrigin.get(origin);
} catch (TernException e) {
return null;
}
}
private void intializeIfNeeded() throws TernException {
if (modules == null) {
Map<String, ITernModule> modules = new HashMap<String, ITernModule>();
Map<String, ITernModule> modulesByOrigin = new HashMap<String, ITernModule>();
loadModules(modules, modulesByOrigin);
this.modules = modules;
this.modulesByOrigin = modulesByOrigin;
linters = searchLinters(modules.values());
}
}
private ITernPlugin[] searchLinters(Collection<ITernModule> values) {
Collection<ITernPlugin> linters = new ArrayList<ITernPlugin>();
for (ITernModule module : values) {
if (module.getModuleType() == ModuleType.Plugin && ((ITernPlugin) module).isLinter()) {
linters.add((ITernPlugin) module);
}
}
return linters.toArray(ITernPlugin.EMPTY_PLUGIN);
}
private void loadModules(Map<String, ITernModule> modules, Map<String, ITernModule> modulesByOrigin)
throws TernException {
// defs
loadModules(modules, modulesByOrigin, new File(getTernBaseDir(), DEFS_FOLDER), null);
// plugin
loadModules(modules, modulesByOrigin, new File(getTernBaseDir(), PLUGIN_FOLDER), IGNORE_PLUGINS);
// node_modules
loadModules(modules, modulesByOrigin, getNodeModulesDir(), null);
}
private void loadModules(Map<String, ITernModule> modules, Map<String, ITernModule> modulesByOrigin, File baseDir,
List<String> ignoreModules) throws TernException {
if (baseDir.exists()) {
File[] files = baseDir.listFiles();
File file = null;
ITernModule module = null;
for (int i = 0; i < files.length; i++) {
file = files[i];
module = TernModuleHelper.createModule(file, this, null);
if (module != null && !isIgnoreModule(module, ignoreModules)) {
modules.put(module.getName(), module);
modulesByOrigin.put(module.getOrigin(), module);
}
}
}
}
private boolean isIgnoreModule(ITernModule module, List<String> ignoreModules) {
if (ignoreModules == null) {
return false;
}
return ignoreModules.contains(module.getName());
}
@Override
public void refresh() {
this.modules = null;
}
@Override
public File getBaseDir() {
return baseDir;
}
@Override
public void setBaseDir(File baseDir) {
this.baseDir = baseDir;
this.nodeModulesDir = new File(baseDir, "node_modules");
this.ternBaseDir = new File(nodeModulesDir, "tern");
}
@Override
public File getNodeModulesDir() {
return nodeModulesDir;
}
@Override
public File getTernBaseDir() {
return ternBaseDir;
}
@Override
public String getTernBaseDirAsString() {
return TernModuleHelper.getPath(getTernBaseDir());
}
@Override
public boolean isDefault() {
return defaultRepository;
}
@Override
public File getFile(ITernModule module) {
// check if module is inside tern/defs or tern/plugin
String fileName = TernModuleHelper.getFileName(module);
File moduleFile = null;
switch (module.getModuleType()) {
case Plugin:
case Configurable:
moduleFile = new File(ternBaseDir,
new StringBuilder(PLUGIN_FOLDER).append('/').append(fileName).toString());
break;
case Def:
moduleFile = new File(ternBaseDir, new StringBuilder(DEFS_FOLDER).append('/').append(fileName).toString());
break;
}
if (moduleFile.exists()) {
return moduleFile;
}
moduleFile = new File(getNodeModulesDir(), new StringBuilder(ExtensionUtils.TERN_SUFFIX)
.append(module.getName()).append('/').append(fileName).toString());
if (moduleFile.exists()) {
return moduleFile;
}
return null;
}
@Override
public ITernPlugin[] getLinters() {
try {
intializeIfNeeded();
} catch (TernException e) {
e.printStackTrace();
return ITernPlugin.EMPTY_PLUGIN;
}
return linters;
}
@Override
public void install(File moduleFile) throws IOException, TernException {
if (!moduleFile.exists()) {
throw new TernException(
"Cannot install module file <" + TernModuleHelper.getPath(moduleFile) + ">. It doesn't exist.");
}
File baseDir = getNodeModulesDir();
if (!baseDir.exists()) {
throw new TernException("Cannot install module file <" + TernModuleHelper.getPath(moduleFile)
+ ">. Tern repository <" + TernModuleHelper.getPath(baseDir) + "> doesn't exists.");
}
if (ZipUtils.isZipFile(moduleFile) || ZipUtils.isJarFile(moduleFile)) {
// Zip or JAR file, unzip it to the tern repository.
ZipUtils.extract(moduleFile, baseDir);
} else if (moduleFile.isDirectory()) {
// Folder, copy this folder to the tern repository
IOUtils.copy(moduleFile, new File(baseDir, moduleFile.getName()), false);
} else {
throw new TernException("Cannot install module file <" + TernModuleHelper.getPath(moduleFile)
+ ">. It must be a folder or a zip/jar file.");
}
}
@Override
public TernModuleMetadata getDefaultMetadata(String moduleName) {
return metadataManager.getMetadata(moduleName);
}
}