/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package se.kth.karamel.common.cookbookmeta;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import se.kth.karamel.common.util.IoUtils;
import se.kth.karamel.common.util.Settings;
import se.kth.karamel.common.exception.CookbookUrlException;
import se.kth.karamel.common.exception.MetadataParseException;
import se.kth.karamel.common.exception.NoKaramelizedCookbookException;
import se.kth.karamel.common.exception.RecipeParseException;
import se.kth.karamel.common.exception.ValidationException;
/**
* Represents a coobook located in github
*
* @author kamal
*/
public class KaramelizedCookbook {
private static final org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(KaramelizedCookbook.class);
private final CookbookUrls urls;
private final DefaultRb defaultRb;
private final MetadataRb metadataRb;
private final KaramelFile karamelFile;
private final Berksfile berksFile;
private final List<ExperimentRecipe> experimentRecipes = new ArrayList<>();
private InstallRecipe installRecipe;
private String json;
private boolean reciepsLoaded = false;
/**
*
* @param homeUrl url or canonical path to the cookbook
* @param local true if it is a canonical path (to a cloned cookbook) and not a URL.
* @throws CookbookUrlException
* @throws MetadataParseException
* @throws se.kth.karamel.common.exception.ValidationException
* @throws se.kth.karamel.common.exception.NoKaramelizedCookbookException
*/
public KaramelizedCookbook(String homeUrl, boolean local) throws CookbookUrlException, MetadataParseException,
ValidationException, NoKaramelizedCookbookException {
if (local) {
Settings.USE_CLONED_REPO_FILES = true;
}
CookbookUrls.Builder builder = new CookbookUrls.Builder();
this.urls = builder.url(homeUrl).build();
String karamelFileC;
try {
karamelFileC = IoUtils.readContent(urls.karamelFile);
} catch (IOException e) {
throw new NoKaramelizedCookbookException(e);
}
try {
String defaultRbC = IoUtils.readContent(urls.attrFile);
String metadataRbC = IoUtils.readContent(urls.metadataFile);
String berksfileC = IoUtils.readContent(urls.berksFile);
this.defaultRb = new DefaultRb(defaultRbC);
this.metadataRb = MetadataParser.parse(metadataRbC);
this.metadataRb.normalizeRecipeNames();
this.metadataRb.setDefaults(defaultRb);
this.karamelFile = new KaramelFile(karamelFileC);
this.berksFile = new Berksfile(berksfileC);
} catch (IOException e) {
Settings.USE_CLONED_REPO_FILES = false;
throw new CookbookUrlException("", e);
}
}
public KaramelizedCookbook(CookbookUrls urls, String defaultRbC, String metadataRbC, String karamelFileC,
String berksfileC) throws CookbookUrlException, MetadataParseException, ValidationException {
this.urls = urls;
this.defaultRb = new DefaultRb(defaultRbC);
this.metadataRb = MetadataParser.parse(metadataRbC);
this.metadataRb.normalizeRecipeNames();
this.metadataRb.setDefaults(defaultRb);
this.karamelFile = new KaramelFile(karamelFileC);
this.berksFile = new Berksfile(berksfileC);
}
private synchronized void loadrecipes() throws MetadataParseException, CookbookUrlException {
if (!reciepsLoaded) {
List<Recipe> recipes = this.metadataRb.getRecipes();
for (Recipe r : recipes) {
String name = r.getName();
if (name == null || name.isEmpty()) {
throw new MetadataParseException("Invalid recipe name in metadata.rb");
}
String[] recipeData = r.getName().split(Settings.COOKBOOK_DELIMITER);
// assume recipe name is 'default'
String experimentFilename = "default.rb";
if (recipeData.length > 1) {
experimentFilename = recipeData[1] + ".rb";
}
String description = r.getDescription();
String searchStr = "configFile=";
int confPos = description.indexOf(searchStr);
String configFileName = "";
String configFileContents = "";
String experimentContent;
if (confPos != -1 && confPos < description.length() + searchStr.length()) {
String desc = description.substring(confPos + searchStr.length());
int pos = desc.indexOf(";");
if (pos != -1) {
configFileName = desc.substring(0, pos);
int pathPos = configFileName.lastIndexOf("/");
if (pathPos != -1) {
configFileName = configFileName.substring(pathPos + 1);
}
}
}
if (!configFileName.isEmpty()) {
String configFileUrl = urls.cookbookRawUrl + File.separator + "templates" + File.separator
+ "defaults" + File.separator + configFileName + ".erb";
try {
configFileContents = IoUtils.readContent(configFileUrl);
} catch (IOException ex) {
logger.debug("Not found in this cookbook: " + urls.recipesHome + experimentFilename, ex);
}
}
ExperimentRecipe er = null;
try {
// Only parse experiment recipes here, parse the install.rb recipe later.
if (experimentFilename.compareTo(Settings.INSTALL_RECIPE + ".rb") != 0) {
experimentContent = IoUtils.readContent(urls.recipesHome + experimentFilename);
er = ExperimentRecipeParser.parse(r.getName(), experimentContent, configFileName, configFileContents);
}
} catch (IOException ex) {
logger.debug("This cookbook does not have a karamelized experiment: " + urls.recipesHome + experimentFilename
+ " - " + ex.getMessage());
} catch (RecipeParseException ex) {
logger.warn("The recipe is not in a karamelized format: " + urls.recipesHome + experimentFilename
+ " - " + ex.getMessage());
}
if (er != null) {
experimentRecipes.add(er);
}
}
try {
String installContent = IoUtils.readContent(urls.recipesHome + "install.rb");
this.installRecipe = InstallRecipeParser.parse(installContent);
} catch (IOException ex) {
throw new CookbookUrlException(
"Could not find the file 'recipes/install.rb'. Does the file exist? Is the Internet working?");
} catch (RecipeParseException ex) {
logger.warn("Install recipe not in a format that can be used by Karamel Experiments: "
+ urls.recipesHome + "install.rb" + " - " + ex.getMessage());
} finally {
Settings.USE_CLONED_REPO_FILES = false;
}
}
reciepsLoaded = true;
}
public Berksfile getBerksFile() {
return berksFile;
}
public String getInfoJson() {
if (json == null) {
CookbookInfoJson cookbookInfoJson = new CookbookInfoJson(urls.id, metadataRb);
GsonBuilder builder = new GsonBuilder();
builder.disableHtmlEscaping();
Gson gson = builder.setPrettyPrinting().create();
json = gson.toJson(cookbookInfoJson);
}
return json;
}
public MetadataRb getMetadataRb() {
return metadataRb;
}
public KaramelFile getKaramelFile() {
return karamelFile;
}
public List<ExperimentRecipe> getExperimentRecipes() throws MetadataParseException, CookbookUrlException {
loadrecipes();
return experimentRecipes;
}
public InstallRecipe getInstallRecipe() throws MetadataParseException, CookbookUrlException {
loadrecipes();
return installRecipe;
}
public DefaultRb getDefaultRb() {
return defaultRb;
}
public CookbookUrls getUrls() {
return urls;
}
}