Full Code of vrecan/death for AI

master 88275e7df60e cached
11 files
21.5 KB
6.6k tokens
40 symbols
1 requests
Download .txt
Repository: vrecan/death
Branch: master
Commit: 88275e7df60e
Files: 11
Total size: 21.5 KB

Directory structure:
gitextract_9tv2jfz4/

├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── death.go
├── death_unix_test.go
├── death_windows_test.go
├── deathlog.go
├── go.mod
├── go.sum
└── pkgPath_test.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Created by .ignore support plugin (hsz.mobi)
### Go template
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so

# Folders
_obj
_test
.idea

# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out

*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*

_testmain.go

*.exe
*.test
*.prof




================================================
FILE: .travis.yml
================================================
language: go
sudo: false
go:
  - "1.14"
before_install:
  - go get github.com/mattn/goveralls
  - export PATH=$PATH:$HOME/gopath/bin
  - go install github.com/vrecan/death/./...
script:
  - $GOPATH/bin/goveralls -service=travis-ci -race -v


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2015 Ben Aldrich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.



================================================
FILE: README.md
================================================
# Death [![Build Status](https://travis-ci.org/vrecan/death.svg?branch=master)](https://travis-ci.org/vrecan/death) [![Coverage Status](https://coveralls.io/repos/github/vrecan/death/badge.svg?branch=master)](https://coveralls.io/github/vrecan/death?branch=master) [![Go Reference](https://pkg.go.dev/badge/github.com/vrecan/death/v3.svg)](https://pkg.go.dev/github.com/vrecan/death/v3) [![Join the chat at https://gitter.im/vrecan/death](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/vrecan/death?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

<p>Simple library to make it easier to manage the death of your application.</p>

## Get The Library

Use gopkg.in to import death based on your logger.

