Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
O
OHR Support
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
97
Issues
97
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
OHR Support
Commits
21ae869d
Commit
21ae869d
authored
Apr 20, 2012
by
Enrique García Cota
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
increased scm file download in scm views
parent
c4f80d5e
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
395 additions
and
361 deletions
+395
-361
repositories_controller.rb
app/controllers/repositories_controller.rb
+38
-31
repository.rb
app/models/repository.rb
+4
-0
abstract_adapter.rb
lib/redmine/scm/adapters/abstract_adapter.rb
+52
-17
bazaar_adapter.rb
lib/redmine/scm/adapters/bazaar_adapter.rb
+1
-1
cvs_adapter.rb
lib/redmine/scm/adapters/cvs_adapter.rb
+1
-1
darcs_adapter.rb
lib/redmine/scm/adapters/darcs_adapter.rb
+1
-1
filesystem_adapter.rb
lib/redmine/scm/adapters/filesystem_adapter.rb
+9
-1
git_adapter.rb
lib/redmine/scm/adapters/git_adapter.rb
+73
-79
mercurial_adapter.rb
lib/redmine/scm/adapters/mercurial_adapter.rb
+122
-120
subversion_adapter.rb
lib/redmine/scm/adapters/subversion_adapter.rb
+94
-110
No files found.
app/controllers/repositories_controller.rb
View file @
21ae869d
...
@@ -118,41 +118,48 @@ class RepositoriesController < ApplicationController
...
@@ -118,41 +118,48 @@ class RepositoriesController < ApplicationController
# If the entry is a dir, show the browser
# If the entry is a dir, show the browser
(
show
;
return
)
if
@entry
.
is_dir?
(
show
;
return
)
if
@entry
.
is_dir?
@content
=
@repository
.
cat
(
@path
,
@rev
)
@repository
.
cat_to_tempfile
(
@path
,
@rev
)
do
|
f
|
(
show_error_not_found
;
return
)
unless
@content
if
params
[
:format
]
==
'raw'
||
is_too_large_to_show?
(
f
)
||
is_binary?
(
f
,
@path
)
if
'raw'
==
params
[
:format
]
||
send_type
=
Redmine
::
MimeType
.
of
(
@path
)
(
@content
.
size
&&
@content
.
size
>
Setting
.
file_max_size_displayed
.
to_i
.
kilobyte
)
||
options
=
{
!
is_entry_text_data?
(
@content
,
@path
)
:filename
=>
filename_for_content_disposition
(
@path
.
split
(
'/'
).
last
),
# Force the download
:disposition
=>
'attachment'
,
send_opt
=
{
:filename
=>
filename_for_content_disposition
(
@path
.
split
(
'/'
).
last
)
}
:x_sendfile
=>
false
# x_sendfile does not work well with tempfiles
send_type
=
Redmine
::
MimeType
.
of
(
@path
)
}
send_opt
[
:type
]
=
send_type
.
to_s
if
send_type
options
[
:type
]
=
send_type
.
to_s
if
send_type
send_data
@content
,
send_opt
send_file
(
f
.
path
,
options
)
else
else
# Prevent empty lines when displaying a file with Windows style eol
@content
=
f
.
read
# TODO: UTF-16
@changeset
=
@repository
.
find_changeset_by_name
(
@rev
)
# Is this needs? AttachmentsController reads file simply.
end
@content
.
gsub!
(
"
\r\n
"
,
"
\n
"
)
@changeset
=
@repository
.
find_changeset_by_name
(
@rev
)
end
end
rescue
Errno
::
ENOENT
show_error_not_found
end
end
def
is_entry_text_data?
(
ent
,
path
)
def
is_too_large_to_show?
(
f
)
# UTF-16 contains "\x00".
f
.
size
>
Setting
.
file_max_size_displayed
.
to_i
.
kilobyte
# It is very strict that file contains less than 30% of ascii symbols
end
# in non Western Europe.
private
:is_too_large_to_show?
return
true
if
Redmine
::
MimeType
.
is_type?
(
'text'
,
path
)
# Ruby 1.8.6 has a bug of integer divisions.
def
is_binary?
(
file
,
path
)
# http://apidock.com/ruby/v1_8_6_287/String/is_binary_data%3F
if
ent
.
respond_to?
(
"is_binary_data?"
)
&&
ent
.
is_binary_data?
# Ruby 1.8.x and <1.9.2
return
false
if
Redmine
::
MimeType
.
is_type?
(
'text'
,
path
)
return
false
elsif
ent
.
respond_to?
(
:force_encoding
)
&&
(
ent
.
dup
.
force_encoding
(
"UTF-8"
)
!=
ent
.
dup
.
force_encoding
(
"BINARY"
)
)
# Ruby 1.9.2
# First block of the file is examined for odd
# TODO: need to handle edge cases of non-binary content that isn't UTF-8
# characters such as strange control codes or char-
return
false
# acters with the high bit set. If too many strange
end
# characters (>30%) are found, it's a binary file,
true
# otherwise it's a text file. Also, any file con-
# taining null in the first block is considered a
# binary file.
blk
=
file
.
read
(
Setting
.
file_max_size_displayed
.
to_i
.
kilobyte
)
return
blk
.
size
==
0
||
blk
.
count
(
"^ -~"
,
"^
\r\n
"
)
/
blk
.
size
>
0.3
||
blk
.
count
(
"
\x00
"
)
>
0
end
end
private
:is_
entry_text_data
?
private
:is_
binary
?
def
annotate
def
annotate
@entry
=
@repository
.
entry
(
@path
,
@rev
)
@entry
=
@repository
.
entry
(
@path
,
@rev
)
...
...
app/models/repository.rb
View file @
21ae869d
...
@@ -104,6 +104,10 @@ class Repository < ActiveRecord::Base
...
@@ -104,6 +104,10 @@ class Repository < ActiveRecord::Base
scm
.
cat
(
path
,
identifier
)
scm
.
cat
(
path
,
identifier
)
end
end
def
cat_to_tempfile
(
path
,
identifier
,
&
block
)
scm
.
cat_to_tempfile
(
path
,
identifier
,
&
block
)
end
def
diff
(
path
,
rev
,
rev_to
)
def
diff
(
path
,
rev
,
rev_to
)
scm
.
diff
(
path
,
rev
,
rev_to
)
scm
.
diff
(
path
,
rev
,
rev_to
)
end
end
...
...
lib/redmine/scm/adapters/abstract_adapter.rb
View file @
21ae869d
...
@@ -69,7 +69,7 @@ module Redmine
...
@@ -69,7 +69,7 @@ module Redmine
end
end
def
adapter_name
def
adapter_name
'Abstract'
self
.
class
.
name
.
gsub
(
"Adapter"
,
""
)
end
end
def
supports_cat?
def
supports_cat?
...
@@ -143,6 +143,19 @@ module Redmine
...
@@ -143,6 +143,19 @@ module Redmine
return
nil
return
nil
end
end
def
cat_to_tempfile
(
path
,
identifier
,
&
block
)
prefix
=
path
.
split
(
"/"
).
last
tmp_path
=
Rails
.
root
.
join
(
'tmp'
)
Tempfile
.
open
(
prefix
,
tmp_path
)
do
|
f
|
save_entry_in_file
(
f
,
path
,
identifier
)
block
.
call
(
f
)
end
end
def
save_entry_in_file
(
file
,
path
,
identifier
)
return
nil
end
def
with_leading_slash
(
path
)
def
with_leading_slash
(
path
)
path
||=
''
path
||=
''
(
path
[
0
,
1
]
!=
"/"
)
?
"/
#{
path
}
"
:
path
(
path
[
0
,
1
]
!=
"/"
)
?
"/
#{
path
}
"
:
path
...
@@ -183,34 +196,56 @@ module Redmine
...
@@ -183,34 +196,56 @@ module Redmine
self
.
class
.
logger
self
.
class
.
logger
end
end
def
shellout
(
cmd
,
&
block
)
def
shellout
(
cmd
,
output_path
=
nil
,
&
block
)
self
.
class
.
shellout
(
cmd
,
&
block
)
self
.
class
.
shellout
(
cmd
,
output_path
,
&
block
)
end
def
build_scm_cmd
(
cmd_args
)
([
self
.
class
.
sq_bin
]
+
cmd_args
).
join
(
' '
)
end
def
scm_cmd
(
cmd_args
,
output_path
=
nil
,
&
block
)
cmd
=
build_scm_cmd
(
cmd_args
)
begin
ret
=
shellout
(
cmd
,
output_path
,
&
block
)
rescue
Exception
=>
e
msg
=
strip_credential
(
e
.
message
)
cmd
=
strip_credential
(
cmd
)
logger
.
error
(
"Error executing
#{
adapter_name
}
command [
#{
cmd
}
]:
#{
msg
}
"
)
end
return
nil
if
$?
&&
$?
.
exitstatus
!=
0
ret
end
end
def
self
.
logger
def
self
.
logger
RAILS_DEFAULT_LOGGER
RAILS_DEFAULT_LOGGER
end
end
def
self
.
shellout
(
cmd
,
&
block
)
def
self
.
process_cmd
(
cmd
,
output_path
)
logger
.
debug
"Shelling out:
#{
strip_credential
(
cmd
)
}
"
if
logger
&&
logger
.
debug?
cmd
=
Rails
.
env
==
'development'
?
"
#{
cmd
}
2>>
#{
RAILS_ROOT
}
/log/scm.stderr.log"
:
cmd
if
Rails
.
env
==
'development'
cmd
=
"
#{
cmd
}
>>
#{
output_path
}
"
if
output_path
.
present?
# Capture stderr when running in dev environment
cmd
cmd
=
"
#{
cmd
}
2>>
#{
RAILS_ROOT
}
/log/scm.stderr.log"
end
end
def
self
.
get_reading_mode_for_ruby_version
RUBY_VERSION
<
'1.9'
?
'r+'
:
'r+:ASCII-8BIT'
end
def
self
.
shellout
(
cmd
,
output_path
=
nil
,
&
block
)
logger
.
debug
(
"Shelling out:
#{
strip_credential
(
cmd
)
}
"
)
if
logger
&&
logger
.
respond_to?
(
:debug
)
cmd
=
process_cmd
(
cmd
,
output_path
)
mode
=
get_reading_mode_for_ruby_version
begin
begin
if
RUBY_VERSION
<
'1.9'
result
=
nil
mode
=
"r+"
else
mode
=
"r+:ASCII-8BIT"
end
IO
.
popen
(
cmd
,
mode
)
do
|
io
|
IO
.
popen
(
cmd
,
mode
)
do
|
io
|
io
.
close_write
io
.
close_write
block
.
call
(
io
)
if
block_given?
result
=
block
.
call
(
io
)
if
block_given?
end
end
result
rescue
Errno
::
ENOENT
=>
e
rescue
Errno
::
ENOENT
=>
e
msg
=
strip_credential
(
e
.
message
)
msg
=
strip_credential
(
e
.
message
)
# The command failed, log it and re-raise
cmd
=
strip_credential
(
cmd
)
logger
.
error
(
"SCM command failed, make sure that your SCM binary (eg. svn) is in PATH (
#{
ENV
[
'PATH'
]
}
):
#{
strip_credential
(
cmd
)
}
\n
with:
#{
msg
}
"
)
logger
.
error
(
"SCM command failed, make sure that your SCM binary (eg. svn) is in PATH (
#{
ENV
[
'PATH'
]
}
):
#{
cmd
}
\n
with:
#{
msg
}
"
)
raise
CommandFailed
.
new
(
msg
)
raise
CommandFailed
.
new
(
msg
)
end
end
end
end
...
...
lib/redmine/scm/adapters/bazaar_adapter.rb
View file @
21ae869d
...
@@ -12,7 +12,7 @@
...
@@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details.
# See doc/COPYRIGHT.rdoc for more details.
#++
#++
require
'redmine/scm/adapters/abstract_adapter'
require
_dependency
'redmine/scm/adapters/abstract_adapter'
module
Redmine
module
Redmine
module
Scm
module
Scm
...
...
lib/redmine/scm/adapters/cvs_adapter.rb
View file @
21ae869d
...
@@ -12,7 +12,7 @@
...
@@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details.
# See doc/COPYRIGHT.rdoc for more details.
#++
#++
require
'redmine/scm/adapters/abstract_adapter'
require
_dependency
'redmine/scm/adapters/abstract_adapter'
module
Redmine
module
Redmine
module
Scm
module
Scm
...
...
lib/redmine/scm/adapters/darcs_adapter.rb
View file @
21ae869d
...
@@ -12,7 +12,7 @@
...
@@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details.
# See doc/COPYRIGHT.rdoc for more details.
#++
#++
require
'redmine/scm/adapters/abstract_adapter'
require
_dependency
'redmine/scm/adapters/abstract_adapter'
require
'rexml/document'
require
'rexml/document'
module
Redmine
module
Redmine
...
...
lib/redmine/scm/adapters/filesystem_adapter.rb
View file @
21ae869d
...
@@ -12,7 +12,7 @@
...
@@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details.
# See doc/COPYRIGHT.rdoc for more details.
#++
#++
require
'redmine/scm/adapters/abstract_adapter'
require
_dependency
'redmine/scm/adapters/abstract_adapter'
require
'find'
require
'find'
module
Redmine
module
Redmine
...
@@ -91,6 +91,14 @@ module Redmine
...
@@ -91,6 +91,14 @@ module Redmine
raise
CommandFailed
.
new
(
err
.
message
)
raise
CommandFailed
.
new
(
err
.
message
)
end
end
def
save_entry_in_file
(
f
,
path
,
identifier
)
p
=
scm_iconv
(
@path_encoding
,
'UTF-8'
,
target
(
path
))
FileUtils
.
cp
(
p
,
f
.
path
)
rescue
=>
err
logger
.
error
"scm: filesystem: error:
#{
err
.
message
}
"
raise
CommandFailed
.
new
(
err
.
message
)
end
private
private
# AbstractAdapter::target is implicitly made to quote paths.
# AbstractAdapter::target is implicitly made to quote paths.
...
...
lib/redmine/scm/adapters/git_adapter.rb
View file @
21ae869d
...
@@ -12,7 +12,7 @@
...
@@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details.
# See doc/COPYRIGHT.rdoc for more details.
#++
#++
require
'redmine/scm/adapters/abstract_adapter'
require
_dependency
'redmine/scm/adapters/abstract_adapter'
module
Redmine
module
Redmine
module
Scm
module
Scm
...
@@ -24,9 +24,6 @@ module Redmine
...
@@ -24,9 +24,6 @@ module Redmine
# Git executable name
# Git executable name
GIT_BIN
=
Redmine
::
Configuration
[
'scm_git_command'
]
||
"git"
unless
defined?
(
GIT_BIN
)
GIT_BIN
=
Redmine
::
Configuration
[
'scm_git_command'
]
||
"git"
unless
defined?
(
GIT_BIN
)
# raised if scm command exited with error, e.g. unknown revision.
class
ScmCommandAborted
<
CommandFailed
;
end
class
<<
self
class
<<
self
def
client_command
def
client_command
@@bin
||=
GIT_BIN
@@bin
||=
GIT_BIN
...
@@ -75,26 +72,22 @@ module Redmine
...
@@ -75,26 +72,22 @@ module Redmine
def
branches
def
branches
return
@branches
if
@branches
return
@branches
if
@branches
@branches
=
[]
cmd_args
=
%w|branch --no-color|
cmd_args
=
%w|branch --no-color|
scm_cmd
(
*
cmd_args
)
do
|
io
|
scm_cmd
(
cmd_args
)
do
|
io
|
@branches
=
[]
io
.
each_line
do
|
line
|
io
.
each_line
do
|
line
|
@branches
<<
line
.
match
(
'\s*\*?\s*(.*)$'
)[
1
]
@branches
<<
line
.
match
(
'\s*\*?\s*(.*)$'
)[
1
]
end
end
@branches
.
sort!
end
end
@branches
.
sort!
rescue
ScmCommandAborted
nil
end
end
def
tags
def
tags
return
@tags
if
@tags
return
@tags
if
@tags
cmd_args
=
%w|tag|
cmd_args
=
%w|tag|
scm_cmd
(
*
cmd_args
)
do
|
io
|
scm_cmd
(
cmd_args
)
do
|
io
|
@tags
=
io
.
readlines
.
sort!
.
map
{
|
t
|
t
.
strip
}
@tags
=
io
.
readlines
.
sort!
.
map
{
|
t
|
t
.
strip
}
end
end
rescue
ScmCommandAborted
nil
end
end
def
default_branch
def
default_branch
...
@@ -106,11 +99,14 @@ module Redmine
...
@@ -106,11 +99,14 @@ module Redmine
def
entries
(
path
=
nil
,
identifier
=
nil
)
def
entries
(
path
=
nil
,
identifier
=
nil
)
path
||=
''
path
||=
''
p
=
scm_iconv
(
@path_encoding
,
'UTF-8'
,
path
)
p
=
scm_iconv
(
@path_encoding
,
'UTF-8'
,
path
)
entries
=
Entries
.
new
cmd_args
=
%w|ls-tree -l|
cmd_args
=
%w|ls-tree -l|
cmd_args
<<
"HEAD:
#{
p
}
"
if
identifier
.
nil?
cmd_args
<<
"HEAD:
#{
p
}
"
if
identifier
.
nil?
cmd_args
<<
"
#{
identifier
}
:
#{
p
}
"
if
identifier
cmd_args
<<
"
#{
identifier
}
:
#{
p
}
"
if
identifier
scm_cmd
(
*
cmd_args
)
do
|
io
|
scm_cmd
(
cmd_args
)
do
|
io
|
entries
=
Entries
.
new
io
.
each_line
do
|
line
|
io
.
each_line
do
|
line
|
e
=
line
.
chomp
.
to_s
e
=
line
.
chomp
.
to_s
if
e
=~
/^\d+\s+(\w+)\s+([0-9a-f]{40})\s+([0-9-]+)\t(.+)$/
if
e
=~
/^\d+\s+(\w+)\s+([0-9a-f]{40})\s+([0-9-]+)\t(.+)$/
...
@@ -124,18 +120,20 @@ module Redmine
...
@@ -124,18 +120,20 @@ module Redmine
full_path
=
p
.
empty?
?
name
:
"
#{
p
}
/
#{
name
}
"
full_path
=
p
.
empty?
?
name
:
"
#{
p
}
/
#{
name
}
"
n
=
scm_iconv
(
'UTF-8'
,
@path_encoding
,
name
)
n
=
scm_iconv
(
'UTF-8'
,
@path_encoding
,
name
)
full_p
=
scm_iconv
(
'UTF-8'
,
@path_encoding
,
full_path
)
full_p
=
scm_iconv
(
'UTF-8'
,
@path_encoding
,
full_path
)
entries
<<
Entry
.
new
({
:name
=>
n
,
:path
=>
full_p
,
unless
entries
.
detect
{
|
entry
|
entry
.
name
==
name
}
:kind
=>
(
type
==
"tree"
)
?
'dir'
:
'file'
,
entries
<<
Entry
.
new
({
:name
=>
n
,
:size
=>
(
type
==
"tree"
)
?
nil
:
size
,
:path
=>
full_p
,
:lastrev
=>
@flag_report_last_commit
?
lastrev
(
full_path
,
identifier
)
:
Revision
.
new
:kind
=>
(
type
==
"tree"
)
?
'dir'
:
'file'
,
})
unless
entries
.
detect
{
|
entry
|
entry
.
name
==
name
}
:size
=>
(
type
==
"tree"
)
?
nil
:
size
,
:lastrev
=>
@flag_report_last_commit
?
lastrev
(
full_path
,
identifier
)
:
Revision
.
new
})
end
end
end
end
end
entries
.
sort_by_name
end
end
entries
.
sort_by_name
rescue
ScmCommandAborted
nil
end
end
def
lastrev
(
path
,
rev
)
def
lastrev
(
path
,
rev
)
...
@@ -143,9 +141,9 @@ module Redmine
...
@@ -143,9 +141,9 @@ module Redmine
cmd_args
=
%w|log --no-color --encoding=UTF-8 --date=iso --pretty=fuller --no-merges -n 1|
cmd_args
=
%w|log --no-color --encoding=UTF-8 --date=iso --pretty=fuller --no-merges -n 1|
cmd_args
<<
rev
if
rev
cmd_args
<<
rev
if
rev
cmd_args
<<
"--"
<<
path
unless
path
.
empty?
cmd_args
<<
"--"
<<
path
unless
path
.
empty?
lines
=
[]
lines
=
scm_cmd
(
cmd_args
)
{
|
io
|
io
.
readlines
}
scm_cmd
(
*
cmd_args
)
{
|
io
|
lines
=
io
.
readlines
}
if
lines
begin
begin
id
=
lines
[
0
].
split
[
1
]
id
=
lines
[
0
].
split
[
1
]
author
=
lines
[
1
].
match
(
'Author:\s+(.*)$'
)[
1
]
author
=
lines
[
1
].
match
(
'Author:\s+(.*)$'
)[
1
]
time
=
Time
.
parse
(
lines
[
4
].
match
(
'CommitDate:\s+(.*)$'
)[
1
])
time
=
Time
.
parse
(
lines
[
4
].
match
(
'CommitDate:\s+(.*)$'
)[
1
])
...
@@ -157,17 +155,17 @@ module Redmine
...
@@ -157,17 +155,17 @@ module Redmine
:time
=>
time
,
:time
=>
time
,
:message
=>
nil
,
:message
=>
nil
,
:paths
=>
nil
:paths
=>
nil
})
})
rescue
NoMethodError
=>
e
rescue
NoMethodError
=>
e
logger
.
error
(
"The revision '
#{
path
}
' has a wrong format"
)
logger
.
error
(
"The revision '
#{
path
}
' has a wrong format"
)
return
nil
return
nil
end
end
end
rescue
ScmCommandAborted
nil
end
end
def
revisions
(
path
,
identifier_from
,
identifier_to
,
options
=
{})
def
revisions
(
path
,
identifier_from
,
identifier_to
,
options
=
{})
revisions
=
Revisions
.
new
revisions
=
Revisions
.
new
cmd_args
=
%w|log --no-color --encoding=UTF-8 --raw --date=iso --pretty=fuller|
cmd_args
=
%w|log --no-color --encoding=UTF-8 --raw --date=iso --pretty=fuller|
cmd_args
<<
"--reverse"
if
options
[
:reverse
]
cmd_args
<<
"--reverse"
if
options
[
:reverse
]
cmd_args
<<
"--all"
if
options
[
:all
]
cmd_args
<<
"--all"
if
options
[
:all
]
...
@@ -179,7 +177,7 @@ module Redmine
...
@@ -179,7 +177,7 @@ module Redmine
cmd_args
<<
"--since='
#{
options
[
:since
].
strftime
(
"%Y-%m-%d %H:%M:%S"
)
}
'"
if
options
[
:since
]
cmd_args
<<
"--since='
#{
options
[
:since
].
strftime
(
"%Y-%m-%d %H:%M:%S"
)
}
'"
if
options
[
:since
]
cmd_args
<<
"--"
<<
scm_iconv
(
@path_encoding
,
'UTF-8'
,
path
)
if
path
&&
!
path
.
empty?
cmd_args
<<
"--"
<<
scm_iconv
(
@path_encoding
,
'UTF-8'
,
path
)
if
path
&&
!
path
.
empty?
scm_cmd
*
cmd_args
do
|
io
|
scm_cmd
cmd_args
do
|
io
|
files
=
[]
files
=
[]
changeset
=
{}
changeset
=
{}
parsing_descr
=
0
#0: not parsing desc or files, 1: parsing desc, 2: parsing files
parsing_descr
=
0
#0: not parsing desc or files, 1: parsing desc, 2: parsing files
...
@@ -255,10 +253,9 @@ module Redmine
...
@@ -255,10 +253,9 @@ module Redmine
revisions
<<
revision
revisions
<<
revision
end
end
end
end
revisions
end
end
revisions
rescue
ScmCommandAborted
revisions
end
end
def
diff
(
path
,
identifier_from
,
identifier_to
=
nil
)
def
diff
(
path
,
identifier_from
,
identifier_to
=
nil
)
...
@@ -271,14 +268,12 @@ module Redmine
...
@@ -271,14 +268,12 @@ module Redmine
end
end
cmd_args
<<
"--"
<<
scm_iconv
(
@path_encoding
,
'UTF-8'
,
path
)
unless
path
.
empty?
cmd_args
<<
"--"
<<
scm_iconv
(
@path_encoding
,
'UTF-8'
,
path
)
unless
path
.
empty?
diff
=
[]
diff
=
[]
scm_cmd
*
cmd_args
do
|
io
|
scm_cmd
cmd_args
do
|
io
|
io
.
each_line
do
|
line
|
io
.
each_line
do
|
line
|
diff
<<
line
diff
<<
line
end
end
diff
end
end
diff
rescue
ScmCommandAborted
nil
end
end
def
annotate
(
path
,
identifier
=
nil
)
def
annotate
(
path
,
identifier
=
nil
)
...
@@ -286,34 +281,36 @@ module Redmine
...
@@ -286,34 +281,36 @@ module Redmine
cmd_args
=
%w|blame|
cmd_args
=
%w|blame|
cmd_args
<<
"-p"
<<
identifier
<<
"--"
<<
scm_iconv
(
@path_encoding
,
'UTF-8'
,
path
)
cmd_args
<<
"-p"
<<
identifier
<<
"--"
<<
scm_iconv
(
@path_encoding
,
'UTF-8'
,
path
)
blame
=
Annotate
.
new
blame
=
Annotate
.
new
content
=
nil
content
=
scm_cmd
(
cmd_args
)
do
|
io
|
scm_cmd
(
*
cmd_args
)
{
|
io
|
io
.
binmode
;
content
=
io
.
read
}
io
.
binmode
# git annotates binary files
io
.
read
if
content
.
respond_to?
(
"is_binary_data?"
)
&&
content
.
is_binary_data?
# Ruby 1.8.x and <1.9.2
return
nil
elsif
content
.
respond_to?
(
:force_encoding
)
&&
(
content
.
dup
.
force_encoding
(
"UTF-8"
)
!=
content
.
dup
.
force_encoding
(
"BINARY"
))
# Ruby 1.9.2
# TODO: need to handle edge cases of non-binary content that isn't UTF-8
return
nil
end
end
identifier
=
''
if
content
# git shows commit author on the first occurrence only
# git annotates binary files
authors_by_commit
=
{}
if
content
.
respond_to?
(
"is_binary_data?"
)
&&
content
.
is_binary_data?
# Ruby 1.8.x and <1.9.2
content
.
split
(
"
\n
"
).
each
do
|
line
|
return
nil
if
line
=~
/^([0-9a-f]{39,40})\s.*/
elsif
content
.
respond_to?
(
:force_encoding
)
&&
(
content
.
dup
.
force_encoding
(
"UTF-8"
)
!=
content
.
dup
.
force_encoding
(
"BINARY"
))
# Ruby 1.9.2
identifier
=
$1
# TODO: need to handle edge cases of non-binary content that isn't UTF-8
elsif
line
=~
/^author (.+)/
return
nil
authors_by_commit
[
identifier
]
=
$1
.
strip
end
elsif
line
=~
/^\t(.*)/
identifier
=
''
blame
.
add_line
(
$1
,
Revision
.
new
(
# git shows commit author on the first occurrence only
:identifier
=>
identifier
,
authors_by_commit
=
{}
:author
=>
authors_by_commit
[
identifier
]))
content
.
split
(
"
\n
"
).
each
do
|
line
|
identifier
=
''
if
line
=~
/^([0-9a-f]{39,40})\s.*/
author
=
''
identifier
=
$1
elsif
line
=~
/^author (.+)/
authors_by_commit
[
identifier
]
=
$1
.
strip
elsif
line
=~
/^\t(.*)/
blame
.
add_line
(
$1
,
Revision
.
new
(
:identifier
=>
identifier
,
:author
=>
authors_by_commit
[
identifier
]))
identifier
=
''
author
=
''
end
end
end
blame
end
end
blame
rescue
ScmCommandAborted
nil
end
end
def
cat
(
path
,
identifier
=
nil
)
def
cat
(
path
,
identifier
=
nil
)
...
@@ -322,14 +319,16 @@ module Redmine
...
@@ -322,14 +319,16 @@ module Redmine
end
end
cmd_args
=
%w|show --no-color|
cmd_args
=
%w|show --no-color|
cmd_args
<<
"
#{
identifier
}
:
#{
scm_iconv
(
@path_encoding
,
'UTF-8'
,
path
)
}
"
cmd_args
<<
"
#{
identifier
}
:
#{
scm_iconv
(
@path_encoding
,
'UTF-8'
,
path
)
}
"
cat
=
nil
scm_cmd
(
cmd_args
)
do
|
io
|
scm_cmd
(
*
cmd_args
)
do
|
io
|
io
.
binmode
io
.
binmode
cat
=
io
.
read
io
.
read
end
end
cat
end
rescue
ScmCommandAborted
nil
def
save_entry_in_file
(
f
,
path
,
identifier
)
cmd_args
=
%w|show --no-color|
cmd_args
<<
"
#{
identifier
}
:
#{
scm_iconv
(
@path_encoding
,
'UTF-8'
,
path
)
}
"
scm_cmd
(
cmd_args
,
f
.
path
)
end
end
class
Revision
<
Redmine
::
Scm
::
Adapters
::
Revision
class
Revision
<
Redmine
::
Scm
::
Adapters
::
Revision
...
@@ -339,20 +338,15 @@ module Redmine
...
@@ -339,20 +338,15 @@ module Redmine
end
end
end
end
def
scm_cmd
(
*
args
,
&
block
)
private
repo_path
=
root_url
||
url
# returns the string that will represent the command for shelling out
full_args
=
[
GIT_BIN
,
'--git-dir'
,
repo_path
]
def
build_scm_cmd
(
args
)
full_args
=
[
GIT_BIN
,
'--git-dir'
,
root_url
||
url
]
if
self
.
class
.
client_version_above?
([
1
,
7
,
2
])
if
self
.
class
.
client_version_above?
([
1
,
7
,
2
])
full_args
<<
'-c'
<<
'core.quotepath=false'
full_args
<<
'-c'
<<
'core.quotepath=false'
end
end
full_args
+=
args
(
full_args
+
args
).
map
{
|
e
|
shell_quote
e
.
to_s
}.
join
(
' '
)
ret
=
shellout
(
full_args
.
map
{
|
e
|
shell_quote
e
.
to_s
}.
join
(
' '
),
&
block
)
if
$?
&&
$?
.
exitstatus
!=
0
raise
ScmCommandAborted
,
"git exited with non-zero status:
#{
$?
.
exitstatus
}
"
end
ret
end
end
private
:scm_cmd
end
end
end
end
end
end
...
...
lib/redmine/scm/adapters/mercurial_adapter.rb
View file @
21ae869d
...
@@ -12,7 +12,7 @@
...
@@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details.
# See doc/COPYRIGHT.rdoc for more details.
#++
#++
require
'redmine/scm/adapters/abstract_adapter'
require
_dependency
'redmine/scm/adapters/abstract_adapter'
require
'cgi'
require
'cgi'
module
Redmine
module
Redmine
...
@@ -27,9 +27,6 @@ module Redmine
...
@@ -27,9 +27,6 @@ module Redmine
TEMPLATE_NAME
=
"hg-template"
TEMPLATE_NAME
=
"hg-template"
TEMPLATE_EXTENSION
=
"tmpl"
TEMPLATE_EXTENSION
=
"tmpl"
# raised if hg command exited with error, e.g. unknown revision.
class
HgCommandAborted
<
CommandFailed
;
end
class
<<
self
class
<<
self
def
client_command
def
client_command
@@bin
||=
HG_BIN
@@bin
||=
HG_BIN
...
@@ -51,10 +48,7 @@ module Redmine
...
@@ -51,10 +48,7 @@ module Redmine
# The hg version is expressed either as a
# The hg version is expressed either as a
# release number (eg 0.9.5 or 1.0) or as a revision
# release number (eg 0.9.5 or 1.0) or as a revision
# id composed of 12 hexa characters.
# id composed of 12 hexa characters.
theversion
=
hgversion_from_command_line
.
dup
theversion
=
to_ascii
(
hgversion_from_command_line
.
dup
)
if
theversion
.
respond_to?
(
:force_encoding
)
theversion
.
force_encoding
(
'ASCII-8BIT'
)
end
if
m
=
theversion
.
match
(
%r{
\A
(.*?)((
\d
+
\.
)+
\d
+)}
)
if
m
=
theversion
.
match
(
%r{
\A
(.*?)((
\d
+
\.
)+
\d
+)}
)
m
[
2
].
scan
(
%r{
\d
+}
).
collect
(
&
:to_i
)
m
[
2
].
scan
(
%r{
\d
+}
).
collect
(
&
:to_i
)
end
end
...
@@ -114,56 +108,43 @@ module Redmine
...
@@ -114,56 +108,43 @@ module Redmine
Hash
[
*
alist
.
flatten
]
Hash
[
*
alist
.
flatten
]
end
end
def
summary
return
@summary
if
@summary
hg
'rhsummary'
do
|
io
|
output
=
io
.
read
if
output
.
respond_to?
(
:force_encoding
)
output
.
force_encoding
(
'UTF-8'
)
end
begin
@summary
=
ActiveSupport
::
XmlMini
.
parse
(
output
)[
'rhsummary'
]
rescue
end
end
end
private
:summary
def
entries
(
path
=
nil
,
identifier
=
nil
)
def
entries
(
path
=
nil
,
identifier
=
nil
)
p1
=
scm_iconv
(
@path_encoding
,
'UTF-8'
,
path
)
p1
=
scm_iconv
(
@path_encoding
,
'UTF-8'
,
path
)
manifest
=
hg
(
'rhmanifest'
,
'-r'
,
CGI
.
escape
(
hgrev
(
identifier
)),
cmd_args
=
[
CGI
.
escape
(
without_leading_slash
(
p1
.
to_s
)))
do
|
io
|
'rhmanifest'
,
output
=
io
.
read
'-r'
,
if
output
.
respond_to?
(
:force_encoding
)
CGI
.
escape
(
hgrev
(
identifier
)),
output
.
force_encoding
(
'UTF-8'
)
CGI
.
escape
(
without_leading_slash
(
p1
.
to_s
)
)
end
]
begin
ActiveSupport
::
XmlMini
.
parse
(
output
)[
'rhmanifest'
][
'repository'
][
'manifest'
]
manifest
=
scm_cmd
cmd_args
do
|
io
|
rescue
output
=
to_utf8
(
io
.
read
)
end
ActiveSupport
::
XmlMini
.
parse
(
output
)[
'rhmanifest'
][
'repository'
][
'manifest'
]
end
end
path_prefix
=
path
.
blank?
?
''
:
with_trailling_slash
(
path
)
entries
=
Entries
.
new
if
manifest
as_ary
(
manifest
[
'dir'
]).
each
do
|
e
|
path_prefix
=
path
.
blank?
?
''
:
with_trailling_slash
(
path
)
n
=
scm_iconv
(
'UTF-8'
,
@path_encoding
,
CGI
.
unescape
(
e
[
'name'
]))
p
=
"
#{
path_prefix
}#{
n
}
"
entries
<<
Entry
.
new
(
:name
=>
n
,
:path
=>
p
,
:kind
=>
'dir'
)
end
as_ary
(
manifest
[
'file'
]).
each
do
|
e
|
entries
=
Entries
.
new
n
=
scm_iconv
(
'UTF-8'
,
@path_encoding
,
CGI
.
unescape
(
e
[
'name'
]))
as_ary
(
manifest
[
'dir'
]).
each
do
|
e
|
p
=
"
#{
path_prefix
}#{
n
}
"
n
=
unescape
(
e
[
'name'
])
lr
=
Revision
.
new
(
:revision
=>
e
[
'revision'
],
:scmid
=>
e
[
'node'
],
p
=
"
#{
path_prefix
}#{
n
}
"
:identifier
=>
e
[
'node'
],
entries
<<
Entry
.
new
(
:name
=>
n
,
:path
=>
p
,
:kind
=>
'dir'
)
:time
=>
Time
.
at
(
e
[
'time'
].
to_i
))
end
entries
<<
Entry
.
new
(
:name
=>
n
,
:path
=>
p
,
:kind
=>
'file'
,
:size
=>
e
[
'size'
].
to_i
,
:lastrev
=>
lr
)
as_ary
(
manifest
[
'file'
]).
each
do
|
e
|
end
n
=
unescape
(
e
[
'name'
])
p
=
"
#{
path_prefix
}#{
n
}
"
lr
=
Revision
.
new
(
:revision
=>
e
[
'revision'
],
:scmid
=>
e
[
'node'
],
:identifier
=>
e
[
'node'
],
:time
=>
Time
.
at
(
e
[
'time'
].
to_i
))
entries
<<
Entry
.
new
(
:name
=>
n
,
:path
=>
p
,
:kind
=>
'file'
,
:size
=>
e
[
'size'
].
to_i
,
:lastrev
=>
lr
)
end
entries
entries
rescue
HgCommandAborted
end
nil
# means not found
end
end
def
revisions
(
path
=
nil
,
identifier_from
=
nil
,
identifier_to
=
nil
,
options
=
{})
def
revisions
(
path
=
nil
,
identifier_from
=
nil
,
identifier_to
=
nil
,
options
=
{})
...
@@ -175,103 +156,100 @@ module Redmine
...
@@ -175,103 +156,100 @@ module Redmine
# Iterates the revisions by using a template file that
# Iterates the revisions by using a template file that
# makes Mercurial produce a xml output.
# makes Mercurial produce a xml output.
def
each_revision
(
path
=
nil
,
identifier_from
=
nil
,
identifier_to
=
nil
,
options
=
{})
def
each_revision
(
path
=
nil
,
identifier_from
=
nil
,
identifier_to
=
nil
,
options
=
{})
hg_args
=
[
'log'
,
'--debug'
,
'-C'
,
'--style'
,
self
.
class
.
template_path
]
cmd_args
=
[
'log'
,
'--debug'
,
'-C'
,
'--style'
,
self
.
class
.
template_path
]
hg_args
<<
'-r'
<<
"
#{
hgrev
(
identifier_from
)
}
:
#{
hgrev
(
identifier_to
)
}
"
cmd_args
<<
'-r'
<<
"
#{
hgrev
(
identifier_from
)
}
:
#{
hgrev
(
identifier_to
)
}
"
hg_args
<<
'--limit'
<<
options
[
:limit
]
if
options
[
:limit
]
cmd_args
<<
'--limit'
<<
options
[
:limit
]
if
options
[
:limit
]
hg_args
<<
hgtarget
(
path
)
unless
path
.
blank?
cmd_args
<<
hgtarget
(
path
)
unless
path
.
blank?
log
=
hg
(
*
hg_args
)
do
|
io
|
log
=
scm_cmd
(
cmd_args
)
do
|
io
|
output
=
io
.
read
output
=
io
.
read
if
output
.
respond_to?
(
:force_encoding
)
if
output
.
respond_to?
(
:force_encoding
)
output
.
force_encoding
(
'UTF-8'
)
output
.
force_encoding
(
'UTF-8'
)
end
end
begin
ActiveSupport
::
XmlMini
.
parse
(
"
#{
output
}
</log>"
)[
'log'
]
# Mercurial < 1.5 does not support footer template for '</log>'
ActiveSupport
::
XmlMini
.
parse
(
"
#{
output
}
</log>"
)[
'log'
]
rescue
end
end
end
as_ary
(
log
[
'logentry'
]).
each
do
|
le
|
if
log
cpalist
=
as_ary
(
le
[
'paths'
][
'path-copied'
]).
map
do
|
e
|
as_ary
(
log
[
'logentry'
]).
each
do
|
le
|
[
e
[
'__content__'
],
e
[
'copyfrom-path'
]].
map
do
|
s
|
cpalist
=
as_ary
(
le
[
'paths'
][
'path-copied'
]).
map
do
|
e
|
scm_iconv
(
'UTF-8'
,
@path_encoding
,
CGI
.
unescape
(
s
))
[
e
[
'__content__'
],
e
[
'copyfrom-path'
]].
map
do
|
s
|
unescape
s
end
end
end
cpmap
=
Hash
[
*
cpalist
.
flatten
]
paths
=
as_ary
(
le
[
'paths'
][
'path'
]).
map
do
|
e
|
p
=
unescape
e
[
'__content__'
]
{
:action
=>
e
[
'action'
],
:path
=>
with_leading_slash
(
p
),
:from_path
=>
(
cpmap
.
member?
(
p
)
?
with_leading_slash
(
cpmap
[
p
])
:
nil
),
:from_revision
=>
(
cpmap
.
member?
(
p
)
?
le
[
'revision'
]
:
nil
)}
end
.
sort
{
|
a
,
b
|
a
[
:path
]
<=>
b
[
:path
]
}
yield
Revision
.
new
(
:revision
=>
le
[
'revision'
],
:scmid
=>
le
[
'node'
],
:author
=>
(
le
[
'author'
][
'__content__'
]
rescue
''
),
:time
=>
Time
.
parse
(
le
[
'date'
][
'__content__'
]),
:message
=>
le
[
'msg'
][
'__content__'
],
:paths
=>
paths
)
end
end
cpmap
=
Hash
[
*
cpalist
.
flatten
]
self
paths
=
as_ary
(
le
[
'paths'
][
'path'
]).
map
do
|
e
|
p
=
scm_iconv
(
'UTF-8'
,
@path_encoding
,
CGI
.
unescape
(
e
[
'__content__'
])
)
{
:action
=>
e
[
'action'
],
:path
=>
with_leading_slash
(
p
),
:from_path
=>
(
cpmap
.
member?
(
p
)
?
with_leading_slash
(
cpmap
[
p
])
:
nil
),
:from_revision
=>
(
cpmap
.
member?
(
p
)
?
le
[
'revision'
]
:
nil
)}
end
.
sort
{
|
a
,
b
|
a
[
:path
]
<=>
b
[
:path
]
}
yield
Revision
.
new
(
:revision
=>
le
[
'revision'
],
:scmid
=>
le
[
'node'
],
:author
=>
(
le
[
'author'
][
'__content__'
]
rescue
''
),
:time
=>
Time
.
parse
(
le
[
'date'
][
'__content__'
]),
:message
=>
le
[
'msg'
][
'__content__'
],
:paths
=>
paths
)
end
end
self
end
end
# Returns list of nodes in the specified branch
# Returns list of nodes in the specified branch
def
nodes_in_branch
(
branch
,
options
=
{})
def
nodes_in_branch
(
branch
,
options
=
{})
hg_args
=
[
'rhlog'
,
'--template'
,
'{node|short}\n'
,
'--rhbranch'
,
CGI
.
escape
(
branch
)]
cmd_args
=
[
'rhlog'
,
'--template'
,
'{node|short}\n'
,
'--rhbranch'
,
CGI
.
escape
(
branch
)]
hg_args
<<
'--from'
<<
CGI
.
escape
(
branch
)
cmd_args
<<
'--from'
<<
CGI
.
escape
(
branch
)
hg_args
<<
'--to'
<<
'0'
cmd_args
<<
'--to'
<<
'0'
hg_args
<<
'--limit'
<<
options
[
:limit
]
if
options
[
:limit
]
cmd_args
<<
'--limit'
<<
options
[
:limit
]
if
options
[
:limit
]
hg
(
*
hg_args
)
{
|
io
|
io
.
readlines
.
map
{
|
e
|
e
.
chomp
}
}
scm_cmd
(
cmd_args
)
do
|
io
|
io
.
readlines
.
map
{
|
e
|
e
.
chomp
}
end
end
end
def
diff
(
path
,
identifier_from
,
identifier_to
=
nil
)
def
diff
(
path
,
identifier_from
,
identifier_to
=
nil
)
hg
_args
=
%w|rhdiff|
cmd
_args
=
%w|rhdiff|
if
identifier_to
if
identifier_to
hg
_args
<<
'-r'
<<
hgrev
(
identifier_to
)
<<
'-r'
<<
hgrev
(
identifier_from
)
cmd
_args
<<
'-r'
<<
hgrev
(
identifier_to
)
<<
'-r'
<<
hgrev
(
identifier_from
)
else
else
hg
_args
<<
'-c'
<<
hgrev
(
identifier_from
)
cmd
_args
<<
'-c'
<<
hgrev
(
identifier_from
)
end
end
unless
path
.
blank?
unless
path
.
blank?
p
=
scm_iconv
(
@path_encoding
,
'UTF-8'
,
path
)
p
=
scm_iconv
(
@path_encoding
,
'UTF-8'
,
path
)
hg
_args
<<
CGI
.
escape
(
hgtarget
(
p
))
cmd
_args
<<
CGI
.
escape
(
hgtarget
(
p
))
end
end
diff
=
[]
scm_cmd
cmd_args
do
|
io
|
hg
*
hg_args
do
|
io
|
diff
=
[]
io
.
each_line
do
|
line
|
io
.
each_line
{
|
line
|
diff
<<
line
}
diff
<<
line
diff
end
end
end
diff
rescue
HgCommandAborted
nil
# means not found
end
end
def
cat
(
path
,
identifier
=
nil
)
def
cat
(
path
,
identifier
=
nil
)
p
=
CGI
.
escape
(
scm_iconv
(
@path_encoding
,
'UTF-8'
,
path
))
p
=
escape
(
path
)
hg
'rhcat'
,
'-r'
,
CGI
.
escape
(
hgrev
(
identifier
)),
hgtarget
(
p
)
do
|
io
|
cmd_args
=
[
'rhcat'
,
'-r'
,
CGI
.
escape
(
hgrev
(
identifier
)),
hgtarget
(
p
)]
scm_cmd
cmd_args
do
|
io
|
io
.
binmode
io
.
binmode
io
.
read
io
.
read
end
end
rescue
HgCommandAborted
nil
# means not found
end
end
def
annotate
(
path
,
identifier
=
nil
)
def
annotate
(
path
,
identifier
=
nil
)
p
=
CGI
.
escape
(
scm_iconv
(
@path_encoding
,
'UTF-8'
,
path
))
p
=
escape
(
path
)
blame
=
Annotate
.
new
cmd_args
=
[
'rhannotate'
,
'-ncu'
,
'-r'
,
CGI
.
escape
(
hgrev
(
identifier
)),
hgtarget
(
p
)]
hg
'rhannotate'
,
'-ncu'
,
'-r'
,
CGI
.
escape
(
hgrev
(
identifier
)),
hgtarget
(
p
)
do
|
io
|
scm_cmd
cmd_args
do
|
io
|
blame
=
Annotate
.
new
io
.
each_line
do
|
line
|
io
.
each_line
do
|
line
|
line
.
force_encoding
(
'ASCII-8BIT'
)
if
line
.
respond_to?
(
:force_encoding
)
to_ascii
(
line
)
next
unless
line
=~
%r{^([^:]+)
\s
(
\d
+)
\s
([0-9a-f]+):
\s
(.*)$}
next
unless
line
=~
%r{^([^:]+)
\s
(
\d
+)
\s
([0-9a-f]+):
\s
(.*)$}
r
=
Revision
.
new
(
:author
=>
$1
.
strip
,
:revision
=>
$2
,
:scmid
=>
$3
,
r
=
Revision
.
new
(
:author
=>
$1
.
strip
,
:revision
=>
$2
,
:scmid
=>
$3
,
:identifier
=>
$3
)
:identifier
=>
$3
)
blame
.
add_line
(
$4
.
rstrip
,
r
)
blame
.
add_line
(
$4
.
rstrip
,
r
)
end
end
blame
end
end
blame
rescue
HgCommandAborted
nil
# means not found or cannot be annotated
end
end
class
Revision
<
Redmine
::
Scm
::
Adapters
::
Revision
class
Revision
<
Redmine
::
Scm
::
Adapters
::
Revision
...
@@ -281,20 +259,16 @@ module Redmine
...
@@ -281,20 +259,16 @@ module Redmine
end
end
end
end
# Runs 'hg' command with the given args
private
def
hg
(
*
args
,
&
block
)
def
build_scm_cmd
(
args
)
repo_path
=
root_url
||
url
repo_path
=
root_url
||
url
full_args
=
[
HG_BIN
,
'-R'
,
repo_path
,
'--encoding'
,
'utf-8'
]
full_args
=
[
HG_BIN
,
'-R'
,
repo_path
,
'--encoding'
,
'utf-8'
]
full_args
<<
'--config'
<<
"extensions.redminehelper=
#{
HG_HELPER_EXT
}
"
full_args
<<
'--config'
<<
"extensions.redminehelper=
#{
HG_HELPER_EXT
}
"
full_args
<<
'--config'
<<
'diff.git=false'
full_args
<<
'--config'
<<
'diff.git=false'
full_args
+=
args
full_args
+=
args
ret
=
shellout
(
full_args
.
map
{
|
e
|
shell_quote
e
.
to_s
}.
join
(
' '
),
&
block
)
full_args
.
map
{
|
e
|
shell_quote
e
.
to_s
}.
join
(
' '
)
if
$?
&&
$?
.
exitstatus
!=
0
raise
HgCommandAborted
,
"hg exited with non-zero status:
#{
$?
.
exitstatus
}
"
end
ret
end
end
private
:hg
# Returns correct revision identifier
# Returns correct revision identifier
def
hgrev
(
identifier
,
sq
=
false
)
def
hgrev
(
identifier
,
sq
=
false
)
...
@@ -302,19 +276,47 @@ module Redmine
...
@@ -302,19 +276,47 @@ module Redmine
rev
=
shell_quote
(
rev
)
if
sq
rev
=
shell_quote
(
rev
)
if
sq
rev
rev
end
end
private
:hgrev
def
hgtarget
(
path
)
def
hgtarget
(
path
)
path
||=
''
path
||=
''
root_url
+
'/'
+
without_leading_slash
(
path
)
root_url
+
'/'
+
without_leading_slash
(
path
)
end
end
private
:hgtarget
def
as_ary
(
o
)
def
as_ary
(
o
)
return
[]
unless
o
return
[]
unless
o
o
.
is_a?
(
Array
)
?
o
:
Array
[
o
]
o
.
is_a?
(
Array
)
?
o
:
Array
[
o
]
end
end
private
:as_ary
def
summary
return
@summary
if
@summary
scm_cmd
[
'rhsummary'
]
do
|
io
|
output
=
to_utf8
(
io
.
read
)
@summary
=
ActiveSupport
::
XmlMini
.
parse
(
output
)[
'rhsummary'
]
end
end
def
to_utf8
(
str
)
str
.
force_encoding
(
'UTF-8'
)
if
str
.
respond_to?
(
:force_encoding
)
str
end
def
self
.
to_ascii
(
str
)
str
.
force_encoding
(
'ASCII-8BIT'
)
if
str
.
respond_to?
(
:force_encoding
)
str
end
def
to_ascii
(
str
)
self
.
class
.
to_ascii
(
str
)
end
def
escape
(
str
)
CGI
.
escape
(
scm_iconv
(
@path_encoding
,
'UTF-8'
,
str
))
end
def
unescape
(
str
)
scm_iconv
(
'UTF-8'
,
@path_encoding
,
CGI
.
unescape
(
str
))
end
end
end
end
end
end
end
...
...
lib/redmine/scm/adapters/subversion_adapter.rb
View file @
21ae869d
...
@@ -12,7 +12,7 @@
...
@@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details.
# See doc/COPYRIGHT.rdoc for more details.
#++
#++
require
'redmine/scm/adapters/abstract_adapter'
require
_dependency
'redmine/scm/adapters/abstract_adapter'
require
'uri'
require
'uri'
module
Redmine
module
Redmine
...
@@ -57,194 +57,178 @@ module Redmine
...
@@ -57,194 +57,178 @@ module Redmine
# Get info about the svn repository
# Get info about the svn repository
def
info
def
info
cmd
=
"
#{
self
.
class
.
sq_bin
}
info --xml
#{
target
}
"
cmd_args
=
[
'info'
,
'--xml'
,
target
,
credentials_string
]
cmd
<<
credentials_string
scm_cmd
(
cmd_args
)
do
|
io
|
info
=
nil
shellout
(
cmd
)
do
|
io
|
output
=
io
.
read
output
=
io
.
read
if
output
.
respond_to?
(
:force_encoding
)
if
output
.
respond_to?
(
:force_encoding
)
output
.
force_encoding
(
'UTF-8'
)
output
.
force_encoding
(
'UTF-8'
)
end
end
begin
doc
=
ActiveSupport
::
XmlMini
.
parse
(
output
)
doc
=
ActiveSupport
::
XmlMini
.
parse
(
output
)
#root_url = doc.elements["info/entry/repository/root"].text
#root_url = doc.elements["info/entry/repository/root"].text
Info
.
new
({
info
=
Info
.
new
({
:root_url
=>
doc
[
'info'
][
'entry'
][
'repository'
][
'root'
][
'__content__'
],
:root_url
=>
doc
[
'info'
][
'entry'
][
'repository'
][
'root'
][
'__content__'
],
:lastrev
=>
Revision
.
new
({
:lastrev
=>
Revision
.
new
({
:identifier
=>
doc
[
'info'
][
'entry'
][
'commit'
][
'revision'
],
:identifier
=>
doc
[
'info'
][
'entry'
][
'commit'
][
'revision'
],
:time
=>
Time
.
parse
(
doc
[
'info'
][
'entry'
][
'commit'
][
'date'
][
'__content__'
]).
localtime
,
:time
=>
Time
.
parse
(
doc
[
'info'
][
'entry'
][
'commit'
][
'date'
][
'__content__'
]).
localtime
,
:author
=>
(
doc
[
'info'
][
'entry'
][
'commit'
][
'author'
]
?
doc
[
'info'
][
'entry'
][
'commit'
][
'author'
][
'__content__'
]
:
""
)
:author
=>
(
doc
[
'info'
][
'entry'
][
'commit'
][
'author'
]
?
doc
[
'info'
][
'entry'
][
'commit'
][
'author'
][
'__content__'
]
:
""
)
})
})
})
})
rescue
end
end
end
return
nil
if
$?
&&
$?
.
exitstatus
!=
0
info
rescue
CommandFailed
return
nil
end
end
# Returns an Entries collection
# Returns an Entries collection
# or nil if the given path doesn't exist in the repository
# or nil if the given path doesn't exist in the repository
def
entries
(
path
=
nil
,
identifier
=
nil
)
def
entries
(
path
=
nil
,
identifier
=
nil
)
path
||=
''
path
||=
''
identifier
=
(
identifier
and
identifier
.
to_i
>
0
)
?
identifier
.
to_i
:
"HEAD"
identifier
=
initialize_identifier
(
identifier
)
entries
=
Entries
.
new
entries
=
Entries
.
new
cmd
=
"
#{
self
.
class
.
sq_bin
}
list --xml
#{
target
(
path
)
}
@
#{
identifier
}
"
cmd_args
=
[
'list'
,
'--xml'
,
"
#{
target
(
path
)
}
@
#{
identifier
}
"
,
credentials_string
]
cmd
<<
credentials_string
scm_cmd
(
cmd_args
)
do
|
io
|
shellout
(
cmd
)
do
|
io
|
output
=
io
.
read
output
=
io
.
read
if
output
.
respond_to?
(
:force_encoding
)
if
output
.
respond_to?
(
:force_encoding
)
output
.
force_encoding
(
'UTF-8'
)
output
.
force_encoding
(
'UTF-8'
)
end
end
begin
doc
=
ActiveSupport
::
XmlMini
.
parse
(
output
)
doc
=
ActiveSupport
::
XmlMini
.
parse
(
output
)
each_xml_element
(
doc
[
'lists'
][
'list'
],
'entry'
)
do
|
entry
|
each_xml_element
(
doc
[
'lists'
][
'list'
],
'entry'
)
do
|
entry
|
commit
=
entry
[
'commit'
]
commit
=
entry
[
'commit'
]
commit_date
=
commit
[
'date'
]
commit_date
=
commit
[
'date'
]
# Skip directory if there is no commit date (usually that
# Skip directory if there is no commit date (usually that
# means that we don't have read access to it)
# means that we don't have read access to it)
next
if
entry
[
'kind'
]
==
'dir'
&&
commit_date
.
nil?
next
if
entry
[
'kind'
]
==
'dir'
&&
commit_date
.
nil?
name
=
entry
[
'name'
][
'__content__'
]
name
=
entry
[
'name'
][
'__content__'
]
entries
<<
Entry
.
new
({
:name
=>
URI
.
unescape
(
name
),
entries
<<
Entry
.
new
({
:name
=>
URI
.
unescape
(
name
),
:path
=>
((
path
.
empty?
?
""
:
"
#{
path
}
/"
)
+
name
),
:path
=>
((
path
.
empty?
?
""
:
"
#{
path
}
/"
)
+
name
),
:kind
=>
entry
[
'kind'
],
:kind
=>
entry
[
'kind'
],
:size
=>
((
s
=
entry
[
'size'
])
?
s
[
'__content__'
].
to_i
:
nil
),
:size
=>
((
s
=
entry
[
'size'
])
?
s
[
'__content__'
].
to_i
:
nil
),
:lastrev
=>
Revision
.
new
({
:lastrev
=>
Revision
.
new
({
:identifier
=>
commit
[
'revision'
],
:identifier
=>
commit
[
'revision'
],
:time
=>
Time
.
parse
(
commit_date
[
'__content__'
].
to_s
).
localtime
,
:time
=>
Time
.
parse
(
commit_date
[
'__content__'
].
to_s
).
localtime
,
:author
=>
((
a
=
commit
[
'author'
])
?
a
[
'__content__'
]
:
nil
)
:author
=>
((
a
=
commit
[
'author'
])
?
a
[
'__content__'
]
:
nil
)
})
})
})
end
})
rescue
Exception
=>
e
logger
.
error
(
"Error parsing svn output:
#{
e
.
message
}
"
)
logger
.
error
(
"Output was:
\n
#{
output
}
"
)
end
end
logger
.
debug
(
"Found
#{
entries
.
size
}
entries in the repository for
#{
target
(
path
)
}
"
)
if
logger
&&
logger
.
debug?
entries
.
sort_by_name
end
end
return
nil
if
$?
&&
$?
.
exitstatus
!=
0
logger
.
debug
(
"Found
#{
entries
.
size
}
entries in the repository for
#{
target
(
path
)
}
"
)
if
logger
&&
logger
.
debug?
entries
.
sort_by_name
end
end
def
properties
(
path
,
identifier
=
nil
)
def
properties
(
path
,
identifier
=
nil
)
# proplist xml output supported in svn 1.5.0 and higher
# proplist xml output supported in svn 1.5.0 and higher
return
nil
unless
self
.
class
.
client_version_above?
([
1
,
5
,
0
])
return
nil
unless
self
.
class
.
client_version_above?
([
1
,
5
,
0
])
identifier
=
(
identifier
and
identifier
.
to_i
>
0
)
?
identifier
.
to_i
:
"HEAD"
identifier
=
initialize_identifier
(
identifier
)
cmd
=
"
#{
self
.
class
.
sq_bin
}
proplist --verbose --xml
#{
target
(
path
)
}
@
#{
identifier
}
"
cmd_args
=
[
'proplist'
,
'--verbose'
,
'--xml'
,
"
#{
target
(
path
)
}
@
#{
identifier
}
"
,
credentials_string
]
cmd
<<
credentials_string
properties
=
{}
properties
=
{}
s
hellout
(
cmd
)
do
|
io
|
s
cm_cmd
(
cmd_args
)
do
|
io
|
output
=
io
.
read
output
=
io
.
read
if
output
.
respond_to?
(
:force_encoding
)
if
output
.
respond_to?
(
:force_encoding
)
output
.
force_encoding
(
'UTF-8'
)
output
.
force_encoding
(
'UTF-8'
)
end
end
begin
doc
=
ActiveSupport
::
XmlMini
.
parse
(
output
)
doc
=
ActiveSupport
::
XmlMini
.
parse
(
output
)
each_xml_element
(
doc
[
'properties'
][
'target'
],
'property'
)
do
|
property
|
each_xml_element
(
doc
[
'properties'
][
'target'
],
'property'
)
do
|
property
|
properties
[
property
[
'name'
]
]
=
property
[
'__content__'
].
to_s
properties
[
property
[
'name'
]
]
=
property
[
'__content__'
].
to_s
end
rescue
end
end
properties
end
end
return
nil
if
$?
&&
$?
.
exitstatus
!=
0
properties
end
end
def
revisions
(
path
=
nil
,
identifier_from
=
nil
,
identifier_to
=
nil
,
options
=
{})
def
revisions
(
path
=
nil
,
identifier_from
=
nil
,
identifier_to
=
nil
,
options
=
{})
path
||=
''
path
||=
''
identifier_from
=
(
identifier_from
&&
identifier_from
.
to_i
>
0
)
?
identifier_from
.
to_i
:
"HEAD"
identifier_from
=
initialize_identifier
(
identifier_from
)
identifier_to
=
(
identifier_to
&&
identifier_to
.
to_i
>
0
)
?
identifier_to
.
to_i
:
1
identifier_to
=
initialize_identifier
(
identifier_to
,
1
)
cmd_args
=
[
'log'
,
'--xml'
,
'-r'
,
"
#{
identifier_from
}
:
#{
identifier_to
}
"
,
credentials_string
]
cmd_args
<<
" --verbose "
if
options
[
:with_paths
]
cmd_args
<<
" --limit
#{
options
[
:limit
].
to_i
}
"
if
options
[
:limit
]
cmd_args
<<
target
(
path
)
revisions
=
Revisions
.
new
revisions
=
Revisions
.
new
cmd
=
"
#{
self
.
class
.
sq_bin
}
log --xml -r
#{
identifier_from
}
:
#{
identifier_to
}
"
cmd
<<
credentials_string
scm_cmd
(
cmd_args
)
do
|
io
|
cmd
<<
" --verbose "
if
options
[
:with_paths
]
cmd
<<
" --limit
#{
options
[
:limit
].
to_i
}
"
if
options
[
:limit
]
cmd
<<
' '
+
target
(
path
)
shellout
(
cmd
)
do
|
io
|
output
=
io
.
read
output
=
io
.
read
if
output
.
respond_to?
(
:force_encoding
)
if
output
.
respond_to?
(
:force_encoding
)
output
.
force_encoding
(
'UTF-8'
)
output
.
force_encoding
(
'UTF-8'
)
end
end
begin
doc
=
ActiveSupport
::
XmlMini
.
parse
(
output
)
doc
=
ActiveSupport
::
XmlMini
.
parse
(
output
)
each_xml_element
(
doc
[
'log'
],
'logentry'
)
do
|
logentry
|
each_xml_element
(
doc
[
'log'
],
'logentry'
)
do
|
logentry
|
paths
=
[]
paths
=
[]
if
logentry
[
'paths'
]
&&
logentry
[
'paths'
][
'path'
]
each_xml_element
(
logentry
[
'paths'
],
'path'
)
do
|
path
|
each_xml_element
(
logentry
[
'paths'
],
'path'
)
do
|
path
|
paths
<<
{
:action
=>
path
[
'action'
],
paths
<<
{
:action
=>
path
[
'action'
],
:path
=>
path
[
'__content__'
],
:path
=>
path
[
'__content__'
],
:from_path
=>
path
[
'copyfrom-path'
],
:from_path
=>
path
[
'copyfrom-path'
],
:from_revision
=>
path
[
'copyfrom-rev'
]
:from_revision
=>
path
[
'copyfrom-rev'
]
}
}
end
if
logentry
[
'paths'
]
&&
logentry
[
'paths'
][
'path'
]
end
paths
.
sort!
{
|
x
,
y
|
x
[
:path
]
<=>
y
[
:path
]
}
revisions
<<
Revision
.
new
({
:identifier
=>
logentry
[
'revision'
],
:author
=>
(
logentry
[
'author'
]
?
logentry
[
'author'
][
'__content__'
]
:
""
),
:time
=>
Time
.
parse
(
logentry
[
'date'
][
'__content__'
].
to_s
).
localtime
,
:message
=>
logentry
[
'msg'
][
'__content__'
],
:paths
=>
paths
})
end
end
rescue
paths
.
sort!
{
|
x
,
y
|
x
[
:path
]
<=>
y
[
:path
]
}
revisions
<<
Revision
.
new
({
:identifier
=>
logentry
[
'revision'
],
:author
=>
(
logentry
[
'author'
]
?
logentry
[
'author'
][
'__content__'
]
:
""
),
:time
=>
Time
.
parse
(
logentry
[
'date'
][
'__content__'
].
to_s
).
localtime
,
:message
=>
logentry
[
'msg'
][
'__content__'
],
:paths
=>
paths
})
end
end
revisions
end
end
return
nil
if
$?
&&
$?
.
exitstatus
!=
0
revisions
end
end
def
diff
(
path
,
identifier_from
,
identifier_to
=
nil
,
type
=
"inline"
)
def
diff
(
path
,
identifier_from
,
identifier_to
=
nil
,
type
=
"inline"
)
path
||=
''
path
||=
''
identifier_from
=
(
identifier_from
and
identifier_from
.
to_i
>
0
)
?
identifier_from
.
to_i
:
''
identifier_to
=
(
identifier_to
and
identifier_to
.
to_i
>
0
)
?
identifier_to
.
to_i
:
(
identifier_from
.
to_i
-
1
)
identifier_from
=
initialize_identifier
(
identifier_from
,
''
)
identifier_to
=
initialize_identifier
(
identifier_to
,
identifier_from
.
to_i
-
1
)
cmd
=
"
#{
self
.
class
.
sq_bin
}
diff -r "
cmd_args
=
[
"diff -r"
,
cmd
<<
"
#{
identifier_to
}
:"
"
#{
identifier_to
}
:
#{
identifier_from
}
"
,
cmd
<<
"
#{
identifier_from
}
"
"
#{
target
(
path
)
}
@
#{
identifier_from
}
"
,
cmd
<<
"
#{
target
(
path
)
}
@
#{
identifier_from
}
"
credentials_string
]
cmd
<<
credentials_string
diff
=
[]
diff
=
[]
s
hellout
(
cmd
)
do
|
io
|
s
cm_cmd
(
cmd_args
)
do
|
io
|
io
.
each_line
do
|
line
|
io
.
each_line
do
|
line
|
diff
<<
line
diff
<<
line
end
end
diff
end
end
return
nil
if
$?
&&
$?
.
exitstatus
!=
0
diff
end
end
def
cat
(
path
,
identifier
=
nil
)
def
cat
(
path
,
identifier
=
nil
)
identifier
=
(
identifier
and
identifier
.
to_i
>
0
)
?
identifier
.
to_i
:
"HEAD"
identifier
=
initialize_identifier
(
identifier
)
cmd
=
"
#{
self
.
class
.
sq_bin
}
cat
#{
target
(
path
)
}
@
#{
identifier
}
"
cmd
<<
credentials_string
cmd_args
=
[
'cat'
,
"
#{
target
(
path
)
}
@
#{
identifier
}
"
,
credentials_string
]
cat
=
nil
scm_cmd
(
cmd_args
)
do
|
io
|
shellout
(
cmd
)
do
|
io
|
io
.
binmode
io
.
binmode
cat
=
io
.
read
io
.
read
end
end
return
nil
if
$?
&&
$?
.
exitstatus
!=
0
end
cat
def
save_entry_in_file
(
f
,
path
,
identifier
)
identifier
=
initialize_identifier
(
identifier
)
cmd_args
=
[
'cat'
,
"
#{
target
(
path
)
}
@
#{
identifier
}
"
,
credentials_string
]
scm_cmd
(
cmd_args
,
f
.
path
)
end
end
def
annotate
(
path
,
identifier
=
nil
)
def
annotate
(
path
,
identifier
=
nil
)
identifier
=
(
identifier
and
identifier
.
to_i
>
0
)
?
identifier
.
to_i
:
"HEAD"
identifier
=
initialize_identifier
(
identifier
)
cmd
=
"
#{
self
.
class
.
sq_bin
}
blame
#{
target
(
path
)
}
@
#{
identifier
}
"
cmd_args
=
[
'blame'
,
"
#{
target
(
path
)
}
@
#{
identifier
}
"
,
credentials_string
]
cmd
<<
credentials_string
blame
=
Annotate
.
new
blame
=
Annotate
.
new
s
hellout
(
cmd
)
do
|
io
|
s
cm_cmd
(
cmd_args
)
do
|
io
|
io
.
each_line
do
|
line
|
io
.
each_line
do
|
line
|
next
unless
line
=~
%r{^
\s
*(
\d
+)
\s
*(
\S
+)
\s
(.*)$}
next
unless
line
=~
%r{^
\s
*(
\d
+)
\s
*(
\S
+)
\s
(.*)$}
blame
.
add_line
(
$3
.
rstrip
,
Revision
.
new
(
:identifier
=>
$1
.
to_i
,
:author
=>
$2
.
strip
))
blame
.
add_line
(
$3
.
rstrip
,
Revision
.
new
(
:identifier
=>
$1
.
to_i
,
:author
=>
$2
.
strip
))
end
end
blame
end
end
return
nil
if
$?
&&
$?
.
exitstatus
!=
0
blame
end
end
private
private
def
initialize_identifier
(
identifier
,
default
=
"HEAD"
)
(
identifier
&&
identifier
.
to_i
>
0
)
?
identifier
.
to_i
:
default
end
def
credentials_string
def
credentials_string
str
=
''
str
=
''
str
<<
" --username
#{
shell_quote
(
@login
)
}
"
unless
@login
.
blank?
str
<<
" --username
#{
shell_quote
(
@login
)
}
"
unless
@login
.
blank?
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment