1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.tradefed.util; 17 18 import com.android.tradefed.log.ITestLogger; 19 import com.android.tradefed.log.LogUtil.CLog; 20 import com.android.tradefed.result.FileInputStreamSource; 21 import com.android.tradefed.result.InputStreamSource; 22 import com.android.tradefed.result.LogDataType; 23 24 import org.apache.commons.compress.archivers.ArchiveException; 25 import org.apache.commons.compress.archivers.ArchiveStreamFactory; 26 import org.apache.commons.compress.archivers.tar.TarArchiveEntry; 27 import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; 28 import org.apache.commons.compress.utils.IOUtils; 29 30 import java.io.File; 31 import java.io.FileInputStream; 32 import java.io.FileNotFoundException; 33 import java.io.FileOutputStream; 34 import java.io.IOException; 35 import java.io.InputStream; 36 import java.io.OutputStream; 37 import java.util.LinkedList; 38 import java.util.List; 39 import java.util.zip.GZIPInputStream; 40 import java.util.zip.GZIPOutputStream; 41 42 /** 43 * Utility to manipulate a tar file. It wraps the commons-compress in order to provide tar support. 44 */ 45 public class TarUtil { 46 47 /** 48 * Untar a tar file into a directory. 49 * tar.gz file need to up {@link #unGzip(File, File)} first. 50 * 51 * @param inputFile The tar file to extract 52 * @param outputDir the directory where to put the extracted files. 53 * @return The list of {@link File} untarred. 54 * @throws FileNotFoundException 55 * @throws IOException 56 */ unTar(final File inputFile, final File outputDir)57 public static List<File> unTar(final File inputFile, final File outputDir) 58 throws FileNotFoundException, IOException { 59 CLog.i(String.format("Untaring %s to dir %s.", inputFile.getAbsolutePath(), 60 outputDir.getAbsolutePath())); 61 final List<File> untaredFiles = new LinkedList<File>(); 62 final InputStream is = new FileInputStream(inputFile); 63 TarArchiveInputStream debInputStream = null; 64 try { 65 debInputStream = (TarArchiveInputStream) 66 new ArchiveStreamFactory().createArchiveInputStream("tar", is); 67 TarArchiveEntry entry = null; 68 while ((entry = (TarArchiveEntry)debInputStream.getNextEntry()) != null) { 69 final File outputFile = new File(outputDir, entry.getName()); 70 if (entry.isDirectory()) { 71 CLog.i(String.format("Attempting to write output directory %s.", 72 outputFile.getAbsolutePath())); 73 if (!outputFile.exists()) { 74 CLog.i(String.format("Attempting to create output directory %s.", 75 outputFile.getAbsolutePath())); 76 if (!outputFile.mkdirs()) { 77 throw new IllegalStateException( 78 String.format("Couldn't create directory %s.", 79 outputFile.getAbsolutePath())); 80 } 81 } 82 } else { 83 CLog.i(String.format("Creating output file %s.", outputFile.getAbsolutePath())); 84 final OutputStream outputFileStream = new FileOutputStream(outputFile); 85 IOUtils.copy(debInputStream, outputFileStream); 86 StreamUtil.close(outputFileStream); 87 } 88 untaredFiles.add(outputFile); 89 } 90 } catch (ArchiveException ae) { 91 // We rethrow the ArchiveException through a more generic one. 92 throw new IOException(ae); 93 } finally { 94 StreamUtil.close(debInputStream); 95 StreamUtil.close(is); 96 } 97 return untaredFiles; 98 } 99 100 /** 101 * UnGZip a file: a tar.gz file will become a tar file. 102 * 103 * @param inputFile The {@link File} to ungzip 104 * @param outputDir The directory where to put the ungzipped file. 105 * @return a {@link File} pointing to the ungzipped file. 106 * @throws FileNotFoundException 107 * @throws IOException 108 */ unGzip(final File inputFile, final File outputDir)109 public static File unGzip(final File inputFile, final File outputDir) 110 throws FileNotFoundException, IOException { 111 CLog.i(String.format("Ungzipping %s to dir %s.", inputFile.getAbsolutePath(), 112 outputDir.getAbsolutePath())); 113 // rename '-3' to remove the '.gz' extension. 114 final File outputFile = new File(outputDir, inputFile.getName().substring(0, 115 inputFile.getName().length() - 3)); 116 GZIPInputStream in = null; 117 FileOutputStream out = null; 118 try { 119 in = new GZIPInputStream(new FileInputStream(inputFile)); 120 out = new FileOutputStream(outputFile); 121 IOUtils.copy(in, out); 122 } finally { 123 StreamUtil.close(in); 124 StreamUtil.close(out); 125 } 126 return outputFile; 127 } 128 129 /** 130 * Utility function to gzip (.gz) a file. the .gz extension will be added to base file name. 131 * 132 * @param inputFile the {@link File} to be gzipped. 133 * @return the gzipped file. 134 * @throws IOException 135 */ gzip(final File inputFile)136 public static File gzip(final File inputFile) throws IOException { 137 File outputFile = FileUtil.createTempFile(inputFile.getName(), ".gz"); 138 GZIPOutputStream out = null; 139 FileInputStream in = null; 140 try { 141 out = new GZIPOutputStream(new FileOutputStream(outputFile)); 142 in = new FileInputStream(inputFile); 143 IOUtils.copy(in, out); 144 } catch (IOException e) { 145 // delete the tmp file if we failed to gzip. 146 FileUtil.deleteFile(outputFile); 147 throw e; 148 } finally { 149 StreamUtil.close(in); 150 StreamUtil.close(out); 151 } 152 return outputFile; 153 } 154 155 /** 156 * Helper to extract and log to the reporters a tar gz file and its content 157 * 158 * @param listener the {@link ITestLogger} where to log the files. 159 * @param targzFile the tar.gz {@link File} that needs its content log. 160 * @param baseName the base name under which the files will be found. 161 */ extractAndLog(ITestLogger listener, File targzFile, String baseName)162 public static void extractAndLog(ITestLogger listener, File targzFile, String baseName) 163 throws FileNotFoundException, IOException { 164 // First upload the tar.gz file 165 InputStreamSource inputStream = null; 166 try { 167 inputStream = new FileInputStreamSource(targzFile); 168 listener.testLog(baseName, LogDataType.TAR_GZ, inputStream); 169 } finally { 170 StreamUtil.cancel(inputStream); 171 } 172 173 // extract and upload internal files. 174 File dir = FileUtil.createTempDir("tmp_tar_dir"); 175 File ungzipLog = null; 176 try { 177 ungzipLog = TarUtil.unGzip(targzFile, dir); 178 List<File> logs = TarUtil.unTar(ungzipLog, dir); 179 for (File f : logs) { 180 InputStreamSource s = null; 181 try { 182 s = new FileInputStreamSource(f); 183 listener.testLog(String.format("%s_%s", baseName, f.getName()), 184 LogDataType.TEXT, s); 185 } finally { 186 StreamUtil.cancel(s); 187 } 188 } 189 } finally { 190 FileUtil.deleteFile(ungzipLog); 191 FileUtil.recursiveDelete(dir); 192 } 193 } 194 } 195