Delete additional third_party

k3s-v1.14.6
Darren Shepherd 2018-10-09 15:21:54 -07:00 committed by Erik Wilson
parent a3bf0b9338
commit 9efef1cdaa
116 changed files with 0 additions and 13373 deletions

33
third_party/BUILD vendored
View File

@ -1,33 +0,0 @@
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
filegroup(
name = "package-srcs",
srcs = glob(
["**"],
exclude = [
"etcd*/**",
"etcd*.tar.gz",
],
),
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//third_party/forked/etcd221/pkg/fileutil:all-srcs",
"//third_party/forked/etcd221/wal:all-srcs",
"//third_party/forked/etcd237/pkg/fileutil:all-srcs",
"//third_party/forked/etcd237/wal:all-srcs",
"//third_party/forked/godep:all-srcs",
"//third_party/forked/golang/expansion:all-srcs",
"//third_party/forked/golang/reflect:all-srcs",
"//third_party/forked/golang/template:all-srcs",
"//third_party/forked/gonum/graph:all-srcs",
"//third_party/go-srcimporter:all-srcs",
],
tags = ["automanaged"],
)

10
third_party/OWNERS vendored
View File

@ -1,10 +0,0 @@
# See the OWNERS docs at https://go.k8s.io/owners
reviewers:
- lavalamp
- smarterclayton
- thockin
approvers:
- lavalamp
- smarterclayton
- thockin

View File

@ -1 +0,0 @@
exports_files(["etcd"])

View File

@ -1 +0,0 @@
Forked from etcd 2.2 release branch to support migration from 3.0 WAL to 2.2 WAL format

View File

@ -1,51 +0,0 @@
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = [
"fileutil_test.go",
"lock_test.go",
"preallocate_test.go",
"purge_test.go",
],
embed = [":go_default_library"],
)
go_library(
name = "go_default_library",
srcs = [
"fileutil.go",
"lock_plan9.go",
"lock_solaris.go",
"lock_unix.go",
"lock_windows.go",
"perallocate_unsupported.go",
"preallocate.go",
"purge.go",
],
importpath = "k8s.io/kubernetes/third_party/forked/etcd221/pkg/fileutil",
deps = [
"//vendor/github.com/coreos/pkg/capnslog:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -1,57 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package fileutil
import (
"io/ioutil"
"os"
"path"
"sort"
"github.com/coreos/pkg/capnslog"
)
const (
privateFileMode = 0600
)
var (
plog = capnslog.NewPackageLogger("github.com/coreos/etcd/pkg", "fileutil")
)
// IsDirWriteable checks if dir is writable by writing and removing a file
// to dir. It returns nil if dir is writable.
func IsDirWriteable(dir string) error {
f := path.Join(dir, ".touch")
if err := ioutil.WriteFile(f, []byte(""), privateFileMode); err != nil {
return err
}
return os.Remove(f)
}
// ReadDir returns the filenames in the given directory in sorted order.
func ReadDir(dirpath string) ([]string, error) {
dir, err := os.Open(dirpath)
if err != nil {
return nil, err
}
defer dir.Close()
names, err := dir.Readdirnames(-1)
if err != nil {
return nil, err
}
sort.Strings(names)
return names, nil
}

View File

@ -1,67 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package fileutil
import (
"io/ioutil"
"os"
"path/filepath"
"reflect"
"testing"
)
func TestIsDirWriteable(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("unexpected ioutil.TempDir error: %v", err)
}
defer os.RemoveAll(tmpdir)
if err := IsDirWriteable(tmpdir); err != nil {
t.Fatalf("unexpected IsDirWriteable error: %v", err)
}
if err := os.Chmod(tmpdir, 0444); err != nil {
t.Fatalf("unexpected os.Chmod error: %v", err)
}
if err := IsDirWriteable(tmpdir); err == nil {
t.Fatalf("expected IsDirWriteable to error")
}
}
func TestReadDir(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "")
defer os.RemoveAll(tmpdir)
if err != nil {
t.Fatalf("unexpected ioutil.TempDir error: %v", err)
}
files := []string{"def", "abc", "xyz", "ghi"}
for _, f := range files {
var fh *os.File
fh, err = os.Create(filepath.Join(tmpdir, f))
if err != nil {
t.Fatalf("error creating file: %v", err)
}
if err := fh.Close(); err != nil {
t.Fatalf("error closing file: %v", err)
}
}
fs, err := ReadDir(tmpdir)
if err != nil {
t.Fatalf("error calling ReadDir: %v", err)
}
wfs := []string{"abc", "def", "ghi", "xyz"}
if !reflect.DeepEqual(fs, wfs) {
t.Fatalf("ReadDir: got %v, want %v", fs, wfs)
}
}

View File

@ -1,90 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package fileutil
import (
"errors"
"os"
"syscall"
"time"
)
var (
ErrLocked = errors.New("file already locked")
)
type Lock interface {
Name() string
TryLock() error
Lock() error
Unlock() error
Destroy() error
}
type lock struct {
fname string
file *os.File
}
func (l *lock) Name() string {
return l.fname
}
// TryLock acquires exclusivity on the lock without blocking
func (l *lock) TryLock() error {
err := os.Chmod(l.fname, syscall.DMEXCL|0600)
if err != nil {
return err
}
f, err := os.Open(l.fname)
if err != nil {
return ErrLocked
}
l.file = f
return nil
}
// Lock acquires exclusivity on the lock with blocking
func (l *lock) Lock() error {
err := os.Chmod(l.fname, syscall.DMEXCL|0600)
if err != nil {
return err
}
for {
f, err := os.Open(l.fname)
if err == nil {
l.file = f
return nil
}
time.Sleep(10 * time.Millisecond)
}
}
// Unlock unlocks the lock
func (l *lock) Unlock() error {
return l.file.Close()
}
func (l *lock) Destroy() error {
return nil
}
func NewLock(file string) (Lock, error) {
l := &lock{fname: file}
return l, nil
}

View File

@ -1,98 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
// +build solaris
package fileutil
import (
"errors"
"os"
"syscall"
)
var (
ErrLocked = errors.New("file already locked")
)
type Lock interface {
Name() string
TryLock() error
Lock() error
Unlock() error
Destroy() error
}
type lock struct {
fd int
file *os.File
}
func (l *lock) Name() string {
return l.file.Name()
}
// TryLock acquires exclusivity on the lock without blocking
func (l *lock) TryLock() error {
var lock syscall.Flock_t
lock.Start = 0
lock.Len = 0
lock.Pid = 0
lock.Type = syscall.F_WRLCK
lock.Whence = 0
lock.Pid = 0
err := syscall.FcntlFlock(uintptr(l.fd), syscall.F_SETLK, &lock)
if err != nil && err == syscall.EAGAIN {
return ErrLocked
}
return err
}
// Lock acquires exclusivity on the lock without blocking
func (l *lock) Lock() error {
var lock syscall.Flock_t
lock.Start = 0
lock.Len = 0
lock.Type = syscall.F_WRLCK
lock.Whence = 0
lock.Pid = 0
return syscall.FcntlFlock(uintptr(l.fd), syscall.F_SETLK, &lock)
}
// Unlock unlocks the lock
func (l *lock) Unlock() error {
var lock syscall.Flock_t
lock.Start = 0
lock.Len = 0
lock.Type = syscall.F_UNLCK
lock.Whence = 0
err := syscall.FcntlFlock(uintptr(l.fd), syscall.F_SETLK, &lock)
if err != nil && err == syscall.EAGAIN {
return ErrLocked
}
return err
}
func (l *lock) Destroy() error {
return l.file.Close()
}
func NewLock(file string) (Lock, error) {
f, err := os.OpenFile(file, os.O_WRONLY, 0600)
if err != nil {
return nil, err
}
l := &lock{int(f.Fd()), f}
return l, nil
}

View File

@ -1,96 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package fileutil
import (
"io/ioutil"
"os"
"testing"
"time"
)
func TestLockAndUnlock(t *testing.T) {
f, err := ioutil.TempFile("", "lock")
if err != nil {
t.Fatal(err)
}
f.Close()
defer func() {
err := os.Remove(f.Name())
if err != nil {
t.Fatal(err)
}
}()
// lock the file
l, err := NewLock(f.Name())
if err != nil {
t.Fatal(err)
}
defer l.Destroy()
err = l.Lock()
if err != nil {
t.Fatal(err)
}
// try lock a locked file
dupl, err := NewLock(f.Name())
if err != nil {
t.Fatal(err)
}
err = dupl.TryLock()
if err != ErrLocked {
t.Errorf("err = %v, want %v", err, ErrLocked)
}
// unlock the file
err = l.Unlock()
if err != nil {
t.Fatal(err)
}
// try lock the unlocked file
err = dupl.TryLock()
if err != nil {
t.Errorf("err = %v, want %v", err, nil)
}
defer dupl.Destroy()
// blocking on locked file
locked := make(chan struct{}, 1)
go func() {
l.Lock()
locked <- struct{}{}
}()
select {
case <-locked:
t.Error("unexpected unblocking")
case <-time.After(10 * time.Millisecond):
}
// unlock
err = dupl.Unlock()
if err != nil {
t.Fatal(err)
}
// the previously blocked routine should be unblocked
select {
case <-locked:
case <-time.After(20 * time.Millisecond):
t.Error("unexpected blocking")
}
}

View File

@ -1,76 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
// +build !windows,!plan9,!solaris
package fileutil
import (
"errors"
"os"
"syscall"
)
var (
ErrLocked = errors.New("file already locked")
)
type Lock interface {
Name() string
TryLock() error
Lock() error
Unlock() error
Destroy() error
}
type lock struct {
fd int
file *os.File
}
func (l *lock) Name() string {
return l.file.Name()
}
// TryLock acquires exclusivity on the lock without blocking
func (l *lock) TryLock() error {
err := syscall.Flock(l.fd, syscall.LOCK_EX|syscall.LOCK_NB)
if err != nil && err == syscall.EWOULDBLOCK {
return ErrLocked
}
return err
}
// Lock acquires exclusivity on the lock without blocking
func (l *lock) Lock() error {
return syscall.Flock(l.fd, syscall.LOCK_EX)
}
// Unlock unlocks the lock
func (l *lock) Unlock() error {
return syscall.Flock(l.fd, syscall.LOCK_UN)
}
func (l *lock) Destroy() error {
return l.file.Close()
}
func NewLock(file string) (Lock, error) {
f, err := os.Open(file)
if err != nil {
return nil, err
}
l := &lock{int(f.Fd()), f}
return l, nil
}

View File

@ -1,71 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
// +build windows
package fileutil
import (
"errors"
"os"
)
var (
ErrLocked = errors.New("file already locked")
)
type Lock interface {
Name() string
TryLock() error
Lock() error
Unlock() error
Destroy() error
}
type lock struct {
fd int
file *os.File
}
func (l *lock) Name() string {
return l.file.Name()
}
// TryLock acquires exclusivity on the lock without blocking
func (l *lock) TryLock() error {
return nil
}
// Lock acquires exclusivity on the lock without blocking
func (l *lock) Lock() error {
return nil
}
// Unlock unlocks the lock
func (l *lock) Unlock() error {
return nil
}
func (l *lock) Destroy() error {
return l.file.Close()
}
func NewLock(file string) (Lock, error) {
f, err := os.Open(file)
if err != nil {
return nil, err
}
l := &lock{int(f.Fd()), f}
return l, nil
}

View File

@ -1,28 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
// +build !linux
package fileutil
import "os"
// Preallocate tries to allocate the space for given
// file. This operation is only supported on linux by a
// few filesystems (btrfs, ext4, etc.).
// If the operation is unsupported, no error will be returned.
// Otherwise, the error encountered will be returned.
func Preallocate(f *os.File, sizeInBytes int) error {
return nil
}

View File

@ -1,42 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
// +build linux
package fileutil
import (
"os"
"syscall"
)
// Preallocate tries to allocate the space for given
// file. This operation is only supported on linux by a
// few filesystems (btrfs, ext4, etc.).
// If the operation is unsupported, no error will be returned.
// Otherwise, the error encountered will be returned.
func Preallocate(f *os.File, sizeInBytes int) error {
// use mode = 1 to keep size
// see FALLOC_FL_KEEP_SIZE
err := syscall.Fallocate(int(f.Fd()), 1, 0, int64(sizeInBytes))
if err != nil {
errno, ok := err.(syscall.Errno)
// treat not support as nil error
if ok && errno == syscall.ENOTSUP {
return nil
}
return err
}
return nil
}

View File

@ -1,53 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package fileutil
import (
"io/ioutil"
"os"
"runtime"
"testing"
)
func TestPreallocate(t *testing.T) {
if runtime.GOOS != "linux" {
t.Skipf("skip testPreallocate, OS = %s", runtime.GOOS)
}
p, err := ioutil.TempDir(os.TempDir(), "preallocateTest")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(p)
f, err := ioutil.TempFile(p, "")
if err != nil {
t.Fatal(err)
}
size := 64 * 1000
err = Preallocate(f, size)
if err != nil {
t.Fatal(err)
}
stat, err := f.Stat()
if err != nil {
t.Fatal(err)
}
if stat.Size() != 0 {
t.Errorf("size = %d, want %d", stat.Size(), 0)
}
}

View File

@ -1,80 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package fileutil
import (
"os"
"path"
"sort"
"strings"
"time"
)
func PurgeFile(dirname string, suffix string, max uint, interval time.Duration, stop <-chan struct{}) <-chan error {
errC := make(chan error, 1)
go func() {
for {
fnames, err := ReadDir(dirname)
if err != nil {
errC <- err
return
}
newfnames := make([]string, 0)
for _, fname := range fnames {
if strings.HasSuffix(fname, suffix) {
newfnames = append(newfnames, fname)
}
}
sort.Strings(newfnames)
for len(newfnames) > int(max) {
f := path.Join(dirname, newfnames[0])
l, err := NewLock(f)
if err != nil {
errC <- err
return
}
err = l.TryLock()
if err != nil {
break
}
err = os.Remove(f)
if err != nil {
errC <- err
return
}
err = l.Unlock()
if err != nil {
plog.Errorf("error unlocking %s when purging file (%v)", l.Name(), err)
errC <- err
return
}
err = l.Destroy()
if err != nil {
plog.Errorf("error destroying lock %s when purging file (%v)", l.Name(), err)
errC <- err
return
}
plog.Infof("purged file %s successfully", f)
newfnames = newfnames[1:]
}
select {
case <-time.After(interval):
case <-stop:
return
}
}
}()
return errC
}

View File

@ -1,132 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package fileutil
import (
"fmt"
"io/ioutil"
"os"
"path"
"reflect"
"testing"
"time"
)
func TestPurgeFile(t *testing.T) {
dir, err := ioutil.TempDir("", "purgefile")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
for i := 0; i < 5; i++ {
_, err = os.Create(path.Join(dir, fmt.Sprintf("%d.test", i)))
if err != nil {
t.Fatal(err)
}
}
stop := make(chan struct{})
errch := PurgeFile(dir, "test", 3, time.Millisecond, stop)
for i := 5; i < 10; i++ {
_, err = os.Create(path.Join(dir, fmt.Sprintf("%d.test", i)))
if err != nil {
t.Fatal(err)
}
time.Sleep(10 * time.Millisecond)
}
fnames, err := ReadDir(dir)
if err != nil {
t.Fatal(err)
}
wnames := []string{"7.test", "8.test", "9.test"}
if !reflect.DeepEqual(fnames, wnames) {
t.Errorf("filenames = %v, want %v", fnames, wnames)
}
select {
case err := <-errch:
t.Errorf("unexpected purge error %v", err)
case <-time.After(time.Millisecond):
}
close(stop)
}
func TestPurgeFileHoldingLock(t *testing.T) {
dir, err := ioutil.TempDir("", "purgefile")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
for i := 0; i < 10; i++ {
_, err = os.Create(path.Join(dir, fmt.Sprintf("%d.test", i)))
if err != nil {
t.Fatal(err)
}
}
// create a purge barrier at 5
l, err := NewLock(path.Join(dir, fmt.Sprintf("%d.test", 5)))
err = l.Lock()
if err != nil {
t.Fatal(err)
}
stop := make(chan struct{})
errch := PurgeFile(dir, "test", 3, time.Millisecond, stop)
time.Sleep(20 * time.Millisecond)
fnames, err := ReadDir(dir)
if err != nil {
t.Fatal(err)
}
wnames := []string{"5.test", "6.test", "7.test", "8.test", "9.test"}
if !reflect.DeepEqual(fnames, wnames) {
t.Errorf("filenames = %v, want %v", fnames, wnames)
}
select {
case err := <-errch:
t.Errorf("unexpected purge error %v", err)
case <-time.After(time.Millisecond):
}
// remove the purge barrier
err = l.Unlock()
if err != nil {
t.Fatal(err)
}
err = l.Destroy()
if err != nil {
t.Fatal(err)
}
time.Sleep(20 * time.Millisecond)
fnames, err = ReadDir(dir)
if err != nil {
t.Fatal(err)
}
wnames = []string{"7.test", "8.test", "9.test"}
if !reflect.DeepEqual(fnames, wnames) {
t.Errorf("filenames = %v, want %v", fnames, wnames)
}
select {
case err := <-errch:
t.Errorf("unexpected purge error %v", err)
case <-time.After(time.Millisecond):
}
close(stop)
}

View File

@ -1,49 +0,0 @@
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"decoder.go",
"doc.go",
"encoder.go",
"metrics.go",
"multi_readcloser.go",
"repair.go",
"util.go",
"wal.go",
],
importpath = "k8s.io/kubernetes/third_party/forked/etcd221/wal",
deps = [
"//third_party/forked/etcd221/pkg/fileutil:go_default_library",
"//vendor/github.com/coreos/etcd/pkg/crc:go_default_library",
"//vendor/github.com/coreos/etcd/pkg/pbutil:go_default_library",
"//vendor/github.com/coreos/etcd/raft:go_default_library",
"//vendor/github.com/coreos/etcd/raft/raftpb:go_default_library",
"//vendor/github.com/coreos/etcd/wal/walpb:go_default_library",
"//vendor/github.com/coreos/pkg/capnslog:go_default_library",
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//third_party/forked/etcd221/wal/walpb:all-srcs",
],
tags = ["automanaged"],
)

View File

@ -1,103 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package wal
import (
"bufio"
"encoding/binary"
"hash"
"io"
"sync"
"github.com/coreos/etcd/pkg/crc"
"github.com/coreos/etcd/pkg/pbutil"
"github.com/coreos/etcd/raft/raftpb"
"github.com/coreos/etcd/wal/walpb"
)
type decoder struct {
mu sync.Mutex
br *bufio.Reader
c io.Closer
crc hash.Hash32
}
func newDecoder(rc io.ReadCloser) *decoder {
return &decoder{
br: bufio.NewReader(rc),
c: rc,
crc: crc.New(0, crcTable),
}
}
func (d *decoder) decode(rec *walpb.Record) error {
d.mu.Lock()
defer d.mu.Unlock()
rec.Reset()
l, err := readInt64(d.br)
if err != nil {
return err
}
data := make([]byte, l)
if _, err = io.ReadFull(d.br, data); err != nil {
// ReadFull returns io.EOF only if no bytes were read
// the decoder should treat this as an ErrUnexpectedEOF instead.
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return err
}
if err := rec.Unmarshal(data); err != nil {
return err
}
// skip crc checking if the record type is crcType
if rec.Type == crcType {
return nil
}
d.crc.Write(rec.Data)
return rec.Validate(d.crc.Sum32())
}
func (d *decoder) updateCRC(prevCrc uint32) {
d.crc = crc.New(prevCrc, crcTable)
}
func (d *decoder) lastCRC() uint32 {
return d.crc.Sum32()
}
func (d *decoder) close() error {
return d.c.Close()
}
func mustUnmarshalEntry(d []byte) raftpb.Entry {
var e raftpb.Entry
pbutil.MustUnmarshal(&e, d)
return e
}
func mustUnmarshalState(d []byte) raftpb.HardState {
var s raftpb.HardState
pbutil.MustUnmarshal(&s, d)
return s
}
func readInt64(r io.Reader) (int64, error) {
var n int64
err := binary.Read(r, binary.LittleEndian, &n)
return n, err
}

View File

@ -1,68 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
/*
Package wal provides an implementation of a write ahead log that is used by
etcd.
A WAL is created at a particular directory and is made up of a number of
segmented WAL files. Inside of each file the raft state and entries are appended
to it with the Save method:
metadata := []byte{}
w, err := wal.Create("/var/lib/etcd", metadata)
...
err := w.Save(s, ents)
After saving an raft snapshot to disk, SaveSnapshot method should be called to
record it. So WAL can match with the saved snapshot when restarting.
err := w.SaveSnapshot(walpb.Snapshot{Index: 10, Term: 2})
When a user has finished using a WAL it must be closed:
w.Close()
WAL files are placed inside of the directory in the following format:
$seq-$index.wal
The first WAL file to be created will be 0000000000000000-0000000000000000.wal
indicating an initial sequence of 0 and an initial raft index of 0. The first
entry written to WAL MUST have raft index 0.
WAL will cuts its current wal files if its size exceeds 8MB. This will increment an internal
sequence number and cause a new file to be created. If the last raft index saved
was 0x20 and this is the first time cut has been called on this WAL then the sequence will
increment from 0x0 to 0x1. The new file will be: 0000000000000001-0000000000000021.wal.
If a second cut issues 0x10 entries with incremental index later then the file will be called:
0000000000000002-0000000000000031.wal.
At a later time a WAL can be opened at a particular snapshot. If there is no
snapshot, an empty snapshot should be passed in.
w, err := wal.Open("/var/lib/etcd", walpb.Snapshot{Index: 10, Term: 2})
...
The snapshot must have been written to the WAL.
Additional items cannot be Saved to this WAL until all of the items from the given
snapshot to the end of the WAL are read first:
metadata, state, ents, err := w.ReadAll()
This will give you the metadata, the last raft.State and the slice of
raft.Entry items in the log.
*/
package wal

View File

@ -1,89 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package wal
import (
"bufio"
"encoding/binary"
"hash"
"io"
"sync"
"github.com/coreos/etcd/pkg/crc"
"github.com/coreos/etcd/wal/walpb"
)
type encoder struct {
mu sync.Mutex
bw *bufio.Writer
crc hash.Hash32
buf []byte
uint64buf []byte
}
func newEncoder(w io.Writer, prevCrc uint32) *encoder {
return &encoder{
bw: bufio.NewWriter(w),
crc: crc.New(prevCrc, crcTable),
// 1MB buffer
buf: make([]byte, 1024*1024),
uint64buf: make([]byte, 8),
}
}
func (e *encoder) encode(rec *walpb.Record) error {
e.mu.Lock()
defer e.mu.Unlock()
e.crc.Write(rec.Data)
rec.Crc = e.crc.Sum32()
var (
data []byte
err error
n int
)
if rec.Size() > len(e.buf) {
data, err = rec.Marshal()
if err != nil {
return err
}
} else {
n, err = rec.MarshalTo(e.buf)
if err != nil {
return err
}
data = e.buf[:n]
}
if err := writeInt64(e.bw, int64(len(data)), e.uint64buf); err != nil {
return err
}
_, err = e.bw.Write(data)
return err
}
func (e *encoder) flush() error {
e.mu.Lock()
defer e.mu.Unlock()
return e.bw.Flush()
}
func writeInt64(w io.Writer, n int64, buf []byte) error {
// http://golang.org/src/encoding/binary/binary.go
binary.LittleEndian.PutUint64(buf, uint64(n))
_, err := w.Write(buf)
return err
}

View File

@ -1,37 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package wal
import "github.com/prometheus/client_golang/prometheus"
var (
syncDurations = prometheus.NewSummary(prometheus.SummaryOpts{
Namespace: "etcd",
Subsystem: "wal",
Name: "fsync_durations_microseconds",
Help: "The latency distributions of fsync called by wal.",
})
lastIndexSaved = prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: "etcd",
Subsystem: "wal",
Name: "last_index_saved",
Help: "The index of the last entry saved by wal.",
})
)
func init() {
prometheus.MustRegister(syncDurations)
prometheus.MustRegister(lastIndexSaved)
}

View File

@ -1,45 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package wal
import "io"
type multiReadCloser struct {
closers []io.Closer
reader io.Reader
}
func (mc *multiReadCloser) Close() error {
var err error
for i := range mc.closers {
err = mc.closers[i].Close()
}
return err
}
func (mc *multiReadCloser) Read(p []byte) (int, error) {
return mc.reader.Read(p)
}
func MultiReadCloser(readClosers ...io.ReadCloser) io.ReadCloser {
cs := make([]io.Closer, len(readClosers))
rs := make([]io.Reader, len(readClosers))
for i := range readClosers {
cs[i] = readClosers[i]
rs[i] = readClosers[i]
}
r := io.MultiReader(rs...)
return &multiReadCloser{cs, r}
}

View File

@ -1,107 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package wal
import (
"io"
"os"
"path"
"k8s.io/kubernetes/third_party/forked/etcd221/pkg/fileutil"
"github.com/coreos/etcd/wal/walpb"
)
// Repair tries to repair the unexpectedEOF error in the
// last wal file by truncating.
func Repair(dirpath string) bool {
f, err := openLast(dirpath)
if err != nil {
return false
}
defer f.Close()
n := 0
rec := &walpb.Record{}
decoder := newDecoder(f)
defer decoder.close()
for {
err := decoder.decode(rec)
switch err {
case nil:
n += 8 + rec.Size()
// update crc of the decoder when necessary
switch rec.Type {
case crcType:
crc := decoder.crc.Sum32()
// current crc of decoder must match the crc of the record.
// do no need to match 0 crc, since the decoder is a new one at this case.
if crc != 0 && rec.Validate(crc) != nil {
return false
}
decoder.updateCRC(rec.Crc)
}
continue
case io.EOF:
return true
case io.ErrUnexpectedEOF:
plog.Noticef("repairing %v", f.Name())
bf, bferr := os.Create(f.Name() + ".broken")
if bferr != nil {
plog.Errorf("could not repair %v, failed to create backup file", f.Name())
return false
}
defer bf.Close()
if _, err = f.Seek(0, os.SEEK_SET); err != nil {
plog.Errorf("could not repair %v, failed to read file", f.Name())
return false
}
if _, err = io.Copy(bf, f); err != nil {
plog.Errorf("could not repair %v, failed to copy file", f.Name())
return false
}
if err = f.Truncate(int64(n)); err != nil {
plog.Errorf("could not repair %v, failed to truncate file", f.Name())
return false
}
if err = f.Sync(); err != nil {
plog.Errorf("could not repair %v, failed to sync file", f.Name())
return false
}
return true
default:
plog.Errorf("could not repair error (%v)", err)
return false
}
}
}
// openLast opens the last wal file for read and write.
func openLast(dirpath string) (*os.File, error) {
names, err := fileutil.ReadDir(dirpath)
if err != nil {
return nil, err
}
names = checkWalNames(names)
if len(names) == 0 {
return nil, ErrFileNotFound
}
last := path.Join(dirpath, names[len(names)-1])
return os.OpenFile(last, os.O_RDWR, 0)
}

View File

@ -1,93 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package wal
import (
"errors"
"fmt"
"strings"
"k8s.io/kubernetes/third_party/forked/etcd221/pkg/fileutil"
)
var (
badWalName = errors.New("bad wal name")
)
func Exist(dirpath string) bool {
names, err := fileutil.ReadDir(dirpath)
if err != nil {
return false
}
return len(names) != 0
}
// searchIndex returns the last array index of names whose raft index section is
// equal to or smaller than the given index.
// The given names MUST be sorted.
func searchIndex(names []string, index uint64) (int, bool) {
for i := len(names) - 1; i >= 0; i-- {
name := names[i]
_, curIndex, err := parseWalName(name)
if err != nil {
plog.Panicf("parse correct name should never fail: %v", err)
}
if index >= curIndex {
return i, true
}
}
return -1, false
}
// names should have been sorted based on sequence number.
// isValidSeq checks whether seq increases continuously.
func isValidSeq(names []string) bool {
var lastSeq uint64
for _, name := range names {
curSeq, _, err := parseWalName(name)
if err != nil {
plog.Panicf("parse correct name should never fail: %v", err)
}
if lastSeq != 0 && lastSeq != curSeq-1 {
return false
}
lastSeq = curSeq
}
return true
}
func checkWalNames(names []string) []string {
wnames := make([]string, 0)
for _, name := range names {
if _, _, err := parseWalName(name); err != nil {
plog.Warningf("ignored file %v in wal", name)
continue
}
wnames = append(wnames, name)
}
return wnames
}
func parseWalName(str string) (seq, index uint64, err error) {
if !strings.HasSuffix(str, ".wal") {
return 0, 0, badWalName
}
_, err = fmt.Sscanf(str, "%016x-%016x.wal", &seq, &index)
return seq, index, err
}
func walName(seq, index uint64) string {
return fmt.Sprintf("%016x-%016x.wal", seq, index)
}

View File

