Commits

joshjcarrier  committed 38714da

UNSTABLE: Transition to 1.1.x . Fully revised ini management, reduced cohesion, and coming support for hooks, plug-ins, multiple hgweb.configs. Many regression bugs as transitioning.

  • Participants
  • Parent commits 46961a5

Comments (0)

Files changed (18)

File admin/application/config/autoload.php

 |	$autoload['helper'] = array('url', 'file');
 */
 
-$autoload['helper'] = array('language', 'url');
+$autoload['helper'] = array('language', 'url', 'hg_directory');
 
 
 /*
 |
 */
 
-$autoload['language'] = array();
+$autoload['language'] = array('phphgadmin');
 
 
 /*

File admin/application/config/config.php

 | variable so that it is blank.
 |
 */
-$config['index_page'] = "index.php";
+$config['index_page'] = "";
 
 /*
 |--------------------------------------------------------------------------

File admin/application/config/hgphp.php

  * Absolute local path and filename to where the hgweb.config file is saved
  * E.g. /home/jcarrier/htdocs/hg/hgweb.config
  */
-$config['hgwebconf_abs_filepath'] = '/host/Users/jcarrier/workspace/hg-php.joshjcarrier.com/cgi-bin/hgweb.config';
+$config['hgwebconf_abs_filepath'] = 'C:\Users\joshjcarrier\workspace\hg-php.joshjcarrier.com\admin\lock\cgi-bin\hgweb.config';
 
 /*
  * Accessing the Mercurial repository.
  * Trailing slash required!
  * E.g. /home/jcarrier/hg_repositories/
  */
