blob: f13101e04c11aa8ff1413603a05817b7bbcc7464 [file] [log] [blame]
/*
* Copyright 2012-present Facebook, 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.facebook.buck.step.fs;
import com.facebook.buck.step.ExecutionContext;
import com.facebook.buck.step.Step;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.io.ByteStreams;
import org.tukaani.xz.LZMA2Options;
import org.tukaani.xz.XZ;
import org.tukaani.xz.XZOutputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* A {@link Step} to compress a file with XZ / LZMA2.
*
* @see <a href="http://tukaani.org/xz/">XZ</a>
* @see <a href="http://tukaani.org/xz/java.html">XZ for Java</a>
* @see <a href="http://tukaani.org/xz/embedded.html">XZ Embedded</a>
*/
public class XzStep implements Step {
private final String sourceFile;
private final String destinationFile;
private final int compressionLevel;
private final boolean keep;
private final int check;
/**
* Create an {@link XzStep} to compress a file using XZ.
* @param sourceFile file to compress
* @param destinationFile where to store compressed data
* @param compressionLevel a value between 0-9, it impacts memory requirements for decompression
* @param keep by default, {@code xz} deletes the source file when compressing. This argument
* forces {@code xz} to keep it.
* @param check integrity check to use. Must be one of {@link XZ#CHECK_CRC32},
* {@link XZ#CHECK_CRC64}, {@link XZ#CHECK_SHA256}, {@link XZ#CHECK_NONE}
* (Note: XZ Embedded can only verify CRC32).
*/
@VisibleForTesting
XzStep(
String sourceFile,
String destinationFile,
int compressionLevel,
boolean keep,
int check) {
this.sourceFile = Preconditions.checkNotNull(sourceFile);
this.destinationFile = Preconditions.checkNotNull(destinationFile);
Preconditions.checkArgument(compressionLevel >= LZMA2Options.PRESET_MIN &&
compressionLevel <= LZMA2Options.PRESET_MAX, "compressionLevel out of bounds.");
this.compressionLevel = compressionLevel;
this.keep = keep;
this.check = check;
}
/**
* Creates an XzStep to compress a file with XZ compression level 4.
*
* <p> The destination file will be {@code sourceFile} with the added {@code .xz} extension.
* <p> Decompression will require 5MiB of RAM.
*
* @param sourceFile file to compress
*/
public XzStep(String sourceFile) {
this(
sourceFile,
sourceFile + ".xz",
/* compressionLevel */ 4,
/* keep */ false,
XZ.CHECK_CRC32);
}
@Override
public int execute(ExecutionContext context) {
try (
InputStream in = new BufferedInputStream(new FileInputStream(sourceFile));
OutputStream out = new BufferedOutputStream(new FileOutputStream(getDestinationFile()));
XZOutputStream xzOut = new XZOutputStream(out, new LZMA2Options(compressionLevel), check);
) {
ByteStreams.copy(in, xzOut);
xzOut.finish();
} catch (IOException e) {
e.printStackTrace(context.getStdErr());
return 1;
}
if (!keep && !context.getProjectFilesystem().deleteFileAtPath(sourceFile)) {
return 1;
}
return 0;
}
public String getDestinationFile() {
return destinationFile;
}
@Override
public String getDescription(ExecutionContext context) {
return Joiner.on(" ").skipNulls().join(
"xz", "-z", "-" + compressionLevel, (keep ? "--keep" : null), "--check=crc32", sourceFile);
}
@Override
public String getShortName() {
return "xz";
}
}