/* * Copyright 2011 gitblit.com. * * 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.gitblit.utils; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.nio.charset.Charset; /** * Common file utilities. * * @author James Moger * */ public class FileUtils { /** 1024 (number of bytes in one kilobyte) */ public static final int KB = 1024; /** 1024 {@link #KB} (number of bytes in one megabyte) */ public static final int MB = 1024 * KB; /** 1024 {@link #MB} (number of bytes in one gigabyte) */ public static final int GB = 1024 * MB; /** * Returns an int from a string representation of a file size. * e.g. 50m = 50 megabytes * * @param aString * @param defaultValue * @return an int value or the defaultValue if aString can not be parsed */ public static int convertSizeToInt(String aString, int defaultValue) { return (int) convertSizeToLong(aString, defaultValue); } /** * Returns a long from a string representation of a file size. * e.g. 50m = 50 megabytes * * @param aString * @param defaultValue * @return a long value or the defaultValue if aString can not be parsed */ public static long convertSizeToLong(String aString, long defaultValue) { // trim string and remove all spaces aString = aString.toLowerCase().trim(); StringBuilder sb = new StringBuilder(); for (String a : aString.split(" ")) { sb.append(a); } aString = sb.toString(); // identify value and unit int idx = 0; int len = aString.length(); while (Character.isDigit(aString.charAt(idx))) { idx++; if (idx == len) { break; } } long value = 0; String unit = null; try { value = Long.parseLong(aString.substring(0, idx)); unit = aString.substring(idx); } catch (Exception e) { return defaultValue; } if (unit.equals("g") || unit.equals("gb")) { return value * GB; } else if (unit.equals("m") || unit.equals("mb")) { return value * MB; } else if (unit.equals("k") || unit.equals("kb")) { return value * KB; } return defaultValue; } /** * Returns the byte [] content of the specified file. * * @param file * @return the byte content of the file */ public static byte [] readContent(File file) { byte [] buffer = new byte[(int) file.length()]; BufferedInputStream is = null; try { is = new BufferedInputStream(new FileInputStream(file)); is.read(buffer, 0, buffer.length); } catch (Throwable t) { System.err.println("Failed to read byte content of " + file.getAbsolutePath()); t.printStackTrace(); } finally { if (is != null) { try { is.close(); } catch (IOException ioe) { System.err.println("Failed to close file " + file.getAbsolutePath()); ioe.printStackTrace(); } } } return buffer; } /** * Returns the string content of the specified file. * * @param file * @param lineEnding * @return the string content of the file */ public static String readContent(File file, String lineEnding) { StringBuilder sb = new StringBuilder(); InputStreamReader is = null; try { is = new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8")); BufferedReader reader = new BufferedReader(is); String line = null; while ((line = reader.readLine()) != null) { sb.append(line); if (lineEnding != null) { sb.append(lineEnding); } } } catch (Throwable t) { System.err.println("Failed to read content of " + file.getAbsolutePath()); t.printStackTrace(); } finally { if (is != null) { try { is.close(); } catch (IOException ioe) { System.err.println("Failed to close file " + file.getAbsolutePath()); ioe.printStackTrace(); } } } return sb.toString(); } /** * Writes the string content to the file. * * @param file * @param content */ public static void writeContent(File file, String content) { OutputStreamWriter os = null; try { os = new OutputStreamWriter(new FileOutputStream(file), Charset.forName("UTF-8")); BufferedWriter writer = new BufferedWriter(os); writer.append(content); writer.flush(); } catch (Throwable t) { System.err.println("Failed to write content of " + file.getAbsolutePath()); t.printStackTrace(); } finally { if (os != null) { try { os.close(); } catch (IOException ioe) { System.err.println("Failed to close file " + file.getAbsolutePath()); ioe.printStackTrace(); } } } } /** * Recursively traverses a folder and its subfolders to calculate the total * size in bytes. * * @param directory * @return folder size in bytes */ public static long folderSize(File directory) { if (directory == null || !directory.exists()) { return -1; } if (directory.isDirectory()) { long length = 0; for (File file : directory.listFiles()) { length += folderSize(file); } return length; } else if (directory.isFile()) { return directory.length(); } return 0; } /** * Delete a file or recursively delete a folder. * * @param fileOrFolder * @return true, if successful */ public static boolean delete(File fileOrFolder) { boolean success = false; if (fileOrFolder.isDirectory()) { File [] files = fileOrFolder.listFiles(); if (files != null) { for (File file : files) { if (file.isDirectory()) { success |= delete(file); } else { success |= file.delete(); } } } } success |= fileOrFolder.delete(); return success; } /** * Copies a file or folder (recursively) to a destination folder. * * @param destinationFolder * @param filesOrFolders * @return * @throws FileNotFoundException * @throws IOException */ public static void copy(File destinationFolder, File... filesOrFolders) throws FileNotFoundException, IOException { destinationFolder.mkdirs(); for (File file : filesOrFolders) { if (file.isDirectory()) { copy(new File(destinationFolder, file.getName()), file.listFiles()); } else { File dFile = new File(destinationFolder, file.getName()); BufferedInputStream bufin = null; FileOutputStream fos = null; try { bufin = new BufferedInputStream(new FileInputStream(file)); fos = new FileOutputStream(dFile); int len = 8196; byte[] buff = new byte[len]; int n = 0; while ((n = bufin.read(buff, 0, len)) != -1) { fos.write(buff, 0, n); } } finally { try { if (bufin != null) bufin.close(); } catch (Throwable t) { } try { if (fos != null) fos.close(); } catch (Throwable t) { } } dFile.setLastModified(file.lastModified()); } } } /** * Determine the relative path between two files. Takes into account * canonical paths, if possible. * * @param basePath * @param path * @return a relative path from basePath to path */ public static String getRelativePath(File basePath, File path) { File exactBase = getExactFile(basePath); File exactPath = getExactFile(path); if (path.getAbsolutePath().startsWith(basePath.getAbsolutePath())) { // absolute base-path match return StringUtils.getRelativePath(basePath.getAbsolutePath(), path.getAbsolutePath()); } else if (exactPath.getPath().startsWith(exactBase.getPath())) { // canonical base-path match return StringUtils.getRelativePath(exactBase.getPath(), exactPath.getPath()); } else if (exactPath.getPath().startsWith(basePath.getAbsolutePath())) { // mixed path match return StringUtils.getRelativePath(basePath.getAbsolutePath(), exactPath.getPath()); } else if (path.getAbsolutePath().startsWith(exactBase.getPath())) { // mixed path match return StringUtils.getRelativePath(exactBase.getPath(), path.getAbsolutePath()); } // no relative relationship return null; } /** * Returns the exact path for a file. This path will be the canonical path * unless an exception is thrown in which case it will be the absolute path. * * @param path * @return the exact file */ public static File getExactFile(File path) { try { return path.getCanonicalFile(); } catch (IOException e) { return path.getAbsoluteFile(); } } public static File resolveParameter(String parameter, File aFolder, String path) { if (aFolder == null) { // strip any parameter reference path = path.replace(parameter, "").trim(); if (path.length() > 0 && path.charAt(0) == '/') { // strip leading / path = path.substring(1); } } else if (path.contains(parameter)) { // replace parameter with path path = path.replace(parameter, aFolder.getAbsolutePath()); } return new File(path); } } ' href='#n182'>182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
/*
* Copyright 2011 gitblit.com.
*
* 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.gitblit.models;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.gitblit.Constants.FederationPullStatus;
import com.gitblit.utils.StringUtils;
/**
* Represents a federated server registration. Gitblit federation allows one
* Gitblit instance to pull the repositories and configuration from another
* Gitblit instance. This is a backup operation and can be considered something
* like svn-sync.
*
*/
public class FederationModel implements Serializable, Comparable<FederationModel> {
private static final long serialVersionUID = 1L;
public String name;
public String url;
public String token;
public String frequency;
public String folder;
public boolean bare;
public boolean mirror;
public boolean mergeAccounts;
public boolean sendStatus;
public boolean notifyOnError;
public List<String> exclusions = new ArrayList<String>();
public List<String> inclusions = new ArrayList<String>();
public Date lastPull;
public Date nextPull;
private Map<String, FederationPullStatus> results = new ConcurrentHashMap<String, FederationPullStatus>();
/**
* The constructor for a remote server configuration.
*
* @param serverName
*/
public FederationModel(String serverName) {
this.name = serverName;
bare = true;
mirror = true;
this.lastPull = new Date(0);
this.nextPull = new Date(0);
}
public boolean isIncluded(RepositoryModel repository) {
// if exclusions has the all wildcard, then check for specific
// inclusions
if (exclusions.contains("*")) {
for (String name : inclusions) {
if (StringUtils.fuzzyMatch(repository.name, name)) {
results.put(repository.name, FederationPullStatus.PENDING);
return true;
}
}
results.put(repository.name, FederationPullStatus.EXCLUDED);
return false;
}
// named exclusions
for (String name : exclusions) {
if (StringUtils.fuzzyMatch(repository.name, name)) {
results.put(repository.name, FederationPullStatus.EXCLUDED);
return false;
}
}
// included by default
results.put(repository.name, FederationPullStatus.PENDING);
return true;
}
/**
* Updates the pull status of a particular repository in this federation
* registration.
*
* @param repository
* @param status
*/
public void updateStatus(RepositoryModel repository, FederationPullStatus status) {
if (!results.containsKey(repository.name)) {
results.put(repository.name, FederationPullStatus.PENDING);
}
if (status != null) {
results.put(repository.name, status);
}
}
public List<RepositoryStatus> getStatusList() {
List<RepositoryStatus> list = new ArrayList<RepositoryStatus>();
for (Map.Entry<String, FederationPullStatus> entry : results.entrySet()) {
list.add(new RepositoryStatus(entry.getKey(), entry.getValue()));
}
return list;
}
/**
* Iterates over the current pull results and returns the lowest pull
* status.
*
* @return the lowest pull status of the registration
*/
public FederationPullStatus getLowestStatus() {
if (results.size() == 0) {
return FederationPullStatus.PENDING;
}
FederationPullStatus status = FederationPullStatus.MIRRORED;
for (FederationPullStatus result : results.values()) {
if (result.ordinal() < status.ordinal()) {
status = result;
}
}
return status;
}
/**
* Returns true if this registration represents the result data sent by a
* pulling Gitblit instance.
*
* @return true, if this is result data
*/
public boolean isResultData() {
return !url.toLowerCase().startsWith("http://") && !url.toLowerCase().startsWith("https://");
}
@Override
public String toString() {
return "Federated " + name + " (" + url + ")";
}
@Override
public int compareTo(FederationModel o) {
boolean r1 = isResultData();
boolean r2 = o.isResultData();
if ((r1 && r2) || (!r1 && !r2)) {
// sort registrations and results by name
return name.compareTo(o.name);
}
// sort registrations first
if (r1) {
return 1;
}
return -1;
}
/**
* Class that encapsulates a point-in-time pull result.
*
*/
public static class RepositoryStatus implements Serializable, Comparable<RepositoryStatus> {
private static final long serialVersionUID = 1L;
public final String name;
public final FederationPullStatus status;
RepositoryStatus(String name, FederationPullStatus status) {
this.name = name;
this.status = status;
}
@Override
public int compareTo(RepositoryStatus o) {
if (status.equals(o.status)) {
return StringUtils.compareRepositoryNames(name, o.name);
}
return status.compareTo(o.status);
}
}
}