supported directory download
This commit is contained in:
		@ -665,7 +665,7 @@ class Code extends Controller
 | 
				
			|||||||
			if ($file === FALSE)
 | 
								if ($file === FALSE)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				$data['project'] = $project;
 | 
									$data['project'] = $project;
 | 
				
			||||||
				$data['message'] = 'Failed to get file';
 | 
									$data['message'] = "Failed to get a file - $path";
 | 
				
			||||||
				$this->load->view ($this->VIEW_ERROR, $data);
 | 
									$this->load->view ($this->VIEW_ERROR, $data);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			else if ($file['type'] == 'file')
 | 
								else if ($file['type'] == 'file')
 | 
				
			||||||
@ -681,36 +681,52 @@ class Code extends Controller
 | 
				
			|||||||
				flush ();
 | 
									flush ();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									$forced_name = $projectid . $file['fullpath'];
 | 
				
			||||||
 | 
									$forced_name = str_replace ('/', '-', $forced_name);
 | 
				
			||||||
 | 
									//$tag = $this->subversion->getRevProp (
 | 
				
			||||||
 | 
										//	$projectid, $file['created_rev'], CODEPOT_SVN_TAG_PROPERTY);
 | 
				
			||||||
 | 
									//if ($tag === FALSE) $tag = '';
 | 
				
			||||||
 | 
									//if (!empty($tag)) 
 | 
				
			||||||
 | 
									//{
 | 
				
			||||||
 | 
									//	$forced_name = $forced_name . '-' . $tag;
 | 
				
			||||||
 | 
									//}
 | 
				
			||||||
 | 
									//else
 | 
				
			||||||
 | 
									//{
 | 
				
			||||||
 | 
										$forced_name = $forced_name . '-r' . $file['created_rev'];
 | 
				
			||||||
 | 
									//}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									$filename = $this->subversion->zipSubdir ($projectid, $path, $rev, $forced_name);
 | 
				
			||||||
 | 
									if ($filename === FALSE)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					$data['project'] = $project;
 | 
										$data['project'] = $project;
 | 
				
			||||||
				$data['headpath'] = $path;
 | 
										$data['message'] = "Failed to zip a directory for $path";
 | 
				
			||||||
				$data['file'] = $file;
 | 
										$this->load->view ($this->VIEW_ERROR, $data);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										$dir_name = $filename . '.d';
 | 
				
			||||||
 | 
										$zip_name = $filename . '.zip';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				$data['revision'] = $rev;
 | 
										$forced_zip_name = $forced_name . '.zip';
 | 
				
			||||||
				$data['prev_revision'] =
 | 
					 | 
				
			||||||
					$this->subversion->getPrevRev ($projectid, $path, $rev);
 | 
					 | 
				
			||||||
				$data['next_revision'] =
 | 
					 | 
				
			||||||
					$this->subversion->getNextRev ($projectid, $path, $rev);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
				$data['readme_text'] = '';
 | 
										header ('Content-Description: File Transfer');
 | 
				
			||||||
				$data['readme_file'] = '';
 | 
										header ('Content-Type: application/zip');
 | 
				
			||||||
				foreach (explode(',', CODEPOT_CODE_FOLDER_README) as $rf)
 | 
										header ('Content-Disposition: attachment; filename='. $forced_zip_name);
 | 
				
			||||||
				{
 | 
										header ('Content-Transfer-Encoding: binary');
 | 
				
			||||||
					$rf = trim($rf);
 | 
										header ('Content-Length: ' . filesize($zip_name));
 | 
				
			||||||
					if (strlen($rf) > 0)
 | 
										flush ();
 | 
				
			||||||
					{
 | 
					
 | 
				
			||||||
						$readme = $this->subversion->getFile ($projectid, $path . '/' . $rf, $rev);
 | 
										@readfile ($zip_name);
 | 
				
			||||||
						if ($readme !== FALSE)
 | 
										// meaningless to show the error page after headers
 | 
				
			||||||
						{
 | 
										// have been sent event if readfile fails.
 | 
				
			||||||
							$data['readme_text'] = $readme['content'];
 | 
					
 | 
				
			||||||
							$data['readme_file'] = $rf;
 | 
										codepot_delete_files ($dir_name, TRUE);
 | 
				
			||||||
							break;
 | 
										@unlink ($zip_name);
 | 
				
			||||||
 | 
										@unlink ($filename);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
				$this->load->view ($this->VIEW_FOLDER, $data);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	function _search_code ($project, $login)
 | 
						function _search_code ($project, $login)
 | 
				
			||||||
@ -737,7 +753,7 @@ class Code extends Controller
 | 
				
			|||||||
			if ($file === FALSE)
 | 
								if ($file === FALSE)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				$data['project'] = $project;
 | 
									$data['project'] = $project;
 | 
				
			||||||
				$data['message'] = "Failed to get file - %path";
 | 
									$data['message'] = "Failed to get file - $path";
 | 
				
			||||||
				$this->load->view ($this->VIEW_ERROR, $data);
 | 
									$this->load->view ($this->VIEW_ERROR, $data);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -983,7 +999,6 @@ class Code extends Controller
 | 
				
			|||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	
 | 
					 | 
				
			||||||
				ksort ($stats);
 | 
									ksort ($stats);
 | 
				
			||||||
				$stats_count = count($stats);
 | 
									$stats_count = count($stats);
 | 
				
			||||||
				$idx = 1;
 | 
									$idx = 1;
 | 
				
			||||||
@ -1001,7 +1016,6 @@ class Code extends Controller
 | 
				
			|||||||
						$max_month = substr($k, 5, 2);
 | 
											$max_month = substr($k, 5, 2);
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
					$idx++;	
 | 
										$idx++;	
 | 
				
			||||||
					$total_commits += $v;
 | 
										$total_commits += $v;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
				
			|||||||
@ -143,6 +143,82 @@ if ( !function_exists ('codepot_delete_files'))
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if ( !function_exists ('codepot_zip_dir'))
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						// $output_file: zip file to create
 | 
				
			||||||
 | 
						// $path: directory to zip recursively
 | 
				
			||||||
 | 
						// $local_path: the leading $path part is translated to $local_path
 | 
				
			||||||
 | 
						// $exclude: file names to exclude. string or array of strings
 | 
				
			||||||
 | 
						function codepot_zip_dir ($output_file, $path, $local_path = NULL, $exclude = NULL)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							$stack = array ();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!is_dir($path)) return FALSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							array_push ($stack, $path); 
 | 
				
			||||||
 | 
							$prefix = strlen($path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							$zip = new ZipArchive();
 | 
				
			||||||
 | 
							if (@$zip->open ($output_file, ZipArchive::OVERWRITE) === FALSE) return FALSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							while (!empty($stack))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								$dir = array_pop($stack);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								$d = @opendir ($dir);
 | 
				
			||||||
 | 
								if ($d === FALSE) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								$new_path = empty($local_path)? $dir: substr_replace($dir, $local_path, 0, $prefix);
 | 
				
			||||||
 | 
								if (@$zip->addEmptyDir($new_path) == FALSE)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									@closedir ($dir);
 | 
				
			||||||
 | 
									$zip->close ();
 | 
				
			||||||
 | 
									return FALSE;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								//printf (">> [%s] [%s]\n", $dir, $new_path);
 | 
				
			||||||
 | 
								while (($f = @readdir($d)) !== FALSE)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if ($f == '.' || $f == '..') continue;
 | 
				
			||||||
 | 
									if (!empty($exclude))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										$found = FALSE;
 | 
				
			||||||
 | 
										if (is_array($exclude))
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											foreach ($exclude as $ex)
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												if (fnmatch ($ex, $f, FNM_PERIOD | FNM_PATHNAME)) 
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													$found = TRUE;
 | 
				
			||||||
 | 
													break;
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											if ($found) continue;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										else if (fnmatch($exclude, $f, FNM_PERIOD | FNM_PATHNAME)) continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									$full_path = $dir . DIRECTORY_SEPARATOR . $f;
 | 
				
			||||||
 | 
									if (is_dir($full_path))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										array_push ($stack, $full_path);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										$new_path = empty($local_path)? $dir: substr_replace($full_path, $local_path, 0, $prefix);
 | 
				
			||||||
 | 
										@$zip->addFile ($full_path, $new_path);
 | 
				
			||||||
 | 
										//printf ("[%s] [%s]\n", $full_path, $new_path);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								@closedir ($dir);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							$zip->close ();
 | 
				
			||||||
 | 
							return TRUE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if ( !function_exists ('codepot_find_longest_matching_sequence'))
 | 
					if ( !function_exists ('codepot_find_longest_matching_sequence'))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	function codepot_find_longest_matching_sequence ($old, $old_start, $old_len, $new, $new_start, $new_len)
 | 
						function codepot_find_longest_matching_sequence ($old, $old_start, $old_len, $new, $new_start, $new_len)
 | 
				
			||||||
 | 
				
			|||||||
@ -999,6 +999,61 @@ class SubversionModel extends Model
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		return $cloc_data;
 | 
							return $cloc_data;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						function zipSubdir ($projectid, $path, $rev, $topdir)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							$orgurl = 'file://'.$this->_canonical_path(CODEPOT_SVNREPO_DIR."/{$projectid}/{$path}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							$workurl = ($path == '')? $orgurl: "{$orgurl}@"; // trailing @ for collision prevention
 | 
				
			||||||
 | 
							$info = @svn_info ($workurl, FALSE, $rev);
 | 
				
			||||||
 | 
							if ($info === FALSE || count($info) != 1) 
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// If a URL is at the root of repository and the url type is file://
 | 
				
			||||||
 | 
								// (e.g. file:///svnrepo/codepot/ where /svnrepo/codepot is a project root),
 | 
				
			||||||
 | 
								// some versions of libsvn end up with an assertion failure like
 | 
				
			||||||
 | 
								//  ... libvvn_subr/path.c:114: svn_path_join: Assertion `svn_path_is_canonical(base, pool)' failed. 
 | 
				
			||||||
 | 
								// 
 | 
				
			||||||
 | 
								// Since the root directory is guaranteed to exist at the head revision,
 | 
				
			||||||
 | 
								// the information can be acquired without using a peg revision.
 | 
				
			||||||
 | 
								// In this case, a normal operational revision is used to work around
 | 
				
			||||||
 | 
								// the assertion failure. Other functions that has to deal with 
 | 
				
			||||||
 | 
								// the root directory should implement this check to work around it.
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								if ($rev == SVN_REVISION_HEAD || $path == '') return FALSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// rebuild the URL with a peg revision and retry it.
 | 
				
			||||||
 | 
								$workurl = "{$orgurl}@{$rev}";
 | 
				
			||||||
 | 
								$info = @svn_info ($workurl, FALSE, $rev);
 | 
				
			||||||
 | 
								if ($info === FALSE || count($info) != 1)  return FALSE;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// pass __FILE__ as the first argument so that tempnam creates a name
 | 
				
			||||||
 | 
							// in the system directory. __FILE__ can never be a valid directory.
 | 
				
			||||||
 | 
							$tfname = @tempnam(__FILE__, 'codepot-fetch-folder-');
 | 
				
			||||||
 | 
							if ($tfname === FALSE) return FALSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							$actual_tfname = $tfname . '.d';
 | 
				
			||||||
 | 
							codepot_delete_files ($actual_tfname, TRUE); // delete the directory in case it exists
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (@svn_checkout ($workurl, $actual_tfname, $rev, 0) === FALSE)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								codepot_delete_files ($actual_tfname, TRUE);
 | 
				
			||||||
 | 
								@unlink ($tfname);
 | 
				
			||||||
 | 
								return FALSE;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//exec ("zip {$tfname}.zip -r {$actual_tfname}");
 | 
				
			||||||
 | 
							if (codepot_zip_dir ("{$tfname}.zip", $actual_tfname, $topdir, array('.svn')) === FALSE) 
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								codepot_delete_files ($actual_tfname, TRUE);
 | 
				
			||||||
 | 
								@unlink ($tfname);
 | 
				
			||||||
 | 
								@unlink ("{$tfname}.zip"); // delete potentially residual zip file 
 | 
				
			||||||
 | 
								return FALSE;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//codepot_delete_files ($actual_tfname, TRUE); // delete the directory in case it exists
 | 
				
			||||||
 | 
							return $tfname;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
?>
 | 
					?>
 | 
				
			||||||
 | 
				
			|||||||
@ -350,6 +350,11 @@ $this->load->view (
 | 
				
			|||||||
		else
 | 
							else
 | 
				
			||||||
			print anchor ("code/history/{$project->id}/{$xpar}", $this->lang->line('History'));
 | 
								print anchor ("code/history/{$project->id}/{$xpar}", $this->lang->line('History'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							print ' | ';
 | 
				
			||||||
 | 
							print anchor (
 | 
				
			||||||
 | 
								"code/fetch/{$project->id}/${xpar}{$revreq}",
 | 
				
			||||||
 | 
								$this->lang->line('Download'));
 | 
				
			||||||
 | 
							
 | 
				
			||||||
		print '</div>';
 | 
							print '</div>';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		usort ($file['content'], 'comp_files');
 | 
							usort ($file['content'], 'comp_files');
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user