--- a/access/access.go Tue Sep 17 20:31:09 2019 -0500
+++ b/access/access.go Tue Dec 17 23:25:25 2019 -0600
@@ -1,6 +1,8 @@
@@ -15,17 +17,37 @@
-func Setup(reposPath, adminRepo string) error {
+func Setup(repositoriesPath, adminRepo string) error { + reposPath = repositoriesPath adminRepoName = adminRepo
adminRepoPath = filepath.Join(reposPath, adminRepo)
+ configPath, err := ioutil.TempFile("", "hgkeeper-hgweb-*.config") + hgwebConfigPath = configPath.Name() + if err := os.Remove(hgwebConfigPath); err != nil { + "failed to remove temporary hgweb config from %q", func AdminRepo() string {
@@ -34,6 +56,10 @@
+func HgwebConfigPath() string { // Refresh will try to reload the casbin model and policies followed by SSH
// keys. If there is an error it's possible that the casbin model and polcies
// could have been updated but the ssh keys were not.
@@ -49,6 +75,10 @@
+ if err := refreshHgWeb(reposPath); err != nil { --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hgweb/files/hgweb.cgi Tue Dec 17 23:25:25 2019 -0600
@@ -0,0 +1,9 @@
+config = '{{.HGWEB_CONFIG}}' +from mercurial import demandimport; demandimport.enable() +from mercurial.hgweb import hgweb, wsgicgi +application = hgweb(config) +wsgicgi.launch(application) --- a/hgweb/hgweb.go Tue Sep 17 20:31:09 2019 -0500
+++ b/hgweb/hgweb.go Tue Dec 17 23:25:25 2019 -0600
@@ -1,3 +1,4 @@
+//go:generate esc -o files.go -pkg hgweb -include files\/.+ -prefix files/ . @@ -5,39 +6,70 @@
log "github.com/sirupsen/logrus"
+ "bitbucket.org/rw_grim/hgkeeper/access"
func NewServer(listenAddr string) (*Server, error) {
+ listenAddr: listenAddr, -func (s *Server) Startup() error {
+func (s *Server) createCGI() error { cgiPath, err := ioutil.TempFile("", "hgkeeper-hgweb-*.cgi")
- log.Warnf("path: %q", cgiPath.Name())
+ // make the cgi file executable + if err := cgiPath.Chmod(0755); err != nil { + // create a template based for the cgi file + t := template.Must(template.New("cgi").Parse(FSMustString(false, "/hgweb.cgi"))) + data := map[string]string{ + "HGWEB_CONFIG": access.HgwebConfigPath(), + if err := t.Execute(cgiPath, data); err != nil { s.cgiPath = cgiPath.Name()
+func (s *Server) Listen() error { + if err := s.createCGI(); err != nil { s.server.Handler = &cgi.Handler{Path: s.cgiPath}
+ log.Infof("http listening on %s", s.listenAddr) return s.server.ListenAndServe()
-func (s *Server) Shutdown() {
+func (s *Server) Close() { if err := os.Remove(s.cgiPath); err != nil {
log.Warnf("failed to remove temporary cgi file %q: %v", s.cgiPath, err)
--- a/serve/command.go Tue Sep 17 20:31:09 2019 -0500
+++ b/serve/command.go Tue Dec 17 23:25:25 2019 -0600
@@ -16,12 +16,14 @@
SSHAddr string `kong:"flag,name='ssh-listen-addr',env='HGK_SSH_LISTEN_ADDR',short='l',help='what address to listen on',default=':22222'"`
SSHHostKeysPath string `kong:"flag,name='ssh-host-keys-path',env='HGK_SSH_HOST_KEYS_PATH',short='H',help='the path where host keys are kept',default='host-keys'"`
+ HTTPAddr string `kong:"flag,name='http-listen-addr',env='HGK_HTTP_LISTEN_ADDR',help='what address the http server listens on',default=':8080'"` func (c *Command) Run(g *globals.Globals) error {
if err := access.Setup(g.ReposPath, g.AdminRepo); err != nil {
+ defer access.Teardown() signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
@@ -32,12 +34,13 @@
- hgweb, err := hgweb.NewServer(":3333")
+ hgweb, err := hgweb.NewServer(c.HTTPAddr)
if err := ssh.Listen(c.SSHAddr); err != nil {
@@ -46,7 +49,7 @@
- if err := hgweb.Startup(); err != nil {
+ if err := hgweb.Listen(); err != nil { --- a/setup/resources/model.conf Tue Sep 17 20:31:09 2019 -0500
+++ b/setup/resources/model.conf Tue Dec 17 23:25:25 2019 -0600
@@ -2,7 +2,7 @@
# This model is based on the priorty example from the casbin documentation. It
# will evaluate polcies in a top to bottom approach accepting the first one that
-# matches. This means that you have to be care when defining your policies.
+# matches. This means that you have to be careful when defining your policies. # Say you would like to disable public access by default but then grant it to
# specific repositories later. This would need to be defined in the following
--- a/ssh/server.go Tue Sep 17 20:31:09 2019 -0500
+++ b/ssh/server.go Tue Dec 17 23:25:25 2019 -0600
@@ -117,3 +117,13 @@
+func (s *Server) Close() error { + if err := s.server.Close(); err != nil {