-$config['repositories_abs_dir'] = '/host/Users/jcarrier/workspace/hg-php.joshjcarrier.com/cgi-bin/';
+$config['repositories_abs_dir'] = 'C:\Users\joshjcarrier\workspace\hg-php.joshjcarrier.com\admin\lock\cgi-bin/';
 
 /*
  * Manager theme - mimics available Mercurial themes
 define('HGPHP_REPO_STATUS_MISSING', 2);
 
 define('HGPHP_NAME', 'phpHgAdmin Mercurial Repository Manager');
-define('HGPHP_VERSION', '1.0.20100603');
+define('HGPHP_VERSION', '1.0.20100609');
 define('HGPHP_AUTHOR_NAME', 'Josh Carrier');
 define('HGPHP_AUTHOR_LINK', 'http://www.joshjcarrier.com');
 

File admin/application/config/phphgadmin.php

+<?php
+
+
+$config['installs']['default']['hgweb_ini'] = 'C:\Users\joshjcarrier\workspace\hg-php.joshjcarrier.com\admin\lock\cgi-bin/hgweb.config';
+$config['installs']['default']['repo_dir'] = 'C:\Users\joshjcarrier\workspace\hg-php.joshjcarrier.com\admin\lock\cgi-bin/';
+
+$config['default_install'] = 'default';

File admin/application/controllers/hgdir.php

 	function HgDir()
 	{
 		parent::Private_Controller();
-		$this->load->library('hgphp');
+//		$this->load->library('hgphp');
 		$this->load->helper(array('form', 'url'));
 		$this->load->library('form_validation');
+		$this->load->library('phphgadmin');
 	}
 	
 	function index()
 		
 		$this->template->title(lang('hgphp_title_directory'), 'Mercurial Repository Manager');
 
-		$this->hgphp->start_transaction($this->ofl_lock_hgwebconf, $dummy='');
-		$lsdir = $this->hgphp->lsdir();
-		$this->hgphp->end_transaction();
+//		$this->hgphp->start_transaction($this->ofl_lock_hgwebconf, $dummy='');
+//		$lsdir = $this->hgphp->lsdir();
+		$lsdir = $this->phphgadmin->lsdir();
+//		$this->hgphp->end_transaction();
 		
 		if(!is_array($lsdir))
 		{
 		}
 		
 		$this->session->set_flashdata('ofl_hgwebconf', $this->ofl_lock_hgwebconf);
+
 		$this->template->build('repo_directory', array('lsdir'=>$lsdir));
 	}
 	
 		}
 		else
 		{
-			$this->hgphp->start_transaction($this->ofl_lock_hgwebconf, $dummy='');
-			$action_status = $this->hgphp->create_repository($r_name);
-			$this->hgphp->end_transaction();
+//			$this->hgphp->start_transaction($this->ofl_lock_hgwebconf, $dummy='');
+			$action_status = $this->phphgadmin->create_repository($r_name);
+			
+			if($action_status == HGPHP_OK)
+			{
+				$action_status = $this->hg_ini->touchHgRC($r_name);
+			}
+//			$this->hgphp->end_transaction();
 			
 			switch($action_status){
 				case HGPHP_OK:
 	
 	function delete()
 	{
-		$r_name = $this->input->post('form_delete_name');
-		$this->form_validation->set_rules('form_delete_name', 'form_delete_name', 'required|alpha_dash|min_length[1]|max_length[255]');
+		$r_key = $this->input->post('form_delete_name');
+		$this->form_validation->set_rules('form_delete_name', 'form_delete_name', 'required');
 			
 		if ($this->form_validation->run() == FALSE)
 		{
 		}
 		else
 		{
-			$this->hgphp->start_transaction($this->ofl_lock_hgwebconf, $dummy='');
-			$action_status = $this->hgphp->delete_repository($r_name);
-			$this->hgphp->end_transaction();
+			$r_name = base64_decode($r_key);
+			$action_status = $this->phphgadmin->delete_repository($r_key);
+//			$this->hgphp->start_transaction($this->ofl_lock_hgwebconf, $dummy='');
+//			$action_status = $this->hgphp->delete_repository($r_name);
+//			$this->hgphp->end_transaction();
 			
 			switch($action_status){
 				case HGPHP_OK:

File admin/application/controllers/hgrepo.php

 	function HgRepo()
 	{
 		parent::Private_Controller();
-		$this->load->library('hgphp');
+		$this->load->library('phphgadmin');
+		$this->load->library('iniparser');
 	}
 	
 	function browse()
 			
 			if($valid)
 			{
-				$this->hgphp->start_transaction($dummy='', $ofl_lock_hgrc);
-				$save_status = $this->hgphp->update_repository($repositoryName, $hgrc_form);
-				$this->hgphp->end_transaction();
+//				$this->hgphp->start_transaction($dummy='', $ofl_lock_hgrc);
+				$ini64 = new ini64($hgrc_form);
+				$save_status = $this->phphgadmin->update_repository($repositoryName, $ini64);
+//				$this->hgphp->end_transaction();
 				
 				switch($save_status)
 				{
 		
 		$this->template->title($repositoryName, 'Mercurial Repository Editor');
 		
-		$this->hgphp->start_transaction($dummy='', $ofl_lock_hgrc);
-		$hgrc = $this->hgphp->stat_repository($repositoryName);
-		$this->hgphp->end_transaction();
+//		$this->hgphp->start_transaction($dummy='', $ofl_lock_hgrc);
+		$hgrc = $this->phphgadmin->stat_repository($repositoryName);
+//		$this->hgphp->end_transaction();
 		
-		if(!is_array($hgrc))
+		if($hgrc === FALSE)
 		{
 			switch($hgrc)
 			{
 		
 		$this->session->set_flashdata('ofl_hgrc_' . $repositoryName, $ofl_lock_hgrc);
 		$this->template->build('repository', 
-			array('hgrc' => $hgrc, 'r_name' => $repositoryName, 
+			array('hgrc' => serialize($hgrc), 'r_name' => $repositoryName, 
 					'hgrc_bools_arr'=>$this->config->item('hgrc_bools_arr', 'hgphp'),
 					'hgrc_form' => $hgrc_form
 			));	

File admin/application/helpers/hg_directory_helper.php

+<?php 
+
+function have_repos()
+{
+}
+
+function the_title()
+{
+	
+}

File admin/application/language/english/hgphp_lang.php

-<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
-
-$lang['hgphp_title_repo'] = 'Repository Name';
-$lang['hgphp_title_repodir'] = 'Path';
-$lang['hgphp_title_status'] = 'Status';
-$lang['hgphp_title_configkey'] = 'Config Key';
-$lang['hgphp_title_configval'] = 'Value';
-$lang['hgphp_title_adminhome'] = 'Administration Home';
-$lang['hgphp_title_listingshome'] = 'Mercurial Front-end';
-$lang['hgphp_title_help'] = 'Help';
-$lang['hgphp_title_directory'] = 'Directory';
-
-$lang['hgphp_action_ok'] = "Ok";
-$lang['hgphp_action_create'] = 'Create';
-$lang['hgphp_action_delete'] = 'Delete';
-$lang['hgphp_action_save'] = 'Save';
-$lang['hgphp_action_reset'] = 'Reset';
-$lang['hgphp_action_cancel'] = 'Cancel';
-$lang['hgphp_action_browse'] = 'Browse';
-$lang['hgphp_action_reload'] = 'Reload configuration';
-$lang['hgphp_action_update_config'] = 'Update configuration';
-
-$lang['hgphp_dialog_repo_create'] = 'Enter a new repository name: ';
-$lang['hgphp_dialog_repo_save'] = 'Saving will immediately put the changes into effect.';
-$lang['hgphp_dialog_repo_delete'] = 'Deleting a repository cannot be undone. Choose a repository to be removed: ';
-
-$lang['hgphp_repostatus_enabled'] = 'Enabled';
-$lang['hgphp_repostatus_missing'] = 'Missing';
-$lang['hgphp_repostatus_disabled'] = 'Disabled';
-
-$lang['hgphp_msg_hgwebconf_read_err_absdirs'] = 'Problem scanning repository directory. Check configuration paths to hgweb.config and the repositories and that the server has write permissions to both.';
-
-$lang['hgphp_msg_hgwebconf_create_success'] = 'Repository created successfully.';
-$lang['hgphp_msg_hgwebconf_create_err_validname'] = 'Creating a repository requires a valid name:<li>contains only alpha-numerics, dashes or underscores<li>between 1 and 255 characters long.';
-$lang['hgphp_msg_hgwebconf_create_err_blacklistname'] = 'Creating a repository name cannot match the path reserved for Hg-PHP.';
-$lang['hgphp_msg_hgwebconf_create_err_permuser'] = 'Repository could not be created; insufficient user privileges.';
-$lang['hgphp_msg_hgwebconf_create_err_permsys'] = 'Repository could not be created; insufficient server privileges.';
-$lang['hgphp_msg_hgwebconf_create_err_preexists'] = 'Repository could not be created; it already exists.';
-$lang['hgphp_msg_hgwebconf_create_err_locking'] = 'Could not complete creation.<br />Configuration had been modified since last loaded.';
-
-$lang['hgphp_msg_hgwebconf_delete_success'] = 'Repository deleted successfully.';
-$lang['hgphp_msg_hgwebconf_delete_err_permuser'] = 'Repository could not be deleted; insufficient user privileges.';
-$lang['hgphp_msg_hgwebconf_delete_err_unspecified_name'] = 'Deleting a repository requires specifying an existing entry.';
-$lang['hgphp_msg_hgwebconf_delete_err_permsys'] = 'Repository could not be deleted; insufficient server privileges.';
-$lang['hgphp_msg_hgwebconf_delete_err_preexists'] = 'Repository could not be deleted; it already exists.';
-$lang['hgphp_msg_hgwebconf_delete_err_locking'] = 'Could not complete deletion.<br />Configuration had been modified since last loaded.';
-
-$lang['hgphp_msg_hgrc_save_success'] = 'Repository configuration successfully saved.';
-$lang['hgphp_msg_hgrc_save_err_locking'] = 'Could not complete update.<br />Configuration had been modified since last loaded.';
-$lang['hgphp_msg_hgrc_save_err_validation'] = 'Repository configuration can only contain alphanumerics or the following characters: ';
-$lang['hgphp_msg_hgrc_read_err'] = 'Repository configuration could not be found or contains invalid characters and cannot be displayed. Contact your repository administrator to fix this issue.';
-$lang['hgphp_msg_hgrc_save_err_notfound'] = 'Repository configuration could not be found.';
-
-$lang['hgphp_msg_err'] = 'Alert';
-$lang['hgphp_msg_unknown_err'] = 'An error prevented the action from completing: ';
-
-$lang['hgphp_doclink_hgrc'] = 'http://www.selenic.com/mercurial/hgrc.5.html#';
-
-$lang['hgphp_tooltip_hgrc_paths_default'] = 'Directory or URL to use when pulling if no source is specified.';
-$lang['hgphp_tooltip_hgrc_web_allow_archive'] = 'List of archive format (bz2, gz, zip) allowed for downloading.';
-$lang['hgphp_tooltip_hgrc_web_allow_push'] = 'Whether to allow pushing to the repository. If empty, push is not allowed. If the special value *, any remote user can push, including unauthenticated users. Otherwise, the remote user must have been authenticated, and the authenticated user name must be present in this list (separated by whitespace or ,).';
-$lang['hgphp_tooltip_hgrc_web_allowpull'] = 'Whether to allow pulling from the repository.';
-$lang['hgphp_tooltip_hgrc_web_allow_read'] = 'This list determines whether to grant repository access to the user. If this list is not empty, and the user is unauthenticated or not present in the list (separated by whitespace or ,), then access is denied for the user. If the list is empty or not set, then access is permitted to all users by default.';
-$lang['hgphp_tooltip_hgrc_web_contact'] = 'Name or email address of the person in charge of the repository. Defaults to ui.username or $EMAIL or "unknown" if empty.';
-$lang['hgphp_tooltip_hgrc_web_description'] = 'Textual description of the repository\'s purpose or contents. Default is "unknown" if unset.';
-$lang['hgphp_tooltip_hgrc_web_name'] = 'Repository name to use in the web interface. Default is current working directory.';
-$lang['hgphp_tooltip_hgrc_web_push_ssl'] = 'Whether to require that inbound pushes be transported over SSL to prevent password sniffing. If using http authentication, must be FALSE.';
-$lang['hgphp_tooltip_hgrc_web_style'] = 'Which template map style to use. Examples: paper (default), coal, gitweb, monoblue, spartan. Also atom, rss.';

File admin/application/language/english/phphgadmin_lang.php

+<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
+
+$lang['hgphp_title_repo'] = 'Repository Name';
+$lang['hgphp_title_repodir'] = 'Path';
+$lang['hgphp_title_status'] = 'Status';
+$lang['hgphp_title_configkey'] = 'Config Key';
+$lang['hgphp_title_configval'] = 'Value';
+$lang['hgphp_title_adminhome'] = 'Administration Home';
+$lang['hgphp_title_listingshome'] = 'Mercurial Front-end';
+$lang['hgphp_title_help'] = 'Help';
+$lang['hgphp_title_directory'] = 'Directory';
+
+$lang['hgphp_action_ok'] = "Ok";
+$lang['hgphp_action_create'] = 'Create';
+$lang['hgphp_action_delete'] = 'Delete';
+$lang['hgphp_action_save'] = 'Save';
+$lang['hgphp_action_reset'] = 'Reset';
+$lang['hgphp_action_cancel'] = 'Cancel';
+$lang['hgphp_action_browse'] = 'Browse';
+$lang['hgphp_action_reload'] = 'Reload configuration';
+$lang['hgphp_action_update_config'] = 'Update configuration';
+
+$lang['hgphp_dialog_repo_create'] = 'Enter a new repository name: ';
+$lang['hgphp_dialog_repo_save'] = 'Saving will immediately put the changes into effect.';
+$lang['hgphp_dialog_repo_delete'] = 'Deleting a repository cannot be undone. Choose a repository to be removed: ';
+
+$lang['hgphp_repostatus_enabled'] = 'Enabled';
+$lang['hgphp_repostatus_missing'] = 'Missing';
+$lang['hgphp_repostatus_disabled'] = 'Disabled';
+
+$lang['hgphp_msg_hgwebconf_read_err_absdirs'] = 'Problem scanning repository directory. Check configuration paths to hgweb.config and the repositories and that the server has write permissions to both.';
+
+$lang['hgphp_msg_hgwebconf_create_success'] = 'Repository created successfully.';
+$lang['hgphp_msg_hgwebconf_create_err_validname'] = 'Creating a repository requires a valid name:<li>contains only alpha-numerics, dashes or underscores<li>between 1 and 255 characters long.';
+$lang['hgphp_msg_hgwebconf_create_err_blacklistname'] = 'Creating a repository name cannot match the path reserved for Hg-PHP.';
+$lang['hgphp_msg_hgwebconf_create_err_permuser'] = 'Repository could not be created; insufficient user privileges.';
+$lang['hgphp_msg_hgwebconf_create_err_permsys'] = 'Repository could not be created; insufficient server privileges.';
+$lang['hgphp_msg_hgwebconf_create_err_preexists'] = 'Repository could not be created; it already exists.';
+$lang['hgphp_msg_hgwebconf_create_err_locking'] = 'Could not complete creation.<br />Configuration had been modified since last loaded.';
+
+$lang['hgphp_msg_hgwebconf_delete_success'] = 'Repository deleted successfully.';
+$lang['hgphp_msg_hgwebconf_delete_err_permuser'] = 'Repository could not be deleted; insufficient user privileges.';
+$lang['hgphp_msg_hgwebconf_delete_err_unspecified_name'] = 'Deleting a repository requires specifying an existing entry.';
+$lang['hgphp_msg_hgwebconf_delete_err_permsys'] = 'Repository could not be deleted; insufficient server privileges.';
+$lang['hgphp_msg_hgwebconf_delete_err_preexists'] = 'Repository could not be deleted; it has already been removed.';
+$lang['hgphp_msg_hgwebconf_delete_err_locking'] = 'Could not complete deletion.<br />Configuration had been modified since last loaded.';
+
+$lang['hgphp_msg_hgrc_save_success'] = 'Repository configuration successfully saved.';
+$lang['hgphp_msg_hgrc_save_err_locking'] = 'Could not complete update.<br />Configuration had been modified since last loaded.';
+$lang['hgphp_msg_hgrc_save_err_validation'] = 'Repository configuration can only contain alphanumerics or the following characters: ';
+$lang['hgphp_msg_hgrc_read_err'] = 'Repository configuration could not be found or contains invalid characters and cannot be displayed. Contact your repository administrator to fix this issue.';
+$lang['hgphp_msg_hgrc_save_err_notfound'] = 'Repository configuration could not be found.';
+
+$lang['hgphp_msg_err'] = 'Alert';
+$lang['hgphp_msg_unknown_err'] = 'An error prevented the action from completing: ';
+
+$lang['hgphp_doclink_hgrc'] = 'http://www.selenic.com/mercurial/hgrc.5.html#';
+
+$lang['hgphp_tooltip_hgrc_paths_default'] = 'Directory or URL to use when pulling if no source is specified.';
+$lang['hgphp_tooltip_hgrc_web_allow_archive'] = 'List of archive format (bz2, gz, zip) allowed for downloading.';
+$lang['hgphp_tooltip_hgrc_web_allow_push'] = 'Whether to allow pushing to the repository. If empty, push is not allowed. If the special value *, any remote user can push, including unauthenticated users. Otherwise, the remote user must have been authenticated, and the authenticated user name must be present in this list (separated by whitespace or ,).';
+$lang['hgphp_tooltip_hgrc_web_allowpull'] = 'Whether to allow pulling from the repository.';
+$lang['hgphp_tooltip_hgrc_web_allow_read'] = 'This list determines whether to grant repository access to the user. If this list is not empty, and the user is unauthenticated or not present in the list (separated by whitespace or ,), then access is denied for the user. If the list is empty or not set, then access is permitted to all users by default.';
+$lang['hgphp_tooltip_hgrc_web_contact'] = 'Name or email address of the person in charge of the repository. Defaults to ui.username or $EMAIL or "unknown" if empty.';
+$lang['hgphp_tooltip_hgrc_web_description'] = 'Textual description of the repository\'s purpose or contents. Default is "unknown" if unset.';
+$lang['hgphp_tooltip_hgrc_web_name'] = 'Repository name to use in the web interface. Default is current working directory.';
+$lang['hgphp_tooltip_hgrc_web_push_ssl'] = 'Whether to require that inbound pushes be transported over SSL to prevent password sniffing. If using http authentication, must be FALSE.';
+$lang['hgphp_tooltip_hgrc_web_style'] = 'Which template map style to use. Examples: paper (default), coal, gitweb, monoblue, spartan. Also atom, rss.';

File admin/application/libraries/hg_filesystem.php

+<?php
+
+class Hg_Filesystem
+{
+	private $_ci;
+	
+	function __construct()
+	{
+		$this->_ci = &get_instance();
+	}
+	
+	/**
+	 * create_repository_dir
+	 * Creates a whole repository directory, with hgrc
+	 * @param r_name name of repository to create directory for
+	 * @return status code
+	 */
+	function create_repository_dir($r_name)
+	{
+		// create repo directory structure recursively
+		$create_status = @mkdir('C:\Users\joshjcarrier\workspace\hg-php.joshjcarrier.com\admin\lock\cgi-bin/' . $r_name . '/.hg/store/data/', 0755, TRUE);
+		
+		if($create_status == TRUE)
+		{
+			// create hgrc
+			
+//			$this->_ci->hgconf2ini->register_OFL($this->_ofl_lock_hgrc);
+//			$create_status = $this->_ci->hgconf2ini->touchHgRC($r_name);
+			$create_status = HGPHP_OK;
+		}
+		else
+		{
+			// system couldn't make directory
+			$create_status = HGPHP_ERR_PERM_SYS_REPODIR;
+		}
+		return $create_status;
+	}
+	
+	/**
+	 * delete_repository_dir
+	 * Deletes a whole repository directory including hgrc and data files
+	 * @param r_name name of repository to delete directory of
+	 * @return status code
+	 */
+	function delete_repository_dir($repository_name)
+	{
+		$cd = 'C:\Users\joshjcarrier\workspace\hg-php.joshjcarrier.com\admin\lock\cgi-bin/' . $repository_name;
+		$this->recursiveDelete($cd . '/.hg/');
+		$del_status = $this->recursiveDelete($cd);
+		if($del_status == TRUE)
+		{
+			$del_status = HGPHP_OK;
+		}
+		else
+		{
+			$del_status = HGPHP_ERR_PERM_SYS_REPODIR;
+		}
+		return $del_status;
+	}
+	
+	/**
+	 * Performs a real directory scan where the projects are suppose to reside.
+	 * 
+	 * @return the array containing 0 or more valid directories
+	 */
+	function real_dirscan()
+	{
+		$this->_ci->load->helper('directory');
+		
+		$realdir = directory_map('C:\Users\joshjcarrier\workspace\hg-php.joshjcarrier.com\admin\lock\cgi-bin/', TRUE);
+		
+		$verifiedrealdir = array();
+		if(is_array($realdir))
+		{
+			foreach($realdir as $file)
+			{
+				// checks if we detected a folder
+				if(is_dir('C:\Users\joshjcarrier\workspace\hg-php.joshjcarrier.com\admin\lock\cgi-bin/' . $file))
+				{
+					$verifiedrealdir[$file] = $file;
+				}
+			}
+		}
+		
+		return $verifiedrealdir;
+	}
+	
+	/**
+     * Delete a file or recursively delete a directory
+     *
+     * @param string $str Path to file or directory
+     * @return true on successful deletion
+     */
+    function recursiveDelete($str){
+        if(is_file($str)){
+            return @unlink($str);
+        }
+        elseif(is_dir($str)){
+            $scan = glob(rtrim($str,'/').'/*');
+            foreach($scan as $index=>$path){
+                $this->recursiveDelete($path);
+            }
+            return @rmdir($str);
+        }
+    }
+}

