// Copyright 2017 The Bazel Authors. All rights reserved.
//
// 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.build.benchmark.codegenerator;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
/** Create 4 types of Cpp project, or modify existing ones. */
public class CppCodeGenerator extends CodeGenerator {
private static final int SIZE_A_FEW_FILES = 10;
private static final int SIZE_MANY_FILES = 200;
private static final int SIZE_LONG_CHAINED_DEPS = 20;
private static final int SIZE_PARALLEL_DEPS = 20;
private static final String DIR_SUFFIX = "/cpp";
@Override
public String getDirSuffix() {
return DIR_SUFFIX;
}
@Override
public int getSizeAFewFiles() {
return SIZE_A_FEW_FILES;
}
@Override
public int getSizeManyFiles() {
return SIZE_MANY_FILES;
}
@Override
public int getSizeLongChainedDeps() {
return SIZE_LONG_CHAINED_DEPS;
}
@Override
public int getSizeParallelDeps() {
return SIZE_PARALLEL_DEPS;
}
/** Target type 1/2: Create targets with some files */
@Override
void createTargetWithSomeFiles(Path projectPath, int numberOfFiles) {
if (pathExists(projectPath)) {
return;
}
try {
Files.createDirectories(projectPath);
for (int i = 0; i < numberOfFiles; ++i) {
CppCodeGeneratorHelper.createRandomClass("RandomClass" + i, projectPath);
}
CppCodeGeneratorHelper.writeBuildFileWithAllFilesToDir(
projectPath.getFileName().toString(), projectPath);
} catch (IOException e) {
System.err.println("Error creating target with some files: " + e.getMessage());
}
}
/** Target type 1/2: Modify targets with some files */
@Override
void modifyTargetWithSomeFiles(Path projectPath) {
File dir = projectPath.toFile();
if (directoryNotExists(dir)) {
System.err.format(
"Project dir (%s) does not contain code for modification.\n", projectPath.toString());
return;
}
try {
CppCodeGeneratorHelper.createRandomClassExtra("RandomClass0", projectPath);
} catch (IOException e) {
System.err.println("Error modifying targets some files: " + e.getMessage());
}
}
/** Target type 3: Create targets with a few long chained dependencies (A -> B -> C -> … -> Z) */
@Override
void createTargetWithLongChainedDeps(Path projectPath) {
if (pathExists(projectPath)) {
return;
}
try {
Files.createDirectories(projectPath);
int count = SIZE_LONG_CHAINED_DEPS;
// Call next one for 1..(count-2)
for (int i = 1; i < count - 1; ++i) {
CppCodeGeneratorHelper.createClassAndBuildFileWithDepsNext(i, projectPath);
}
// Don't call next one for (count-1)
CppCodeGeneratorHelper.createRandomClass("Deps" + (count - 1), projectPath);
CppCodeGeneratorHelper.appendTargetToBuildFile("Deps" + (count - 1), projectPath);
// Main
String deps = " deps=[ ':Deps1' ],";
CppCodeGeneratorHelper.createMainClassAndBuildFileWithDeps(
TARGET_LONG_CHAINED_DEPS, deps, projectPath);
} catch (IOException e) {
System.err.println(
"Error creating targets with a few long chained dependencies: " + e.getMessage());
}
}
/** Target type 3: Modify targets with a few long chained dependencies (A -> B -> C -> … -> Z) */
@Override
void modifyTargetWithLongChainedDeps(Path projectPath) {
File dir = projectPath.toFile();
if (directoryNotExists(dir)) {
System.err.format(
"Project dir (%s) does not contain code for modification.\n", projectPath.toString());
return;
}
try {
CppCodeGeneratorHelper.createClassWithDepsNextExtra(
(SIZE_LONG_CHAINED_DEPS + 1) >> 1, projectPath);
} catch (IOException e) {
System.err.println(
"Error modifying targets with a few long chained dependencies: " + e.getMessage());
}
}
/** Target type 4: Create targets with lots of parallel dependencies (A -> B, C, D, E, F, G, H) */
@Override
void createTargetWithParallelDeps(Path projectPath) {
if (pathExists(projectPath)) {
return;
}
try {
Files.createDirectories(projectPath);
int count = SIZE_PARALLEL_DEPS;
// parallel dependencies B~Z
for (int i = 1; i < count; ++i) {
CppCodeGeneratorHelper.createRandomClass("Deps" + i, projectPath);
CppCodeGeneratorHelper.appendTargetToBuildFile("Deps" + i, projectPath);
}
// A(Main)
String deps = " deps=[ ";
for (int i = 1; i < count; ++i) {
deps += "\":Deps" + i + "\", ";
}
deps += "],";
CppCodeGeneratorHelper.createMainClassAndBuildFileWithDeps(
TARGET_PARALLEL_DEPS, deps, projectPath);
} catch (IOException e) {
System.err.println(
"Error creating targets with lots of parallel dependencies: " + e.getMessage());
}
}
/** Target type 4: Modify targets with lots of parallel dependencies (A -> B, C, D, E, F, G, H) */
@Override
void modifyTargetWithParallelDeps(Path projectPath) {
File dir = projectPath.toFile();
if (directoryNotExists(dir)) {
System.err.format(
"Project dir (%s) does not contain code for modification.\n", projectPath.toString());
return;
}
try {
CppCodeGeneratorHelper.createRandomClassExtra("Deps1", projectPath);
} catch (IOException e) {
System.err.println(
"Error creating targets with lots of parallel dependencies: " + e.getMessage());
}
}
private static boolean pathExists(Path path) {
File dir = path.toFile();
if (dir.exists()) {
System.err.println("File or directory exists, not rewriting it: " + path);
return true;
}
return false;
}
private static boolean directoryNotExists(File file) {
return !(file.exists() && file.isDirectory());
}
}