{"thread":{"id":"35519","subject":"[PATCH v7 0/4] Show extra branch refs in gitweb","startedAt":"2013-12-11T11:54:40Z","lastAt":"2013-12-12T21:46:13Z","messageCount":7,"participants":["Krzesimir Nowak","Jakub Narębski","Junio C Hamano"],"isPatch":true,"patchVersion":7,"patchTotal":4},"messages":[{"id":"231903","messageId":"1386762884-7564-1-git-send-email-krzesimir@endocode.com","threadId":"35519","inReplyTo":null,"subject":"[PATCH v7 0/4] Show extra branch refs in gitweb","fromName":"Krzesimir Nowak","fromEmail":"krzesimir@endocode.com","sentAt":"2013-12-11T11:54:40Z","receivedAt":"2013-12-11T11:54:40Z","isPatch":true,"sender":{"key":"krzesimir@endocode.com","avatar":"https://avatars.githubusercontent.com/u/96081?v=4"},"body":"First patch splits some code to a function.\n\nSecond patch fixes validation functions to return either 0 or 1,\ninstead of undef or passed $input.\n\nThird patch adds the extra-branch-feature and some documentation.\n\nFourth patch adds some visual differentation of branches from\nnon-standard ref directories.\n\nKrzesimir Nowak (4):\n  gitweb: Move check-ref-format code into separate function\n  gitweb: Return 1 on validation success instead of passed input\n  gitweb: Add a feature for adding more branch refs\n  gitweb: Denote non-heads, non-remotes branches\n\n Documentation/gitweb.conf.txt |  37 +++++++++\n gitweb/gitweb.perl            | 184 +++++++++++++++++++++++++++++++-----------\n 2 files changed, 175 insertions(+), 46 deletions(-)\n\n-- \n1.8.3.1\n"},{"id":"231905","messageId":"1386762884-7564-2-git-send-email-krzesimir@endocode.com","threadId":"35519","inReplyTo":"1386762884-7564-1-git-send-email-krzesimir@endocode.com","subject":"[PATCH v7 1/4] gitweb: Move check-ref-format code into separate function","fromName":"Krzesimir Nowak","fromEmail":"krzesimir@endocode.com","sentAt":"2013-12-11T11:54:41Z","receivedAt":"2013-12-11T11:54:41Z","isPatch":true,"sender":{"key":"krzesimir@endocode.com","avatar":"https://avatars.githubusercontent.com/u/96081?v=4"},"body":"This check will be used in more than one place later.\n\nSigned-off-by: Krzesimir Nowak <krzesimir@endocode.com>\n---\n gitweb/gitweb.perl | 17 +++++++++++++----\n 1 file changed, 13 insertions(+), 4 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 68c77f6..46bd6ac 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -1452,6 +1452,16 @@ sub validate_pathname {\n \treturn $input;\n }\n \n+sub is_valid_ref_format {\n+\tmy $input = shift || return undef;\n+\n+\t# restrictions on ref name according to git-check-ref-format\n+\tif ($input =~ m!(/\\.|\\.\\.|[\\000-\\040\\177 ~^:?*\\[]|/$)!) {\n+\t\treturn undef;\n+\t}\n+\treturn $input;\n+}\n+\n sub validate_refname {\n \tmy $input = shift || return undef;\n \n@@ -1462,10 +1472,9 @@ sub validate_refname {\n \t# it must be correct pathname\n \t$input = validate_pathname($input)\n \t\tor return undef;\n-\t# restrictions on ref name according to git-check-ref-format\n-\tif ($input =~ m!(/\\.|\\.\\.|[\\000-\\040\\177 ~^:?*\\[]|/$)!) {\n-\t\treturn undef;\n-\t}\n+\t# check git-check-ref-format restrictions\n+\tis_valid_ref_format($input)\n+\t\tor return undef;\n \treturn $input;\n }\n \n-- \n1.8.3.1\n"},{"id":"231904","messageId":"1386762884-7564-3-git-send-email-krzesimir@endocode.com","threadId":"35519","inReplyTo":"1386762884-7564-1-git-send-email-krzesimir@endocode.com","subject":"[PATCH v7 2/4] gitweb: Return 1 on validation success instead of passed input","fromName":"Krzesimir Nowak","fromEmail":"krzesimir@endocode.com","sentAt":"2013-12-11T11:54:42Z","receivedAt":"2013-12-11T11:54:42Z","isPatch":true,"sender":{"key":"krzesimir@endocode.com","avatar":"https://avatars.githubusercontent.com/u/96081?v=4"},"body":"Users of validate_* passing \"0\" might get failures on correct name\nbecause of coercion of \"0\" to false in code like:\ndie_error(500, \"invalid ref\") unless (check_ref_format (\"0\"));\n\nAlso, the validate_foo subs are renamed to is_valid_foo.\n\nSigned-off-by: Krzesimir Nowak <krzesimir@endocode.com>\n---\n gitweb/gitweb.perl | 61 ++++++++++++++++++++++++++++--------------------------\n 1 file changed, 32 insertions(+), 29 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 46bd6ac..b5a8a36 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -994,7 +994,7 @@ our ($action, $project, $file_name, $file_parent, $hash, $hash_parent, $hash_bas\n sub evaluate_and_validate_params {\n \tour $action = $input_params{'action'};\n \tif (defined $action) {\n-\t\tif (!validate_action($action)) {\n+\t\tif (!is_valid_action($action)) {\n \t\t\tdie_error(400, \"Invalid action parameter\");\n \t\t}\n \t}\n@@ -1002,7 +1002,7 @@ sub evaluate_and_validate_params {\n \t# parameters which are pathnames\n \tour $project = $input_params{'project'};\n \tif (defined $project) {\n-\t\tif (!validate_project($project)) {\n+\t\tif (!is_valid_project($project)) {\n \t\t\tundef $project;\n \t\t\tdie_error(404, \"No such project\");\n \t\t}\n@@ -1010,21 +1010,21 @@ sub evaluate_and_validate_params {\n \n \tour $project_filter = $input_params{'project_filter'};\n \tif (defined $project_filter) {\n-\t\tif (!validate_pathname($project_filter)) {\n+\t\tif (!is_valid_pathname($project_filter)) {\n \t\t\tdie_error(404, \"Invalid project_filter parameter\");\n \t\t}\n \t}\n \n \tour $file_name = $input_params{'file_name'};\n \tif (defined $file_name) {\n-\t\tif (!validate_pathname($file_name)) {\n+\t\tif (!is_valid_pathname($file_name)) {\n \t\t\tdie_error(400, \"Invalid file parameter\");\n \t\t}\n \t}\n \n \tour $file_parent = $input_params{'file_parent'};\n \tif (defined $file_parent) {\n-\t\tif (!validate_pathname($file_parent)) {\n+\t\tif (!is_valid_pathname($file_parent)) {\n \t\t\tdie_error(400, \"Invalid file parent parameter\");\n \t\t}\n \t}\n@@ -1032,21 +1032,21 @@ sub evaluate_and_validate_params {\n \t# parameters which are refnames\n \tour $hash = $input_params{'hash'};\n \tif (defined $hash) {\n-\t\tif (!validate_refname($hash)) {\n+\t\tif (!is_valid_refname($hash)) {\n \t\t\tdie_error(400, \"Invalid hash parameter\");\n \t\t}\n \t}\n \n \tour $hash_parent = $input_params{'hash_parent'};\n \tif (defined $hash_parent) {\n-\t\tif (!validate_refname($hash_parent)) {\n+\t\tif (!is_valid_refname($hash_parent)) {\n \t\t\tdie_error(400, \"Invalid hash parent parameter\");\n \t\t}\n \t}\n \n \tour $hash_base = $input_params{'hash_base'};\n \tif (defined $hash_base) {\n-\t\tif (!validate_refname($hash_base)) {\n+\t\tif (!is_valid_refname($hash_base)) {\n \t\t\tdie_error(400, \"Invalid hash base parameter\");\n \t\t}\n \t}\n@@ -1066,7 +1066,7 @@ sub evaluate_and_validate_params {\n \n \tour $hash_parent_base = $input_params{'hash_parent_base'};\n \tif (defined $hash_parent_base) {\n-\t\tif (!validate_refname($hash_parent_base)) {\n+\t\tif (!is_valid_refname($hash_parent_base)) {\n \t\t\tdie_error(400, \"Invalid hash parent base parameter\");\n \t\t}\n \t}\n@@ -1418,27 +1418,30 @@ sub href {\n ## ======================================================================\n ## validation, quoting/unquoting and escaping\n \n-sub validate_action {\n-\tmy $input = shift || return undef;\n+sub is_valid_action {\n+\tmy $input = shift;\n \treturn undef unless exists $actions{$input};\n-\treturn $input;\n+\treturn 1;\n }\n \n-sub validate_project {\n-\tmy $input = shift || return undef;\n-\tif (!validate_pathname($input) ||\n+sub is_valid_project {\n+\tmy $input = shift;\n+\n+\treturn unless defined $input;\n+\tif (!is_valid_pathname($input) ||\n \t\t!(-d \"$projectroot/$input\") ||\n \t\t!check_export_ok(\"$projectroot/$input\") ||\n \t\t($strict_export && !project_in_list($input))) {\n \t\treturn undef;\n \t} else {\n-\t\treturn $input;\n+\t\treturn 1;\n \t}\n }\n \n-sub validate_pathname {\n-\tmy $input = shift || return undef;\n+sub is_valid_pathname {\n+\tmy $input = shift;\n \n+\treturn undef unless defined $input;\n \t# no '.' or '..' as elements of path, i.e. no '.' nor '..'\n \t# at the beginning, at the end, and between slashes.\n \t# also this catches doubled slashes\n@@ -1449,33 +1452,33 @@ sub validate_pathname {\n \tif ($input =~ m!\\0!) {\n \t\treturn undef;\n \t}\n-\treturn $input;\n+\treturn 1;\n }\n \n sub is_valid_ref_format {\n-\tmy $input = shift || return undef;\n+\tmy $input = shift;\n \n+\treturn undef unless defined $input;\n \t# restrictions on ref name according to git-check-ref-format\n \tif ($input =~ m!(/\\.|\\.\\.|[\\000-\\040\\177 ~^:?*\\[]|/$)!) {\n \t\treturn undef;\n \t}\n-\treturn $input;\n+\treturn 1;\n }\n \n-sub validate_refname {\n-\tmy $input = shift || return undef;\n+sub is_valid_refname {\n+\tmy $input = shift;\n \n+\treturn undef unless defined $input;\n \t# textual hashes are O.K.\n \tif ($input =~ m/^[0-9a-fA-F]{40}$/) {\n-\t\treturn $input;\n+\t\treturn 1;\n \t}\n \t# it must be correct pathname\n-\t$input = validate_pathname($input)\n-\t\tor return undef;\n+\tis_valid_pathname($input) or return undef;\n \t# check git-check-ref-format restrictions\n-\tis_valid_ref_format($input)\n-\t\tor return undef;\n-\treturn $input;\n+\tis_valid_ref_format($input) or return undef;\n+\treturn 1;\n }\n \n # decode sequences of octets in utf8 into Perl's internal form,\n-- \n1.8.3.1\n"},{"id":"231907","messageId":"1386762884-7564-4-git-send-email-krzesimir@endocode.com","threadId":"35519","inReplyTo":"1386762884-7564-1-git-send-email-krzesimir@endocode.com","subject":"[PATCH v7 3/4] gitweb: Add a feature for adding more branch refs","fromName":"Krzesimir Nowak","fromEmail":"krzesimir@endocode.com","sentAt":"2013-12-11T11:54:43Z","receivedAt":"2013-12-11T11:54:43Z","isPatch":true,"sender":{"key":"krzesimir@endocode.com","avatar":"https://avatars.githubusercontent.com/u/96081?v=4"},"body":"Allow extra-branch-refs feature to tell gitweb to show refs from\nadditional hierarchies in addition to branches in the list-of-branches\nview.\n\nSigned-off-by: Krzesimir Nowak <krzesimir@endocode.com>\n---\n Documentation/gitweb.conf.txt | 37 ++++++++++++++++++++\n gitweb/gitweb.perl            | 80 ++++++++++++++++++++++++++++++++++++-------\n 2 files changed, 105 insertions(+), 12 deletions(-)\n\ndiff --git a/Documentation/gitweb.conf.txt b/Documentation/gitweb.conf.txt\nindex e2113d9..db4154f 100644\n--- a/Documentation/gitweb.conf.txt\n+++ b/Documentation/gitweb.conf.txt\n@@ -849,6 +849,43 @@ time zones in the form of \"+/-HHMM\", such as \"+0200\".\n +\n Project specific override is not supported.\n \n+extra-branch-refs::\n+\tList of additional directories under \"refs\" which are going to\n+\tbe used as branch refs. For example if you have a gerrit setup\n+\twhere all branches under refs/heads/ are official,\n+\tpush-after-review ones and branches under refs/sandbox/,\n+\trefs/wip and refs/other are user ones where permissions are\n+\tmuch wider, then you might want to set this variable as\n+\tfollows:\n++\n+--------------------------------------------------------------------------------\n+$feature{'extra-branch-refs'}{'default'} =\n+\t['sandbox', 'wip', 'other'];\n+--------------------------------------------------------------------------------\n++\n+This feature can be configured on per-repository basis after setting\n+$feature{'extra-branch-refs'}{'override'} to true, via repository's\n+`gitweb.extraBranchRefs` configuration variable, which contains a\n+space separated list of refs. An example:\n++\n+--------------------------------------------------------------------------------\n+[gitweb]\n+\textraBranchRefs = sandbox wip other\n+--------------------------------------------------------------------------------\n++\n+The gitweb.extraBranchRefs is actually a multi-valued configuration\n+variable, so following example is also correct and the result is the\n+same as of the snippet above:\n++\n+--------------------------------------------------------------------------------\n+[gitweb]\n+\textraBranchRefs = sandbox\n+\textraBranchRefs = wip other\n+--------------------------------------------------------------------------------\n++\n+It is an error to specify a ref that does not pass \"git check-ref-format\"\n+scrutiny. Duplicated values are filtered.\n+\n \n EXAMPLES\n --------\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex b5a8a36..222699a 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -548,6 +548,20 @@ our %feature = (\n \t\t'sub' => sub { feature_bool('remote_heads', @_) },\n \t\t'override' => 0,\n \t\t'default' => [0]},\n+\n+\t# Enable showing branches under other refs in addition to heads\n+\n+\t# To set system wide extra branch refs have in $GITWEB_CONFIG\n+\t# $feature{'extra-branch-refs'}{'default'} = ['dirs', 'of', 'choice'];\n+\t# To have project specific config enable override in $GITWEB_CONFIG\n+\t# $feature{'extra-branch-refs'}{'override'} = 1;\n+\t# and in project config gitweb.extrabranchrefs = dirs of choice\n+\t# Every directory is separated with whitespace.\n+\n+\t'extra-branch-refs' => {\n+\t\t'sub' => \\&feature_extra_branch_refs,\n+\t\t'override' => 0,\n+\t\t'default' => []},\n );\n \n sub gitweb_get_feature {\n@@ -626,6 +640,21 @@ sub feature_avatar {\n \treturn @val ? @val : @_;\n }\n \n+sub feature_extra_branch_refs {\n+\tmy (@branch_refs) = @_;\n+\tmy $values = git_get_project_config('extrabranchrefs');\n+\n+\tif ($values) {\n+\t\t$values = config_to_multi ($values);\n+\t\t@branch_refs = ();\n+\t\tforeach my $value (@{$values}) {\n+\t\t\tpush @branch_refs, split /\\s+/, $value;\n+\t\t}\n+\t}\n+\n+\treturn @branch_refs;\n+}\n+\n # checking HEAD file with -e is fragile if the repository was\n # initialized long time ago (i.e. symlink HEAD) and was pack-ref'ed\n # and then pruned.\n@@ -656,6 +685,18 @@ sub filter_snapshot_fmts {\n \t\t!$known_snapshot_formats{$_}{'disabled'}} @fmts;\n }\n \n+sub filter_and_validate_refs {\n+\tmy @refs = @_;\n+\tmy %unique_refs = ();\n+\n+\tforeach my $ref (@refs) {\n+\t\tdie_error(500, \"Invalid ref '$ref' in 'extra-branch-refs' feature\") unless (is_valid_ref_format($ref));\n+\t\t# 'heads' are added implicitly in get_branch_refs().\n+\t\t$unique_refs{$ref} = 1 if ($ref ne 'heads');\n+\t}\n+\treturn sort keys %unique_refs;\n+}\n+\n # If it is set to code reference, it is code that it is to be run once per\n # request, allowing updating configurations that change with each request,\n # while running other code in config file only once.\n@@ -1113,7 +1154,7 @@ sub evaluate_git_dir {\n \tour $git_dir = \"$projectroot/$project\" if $project;\n }\n \n-our (@snapshot_fmts, $git_avatar);\n+our (@snapshot_fmts, $git_avatar, @extra_branch_refs);\n sub configure_gitweb_features {\n \t# list of supported snapshot formats\n \tour @snapshot_fmts = gitweb_get_feature('snapshot');\n@@ -1131,6 +1172,13 @@ sub configure_gitweb_features {\n \t} else {\n \t\t$git_avatar = '';\n \t}\n+\n+\tour @extra_branch_refs = gitweb_get_feature('extra-branch-refs');\n+\t@extra_branch_refs = filter_and_validate_refs (@extra_branch_refs);\n+}\n+\n+sub get_branch_refs {\n+\treturn ('heads', @extra_branch_refs);\n }\n \n # custom error handler: 'die <message>' is Internal Server Error\n@@ -2527,6 +2575,7 @@ sub format_snapshot_links {\n sub get_feed_info {\n \tmy $format = shift || 'Atom';\n \tmy %res = (action => lc($format));\n+\tmy $matched_ref = 0;\n \n \t# feed links are possible only for project views\n \treturn unless (defined $project);\n@@ -2534,12 +2583,17 @@ sub get_feed_info {\n \t# or don't have specific feed yet (so they should use generic)\n \treturn if (!$action || $action =~ /^(?:tags|heads|forks|tag|search)$/x);\n \n-\tmy $branch;\n-\t# branches refs uses 'refs/heads/' prefix (fullname) to differentiate\n-\t# from tag links; this also makes possible to detect branch links\n-\tif ((defined $hash_base && $hash_base =~ m!^refs/heads/(.*)$!) ||\n-\t    (defined $hash      && $hash      =~ m!^refs/heads/(.*)$!)) {\n-\t\t$branch = $1;\n+\tmy $branch = undef;\n+\t# branches refs uses 'refs/' + $get_branch_refs()[x] + '/' prefix\n+\t# (fullname) to differentiate from tag links; this also makes\n+\t# possible to detect branch links\n+\tfor my $ref (get_branch_refs()) {\n+\t\tif ((defined $hash_base && $hash_base =~ m!^refs/\\Q$ref\\E/(.*)$!) ||\n+\t\t    (defined $hash      && $hash      =~ m!^refs/\\Q$ref\\E/(.*)$!)) {\n+\t\t\t$branch = $1;\n+\t\t\t$matched_ref = $ref;\n+\t\t\tlast;\n+\t\t}\n \t}\n \t# find log type for feed description (title)\n \tmy $type = 'log';\n@@ -2552,7 +2606,7 @@ sub get_feed_info {\n \t}\n \n \t$res{-title} = $type;\n-\t$res{'hash'} = (defined $branch ? \"refs/heads/$branch\" : undef);\n+\t$res{'hash'} = (defined $branch ? \"refs/$matched_ref/$branch\" : undef);\n \t$res{'file_name'} = $file_name;\n \n \treturn %res;\n@@ -3205,7 +3259,7 @@ sub git_get_last_activity {\n \t     '--format=%(committer)',\n \t     '--sort=-committerdate',\n \t     '--count=1',\n-\t     'refs/heads') or return;\n+\t     map { \"refs/$_\" } get_branch_refs ()) or return;\n \tmy $most_recent = <$fd>;\n \tclose $fd or return;\n \tif (defined $most_recent &&\n@@ -3656,7 +3710,7 @@ sub parse_from_to_diffinfo {\n \n sub git_get_heads_list {\n \tmy ($limit, @classes) = @_;\n-\t@classes = ('heads') unless @classes;\n+\t@classes = get_branch_refs() unless @classes;\n \tmy @patterns = map { \"refs/$_\" } @classes;\n \tmy @headslist;\n \n@@ -3674,7 +3728,8 @@ sub git_get_heads_list {\n \t\tmy ($committer, $epoch, $tz) =\n \t\t\t($committerinfo =~ /^(.*) ([0-9]+) (.*)$/);\n \t\t$ref_item{'fullname'}  = $name;\n-\t\t$name =~ s!^refs/(?:head|remote)s/!!;\n+\t\tmy $strip_refs = join '|', map { quotemeta } get_branch_refs();\n+\t\t$name =~ s!^refs/($strip_refs|remotes)/!!;\n \n \t\t$ref_item{'name'}  = $name;\n \t\t$ref_item{'id'}    = $hash;\n@@ -7191,7 +7246,8 @@ sub snapshot_name {\n \t\t$ver = $1;\n \t} else {\n \t\t# branches and other need shortened SHA-1 hash\n-\t\tif ($hash =~ m!^refs/(?:heads|remotes)/(.*)$!) {\n+\t\tmy $strip_refs = join '|', map { quotemeta } get_branch_refs();\n+\t\tif ($hash =~ m!^refs/($strip_refs|remotes)/(.*)$!) {\n \t\t\t$ver = $1;\n \t\t}\n \t\t$ver .= '-' . git_get_short_hash($project, $hash);\n-- \n1.8.3.1\n"},{"id":"231906","messageId":"1386762884-7564-5-git-send-email-krzesimir@endocode.com","threadId":"35519","inReplyTo":"1386762884-7564-1-git-send-email-krzesimir@endocode.com","subject":"[PATCH v7 4/4] gitweb: Denote non-heads, non-remotes branches","fromName":"Krzesimir Nowak","fromEmail":"krzesimir@endocode.com","sentAt":"2013-12-11T11:54:44Z","receivedAt":"2013-12-11T11:54:44Z","isPatch":true,"sender":{"key":"krzesimir@endocode.com","avatar":"https://avatars.githubusercontent.com/u/96081?v=4"},"body":"Given two branches residing in refs/heads/master and refs/wip/feature\nthe list-of-branches view will present them in following way:\nmaster\nfeature (wip)\n\nWhen getting a snapshot of a 'feature' branch, the tarball is going to\nhave name like 'project-wip-feature-<short hash>.tgz'.\n\nSigned-off-by: Krzesimir Nowak <krzesimir@endocode.com>\n---\n gitweb/gitweb.perl | 34 +++++++++++++++++++++++++++++-----\n 1 file changed, 29 insertions(+), 5 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 222699a..3bc0f0b 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -3730,8 +3730,14 @@ sub git_get_heads_list {\n \t\t$ref_item{'fullname'}  = $name;\n \t\tmy $strip_refs = join '|', map { quotemeta } get_branch_refs();\n \t\t$name =~ s!^refs/($strip_refs|remotes)/!!;\n+\t\t$ref_item{'name'} = $name;\n+\t\t# for refs neither in 'heads' nor 'remotes' we want to\n+\t\t# show their ref dir\n+\t\tmy $ref_dir = (defined $1) ? $1 : '';\n+\t\tif ($ref_dir ne '' and $ref_dir ne 'heads' and $ref_dir ne 'remotes') {\n+\t\t    $ref_item{'name'} .= ' (' . $ref_dir . ')';\n+\t\t}\n \n-\t\t$ref_item{'name'}  = $name;\n \t\t$ref_item{'id'}    = $hash;\n \t\t$ref_item{'title'} = $title || '(no commit message)';\n \t\t$ref_item{'epoch'} = $epoch;\n@@ -7223,6 +7229,15 @@ sub git_tree {\n \tgit_footer_html();\n }\n \n+sub sanitize_for_filename {\n+    my $name = shift;\n+\n+    $name =~ s!/!-!g;\n+    $name =~ s/[^[:alnum:]_.-]//g;\n+\n+    return $name;\n+}\n+\n sub snapshot_name {\n \tmy ($project, $hash) = @_;\n \n@@ -7230,9 +7245,7 @@ sub snapshot_name {\n \t# path/to/project/.git -> project\n \tmy $name = to_utf8($project);\n \t$name =~ s,([^/])/*\\.git$,$1,;\n-\t$name = basename($name);\n-\t# sanitize name\n-\t$name =~ s/[[:cntrl:]]/?/g;\n+\t$name = sanitize_for_filename(basename($name));\n \n \tmy $ver = $hash;\n \tif ($hash =~ /^[0-9a-fA-F]+$/) {\n@@ -7248,12 +7261,23 @@ sub snapshot_name {\n \t\t# branches and other need shortened SHA-1 hash\n \t\tmy $strip_refs = join '|', map { quotemeta } get_branch_refs();\n \t\tif ($hash =~ m!^refs/($strip_refs|remotes)/(.*)$!) {\n-\t\t\t$ver = $1;\n+\t\t\tmy $ref_dir = (defined $1) ? $1 : '';\n+\t\t\t$ver = $2;\n+\n+\t\t\t$ref_dir = sanitize_for_filename($ref_dir);\n+\t\t\t# for refs neither in heads nor remotes we want to\n+\t\t\t# add a ref dir to archive name\n+\t\t\tif ($ref_dir ne '' and $ref_dir ne 'heads' and $ref_dir ne 'remotes') {\n+\t\t\t\t$ver = $ref_dir . '-' . $ver;\n+\t\t\t}\n \t\t}\n \t\t$ver .= '-' . git_get_short_hash($project, $hash);\n \t}\n+\t# special case of sanitization for filename - we change\n+\t# slashes to dots instead of dashes\n \t# in case of hierarchical branch names\n \t$ver =~ s!/!.!g;\n+\t$ver =~ s/[^[:alnum:]_.-]//g;\n \n \t# name = project-version_string\n \t$name = \"$name-$ver\";\n-- \n1.8.3.1\n"},{"id":"231921","messageId":"CANQwDwc5iagW+yLxG-DempZuoNk7Nc0W4rg8ZXA_bU=Eu2vTiA@mail.gmail.com","threadId":"35519","inReplyTo":"1386762884-7564-3-git-send-email-krzesimir@endocode.com","subject":"Re: [PATCH v7 2/4] gitweb: Return 1 on validation success instead of passed input","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2013-12-11T16:08:39Z","receivedAt":"2013-12-11T16:08:39Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"On Wed, Dec 11, 2013 at 12:54 PM, Krzesimir Nowak\n<krzesimir@endocode.com> wrote:\n\n> Users of validate_* passing \"0\" might get failures on correct name\n> because of coercion of \"0\" to false in code like:\n> die_error(500, \"invalid ref\") unless (check_ref_format (\"0\"));\n\nVery minor issue: there is no check_ref_format() after v7; perhaps\nvalidate_pathname / is_valid_pathname\n\n> Also, the validate_foo subs are renamed to is_valid_foo.\n\nis_valid_foo is better than validate_foo IMVHO, though still not perfect\n(it does some validation, but complete validation is done by git command).\n\n>\n> Signed-off-by: Krzesimir Nowak <krzesimir@endocode.com>\n\n-- \nJakub Narebski\n"},{"id":"231963","messageId":"xmqqfvpxspy2.fsf@gitster.dls.corp.google.com","threadId":"35519","inReplyTo":"1386762884-7564-1-git-send-email-krzesimir@endocode.com","subject":"Re: [PATCH v7 0/4] Show extra branch refs in gitweb","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-12-12T21:46:13Z","receivedAt":"2013-12-12T21:46:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Krzesimir Nowak <krzesimir@endocode.com> writes:\n\n> First patch splits some code to a function.\n>\n> Second patch fixes validation functions to return either 0 or 1,\n> instead of undef or passed $input.\n>\n> Third patch adds the extra-branch-feature and some documentation.\n>\n> Fourth patch adds some visual differentation of branches from\n> non-standard ref directories.\n\nThanks; will queue.\n"}]}