use of com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryFunctionException in project bazel by bazelbuild.
the class DecompressorValueTest method testUnknownFileExtensionsThrow.
@Test
public void testUnknownFileExtensionsThrow() throws Exception {
Path zipPath = fs.getPath("/foo/.external-repositories/some-repo/bar.baz");
try {
DecompressorDescriptor.builder().setArchivePath(zipPath).build();
fail(".baz isn't a valid suffix");
} catch (RepositoryFunctionException expected) {
assertThat(expected.getMessage()).contains("Expected a file with a .zip, .jar,");
}
}
use of com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryFunctionException in project bazel by bazelbuild.
the class CompressedTarFunction method decompress.
@Override
public Path decompress(DecompressorDescriptor descriptor) throws RepositoryFunctionException {
Optional<String> prefix = descriptor.prefix();
boolean foundPrefix = false;
try (InputStream decompressorStream = getDecompressorStream(descriptor)) {
TarArchiveInputStream tarStream = new TarArchiveInputStream(decompressorStream);
TarArchiveEntry entry;
while ((entry = tarStream.getNextTarEntry()) != null) {
StripPrefixedPath entryPath = StripPrefixedPath.maybeDeprefix(entry.getName(), prefix);
foundPrefix = foundPrefix || entryPath.foundPrefix();
if (entryPath.skip()) {
continue;
}
Path filename = descriptor.repositoryPath().getRelative(entryPath.getPathFragment());
FileSystemUtils.createDirectoryAndParents(filename.getParentDirectory());
if (entry.isDirectory()) {
FileSystemUtils.createDirectoryAndParents(filename);
} else {
if (entry.isSymbolicLink() || entry.isLink()) {
PathFragment linkName = new PathFragment(entry.getLinkName());
boolean wasAbsolute = linkName.isAbsolute();
// Strip the prefix from the link path if set.
linkName = StripPrefixedPath.maybeDeprefix(linkName.getPathString(), prefix).getPathFragment();
if (wasAbsolute) {
// Recover the path to an absolute path as maybeDeprefix() relativize the path
// even if the prefix is not set
linkName = descriptor.repositoryPath().getRelative(linkName).asFragment();
}
if (entry.isSymbolicLink()) {
FileSystemUtils.ensureSymbolicLink(filename, linkName);
} else {
FileSystemUtils.createHardLink(filename, descriptor.repositoryPath().getRelative(linkName));
}
} else {
Files.copy(tarStream, filename.getPathFile().toPath(), StandardCopyOption.REPLACE_EXISTING);
filename.chmod(entry.getMode());
// This can only be done on real files, not links, or it will skip the reader to
// the next "real" file to try to find the mod time info.
Date lastModified = entry.getLastModifiedDate();
filename.setLastModifiedTime(lastModified.getTime());
}
}
}
} catch (IOException e) {
throw new RepositoryFunctionException(e, Transience.TRANSIENT);
}
if (prefix.isPresent() && !foundPrefix) {
throw new RepositoryFunctionException(new IOException("Prefix " + prefix.get() + " was given, but not found in the archive"), Transience.PERSISTENT);
}
return descriptor.repositoryPath();
}
use of com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryFunctionException in project bazel by bazelbuild.
the class GitCloner method clone.
public static SkyValue clone(Rule rule, Path outputDirectory, ExtendedEventHandler eventHandler, Map<String, String> clientEnvironment) throws RepositoryFunctionException {
WorkspaceAttributeMapper mapper = WorkspaceAttributeMapper.of(rule);
if (mapper.isAttributeValueExplicitlySpecified("commit") == mapper.isAttributeValueExplicitlySpecified("tag")) {
throw new RepositoryFunctionException(new EvalException(rule.getLocation(), "One of either commit or tag must be defined"), Transience.PERSISTENT);
}
GitRepositoryDescriptor descriptor;
String startingPoint;
try {
if (mapper.isAttributeValueExplicitlySpecified("commit")) {
startingPoint = mapper.get("commit", Type.STRING);
} else {
startingPoint = "tags/" + mapper.get("tag", Type.STRING);
}
descriptor = new GitRepositoryDescriptor(mapper.get("remote", Type.STRING), startingPoint, mapper.get("init_submodules", Type.BOOLEAN), outputDirectory);
} catch (EvalException e) {
throw new RepositoryFunctionException(e, Transience.PERSISTENT);
}
// Setup proxy if remote is http or https
if (descriptor.remote != null && Ascii.toLowerCase(descriptor.remote).startsWith("http")) {
try {
new ProxyHelper(clientEnvironment).createProxyIfNeeded(new URL(descriptor.remote));
} catch (IOException ie) {
throw new RepositoryFunctionException(ie, Transience.TRANSIENT);
}
}
Git git = null;
try {
if (descriptor.directory.exists()) {
if (isUpToDate(descriptor)) {
return new HttpDownloadValue(descriptor.directory);
}
try {
FileSystemUtils.deleteTree(descriptor.directory);
} catch (IOException e) {
throw new RepositoryFunctionException(e, Transience.TRANSIENT);
}
}
git = Git.cloneRepository().setURI(descriptor.remote).setCredentialsProvider(new NetRCCredentialsProvider()).setDirectory(descriptor.directory.getPathFile()).setCloneSubmodules(false).setNoCheckout(true).setProgressMonitor(new GitProgressMonitor(descriptor.remote, "Cloning " + descriptor.remote, eventHandler)).call();
git.checkout().setCreateBranch(true).setName("bazel-checkout").setStartPoint(descriptor.checkout).call();
// the first level.
if (descriptor.initSubmodules && !git.submoduleInit().call().isEmpty()) {
git.submoduleUpdate().setProgressMonitor(new GitProgressMonitor(descriptor.remote, "Cloning submodules for " + descriptor.remote, eventHandler)).call();
}
} catch (InvalidRemoteException e) {
throw new RepositoryFunctionException(new IOException("Invalid Git repository URI: " + e.getMessage()), Transience.PERSISTENT);
} catch (RefNotFoundException | InvalidRefNameException e) {
throw new RepositoryFunctionException(new IOException("Invalid branch, tag, or commit: " + e.getMessage()), Transience.PERSISTENT);
} catch (GitAPIException e) {
// This is a sad attempt to actually get a useful error message out of jGit, which will bury
// the actual (useful) cause of the exception under several throws.
StringBuilder errmsg = new StringBuilder();
errmsg.append(e.getMessage());
Throwable throwable = e;
while (throwable.getCause() != null) {
throwable = throwable.getCause();
errmsg.append(" caused by " + throwable.getMessage());
}
throw new RepositoryFunctionException(new IOException("Error cloning repository: " + errmsg), Transience.PERSISTENT);
} catch (JGitInternalException e) {
// caller of the command can handle them effectively." Thanks, jgit.
throw new RepositoryFunctionException(new IOException(e.getMessage()), Transience.PERSISTENT);
} finally {
if (git != null) {
git.close();
}
}
return new HttpDownloadValue(descriptor.directory);
}
use of com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryFunctionException in project bazel by bazelbuild.
the class SkylarkRepositoryContext method downloadAndExtract.
@SkylarkCallable(name = "download_and_extract", doc = "Download a file to the output path for the provided url, and extract it.", parameters = { @Param(name = "url", allowedTypes = { @ParamType(type = String.class), @ParamType(type = SkylarkList.class, generic1 = String.class) }, named = true, doc = "List of mirror URLs referencing the same file."), @Param(name = "output", allowedTypes = { @ParamType(type = String.class), @ParamType(type = Label.class), @ParamType(type = SkylarkPath.class) }, defaultValue = "''", named = true, doc = "path to the directory where the archive will be unpacked," + " relative to the repository directory."), @Param(name = "sha256", type = String.class, defaultValue = "''", named = true, doc = "the expected SHA-256 hash of the file downloaded." + " This must match the SHA-256 hash of the file downloaded. It is a security risk" + " to omit the SHA-256 as remote files can change. At best omitting this field" + " will make your build non-hermetic. It is optional to make development easier" + " but should be set before shipping."), @Param(name = "type", type = String.class, defaultValue = "''", named = true, doc = "the archive type of the downloaded file." + " By default, the archive type is determined from the file extension of the URL." + " If the file has no extension, you can explicitly specify either \"zip\"," + " \"jar\", \"war\", \"tar.gz\", \"tgz\", \"tar.bz2\", or \"tar.xz\" here."), @Param(name = "stripPrefix", type = String.class, defaultValue = "''", named = true, doc = "a directory prefix to strip from the extracted files." + "\nMany archives contain a top-level directory that contains all files in the" + " archive. Instead of needing to specify this prefix over and over in the" + " <code>build_file</code>, this field can be used to strip it from extracted" + " files.") })
public void downloadAndExtract(Object url, Object output, String sha256, String type, String stripPrefix) throws RepositoryFunctionException, InterruptedException, EvalException {
validateSha256(sha256);
List<URL> urls = getUrls(url);
// Download to outputDirectory and delete it after extraction
SkylarkPath outputPath = getPath("download_and_extract()", output);
checkInOutputDirectory(outputPath);
createDirectory(outputPath.getPath());
Path downloadedPath;
try {
downloadedPath = httpDownloader.download(urls, sha256, Optional.of(type), outputPath.getPath(), env.getListener(), osObject.getEnvironmentVariables());
} catch (InterruptedException e) {
throw new RepositoryFunctionException(new IOException("thread interrupted"), Transience.TRANSIENT);
} catch (IOException e) {
throw new RepositoryFunctionException(e, Transience.TRANSIENT);
}
DecompressorValue.decompress(DecompressorDescriptor.builder().setTargetKind(rule.getTargetKind()).setTargetName(rule.getName()).setArchivePath(downloadedPath).setRepositoryPath(outputPath.getPath()).setPrefix(stripPrefix).build());
try {
if (downloadedPath.exists()) {
downloadedPath.delete();
}
} catch (IOException e) {
throw new RepositoryFunctionException(new IOException("Couldn't delete temporary file (" + downloadedPath.getPathString() + ")", e), Transience.TRANSIENT);
}
}
use of com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryFunctionException in project bazel by bazelbuild.
the class SkylarkRepositoryContext method createFileFromTemplate.
@SkylarkCallable(name = "template", doc = "Generate a new file using a <code>template</code>. Every occurrence in " + "<code>template</code> of a key of <code>substitutions</code> will be replaced by " + "the corresponding value. The result is written in <code>path</code>. An optional" + "<code>executable</code> argument (default to true) can be set to turn on or off" + "the executable bit.", parameters = { @Param(name = "path", allowedTypes = { @ParamType(type = String.class), @ParamType(type = Label.class), @ParamType(type = SkylarkPath.class) }, doc = "path of the file to create, relative to the repository directory."), @Param(name = "template", allowedTypes = { @ParamType(type = String.class), @ParamType(type = Label.class), @ParamType(type = SkylarkPath.class) }, doc = "path to the template file."), @Param(name = "substitutions", type = SkylarkDict.class, defaultValue = "{}", named = true, doc = "substitutions to make when expanding the template."), @Param(name = "executable", type = Boolean.class, defaultValue = "True", named = true, doc = "set the executable flag on the created file, true by default.") })
public void createFileFromTemplate(Object path, Object template, SkylarkDict<String, String> substitutions, Boolean executable) throws RepositoryFunctionException, EvalException, InterruptedException {
SkylarkPath p = getPath("template()", path);
SkylarkPath t = getPath("template()", template);
try {
checkInOutputDirectory(p);
makeDirectories(p.getPath());
String tpl = FileSystemUtils.readContent(t.getPath(), StandardCharsets.UTF_8);
for (Map.Entry<String, String> substitution : substitutions.entrySet()) {
tpl = StringUtilities.replaceAllLiteral(tpl, substitution.getKey(), substitution.getValue());
}
try (OutputStream stream = p.getPath().getOutputStream()) {
stream.write(tpl.getBytes(StandardCharsets.UTF_8));
}
if (executable) {
p.getPath().setExecutable(true);
}
} catch (IOException e) {
throw new RepositoryFunctionException(e, Transience.TRANSIENT);
}
}
Aggregations