/**
* Copyright (c) 2011 Cloudsmith Inc. and other contributors, as listed below.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Cloudsmith
*
*/
package org.cloudsmith.geppetto.common.os;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class OsUtil {
public static boolean chgrp(File dir, String group, String... filenames) throws IOException {
if(isOS("win32", "win64"))
return false;
int result = runProcess(dir, concat("chgrp", group, filenames));
if(result != 0)
throw new IOException("Unable to change group of " + enumerateToString(filenames) + " to " + group +
" in " + dir.getAbsolutePath());
return true;
}
public static boolean chmod(File dir, int mode, String... filenames) throws IOException {
if(isOS("win32", "win64"))
return false;
if(!isOS("macosx"))
mode = mode & 0xFFF;
String modeStr = String.format("%o", Integer.valueOf(mode));
int result = runProcess(dir, concat("chmod", modeStr, filenames));
if(result != 0)
throw new IOException("Unable to change mode of " + enumerateToString(filenames) + " to " + modeStr +
" in " + dir.getAbsolutePath());
return true;
}
public static boolean chown(File dir, String owner, String... filenames) throws IOException {
if(isOS("win32", "win64"))
return false;
int result = runProcess(dir, concat("chown", owner, filenames));
if(result != 0)
throw new IOException("Unable to change owner of " + enumerateToString(filenames) + " to " + owner +
" in " + dir.getAbsolutePath());
return true;
}
private static String[] concat(String p1, String p2, String[] ps) {
String[] all = new String[ps.length + 2];
all[0] = p1;
all[1] = p2;
System.arraycopy(ps, 0, all, 2, ps.length);
return all;
}
public static void copyRecursive(File source, File target) throws IOException {
if(source.equals(target))
return;
Set<File> visited = new HashSet<File>();
copyRecursive(source, target, visited);
}
private static void copyRecursive(File source, File target, Set<File> visited) throws IOException {
if(visited.contains(source))
throw new IOException("Circular file structure detected");
visited.add(source);
if(source.isDirectory()) {
for(File subSource : source.listFiles()) {
File subTarget = new File(target, subSource.getPath());
subTarget.mkdirs();
if(!subTarget.isDirectory())
throw new IOException("Unable to create or access directory " + subTarget.getAbsolutePath());
copyRecursive(subSource, subTarget, visited);
}
}
else {
File directory = target.getParentFile();
directory.mkdirs();
if(!directory.isDirectory())
throw new IOException("Unable to create or access directory " + directory.getAbsolutePath());
OutputStream targetStream = new FileOutputStream(target);
InputStream sourceStream = new FileInputStream(source);
StreamUtil.copy(sourceStream, targetStream);
sourceStream.close();
targetStream.close();
}
}
public static void copyRecursive(String source, String target) throws IOException {
copyRecursive(new File(source), new File(target));
}
public static Process createProcess(File dir, String... parameters) throws IOException {
ProcessBuilder processBuilder = new ProcessBuilder(parameters);
if(dir != null)
processBuilder.directory(dir);
return processBuilder.start();
}
public static Process createProcess(Object... parameters) throws IOException {
return createProcess(null, parameters);
}
public static void deleteRecursive(File file) throws IOException {
Set<File> visited = new HashSet<File>();
deleteRecursive(file, visited);
}
private static void deleteRecursive(File file, Set<File> visited) throws IOException {
if(visited.contains(file))
throw new IOException("Circular file structure detected");
visited.add(file);
if(file.isDirectory()) {
for(File subFile : file.listFiles())
deleteRecursive(subFile, visited);
}
if(!file.delete()) {
if(file.exists())
throw new IOException("Unable to delete " + file.getAbsolutePath());
}
}
public static void deleteRecursive(String path) throws IOException {
deleteRecursive(new File(path));
}
private static String enumerateToString(String[] tokens) {
StringBuilder sb = new StringBuilder();
boolean first = true;
for(String token : tokens) {
if(first)
first = false;
else {
sb.append(',');
sb.append(' ');
}
sb.append(token);
}
return sb.toString();
}
private static void find(File file, Pattern pattern, int limit, List<File> found, Set<File> visited)
throws IOException {
if(visited.contains(file))
throw new IOException("Circular file structure detected");
visited.add(file);
if(limit > -1 && found.size() >= limit)
return;
if(file.isDirectory()) {
File[] subFiles = file.listFiles();
Arrays.sort(subFiles);
for(File subFile : subFiles) {
find(subFile, pattern, limit, found, visited);
}
}
else {
Matcher m = pattern.matcher(file.getName());
if(m.matches())
found.add(file);
}
}
public static File[] find(File file, String pattern) throws IOException {
return find(file, pattern, -1);
}
public static File[] find(File file, String pattern, int limit) throws IOException {
Set<File> visited = new HashSet<File>();
Pattern compiledPattern = Pattern.compile(pattern);
List<File> found = new ArrayList<File>();
find(file, compiledPattern, limit, found, visited);
return found.toArray(new File[found.size()]);
}
public static File[] find(String root, String pattern) throws IOException {
return find(new File(root), pattern, -1);
}
public static File[] find(String root, String pattern, int limit) throws IOException {
return find(new File(root), pattern, limit);
}
public static File findFirst(File file, String pattern) throws IOException {
Set<File> visited = new HashSet<File>();
Pattern compiledPattern = Pattern.compile(pattern);
List<File> files = new ArrayList<File>(1);
find(file, compiledPattern, 1, files, visited);
if(files.size() == 1)
return files.get(0);
return null;
}
public static File findFirst(String root, String pattern) throws IOException {
return findFirst(new File(root), pattern);
}
public static boolean isOS(String... oss) {
String currentOs = System.getProperty("osgi.os");
if(currentOs == null) {
currentOs = System.getProperty("os.name");
if(currentOs == null)
throw new IllegalStateException("Missing required property: osgi.os");
currentOs = currentOs.toLowerCase();
if("windows".equals(currentOs)) {
String arch = System.getProperty("os.arch");
if("amd64".equals(arch))
currentOs = "win64";
else
currentOs = "win32";
}
}
for(String os : oss)
if(os.equals(currentOs))
return true;
return false;
}
public static boolean link(File dir, String target, String name) throws IOException {
if(isOS("win32", "win64"))
return false;
int result = runProcess(dir, "ln", "-s", name, target);
if(result != 0)
throw new IOException("Unable to link " + target + " to " + name + " in " + dir.getAbsolutePath());
return true;
}
public static int runProcess(Collection<String> params) throws IOException {
return runProcess(params.toArray(new String[params.size()]));
}
public static int runProcess(File dir, OutputStream out, OutputStream err, String... parameters) throws IOException {
Process process = createProcess(dir, parameters);
Thread outCopier = StreamUtil.backgroundCopy(process.getInputStream(), out);
Thread errCopier = StreamUtil.backgroundCopy(process.getErrorStream(), err);
try {
process.waitFor();
}
catch(InterruptedException e) {
throw new IOException("Process was interrupted", e);
}
try {
outCopier.join(2000);
}
catch(InterruptedException e) {
// Ignore
}
try {
errCopier.join(2000);
}
catch(InterruptedException e) {
// Ignore
}
return process.exitValue();
}
public static int runProcess(File dir, String... parameters) throws IOException {
return runProcess(dir, System.out, System.err, parameters);
}
public static int runProcess(String... parameters) throws IOException {
return runProcess(null, parameters);
}
public static String stringifyCommand(String... parameters) {
StringBuilder cmd = new StringBuilder();
boolean empty = true;
for(Object parameter : parameters) {
if(empty)
empty = false;
else
cmd.append(' ');
cmd.append(parameter);
}
return cmd.toString();
}
/**
* Copy a file or directory to a target directory. All attributes are
* preserved and no links are dereferenced.
*
* @param source
* The source of the copy.
* @param targetDirectory
* @return
* @throws IOException
*/
public static boolean unixCopy(File source, File targetDirectory) throws IOException {
if(isOS("win32", "win64"))
return false;
File sourceDir = source.getParentFile();
if(sourceDir == null)
return false;
return runProcess(sourceDir, "cp", "-a", source.getName(), targetDirectory.getAbsolutePath()) == 0;
}
}