Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
caddy
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
caddy
Commits
f44cd5d7
Commit
f44cd5d7
authored
May 22, 2015
by
Abiola Ibrahim
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Git: Minor fixes. Refactor. Added tests.
parent
d311345a
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
781 additions
and
36 deletions
+781
-36
config/setup/git.go
config/setup/git.go
+26
-4
config/setup/git_test.go
config/setup/git_test.go
+144
-0
middleware/git/git.go
middleware/git/git.go
+52
-32
middleware/git/git_test.go
middleware/git/git_test.go
+218
-0
middleware/git/gitos/gitos.go
middleware/git/gitos/gitos.go
+160
-0
middleware/git/gittest/gittest.go
middleware/git/gittest/gittest.go
+167
-0
middleware/git/os.go
middleware/git/os.go
+12
-0
middleware/rewrite/rewrite_test.go
middleware/rewrite/rewrite_test.go
+2
-0
No files found.
config/setup/git.go
View file @
f44cd5d7
...
...
@@ -96,6 +96,8 @@ func gitParse(c *Controller) (*git.Repo, error) {
return
nil
,
c
.
ArgErr
()
}
repo
.
Then
=
strings
.
Join
(
thenArgs
,
" "
)
default
:
return
nil
,
c
.
ArgErr
()
}
}
}
...
...
@@ -124,8 +126,8 @@ func gitParse(c *Controller) (*git.Repo, error) {
return
nil
,
err
}
// validate git
availability in PATH
if
err
=
git
.
Init
Git
();
err
!=
nil
{
// validate git
requirements
if
err
=
git
.
Init
();
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -153,19 +155,39 @@ func sanitizeHttp(repoUrl string) (string, string, error) {
}
repoUrl
=
"https://"
+
url
.
Host
+
url
.
Path
// add .git suffix if missing
if
!
strings
.
HasSuffix
(
repoUrl
,
".git"
)
{
repoUrl
+=
".git"
}
return
repoUrl
,
url
.
Host
,
nil
}
// sanitizeGit cleans up repository url and validate ssh format.
// sanitizeGit cleans up repository url and converts to ssh format for private
// repositories if required.
// Returns sanitized url, hostName (e.g. github.com, bitbucket.com)
// and possible error
func
sanitizeGit
(
repoUrl
string
)
(
string
,
string
,
error
)
{
repoUrl
=
strings
.
TrimSpace
(
repoUrl
)
// check if valid ssh format
if
!
strings
.
HasPrefix
(
repoUrl
,
"git@"
)
||
strings
.
Index
(
repoUrl
,
":"
)
<
len
(
"git@a:"
)
{
return
""
,
""
,
fmt
.
Errorf
(
"Invalid git url %s"
,
repoUrl
)
// check if valid http format and convert to ssh
if
url
,
err
:=
url
.
Parse
(
repoUrl
);
err
==
nil
&&
strings
.
HasPrefix
(
url
.
Scheme
,
"http"
)
{
repoUrl
=
fmt
.
Sprintf
(
"git@%v:%v"
,
url
.
Host
,
url
.
Path
[
1
:
])
}
else
{
return
""
,
""
,
fmt
.
Errorf
(
"Invalid git url %s"
,
repoUrl
)
}
}
hostUrl
:=
repoUrl
[
len
(
"git@"
)
:
]
i
:=
strings
.
Index
(
hostUrl
,
":"
)
host
:=
hostUrl
[
:
i
]
// add .git suffix if missing
if
!
strings
.
HasSuffix
(
repoUrl
,
".git"
)
{
repoUrl
+=
".git"
}
return
repoUrl
,
host
,
nil
}
config/setup/git_test.go
0 → 100644
View file @
f44cd5d7
package
setup
import
(
"testing"
"time"
"github.com/mholt/caddy/middleware/git"
"github.com/mholt/caddy/middleware/git/gittest"
)
// init sets the OS used to fakeOS
func
init
()
{
git
.
SetOS
(
gittest
.
FakeOS
)
}
func
TestGit
(
t
*
testing
.
T
)
{
c
:=
newTestController
(
`git git@github.com:mholt/caddy.git`
)
mid
,
err
:=
Git
(
c
)
if
err
!=
nil
{
t
.
Errorf
(
"Expected no errors, but got: %v"
,
err
)
}
if
mid
!=
nil
{
t
.
Fatal
(
"Git middleware is a background service and expected to be nil."
)
}
}
func
TestGitParse
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
input
string
shouldErr
bool
expected
*
git
.
Repo
}{
{
`git git@github.com:user/repo`
,
false
,
&
git
.
Repo
{
Url
:
"https://github.com/user/repo.git"
,
}},
{
`git github.com/user/repo`
,
false
,
&
git
.
Repo
{
Url
:
"https://github.com/user/repo.git"
,
}},
{
`git git@github.com/user/repo`
,
true
,
nil
},
{
`git http://github.com/user/repo`
,
false
,
&
git
.
Repo
{
Url
:
"https://github.com/user/repo.git"
,
}},
{
`git https://github.com/user/repo`
,
false
,
&
git
.
Repo
{
Url
:
"https://github.com/user/repo.git"
,
}},
{
`git http://github.com/user/repo {
key ~/.key
}`
,
false
,
&
git
.
Repo
{
KeyPath
:
"~/.key"
,
Url
:
"git@github.com:user/repo.git"
,
}},
{
`git git@github.com:user/repo {
key ~/.key
}`
,
false
,
&
git
.
Repo
{
KeyPath
:
"~/.key"
,
Url
:
"git@github.com:user/repo.git"
,
}},
{
`git `
,
true
,
nil
},
{
`git {
}`
,
true
,
nil
},
{
`git {
repo git@github.com:user/repo.git`
,
true
,
nil
},
{
`git {
repo git@github.com:user/repo
key ~/.key
}`
,
false
,
&
git
.
Repo
{
KeyPath
:
"~/.key"
,
Url
:
"git@github.com:user/repo.git"
,
}},
{
`git {
repo git@github.com:user/repo
key ~/.key
interval 600
}`
,
false
,
&
git
.
Repo
{
KeyPath
:
"~/.key"
,
Url
:
"git@github.com:user/repo.git"
,
Interval
:
time
.
Second
*
600
,
}},
{
`git {
repo git@github.com:user/repo
branch dev
}`
,
false
,
&
git
.
Repo
{
Branch
:
"dev"
,
Url
:
"https://github.com/user/repo.git"
,
}},
{
`git {
key ~/.key
}`
,
true
,
nil
},
{
`git {
repo git@github.com:user/repo
key ~/.key
then echo hello world
}`
,
false
,
&
git
.
Repo
{
KeyPath
:
"~/.key"
,
Url
:
"git@github.com:user/repo.git"
,
Then
:
"echo hello world"
,
}},
}
for
i
,
test
:=
range
tests
{
c
:=
newTestController
(
test
.
input
)
repo
,
err
:=
gitParse
(
c
)
if
!
test
.
shouldErr
&&
err
!=
nil
{
t
.
Errorf
(
"Test %v should not error but found %v"
,
i
,
err
)
continue
}
if
test
.
shouldErr
&&
err
==
nil
{
t
.
Errorf
(
"Test %v should error but found nil"
,
i
)
continue
}
if
!
reposEqual
(
test
.
expected
,
repo
)
{
t
.
Errorf
(
"Test %v expects %v but found %v"
,
i
,
test
.
expected
,
repo
)
}
}
}
func
reposEqual
(
expected
,
repo
*
git
.
Repo
)
bool
{
if
expected
==
nil
{
return
repo
==
nil
}
if
expected
.
Branch
!=
""
&&
expected
.
Branch
!=
repo
.
Branch
{
return
false
}
if
expected
.
Host
!=
""
&&
expected
.
Host
!=
repo
.
Host
{
return
false
}
if
expected
.
Interval
!=
0
&&
expected
.
Interval
!=
repo
.
Interval
{
return
false
}
if
expected
.
KeyPath
!=
""
&&
expected
.
KeyPath
!=
repo
.
KeyPath
{
return
false
}
if
expected
.
Path
!=
""
&&
expected
.
Path
!=
repo
.
Path
{
return
false
}
if
expected
.
Then
!=
""
&&
expected
.
Then
!=
repo
.
Then
{
return
false
}
if
expected
.
Url
!=
""
&&
expected
.
Url
!=
repo
.
Url
{
return
false
}
return
true
}
middleware/git/git.go
View file @
f44cd5d7
...
...
@@ -3,15 +3,14 @@ package git
import
(
"bytes"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"strings"
"sync"
"time"
"github.com/mholt/caddy/middleware"
"github.com/mholt/caddy/middleware/git/gitos"
)
// DefaultInterval is the minimum interval to delay before
...
...
@@ -24,8 +23,11 @@ const numRetries = 3
// gitBinary holds the absolute path to git executable
var
gitBinary
string
// shell holds the shell to be used. Either sh or bash.
var
shell
string
// initMutex prevents parallel attempt to validate
// git
availability in PATH
// git
requirements.
var
initMutex
sync
.
Mutex
=
sync
.
Mutex
{}
// Logger is used to log errors; if nil, the default log.Logger is used.
...
...
@@ -120,20 +122,20 @@ func (r *Repo) pull() error {
// pullWithKey is used for private repositories and requires an ssh key.
// Note: currently only limited to Linux and OSX.
func
(
r
*
Repo
)
pullWithKey
(
params
[]
string
)
error
{
var
gitSsh
,
script
*
os
.
File
var
gitSsh
,
script
git
os
.
File
// ensure temporary files deleted after usage
defer
func
()
{
if
gitSsh
!=
nil
{
os
.
Remove
(
gitSsh
.
Name
())
g
os
.
Remove
(
gitSsh
.
Name
())
}
if
script
!=
nil
{
os
.
Remove
(
script
.
Name
())
g
os
.
Remove
(
script
.
Name
())
}
}()
var
err
error
// write git.sh script to temp file
gitSsh
,
err
=
writeScriptFile
(
gitWrapperScript
(
gitBinary
))
gitSsh
,
err
=
writeScriptFile
(
gitWrapperScript
())
if
err
!=
nil
{
return
err
}
...
...
@@ -163,9 +165,9 @@ func (r *Repo) pullWithKey(params []string) error {
func
(
r
*
Repo
)
Prepare
()
error
{
// check if directory exists or is empty
// if not, create directory
fs
,
err
:=
ioutil
.
ReadDir
(
r
.
Path
)
fs
,
err
:=
gos
.
ReadDir
(
r
.
Path
)
if
err
!=
nil
||
len
(
fs
)
==
0
{
return
os
.
MkdirAll
(
r
.
Path
,
os
.
FileMode
(
0755
))
return
g
os
.
MkdirAll
(
r
.
Path
,
os
.
FileMode
(
0755
))
}
// validate git repo
...
...
@@ -180,9 +182,15 @@ func (r *Repo) Prepare() error {
if
isGit
{
// check if same repository
var
repoUrl
string
if
repoUrl
,
err
=
r
.
getRepoUrl
();
err
==
nil
&&
repoUrl
==
r
.
Url
{
r
.
pulled
=
true
return
nil
if
repoUrl
,
err
=
r
.
getRepoUrl
();
err
==
nil
{
// add .git suffix if missing for adequate comparison.
if
!
strings
.
HasSuffix
(
repoUrl
,
".git"
)
{
repoUrl
+=
".git"
}
if
repoUrl
==
r
.
Url
{
r
.
pulled
=
true
return
nil
}
}
if
err
!=
nil
{
return
fmt
.
Errorf
(
"Cannot retrieve repo url for %v Error: %v"
,
r
.
Path
,
err
)
...
...
@@ -205,7 +213,7 @@ func (r *Repo) getMostRecentCommit() (string, error) {
// getRepoUrl retrieves remote origin url for the git repository at path
func
(
r
*
Repo
)
getRepoUrl
()
(
string
,
error
)
{
_
,
err
:=
os
.
Stat
(
r
.
Path
)
_
,
err
:=
g
os
.
Stat
(
r
.
Path
)
if
err
!=
nil
{
return
""
,
err
}
...
...
@@ -230,9 +238,9 @@ func (r *Repo) postPullCommand() error {
return
err
}
// Init
Git validates git installation and
locates the git executable
// binary in PATH
func
Init
Git
()
error
{
// Init
validates git installation,
locates the git executable
// binary in PATH
and check for available shell to use.
func
Init
()
error
{
// prevent concurrent call
initMutex
.
Lock
()
defer
initMutex
.
Unlock
()
...
...
@@ -245,18 +253,30 @@ func InitGit() error {
// locate git binary in path
var
err
error
gitBinary
,
err
=
exec
.
LookPath
(
"git"
)
return
err
if
gitBinary
,
err
=
gos
.
LookPath
(
"git"
);
err
!=
nil
{
return
fmt
.
Errorf
(
"Git middleware requires git installed. Cannot find git binary in PATH"
)
}
// locate bash in PATH. If not found, fallback to sh.
// If neither is found, return error.
shell
=
"bash"
if
_
,
err
=
gos
.
LookPath
(
"bash"
);
err
!=
nil
{
shell
=
"sh"
if
_
,
err
=
gos
.
LookPath
(
"sh"
);
err
!=
nil
{
return
fmt
.
Errorf
(
"Git middleware requires either bash or sh."
)
}
}
return
nil
}
// runCmd is a helper function to run commands.
// It runs command with args from directory at dir.
// The executed process outputs to os.Stderr
func
runCmd
(
command
string
,
args
[]
string
,
dir
string
)
error
{
cmd
:=
exec
.
Command
(
command
,
args
...
)
cmd
.
Std
err
=
os
.
Stderr
cmd
.
Std
out
=
os
.
Stderr
cmd
.
Dir
=
dir
cmd
:=
gos
.
Command
(
command
,
args
...
)
cmd
.
Std
out
(
os
.
Stderr
)
cmd
.
Std
err
(
os
.
Stderr
)
cmd
.
Dir
(
dir
)
if
err
:=
cmd
.
Start
();
err
!=
nil
{
return
err
}
...
...
@@ -267,8 +287,8 @@ func runCmd(command string, args []string, dir string) error {
// It runs command with args from directory at dir.
// If successful, returns output and nil error
func
runCmdOutput
(
command
string
,
args
[]
string
,
dir
string
)
(
string
,
error
)
{
cmd
:=
exec
.
Command
(
command
,
args
...
)
cmd
.
Dir
=
dir
cmd
:=
gos
.
Command
(
command
,
args
...
)
cmd
.
Dir
(
dir
)
var
err
error
if
output
,
err
:=
cmd
.
Output
();
err
==
nil
{
return
string
(
bytes
.
TrimSpace
(
output
)),
nil
...
...
@@ -279,8 +299,8 @@ func runCmdOutput(command string, args []string, dir string) (string, error) {
// writeScriptFile writes content to a temporary file.
// It changes the temporary file mode to executable and
// closes it to prepare it for execution.
func
writeScriptFile
(
content
[]
byte
)
(
file
*
os
.
File
,
err
error
)
{
if
file
,
err
=
ioutil
.
TempFile
(
""
,
"caddy"
);
err
!=
nil
{
func
writeScriptFile
(
content
[]
byte
)
(
file
git
os
.
File
,
err
error
)
{
if
file
,
err
=
gos
.
TempFile
(
""
,
"caddy"
);
err
!=
nil
{
return
nil
,
err
}
if
_
,
err
=
file
.
Write
(
content
);
err
!=
nil
{
...
...
@@ -293,8 +313,8 @@ func writeScriptFile(content []byte) (file *os.File, err error) {
}
// gitWrapperScript forms content for git.sh script
var
gitWrapperScript
=
func
(
gitBinary
string
)
[]
byte
{
return
[]
byte
(
fmt
.
Sprintf
(
`#!/bin/
bash
func
gitWrapperScript
(
)
[]
byte
{
return
[]
byte
(
fmt
.
Sprintf
(
`#!/bin/
%v
# The MIT License (MIT)
# Copyright (c) 2013 Alvin Abad
...
...
@@ -323,17 +343,17 @@ fi
# Run the git command
%v "$@"
`
,
gitBinary
))
`
,
shell
,
gitBinary
))
}
// bashScript forms content of bash script to clone or update a repo using ssh
var
bashScript
=
func
(
gitShPath
string
,
repo
*
Repo
,
params
[]
string
)
[]
byte
{
return
[]
byte
(
fmt
.
Sprintf
(
`#!/bin/
bash
func
bashScript
(
gitShPath
string
,
repo
*
Repo
,
params
[]
string
)
[]
byte
{
return
[]
byte
(
fmt
.
Sprintf
(
`#!/bin/
%v
mkdir -p ~/.ssh;
touch ~/.ssh/known_hosts;
ssh-keyscan -t rsa,dsa %v 2>&1 | sort -u - ~/.ssh/known_hosts > ~/.ssh/tmp_hosts;
cat ~/.ssh/tmp_hosts >> ~/.ssh/known_hosts;
%v -i %v %v;
`
,
repo
.
Host
,
gitShPath
,
repo
.
KeyPath
,
strings
.
Join
(
params
,
" "
)))
`
,
shell
,
repo
.
Host
,
gitShPath
,
repo
.
KeyPath
,
strings
.
Join
(
params
,
" "
)))
}
middleware/git/git_test.go
0 → 100644
View file @
f44cd5d7
package
git
import
(
"io/ioutil"
"log"
"testing"
"time"
"github.com/mholt/caddy/middleware/git/gittest"
)
// init sets the OS used to fakeOS.
func
init
()
{
SetOS
(
gittest
.
FakeOS
)
}
func
check
(
t
*
testing
.
T
,
err
error
)
{
if
err
!=
nil
{
t
.
Errorf
(
"Error not expected but found %v"
,
err
)
}
}
func
TestInit
(
t
*
testing
.
T
)
{
err
:=
Init
()
check
(
t
,
err
)
}
func
TestHelpers
(
t
*
testing
.
T
)
{
f
,
err
:=
writeScriptFile
([]
byte
(
"script"
))
check
(
t
,
err
)
var
b
[
6
]
byte
_
,
err
=
f
.
Read
(
b
[
:
])
check
(
t
,
err
)
if
string
(
b
[
:
])
!=
"script"
{
t
.
Errorf
(
"Expected script found %v"
,
string
(
b
[
:
]))
}
out
,
err
:=
runCmdOutput
(
gitBinary
,
[]
string
{
"-version"
},
""
)
check
(
t
,
err
)
if
out
!=
gittest
.
CmdOutput
{
t
.
Errorf
(
"Expected %v found %v"
,
gittest
.
CmdOutput
,
out
)
}
err
=
runCmd
(
gitBinary
,
[]
string
{
"-version"
},
""
)
check
(
t
,
err
)
wScript
:=
gitWrapperScript
()
if
string
(
wScript
)
!=
expectedWrapperScript
{
t
.
Errorf
(
"Expected %v found %v"
,
expectedWrapperScript
,
string
(
wScript
))
}
f
,
err
=
writeScriptFile
(
wScript
)
check
(
t
,
err
)
repo
:=
&
Repo
{
Host
:
"github.com"
,
KeyPath
:
"~/.key"
}
script
:=
string
(
bashScript
(
f
.
Name
(),
repo
,
[]
string
{
"clone"
,
"git@github.com/repo/user"
}))
if
script
!=
expectedBashScript
{
t
.
Errorf
(
"Expected %v found %v"
,
expectedBashScript
,
script
)
}
}
func
TestGit
(
t
*
testing
.
T
)
{
// prepare
repos
:=
[]
*
Repo
{
nil
,
&
Repo
{
Path
:
"gitdir"
,
Url
:
"success.git"
},
}
for
_
,
r
:=
range
repos
{
repo
:=
createRepo
(
r
)
err
:=
repo
.
Prepare
()
check
(
t
,
err
)
}
// pull with success
logFile
:=
gittest
.
Open
(
"file"
)
Logger
=
log
.
New
(
logFile
,
""
,
0
)
tests
:=
[]
struct
{
repo
*
Repo
output
string
}{
{
&
Repo
{
Path
:
"gitdir"
,
Url
:
"git@github.com:user/repo.git"
,
KeyPath
:
"~/.key"
,
Then
:
"echo Hello"
},
`git@github.com:user/repo.git pulled.
Command echo Hello successful.
`
,
},
{
&
Repo
{
Path
:
"gitdir"
,
Url
:
"https://github.com/user/repo.git"
,
Then
:
"echo Hello"
},
`https://github.com/user/repo.git pulled.
Command echo Hello successful.
`
,
},
{
&
Repo
{
Url
:
"git@github.com:user/repo"
},
`git@github.com:user/repo pulled.
`
,
},
}
for
i
,
test
:=
range
tests
{
gittest
.
CmdOutput
=
test
.
repo
.
Url
test
.
repo
=
createRepo
(
test
.
repo
)
err
:=
test
.
repo
.
Prepare
()
check
(
t
,
err
)
err
=
test
.
repo
.
Pull
()
check
(
t
,
err
)
out
,
err
:=
ioutil
.
ReadAll
(
logFile
)
check
(
t
,
err
)
if
test
.
output
!=
string
(
out
)
{
t
.
Errorf
(
"Pull with Success %v: Expected %v found %v"
,
i
,
test
.
output
,
string
(
out
))
}
}
// pull with error
repos
=
[]
*
Repo
{
&
Repo
{
Path
:
"gitdir"
,
Url
:
"http://github.com:u/repo.git"
},
&
Repo
{
Path
:
"gitdir"
,
Url
:
"https://github.com/user/repo.git"
,
Then
:
"echo Hello"
},
&
Repo
{
Path
:
"gitdir"
},
&
Repo
{
Path
:
"gitdir"
,
KeyPath
:
".key"
},
}
gittest
.
CmdOutput
=
"git@github.com:u1/repo.git"
for
i
,
repo
:=
range
repos
{
repo
=
createRepo
(
repo
)
err
:=
repo
.
Prepare
()
if
err
==
nil
{
t
.
Errorf
(
"Pull with Error %v: Error expected but not found %v"
,
i
,
err
)
continue
}
expected
:=
"Another git repo 'git@github.com:u1/repo.git' exists at gitdir"
if
expected
!=
err
.
Error
()
{
t
.
Errorf
(
"Pull with Error %v: Expected %v found %v"
,
i
,
expected
,
err
.
Error
())
}
}
}
func
createRepo
(
r
*
Repo
)
*
Repo
{
repo
:=
&
Repo
{
Url
:
"git@github.com/user/test"
,
Path
:
"."
,
Host
:
"github.com"
,
Branch
:
"master"
,
Interval
:
time
.
Second
*
60
,
}
if
r
==
nil
{
return
repo
}
if
r
.
Branch
!=
""
{
repo
.
Branch
=
r
.
Branch
}
if
r
.
Host
!=
""
{
repo
.
Branch
=
r
.
Branch
}
if
r
.
Interval
!=
0
{
repo
.
Interval
=
r
.
Interval
}
if
r
.
KeyPath
!=
""
{
repo
.
KeyPath
=
r
.
KeyPath
}
if
r
.
Path
!=
""
{
repo
.
Path
=
r
.
Path
}
if
r
.
Then
!=
""
{
repo
.
Then
=
r
.
Then
}
if
r
.
Url
!=
""
{
repo
.
Url
=
r
.
Url
}
return
repo
}
var
expectedBashScript
=
`#!/bin/bash
mkdir -p ~/.ssh;
touch ~/.ssh/known_hosts;
ssh-keyscan -t rsa,dsa github.com 2>&1 | sort -u - ~/.ssh/known_hosts > ~/.ssh/tmp_hosts;
cat ~/.ssh/tmp_hosts >> ~/.ssh/known_hosts;
`
+
gittest
.
TempFileName
+
` -i ~/.key clone git@github.com/repo/user;
`
var
expectedWrapperScript
=
`#!/bin/bash
# The MIT License (MIT)
# Copyright (c) 2013 Alvin Abad
if [ $# -eq 0 ]; then
echo "Git wrapper script that can specify an ssh-key file
Usage:
git.sh -i ssh-key-file git-command
"
exit 1
fi
# remove temporary file on exit
trap 'rm -f /tmp/.git_ssh.$$' 0
if [ "$1" = "-i" ]; then
SSH_KEY=$2; shift; shift
echo "ssh -i $SSH_KEY \$@" > /tmp/.git_ssh.$$
chmod +x /tmp/.git_ssh.$$
export GIT_SSH=/tmp/.git_ssh.$$
fi
# in case the git command is repeated
[ "$1" = "git" ] && shift
# Run the git command
/usr/bin/git "$@"
`
middleware/git/gitos/gitos.go
0 → 100644
View file @
f44cd5d7
package
gitos
import
(
"io"
"io/ioutil"
"os"
"os/exec"
)
// File is an abstraction for file (os.File).
type
File
interface
{
// Name returns the name of the file
Name
()
string
// Stat returns the FileInfo structure describing file.
Stat
()
(
os
.
FileInfo
,
error
)
// Close closes the File, rendering it unusable for I/O.
Close
()
error
// Chmod changes the mode of the file.
Chmod
(
os
.
FileMode
)
error
// Read reads up to len(b) bytes from the File. It returns the number of
// bytes read and an error, if any.
Read
([]
byte
)
(
int
,
error
)
// Write writes len(b) bytes to the File. It returns the number of bytes
// written and an error, if any.
Write
([]
byte
)
(
int
,
error
)
}
// Cmd is an abstraction for external commands (os.Cmd).
type
Cmd
interface
{
// Run starts the specified command and waits for it to complete.
Run
()
error
// Start starts the specified command but does not wait for it to complete.
Start
()
error
// Wait waits for the command to exit. It must have been started by Start.
Wait
()
error
// Output runs the command and returns its standard output.
Output
()
([]
byte
,
error
)
// Dir sets the working directory of the command.
Dir
(
string
)
// Stdin sets the process's standard input.
Stdin
(
io
.
Reader
)
// Stdout sets the process's standard output.
Stdout
(
io
.
Writer
)
// Stderr sets the process's standard output.
Stderr
(
io
.
Writer
)
}
// gitCmd represents external commands executed by git.
type
gitCmd
struct
{
*
exec
.
Cmd
}
// Dir sets the working directory of the command.
func
(
g
*
gitCmd
)
Dir
(
dir
string
)
{
g
.
Cmd
.
Dir
=
dir
}
// Stdin sets the process's standard input.
func
(
g
*
gitCmd
)
Stdin
(
stdin
io
.
Reader
)
{
g
.
Cmd
.
Stdin
=
stdin
}
// Stdout sets the process's standard output.
func
(
g
*
gitCmd
)
Stdout
(
stdout
io
.
Writer
)
{
g
.
Cmd
.
Stdout
=
stdout
}
// Stderr sets the process's standard output.
func
(
g
*
gitCmd
)
Stderr
(
stderr
io
.
Writer
)
{
g
.
Cmd
.
Stderr
=
stderr
}
// OS is an abstraction for required OS level functions.
type
OS
interface
{
// Command returns the Cmd to execute the named program with the
// given arguments.
Command
(
string
,
...
string
)
Cmd
// Mkdir creates a new directory with the specified name and permission
// bits.
Mkdir
(
string
,
os
.
FileMode
)
error
// MkdirAll creates a directory named path, along with any necessary
// parents.
MkdirAll
(
string
,
os
.
FileMode
)
error
// Stat returns a FileInfo describing the named file.
Stat
(
string
)
(
os
.
FileInfo
,
error
)
// Remove removes the named file or directory.
Remove
(
string
)
error
// ReadDir reads the directory named by dirname and returns a list of
// directory entries.
ReadDir
(
string
)
([]
os
.
FileInfo
,
error
)
// LookPath searches for an executable binary named file in the directories
// named by the PATH environment variable.
LookPath
(
string
)
(
string
,
error
)
// TempFile creates a new temporary file in the directory dir with a name
// beginning with prefix, opens the file for reading and writing, and
// returns the resulting File.
TempFile
(
string
,
string
)
(
File
,
error
)
}
// GitOS is the implementation of OS for git.
type
GitOS
struct
{}
// Mkdir calls os.Mkdir.
func
(
g
GitOS
)
Mkdir
(
name
string
,
perm
os
.
FileMode
)
error
{
return
os
.
Mkdir
(
name
,
perm
)
}
// MkdirAll calls os.MkdirAll.
func
(
g
GitOS
)
MkdirAll
(
path
string
,
perm
os
.
FileMode
)
error
{
return
os
.
MkdirAll
(
path
,
perm
)
}
// Stat calls os.Stat.
func
(
g
GitOS
)
Stat
(
name
string
)
(
os
.
FileInfo
,
error
)
{
return
os
.
Stat
(
name
)
}
// Remove calls os.Remove.
func
(
g
GitOS
)
Remove
(
name
string
)
error
{
return
os
.
Remove
(
name
)
}
// LookPath calls exec.LookPath.
func
(
g
GitOS
)
LookPath
(
file
string
)
(
string
,
error
)
{
return
exec
.
LookPath
(
file
)
}
// TempFile calls ioutil.TempFile.
func
(
g
GitOS
)
TempFile
(
dir
,
prefix
string
)
(
File
,
error
)
{
return
ioutil
.
TempFile
(
dir
,
prefix
)
}
// ReadDir calls ioutil.ReadDir.
func
(
g
GitOS
)
ReadDir
(
dirname
string
)
([]
os
.
FileInfo
,
error
)
{
return
ioutil
.
ReadDir
(
dirname
)
}
// Command calls exec.Command.
func
(
g
GitOS
)
Command
(
name
string
,
args
...
string
)
Cmd
{
return
&
gitCmd
{
exec
.
Command
(
name
,
args
...
)}
}
middleware/git/gittest/gittest.go
0 → 100644
View file @
f44cd5d7
// Package gittest is a test package for the git middleware.
// It implements a mock gitos.OS, gitos.Cmd and gitos.File.
package
gittest
import
(
"io"
"os"
"time"
"github.com/mholt/caddy/middleware/git/gitos"
)
// FakeOS implements a mock gitos.OS, gitos.Cmd and gitos.File.
var
FakeOS
=
fakeOS
{}
// CmdOutput is the output of any call to the mocked gitos.Cmd's Output().
var
CmdOutput
=
"success"
// TempFileName is the name of any file returned by mocked gitos.OS's TempFile().
var
TempFileName
=
"tempfile"
// dirs mocks a fake git dir if filename is "gitdir".
var
dirs
=
map
[
string
][]
os
.
FileInfo
{
"gitdir"
:
{
fakeInfo
{
name
:
".git"
,
dir
:
true
},
},
}
// Open creates a new mock gitos.File.
func
Open
(
name
string
)
gitos
.
File
{
return
&
fakeFile
{
name
:
name
}
}
// fakeFile is a mock gitos.File.
type
fakeFile
struct
{
name
string
dir
bool
content
[]
byte
info
fakeInfo
}
func
(
f
fakeFile
)
Name
()
string
{
return
f
.
name
}
func
(
f
fakeFile
)
Stat
()
(
os
.
FileInfo
,
error
)
{
return
fakeInfo
{
name
:
f
.
name
},
nil
}
func
(
f
fakeFile
)
Close
()
error
{
return
nil
}
func
(
f
fakeFile
)
Chmod
(
mode
os
.
FileMode
)
error
{
f
.
info
.
mode
=
mode
return
nil
}
func
(
f
*
fakeFile
)
Read
(
b
[]
byte
)
(
int
,
error
)
{
if
len
(
f
.
content
)
==
0
{
return
0
,
io
.
EOF
}
n
:=
copy
(
b
,
f
.
content
)
f
.
content
=
f
.
content
[
n
:
]
return
n
,
nil
}
func
(
f
*
fakeFile
)
Write
(
b
[]
byte
)
(
int
,
error
)
{
f
.
content
=
append
(
f
.
content
,
b
...
)
return
len
(
b
),
nil
}
// fakeCmd is a mock git.Cmd.
type
fakeCmd
struct
{}
func
(
f
fakeCmd
)
Run
()
error
{
return
nil
}
func
(
f
fakeCmd
)
Start
()
error
{
return
nil
}
func
(
f
fakeCmd
)
Wait
()
error
{
return
nil
}
func
(
f
fakeCmd
)
Output
()
([]
byte
,
error
)
{
return
[]
byte
(
CmdOutput
),
nil
}
func
(
f
fakeCmd
)
Dir
(
dir
string
)
{}
func
(
f
fakeCmd
)
Stdin
(
stdin
io
.
Reader
)
{}
func
(
f
fakeCmd
)
Stdout
(
stdout
io
.
Writer
)
{}
func
(
f
fakeCmd
)
Stderr
(
stderr
io
.
Writer
)
{}
// fakeInfo is a mock os.FileInfo.
type
fakeInfo
struct
{
name
string
dir
bool
mode
os
.
FileMode
}
func
(
f
fakeInfo
)
Name
()
string
{
return
f
.
name
}
func
(
f
fakeInfo
)
Size
()
int64
{
return
1024
}
func
(
f
fakeInfo
)
Mode
()
os
.
FileMode
{
return
f
.
mode
}
func
(
f
fakeInfo
)
ModTime
()
time
.
Time
{
return
time
.
Now
()
.
Truncate
(
time
.
Hour
)
}
func
(
f
fakeInfo
)
IsDir
()
bool
{
return
f
.
dir
}
func
(
f
fakeInfo
)
Sys
()
interface
{}
{
return
nil
}
// fakeOS is a mock git.OS.
type
fakeOS
struct
{}
func
(
f
fakeOS
)
Mkdir
(
name
string
,
perm
os
.
FileMode
)
error
{
return
nil
}
func
(
f
fakeOS
)
MkdirAll
(
path
string
,
perm
os
.
FileMode
)
error
{
return
nil
}
func
(
f
fakeOS
)
Stat
(
name
string
)
(
os
.
FileInfo
,
error
)
{
return
fakeInfo
{
name
:
name
},
nil
}
func
(
f
fakeOS
)
Remove
(
name
string
)
error
{
return
nil
}
func
(
f
fakeOS
)
LookPath
(
file
string
)
(
string
,
error
)
{
return
"/usr/bin/"
+
file
,
nil
}
func
(
f
fakeOS
)
TempFile
(
dir
,
prefix
string
)
(
gitos
.
File
,
error
)
{
return
&
fakeFile
{
name
:
TempFileName
,
info
:
fakeInfo
{
name
:
TempFileName
}},
nil
}
func
(
f
fakeOS
)
ReadDir
(
dirname
string
)
([]
os
.
FileInfo
,
error
)
{
if
f
,
ok
:=
dirs
[
dirname
];
ok
{
return
f
,
nil
}
return
nil
,
nil
}
func
(
f
fakeOS
)
Command
(
name
string
,
args
...
string
)
gitos
.
Cmd
{
return
fakeCmd
{}
}
middleware/git/os.go
0 → 100644
View file @
f44cd5d7
package
git
import
"github.com/mholt/caddy/middleware/git/gitos"
// gos is the OS used by git.
var
gos
gitos
.
OS
=
gitos
.
GitOS
{}
// SetOS sets the OS to be used. Intended to be used for tests
// to abstract OS level git actions.
func
SetOS
(
os
gitos
.
OS
)
{
gos
=
os
}
middleware/rewrite/rewrite_test.go
View file @
f44cd5d7
...
...
@@ -28,6 +28,7 @@ func TestRewrite(t *testing.T) {
[]
string
{
"/abc/"
,
"ab"
,
"/abc/{file}"
,
".html|"
},
[]
string
{
"/abcd/"
,
"ab"
,
"/a/{dir}/{file}"
,
".html|"
},
[]
string
{
"/abcde/"
,
"ab"
,
"/a#{frag}"
,
".html|"
},
[]
string
{
"/ab/"
,
`.*\.jpg`
,
"/ajpg"
,
""
},
}
for
_
,
regexpRule
:=
range
regexpRules
{
...
...
@@ -76,6 +77,7 @@ func TestRewrite(t *testing.T) {
{
"/abcd/abcd.html"
,
"/a/abcd/abcd.html"
},
{
"/abcde/abcde.html"
,
"/a"
},
{
"/abcde/abcde.html#1234"
,
"/a#1234"
},
{
"/ab/ab.jpg"
,
"/ajpg"
},
}
for
i
,
test
:=
range
tests
{
...
...
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