| Version | Go Get URL                                                                           | source                                                           | doc                                                  | Notes                                                                                                                                                                                                                                                                                                |
| ------- | ------------------------------------------------------------------------------------ | ---------------------------------------------------------------- | ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 3.x     | [github.com/vrecan/death/v3](https://github.com/vrecan/death/tree/release-branch.v3) | [source](https://github.com/vrecan/death/tree/release-branch.v3) | [doc](https://pkg.go.dev/github.com/vrecan/death/v3) | This removes the need for an independent logger. By default death will not log but will return an error if all the closers do not properly close. If you want to provide a logger just satisfy the deathlog.Logger interface. This also uses go modules so import it as `github.com/vrecan/death/v3` |
| 2.x     | [gopkg.in/vrecan/death.v2](https://gopkg.in/vrecan/death.v2)                         | [source](https://github.com/vrecan/death/tree/v2.0)              | [doc](https://godoc.org/gopkg.in/vrecan/death.v2)    | This supports loggers who _do not_ return an error from their `Error` and `Warn` functions like [logrus](https://github.com/sirupsen/logrus)                                                                                                                                                         |
| 1.x     | [gopkg.in/vrecan/death.v1](https://gopkg.in/vrecan/death.v1)                         | [souce](https://github.com/vrecan/death/tree/v1.0)               | [doc](https://godoc.org/gopkg.in/vrecan/death.v1)    | This supports loggers who _do_ return an error from their `Error` and `Warn` functions like [seelog](https://github.com/cihub/seelog)                                                                                                                                                                |

Example

```bash
go get github.com/vrecan/death/v3
```

## Use The Library

```go
package main

import (
	DEATH "github.com/vrecan/death/v3"
	SYS "syscall"
)

func main() {
	death := DEATH.NewDeath(SYS.SIGINT, SYS.SIGTERM) //pass the signals you want to end your application
	//when you want to block for shutdown signals
	death.WaitForDeath() // this will finish when a signal of your type is sent to your application
}
```

### Close Other Objects On Shutdown

<p>One simple feature of death is that it can also close other objects when shutdown starts</p>

```go
package main

import (
	"log"
	DEATH "github.com/vrecan/death/v3"
	SYS "syscall"
	"io"
)

func main() {
	death := DEATH.NewDeath(SYS.SIGINT, SYS.SIGTERM) //pass the signals you want to end your application
	objects := make([]io.Closer, 0)

	objects = append(objects, &NewType{}) // this will work as long as the type implements a Close method

	//when you want to block for shutdown signals
	err := death.WaitForDeath(objects...) // this will finish when a signal of your type is sent to your application
	if err != nil {
		log.Println(err)
		os.Exit(1)
	}
}

type NewType struct {
}

func (c *NewType) Close() error {
	return nil
}

```

### Or close using an anonymous function

```go
package main

import (
	DEATH "github.com/vrecan/death/v3"
	SYS "syscall"
)

func main() {
	death := DEATH.NewDeath(SYS.SIGINT, SYS.SIGTERM) //pass the signals you want to end your application
	//when you want to block for shutdown signals
	death.WaitForDeathWithFunc(func(){
		//do whatever you want on death
	})
}
```

# Release Process

## Rules for release branches:

- If you are releasing a new major version you need to branch off of master into a branch `release-branch.v#` (example `release-branch.v2` for a 2.x release)
- If you are releasing a minor or patch update to an existing major release make sure to merge master into the release branch

## Rules for tagging and publishing the release

When you are ready to publish the release make sure you...

1. Merge your changes into the correct release branch.
2. Check out the release branch locally (example: `git pull origin release-branch.v3`)
3. Create a new tag for the specific release version you will publish (example: `git tag v3.0.1`)
4. Push the tag up to github (example: `git push origin v3.0.1`)
5. Go to the release tab in github
6. Select the target branch as the release branch and type in the tag name (tagname should include `v` so example: `v3.0.1`)
7. Write a title and a well worded description on exactly what is in this change
8. Click publish release


================================================
FILE: death.go
================================================
package death

//Manage the death of your application.

import (
	"fmt"
	"io"
	"os"
	"os/signal"
	"reflect"
	"strings"
	"sync"
	"time"
)

// Death manages the death of your application.
type Death struct {
	wg          *sync.WaitGroup
	sigChannel  chan os.Signal
	callChannel chan struct{}
	timeout     time.Duration
	log         Logger
}

// closer is a wrapper to the struct we are going to close with metadata
// to help with debuging close.
type closer struct {
	Index   int
	C       io.Closer
	Name    string
	PKGPath string
	Err     error
}

// NewDeath Create Death with the signals you want to die from.
func NewDeath(signals ...os.Signal) (death *Death) {
	death = &Death{timeout: 10 * time.Second,
		sigChannel:  make(chan os.Signal, 1),
		callChannel: make(chan struct{}, 1),
		wg:          &sync.WaitGroup{},
		log:         DefaultLogger()}
	signal.Notify(death.sigChannel, signals...)
	death.wg.Add(1)
	go death.listenForSignal()
	return death
}

// SetTimeout Overrides the time death is willing to wait for a objects to be closed.
func (d *Death) SetTimeout(t time.Duration) *Death {
	d.timeout = t
	return d
}

// SetLogger Overrides the default logger (seelog)
func (d *Death) SetLogger(l Logger) *Death {
	d.log = l
	return d
}

// WaitForDeath wait for signal and then kill all items that need to die. If they fail to
// die when instructed we return an error
func (d *Death) WaitForDeath(closable ...io.Closer) (err error) {
	d.wg.Wait()
	d.log.Info("Shutdown started...")
	count := len(closable)
	d.log.Debug("Closing ", count, " objects")
	if count > 0 {
		return d.closeInMass(closable...)
	}
	return nil
}

// WaitForDeathWithFunc allows you to have a single function get called when it's time to
// kill your application.
func (d *Death) WaitForDeathWithFunc(f func()) {
	d.wg.Wait()
	d.log.Info("Shutdown started...")
	f()
}

// getPkgPath for an io closer.
func getPkgPath(c io.Closer) (name string, pkgPath string) {
	t := reflect.TypeOf(c)
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	return t.Name(), t.PkgPath()
}

// closeInMass Close all the objects at once and wait for them to finish with a channel. Return an
// error if you fail to close all the objects
func (d *Death) closeInMass(closable ...io.Closer) (err error) {

	count := len(closable)
	sentToClose := make(map[int]closer)
	//call close async
	doneClosers := make(chan closer, count)
	for i, c := range closable {
		name, pkgPath := getPkgPath(c)
		closer := closer{Index: i, C: c, Name: name, PKGPath: pkgPath}
		go d.closeObjects(closer, doneClosers)
		sentToClose[i] = closer
	}

	// wait on channel for notifications.
	timer := time.NewTimer(d.timeout)
	failedClosers := []closer{}
	for {
		select {
		case <-timer.C:
			s := "failed to close: "
			pkgs := []string{}
			for _, c := range sentToClose {
				pkgs = append(pkgs, fmt.Sprintf("%s/%s", c.PKGPath, c.Name))
				d.log.Error("Failed to close: ", c.PKGPath, "/", c.Name)
			}
			return fmt.Errorf("%s", fmt.Sprintf("%s %s", s, strings.Join(pkgs, ", ")))
		case closer := <-doneClosers:
			delete(sentToClose, closer.Index)
			count--
			if closer.Err != nil {
				failedClosers = append(failedClosers, closer)
			}

			d.log.Debug(count, " object(s) left")
			if count != 0 || len(sentToClose) != 0 {
				continue
			}

			if len(failedClosers) != 0 {
				errString := generateErrString(failedClosers)
				return fmt.Errorf("errors from closers: %s", errString)
			}

			return nil
		}
	}
}

// closeObjects and return a bool when finished on a channel.
func (d *Death) closeObjects(closer closer, done chan<- closer) {
	err := closer.C.Close()
	if err != nil {
		d.log.Error(err)
		closer.Err = err
	}
	done <- closer
}

// FallOnSword manually initiates the death process.
func (d *Death) FallOnSword() {
	select {
	case d.callChannel <- struct{}{}:
	default:
	}
}

// ListenForSignal Manage death of application by signal.
func (d *Death) listenForSignal() {
	defer d.wg.Done()
	for {
		select {
		case <-d.sigChannel:
			return
		case <-d.callChannel:
			return
		}
	}
}

// generateErrString generates a string containing a list of tuples of pkgname to error message
func generateErrString(failedClosers []closer) (errString string) {
	for i, fc := range failedClosers {
		if i == 0 {
			errString = fmt.Sprintf("%s/%s: %s", fc.PKGPath, fc.Name, fc.Err)
			continue
		}
		errString = fmt.Sprintf("%s, %s/%s: %s", errString, fc.PKGPath, fc.Name, fc.Err)
	}

	return errString
}


================================================
FILE: death_unix_test.go
================================================
// +build linux bsd darwin

package death

import (
	"fmt"
	"os"
	"syscall"
	"testing"
	"time"

	. "github.com/smartystreets/goconvey/convey"
)

type Unhashable map[string]interface{}

func (u Unhashable) Close() error {
	return nil
}

func TestDeath(t *testing.T) {

	Convey("Validate death handles unhashable types", t, func() {
		u := make(Unhashable)
		death := NewDeath(syscall.SIGTERM)
		syscall.Kill(os.Getpid(), syscall.SIGTERM)
		err := death.WaitForDeath(u)
		So(err, ShouldBeNil)
	})

	Convey("Validate death happens cleanly", t, func() {
		death := NewDeath(syscall.SIGTERM)
		syscall.Kill(os.Getpid(), syscall.SIGTERM)
		err := death.WaitForDeath()
		So(err, ShouldBeNil)
	})

	Convey("Validate death happens with other signals", t, func() {
		death := NewDeath(syscall.SIGHUP)
		closeMe := &CloseMe{}
		syscall.Kill(os.Getpid(), syscall.SIGHUP)
		err := death.WaitForDeath(closeMe)
		So(err, ShouldBeNil)
		So(closeMe.Closed, ShouldEqual, 1)
	})

	Convey("Validate death happens with a manual call", t, func() {
		death := NewDeath(syscall.SIGHUP)
		closeMe := &CloseMe{}
		death.FallOnSword()
		err := death.WaitForDeath(closeMe)
		So(err, ShouldBeNil)
		So(closeMe.Closed, ShouldEqual, 1)
	})

	Convey("Validate multiple sword falls do not block", t, func() {
		death := NewDeath(syscall.SIGHUP)
		closeMe := &CloseMe{}
		death.FallOnSword()
		death.FallOnSword()
		err := death.WaitForDeath(closeMe)
		So(err, ShouldBeNil)
		So(closeMe.Closed, ShouldEqual, 1)
	})

	Convey("Validate multiple sword falls do not block even after we have exited waitForDeath", t, func() {
		death := NewDeath(syscall.SIGHUP)
		closeMe := &CloseMe{}
		death.FallOnSword()
		death.FallOnSword()
		err := death.WaitForDeath(closeMe)
		So(err, ShouldBeNil)
		death.FallOnSword()
		death.FallOnSword()
		So(closeMe.Closed, ShouldEqual, 1)
	})

	Convey("Validate death gives up after timeout", t, func() {
		death := NewDeath(syscall.SIGHUP)
		death.SetTimeout(10 * time.Millisecond)
		neverClose := &neverClose{}
		syscall.Kill(os.Getpid(), syscall.SIGHUP)
		err := death.WaitForDeath(neverClose)
		So(err, ShouldNotBeNil)
	})

	Convey("Validate death uses new logger", t, func() {
		death := NewDeath(syscall.SIGHUP)
		closeMe := &CloseMe{}
		logger := &MockLogger{}
		death.SetLogger(logger)

		syscall.Kill(os.Getpid(), syscall.SIGHUP)
		err := death.WaitForDeath(closeMe)
		So(err, ShouldBeNil)
		So(closeMe.Closed, ShouldEqual, 1)
		So(logger.Logs, ShouldNotBeEmpty)
	})

	Convey("Close multiple things with one that fails the timer", t, func() {
		death := NewDeath(syscall.SIGHUP)
		death.SetTimeout(10 * time.Millisecond)
		neverClose := &neverClose{}
		closeMe := &CloseMe{}
		syscall.Kill(os.Getpid(), syscall.SIGHUP)
		err := death.WaitForDeath(neverClose, closeMe)
		So(err, ShouldNotBeNil)
		So(closeMe.Closed, ShouldEqual, 1)
	})

	Convey("Close with anonymous function", t, func() {
		death := NewDeath(syscall.SIGHUP)
		death.SetTimeout(5 * time.Millisecond)
		closeMe := &CloseMe{}
		syscall.Kill(os.Getpid(), syscall.SIGHUP)
		death.WaitForDeathWithFunc(func() {
			closeMe.Close()
			So(true, ShouldBeTrue)
		})
		So(closeMe.Closed, ShouldEqual, 1)
	})

	Convey("Validate death errors when closer returns error", t, func() {
		death := NewDeath(syscall.SIGHUP)
		killMe := &KillMe{}
		death.FallOnSword()
		err := death.WaitForDeath(killMe)
		So(err, ShouldNotBeNil)
	})

}

func TestGenerateErrString(t *testing.T) {
	Convey("Generate for multiple errors", t, func() {
		closers := []closer{
			closer{
				Err:     fmt.Errorf("error 1"),
				Name:    "foo",
				PKGPath: "my/pkg",
			},
			closer{
				Err:     fmt.Errorf("error 2"),
				Name:    "bar",
				PKGPath: "my/otherpkg",
			},
		}

		expected := "my/pkg/foo: error 1, my/otherpkg/bar: error 2"
		actual := generateErrString(closers)

		So(actual, ShouldEqual, expected)
	})

	Convey("Generate for single error", t, func() {
		closers := []closer{
			closer{
				Err:     fmt.Errorf("error 1"),
				Name:    "foo",
				PKGPath: "my/pkg",
			},
		}

		expected := "my/pkg/foo: error 1"
		actual := generateErrString(closers)

		So(actual, ShouldEqual, expected)
	})
}

type MockLogger struct {
	Logs []interface{}
}

func (l *MockLogger) Info(v ...interface{}) {
	for _, log := range v {
		l.Logs = append(l.Logs, log)
	}
}

func (l *MockLogger) Debug(v ...interface{}) {
	for _, log := range v {
		l.Logs = append(l.Logs, log)
	}
}

func (l *MockLogger) Error(v ...interface{}) {
	for _, log := range v {
		l.Logs = append(l.Logs, log)
	}
}

func (l *MockLogger) Warn(v ...interface{}) {
	for _, log := range v {
		l.Logs = append(l.Logs, log)
	}
}

type neverClose struct {
}

func (n *neverClose) Close() error {
	time.Sleep(2 * time.Minute)
	return nil
}

// CloseMe returns nil from close
type CloseMe struct {
	Closed int
}

func (c *CloseMe) Close() error {
	c.Closed++
	return nil
}

// KillMe returns an error from close
type KillMe struct{}

func (c *KillMe) Close() error {
	return fmt.Errorf("error from closer")
}


================================================
FILE: death_windows_test.go
================================================
package death

import (
	"bytes"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"syscall"
	"testing"
	"time"

	. "github.com/smartystreets/goconvey/convey"
)

func TestDeath(t *testing.T) {

	Convey("Validate death happens cleanly on windows with ctrl-c event", t, func() {
		// create source file
		const source = `
package main
import (
	"syscall"
	"github.com/vrecan/death/v3"
)
func main() {
	death := death.NewDeath(syscall.SIGINT)
	death.WaitForDeath()
}
`
		tmp, err := ioutil.TempDir("", "TestCtrlBreak")
		if err != nil {
			t.Fatal("TempDir failed: ", err)
		}
		defer os.RemoveAll(tmp)

		// write ctrlbreak.go
		name := filepath.Join(tmp, "ctlbreak")
		src := name + ".go"
		f, err := os.Create(src)
		if err != nil {
			t.Fatalf("Failed to create %v: %v", src, err)
		}
		defer f.Close()
		f.Write([]byte(source))

		// compile it
		exe := name + ".exe"
		defer os.Remove(exe)
		o, err := exec.Command("go", "build", "-o", exe, src).CombinedOutput()
		if err != nil {
			t.Fatalf("Failed to compile: %v\n%v", err, string(o))
		}

		// run it
		cmd := exec.Command(exe)
		var b bytes.Buffer
		cmd.Stdout = &b
		cmd.Stderr = &b
		cmd.SysProcAttr = &syscall.SysProcAttr{
			CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP,
		}
		err = cmd.Start()
		if err != nil {
			t.Fatalf("Start failed: %v", err)
		}
		go func() {
			time.Sleep(1 * time.Second)
			sendCtrlBreak(t, cmd.Process.Pid)
		}()
		err = cmd.Wait()
		if err != nil {
			t.Fatalf("Program exited with error: %v\n%v", err, string(b.Bytes()))
		}
	})
}

func sendCtrlBreak(t *testing.T, pid int) {
	d, e := syscall.LoadDLL("kernel32.dll")
	if e != nil {
		t.Fatalf("LoadDLL: %v\n", e)
	}
	p, e := d.FindProc("GenerateConsoleCtrlEvent")
	if e != nil {
		t.Fatalf("FindProc: %v\n", e)
	}
	r, _, e := p.Call(syscall.CTRL_BREAK_EVENT, uintptr(pid))
	if r == 0 {
		t.Fatalf("GenerateConsoleCtrlEvent: %v\n", e)
	}
}


================================================
FILE: deathlog.go
================================================
package death

// Logger interface to log.
type Logger interface {
	Error(v ...interface{})
	Debug(v ...interface{})
	Info(v ...interface{})
}

type defaultLogger struct{}

var logger = defaultLogger{}

// DefaultLogger returns a logger that does nothing
func DefaultLogger() Logger {
	return logger
}

func (d defaultLogger) Error(v ...interface{}) {}
func (d defaultLogger) Debug(v ...interface{}) {}
func (d defaultLogger) Info(v ...interface{})  {}


================================================
FILE: go.mod
================================================
module github.com/vrecan/death/v3

go 1.18

require github.com/smartystreets/goconvey v1.7.2

require (
	github.com/gopherjs/gopherjs v0.0.0-20211219123610-ec9572f70e60 // indirect
	github.com/jtolds/gls v4.20.0+incompatible // indirect
	github.com/smartystreets/assertions v1.2.1 // indirect
)


================================================
FILE: go.sum
================================================
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20211219123610-ec9572f70e60 h1:btMZK5oA0NpSAOOE7zRfq2UEuPC9apJ2UBackURyaTU=
github.com/gopherjs/gopherjs v0.0.0-20211219123610-ec9572f70e60/go.mod h1:cz9oNYuRUWGdHmLF2IodMLkAhcPtXeULvcBNagUrxTI=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
github.com/smartystreets/assertions v1.2.1 h1:bKNHfEv7tSIjZ8JbKaFjzFINljxG4lzZvmHUnElzOIg=
github.com/smartystreets/assertions v1.2.1/go.mod h1:wDmR7qL282YbGsPy6H/yAsesrxfxaaSlJazyFLYVFx8=
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=


================================================
FILE: pkgPath_test.go
================================================
package death

import (
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestGetPkgPath(t *testing.T) {

	Convey("Give pkgPath a ptr", t, func() {
		c := &Closer{}
		name, pkgPath := getPkgPath(c)
		So(name, ShouldEqual, "Closer")
		So(pkgPath, ShouldEqual, "github.com/vrecan/death/v3")

	})

	Convey("Give pkgPath a interface", t, func() {
		var closable Closable
		closable = Closer{}
		name, pkgPath := getPkgPath(closable)
		So(name, ShouldEqual, "Closer")
		So(pkgPath, ShouldEqual, "github.com/vrecan/death/v3")
	})

	Convey("Give pkgPath a copy", t, func() {
		c := Closer{}
		name, pkgPath := getPkgPath(c)
		So(name, ShouldEqual, "Closer")
		So(pkgPath, ShouldEqual, "github.com/vrecan/death/v3")
	})
}

type Closable interface {
	Close() error
}
type Closer struct {
}

func (c Closer) Close() error {
	return nil
}
Download .txt
gitextract_9tv2jfz4/

├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── death.go
├── death_unix_test.go
├── death_windows_test.go
├── deathlog.go
├── go.mod
├── go.sum
└── pkgPath_test.go
Download .txt
SYMBOL INDEX (40 symbols across 5 files)

FILE: death.go
  type Death (line 17) | type Death struct
    method SetTimeout (line 49) | func (d *Death) SetTimeout(t time.Duration) *Death {
    method SetLogger (line 55) | func (d *Death) SetLogger(l Logger) *Death {
    method WaitForDeath (line 62) | func (d *Death) WaitForDeath(closable ...io.Closer) (err error) {
    method WaitForDeathWithFunc (line 75) | func (d *Death) WaitForDeathWithFunc(f func()) {
    method closeInMass (line 92) | func (d *Death) closeInMass(closable ...io.Closer) (err error) {
    method closeObjects (line 141) | func (d *Death) closeObjects(closer closer, done chan<- closer) {
    method FallOnSword (line 151) | func (d *Death) FallOnSword() {
    method listenForSignal (line 159) | func (d *Death) listenForSignal() {
  type closer (line 27) | type closer struct
  function NewDeath (line 36) | func NewDeath(signals ...os.Signal) (death *Death) {
  function getPkgPath (line 82) | func getPkgPath(c io.Closer) (name string, pkgPath string) {
  function generateErrString (line 172) | func generateErrString(failedClosers []closer) (errString string) {

FILE: death_unix_test.go
  type Unhashable (line 15) | type Unhashable
    method Close (line 17) | func (u Unhashable) Close() error {
  function TestDeath (line 21) | func TestDeath(t *testing.T) {
  function TestGenerateErrString (line 133) | func TestGenerateErrString(t *testing.T) {
  type MockLogger (line 170) | type MockLogger struct
    method Info (line 174) | func (l *MockLogger) Info(v ...interface{}) {
    method Debug (line 180) | func (l *MockLogger) Debug(v ...interface{}) {
    method Error (line 186) | func (l *MockLogger) Error(v ...interface{}) {
    method Warn (line 192) | func (l *MockLogger) Warn(v ...interface{}) {
  type neverClose (line 198) | type neverClose struct
    method Close (line 201) | func (n *neverClose) Close() error {
  type CloseMe (line 207) | type CloseMe struct
    method Close (line 211) | func (c *CloseMe) Close() error {
  type KillMe (line 217) | type KillMe struct
    method Close (line 219) | func (c *KillMe) Close() error {

FILE: death_windows_test.go
  function TestDeath (line 16) | func TestDeath(t *testing.T) {
  function sendCtrlBreak (line 78) | func sendCtrlBreak(t *testing.T, pid int) {

FILE: deathlog.go
  type Logger (line 4) | type Logger interface
  type defaultLogger (line 10) | type defaultLogger struct
    method Error (line 19) | func (d defaultLogger) Error(v ...interface{}) {}
    method Debug (line 20) | func (d defaultLogger) Debug(v ...interface{}) {}
    method Info (line 21) | func (d defaultLogger) Info(v ...interface{})  {}
  function DefaultLogger (line 15) | func DefaultLogger() Logger {

FILE: pkgPath_test.go
  function TestGetPkgPath (line 9) | func TestGetPkgPath(t *testing.T) {
  type Closable (line 35) | type Closable interface
  type Closer (line 38) | type Closer struct
    method Close (line 41) | func (c Closer) Close() error {
Condensed preview — 11 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (24K chars).
[
  {
    "path": ".gitignore",
    "chars": 337,
    "preview": "# Created by .ignore support plugin (hsz.mobi)\n### Go template\n# Compiled Object files, Static and Dynamic libs (Shared "
  },
  {
    "path": ".travis.yml",
    "chars": 240,
    "preview": "language: go\nsudo: false\ngo:\n  - \"1.14\"\nbefore_install:\n  - go get github.com/mattn/goveralls\n  - export PATH=$PATH:$HOM"
  },
  {
    "path": "LICENSE",
    "chars": 1079,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2015 Ben Aldrich\n\nPermission is hereby granted, free of charge, to any person obtai"
  },
  {
    "path": "README.md",
    "chars": 5914,
    "preview": "# Death [![Build Status](https://travis-ci.org/vrecan/death.svg?branch=master)](https://travis-ci.org/vrecan/death) [![C"
  },
  {
    "path": "death.go",
    "chars": 4443,
    "preview": "package death\n\n//Manage the death of your application.\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/signal\"\n\t\"reflect\"\n\t\"strings\"\n\t"
  },
  {
    "path": "death_unix_test.go",
    "chars": 5000,
    "preview": "// +build linux bsd darwin\n\npackage death\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"syscall\"\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/smartystr"
  },
  {
    "path": "death_windows_test.go",
    "chars": 1883,
    "preview": "package death\n\nimport (\n\t\"bytes\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"syscall\"\n\t\"testing\"\n\t\"time\"\n\n\t. \"githu"
  },
  {
    "path": "deathlog.go",
    "chars": 453,
    "preview": "package death\n\n// Logger interface to log.\ntype Logger interface {\n\tError(v ...interface{})\n\tDebug(v ...interface{})\n\tIn"
  },
  {
    "path": "go.mod",
    "chars": 295,
    "preview": "module github.com/vrecan/death/v3\n\ngo 1.18\n\nrequire github.com/smartystreets/goconvey v1.7.2\n\nrequire (\n\tgithub.com/goph"
  },
  {
    "path": "go.sum",
    "chars": 1524,
    "preview": "github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ng"
  },
  {
    "path": "pkgPath_test.go",
    "chars": 844,
    "preview": "package death\n\nimport (\n\t\"testing\"\n\n\t. \"github.com/smartystreets/goconvey/convey\"\n)\n\nfunc TestGetPkgPath(t *testing.T) {"
  }
]

About this extraction

This page contains the full source code of the vrecan/death GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 11 files (21.5 KB), approximately 6.6k tokens, and a symbol index with 40 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!