git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH] gitweb: Better symbolic link support in "tree" view
@ 2006-12-04 18:26 Jakub Narebsmi
  2006-12-05  1:08 ` Junio C Hamano
  0 siblings, 1 reply; 12+ messages in thread
From: Jakub Narebsmi @ 2006-12-04 18:26 UTC (permalink / raw
  To: git; +Cc: Jakub Narebski

From: Jakub Narebski <jnareb@gmail.com>

In "tree" view (git_print_tree_entry subroutine), add for symbolic
links after file name " -> link_target", a la "ls -l".  Use
git_get_link_target_html to escape target name and make it into
hyperlink if possible.

Target of link is made into hyperlink when:
 * hash_base is provided (otherwise we cannot find hash of link
   target)
 * link is relative
 * in no place link goes out of root tree (top dir)
 * target of link exists for hash_base

Full path of symlink target from the root dir is provided in the title
attribute of hyperlink. If symlink target is a directory, '/' is added
to end of path in title attribute.

Currently symbolic link name uses ordinary file style (hidden
hyperlink), while the hyperlink to symlink target uses default
hyperlink style.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
 gitweb/gitweb.perl |   91 +++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 83 insertions(+), 8 deletions(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index ffe8ce1..3c1b75d 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -1989,12 +1989,83 @@ sub git_print_log ($;%) {
 	}
 }
 
+# print link tree entry (name of what link points to, possibly hyperlink)
+sub git_get_link_target_html {
+	my ($t, $basedir, $hash_base) = @_;
+
+	my $fd;
+	my %target = ();
+
+	# read link
+	open $fd, "-|", git_cmd(), "cat-file", "blob", $t->{'hash'};
+	{
+		local $/;
+		$target{'orig'} = <$fd>;
+	}
+	close $fd;
+
+	# we can make hyperlink out of link target only if $hash_base is provided
+	return esc_path($target{'orig'})
+		unless $hash_base;
+
+	# absolute links are returned as is, no hyperlink
+	if (substr($target{'orig'}, 0, 1) eq '/') {
+		return esc_path($target{'orig'});
+	}
+
+	# normalize link target to path from top (root) tree (dir)
+	if ($basedir) {
+		$target{'path'} = $basedir . '/' . $target{'orig'};
+	} else {
+		# we are in top (root) tree (dir)
+		$target{'path'} = $target{'orig'};
+	}
+	$target{'parts'} = [ ];
+	foreach my $part (split('/', $target{'path'})) {
+		# discard '.' and ''
+		next if (!$part || $part eq '.');
+		# handle '..'
+		if ($part eq '..') {
+			if (@{$target{'parts'}}) {
+				pop @{$target{'parts'}};
+			} else {
+				# link leads outside repository
+				return esc_path($target{'orig'});
+			}
+		} else {
+			push @{$target{'parts'}}, $part;
+		}
+	}
+	$target{'path'} = join('/', @{$target{'parts'}});
+
+	# check if path exists
+	open $fd, "-|", git_cmd(), "ls-tree", $hash_base, "--", $target{'path'}
+		or return esc_path($target{'orig'});
+	my $line = <$fd>;
+	close $fd
+		or return esc_path($target{'orig'});
+	return esc_path($target{'orig'}) unless $line;
+
+	# parse ls-tree line to get type and hash of target of link
+	(undef, $target{'type'}, $target{'hash'}) =
+		($line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t/);
+
+	# make a link if path exists
+	return $cgi->a({-href => href(action    => $target{'type'},
+	                              hash      => $target{'hash'},
+	                              file_name => $target{'path'},
+	                              hash_base => $hash_base),
+	                -title => $target{'path'} .
+	                          ($target{'type'} eq "tree" ? '/' : '')},
+	               esc_path($target{'orig'}));
+}
+
 # print tree entry (row of git_tree), but without encompassing <tr> element
 sub git_print_tree_entry {
 	my ($t, $basedir, $hash_base, $have_blame) = @_;
 
 	my %base_key = ();
-	$base_key{hash_base} = $hash_base if defined $hash_base;
+	$base_key{'hash_base'} = $hash_base if defined $hash_base;
 
 	# The format of a table row is: mode list link.  Where mode is
 	# the mode of the entry, list is the name of the entry, an href,
@@ -2005,16 +2076,20 @@ sub git_print_tree_entry {
 		print "<td class=\"list\">" .
 			$cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
 			                       file_name=>"$basedir$t->{'name'}", %base_key),
-			        -class => "list"}, esc_path($t->{'name'})) . "</td>\n";
+			        -class => "list"}, esc_path($t->{'name'}));
+		if (S_ISLNK(oct $t->{'mode'})) {
+			print " -> " . git_get_link_target_html($t, $basedir, $hash_base);
+		}
+		print "</td>\n";
 		print "<td class=\"link\">";
 		print $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
-					     file_name=>"$basedir$t->{'name'}", %base_key)},
-			      "blob");
+		                             file_name=>"$basedir$t->{'name'}", %base_key)},
+		              "blob");
 		if ($have_blame) {
 			print " | " .
 			      $cgi->a({-href => href(action=>"blame", hash=>$t->{'hash'},
-				                           file_name=>"$basedir$t->{'name'}", %base_key)},
-				            "blame");
+			                             file_name=>"$basedir$t->{'name'}", %base_key)},
+			              "blame");
 		}
 		if (defined $hash_base) {
 			print " | " .
@@ -2036,8 +2111,8 @@ sub git_print_tree_entry {
 		print "</td>\n";
 		print "<td class=\"link\">";
 		print $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'},
-					     file_name=>"$basedir$t->{'name'}", %base_key)},
-			      "tree");
+		                             file_name=>"$basedir$t->{'name'}", %base_key)},
+		              "tree");
 		if (defined $hash_base) {
 			print " | " .
 			      $cgi->a({-href => href(action=>"history", hash_base=>$hash_base,
-- 
1.4.4.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH] gitweb: Better symbolic link support in "tree" view
  2006-12-04 18:26 [PATCH] gitweb: Better symbolic link support in "tree" view Jakub Narebsmi
@ 2006-12-05  1:08 ` Junio C Hamano
  2006-12-05 21:27   ` Jakub Narebski
  0 siblings, 1 reply; 12+ messages in thread
From: Junio C Hamano @ 2006-12-05  1:08 UTC (permalink / raw
  To: Jakub Narebsmi; +Cc: git

Jakub Narebsmi <jnareb@gmail.com> writes:

> In "tree" view (git_print_tree_entry subroutine), add for symbolic
> links after file name " -> link_target", a la "ls -l".  Use
> git_get_link_target_html to escape target name and make it into
> hyperlink if possible.

I think " -> link_target" is fine, but I do not know if it is
useful (while I do not think it is wrong) to make the value that
would have been returned from readlink() into an href, even when
it points at something inside the same revision.


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] gitweb: Better symbolic link support in "tree" view
  2006-12-05  1:08 ` Junio C Hamano
