mirror of
https://github.com/dutchcoders/transfer.sh.git
synced 2025-01-15 05:00:18 +01:00
cb6e5cb0c7
* use dep for vendoring * lets encrypt * moved web to transfer.sh-web repo * single command install * added first tests
171 lines
4.3 KiB
Go
171 lines
4.3 KiB
Go
// Copyright 2013 The Go Authors. All rights reserved.
|
|
//
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file or at
|
|
// https://developers.google.com/open-source/licenses/bsd.
|
|
|
|
package gosrc
|
|
|
|
import (
|
|
"log"
|
|
"net/http"
|
|
"path"
|
|
"regexp"
|
|
"time"
|
|
)
|
|
|
|
func init() {
|
|
addService(&service{
|
|
pattern: regexp.MustCompile(`^bitbucket\.org/(?P<owner>[a-z0-9A-Z_.\-]+)/(?P<repo>[a-z0-9A-Z_.\-]+)(?P<dir>/[a-z0-9A-Z_.\-/]*)?$`),
|
|
prefix: "bitbucket.org/",
|
|
get: getBitbucketDir,
|
|
})
|
|
}
|
|
|
|
var bitbucketEtagRe = regexp.MustCompile(`^(hg|git)-`)
|
|
|
|
type bitbucketRepo struct {
|
|
Scm string
|
|
CreatedOn string `json:"created_on"`
|
|
LastUpdated string `json:"last_updated"`
|
|
ForkOf struct {
|
|
Scm string
|
|
} `json:"fork_of"`
|
|
Followers int `json:"followers_count"`
|
|
IsFork bool `json:"is_fork"`
|
|
}
|
|
|
|
type bitbucketNode struct {
|
|
Node string `json:"node"`
|
|
Timestamp string `json:"utctimestamp"`
|
|
}
|
|
|
|
func getBitbucketDir(client *http.Client, match map[string]string, savedEtag string) (*Directory, error) {
|
|
var repo *bitbucketRepo
|
|
c := &httpClient{client: client}
|
|
|
|
if m := bitbucketEtagRe.FindStringSubmatch(savedEtag); m != nil {
|
|
match["vcs"] = m[1]
|
|
} else {
|
|
repo, err := getBitbucketRepo(c, match)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
match["vcs"] = repo.Scm
|
|
}
|
|
|
|
tags := make(map[string]string)
|
|
timestamps := make(map[string]time.Time)
|
|
|
|
for _, nodeType := range []string{"branches", "tags"} {
|
|
var nodes map[string]bitbucketNode
|
|
if _, err := c.getJSON(expand("https://api.bitbucket.org/1.0/repositories/{owner}/{repo}/{0}", match, nodeType), &nodes); err != nil {
|
|
return nil, err
|
|
}
|
|
for t, n := range nodes {
|
|
tags[t] = n.Node
|
|
const timeFormat = "2006-01-02 15:04:05Z07:00"
|
|
committed, err := time.Parse(timeFormat, n.Timestamp)
|
|
if err != nil {
|
|
log.Println("error parsing timestamp:", n.Timestamp)
|
|
continue
|
|
}
|
|
timestamps[t] = committed
|
|
}
|
|
}
|
|
|
|
var err error
|
|
tag, commit, err := bestTag(tags, defaultTags[match["vcs"]])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
match["tag"] = tag
|
|
match["commit"] = commit
|
|
etag := expand("{vcs}-{commit}", match)
|
|
if etag == savedEtag {
|
|
return nil, NotModifiedError{Since: timestamps[tag]}
|
|
}
|
|
|
|
if repo == nil {
|
|
repo, err = getBitbucketRepo(c, match)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
var contents struct {
|
|
Directories []string
|
|
Files []struct {
|
|
Path string
|
|
}
|
|
}
|
|
|
|
if _, err := c.getJSON(expand("https://api.bitbucket.org/1.0/repositories/{owner}/{repo}/src/{tag}{dir}/", match), &contents); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var files []*File
|
|
var dataURLs []string
|
|
|
|
for _, f := range contents.Files {
|
|
_, name := path.Split(f.Path)
|
|
if isDocFile(name) {
|
|
files = append(files, &File{Name: name, BrowseURL: expand("https://bitbucket.org/{owner}/{repo}/src/{tag}/{0}", match, f.Path)})
|
|
dataURLs = append(dataURLs, expand("https://api.bitbucket.org/1.0/repositories/{owner}/{repo}/raw/{tag}/{0}", match, f.Path))
|
|
}
|
|
}
|
|
|
|
if err := c.getFiles(dataURLs, files); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
status := Active
|
|
if isBitbucketDeadEndFork(repo) {
|
|
status = DeadEndFork
|
|
}
|
|
|
|
return &Directory{
|
|
BrowseURL: expand("https://bitbucket.org/{owner}/{repo}/src/{tag}{dir}", match),
|
|
Etag: etag,
|
|
Files: files,
|
|
LineFmt: "%s#cl-%d",
|
|
ProjectName: match["repo"],
|
|
ProjectRoot: expand("bitbucket.org/{owner}/{repo}", match),
|
|
ProjectURL: expand("https://bitbucket.org/{owner}/{repo}/", match),
|
|
Subdirectories: contents.Directories,
|
|
VCS: match["vcs"],
|
|
Status: status,
|
|
Fork: repo.IsFork,
|
|
Stars: repo.Followers,
|
|
}, nil
|
|
}
|
|
|
|
func getBitbucketRepo(c *httpClient, match map[string]string) (*bitbucketRepo, error) {
|
|
var repo bitbucketRepo
|
|
if _, err := c.getJSON(expand("https://api.bitbucket.org/1.0/repositories/{owner}/{repo}", match), &repo); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &repo, nil
|
|
}
|
|
|
|
func isBitbucketDeadEndFork(repo *bitbucketRepo) bool {
|
|
l := "2006-01-02T15:04:05.999999999"
|
|
created, err := time.Parse(l, repo.CreatedOn)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
updated, err := time.Parse(l, repo.LastUpdated)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
isDeadEndFork := false
|
|
if repo.ForkOf.Scm != "" && created.Unix() >= updated.Unix() {
|
|
isDeadEndFork = true
|
|
}
|
|
|
|
return isDeadEndFork
|
|
}
|