Make archiver into its own class
Make archiver into its own class

This moves all archiver functions into a class to wrap around a commit.
This makes it a lot easier to share code, so we don't have to repeatedly
test everywhere if the gzip and bzip2 functions exist, and the
controller doesn't have to worry about things like compressing data.
Plus it gives a central place to add additional archiving related
functions.

--- a/include/controller/Controller_Snapshot.class.php
+++ b/include/controller/Controller_Snapshot.class.php
@@ -18,6 +18,15 @@
  */
 class GitPHP_Controller_Snapshot extends GitPHP_ControllerBase
 {
+
+	/**
+	 * archive
+	 *
+	 * Stores the archive object
+	 *
+	 * @access private
+	 */
+	private $archive = null;
 
 	/**
 	 * __construct
@@ -102,23 +111,14 @@
 	 */
 	protected function LoadHeaders()
 	{
-		$this->params['compressformat'] = GitPHP_Config::GetInstance()->GetValue('compressformat', GITPHP_COMPRESS_ZIP);
-		$rname = $this->project->GetSlug();
+		$format = GitPHP_Config::GetInstance()->GetValue('compressformat', GITPHP_COMPRESS_ZIP);
 
-		if ($this->params['compressformat'] == GITPHP_COMPRESS_ZIP) {
-			$this->headers[] = 'Content-Type: application/x-zip';
-			$this->headers[] = 'Content-Disposition: attachment; filename=' . $rname . '.zip';
-		} else if (($this->params['compressformat'] == GITPHP_COMPRESS_BZ2) && function_exists('bzcompress')) {
-			$this->headers[] = 'Content-Type: application/x-bzip2';
-			$this->headers[] = 'Content-Disposition: attachment; filename=' . $rname . '.tar.bz2';
-		} else if (($this->params['compressformat'] == GITPHP_COMPRESS_GZ) && function_exists('gzencode')) {
-			$this->headers[] = 'Content-Type: application/x-gzip';
-			$this->headers[] = 'Content-Disposition: attachment; filename=' . $rname . '.tar.gz';
-		} else {
-			$this->headers[] = 'Content-Type: application/x-tar';
-			$this->headers[] = 'Content-Disposition: attachment; filename=' . $rname . '.tar';
-		}
+		$this->archive = new GitPHP_Archive($this->project, null, $format, (isset($this->params['path']) ? $this->params['path'] : ''), (isset($this->params['prefix']) ? $this->params['prefix'] : ''));
 
+		$headers = $this->archive->GetHeaders();
+		
+		if (count($headers) > 0)
+			$this->headers = array_merge($this->headers, $headers);
 	}
 
 	/**
@@ -137,7 +137,9 @@
 		else
 			$commit = $this->project->GetCommit($this->params['hash']);
 
-		$this->tpl->assign("archive", $commit->GetArchive($this->params['compressformat'], (isset($this->params['path']) ? $this->params['path'] : null), (isset($this->params['prefix']) ? $this->params['prefix'] : null)));
+		$this->archive->SetObject($commit);
+
+		$this->tpl->assign('archive', $this->archive->GetData());
 	}
 
 }

--- /dev/null
+++ b/include/git/Archive.class.php
@@ -1,1 +1,413 @@
-
+<?php
+/**
+ * GitPHP Archive
+ *
+ * Represents an archive (snapshot)
+ *
+ * @author Christopher Han <xiphux@gmail.com>
+ * @copyright Copyright (c) 2010 Christopher Han
+ * @package GitPHP
+ * @subpackage Git
+ */
+
+require_once(GITPHP_GITOBJECTDIR . 'GitExe.class.php');
+require_once(GITPHP_GITOBJECTDIR . 'Commit.class.php');
+
+define('GITPHP_COMPRESS_TAR', 0);
+define('GITPHP_COMPRESS_BZ2', 1);
+define('GITPHP_COMPRESS_GZ', 2);
+define('GITPHP_COMPRESS_ZIP', 3);
+
+/**
+ * Archive class
+ *
+ * @package GitPHP
+ * @subpackage Git
+ */
+class GitPHP_Archive
+{
+	/**
+	 * gitObject
+	 *
+	 * Stores the object for this archive internally
+	 *
+	 * @access protected
+	 */
+	protected $gitObject = null;
+
+	/**
+	 * project
+	 *
+	 * Stores the project for this archive internally
+	 *
+	 * @access protected
+	 */
+	protected $project = null;
+
+	/**
+	 * format
+	 *
+	 * Stores the archive format internally
+	 *
+	 * @access protected
+	 */
+	protected $format;
+
+	/**
+	 * fileName
+	 *
+	 * Stores the archive filename internally
+	 *
+	 * @access protected
+	 */
+	protected $fileName = '';
+
+	/**
+	 * path
+	 *
+	 * Stores the archive path internally
+	 *
+	 * @access protected
+	 */
+	protected $path = '';
+
+	/**
+	 * prefix
+	 *
+	 * Stores the archive prefix internally
+	 *
+	 * @access protected
+	 */
+	protected $prefix = '';
+
+	/**
+	 * __construct
+	 *
+	 * Instantiates object
+	 *
+	 * @access public
+	 * @param mixed $gitObject the object
+	 * @param integer $format the format for the archive
+	 * @return mixed git archive
+	 */
+	public function __construct($project, $gitObject, $format = 0, $path = '', $prefix = '')
+	{
+		$this->SetProject($project);
+		$this->SetObject($gitObject);
+		$this->SetFormat($format);
+		$this->SetPath($path);
+		$this->SetPrefix($prefix);
+	}
+
+	/**
+	 * GetFormat
+	 *
+	 * Gets the archive format
+	 *
+	 * @access public
+	 * @return integer archive format
+	 */
+	public function GetFormat()
+	{
+		return $this->format;
+	}
+
+	/**
+	 * SetFormat
+	 *
+	 * Sets the archive format
+	 *
+	 * @access public
+	 * @param integer $format archive format
+	 */
+	public function SetFormat($format)
+	{
+		if ((($format == GITPHP_COMPRESS_BZ2) && (!function_exists('bzcompress'))) ||
+		    (($format == GITPHP_COMPRESS_GZ) && (!function_exists('gzencode')))) {
+		    /*
+		     * Trying to set a format but doesn't have the appropriate
+		     * compression function, fall back to tar
+		     */
+		    $format = GITPHP_COMPRESS_TAR;
+		}
+
+		$this->format = $format;
+	}
+
+	/**
+	 * GetObject
+	 *
+	 * Gets the object for this archive
+	 *
+	 * @access public
+	 * @return mixed the git object
+	 */
+	public function GetObject()
+	{
+		return $this->gitObject;
+	}
+
+	/**
+	 * SetObject
+	 *
+	 * Sets the object for this archive
+	 *
+	 * @access public
+	 * @param mixed $object the git object
+	 */
+	public function SetObject($object)
+	{
+		// Archive only works for commits and trees
+		if (($object != null) && (!(($object instanceof GitPHP_Commit) || ($object instanceof GitPHP_Tree)))) {
+			throw new Exception('Invalid source object for archive');
+		}
+
+		$this->gitObject = $object;
+	}
+
+	/**
+	 * GetProject
+	 *
+	 * Gets the project for this archive
+	 *
+	 * @access public
+	 * @return mixed the project
+	 */
+	public function GetProject()
+	{
+		if ($this->project)
+			return $this->project;
+
+		if ($this->gitObject)
+			return $this->gitObject->GetProject();
+
+		return null;
+	}
+
+	/**
+	 * SetProject
+	 *
+	 * Sets the project for this archive
+	 *
+	 * @access public
+	 * @param mixed $project the project
+	 */
+	public function SetProject($project)
+	{
+		$this->project = $project;
+	}
+
+	/**
+	 * GetExtension
+	 *
+	 * Gets the extension to use for this archive
+	 *
+	 * @access public
+	 * @return string extension for the archive
+	 */
+	public function GetExtension()
+	{
+		switch ($this->format) {
+			case GITPHP_COMPRESS_TAR:
+				return 'tar';
+				break;
+			case GITPHP_COMPRESS_BZ2:
+				return 'tar.bz2';
+				break;
+			case GITPHP_COMPRESS_GZ:
+				return 'tar.gz';
+				break;
+			case GITPHP_COMPRESS_ZIP:
+				return 'zip';
+				break;
+		}
+	}
+
+	/**
+	 * GetFilename
+	 *
+	 * Gets the filename for this archive
+	 *
+	 * @access public
+	 * @return string filename
+	 */
+	public function GetFilename()
+	{
+		if (!empty($this->fileName)) {
+			return $this->fileName;
+		}
+
+		$fname = $this->GetProject()->GetSlug();
+
+		$fname .= '.' . $this->GetExtension();
+
+		return $fname;
+	}
+
+	/**
+	 * SetFilename
+	 *
+	 * Sets the filename for this archive
+	 *
+	 * @access public
+	 * @param string $name filename
+	 */
+	public function SetFilename($name = '')
+	{
+		$this->fileName = $name;
+	}
+
+	/**
+	 * GetPath
+	 *
+	 * Gets the path to restrict this archive to
+	 *
+	 * @access public
+	 * @return string path
+	 */
+	public function GetPath()
+	{
+		return $this->path;
+	}
+
+	/**
+	 * SetPath
+	 *
+	 * Sets the path to restrict this archive to
+	 *
+	 * @access public
+	 * @param string $path path to restrict
+	 */
+	public function SetPath($path = '')
+	{
+		$this->path = $path;
+	}
+
+	/**
+	 * GetPrefix
+	 *
+	 * Gets the directory prefix to use for files in this archive
+	 *
+	 * @access public
+	 * @return string prefix
+	 */
+	public function GetPrefix()
+	{
+		if (!empty($this->prefix)) {
+			return $this->prefix;
+		}
+
+		return $this->GetProject()->GetSlug() . '/';
+	}
+
+	/**
+	 * SetPrefix
+	 *
+	 * Sets the directory prefix to use for files in this archive
+	 *
+	 * @access public
+	 * @param string $prefix prefix to use
+	 */
+	public function SetPrefix($prefix = '')
+	{
+		if (empty($prefix)) {
+			$this->prefix = $prefix;
+			return;
+		}
+
+		if (substr($prefix, -1) != '/') {
+			$prefix .= '/';
+		}
+
+		$this->prefix = $prefix;
+	}
+
+	/**
+	 * GetHeaders
+	 *
+	 * Gets the headers to send to the browser for this file
+	 *
+	 * @access public
+	 * @return array header strings
+	 */
+	public function GetHeaders()
+	{
+		$headers = array();
+
+		switch ($this->format) {
+			case GITPHP_COMPRESS_TAR:
+				$headers[] = 'Content-Type: application/x-tar';
+				break;
+			case GITPHP_COMPRESS_BZ2:
+				$headers[] = 'Content-Type: application/x-bzip2';
+				break;
+			case GITPHP_COMPRESS_GZ:
+				$headers[] = 'Content-Type: application/x-gzip';
+				break;
+			case GITPHP_COMPRESS_ZIP:
+				$headers[] = 'Content-Type: application/x-zip';
+				break;
+			default:
+				throw new Exception('Unknown compression type');
+		}
+
+		if (count($headers) > 0) {
+			$headers[] = 'Content-Disposition: attachment; filename=' . $this->GetFilename();
+		}
+
+		return $headers;
+	}
+
+	/**
+	 * GetData
+	 *
+	 * Gets the archive data
+	 *
+	 * @access public
+	 * @return string archive data
+	 */
+	public function GetData()
+	{
+		if (!$this->gitObject)
+		{
+			throw new Exception('Invalid object for archive');
+		}
+
+		$exe = new GitPHP_GitExe($this->GetProject());
+
+		$args = array();
+
+		switch ($this->format) {
+			case GITPHP_COMPRESS_ZIP:
+				$args[] = '--format=zip';
+				break;
+			case GITPHP_COMPRESS_TAR:
+			case GITPHP_COMPRESS_BZ2:
+			case GITPHP_COMPRESS_GZ:
+				$args[] = '--format=tar';
+				break;
+		}
+
+		$args[] = '--prefix=' . $this->GetPrefix();
+		$args[] = $this->gitObject->GetHash();
+
+		if (!empty($this->path))
+			$args[] = $this->path;
+
+		$data = $exe->Execute(GIT_ARCHIVE, $args);
+		unset($exe);
+
+		switch ($this->format) {
+			case GITPHP_COMPRESS_BZ2:
+				$data = bzcompress($data, GitPHP_Config::GetInstance()->GetValue('compresslevel', 4));
+				break;
+			case GITPHP_COMPRESS_GZ:
+				$data = gzencode($data, GitPHP_Config::GetInstance()->GetValue('compresslevel', -1));
+				break;
+		}
+
+		return $data;
+	}
+
+}
+

--- a/include/git/Commit.class.php
+++ b/include/git/Commit.class.php
@@ -671,44 +671,6 @@
 	}
 
 	/**
-	 * GetArchive
-	 *
-	 * Gets an archive of this commit
-	 *
-	 * @access public
-	 * @return string the archive data
-	 * @param format the archive format
-	 * @param path The Path to archive
-	 */
-	public function GetArchive($format, $path = null, $prefix = null)
-	{
-
-		if (is_null($prefix))
-			$prefix = $this->project->GetSlug() . "/";
-		
-		$exe = new GitPHP_GitExe($this->project);
-		$args = array();
-		if ($format == GITPHP_COMPRESS_ZIP)
-			$args[] = '--format=zip';
-		else
-			$args[] = '--format=tar';
-		$args[] = '--prefix=' . $prefix;
-		$args[] = $this->hash;
-		if (! is_null($path)) $args[] = $path;
-
-		$data = $exe->Execute(GIT_ARCHIVE, $args);
-		unset($exe);
-
-		if (($format == GITPHP_COMPRESS_BZ2) && function_exists('bzcompress')) {
-			return bzcompress($data, GitPHP_Config::GetInstance()->GetValue('compresslevel', 4));
-		} else if (($format == GITPHP_COMPRESS_GZ) && function_exists('gzencode')) {
-			return gzencode($data, GitPHP_Config::GetInstance()->GetValue('compresslevel', -1));
-		}
-
-		return $data;
-	}
-
-	/**
 	 * DiffToParent
 	 *
 	 * Diffs this commit with its immediate parent

file:a/index.php -> file:b/index.php
--- a/index.php
+++ b/index.php
@@ -35,6 +35,9 @@
 require_once(GITPHP_INCLUDEDIR . 'MessageException.class.php');
 
 require_once(GITPHP_CONTROLLERDIR . 'Controller.class.php');
+
+// Need this include for the compression constants used in the config file
+require_once(GITPHP_GITOBJECTDIR . 'Archive.class.php');
 
 date_default_timezone_set('UTC');
 
@@ -82,11 +85,6 @@
 
 
 try {
-
-	// Define these here because these get used in the config file
-	define('GITPHP_COMPRESS_BZ2', 1);
-	define('GITPHP_COMPRESS_GZ', 2);
-	define('GITPHP_COMPRESS_ZIP', 3);
 
 	/*
 	 * Configuration

comments