@ 2006-12-05 21:27   ` Jakub Narebski
  2006-12-05 22:34     ` Junio C Hamano
  0 siblings, 1 reply; 12+ messages in thread
From: Jakub Narebski @ 2006-12-05 21:27 UTC (permalink / raw
  To: Junio C Hamano; +Cc: git

Junio C Hamano wrote:
> Jakub Narebski <jnareb@gmail.com> writes:
> 
>> In "tree" view (git_print_tree_entry subroutine), add for symbolic
>> links after file name " -> link_target", a la "ls -l".  Use
>> git_get_link_target_html to escape target name and make it into
>> hyperlink if possible.
> 
> I think " -> link_target" is fine, but I do not know if it is
> useful (while I do not think it is wrong) to make the value that
> would have been returned from readlink() into an href, even when
> it points at something inside the same revision.

I have added this bit (making symbolic link target symlink) because 
otherwise there is no way, besides hand-munging the URL, to go to the 
link target.

From the command line, tools usually follow symlinks. In gitweb, "blob" 
view (and "blob_plain" view) show symbolic link contents... not that 
I'm for changing this, mind you.
-- 
Jakub Narebski

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] gitweb: Better symbolic link support in "tree" view
  2006-12-05 21:27   ` Jakub Narebski
@ 2006-12-05 22:34     ` Junio C Hamano
  2006-12-05 23:06       ` Jakub Narebski
                         ` (6 more replies)
  0 siblings, 7 replies; 12+ messages in thread
