• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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