File admin/application/libraries/hg_ini.php

+<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
+
+/**
+ * CodeIgniter Mercurial Config Parser Class
+ * 
+ * Overcomes general PHP ini parsing limitation due to invalid characters in hgweb.conf 'Collection' keys when
+ * generating key-value pairs, and handles concurrency. Also handles per-repository HGRC configuration.
+ * 
+ * @package        	CodeIgniter
+ * @subpackage    	Libraries
+ * @category    	Libraries
+ * @author 			Josh Carrier
+ * @link			blog.joshjcarrier.com
+ * 
+ */
+class Hg_Ini
+{
+	private $_ci;
+	
+	function __construct()
+	{
+		$this->_ci = &get_instance();
+		$this->_ci->load->library('optimisticflock');
+	}
+	
+	function registerRepo($r_name)
+	{
+		$ini = $this->loadHgWeb();
+		$ini->set('testing', $r_name, 'collections');
+		return $this->saveHgWeb($ini);
+	}
+	
+	function unregisterRepo($r_key)
+	{
+		$ini = $this->loadHgWeb();
+		$ini->unsetKey($r_key, 'collections');
+		return $this->saveHgWeb($ini);
+	}
+	
+	function getRepoList()
+	{
+		$ini = $this->loadHgWeb();
+		if(is_object($ini))
+		{
+			return $ini->get('collections');
+		}
+		return FALSE; // FIXME
+	}
+	
+	function loadHgWeb()
+	{
+		// load the PHP to file
+		$hgwebconf = 'C:\Users\joshjcarrier\workspace\hg-php.joshjcarrier.com\admin\lock\cgi-bin/hgweb.config';
+
+		// concurrency-safe get contents
+		$hgwebconf_err_code = '';
+		$hgwebconf_all = $this->_ci->optimisticflock->ofl_parse_ini_file($hgwebconf, true, $this->_ofl_lock, $hgwebconf_err_code);
+		if($hgwebconf_err_code == HGPHP_OK)
+		{
+				return $hgwebconf_all;
+		}
+		return $hgwebconf_err_code;
+	}
+	
+	function saveHgWeb($hgrc_data)
+	{
+		$hgwebconf = 'C:\Users\joshjcarrier\workspace\hg-php.joshjcarrier.com\admin\lock\cgi-bin/hgweb.config';
+		$hgrc_new_ini = ';Generated by Hg-PHP Mercurial Repository Manager v'.HGPHP_VERSION;
+		
+		if(is_object($hgrc_data))
+		{
+			$hgrc_new_ini .= $hgrc_data->toString();
+			$hgrc_new_ini .= "\n;End generated HGRC\n";
+			
+			// concurrency-safe persist to disk
+			return $this->_ci->optimisticflock->ofl_file_put_contents($hgwebconf, $hgrc_new_ini, $this->_ofl_lock, true);
+		}
+		else
+		{
+			return HGPHP_ERR_FS_PREEXISTS;
+		}
+	}
+	
+	function loadHgRC($r_id)
+	{
+		// load the PHP to file
+		$hgwebconf = 'C:\Users\joshjcarrier\workspace\hg-php.joshjcarrier.com\admin\lock\cgi-bin/test/.hg/hgrc';
+
+		// concurrency-safe get contents
+		$hgwebconf_err_code = '';
+		$hgwebconf_all = $this->_ci->optimisticflock->ofl_parse_ini_file($hgwebconf, true, $this->_ofl_lock, $hgwebconf_err_code);
+		if($hgwebconf_err_code == HGPHP_OK)
+		{
+				return $hgwebconf_all;
+		}
+		return $hgwebconf_err_code;
+	}
+	
+	/**
+	 * touchHGRC
+	 * Generates a new HGRC file in a given repository directory, with default values
+	 * @param r_name name of the repo folder which will have an HGRC file added to
+	 * @return status code
+	 */
+	function touchHgRC($r_name)
+	{
+		$hgrc_path = 'C:\Users\joshjcarrier\workspace\hg-php.joshjcarrier.com\admin\lock\cgi-bin/' . $r_name . '/.hg/hgrc';
+		
+		// create file
+		$touch_status = $this->_ci->optimisticflock->ofl_touch($hgrc_path, $this->_ofl_lock);
+		if($touch_status == HGPHP_OK)
+		{
+			$blank_hgrc = $this->__blank_hgrc($r_name);
+			
+			// update touch status for setHGRC return code
+			$touch_status = $this->saveHgRC($r_name, $blank_hgrc);
+		}
+		return $touch_status;
+	}
+	
+	/**
+	 * unlinkHGRC
+	 * @param r_name name of repo to delete
+	 * @return status code
+	 */
+	function unlinkHgRC($r_name)
+	{
+		$hgrc_path = 'C:\Users\joshjcarrier\workspace\hg-php.joshjcarrier.com\admin\lock\cgi-bin/' . $r_name . '/.hg/hgrc';
+		
+		// design decision - force deletion of repository always
+		return $this->_ci->optimisticflock->ofl_unlink($hgrc_path, $this->_ofl_lock, TRUE);
+	}
+	
+/**
+	 * __hgrc_compat_persist (private method)
+	 * Replaces the current HGRC file with one generated represented by a multi-dimensional array
+	 * @param r_name name of the repository containing the target HGRC file
+	 * @param hgrc_data multi-array representation of the new HGRC file
+	 * @return status code
+	 */
+	function saveHgRC($r_name, $hgrc_data)
+	{
+		$hgrc_path = 'C:\Users\joshjcarrier\workspace\hg-php.joshjcarrier.com\admin\lock\cgi-bin/' . $r_name . '/.hg/hgrc';
+		
+		$hgrc_new_ini = ';Generated by Hg-PHP Mercurial Repository Manager v'.HGPHP_VERSION;
+		
+		if(is_object($hgrc_data))
+		{
+			$hgrc_new_ini .= $hgrc_data->toString();
+			$hgrc_new_ini .= "\n;End generated HGRC\n";
+			
+			// concurrency-safe persist to disk
+			return $this->_ci->optimisticflock->ofl_file_put_contents($hgrc_path, $hgrc_new_ini, $this->_ofl_lock, false);
+		}
+		else
+		{
+			return HGPHP_ERR_FS_PREEXISTS;
+		}
+	}
+
+	/**
+	 * touchHGRC
+	 * Generates a new HGRC representation as an array
+	 * @param r_name name of the repository which will own the hgrc file
+	 * @return hgrc reprsented as array
+	 */
+	function __blank_hgrc($r_name)
+	{
+		// automatic appending
+//		$blank_hgrc = $this->_hgrc_default_arr;
+//		$blank_hgrc['paths']['default'] = sprintf($blank_hgrc['paths']['default'], $r_name);
+//		$blank_hgrc['web']['name'] = sprintf($blank_hgrc['web']['name'], $r_name);
+		$blank_hgrc = array('paths'=>array('default'=>'testing'));
+		return new ini64($blank_hgrc);
+	}
+	
+//	private $_ci;
+//	private $_ofl_lock;
+//	private $cache_hgwebconf;
+//	private $cache_hgrc = array();
+//	
+//	function __construct($config = array())
+//	{
+//		$this->_ci =& get_instance();
+//		
+//		if(!empty($config))
+//		{
+//			$this->initialize($config);
+//		}
+//		else
+//		{
+//			
+//			$this->_ci->config->load('hgphp', TRUE);
+//			$this->initialize($this->_ci->config->item('hgphp'));
+//		}
+//		
+//		$this->_ci->load->library('optimisticflock', 
+//			array(
+//				'lock_dir' => $this->_lock_dir, 
+//				'lock_ofl_index' => $this->_lock_ofl_index,
+//				'ofl_disabled' => $this->_ofl_disabled
+//			));
+//        log_message('debug', 'HgConf2Ini class Initialized');
+//	}
+//	
+//	function initialize($config = array())
+//	{
+//		foreach($config as $key=>$val)
+//		{
+//			$this->{'_'.$key} = $val;
+//		}
+//	}
+//	
+//	/**
+//	 * Registers OFL lock
+//	 */
+//	function register_OFL(&$ofl_lock)
+//	{
+//		$this->_ofl_lock = &$ofl_lock;
+//	}
+//	
+//	function unregister_OFL()
+//	{
+//		$dummy = '';
+//		$this->_ofl_lock = &$dummy;
+//	}
+//	
+//	/**
+//	 * getHgWebDirConfig
+//	 * Scans Mercurial's hgweb.conf configuration file and returns
+//	 * representation in key/value pairs.
+//	 * @return multi-dimensional array representing Hg directory config file (see PHP ini parsing), status code otherwise
+//	 */
+//	function getHgWebDirConfig()
+//	{
+//		// check if need to create cache
+//		if(!is_object($this->cache_hgwebconf))
+//		{
+//			$hgwebconf_all = $this->__hgwebconf_compat_load();
+//			$this->cache_hgwebconf = $hgwebconf_all;
+//		}
+//
+//		// cached copy returned
+//		return $this->cache_hgwebconf;
+//	}
+//	
+//	/**
+//	 * setHgWebDirConfig
+//	 * Converts a multi-dimensional array representing a Hg directory config file (see PHP ini parsing) to file
+//	 * @param hgwebconf_data multi-dimensional array representing a Hg directory config file
+//	 * @return status code
+//	 */
+//	function setHgWebDirConfig($hgwebconf_data)
+//	{
+//		$hgwebconf_status = $this->__hgwebconf_compat_persist($hgwebconf_data);
+//		
+//		if($hgwebconf_status == HGPHP_OK)
+//		{
+//			// update cache on success
+//			$this->cache_hgwebconf = $hgwebconf_data;
+//			return HGPHP_OK;
+//		}
+//		else
+//		{
+//			// is a status code
+//			return $hgwebconf_status;
+//		}
+//	}
+//	
+//	/**
+//	 * getHgWebDirCollections
+//	 * Scans Mercurial's hgweb.conf configuration file and returns
+//	 * a single associative array whose key/value pairs are the names of each listed repository
+//	 * @return a single associative array whose key/value pairs are the names of each listed repository, status code otherwise
+//	 */
+//	function getHgWebDirCollections()
+//	{
+//		$hgwebconf_all = $this->getHgWebDirConfig();
+//		
+//		if(is_object($hgwebconf_all))
+//		{
+//			return $hgwebconf_all->get('collections');
+//		}
+//		else
+//		{
+//			// is a status code
+//			return $hgwebconf_all;
+//		}
+//	}
+//	
+//	/**
+//	 * setHgWebDirCollections
+//	 * Replaces the current directory config collections with ones represented by a single associative array whose key/value pairs 
+//	 * are the names of each listed repository
+//	 * @param hgwebconf_collections a single associative array whose key/value pairs are the names of each listed repository
+//	 * @return status code
+//	 */
+//	function setHgWebDirCollections($hgwebconf_collections)
+//	{
+//		$hgwebconf_all = $this->getHgWebDirConfig(); // no need to update lock yet
+//		
+//		if(is_object($hgwebconf_all))
+//		{
+//			$hgwebconf_all->set('collections', $hgwebconf_collections);
+//			return $this->setHgWebDirConfig($hgwebconf_all);
+//		}
+//		else
+//		{
+//			// is a status code
+//			return $hgwebconf_all;
+//		}
+//	}
+//	
+//	/**
+//	 * getHGRC
+//	 * Scans a Mercurial repository's HGRC configuration file into a multi-dimensional array representing 
+//	 * Hg directory config file (see PHP ini parsing)
+//	 * @param r_name name of the repository containing the target HGRC file
+//	 * @return a multi-dimensional array representing HGRC configuration file, status code otherwise
+//	 */
+//	function getHGRC($r_name)
+//	{
+//		// check if need to create cache
+//		if(!isset($this->cache_hgrc[$r_name]))
+//		{
+//			$hgrc_data = $this->__hgrc_compat_load($r_name);
+//			if(is_object($hgrc_data))
+//			{
+//				$this->cache_hgrc[$r_name] = $hgrc_data;
+//			}
+//			else
+//			{
+//				// is status code
+//				return $hgrc_data;
+//			}
+//		}
+//		
+//		// always return from cache
+//		return $this->cache_hgrc[$r_name];
+//	}
+//	
+//	/**
+//	 * setHGRC
+//	 * Replaces the current HGRC file with one generated represented by a multi-dimensional array
+//	 * @param r_name name of the repository containing the target HGRC file
+//	 * @param hgrc_data multi-array representation of the new HGRC file
+//	 * @return status code
+//	 */
+//	function setHGRC($r_name, $hgrc_data)
+//	{
+//		// always update cache
+//		$this->cache_hgrc[$r_name] = $hgrc_data;
+//		
+//		// always persist updated cache
+//		return $this->__hgrc_compat_persist($r_name, $this->cache_hgrc[$r_name]);
+//	}
+//	
+//	/**
+//	 * touchHGRC
+//	 * Generates a new HGRC file in a given repository directory, with default values
+//	 * @param r_name name of the repo folder which will have an HGRC file added to
+//	 * @return status code
+//	 */
+//	function touchHGRC($r_name)
+//	{
+//		$hgrc_path = $this->_repositories_abs_dir . $r_name . '/.hg/hgrc';
+//		
+//		// create file
+//		$touch_status = $this->_ci->optimisticflock->ofl_touch($hgrc_path, $this->_ofl_lock);
+//		if($touch_status == HGPHP_OK)
+//		{
+//			$blank_hgrc = $this->__blank_hgrc($r_name);
+//			
+//			// update touch status for setHGRC return code
+//			$touch_status = $this->setHGRC($r_name, $blank_hgrc);
+//		}
+//		return $touch_status;
+//	}
+//	
+//	/**
+//	 * unlinkHGRC
+//	 * @param r_name name of repo to delete
+//	 * @return status code
+//	 */
+//	function unlinkHGRC($r_name)
+//	{
+//		$hgrc_path = $this->_repositories_abs_dir . $r_name . '/.hg/hgrc';
+//		
+//		// design decision - force deletion of repository always
+//		return $this->_ci->optimisticflock->ofl_unlink($hgrc_path, $this->_ofl_lock, TRUE);
+//	}
+//	
+//	/**
+//	 * touchHGRC
+//	 * Generates a new HGRC representation as an array
+//	 * @param r_name name of the repository which will own the hgrc file
+//	 * @return hgrc reprsented as array
+//	 */
+//	function __blank_hgrc($r_name)
+//	{
+//		// automatic appending
+//		$blank_hgrc = $this->_hgrc_default_arr;
+//		$blank_hgrc['paths']['default'] = sprintf($blank_hgrc['paths']['default'], $r_name);
+//		$blank_hgrc['web']['name'] = sprintf($blank_hgrc['web']['name'], $r_name);
+//		
+//		return $blank_hgrc;
+//	}
+//	
+//	/**
+//	 * __hgwebconf_compat_load (private method)
+//	 * Compatibility layer for Mercurial PHP config files,
+//	 * which contain forward slashes '\' as key values.
+//	 * 
+//	 * @return contents of a php_ini array compatible representation, status code otherwise
+//	 */
+//	function __hgwebconf_compat_load()
+//	{
+//		// load the PHP to file
+//		$hgwebconf = $this->_hgwebconf_abs_filepath;
+//
+//		// concurrency-safe get contents
+//		$hgwebconf_err_code = '';
+////		$hgwebconf_str = $this->_ci->optimisticflock->ofl_file_get_contents($hgwebconf, $this->_ofl_lock, $hgwebconf_err_code);
+//		$hgwebconf_all = $this->_ci->optimisticflock->ofl_parse_ini_file($hgwebconf, true, $this->_ofl_lock, $hgwebconf_err_code);
+//		if($hgwebconf_err_code == HGPHP_OK)
+//		{
+//			/*
+//			// replace all occurances of the forward slash '/'
+//			$hgwebconf_str = str_replace('/', $this->_compatability_delimiter, $hgwebconf_str);
+//			
+//			// FIXME replace this with PHP version-independent and improved parser
+//			// write to private temporary file (no concurrency worry)	
+//			// prepare a temp file in scratch space for compatability conversion
+//			$hgwebconf_tmp_name = $this->_lock_dir . uniqid('hgweb.config.lock.', TRUE);
+//			$hgwebconf_tmp_fp = @fopen($hgwebconf_tmp_name, 'x');		
+//			$put_status = @fwrite($hgwebconf_tmp_fp, $hgwebconf_str);
+//			@fclose($hgwebconf_tmp_fp);
+//			if($put_status != FALSE)
+//			{
+//				// load the new compat ini
+//				
+//				// maintain PHP<5.3 compatability, instead of using parse_ini_string
+//				$hgwebconf_all = @parse_ini_file($hgwebconf_tmp_name, TRUE);
+//				@unlink($hgwebconf_tmp_name);
+//				*/
+////				$hgwebconf_collections = array();
+////				if(is_array($hgwebconf_all) && isset($hgwebconf_all['collections']))
+////				{
+////					foreach($hgwebconf_all['collections'] as $path => $name)
+////					{
+////						$hgwebconf_collections[$name] = $name;
+////					}
+////				}
+////				$hgwebconf_all['collections'] = $hgwebconf_collections;
+//				
+//				return $hgwebconf_all;
+////			}
+////			return HGPHP_ERR_PERM_SYS_TMPFILE;
+//		}
+//		return $hgwebconf_err_code;
+//	}
+//	
+//	
+//	/**
+//	 * __hgwebconf_compat_persist (private method)
+//	 * Takes a PHP-compatable php_ini array and converts it back into the original file.
+//	 * 
+//	 * @param status code
+//	 */
+//	function __hgwebconf_compat_persist($hgwebconf_all)
+//	{
+//		$hgwebconf_new_ini = ';Generated by Hg-PHP Mercurial Repository Manager v'.HGPHP_VERSION;
+//		// generate ini string
+//		if(is_object($hgwebconf_all))
+//		{
+//			$hgwebconf_new_ini .= $hgwebconf_all->toString();
+////			foreach($hgwebconf_all as $ini_section_name => $ini_section_items)
+////			{
+////				// section header
+////				$hgwebconf_new_ini .= "\n[".$ini_section_name.']';
+////				
+////				if($ini_section_name == 'collections')
+////				{
+////					foreach($ini_section_items as $ini_item_name => $ini_item_value)
+////					{
+////						$hgwebconf_new_ini .= "\n" . $this->_repositories_abs_dir . $ini_item_value . ' = ' . $ini_item_value;
+////					}
+////				}
+////				
+////				else
+////				{
+////					foreach($ini_section_items as $ini_item_name => $ini_item_value)
+////					{
+////						$hgwebconf_new_ini .= "\n" . $ini_item_name . ' = ' . $ini_item_value;
+////					}	
+////				}
+////			}	
+//		}
+//		$hgwebconf_new_ini .= "\n;End generated file\n";
+//		
+//		// undo the compatibility to allow Mercurial
+////		$hgwebconf_new_ini = str_replace($this->_compatability_delimiter, '/', $hgwebconf_new_ini);
+//		
+//		// concurrent-safe write
+//		$put_status = $this->_ci->optimisticflock->ofl_file_put_contents($this->_hgwebconf_abs_filepath, $hgwebconf_new_ini, $this->_ofl_lock);
+//		
+//		return $put_status;
+//	}
+//	
+//	/**
+//	 * __hgrc_compat_load (private method)
+//	 * Scans a Mercurial repository's HGRC configuration file into a multi-dimensional array representing 
+//	 * Hg directory config file (see PHP ini parsing)
+//	 * @param r_name name of the repository containing the target HGRC file
+//	 * @return a multi-dimensional array representing HGRC configuration file, FALSE otherwise
+//	 */
+//	function __hgrc_compat_load($r_name)
+//	{
+//		$hgrc = $this->_repositories_abs_dir . $r_name . '/.hg/hgrc';
+//		
+//		// concurrency-safe ini parse
+//		$hgrc_err_code = '';
+//		$hgrc_all = $this->_ci->optimisticflock->ofl_parse_ini_file($hgrc, true, $this->_ofl_lock, $hgrc_err_code);
+//
+//		if($hgrc_err_code == HGPHP_OK)
+//		{
+//			if(empty($hgrc_all))
+//			{
+//				return $this->__blank_hgrc($r_name);
+//			}
+//			else
+//			{
+//				return $hgrc_all;
+//			}
+//		}
+//		return $hgrc_err_code;
+//	}
+//	
+//	/**
+//	 * __hgrc_compat_persist (private method)
+//	 * Replaces the current HGRC file with one generated represented by a multi-dimensional array
+//	 * @param r_name name of the repository containing the target HGRC file
+//	 * @param hgrc_data multi-array representation of the new HGRC file
+//	 * @return status code
+//	 */
+//	function __hgrc_compat_persist($r_name, $hgrc_data)
+//	{
+//		$hgrc_path = $this->_repositories_abs_dir . $r_name . '/.hg/hgrc';
+//		
+//		$hgrc_new_ini = ';Generated by Hg-PHP Mercurial Repository Manager v'.HGPHP_VERSION;
+//		
+//		if(is_object($hgrc_data))
+//		{
+//			$hgrc_new_ini .= $hgrc_data->toString();
+//			$hgrc_new_ini .= "\n;End generated HGRC\n";
+//			
+//			// concurrency-safe persist to disk
+//			return $this->_ci->optimisticflock->ofl_file_put_contents($hgrc_path, $hgrc_new_ini, $this->_ofl_lock, false);
+//		}
+//		else
+//		{
+//			return HGPHP_ERR_FS_PREEXISTS;
+//		}
+//	}
+}

