repobrowse 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitattributes +5 -0
- data/.gitignore +3 -0
- data/COPYING +661 -0
- data/GNUmakefile +38 -0
- data/MANIFEST +42 -0
- data/README +35 -0
- data/lib/repobrowse.rb +7 -0
- data/lib/repobrowse/app.rb +60 -0
- data/lib/repobrowse/config.rb +66 -0
- data/lib/repobrowse/error.rb +21 -0
- data/lib/repobrowse/escape.rb +28 -0
- data/lib/repobrowse/git.rb +71 -0
- data/lib/repobrowse/git_atom.rb +109 -0
- data/lib/repobrowse/git_commit_html.rb +320 -0
- data/lib/repobrowse/git_disambiguate.rb +21 -0
- data/lib/repobrowse/git_http_backend.rb +109 -0
- data/lib/repobrowse/git_log.rb +4 -0
- data/lib/repobrowse/git_patch.rb +55 -0
- data/lib/repobrowse/git_raw.rb +50 -0
- data/lib/repobrowse/git_raw_tree_html.rb +50 -0
- data/lib/repobrowse/git_show.rb +32 -0
- data/lib/repobrowse/git_src.rb +37 -0
- data/lib/repobrowse/git_src_blob_html.rb +89 -0
- data/lib/repobrowse/git_src_tree_html.rb +118 -0
- data/lib/repobrowse/html.rb +66 -0
- data/lib/repobrowse/limit_rd.rb +86 -0
- data/lib/repobrowse/pipe_body.rb +25 -0
- data/lib/repobrowse/repo.rb +21 -0
- data/lib/repobrowse/static.rb +96 -0
- data/repobrowse.gemspec +29 -0
- data/test/covshow.rb +30 -0
- data/test/git.fast-import-data +101 -0
- data/test/helper.rb +182 -0
- data/test/test_config.rb +29 -0
- data/test/test_git.rb +15 -0
- data/test/test_git_atom.rb +27 -0
- data/test/test_git_clone.rb +73 -0
- data/test/test_git_patch.rb +44 -0
- data/test/test_git_raw_tree_html.rb +34 -0
- data/test/test_git_show.rb +17 -0
- data/test/test_html.rb +23 -0
- metadata +139 -0
data/GNUmakefile
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Copyright (C) 2013-2018 all contributors <repobrowse-public@80x24.org>
|
|
2
|
+
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
|
|
3
|
+
all::
|
|
4
|
+
rubybin := $(shell which ruby)
|
|
5
|
+
RUBY = $(rubybin)
|
|
6
|
+
lib := lib
|
|
7
|
+
|
|
8
|
+
# support using eatmydata to speed up tests (apt-get install eatmydata):
|
|
9
|
+
# https://www.flamingspork.com/projects/libeatmydata/
|
|
10
|
+
EATMYDATA =
|
|
11
|
+
-include config.mak
|
|
12
|
+
|
|
13
|
+
ifeq ($(RUBY_TEST_OPTS),)
|
|
14
|
+
ifeq ($(V),1)
|
|
15
|
+
RUBY_TEST_OPTS := -v
|
|
16
|
+
endif
|
|
17
|
+
endif
|
|
18
|
+
|
|
19
|
+
all:: test
|
|
20
|
+
test_units := $(wildcard test/test_*.rb)
|
|
21
|
+
test: $(test_units)
|
|
22
|
+
$(test_units):
|
|
23
|
+
$(EATMYDATA) $(RUBY) -w -I $(lib) $@ $(RUBY_TEST_OPTS)
|
|
24
|
+
|
|
25
|
+
check-warnings:
|
|
26
|
+
@(for i in $$(git ls-files '*.rb'| grep -v '^setup\.rb$$'); \
|
|
27
|
+
do $(RUBY) -d -W2 -c $$i; done) | grep -v '^Syntax OK$$' || :
|
|
28
|
+
|
|
29
|
+
check: test
|
|
30
|
+
|
|
31
|
+
coverage: export COVERAGE=1
|
|
32
|
+
coverage:
|
|
33
|
+
>coverage.dump
|
|
34
|
+
$(MAKE) check
|
|
35
|
+
$(RUBY) ./test/covshow.rb
|
|
36
|
+
|
|
37
|
+
.PHONY: all test $(test_units) NEWS
|
|
38
|
+
.PHONY: check-warnings fix-perms
|
data/MANIFEST
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
.gitattributes
|
|
2
|
+
.gitignore
|
|
3
|
+
COPYING
|
|
4
|
+
GNUmakefile
|
|
5
|
+
MANIFEST
|
|
6
|
+
README
|
|
7
|
+
TODO
|
|
8
|
+
lib/repobrowse.rb
|
|
9
|
+
lib/repobrowse/app.rb
|
|
10
|
+
lib/repobrowse/config.rb
|
|
11
|
+
lib/repobrowse/error.rb
|
|
12
|
+
lib/repobrowse/escape.rb
|
|
13
|
+
lib/repobrowse/git.rb
|
|
14
|
+
lib/repobrowse/git_atom.rb
|
|
15
|
+
lib/repobrowse/git_commit_html.rb
|
|
16
|
+
lib/repobrowse/git_disambiguate.rb
|
|
17
|
+
lib/repobrowse/git_http_backend.rb
|
|
18
|
+
lib/repobrowse/git_log.rb
|
|
19
|
+
lib/repobrowse/git_patch.rb
|
|
20
|
+
lib/repobrowse/git_raw.rb
|
|
21
|
+
lib/repobrowse/git_raw_tree_html.rb
|
|
22
|
+
lib/repobrowse/git_show.rb
|
|
23
|
+
lib/repobrowse/git_src.rb
|
|
24
|
+
lib/repobrowse/git_src_blob_html.rb
|
|
25
|
+
lib/repobrowse/git_src_tree_html.rb
|
|
26
|
+
lib/repobrowse/html.rb
|
|
27
|
+
lib/repobrowse/limit_rd.rb
|
|
28
|
+
lib/repobrowse/pipe_body.rb
|
|
29
|
+
lib/repobrowse/repo.rb
|
|
30
|
+
lib/repobrowse/static.rb
|
|
31
|
+
repobrowse.gemspec
|
|
32
|
+
test/covshow.rb
|
|
33
|
+
test/git.fast-import-data
|
|
34
|
+
test/helper.rb
|
|
35
|
+
test/test_config.rb
|
|
36
|
+
test/test_git.rb
|
|
37
|
+
test/test_git_atom.rb
|
|
38
|
+
test/test_git_clone.rb
|
|
39
|
+
test/test_git_patch.rb
|
|
40
|
+
test/test_git_raw_tree_html.rb
|
|
41
|
+
test/test_git_show.rb
|
|
42
|
+
test/test_html.rb
|
data/README
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
repobrowse - old-fashioned repository browser
|
|
2
|
+
---------------------------------------------
|
|
3
|
+
|
|
4
|
+
A repository browser with only basic HTML and text; free of
|
|
5
|
+
images and JavaScript. It is intended as a companion to
|
|
6
|
+
public-inbox[1] but may be used on its own. It only supports
|
|
7
|
+
git for now, but support for other Free Software version control
|
|
8
|
+
systems may happen.
|
|
9
|
+
|
|
10
|
+
Features
|
|
11
|
+
--------
|
|
12
|
+
|
|
13
|
+
* low bandwidth usage
|
|
14
|
+
* git smart HTTP clone/fetch support
|
|
15
|
+
* optional public-inbox integration
|
|
16
|
+
|
|
17
|
+
[1] public-inbox is an "archives first" approach to mailing lists
|
|
18
|
+
https://public-inbox.org/
|
|
19
|
+
|
|
20
|
+
Contact
|
|
21
|
+
-------
|
|
22
|
+
|
|
23
|
+
All discussion is archived via public-inbox:
|
|
24
|
+
|
|
25
|
+
https://80x24.org/repobrowse-public/
|
|
26
|
+
nntp://80x24.org/inbox.comp.version-control.repobrowse
|
|
27
|
+
|
|
28
|
+
No subscription will ever be required to mail us, but HTML mail
|
|
29
|
+
will be rejected:
|
|
30
|
+
|
|
31
|
+
repobrowse-public@80x24.org
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
repobrowse is Copyright (C) 2018 all contributors <repobrowse-public@80x24.org>
|
|
35
|
+
License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
|
data/lib/repobrowse.rb
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# -*- encoding: binary -*-
|
|
2
|
+
# Copyright (C) 2017-2018 all contributors <repobrowse-public@80x24.org>
|
|
3
|
+
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
|
|
4
|
+
# frozen_string_literal: true
|
|
5
|
+
|
|
6
|
+
Repobrowse = Module.new # :nodoc:
|
|
7
|
+
require_relative 'repobrowse/app'
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# -*- encoding: binary -*-
|
|
2
|
+
# Copyright (C) 2017-2018 all contributors <repobrowse-public@80x24.org>
|
|
3
|
+
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
|
|
4
|
+
# frozen_string_literal: true
|
|
5
|
+
require_relative 'error'
|
|
6
|
+
require_relative 'static'
|
|
7
|
+
require_relative 'git_http_backend'
|
|
8
|
+
require_relative 'config'
|
|
9
|
+
require 'roda'
|
|
10
|
+
|
|
11
|
+
module Repobrowse::App
|
|
12
|
+
|
|
13
|
+
# main entry point for rackup config.ru files
|
|
14
|
+
def self.new(config)
|
|
15
|
+
case config
|
|
16
|
+
when Hash, String, nil
|
|
17
|
+
config = Repobrowse::Config.new(config)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# allow multiple instances of our app:
|
|
21
|
+
c = Class.new(Roda)
|
|
22
|
+
c.class_eval do
|
|
23
|
+
include Repobrowse::Error
|
|
24
|
+
include Repobrowse::Static
|
|
25
|
+
include Repobrowse::GitHTTPBackend
|
|
26
|
+
plugin :symbol_matchers
|
|
27
|
+
plugin :streaming
|
|
28
|
+
plugin :head
|
|
29
|
+
|
|
30
|
+
symbol_matcher :git_pack, %r{(pack-[a-f0-9]{40,}\.pack)}
|
|
31
|
+
symbol_matcher :git_pack_idx, %r{(pack-[a-f0-9]{40,}\.idx)}
|
|
32
|
+
symbol_matcher :git_x2, %r{([a-f0-9]{2})}
|
|
33
|
+
symbol_matcher :git_x38, %r{([a-f0-9]{38,})}
|
|
34
|
+
symbol_matcher :patch, %r{([a-f0-9]{7,})\.patch}
|
|
35
|
+
symbol_matcher :show, %r{([a-f0-9]{7,})}
|
|
36
|
+
symbol_matcher :tree_path, %r{([^:]+)(?::(.+))?}
|
|
37
|
+
|
|
38
|
+
route do |r|
|
|
39
|
+
config.repos.each_value do |repo|
|
|
40
|
+
r.on(repo.name) do
|
|
41
|
+
git_http_backend_routes(r, repo)
|
|
42
|
+
r.is { r.get { repo.driver.summary(r, repo) } }
|
|
43
|
+
r.is('src', :tree_path) { |ref, path|
|
|
44
|
+
r.get { repo.driver.src(r, repo, ref, path) }
|
|
45
|
+
}
|
|
46
|
+
r.is('raw', :tree_path) { |ref, path|
|
|
47
|
+
r.get { repo.driver.raw(r, repo, ref, path) }
|
|
48
|
+
}
|
|
49
|
+
r.is(:show) { |x| r.get { repo.driver.show(r, repo, x) } }
|
|
50
|
+
r.is(:patch) { |x| r.get { repo.driver.patch(r, repo, x) } }
|
|
51
|
+
r.is('atom', :tree_path) { |ref, path|
|
|
52
|
+
r.get { repo.driver.atom(r, repo, ref, path) }
|
|
53
|
+
}
|
|
54
|
+
end # r.on
|
|
55
|
+
end # projects.each
|
|
56
|
+
end # ret.route
|
|
57
|
+
end
|
|
58
|
+
c.freeze.app
|
|
59
|
+
end # self.new
|
|
60
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# -*- encoding: binary -*-
|
|
2
|
+
# Copyright (C) 2017-2018 all contributors <repobrowse-public@80x24.org>
|
|
3
|
+
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
|
|
4
|
+
# frozen_string_literal: true
|
|
5
|
+
require_relative 'repo'
|
|
6
|
+
require_relative 'git'
|
|
7
|
+
|
|
8
|
+
class Repobrowse::Config
|
|
9
|
+
attr_reader :repos
|
|
10
|
+
|
|
11
|
+
def initialize(file = ENV['REPOBROWSE_CONFIG'] ||
|
|
12
|
+
File.expand_path('~/.repobrowse/config'))
|
|
13
|
+
@groups = Hash.new { |h,k| h[k] = [] }
|
|
14
|
+
if Hash === file
|
|
15
|
+
raw = file
|
|
16
|
+
else
|
|
17
|
+
raw = {}
|
|
18
|
+
if File.exist?(file)
|
|
19
|
+
cfg = Rugged::Config.new(file)
|
|
20
|
+
cfg.each_key { |k| raw[-k] = cfg.get_all(k) }
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
raw[:snapshots] ||= '-tar.bz2 -tar.xz'
|
|
24
|
+
raw[:groups] = { hidden: [], none: [] }
|
|
25
|
+
@raw = raw
|
|
26
|
+
@repos = {}
|
|
27
|
+
raw.each do |k, v|
|
|
28
|
+
v = Array(v)
|
|
29
|
+
case k
|
|
30
|
+
when %r{\Arepo\.(.+)\.path\z}
|
|
31
|
+
repo_name = -$1
|
|
32
|
+
warn "multiple values defined for #{k.inspect}\n" if v.size > 1
|
|
33
|
+
path = v[-1]
|
|
34
|
+
add_repo(repo_name, path)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def add_repo(repo_name, path) # repo_name "git.git"
|
|
40
|
+
rv = { path: path, name: repo_name }
|
|
41
|
+
rv[:snapshot_pfx] = -path.split(%r{/+})[-1].chomp('.git')
|
|
42
|
+
%i[ vcs readme group snapshots ].each do |key|
|
|
43
|
+
rv[key] = @raw["repo.#{repo_name}.#{key}"]
|
|
44
|
+
end
|
|
45
|
+
rv[:snapshots] ||= @raw[:snapshots]
|
|
46
|
+
rv[:snapshots_disabled] = disabled = {}
|
|
47
|
+
rv[:snapshots].split(/\s+/n).each do |type|
|
|
48
|
+
# "-tar.bz2", "-" prefix denotes disabled
|
|
49
|
+
type.sub!(/\A-/, '') and
|
|
50
|
+
disabled[type] = true
|
|
51
|
+
end
|
|
52
|
+
group = rv[:group] ||= :none
|
|
53
|
+
case group
|
|
54
|
+
when Array
|
|
55
|
+
Array(group).each { |g| @groups[g] << repo_name }
|
|
56
|
+
else
|
|
57
|
+
@groups[group] << repo_name
|
|
58
|
+
end
|
|
59
|
+
snap = repo_name.split('/')[-1]
|
|
60
|
+
if (rv[:vcs] ||= 'git') == 'git'
|
|
61
|
+
snap.chomp!('.git') # seems common for git URLs to end in ".git"
|
|
62
|
+
end
|
|
63
|
+
rv[:snapshot_re] = %r{\A\Q#{Regexp.escape(snap)}[-_]}
|
|
64
|
+
@repos[repo_name] = Repobrowse::Repo.new(rv)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# -*- encoding: binary -*-
|
|
2
|
+
# Copyright (C) 2017-2018 all contributors <repobrowse-public@80x24.org>
|
|
3
|
+
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
|
|
4
|
+
# frozen_string_literal: true
|
|
5
|
+
|
|
6
|
+
module Repobrowse::Error
|
|
7
|
+
def r_err(r, msg)
|
|
8
|
+
r.env['rack.logger']&.error(msg)
|
|
9
|
+
b = "Internal server error\n"
|
|
10
|
+
r.halt [ 500, { 'Content-Type' => 'text/plain; charset=UTF-8' }, [ b ] ]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def r404(r)
|
|
14
|
+
b = "Not Found\n"
|
|
15
|
+
h = {
|
|
16
|
+
'Content-Type' => -'text/plain; charset=UTF-8',
|
|
17
|
+
'Content-Length' => -(b.size.to_s),
|
|
18
|
+
}
|
|
19
|
+
r.halt [ 404, h, [ b ] ]
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# -*- encoding: binary -*-
|
|
2
|
+
# Copyright (C) 2017-2018 all contributors <repobrowse-public@80x24.org>
|
|
3
|
+
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
|
|
4
|
+
# frozen_string_literal: true
|
|
5
|
+
require 'cgi'
|
|
6
|
+
|
|
7
|
+
module Repobrowse::Escape
|
|
8
|
+
# like format_sanitized_subject in git.git pretty.c with '%f' format string
|
|
9
|
+
def to_filename(str)
|
|
10
|
+
str = str.sub(/\n.*\z/s, '')
|
|
11
|
+
str.gsub!(/[^A-Za-z0-9_\.]+/, '-')
|
|
12
|
+
str.squeeze!('.')
|
|
13
|
+
str.sub!(/[\.\-]+\z/, '')
|
|
14
|
+
str.sub!(/\A[\.\-]+/, '')
|
|
15
|
+
str
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def xt(str)
|
|
19
|
+
str.encode!(xml: :text)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def xa(str)
|
|
23
|
+
str.encode!(xml: :attr)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
alias ha xa
|
|
27
|
+
alias ht xt
|
|
28
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# -*- encoding: binary -*-
|
|
2
|
+
# Copyright (C) 2017-2018 all contributors <repobrowse-public@80x24.org>
|
|
3
|
+
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
|
|
4
|
+
# frozen_string_literal: true
|
|
5
|
+
#
|
|
6
|
+
require_relative 'git_show'
|
|
7
|
+
require_relative 'git_patch'
|
|
8
|
+
require_relative 'git_raw'
|
|
9
|
+
require_relative 'git_src'
|
|
10
|
+
require_relative 'git_atom'
|
|
11
|
+
require 'rugged'
|
|
12
|
+
|
|
13
|
+
class Repobrowse::Git
|
|
14
|
+
GIT_ESC = {
|
|
15
|
+
'\\a' => "\a",
|
|
16
|
+
'\\b' => "\b",
|
|
17
|
+
'\\f' => "\f",
|
|
18
|
+
'\\n' => "\n",
|
|
19
|
+
'\\r' => "\r",
|
|
20
|
+
'\\t' => "\t",
|
|
21
|
+
'\\v' => "\013",
|
|
22
|
+
}.freeze
|
|
23
|
+
|
|
24
|
+
def initialize(git_dir)
|
|
25
|
+
@git_dir = -git_dir
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def rugged
|
|
29
|
+
Thread.current["rgd.#@git_dir".to_sym] ||= Rugged::Repository.new(@git_dir)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def description
|
|
33
|
+
s = File.open("#@git_dir/description", &:read)
|
|
34
|
+
s.strip!
|
|
35
|
+
-s
|
|
36
|
+
rescue
|
|
37
|
+
'[error reading $GIT_DIR/description]'
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def cloneurl
|
|
41
|
+
File.open("#@git_dir/cloneurl", &:readlines).map! { |s| s.strip!; -s }
|
|
42
|
+
rescue
|
|
43
|
+
'[error reading $GIT_DIR/cloneurl]'
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def popen(argv, encoding: Encoding::ASCII_8BIT)
|
|
47
|
+
cmd = %w(git).concat(argv)
|
|
48
|
+
IO.popen(cmd, chdir: @git_dir, encoding: encoding)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def tip
|
|
52
|
+
rugged.head.name
|
|
53
|
+
rescue
|
|
54
|
+
'[error running git symbolic-ref --short HEAD]'
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def git_unquote(s)
|
|
58
|
+
return s unless s =~ /\A"(.*)"\z/n
|
|
59
|
+
s = $1
|
|
60
|
+
s.gsub!(/\\[abfnrtv]/n, GIT_ESC)
|
|
61
|
+
s.gsub!(/\\([0-7]{1,3})/n) { $1.oct.chr }
|
|
62
|
+
s
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
include Repobrowse::Error
|
|
66
|
+
include Repobrowse::GitShow
|
|
67
|
+
include Repobrowse::GitPatch
|
|
68
|
+
include Repobrowse::GitRaw
|
|
69
|
+
include Repobrowse::GitAtom
|
|
70
|
+
include Repobrowse::GitSrc
|
|
71
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# -*- encoding: binary -*-
|
|
2
|
+
# Copyright (C) 2017-2018 all contributors <repobrowse-public@80x24.org>
|
|
3
|
+
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
|
|
4
|
+
# frozen_string_literal: true
|
|
5
|
+
|
|
6
|
+
module Repobrowse::GitAtom
|
|
7
|
+
DATEFMT = '%Y-%m-%dT%H:%M:%SZ'
|
|
8
|
+
|
|
9
|
+
# running git-log(1) here for now, path-limiting with libgit2|rugged
|
|
10
|
+
# seems like a pain to implement
|
|
11
|
+
ATOM_ARGV = %W(log --no-notes --no-color --no-abbrev --encoding=UTF-8
|
|
12
|
+
--pretty=tformat:%#{%w(H s ct an ae at b).join('%n%')}%x00)
|
|
13
|
+
|
|
14
|
+
class Body
|
|
15
|
+
include Repobrowse::Error
|
|
16
|
+
include Repobrowse::Escape
|
|
17
|
+
|
|
18
|
+
def initialize(rd, r, repo, ref, path)
|
|
19
|
+
@rd = rd
|
|
20
|
+
title = xt(+"#{repo.name} #{ref} #{path || '/'}")
|
|
21
|
+
subtitle = xt(repo.driver.description.dup)
|
|
22
|
+
@url = "#{r.base_url}#{r.script_name}/#{repo.name}"
|
|
23
|
+
# read the first entry to ensure we have something
|
|
24
|
+
updated = +''
|
|
25
|
+
tmp = entry_begin(updated) or r404(r)
|
|
26
|
+
|
|
27
|
+
@buf = +<<~EOF
|
|
28
|
+
<?xml version="1.0"?><feed
|
|
29
|
+
xmlns="http://www.w3.org/2005/Atom"><title>#{
|
|
30
|
+
title}</title><subtitle>#{
|
|
31
|
+
subtitle}</subtitle><link
|
|
32
|
+
rel="alternate"
|
|
33
|
+
type="text/html"
|
|
34
|
+
href=#{xa(@url.dup)}
|
|
35
|
+
/><id>#{
|
|
36
|
+
xt("#@url/log/" + ref)
|
|
37
|
+
}</id><updated>#{updated}</updated>
|
|
38
|
+
EOF
|
|
39
|
+
|
|
40
|
+
@buf << tmp
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def entry_begin(updated = +'')
|
|
44
|
+
x40 = @rd.gets(chomp: true) or return
|
|
45
|
+
+<<~EOF
|
|
46
|
+
<entry><title>#{ # %s
|
|
47
|
+
xt(@rd.gets(chomp: true))
|
|
48
|
+
}</title><updated>#{ # %ct
|
|
49
|
+
updated.replace(Time.at(@rd.gets.to_i).strftime(DATEFMT))
|
|
50
|
+
}</updated><author><name>#{ # %an
|
|
51
|
+
xt(@rd.gets(chomp: true))
|
|
52
|
+
}</name><email>#{ # %ae
|
|
53
|
+
xt(@rd.gets(chomp: true))
|
|
54
|
+
}</email></author><published>#{ # %at
|
|
55
|
+
Time.at(@rd.gets.to_i).strftime(DATEFMT)
|
|
56
|
+
}</published><link
|
|
57
|
+
rel="alternate"
|
|
58
|
+
type="text/html"
|
|
59
|
+
href=#{xa("#@url/" + x40)
|
|
60
|
+
}/><id>#{x40}</id><content
|
|
61
|
+
type="xhtml"><div
|
|
62
|
+
xmlns="http://www.w3.org/1999/xhtml"><pre
|
|
63
|
+
style="white-space:pre-wrap">
|
|
64
|
+
EOF
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def entry_body
|
|
68
|
+
tmp = @rd.gets("\0\n", chomp: true)
|
|
69
|
+
tmp.strip!
|
|
70
|
+
xt(tmp)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def each
|
|
74
|
+
entry_end = '</pre></div></content></entry>'
|
|
75
|
+
tmp = @buf
|
|
76
|
+
@buf = nil
|
|
77
|
+
yield tmp
|
|
78
|
+
tmp.clear
|
|
79
|
+
tmp = entry_body
|
|
80
|
+
yield tmp
|
|
81
|
+
tmp.clear
|
|
82
|
+
yield entry_end
|
|
83
|
+
while tmp = entry_begin
|
|
84
|
+
yield tmp
|
|
85
|
+
tmp.clear
|
|
86
|
+
tmp = entry_body
|
|
87
|
+
yield tmp
|
|
88
|
+
tmp.clear
|
|
89
|
+
yield entry_end
|
|
90
|
+
end
|
|
91
|
+
yield '</feed>'
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def close
|
|
95
|
+
@rd.close
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# /$REPO_NAME/atom/$REF:PATH
|
|
100
|
+
def atom(r, repo, ref, path)
|
|
101
|
+
git_disambiguate(r, repo, 'atom', ref, path)
|
|
102
|
+
max = 50
|
|
103
|
+
argv = [ *ATOM_ARGV, *%W(-#{max} #{ref} --) ]
|
|
104
|
+
argv << path if path
|
|
105
|
+
rd = repo.driver.popen(argv)
|
|
106
|
+
body = Body.new(rd, r, repo, ref, path)
|
|
107
|
+
r.halt([ 200, { 'Content-Type' => 'application/atom+xml' }, body ])
|
|
108
|
+
end
|
|
109
|
+
end
|