diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..eb09a7d --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,45 @@ +# Repository Guidelines + +## Project Structure & Module Organization + +This is a PHP Smart HTTP Git server with no dependency manager or generated build output. + +- `index.php` is the public entry point and request router. +- `install.php` creates the initial configuration and database schema. +- `manage.php` provides administrator and managed-repository operations. +- `lib/` contains shared HTTP, authentication, repository, routing, Git protocol, and i18n code. +- `operations/` handles clone, pull, push, branch, and tag requests. +- `schema.mysql.sql` and `migration.repository-ownership.mysql.sql` define database changes. +- `config.php.sample` documents settings; local `config.php` must never be committed. +- `repos/` contains runtime bare repositories. `README.md` and `usage.md` document deployment. + +There is no dedicated automated test directory. + +## Build, Test, and Development Commands + +PHP is interpreted directly, so there is no build step. Run syntax checks from the repository root: + +```sh +php -l index.php +php -l install.php +php -l manage.php +for file in lib/*.php operations/*.php; do php -l "$file" || exit 1; done +``` + +Check required runtime support with `php -m | grep pdo_mysql`. For a local smoke test, use a disposable `config.php` and PHP-capable web server, then exercise the UI and Git endpoints with `git ls-remote` or `git clone`. + +## Coding Style & Naming Conventions + +Use four-space indentation, same-line opening braces, uppercase PHP constants (`TRUE`, `FALSE`, `NULL`), and explicit ` $name))); + case 'create_busy': return array(409, 'error', t('notice.repository_create_busy')); + case 'root_unavailable': return array(503, 'error', t('notice.repository_root_unavailable')); + case 'git_unavailable': return array(503, 'error', t('notice.repository_git_unavailable')); + case 'metadata_unavailable': return array(503, 'error', t('notice.repository_metadata_unsaved')); + default: return array(500, 'error', t('notice.repository_create_failed')); } } function home_deletion_result_notice($result) { $name = isset($result['name']) ? $result['name'] : ''; switch ($result['status']) { - case 'deleted': - return array(303, 'success', '仓库 '.$name.' 已删除。'); - case 'record_deleted': - return array(303, 'success', '仓库记录 '.$name.' 已删除,非 bare 路径未作改动。'); - case 'invalid_repository': - return array(422, 'error', '仓库名称格式无效。'); - case 'forbidden': - return array(403, 'error', '只有仓库所有者可以删除该仓库。'); - case 'configured_repository': - return array(403, 'error', '该路径由 config.php 静态配置,不能从网页删除。'); - case 'not_found': - return array(404, 'error', '托管仓库不存在或尚未创建完成。'); - case 'repository_busy': - return array(409, 'error', '仓库正在执行其他操作,请稍后重试。'); - case 'root_unavailable': - return array(503, 'error', '仓库存放目录不可用或不可写。'); - case 'metadata_unavailable': - return array(503, 'error', '仓库所有权信息当前不可用。'); - case 'cleanup_failed': - return array(500, 'error', '仓库记录已删除,但残留目录清理失败,请检查服务器日志。'); - case 'restore_failed': - return array(500, 'error', '删除失败且仓库目录无法恢复,请立即检查服务器日志。'); - default: - return array(500, 'error', '仓库删除失败,请检查服务器日志。'); + case 'deleted': return array(303, 'success', t('notice.repository_deleted', array('name' => $name))); + case 'record_deleted': return array(303, 'success', t('notice.repository_record_deleted', array('name' => $name))); + case 'invalid_repository': return array(422, 'error', t('notice.repository_invalid_name')); + case 'forbidden': return array(403, 'error', t('notice.repository_delete_forbidden')); + case 'configured_repository': return array(403, 'error', t('notice.repository_configured_home')); + case 'not_found': return array(404, 'error', t('notice.repository_not_found')); + case 'repository_busy': return array(409, 'error', t('notice.repository_busy')); + case 'root_unavailable': return array(503, 'error', t('notice.repository_root_unavailable')); + case 'metadata_unavailable': return array(503, 'error', t('notice.repository_metadata_unavailable')); + case 'cleanup_failed': return array(500, 'error', t('notice.repository_cleanup_failed')); + case 'restore_failed': return array(500, 'error', t('notice.repository_restore_failed')); + default: return array(500, 'error', t('notice.repository_delete_failed')); } } @@ -338,7 +306,7 @@ function home_create_repository( if ($result['status'] === 'created') { home_set_notice( - $url_base, $configuration, 'success', '仓库 '.$result['name'].' 已创建。'); + $url_base, $configuration, 'success', t('notice.repository_created', array('name' => $result['name']))); home_redirect($url_base); } @@ -476,14 +444,16 @@ function home_clone_url_prefix() { return $scheme.'://'.$host; } -function home_send_head() { +function home_send_head($url_base='') { + $lang = home_escape(i18n_html_lang()); + $title = home_escape(t('home.title')); + echo ''."\n" + .''."\n" + .'
'."\n" + .''."\n" + .''."\n" + .'通过 HTTP 发布下列 Git 仓库,支持 clone、fetch、pull,并可按仓库启用 push。
HTML; + echo ''.home_escape(t('home.lead')).'
'."\n"; + echo i18n_language_switcher(home_page_url($url_base))."\n"; } function home_send_authentication($url_base, $configuration, $notice) { @@ -592,14 +565,14 @@ function home_send_authentication($url_base, $configuration, $notice) { } echo ''.home_escape($notice['token']).'' ."\n";
}
$csrf_token = home_csrf_token($url_base, $configuration);
if ($csrf_token === FALSE) {
- echo '当前无法初始化安全表单。
' ."\n"; + echo ''.home_escape(t('home.form_unavailable')).'
' ."\n"; echo '