build/devapp/noappengine.go

169 строки
4.2 KiB
Go

// Copyright 2017 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.
// +build !appengine
package devapp
import (
"errors"
"flag"
"fmt"
"io/ioutil"
stdlog "log"
"net/http"
"os"
"path/filepath"
"strings"
"sync"
"time"
"golang.org/x/net/context"
)
var tokenFile = flag.String("token", "", "read GitHub token personal access token from `file` (default $HOME/.github-issue-token)")
func init() {
log = &stderrLogger{}
}
type stderrLogger struct{}
func (s *stderrLogger) Infof(_ context.Context, format string, args ...interface{}) {
stdlog.Printf(format, args...)
}
func (s *stderrLogger) Errorf(_ context.Context, format string, args ...interface{}) {
stdlog.Printf(format, args...)
}
func (s *stderrLogger) Criticalf(_ context.Context, format string, args ...interface{}) {
stdlog.Printf(format, args...)
}
func newTransport(ctx context.Context) http.RoundTripper {
dline, ok := ctx.Deadline()
t := &http.Transport{}
if ok {
t.ResponseHeaderTimeout = time.Until(dline)
}
return t
}
func currentUserEmail(ctx context.Context) string {
// TODO
return ""
}
// loginURL returns a URL that, when visited, prompts the user to sign in,
// then redirects the user to the URL specified by dest.
func loginURL(ctx context.Context, path string) (string, error) {
return "", errors.New("loginURL: unimplemented")
}
func logoutURL(ctx context.Context, path string) (string, error) {
return "", errors.New("logoutURL: unimplemented")
}
func newHTTPClient(ctx context.Context) *http.Client {
return &http.Client{}
}
func getCaches(ctx context.Context, names ...string) map[string]*Cache {
out := make(map[string]*Cache)
dstoreMu.Lock()
defer dstoreMu.Unlock()
for _, name := range names {
if val, ok := dstore[name]; ok {
out[name] = val
} else {
// Ignore errors since they might not exist.
out[name] = &Cache{}
}
}
return out
}
var dstore = make(map[string]*Cache)
var dstoreMu sync.Mutex
var pageStore = make(map[string]*Page)
var pageStoreMu sync.Mutex
func getCache(_ context.Context, name string) (*Cache, error) {
dstoreMu.Lock()
defer dstoreMu.Unlock()
cache, ok := dstore[name]
if ok {
return cache, nil
}
return &Cache{}, fmt.Errorf("cache key %s not found", name)
}
func getPage(ctx context.Context, name string) (*Page, error) {
pageStoreMu.Lock()
defer pageStoreMu.Unlock()
page, ok := pageStore[name]
if ok {
return page, nil
}
return &Page{}, fmt.Errorf("page key %s not found", name)
}
func writePage(ctx context.Context, page string, content []byte) error {
pageStoreMu.Lock()
defer pageStoreMu.Unlock()
entity := &Page{
Content: content,
}
pageStore[page] = entity
return nil
}
func putCache(_ context.Context, name string, c *Cache) error {
dstoreMu.Lock()
defer dstoreMu.Unlock()
dstore[name] = c
return nil
}
var githubToken string
var githubOnceErr error
var githubOnce sync.Once
func getToken(ctx context.Context) (string, error) {
githubOnce.Do(func() {
const short = ".github-issue-token"
filename := filepath.Clean(os.Getenv("HOME") + "/" + short)
shortFilename := filepath.Clean("$HOME/" + short)
if *tokenFile != "" {
filename = *tokenFile
shortFilename = *tokenFile
}
data, err := ioutil.ReadFile(filename)
if err != nil {
msg := fmt.Sprintln("reading token: ", err, "\n\n"+
"Please create a personal access token at https://github.com/settings/tokens/new\n"+
"and write it to ", shortFilename, " to use this program.\n"+
"The token only needs the repo scope, or private_repo if you want to\n"+
"view or edit issues for private repositories.\n"+
"The benefit of using a personal access token over using your GitHub\n"+
"password directly is that you can limit its use and revoke it at any time.\n\n")
githubOnceErr = errors.New(msg)
return
}
fi, err := os.Stat(filename)
if fi.Mode()&0077 != 0 {
githubOnceErr = fmt.Errorf("reading token: %s mode is %#o, want %#o", shortFilename, fi.Mode()&0777, fi.Mode()&0700)
return
}
githubToken = strings.TrimSpace(string(data))
})
return githubToken, githubOnceErr
}
func getContext(r *http.Request) context.Context {
return r.Context()
}