commit
182c2d5611
|
|
@ -1,2 +1 @@
|
|||
/pkg
|
||||
/bin
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
FROM gcr.io/google_containers/ubuntu-slim:0.1
|
||||
|
||||
ARG ARCH
|
||||
ADD bin/git-sync-${ARCH} /git-sync
|
||||
|
||||
ENV GIT_SYNC_DEST /git
|
||||
VOLUME ["/git"]
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y git ca-certificates --no-install-recommends && \
|
||||
|
|
@ -9,8 +11,6 @@ RUN apt-get update && \
|
|||
apt-get clean -y && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY git-sync /git-sync
|
||||
|
||||
# Move the existing SSH binary, then replace it with the wrapper script
|
||||
RUN mv /usr/bin/ssh /usr/bin/ssh-binary
|
||||
COPY ssh-wrapper.sh /usr/bin/ssh
|
||||
|
|
|
|||
|
|
@ -1,8 +1,22 @@
|
|||
{
|
||||
"ImportPath": "k8s.io/git-sync",
|
||||
"GoVersion": "go1.5",
|
||||
"GoVersion": "go1.6",
|
||||
"GodepVersion": "v66",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
"Deps": []
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "github.com/golang/glog",
|
||||
"Rev": "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/thockin/glogr",
|
||||
"Rev": "7a7f3ced4f9f52e96710761820bd85ed6c400aa5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/thockin/logr",
|
||||
"Rev": "103d90809f342ce8b186c0bc903a34bc1c8007be"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
95
Makefile
95
Makefile
|
|
@ -1,17 +1,90 @@
|
|||
all: push
|
||||
# Copyright 2016 The Kubernetes 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.
|
||||
|
||||
# 0.0 shouldn't clobber any released builds
|
||||
TAG = 0.0
|
||||
PREFIX = gcr.io/google_containers/git-sync
|
||||
.PHONY: all push push-legacy container clean
|
||||
|
||||
binary: main.go
|
||||
CGO_ENABLED=0 GOOS=linux godep go build -a -installsuffix cgo -ldflags '-w' -o git-sync
|
||||
REGISTRY ?= gcr.io/google_containers
|
||||
IMAGE = $(REGISTRY)/git-sync-$(ARCH)
|
||||
LEGACY_AMD64_IMAGE = $(REGISTRY)/git-sync
|
||||
|
||||
container: binary
|
||||
docker build -t $(PREFIX):$(TAG) .
|
||||
TAG = 1.0
|
||||
|
||||
push: container
|
||||
gcloud docker push $(PREFIX):$(TAG)
|
||||
# Architectures supported: amd64, arm, arm64 and ppc64le
|
||||
ARCH ?= amd64
|
||||
|
||||
# TODO: get a base image for non-x86 archs
|
||||
# arm arm64 ppc64le
|
||||
ALL_ARCH = amd64
|
||||
|
||||
KUBE_CROSS_IMAGE ?= gcr.io/google_containers/kube-cross
|
||||
KUBE_CROSS_VERSION ?= v1.6.3-2
|
||||
|
||||
GO_PKG = k8s.io/git-sync
|
||||
BIN = git-sync
|
||||
|
||||
# If you want to build all containers, see the 'all-container' rule.
|
||||
# If you want to build AND push all containers, see the 'all-push' rule.
|
||||
all: all-build
|
||||
|
||||
sub-container-%:
|
||||
$(MAKE) ARCH=$* container
|
||||
|
||||
sub-push-%:
|
||||
$(MAKE) ARCH=$* push
|
||||
|
||||
all-build: $(addprefix bin/$(BIN)-,$(ALL_ARCH))
|
||||
|
||||
all-container: $(addprefix sub-container-,$(ALL_ARCH))
|
||||
|
||||
all-push: $(addprefix sub-push-,$(ALL_ARCH))
|
||||
|
||||
build: bin/$(BIN)-$(ARCH)
|
||||
|
||||
bin/$(BIN)-$(ARCH): FORCE
|
||||
mkdir -p bin
|
||||
docker run \
|
||||
-u $$(id -u):$$(id -g) \
|
||||
-v $$(pwd):/go/src/$(GO_PKG) \
|
||||
$(KUBE_CROSS_IMAGE):$(KUBE_CROSS_VERSION) \
|
||||
/bin/bash -c " \
|
||||
cd /go/src/$(GO_PKG) && \
|
||||
CGO_ENABLED=0 go build \
|
||||
-installsuffix cgo \
|
||||
-ldflags '-w' \
|
||||
-o $@"
|
||||
|
||||
container: .container-$(ARCH)
|
||||
.container-$(ARCH): bin/$(BIN)-$(ARCH)
|
||||
docker build -t $(IMAGE):$(TAG) --build-arg ARCH=$(ARCH) .
|
||||
ifeq ($(ARCH),amd64)
|
||||
docker tag $(IMAGE):$(TAG) $(LEGACY_AMD64_IMAGE):$(TAG)
|
||||
endif
|
||||
touch $@
|
||||
|
||||
push: .push-$(ARCH)
|
||||
.push-$(ARCH): .container-$(ARCH)
|
||||
gcloud docker push $(IMAGE):$(TAG)
|
||||
touch $@
|
||||
|
||||
push-legacy: .push-legacy-$(ARCH)
|
||||
.push-legacy-$(ARCH): .container-$(ARCH)
|
||||
ifeq ($(ARCH),amd64)
|
||||
gcloud docker push $(LEGACY_AMD64_IMAGE):$(TAG)
|
||||
endif
|
||||
touch $@
|
||||
|
||||
clean:
|
||||
docker rmi -f $(PREFIX):$(TAG) || true
|
||||
rm -rf .container-* .push-* bin/
|
||||
|
||||
FORCE:
|
||||
|
|
|
|||
35
README.md
35
README.md
|
|
@ -1,22 +1,35 @@
|
|||
# git-sync
|
||||
|
||||
git-sync is a command that pull a git repository to a local directory.
|
||||
git-sync is a simple command that pulls a git repository into a local directory.
|
||||
It is a perfect "sidecar" container in Kubernetes - it can periodically pull
|
||||
files down from a repository so that an application can consume them.
|
||||
|
||||
It can be used to source a container volume with the content of a git repo.
|
||||
|
||||
In order to ensure that the git repository content is cloned and updated atomically, you cannot use a volume root directory as the directory for your local repository.
|
||||
|
||||
The local repository is created in a subdirectory of /git, with the subdirectory name specified by GIT_SYNC_DEST.
|
||||
git-sync can pull one time, or on a regular inteval. It can pull from the HEAD
|
||||
of a branch, or from a git tag, or from a specific git hash. It will only
|
||||
re-pull if the target of the run has changed in the upstream repository. When
|
||||
it re-pulls, it updates the destination directory atomically. In order to do
|
||||
this, it uses a git worktree in a subdirectory of the `--root` and flips a
|
||||
symlink.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
# build the container
|
||||
docker build -t git-sync .
|
||||
# run the git-sync container
|
||||
docker run -d GIT_SYNC_REPO=https://github.com/GoogleCloudPlatform/kubernetes GIT_SYNC_DEST=/git -e GIT_SYNC_BRANCH=gh-pages -r HEAD -v /git-data:/git git-sync
|
||||
# run a nginx container to serve sync'ed content
|
||||
docker run -d -p 8080:80 -v /git-data:/usr/share/nginx/html nginx
|
||||
make container REGISTRY=registry TAG=tag
|
||||
|
||||
# run the container
|
||||
docker run -d \
|
||||
-v /tmp/git-data:/git \
|
||||
registry/git-sync:tag \
|
||||
--repo=https://github.com/kubernetes/git-sync
|
||||
--branch=master
|
||||
--wait=30
|
||||
|
||||
# run an nginx container to serve the content
|
||||
docker run -d \
|
||||
-p 8080:80 \
|
||||
-v /tmp/git-data:/usr/share/nginx/html \
|
||||
nginx
|
||||
```
|
||||
|
||||
[]()
|
||||
|
|
|
|||
275
main.go
275
main.go
|
|
@ -24,37 +24,53 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const volMount = "/git"
|
||||
"github.com/thockin/glogr"
|
||||
"github.com/thockin/logr"
|
||||
)
|
||||
|
||||
var flRepo = flag.String("repo", envString("GIT_SYNC_REPO", ""), "git repo url")
|
||||
var flBranch = flag.String("branch", envString("GIT_SYNC_BRANCH", "master"), "git branch")
|
||||
var flRev = flag.String("rev", envString("GIT_SYNC_REV", "HEAD"), "git rev")
|
||||
var flDest = flag.String("dest", envString("GIT_SYNC_DEST", ""), "destination subdirectory path within volume")
|
||||
var flWait = flag.Int("wait", envInt("GIT_SYNC_WAIT", 0), "number of seconds to wait before next sync")
|
||||
var flOneTime = flag.Bool("one-time", envBool("GIT_SYNC_ONE_TIME", false), "exit after the initial checkout")
|
||||
var flDepth = flag.Int("depth", envInt("GIT_SYNC_DEPTH", 0), "shallow clone with a history truncated to the specified number of commits")
|
||||
var flDepth = flag.Int("depth", envInt("GIT_SYNC_DEPTH", 0),
|
||||
"shallow clone with a history truncated to the specified number of commits")
|
||||
|
||||
var flRoot = flag.String("root", envString("GIT_SYNC_ROOT", "/git"),
|
||||
"root directory for git operations")
|
||||
var flDest = flag.String("dest", envString("GIT_SYNC_DEST", ""),
|
||||
"path at which to publish the checked-out files (a subdirectory under --root, defaults to leaf dir of --root)")
|
||||
var flWait = flag.Int("wait", envInt("GIT_SYNC_WAIT", 0),
|
||||
"number of seconds between syncs")
|
||||
var flOneTime = flag.Bool("one-time", envBool("GIT_SYNC_ONE_TIME", false),
|
||||
"exit after the initial checkout")
|
||||
var flMaxSyncFailures = flag.Int("max-sync-failures", envInt("GIT_SYNC_MAX_SYNC_FAILURES", 0),
|
||||
`number of consecutive failures allowed before aborting (the first pull must succeed)`)
|
||||
"number of consecutive failures allowed before aborting (the first pull must succeed)")
|
||||
var flChmod = flag.Int("change-permissions", envInt("GIT_SYNC_PERMISSIONS", 0),
|
||||
"change the permissions of the checked-out files to this")
|
||||
|
||||
var flUsername = flag.String("username", envString("GIT_SYNC_USERNAME", ""), "username")
|
||||
var flPassword = flag.String("password", envString("GIT_SYNC_PASSWORD", ""), "password")
|
||||
|
||||
var flSSH = flag.Bool("ssh", envBool("GIT_SYNC_SSH", false), "use SSH protocol")
|
||||
|
||||
var flChmod = flag.Int("change-permissions", envInt("GIT_SYNC_PERMISSIONS", 0), `If set it will change the permissions of the directory
|
||||
that contains the git repository. Example: 744`)
|
||||
var log = newLoggerOrDie()
|
||||
|
||||
func newLoggerOrDie() logr.Logger {
|
||||
g, err := glogr.New()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failind to initialize logging: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
return g
|
||||
}
|
||||
|
||||
func envString(key, def string) string {
|
||||
if env := os.Getenv(key); env != "" {
|
||||
|
|
@ -79,7 +95,7 @@ func envInt(key string, def int) int {
|
|||
if env := os.Getenv(key); env != "" {
|
||||
val, err := strconv.Atoi(env)
|
||||
if err != nil {
|
||||
log.Printf("invalid value for %q: using default: %q", key, def)
|
||||
log.Errorf("invalid value for %q: using default: %q", key, def)
|
||||
return def
|
||||
}
|
||||
return val
|
||||
|
|
@ -87,84 +103,115 @@ func envInt(key string, def int) int {
|
|||
return def
|
||||
}
|
||||
|
||||
const usage = "usage: GIT_SYNC_REPO= GIT_SYNC_DEST= [GIT_SYNC_BRANCH= GIT_SYNC_WAIT= GIT_SYNC_DEPTH= GIT_SYNC_USERNAME= GIT_SYNC_PASSWORD= GIT_SYNC_SSH= GIT_SYNC_ONE_TIME= GIT_SYNC_MAX_SYNC_FAILURES=] git-sync -repo GIT_REPO_URL -dest PATH [-branch -wait -username -password -ssh -depth -one-time -max-sync-failures]"
|
||||
|
||||
func main() {
|
||||
setFlagDefaults()
|
||||
|
||||
flag.Parse()
|
||||
if *flRepo == "" || *flDest == "" {
|
||||
if *flRepo == "" {
|
||||
flag.Usage()
|
||||
log.Fatal(usage)
|
||||
os.Exit(1)
|
||||
}
|
||||
if *flDest == "" {
|
||||
parts := strings.Split(strings.Trim(*flRepo, "/"), "/")
|
||||
*flDest = parts[len(parts)-1]
|
||||
}
|
||||
if _, err := exec.LookPath("git"); err != nil {
|
||||
log.Fatalf("required git executable not found: %v", err)
|
||||
log.Errorf("required git executable not found: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if *flUsername != "" && *flPassword != "" {
|
||||
if err := setupGitAuth(*flUsername, *flPassword, *flRepo); err != nil {
|
||||
log.Fatalf("error creating .netrc file: %v", err)
|
||||
log.Errorf("error creating .netrc file: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
if *flSSH {
|
||||
if err := setupGitSSH(); err != nil {
|
||||
log.Fatalf("error configuring SSH: %v", err)
|
||||
log.Errorf("error configuring SSH: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
initialSync := true
|
||||
failCount := 0
|
||||
for {
|
||||
if err := syncRepo(*flRepo, *flDest, *flBranch, *flRev, *flDepth); err != nil {
|
||||
if err := syncRepo(*flRepo, *flBranch, *flRev, *flDepth, *flRoot, *flDest); err != nil {
|
||||
if initialSync || failCount >= *flMaxSyncFailures {
|
||||
log.Fatalf("error syncing repo: %v", err)
|
||||
log.Errorf("error syncing repo: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
failCount++
|
||||
log.Printf("unexpected error syncing repo: %v", err)
|
||||
log.Printf("waiting %d seconds before retryng", *flWait)
|
||||
log.Errorf("unexpected error syncing repo: %v", err)
|
||||
log.V(0).Infof("waiting %d seconds before retryng", *flWait)
|
||||
time.Sleep(time.Duration(*flWait) * time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
initialSync = false
|
||||
failCount = 0
|
||||
|
||||
if initialSync {
|
||||
if isHash, err := revIsHash(*flRev, *flRoot); err != nil {
|
||||
log.Errorf("can't tell if rev %s is a git hash, exiting", *flRev)
|
||||
os.Exit(1)
|
||||
} else if isHash {
|
||||
log.V(0).Infof("rev %s appears to be a git hash, no further sync needed", *flRev)
|
||||
sleepForever()
|
||||
}
|
||||
if *flOneTime {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
log.Printf("waiting %d seconds", *flWait)
|
||||
time.Sleep(time.Duration(*flWait) * time.Second)
|
||||
log.Println("done")
|
||||
initialSync = false
|
||||
}
|
||||
|
||||
failCount = 0
|
||||
log.V(0).Infof("next sync in %d seconds", *flWait)
|
||||
time.Sleep(time.Duration(*flWait) * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func setFlagDefaults() {
|
||||
// Force logging to stderr.
|
||||
stderrFlag := flag.Lookup("logtostderr")
|
||||
if stderrFlag == nil {
|
||||
fmt.Fprintf(os.Stderr, "can't find flag 'logtostderr'")
|
||||
os.Exit(1)
|
||||
}
|
||||
stderrFlag.Value.Set("true")
|
||||
}
|
||||
|
||||
// Do no work, but don't do something that triggers go's runtime into thinking
|
||||
// it is deadlocked.
|
||||
func sleepForever() {
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt, os.Kill)
|
||||
<-c
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// updateSymlink atomically swaps the symlink to point at the specified directory and cleans up the previous worktree.
|
||||
func updateSymlink(link, newDir string) error {
|
||||
func updateSymlink(gitRoot, link, newDir string) error {
|
||||
// Get currently-linked repo directory (to be removed), unless it doesn't exist
|
||||
currentDir, err := filepath.EvalSymlinks(path.Join(volMount, link))
|
||||
currentDir, err := filepath.EvalSymlinks(path.Join(gitRoot, link))
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return fmt.Errorf("error accessing symlink: %v", err)
|
||||
}
|
||||
|
||||
// newDir is /git/rev-..., we need to change it to relative path.
|
||||
// Volume in other container may not be mounted at /git, so the symlink can't point to /git.
|
||||
newDirRelative, err := filepath.Rel(volMount, newDir)
|
||||
newDirRelative, err := filepath.Rel(gitRoot, newDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error converting to relative path: %v", err)
|
||||
}
|
||||
|
||||
if _, err := runCommand("ln", volMount, []string{"-snf", newDirRelative, "tmp-link"}); err != nil {
|
||||
if _, err := runCommand(gitRoot, "ln", "-snf", newDirRelative, "tmp-link"); err != nil {
|
||||
return fmt.Errorf("error creating symlink: %v", err)
|
||||
}
|
||||
log.V(1).Infof("created symlink %s -> %s", "tmp-link", newDirRelative)
|
||||
|
||||
log.Printf("create symlink %v->%v", "tmp-link", newDirRelative)
|
||||
|
||||
if _, err := runCommand("mv", volMount, []string{"-T", "tmp-link", link}); err != nil {
|
||||
if _, err := runCommand(gitRoot, "mv", "-T", "tmp-link", link); err != nil {
|
||||
return fmt.Errorf("error replacing symlink: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("rename symlink %v to %v", "tmp-link", link)
|
||||
log.V(1).Infof("renamed symlink %s to %s", "tmp-link", link)
|
||||
|
||||
// Clean up previous worktree
|
||||
if len(currentDir) > 0 {
|
||||
|
|
@ -172,42 +219,51 @@ func updateSymlink(link, newDir string) error {
|
|||
return fmt.Errorf("error removing directory: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("remove %v", currentDir)
|
||||
log.V(1).Infof("removed %s", currentDir)
|
||||
|
||||
output, err := runCommand("git", volMount, []string{"worktree", "prune"})
|
||||
_, err := runCommand(gitRoot, "git", "worktree", "prune")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("worktree prune %v", string(output))
|
||||
log.V(1).Infof("pruned old worktrees")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// addWorktreeAndSwap creates a new worktree and calls updateSymlink to swap the symlink to point to the new worktree
|
||||
func addWorktreeAndSwap(dest, branch, rev string) error {
|
||||
// fetch branch
|
||||
output, err := runCommand("git", volMount, []string{"fetch", "origin", branch})
|
||||
func addWorktreeAndSwap(gitRoot, dest, branch, rev string) error {
|
||||
// Fetch the branch. This is required for the worktree to be based on the
|
||||
// current rev.
|
||||
_, err := runCommand(gitRoot, "git", "fetch", "--tags", "origin", branch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("fetch %q: %s", branch, string(output))
|
||||
|
||||
// add worktree in subdir
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
worktreePath := path.Join(volMount, "rev-"+strconv.Itoa(rand.Int()))
|
||||
output, err = runCommand("git", volMount, []string{"worktree", "add", worktreePath, "origin/" + branch})
|
||||
// Find the real commit for the rev.
|
||||
output, err := runCommand(gitRoot, "git", "rev-list", "-n1", rev)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
revhash := strings.Trim(string(output), "\n")
|
||||
if revhash != rev {
|
||||
log.V(0).Infof("rev %s resolves to %s", rev, revhash)
|
||||
}
|
||||
|
||||
log.Printf("add worktree origin/%q: %v", branch, string(output))
|
||||
// Make a worktree for this exact git hash.
|
||||
worktreePath := path.Join(gitRoot, "rev-"+revhash)
|
||||
_, err = runCommand(gitRoot, "git", "worktree", "add", worktreePath, "origin/"+branch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.V(0).Infof("added worktree %s for origin/%s", worktreePath, branch)
|
||||
|
||||
// .git file in worktree directory holds a reference to /git/.git/worktrees/<worktree-dir-name>
|
||||
// Replace it with a reference using relative paths, so that other containers can use a different volume mount name
|
||||
worktreePathRelative, err := filepath.Rel(volMount, worktreePath)
|
||||
// The .git file in the worktree directory holds a reference to
|
||||
// /git/.git/worktrees/<worktree-dir-name>. Replace it with a reference
|
||||
// using relative paths, so that other containers can use a different volume
|
||||
// mount name.
|
||||
worktreePathRelative, err := filepath.Rel(gitRoot, worktreePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -216,103 +272,136 @@ func addWorktreeAndSwap(dest, branch, rev string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// reset working copy
|
||||
output, err = runCommand("git", worktreePath, []string{"reset", "--hard", rev})
|
||||
// Reset the worktree's working copy to the specific rev.
|
||||
_, err = runCommand(worktreePath, "git", "reset", "--hard", rev)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("reset %q: %v", rev, string(output))
|
||||
log.V(0).Infof("reset worktree %s to %s", worktreePath, rev)
|
||||
|
||||
if *flChmod != 0 {
|
||||
// set file permissions
|
||||
_, err = runCommand("chmod", "", []string{"-R", string(*flChmod), worktreePath})
|
||||
_, err = runCommand("", "chmod", "-R", strconv.Itoa(*flChmod), worktreePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return updateSymlink(dest, worktreePath)
|
||||
return updateSymlink(gitRoot, dest, worktreePath)
|
||||
}
|
||||
|
||||
func initRepo(repo, dest, branch, rev string, depth int) error {
|
||||
// clone repo
|
||||
func cloneRepo(repo, branch, rev string, depth int, gitRoot string) error {
|
||||
args := []string{"clone", "--no-checkout", "-b", branch}
|
||||
if depth != 0 {
|
||||
args = append(args, "-depth")
|
||||
args = append(args, string(depth))
|
||||
args = append(args, "-depth", strconv.Itoa(depth))
|
||||
}
|
||||
args = append(args, repo)
|
||||
args = append(args, volMount)
|
||||
output, err := runCommand("git", "", args)
|
||||
args = append(args, repo, gitRoot)
|
||||
_, err := runCommand("", "git", args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("clone %q: %s", repo, string(output))
|
||||
log.V(0).Infof("cloned %s", repo)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func revIsHash(rev, gitRoot string) (bool, error) {
|
||||
// If a rev is a tag name or HEAD, rev-list will produce the git hash. If
|
||||
// it is already a git hash, the output will be the same hash. Of course, a
|
||||
// user could specify "abc" and match "abcdef12345678", so we just do a
|
||||
// prefix match.
|
||||
output, err := runCommand(gitRoot, "git", "rev-list", "-n1", rev)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return strings.HasPrefix(output, rev), nil
|
||||
}
|
||||
|
||||
// syncRepo syncs the branch of a given repository to the destination at the given rev.
|
||||
func syncRepo(repo, dest, branch, rev string, depth int) error {
|
||||
target := path.Join(volMount, dest)
|
||||
func syncRepo(repo, branch, rev string, depth int, gitRoot, dest string) error {
|
||||
target := path.Join(gitRoot, dest)
|
||||
gitRepoPath := path.Join(target, ".git")
|
||||
_, err := os.Stat(gitRepoPath)
|
||||
switch {
|
||||
case os.IsNotExist(err):
|
||||
err = initRepo(repo, target, branch, rev, depth)
|
||||
err = cloneRepo(repo, branch, rev, depth, gitRoot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case err != nil:
|
||||
return fmt.Errorf("error checking if repo exist %q: %v", gitRepoPath, err)
|
||||
default:
|
||||
needUpdate, err := gitRemoteChanged(target, branch)
|
||||
needed, err := needResync(target, rev)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !needUpdate {
|
||||
log.Printf("No change")
|
||||
if needed {
|
||||
log.V(0).Infof("update required")
|
||||
} else {
|
||||
log.V(0).Infof("no update required")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return addWorktreeAndSwap(dest, branch, rev)
|
||||
return addWorktreeAndSwap(gitRoot, dest, branch, rev)
|
||||
}
|
||||
|
||||
// gitRemoteChanged returns true if the remote HEAD is different from the local HEAD, false otherwise
|
||||
func gitRemoteChanged(localDir, branch string) (bool, error) {
|
||||
_, err := runCommand("git", localDir, []string{"remote", "update"})
|
||||
// needResync returns true if the upstream hash for rev is different from the local one.
|
||||
func needResync(localDir, rev string) (bool, error) {
|
||||
// Ask git what the exact hash is for rev.
|
||||
local, err := runCommand(localDir, "git", "rev-list", "-n1", rev)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
localHead, err := runCommand("git", localDir, []string{"rev-parse", "HEAD"})
|
||||
local = strings.Trim(local, "\n")
|
||||
|
||||
// Fetch rev from upstream.
|
||||
_, err = runCommand(localDir, "git", "fetch", "origin", rev)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
remoteHead, err := runCommand("git", localDir, []string{"rev-parse", fmt.Sprintf("origin/%v", branch)})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return (strings.Compare(string(localHead), string(remoteHead)) != 0), nil
|
||||
}
|
||||
|
||||
func runCommand(command, cwd string, args []string) ([]byte, error) {
|
||||
// Ask git what the exact hash is for upstream rev.
|
||||
remote, err := runCommand(localDir, "git", "rev-list", "-n1", "FETCH_HEAD")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
remote = strings.Trim(remote, "\n")
|
||||
|
||||
log.V(2).Infof("local hash: %s", local)
|
||||
log.V(2).Infof("remote hash: %s", remote)
|
||||
return (local != remote), nil
|
||||
}
|
||||
|
||||
func cmdForLog(command string, args ...string) string {
|
||||
if strings.ContainsAny(command, " \t\n") {
|
||||
command = fmt.Sprintf("%q", command)
|
||||
}
|
||||
for i := range args {
|
||||
if strings.ContainsAny(args[i], " \t\n") {
|
||||
args[i] = fmt.Sprintf("%q", args[i])
|
||||
}
|
||||
}
|
||||
return command + " " + strings.Join(args, " ")
|
||||
}
|
||||
|
||||
func runCommand(cwd, command string, args ...string) (string, error) {
|
||||
log.V(5).Infof("run(%q): %s", cwd, cmdForLog(command, args...))
|
||||
|
||||
cmd := exec.Command(command, args...)
|
||||
if cwd != "" {
|
||||
cmd.Dir = cwd
|
||||
}
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return []byte{}, fmt.Errorf("error running command %q : %v: %s", strings.Join(cmd.Args, " "), err, string(output))
|
||||
return "", fmt.Errorf("error running command: %v: %q", err, string(output))
|
||||
}
|
||||
|
||||
return output, nil
|
||||
return string(output), nil
|
||||
}
|
||||
|
||||
func setupGitAuth(username, password, gitURL string) error {
|
||||
log.Println("setting up the git credential cache")
|
||||
log.V(1).Infof("setting up the git credential cache")
|
||||
cmd := exec.Command("git", "config", "--global", "credential.helper", "cache")
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
|
|
@ -336,7 +425,7 @@ func setupGitAuth(username, password, gitURL string) error {
|
|||
}
|
||||
|
||||
func setupGitSSH() error {
|
||||
log.Println("setting up git SSH credentials")
|
||||
log.V(1).Infof("setting up git SSH credentials")
|
||||
|
||||
if _, err := os.Stat("/etc/git-secret/ssh"); err != nil {
|
||||
return fmt.Errorf("error: could not find SSH key Secret: %v", err)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,191 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and
|
||||
distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright
|
||||
owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities
|
||||
that control, are controlled by, or are under common control with that entity.
|
||||
For the purposes of this definition, "control" means (i) the power, direct or
|
||||
indirect, to cause the direction or management of such entity, whether by
|
||||
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising
|
||||
permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including
|
||||
but not limited to software source code, documentation source, and configuration
|
||||
files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or
|
||||
translation of a Source form, including but not limited to compiled object code,
|
||||
generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made
|
||||
available under the License, as indicated by a copyright notice that is included
|
||||
in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that
|
||||
is based on (or derived from) the Work and for which the editorial revisions,
|
||||
annotations, elaborations, or other modifications represent, as a whole, an
|
||||
original work of authorship. For the purposes of this License, Derivative Works
|
||||
shall not include works that remain separable from, or merely link (or bind by
|
||||
name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version
|
||||
of the Work and any modifications or additions to that Work or Derivative Works
|
||||
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
||||
by the copyright owner or by an individual or Legal Entity authorized to submit
|
||||
on behalf of the copyright owner. For the purposes of this definition,
|
||||
"submitted" means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems, and
|
||||
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
||||
the purpose of discussing and improving the Work, but excluding communication
|
||||
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||
owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
|
||||
of whom a Contribution has been received by Licensor and subsequently
|
||||
incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License.
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the Work and such
|
||||
Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License.
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable (except as stated in this section) patent license to make, have
|
||||
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
|
||||
such license applies only to those patent claims licensable by such Contributor
|
||||
that are necessarily infringed by their Contribution(s) alone or by combination
|
||||
of their Contribution(s) with the Work to which such Contribution(s) was
|
||||
submitted. If You institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
||||
Contribution incorporated within the Work constitutes direct or contributory
|
||||
patent infringement, then any patent licenses granted to You under this License
|
||||
for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution.
|
||||
|
||||
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
||||
in any medium, with or without modifications, and in Source or Object form,
|
||||
provided that You meet the following conditions:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of
|
||||
this License; and
|
||||
You must cause any modified files to carry prominent notices stating that You
|
||||
changed the files; and
|
||||
You must retain, in the Source form of any Derivative Works that You distribute,
|
||||
all copyright, patent, trademark, and attribution notices from the Source form
|
||||
of the Work, excluding those notices that do not pertain to any part of the
|
||||
Derivative Works; and
|
||||
If the Work includes a "NOTICE" text file as part of its distribution, then any
|
||||
Derivative Works that You distribute must include a readable copy of the
|
||||
attribution notices contained within such NOTICE file, excluding those notices
|
||||
that do not pertain to any part of the Derivative Works, in at least one of the
|
||||
following places: within a NOTICE text file distributed as part of the
|
||||
Derivative Works; within the Source form or documentation, if provided along
|
||||
with the Derivative Works; or, within a display generated by the Derivative
|
||||
Works, if and wherever such third-party notices normally appear. The contents of
|
||||
the NOTICE file are for informational purposes only and do not modify the
|
||||
License. You may add Your own attribution notices within Derivative Works that
|
||||
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
||||
provided that such additional attribution notices cannot be construed as
|
||||
modifying the License.
|
||||
You may add Your own copyright statement to Your modifications and may provide
|
||||
additional or different license terms and conditions for use, reproduction, or
|
||||
distribution of Your modifications, or for any such Derivative Works as a whole,
|
||||
provided Your use, reproduction, and distribution of the Work otherwise complies
|
||||
with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions.
|
||||
|
||||
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
||||
for inclusion in the Work by You to the Licensor shall be under the terms and
|
||||
conditions of this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
||||
any separate license agreement you may have executed with Licensor regarding
|
||||
such Contributions.
|
||||
|
||||
6. Trademarks.
|
||||
|
||||
This License does not grant permission to use the trade names, trademarks,
|
||||
service marks, or product names of the Licensor, except as required for
|
||||
reasonable and customary use in describing the origin of the Work and
|
||||
reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, Licensor provides the
|
||||
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
||||
including, without limitation, any warranties or conditions of TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
||||
solely responsible for determining the appropriateness of using or
|
||||
redistributing the Work and assume any risks associated with Your exercise of
|
||||
permissions under this License.
|
||||
|
||||
8. Limitation of Liability.
|
||||
|
||||
In no event and under no legal theory, whether in tort (including negligence),
|
||||
contract, or otherwise, unless required by applicable law (such as deliberate
|
||||
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special, incidental,
|
||||
or consequential damages of any character arising as a result of this License or
|
||||
out of the use or inability to use the Work (including but not limited to
|
||||
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
||||
any and all other commercial damages or losses), even if such Contributor has
|
||||
been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability.
|
||||
|
||||
While redistributing the Work or Derivative Works thereof, You may choose to
|
||||
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
||||
other liability obligations and/or rights consistent with this License. However,
|
||||
in accepting such obligations, You may act only on Your own behalf and on Your
|
||||
sole responsibility, not on behalf of any other Contributor, and only if You
|
||||
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason of your
|
||||
accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work
|
||||
|
||||
To apply the Apache License to your work, attach the following boilerplate
|
||||
notice, with the fields enclosed by brackets "[]" replaced with your own
|
||||
identifying information. (Don't include the brackets!) The text should be
|
||||
enclosed in the appropriate comment syntax for the file format. We also
|
||||
recommend that a file or class name and description of purpose be included on
|
||||
the same "printed page" as the copyright notice for easier identification within
|
||||
third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
glog
|
||||
====
|
||||
|
||||
Leveled execution logs for Go.
|
||||
|
||||
This is an efficient pure Go implementation of leveled logs in the
|
||||
manner of the open source C++ package
|
||||
https://github.com/google/glog
|
||||
|
||||
By binding methods to booleans it is possible to use the log package
|
||||
without paying the expense of evaluating the arguments to the log.
|
||||
Through the -vmodule flag, the package also provides fine-grained
|
||||
control over logging at the file level.
|
||||
|
||||
The comment from glog.go introduces the ideas:
|
||||
|
||||
Package glog implements logging analogous to the Google-internal
|
||||
C++ INFO/ERROR/V setup. It provides functions Info, Warning,
|
||||
Error, Fatal, plus formatting variants such as Infof. It
|
||||
also provides V-style logging controlled by the -v and
|
||||
-vmodule=file=2 flags.
|
||||
|
||||
Basic examples:
|
||||
|
||||
glog.Info("Prepare to repel boarders")
|
||||
|
||||
glog.Fatalf("Initialization failed: %s", err)
|
||||
|
||||
See the documentation for the V function for an explanation
|
||||
of these examples:
|
||||
|
||||
if glog.V(2) {
|
||||
glog.Info("Starting transaction...")
|
||||
}
|
||||
|
||||
glog.V(2).Infoln("Processed", nItems, "elements")
|
||||
|
||||
|
||||
The repository contains an open source version of the log package
|
||||
used inside Google. The master copy of the source lives inside
|
||||
Google, not here. The code in this repo is for export only and is not itself
|
||||
under development. Feature requests will be ignored.
|
||||
|
||||
Send bug reports to golang-nuts@googlegroups.com.
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,124 @@
|
|||
// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/
|
||||
//
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// File I/O for logs.
|
||||
|
||||
package glog
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// MaxSize is the maximum size of a log file in bytes.
|
||||
var MaxSize uint64 = 1024 * 1024 * 1800
|
||||
|
||||
// logDirs lists the candidate directories for new log files.
|
||||
var logDirs []string
|
||||
|
||||
// If non-empty, overrides the choice of directory in which to write logs.
|
||||
// See createLogDirs for the full list of possible destinations.
|
||||
var logDir = flag.String("log_dir", "", "If non-empty, write log files in this directory")
|
||||
|
||||
func createLogDirs() {
|
||||
if *logDir != "" {
|
||||
logDirs = append(logDirs, *logDir)
|
||||
}
|
||||
logDirs = append(logDirs, os.TempDir())
|
||||
}
|
||||
|
||||
var (
|
||||
pid = os.Getpid()
|
||||
program = filepath.Base(os.Args[0])
|
||||
host = "unknownhost"
|
||||
userName = "unknownuser"
|
||||
)
|
||||
|
||||
func init() {
|
||||
h, err := os.Hostname()
|
||||
if err == nil {
|
||||
host = shortHostname(h)
|
||||
}
|
||||
|
||||
current, err := user.Current()
|
||||
if err == nil {
|
||||
userName = current.Username
|
||||
}
|
||||
|
||||
// Sanitize userName since it may contain filepath separators on Windows.
|
||||
userName = strings.Replace(userName, `\`, "_", -1)
|
||||
}
|
||||
|
||||
// shortHostname returns its argument, truncating at the first period.
|
||||
// For instance, given "www.google.com" it returns "www".
|
||||
func shortHostname(hostname string) string {
|
||||
if i := strings.Index(hostname, "."); i >= 0 {
|
||||
return hostname[:i]
|
||||
}
|
||||
return hostname
|
||||
}
|
||||
|
||||
// logName returns a new log file name containing tag, with start time t, and
|
||||
// the name for the symlink for tag.
|
||||
func logName(tag string, t time.Time) (name, link string) {
|
||||
name = fmt.Sprintf("%s.%s.%s.log.%s.%04d%02d%02d-%02d%02d%02d.%d",
|
||||
program,
|
||||
host,
|
||||
userName,
|
||||
tag,
|
||||
t.Year(),
|
||||
t.Month(),
|
||||
t.Day(),
|
||||
t.Hour(),
|
||||
t.Minute(),
|
||||
t.Second(),
|
||||
pid)
|
||||
return name, program + "." + tag
|
||||
}
|
||||
|
||||
var onceLogDirs sync.Once
|
||||
|
||||
// create creates a new log file and returns the file and its filename, which
|
||||
// contains tag ("INFO", "FATAL", etc.) and t. If the file is created
|
||||
// successfully, create also attempts to update the symlink for that tag, ignoring
|
||||
// errors.
|
||||
func create(tag string, t time.Time) (f *os.File, filename string, err error) {
|
||||
onceLogDirs.Do(createLogDirs)
|
||||
if len(logDirs) == 0 {
|
||||
return nil, "", errors.New("log: no log dirs")
|
||||
}
|
||||
name, link := logName(tag, t)
|
||||
var lastErr error
|
||||
for _, dir := range logDirs {
|
||||
fname := filepath.Join(dir, name)
|
||||
f, err := os.Create(fname)
|
||||
if err == nil {
|
||||
symlink := filepath.Join(dir, link)
|
||||
os.Remove(symlink) // ignore err
|
||||
os.Symlink(name, symlink) // ignore err
|
||||
return f, fname, nil
|
||||
}
|
||||
lastErr = err
|
||||
}
|
||||
return nil, "", fmt.Errorf("log: cannot create log: %v", lastErr)
|
||||
}
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
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.
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
# Minimal Go logging using glog
|
||||
|
||||
This package implements the [logr interface](https://github.com/thockin/logr)
|
||||
in terms of Google's [glog](https://godoc.org/github.com/golang/glog). This
|
||||
provides a relatively minimalist API to logging in Go, backed by a well-proven
|
||||
implementation.
|
||||
|
||||
This is a BETA grade implementation.
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
// Package glogr implements github.com/thockin/logr.Logger in terms of
|
||||
// github.com/golang/glog.
|
||||
package glogr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/thockin/logr"
|
||||
)
|
||||
|
||||
// New returns a logr.Logger which is implemented by glog.
|
||||
func New() (logr.Logger, error) {
|
||||
return glogger{
|
||||
level: 0,
|
||||
prefix: "",
|
||||
}, nil
|
||||
}
|
||||
|
||||
type glogger struct {
|
||||
level int
|
||||
prefix string
|
||||
}
|
||||
|
||||
func prepend(prefix interface{}, args []interface{}) []interface{} {
|
||||
return append([]interface{}{prefix}, args...)
|
||||
}
|
||||
|
||||
// Magic string for intermediate frames that we should ignore.
|
||||
const autogeneratedFrameName = "<autogenerated>"
|
||||
|
||||
// Discover how many frames we need to climb to find the caller. This approach
|
||||
// was suggested by Ian Lance Taylor of the Go team, so it *should* be safe
|
||||
// enough (famous last words).
|
||||
func framesToCaller() int {
|
||||
// 1 is the immediate caller. 3 should be too many.
|
||||
for i := 1; i < 3; i++ {
|
||||
_, file, _, _ := runtime.Caller(i + 1) // +1 for this function's frame
|
||||
if file != autogeneratedFrameName {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return 1 // something went wrong, this is safe
|
||||
}
|
||||
|
||||
func (l glogger) Info(args ...interface{}) {
|
||||
if l.Enabled() {
|
||||
glog.InfoDepth(framesToCaller(), prepend(l.prefix, args)...)
|
||||
}
|
||||
}
|
||||
|
||||
func (l glogger) Infof(format string, args ...interface{}) {
|
||||
if l.Enabled() {
|
||||
glog.InfoDepth(framesToCaller(), fmt.Sprintf("%s"+format, prepend(l.prefix, args)...))
|
||||
}
|
||||
}
|
||||
|
||||
func (l glogger) Enabled() bool {
|
||||
return bool(glog.V(glog.Level(l.level)))
|
||||
}
|
||||
|
||||
func (l glogger) Error(args ...interface{}) {
|
||||
glog.ErrorDepth(framesToCaller(), prepend(l.prefix, args)...)
|
||||
}
|
||||
|
||||
func (l glogger) Errorf(format string, args ...interface{}) {
|
||||
glog.ErrorDepth(framesToCaller(), fmt.Sprintf("%s"+format, prepend(l.prefix, args)...))
|
||||
}
|
||||
|
||||
func (l glogger) V(level int) logr.InfoLogger {
|
||||
return glogger{
|
||||
level: level,
|
||||
prefix: l.prefix,
|
||||
}
|
||||
}
|
||||
|
||||
func (l glogger) NewWithPrefix(prefix string) logr.Logger {
|
||||
return glogger{
|
||||
level: l.level,
|
||||
prefix: prefix,
|
||||
}
|
||||
}
|
||||
|
||||
var _ logr.Logger = glogger{}
|
||||
var _ logr.InfoLogger = glogger{}
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
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.
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
# A more minimal logging API for Go
|
||||
|
||||
Before you consider this package, please read [this blog post by the inimitable
|
||||
Dave Cheney](http://dave.cheney.net/2015/11/05/lets-talk-about-logging). I
|
||||
really appreciate what he has to say, and it largely aligns with my own
|
||||
experiences. Too many choices of levels means inconsistent logs.
|
||||
|
||||
This package offers a purely abstract interface, based on these ideas but with
|
||||
a few twists. Code can depend on just this interface and have the actual
|
||||
logging implementation be injected from callers. Ideally only `main()` knows
|
||||
what logging implementation is being used.
|
||||
|
||||
# Differences from Dave's ideas
|
||||
|
||||
The main differences are:
|
||||
|
||||
1) Dave basically proposes doing away with the notion of a logging API in favor
|
||||
of `fmt.Printf()`. I disagree, especially when you consider things like output
|
||||
locations, timestamps, file and line decorations, and structured logging. I
|
||||
restrict the API to just 2 types of logs: info and error.
|
||||
|
||||
Info logs are things you want to tell the user which are not errors. Error
|
||||
logs are, well, errors. If your code receives an `error` from a subordinate
|
||||
function call and is logging that `error` *and not returning it*, use error
|
||||
logs.
|
||||
|
||||
2) Verbosity-levels on info logs. This gives developers a chance to indicate
|
||||
arbitrary grades of importance for info logs, without assigning names with
|
||||
semantic meaning such as "warning", "trace", and "debug". Superficially this
|
||||
may feel very similar, but the primary difference is the lack of semantics.
|
||||
Because verbosity is a numerical value, it's safe to assume that an app running
|
||||
with higher verbosity means more (and less important) logs will be generated.
|
||||
|
||||
This is a BETA grade API. I have implemented it for
|
||||
[glog](https://godoc.org/github.com/golang/glog). Until there is a significant
|
||||
2nd implementation, I don't really know how it will change.
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
// Package logr defines abstract interfaces for logging. Packages can depend on
|
||||
// these interfaces and callers can implement logging in whatever way is
|
||||
// appropriate.
|
||||
//
|
||||
// This design derives from Dave Cheney's blog:
|
||||
// http://dave.cheney.net/2015/11/05/lets-talk-about-logging
|
||||
//
|
||||
// This is a BETA grade API. Until there is a significant 2nd implementation,
|
||||
// I don't really know how it will change.
|
||||
package logr
|
||||
|
||||
// TODO: consider structured logging, a la uber-go/zap
|
||||
// TODO: consider other bits of glog functionality like Flush, InfoDepth, OutputStats
|
||||
|
||||
// InfoLogger represents the ability to log non-error messages.
|
||||
type InfoLogger interface {
|
||||
// Info logs a non-error message. This is behaviorally akin to fmt.Print.
|
||||
Info(args ...interface{})
|
||||
|
||||
// Infof logs a formatted non-error message.
|
||||
Infof(format string, args ...interface{})
|
||||
|
||||
// Enabled test whether this InfoLogger is enabled. For example,
|
||||
// commandline flags might be used to set the logging verbosity and disable
|
||||
// some info logs.
|
||||
Enabled() bool
|
||||
}
|
||||
|
||||
// Logger represents the ability to log messages, both errors and not.
|
||||
type Logger interface {
|
||||
// All Loggers implement InfoLogger. Calling InfoLogger methods directly on
|
||||
// a Logger value is equivalent to calling them on a V(0) InfoLogger. For
|
||||
// example, logger.Info() produces the same result as logger.V(0).Info.
|
||||
InfoLogger
|
||||
|
||||
// Error logs a error message. This is behaviorally akin to fmt.Print.
|
||||
Error(args ...interface{})
|
||||
|
||||
// Errorf logs a formatted error message.
|
||||
Errorf(format string, args ...interface{})
|
||||
|
||||
// V returns an InfoLogger value for a specific verbosity level. A higher
|
||||
// verbosity level means a log message is less important.
|
||||
V(level int) InfoLogger
|
||||
|
||||
// NewWithPrefix returns a Logger which prefixes all messages.
|
||||
NewWithPrefix(prefix string) Logger
|
||||
}
|
||||
Loading…
Reference in New Issue