summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2014-02-19 17:50:53 +0800
committerLunny Xiao <xiaolunwen@gmail.com>2014-02-19 17:50:53 +0800
commitbe0ba9ea88aff8a658d0495d36accf944b74888d (patch)
treeff0b9b7eea8cd0d702a1a1ec1d9050110a5dab0e
parent94311e187f07b4ee2344db03279f39f200b4d39c (diff)
downloadgitea-be0ba9ea88aff8a658d0495d36accf944b74888d.tar.gz
gitea-be0ba9ea88aff8a658d0495d36accf944b74888d.zip
add ssh supports(unfinished)
-rw-r--r--conf/app.ini2
-rw-r--r--gogs.go67
-rw-r--r--models/models.go8
-rw-r--r--models/repo.go15
-rw-r--r--models/user.go13
-rw-r--r--serve.go164
-rw-r--r--utils/conf.go26
-rw-r--r--web.go51
8 files changed, 306 insertions, 40 deletions
diff --git a/conf/app.ini b/conf/app.ini
index fe279cb52b..c8fba31d7c 100644
--- a/conf/app.ini
+++ b/conf/app.ini
@@ -9,4 +9,4 @@ DB_TYPE = mysql
HOST =
NAME = gogs
USER = root
-PASSWD = root \ No newline at end of file
+PASSWD =
diff --git a/gogs.go b/gogs.go
index 140ee6518a..a0ed460d90 100644
--- a/gogs.go
+++ b/gogs.go
@@ -1,44 +1,49 @@
-// Copyright 2014 The Gogs Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
+// Copyright 2013-2014 gogs authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+// gogs(Go Git Service) is a Go clone of Github.
package main
import (
- "fmt"
- "net/http"
-
- "github.com/codegangsta/martini"
- "github.com/martini-contrib/render"
+ "os"
+ "runtime"
- "github.com/gogits/gogs/routers"
- "github.com/gogits/gogs/routers/user"
- "github.com/gogits/gogs/utils"
- "github.com/gogits/gogs/utils/log"
+ "github.com/codegangsta/cli"
)
+// +build go1.1
+
+// Test that go1.1 tag above is included in builds. main.go refers to this definition.
+const go11tag = true
+
const APP_VER = "0.0.0.0218"
func init() {
-
+ runtime.GOMAXPROCS(runtime.NumCPU())
}
func main() {
- log.Info("%s %s", utils.Cfg.MustValue("", "APP_NAME"), APP_VER)
-
- m := martini.Classic()
-
- // Middleware.
- m.Use(render.Renderer())
-
- // Routers.
- m.Get("/", routers.Dashboard)
- m.Get("/user/signin", user.SignIn)
- m.Any("/user/signup", user.SignUp)
-
- listenAddr := fmt.Sprintf("%s:%s",
- utils.Cfg.MustValue("server", "HTTP_ADDR"),
- utils.Cfg.MustValue("server", "HTTP_PORT", "3000"))
- log.Info("Listen: %s", listenAddr)
- http.ListenAndServe(listenAddr, m)
+ app := cli.NewApp()
+ app.Name = "gogs"
+ app.Usage = "Go Git Service"
+ app.Version = APP_VER
+ app.Commands = []cli.Command{
+ CmdWeb,
+ CmdServ,
+ }
+ app.Flags = append(app.Flags, []cli.Flag{
+ cli.BoolFlag{"noterm", "disable color output"},
+ }...)
+ app.Run(os.Args)
}
diff --git a/models/models.go b/models/models.go
index b4e69d94f8..55e441c530 100644
--- a/models/models.go
+++ b/models/models.go
@@ -17,7 +17,7 @@ import (
var (
orm *xorm.Engine
- repoRootPath string
+ RepoRootPath string
)
type Members struct {
@@ -71,5 +71,9 @@ func setEngine() {
func init() {
setEngine()
- orm.Sync(new(User))
+ err := orm.Sync(new(User), new(PublicKey), new(Repo), new(Access))
+ if err != nil {
+ log.Error("sync database struct error: %s", err)
+ os.Exit(1)
+ }
}
diff --git a/models/repo.go b/models/repo.go
index 489530f2a4..1eeeaa63ff 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -29,15 +29,22 @@ type Repo struct {
// check if repository is exist
func IsRepositoryExist(user *User, reposName string) (bool, error) {
repo := Repo{OwnerId: user.Id}
- // TODO: get repository by nocase name
- return orm.Where("lower_name = ?", strings.ToLower(reposName)).Get(&repo)
+ has, err := orm.Where("lower_name = ?", strings.ToLower(reposName)).Get(&repo)
+ if err != nil {
+ return has, err
+ }
+ s, err := os.Stat(filepath.Join(RepoRootPath, user.Name, reposName))
+ if err != nil {
+ return false, err
+ }
+ return s.IsDir(), nil
}
//
// create a repository for a user or orgnaziation
//
func CreateRepository(user *User, reposName string) (*Repo, error) {
- p := filepath.Join(repoRootPath, user.Name)
+ p := filepath.Join(RepoRootPath, user.Name)
os.MkdirAll(p, os.ModePerm)
f := filepath.Join(p, reposName+".git")
_, err := git.InitRepository(f, false)
@@ -108,7 +115,7 @@ func DeleteRepository(user *User, reposName string) (err error) {
session.Rollback()
return err
}
- if err = os.RemoveAll(filepath.Join(repoRootPath, user.Name, reposName+".git")); err != nil {
+ if err = os.RemoveAll(filepath.Join(RepoRootPath, user.Name, reposName+".git")); err != nil {
// TODO: log and delete manully
return err
}
diff --git a/models/user.go b/models/user.go
index bc9b8fc746..6cf7f67464 100644
--- a/models/user.go
+++ b/models/user.go
@@ -123,6 +123,19 @@ func (user *User) EncodePasswd() error {
return err
}
+func GetUserByKeyId(keyId int64) (*User, error) {
+ user := new(User)
+ has, err := orm.Sql("select a.* from user as a, public_key as b where a.id = b.owner_id and b.id=?", keyId).Get(user)
+ if err != nil {
+ return nil, err
+ }
+ if !has {
+ err = errors.New("not exist key owner")
+ return nil, err
+ }
+ return user, nil
+}
+
// LoginUserPlain validates user by raw user name and password.
func LoginUserPlain(name, passwd string) (*User, error) {
user := User{Name: name, Passwd: passwd}
diff --git a/serve.go b/serve.go
new file mode 100644
index 0000000000..066faa30ec
--- /dev/null
+++ b/serve.go
@@ -0,0 +1,164 @@
+package main
+
+import (
+ "fmt"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strconv"
+ "strings"
+
+ "github.com/codegangsta/cli"
+ "github.com/gogits/gogs/models"
+ "github.com/gogits/gogs/utils/log"
+)
+
+var (
+ COMMANDS_READONLY = map[string]int{
+ "git-upload-pack": models.AU_WRITABLE,
+ "git upload-pack": models.AU_WRITABLE,
+ }
+
+ COMMANDS_WRITE = map[string]int{
+ "git-receive-pack": models.AU_READABLE,
+ "git receive-pack": models.AU_READABLE,
+ }
+)
+
+var CmdServ = cli.Command{
+ Name: "serv",
+ Usage: "just run",
+ Description: `
+gogs serv`,
+ Action: runServ,
+ Flags: []cli.Flag{
+ //cli.BoolFlag{"update, u", "update pakcage(s) and dependencies if any"},
+ //cli.BoolFlag{"verbose, v", "show process details"},
+ },
+}
+
+func In(b string, sl map[string]int) bool {
+ _, e := sl[b]
+ return e
+}
+
+func runServ(*cli.Context) {
+ keys := strings.Split(os.Args[2], "-")
+ if len(keys) != 2 {
+ fmt.Println("auth file format error")
+ return
+ }
+
+ keyId, err := strconv.ParseInt(keys[1], 10, 64)
+ if err != nil {
+ fmt.Println("auth file format error")
+ return
+ }
+ user, err := models.GetUserByKeyId(keyId)
+ if err != nil {
+ fmt.Println("You have no right to access")
+ return
+ }
+
+ cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
+ if cmd == "" {
+ fmt.Printf("Hi %s! You've successfully authenticated, but Gogits does not provide shell access.\n", user.Name)
+ return
+ }
+
+ f, _ := os.Create("test2.log")
+ f.WriteString(cmd)
+ f.Close()
+
+ log.Info("cmd is %s", cmd)
+
+ verb, args := parseCmd(cmd)
+ rr := strings.SplitN(strings.Trim(args, "'"), "/", 1)
+ if len(rr) != 2 {
+ fmt.Printf("Unavilable repository")
+ return
+ }
+ repoName := rr[1]
+ if strings.HasSuffix(repoName, ".git") {
+ repoName = repoName[:len(repoName)-4]
+ }
+ isWrite := In(verb, COMMANDS_WRITE)
+ isRead := In(verb, COMMANDS_READONLY)
+ switch {
+ case isWrite:
+ has, err := models.HasAccess(user.Name, repoName, COMMANDS_WRITE[verb])
+ if err != nil {
+ fmt.Println("Inernel error")
+ return
+ }
+ if !has {
+ fmt.Println("You have no right to access this repository")
+ return
+ }
+ case isRead:
+ has, err := models.HasAccess(user.Name, repoName, COMMANDS_READONLY[verb])
+ if err != nil {
+ fmt.Println("Inernel error")
+ return
+ }
+ if !has {
+ has, err = models.HasAccess(user.Name, repoName, COMMANDS_WRITE[verb])
+ if err != nil {
+ fmt.Println("Inernel error")
+ return
+ }
+ }
+ if !has {
+ fmt.Println("You have no right to access this repository")
+ return
+ }
+ default:
+ fmt.Println("Unknown command")
+ return
+ }
+
+ isExist, err := models.IsRepositoryExist(user, repoName)
+ if err != nil {
+ fmt.Println("Inernel error")
+ return
+ }
+
+ if !isExist {
+ if isRead {
+ fmt.Println("Repository is not exist")
+ return
+ } else if isWrite {
+ _, err := models.CreateRepository(user, repoName)
+ if err != nil {
+ fmt.Println("Create repository failed")
+ return
+ }
+ }
+ }
+
+ fullPath := filepath.Join(models.RepoRootPath, user.Name, repoName+".git")
+ newcmd := fmt.Sprintf("%s '%s'", verb, fullPath)
+ fmt.Println(newcmd)
+ gitcmd := exec.Command("git", "shell", "-c", newcmd)
+ gitcmd.Stdout = os.Stdout
+ gitcmd.Stderr = os.Stderr
+
+ err = gitcmd.Run()
+ if err != nil {
+ log.Error("execute command error: %s", err)
+ }
+}
+
+func parseCmd(cmd string) (string, string) {
+ ss := strings.SplitN(cmd, " ", 1)
+ if len(ss) != 2 {
+ return "", ""
+ }
+ verb, args := ss[0], ss[1]
+ if verb == "git" {
+ ss = strings.SplitN(args, " ", 1)
+ args = ss[1]
+ verb = fmt.Sprintf("%s %s", verb, ss[0])
+ }
+ return verb, args
+}
diff --git a/utils/conf.go b/utils/conf.go
index 0b1a39908d..75bd2462d6 100644
--- a/utils/conf.go
+++ b/utils/conf.go
@@ -7,17 +7,39 @@ package utils
import (
"fmt"
"os"
+ "os/exec"
+ "path"
+ "path/filepath"
"github.com/Unknwon/goconfig"
)
var Cfg *goconfig.ConfigFile
+func exeDir() (string, error) {
+ file, err := exec.LookPath(os.Args[0])
+ if err != nil {
+ return "", err
+ }
+ p, err := filepath.Abs(file)
+ if err != nil {
+ return "", err
+ }
+ return path.Dir(p), nil
+}
+
func init() {
var err error
- Cfg, err = goconfig.LoadConfigFile("conf/app.ini")
+ workDir, err := exeDir()
+ if err != nil {
+ fmt.Printf("Fail to get work directory: %s\n", err)
+ os.Exit(2)
+ }
+
+ cfgPath := filepath.Join(workDir, "conf", "app.ini")
+ Cfg, err = goconfig.LoadConfigFile(cfgPath)
if err != nil {
- fmt.Println("Cannot load config file 'app.ini'")
+ fmt.Printf("Cannot load config file '%s'\n", cfgPath)
os.Exit(2)
}
Cfg.BlockMode = false
diff --git a/web.go b/web.go
new file mode 100644
index 0000000000..f64b606383
--- /dev/null
+++ b/web.go
@@ -0,0 +1,51 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/codegangsta/cli"
+ "github.com/codegangsta/martini"
+ "github.com/martini-contrib/render"
+
+ "github.com/gogits/gogs/routers"
+ "github.com/gogits/gogs/routers/user"
+ "github.com/gogits/gogs/utils"
+ "github.com/gogits/gogs/utils/log"
+)
+
+var CmdWeb = cli.Command{
+ Name: "web",
+ Usage: "just run",
+ Description: `
+gogs web`,
+ Action: runWeb,
+ Flags: []cli.Flag{
+ //cli.BoolFlag{"update, u", "update pakcage(s) and dependencies if any"},
+ //cli.BoolFlag{"verbose, v", "show process details"},
+ },
+}
+
+func runWeb(*cli.Context) {
+ log.Info("%s %s", utils.Cfg.MustValue("", "APP_NAME"), APP_VER)
+
+ m := martini.Classic()
+
+ // Middleware.
+ m.Use(render.Renderer())
+
+ // Routers.
+ m.Get("/", routers.Dashboard)
+ m.Get("/user/signin", user.SignIn)
+ m.Any("/user/signup", user.SignUp)
+
+ listenAddr := fmt.Sprintf("%s:%s",
+ utils.Cfg.MustValue("server", "HTTP_ADDR"),
+ utils.Cfg.MustValue("server", "HTTP_PORT", "3000"))
+ log.Info("Listen: %s", listenAddr)
+ http.ListenAndServe(listenAddr, m)
+}