File admin/application/libraries/hgconf2ini.php

-<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
-
-/**
- * CodeIgniter Mercurial Config Parser Class
- * 
- * Overcomes general PHP ini parsing limitation due to invalid characters in hgweb.conf 'Collection' keys when
- * generating key-value pairs, and handles concurrency. Also handles per-repository HGRC configuration.
- * 
- * @package        	CodeIgniter
- * @subpackage    	Libraries
- * @category    	Libraries
- * @author 			Josh Carrier
- * @link			blog.joshjcarrier.com
- * 
- */
-class HgConf2Ini
-{
-	private $_ci;
-	private $_ofl_lock;
-	private $cache_hgwebconf;
-	private $cache_hgrc = array();
-	
-	function __construct($config = array())
-	{
-		$this->_ci =& get_instance();
-		
-		if(!empty($config))
-		{
-			$this->initialize($config);
-		}
-		else
-		{
-			
-			$this->_ci->config->load('hgphp', TRUE);
-			$this->initialize($this->_ci->config->item('hgphp'));
-		}
-		
-		$this->_ci->load->library('optimisticflock', 
-			array(
-				'lock_dir' => $this->_lock_dir, 
-				'lock_ofl_index' => $this->_lock_ofl_index,
-				'ofl_disabled' => $this->_ofl_disabled
-			));
-        log_message('debug', 'HgConf2Ini class Initialized');
-	}
-	
-	function initialize($config = array())
-	{
-		foreach($config as $key=>$val)
-		{
-			$this->{'_'.$key} = $val;
-		}
-	}
-	
-	/**
-	 * Registers OFL lock
-	 */
-	function register_OFL(&$ofl_lock)
-	{
-		$this->_ofl_lock = &$ofl_lock;
-	}
-	
-	function unregister_OFL()
-	{
-		$dummy = '';
-		$this->_ofl_lock = &$dummy;
-	}
-	
-	/**
-	 * getHgWebDirConfig
-	 * Scans Mercurial's hgweb.conf configuration file and returns
-	 * representation in key/value pairs.
-	 * @return multi-dimensional array representing Hg directory config file (see PHP ini parsing), status code otherwise
-	 */
-	function getHgWebDirConfig()
-	{
-		// check if need to create cache
-		if(!is_array($this->cache_hgwebconf))
-		{
-			$hgwebconf_all = $this->__hgwebconf_compat_load();
-			$this->cache_hgwebconf = $hgwebconf_all;
-		}
-
-		// cached copy returned
-		return $this->cache_hgwebconf;
-	}
-	
-	/**
-	 * setHgWebDirConfig
-	 * Converts a multi-dimensional array representing a Hg directory config file (see PHP ini parsing) to file
-	 * @param hgwebconf_data multi-dimensional array representing a Hg directory config file
-	 * @return status code
-	 */
-	function setHgWebDirConfig($hgwebconf_data)
-	{
-		$hgwebconf_status = $this->__hgwebconf_compat_persist($hgwebconf_data);
-		
-		if($hgwebconf_status == HGPHP_OK)
-		{
-			// update cache on success
-			$this->cache_hgwebconf = $hgwebconf_data;
-			return HGPHP_OK;
-		}
-		else
-		{
-			// is a status code
-			return $hgwebconf_status;
-		}
-	}
-	
-	/**
-	 * getHgWebDirCollections
-	 * Scans Mercurial's hgweb.conf configuration file and returns
-	 * a single associative array whose key/value pairs are the names of each listed repository
-	 * @return a single associative array whose key/value pairs are the names of each listed repository, status code otherwise
-	 */
-	function getHgWebDirCollections()
-	{
-		$hgwebconf_all = $this->getHgWebDirConfig();
-		
-		if(!is_integer($hgwebconf_all))
-		{
-			return $hgwebconf_all['collections'];
-		}
-		else
-		{
-			// is a status code
-			return $hgwebconf_all;
-		}
-	}
-	
-	/**
-	 * setHgWebDirCollections
-	 * Replaces the current directory config collections with ones represented by a single associative array whose key/value pairs 
-	 * are the names of each listed repository
-	 * @param hgwebconf_collections a single associative array whose key/value pairs are the names of each listed repository
-	 * @return status code
-	 */
-	function setHgWebDirCollections($hgwebconf_collections)
-	{
-		$hgwebconf_all = $this->getHgWebDirConfig(); // no need to update lock yet
-		
-		if(is_array($hgwebconf_all))
-		{
-			$hgwebconf_all['collections'] = $hgwebconf_collections;
-			return $this->setHgWebDirConfig($hgwebconf_all);
-		}
-		else
-		{
-			// is a status code
-			return $hgwebconf_all;
-		}
-	}
-	
-	/**
-	 * getHGRC
-	 * Scans a Mercurial repository's HGRC configuration file into a multi-dimensional array representing 
-	 * Hg directory config file (see PHP ini parsing)
-	 * @param r_name name of the repository containing the target HGRC file
-	 * @return a multi-dimensional array representing HGRC configuration file, status code otherwise
-	 */
-	function getHGRC($r_name)
-	{
-		// check if need to create cache
-		if(!isset($this->cache_hgrc[$r_name]))
-		{
-			$hgrc_data = $this->__hgrc_compat_load($r_name);
-			if(is_array($hgrc_data))
-			{
-				$this->cache_hgrc[$r_name] = $hgrc_data;
-			}
-			else
-			{
-				// is status code
-				return $hgrc_data;
-			}
-		}
-		
-		// always return from cache
-		return $this->cache_hgrc[$r_name];
-	}
-	
-	/**
-	 * setHGRC
-	 * Replaces the current HGRC file with one generated represented by a multi-dimensional array
-	 * @param r_name name of the repository containing the target HGRC file
-	 * @param hgrc_data multi-array representation of the new HGRC file
-	 * @return status code
-	 */
-	function setHGRC($r_name, $hgrc_data)
-	{
-		// always update cache
-		$this->cache_hgrc[$r_name] = $hgrc_data;
-		
-		// always persist updated cache
-		return $this->__hgrc_compat_persist($r_name, $this->cache_hgrc[$r_name]);
-	}
-	
-	/**
-	 * touchHGRC
-	 * Generates a new HGRC file in a given repository directory, with default values
-	 * @param r_name name of the repo folder which will have an HGRC file added to
-	 * @return status code
-	 */
-	function touchHGRC($r_name)
-	{
-		$hgrc_path = $this->_repositories_abs_dir . $r_name . '/.hg/hgrc';
-		
-		// create file
-		$touch_status = $this->_ci->optimisticflock->ofl_touch($hgrc_path, $this->_ofl_lock);
-		if($touch_status == HGPHP_OK)
-		{
-			$blank_hgrc = $this->__blank_hgrc($r_name);
-			
-			// update touch status for setHGRC return code
-			$touch_status = $this->setHGRC($r_name, $blank_hgrc);
-		}
-		return $touch_status;
-	}
-	
-	/**
-	 * unlinkHGRC
-	 * @param r_name name of repo to delete
-	 * @return status code
-	 */
-	function unlinkHGRC($r_name)
-	{
-		$hgrc_path = $this->_repositories_abs_dir . $r_name . '/.hg/hgrc';
-		
-		// design decision - force deletion of repository always
-		return $this->_ci->optimisticflock->ofl_unlink($hgrc_path, $this->_ofl_lock, TRUE);
-	}
-	
-	/**
-	 * touchHGRC
-	 * Generates a new HGRC representation as an array
-	 * @param r_name name of the repository which will own the hgrc file
-	 * @return hgrc reprsented as array
-	 */
-	function __blank_hgrc($r_name)
-	{
-		// automatic appending
-		$blank_hgrc = $this->_hgrc_default_arr;
-		$blank_hgrc['paths']['default'] = sprintf($blank_hgrc['paths']['default'], $r_name);
-		$blank_hgrc['web']['name'] = sprintf($blank_hgrc['web']['name'], $r_name);
-		
-		return $blank_hgrc;
-	}
-	
-	/**
-	 * __hgwebconf_compat_load (private method)
-	 * Compatibility layer for Mercurial PHP config files,
-	 * which contain forward slashes '\' as key values.
-	 * 
-	 * @return contents of a php_ini array compatible representation, status code otherwise
-	 */
-	function __hgwebconf_compat_load()
-	{
-		// load the PHP to file
-		$hgwebconf = $this->_hgwebconf_abs_filepath;
-
-		// concurrency-safe get contents
-		$hgwebconf_err_code = '';
-		$hgwebconf_str = $this->_ci->optimisticflock->ofl_file_get_contents($hgwebconf, $this->_ofl_lock, $hgwebconf_err_code);
-		
-		if($hgwebconf_err_code == HGPHP_OK)
-		{
-			// replace all occurances of the forward slash '/'
-			$hgwebconf_str = str_replace('/', $this->_compatability_delimiter, $hgwebconf_str);
-			
-			// FIXME replace this with PHP version-independent and improved parser
-			// write to private temporary file (no concurrency worry)	
-			// prepare a temp file in scratch space for compatability conversion
-			$hgwebconf_tmp_name = $this->_lock_dir . uniqid('hgweb.config.lock.', TRUE);
-			$hgwebconf_tmp_fp = @fopen($hgwebconf_tmp_name, 'x');		
-			$put_status = @fwrite($hgwebconf_tmp_fp, $hgwebconf_str);
-			@fclose($hgwebconf_tmp_fp);
-			if($put_status != FALSE)
-			{
-				// load the new compat ini
-				
-				// maintain PHP<5.3 compatability, instead of using parse_ini_string
-				$hgwebconf_all = @parse_ini_file($hgwebconf_tmp_name, TRUE);
-				@unlink($hgwebconf_tmp_name);
-				
-				$hgwebconf_collections = array();
-				if(is_array($hgwebconf_all) && isset($hgwebconf_all['collections']))
-				{
-					foreach($hgwebconf_all['collections'] as $path => $name)
-					{
-						$hgwebconf_collections[$name] = $name;
-					}
-				}
-				$hgwebconf_all['collections'] = $hgwebconf_collections;
-				
-				return $hgwebconf_all;
-			}
-			return HGPHP_ERR_PERM_SYS_TMPFILE;
-		}
-		return $hgwebconf_err_code;
-	}
-	
-	
-	/**
-	 * __hgwebconf_compat_persist (private method)
-	 * Takes a PHP-compatable php_ini array and converts it back into the original file.
-	 * 
-	 * @param status code
-	 */
-	function __hgwebconf_compat_persist($hgwebconf_all)
-	{
-		$hgwebconf_new_ini = ';Generated by Hg-PHP Mercurial Repository Manager v'.HGPHP_VERSION;
-		// generate ini string
-		if(isset($hgwebconf_all) && is_array($hgwebconf_all))
-		{
-			foreach($hgwebconf_all as $ini_section_name => $ini_section_items)
-			{
-				// section header
-				$hgwebconf_new_ini .= "\n[".$ini_section_name.']';
-				
-				if($ini_section_name == 'collections')
-				{
-					foreach($ini_section_items as $ini_item_name => $ini_item_value)
-					{
-						$hgwebconf_new_ini .= "\n" . $this->_repositories_abs_dir . $ini_item_value . ' = ' . $ini_item_value;
-					}
-				}
-				
-				else
-				{
-					foreach($ini_section_items as $ini_item_name => $ini_item_value)
-					{
-						$hgwebconf_new_ini .= "\n" . $ini_item_name . ' = ' . $ini_item_value;
-					}	
-				}
-			}	
-		}
-		$hgwebconf_new_ini .= "\n;End generated file\n";
-		
-		// undo the compatibility to allow Mercurial
-		$hgwebconf_new_ini = str_replace($this->_compatability_delimiter, '/', $hgwebconf_new_ini);
-		
-		// concurrent-safe write
-		$put_status = $this->_ci->optimisticflock->ofl_file_put_contents($this->_hgwebconf_abs_filepath, $hgwebconf_new_ini, $this->_ofl_lock);
-		
-		return $put_status;
-	}
-	
-	/**
-	 * __hgrc_compat_load (private method)
-	 * Scans a Mercurial repository's HGRC configuration file into a multi-dimensional array representing 
-	 * Hg directory config file (see PHP ini parsing)
-	 * @param r_name name of the repository containing the target HGRC file
-	 * @return a multi-dimensional array representing HGRC configuration file, FALSE otherwise
-	 */
-	function __hgrc_compat_load($r_name)
-	{
-		$hgrc = $this->_repositories_abs_dir . $r_name . '/.hg/hgrc';
-		
-		// concurrency-safe ini parse
-		$hgrc_err_code = '';
-		$hgrc_all = $this->_ci->optimisticflock->ofl_parse_ini_file($hgrc, true, $this->_ofl_lock, $hgrc_err_code);
-
-		if($hgrc_err_code == HGPHP_OK)
-		{
-			if(empty($hgrc_all))
-			{
-				return $this->__blank_hgrc($r_name);
-			}
-			else
-			{
-				// help out the php ini parser (remove PHP 5.3 dependency on SCANNER_RAW) detecting true/false values
-				$bool_keys = $this->_hgrc_bools_arr;
-				foreach($bool_keys as $collection => $collection_keys)
-				{
-					foreach($collection_keys as $key)
-					{
-						if(isset($hgrc_all[$collection]) && isset($hgrc_all[$collection][$key]))
-						{
-							if($hgrc_all[$collection][$key] == '1')
-							{
-								$hgrc_all[$collection][$key] = 'true';
-							}
-							else
-							{
-								$hgrc_all[$collection][$key] = 'false';
-							}
-						}
-					}
-				}
-				
-				// ensures new (default) hgrc keys are made available, retaining old ones
-				$hgrc_all_sorted = array();
-				foreach($hgrc_all as $collection_name => $collection)
-				{
-					$hgrc_default = $this->_hgrc_default_arr;
-					$hgrc_all_sorted[$collection_name] = array_merge($hgrc_default[$collection_name], $hgrc_all[$collection_name]);
-				}
-				
-				return $hgrc_all_sorted;
-			}
-		}
-		return $hgrc_err_code;
-	}
-	
-	/**
-	 * __hgrc_compat_persist (private method)
-	 * Replaces the current HGRC file with one generated represented by a multi-dimensional array
-	 * @param r_name name of the repository containing the target HGRC file
-	 * @param hgrc_data multi-array representation of the new HGRC file
-	 * @return status code
-	 */
-	function __hgrc_compat_persist($r_name, $hgrc_data)
-	{
-		$hgrc_path = $this->_repositories_abs_dir . $r_name . '/.hg/hgrc';
-		
-		$hgrc_new_ini = ';Generated by Hg-PHP Mercurial Repository Manager v'.HGPHP_VERSION;
-		
-		if(is_array($hgrc_data))
-		{
-			// order before saving
-			foreach($hgrc_data as $collection_name => $collection)
-			{
-				ksort($hgrc_data[$collection_name]);
-			}
-			
-			// generate ini string
-			foreach($hgrc_data as $ini_section_name => $ini_section_items)
-			{
-				// section header
-				$hgrc_new_ini .= "\n[".$ini_section_name.']';
-				
-				foreach($ini_section_items as $ini_item_name => $ini_item_value)
-				{
-					$hgrc_new_ini .= "\n" . $ini_item_name . ' = ' . $ini_item_value;
-				}	
-			}
-			$hgrc_new_ini .= "\n;End generated HGRC\n";
-			
-			// concurrency-safe persist to disk
-			return $this->_ci->optimisticflock->ofl_file_put_contents($hgrc_path, $hgrc_new_ini, $this->_ofl_lock, false);
-		}
-		else
-		{
-			return HGPHP_ERR_FS_PREEXISTS;
-		}
-	}
-}