@ -1,548 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package wal
import (
"errors"
"fmt"
"hash/crc32"
"io"
"os"
"path"
"reflect"
"sync"
"time"
"k8s.io/kubernetes/third_party/forked/etcd221/pkg/fileutil"
"github.com/coreos/etcd/pkg/pbutil"
"github.com/coreos/etcd/raft"
"github.com/coreos/etcd/raft/raftpb"
"github.com/coreos/etcd/wal/walpb"
"github.com/coreos/pkg/capnslog"
)
const (
metadataType int64 = iota + 1
entryType
stateType
crcType
snapshotType
// the owner can make/remove files inside the directory
privateDirMode = 0700
// the expected size of each wal segment file.
// the actual size might be bigger than it.
segmentSizeBytes = 64 * 1000 * 1000 // 64MB
)
var (
plog = capnslog.NewPackageLogger("github.com/coreos/etcd", "wal")
ErrMetadataConflict = errors.New("wal: conflicting metadata found")
ErrFileNotFound = errors.New("wal: file not found")
ErrCRCMismatch = errors.New("wal: crc mismatch")
ErrSnapshotMismatch = errors.New("wal: snapshot mismatch")
ErrSnapshotNotFound = errors.New("wal: snapshot not found")
crcTable = crc32.MakeTable(crc32.Castagnoli)
)
// WAL is a logical repersentation of the stable storage.
// WAL is either in read mode or append mode but not both.
// A newly created WAL is in append mode, and ready for appending records.
// A just opened WAL is in read mode, and ready for reading records.
// The WAL will be ready for appending after reading out all the previous records.
type WAL struct {
dir string // the living directory of the underlay files
metadata []byte // metadata recorded at the head of each WAL
state raftpb.HardState // hardstate recorded at the head of WAL
start walpb.Snapshot // snapshot to start reading
decoder *decoder // decoder to decode records
mu sync.Mutex
f *os.File // underlay file opened for appending, sync
seq uint64 // sequence of the wal file currently used for writes
enti uint64 // index of the last entry saved to the wal
encoder *encoder // encoder to encode records
locks []fileutil.Lock // the file locks the WAL is holding (the name is increasing)
}
// Create creates a WAL ready for appending records. The given metadata is
// recorded at the head of each WAL file, and can be retrieved with ReadAll.
func Create(dirpath string, metadata []byte) (*WAL, error) {
if Exist(dirpath) {
return nil, os.ErrExist
}
if err := os.MkdirAll(dirpath, privateDirMode); err != nil {
return nil, err
}
p := path.Join(dirpath, walName(0, 0))
f, err := os.OpenFile(p, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
if err != nil {
return nil, err
}
l, err := fileutil.NewLock(f.Name())
if err != nil {
return nil, err
}
err = l.Lock()
if err != nil {
return nil, err
}
w := &WAL{
dir: dirpath,
metadata: metadata,
seq: 0,
f: f,
encoder: newEncoder(f, 0),
}
w.locks = append(w.locks, l)
if err := w.saveCrc(0); err != nil {
return nil, err
}
if err := w.encoder.encode(&walpb.Record{Type: metadataType, Data: metadata}); err != nil {
return nil, err
}
if err = w.SaveSnapshot(walpb.Snapshot{}); err != nil {
return nil, err
}
return w, nil
}
// Open opens the WAL at the given snap.
// The snap SHOULD have been previously saved to the WAL, or the following
// ReadAll will fail.
// The returned WAL is ready to read and the first record will be the one after
// the given snap. The WAL cannot be appended to before reading out all of its
// previous records.
func Open(dirpath string, snap walpb.Snapshot) (*WAL, error) {
return openAtIndex(dirpath, snap, true)
}
// OpenForRead only opens the wal files for read.
// Write on a read only wal panics.
func OpenForRead(dirpath string, snap walpb.Snapshot) (*WAL, error) {
return openAtIndex(dirpath, snap, false)
}
func openAtIndex(dirpath string, snap walpb.Snapshot, write bool) (*WAL, error) {
names, err := fileutil.ReadDir(dirpath)
if err != nil {
return nil, err
}
names = checkWalNames(names)
if len(names) == 0 {
return nil, ErrFileNotFound
}
nameIndex, ok := searchIndex(names, snap.Index)
if !ok || !isValidSeq(names[nameIndex:]) {
return nil, ErrFileNotFound
}
// open the wal files for reading
rcs := make([]io.ReadCloser, 0)
ls := make([]fileutil.Lock, 0)
for _, name := range names[nameIndex:] {
f, err := os.Open(path.Join(dirpath, name))
if err != nil {
return nil, err
}
l, err := fileutil.NewLock(f.Name())
if err != nil {
return nil, err
}
err = l.TryLock()
if err != nil {
if write {
return nil, err
}
}
rcs = append(rcs, f)
ls = append(ls, l)
}
rc := MultiReadCloser(rcs...)
// create a WAL ready for reading
w := &WAL{
dir: dirpath,
start: snap,
decoder: newDecoder(rc),
locks: ls,
}
if write {
// open the lastest wal file for appending
seq, _, err := parseWalName(names[len(names)-1])
if err != nil {
rc.Close()
return nil, err
}
last := path.Join(dirpath, names[len(names)-1])
f, err := os.OpenFile(last, os.O_WRONLY|os.O_APPEND, 0)
if err != nil {
rc.Close()
return nil, err
}
err = fileutil.Preallocate(f, segmentSizeBytes)
if err != nil {
rc.Close()
plog.Errorf("failed to allocate space when creating new wal file (%v)", err)
return nil, err
}
w.f = f
w.seq = seq
}
return w, nil
}
// ReadAll reads out records of the current WAL.
// If opened in write mode, it must read out all records until EOF. Or an error
// will be returned.
// If opened in read mode, it will try to read all records if possible.
// If it cannot read out the expected snap, it will return ErrSnapshotNotFound.
// If loaded snap doesn't match with the expected one, it will return
// all the records and error ErrSnapshotMismatch.
// TODO: detect not-last-snap error.
// TODO: maybe loose the checking of match.
// After ReadAll, the WAL will be ready for appending new records.
func (w *WAL) ReadAll() (metadata []byte, state raftpb.HardState, ents []raftpb.Entry, err error) {
w.mu.Lock()
defer w.mu.Unlock()
rec := &walpb.Record{}
decoder := w.decoder
var match bool
for err = decoder.decode(rec); err == nil; err = decoder.decode(rec) {
switch rec.Type {
case entryType:
e := mustUnmarshalEntry(rec.Data)
if e.Index > w.start.Index {
ents = append(ents[:e.Index-w.start.Index-1], e)
}
w.enti = e.Index
case stateType:
state = mustUnmarshalState(rec.Data)
case metadataType:
if metadata != nil && !reflect.DeepEqual(metadata, rec.Data) {
state.Reset()
return nil, state, nil, ErrMetadataConflict
}
metadata = rec.Data
case crcType:
crc := decoder.crc.Sum32()
// current crc of decoder must match the crc of the record.
// do no need to match 0 crc, since the decoder is a new one at this case.
if crc != 0 && rec.Validate(crc) != nil {
state.Reset()
return nil, state, nil, ErrCRCMismatch
}
decoder.updateCRC(rec.Crc)
case snapshotType:
var snap walpb.Snapshot
pbutil.MustUnmarshal(&snap, rec.Data)
if snap.Index == w.start.Index {
if snap.Term != w.start.Term {
state.Reset()
return nil, state, nil, ErrSnapshotMismatch
}
match = true
}
default:
state.Reset()
return nil, state, nil, fmt.Errorf("unexpected block type %d", rec.Type)
}
}
switch w.f {
case nil:
// We do not have to read out all entries in read mode.
// The last record maybe a partial written one, so
// ErrunexpectedEOF might be returned.
if err != io.EOF && err != io.ErrUnexpectedEOF {
state.Reset()
return nil, state, nil, err
}
default:
// We must read all of the entries if WAL is opened in write mode.
if err != io.EOF {
state.Reset()
return nil, state, nil, err
}
}
err = nil
if !match {
err = ErrSnapshotNotFound
}
// close decoder, disable reading
w.decoder.close()
w.start = walpb.Snapshot{}
w.metadata = metadata
if w.f != nil {
// create encoder (chain crc with the decoder), enable appending
w.encoder = newEncoder(w.f, w.decoder.lastCRC())
w.decoder = nil
lastIndexSaved.Set(float64(w.enti))
}
return metadata, state, ents, err
}
// cut closes current file written and creates a new one ready to append.
// cut first creates a temp wal file and writes necessary headers into it.
// Then cut atomtically rename temp wal file to a wal file.
func (w *WAL) cut() error {
// close old wal file
if err := w.sync(); err != nil {
return err
}
if err := w.f.Close(); err != nil {
return err
}
fpath := path.Join(w.dir, walName(w.seq+1, w.enti+1))
ftpath := fpath + ".tmp"
// create a temp wal file with name sequence + 1, or tuncate the existing one
ft, err := os.OpenFile(ftpath, os.O_WRONLY|os.O_APPEND|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return err
}
// update writer and save the previous crc
w.f = ft
prevCrc := w.encoder.crc.Sum32()
w.encoder = newEncoder(w.f, prevCrc)
if err := w.saveCrc(prevCrc); err != nil {
return err
}
if err := w.encoder.encode(&walpb.Record{Type: metadataType, Data: w.metadata}); err != nil {
return err
}
if err := w.saveState(&w.state); err != nil {
return err
}
// close temp wal file
if err := w.sync(); err != nil {
return err
}
if err := w.f.Close(); err != nil {
return err
}
// atomically move temp wal file to wal file
if err := os.Rename(ftpath, fpath); err != nil {
return err
}
// open the wal file and update writer again
f, err := os.OpenFile(fpath, os.O_WRONLY|os.O_APPEND, 0600)
if err != nil {
return err
}
err = fileutil.Preallocate(f, segmentSizeBytes)
if err != nil {
plog.Errorf("failed to allocate space when creating new wal file (%v)", err)
return err
}
w.f = f
prevCrc = w.encoder.crc.Sum32()
w.encoder = newEncoder(w.f, prevCrc)
// lock the new wal file
l, err := fileutil.NewLock(f.Name())
if err != nil {
return err
}
err = l.Lock()
if err != nil {
return err
}
w.locks = append(w.locks, l)
// increase the wal seq
w.seq++
plog.Infof("segmented wal file %v is created", fpath)
return nil
}
func (w *WAL) sync() error {
if w.encoder != nil {
if err := w.encoder.flush(); err != nil {
return err
}
}
start := time.Now()
err := w.f.Sync()
syncDurations.Observe(float64(time.Since(start).Nanoseconds() / int64(time.Microsecond)))
return err
}
// ReleaseLockTo releases the locks, which has smaller index than the given index
// except the largest one among them.
// For example, if WAL is holding lock 1,2,3,4,5,6, ReleaseLockTo(4) will release
// lock 1,2 but keep 3. ReleaseLockTo(5) will release 1,2,3 but keep 4.
func (w *WAL) ReleaseLockTo(index uint64) error {
w.mu.Lock()
defer w.mu.Unlock()
var smaller int
found := false
for i, l := range w.locks {
_, lockIndex, err := parseWalName(path.Base(l.Name()))
if err != nil {
return err
}
if lockIndex >= index {
smaller = i - 1
found = true
break
}
}
// if no lock index is greater than the release index, we can
// release lock upto the last one(excluding).
if !found && len(w.locks) != 0 {
smaller = len(w.locks) - 1
}
if smaller <= 0 {
return nil
}
for i := 0; i < smaller; i++ {
w.locks[i].Unlock()
w.locks[i].Destroy()
}
w.locks = w.locks[smaller:]
return nil
}
func (w *WAL) Close() error {
w.mu.Lock()
defer w.mu.Unlock()
if w.f != nil {
if err := w.sync(); err != nil {
return err
}
if err := w.f.Close(); err != nil {
return err
}
}
for _, l := range w.locks {
err := l.Unlock()
if err != nil {
plog.Errorf("failed to unlock during closing wal: %s", err)
}
err = l.Destroy()
if err != nil {
plog.Errorf("failed to destroy lock during closing wal: %s", err)
}
}
return nil
}
func (w *WAL) saveEntry(e *raftpb.Entry) error {
// TODO: add MustMarshalTo to reduce one allocation.
b := pbutil.MustMarshal(e)
rec := &walpb.Record{Type: entryType, Data: b}
if err := w.encoder.encode(rec); err != nil {
return err
}
w.enti = e.Index
lastIndexSaved.Set(float64(w.enti))
return nil
}
func (w *WAL) saveState(s *raftpb.HardState) error {
if raft.IsEmptyHardState(*s) {
return nil
}
w.state = *s
b := pbutil.MustMarshal(s)
rec := &walpb.Record{Type: stateType, Data: b}
return w.encoder.encode(rec)
}
func (w *WAL) Save(st raftpb.HardState, ents []raftpb.Entry) error {
w.mu.Lock()
defer w.mu.Unlock()
// short cut, do not call sync
if raft.IsEmptyHardState(st) && len(ents) == 0 {
return nil
}
// TODO(xiangli): no more reference operator
for i := range ents {
if err := w.saveEntry(&ents[i]); err != nil {
return err
}
}
if err := w.saveState(&st); err != nil {
return err
}
fstat, err := w.f.Stat()
if err != nil {
return err
}
if fstat.Size() < segmentSizeBytes {
return w.sync()
}
// TODO: add a test for this code path when refactoring the tests
return w.cut()
}
func (w *WAL) SaveSnapshot(e walpb.Snapshot) error {
w.mu.Lock()
defer w.mu.Unlock()
b := pbutil.MustMarshal(&e)
rec := &walpb.Record{Type: snapshotType, Data: b}
if err := w.encoder.encode(rec); err != nil {
return err
}
// update enti only when snapshot is ahead of last index
if w.enti < e.Index {
w.enti = e.Index
}
lastIndexSaved.Set(float64(w.enti))
return w.sync()
}
func (w *WAL) saveCrc(prevCrc uint32) error {
return w.encoder.encode(&walpb.Record{Type: crcType, Crc: prevCrc})
}

View File

@ -1,31 +0,0 @@
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"record.go",
"record.pb.go",
],
importpath = "k8s.io/kubernetes/third_party/forked/etcd221/wal/walpb",
deps = ["//vendor/github.com/gogo/protobuf/proto:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -1,29 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package walpb
import "errors"
var (
ErrCRCMismatch = errors.New("walpb: crc mismatch")
)
func (rec *Record) Validate(crc uint32) error {
if rec.Crc == crc {
return nil
}
rec.Reset()
return ErrCRCMismatch
}

View File

@ -1,447 +0,0 @@
// Code generated by protoc-gen-gogo.
// source: record.proto
// DO NOT EDIT!
/*
Package walpb is a generated protocol buffer package.
It is generated from these files:
record.proto
It has these top-level messages:
Record
Snapshot
*/
package walpb
import proto "github.com/gogo/protobuf/proto"
import math "math"
// discarding unused import gogoproto "github.com/coreos/etcd/Godeps/_workspace/src/gogoproto"
import io "io"
import fmt "fmt"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = math.Inf
type Record struct {
Type int64 `protobuf:"varint,1,opt,name=type" json:"type"`
Crc uint32 `protobuf:"varint,2,opt,name=crc" json:"crc"`
Data []byte `protobuf:"bytes,3,opt,name=data" json:"data,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *Record) Reset() { *m = Record{} }
func (m *Record) String() string { return proto.CompactTextString(m) }
func (*Record) ProtoMessage() {}
type Snapshot struct {
Index uint64 `protobuf:"varint,1,opt,name=index" json:"index"`
Term uint64 `protobuf:"varint,2,opt,name=term" json:"term"`
XXX_unrecognized []byte `json:"-"`
}
func (m *Snapshot) Reset() { *m = Snapshot{} }
func (m *Snapshot) String() string { return proto.CompactTextString(m) }
func (*Snapshot) ProtoMessage() {}
func (m *Record) Marshal() (data []byte, err error) {
size := m.Size()
data = make([]byte, size)
n, err := m.MarshalTo(data)
if err != nil {
return nil, err
}
return data[:n], nil
}
func (m *Record) MarshalTo(data []byte) (int, error) {
var i int
_ = i
var l int
_ = l
data[i] = 0x8
i++
i = encodeVarintRecord(data, i, uint64(m.Type))
data[i] = 0x10
i++
i = encodeVarintRecord(data, i, uint64(m.Crc))
if m.Data != nil {
data[i] = 0x1a
i++
i = encodeVarintRecord(data, i, uint64(len(m.Data)))
i += copy(data[i:], m.Data)
}
if m.XXX_unrecognized != nil {
i += copy(data[i:], m.XXX_unrecognized)
}
return i, nil
}
func (m *Snapshot) Marshal() (data []byte, err error) {
size := m.Size()
data = make([]byte, size)
n, err := m.MarshalTo(data)
if err != nil {
return nil, err
}
return data[:n], nil
}
func (m *Snapshot) MarshalTo(data []byte) (int, error) {
var i int
_ = i
var l int
_ = l
data[i] = 0x8
i++
i = encodeVarintRecord(data, i, uint64(m.Index))
data[i] = 0x10
i++
i = encodeVarintRecord(data, i, uint64(m.Term))
if m.XXX_unrecognized != nil {
i += copy(data[i:], m.XXX_unrecognized)
}
return i, nil
}
func encodeFixed64Record(data []byte, offset int, v uint64) int {
data[offset] = uint8(v)
data[offset+1] = uint8(v >> 8)
data[offset+2] = uint8(v >> 16)
data[offset+3] = uint8(v >> 24)
data[offset+4] = uint8(v >> 32)
data[offset+5] = uint8(v >> 40)
data[offset+6] = uint8(v >> 48)
data[offset+7] = uint8(v >> 56)
return offset + 8
}
func encodeFixed32Record(data []byte, offset int, v uint32) int {
data[offset] = uint8(v)
data[offset+1] = uint8(v >> 8)
data[offset+2] = uint8(v >> 16)
data[offset+3] = uint8(v >> 24)
return offset + 4
}
func encodeVarintRecord(data []byte, offset int, v uint64) int {
for v >= 1<<7 {
data[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
data[offset] = uint8(v)
return offset + 1
}
func (m *Record) Size() (n int) {
var l int
_ = l
n += 1 + sovRecord(uint64(m.Type))
n += 1 + sovRecord(uint64(m.Crc))
if m.Data != nil {
l = len(m.Data)
n += 1 + l + sovRecord(uint64(l))
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
return n
}
func (m *Snapshot) Size() (n int) {
var l int
_ = l
n += 1 + sovRecord(uint64(m.Index))
n += 1 + sovRecord(uint64(m.Term))
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
return n
}
func sovRecord(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
func sozRecord(x uint64) (n int) {
return sovRecord(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *Record) Unmarshal(data []byte) error {
l := len(data)
iNdEx := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType)
}
m.Type = 0
for shift := uint(0); ; shift += 7 {
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
m.Type |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Crc", wireType)
}
m.Crc = 0
for shift := uint(0); ; shift += 7 {
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
m.Crc |= (uint32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
byteLen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthRecord
}
postIndex := iNdEx + byteLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Data = append([]byte{}, data[iNdEx:postIndex]...)
iNdEx = postIndex
default:
var sizeOfWire int
for {
sizeOfWire++
wire >>= 7
if wire == 0 {
break
}
}
iNdEx -= sizeOfWire
skippy, err := skipRecord(data[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthRecord
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, data[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
return nil
}
func (m *Snapshot) Unmarshal(data []byte) error {
l := len(data)
iNdEx := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Index", wireType)
}
m.Index = 0
for shift := uint(0); ; shift += 7 {
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
m.Index |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Term", wireType)
}
m.Term = 0
for shift := uint(0); ; shift += 7 {
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
m.Term |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
var sizeOfWire int
for {
sizeOfWire++
wire >>= 7
if wire == 0 {
break
}
}
iNdEx -= sizeOfWire
skippy, err := skipRecord(data[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthRecord
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, data[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
return nil
}
func skipRecord(data []byte) (n int, err error) {
l := len(data)
iNdEx := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for {
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if data[iNdEx-1] < 0x80 {
break
}
}
return iNdEx, nil
case 1:
iNdEx += 8
return iNdEx, nil
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
iNdEx += length
if length < 0 {
return 0, ErrInvalidLengthRecord
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
innerWire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
innerWireType := int(innerWire & 0x7)
if innerWireType == 4 {
break
}
next, err := skipRecord(data[start:])
if err != nil {
return 0, err
}
iNdEx = start + next
}
return iNdEx, nil
case 4:
return iNdEx, nil
case 5:
iNdEx += 4
return iNdEx, nil
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
}
panic("unreachable")
}
var (
ErrInvalidLengthRecord = fmt.Errorf("proto: negative length found during unmarshaling")
)

View File

@ -1,20 +0,0 @@
syntax = "proto2";
package walpb;
import "gogoproto/gogo.proto";
option (gogoproto.marshaler_all) = true;
option (gogoproto.sizer_all) = true;
option (gogoproto.unmarshaler_all) = true;
option (gogoproto.goproto_getters_all) = false;
message Record {
optional int64 type = 1 [(gogoproto.nullable) = false];
optional uint32 crc = 2 [(gogoproto.nullable) = false];
optional bytes data = 3;
}
message Snapshot {
optional uint64 index = 1 [(gogoproto.nullable) = false];
optional uint64 term = 2 [(gogoproto.nullable) = false];
}

View File

@ -1 +0,0 @@
Forked from etcd 2.3 release branch to support migration from 3.0 WAL to 2.3 WAL format

View File

@ -1,54 +0,0 @@
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = [
"fileutil_test.go",
"lock_test.go",
"preallocate_test.go",
"purge_test.go",
],
embed = [":go_default_library"],
)
go_library(
name = "go_default_library",
srcs = [
"fileutil.go",
"lock.go",
"lock_plan9.go",
"lock_solaris.go",
"lock_unix.go",
"lock_windows.go",
"perallocate_unsupported.go",
"preallocate.go",
"purge.go",
"sync.go",
"sync_linux.go",
],
importpath = "k8s.io/kubernetes/third_party/forked/etcd237/pkg/fileutil",
deps = [
"//vendor/github.com/coreos/pkg/capnslog:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -1,75 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
// Package fileutil implements utility functions related to files and paths.
package fileutil
import (
"io/ioutil"
"os"
"path"
"sort"
"github.com/coreos/pkg/capnslog"
)
const (
privateFileMode = 0600
// owner can make/remove files inside the directory
privateDirMode = 0700
)
var (
plog = capnslog.NewPackageLogger("github.com/coreos/etcd/pkg", "fileutil")
)
// IsDirWriteable checks if dir is writable by writing and removing a file
// to dir. It returns nil if dir is writable.
func IsDirWriteable(dir string) error {
f := path.Join(dir, ".touch")
if err := ioutil.WriteFile(f, []byte(""), privateFileMode); err != nil {
return err
}
return os.Remove(f)
}
// ReadDir returns the filenames in the given directory in sorted order.
func ReadDir(dirpath string) ([]string, error) {
dir, err := os.Open(dirpath)
if err != nil {
return nil, err
}
defer dir.Close()
names, err := dir.Readdirnames(-1)
if err != nil {
return nil, err
}
sort.Strings(names)
return names, nil
}
// TouchDirAll is similar to os.MkdirAll. It creates directories with 0700 permission if any directory
// does not exists. TouchDirAll also ensures the given directory is writable.
func TouchDirAll(dir string) error {
err := os.MkdirAll(dir, privateDirMode)
if err != nil && err != os.ErrExist {
return err
}
return IsDirWriteable(dir)
}
func Exist(name string) bool {
_, err := os.Stat(name)
return err == nil
}

View File

@ -1,96 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package fileutil
import (
"io/ioutil"
"os"
"os/user"
"path/filepath"
"reflect"
"testing"
)
func TestIsDirWriteable(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("unexpected ioutil.TempDir error: %v", err)
}
defer os.RemoveAll(tmpdir)
if err = IsDirWriteable(tmpdir); err != nil {
t.Fatalf("unexpected IsDirWriteable error: %v", err)
}
if err = os.Chmod(tmpdir, 0444); err != nil {
t.Fatalf("unexpected os.Chmod error: %v", err)
}
me, err := user.Current()
if err != nil {
// err can be non-nil when cross compiled
// http://stackoverflow.com/questions/20609415/cross-compiling-user-current-not-implemented-on-linux-amd64
t.Skipf("failed to get current user: %v", err)
}
if me.Name == "root" || me.Name == "Administrator" {
// ideally we should check CAP_DAC_OVERRIDE.
// but it does not matter for tests.
t.Skipf("running as a superuser")
}
if err := IsDirWriteable(tmpdir); err == nil {
t.Fatalf("expected IsDirWriteable to error")
}
}
func TestReadDir(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "")
defer os.RemoveAll(tmpdir)
if err != nil {
t.Fatalf("unexpected ioutil.TempDir error: %v", err)
}
files := []string{"def", "abc", "xyz", "ghi"}
for _, f := range files {
var fh *os.File
fh, err = os.Create(filepath.Join(tmpdir, f))
if err != nil {
t.Fatalf("error creating file: %v", err)
}
if err = fh.Close(); err != nil {
t.Fatalf("error closing file: %v", err)
}
}
fs, err := ReadDir(tmpdir)
if err != nil {
t.Fatalf("error calling ReadDir: %v", err)
}
wfs := []string{"abc", "def", "ghi", "xyz"}
if !reflect.DeepEqual(fs, wfs) {
t.Fatalf("ReadDir: got %v, want %v", fs, wfs)
}
}
func TestExist(t *testing.T) {
f, err := ioutil.TempFile(os.TempDir(), "fileutil")
if err != nil {
t.Fatal(err)
}
f.Close()
if g := Exist(f.Name()); g != true {
t.Errorf("exist = %v, want true", g)
}
os.Remove(f.Name())
if g := Exist(f.Name()); g != false {
t.Errorf("exist = %v, want false", g)
}
}

View File

@ -1,29 +0,0 @@
// Copyright 2016 CoreOS, Inc.
//
// 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.
package fileutil
type Lock interface {
// Name returns the name of the file.
Name() string
// TryLock acquires exclusivity on the lock without blocking.
TryLock() error
// Lock acquires exclusivity on the lock.
Lock() error
// Unlock unlocks the lock.
Unlock() error
// Destroy should be called after Unlock to clean up
// the resources.
Destroy() error
}

View File

@ -1,79 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package fileutil
import (
"errors"
"os"
"syscall"
"time"
)
var (
ErrLocked = errors.New("file already locked")
)
type lock struct {
fname string
file *os.File
}
func (l *lock) Name() string {
return l.fname
}
func (l *lock) TryLock() error {
err := os.Chmod(l.fname, syscall.DMEXCL|0600)
if err != nil {
return err
}
f, err := os.Open(l.fname)
if err != nil {
return ErrLocked
}
l.file = f
return nil
}
func (l *lock) Lock() error {
err := os.Chmod(l.fname, syscall.DMEXCL|0600)
if err != nil {
return err
}
for {
f, err := os.Open(l.fname)
if err == nil {
l.file = f
return nil
}
time.Sleep(10 * time.Millisecond)
}
}
func (l *lock) Unlock() error {
return l.file.Close()
}
func (l *lock) Destroy() error {
return nil
}
func NewLock(file string) (Lock, error) {
l := &lock{fname: file}
return l, nil
}

View File

@ -1,87 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
// +build solaris
package fileutil
import (
"errors"
"os"
"syscall"
)
var (
ErrLocked = errors.New("file already locked")
)
type lock struct {
fd int
file *os.File
}
func (l *lock) Name() string {
return l.file.Name()
}
func (l *lock) TryLock() error {
var lock syscall.Flock_t
lock.Start = 0
lock.Len = 0
lock.Pid = 0
lock.Type = syscall.F_WRLCK
lock.Whence = 0
lock.Pid = 0
err := syscall.FcntlFlock(uintptr(l.fd), syscall.F_SETLK, &lock)
if err != nil && err == syscall.EAGAIN {
return ErrLocked
}
return err
}
func (l *lock) Lock() error {
var lock syscall.Flock_t
lock.Start = 0
lock.Len = 0
lock.Type = syscall.F_WRLCK
lock.Whence = 0
lock.Pid = 0
return syscall.FcntlFlock(uintptr(l.fd), syscall.F_SETLK, &lock)
}
func (l *lock) Unlock() error {
var lock syscall.Flock_t
lock.Start = 0
lock.Len = 0
lock.Type = syscall.F_UNLCK
lock.Whence = 0
err := syscall.FcntlFlock(uintptr(l.fd), syscall.F_SETLK, &lock)
if err != nil && err == syscall.EAGAIN {
return ErrLocked
}
return err
}
func (l *lock) Destroy() error {
return l.file.Close()
}
func NewLock(file string) (Lock, error) {
f, err := os.OpenFile(file, os.O_WRONLY, 0600)
if err != nil {
return nil, err
}
l := &lock{int(f.Fd()), f}
return l, nil
}

View File

@ -1,96 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package fileutil
import (
"io/ioutil"
"os"
"testing"
"time"
)
func TestLockAndUnlock(t *testing.T) {
f, err := ioutil.TempFile("", "lock")
if err != nil {
t.Fatal(err)
}
f.Close()
defer func() {
err = os.Remove(f.Name())
if err != nil {
t.Fatal(err)
}
}()
// lock the file
l, err := NewLock(f.Name())
if err != nil {
t.Fatal(err)
}
defer l.Destroy()
err = l.Lock()
if err != nil {
t.Fatal(err)
}
// try lock a locked file
dupl, err := NewLock(f.Name())
if err != nil {
t.Fatal(err)
}
err = dupl.TryLock()
if err != ErrLocked {
t.Errorf("err = %v, want %v", err, ErrLocked)
}
// unlock the file
err = l.Unlock()
if err != nil {
t.Fatal(err)
}
// try lock the unlocked file
err = dupl.TryLock()
if err != nil {
t.Errorf("err = %v, want %v", err, nil)
}
defer dupl.Destroy()
// blocking on locked file
locked := make(chan struct{}, 1)
go func() {
l.Lock()
locked <- struct{}{}
}()
select {
case <-locked:
t.Error("unexpected unblocking")
case <-time.After(100 * time.Millisecond):
}
// unlock
err = dupl.Unlock()
if err != nil {
t.Fatal(err)
}
// the previously blocked routine should be unblocked
select {
case <-locked:
case <-time.After(1 * time.Second):
t.Error("unexpected blocking")
}
}

View File

@ -1,65 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
// +build !windows,!plan9,!solaris
package fileutil
import (
"errors"
"os"
"syscall"
)
var (
ErrLocked = errors.New("file already locked")
)
type lock struct {
fd int
file *os.File
}
func (l *lock) Name() string {
return l.file.Name()
}
func (l *lock) TryLock() error {
err := syscall.Flock(l.fd, syscall.LOCK_EX|syscall.LOCK_NB)
if err != nil && err == syscall.EWOULDBLOCK {
return ErrLocked
}
return err
}
func (l *lock) Lock() error {
return syscall.Flock(l.fd, syscall.LOCK_EX)
}
func (l *lock) Unlock() error {
return syscall.Flock(l.fd, syscall.LOCK_UN)
}
func (l *lock) Destroy() error {
return l.file.Close()
}
func NewLock(file string) (Lock, error) {
f, err := os.Open(file)
if err != nil {
return nil, err
}
l := &lock{int(f.Fd()), f}
return l, nil
}

View File

@ -1,60 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
// +build windows
package fileutil
import (
"errors"
"os"
)
var (
ErrLocked = errors.New("file already locked")
)
type lock struct {
fd int
file *os.File
}
func (l *lock) Name() string {
return l.file.Name()
}
func (l *lock) TryLock() error {
return nil
}
func (l *lock) Lock() error {
return nil
}
func (l *lock) Unlock() error {
return nil
}
func (l *lock) Destroy() error {
return l.file.Close()
}
func NewLock(file string) (Lock, error) {
f, err := os.Open(file)
if err != nil {
return nil, err
}
l := &lock{int(f.Fd()), f}
return l, nil
}

View File

@ -1,28 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
// +build !linux
package fileutil
import "os"
// Preallocate tries to allocate the space for given
// file. This operation is only supported on linux by a
// few filesystems (btrfs, ext4, etc.).
// If the operation is unsupported, no error will be returned.
// Otherwise, the error encountered will be returned.
func Preallocate(f *os.File, sizeInBytes int) error {
return nil
}

View File

@ -1,42 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
// +build linux
package fileutil
import (
"os"
"syscall"
)
// Preallocate tries to allocate the space for given
// file. This operation is only supported on linux by a
// few filesystems (btrfs, ext4, etc.).
// If the operation is unsupported, no error will be returned.
// Otherwise, the error encountered will be returned.
func Preallocate(f *os.File, sizeInBytes int) error {
// use mode = 1 to keep size
// see FALLOC_FL_KEEP_SIZE
err := syscall.Fallocate(int(f.Fd()), 1, 0, int64(sizeInBytes))
if err != nil {
errno, ok := err.(syscall.Errno)
// treat not support as nil error
if ok && errno == syscall.ENOTSUP {
return nil
}
return err
}
return nil
}

View File

@ -1,53 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package fileutil
import (
"io/ioutil"
"os"
"runtime"
"testing"
)
func TestPreallocate(t *testing.T) {
if runtime.GOOS != "linux" {
t.Skipf("skip testPreallocate, OS = %s", runtime.GOOS)
}
p, err := ioutil.TempDir(os.TempDir(), "preallocateTest")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(p)
f, err := ioutil.TempFile(p, "")
if err != nil {
t.Fatal(err)
}
size := 64 * 1000
err = Preallocate(f, size)
if err != nil {
t.Fatal(err)
}
stat, err := f.Stat()
if err != nil {
t.Fatal(err)
}
if stat.Size() != 0 {
t.Errorf("size = %d, want %d", stat.Size(), 0)
}
}

View File

@ -1,80 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package fileutil
import (
"os"
"path"
"sort"
"strings"
"time"
)
func PurgeFile(dirname string, suffix string, max uint, interval time.Duration, stop <-chan struct{}) <-chan error {
errC := make(chan error, 1)
go func() {
for {
fnames, err := ReadDir(dirname)
if err != nil {
errC <- err
return
}
newfnames := make([]string, 0)
for _, fname := range fnames {
if strings.HasSuffix(fname, suffix) {
newfnames = append(newfnames, fname)
}
}
sort.Strings(newfnames)
for len(newfnames) > int(max) {
f := path.Join(dirname, newfnames[0])
l, err := NewLock(f)
if err != nil {
errC <- err
return
}
err = l.TryLock()
if err != nil {
break
}
err = os.Remove(f)
if err != nil {
errC <- err
return
}
err = l.Unlock()
if err != nil {
plog.Errorf("error unlocking %s when purging file (%v)", l.Name(), err)
errC <- err
return
}
err = l.Destroy()
if err != nil {
plog.Errorf("error destroying lock %s when purging file (%v)", l.Name(), err)
errC <- err
return
}
plog.Infof("purged file %s successfully", f)
newfnames = newfnames[1:]
}
select {
case <-time.After(interval):
case <-stop:
return
}
}
}()
return errC
}

View File

@ -1,161 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package fileutil
import (
"fmt"
"io/ioutil"
"os"
"path"
"reflect"
"testing"
"time"
)
func TestPurgeFile(t *testing.T) {
dir, err := ioutil.TempDir("", "purgefile")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
for i := 0; i < 5; i++ {
_, err = os.Create(path.Join(dir, fmt.Sprintf("%d.test", i)))
if err != nil {
t.Fatal(err)
}
}
stop := make(chan struct{})
// keep at most 3 most recent files
errch := PurgeFile(dir, "test", 3, time.Millisecond, stop)
// create 5 more files
for i := 5; i < 10; i++ {
_, err = os.Create(path.Join(dir, fmt.Sprintf("%d.test", i)))
if err != nil {
t.Fatal(err)
}
time.Sleep(10 * time.Millisecond)
}
// purge routine should purge 7 out of 10 files and only keep the
// 3 most recent ones.
// wait for purging for at most 100ms.
var fnames []string
for i := 0; i < 10; i++ {
fnames, err = ReadDir(dir)
if err != nil {
t.Fatal(err)
}
if len(fnames) <= 3 {
break
}
time.Sleep(10 * time.Millisecond)
}
wnames := []string{"7.test", "8.test", "9.test"}
if !reflect.DeepEqual(fnames, wnames) {
t.Errorf("filenames = %v, want %v", fnames, wnames)
}
// no error should be reported from purge routine
select {
case err := <-errch:
t.Errorf("unexpected purge error %v", err)
case <-time.After(time.Millisecond):
}
close(stop)
}
func TestPurgeFileHoldingLock(t *testing.T) {
dir, err := ioutil.TempDir("", "purgefile")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
for i := 0; i < 10; i++ {
_, err = os.Create(path.Join(dir, fmt.Sprintf("%d.test", i)))
if err != nil {
t.Fatal(err)
}
}
// create a purge barrier at 5
l, err := NewLock(path.Join(dir, fmt.Sprintf("%d.test", 5)))
err = l.Lock()
if err != nil {
t.Fatal(err)
}
stop := make(chan struct{})
errch := PurgeFile(dir, "test", 3, time.Millisecond, stop)
var fnames []string
for i := 0; i < 10; i++ {
fnames, err = ReadDir(dir)
if err != nil {
t.Fatal(err)
}
if len(fnames) <= 5 {
break
}
time.Sleep(10 * time.Millisecond)
}
wnames := []string{"5.test", "6.test", "7.test", "8.test", "9.test"}
if !reflect.DeepEqual(fnames, wnames) {
t.Errorf("filenames = %v, want %v", fnames, wnames)
}
select {
case err = <-errch:
t.Errorf("unexpected purge error %v", err)
case <-time.After(time.Millisecond):
}
// remove the purge barrier
err = l.Unlock()
if err != nil {
t.Fatal(err)
}
err = l.Destroy()
if err != nil {
t.Fatal(err)
}
for i := 0; i < 10; i++ {
fnames, err = ReadDir(dir)
if err != nil {
t.Fatal(err)
}
if len(fnames) <= 3 {
break
}
time.Sleep(10 * time.Millisecond)
}
wnames = []string{"7.test", "8.test", "9.test"}
if !reflect.DeepEqual(fnames, wnames) {
t.Errorf("filenames = %v, want %v", fnames, wnames)
}
select {
case err := <-errch:
t.Errorf("unexpected purge error %v", err)
case <-time.After(time.Millisecond):
}
close(stop)
}

View File

@ -1,26 +0,0 @@
// Copyright 2016 CoreOS, Inc.
//
// 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.
// +build !linux
package fileutil
import "os"
// Fdatasync is similar to fsync(), but does not flush modified metadata
// unless that metadata is needed in order to allow a subsequent data retrieval
// to be correctly handled.
func Fdatasync(f *os.File) error {
return f.Sync()
}

View File

@ -1,29 +0,0 @@
// Copyright 2016 CoreOS, Inc.
//
// 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.
// +build linux
package fileutil
import (
"os"
"syscall"
)
// Fdatasync is similar to fsync(), but does not flush modified metadata
// unless that metadata is needed in order to allow a subsequent data retrieval
// to be correctly handled.
func Fdatasync(f *os.File) error {
return syscall.Fdatasync(int(f.Fd()))
}

View File

@ -1,48 +0,0 @@
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"decoder.go",
"doc.go",
"encoder.go",
"metrics.go",
"multi_readcloser.go",
"repair.go",
"util.go",
"wal.go",
],
importpath = "k8s.io/kubernetes/third_party/forked/etcd237/wal",
deps = [
"//third_party/forked/etcd237/pkg/fileutil:go_default_library",
"//vendor/github.com/coreos/etcd/pkg/crc:go_default_library",
"//vendor/github.com/coreos/etcd/pkg/pbutil:go_default_library",
"//vendor/github.com/coreos/etcd/raft/raftpb:go_default_library",
"//vendor/github.com/coreos/etcd/wal/walpb:go_default_library",
"//vendor/github.com/coreos/pkg/capnslog:go_default_library",
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//third_party/forked/etcd237/wal/walpb:all-srcs",
],
tags = ["automanaged"],
)

View File

@ -1,103 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package wal
import (
"bufio"
"encoding/binary"
"hash"
"io"
"sync"
"github.com/coreos/etcd/pkg/crc"
"github.com/coreos/etcd/pkg/pbutil"
"github.com/coreos/etcd/raft/raftpb"
"github.com/coreos/etcd/wal/walpb"
)
type decoder struct {
mu sync.Mutex
br *bufio.Reader
c io.Closer
crc hash.Hash32
}
func newDecoder(rc io.ReadCloser) *decoder {
return &decoder{
br: bufio.NewReader(rc),
c: rc,
crc: crc.New(0, crcTable),
}
}
func (d *decoder) decode(rec *walpb.Record) error {
d.mu.Lock()
defer d.mu.Unlock()
rec.Reset()
l, err := readInt64(d.br)
if err != nil {
return err
}
data := make([]byte, l)
if _, err = io.ReadFull(d.br, data); err != nil {
// ReadFull returns io.EOF only if no bytes were read
// the decoder should treat this as an ErrUnexpectedEOF instead.
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return err
}
if err := rec.Unmarshal(data); err != nil {
return err
}
// skip crc checking if the record type is crcType
if rec.Type == crcType {
return nil
}
d.crc.Write(rec.Data)
return rec.Validate(d.crc.Sum32())
}
func (d *decoder) updateCRC(prevCrc uint32) {
d.crc = crc.New(prevCrc, crcTable)
}
func (d *decoder) lastCRC() uint32 {
return d.crc.Sum32()
}
func (d *decoder) close() error {
return d.c.Close()
}
func mustUnmarshalEntry(d []byte) raftpb.Entry {
var e raftpb.Entry
pbutil.MustUnmarshal(&e, d)
return e
}
func mustUnmarshalState(d []byte) raftpb.HardState {
var s raftpb.HardState
pbutil.MustUnmarshal(&s, d)
return s
}
func readInt64(r io.Reader) (int64, error) {
var n int64
err := binary.Read(r, binary.LittleEndian, &n)
return n, err
}

View File

@ -1,68 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
/*
Package wal provides an implementation of a write ahead log that is used by
etcd.
A WAL is created at a particular directory and is made up of a number of
segmented WAL files. Inside of each file the raft state and entries are appended
to it with the Save method:
metadata := []byte{}
w, err := wal.Create("/var/lib/etcd", metadata)
...
err := w.Save(s, ents)
After saving an raft snapshot to disk, SaveSnapshot method should be called to
record it. So WAL can match with the saved snapshot when restarting.
err := w.SaveSnapshot(walpb.Snapshot{Index: 10, Term: 2})
When a user has finished using a WAL it must be closed:
w.Close()
WAL files are placed inside of the directory in the following format:
$seq-$index.wal
The first WAL file to be created will be 0000000000000000-0000000000000000.wal
indicating an initial sequence of 0 and an initial raft index of 0. The first
entry written to WAL MUST have raft index 0.
WAL will cuts its current wal files if its size exceeds 8MB. This will increment an internal
sequence number and cause a new file to be created. If the last raft index saved
was 0x20 and this is the first time cut has been called on this WAL then the sequence will
increment from 0x0 to 0x1. The new file will be: 0000000000000001-0000000000000021.wal.
If a second cut issues 0x10 entries with incremental index later then the file will be called:
0000000000000002-0000000000000031.wal.
At a later time a WAL can be opened at a particular snapshot. If there is no
snapshot, an empty snapshot should be passed in.
w, err := wal.Open("/var/lib/etcd", walpb.Snapshot{Index: 10, Term: 2})
...
The snapshot must have been written to the WAL.
Additional items cannot be Saved to this WAL until all of the items from the given
snapshot to the end of the WAL are read first:
metadata, state, ents, err := w.ReadAll()
This will give you the metadata, the last raft.State and the slice of
raft.Entry items in the log.
*/
package wal

View File

@ -1,89 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package wal
import (
"bufio"
"encoding/binary"
"hash"
"io"
"sync"
"github.com/coreos/etcd/pkg/crc"
"github.com/coreos/etcd/wal/walpb"
)
type encoder struct {
mu sync.Mutex
bw *bufio.Writer
crc hash.Hash32
buf []byte
uint64buf []byte
}
func newEncoder(w io.Writer, prevCrc uint32) *encoder {
return &encoder{
bw: bufio.NewWriter(w),
crc: crc.New(prevCrc, crcTable),
// 1MB buffer
buf: make([]byte, 1024*1024),
uint64buf: make([]byte, 8),
}
}
func (e *encoder) encode(rec *walpb.Record) error {
e.mu.Lock()
defer e.mu.Unlock()
e.crc.Write(rec.Data)
rec.Crc = e.crc.Sum32()
var (
data []byte
err error
n int
)
if rec.Size() > len(e.buf) {
data, err = rec.Marshal()
if err != nil {
return err
}
} else {
n, err = rec.MarshalTo(e.buf)
if err != nil {
return err
}
data = e.buf[:n]
}
if err = writeInt64(e.bw, int64(len(data)), e.uint64buf); err != nil {
return err
}
_, err = e.bw.Write(data)
return err
}
func (e *encoder) flush() error {
e.mu.Lock()
defer e.mu.Unlock()
return e.bw.Flush()
}
func writeInt64(w io.Writer, n int64, buf []byte) error {
// http://golang.org/src/encoding/binary/binary.go
binary.LittleEndian.PutUint64(buf, uint64(n))
_, err := w.Write(buf)
return err
}

View File

@ -1,38 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package wal
import "github.com/prometheus/client_golang/prometheus"
var (
syncDurations = prometheus.NewHistogram(prometheus.HistogramOpts{
Namespace: "etcd",
Subsystem: "wal",
Name: "fsync_durations_seconds",
Help: "The latency distributions of fsync called by wal.",
Buckets: prometheus.ExponentialBuckets(0.001, 2, 14),
})
lastIndexSaved = prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: "etcd",
Subsystem: "wal",
Name: "last_index_saved",
Help: "The index of the last entry saved by wal.",
})
)
func init() {
prometheus.MustRegister(syncDurations)
prometheus.MustRegister(lastIndexSaved)
}

View File

@ -1,45 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package wal
import "io"
type multiReadCloser struct {
closers []io.Closer
reader io.Reader
}
func (mc *multiReadCloser) Close() error {
var err error
for i := range mc.closers {
err = mc.closers[i].Close()
}
return err
}
func (mc *multiReadCloser) Read(p []byte) (int, error) {
return mc.reader.Read(p)
}
func MultiReadCloser(readClosers ...io.ReadCloser) io.ReadCloser {
cs := make([]io.Closer, len(readClosers))
rs := make([]io.Reader, len(readClosers))
for i := range readClosers {
cs[i] = readClosers[i]
rs[i] = readClosers[i]
}
r := io.MultiReader(rs...)
return &multiReadCloser{cs, r}
}

View File

@ -1,107 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package wal
import (
"io"
"os"
"path"
"k8s.io/kubernetes/third_party/forked/etcd237/pkg/fileutil"
"github.com/coreos/etcd/wal/walpb"
)
// Repair tries to repair ErrUnexpectedEOF in the
// last wal file by truncating.
func Repair(dirpath string) bool {
f, err := openLast(dirpath)
if err != nil {
return false
}
defer f.Close()
n := 0
rec := &walpb.Record{}
decoder := newDecoder(f)
defer decoder.close()
for {
err := decoder.decode(rec)
switch err {
case nil:
n += 8 + rec.Size()
// update crc of the decoder when necessary
switch rec.Type {
case crcType:
crc := decoder.crc.Sum32()
// current crc of decoder must match the crc of the record.
// do no need to match 0 crc, since the decoder is a new one at this case.
if crc != 0 && rec.Validate(crc) != nil {
return false
}
decoder.updateCRC(rec.Crc)
}
continue
case io.EOF:
return true
case io.ErrUnexpectedEOF:
plog.Noticef("repairing %v", f.Name())
bf, bferr := os.Create(f.Name() + ".broken")
if bferr != nil {
plog.Errorf("could not repair %v, failed to create backup file", f.Name())
return false
}
defer bf.Close()
if _, err = f.Seek(0, os.SEEK_SET); err != nil {
plog.Errorf("could not repair %v, failed to read file", f.Name())
return false
}
if _, err = io.Copy(bf, f); err != nil {
plog.Errorf("could not repair %v, failed to copy file", f.Name())
return false
}
if err = f.Truncate(int64(n)); err != nil {
plog.Errorf("could not repair %v, failed to truncate file", f.Name())
return false
}
if err = f.Sync(); err != nil {
plog.Errorf("could not repair %v, failed to sync file", f.Name())
return false
}
return true
default:
plog.Errorf("could not repair error (%v)", err)
return false
}
}
}
// openLast opens the last wal file for read and write.
func openLast(dirpath string) (*os.File, error) {
names, err := fileutil.ReadDir(dirpath)
if err != nil {
return nil, err
}
names = checkWalNames(names)
if len(names) == 0 {
return nil, ErrFileNotFound
}
last := path.Join(dirpath, names[len(names)-1])
return os.OpenFile(last, os.O_RDWR, 0)
}

View File

@ -1,93 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package wal
import (
"errors"
"fmt"
"strings"
"k8s.io/kubernetes/third_party/forked/etcd237/pkg/fileutil"
)
var (
badWalName = errors.New("bad wal name")
)
func Exist(dirpath string) bool {
names, err := fileutil.ReadDir(dirpath)
if err != nil {
return false
}
return len(names) != 0
}
// searchIndex returns the last array index of names whose raft index section is
// equal to or smaller than the given index.
// The given names MUST be sorted.
func searchIndex(names []string, index uint64) (int, bool) {
for i := len(names) - 1; i >= 0; i-- {
name := names[i]
_, curIndex, err := parseWalName(name)
if err != nil {
plog.Panicf("parse correct name should never fail: %v", err)
}
if index >= curIndex {
return i, true
}
}
return -1, false
}
// names should have been sorted based on sequence number.
// isValidSeq checks whether seq increases continuously.
func isValidSeq(names []string) bool {
var lastSeq uint64
for _, name := range names {
curSeq, _, err := parseWalName(name)
if err != nil {
plog.Panicf("parse correct name should never fail: %v", err)
}
if lastSeq != 0 && lastSeq != curSeq-1 {
return false
}
lastSeq = curSeq
}
return true
}
func checkWalNames(names []string) []string {
wnames := make([]string, 0)
for _, name := range names {
if _, _, err := parseWalName(name); err != nil {
plog.Warningf("ignored file %v in wal", name)
continue
}
wnames = append(wnames, name)
}
return wnames
}
func parseWalName(str string) (seq, index uint64, err error) {
if !strings.HasSuffix(str, ".wal") {
return 0, 0, badWalName
}
_, err = fmt.Sscanf(str, "%016x-%016x.wal", &seq, &index)
return seq, index, err
}
func walName(seq, index uint64) string {
return fmt.Sprintf("%016x-%016x.wal", seq, index)
}

View File

@ -1,571 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package wal
import (
"errors"
"fmt"
"hash/crc32"
"io"
"os"
"path"
"reflect"
"sync"
"time"
"k8s.io/kubernetes/third_party/forked/etcd237/pkg/fileutil"
"github.com/coreos/etcd/pkg/pbutil"
"github.com/coreos/etcd/raft/raftpb"
"github.com/coreos/etcd/wal/walpb"
"github.com/coreos/pkg/capnslog"
)
const (
metadataType int64 = iota + 1
entryType
stateType
crcType
snapshotType
// the owner can make/remove files inside the directory
privateDirMode = 0700
// the expected size of each wal segment file.
// the actual size might be bigger than it.
segmentSizeBytes = 64 * 1000 * 1000 // 64MB
)
var (
plog = capnslog.NewPackageLogger("github.com/coreos/etcd", "wal")
ErrMetadataConflict = errors.New("wal: conflicting metadata found")
ErrFileNotFound = errors.New("wal: file not found")
ErrCRCMismatch = errors.New("wal: crc mismatch")
ErrSnapshotMismatch = errors.New("wal: snapshot mismatch")
ErrSnapshotNotFound = errors.New("wal: snapshot not found")
crcTable = crc32.MakeTable(crc32.Castagnoli)
)
// WAL is a logical representation of the stable storage.
// WAL is either in read mode or append mode but not both.
// A newly created WAL is in append mode, and ready for appending records.
// A just opened WAL is in read mode, and ready for reading records.
// The WAL will be ready for appending after reading out all the previous records.
type WAL struct {
dir string // the living directory of the underlay files
metadata []byte // metadata recorded at the head of each WAL
state raftpb.HardState // hardstate recorded at the head of WAL
start walpb.Snapshot // snapshot to start reading
decoder *decoder // decoder to decode records
mu sync.Mutex
f *os.File // underlay file opened for appending, sync
seq uint64 // sequence of the wal file currently used for writes
enti uint64 // index of the last entry saved to the wal
encoder *encoder // encoder to encode records
locks []fileutil.Lock // the file locks the WAL is holding (the name is increasing)
}
// Create creates a WAL ready for appending records. The given metadata is
// recorded at the head of each WAL file, and can be retrieved with ReadAll.
func Create(dirpath string, metadata []byte) (*WAL, error) {
if Exist(dirpath) {
return nil, os.ErrExist
}
if err := os.MkdirAll(dirpath, privateDirMode); err != nil {
return nil, err
}
p := path.Join(dirpath, walName(0, 0))
f, err := os.OpenFile(p, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
if err != nil {
return nil, err
}
l, err := fileutil.NewLock(f.Name())
if err != nil {
return nil, err
}
if err = l.Lock(); err != nil {
return nil, err
}
w := &WAL{
dir: dirpath,
metadata: metadata,
seq: 0,
f: f,
encoder: newEncoder(f, 0),
}
w.locks = append(w.locks, l)
if err := w.saveCrc(0); err != nil {
return nil, err
}
if err := w.encoder.encode(&walpb.Record{Type: metadataType, Data: metadata}); err != nil {
return nil, err
}
if err := w.SaveSnapshot(walpb.Snapshot{}); err != nil {
return nil, err
}
return w, nil
}
// Open opens the WAL at the given snap.
// The snap SHOULD have been previously saved to the WAL, or the following
// ReadAll will fail.
// The returned WAL is ready to read and the first record will be the one after
// the given snap. The WAL cannot be appended to before reading out all of its
// previous records.
func Open(dirpath string, snap walpb.Snapshot) (*WAL, error) {
return openAtIndex(dirpath, snap, true)
}
// OpenForRead only opens the wal files for read.
// Write on a read only wal panics.
func OpenForRead(dirpath string, snap walpb.Snapshot) (*WAL, error) {
return openAtIndex(dirpath, snap, false)
}
func openAtIndex(dirpath string, snap walpb.Snapshot, write bool) (*WAL, error) {
names, err := fileutil.ReadDir(dirpath)
if err != nil {
return nil, err
}
names = checkWalNames(names)
if len(names) == 0 {
return nil, ErrFileNotFound
}
nameIndex, ok := searchIndex(names, snap.Index)
if !ok || !isValidSeq(names[nameIndex:]) {
return nil, ErrFileNotFound
}
// open the wal files for reading
rcs := make([]io.ReadCloser, 0)
ls := make([]fileutil.Lock, 0)
for _, name := range names[nameIndex:] {
f, err := os.Open(path.Join(dirpath, name))
if err != nil {
return nil, err
}
l, err := fileutil.NewLock(f.Name())
if err != nil {
return nil, err
}
err = l.TryLock()
if err != nil {
if write {
return nil, err
}
}
rcs = append(rcs, f)
ls = append(ls, l)
}
rc := MultiReadCloser(rcs...)
// create a WAL ready for reading
w := &WAL{
dir: dirpath,
start: snap,
decoder: newDecoder(rc),
locks: ls,
}
if write {
// open the last wal file for appending
seq, _, err := parseWalName(names[len(names)-1])
if err != nil {
rc.Close()
return nil, err
}
last := path.Join(dirpath, names[len(names)-1])
f, err := os.OpenFile(last, os.O_WRONLY|os.O_APPEND, 0)
if err != nil {
rc.Close()
return nil, err
}
err = fileutil.Preallocate(f, segmentSizeBytes)
if err != nil {
rc.Close()
plog.Errorf("failed to allocate space when creating new wal file (%v)", err)
return nil, err
}
w.f = f
w.seq = seq
}
return w, nil
}
// ReadAll reads out records of the current WAL.
// If opened in write mode, it must read out all records until EOF. Or an error
// will be returned.
// If opened in read mode, it will try to read all records if possible.
// If it cannot read out the expected snap, it will return ErrSnapshotNotFound.
// If loaded snap doesn't match with the expected one, it will return
// all the records and error ErrSnapshotMismatch.
// TODO: detect not-last-snap error.
// TODO: maybe loose the checking of match.
// After ReadAll, the WAL will be ready for appending new records.
func (w *WAL) ReadAll() (metadata []byte, state raftpb.HardState, ents []raftpb.Entry, err error) {
w.mu.Lock()
defer w.mu.Unlock()
rec := &walpb.Record{}
decoder := w.decoder
var match bool
for err = decoder.decode(rec); err == nil; err = decoder.decode(rec) {
switch rec.Type {
case entryType:
e := mustUnmarshalEntry(rec.Data)
if e.Index > w.start.Index {
ents = append(ents[:e.Index-w.start.Index-1], e)
}
w.enti = e.Index
case stateType:
state = mustUnmarshalState(rec.Data)
case metadataType:
if metadata != nil && !reflect.DeepEqual(metadata, rec.Data) {
state.Reset()
return nil, state, nil, ErrMetadataConflict
}
metadata = rec.Data
case crcType:
crc := decoder.crc.Sum32()
// current crc of decoder must match the crc of the record.
// do no need to match 0 crc, since the decoder is a new one at this case.
if crc != 0 && rec.Validate(crc) != nil {
state.Reset()
return nil, state, nil, ErrCRCMismatch
}
decoder.updateCRC(rec.Crc)
case snapshotType:
var snap walpb.Snapshot
pbutil.MustUnmarshal(&snap, rec.Data)
if snap.Index == w.start.Index {
if snap.Term != w.start.Term {
state.Reset()
return nil, state, nil, ErrSnapshotMismatch
}
match = true
}
default:
state.Reset()
return nil, state, nil, fmt.Errorf("unexpected block type %d", rec.Type)
}
}
switch w.f {
case nil:
// We do not have to read out all entries in read mode.
// The last record maybe a partial written one, so
// ErrunexpectedEOF might be returned.
if err != io.EOF && err != io.ErrUnexpectedEOF {
state.Reset()
return nil, state, nil, err
}
default:
// We must read all of the entries if WAL is opened in write mode.
if err != io.EOF {
state.Reset()
return nil, state, nil, err
}
}
err = nil
if !match {
err = ErrSnapshotNotFound
}
// close decoder, disable reading
w.decoder.close()
w.start = walpb.Snapshot{}
w.metadata = metadata
if w.f != nil {
// create encoder (chain crc with the decoder), enable appending
w.encoder = newEncoder(w.f, w.decoder.lastCRC())
w.decoder = nil
lastIndexSaved.Set(float64(w.enti))
}
return metadata, state, ents, err
}
// cut closes current file written and creates a new one ready to append.
// cut first creates a temp wal file and writes necessary headers into it.
// Then cut atomically rename temp wal file to a wal file.
func (w *WAL) cut() error {
// close old wal file
if err := w.sync(); err != nil {
return err
}
if err := w.f.Close(); err != nil {
return err
}
fpath := path.Join(w.dir, walName(w.seq+1, w.enti+1))
ftpath := fpath + ".tmp"
// create a temp wal file with name sequence + 1, or truncate the existing one
ft, err := os.OpenFile(ftpath, os.O_WRONLY|os.O_APPEND|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return err
}
// update writer and save the previous crc
w.f = ft
prevCrc := w.encoder.crc.Sum32()
w.encoder = newEncoder(w.f, prevCrc)
if err = w.saveCrc(prevCrc); err != nil {
return err
}
if err = w.encoder.encode(&walpb.Record{Type: metadataType, Data: w.metadata}); err != nil {
return err
}
if err = w.saveState(&w.state); err != nil {
return err
}
// close temp wal file
if err = w.sync(); err != nil {
return err
}
if err = w.f.Close(); err != nil {
return err
}
// atomically move temp wal file to wal file
if err = os.Rename(ftpath, fpath); err != nil {
return err
}
// open the wal file and update writer again
f, err := os.OpenFile(fpath, os.O_WRONLY|os.O_APPEND, 0600)
if err != nil {
return err
}
if err = fileutil.Preallocate(f, segmentSizeBytes); err != nil {
plog.Errorf("failed to allocate space when creating new wal file (%v)", err)
return err
}
w.f = f
prevCrc = w.encoder.crc.Sum32()
w.encoder = newEncoder(w.f, prevCrc)
// lock the new wal file
l, err := fileutil.NewLock(f.Name())
if err != nil {
return err
}
if err := l.Lock(); err != nil {
return err
}
w.locks = append(w.locks, l)
// increase the wal seq
w.seq++
plog.Infof("segmented wal file %v is created", fpath)
return nil
}
func (w *WAL) sync() error {
if w.encoder != nil {
if err := w.encoder.flush(); err != nil {
return err
}
}
start := time.Now()
err := fileutil.Fdatasync(w.f)
syncDurations.Observe(float64(time.Since(start)) / float64(time.Second))
return err
}
// ReleaseLockTo releases the locks, which has smaller index than the given index
// except the largest one among them.
// For example, if WAL is holding lock 1,2,3,4,5,6, ReleaseLockTo(4) will release
// lock 1,2 but keep 3. ReleaseLockTo(5) will release 1,2,3 but keep 4.
func (w *WAL) ReleaseLockTo(index uint64) error {
w.mu.Lock()
defer w.mu.Unlock()
var smaller int
found := false
for i, l := range w.locks {
_, lockIndex, err := parseWalName(path.Base(l.Name()))
if err != nil {
return err
}
if lockIndex >= index {
smaller = i - 1
found = true
break
}
}
// if no lock index is greater than the release index, we can
// release lock up to the last one(excluding).
if !found && len(w.locks) != 0 {
smaller = len(w.locks) - 1
}
if smaller <= 0 {
return nil
}
for i := 0; i < smaller; i++ {
w.locks[i].Unlock()
w.locks[i].Destroy()
}
w.locks = w.locks[smaller:]
return nil
}
func (w *WAL) Close() error {
w.mu.Lock()
defer w.mu.Unlock()
if w.f != nil {
if err := w.sync(); err != nil {
return err
}
if err := w.f.Close(); err != nil {
return err
}
}
for _, l := range w.locks {
err := l.Unlock()
if err != nil {
plog.Errorf("failed to unlock during closing wal: %s", err)
}
err = l.Destroy()
if err != nil {
plog.Errorf("failed to destroy lock during closing wal: %s", err)
}
}
return nil
}
func (w *WAL) saveEntry(e *raftpb.Entry) error {
// TODO: add MustMarshalTo to reduce one allocation.
b := pbutil.MustMarshal(e)
rec := &walpb.Record{Type: entryType, Data: b}
if err := w.encoder.encode(rec); err != nil {
return err
}
w.enti = e.Index
lastIndexSaved.Set(float64(w.enti))
return nil
}
func (w *WAL) saveState(s *raftpb.HardState) error {
if isEmptyHardState(*s) {
return nil
}
w.state = *s
b := pbutil.MustMarshal(s)
rec := &walpb.Record{Type: stateType, Data: b}
return w.encoder.encode(rec)
}
func (w *WAL) Save(st raftpb.HardState, ents []raftpb.Entry) error {
w.mu.Lock()
defer w.mu.Unlock()
// short cut, do not call sync
if isEmptyHardState(st) && len(ents) == 0 {
return nil
}
mustSync := mustSync(st, w.state, len(ents))
// TODO(xiangli): no more reference operator
for i := range ents {
if err := w.saveEntry(&ents[i]); err != nil {
return err
}
}
if err := w.saveState(&st); err != nil {
return err
}
fstat, err := w.f.Stat()
if err != nil {
return err
}
if fstat.Size() < segmentSizeBytes {
if mustSync {
return w.sync()
}
return nil
}
// TODO: add a test for this code path when refactoring the tests
return w.cut()
}
func (w *WAL) SaveSnapshot(e walpb.Snapshot) error {
w.mu.Lock()
defer w.mu.Unlock()
b := pbutil.MustMarshal(&e)
rec := &walpb.Record{Type: snapshotType, Data: b}
if err := w.encoder.encode(rec); err != nil {
return err
}
// update enti only when snapshot is ahead of last index
if w.enti < e.Index {
w.enti = e.Index
}
lastIndexSaved.Set(float64(w.enti))
return w.sync()
}
func (w *WAL) saveCrc(prevCrc uint32) error {
return w.encoder.encode(&walpb.Record{Type: crcType, Crc: prevCrc})
}
func mustSync(st, prevst raftpb.HardState, entsnum int) bool {
// Persistent state on all servers:
// (Updated on stable storage before responding to RPCs)
// currentTerm
// votedFor
// log entries[]
if entsnum != 0 || st.Vote != prevst.Vote || st.Term != prevst.Term {
return true
}
return false
}
func isHardStateEqual(a, b raftpb.HardState) bool {
return a.Term == b.Term && a.Vote == b.Vote && a.Commit == b.Commit
}
var emptyState = raftpb.HardState{}
func isEmptyHardState(st raftpb.HardState) bool {
return isHardStateEqual(st, emptyState)
}

View File

@ -1,31 +0,0 @@
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"record.go",
"record.pb.go",
],
importpath = "k8s.io/kubernetes/third_party/forked/etcd237/wal/walpb",
deps = ["//vendor/github.com/golang/protobuf/proto:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -1,29 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
package walpb
import "errors"
var (
ErrCRCMismatch = errors.New("walpb: crc mismatch")
)
func (rec *Record) Validate(crc uint32) error {
if rec.Crc == crc {
return nil
}
rec.Reset()
return ErrCRCMismatch
}

View File

@ -1,495 +0,0 @@
// Code generated by protoc-gen-gogo.
// source: record.proto
// DO NOT EDIT!
/*
Package walpb is a generated protocol buffer package.
It is generated from these files:
record.proto
It has these top-level messages:
Record
Snapshot
*/
package walpb
import (
"fmt"
proto "github.com/golang/protobuf/proto"
)
import math "math"
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
type Record struct {
Type int64 `protobuf:"varint,1,opt,name=type" json:"type"`
Crc uint32 `protobuf:"varint,2,opt,name=crc" json:"crc"`
Data []byte `protobuf:"bytes,3,opt,name=data" json:"data,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *Record) Reset() { *m = Record{} }
func (m *Record) String() string { return proto.CompactTextString(m) }
func (*Record) ProtoMessage() {}
type Snapshot struct {
Index uint64 `protobuf:"varint,1,opt,name=index" json:"index"`
Term uint64 `protobuf:"varint,2,opt,name=term" json:"term"`
XXX_unrecognized []byte `json:"-"`
}
func (m *Snapshot) Reset() { *m = Snapshot{} }
func (m *Snapshot) String() string { return proto.CompactTextString(m) }
func (*Snapshot) ProtoMessage() {}
func init() {
proto.RegisterType((*Record)(nil), "walpb.Record")
proto.RegisterType((*Snapshot)(nil), "walpb.Snapshot")
}
func (m *Record) Marshal() (data []byte, err error) {
size := m.Size()
data = make([]byte, size)
n, err := m.MarshalTo(data)
if err != nil {
return nil, err
}
return data[:n], nil
}
func (m *Record) MarshalTo(data []byte) (int, error) {
var i int
_ = i
var l int
_ = l
data[i] = 0x8
i++
i = encodeVarintRecord(data, i, uint64(m.Type))
data[i] = 0x10
i++
i = encodeVarintRecord(data, i, uint64(m.Crc))
if m.Data != nil {
data[i] = 0x1a
i++
i = encodeVarintRecord(data, i, uint64(len(m.Data)))
i += copy(data[i:], m.Data)
}
if m.XXX_unrecognized != nil {
i += copy(data[i:], m.XXX_unrecognized)
}
return i, nil
}
func (m *Snapshot) Marshal() (data []byte, err error) {
size := m.Size()
data = make([]byte, size)
n, err := m.MarshalTo(data)
if err != nil {
return nil, err
}
return data[:n], nil
}
func (m *Snapshot) MarshalTo(data []byte) (int, error) {
var i int
_ = i
var l int
_ = l
data[i] = 0x8
i++
i = encodeVarintRecord(data, i, uint64(m.Index))
data[i] = 0x10
i++
i = encodeVarintRecord(data, i, uint64(m.Term))
if m.XXX_unrecognized != nil {
i += copy(data[i:], m.XXX_unrecognized)
}
return i, nil
}
func encodeFixed64Record(data []byte, offset int, v uint64) int {
data[offset] = uint8(v)
data[offset+1] = uint8(v >> 8)
data[offset+2] = uint8(v >> 16)
data[offset+3] = uint8(v >> 24)
data[offset+4] = uint8(v >> 32)
data[offset+5] = uint8(v >> 40)
data[offset+6] = uint8(v >> 48)
data[offset+7] = uint8(v >> 56)
return offset + 8
}
func encodeFixed32Record(data []byte, offset int, v uint32) int {
data[offset] = uint8(v)
data[offset+1] = uint8(v >> 8)
data[offset+2] = uint8(v >> 16)
data[offset+3] = uint8(v >> 24)
return offset + 4
}
func encodeVarintRecord(data []byte, offset int, v uint64) int {
for v >= 1<<7 {
data[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
data[offset] = uint8(v)
return offset + 1
}
func (m *Record) Size() (n int) {
var l int
_ = l
n += 1 + sovRecord(uint64(m.Type))
n += 1 + sovRecord(uint64(m.Crc))
if m.Data != nil {
l = len(m.Data)
n += 1 + l + sovRecord(uint64(l))
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
return n
}
func (m *Snapshot) Size() (n int) {
var l int
_ = l
n += 1 + sovRecord(uint64(m.Index))
n += 1 + sovRecord(uint64(m.Term))
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
return n
}
func sovRecord(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
func sozRecord(x uint64) (n int) {
return sovRecord(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *Record) Unmarshal(data []byte) error {
l := len(data)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRecord
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: Record: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Record: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType)
}
m.Type = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRecord
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
m.Type |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Crc", wireType)
}
m.Crc = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRecord
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
m.Crc |= (uint32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRecord
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
byteLen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthRecord
}
postIndex := iNdEx + byteLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Data = append(m.Data[:0], data[iNdEx:postIndex]...)
if m.Data == nil {
m.Data = []byte{}
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipRecord(data[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthRecord
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, data[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *Snapshot) Unmarshal(data []byte) error {
l := len(data)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRecord
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: Snapshot: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Snapshot: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Index", wireType)
}
m.Index = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRecord
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
m.Index |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Term", wireType)
}
m.Term = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRecord
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
m.Term |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipRecord(data[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthRecord
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, data[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipRecord(data []byte) (n int, err error) {
l := len(data)
iNdEx := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowRecord
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowRecord
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if data[iNdEx-1] < 0x80 {
break
}
}
return iNdEx, nil
case 1:
iNdEx += 8
return iNdEx, nil
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowRecord
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
iNdEx += length
if length < 0 {
return 0, ErrInvalidLengthRecord
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowRecord
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
innerWire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
innerWireType := int(innerWire & 0x7)
if innerWireType == 4 {
break
}
next, err := skipRecord(data[start:])
if err != nil {
return 0, err
}
iNdEx = start + next
}
return iNdEx, nil
case 4:
return iNdEx, nil
case 5:
iNdEx += 4
return iNdEx, nil
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
}
panic("unreachable")
}
var (
ErrInvalidLengthRecord = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowRecord = fmt.Errorf("proto: integer overflow")
)

View File

@ -1,20 +0,0 @@
syntax = "proto2";
package walpb;
import "gogoproto/gogo.proto";
option (gogoproto.marshaler_all) = true;
option (gogoproto.sizer_all) = true;
option (gogoproto.unmarshaler_all) = true;
option (gogoproto.goproto_getters_all) = false;
message Record {
optional int64 type = 1 [(gogoproto.nullable) = false];
optional uint32 crc = 2 [(gogoproto.nullable) = false];
optional bytes data = 3;
}
message Snapshot {
optional uint64 index = 1 [(gogoproto.nullable) = false];
optional uint64 term = 2 [(gogoproto.nullable) = false];
}

View File

@ -1 +0,0 @@
/godep

View File

@ -1,34 +0,0 @@
language: go
sudo: false
go: 1.6
script:
# Godep's unit tests run git, and git complains
# if we don't set these config parameters.
# We put dummy values here because they don't matter.
- git config --global user.email "you@example.com"
- git config --global user.name "Your Name"
- test -z "$(go fmt)"
- go vet
- go test -v
- go test -v -race
- test -z "$(goimports -l .)"
before_install:
- go get golang.org/x/tools/cmd/goimports
before_deploy:
- export OS_TARGETS="linux darwin windows"
- export ARCH_TARGETS="386 amd64"
- go get github.com/mitchellh/gox
- gox -os "$OS_TARGETS" -arch="$ARCH_TARGETS"
deploy:
skip_cleanup: true
provider: releases
api_key:
secure: Q1JP8LziaXMTxFmNXiyC1YhS9e4M4WnI6UDjRTMf6mm1LZeJyUFOCCtXnifL7RyCIR1hpjp6s8M1aWE+NpuweF96IZI3Uk4ASx5C8FePC4qvhsCdtJ2sLD2GTIrp9b0MS9/+ao20AIbpVDSaLaF9IjqXpMxMyM0P8P5coRTkwItlGxmQbVJW3YuiYcPa8UojwM4EyafO2CIoUKapW8lwb9KcimBJV8PfF/XZjPVhMkn2ABhh5Hqbn2zBJtvPYMMzi0CnY50JQF5LwN3vGTMpTsRP+lOLCNbOWfkl+2hgG7VpKrtx+cX62knOodpF457sIJ31KUzmeLUVBejTGb1zuVeTojuyi8Huo8YBIBCcN+p3Dqd+n2ZK45mIrheGiEJIkf/vI4MI6A01Nu/o+xU0IPsVfAL/xU5j5nntEGfFWVoclPrl9qcfqf74xdRcARzcCJVmdc8iw49DBDHJfnPa3zxzVz//00+Rz6mZXmhk+Npk/HLLNW59vmJIjP+8XOtPor7dST9HrS1a9AcnmIjNuw9yfbwK5769SDVxCKgqNwXW/Dy5F39aIH5AL4I4y9hCEeeT8ctvSJHGOyiB9MWU5jnt5tluPtz5opG51tFXnIYP/XaWpTfO+eJ6x55pbwT+n3LfRS5l1POM+jGAFF1MFWwc14RY7qynEIEzm4Wb/UE=
file:
- godep_darwin_amd64
- godep_linux_amd64
- godep_windows_386.exe
- godep_windows_amd64.exe
on:
tags: true
repo: tools/godep

View File

@ -1,57 +0,0 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
licenses(["notice"])
go_library(
name = "go_default_library",
srcs = [
"dep.go",
"diff.go",
"doc.go",
"errors.go",
"get.go",
"go.go",
"godepfile.go",
"license.go",
"list.go",
"main.go",
"msg.go",
"path.go",
"pkg.go",
"restore.go",
"rewrite.go",
"save.go",
"update.go",
"util.go",
"vcs.go",
"version.go",
],
importpath = "k8s.io/kubernetes/third_party/forked/godep",
visibility = ["//visibility:private"],
deps = [
"//vendor/github.com/kr/fs:go_default_library",
"//vendor/github.com/kr/pretty:go_default_library",
"//vendor/github.com/pmezard/go-difflib/difflib:go_default_library",
"//vendor/golang.org/x/tools/go/vcs:go_default_library",
],
)
go_binary(
name = "godep",
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -1,412 +0,0 @@
#v80 (2018/01/26)
* Address lin/vet feedback.
#v79 (2017/02/01)
* Fixes #531: fullPackageInDir didn't capture the error from fillPackage()
#v78 (2017/01/19)
* Don't use build.ImportDir when discovering packages for the package spec. Fixes #529
#v77 (2017/01/13)
* Don't include quotes around hg revisions
#v76 (2017/01/10)
* Default to vendor being on unless older go versions.
#v75 (2016/11/02)
* Add "AUTHORS" and "CONTRIBUTORS" to legal files list: https://github.com/tools/godep/pull/522
#v74 (2016/06/01)
* Enable vendor/ on go1.7
* No longer use a godep workspace, use vendor/ (yay!)
* Notify that support for Godep workspaces will be removed once go1.8 ships
#v73 (2016/05/31)
* Fix permission changes on Windows via @alexbrand. Closes #481.
#v72 (2016/05/27)
* Improve handling of git remote show origin. Should help in cases where remote HEAD is ambiguous.
* Add ISSUE_TEMPLATE
#v71 (2016/05/24)
* Preserve permissions on copied files.
#v70 (2016/05/20)
* Fix the May changelog dates
* No need to call build.Import, we already have the root of the dependency. Fixes an additional comment on #365
#v69 (2016/05/16)
* Make sure `devel-<short sha>` enabled `vendor/` unless there is a classic Godep _workspace already.
#v68 (2016/05/16)
* `devel-<short sha>` is always considered newer than any released go version
#v67 (2016/05/13)
* Attempt to handle missing deps a little better.
#v66 (2016/05/10)
* Use `git remote show origin` to find the default branch when restoring a git based package repository that is in detached head state
#v65 (2016/05/09)
* Rewrite update so that it considers new transitive dependencies, both in the same repo and outside of it.
#v64 (2016/05/09)
* godep update golang.org/x/tools/go/vcs
#v63 (2016/05/03)
* Support recording devel-<short sha> so development versions of Go can be matched
#v62 (2016/04/07)
* Note new go1.6+ behavior of not checking out master in README / restore help text.
#v61 (2016/04/06)
* Obey go version build tags based on recorded major go version. Fixes #448.
#v60 (2016/03/18)
* Make the $GOPATH check a warning.
#v59 (2016/03/18)
* Enforce requirement to be inside of a go src directory. A lot of time is usually spent
tracking down bug reports where people are doign stuff from outside of their $GOPATH. This
should help with that, at least until there it time to properly test godep use outside of a
$GOPATH and fix the issues.
#v58 (2016/03/15)
* Add GodepVersion to Godeps.json file so that as godep changes / adds features / fixes bugs we can know which version of godep most recently wrote out the file.
#v57 (2016/03/07)
* Don't use `git rev-parse --show-toplevel` to determine git repo roots as it resolves symlinks: https://github.com/tools/godep/pull/418
# v56 (2016/02/26)
* replace path comparisons with case insensitive pathEqual()
* add versionString() to debug output
* Send log output to Stderr
# v55 2016/02/22
* re-saved deps to clean out extra stuff (see v54; godep restore; godep save -r=false; rm -rf Godeps; godep save -r). We're still using a workspace with rewrites so users of older go version can still go get this tool.
* Replace simple == with strings.EqualFold in listFiles to avoid problems with case insensitive filesystems ("Code" != "code" when doing a byte by byte comparison)
# v54 2016/02/22
* Update some docs around vendor/
* More precise recording of dependencies. Removed recursive copying of sub directories of a package (precise vendoring). This should allow using `./...` with the go tool for compilation of project using `vendor/`. See https://github.com/tools/godep/pull/415
# v53 2016/02/11
* Disable VendorExperiment if a godep workspace already exists.
# v52 2016/01/27
* Trim 'rc' out of go version strings when determining major version.
# v51 2016/01/21
* Trim 'beta' out of go version strings when determining major version.
# v50 2016/01/19
* More verbose output on save -v.
# v49 2016/01/13
* Add UK spelling license/licence to the pile + fix up a bunch of typos
* Clarify tag handling in docs
# v48 2016/01/13
* Abort restore if there is no $GOPATH set.
# v47 2016/01/12
* Dev versions of go should honor the current meaning of GO15VENDOREXPERIMENT
# v46 2016/01/03
* Record "devel" when the release is a devel release of go (compiled from git).
# v45 2015/12/28
* Upcase windows drive letters before comparing. Fixes #383.
# v44 2015/12/23
* Clean package roots when attempting to find a vendor directory so we don't loop forever.
* Fixes 382
# v43 2015/12/22
* Better error messages when parsing Godeps.json: Fixes #372
# v42 2015/12/22
* Fix a bunch of GO15VENDOREXPERIMENT issues
* Find package directories better. Previously we used build.FindOnly which didn't work the way I expected it to (any dir would work w/o error).
* Set the VendorExperiment bool based on go version as 1.6 defaults to on.
* A bunch of extra debugging for use while sanity checking myself.
* vendor flag for test structs.
* Some tests for vendor/ stuff:
* Basic Test
* Transitive
* Transitive, across GOPATHs + collapse vendor/ directories.
* Should Fix #358
# v41 2015/12/17
* Don't rewrite packages outside of the project. This would happen if you specified
an external package for vendoring when you ran `goodep save -r ./... github.com/some/other/package`
# v40 2015/12/17
* When downloading a dependency, create the base directory if needed.
# v39 2015/12/16
* Record only the major go version (ex. go1.5) instead of the complete string.
# v38 2015/12/16
* Replace `go get`, further fix up restore error handling/reporting.
* Fixes #186
* Don't bother restoring/downloading if already done.
# v37 2015/12/15
* Change up how download/restore works a little
* Try to load the package after downloading/restoring. Previously
that was done too early in the process.
* make previous verbose output debug output
* report a typed error instead of a string from listPackage so it can
be asserted to provide a nicer error.
* Catch go get errors that say there are no go files found. See code
comment as to why.
* do *all* downloading during download phase.
# v36 2015/12/14
* Fixes #358: Using wrong variable. Will add test after release.
# v35 2015/12/11
* Fixes #356: Major performance regressions in v34
* Enable cpu profiling via flag on save.
* Cache packages by dir
* Don't do a full import pass on deps for packages in the GOROOT
* create a bit less garbage at times
* Generalize -v & -d flags
# v34 2015/12/08
* We now use build.Context to help locate packages only and do our own parsing (via go/ast).
* Fixes reported issues caused by v33 (Removal of `go list`):
* #345: Bug in godep restore
* #346: Fix loading a dot package
* #348: Godep save issue when importing lib/pq
* #350: undefined: build.MultiplePackageError
* #351: stow away helper files
* #353: cannot find package "appengine"
* Don't process imports of `.go` files tagged with the `appengine` build tag.
# v33 2015/12/07
* Replace the use of `go list`. This is a large change although all existing tests pass.
* Don't process the imports of `.go` files with the `ignore` build tag.
# v32 2015/12/02
* Eval Symlinks in Contains() check.
# v31 2015/12/02
* In restore, mention which package had the problem -- @shurcool
# v30 2015/11/25
* Add `-t` flag to the `godep get` command.
# v29 2015/11/17
* Temp work around to fix issue with LICENSE files.
# v28 2015/11/09
* Make `version` an actual command.
# v27 2015/11/06
* run command once during restore -v
# v26 2015/11/05
* Better fix for the issue fixed in v25: All update paths are now path.Clean()'d
# v25 2015/11/05
* `godep update package/` == `godep update package`. Fixes #313
# v24 2015/11/05
* Honor -t during update. Fixes #312
# v23 2015/11/05
* Do not use --debug to find full revision name for mercurial repositories
# v22 2015/11/14
* s/GOVENDOREXPERIMENT/GO15VENDOREXPERIMENT :-(
# v21 2015/11/13
* Fix #310: Case insensitive fs issue
# v20 2015/11/13
* Attempt to include license files when vendoring. (@client9)
# v19 2015/11/3
* Fix conflict error message. Revisions were swapped. Also better selection of package that needs update.
# v18 2015/10/16
* Improve error message when trying to save a conflicting revision.
# v17 2015/10/15
* Fix for v16 bug. All vcs list commands now produce paths relative to the root of the vcs.
# v16 2015/10/15
* Determine repo root using vcs commands and use that instead of dep.dir
# v15 2015/10/14
* Update .travis.yml file to do releases to github
# v14 2015/10/08
* Don't print out a workspace path when GO15VENDOREXPERIMENT is active. The vendor/ directory is not a valid workspace, so can't be added to your $GOPATH.
# v13 2015/10/07
* Do restores in 2 separate steps, first download all deps and then check out the recorded revisions.
* Update Changelog date format
# v12 2015/09/22
* Extract errors into separate file.
# v11 2015/08/22
* Amend code to pass golint.
# v10 2015/09/21
* Analyse vendored package test dependencies.
* Update documentation.
# v9 2015/09/17
* Don't save test dependencies by default.
# v8 2015/09/17
* Reorganize code.
# v7 2015/09/09
* Add verbose flag.
* Skip untracked files.
* Add VCS list command.
# v6 2015/09/04
* Revert ignoring testdata directories and instead ignore it while
processing Go files and copy the whole directory unmodified.
# v5 2015/09/04
* Fix vcs selection in restore command to work as go get does
# v4 2015/09/03
* Remove the deprecated copy option.
# v3 2015/08/26
* Ignore testdata directories
# v2 2015/08/11
* Include command line packages in the set to copy
This is a simplification to how we define the behavior
of the save command. Now it has two distinct package
parameters, the "root set" and the "destination", and
they have clearer roles. The packages listed on the
command line form the root set; they and all their
dependencies will be copied into the Godeps directory.
Additionally, the destination (always ".") will form the
initial list of "seen" import paths to exclude from
copying.
In the common case, the root set is equal to the
destination, so the effective behavior doesn't change.
This is primarily just a simpler definition. However, if
the user specifies a package on the command line that
lives outside of . then that package will be copied.
As a side effect, there's a simplification to the way we
add packages to the initial "seen" set. Formerly, to
avoid copying dependencies unnecessarily, we would try
to find the root of the VCS repo for each package in the
root set, and mark the import path of the entire repo as
seen. This meant for a repo at path C, if destination
C/S imports C/T, we would not copy C/T into C/S/Godeps.
Now we don't treat the repo root specially, and as
mentioned above, the destination alone is considered
seen.
This also means we don't require listed packages to be
in VCS unless they're outside of the destination.
# v1 2015/07/20
* godep version command
Output the version as well as some godep runtime information that is
useful for debugging user's issues.
The version const would be bumped each time a PR is merged into master
to ensure that we'll be able to tell which version someone got when they
did a `go get github.com/tools/godep`.
# Older changes
Many and more, see `git log -p`

View File

@ -1,22 +0,0 @@
## Why do I need to check in `vendor/`?
godep's primary concern is to allow you to repeatably build your project. Your
dependencies are part of that project. Without them it won't build. Not
committing `vendor/` adds additional external dependencies that are outside of
your control. In Go, fetching packages is tied to multiple external systems
(DNS, web servers, etc). Over time other developers or code hosting sites may
discontinue service, delete code, force push, or take any number of other
actions that may make a package unreachable. Therefore it's the opinion of the
godep authors that `vendor/` should always be checked in.
## Should I use `godep restore`?
Probably not, unless you **need** to. Situations where you would **need** to are:
1. Using older Godep Workspaces (`Godeps/_workspace`) and not using `godep go
<cmd>`.
1. Resetting the state of $GOPATH to what is in your `Godeps.json` file in order
to cleanly re-vendor everything w/o upgrading/changing any deps. This is
useful when [migrating](https://github.com/tools/godep#migrating-to-vendor)
from workspaces to `vendor` or when a bug is fixed in `godep` that cleans up
a previous vendoring error.

View File

@ -1,28 +0,0 @@
Copyright © 2013 Keith Rarick.
Portions Copyright (c) 2012 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,209 +0,0 @@
# Godep - Archived
Please use [dep](https://github.com/golang/dep) or another tool instead.
The rest of this readme is preserved for those that may still need its contents.
[![Build Status](https://travis-ci.org/tools/godep.svg)](https://travis-ci.org/tools/godep)
[![GoDoc](https://godoc.org/github.com/tools/godep?status.svg)](https://godoc.org/github.com/tools/godep)
godep helps build packages reproducibly by fixing their dependencies.
This tool assumes you are working in a standard Go workspace, as described [here](http://golang.org/doc/code.html). We
expect godep to build on Go 1.4* or newer, but you can use it on any project that works with Go 1 or newer.
Please check the [FAQ](FAQ.md) if you have a question.
## Golang Dep
The Go community now has the [dep](https://github.com/golang/dep) project to
manage dependencies. Please consider trying to migrate from Godep to dep. If there
is an issue preventing you from migrating please file an issue with dep so the
problem can be corrected. Godep will continue to be supported for some time but
is considered to be in a state of support rather than active feature development.
## Install
```console
go get github.com/tools/godep
```
## How to use godep with a new project
Assuming you've got everything working already, so you can build your project
with `go install` and test it with `go test`, it's one command to start using:
```console
godep save
```
This will save a list of dependencies to the file `Godeps/Godeps.json` and copy
their source code into `vendor/` (or `Godeps/_workspace/` when using older
versions of Go). Godep does **not copy**:
- files from source repositories that are not tracked in version control.
- `*_test.go` files.
- `testdata` directories.
- files outside of the go packages.
Godep does not process the imports of `.go` files with either the `ignore`
or `appengine` build tags.
Test files and testdata directories can be saved by adding `-t`.
Read over the contents of `vendor/` and make sure it looks reasonable. Then
commit the `Godeps/` and `vendor/` directories to version control.
## The deprecated `-r` flag
For older versions of Go, the `-r` flag tells save to automatically rewrite
package import paths. This allows your code to refer directly to the copied
dependencies in `Godeps/_workspace`. So, a package C that depends on package
D will actually import `C/Godeps/_workspace/src/D`. This makes C's repo
self-contained and causes `go get` to build C with the right version of all
dependencies.
If you don't use `-r`, when using older version of Go, then in order to use the
fixed dependencies and get reproducible builds, you must make sure that **every
time** you run a Go-related command, you wrap it in one of these two ways:
- If the command you are running is just `go`, run it as `godep go ...`, e.g.
`godep go install -v ./...`
- When using a different command, set your `$GOPATH` using `godep path` as
described below.
`-r` isn't necessary with go1.6+ and isn't allowed.
## Additional Operations
### Restore
The `godep restore` installs the
package versions specified in `Godeps/Godeps.json` to your `$GOPATH`. This
modifies the state of packages in your `$GOPATH`. NOTE: `godep restore` leaves
git repositories in a detached state. `go1.6`+ no longer checks out the master
branch when doing a `go get`, see [here](https://github.com/golang/go/commit/42206598671a44111c8f726ad33dc7b265bdf669).
> If you run `godep restore` in your main `$GOPATH` `go get -u` will fail on packages that are behind master.
Please see the [FAQ](https://github.com/tools/godep/blob/master/FAQ.md#should-i-use-godep-restore) section about restore.
### Edit-test Cycle
1. Edit code
1. Run `godep go test`
1. (repeat)
### Add a Dependency
To add a new package foo/bar, do this:
1. Run `go get foo/bar`
1. Edit your code to import foo/bar.
1. Run `godep save` (or `godep save ./...`).
### Update a Dependency
To update a package from your `$GOPATH`, do this:
1. Run `go get -u foo/bar`
1. Run `godep update foo/bar`.
You can use the `...` wildcard, for example `godep update foo/...`. Before comitting the change, you'll probably want to
inspect the changes to Godeps, for example with `git diff`, and make sure it looks reasonable.
## Multiple Packages
If your repository has more than one package, you're probably accustomed to
running commands like `go test ./...`, `go install ./...`, and `go fmt ./...`.
Similarly, you should run `godep save ./...` to capture the dependencies of all
packages in your application.
## File Format
Godeps is a json file with the following structure:
```go
type Godeps struct {
ImportPath string
GoVersion string // Abridged output of 'go version'.
GodepVersion string // Abridged output of 'godep version'
Packages []string // Arguments to godep save, if any.
Deps []struct {
ImportPath string
Comment string // Description of commit, if present.
Rev string // VCS-specific commit ID.
}
}
```
Example Godeps:
```json
{
"ImportPath": "github.com/kr/hk",
"GoVersion": "go1.6",
"Deps": [
{
"ImportPath": "code.google.com/p/go-netrc/netrc",
"Rev": "28676070ab99"
},
{
"ImportPath": "github.com/kr/binarydist",
"Rev": "3380ade90f8b0dfa3e363fd7d7e941fa857d0d13"
}
]
}
```
## Migrating to vendor/
Godep supports the Go 1.5+ vendor/
[experiment](https://github.com/golang/go/commit/183cc0cd41f06f83cb7a2490a499e3f9101befff)
utilizing the same environment variable that the go tooling itself supports
(`GO15VENDOREXPERIMENT`).
godep mostly works the same way as the `go` command line tool. If you have go
1.5.X and set `GO15VENDOREXPERIMENT=1` or have go1.6.X (or devel) `vendor/`
is enabled. **Unless** you already have a `Godeps/_workspace`. This is a safety
feature and godep warns you about this.
When `vendor/` is enabled godep will write the vendored code into the top level
`./vendor/` directory. A `./Godeps/Godeps.json` file is created to track
the dependencies and revisions. `vendor/` is not compatible with rewrites.
There is currently no automated migration between the old Godeps workspace and
the vendor directory, but the following steps should work:
```term
# just to be safe
$ unset GO15VENDOREXPERIMENT
# restore currently vendored deps to the $GOPATH
$ godep restore
# The next line is only needed to automatically undo rewritten imports that were
# created with godep save -r.
$ godep save -r=false <pkg spec>
# Remove the old Godeps folder
$ rm -rf Godeps
# If on go1.5.X to enable `vendor/`
$ export GO15VENDOREXPERIMENT=1
# re-analyze deps and save to `vendor/`.
$ godep save <pkg spec>
# Add the changes to your VCS
$ git add -A . ; git commit -am "Godep workspace -> vendor/"
# You should see your Godeps/_workspace/src files "moved" to vendor/.
```
## Releasing
1. Increment the version in `version.go`.
1. Tag the commit with the same version number.
1. Update `Changelog.md`.

View File

@ -1,128 +0,0 @@
package main
import (
"fmt"
"os"
"os/exec"
"sort"
"strings"
)
// A Dependency is a specific revision of a package.
type Dependency struct {
ImportPath string
Comment string `json:",omitempty"` // Description of commit, if present.
Rev string // VCS-specific commit ID.
// used by command save & update
ws string // workspace
root string // import path to repo root
dir string // full path to package
// used by command update
matched bool // selected for update by command line
pkg *Package
missing bool // packages is missing
// used by command go
vcs *VCS
}
func eqDeps(a, b []Dependency) bool {
ok := true
for _, da := range a {
for _, db := range b {
if da.ImportPath == db.ImportPath && da.Rev != db.Rev {
ok = false
}
}
}
return ok
}
// containsPathPrefix returns whether any string in a
// is s or a directory containing s.
// For example, pattern ["a"] matches "a" and "a/b"
// (but not "ab").
func containsPathPrefix(pats []string, s string) bool {
for _, pat := range pats {
if pat == s || strings.HasPrefix(s, pat+"/") {
return true
}
}
return false
}
func uniq(a []string) []string {
var s string
var i int
if !sort.StringsAreSorted(a) {
sort.Strings(a)
}
for _, t := range a {
if t != s {
a[i] = t
i++
s = t
}
}
return a[:i]
}
// trimGoVersion and return the major version
func trimGoVersion(version string) (string, error) {
if version == "devel" {
return "devel", nil
}
if strings.HasPrefix(version, "devel+") || strings.HasPrefix(version, "devel-") {
return strings.Replace(version, "devel+", "devel-", 1), nil
}
p := strings.Split(version, ".")
if len(p) < 2 {
return "", fmt.Errorf("Error determining major go version from: %q", version)
}
var split string
switch {
case strings.Contains(p[1], "beta"):
split = "beta"
case strings.Contains(p[1], "rc"):
split = "rc"
}
if split != "" {
p[1] = strings.Split(p[1], split)[0]
}
return p[0] + "." + p[1], nil
}
var goVersionTestOutput = ""
func getGoVersion() (string, error) {
// For testing purposes only
if goVersionTestOutput != "" {
return goVersionTestOutput, nil
}
// Godep might have been compiled with a different
// version, so we can't just use runtime.Version here.
cmd := exec.Command("go", "version")
cmd.Stderr = os.Stderr
out, err := cmd.Output()
return string(out), err
}
// goVersion returns the major version string of the Go compiler
// currently installed, e.g. "go1.5".
func goVersion() (string, error) {
out, err := getGoVersion()
if err != nil {
return "", err
}
gv := strings.Split(out, " ")
if len(gv) < 4 {
return "", fmt.Errorf("Error splitting output of `go version`: Expected 4 or more elements, but there are < 4: %q", out)
}
if gv[2] == "devel" {
return trimGoVersion(gv[2] + gv[3])
}
return trimGoVersion(gv[2])
}

View File

@ -1,74 +0,0 @@
package main
import (
"bytes"
"fmt"
"log"
"github.com/pmezard/go-difflib/difflib"
)
var cmdDiff = &Command{
Name: "diff",
Short: "shows the diff between current and previously saved set of dependencies",
Long: `
Shows the difference, in a unified diff format, between the
current set of dependencies and those generated on a
previous 'go save' execution.
`,
Run: runDiff,
OnlyInGOPATH: true,
}
func runDiff(cmd *Command, args []string) {
gold, err := loadDefaultGodepsFile()
if err != nil {
log.Fatalln(err)
}
pkgs := []string{"."}
dot, err := LoadPackages(pkgs...)
if err != nil {
log.Fatalln(err)
}
gnew := &Godeps{
ImportPath: dot[0].ImportPath,
GoVersion: gold.GoVersion,
}
err = gnew.fill(dot, dot[0].ImportPath)
if err != nil {
log.Fatalln(err)
}
diff, err := diffStr(&gold, gnew)
if err != nil {
log.Fatalln(err)
}
fmt.Println(diff)
}
// diffStr returns a unified diff string of two Godeps.
func diffStr(a, b *Godeps) (string, error) {
var ab, bb bytes.Buffer
_, err := a.writeTo(&ab)
if err != nil {
log.Fatalln(err)
}
_, err = b.writeTo(&bb)
if err != nil {
log.Fatalln(err)
}
diff := difflib.UnifiedDiff{
A: difflib.SplitLines(ab.String()),
B: difflib.SplitLines(bb.String()),
FromFile: b.file(),
ToFile: "$GOPATH",
Context: 10,
}
return difflib.GetUnifiedDiffString(diff)
}

View File

@ -1,22 +0,0 @@
/*
Command godep helps build packages reproducibly by fixing
their dependencies.
Example Usage
Save currently-used dependencies to file Godeps:
$ godep save
Build project using saved dependencies:
$ godep go install
or
$ GOPATH=`godep path`:$GOPATH
$ go install
*/
package main

View File

@ -1,18 +0,0 @@
package main
import "errors"
var (
errorLoadingDeps = errors.New("error loading dependencies")
errorLoadingPackages = errors.New("error loading packages")
errorCopyingSourceCode = errors.New("error copying source code")
errorNoPackagesUpdatable = errors.New("no packages can be updated")
)
type errPackageNotFound struct {
path string
}
func (e errPackageNotFound) Error() string {
return "Package (" + e.path + ") not found"
}

View File

@ -1,96 +0,0 @@
package main
import (
"log"
"os"
"os/exec"
)
var cmdGet = &Command{
Name: "get",
Args: "[-t] [packages]",
Short: "download and install packages with specified dependencies",
Long: `
Get downloads to GOPATH the packages named by the import paths, and installs
them with the dependencies specified in their Godeps files.
If any of the packages do not have Godeps files, those are installed
as if by go get.
If -t is given, dependencies of test files are also downloaded and installed.
For more about specifying packages, see 'go help packages'.
`,
Run: runGet,
OnlyInGOPATH: true,
}
var getT bool
func init() {
cmdGet.Flag.BoolVar(&getT, "t", false, "get test dependencies")
}
func runGet(cmd *Command, args []string) {
if len(args) == 0 {
args = []string{"."}
}
cmdArgs := []interface{}{"get", "-d"}
if verbose {
cmdArgs = append(cmdArgs, "-v")
}
if getT {
cmdArgs = append(cmdArgs, "-t")
}
err := command("go", append(cmdArgs, args)...).Run()
if err != nil {
log.Fatalln(err)
}
// group import paths by Godeps location
groups := make(map[string][]string)
ps, err := LoadPackages(args...)
if err != nil {
log.Fatalln(err)
}
for _, pkg := range ps {
if pkg.Error.Err != "" {
log.Fatalln(pkg.Error.Err)
}
dir, _ := findInParents(pkg.Dir, "Godeps")
groups[dir] = append(groups[dir], pkg.ImportPath)
}
for dir, packages := range groups {
var c *exec.Cmd
if dir == "" {
c = command("go", "install", packages)
} else {
c = command("godep", "go", "install", packages)
c.Dir = dir
}
if err := c.Run(); err != nil {
log.Fatalln(err)
}
}
}
// command is like exec.Command, but the returned
// Cmd inherits stderr from the current process, and
// elements of args may be either string or []string.
func command(name string, args ...interface{}) *exec.Cmd {
var a []string
for _, arg := range args {
switch v := arg.(type) {
case string:
a = append(a, v)
case []string:
a = append(a, v...)
}
}
c := exec.Command(name, a...)
c.Stderr = os.Stderr
return c
}

View File

@ -1,129 +0,0 @@
package main
import (
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
)
var cmdGo = &Command{
Name: "go",
Args: "command [arguments]",
Short: "run the go tool with saved dependencies",
Long: `
Go runs the go tool with a modified GOPATH giving access to
dependencies saved in Godeps.
Any go tool command can run this way, but "godep go get"
is unnecessary and has been disabled. Instead, use
"godep go install".
`,
Run: runGo,
OnlyInGOPATH: true,
}
// Find the godep GOPATH for this file tree and run the go tool.
func runGo(cmd *Command, args []string) {
gopath := prepareGopath()
if s := os.Getenv("GOPATH"); s != "" {
gopath += string(os.PathListSeparator) + os.Getenv("GOPATH")
}
if len(args) > 0 && args[0] == "get" {
log.Printf("invalid subcommand: %q", "go get")
fmt.Fprintln(os.Stderr, "Use 'godep go install' instead.")
fmt.Fprintln(os.Stderr, "Run 'godep help go' for usage.")
os.Exit(2)
}
c := exec.Command("go", args...)
c.Env = append(envNoGopath(), "GOPATH="+gopath)
c.Stdin = os.Stdin
c.Stdout = os.Stdout
c.Stderr = os.Stderr
err := c.Run()
if err != nil {
log.Fatalln("go", err)
}
}
// prepareGopath reads dependency information from the filesystem
// entry name, fetches any necessary code, and returns a gopath
// causing the specified dependencies to be used.
func prepareGopath() (gopath string) {
dir, isDir := findGodeps()
if dir == "" {
log.Fatalln("No Godeps found (or in any parent directory)")
}
if !isDir {
log.Fatalln(strings.TrimSpace(needSource))
}
return filepath.Join(dir, "Godeps", "_workspace")
}
// findGodeps looks for a directory entry "Godeps" in the
// current directory or any parent, and returns the containing
// directory and whether the entry itself is a directory.
// If Godeps can't be found, findGodeps returns "".
// For any other error, it exits the program.
func findGodeps() (dir string, isDir bool) {
wd, err := os.Getwd()
if err != nil {
log.Fatalln(err)
}
return findInParents(wd, "Godeps")
}
// isRoot returns true iff a path is a root.
// On Unix: "/".
// On Windows: "C:\", "D:\", ...
func isRoot(p string) bool {
p = filepath.Clean(p)
volume := filepath.VolumeName(p)
p = strings.TrimPrefix(p, volume)
p = filepath.ToSlash(p)
return p == "/"
}
// findInParents returns the path to the directory containing name
// in dir or any ancestor, and whether name itself is a directory.
// If name cannot be found, findInParents returns the empty string.
func findInParents(dir, name string) (container string, isDir bool) {
for {
fi, err := os.Stat(filepath.Join(dir, name))
if os.IsNotExist(err) && isRoot(dir) {
return "", false
}
if os.IsNotExist(err) {
dir = filepath.Dir(dir)
continue
}
if err != nil {
log.Fatalln(err)
}
return dir, fi.IsDir()
}
}
func envNoGopath() (a []string) {
for _, s := range os.Environ() {
if !strings.HasPrefix(s, "GOPATH=") {
a = append(a, s)
}
}
return a
}
const needSource = `
outdated Godeps missing source code
This dependency list was created with an old version of godep.
To work around this, you have two options:
1. Run 'godep restore', and try again.
2. Ask the maintainer to switch to a newer version of godep,
then try again with the updated package.
`

View File

@ -1,218 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"os"
"path/filepath"
)
var (
godepsFile = filepath.Join("Godeps", "Godeps.json")
oldGodepsFile = filepath.Join("Godeps")
)
// Godeps describes what a package needs to be rebuilt reproducibly.
// It's the same information stored in file Godeps.
type Godeps struct {
ImportPath string
GoVersion string
GodepVersion string
Packages []string `json:",omitempty"` // Arguments to save, if any.
Deps []Dependency
isOldFile bool
}
func loadGodepsFile(path string) (Godeps, error) {
var g Godeps
f, err := os.Open(path)
if err != nil {
return g, err
}
defer f.Close()
err = json.NewDecoder(f).Decode(&g)
if err != nil {
err = fmt.Errorf("Unable to parse %s: %s", path, err.Error())
}
return g, err
}
func loadDefaultGodepsFile() (Godeps, error) {
var g Godeps
var err error
g, err = loadGodepsFile(godepsFile)
if err != nil {
if os.IsNotExist(err) {
var err1 error
g, err1 = loadGodepsFile(oldGodepsFile)
if err1 != nil {
if os.IsNotExist(err1) {
return g, err
}
return g, err1
}
g.isOldFile = true
return g, nil
}
}
return g, err
}
// pkgs is the list of packages to read dependencies for
func (g *Godeps) fill(pkgs []*Package, destImportPath string) error {
debugln("fill", destImportPath)
ppln(pkgs)
var err1 error
var path, testImports []string
dipp := []string{destImportPath}
for _, p := range pkgs {
if p.Standard {
log.Println("ignoring stdlib package:", p.ImportPath)
continue
}
if p.Error.Err != "" {
log.Println(p.Error.Err)
err1 = errorLoadingPackages
continue
}
path = append(path, p.ImportPath)
path = append(path, p.Deps...)
testImports = append(testImports, p.TestImports...)
testImports = append(testImports, p.XTestImports...)
}
ps, err := LoadPackages(testImports...)
if err != nil {
return err
}
for _, p := range ps {
if p.Standard {
continue
}
if p.Error.Err != "" {
log.Println(p.Error.Err)
err1 = errorLoadingPackages
continue
}
path = append(path, p.ImportPath)
path = append(path, p.Deps...)
}
debugln("path", path)
for i, p := range path {
path[i] = unqualify(p)
}
path = uniq(path)
debugln("uniq, unqualify'd path", path)
ps, err = LoadPackages(path...)
if err != nil {
return err
}
for _, pkg := range ps {
if pkg.Error.Err != "" {
log.Println(pkg.Error.Err)
err1 = errorLoadingDeps
continue
}
if pkg.Standard || containsPathPrefix(dipp, pkg.ImportPath) {
debugln("standard or dest skipping", pkg.ImportPath)
continue
}
vcs, reporoot, err := VCSFromDir(pkg.Dir, filepath.Join(pkg.Root, "src"))
if err != nil {
log.Println(err)
err1 = errorLoadingDeps
continue
}
id, err := vcs.identify(pkg.Dir)
if err != nil {
log.Println(err)
err1 = errorLoadingDeps
continue
}
if vcs.isDirty(pkg.Dir, id) {
log.Println("dirty working tree (please commit changes):", pkg.Dir)
err1 = errorLoadingDeps
continue
}
comment := vcs.describe(pkg.Dir, id)
g.Deps = append(g.Deps, Dependency{
ImportPath: pkg.ImportPath,
Rev: id,
Comment: comment,
dir: pkg.Dir,
ws: pkg.Root,
root: filepath.ToSlash(reporoot),
vcs: vcs,
})
}
return err1
}
func (g *Godeps) copy() *Godeps {
h := *g
h.Deps = make([]Dependency, len(g.Deps))
copy(h.Deps, g.Deps)
return &h
}
func (g *Godeps) file() string {
if g.isOldFile {
return oldGodepsFile
}
return godepsFile
}
func (g *Godeps) save() (int64, error) {
f, err := os.Create(g.file())
if err != nil {
return 0, err
}
defer f.Close()
return g.writeTo(f)
}
func (g *Godeps) writeTo(w io.Writer) (int64, error) {
g.GodepVersion = fmt.Sprintf("v%s", version) // godep always writes its current version.
b, err := json.MarshalIndent(g, "", "\t")
if err != nil {
return 0, err
}
n, err := w.Write(append(b, '\n'))
return int64(n), err
}
func (g *Godeps) addOrUpdateDeps(deps []Dependency) {
var missing []Dependency
for _, d := range deps {
var found bool
for i := range g.Deps {
if g.Deps[i].ImportPath == d.ImportPath {
g.Deps[i] = d
found = true
break
}
}
if !found {
missing = append(missing, d)
}
}
g.Deps = append(g.Deps, missing...)
}
func (g *Godeps) removeDeps(deps []Dependency) {
var f []Dependency
for i := range g.Deps {
var found bool
for _, d := range deps {
if g.Deps[i].ImportPath == d.ImportPath {
found = true
break
}
}
if !found {
f = append(f, g.Deps[i])
}
}
g.Deps = f
}

View File

@ -1,59 +0,0 @@
package main
import (
"strings"
)
// LicenseFilePrefix is a list of filename prefixes that indicate it
// might contain a software license
var LicenseFilePrefix = []string{
"licence", // UK spelling
"license", // US spelling
"copying",
"unlicense",
"copyright",
"copyleft",
"authors",
"contributors",
}
// LegalFileSubstring are substrings that indicate the file is likely
// to contain some type of legal declaration. "legal" is often used
// that it might moved to LicenseFilePrefix
var LegalFileSubstring = []string{
"legal",
"notice",
"disclaimer",
"patent",
"third-party",
"thirdparty",
}
// IsLicenseFile returns true if the filename might be contain a
// software license
func IsLicenseFile(filename string) bool {
lowerfile := strings.ToLower(filename)
for _, prefix := range LicenseFilePrefix {
if strings.HasPrefix(lowerfile, prefix) {
return true
}
}
return false
}
// IsLegalFile returns true if the file is likely to contain some type
// of of legal declaration or licensing information
func IsLegalFile(filename string) bool {
lowerfile := strings.ToLower(filename)
for _, prefix := range LicenseFilePrefix {
if strings.HasPrefix(lowerfile, prefix) {
return true
}
}
for _, substring := range LegalFileSubstring {
if strings.Contains(lowerfile, substring) {
return true
}
}
return false
}

View File

@ -1,601 +0,0 @@
package main
import (
"errors"
"fmt"
"go/build"
"go/parser"
"go/token"
"log"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"unicode"
pathpkg "path"
)
var (
gorootSrc = filepath.Join(build.Default.GOROOT, "src")
ignoreTags = []string{"appengine", "ignore"} //TODO: appengine is a special case for now: https://github.com/tools/godep/issues/353
versionMatch = regexp.MustCompile(`\Ago\d+\.\d+\z`)
versionNegativeMatch = regexp.MustCompile(`\A\!go\d+\.\d+\z`)
)
type errorMissingDep struct {
i, dir string // import, dir
}
func (e errorMissingDep) Error() string {
return "Unable to find dependent package " + e.i + " in context of " + e.dir
}
// packageContext is used to track an import and which package imported it.
type packageContext struct {
pkg *build.Package // package that imports the import
imp string // import
}
// depScanner tracks the processed and to be processed packageContexts
type depScanner struct {
processed []packageContext
todo []packageContext
}
// Next package and import to process
func (ds *depScanner) Next() (*build.Package, string) {
c := ds.todo[0]
ds.processed = append(ds.processed, c)
ds.todo = ds.todo[1:]
return c.pkg, c.imp
}
// Continue looping?
func (ds *depScanner) Continue() bool {
return len(ds.todo) > 0
}
// Add a package and imports to the depScanner. Skips already processed/pending package/import combos
func (ds *depScanner) Add(pkg *build.Package, imports ...string) {
NextImport:
for _, i := range imports {
if i == "C" {
i = "runtime/cgo"
}
for _, epc := range ds.processed {
if pkg.Dir == epc.pkg.Dir && i == epc.imp {
debugln("ctxts epc.pkg.Dir == pkg.Dir && i == epc.imp, skipping", epc.pkg.Dir, i)
continue NextImport
}
}
for _, epc := range ds.todo {
if pkg.Dir == epc.pkg.Dir && i == epc.imp {
debugln("ctxts epc.pkg.Dir == pkg.Dir && i == epc.imp, skipping", epc.pkg.Dir, i)
continue NextImport
}
}
pc := packageContext{pkg, i}
debugln("Adding pc:", pc.pkg.Dir, pc.imp)
ds.todo = append(ds.todo, pc)
}
}
var (
pkgCache = make(map[string]*build.Package) // dir => *build.Package
)
// returns the package in dir either from a cache or by importing it and then caching it
func fullPackageInDir(dir string) (*build.Package, error) {
var err error
pkg, ok := pkgCache[dir]
if !ok {
pkg, _ = build.ImportDir(dir, build.FindOnly)
if pkg.Goroot {
pkg, err = build.ImportDir(pkg.Dir, 0)
} else {
err = fillPackage(pkg)
}
if err == nil {
pkgCache[dir] = pkg
}
}
return pkg, err
}
// listPackage specified by path
func listPackage(path string) (*Package, error) {
debugln("listPackage", path)
var lp *build.Package
dir, err := findDirForPath(path, nil)
if err != nil {
return nil, err
}
lp, err = fullPackageInDir(dir)
p := &Package{
Dir: lp.Dir,
Root: lp.Root,
ImportPath: lp.ImportPath,
XTestImports: lp.XTestImports,
TestImports: lp.TestImports,
GoFiles: lp.GoFiles,
CgoFiles: lp.CgoFiles,
TestGoFiles: lp.TestGoFiles,
XTestGoFiles: lp.XTestGoFiles,
IgnoredGoFiles: lp.IgnoredGoFiles,
}
p.Standard = lp.Goroot && lp.ImportPath != "" && !strings.Contains(lp.ImportPath, ".")
if err != nil || p.Standard {
return p, err
}
debugln("Looking For Package:", path, "in", dir)
ppln(lp)
ds := depScanner{}
ds.Add(lp, lp.Imports...)
for ds.Continue() {
ip, i := ds.Next()
debugf("Processing import %s for %s\n", i, ip.Dir)
pdir, err := findDirForPath(i, ip)
if err != nil {
return nil, err
}
dp, err := fullPackageInDir(pdir)
if err != nil { // This really should happen in this context though
ppln(err)
return nil, errorMissingDep{i: i, dir: ip.Dir}
}
ppln(dp)
if !dp.Goroot {
// Don't bother adding packages in GOROOT to the dependency scanner, they don't import things from outside of it.
ds.Add(dp, dp.Imports...)
}
debugln("lp:")
ppln(lp)
debugln("ip:")
ppln(ip)
if lp == ip {
debugln("lp == ip")
p.Imports = append(p.Imports, dp.ImportPath)
}
p.Deps = append(p.Deps, dp.ImportPath)
p.Dependencies = addDependency(p.Dependencies, dp)
}
p.Imports = uniq(p.Imports)
p.Deps = uniq(p.Deps)
debugln("Done Looking For Package:", path, "in", dir)
ppln(p)
return p, nil
}
func addDependency(deps []build.Package, d *build.Package) []build.Package {
for i := range deps {
if deps[i].Dir == d.Dir {
return deps
}
}
return append(deps, *d)
}
// finds the directory for the given import path in the context of the provided build.Package (if provided)
func findDirForPath(path string, ip *build.Package) (string, error) {
debugln("findDirForPath", path, ip)
var search []string
if build.IsLocalImport(path) {
dir := path
if !filepath.IsAbs(dir) {
if abs, err := filepath.Abs(dir); err == nil {
// interpret relative to current directory
dir = abs
}
}
return dir, nil
}
// We need to check to see if the import exists in vendor/ folders up the hierarchy of the importing package
if VendorExperiment && ip != nil {
debugln("resolving vendor posibilities:", ip.Dir, ip.Root)
cr := cleanPath(ip.Root)
for base := cleanPath(ip.Dir); !pathEqual(base, cr); base = cleanPath(filepath.Dir(base)) {
s := filepath.Join(base, "vendor", path)
debugln("Adding search dir:", s)
search = append(search, s)
}
}
for _, base := range build.Default.SrcDirs() {
search = append(search, filepath.Join(base, path))
}
for _, dir := range search {
debugln("searching", dir)
fi, err := stat(dir)
if err == nil && fi.IsDir() {
return dir, nil
}
}
return "", errPackageNotFound{path}
}
type statEntry struct {
fi os.FileInfo
err error
}
var (
statCache = make(map[string]statEntry)
)
func clearStatCache() {
statCache = make(map[string]statEntry)
}
func stat(p string) (os.FileInfo, error) {
if e, ok := statCache[p]; ok {
return e.fi, e.err
}
fi, err := os.Stat(p)
statCache[p] = statEntry{fi, err}
return fi, err
}
// fillPackage full of info. Assumes p.Dir is set at a minimum
func fillPackage(p *build.Package) error {
if p.Goroot {
return nil
}
if p.SrcRoot == "" {
for _, base := range build.Default.SrcDirs() {
if strings.HasPrefix(p.Dir, base) {
p.SrcRoot = base
}
}
}
if p.SrcRoot == "" {
return errors.New("Unable to find SrcRoot for package " + p.ImportPath)
}
if p.Root == "" {
p.Root = filepath.Dir(p.SrcRoot)
}
var buildMatch = "+build "
var buildFieldSplit = func(r rune) bool {
return unicode.IsSpace(r) || r == ','
}
debugln("Filling package:", p.ImportPath, "from", p.Dir)
gofiles, err := filepath.Glob(filepath.Join(p.Dir, "*.go"))
if err != nil {
debugln("Error globbing", err)
return err
}
if len(gofiles) == 0 {
return &build.NoGoError{Dir: p.Dir}
}
var testImports []string
var imports []string
NextFile:
for _, file := range gofiles {
debugln(file)
pf, err := parser.ParseFile(token.NewFileSet(), file, nil, parser.ImportsOnly|parser.ParseComments)
if err != nil {
return err
}
testFile := strings.HasSuffix(file, "_test.go")
fname := filepath.Base(file)
for _, c := range pf.Comments {
ct := c.Text()
if i := strings.Index(ct, buildMatch); i != -1 {
for _, t := range strings.FieldsFunc(ct[i+len(buildMatch):], buildFieldSplit) {
for _, tag := range ignoreTags {
if t == tag {
p.IgnoredGoFiles = append(p.IgnoredGoFiles, fname)
continue NextFile
}
}
if versionMatch.MatchString(t) && !isSameOrNewer(t, majorGoVersion) {
debugln("Adding", fname, "to ignored list because of version tag", t)
p.IgnoredGoFiles = append(p.IgnoredGoFiles, fname)
continue NextFile
}
if versionNegativeMatch.MatchString(t) && isSameOrNewer(t[1:], majorGoVersion) {
debugln("Adding", fname, "to ignored list because of version tag", t)
p.IgnoredGoFiles = append(p.IgnoredGoFiles, fname)
continue NextFile
}
}
}
}
if testFile {
p.TestGoFiles = append(p.TestGoFiles, fname)
} else {
p.GoFiles = append(p.GoFiles, fname)
}
for _, is := range pf.Imports {
name, err := strconv.Unquote(is.Path.Value)
if err != nil {
return err // can't happen?
}
if testFile {
testImports = append(testImports, name)
} else {
imports = append(imports, name)
}
}
}
imports = uniq(imports)
testImports = uniq(testImports)
p.Imports = imports
p.TestImports = testImports
return nil
}
// All of the following functions were vendored from go proper. Locations are noted in comments, but may change in future Go versions.
// importPaths returns the import paths to use for the given command line.
// $GOROOT/src/cmd/main.go:366
func importPaths(args []string) []string {
debugf("importPathsNoDotExpansion(%q) == ", args)
args = importPathsNoDotExpansion(args)
debugf("%q\n", args)
var out []string
for _, a := range args {
if strings.Contains(a, "...") {
if build.IsLocalImport(a) {
debugf("build.IsLocalImport(%q) == true\n", a)
pkgs := allPackagesInFS(a)
debugf("allPackagesInFS(%q) == %q\n", a, pkgs)
out = append(out, pkgs...)
} else {
debugf("build.IsLocalImport(%q) == false\n", a)
pkgs := allPackages(a)
debugf("allPackages(%q) == %q\n", a, pkgs)
out = append(out, allPackages(a)...)
}
continue
}
out = append(out, a)
}
return out
}
// importPathsNoDotExpansion returns the import paths to use for the given
// command line, but it does no ... expansion.
// $GOROOT/src/cmd/main.go:332
func importPathsNoDotExpansion(args []string) []string {
if len(args) == 0 {
return []string{"."}
}
var out []string
for _, a := range args {
// Arguments are supposed to be import paths, but
// as a courtesy to Windows developers, rewrite \ to /
// in command-line arguments. Handles .\... and so on.
if filepath.Separator == '\\' {
a = strings.Replace(a, `\`, `/`, -1)
}
// Put argument in canonical form, but preserve leading ./.
if strings.HasPrefix(a, "./") {
a = "./" + pathpkg.Clean(a)
if a == "./." {
a = "."
}
} else {
a = pathpkg.Clean(a)
}
if a == "all" || a == "std" || a == "cmd" {
out = append(out, allPackages(a)...)
continue
}
out = append(out, a)
}
return out
}
// allPackagesInFS is like allPackages but is passed a pattern
// beginning ./ or ../, meaning it should scan the tree rooted
// at the given directory. There are ... in the pattern too.
// $GOROOT/src/cmd/main.go:620
func allPackagesInFS(pattern string) []string {
pkgs := matchPackagesInFS(pattern)
if len(pkgs) == 0 {
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
}
return pkgs
}
// allPackages returns all the packages that can be found
// under the $GOPATH directories and $GOROOT matching pattern.
// The pattern is either "all" (all packages), "std" (standard packages),
// "cmd" (standard commands), or a path including "...".
// $GOROOT/src/cmd/main.go:542
func allPackages(pattern string) []string {
pkgs := matchPackages(pattern)
if len(pkgs) == 0 {
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
}
return pkgs
}
// $GOROOT/src/cmd/main.go:554
// This has been changed to not use build.ImportDir
func matchPackages(pattern string) []string {
match := func(string) bool { return true }
treeCanMatch := func(string) bool { return true }
if pattern != "all" && pattern != "std" && pattern != "cmd" {
match = matchPattern(pattern)
treeCanMatch = treeCanMatchPattern(pattern)
}
have := map[string]bool{
"builtin": true, // ignore pseudo-package that exists only for documentation
}
if !build.Default.CgoEnabled {
have["runtime/cgo"] = true // ignore during walk
}
var pkgs []string
for _, src := range build.Default.SrcDirs() {
if (pattern == "std" || pattern == "cmd") && src != gorootSrc {
continue
}
src = filepath.Clean(src) + string(filepath.Separator)
root := src
if pattern == "cmd" {
root += "cmd" + string(filepath.Separator)
}
filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() || path == src {
return nil
}
// Avoid .foo, _foo, and testdata directory trees.
_, elem := filepath.Split(path)
if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
return filepath.SkipDir
}
name := filepath.ToSlash(path[len(src):])
if pattern == "std" && (strings.Contains(name, ".") || name == "cmd") {
// The name "std" is only the standard library.
// If the name has a dot, assume it's a domain name for go get,
// and if the name is cmd, it's the root of the command tree.
return filepath.SkipDir
}
if !treeCanMatch(name) {
return filepath.SkipDir
}
if have[name] {
return nil
}
have[name] = true
if !match(name) {
return nil
}
ap, err := filepath.Abs(path)
if err != nil {
return nil
}
if _, err = fullPackageInDir(ap); err != nil {
debugf("matchPackage(%q) ap=%q Error: %q\n", ap, pattern, err)
if _, noGo := err.(*build.NoGoError); noGo {
return nil
}
}
pkgs = append(pkgs, name)
return nil
})
}
return pkgs
}
// treeCanMatchPattern(pattern)(name) reports whether
// name or children of name can possibly match pattern.
// Pattern is the same limited glob accepted by matchPattern.
// $GOROOT/src/cmd/main.go:527
func treeCanMatchPattern(pattern string) func(name string) bool {
wildCard := false
if i := strings.Index(pattern, "..."); i >= 0 {
wildCard = true
pattern = pattern[:i]
}
return func(name string) bool {
return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
wildCard && strings.HasPrefix(name, pattern)
}
}
// hasPathPrefix reports whether the path s begins with the
// elements in prefix.
// $GOROOT/src/cmd/main.go:489
func hasPathPrefix(s, prefix string) bool {
switch {
default:
return false
case len(s) == len(prefix):
return s == prefix
case len(s) > len(prefix):
if prefix != "" && prefix[len(prefix)-1] == '/' {
return strings.HasPrefix(s, prefix)
}
return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
}
}
// $GOROOT/src/cmd/go/main.go:631
// This has been changed to not use build.ImportDir
func matchPackagesInFS(pattern string) []string {
// Find directory to begin the scan.
// Could be smarter but this one optimization
// is enough for now, since ... is usually at the
// end of a path.
i := strings.Index(pattern, "...")
dir, _ := pathpkg.Split(pattern[:i])
// pattern begins with ./ or ../.
// path.Clean will discard the ./ but not the ../.
// We need to preserve the ./ for pattern matching
// and in the returned import paths.
prefix := ""
if strings.HasPrefix(pattern, "./") {
prefix = "./"
}
match := matchPattern(pattern)
var pkgs []string
filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() {
return nil
}
if path == dir {
// filepath.Walk starts at dir and recurses. For the recursive case,
// the path is the result of filepath.Join, which calls filepath.Clean.
// The initial case is not Cleaned, though, so we do this explicitly.
//
// This converts a path like "./io/" to "io". Without this step, running
// "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io
// package, because prepending the prefix "./" to the unclean path would
// result in "././io", and match("././io") returns false.
path = filepath.Clean(path)
}
// Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
_, elem := filepath.Split(path)
dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
return filepath.SkipDir
}
name := prefix + filepath.ToSlash(path)
if !match(name) {
return nil
}
ap, err := filepath.Abs(path)
if err != nil {
return nil
}
if _, err = fullPackageInDir(ap); err != nil {
debugf("matchPackageInFS(%q) ap=%q Error: %q\n", ap, pattern, err)
if _, noGo := err.(*build.NoGoError); !noGo {
log.Print(err)
}
return nil
}
pkgs = append(pkgs, name)
return nil
})
return pkgs
}

View File

@ -1,255 +0,0 @@
package main
import (
"flag"
"fmt"
"go/build"
"io"
"log"
"os"
"path/filepath"
"runtime/pprof"
"strings"
"text/template"
)
var (
cpuprofile string
verbose bool // Verbose flag for commands that support it
debug bool // Debug flag for commands that support it
majorGoVersion string
VendorExperiment bool
sep string
)
// Command is an implementation of a godep command
// like godep save or godep go.
type Command struct {
// Run runs the command.
// The args are the arguments after the command name.
Run func(cmd *Command, args []string)
// Name of the command
Name string
// Args the command would expect
Args string
// Short is the short description shown in the 'godep help' output.
Short string
// Long is the long message shown in the
// 'godep help <this-command>' output.
Long string
// Flag is a set of flags specific to this command.
Flag flag.FlagSet
// OnlyInGOPATH limits this command to being run only while inside of a GOPATH
OnlyInGOPATH bool
}
// UsageExit prints usage information and exits.
func (c *Command) UsageExit() {
fmt.Fprintf(os.Stderr, "Args: godep %s [-v] [-d] %s\n\n", c.Name, c.Args)
fmt.Fprintf(os.Stderr, "Run 'godep help %s' for help.\n", c.Name)
os.Exit(2)
}
// Commands lists the available commands and help topics.
// The order here is the order in which they are printed
// by 'godep help'.
var commands = []*Command{
cmdSave,
cmdGo,
cmdGet,
cmdPath,
cmdRestore,
cmdUpdate,
cmdDiff,
cmdVersion,
}
// VendorExperiment is the Go 1.5 vendor directory experiment flag, see
// https://github.com/golang/go/commit/183cc0cd41f06f83cb7a2490a499e3f9101befff
// Honor the env var unless the project already has an old school godep workspace
func determineVendor(v string) bool {
go15ve := os.Getenv("GO15VENDOREXPERIMENT")
var ev bool
switch v {
case "go1", "go1.1", "go1.2", "go1.3", "go1.4":
ev = false
case "go1.5":
ev = go15ve == "1"
case "go1.6":
ev = go15ve != "0"
default: //go1.7+, devel*
ev = true
}
ws := filepath.Join("Godeps", "_workspace")
s, err := os.Stat(ws)
if err == nil && s.IsDir() {
log.Printf("WARNING: Godep workspaces (./Godeps/_workspace) are deprecated and support for them will be removed when go1.8 is released.")
if ev {
log.Printf("WARNING: Go version (%s) & $GO15VENDOREXPERIMENT=%s wants to enable the vendor experiment, but disabling because a Godep workspace (%s) exists\n", v, go15ve, ws)
}
return false
}
return ev
}
func main() {
log.SetFlags(0)
log.SetPrefix("godep: ")
log.SetOutput(os.Stderr)
flag.Usage = usageExit
flag.Parse()
args := flag.Args()
if len(args) < 1 {
usageExit()
}
if args[0] == "help" {
help(args[1:])
return
}
var err error
majorGoVersion, err = goVersion()
if err != nil {
log.Fatal(err)
}
for _, cmd := range commands {
if cmd.Name == args[0] {
if cmd.OnlyInGOPATH {
checkInGOPATH()
}
VendorExperiment = determineVendor(majorGoVersion)
// sep is the signature set of path elements that
// precede the original path of an imported package.
sep = defaultSep(VendorExperiment)
cmd.Flag.BoolVar(&verbose, "v", false, "enable verbose output")
cmd.Flag.BoolVar(&debug, "d", false, "enable debug output")
cmd.Flag.StringVar(&cpuprofile, "cpuprofile", "", "Write cpu profile to this file")
cmd.Flag.Usage = func() { cmd.UsageExit() }
cmd.Flag.Parse(args[1:])
debugln("versionString()", versionString())
debugln("majorGoVersion", majorGoVersion)
debugln("VendorExperiment", VendorExperiment)
debugln("sep", sep)
if cpuprofile != "" {
f, err := os.Create(cpuprofile)
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
cmd.Run(cmd, cmd.Flag.Args())
return
}
}
fmt.Fprintf(os.Stderr, "godep: unknown command %q\n", args[0])
fmt.Fprintf(os.Stderr, "Run 'godep help' for usage.\n")
os.Exit(2)
}
func subPath(sub, path string) bool {
ls := strings.ToLower(sub)
lp := strings.ToLower(path)
if ls == lp {
return false
}
return strings.HasPrefix(ls, lp)
}
func checkInGOPATH() {
pwd, err := os.Getwd()
if err != nil {
log.Fatal("Unable to determine current working directory", err)
}
dirs := build.Default.SrcDirs()
for _, p := range dirs {
if ok := subPath(pwd, p); ok {
return
}
}
log.Println("[WARNING]: godep should only be used inside a valid go package directory and")
log.Println("[WARNING]: may not function correctly. You are probably outside of your $GOPATH.")
log.Printf("[WARNING]:\tCurrent Directory: %s\n", pwd)
log.Printf("[WARNING]:\t$GOPATH: %s\n", os.Getenv("GOPATH"))
}
var usageTemplate = `
Godep is a tool for managing Go package dependencies.
Usage:
godep command [arguments]
The commands are:
{{range .}}
{{.Name | printf "%-8s"}} {{.Short}}{{end}}
Use "godep help [command]" for more information about a command.
`
var helpTemplate = `
Args: godep {{.Name}} [-v] [-d] {{.Args}}
{{.Long | trim}}
If -v is given, verbose output is enabled.
If -d is given, debug output is enabled (you probably don't want this, see -v).
`
func help(args []string) {
if len(args) == 0 {
printUsage(os.Stdout)
return
}
if len(args) != 1 {
fmt.Fprintf(os.Stderr, "usage: godep help command\n\n")
fmt.Fprintf(os.Stderr, "Too many arguments given.\n")
os.Exit(2)
}
for _, cmd := range commands {
if cmd.Name == args[0] {
tmpl(os.Stdout, helpTemplate, cmd)
return
}
}
}
func usageExit() {
printUsage(os.Stderr)
os.Exit(2)
}
func printUsage(w io.Writer) {
tmpl(w, usageTemplate, commands)
}
// tmpl executes the given template text on data, writing the result to w.
func tmpl(w io.Writer, text string, data interface{}) {
t := template.New("top")
t.Funcs(template.FuncMap{
"trim": strings.TrimSpace,
})
template.Must(t.Parse(strings.TrimSpace(text) + "\n\n"))
if err := t.Execute(w, data); err != nil {
panic(err)
}
}

View File

@ -1,35 +0,0 @@
package main
import (
"fmt"
"log"
"github.com/kr/pretty"
)
func debugln(a ...interface{}) (int, error) {
if debug {
return fmt.Println(a...)
}
return 0, nil
}
func verboseln(a ...interface{}) {
if verbose {
log.Println(a...)
}
}
func debugf(format string, a ...interface{}) (int, error) {
if debug {
return fmt.Printf(format, a...)
}
return 0, nil
}
func ppln(a ...interface{}) (int, error) {
if debug {
return pretty.Println(a...)
}
return 0, nil
}

View File

@ -1,36 +0,0 @@
package main
import (
"fmt"
"os"
)
var cmdPath = &Command{
Name: "path",
Short: "print GOPATH for dependency code",
Long: `
Command path prints a path for use in env var GOPATH
that makes available the specified version of each dependency.
The printed path does not include any GOPATH value from
the environment.
For more about how GOPATH works, see 'go help gopath'.
`,
Run: runPath,
OnlyInGOPATH: true,
}
// Print the gopath that points to
// the included dependency code.
func runPath(cmd *Command, args []string) {
if len(args) != 0 {
cmd.UsageExit()
}
if VendorExperiment {
fmt.Fprintln(os.Stderr, "Error: GO15VENDOREXPERIMENT is enabled and the vendor/ directory is not a valid Go workspace.")
os.Exit(1)
}
gopath := prepareGopath()
fmt.Println(gopath)
}

View File

@ -1,94 +0,0 @@
package main
import (
"fmt"
"go/build"
"os"
"regexp"
"sort"
"strings"
)
// Package represents a Go package.
type Package struct {
Dir string
Root string
ImportPath string
Deps []string
Standard bool
Processed bool
GoFiles []string
CgoFiles []string
IgnoredGoFiles []string
TestGoFiles []string
TestImports []string
XTestGoFiles []string
XTestImports []string
Error struct {
Err string
}
// --- New stuff for now
Imports []string
Dependencies []build.Package
}
// LoadPackages loads the named packages
// Unlike the go tool, an empty argument list is treated as an empty list; "."
// must be given explicitly if desired.
// IgnoredGoFiles will be processed and their dependencies resolved recursively
func LoadPackages(names ...string) (a []*Package, err error) {
debugln("LoadPackages", names)
if len(names) == 0 {
return nil, nil
}
pkgs := strings.Split(ignorePackages, ",")
sort.Strings(pkgs)
for _, i := range importPaths(names) {
p, err := listPackage(i)
if err != nil {
if len(pkgs) > 0 {
idx := sort.SearchStrings(pkgs, i)
if idx < len(pkgs) && pkgs[idx] == i {
fmt.Fprintf(os.Stderr, "warning: ignoring package %q \n", i)
continue
}
}
return nil, err
}
a = append(a, p)
}
return a, nil
}
func (p *Package) allGoFiles() []string {
var a []string
a = append(a, p.GoFiles...)
a = append(a, p.CgoFiles...)
a = append(a, p.TestGoFiles...)
a = append(a, p.XTestGoFiles...)
a = append(a, p.IgnoredGoFiles...)
return a
}
// matchPattern(pattern)(name) reports whether
// name matches pattern. Pattern is a limited glob
// pattern in which '...' means 'any string' and there
// is no other special syntax.
// Taken from $GOROOT/src/cmd/go/main.go.
func matchPattern(pattern string) func(name string) bool {
re := regexp.QuoteMeta(pattern)
re = strings.Replace(re, `\.\.\.`, `.*`, -1)
// Special case: foo/... matches foo too.
if strings.HasSuffix(re, `/.*`) {
re = re[:len(re)-len(`/.*`)] + `(/.*)?`
}
reg := regexp.MustCompile(`^` + re + `$`)
return func(name string) bool {
return reg.MatchString(name)
}
}

View File

@ -1,195 +0,0 @@
package main
import (
"errors"
"go/build"
"log"
"os"
"path/filepath"
"golang.org/x/tools/go/vcs"
)
var cmdRestore = &Command{
Name: "restore",
Short: "check out listed dependency versions in GOPATH",
Long: `
Restore checks out the Godeps-specified version of each package in GOPATH.
NOTE: restore leaves git repositories in a detached state. go1.6+ no longer
checks out the master branch when doing a "go get", see:
https://github.com/golang/go/commit/42206598671a44111c8f726ad33dc7b265bdf669.
`,
Run: runRestore,
OnlyInGOPATH: true,
}
// Three phases:
// 1. Download all deps
// 2. Restore all deps (checkout the recorded rev)
// 3. Attempt to load all deps as a simple consistency check
func runRestore(cmd *Command, args []string) {
if len(build.Default.GOPATH) == 0 {
log.Println("Error restore requires GOPATH but it is empty.")
os.Exit(1)
}
var hadError bool
checkErr := func(s string) {
if hadError {
log.Println(s)
os.Exit(1)
}
}
g, err := loadDefaultGodepsFile()
if err != nil {
log.Fatalln(err)
}
for i, dep := range g.Deps {
verboseln("Downloading dependency (if needed):", dep.ImportPath)
err := download(&dep)
if err != nil {
log.Printf("error downloading dep (%s): %s\n", dep.ImportPath, err)
hadError = true
}
g.Deps[i] = dep
}
checkErr("Error downloading some deps. Aborting restore and check.")
for _, dep := range g.Deps {
verboseln("Restoring dependency (if needed):", dep.ImportPath)
err := restore(dep)
if err != nil {
log.Printf("error restoring dep (%s): %s\n", dep.ImportPath, err)
hadError = true
}
}
checkErr("Error restoring some deps. Aborting check.")
for _, dep := range g.Deps {
verboseln("Checking dependency:", dep.ImportPath)
_, err := LoadPackages(dep.ImportPath)
if err != nil {
log.Printf("Dep (%s) restored, but was unable to load it with error:\n\t%s\n", dep.ImportPath, err)
if me, ok := err.(errorMissingDep); ok {
log.Println("\tThis may be because the dependencies were saved with an older version of godep (< v33).")
log.Printf("\tTry `go get %s`. Then `godep save` to update deps.\n", me.i)
}
hadError = true
}
}
checkErr("Error checking some deps.")
}
var downloaded = make(map[string]bool)
// download the given dependency.
// 2 Passes: 1) go get -d <pkg>, 2) git pull (if necessary)
func download(dep *Dependency) error {
rr, err := vcs.RepoRootForImportPath(dep.ImportPath, debug)
if err != nil {
debugln("Error determining repo root for", dep.ImportPath)
return err
}
ppln("rr", rr)
dep.vcs = cmd[rr.VCS]
// try to find an existing directory in the GOPATHs
for _, gp := range filepath.SplitList(build.Default.GOPATH) {
t := filepath.Join(gp, "src", rr.Root)
fi, err := os.Stat(t)
if err != nil {
continue
}
if fi.IsDir() {
dep.root = t
break
}
}
// If none found, just pick the first GOPATH entry (AFAICT that's what go get does)
if dep.root == "" {
dep.root = filepath.Join(filepath.SplitList(build.Default.GOPATH)[0], "src", rr.Root)
}
ppln("dep", dep)
if downloaded[rr.Repo] {
verboseln("Skipping already downloaded repo", rr.Repo)
return nil
}
fi, err := os.Stat(dep.root)
if err != nil {
if os.IsNotExist(err) {
if err := os.MkdirAll(filepath.Dir(dep.root), os.ModePerm); err != nil {
debugln("Error creating base dir of", dep.root)
return err
}
err := rr.VCS.CreateAtRev(dep.root, rr.Repo, dep.Rev)
debugln("CreatedAtRev", dep.root, rr.Repo, dep.Rev)
if err != nil {
debugln("CreateAtRev error", err)
return err
}
downloaded[rr.Repo] = true
return nil
}
debugln("Error checking repo root for", dep.ImportPath, "at", dep.root, ":", err)
return err
}
if !fi.IsDir() {
return errors.New("repo root src dir exists, but isn't a directory for " + dep.ImportPath + " at " + dep.root)
}
if !dep.vcs.exists(dep.root, dep.Rev) {
debugln("Updating existing", dep.root)
if dep.vcs == vcsGit {
detached, err := gitDetached(dep.root)
if err != nil {
return err
}
if detached {
db, err := gitDefaultBranch(dep.root)
if err != nil {
return err
}
if err := gitCheckout(dep.root, db); err != nil {
return err
}
}
}
dep.vcs.vcs.Download(dep.root)
downloaded[rr.Repo] = true
}
debugln("Nothing to download")
return nil
}
var restored = make(map[string]string) // dep.root -> dep.Rev
// restore checks out the given revision.
func restore(dep Dependency) error {
rev, ok := restored[dep.root]
debugln(rev)
debugln(ok)
debugln(dep.root)
if ok {
if rev != dep.Rev {
return errors.New("Wanted to restore rev " + dep.Rev + ", already restored rev " + rev + " for another package in the repo")
}
verboseln("Skipping already restored repo")
return nil
}
debugln("Restoring:", dep.ImportPath, dep.Rev)
err := dep.vcs.RevSync(dep.root, dep.Rev)
if err == nil {
restored[dep.root] = dep.Rev
}
return err
}

View File

@ -1,171 +0,0 @@
package main
import (
"bytes"
"log"
"os"
"path/filepath"
"strconv"
"strings"
"go/ast"
"go/parser"
"go/printer"
"go/token"
"github.com/kr/fs"
)
// rewrite visits the go files in pkgs, plus all go files
// in the directory tree Godeps, rewriting import statements
// according to the rules for func qualify.
func rewrite(pkgs []*Package, qual string, paths []string) error {
for _, path := range pkgFiles(pkgs) {
debugln("rewrite", path)
err := rewriteTree(path, qual, paths)
if err != nil {
return err
}
}
return rewriteTree("Godeps", qual, paths)
}
// pkgFiles returns the full filesystem path to all go files in pkgs.
func pkgFiles(pkgs []*Package) []string {
var a []string
for _, pkg := range pkgs {
for _, s := range pkg.allGoFiles() {
a = append(a, filepath.Join(pkg.Dir, s))
}
}
return a
}
// rewriteTree recursively visits the go files in path, rewriting
// import statements according to the rules for func qualify.
// This function ignores the 'testdata' directory.
func rewriteTree(path, qual string, paths []string) error {
w := fs.Walk(path)
for w.Step() {
if w.Err() != nil {
log.Println("rewrite:", w.Err())
continue
}
s := w.Stat()
if s.IsDir() && s.Name() == "testdata" {
w.SkipDir()
continue
}
if strings.HasSuffix(w.Path(), ".go") {
err := rewriteGoFile(w.Path(), qual, paths)
if err != nil {
return err
}
}
}
return nil
}
// rewriteGoFile rewrites import statements in the named file
// according to the rules for func qualify.
func rewriteGoFile(name, qual string, paths []string) error {
debugln("rewriteGoFile", name, ",", qual, ",", paths)
printerConfig := &printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, name, nil, parser.ParseComments)
if err != nil {
return err
}
var changed bool
for _, s := range f.Imports {
name, err := strconv.Unquote(s.Path.Value)
if err != nil {
return err // can't happen
}
q := qualify(unqualify(name), qual, paths)
if q != name {
s.Path.Value = strconv.Quote(q)
changed = true
}
}
if !changed {
return nil
}
var buffer bytes.Buffer
if err = printerConfig.Fprint(&buffer, fset, f); err != nil {
return err
}
fset = token.NewFileSet()
f, err = parser.ParseFile(fset, name, &buffer, parser.ParseComments)
if err != nil {
return err
}
ast.SortImports(fset, f)
tpath := name + ".temp"
t, err := os.Create(tpath)
if err != nil {
return err
}
if err = printerConfig.Fprint(t, fset, f); err != nil {
return err
}
if err = t.Close(); err != nil {
return err
}
// This is required before the rename on windows.
if err = os.Remove(name); err != nil {
return err
}
return os.Rename(tpath, name)
}
func defaultSep(experiment bool) string {
if experiment {
return "/vendor/"
}
return "/Godeps/_workspace/src/"
}
func relativeVendorTarget(experiment bool) string {
full := defaultSep(experiment)
if full[0] == '/' {
full = full[1:]
}
return filepath.FromSlash(full)
}
// unqualify returns the part of importPath after the last
// occurrence of the signature path elements
// (Godeps/_workspace/src) that always precede imported
// packages in rewritten import paths.
//
// For example,
// unqualify(C) = C
// unqualify(D/Godeps/_workspace/src/C) = C
func unqualify(importPath string) string {
if i := strings.LastIndex(importPath, sep); i != -1 {
importPath = importPath[i+len(sep):]
}
return importPath
}
// qualify qualifies importPath with its corresponding import
// path in the Godeps src copy of package pkg. If importPath
// is a directory lexically contained in a path in paths,
// it will be qualified with package pkg; otherwise, it will
// be returned unchanged.
//
// For example, given paths {D, T} and pkg C,
// importPath returns
// C C
// fmt fmt
// D C/Godeps/_workspace/src/D
// D/P C/Godeps/_workspace/src/D/P
// T C/Godeps/_workspace/src/T
func qualify(importPath, pkg string, paths []string) string {
if containsPathPrefix(paths, importPath) {
return pkg + sep + importPath
}
return importPath
}

View File

@ -1,613 +0,0 @@
package main
import (
"bufio"
"bytes"
"errors"
"fmt"
"go/build"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/kr/fs"
)
var cmdSave = &Command{
Name: "save",
Args: "[-r] [-t] [packages]",
Short: "list and copy dependencies into Godeps",
Long: `
Save writes a list of the named packages and their dependencies along
with the exact source control revision of each package, and copies
their source code into a subdirectory. Packages inside "." are excluded
from the list to be copied.
The list is written to Godeps/Godeps.json, and source code for all
dependencies is copied into either Godeps/_workspace or, if the vendor
experiment is turned on, vendor/.
The dependency list is a JSON document with the following structure:
type Godeps struct {
ImportPath string
GoVersion string // Abridged output of 'go version'.
Packages []string // Arguments to godep save, if any.
Deps []struct {
ImportPath string
Comment string // Tag or description of commit.
Rev string // VCS-specific commit ID.
}
}
Any packages already present in the list will be left unchanged.
To update a dependency to a newer revision, use 'godep update'.
If -r is given, import statements will be rewritten to refer directly
to the copied source code. This is not compatible with the vendor
experiment. Note that this will not rewrite the statements in the
files outside the project.
If -t is given, test files (*_test.go files + testdata directories) are
also saved.
For more about specifying packages, see 'go help packages'.
`,
Run: runSave,
OnlyInGOPATH: true,
}
var (
saveR, saveT bool
ignorePackages string
)
func init() {
cmdSave.Flag.BoolVar(&saveR, "r", false, "rewrite import paths")
cmdSave.Flag.BoolVar(&saveT, "t", false, "save test files")
cmdSave.Flag.StringVar(&ignorePackages, "i", "", "list of packages to ignore separated by commas")
}
func runSave(cmd *Command, args []string) {
if VendorExperiment && saveR {
log.Println("flag -r is incompatible with the vendoring experiment")
cmd.UsageExit()
}
err := save(args)
if err != nil {
log.Fatalln(err)
}
}
func dotPackage() (*build.Package, error) {
dir, err := filepath.Abs(".")
if err != nil {
return nil, err
}
return build.ImportDir(dir, build.FindOnly)
}
func projectPackages(dDir string, a []*Package) []*Package {
var projPkgs []*Package
dotDir := fmt.Sprintf("%s%c", dDir, filepath.Separator)
for _, p := range a {
pkgDir := fmt.Sprintf("%s%c", p.Dir, filepath.Separator)
if strings.HasPrefix(pkgDir, dotDir) {
projPkgs = append(projPkgs, p)
}
}
return projPkgs
}
func save(pkgs []string) error {
var err error
dp, err := dotPackage()
if err != nil {
return err
}
debugln("dotPackageImportPath:", dp.ImportPath)
debugln("dotPackageDir:", dp.Dir)
cv, err := goVersion()
if err != nil {
return err
}
verboseln("Go Version:", cv)
gold, err := loadDefaultGodepsFile()
if err != nil {
if !os.IsNotExist(err) {
return err
}
verboseln("No old Godeps.json found.")
gold.GoVersion = cv
}
printVersionWarnings(gold.GoVersion)
if len(gold.GoVersion) == 0 {
gold.GoVersion = majorGoVersion
} else {
majorGoVersion, err = trimGoVersion(gold.GoVersion)
if err != nil {
log.Fatalf("Unable to determine go major version from value specified in %s: %s\n", gold.file(), gold.GoVersion)
}
}
gnew := &Godeps{
ImportPath: dp.ImportPath,
GoVersion: gold.GoVersion,
}
switch len(pkgs) {
case 0:
pkgs = []string{"."}
default:
gnew.Packages = pkgs
}
verboseln("Finding dependencies for", pkgs)
a, err := LoadPackages(pkgs...)
if err != nil {
return err
}
for _, p := range a {
verboseln("Found package:", p.ImportPath)
verboseln("\tDeps:", strings.Join(p.Deps, " "))
}
ppln(a)
projA := projectPackages(dp.Dir, a)
debugln("Filtered projectPackages")
ppln(projA)
verboseln("Computing new Godeps.json file")
err = gnew.fill(a, dp.ImportPath)
if err != nil {
return err
}
debugln("New Godeps Filled")
ppln(gnew)
if gnew.Deps == nil {
gnew.Deps = make([]Dependency, 0) // produce json [], not null
}
gdisk := gnew.copy()
err = carryVersions(&gold, gnew)
if err != nil {
return err
}
if gold.isOldFile {
// If we are migrating from an old format file,
// we require that the listed version of every
// dependency must be installed in GOPATH, so it's
// available to copy.
if !eqDeps(gnew.Deps, gdisk.Deps) {
return errors.New(strings.TrimSpace(needRestore))
}
gold = Godeps{}
}
os.Remove("Godeps") // remove regular file if present; ignore error
readme := filepath.Join("Godeps", "Readme")
err = writeFile(readme, strings.TrimSpace(Readme)+"\n")
if err != nil {
log.Println(err)
}
_, err = gnew.save()
if err != nil {
return err
}
verboseln("Computing diff between old and new deps")
// We use a name starting with "_" so the go tool
// ignores this directory when traversing packages
// starting at the project's root. For example,
// godep go list ./...
srcdir := filepath.FromSlash(strings.Trim(sep, "/"))
rem := subDeps(gold.Deps, gnew.Deps)
ppln(rem)
add := subDeps(gnew.Deps, gold.Deps)
ppln(add)
if len(rem) > 0 {
verboseln("Deps to remove:")
for _, r := range rem {
verboseln("\t", r.ImportPath)
}
verboseln("Removing unused dependencies")
err = removeSrc(srcdir, rem)
if err != nil {
return err
}
}
if len(add) > 0 {
verboseln("Deps to add:")
for _, a := range add {
verboseln("\t", a.ImportPath)
}
verboseln("Adding new dependencies")
err = copySrc(srcdir, add)
if err != nil {
return err
}
}
if !VendorExperiment {
f, _ := filepath.Split(srcdir)
writeVCSIgnore(f)
}
var rewritePaths []string
if saveR {
for _, dep := range gnew.Deps {
rewritePaths = append(rewritePaths, dep.ImportPath)
}
}
verboseln("Rewriting paths (if necessary)")
ppln(rewritePaths)
return rewrite(projA, dp.ImportPath, rewritePaths)
}
func printVersionWarnings(ov string) {
var warning bool
cv, err := goVersion()
if err != nil {
return
}
// Trim the old version because we may have saved it w/o trimming it
// cv is already trimmed by goVersion()
tov, err := trimGoVersion(ov)
if err != nil {
return
}
if tov != ov {
log.Printf("WARNING: Recorded go version (%s) with minor version string found.\n", ov)
warning = true
}
if cv != tov {
log.Printf("WARNING: Recorded major go version (%s) and in-use major go version (%s) differ.\n", tov, cv)
warning = true
}
if warning {
log.Println("To record current major go version run `godep update -goversion`.")
}
}
type revError struct {
ImportPath string
WantRev string
HavePath string
HaveRev string
}
func (v *revError) Error() string {
return fmt.Sprintf("cannot save %s at revision %s: already have %s at revision %s.\n"+
"Run `godep update %s' first.", v.ImportPath, v.WantRev, v.HavePath, v.HaveRev, v.HavePath)
}
// carryVersions copies Rev and Comment from a to b for
// each dependency with an identical ImportPath. For any
// dependency in b that appears to be from the same repo
// as one in a (for example, a parent or child directory),
// the Rev must already match - otherwise it is an error.
func carryVersions(a, b *Godeps) error {
for i := range b.Deps {
err := carryVersion(a, &b.Deps[i])
if err != nil {
return err
}
}
return nil
}
func carryVersion(a *Godeps, db *Dependency) error {
// First see if this exact package is already in the list.
for _, da := range a.Deps {
if db.ImportPath == da.ImportPath {
db.Rev = da.Rev
db.Comment = da.Comment
return nil
}
}
// No exact match, check for child or sibling package.
// We can't handle mismatched versions for packages in
// the same repo, so report that as an error.
for _, da := range a.Deps {
if strings.HasPrefix(db.ImportPath, da.ImportPath+"/") ||
strings.HasPrefix(da.ImportPath, db.root+"/") {
if da.Rev != db.Rev {
return &revError{
ImportPath: db.ImportPath,
WantRev: db.Rev,
HavePath: da.ImportPath,
HaveRev: da.Rev,
}
}
}
}
// No related package in the list, must be a new repo.
return nil
}
// subDeps returns a - b, using ImportPath for equality.
func subDeps(a, b []Dependency) (diff []Dependency) {
Diff:
for _, da := range a {
for _, db := range b {
if da.ImportPath == db.ImportPath {
continue Diff
}
}
diff = append(diff, da)
}
return diff
}
func removeSrc(srcdir string, deps []Dependency) error {
for _, dep := range deps {
path := filepath.FromSlash(dep.ImportPath)
err := os.RemoveAll(filepath.Join(srcdir, path))
if err != nil {
return err
}
}
return nil
}
func copySrc(dir string, deps []Dependency) error {
// mapping to see if we visited a parent directory already
visited := make(map[string]bool)
ok := true
for _, dep := range deps {
debugln("copySrc for", dep.ImportPath)
srcdir := filepath.Join(dep.ws, "src")
rel, err := filepath.Rel(srcdir, dep.dir)
debugln("srcdir", srcdir)
debugln("rel", rel)
debugln("err", err)
if err != nil { // this should never happen
return err
}
dstpkgroot := filepath.Join(dir, rel)
err = os.RemoveAll(dstpkgroot)
if err != nil {
log.Println(err)
ok = false
}
// copy actual dependency
vf := dep.vcs.listFiles(dep.dir)
debugln("vf", vf)
w := fs.Walk(dep.dir)
for w.Step() {
err = copyPkgFile(vf, dir, srcdir, w)
if err != nil {
log.Println(err)
ok = false
}
}
// Look for legal files in root
// some packages are imports as a sub-package but license info
// is at root: exampleorg/common has license file in exampleorg
//
if dep.ImportPath == dep.root {
// we are already at root
continue
}
// prevent copying twice This could happen if we have
// two subpackages listed someorg/common and
// someorg/anotherpack which has their license in
// the parent dir of someorg
rootdir := filepath.Join(srcdir, filepath.FromSlash(dep.root))
if visited[rootdir] {
continue
}
visited[rootdir] = true
vf = dep.vcs.listFiles(rootdir)
w = fs.Walk(rootdir)
for w.Step() {
fname := filepath.Base(w.Path())
if IsLegalFile(fname) && !strings.Contains(w.Path(), sep) {
err = copyPkgFile(vf, dir, srcdir, w)
if err != nil {
log.Println(err)
ok = false
}
}
}
}
if !ok {
return errorCopyingSourceCode
}
return nil
}
func copyPkgFile(vf vcsFiles, dstroot, srcroot string, w *fs.Walker) error {
if w.Err() != nil {
return w.Err()
}
name := w.Stat().Name()
if w.Stat().IsDir() {
if name[0] == '.' || name[0] == '_' || (!saveT && name == "testdata") {
// Skip directories starting with '.' or '_' or
// 'testdata' (last is only skipped if saveT is false)
w.SkipDir()
}
return nil
}
rel, err := filepath.Rel(srcroot, w.Path())
if err != nil { // this should never happen
return err
}
if !saveT && strings.HasSuffix(name, "_test.go") {
if verbose {
log.Printf("save: skipping test file: %s", w.Path())
}
return nil
}
if !vf.Contains(w.Path()) {
if verbose {
log.Printf("save: skipping untracked file: %s", w.Path())
}
return nil
}
return copyFile(filepath.Join(dstroot, rel), w.Path())
}
// copyFile copies a regular file from src to dst.
// dst is opened with os.Create.
// If the file name ends with .go,
// copyFile strips canonical import path annotations.
// These are comments of the form:
// package foo // import "bar/foo"
// package foo /* import "bar/foo" */
func copyFile(dst, src string) error {
err := os.MkdirAll(filepath.Dir(dst), 0777)
if err != nil {
return err
}
linkDst, err := os.Readlink(src)
if err == nil {
return os.Symlink(linkDst, dst)
}
si, err := stat(src)
if err != nil {
return err
}
r, err := os.Open(src)
if err != nil {
return err
}
defer r.Close()
w, err := os.Create(dst)
if err != nil {
return err
}
if err := os.Chmod(dst, si.Mode()); err != nil {
return err
}
if strings.HasSuffix(dst, ".go") {
debugln("Copy Without Import Comment", w, r)
err = copyWithoutImportComment(w, r)
} else {
debugln("Copy (plain)", w, r)
_, err = io.Copy(w, r)
}
err1 := w.Close()
if err == nil {
err = err1
}
return err
}
func copyWithoutImportComment(w io.Writer, r io.Reader) error {
b := bufio.NewReader(r)
for {
l, err := b.ReadBytes('\n')
eof := err == io.EOF
if err != nil && err != io.EOF {
return err
}
// If we have data then write it out...
if len(l) > 0 {
// Strip off \n if it exists because stripImportComment
_, err := w.Write(append(stripImportComment(bytes.TrimRight(l, "\n")), '\n'))
if err != nil {
return err
}
}
if eof {
return nil
}
}
}
const (
importAnnotation = `import\s+(?:"[^"]*"|` + "`[^`]*`" + `)`
importComment = `(?://\s*` + importAnnotation + `\s*$|/\*\s*` + importAnnotation + `\s*\*/)`
)
var (
importCommentRE = regexp.MustCompile(`^\s*(package\s+\w+)\s+` + importComment + `(.*)`)
pkgPrefix = []byte("package ")
)
// stripImportComment returns line with its import comment removed.
// If s is not a package statement containing an import comment,
// it is returned unaltered.
// FIXME: expects lines w/o a \n at the end
// See also http://golang.org/s/go14customimport.
func stripImportComment(line []byte) []byte {
if !bytes.HasPrefix(line, pkgPrefix) {
// Fast path; this will skip all but one line in the file.
// This assumes there is no whitespace before the keyword.
return line
}
if m := importCommentRE.FindSubmatch(line); m != nil {
return append(m[1], m[2]...)
}
return line
}
// Func writeVCSIgnore writes "ignore" files inside dir for known VCSs,
// so that dir/pkg and dir/bin don't accidentally get committed.
// It logs any errors it encounters.
func writeVCSIgnore(dir string) {
// Currently git is the only VCS for which we know how to do this.
// Mercurial and Bazaar have similar mechanisms, but they apparently
// require writing files outside of dir.
const ignore = "/pkg\n/bin\n"
name := filepath.Join(dir, ".gitignore")
err := writeFile(name, ignore)
if err != nil {
log.Println(err)
}
}
// writeFile is like ioutil.WriteFile but it creates
// intermediate directories with os.MkdirAll.
func writeFile(name, body string) error {
err := os.MkdirAll(filepath.Dir(name), 0777)
if err != nil {
return err
}
return ioutil.WriteFile(name, []byte(body), 0666)
}
const (
// Readme contains the README text.
Readme = `
This directory tree is generated automatically by godep.
Please do not edit.
See https://github.com/tools/godep for more information.
`
needRestore = `
mismatched versions while migrating
It looks like you are switching from the old Godeps format
(from flag -copy=false). The old format is just a file; it
doesn't contain source code. For this migration, godep needs
the appropriate version of each dependency to be installed in
GOPATH, so that the source code is available to copy.
To fix this, run 'godep restore'.
`
)

View File

@ -1,292 +0,0 @@
package main
import (
"go/parser"
"go/token"
"log"
"os"
"path"
"path/filepath"
"strconv"
"strings"
)
var cmdUpdate = &Command{
Name: "update",
Args: "[-goversion] [packages]",
Short: "update selected packages or the go version",
Long: `
Update changes the named dependency packages to use the
revision of each currently installed in GOPATH. New code will
be copied into the Godeps workspace or vendor folder and the
new revision will be written to the manifest.
If -goversion is specified, update the recorded go version.
For more about specifying packages, see 'go help packages'.
`,
Run: runUpdate,
OnlyInGOPATH: true,
}
var (
updateGoVer bool
)
func init() {
cmdUpdate.Flag.BoolVar(&saveT, "t", false, "save test files during update")
cmdUpdate.Flag.BoolVar(&updateGoVer, "goversion", false, "update the recorded go version")
}
func runUpdate(cmd *Command, args []string) {
if updateGoVer {
err := updateGoVersion()
if err != nil {
log.Fatalln(err)
}
}
if len(args) > 0 {
err := update(args)
if err != nil {
log.Fatalln(err)
}
}
}
func updateGoVersion() error {
gold, err := loadDefaultGodepsFile()
if err != nil {
if !os.IsNotExist(err) {
return err
}
}
cv, err := goVersion()
if err != nil {
return err
}
gv := gold.GoVersion
gold.GoVersion = cv
_, err = gold.save()
if err != nil {
return err
}
if gv != cv {
log.Println("Updated major go version to", cv)
}
return nil
}
func update(args []string) error {
if len(args) == 0 {
args = []string{"."}
}
g, err := loadDefaultGodepsFile()
if err != nil {
return err
}
for _, arg := range args {
arg := path.Clean(arg)
any := markMatches(arg, g.Deps)
if !any {
log.Println("not in manifest:", arg)
}
}
deps, rdeps, err := LoadVCSAndUpdate(g.Deps)
if err != nil {
return err
}
if len(deps) == 0 {
return errorNoPackagesUpdatable
}
g.addOrUpdateDeps(deps)
g.removeDeps(rdeps)
if _, err = g.save(); err != nil {
return err
}
srcdir := relativeVendorTarget(VendorExperiment)
if err := removeSrc(filepath.FromSlash(strings.Trim(sep, "/")), rdeps); err != nil {
return err
}
copySrc(srcdir, deps)
ok, err := needRewrite(g.Packages)
if err != nil {
return err
}
var rewritePaths []string
if ok {
for _, dep := range g.Deps {
rewritePaths = append(rewritePaths, dep.ImportPath)
}
}
return rewrite(nil, g.ImportPath, rewritePaths)
}
func needRewrite(importPaths []string) (bool, error) {
if len(importPaths) == 0 {
importPaths = []string{"."}
}
a, err := LoadPackages(importPaths...)
if err != nil {
return false, err
}
for _, p := range a {
for _, name := range p.allGoFiles() {
path := filepath.Join(p.Dir, name)
hasSep, err := hasRewrittenImportStatement(path)
if err != nil {
return false, err
}
if hasSep {
return true, nil
}
}
}
return false, nil
}
func hasRewrittenImportStatement(path string) (bool, error) {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, path, nil, 0)
if err != nil {
return false, err
}
for _, s := range f.Imports {
name, _ := strconv.Unquote(s.Path.Value)
if strings.Contains(name, sep) {
return true, nil
}
}
return false, nil
}
// markMatches marks each entry in deps with an import path that
// matches pat. It returns whether any matches occurred.
func markMatches(pat string, deps []Dependency) (matched bool) {
f := matchPattern(pat)
for i, dep := range deps {
if f(dep.ImportPath) {
deps[i].matched = true
matched = true
}
}
return matched
}
func fillDeps(deps []Dependency) ([]Dependency, error) {
for i := range deps {
if deps[i].pkg != nil {
continue
}
ps, err := LoadPackages(deps[i].ImportPath)
if err != nil {
if _, ok := err.(errPackageNotFound); ok {
deps[i].missing = true
continue
}
return nil, err
}
if len(ps) > 1 {
panic("More than one package found for " + deps[i].ImportPath)
}
p := ps[0]
deps[i].pkg = p
deps[i].dir = p.Dir
deps[i].ws = p.Root
vcs, reporoot, err := VCSFromDir(p.Dir, filepath.Join(p.Root, "src"))
if err != nil {
return nil, errorLoadingDeps
}
deps[i].root = filepath.ToSlash(reporoot)
deps[i].vcs = vcs
}
return deps, nil
}
// LoadVCSAndUpdate loads and updates a set of dependencies.
func LoadVCSAndUpdate(deps []Dependency) ([]Dependency, []Dependency, error) {
var err1 error
deps, err := fillDeps(deps)
if err != nil {
return nil, nil, err
}
repoMask := make(map[string]bool)
for i := range deps {
if !deps[i].matched {
repoMask[deps[i].root] = true
}
}
// Determine if we need any new packages because of new transitive imports
for _, dep := range deps {
if !dep.matched || dep.missing {
continue
}
for _, dp := range dep.pkg.Dependencies {
if dp.Goroot {
continue
}
var have bool
for _, d := range deps {
if d.ImportPath == dp.ImportPath {
have = true
break
}
}
if !have {
deps = append(deps, Dependency{ImportPath: dp.ImportPath, matched: true})
}
}
}
deps, err = fillDeps(deps)
if err != nil {
return nil, nil, err
}
var toUpdate, toRemove []Dependency
for _, d := range deps {
if !d.matched || repoMask[d.root] {
continue
}
if d.missing {
toRemove = append(toRemove, d)
continue
}
toUpdate = append(toUpdate, d)
}
debugln("toUpdate")
ppln(toUpdate)
var toCopy []Dependency
for _, d := range toUpdate {
id, err := d.vcs.identify(d.dir)
if err != nil {
log.Println(err)
err1 = errorLoadingDeps
continue
}
if d.vcs.isDirty(d.dir, id) {
log.Println("dirty working tree (please commit changes):", d.dir)
}
d.Rev = id
d.Comment = d.vcs.describe(d.dir, id)
toCopy = append(toCopy, d)
}
debugln("toCopy")
ppln(toCopy)
if err1 != nil {
return nil, nil, err1
}
return toCopy, toRemove, nil
}

View File

@ -1,36 +0,0 @@
package main
import (
"path/filepath"
"runtime"
"strings"
)
// driveLetterToUpper converts Windows path's drive letters to uppercase. This
// is needed when comparing 2 paths with different drive letter case.
func driveLetterToUpper(path string) string {
if runtime.GOOS != "windows" || path == "" {
return path
}
p := path
// If path's drive letter is lowercase, change it to uppercase.
if len(p) >= 2 && p[1] == ':' && 'a' <= p[0] && p[0] <= 'z' {
p = string(p[0]+'A'-'a') + p[1:]
}
return p
}
// clean the path and ensure that a drive letter is upper case (if it exists).
func cleanPath(path string) string {
return driveLetterToUpper(filepath.Clean(path))
}
// deal with case insensitive filesystems and other weirdness
func pathEqual(a, b string) bool {
a = cleanPath(a)
b = cleanPath(b)
return strings.EqualFold(a, b)
}

View File

@ -1,293 +0,0 @@
package main
import (
"bytes"
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"golang.org/x/tools/go/vcs"
)
// VCS represents a version control system.
type VCS struct {
vcs *vcs.Cmd
IdentifyCmd string
DescribeCmd string
DiffCmd string
ListCmd string
RootCmd string
// run in sandbox repos
ExistsCmd string
}
var vcsBzr = &VCS{
vcs: vcs.ByCmd("bzr"),
IdentifyCmd: "version-info --custom --template {revision_id}",
DescribeCmd: "revno", // TODO(kr): find tag names if possible
DiffCmd: "diff -r {rev}",
ListCmd: "ls --from-root -R",
RootCmd: "root",
}
var vcsGit = &VCS{
vcs: vcs.ByCmd("git"),
IdentifyCmd: "rev-parse HEAD",
DescribeCmd: "describe --tags --abbrev=14",
DiffCmd: "diff {rev}",
ListCmd: "ls-files --full-name",
RootCmd: "rev-parse --show-cdup",
ExistsCmd: "cat-file -e {rev}",
}
var vcsHg = &VCS{
vcs: vcs.ByCmd("hg"),
IdentifyCmd: "parents --template {node}",
DescribeCmd: "log -r . --template {latesttag}-{latesttagdistance}",
DiffCmd: "diff -r {rev}",
ListCmd: "status --all --no-status",
RootCmd: "root",
ExistsCmd: "cat -r {rev} .",
}
var cmd = map[*vcs.Cmd]*VCS{
vcsBzr.vcs: vcsBzr,
vcsGit.vcs: vcsGit,
vcsHg.vcs: vcsHg,
}
// VCSFromDir returns a VCS value from a directory.
func VCSFromDir(dir, srcRoot string) (*VCS, string, error) {
vcscmd, reporoot, err := vcs.FromDir(dir, srcRoot)
if err != nil {
return nil, "", fmt.Errorf("error while inspecting %q: %v", dir, err)
}
vcsext := cmd[vcscmd]
if vcsext == nil {
return nil, "", fmt.Errorf("%s is unsupported: %s", vcscmd.Name, dir)
}
return vcsext, reporoot, nil
}
func (v *VCS) identify(dir string) (string, error) {
out, err := v.runOutput(dir, v.IdentifyCmd)
return string(bytes.TrimSpace(out)), err
}
func absRoot(dir, out string) string {
if filepath.IsAbs(out) {
return filepath.Clean(out)
}
return filepath.Join(dir, out)
}
func (v *VCS) root(dir string) (string, error) {
out, err := v.runOutput(dir, v.RootCmd)
return absRoot(dir, string(bytes.TrimSpace(out))), err
}
func (v *VCS) describe(dir, rev string) string {
out, err := v.runOutputVerboseOnly(dir, v.DescribeCmd, "rev", rev)
if err != nil {
return ""
}
return string(bytes.TrimSpace(out))
}
func (v *VCS) isDirty(dir, rev string) bool {
out, err := v.runOutput(dir, v.DiffCmd, "rev", rev)
return err != nil || len(out) != 0
}
type vcsFiles map[string]bool
func (vf vcsFiles) Contains(path string) bool {
// Fast path, we have the path
if vf[path] {
return true
}
// Slow path for case insensitive filesystems
// See #310
for f := range vf {
if pathEqual(f, path) {
return true
}
// git's root command (maybe other vcs as well) resolve symlinks, so try that too
// FIXME: rev-parse --show-cdup + extra logic will fix this for git but also need to validate the other vcs commands. This is maybe temporary.
p, err := filepath.EvalSymlinks(path)
if err != nil {
return false
}
if pathEqual(f, p) {
return true
}
}
// No matches by either method
return false
}
// listFiles tracked by the VCS in the repo that contains dir, converted to absolute path.
func (v *VCS) listFiles(dir string) vcsFiles {
root, err := v.root(dir)
debugln("vcs dir", dir)
debugln("vcs root", root)
ppln(v)
if err != nil {
return nil
}
out, err := v.runOutput(dir, v.ListCmd)
if err != nil {
return nil
}
files := make(vcsFiles)
for _, file := range bytes.Split(out, []byte{'\n'}) {
if len(file) > 0 {
path, err := filepath.Abs(filepath.Join(root, string(file)))
if err != nil {
panic(err) // this should not happen
}
if pathEqual(filepath.Dir(path), dir) {
files[path] = true
}
}
}
return files
}
func (v *VCS) exists(dir, rev string) bool {
err := v.runVerboseOnly(dir, v.ExistsCmd, "rev", rev)
return err == nil
}
// RevSync checks out the revision given by rev in dir.
// The dir must exist and rev must be a valid revision.
func (v *VCS) RevSync(dir, rev string) error {
return v.run(dir, v.vcs.TagSyncCmd, "tag", rev)
}
// run runs the command line cmd in the given directory.
// keyval is a list of key, value pairs. run expands
// instances of {key} in cmd into value, but only after
// splitting cmd into individual arguments.
// If an error occurs, run prints the command line and the
// command's combined stdout+stderr to standard error.
// Otherwise run discards the command's output.
func (v *VCS) run(dir string, cmdline string, kv ...string) error {
_, err := v.run1(dir, cmdline, kv, true)
return err
}
// runVerboseOnly is like run but only generates error output to standard error in verbose mode.
func (v *VCS) runVerboseOnly(dir string, cmdline string, kv ...string) error {
_, err := v.run1(dir, cmdline, kv, false)
return err
}
// runOutput is like run but returns the output of the command.
func (v *VCS) runOutput(dir string, cmdline string, kv ...string) ([]byte, error) {
return v.run1(dir, cmdline, kv, true)
}
// runOutputVerboseOnly is like runOutput but only generates error output to standard error in verbose mode.
func (v *VCS) runOutputVerboseOnly(dir string, cmdline string, kv ...string) ([]byte, error) {
return v.run1(dir, cmdline, kv, false)
}
// run1 is the generalized implementation of run and runOutput.
func (v *VCS) run1(dir string, cmdline string, kv []string, verbose bool) ([]byte, error) {
m := make(map[string]string)
for i := 0; i < len(kv); i += 2 {
m[kv[i]] = kv[i+1]
}
args := strings.Fields(cmdline)
for i, arg := range args {
args[i] = expand(m, arg)
}
_, err := exec.LookPath(v.vcs.Cmd)
if err != nil {
fmt.Fprintf(os.Stderr, "godep: missing %s command.\n", v.vcs.Name)
return nil, err
}
cmd := exec.Command(v.vcs.Cmd, args...)
cmd.Dir = dir
var buf bytes.Buffer
cmd.Stdout = &buf
cmd.Stderr = &buf
err = cmd.Run()
out := buf.Bytes()
if err != nil {
if verbose {
fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.vcs.Cmd, strings.Join(args, " "))
os.Stderr.Write(out)
}
return nil, err
}
return out, nil
}
func expand(m map[string]string, s string) string {
for k, v := range m {
s = strings.Replace(s, "{"+k+"}", v, -1)
}
return s
}
func gitDetached(r string) (bool, error) {
o, err := vcsGit.runOutput(r, "status")
if err != nil {
return false, errors.New("unable to determine git status " + err.Error())
}
return bytes.Contains(o, []byte("HEAD detached at")), nil
}
func gitDefaultBranch(r string) (string, error) {
o, err := vcsGit.runOutput(r, "remote show origin")
if err != nil {
return "", errors.New("Running git remote show origin errored with: " + err.Error())
}
return gitDetermineDefaultBranch(r, string(o))
}
func gitDetermineDefaultBranch(r, o string) (string, error) {
e := "Unable to determine HEAD branch: "
hb := "HEAD branch:"
lbcfgp := "Local branch configured for 'git pull':"
s := strings.Index(o, hb)
if s < 0 {
b := strings.Index(o, lbcfgp)
if b < 0 {
return "", errors.New(e + "Remote HEAD is ambiguous. Before godep can pull new commits you will need to:" + `
cd ` + r + `
git checkout <a HEAD branch>
Here is what was reported:
` + o)
}
s = b + len(lbcfgp)
} else {
s += len(hb)
}
f := strings.Fields(o[s:])
if len(f) < 3 {
return "", errors.New(e + "git output too short")
}
return f[0], nil
}
func gitCheckout(r, b string) error {
return vcsGit.run(r, "checkout "+b)
}

View File

@ -1,63 +0,0 @@
package main
import (
"fmt"
"log"
"runtime"
"strconv"
"strings"
)
const version = "80-k8s-r1"
var cmdVersion = &Command{
Name: "version",
Short: "show version info",
Long: `
Displays the version of godep as well as the target OS, architecture and go runtime version.
`,
Run: runVersion,
}
func versionString() string {
return fmt.Sprintf("godep v%s (%s/%s/%s)", version, runtime.GOOS, runtime.GOARCH, runtime.Version())
}
func runVersion(cmd *Command, args []string) {
fmt.Printf("%s\n", versionString())
}
func GoVersionFields(c rune) bool {
return c == 'g' || c == 'o' || c == '.'
}
// isSameOrNewer go version (goA.B)
// go1.6 >= go1.6 == true
// go1.5 >= go1.6 == false
func isSameOrNewer(base, check string) bool {
if base == check {
return true
}
if strings.HasPrefix(check, "devel-") {
return true
}
bp := strings.FieldsFunc(base, GoVersionFields)
cp := strings.FieldsFunc(check, GoVersionFields)
if len(bp) < 2 || len(cp) < 2 {
log.Fatalf("Error comparing %s to %s\n", base, check)
}
if bp[0] == cp[0] { // We only have go version 1 right now
bm, err := strconv.Atoi(bp[1])
// These errors are unlikely and there is nothing nice to do here anyway
if err != nil {
panic(err)
}
cm, err := strconv.Atoi(cp[1])
if err != nil {
panic(err)
}
return cm >= bm
}
return false
}

View File

@ -1,27 +0,0 @@
Copyright (c) 2012 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,22 +0,0 @@
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Go project.
Google 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,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.

View File

@ -1,37 +0,0 @@
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"deep_equal.go",
"type.go",
],
importpath = "k8s.io/kubernetes/third_party/forked/golang/reflect",
)
go_test(
name = "go_default_test",
srcs = ["deep_equal_test.go"],
embed = [":go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -1,388 +0,0 @@
// Copyright 2009 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.
// Package reflect is a fork of go's standard library reflection package, which
// allows for deep equal with equality functions defined.
package reflect
import (
"fmt"
"reflect"
"strings"
)
// Equalities is a map from type to a function comparing two values of
// that type.
type Equalities map[reflect.Type]reflect.Value
// For convenience, panics on errrors
func EqualitiesOrDie(funcs ...interface{}) Equalities {
e := Equalities{}
if err := e.AddFuncs(funcs...); err != nil {
panic(err)
}
return e
}
// AddFuncs is a shortcut for multiple calls to AddFunc.
func (e Equalities) AddFuncs(funcs ...interface{}) error {
for _, f := range funcs {
if err := e.AddFunc(f); err != nil {
return err
}
}
return nil
}
// AddFunc uses func as an equality function: it must take
// two parameters of the same type, and return a boolean.
func (e Equalities) AddFunc(eqFunc interface{}) error {
fv := reflect.ValueOf(eqFunc)
ft := fv.Type()
if ft.Kind() != reflect.Func {
return fmt.Errorf("expected func, got: %v", ft)
}
if ft.NumIn() != 2 {
return fmt.Errorf("expected two 'in' params, got: %v", ft)
}
if ft.NumOut() != 1 {
return fmt.Errorf("expected one 'out' param, got: %v", ft)
}
if ft.In(0) != ft.In(1) {
return fmt.Errorf("expected arg 1 and 2 to have same type, but got %v", ft)
}
var forReturnType bool
boolType := reflect.TypeOf(forReturnType)
if ft.Out(0) != boolType {
return fmt.Errorf("expected bool return, got: %v", ft)
}
e[ft.In(0)] = fv
return nil
}
// Below here is forked from go's reflect/deepequal.go
// During deepValueEqual, must keep track of checks that are
// in progress. The comparison algorithm assumes that all
// checks in progress are true when it reencounters them.
// Visited comparisons are stored in a map indexed by visit.
type visit struct {
a1 uintptr
a2 uintptr
typ reflect.Type
}
// unexportedTypePanic is thrown when you use this DeepEqual on something that has an
// unexported type. It indicates a programmer error, so should not occur at runtime,
// which is why it's not public and thus impossible to catch.
type unexportedTypePanic []reflect.Type
func (u unexportedTypePanic) Error() string { return u.String() }
func (u unexportedTypePanic) String() string {
strs := make([]string, len(u))
for i, t := range u {
strs[i] = fmt.Sprintf("%v", t)
}
return "an unexported field was encountered, nested like this: " + strings.Join(strs, " -> ")
}
func makeUsefulPanic(v reflect.Value) {
if x := recover(); x != nil {
if u, ok := x.(unexportedTypePanic); ok {
u = append(unexportedTypePanic{v.Type()}, u...)
x = u
}
panic(x)
}
}
// Tests for deep equality using reflected types. The map argument tracks
// comparisons that have already been seen, which allows short circuiting on
// recursive types.
func (e Equalities) deepValueEqual(v1, v2 reflect.Value, visited map[visit]bool, depth int) bool {
defer makeUsefulPanic(v1)
if !v1.IsValid() || !v2.IsValid() {
return v1.IsValid() == v2.IsValid()
}
if v1.Type() != v2.Type() {
return false
}
if fv, ok := e[v1.Type()]; ok {
return fv.Call([]reflect.Value{v1, v2})[0].Bool()
}
hard := func(k reflect.Kind) bool {
switch k {
case reflect.Array, reflect.Map, reflect.Slice, reflect.Struct:
return true
}
return false
}
if v1.CanAddr() && v2.CanAddr() && hard(v1.Kind()) {
addr1 := v1.UnsafeAddr()
addr2 := v2.UnsafeAddr()
if addr1 > addr2 {
// Canonicalize order to reduce number of entries in visited.
addr1, addr2 = addr2, addr1
}
// Short circuit if references are identical ...
if addr1 == addr2 {
return true
}
// ... or already seen
typ := v1.Type()
v := visit{addr1, addr2, typ}
if visited[v] {
return true
}
// Remember for later.
visited[v] = true
}
switch v1.Kind() {
case reflect.Array:
// We don't need to check length here because length is part of
// an array's type, which has already been filtered for.
for i := 0; i < v1.Len(); i++ {
if !e.deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) {
return false
}
}
return true
case reflect.Slice:
if (v1.IsNil() || v1.Len() == 0) != (v2.IsNil() || v2.Len() == 0) {
return false
}
if v1.IsNil() || v1.Len() == 0 {
return true
}
if v1.Len() != v2.Len() {
return false
}
if v1.Pointer() == v2.Pointer() {
return true
}
for i := 0; i < v1.Len(); i++ {
if !e.deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) {
return false
}
}
return true
case reflect.Interface:
if v1.IsNil() || v2.IsNil() {
return v1.IsNil() == v2.IsNil()
}
return e.deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1)
case reflect.Ptr:
return e.deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1)
case reflect.Struct:
for i, n := 0, v1.NumField(); i < n; i++ {
if !e.deepValueEqual(v1.Field(i), v2.Field(i), visited, depth+1) {
return false
}
}
return true
case reflect.Map:
if (v1.IsNil() || v1.Len() == 0) != (v2.IsNil() || v2.Len() == 0) {
return false
}
if v1.IsNil() || v1.Len() == 0 {
return true
}
if v1.Len() != v2.Len() {
return false
}
if v1.Pointer() == v2.Pointer() {
return true
}
for _, k := range v1.MapKeys() {
if !e.deepValueEqual(v1.MapIndex(k), v2.MapIndex(k), visited, depth+1) {
return false
}
}
return true
case reflect.Func:
if v1.IsNil() && v2.IsNil() {
return true
}
// Can't do better than this:
return false
default:
// Normal equality suffices
if !v1.CanInterface() || !v2.CanInterface() {
panic(unexportedTypePanic{})
}
return v1.Interface() == v2.Interface()
}
}
// DeepEqual is like reflect.DeepEqual, but focused on semantic equality
// instead of memory equality.
//
// It will use e's equality functions if it finds types that match.
//
// An empty slice *is* equal to a nil slice for our purposes; same for maps.
//
// Unexported field members cannot be compared and will cause an imformative panic; you must add an Equality
// function for these types.
func (e Equalities) DeepEqual(a1, a2 interface{}) bool {
if a1 == nil || a2 == nil {
return a1 == a2
}
v1 := reflect.ValueOf(a1)
v2 := reflect.ValueOf(a2)
if v1.Type() != v2.Type() {
return false
}
return e.deepValueEqual(v1, v2, make(map[visit]bool), 0)
}
func (e Equalities) deepValueDerive(v1, v2 reflect.Value, visited map[visit]bool, depth int) bool {
defer makeUsefulPanic(v1)
if !v1.IsValid() || !v2.IsValid() {
return v1.IsValid() == v2.IsValid()
}
if v1.Type() != v2.Type() {
return false
}
if fv, ok := e[v1.Type()]; ok {
return fv.Call([]reflect.Value{v1, v2})[0].Bool()
}
hard := func(k reflect.Kind) bool {
switch k {
case reflect.Array, reflect.Map, reflect.Slice, reflect.Struct:
return true
}
return false
}
if v1.CanAddr() && v2.CanAddr() && hard(v1.Kind()) {
addr1 := v1.UnsafeAddr()
addr2 := v2.UnsafeAddr()
if addr1 > addr2 {
// Canonicalize order to reduce number of entries in visited.
addr1, addr2 = addr2, addr1
}
// Short circuit if references are identical ...
if addr1 == addr2 {
return true
}
// ... or already seen
typ := v1.Type()
v := visit{addr1, addr2, typ}
if visited[v] {
return true
}
// Remember for later.
visited[v] = true
}
switch v1.Kind() {
case reflect.Array:
// We don't need to check length here because length is part of
// an array's type, which has already been filtered for.
for i := 0; i < v1.Len(); i++ {
if !e.deepValueDerive(v1.Index(i), v2.Index(i), visited, depth+1) {
return false
}
}
return true
case reflect.Slice:
if v1.IsNil() || v1.Len() == 0 {
return true
}
if v1.Len() > v2.Len() {
return false
}
if v1.Pointer() == v2.Pointer() {
return true
}
for i := 0; i < v1.Len(); i++ {
if !e.deepValueDerive(v1.Index(i), v2.Index(i), visited, depth+1) {
return false
}
}
return true
case reflect.String:
if v1.Len() == 0 {
return true
}
if v1.Len() > v2.Len() {
return false
}
return v1.String() == v2.String()
case reflect.Interface:
if v1.IsNil() {
return true
}
return e.deepValueDerive(v1.Elem(), v2.Elem(), visited, depth+1)
case reflect.Ptr:
if v1.IsNil() {
return true
}
return e.deepValueDerive(v1.Elem(), v2.Elem(), visited, depth+1)
case reflect.Struct:
for i, n := 0, v1.NumField(); i < n; i++ {
if !e.deepValueDerive(v1.Field(i), v2.Field(i), visited, depth+1) {
return false
}
}
return true
case reflect.Map:
if v1.IsNil() || v1.Len() == 0 {
return true
}
if v1.Len() > v2.Len() {
return false
}
if v1.Pointer() == v2.Pointer() {
return true
}
for _, k := range v1.MapKeys() {
if !e.deepValueDerive(v1.MapIndex(k), v2.MapIndex(k), visited, depth+1) {
return false
}
}
return true
case reflect.Func:
if v1.IsNil() && v2.IsNil() {
return true
}
// Can't do better than this:
return false
default:
// Normal equality suffices
if !v1.CanInterface() || !v2.CanInterface() {
panic(unexportedTypePanic{})
}
return v1.Interface() == v2.Interface()
}
}
// DeepDerivative is similar to DeepEqual except that unset fields in a1 are
// ignored (not compared). This allows us to focus on the fields that matter to
// the semantic comparison.
//
// The unset fields include a nil pointer and an empty string.
func (e Equalities) DeepDerivative(a1, a2 interface{}) bool {
if a1 == nil {
return true
}
v1 := reflect.ValueOf(a1)
v2 := reflect.ValueOf(a2)
if v1.Type() != v2.Type() {
return false
}
return e.deepValueDerive(v1, v2, make(map[visit]bool), 0)
}

View File

@ -1,137 +0,0 @@
// Copyright 2009 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.
package reflect
import (
"testing"
)
func TestEqualities(t *testing.T) {
e := Equalities{}
type Bar struct {
X int
}
type Baz struct {
Y Bar
}
err := e.AddFuncs(
func(a, b int) bool {
return a+1 == b
},
func(a, b Bar) bool {
return a.X*10 == b.X
},
)
if err != nil {
t.Fatalf("Unexpected: %v", err)
}
type Foo struct {
X int
}
table := []struct {
a, b interface{}
equal bool
}{
{1, 2, true},
{2, 1, false},
{"foo", "fo", false},
{"foo", "foo", true},
{"foo", "foobar", false},
{Foo{1}, Foo{2}, true},
{Foo{2}, Foo{1}, false},
{Bar{1}, Bar{10}, true},
{&Bar{1}, &Bar{10}, true},
{Baz{Bar{1}}, Baz{Bar{10}}, true},
{[...]string{}, [...]string{"1", "2", "3"}, false},
{[...]string{"1"}, [...]string{"1", "2", "3"}, false},
{[...]string{"1", "2", "3"}, [...]string{}, false},
{[...]string{"1", "2", "3"}, [...]string{"1", "2", "3"}, true},
{map[string]int{"foo": 1}, map[string]int{}, false},
{map[string]int{"foo": 1}, map[string]int{"foo": 2}, true},
{map[string]int{"foo": 2}, map[string]int{"foo": 1}, false},
{map[string]int{"foo": 1}, map[string]int{"foo": 2, "bar": 6}, false},
{map[string]int{"foo": 1, "bar": 6}, map[string]int{"foo": 2}, false},
{map[string]int{}, map[string]int(nil), true},
{[]string(nil), []string(nil), true},
{[]string{}, []string(nil), true},
{[]string(nil), []string{}, true},
{[]string{"1"}, []string(nil), false},
{[]string{}, []string{"1", "2", "3"}, false},
{[]string{"1"}, []string{"1", "2", "3"}, false},
{[]string{"1", "2", "3"}, []string{}, false},
}
for _, item := range table {
if e, a := item.equal, e.DeepEqual(item.a, item.b); e != a {
t.Errorf("Expected (%+v == %+v) == %v, but got %v", item.a, item.b, e, a)
}
}
}
func TestDerivates(t *testing.T) {
e := Equalities{}
type Bar struct {
X int
}
type Baz struct {
Y Bar
}
err := e.AddFuncs(
func(a, b int) bool {
return a+1 == b
},
func(a, b Bar) bool {
return a.X*10 == b.X
},
)
if err != nil {
t.Fatalf("Unexpected: %v", err)
}
type Foo struct {
X int
}
table := []struct {
a, b interface{}
equal bool
}{
{1, 2, true},
{2, 1, false},
{"foo", "fo", false},
{"foo", "foo", true},
{"foo", "foobar", false},
{Foo{1}, Foo{2}, true},
{Foo{2}, Foo{1}, false},
{Bar{1}, Bar{10}, true},
{&Bar{1}, &Bar{10}, true},
{Baz{Bar{1}}, Baz{Bar{10}}, true},
{[...]string{}, [...]string{"1", "2", "3"}, false},
{[...]string{"1"}, [...]string{"1", "2", "3"}, false},
{[...]string{"1", "2", "3"}, [...]string{}, false},
{[...]string{"1", "2", "3"}, [...]string{"1", "2", "3"}, true},
{map[string]int{"foo": 1}, map[string]int{}, false},
{map[string]int{"foo": 1}, map[string]int{"foo": 2}, true},
{map[string]int{"foo": 2}, map[string]int{"foo": 1}, false},
{map[string]int{"foo": 1}, map[string]int{"foo": 2, "bar": 6}, true},
{map[string]int{"foo": 1, "bar": 6}, map[string]int{"foo": 2}, false},
{map[string]int{}, map[string]int(nil), true},
{[]string(nil), []string(nil), true},
{[]string{}, []string(nil), true},
{[]string(nil), []string{}, true},
{[]string{"1"}, []string(nil), false},
{[]string{}, []string{"1", "2", "3"}, true},
{[]string{"1"}, []string{"1", "2", "3"}, true},
{[]string{"1", "2", "3"}, []string{}, false},
}
for _, item := range table {
if e, a := item.equal, e.DeepDerivative(item.a, item.b); e != a {
t.Errorf("Expected (%+v ~ %+v) == %v, but got %v", item.a, item.b, e, a)
}
}
}

View File

@ -1,91 +0,0 @@
//This package is copied from Go library reflect/type.go.
//The struct tag library provides no way to extract the list of struct tags, only
//a specific tag
package reflect
import (
"fmt"
"strconv"
"strings"
)
type StructTag struct {
Name string
Value string
}
func (t StructTag) String() string {
return fmt.Sprintf("%s:%q", t.Name, t.Value)
}
type StructTags []StructTag
func (tags StructTags) String() string {
s := make([]string, 0, len(tags))
for _, tag := range tags {
s = append(s, tag.String())
}
return "`" + strings.Join(s, " ") + "`"
}
func (tags StructTags) Has(name string) bool {
for i := range tags {
if tags[i].Name == name {
return true
}
}
return false
}
// ParseStructTags returns the full set of fields in a struct tag in the order they appear in
// the struct tag.
func ParseStructTags(tag string) (StructTags, error) {
tags := StructTags{}
for tag != "" {
// Skip leading space.
i := 0
for i < len(tag) && tag[i] == ' ' {
i++
}
tag = tag[i:]
if tag == "" {
break
}
// Scan to colon. A space, a quote or a control character is a syntax error.
// Strictly speaking, control chars include the range [0x7f, 0x9f], not just
// [0x00, 0x1f], but in practice, we ignore the multi-byte control characters
// as it is simpler to inspect the tag's bytes than the tag's runes.
i = 0
for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
i++
}
if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
break
}
name := string(tag[:i])
tag = tag[i+1:]
// Scan quoted string to find value.
i = 1
for i < len(tag) && tag[i] != '"' {
if tag[i] == '\\' {
i++
}
i++
}
if i >= len(tag) {
break
}
qvalue := string(tag[:i+1])
tag = tag[i+1:]
value, err := strconv.Unquote(qvalue)
if err != nil {
return nil, err
}
tags = append(tags, StructTag{Name: name, Value: value})
}
return tags, nil
}

View File

@ -1,30 +0,0 @@
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"exec.go",
"funcs.go",
],
importpath = "k8s.io/kubernetes/third_party/forked/golang/template",
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -1,94 +0,0 @@
//This package is copied from Go library text/template.
//The original private functions indirect and printableValue
//are exported as public functions.
package template
import (
"fmt"
"reflect"
)
var Indirect = indirect
var PrintableValue = printableValue
var (
errorType = reflect.TypeOf((*error)(nil)).Elem()
fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
)
// indirect returns the item at the end of indirection, and a bool to indicate if it's nil.
// We indirect through pointers and empty interfaces (only) because
// non-empty interfaces have methods we might need.
func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
if v.IsNil() {
return v, true
}
if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
break
}
}
return v, false
}
// printableValue returns the, possibly indirected, interface value inside v that
// is best for a call to formatted printer.
func printableValue(v reflect.Value) (interface{}, bool) {
if v.Kind() == reflect.Ptr {
v, _ = indirect(v) // fmt.Fprint handles nil.
}
if !v.IsValid() {
return "<no value>", true
}
if !v.Type().Implements(errorType) && !v.Type().Implements(fmtStringerType) {
if v.CanAddr() && (reflect.PtrTo(v.Type()).Implements(errorType) || reflect.PtrTo(v.Type()).Implements(fmtStringerType)) {
v = v.Addr()
} else {
switch v.Kind() {
case reflect.Chan, reflect.Func:
return nil, false
}
}
}
return v.Interface(), true
}
// canBeNil reports whether an untyped nil can be assigned to the type. See reflect.Zero.
func canBeNil(typ reflect.Type) bool {
switch typ.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
return true
}
return false
}
// isTrue reports whether the value is 'true', in the sense of not the zero of its type,
// and whether the value has a meaningful truth value.
func isTrue(val reflect.Value) (truth, ok bool) {
if !val.IsValid() {
// Something like var x interface{}, never set. It's a form of nil.
return false, true
}
switch val.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
truth = val.Len() > 0
case reflect.Bool:
truth = val.Bool()
case reflect.Complex64, reflect.Complex128:
truth = val.Complex() != 0
case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Interface:
truth = !val.IsNil()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
truth = val.Int() != 0
case reflect.Float32, reflect.Float64:
truth = val.Float() != 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
truth = val.Uint() != 0
case reflect.Struct:
truth = true // Struct values are always true.
default:
return
}
return truth, true
}

View File

@ -1,599 +0,0 @@
//This package is copied from Go library text/template.
//The original private functions eq, ge, gt, le, lt, and ne
//are exported as public functions.
package template
import (
"bytes"
"errors"
"fmt"
"io"
"net/url"
"reflect"
"strings"
"unicode"
"unicode/utf8"
)
var Equal = eq
var GreaterEqual = ge
var Greater = gt
var LessEqual = le
var Less = lt
var NotEqual = ne
// FuncMap is the type of the map defining the mapping from names to functions.
// Each function must have either a single return value, or two return values of
// which the second has type error. In that case, if the second (error)
// return value evaluates to non-nil during execution, execution terminates and
// Execute returns that error.
type FuncMap map[string]interface{}
var builtins = FuncMap{
"and": and,
"call": call,
"html": HTMLEscaper,
"index": index,
"js": JSEscaper,
"len": length,
"not": not,
"or": or,
"print": fmt.Sprint,
"printf": fmt.Sprintf,
"println": fmt.Sprintln,
"urlquery": URLQueryEscaper,
// Comparisons
"eq": eq, // ==
"ge": ge, // >=
"gt": gt, // >
"le": le, // <=
"lt": lt, // <
"ne": ne, // !=
}
var builtinFuncs = createValueFuncs(builtins)
// createValueFuncs turns a FuncMap into a map[string]reflect.Value
func createValueFuncs(funcMap FuncMap) map[string]reflect.Value {
m := make(map[string]reflect.Value)
addValueFuncs(m, funcMap)
return m
}
// addValueFuncs adds to values the functions in funcs, converting them to reflect.Values.
func addValueFuncs(out map[string]reflect.Value, in FuncMap) {
for name, fn := range in {
v := reflect.ValueOf(fn)
if v.Kind() != reflect.Func {
panic("value for " + name + " not a function")
}
if !goodFunc(v.Type()) {
panic(fmt.Errorf("can't install method/function %q with %d results", name, v.Type().NumOut()))
}
out[name] = v
}
}
// AddFuncs adds to values the functions in funcs. It does no checking of the input -
// call addValueFuncs first.
func addFuncs(out, in FuncMap) {
for name, fn := range in {
out[name] = fn
}
}
// goodFunc checks that the function or method has the right result signature.
func goodFunc(typ reflect.Type) bool {
// We allow functions with 1 result or 2 results where the second is an error.
switch {
case typ.NumOut() == 1:
return true
case typ.NumOut() == 2 && typ.Out(1) == errorType:
return true
}
return false
}
// findFunction looks for a function in the template, and global map.
func findFunction(name string) (reflect.Value, bool) {
if fn := builtinFuncs[name]; fn.IsValid() {
return fn, true
}
return reflect.Value{}, false
}
// Indexing.
// index returns the result of indexing its first argument by the following
// arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
// indexed item must be a map, slice, or array.
func index(item interface{}, indices ...interface{}) (interface{}, error) {
v := reflect.ValueOf(item)
for _, i := range indices {
index := reflect.ValueOf(i)
var isNil bool
if v, isNil = indirect(v); isNil {
return nil, fmt.Errorf("index of nil pointer")
}
switch v.Kind() {
case reflect.Array, reflect.Slice, reflect.String:
var x int64
switch index.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
x = index.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
x = int64(index.Uint())
default:
return nil, fmt.Errorf("cannot index slice/array with type %s", index.Type())
}
if x < 0 || x >= int64(v.Len()) {
return nil, fmt.Errorf("index out of range: %d", x)
}
v = v.Index(int(x))
case reflect.Map:
if !index.IsValid() {
index = reflect.Zero(v.Type().Key())
}
if !index.Type().AssignableTo(v.Type().Key()) {
return nil, fmt.Errorf("%s is not index type for %s", index.Type(), v.Type())
}
if x := v.MapIndex(index); x.IsValid() {
v = x
} else {
v = reflect.Zero(v.Type().Elem())
}
default:
return nil, fmt.Errorf("can't index item of type %s", v.Type())
}
}
return v.Interface(), nil
}
// Length
// length returns the length of the item, with an error if it has no defined length.
func length(item interface{}) (int, error) {
v, isNil := indirect(reflect.ValueOf(item))
if isNil {
return 0, fmt.Errorf("len of nil pointer")
}
switch v.Kind() {
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
return v.Len(), nil
}
return 0, fmt.Errorf("len of type %s", v.Type())
}
// Function invocation
// call returns the result of evaluating the first argument as a function.
// The function must return 1 result, or 2 results, the second of which is an error.
func call(fn interface{}, args ...interface{}) (interface{}, error) {
v := reflect.ValueOf(fn)
typ := v.Type()
if typ.Kind() != reflect.Func {
return nil, fmt.Errorf("non-function of type %s", typ)
}
if !goodFunc(typ) {
return nil, fmt.Errorf("function called with %d args; should be 1 or 2", typ.NumOut())
}
numIn := typ.NumIn()
var dddType reflect.Type
if typ.IsVariadic() {
if len(args) < numIn-1 {
return nil, fmt.Errorf("wrong number of args: got %d want at least %d", len(args), numIn-1)
}
dddType = typ.In(numIn - 1).Elem()
} else {
if len(args) != numIn {
return nil, fmt.Errorf("wrong number of args: got %d want %d", len(args), numIn)
}
}
argv := make([]reflect.Value, len(args))
for i, arg := range args {
value := reflect.ValueOf(arg)
// Compute the expected type. Clumsy because of variadics.
var argType reflect.Type
if !typ.IsVariadic() || i < numIn-1 {
argType = typ.In(i)
} else {
argType = dddType
}
if !value.IsValid() && canBeNil(argType) {
value = reflect.Zero(argType)
}
if !value.Type().AssignableTo(argType) {
return nil, fmt.Errorf("arg %d has type %s; should be %s", i, value.Type(), argType)
}
argv[i] = value
}
result := v.Call(argv)
if len(result) == 2 && !result[1].IsNil() {
return result[0].Interface(), result[1].Interface().(error)
}
return result[0].Interface(), nil
}
// Boolean logic.
func truth(a interface{}) bool {
t, _ := isTrue(reflect.ValueOf(a))
return t
}
// and computes the Boolean AND of its arguments, returning
// the first false argument it encounters, or the last argument.
func and(arg0 interface{}, args ...interface{}) interface{} {
if !truth(arg0) {
return arg0
}
for i := range args {
arg0 = args[i]
if !truth(arg0) {
break
}
}
return arg0
}
// or computes the Boolean OR of its arguments, returning
// the first true argument it encounters, or the last argument.
func or(arg0 interface{}, args ...interface{}) interface{} {
if truth(arg0) {
return arg0
}
for i := range args {
arg0 = args[i]
if truth(arg0) {
break
}
}
return arg0
}
// not returns the Boolean negation of its argument.
func not(arg interface{}) (truth bool) {
truth, _ = isTrue(reflect.ValueOf(arg))
return !truth
}
// Comparison.
// TODO: Perhaps allow comparison between signed and unsigned integers.
var (
errBadComparisonType = errors.New("invalid type for comparison")
errBadComparison = errors.New("incompatible types for comparison")
errNoComparison = errors.New("missing argument for comparison")
)
type kind int
const (
invalidKind kind = iota
boolKind
complexKind
intKind
floatKind
integerKind
stringKind
uintKind
)
func basicKind(v reflect.Value) (kind, error) {
switch v.Kind() {
case reflect.Bool:
return boolKind, nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return intKind, nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return uintKind, nil
case reflect.Float32, reflect.Float64:
return floatKind, nil
case reflect.Complex64, reflect.Complex128:
return complexKind, nil
case reflect.String:
return stringKind, nil
}
return invalidKind, errBadComparisonType
}
// eq evaluates the comparison a == b || a == c || ...
func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) {
v1 := reflect.ValueOf(arg1)
k1, err := basicKind(v1)
if err != nil {
return false, err
}
if len(arg2) == 0 {
return false, errNoComparison
}
for _, arg := range arg2 {
v2 := reflect.ValueOf(arg)
k2, err := basicKind(v2)
if err != nil {
return false, err
}
truth := false
if k1 != k2 {
// Special case: Can compare integer values regardless of type's sign.
switch {
case k1 == intKind && k2 == uintKind:
truth = v1.Int() >= 0 && uint64(v1.Int()) == v2.Uint()
case k1 == uintKind && k2 == intKind:
truth = v2.Int() >= 0 && v1.Uint() == uint64(v2.Int())
default:
return false, errBadComparison
}
} else {
switch k1 {
case boolKind:
truth = v1.Bool() == v2.Bool()
case complexKind:
truth = v1.Complex() == v2.Complex()
case floatKind:
truth = v1.Float() == v2.Float()
case intKind:
truth = v1.Int() == v2.Int()
case stringKind:
truth = v1.String() == v2.String()
case uintKind:
truth = v1.Uint() == v2.Uint()
default:
panic("invalid kind")
}
}
if truth {
return true, nil
}
}
return false, nil
}
// ne evaluates the comparison a != b.
func ne(arg1, arg2 interface{}) (bool, error) {
// != is the inverse of ==.
equal, err := eq(arg1, arg2)
return !equal, err
}
// lt evaluates the comparison a < b.
func lt(arg1, arg2 interface{}) (bool, error) {
v1 := reflect.ValueOf(arg1)
k1, err := basicKind(v1)
if err != nil {
return false, err
}
v2 := reflect.ValueOf(arg2)
k2, err := basicKind(v2)
if err != nil {
return false, err
}
truth := false
if k1 != k2 {
// Special case: Can compare integer values regardless of type's sign.
switch {
case k1 == intKind && k2 == uintKind:
truth = v1.Int() < 0 || uint64(v1.Int()) < v2.Uint()
case k1 == uintKind && k2 == intKind:
truth = v2.Int() >= 0 && v1.Uint() < uint64(v2.Int())
default:
return false, errBadComparison
}
} else {
switch k1 {
case boolKind, complexKind:
return false, errBadComparisonType
case floatKind:
truth = v1.Float() < v2.Float()
case intKind:
truth = v1.Int() < v2.Int()
case stringKind:
truth = v1.String() < v2.String()
case uintKind:
truth = v1.Uint() < v2.Uint()
default:
panic("invalid kind")
}
}
return truth, nil
}
// le evaluates the comparison <= b.
func le(arg1, arg2 interface{}) (bool, error) {
// <= is < or ==.
lessThan, err := lt(arg1, arg2)
if lessThan || err != nil {
return lessThan, err
}
return eq(arg1, arg2)
}
// gt evaluates the comparison a > b.
func gt(arg1, arg2 interface{}) (bool, error) {
// > is the inverse of <=.
lessOrEqual, err := le(arg1, arg2)
if err != nil {
return false, err
}
return !lessOrEqual, nil
}
// ge evaluates the comparison a >= b.
func ge(arg1, arg2 interface{}) (bool, error) {
// >= is the inverse of <.
lessThan, err := lt(arg1, arg2)
if err != nil {
return false, err
}
return !lessThan, nil
}
// HTML escaping.
var (
htmlQuot = []byte("&#34;") // shorter than "&quot;"
htmlApos = []byte("&#39;") // shorter than "&apos;" and apos was not in HTML until HTML5
htmlAmp = []byte("&amp;")
htmlLt = []byte("&lt;")
htmlGt = []byte("&gt;")
)
// HTMLEscape writes to w the escaped HTML equivalent of the plain text data b.
func HTMLEscape(w io.Writer, b []byte) {
last := 0
for i, c := range b {
var html []byte
switch c {
case '"':
html = htmlQuot
case '\'':
html = htmlApos
case '&':
html = htmlAmp
case '<':
html = htmlLt
case '>':
html = htmlGt
default:
continue
}
w.Write(b[last:i])
w.Write(html)
last = i + 1
}
w.Write(b[last:])
}
// HTMLEscapeString returns the escaped HTML equivalent of the plain text data s.
func HTMLEscapeString(s string) string {
// Avoid allocation if we can.
if strings.IndexAny(s, `'"&<>`) < 0 {
return s
}
var b bytes.Buffer
HTMLEscape(&b, []byte(s))
return b.String()
}
// HTMLEscaper returns the escaped HTML equivalent of the textual
// representation of its arguments.
func HTMLEscaper(args ...interface{}) string {
return HTMLEscapeString(evalArgs(args))
}
// JavaScript escaping.
var (
jsLowUni = []byte(`\u00`)
hex = []byte("0123456789ABCDEF")
jsBackslash = []byte(`\\`)
jsApos = []byte(`\'`)
jsQuot = []byte(`\"`)
jsLt = []byte(`\x3C`)
jsGt = []byte(`\x3E`)
)
// JSEscape writes to w the escaped JavaScript equivalent of the plain text data b.
func JSEscape(w io.Writer, b []byte) {
last := 0
for i := 0; i < len(b); i++ {
c := b[i]
if !jsIsSpecial(rune(c)) {
// fast path: nothing to do
continue
}
w.Write(b[last:i])
if c < utf8.RuneSelf {
// Quotes, slashes and angle brackets get quoted.
// Control characters get written as \u00XX.
switch c {
case '\\':
w.Write(jsBackslash)
case '\'':
w.Write(jsApos)
case '"':
w.Write(jsQuot)
case '<':
w.Write(jsLt)
case '>':
w.Write(jsGt)
default:
w.Write(jsLowUni)
t, b := c>>4, c&0x0f
w.Write(hex[t : t+1])
w.Write(hex[b : b+1])
}
} else {
// Unicode rune.
r, size := utf8.DecodeRune(b[i:])
if unicode.IsPrint(r) {
w.Write(b[i : i+size])
} else {
fmt.Fprintf(w, "\\u%04X", r)
}
i += size - 1
}
last = i + 1
}
w.Write(b[last:])
}
// JSEscapeString returns the escaped JavaScript equivalent of the plain text data s.
func JSEscapeString(s string) string {
// Avoid allocation if we can.
if strings.IndexFunc(s, jsIsSpecial) < 0 {
return s
}
var b bytes.Buffer
JSEscape(&b, []byte(s))
return b.String()
}
func jsIsSpecial(r rune) bool {
switch r {
case '\\', '\'', '"', '<', '>':
return true
}
return r < ' ' || utf8.RuneSelf <= r
}
// JSEscaper returns the escaped JavaScript equivalent of the textual
// representation of its arguments.
func JSEscaper(args ...interface{}) string {
return JSEscapeString(evalArgs(args))
}
// URLQueryEscaper returns the escaped value of the textual representation of
// its arguments in a form suitable for embedding in a URL query.
func URLQueryEscaper(args ...interface{}) string {
return url.QueryEscape(evalArgs(args))
}
// evalArgs formats the list of arguments into a string. It is therefore equivalent to
// fmt.Sprint(args...)
// except that each argument is indirected (if a pointer), as required,
// using the same rules as the default string evaluation during template
// execution.
func evalArgs(args []interface{}) string {
ok := false
var s string
// Fast path for simple common case.
if len(args) == 1 {
s, ok = args[0].(string)
}
if !ok {
for i, arg := range args {
a, ok := printableValue(reflect.ValueOf(arg))
if ok {
args[i] = a
} // else left fmt do its thing
}
s = fmt.Sprint(args...)
}
return s
}

View File

@ -1,172 +0,0 @@
Shell2Junit License Information
Feb, 2010
shell2junit library and sample code is licensed under Apache License, v.2.0.
(c) 2009 Manolo Carrasco (Manuel Carrasco Moñino)
=====
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
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.

View File

@ -1,12 +0,0 @@
# See the OWNERS docs at https://go.k8s.io/owners
reviewers:
- cblecker
- ixdy
- mengqiy
- pwittrock
approvers:
- cblecker
- ixdy
- mengqiy
- pwittrock

View File

@ -1,179 +0,0 @@
#!/usr/bin/env bash
### Copyright 2010 Manuel Carrasco Moñino. (manolo at apache.org)
###
### Licensed under the Apache License, Version 2.0.
### You may obtain a copy of it at
### http://www.apache.org/licenses/LICENSE-2.0
###
### A library for shell scripts which creates reports in jUnit format.
### These reports can be used in Jenkins, or any other CI.
###
### Usage:
### - Include this file in your shell script
### - Use juLog to call your command any time you want to produce a new report
### Usage: juLog <options> command arguments
### options:
### -class="MyClass" : a class name which will be shown in the junit report
### -name="TestName" : the test name which will be shown in the junit report
### -error="RegExp" : a regexp which sets the test as failure when the output matches it
### -ierror="RegExp" : same as -error but case insensitive
### -output="Path" : path to output directory, defaults to "./results"
### - Junit reports are left in the folder 'result' under the directory where the script is executed.
### - Configure Jenkins to parse junit files from the generated folder
###
asserts=00; errors=0; total=0; content=""
date=`which gdate 2>/dev/null || which date`
# default output folder
juDIR=`pwd`/results
# The name of the suite is calculated based in your script name
suite=""
if LANG=C sed --help 2>&1 | grep -q GNU; then
SED="sed"
elif which gsed &>/dev/null; then
SED="gsed"
else
echo "Failed to find GNU sed as sed or gsed. If you are on Mac: brew install gnu-sed." >&2
exit 1
fi
# A wrapper for the eval method witch allows catching seg-faults and use tee
errfile=/tmp/evErr.$$.log
function eVal() {
(eval "$1")
# stdout and stderr may currently be inverted (see below) so echo may write to stderr
echo "$?" 2>&1 | tr -d "\n" > "${errfile}"
}
# Method to clean old tests
function juLogClean() {
echo "+++ Removing old junit reports from: ${juDIR} "
rm -f "${juDIR}"/junit-*
}
# Execute a command and record its results
function juLog() {
suite="";
errfile=/tmp/evErr.$$.log
date=`which gdate 2>/dev/null || which date`
asserts=00; errors=0; total=0; content=""
# parse arguments
ya=""; icase=""
while [[ -z "$ya" ]]; do
case "$1" in
-name=*) name=`echo "$1" | ${SED} -e 's/-name=//'`; shift;;
-class=*) class=`echo "$1" | ${SED} -e 's/-class=//'`; shift;;
-ierror=*) ereg=`echo "$1" | ${SED} -e 's/-ierror=//'`; icase="-i"; shift;;
-error=*) ereg=`echo "$1" | ${SED} -e 's/-error=//'`; shift;;
-output=*) juDIR=`echo "$1" | ${SED} -e 's/-output=//'`; shift;;
*) ya=1;;
esac
done
# create output directory
mkdir -p "${juDIR}" || exit
# use first arg as name if it was not given
if [[ -z "${name}" ]]; then
name="${asserts}-$1"
shift
fi
if [[ "${class}" = "" ]]; then
class="default"
fi
suite=${class}
# calculate command to eval
[[ -z "$1" ]] && return
cmd="$1"; shift
while [[ -n "${1:-}" ]]
do
cmd="${cmd} \"$1\""
shift
done
# eval the command sending output to a file
outf=/var/tmp/ju$$.txt
errf=/var/tmp/ju$$-err.txt
>${outf}
echo "" | tee -a ${outf}
echo "+++ Running case: ${class}.${name} " | tee -a ${outf}
echo "+++ working dir: "`pwd` | tee -a ${outf}
echo "+++ command: ${cmd}" | tee -a ${outf}
ini=`${date} +%s.%N`
# execute the command, temporarily swapping stderr and stdout so they can be tee'd to separate files,
# then swapping them back again so that the streams are written correctly for the invoking process
( (eVal "${cmd}" | tee -a ${outf}) 3>&1 1>&2 2>&3 | tee ${errf}) 3>&1 1>&2 2>&3
evErr=`cat ${errfile}`
rm -f ${errfile}
end=`${date} +%s.%N`
echo "+++ exit code: ${evErr}" | tee -a ${outf}
# set the appropriate error, based in the exit code and the regex
[[ ${evErr} != 0 ]] && err=1 || err=0
out=`cat $outf | ${SED} -e 's/^\([^+]\)/| \1/g'`
if [ ${err} = 0 -a -n "${ereg:-}" ]; then
H=`echo "${out}" | egrep ${icase} "${ereg}"`
[[ -n "${H}" ]] && err=1
fi
[[ ${err} != 0 ]] && echo "+++ error: ${err}" | tee -a ${outf}
rm -f ${outf}
errMsg=`cat ${errf}`
rm -f ${errf}
# calculate vars
asserts=$(($asserts+1))
errors=$(($errors+$err))
time=`echo "${end} ${ini}" | awk '{print $1 - $2}'`
total=`echo "${total} ${time}" | awk '{print $1 + $2}'`
# write the junit xml report
## failure tag
[[ ${err} = 0 ]] && failure="" || failure="
<failure type=\"ScriptError\" message=\"Script Error\"><![CDATA[${errMsg}]]></failure>
"
## testcase tag
content="${content}
<testcase assertions=\"1\" name=\"${name}\" time=\"${time}\" classname=\"${class}\">
${failure}
<system-err><![CDATA[${errMsg}]]></system-err>
</testcase>
"
## testsuite block
if [[ -e "${juDIR}/junit_${suite}.xml" ]]; then
# file exists. first update the failures count
failCount=`${SED} -n "s/.*testsuite.*failures=\"\([0-9]*\)\".*/\1/p" "${juDIR}/junit_${suite}.xml"`
errors=$(($failCount+$errors))
${SED} -i "0,/failures=\"${failCount}\"/ s/failures=\"${failCount}\"/failures=\"${errors}\"/" "${juDIR}/junit_${suite}.xml"
${SED} -i "0,/errors=\"${failCount}\"/ s/errors=\"${failCount}\"/errors=\"${errors}\"/" "${juDIR}/junit_${suite}.xml"
# file exists. Need to append to it. If we remove the testsuite end tag, we can just add it in after.
${SED} -i "s^</testsuite>^^g" ${juDIR}/junit_${suite}.xml ## remove testSuite so we can add it later
${SED} -i "s^</testsuites>^^g" ${juDIR}/junit_${suite}.xml
cat <<EOF >> "$juDIR/junit_$suite.xml"
${content:-}
</testsuite>
</testsuites>
EOF
else
# no file exists. Adding a new file
cat <<EOF > "${juDIR}/junit_${suite}.xml"
<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
<testsuite failures="${errors}" assertions="${assertions:-}" name="${suite}" tests="1" errors="${errors}" time="${total}">
${content:-}
</testsuite>
</testsuites>
EOF
fi
return ${err}
}

Some files were not shown because too many files have changed in this diff Show More