From: Junio C Hamano @ 2006-12-05 22:34 UTC (permalink / raw
  To: Jakub Narebski; +Cc: git

Jakub Narebski <jnareb@gmail.com> writes:

> Junio C Hamano wrote:
>> ...
>> I think " -> link_target" is fine, but I do not know if it is
>> useful (while I do not think it is wrong) to make the value that
>> would have been returned from readlink() into an href, even when
>> it points at something inside the same revision.
>
> I have added this bit (making symbolic link target symlink) because 
> otherwise there is no way, besides hand-munging the URL, to go to the 
> link target.

I can read what you wrote it does.

For one thing, the user is tracking the symbolic link itself,
not the contents of the file or directory the link points at.
For that "tracked symlink", where it points at is the important
content, not what the file that is pointed at happens to contain
in the same revision.

If you have to open an extra object while drawing the list, I do
not think it is worth doing it.

In order to show " -> link_target", you have to read the
contents of the blob.  I think that overhead to read one extra
blob is probably an acceptable tradeoff for convenience.

But if you want to make it a link into the same tree, you would
need to check if link_target path exists and if it is a blob or
tree to produce an appropriate tree_view/blob_view link (I
haven't read your code but that is the natural thing to do).

That would involve in reading a few more tree objects (depending
on how deep the target is in the tree), and I do not think it is
worth doing it while drawing a list.  After you prepared dozens
of such links, the user would click at most one of them and 
leaves the page; your cycles to draw those unclicked links were
wasted.

If you wanted to do this, a better way would be to have a new
view that takes a commit/tree object and a path from the top of
the repository, and shows either "no such path in that tree" or
"here is the view for that object, by the way it was a blob."
page.  Then your list drawing would still need to open each
symlink blob to show " -> link_target", and need to check if it
goes outside the repository (I would assume you are handling
relative links as well), but you do not need to do expensive
ls-tree step one per symlink on the page.  The href attr of the
A element " -> link_target" would point at that "universal
object view" with the link_target pathname (that is, the blob
contents) and the commit/tree object name (h or hb I do not know
which) and you will spend cycles to run ls-tree only when the
user actually asks to follow that link.

In other words, I think trying to be lazy is extremely important
while drawing a big list.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] gitweb: Better symbolic link support in "tree" view
  2006-12-05 22:34     ` Junio C Hamano
@ 2006-12-05 23:06       ` Jakub Narebski
  2006-12-10 12:25       ` [PATCH 0/3] " Jakub Narebski
                         ` (5 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Jakub Narebski @ 2006-12-05 23:06 UTC (permalink / raw
  To: Junio C Hamano; +Cc: git

Junio C Hamano wrote:

> Jakub Narebski <jnareb@gmail.com> writes:
> 
>> Junio C Hamano wrote:
>>> ...
>>> I think " -> link_target" is fine, but I do not know if it is
>>> useful (while I do not think it is wrong) to make the value that
>>> would have been returned from readlink() into an href, even when
>>> it points at something inside the same revision.
>>
>> I have added this bit (making symbolic link target symlink) because 
>> otherwise there is no way, besides hand-munging the URL, to go to the 
>> link target.
> 
> I can read what you wrote it does.
> 
> For one thing, the user is tracking the symbolic link itself,
> not the contents of the file or directory the link points at.
> For that "tracked symlink", where it points at is the important
> content, not what the file that is pointed at happens to contain
> in the same revision.
> 
> If you have to open an extra object while drawing the list, I do
> not think it is worth doing it.
> 
> In order to show " -> link_target", you have to read the
> contents of the blob.  I think that overhead to read one extra
> blob is probably an acceptable tradeoff for convenience.

Especially that it is done _only_ if there exist symbolic link
entry in a tree.
 
> But if you want to make it a link into the same tree, you would
> need to check if link_target path exists and if it is a blob or
> tree to produce an appropriate tree_view/blob_view link (I
> haven't read your code but that is the natural thing to do).
> 
> That would involve in reading a few more tree objects (depending
> on how deep the target is in the tree), and I do not think it is
> worth doing it while drawing a list.  After you prepared dozens
> of such links, the user would click at most one of them and 
> leaves the page; your cycles to draw those unclicked links were
> wasted.

Actually this requires only one call to git-ls-tree

  $ git ls-tree $hash_base -- $target_path

Internally this mean reading a few more tree objects, but in gitweb
the cost of fork is what (I think) dominates.

> If you wanted to do this, a better way would be to have a new
> view that takes a commit/tree object and a path from the top of
> the repository, and shows either "no such path in that tree" or
> "here is the view for that object, by the way it was a blob."
> page.  Then your list drawing would still need to open each
> symlink blob to show " -> link_target", and need to check if it
> goes outside the repository (I would assume you are handling
> relative links as well),

I handle _only_ relative links. There is no way to treat absolute links 
leading within repository (well, there is, but absoulte links depends 
on position of repository in the filesystem, and that is usually bad 
idea... unless absolute link is not to file within repository). The 
link is "normalized" to path from the top of the tree/top of repository 
tree (dealing with /./, /../, and // in the way).

>                          but you do not need to do expensive 
> ls-tree step one per symlink on the page.  The href attr of the
> A element " -> link_target" would point at that "universal
> object view" with the link_target pathname (that is, the blob
> contents) and the commit/tree object name (h or hb I do not know
> which) and you will spend cycles to run ls-tree only when the
> user actually asks to follow that link.
> 
> In other words, I think trying to be lazy is extremely important
> while drawing a big list.

Well, that is certainly another solution. I'm not sure if distinction 
between checking if link target exists (and getting target type while 
at it) and providing link to perhaps "no such patch in that tree" page 
is worth %feature... well, I guess it is not.

I'll split the patch into two: first to read link target and show it in 
"tree" view _without_ hyperlink, and later perhaps either your or mine 
solution (most probably yours), depending on feedback.

-- 
Jakub Narebski

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 0/3] gitweb: Better symbolic link support in "tree" view
  2006-12-05 22:34     ` Junio C Hamano
  2006-12-05 23:06       ` Jakub Narebski
@ 2006-12-10 12:25       ` Jakub Narebski
  2006-12-10 12:25       ` Jakub Narebski
                         ` (4 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Jakub Narebski @ 2006-12-10 12:25 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano

Junio C Hamano wrote in
"Re: [PATCH] gitweb: Better symbolic link support in "tree" view":

> If you wanted to do this, a better way would be to have a new
> view that takes a commit/tree object and a path from the top of
> the repository, and shows either "no such path in that tree" or
> "here is the view for that object, by the way it was a blob."
> page.  Then your list drawing would still need to open each
> symlink blob to show " -> link_target", and need to check if it
> goes outside the repository (I would assume you are handling
> relative links as well), but you do not need to do expensive
> ls-tree step one per symlink on the page.  The href attr of the
> A element " -> link_target" would point at that "universal
> object view" with the link_target pathname (that is, the blob
> contents) and the commit/tree object name (h or hb I do not know
> which) and you will spend cycles to run ls-tree only when the
> user actually asks to follow that link.
> 
> In other words, I think trying to be lazy is extremely important
> while drawing a big list.

I not necessarily agree; I think that symbolic links are sufficnetly
rare that a bit more time spent to make the view better for end user
(link only if target exists) is worth it. But...

Here follows the implementation of this idea: first to read link
target and show it in "tree" view _without_ hyperlink, then
introduction of generic "object" view which does the verification and
redirect to correct view accorting to the type of object, and last
show link target hyperlinked in "tree" view using "object" view/action
link.

While at it implement the same "lazy" solution in commitsha1 commitag
in format_log_line_html subroutine.

Table of contents:
 [PATCH 1/3] gitweb: Show target of symbolic link in "tree" view
 [PATCH 2/3] gitweb: Add generic git_object subroutine to display object of any type
 [PATCH 3/3] gitweb: Hyperlink target of symbolic link in "tree" view (if possible)
 [PATCH/RFC 4/3] gitweb: SHA-1 in commit log message links to "object" view

Diffstat:
 gitweb/gitweb.perl |  152 ++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 137 insertions(+), 15 deletions(-)

-- 
Jakub Narebski
ShadeHawk on #git

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 0/3] gitweb: Better symbolic link support in "tree" view
  2006-12-05 22:34     ` Junio C Hamano
  2006-12-05 23:06       ` Jakub Narebski
  2006-12-10 12:25       ` [PATCH 0/3] " Jakub Narebski
@ 2006-12-10 12:25       ` Jakub Narebski
  2006-12-10 12:25       ` [PATCH 1/3] gitweb: Show target of symbolic link " Jakub Narebski
                         ` (3 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Jakub Narebski @ 2006-12-10 12:25 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano

Junio C Hamano wrote in
"Re: [PATCH] gitweb: Better symbolic link support in "tree" view":

> If you wanted to do this, a better way would be to have a new
> view that takes a commit/tree object and a path from the top of
> the repository, and shows either "no such path in that tree" or
> "here is the view for that object, by the way it was a blob."
> page.  Then your list drawing would still need to open each
> symlink blob to show " -> link_target", and need to check if it
> goes outside the repository (I would assume you are handling
> relative links as well), but you do not need to do expensive
> ls-tree step one per symlink on the page.  The href attr of the
> A element " -> link_target" would point at that "universal
> object view" with the link_target pathname (that is, the blob
> contents) and the commit/tree object name (h or hb I do not know
> which) and you will spend cycles to run ls-tree only when the
> user actually asks to follow that link.
> 
> In other words, I think trying to be lazy is extremely important
> while drawing a big list.

I not necessarily agree; I think that symbolic links are sufficnetly
rare that a bit more time spent to make the view better for end user
(link only if target exists) is worth it. But...

Here follows the implementation of this idea: first to read link
target and show it in "tree" view _without_ hyperlink, then
introduction of generic "object" view which does the verification and
redirect to correct view accorting to the type of object, and last
show link target hyperlinked in "tree" view using "object" view/action
link.

While at it implement the same "lazy" solution in commitsha1 commitag
in format_log_line_html subroutine.

Table of contents:
 [PATCH 1/3] gitweb: Show target of symbolic link in "tree" view
 [PATCH 2/3] gitweb: Add generic git_object subroutine to display object of any type
 [PATCH 3/3] gitweb: Hyperlink target of symbolic link in "tree" view (if possible)
 [PATCH/RFC 4/3] gitweb: SHA-1 in commit log message links to "object" view

Diffstat:
 gitweb/gitweb.perl |  152 ++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 137 insertions(+), 15 deletions(-)

-- 
Jakub Narebski
ShadeHawk on #git

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/3] gitweb: Show target of symbolic link in "tree" view
  2006-12-05 22:34     ` Junio C Hamano
                         ` (2 preceding siblings ...)
  2006-12-10 12:25       ` Jakub Narebski
@ 2006-12-10 12:25       ` Jakub Narebski
  2006-12-10 12:25       ` [PATCH 2/3] gitweb: Add generic git_object subroutine to display object of any type Jakub Narebski
                         ` (2 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Jakub Narebski @ 2006-12-10 12:25 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Jakub Narebski

In "tree" view (git_print_tree_entry subroutine), for entries which are
symbolic links, add " -> link_target" after file name (a la "ls -l").

Link target is _not_ hyperlinked.

While at it, correct whitespaces (tabs are for aling, spaces are for indent)
in modified git_print_tree_entry subroutine.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
Jakub Narebski wrote:
> I'll split the patch into two: first to read link target and show it in 
> "tree" view _without_ hyperlink, and later perhaps either your or mine 
> solution (most probably yours), depending on feedback.

That implements the first part.

 gitweb/gitweb.perl |   42 ++++++++++++++++++++++++++++++++++--------
 1 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 5ea3fda..0c2cfc7 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -1989,12 +1989,31 @@ sub git_print_log ($;%) {
 	}
 }
 
+# return link target (what link points to)
+sub git_get_link_target {
+	my $hash = shift;
+	my $link_target;
+
+	# read link
+	open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash
+		or return;
+	{
+		local $/;
+		$link_target = <$fd>;
+	}
+	close $fd
+		or return;
+
+	return $link_target;
+}
+
+
 # print tree entry (row of git_tree), but without encompassing <tr> element
 sub git_print_tree_entry {
 	my ($t, $basedir, $hash_base, $have_blame) = @_;
 
 	my %base_key = ();
-	$base_key{hash_base} = $hash_base if defined $hash_base;
+	$base_key{'hash_base'} = $hash_base if defined $hash_base;
 
 	# The format of a table row is: mode list link.  Where mode is
 	# the mode of the entry, list is the name of the entry, an href,
@@ -2005,16 +2024,23 @@ sub git_print_tree_entry {
 		print "<td class=\"list\">" .
 			$cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
 			                       file_name=>"$basedir$t->{'name'}", %base_key),
-			        -class => "list"}, esc_path($t->{'name'})) . "</td>\n";
+			        -class => "list"}, esc_path($t->{'name'}));
+		if (S_ISLNK(oct $t->{'mode'})) {
+			my $link_target = git_get_link_target($t->{'hash'});
+			if ($link_target) {
+				print " -> " . esc_path($link_target);
+			}
+		}
+		print "</td>\n";
 		print "<td class=\"link\">";
 		print $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
-					     file_name=>"$basedir$t->{'name'}", %base_key)},
-			      "blob");
+		                             file_name=>"$basedir$t->{'name'}", %base_key)},
+		              "blob");
 		if ($have_blame) {
 			print " | " .
 			      $cgi->a({-href => href(action=>"blame", hash=>$t->{'hash'},
-				                           file_name=>"$basedir$t->{'name'}", %base_key)},
-				            "blame");
+			                             file_name=>"$basedir$t->{'name'}", %base_key)},
+			              "blame");
 		}
 		if (defined $hash_base) {
 			print " | " .
@@ -2036,8 +2062,8 @@ sub git_print_tree_entry {
 		print "</td>\n";
 		print "<td class=\"link\">";
 		print $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'},
-					     file_name=>"$basedir$t->{'name'}", %base_key)},
-			      "tree");
+		                             file_name=>"$basedir$t->{'name'}", %base_key)},
+		              "tree");
 		if (defined $hash_base) {
 			print " | " .
 			      $cgi->a({-href => href(action=>"history", hash_base=>$hash_base,
-- 
1.4.4.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/3] gitweb: Add generic git_object subroutine to display object of any type
  2006-12-05 22:34     ` Junio C Hamano
                         ` (3 preceding siblings ...)
  2006-12-10 12:25       ` [PATCH 1/3] gitweb: Show target of symbolic link " Jakub Narebski
@ 2006-12-10 12:25       ` Jakub Narebski
  2006-12-10 12:25       ` [PATCH 3/3] gitweb: Hyperlink target of symbolic link in "tree" view (if possible) Jakub Narebski
  2006-12-10 12:25       ` [PATCH/RFC 4/3] gitweb: SHA-1 in commit log message links to "object" view Jakub Narebski
  6 siblings, 0 replies; 12+ messages in thread
From: Jakub Narebski @ 2006-12-10 12:25 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Jakub Narebski

Add generic "object" view implemented in git_object subroutine, which is
used to display object of any type; to be more exact it redirects to the
view of correct type: "blob", "tree", "commit" or "tag".  To identify object
you have to provide either hash (identifier of an object), or (in the case of
tree and blob objects) hash of commit object (hash_base) and path (file_name).

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
First version had checking if $hash and $hash_base are explicit SHA-1
if are defined.  This version doesn't have this check, which is
important for next patch.

 gitweb/gitweb.perl |   48 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 48 insertions(+), 0 deletions(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 0c2cfc7..a988f85 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -434,6 +434,7 @@ my %actions = (
 	"tags" => \&git_tags,
 	"tree" => \&git_tree,
 	"snapshot" => \&git_snapshot,
+	"object" => \&git_object,
 	# those below don't need $project
 	"opml" => \&git_opml,
 	"project_list" => \&git_project_list,
@@ -3620,6 +3621,53 @@ sub git_commit {
 	git_footer_html();
 }
 
+sub git_object {
+	# object is defined by:
+	# - hash or hash_base alone
+	# - hash_base and file_name
+	my $type;
+
+	# - hash or hash_base alone
+	if ($hash || ($hash_base && !defined $file_name)) {
+		my $object_id = $hash || $hash_base;
+
+		my $git_command = git_cmd_str();
+		open my $fd, "-|", "$git_command cat-file -t $object_id 2>/dev/null"
+			or die_error('404 Not Found', "Object does not exist");
+		$type = <$fd>;
+		chomp $type;
+		close $fd
+			or die_error('404 Not Found', "Object does not exist");
+
+	# - hash_base and file_name
+	} elsif ($hash_base && defined $file_name) {
+		$file_name =~ s,/+$,,;
+
+		system(git_cmd(), "cat-file", '-e', $hash_base) == 0
+			or die_error('404 Not Found', "Base object does not exist");
+
+		# here errors should not hapen
+		open my $fd, "-|", git_cmd(), "ls-tree", $hash_base, "--", $file_name
+			or die_error(undef, "Open git-ls-tree failed");
+		my $line = <$fd>;
+		close $fd;
+
+		#'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa	panic.c'
+		unless ($line && $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t/) {
+			die_error('404 Not Found', "File or directory for given base does not exist");
+		}
+		$type = $2;
+		$hash = $3;
+	} else {
+		die_error('404 Not Found', "Not enough information to find object");
+	}
+
+	print $cgi->redirect(-uri => href(action=>$type, -full=>1,
+	                                  hash=>$hash, hash_base=>$hash_base,
+	                                  file_name=>$file_name),
+	                     -status => '302 Found');
+}
+
 sub git_blobdiff {
 	my $format = shift || 'html';
 
-- 
1.4.4.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/3] gitweb: Hyperlink target of symbolic link in "tree" view (if possible)
  2006-12-05 22:34     ` Junio C Hamano
                         ` (4 preceding siblings ...)
  2006-12-10 12:25       ` [PATCH 2/3] gitweb: Add generic git_object subroutine to display object of any type Jakub Narebski
@ 2006-12-10 12:25       ` Jakub Narebski
  2006-12-10 12:25       ` [PATCH/RFC 4/3] gitweb: SHA-1 in commit log message links to "object" view Jakub Narebski
  6 siblings, 0 replies; 12+ messages in thread
From: Jakub Narebski @ 2006-12-10 12:25 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Jakub Narebski

Make symbolic link target in "tree" view into hyperlink to generic
"object" view (as we don't know if the link target is file (blob) or
directory (tree), and if it exist at all).

Target of link is made into hyperlink when:
 * hash_base is provided (otherwise we cannot find hash
   of link target)
 * link is relative
 * in no place link goes out of root tree (top dir)

Full path of symlink target from the root dir is provided in the title
attribute of hyperlink.

Currently symbolic link name uses ordinary file style (hidden
hyperlink), while the hyperlink to symlink target uses default
hyperlink style, so it is underlined while link target which is not
made into hyperlink is not underlined.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
Junio C Hamano wrote:
> In other words, I think trying to be lazy is extremely important
> while drawing a big list.

This implements "lazy" hyperlinking of symbolic link target in "tree"
view.

 gitweb/gitweb.perl |   52 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 51 insertions(+), 1 deletions(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index a988f85..6493311 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -2008,6 +2008,48 @@ sub git_get_link_target {
 	return $link_target;
 }
 
+# given link target, and the directory (basedir) the link is in,
+# return target of link relative to top directory (top tree);
+# return undef if it is not possible (including absolute links).
+sub normalize_link_target {
+	my ($link_target, $basedir, $hash_base) = @_;
+
+	# we can normalize symlink target only if $hash_base is provided
+	return unless $hash_base;
+
+	# absolute symlinks (beginning with '/') cannot be normalized
+	return if (substr($link_target, 0, 1) eq '/');
+
+	# normalize link target to path from top (root) tree (dir)
+	my $path;
+	if ($basedir) {
+		$path = $basedir . '/' . $link_target;
+	} else {
+		# we are in top (root) tree (dir)
+		$path = $link_target;
+	}
+
+	# remove //, /./, and /../
+	my @path_parts;
+	foreach my $part (split('/', $path)) {
+		# discard '.' and ''
+		next if (!$part || $part eq '.');
+		# handle '..'
+		if ($part eq '..') {
+			if (@path_parts) {
+				pop @path_parts;
+			} else {
+				# link leads outside repository (outside top dir)
+				return;
+			}
+		} else {
+			push @path_parts, $part;
+		}
+	}
+	$path = join('/', @path_parts);
+
+	return $path;
+}
 
 # print tree entry (row of git_tree), but without encompassing <tr> element
 sub git_print_tree_entry {
@@ -2029,7 +2071,15 @@ sub git_print_tree_entry {
 		if (S_ISLNK(oct $t->{'mode'})) {
 			my $link_target = git_get_link_target($t->{'hash'});
 			if ($link_target) {
-				print " -> " . esc_path($link_target);
+				my $norm_target = normalize_link_target($link_target, $basedir, $hash_base);
+				if (defined $norm_target) {
+					print " -> " .
+					      $cgi->a({-href => href(action=>"object", hash_base=>$hash_base,
+					                             file_name=>$norm_target),
+					               -title => $norm_target}, esc_path($link_target));
+				} else {
+					print " -> " . esc_path($link_target);
+				}
 			}
 		}
 		print "</td>\n";
-- 
1.4.4.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH/RFC 4/3] gitweb: SHA-1 in commit log message links to "object" view
  2006-12-05 22:34     ` Junio C Hamano
                         ` (5 preceding siblings ...)
  2006-12-10 12:25       ` [PATCH 3/3] gitweb: Hyperlink target of symbolic link in "tree" view (if possible) Jakub Narebski
@ 2006-12-10 12:25       ` Jakub Narebski
  2006-12-10 21:29         ` Junio C Hamano
  6 siblings, 1 reply; 12+ messages in thread
From: Jakub Narebski @ 2006-12-10 12:25 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Jakub Narebski

Instead of checking if explicit SHA-1 in commit log message is sha1 of
commit and making link to "commit" view, make [fragment of] explicit
SHA-1 in commit log message link to "object" view.  While at it allow
to hyperlink also shortened SHA-1, from 8 characters up to full SHA-1,
instead of requiring full 40 characters of SHA-1.

This makes the following changes:

 * SHA-1 of objects which no longer exists, for example in commit
   cherry-picked from no longer existing temporary branch, or revert
   of commit in rebased branch, are no longer marked as such by not
   being made into hyperlink (and not having default hyperlink view:
   being underlined among others).  On the other hand it makes gitweb
   to not write error messages when object is not found to web serwer
   log; it also moves cost of getting type and SHA-1 validation to
   when link is clicked, and not only viewed.

 * SHA-1 of other objects: blobs, trees, tags are also hyperlinked
   and lead to appropriate view (although in the case of tags it is
   more natural to just use tag name).

 * You can put shortened SHA-1 of commit in the commit message, and it
   would be hyperlinked; it would be checked on clicking if abbrev is
   unique.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
This follows the "lazy hyperlink" idea of symbolic link support in the
"tree" view.

It is an RFC (Requests For Comments) because I'm not sure if it
wouldn't be better to make dead SHA-1 marked in commit log message,
instead of finfing it out after clicking...

 gitweb/gitweb.perl |   12 +++++-------
 1 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 6493311..7d24c10 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -828,14 +828,12 @@ sub format_log_line_html {
 	my $line = shift;
 
 	$line = esc_html($line, -nbsp=>1);
-	if ($line =~ m/([0-9a-fA-F]{40})/) {
+	if ($line =~ m/([0-9a-fA-F]{8,40})/) {
 		my $hash_text = $1;
-		if (git_get_type($hash_text) eq "commit") {
-			my $link =
-				$cgi->a({-href => href(action=>"commit", hash=>$hash_text),
-				        -class => "text"}, $hash_text);
-			$line =~ s/$hash_text/$link/;
-		}
+		my $link =
+			$cgi->a({-href => href(action=>"object", hash=>$hash_text),
+			        -class => "text"}, $hash_text);
+		$line =~ s/$hash_text/$link/;
 	}
 	return $line;
 }
-- 
1.4.4.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH/RFC 4/3] gitweb: SHA-1 in commit log message links to "object" view
  2006-12-10 12:25       ` [PATCH/RFC 4/3] gitweb: SHA-1 in commit log message links to "object" view Jakub Narebski
@ 2006-12-10 21:29         ` Junio C Hamano
  0 siblings, 0 replies; 12+ messages in thread
From: Junio C Hamano @ 2006-12-10 21:29 UTC (permalink / raw
  To: Jakub Narebski; +Cc: git

Jakub Narebski <jnareb@gmail.com> writes:

> Instead of checking if explicit SHA-1 in commit log message is sha1 of
> commit and making link to "commit" view, make [fragment of] explicit
> SHA-1 in commit log message link to "object" view.  While at it allow
> to hyperlink also shortened SHA-1, from 8 characters up to full SHA-1,
> instead of requiring full 40 characters of SHA-1.
>
> This makes the following changes:
>
>  * SHA-1 of objects which no longer exists, for example in commit
>    cherry-picked from no longer existing temporary branch, or revert
>    of commit in rebased branch, are no longer marked as such by not
>    being made into hyperlink (and not having default hyperlink view:
>    being underlined among others).  On the other hand it makes gitweb
>    to not write error messages when object is not found to web serwer
>    log; it also moves cost of getting type and SHA-1 validation to
>    when link is clicked, and not only viewed.
>
>  * SHA-1 of other objects: blobs, trees, tags are also hyperlinked
>    and lead to appropriate view (although in the case of tags it is
>    more natural to just use tag name).
>
>  * You can put shortened SHA-1 of commit in the commit message, and it
>    would be hyperlinked; it would be checked on clicking if abbrev is
>    unique.
>
> Signed-off-by: Jakub Narebski <jnareb@gmail.com>
> ---
> This follows the "lazy hyperlink" idea of symbolic link support in the
> "tree" view.
>
> It is an RFC (Requests For Comments) because I'm not sure if it
> wouldn't be better to make dead SHA-1 marked in commit log message,
> instead of finfing it out after clicking...

I am certainly in favor of the approach.  Will look at the code
later.  Thanks.

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2006-12-10 21:29 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-12-04 18:26 [PATCH] gitweb: Better symbolic link support in "tree" view Jakub Narebsmi
2006-12-05  1:08 ` Junio C Hamano
2006-12-05 21:27   ` Jakub Narebski
2006-12-05 22:34     ` Junio C Hamano
2006-12-05 23:06       ` Jakub Narebski
2006-12-10 12:25       ` [PATCH 0/3] " Jakub Narebski
2006-12-10 12:25       ` Jakub Narebski
2006-12-10 12:25       ` [PATCH 1/3] gitweb: Show target of symbolic link " Jakub Narebski
2006-12-10 12:25       ` [PATCH 2/3] gitweb: Add generic git_object subroutine to display object of any type Jakub Narebski
2006-12-10 12:25       ` [PATCH 3/3] gitweb: Hyperlink target of symbolic link in "tree" view (if possible) Jakub Narebski
2006-12-10 12:25       ` [PATCH/RFC 4/3] gitweb: SHA-1 in commit log message links to "object" view Jakub Narebski
2006-12-10 21:29         ` Junio C Hamano

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).