File admin/application/libraries/hgphp.php

-<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
-
-/**
- * CodeIgniter Mercurial Repository Management class
- * 
- * Scans file system and Mercurial projects directory, allowing
- * web-based manipulation of the hgweb.config and hgrc configuration files.
- * 
- * Depends on the HgConf2Ini library.
- * 
- * @package        	CodeIgniter
- * @subpackage    	Libraries
- * @category    	Libraries
- * @author 			Josh Carrier
- * @link			blog.joshjcarrier.com
- * 
- */
-class HgPHP
-{
-	private $_ci;
-	private $_ofl_lock_hgweb;
-	private $_ofl_lock_hgrc;
-	
-	function __construct($config = array())
-	{
-		$this->_ci =& get_instance();
-		if(!empty($config))
-		{
-			$this->initialize($config);
-		}
-		else
-		{
-			$this->_ci->config->load('hgphp', TRUE);
-			$this->initialize($this->_ci->config->item('hgphp'));
-		}
-		
-		$this->_ci->lang->load('hgphp');
-		$this->_ci->load->library('hgconf2ini');
-        log_message('debug', 'HgPHP class Initialized');
-	}
-	
-	function initialize($config = array())
-	{
-		foreach($config as $key=>$val)
-		{
-			$this->{'_'.$key} = $val;
-		}
-	}
-	
-	/**
-	 * Public accessors - hgweb.config
-	 */
-	
-	/**
-	 * Associates OFL locks
-	 */
-	function start_transaction(&$ofl_lock_hgweb, &$ofl_lock_hgrc)
-	{
-		$this->_ofl_lock_hgweb = &$ofl_lock_hgweb;
-		$this->_ofl_lock_hgrc = &$ofl_lock_hgrc;
-	}
-	
-	/**
-	 * Disassociates OFL locks
-	 */
-	function end_transaction()
-	{
-		$dummy = '';
-		$this->_ofl_lock_hgweb = &$dummy;
-		$this->_ofl_lock_hgrc = &$dummy;
-	}
-	
-	/**
-	 * Returns a list of available repositories.
-	 * Will show up if: detected in repo directory
-	 * Will have status "enabled" if: detected in hgweb.config
-	 * 
-	 * @return an array of 0 or more detected repositories
-	 */
-	function lsdir()
-	{
-		$realdir = $this->__realdirscan();
-		$this->_ci->hgconf2ini->register_OFL($this->_ofl_lock_hgweb);
-		$hgwebdir_compat = $this->_ci->hgconf2ini->getHgWebDirCollections();
-				
-		$allrepo = $realdir;
-		if(!is_integer($hgwebdir_compat))
-		{
-			$allrepo = array_merge($realdir, $hgwebdir_compat);
-		}
-		else
-		{
-			// error code
-			return $hgwebdir_compat;
-		}
-		
-		$hgrepos = array();
-		foreach($allrepo as $repo)
-		{
-			$hgrepos[$repo]['name'] = $repo;
-
-			if(isset($realdir[$repo]) && isset($hgwebdir_compat[$repo]))
-			{
-				$hgrepos[$repo]['status'] = HGPHP_REPO_STATUS_ENABLED;
-			}
-			else if(isset($realdir[$repo]) && !isset($hgwebdir_compat[$repo]))
-			{
-				$hgrepos[$repo]['status'] = HGPHP_REPO_STATUS_DISABLED;
-			}
-			else if(!isset($realdir[$repo]) && isset($hgwebdir_compat[$repo]))
-			{
-				$hgrepos[$repo]['status'] = HGPHP_REPO_STATUS_MISSING;
-			}
-		}
-		
-		return $hgrepos;
-	}
-	
-	/**
-	 * Create a Hg repository by:
-	 * - adding an entry in hgrc if not present
-	 * - creating a bare repository if not present
-	 * @param r_name name of the new repository to create, used as folder name
-	 * @return status code
-	 */
-	function create_repository($r_name)
-	{
-		if(!$this->can_create($r_name))
-		{
-			return HGPHP_ERR_PERM_USR;
-		}
-		
-		$create_status = HGPHP_OK;
-		
-		$lsdir = $this->_ci->hgconf2ini->getHgWebDirCollections(); 
-
-		// simplifies repo list into array where name is both key and value
-		// this is how hgweb.config wants it
-		$existingdir = array();
-		
-		if(!is_integer($lsdir))
-		{
-			$existingdir = array_keys($lsdir);
-		}
-		else
-		{
-			// error code
-			return $lsdir;
-		}
-		
-		$tempexistingdir = array();
-		foreach($existingdir as $repo_name)
-		{
-			$tempexistingdir[$repo_name] = $repo_name;
-		}
-		$existingdir = $tempexistingdir;
-		
-		// not registered in hgweb.config
-		if(!isset($lsdir[$r_name]))
-		{
-			// edit the directory
-			$existingdir[$r_name] = $r_name;
-			$this->_ci->hgconf2ini->register_OFL($this->_ofl_lock_hgweb);
-			$create_status = $this->_ci->hgconf2ini->setHgWebDirCollections($existingdir);
-			if($create_status == HGPHP_OK)
-			{
-				// then create the repository
-				$this->_ci->hgconf2ini->register_OFL($this->_ofl_lock_hgrc);
-				$create_status = $this->create_repository_dir($r_name);
-			}
-		}
-		else
-		{
-			// repository already exists
-			$create_status = HGPHP_ERR_FS_PREEXISTS;
-		}
-		return $create_status;
-	}
-	
-	/**
-	 * update_repository
-	 * Update repository's hgrc
-	 * @param r_name name of the repository to update hgrc for
-	 * @param hgrc_data array representing new hgrc file
-	 * @return status code
-	 */
-	function update_repository($r_name, $hgrc_data)
-	{
-		if(!$this->can_update($r_name))
-		{
-			return HGPHP_ERR_PERM_USR;
-		}
-		$this->_ci->hgconf2ini->register_OFL($this->_ofl_lock_hgrc);
-		return $this->_ci->hgconf2ini->setHGRC($r_name, $hgrc_data);
-	}
-	
-	/**
-	 * delete_repository
-	 * Deletes a repository from the file system and unregisters it from hgweb.config
-	 * @param r_name name of the repo to delete permanently
-	 * @return status code
-	 */
-	function delete_repository($r_name)
-	{
-		if(!$this->can_delete($r_name))
-		{
-			return HGPHP_ERR_PERM_USR;
-		}
-		
-		$del_status = HGPHP_OK;
-		$lsdir = $this->_ci->hgconf2ini->getHgWebDirCollections(); 
-		
-		// simplifies repo list into array where name is both key and value
-		// this is how hgweb.config wants it
-		$existingdir = array_keys($lsdir);
-		$tempexistingdir = array();
-		foreach($existingdir as $repo_name)
-		{
-			$tempexistingdir[$repo_name] = $repo_name;
-		}
-		$existingdir = $tempexistingdir;
-		
-		if(isset($lsdir[$r_name]))
-		{
-			// edit the directory
-			unset($existingdir[$r_name]);
-			// remove hgweb.config
-			$this->_ci->hgconf2ini->register_OFL($this->_ofl_lock_hgweb);
-			$del_status = $this->_ci->hgconf2ini->setHgWebDirCollections($existingdir);
-				
-			// remove from hgweb.config
-			if($del_status == HGPHP_OK)
-			{
-				// existing filesystem is not missing, thus needs to be deleted
-				if($lsdir[$r_name]['status'] != HGPHP_REPO_STATUS_MISSING)
-				{
-					// unregister hgrc from transaction manager to keep index small
-					$this->_ci->hgconf2ini->register_OFL($this->_ofl_lock_hgrc);
-					$del_status = $this->_ci->hgconf2ini->unlinkHGRC($r_name);
-					
-					if($del_status == HGPHP_OK)
-					{
-						$del_status = $this->delete_repository_dir($r_name);
-					}
-				}
-			}
-		}
-		else
-		{
-			$del_status = HGPHP_ERR_FS_PREEXISTS;
-		}
-		return $del_status;
-	}
-	
-	/**
-	 * stat_repository
-	 * Returns the HGRC represented as an array for the specified repository
-	 * @param r_name name of the project whose hgrc to retrieve
-	 * @return array representing hgrc or status code
-	 */
-	function stat_repository($r_name)
-	{
-		if(!$this->can_view($r_name))
-		{
-			return HGPHP_ERR_PERM_USR;
-		}
-		$this->_ci->hgconf2ini->register_OFL($this->_ofl_lock_hgrc);
-		return $this->_ci->hgconf2ini->getHGRC($r_name);
-	}
-	 
-
-	/**
-	 * can_create
-	 * Checks if user has permissions to create this repository.
-	 * Requires view permission.
-	 * @param r_name name of repository wanting to be created
-	 * @return true if allowed
-	 */
-	function can_create($r_name)
-	{
-		return $this->can_view($r_name) && $this->_hgwebconf_allow_repo_create;
-	}
-	
-	/**
-	 * can_update
-	 * Checks if user has permissions to update this repository
-	 * Requires view permission.
-	 * @param r_name name of repository wanting to be updated
-	 * @return true if allowed
-	 */
-	function can_update($r_name)
-	{
-		return $this->can_view($r_name) && $this->_hgwebconf_allow_repo_update;
-	}
-	
-	/**
-	 * can_create
-	 * Checks if user has permissions to view this repository
-	 * @param r_name name of repository wanting to be created
-	 * @return true if allowed
-	 */
-	function can_view($r_name)
-	{
-		return $this->_hgwebconf_allow_repo_view;
-	}
-	
-	/**
-	 * can_delete
-	 * Checks if user has permissions to delete this repository
-	 * Requires view permission.
-	 * @param r_name name of repository wanting to be deleted
-	 * @return true if allowed
-	 */
-	function can_delete($r_name)
-	{
-		return $this->can_view($r_name) && $this->_hgwebconf_allow_repo_delete;
-	}
-	 
-	/**
-	 * create_repository_dir
-	 * Creates a whole repository directory, with hgrc
-	 * @param r_name name of repository to create directory for
-	 * @return status code
-	 */
-	function create_repository_dir($r_name)
-	{
-		if(!$this->can_create($r_name))
-		{
-			return HGPHP_ERR_PERM_USR;
-		}
-		
-		// create repo directory structure recursively
-		$create_status = mkdir($this->_repositories_abs_dir . $r_name . '/.hg/store/data/', 0755, TRUE);
-		
-		if($create_status == TRUE)
-		{
-			// create hgrc
-			$this->_ci->hgconf2ini->register_OFL($this->_ofl_lock_hgrc);
-			$create_status = $this->_ci->hgconf2ini->touchHGRC($r_name);
-		}
-		else
-		{
-			// system couldn't make directory
-			$create_status = HGPHP_ERR_PERM_SYS_REPODIR;
-		}
-		return $create_status;
-	}
-	
-	/**
-	 * delete_repository_dir
-	 * Deletes a whole repository directory including hgrc and data files
-	 * @param r_name name of repository to delete directory of
-	 * @return status code
-	 */
-	function delete_repository_dir($repository_name)
-	{
-		if(!$this->can_delete($repository_name))
-		{
-			return HGPHP_ERR_PERM_USR;
-		}
-		
-		$cd = $this->_repositories_abs_dir . $repository_name;
-		$this->recursiveDelete($cd . '/.hg/');
-		$del_status = $this->recursiveDelete($cd);
-		if($del_status == TRUE)
-		{
-			$del_status = HGPHP_OK;
-		}
-		else
-		{
-			$del_status = HGPHP_ERR_PERM_SYS_REPODIR;
-		}
-		return $del_status;
-	}
-	
-	/**
-	 * Performs a real directory scan where the projects are suppose to reside.
-	 * 
-	 * @return the array containing 0 or more valid directories
-	 */
-	function __realdirscan()
-	{
-		$this->_ci->load->helper('directory');
-		
-		$realdir = directory_map($this->_repositories_abs_dir, TRUE);
-		
-		$verifiedrealdir = array();
-		if(is_array($realdir))
-		{
-			foreach($realdir as $file)
-			{
-				// checks if we detected a folder
-				if(is_dir($this->_repositories_abs_dir . $file))
-				{
-					$verifiedrealdir[$file] = $file;
-				}
-			}
-		}
-		
-		return $verifiedrealdir;
-	}
-	
-	/**
-     * Delete a file or recursively delete a directory
-     *
-     * @param string $str Path to file or directory
-     * @return true on successful deletion
-     */
-    function recursiveDelete($str){
-        if(is_file($str)){
-            return @unlink($str);
-        }
-        elseif(is_dir($str)){
-            $scan = glob(rtrim($str,'/').'/*');
-            foreach($scan as $index=>$path){
-                $this->recursiveDelete($path);
-            }
-            return @rmdir($str);
-        }
-    }
-}

File admin/application/libraries/iniparser.php

+<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
+
+/**
+ * CodeIgniter INI Parser class
+ * 
+ * Provides a 'better' implementation of PHP's parse_ini_file and parse_ini_string
+ * which is independent of PHP version.
+ * 
+ * @package        	CodeIgniter
+ * @subpackage    	Libraries
+ * @category    	Libraries
+ * @author 			Josh Carrier
+ * @link			blog.joshjcarrier.com
+ * 
+ */
+class IniParser
+{
+	
+	/**
+	 * Mimics PHP's function call of similar name
+	 * 
+	 * @see http://ca2.php.net/manual/en/function.parse-ini-string.php
+	 */
+	function parse_ini_string_base64($ini, $process_sections = FALSE)
+	{
+		$lines = explode("\n", $ini);
+		$ini_arr = array();
+		$hashcollection = FALSE;
+		foreach($lines as $line)
+		{
+			$line = trim($line);
+			
+			// comments
+			if(!$line || $line[0] == ';' || $line[0] == '#')
+			{
+				continue;
+			}
+			else if($line[0] == '[' && $endline = strpos($line, ']'))
+			{
+				$collection = substr($line, 1, $endline-1);
+				$hashcollection = base64_encode($collection);
+				continue;
+			}
+			
+			$keyval = explode('=', $line, 2);
+			$key = trim($keyval[0]);