/* * Copyright (c) 2011 Google, Inc. * * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 * * 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.devtools.moe.client.testing; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; import com.google.devtools.moe.client.CommandRunner.CommandException; import com.google.devtools.moe.client.FileSystem; import com.google.devtools.moe.client.Utils; import com.google.devtools.moe.client.codebase.Codebase; import com.google.devtools.moe.client.codebase.CodebaseCreationError; import com.google.devtools.moe.client.codebase.CodebaseCreator; import com.google.devtools.moe.client.parser.RepositoryExpression; import com.google.devtools.moe.client.parser.Term; import com.google.devtools.moe.client.tools.TarUtils; import java.io.File; import java.io.IOException; import java.util.Map; /** * Creates a codebase based upon a local existing directory. Primarily used for testing purposes. * Works with single files and directories. */ public class FileCodebaseCreator extends CodebaseCreator { private static final String PATH_OPTION = "path"; private static final String PROJECT_SPACE_OPTION = "projectspace"; private final FileSystem filesystem; private final TarUtils tarUtils; public FileCodebaseCreator(FileSystem filesystem, TarUtils tarUtils) { this.filesystem = filesystem; this.tarUtils = tarUtils; } @Override public Codebase create(Map<String, String> options) throws CodebaseCreationError { // Validate that the options passed are valid. Utils.checkKeys(options, ImmutableSet.of(PATH_OPTION, PROJECT_SPACE_OPTION)); // Get the source path to the file/directory described in the options list. String source = options.get(PATH_OPTION); if (Strings.isNullOrEmpty(source)) { throw new CodebaseCreationError( "Please specify the mandatory '%s' option for the FileCodebaseCreator", PATH_OPTION); } // Create the codebase instance. File codebasePath = getCodebasePath(new File(source)); String projectSpace = options.containsKey(PROJECT_SPACE_OPTION) ? options.get(PROJECT_SPACE_OPTION) : "public"; RepositoryExpression expression = new RepositoryExpression(new Term("file", options)); return Codebase.create(codebasePath, projectSpace, expression); } /** * Returns a folder reference to the codebase described by the source file. Will extract * .tar/.tar.gz automatically. * * @param sourceFile The file describing a codebase, or a directory. * @return A reference to a codebase directory * @throws CodebaseCreationError */ @VisibleForTesting File getCodebasePath(File sourceFile) throws CodebaseCreationError { // Check whether the specified path is valid. if (!filesystem.exists(sourceFile)) { throw new CodebaseCreationError( "The specified codebase path \"%s\" does not exist.", sourceFile); } try { // Get the target path based upon whether we are dealing with a directory or a file. if (filesystem.isDirectory(sourceFile)) { // If it is a directory, make a copy and return the path of the copy. File destFile = filesystem.getTemporaryDirectory("file_codebase_copy_"); filesystem.copyDirectory(sourceFile, destFile); return destFile; } else if (filesystem.isFile(sourceFile)) { // If it is a file, assume that it is an archive and try to extract it. File extractedArchive = expandToDirectory(sourceFile); if (extractedArchive != null) { return extractedArchive; } } } catch (CommandException exception) { throw new CodebaseCreationError( String.format("Could not extract archive: '%s' %s", sourceFile, exception.getMessage())); } catch (IOException exception) { throw new CodebaseCreationError( String.format("Could not extract archive '%s': %s", sourceFile, exception.getMessage())); } // If we did not return a codebase-path by now, we have no way of handling it. throw new CodebaseCreationError( String.format( "The '%s'-option of a FileCodebaseCreator must specify either a directory " + "or a .tar/.tar.gz-archive", PATH_OPTION)); } /** * Expands the specified File to a new temporary directory, or returns null if the file type is * unsupported. * * @param inputFile The File to be extracted. * @return File pointing to a directory, or null. * @throws CommandException * @throws IOException */ File expandToDirectory(File inputFile) throws IOException, CommandException { // If the specified path already is a directory, return it without modification. if (inputFile.isDirectory()) { return inputFile; } // Determine the file type by looking at the file extension. String lowerName = inputFile.getName().toLowerCase(); if (lowerName.endsWith(".tar.gz") || lowerName.endsWith(".tar")) { return tarUtils.expandTar(inputFile); } // If this file extension is unknown, return null. return null; } }