Merge lp:~kyrofa/crackly/vendor_dependencies into lp:crackly

Proposed by Kyle Fazzari on 2015-10-30
Status: Merged
Approved by: Kyle Fazzari on 2015-10-30
Approved revision: 4
Merged at revision: 3
Proposed branch: lp:~kyrofa/crackly/vendor_dependencies
Merge into: lp:crackly
Prerequisite: lp:~kyrofa/crackly/desktop_file_support
Diff against target: 47805 lines (+46640/-40)
205 files modified
internal/github.com/blakesmith/ar/README.md (+7/-0)
internal/github.com/blakesmith/ar/common.go (+27/-0)
internal/github.com/blakesmith/ar/reader.go (+134/-0)
internal/github.com/blakesmith/ar/reader_test.go (+92/-0)
internal/github.com/blakesmith/ar/writer.go (+103/-0)
internal/github.com/blakesmith/ar/writer_test.go (+71/-0)
internal/github.com/cheggaaa/pb/LICENSE (+12/-0)
internal/github.com/cheggaaa/pb/README.md (+98/-0)
internal/github.com/cheggaaa/pb/format.go (+42/-0)
internal/github.com/cheggaaa/pb/format_test.go (+37/-0)
internal/github.com/cheggaaa/pb/pb.go (+341/-0)
internal/github.com/cheggaaa/pb/pb_nix.go (+7/-0)
internal/github.com/cheggaaa/pb/pb_solaris.go (+5/-0)
internal/github.com/cheggaaa/pb/pb_test.go (+30/-0)
internal/github.com/cheggaaa/pb/pb_win.go (+16/-0)
internal/github.com/cheggaaa/pb/pb_x.go (+46/-0)
internal/github.com/cheggaaa/pb/reader.go (+17/-0)
internal/github.com/gosexy/gettext/LICENSE (+20/-0)
internal/github.com/gosexy/gettext/README.md (+94/-0)
internal/github.com/gosexy/gettext/gettext.go (+207/-0)
internal/github.com/gosexy/gettext/gettext_test.go (+130/-0)
internal/github.com/mvo5/goconfigparser/COPYING (+19/-0)
internal/github.com/mvo5/goconfigparser/README.md (+18/-0)
internal/github.com/mvo5/goconfigparser/configparser.go (+181/-0)
internal/github.com/mvo5/goconfigparser/configparser_test.go (+127/-0)
internal/github.com/mvo5/uboot-go/uenv/env.go (+235/-0)
internal/github.com/mvo5/uboot-go/uenv/env_test.go (+203/-0)
internal/github.com/olekukonko/ts/LICENCE (+19/-0)
internal/github.com/olekukonko/ts/README.md (+28/-0)
internal/github.com/olekukonko/ts/doc.go (+36/-0)
internal/github.com/olekukonko/ts/ts.go (+36/-0)
internal/github.com/olekukonko/ts/ts_darwin.go (+14/-0)
internal/github.com/olekukonko/ts/ts_linux.go (+13/-0)
internal/github.com/olekukonko/ts/ts_other.go (+14/-0)
internal/github.com/olekukonko/ts/ts_test.go (+32/-0)
internal/github.com/olekukonko/ts/ts_unix.go (+14/-0)
internal/github.com/olekukonko/ts/ts_windows.go (+64/-0)
internal/github.com/olekukonko/ts/ts_x.go (+46/-0)
internal/gopkg.in/check.v1/LICENSE (+25/-0)
internal/gopkg.in/check.v1/README.md (+20/-0)
internal/gopkg.in/check.v1/TODO (+2/-0)
internal/gopkg.in/check.v1/benchmark.go (+163/-0)
internal/gopkg.in/check.v1/benchmark_test.go (+91/-0)
internal/gopkg.in/check.v1/bootstrap_test.go (+82/-0)
internal/gopkg.in/check.v1/check.go (+945/-0)
internal/gopkg.in/check.v1/check_test.go (+207/-0)
internal/gopkg.in/check.v1/checkers.go (+458/-0)
internal/gopkg.in/check.v1/checkers_test.go (+272/-0)
internal/gopkg.in/check.v1/export_test.go (+9/-0)
internal/gopkg.in/check.v1/fixture_test.go (+484/-0)
internal/gopkg.in/check.v1/foundation_test.go (+335/-0)
internal/gopkg.in/check.v1/helpers.go (+231/-0)
internal/gopkg.in/check.v1/helpers_test.go (+519/-0)
internal/gopkg.in/check.v1/printer.go (+168/-0)
internal/gopkg.in/check.v1/printer_test.go (+109/-0)
internal/gopkg.in/check.v1/run.go (+175/-0)
internal/gopkg.in/check.v1/run_test.go (+419/-0)
internal/gopkg.in/yaml.v2/LICENSE (+188/-0)
internal/gopkg.in/yaml.v2/LICENSE.libyaml (+31/-0)
internal/gopkg.in/yaml.v2/README.md (+128/-0)
internal/gopkg.in/yaml.v2/apic.go (+742/-0)
internal/gopkg.in/yaml.v2/decode.go (+683/-0)
internal/gopkg.in/yaml.v2/decode_test.go (+966/-0)
internal/gopkg.in/yaml.v2/emitterc.go (+1685/-0)
internal/gopkg.in/yaml.v2/encode.go (+306/-0)
internal/gopkg.in/yaml.v2/encode_test.go (+501/-0)
internal/gopkg.in/yaml.v2/parserc.go (+1096/-0)
internal/gopkg.in/yaml.v2/readerc.go (+391/-0)
internal/gopkg.in/yaml.v2/resolve.go (+203/-0)
internal/gopkg.in/yaml.v2/scannerc.go (+2710/-0)
internal/gopkg.in/yaml.v2/sorter.go (+104/-0)
internal/gopkg.in/yaml.v2/suite_test.go (+12/-0)
internal/gopkg.in/yaml.v2/writerc.go (+89/-0)
internal/gopkg.in/yaml.v2/yaml.go (+346/-0)
internal/gopkg.in/yaml.v2/yamlh.go (+716/-0)
internal/gopkg.in/yaml.v2/yamlprivateh.go (+173/-0)
internal/launchpad.net/gocheck/LICENSE (+25/-0)
internal/launchpad.net/gocheck/Makefile (+30/-0)
internal/launchpad.net/gocheck/TODO (+2/-0)
internal/launchpad.net/gocheck/benchmark.go (+136/-0)
internal/launchpad.net/gocheck/benchmark_test.go (+75/-0)
internal/launchpad.net/gocheck/bootstrap_test.go (+82/-0)
internal/launchpad.net/gocheck/checkers.go (+458/-0)
internal/launchpad.net/gocheck/checkers_test.go (+272/-0)
internal/launchpad.net/gocheck/export_test.go (+9/-0)
internal/launchpad.net/gocheck/fixture_test.go (+479/-0)
internal/launchpad.net/gocheck/foundation_test.go (+335/-0)
internal/launchpad.net/gocheck/gocheck.go (+917/-0)
internal/launchpad.net/gocheck/gocheck_test.go (+196/-0)
internal/launchpad.net/gocheck/helpers.go (+224/-0)
internal/launchpad.net/gocheck/helpers_test.go (+491/-0)
internal/launchpad.net/gocheck/printer.go (+168/-0)
internal/launchpad.net/gocheck/printer_test.go (+109/-0)
internal/launchpad.net/gocheck/run.go (+152/-0)
internal/launchpad.net/gocheck/run_test.go (+397/-0)
internal/launchpad.net/snappy/clickdeb/deb.go (+504/-0)
internal/launchpad.net/snappy/clickdeb/deb_test.go (+241/-0)
internal/launchpad.net/snappy/clickdeb/verify.go (+97/-0)
internal/launchpad.net/snappy/clickdeb/verify_test.go (+87/-0)
internal/launchpad.net/snappy/coreconfig/config.go (+262/-0)
internal/launchpad.net/snappy/coreconfig/config_test.go (+400/-0)
internal/launchpad.net/snappy/helpers/cmp.go (+118/-0)
internal/launchpad.net/snappy/helpers/cmp_test.go (+148/-0)
internal/launchpad.net/snappy/helpers/cp.go (+136/-0)
internal/launchpad.net/snappy/helpers/cp_linux.go (+48/-0)
internal/launchpad.net/snappy/helpers/cp_linux_test.go (+46/-0)
internal/launchpad.net/snappy/helpers/cp_other.go (+31/-0)
internal/launchpad.net/snappy/helpers/cp_test.go (+214/-0)
internal/launchpad.net/snappy/helpers/helpers.go (+525/-0)
internal/launchpad.net/snappy/helpers/helpers_test.go (+485/-0)
internal/launchpad.net/snappy/helpers/touch.go (+61/-0)
internal/launchpad.net/snappy/helpers/touch_test.go (+76/-0)
internal/launchpad.net/snappy/helpers/winsize.go (+48/-0)
internal/launchpad.net/snappy/i18n/i18n.go (+45/-0)
internal/launchpad.net/snappy/i18n/i18n_test.go (+111/-0)
internal/launchpad.net/snappy/logger/logger.go (+151/-0)
internal/launchpad.net/snappy/logger/logger_test.go (+134/-0)
internal/launchpad.net/snappy/oauth/oauth.go (+80/-0)
internal/launchpad.net/snappy/oauth/oauth_test.go (+69/-0)
internal/launchpad.net/snappy/partition/assets.go (+87/-0)
internal/launchpad.net/snappy/partition/assets_test.go (+36/-0)
internal/launchpad.net/snappy/partition/bootloader.go (+300/-0)
internal/launchpad.net/snappy/partition/bootloader_grub.go (+133/-0)
internal/launchpad.net/snappy/partition/bootloader_grub_test.go (+182/-0)
internal/launchpad.net/snappy/partition/bootloader_uboot.go (+268/-0)
internal/launchpad.net/snappy/partition/bootloader_uboot_test.go (+384/-0)
internal/launchpad.net/snappy/partition/dirs.go (+41/-0)
internal/launchpad.net/snappy/partition/mount.go (+153/-0)
internal/launchpad.net/snappy/partition/mount_test.go (+64/-0)
internal/launchpad.net/snappy/partition/partition.go (+622/-0)
internal/launchpad.net/snappy/partition/partition_test.go (+450/-0)
internal/launchpad.net/snappy/partition/utils.go (+82/-0)
internal/launchpad.net/snappy/partition/utils_test.go (+47/-0)
internal/launchpad.net/snappy/pkg/types.go (+60/-0)
internal/launchpad.net/snappy/pkg/types_test.go (+66/-0)
internal/launchpad.net/snappy/policy/policy.go (+144/-0)
internal/launchpad.net/snappy/policy/policy_test.go (+186/-0)
internal/launchpad.net/snappy/progress/isatty.go (+31/-0)
internal/launchpad.net/snappy/progress/progress.go (+204/-0)
internal/launchpad.net/snappy/progress/progress_test.go (+150/-0)
internal/launchpad.net/snappy/provisioning/provisioning.go (+150/-0)
internal/launchpad.net/snappy/provisioning/provisioning_test.go (+183/-0)
internal/launchpad.net/snappy/release/release.go (+99/-0)
internal/launchpad.net/snappy/release/release_test.go (+97/-0)
internal/launchpad.net/snappy/snappy/arch.go (+48/-0)
internal/launchpad.net/snappy/snappy/auth.go (+160/-0)
internal/launchpad.net/snappy/snappy/auth_test.go (+148/-0)
internal/launchpad.net/snappy/snappy/build.go (+574/-0)
internal/launchpad.net/snappy/snappy/build_test.go (+495/-0)
internal/launchpad.net/snappy/snappy/click.go (+812/-0)
internal/launchpad.net/snappy/snappy/click_test.go (+1564/-0)
internal/launchpad.net/snappy/snappy/common_test.go (+238/-0)
internal/launchpad.net/snappy/snappy/config.go (+71/-0)
internal/launchpad.net/snappy/snappy/config_test.go (+129/-0)
internal/launchpad.net/snappy/snappy/datadir.go (+106/-0)
internal/launchpad.net/snappy/snappy/datadir_test.go (+121/-0)
internal/launchpad.net/snappy/snappy/dbus.go (+84/-0)
internal/launchpad.net/snappy/snappy/dbus_test.go (+95/-0)
internal/launchpad.net/snappy/snappy/dirs.go (+74/-0)
internal/launchpad.net/snappy/snappy/errors.go (+275/-0)
internal/launchpad.net/snappy/snappy/firstboot.go (+152/-0)
internal/launchpad.net/snappy/snappy/firstboot_test.go (+190/-0)
internal/launchpad.net/snappy/snappy/globals.go (+40/-0)
internal/launchpad.net/snappy/snappy/hashes.go (+121/-0)
internal/launchpad.net/snappy/snappy/hashes_test.go (+154/-0)
internal/launchpad.net/snappy/snappy/hwaccess.go (+248/-0)
internal/launchpad.net/snappy/snappy/hwaccess_test.go (+300/-0)
internal/launchpad.net/snappy/snappy/install.go (+185/-0)
internal/launchpad.net/snappy/snappy/install_test.go (+265/-0)
internal/launchpad.net/snappy/snappy/list.go (+34/-0)
internal/launchpad.net/snappy/snappy/oem.go (+293/-0)
internal/launchpad.net/snappy/snappy/oem_test.go (+93/-0)
internal/launchpad.net/snappy/snappy/parts.go (+335/-0)
internal/launchpad.net/snappy/snappy/parts_test.go (+180/-0)
internal/launchpad.net/snappy/snappy/purge.go (+93/-0)
internal/launchpad.net/snappy/snappy/purge_test.go (+200/-0)
internal/launchpad.net/snappy/snappy/remove.go (+72/-0)
internal/launchpad.net/snappy/snappy/remove_test.go (+87/-0)
internal/launchpad.net/snappy/snappy/rollback.go (+56/-0)
internal/launchpad.net/snappy/snappy/rollback_test.go (+63/-0)
internal/launchpad.net/snappy/snappy/search.go (+29/-0)
internal/launchpad.net/snappy/snappy/security.go (+226/-0)
internal/launchpad.net/snappy/snappy/security_test.go (+302/-0)
internal/launchpad.net/snappy/snappy/service.go (+180/-0)
internal/launchpad.net/snappy/snappy/service_test.go (+160/-0)
internal/launchpad.net/snappy/snappy/set.go (+57/-0)
internal/launchpad.net/snappy/snappy/set_test.go (+99/-0)
internal/launchpad.net/snappy/snappy/snapp.go (+1911/-0)
internal/launchpad.net/snappy/snappy/snapp_test.go (+1615/-0)
internal/launchpad.net/snappy/snappy/sort.go (+206/-0)
internal/launchpad.net/snappy/snappy/sort_test.go (+103/-0)
internal/launchpad.net/snappy/snappy/systemimage.go (+518/-0)
internal/launchpad.net/snappy/snappy/systemimage_native.go (+211/-0)
internal/launchpad.net/snappy/snappy/systemimage_native_test.go (+123/-0)
internal/launchpad.net/snappy/snappy/systemimage_test.go (+486/-0)
internal/launchpad.net/snappy/snappy/timeout.go (+63/-0)
internal/launchpad.net/snappy/snappy/timeout_test.go (+49/-0)
internal/launchpad.net/snappy/systemd/systemd.go (+315/-0)
internal/launchpad.net/snappy/systemd/systemd_test.go (+314/-0)
internal/vendor.json (+166/-0)
main.go (+1/-1)
operations/generate_desktop_files.go (+31/-31)
operations/install.go (+3/-3)
operations/remove.go (+2/-2)
snap/metadata.go (+3/-3)
To merge this branch: bzr merge lp:~kyrofa/crackly/vendor_dependencies
Reviewer Review Type Date Requested Status
Unity API Team 2015-10-30 Pending
Review via email: mp+276269@code.launchpad.net

This proposal supersedes a proposal from 2015-10-30.

Commit message

Vendor all dependencies.

Description of the change

Vendor all dependencies.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'internal'
2=== added directory 'internal/github.com'
3=== added directory 'internal/github.com/blakesmith'
4=== added directory 'internal/github.com/blakesmith/ar'
5=== added file 'internal/github.com/blakesmith/ar/README.md'
6--- internal/github.com/blakesmith/ar/README.md 1970-01-01 00:00:00 +0000
7+++ internal/github.com/blakesmith/ar/README.md 2015-10-30 14:13:06 +0000
8@@ -0,0 +1,7 @@
9+# Golang ar (archive) file reader
10+
11+This is a simple library for reading and writing [ar](http://en.wikipedia.org/wiki/Ar_(Unix)) files in common format. It is influenced heavily in style and interface from the golang [tar](http://golang.org/pkg/archive/tar/) package.
12+
13+## Author
14+
15+Written by Blake Smith <blakesmith0@gmail.com>
16
17=== added file 'internal/github.com/blakesmith/ar/common.go'
18--- internal/github.com/blakesmith/ar/common.go 1970-01-01 00:00:00 +0000
19+++ internal/github.com/blakesmith/ar/common.go 2015-10-30 14:13:06 +0000
20@@ -0,0 +1,27 @@
21+package ar
22+
23+import (
24+ "time"
25+)
26+
27+const (
28+ HEADER_BYTE_SIZE = 60
29+ GLOBAL_HEADER = "!<arch>\n"
30+)
31+
32+type Header struct {
33+ Name string
34+ ModTime time.Time
35+ Uid int
36+ Gid int
37+ Mode int64
38+ Size int64
39+}
40+
41+type slicer []byte
42+
43+func (sp *slicer) next(n int) (b []byte) {
44+ s := *sp
45+ b, *sp = s[0:n], s[n:]
46+ return
47+}
48
49=== added file 'internal/github.com/blakesmith/ar/reader.go'
50--- internal/github.com/blakesmith/ar/reader.go 1970-01-01 00:00:00 +0000
51+++ internal/github.com/blakesmith/ar/reader.go 2015-10-30 14:13:06 +0000
52@@ -0,0 +1,134 @@
53+package ar
54+
55+import (
56+ "io"
57+ "io/ioutil"
58+ "os"
59+ "strconv"
60+ "time"
61+)
62+
63+// Provides read access to an ar archive.
64+// Call next to skip files
65+//
66+// Example:
67+// reader := NewReader(f)
68+// var buf bytes.Buffer
69+// for {
70+// _, err := reader.Next()
71+// if err == io.EOF {
72+// break
73+// }
74+// if err != nil {
75+// t.Errorf(err.Error())
76+// }
77+// io.Copy(&buf, reader)
78+// }
79+
80+type Reader struct {
81+ r io.Reader
82+ nb int64
83+ pad int64
84+}
85+
86+// Copies read data to r. Strips the global ar header.
87+func NewReader(r io.Reader) *Reader {
88+ io.CopyN(ioutil.Discard, r, 8) // Discard global header
89+
90+ return &Reader{r: r}
91+}
92+
93+func (rd *Reader) string(b []byte) string {
94+ i := len(b) - 1
95+ for i > 0 && b[i] == 32 {
96+ i--
97+ }
98+
99+ return string(b[0 : i+1])
100+}
101+
102+func (rd *Reader) numeric(b []byte) int64 {
103+ i := len(b) - 1
104+ for i > 0 && b[i] == 32 {
105+ i--
106+ }
107+
108+ n, _ := strconv.ParseInt(string(b[0:i+1]), 10, 64)
109+
110+ return n
111+}
112+
113+func (rd *Reader) octal(b []byte) int64 {
114+ i := len(b) - 1
115+ for i > 0 && b[i] == 32 {
116+ i--
117+ }
118+
119+ n, _ := strconv.ParseInt(string(b[3:i+1]), 8, 64)
120+
121+ return n
122+}
123+
124+func (rd *Reader) skipUnread() error {
125+ skip := rd.nb + rd.pad
126+ rd.nb, rd.pad = 0, 0
127+ if seeker, ok := rd.r.(io.Seeker); ok {
128+ _, err := seeker.Seek(skip, os.SEEK_CUR)
129+ return err
130+ }
131+
132+ _, err := io.CopyN(ioutil.Discard, rd.r, skip)
133+ return err
134+}
135+
136+func (rd *Reader) readHeader() (*Header, error) {
137+ headerBuf := make([]byte, HEADER_BYTE_SIZE)
138+ if _, err := io.ReadFull(rd.r, headerBuf); err != nil {
139+ return nil, err
140+ }
141+
142+ header := new(Header)
143+ s := slicer(headerBuf)
144+
145+ header.Name = rd.string(s.next(16))
146+ header.ModTime = time.Unix(rd.numeric(s.next(12)), 0)
147+ header.Uid = int(rd.numeric(s.next(6)))
148+ header.Gid = int(rd.numeric(s.next(6)))
149+ header.Mode = rd.octal(s.next(8))
150+ header.Size = rd.numeric(s.next(10))
151+
152+ rd.nb = int64(header.Size)
153+ if header.Size%2 == 1 {
154+ rd.pad = 1
155+ } else {
156+ rd.pad = 0
157+ }
158+
159+ return header, nil
160+}
161+
162+// Call Next() to skip to the next file in the archive file.
163+// Returns a Header which contains the metadata about the
164+// file in the archive.
165+func (rd *Reader) Next() (*Header, error) {
166+ err := rd.skipUnread()
167+ if err != nil {
168+ return nil, err
169+ }
170+
171+ return rd.readHeader()
172+}
173+
174+// Read data from the current entry in the archive.
175+func (rd *Reader) Read(b []byte) (n int, err error) {
176+ if rd.nb == 0 {
177+ return 0, io.EOF
178+ }
179+ if int64(len(b)) > rd.nb {
180+ b = b[0:rd.nb]
181+ }
182+ n, err = rd.r.Read(b)
183+ rd.nb -= int64(n)
184+
185+ return
186+}
187
188=== added file 'internal/github.com/blakesmith/ar/reader_test.go'
189--- internal/github.com/blakesmith/ar/reader_test.go 1970-01-01 00:00:00 +0000
190+++ internal/github.com/blakesmith/ar/reader_test.go 2015-10-30 14:13:06 +0000
191@@ -0,0 +1,92 @@
192+package ar
193+
194+import (
195+ "bytes"
196+ "io"
197+ "os"
198+ "testing"
199+ "time"
200+)
201+
202+func TestReadHeader(t *testing.T) {
203+ f, err := os.Open("./fixtures/hello.a")
204+ defer f.Close()
205+
206+ if err != nil {
207+ t.Errorf(err.Error())
208+ }
209+ reader := NewReader(f)
210+ header, err := reader.Next()
211+ if err != nil {
212+ t.Errorf(err.Error())
213+ }
214+
215+ expectedName := "hello.txt"
216+ if header.Name != expectedName {
217+ t.Errorf("Header name should be %s but is %s", expectedName, header.Name)
218+ }
219+ expectedModTime := time.Unix(1361157466, 0)
220+ if header.ModTime != expectedModTime {
221+ t.Errorf("ModTime should be %s but is %s", expectedModTime, header.ModTime)
222+ }
223+ expectedUid := 501
224+ if header.Uid != expectedUid {
225+ t.Errorf("Uid should be %s but is %s", expectedUid, header.Uid)
226+ }
227+ expectedGid := 20
228+ if header.Gid != expectedGid {
229+ t.Errorf("Gid should be %s but is %s", expectedGid, header.Gid)
230+ }
231+ expectedMode := int64(0644)
232+ if header.Mode != expectedMode {
233+ t.Errorf("Mode should be %s but is %s", expectedMode, header.Mode)
234+ }
235+}
236+
237+func TestReadBody(t *testing.T) {
238+ f, err := os.Open("./fixtures/hello.a")
239+ defer f.Close()
240+
241+ if err != nil {
242+ t.Errorf(err.Error())
243+ }
244+ reader := NewReader(f)
245+ _, err = reader.Next()
246+ if err != nil && err != io.EOF {
247+ t.Errorf(err.Error())
248+ }
249+ var buf bytes.Buffer
250+ io.Copy(&buf, reader)
251+
252+ expected := []byte("Hello world!\n")
253+ actual := buf.Bytes()
254+ if !bytes.Equal(actual, expected) {
255+ t.Errorf("Data value should be %s but is %s", expected, actual)
256+ }
257+}
258+
259+func TestReadMulti(t *testing.T) {
260+ f, err := os.Open("./fixtures/multi_archive.a")
261+ defer f.Close()
262+
263+ if err != nil {
264+ t.Errorf(err.Error())
265+ }
266+ reader := NewReader(f)
267+ var buf bytes.Buffer
268+ for {
269+ _, err := reader.Next()
270+ if err == io.EOF {
271+ break
272+ }
273+ if err != nil {
274+ t.Errorf(err.Error())
275+ }
276+ io.Copy(&buf, reader)
277+ }
278+ expected := []byte("Hello world!\nI love lamp.\n")
279+ actual := buf.Bytes()
280+ if !bytes.Equal(expected, actual) {
281+ t.Errorf("Concatted byte buffer should be %s but is %s", expected, actual)
282+ }
283+}
284
285=== added file 'internal/github.com/blakesmith/ar/writer.go'
286--- internal/github.com/blakesmith/ar/writer.go 1970-01-01 00:00:00 +0000
287+++ internal/github.com/blakesmith/ar/writer.go 2015-10-30 14:13:06 +0000
288@@ -0,0 +1,103 @@
289+package ar
290+
291+import (
292+ "errors"
293+ "io"
294+ "strconv"
295+)
296+
297+var (
298+ ErrWriteTooLong = errors.New("ar: write too long")
299+)
300+
301+// Writer provides sequential writing of an ar archive.
302+// An ar archive is sequence of header file pairs
303+// Call WriteHeader to begin writing a new file, then call Write to supply the file's data
304+//
305+// Example:
306+// archive := ar.NewWriter(writer)
307+// archive.WriteGlobalHeader()
308+// header := new(ar.Header)
309+// header.Size = 15 // bytes
310+// if err := archive.WriteHeader(header); err != nil {
311+// return err
312+// }
313+// io.Copy(archive, data)
314+type Writer struct {
315+ w io.Writer
316+ nb int64 // number of unwritten bytes for the current file entry
317+}
318+
319+// Create a new ar writer that writes to w
320+func NewWriter(w io.Writer) *Writer { return &Writer{w: w} }
321+
322+func (aw *Writer) numeric(b []byte, x int64) {
323+ s := strconv.FormatInt(x, 10)
324+ for len(s) < len(b) {
325+ s = s + " "
326+ }
327+ copy(b, []byte(s))
328+}
329+
330+func (aw *Writer) octal(b []byte, x int64) {
331+ s := "100" + strconv.FormatInt(x, 8)
332+ for len(s) < len(b) {
333+ s = s + " "
334+ }
335+ copy(b, []byte(s))
336+}
337+
338+func (aw *Writer) string(b []byte, str string) {
339+ s := str
340+ for len(s) < len(b) {
341+ s = s + " "
342+ }
343+ copy(b, []byte(s))
344+}
345+
346+// Writes to the current entry in the ar archive
347+// Returns ErrWriteTooLong if more than header.Size
348+// bytes are written after a call to WriteHeader
349+func (aw *Writer) Write(b []byte) (n int, err error) {
350+ if int64(len(b)) > aw.nb {
351+ b = b[0:aw.nb]
352+ err = ErrWriteTooLong
353+ }
354+ n, werr := aw.w.Write(b)
355+ aw.nb -= int64(n)
356+ if werr != nil {
357+ return n, werr
358+ }
359+
360+ if len(b)%2 == 1 { // data size must be aligned to an even byte
361+ n2, _ := aw.w.Write([]byte{'\n'})
362+ return n + n2, err
363+ }
364+
365+ return
366+}
367+
368+func (aw *Writer) WriteGlobalHeader() error {
369+ _, err := aw.w.Write([]byte(GLOBAL_HEADER))
370+ return err
371+}
372+
373+// Writes the header to the underlying writer and prepares
374+// to receive the file payload
375+func (aw *Writer) WriteHeader(hdr *Header) error {
376+ aw.nb = int64(hdr.Size)
377+ header := make([]byte, HEADER_BYTE_SIZE)
378+ s := slicer(header)
379+
380+ aw.string(s.next(16), hdr.Name)
381+ aw.numeric(s.next(12), hdr.ModTime.Unix())
382+ aw.numeric(s.next(6), int64(hdr.Uid))
383+ aw.numeric(s.next(6), int64(hdr.Gid))
384+ aw.octal(s.next(8), hdr.Mode)
385+ aw.numeric(s.next(10), hdr.Size)
386+ aw.string(s.next(2), "`\n")
387+
388+ _, err := aw.w.Write(header)
389+
390+ return err
391+}
392
393=== added file 'internal/github.com/blakesmith/ar/writer_test.go'
394--- internal/github.com/blakesmith/ar/writer_test.go 1970-01-01 00:00:00 +0000
395+++ internal/github.com/blakesmith/ar/writer_test.go 2015-10-30 14:13:06 +0000
396@@ -0,0 +1,71 @@
397+package ar
398+
399+import (
400+ "bytes"
401+ "io/ioutil"
402+ "os"
403+ "testing"
404+ "time"
405+)
406+
407+func TestGlobalHeaderWrite(t *testing.T) {
408+ var buf bytes.Buffer
409+ writer := NewWriter(&buf)
410+ if err := writer.WriteGlobalHeader(); err != nil {
411+ t.Errorf(err.Error())
412+ }
413+
414+ globalHeader := buf.Bytes()
415+ expectedHeader := []byte("!<arch>\n")
416+ if !bytes.Equal(globalHeader, expectedHeader) {
417+ t.Errorf("Global header should be %s but is %s", expectedHeader, globalHeader)
418+ }
419+}
420+
421+func TestSimpleFile(t *testing.T) {
422+ hdr := new(Header)
423+ body := "Hello world!\n"
424+ hdr.ModTime = time.Unix(1361157466, 0)
425+ hdr.Name = "hello.txt"
426+ hdr.Size = int64(len(body))
427+ hdr.Mode = 0644
428+ hdr.Uid = 501
429+ hdr.Gid = 20
430+
431+ var buf bytes.Buffer
432+ writer := NewWriter(&buf)
433+ writer.WriteGlobalHeader()
434+ writer.WriteHeader(hdr)
435+ _, err := writer.Write([]byte(body))
436+ if err != nil {
437+ t.Errorf(err.Error())
438+ }
439+
440+ f, _ := os.Open("./fixtures/hello.a")
441+ defer f.Close()
442+
443+ b, err := ioutil.ReadAll(f)
444+ if err != nil {
445+ t.Errorf(err.Error())
446+ }
447+
448+ actual := buf.Bytes()
449+ if !bytes.Equal(b, actual) {
450+ t.Errorf("Expected %s to equal %s", actual, b)
451+ }
452+}
453+
454+func TestWriteTooLong(t *testing.T) {
455+ body := "Hello world!\n"
456+
457+ hdr := new(Header)
458+ hdr.Size = 1
459+
460+ var buf bytes.Buffer
461+ writer := NewWriter(&buf)
462+ writer.WriteHeader(hdr)
463+ _, err := writer.Write([]byte(body))
464+ if err != ErrWriteTooLong {
465+ t.Errorf("Error should have been: %s", ErrWriteTooLong)
466+ }
467+}
468
469=== added directory 'internal/github.com/cheggaaa'
470=== added directory 'internal/github.com/cheggaaa/pb'
471=== added file 'internal/github.com/cheggaaa/pb/LICENSE'
472--- internal/github.com/cheggaaa/pb/LICENSE 1970-01-01 00:00:00 +0000
473+++ internal/github.com/cheggaaa/pb/LICENSE 2015-10-30 14:13:06 +0000
474@@ -0,0 +1,12 @@
475+Copyright (c) 2012, Sergey Cherepanov
476+All rights reserved.
477+
478+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
479+
480+* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
481+
482+* 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.
483+
484+* Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
485+
486+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 HOLDER 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.
487\ No newline at end of file
488
489=== added file 'internal/github.com/cheggaaa/pb/README.md'
490--- internal/github.com/cheggaaa/pb/README.md 1970-01-01 00:00:00 +0000
491+++ internal/github.com/cheggaaa/pb/README.md 2015-10-30 14:13:06 +0000
492@@ -0,0 +1,98 @@
493+## Terminal progress bar for Go
494+
495+Simple progress bar for console programms.
496+
497+
498+### Installation
499+```
500+go get github.com/cheggaaa/pb
501+```
502+
503+### Usage
504+```Go
505+package main
506+
507+import (
508+ "github.com/cheggaaa/pb"
509+ "time"
510+)
511+
512+func main() {
513+ count := 100000
514+ bar := pb.StartNew(count)
515+ for i := 0; i < count; i++ {
516+ bar.Increment()
517+ time.Sleep(time.Millisecond)
518+ }
519+ bar.FinishPrint("The End!")
520+}
521+```
522+Result will be like this:
523+```
524+> go run test.go
525+37158 / 100000 [================>_______________________________] 37.16% 1m11s
526+```
527+
528+
529+More functions?
530+```Go
531+// create bar
532+bar := pb.New(count)
533+
534+// refresh info every second (default 200ms)
535+bar.SetRefreshRate(time.Second)
536+
537+// show percents (by default already true)
538+bar.ShowPercent = true
539+
540+// show bar (by default already true)
541+bar.ShowBar = true
542+
543+// no need counters
544+bar.ShowCounters = false
545+
546+// show "time left"
547+bar.ShowTimeLeft = true
548+
549+// show average speed
550+bar.ShowSpeed = true
551+
552+// sets the width of the progress bar
553+bar.SetWith(80)
554+
555+// sets the width of the progress bar, but if terminal size smaller will be ignored
556+bar.SetMaxWith(80)
557+
558+// convert output to readable format (like KB, MB)
559+bar.SetUnits(pb.U_BYTES)
560+
561+// and start
562+bar.Start()
563+```
564+
565+Want handle progress of io operations?
566+```Go
567+// create and start bar
568+bar := pb.New(myDataLen).SetUnits(pb.U_BYTES)
569+bar.Start()
570+
571+// my io.Reader
572+r := myReader
573+
574+// my io.Writer
575+w := myWriter
576+
577+// create multi writer
578+writer := io.MultiWriter(w, bar)
579+
580+// and copy
581+io.Copy(writer, r)
582+
583+// show example/copy/copy.go for advanced example
584+
585+```
586+
587+Not like the looks?
588+```Go
589+bar.Format("<.- >")
590+```
591
592=== added file 'internal/github.com/cheggaaa/pb/format.go'
593--- internal/github.com/cheggaaa/pb/format.go 1970-01-01 00:00:00 +0000
594+++ internal/github.com/cheggaaa/pb/format.go 2015-10-30 14:13:06 +0000
595@@ -0,0 +1,42 @@
596+package pb
597+
598+import (
599+ "fmt"
600+ "strconv"
601+ "strings"
602+)
603+
604+const (
605+ // By default, without type handle
606+ U_NO = 0
607+ // Handle as b, Kb, Mb, etc
608+ U_BYTES = 1
609+)
610+
611+// Format integer
612+func Format(i int64, units int) string {
613+ switch units {
614+ case U_BYTES:
615+ return FormatBytes(i)
616+ }
617+ // by default just convert to string
618+ return strconv.Itoa(int(i))
619+}
620+
621+// Convert bytes to human readable string. Like a 2 MB, 64.2 KB, 52 B
622+func FormatBytes(i int64) (result string) {
623+ switch {
624+ case i > (1024 * 1024 * 1024 * 1024):
625+ result = fmt.Sprintf("%#.02f TB", float64(i)/1024/1024/1024/1024)
626+ case i > (1024 * 1024 * 1024):
627+ result = fmt.Sprintf("%#.02f GB", float64(i)/1024/1024/1024)
628+ case i > (1024 * 1024):
629+ result = fmt.Sprintf("%#.02f MB", float64(i)/1024/1024)
630+ case i > 1024:
631+ result = fmt.Sprintf("%#.02f KB", float64(i)/1024)
632+ default:
633+ result = fmt.Sprintf("%d B", i)
634+ }
635+ result = strings.Trim(result, " ")
636+ return
637+}
638
639=== added file 'internal/github.com/cheggaaa/pb/format_test.go'
640--- internal/github.com/cheggaaa/pb/format_test.go 1970-01-01 00:00:00 +0000
641+++ internal/github.com/cheggaaa/pb/format_test.go 2015-10-30 14:13:06 +0000
642@@ -0,0 +1,37 @@
643+package pb
644+
645+import (
646+ "fmt"
647+ "strconv"
648+ "testing"
649+)
650+
651+func Test_DefaultsToInteger(t *testing.T) {
652+ value := int64(1000)
653+ expected := strconv.Itoa(int(value))
654+ actual := Format(value, -1)
655+
656+ if actual != expected {
657+ t.Error(fmt.Sprintf("Expected {%s} was {%s}", expected, actual))
658+ }
659+}
660+
661+func Test_CanFormatAsInteger(t *testing.T) {
662+ value := int64(1000)
663+ expected := strconv.Itoa(int(value))
664+ actual := Format(value, U_NO)
665+
666+ if actual != expected {
667+ t.Error(fmt.Sprintf("Expected {%s} was {%s}", expected, actual))
668+ }
669+}
670+
671+func Test_CanFormatAsBytes(t *testing.T) {
672+ value := int64(1000)
673+ expected := "1000 B"
674+ actual := Format(value, U_BYTES)
675+
676+ if actual != expected {
677+ t.Error(fmt.Sprintf("Expected {%s} was {%s}", expected, actual))
678+ }
679+}
680
681=== added file 'internal/github.com/cheggaaa/pb/pb.go'
682--- internal/github.com/cheggaaa/pb/pb.go 1970-01-01 00:00:00 +0000
683+++ internal/github.com/cheggaaa/pb/pb.go 2015-10-30 14:13:06 +0000
684@@ -0,0 +1,341 @@
685+package pb
686+
687+import (
688+ "fmt"
689+ "io"
690+ "math"
691+ "strings"
692+ "sync/atomic"
693+ "time"
694+)
695+
696+const (
697+ // Default refresh rate - 200ms
698+ DEFAULT_REFRESH_RATE = time.Millisecond * 200
699+ FORMAT = "[=>-]"
700+)
701+
702+// DEPRECATED
703+// variables for backward compatibility, from now do not work
704+// use pb.Format and pb.SetRefreshRate
705+var (
706+ DefaultRefreshRate = DEFAULT_REFRESH_RATE
707+ BarStart, BarEnd, Empty, Current, CurrentN string
708+)
709+
710+// Create new progress bar object
711+func New(total int) (pb *ProgressBar) {
712+ return New64(int64(total))
713+}
714+
715+// Create new progress bar object uding int64 as total
716+func New64(total int64) (pb *ProgressBar) {
717+ pb = &ProgressBar{
718+ Total: total,
719+ RefreshRate: DEFAULT_REFRESH_RATE,
720+ ShowPercent: true,
721+ ShowCounters: true,
722+ ShowBar: true,
723+ ShowTimeLeft: true,
724+ ShowFinalTime: true,
725+ ManualUpdate: false,
726+ currentValue: -1,
727+ }
728+ pb.Format(FORMAT)
729+ return
730+}
731+
732+// Create new object and start
733+func StartNew(total int) (pb *ProgressBar) {
734+ pb = New(total)
735+ pb.Start()
736+ return
737+}
738+
739+// Callback for custom output
740+// For example:
741+// bar.Callback = func(s string) {
742+// mySuperPrint(s)
743+// }
744+//
745+type Callback func(out string)
746+
747+type ProgressBar struct {
748+ current int64 // current must be first member of struct (https://code.google.com/p/go/issues/detail?id=5278)
749+
750+ Total int64
751+ RefreshRate time.Duration
752+ ShowPercent, ShowCounters bool
753+ ShowSpeed, ShowTimeLeft, ShowBar bool
754+ ShowFinalTime bool
755+ Output io.Writer
756+ Callback Callback
757+ NotPrint bool
758+ Units int
759+ Width int
760+ ForceWidth bool
761+ ManualUpdate bool
762+
763+ isFinish bool
764+ startTime time.Time
765+ currentValue int64
766+
767+ prefix, postfix string
768+
769+ BarStart string
770+ BarEnd string
771+ Empty string
772+ Current string
773+ CurrentN string
774+}
775+
776+// Start print
777+func (pb *ProgressBar) Start() {
778+ pb.startTime = time.Now()
779+ if pb.Total == 0 {
780+ pb.ShowBar = false
781+ pb.ShowTimeLeft = false
782+ pb.ShowPercent = false
783+ }
784+ if !pb.ManualUpdate {
785+ go pb.writer()
786+ }
787+}
788+
789+// Increment current value
790+func (pb *ProgressBar) Increment() int {
791+ return pb.Add(1)
792+}
793+
794+// Set current value
795+func (pb *ProgressBar) Set(current int) {
796+ atomic.StoreInt64(&pb.current, int64(current))
797+}
798+
799+// Add to current value
800+func (pb *ProgressBar) Add(add int) int {
801+ return int(pb.Add64(int64(add)))
802+}
803+
804+func (pb *ProgressBar) Add64(add int64) int64 {
805+ return atomic.AddInt64(&pb.current, add)
806+}
807+
808+// Set prefix string
809+func (pb *ProgressBar) Prefix(prefix string) (bar *ProgressBar) {
810+ pb.prefix = prefix
811+ return pb
812+}
813+
814+// Set postfix string
815+func (pb *ProgressBar) Postfix(postfix string) (bar *ProgressBar) {
816+ pb.postfix = postfix
817+ return pb
818+}
819+
820+// Set custom format for bar
821+// Example: bar.Format("[=>_]")
822+func (pb *ProgressBar) Format(format string) (bar *ProgressBar) {
823+ bar = pb
824+ formatEntries := strings.Split(format, "")
825+ if len(formatEntries) != 5 {
826+ return
827+ }
828+ pb.BarStart = formatEntries[0]
829+ pb.BarEnd = formatEntries[4]
830+ pb.Empty = formatEntries[3]
831+ pb.Current = formatEntries[1]
832+ pb.CurrentN = formatEntries[2]
833+ return
834+}
835+
836+// Set bar refresh rate
837+func (pb *ProgressBar) SetRefreshRate(rate time.Duration) (bar *ProgressBar) {
838+ bar = pb
839+ pb.RefreshRate = rate
840+ return
841+}
842+
843+// Set units
844+// bar.SetUnits(U_NO) - by default
845+// bar.SetUnits(U_BYTES) - for Mb, Kb, etc
846+func (pb *ProgressBar) SetUnits(units int) (bar *ProgressBar) {
847+ bar = pb
848+ switch units {
849+ case U_NO, U_BYTES:
850+ pb.Units = units
851+ }
852+ return
853+}
854+
855+// Set max width, if width is bigger than terminal width, will be ignored
856+func (pb *ProgressBar) SetMaxWidth(width int) (bar *ProgressBar) {
857+ bar = pb
858+ pb.Width = width
859+ pb.ForceWidth = false
860+ return
861+}
862+
863+// Set bar width
864+func (pb *ProgressBar) SetWidth(width int) (bar *ProgressBar) {
865+ bar = pb
866+ pb.Width = width
867+ pb.ForceWidth = true
868+ return
869+}
870+
871+// End print
872+func (pb *ProgressBar) Finish() {
873+ pb.isFinish = true
874+ pb.write(atomic.LoadInt64(&pb.current))
875+ if !pb.NotPrint {
876+ fmt.Println()
877+ }
878+}
879+
880+// End print and write string 'str'
881+func (pb *ProgressBar) FinishPrint(str string) {
882+ pb.Finish()
883+ fmt.Println(str)
884+}
885+
886+// implement io.Writer
887+func (pb *ProgressBar) Write(p []byte) (n int, err error) {
888+ n = len(p)
889+ pb.Add(n)
890+ return
891+}
892+
893+// implement io.Reader
894+func (pb *ProgressBar) Read(p []byte) (n int, err error) {
895+ n = len(p)
896+ pb.Add(n)
897+ return
898+}
899+
900+// Create new proxy reader over bar
901+func (pb *ProgressBar) NewProxyReader(r io.Reader) *Reader {
902+ return &Reader{r, pb}
903+}
904+
905+func (pb *ProgressBar) write(current int64) {
906+ width := pb.getWidth()
907+
908+ var percentBox, countersBox, timeLeftBox, speedBox, barBox, end, out string
909+
910+ // percents
911+ if pb.ShowPercent {
912+ percent := float64(current) / (float64(pb.Total) / float64(100))
913+ percentBox = fmt.Sprintf(" %#.02f %% ", percent)
914+ }
915+
916+ // counters
917+ if pb.ShowCounters {
918+ if pb.Total > 0 {
919+ countersBox = fmt.Sprintf("%s / %s ", Format(current, pb.Units), Format(pb.Total, pb.Units))
920+ } else {
921+ countersBox = Format(current, pb.Units) + " "
922+ }
923+ }
924+
925+ // time left
926+ fromStart := time.Now().Sub(pb.startTime)
927+ if pb.isFinish {
928+ if pb.ShowFinalTime {
929+ left := (fromStart / time.Second) * time.Second
930+ timeLeftBox = left.String()
931+ }
932+ } else if pb.ShowTimeLeft && current > 0 {
933+ perEntry := fromStart / time.Duration(current)
934+ left := time.Duration(pb.Total-current) * perEntry
935+ left = (left / time.Second) * time.Second
936+ timeLeftBox = left.String()
937+ }
938+
939+ // speed
940+ if pb.ShowSpeed && current > 0 {
941+ fromStart := time.Now().Sub(pb.startTime)
942+ speed := float64(current) / (float64(fromStart) / float64(time.Second))
943+ speedBox = Format(int64(speed), pb.Units) + "/s "
944+ }
945+
946+ // bar
947+ if pb.ShowBar {
948+ size := width - len(countersBox+pb.BarStart+pb.BarEnd+percentBox+timeLeftBox+speedBox+pb.prefix+pb.postfix)
949+ if size > 0 {
950+ curCount := int(math.Ceil((float64(current) / float64(pb.Total)) * float64(size)))
951+ emptCount := size - curCount
952+ barBox = pb.BarStart
953+ if emptCount < 0 {
954+ emptCount = 0
955+ }
956+ if curCount > size {
957+ curCount = size
958+ }
959+ if emptCount <= 0 {
960+ barBox += strings.Repeat(pb.Current, curCount)
961+ } else if curCount > 0 {
962+ barBox += strings.Repeat(pb.Current, curCount-1) + pb.CurrentN
963+ }
964+
965+ barBox += strings.Repeat(pb.Empty, emptCount) + pb.BarEnd
966+ }
967+ }
968+
969+ // check len
970+ out = pb.prefix + countersBox + barBox + percentBox + speedBox + timeLeftBox + pb.postfix
971+ if len(out) < width {
972+ end = strings.Repeat(" ", width-len(out))
973+ }
974+
975+ // and print!
976+ switch {
977+ case pb.Output != nil:
978+ fmt.Fprint(pb.Output, "\r"+out+end)
979+ case pb.Callback != nil:
980+ pb.Callback(out + end)
981+ case !pb.NotPrint:
982+ fmt.Print("\r" + out + end)
983+ }
984+}
985+
986+func (pb *ProgressBar) getWidth() int {
987+ if pb.ForceWidth {
988+ return pb.Width
989+ }
990+
991+ width := pb.Width
992+ termWidth, _ := terminalWidth()
993+ if width == 0 || termWidth <= width {
994+ width = termWidth
995+ }
996+
997+ return width
998+}
999+
1000+// Write the current state of the progressbar
1001+func (pb *ProgressBar) Update() {
1002+ c := atomic.LoadInt64(&pb.current)
1003+ if c != pb.currentValue {
1004+ pb.write(c)
1005+ pb.currentValue = c
1006+ }
1007+}
1008+
1009+// Internal loop for writing progressbar
1010+func (pb *ProgressBar) writer() {
1011+ for {
1012+ if pb.isFinish {
1013+ break
1014+ }
1015+ pb.Update()
1016+ time.Sleep(pb.RefreshRate)
1017+ }
1018+}
1019+
1020+type window struct {
1021+ Row uint16
1022+ Col uint16
1023+ Xpixel uint16
1024+ Ypixel uint16
1025+}
1026
1027=== added file 'internal/github.com/cheggaaa/pb/pb_nix.go'
1028--- internal/github.com/cheggaaa/pb/pb_nix.go 1970-01-01 00:00:00 +0000
1029+++ internal/github.com/cheggaaa/pb/pb_nix.go 2015-10-30 14:13:06 +0000
1030@@ -0,0 +1,7 @@
1031+// +build linux darwin freebsd openbsd
1032+
1033+package pb
1034+
1035+import "syscall"
1036+
1037+const sys_ioctl = syscall.SYS_IOCTL
1038
1039=== added file 'internal/github.com/cheggaaa/pb/pb_solaris.go'
1040--- internal/github.com/cheggaaa/pb/pb_solaris.go 1970-01-01 00:00:00 +0000
1041+++ internal/github.com/cheggaaa/pb/pb_solaris.go 2015-10-30 14:13:06 +0000
1042@@ -0,0 +1,5 @@
1043+// +build solaris
1044+
1045+package pb
1046+
1047+const sys_ioctl = 54
1048
1049=== added file 'internal/github.com/cheggaaa/pb/pb_test.go'
1050--- internal/github.com/cheggaaa/pb/pb_test.go 1970-01-01 00:00:00 +0000
1051+++ internal/github.com/cheggaaa/pb/pb_test.go 2015-10-30 14:13:06 +0000
1052@@ -0,0 +1,30 @@
1053+package pb
1054+
1055+import (
1056+ "testing"
1057+)
1058+
1059+func Test_IncrementAddsOne(t *testing.T) {
1060+ count := 5000
1061+ bar := New(count)
1062+ expected := 1
1063+ actual := bar.Increment()
1064+
1065+ if actual != expected {
1066+ t.Errorf("Expected {%d} was {%d}", expected, actual)
1067+ }
1068+}
1069+
1070+func Test_Width(t *testing.T) {
1071+ count := 5000
1072+ bar := New(count)
1073+ width := 100
1074+ bar.SetWidth(100).Callback = func(out string) {
1075+ if len(out) != width {
1076+ t.Errorf("Bar width expected {%d} was {%d}", len(out), width)
1077+ }
1078+ }
1079+ bar.Start()
1080+ bar.Increment()
1081+ bar.Finish()
1082+}
1083
1084=== added file 'internal/github.com/cheggaaa/pb/pb_win.go'
1085--- internal/github.com/cheggaaa/pb/pb_win.go 1970-01-01 00:00:00 +0000
1086+++ internal/github.com/cheggaaa/pb/pb_win.go 2015-10-30 14:13:06 +0000
1087@@ -0,0 +1,16 @@
1088+// +build windows
1089+
1090+package pb
1091+
1092+import (
1093+ "launchpad.net/crackly/internal/github.com/olekukonko/ts"
1094+)
1095+
1096+func bold(str string) string {
1097+ return str
1098+}
1099+
1100+func terminalWidth() (int, error) {
1101+ size, err := ts.GetSize()
1102+ return size.Col(), err
1103+}
1104
1105=== added file 'internal/github.com/cheggaaa/pb/pb_x.go'
1106--- internal/github.com/cheggaaa/pb/pb_x.go 1970-01-01 00:00:00 +0000
1107+++ internal/github.com/cheggaaa/pb/pb_x.go 2015-10-30 14:13:06 +0000
1108@@ -0,0 +1,46 @@
1109+// +build linux darwin freebsd openbsd solaris
1110+
1111+package pb
1112+
1113+import (
1114+ "os"
1115+ "runtime"
1116+ "syscall"
1117+ "unsafe"
1118+)
1119+
1120+const (
1121+ TIOCGWINSZ = 0x5413
1122+ TIOCGWINSZ_OSX = 1074295912
1123+)
1124+
1125+var tty *os.File
1126+
1127+func init() {
1128+ var err error
1129+ tty, err = os.Open("/dev/tty")
1130+ if err != nil {
1131+ tty = os.Stdin
1132+ }
1133+}
1134+
1135+func bold(str string) string {
1136+ return "\033[1m" + str + "\033[0m"
1137+}
1138+
1139+func terminalWidth() (int, error) {
1140+ w := new(window)
1141+ tio := syscall.TIOCGWINSZ
1142+ if runtime.GOOS == "darwin" {
1143+ tio = TIOCGWINSZ_OSX
1144+ }
1145+ res, _, err := syscall.Syscall(sys_ioctl,
1146+ tty.Fd(),
1147+ uintptr(tio),
1148+ uintptr(unsafe.Pointer(w)),
1149+ )
1150+ if int(res) == -1 {
1151+ return 0, err
1152+ }
1153+ return int(w.Col), nil
1154+}
1155
1156=== added file 'internal/github.com/cheggaaa/pb/reader.go'
1157--- internal/github.com/cheggaaa/pb/reader.go 1970-01-01 00:00:00 +0000
1158+++ internal/github.com/cheggaaa/pb/reader.go 2015-10-30 14:13:06 +0000
1159@@ -0,0 +1,17 @@
1160+package pb
1161+
1162+import (
1163+ "io"
1164+)
1165+
1166+// It's proxy reader, implement io.Reader
1167+type Reader struct {
1168+ io.Reader
1169+ bar *ProgressBar
1170+}
1171+
1172+func (r *Reader) Read(p []byte) (n int, err error) {
1173+ n, err = r.Reader.Read(p)
1174+ r.bar.Add(n)
1175+ return
1176+}
1177
1178=== added directory 'internal/github.com/gosexy'
1179=== added directory 'internal/github.com/gosexy/gettext'
1180=== added file 'internal/github.com/gosexy/gettext/LICENSE'
1181--- internal/github.com/gosexy/gettext/LICENSE 1970-01-01 00:00:00 +0000
1182+++ internal/github.com/gosexy/gettext/LICENSE 2015-10-30 14:13:06 +0000
1183@@ -0,0 +1,20 @@
1184+Copyright (c) 2012-2013 José Carlos Nieto, http://xiam.menteslibres.org/
1185+
1186+Permission is hereby granted, free of charge, to any person obtaining
1187+a copy of this software and associated documentation files (the
1188+"Software"), to deal in the Software without restriction, including
1189+without limitation the rights to use, copy, modify, merge, publish,
1190+distribute, sublicense, and/or sell copies of the Software, and to
1191+permit persons to whom the Software is furnished to do so, subject to
1192+the following conditions:
1193+
1194+The above copyright notice and this permission notice shall be
1195+included in all copies or substantial portions of the Software.
1196+
1197+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1198+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1199+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1200+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
1201+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
1202+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1203+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1204
1205=== added file 'internal/github.com/gosexy/gettext/README.md'
1206--- internal/github.com/gosexy/gettext/README.md 1970-01-01 00:00:00 +0000
1207+++ internal/github.com/gosexy/gettext/README.md 2015-10-30 14:13:06 +0000
1208@@ -0,0 +1,94 @@
1209+# gosexy/gettext
1210+
1211+Go bindings for [GNU gettext][1], an internationalization and localization
1212+library for writing multilingual systems.
1213+
1214+## Requeriments
1215+
1216+The GNU C library. If you're using GNU/Linux, FreeBSD or OSX you should already
1217+have it.
1218+
1219+## Installation
1220+
1221+Use `go get` to download and install the binding:
1222+
1223+```sh
1224+go get github.com/gosexy/gettext
1225+```
1226+
1227+## Usage
1228+
1229+```go
1230+package main
1231+
1232+import (
1233+ "github.com/gosexy/gettext"
1234+ "fmt"
1235+ "os"
1236+)
1237+
1238+func main() {
1239+ gettext.BindTextdomain("example", ".")
1240+ gettext.Textdomain("example")
1241+
1242+ os.Setenv("LANGUAGE", "es_MX.utf8")
1243+
1244+ gettext.SetLocale(gettext.LC_ALL, "")
1245+
1246+ fmt.Println(gettext.Gettext("Hello, world!"))
1247+}
1248+```
1249+
1250+You can use `os.Setenv` to set the `LANGUAGE` environment variable or set it
1251+on a terminal:
1252+
1253+```sh
1254+export LANGUAGE="es_MX.utf8"
1255+./gettext-program
1256+```
1257+
1258+Note that `xgettext` does not officially support Go syntax yet, however, you
1259+can generate a valid `.pot` file by forcing `xgettest` to use the C++
1260+syntax:
1261+
1262+```sh
1263+xgettext -d example -s gettext_test.go -o example.pot -L c++ -i \
1264+--keyword=NGettext:1,2 --keyword=Gettext
1265+```
1266+
1267+This will generate a `example.pot` file.
1268+
1269+After translating the `.pot` file, you must generate `.po` and `.mo` files and
1270+remember to set the UTF-8 charset.
1271+
1272+```sh
1273+msginit -l es_MX -o example.po -i example.pot
1274+msgfmt -c -v -o example.mo example.po
1275+```
1276+
1277+Finally, move the `.mo` file to an appropriate location.
1278+
1279+```sh
1280+mv example.mo examples/es_MX.utf8/LC_MESSAGES/example.mo
1281+```
1282+
1283+## Documentation
1284+
1285+You can read `gosexy/gettext` documentation from a terminal
1286+
1287+```sh
1288+go doc github.com/gosexy/gettext
1289+```
1290+
1291+Or you can [browse it](http://godoc.org/github.com/gosexy/gettext) online.
1292+
1293+The original gettext documentation could be very useful as well:
1294+
1295+```sh
1296+man 3 gettext
1297+```
1298+
1299+Here's another [good tutorial][2] on using gettext.
1300+
1301+[1]: http://www.gnu.org/software/gettext/
1302+[2]: http://oriya.sarovar.org/docs/gettext_single.html
1303
1304=== added file 'internal/github.com/gosexy/gettext/gettext.go'
1305--- internal/github.com/gosexy/gettext/gettext.go 1970-01-01 00:00:00 +0000
1306+++ internal/github.com/gosexy/gettext/gettext.go 2015-10-30 14:13:06 +0000
1307@@ -0,0 +1,207 @@
1308+/*
1309+ Copyright (c) 2012 José Carlos Nieto, http://xiam.menteslibres.org/
1310+
1311+ Permission is hereby granted, free of charge, to any person obtaining
1312+ a copy of this software and associated documentation files (the
1313+ "Software"), to deal in the Software without restriction, including
1314+ without limitation the rights to use, copy, modify, merge, publish,
1315+ distribute, sublicense, and/or sell copies of the Software, and to
1316+ permit persons to whom the Software is furnished to do so, subject to
1317+ the following conditions:
1318+
1319+ The above copyright notice and this permission notice shall be
1320+ included in all copies or substantial portions of the Software.
1321+
1322+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1323+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1324+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1325+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
1326+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
1327+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1328+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1329+*/
1330+
1331+package gettext
1332+
1333+/*
1334+
1335+#include <libintl.h>
1336+#include <locale.h>
1337+#include <stdlib.h>
1338+*/
1339+import "C"
1340+
1341+import (
1342+ "fmt"
1343+ "strings"
1344+ "unsafe"
1345+)
1346+
1347+var (
1348+ // For all of the locale.
1349+ LC_ALL = uint(C.LC_ALL)
1350+
1351+ // For regular expression matching (it determines the meaning of range
1352+ // expressions and equivalence classes) and string collation.
1353+ LC_COLATE = uint(C.LC_ALL)
1354+
1355+ // For regular expression matching, character classification, conversion,
1356+ // case-sensitive comparison, and wide character functions.
1357+ LC_CTYPE = uint(C.LC_CTYPE)
1358+
1359+ // For localizable natural-language messages.
1360+ LC_MESSAGES = uint(C.LC_MESSAGES)
1361+
1362+ // For monetary formatting.
1363+ LC_MONETARY = uint(C.LC_MONETARY)
1364+
1365+ // For number formatting (such as the decimal point and the thousands
1366+ // separator).
1367+ LC_NUMERIC = uint(C.LC_NUMERIC)
1368+
1369+ // For time and date formatting.
1370+ LC_TIME = uint(C.LC_TIME)
1371+)
1372+
1373+// Sets or queries the program's current locale.
1374+func SetLocale(category uint, locale string) string {
1375+ clocale := C.CString(locale)
1376+
1377+ res := C.GoString(C.setlocale(C.int(category), clocale))
1378+
1379+ C.free(unsafe.Pointer(clocale))
1380+ return res
1381+}
1382+
1383+// Sets directory containing message catalogs.
1384+func BindTextdomain(domainname string, dirname string) string {
1385+ cdirname := C.CString(dirname)
1386+ cdomainname := C.CString(domainname)
1387+
1388+ res := C.GoString(C.bindtextdomain(cdomainname, cdirname))
1389+
1390+ C.free(unsafe.Pointer(cdirname))
1391+ C.free(unsafe.Pointer(cdomainname))
1392+ return res
1393+}
1394+
1395+// Sets the output codeset for message catalogs for domain domainname.
1396+func BindTextdomainCodeset(domainname string, codeset string) string {
1397+ cdomainname := C.CString(domainname)
1398+ ccodeset := C.CString(codeset)
1399+
1400+ res := C.GoString(C.bind_textdomain_codeset(cdomainname, ccodeset))
1401+
1402+ C.free(unsafe.Pointer(cdomainname))
1403+ C.free(unsafe.Pointer(ccodeset))
1404+ return res
1405+}
1406+
1407+// Sets or retrieves the current message domain.
1408+func Textdomain(domainname string) string {
1409+ cdomainname := C.CString(domainname)
1410+
1411+ res := C.GoString(C.textdomain(cdomainname))
1412+
1413+ C.free(unsafe.Pointer(cdomainname))
1414+ return res
1415+}
1416+
1417+// Attempt to translate a text string into the user's native language, by
1418+// looking up the translation in a message catalog.
1419+func Gettext(msgid string) string {
1420+ cmsgid := C.CString(msgid)
1421+
1422+ res := C.GoString(C.gettext(cmsgid))
1423+
1424+ C.free(unsafe.Pointer(cmsgid))
1425+ return res
1426+}
1427+
1428+// Like Gettext(), but looking up the message in the specified domain.
1429+func DGettext(domain string, msgid string) string {
1430+ cdomain := C.CString(domain)
1431+ cmsgid := C.CString(msgid)
1432+
1433+ res := C.GoString(C.dgettext(cdomain, cmsgid))
1434+
1435+ C.free(unsafe.Pointer(cdomain))
1436+ C.free(unsafe.Pointer(cmsgid))
1437+ return res
1438+}
1439+
1440+// Like Gettext(), but looking up the message in the specified domain and
1441+// category.
1442+func DCGettext(domain string, msgid string, category uint) string {
1443+ cdomain := C.CString(domain)
1444+ cmsgid := C.CString(msgid)
1445+
1446+ res := C.GoString(C.dcgettext(cdomain, cmsgid, C.int(category)))
1447+
1448+ C.free(unsafe.Pointer(cdomain))
1449+ C.free(unsafe.Pointer(cmsgid))
1450+ return res
1451+}
1452+
1453+// Attempt to translate a text string into the user's native language, by
1454+// looking up the appropriate plural form of the translation in a message
1455+// catalog.
1456+func NGettext(msgid string, msgid_plural string, n uint64) string {
1457+ cmsgid := C.CString(msgid)
1458+ cmsgid_plural := C.CString(msgid_plural)
1459+
1460+ res := C.GoString(C.ngettext(cmsgid, cmsgid_plural, C.ulong(n)))
1461+
1462+ C.free(unsafe.Pointer(cmsgid))
1463+ C.free(unsafe.Pointer(cmsgid_plural))
1464+
1465+ return res
1466+}
1467+
1468+// Like fmt.Sprintf() but without %!(EXTRA) errors.
1469+func Sprintf(format string, a ...interface{}) string {
1470+ expects := strings.Count(format, "%") - strings.Count(format, "%%")
1471+
1472+ if expects > 0 {
1473+ arguments := make([]interface{}, expects)
1474+ for i := 0; i < expects; i++ {
1475+ if len(a) > i {
1476+ arguments[i] = a[i]
1477+ }
1478+ }
1479+ return fmt.Sprintf(format, arguments...)
1480+ }
1481+
1482+ return format
1483+}
1484+
1485+// Like NGettext(), but looking up the message in the specified domain.
1486+func DNGettext(domainname string, msgid string, msgid_plural string, n uint64) string {
1487+ cdomainname := C.CString(domainname)
1488+ cmsgid := C.CString(msgid)
1489+ cmsgid_plural := C.CString(msgid_plural)
1490+
1491+ res := C.GoString(C.dngettext(cdomainname, cmsgid, cmsgid_plural, C.ulong(n)))
1492+
1493+ C.free(unsafe.Pointer(cdomainname))
1494+ C.free(unsafe.Pointer(cmsgid))
1495+ C.free(unsafe.Pointer(cmsgid_plural))
1496+
1497+ return res
1498+}
1499+
1500+// Like NGettext(), but looking up the message in the specified domain and
1501+// category.
1502+func DCNGettext(domainname string, msgid string, msgid_plural string, n uint64, category uint) string {
1503+ cdomainname := C.CString(domainname)
1504+ cmsgid := C.CString(msgid)
1505+ cmsgid_plural := C.CString(msgid_plural)
1506+
1507+ res := C.GoString(C.dcngettext(cdomainname, cmsgid, cmsgid_plural, C.ulong(n), C.int(category)))
1508+
1509+ C.free(unsafe.Pointer(cdomainname))
1510+ C.free(unsafe.Pointer(cmsgid))
1511+ C.free(unsafe.Pointer(cmsgid_plural))
1512+
1513+ return res
1514+}
1515
1516=== added file 'internal/github.com/gosexy/gettext/gettext_test.go'
1517--- internal/github.com/gosexy/gettext/gettext_test.go 1970-01-01 00:00:00 +0000
1518+++ internal/github.com/gosexy/gettext/gettext_test.go 2015-10-30 14:13:06 +0000
1519@@ -0,0 +1,130 @@
1520+package gettext
1521+
1522+import (
1523+ "fmt"
1524+ "os"
1525+ "testing"
1526+)
1527+
1528+/*
1529+ NOTE:
1530+
1531+ xgettext does not officially support Go syntax, however, you can generate a valid .pot file by forcing
1532+ xgettest to use the C++ syntax:
1533+
1534+ % xgettext -d example -s gettext_test.go -o example.pot -L c++ -i --keyword=NGettext:1,2 --keyword=Gettext
1535+
1536+ This will generate a example.pot file.
1537+
1538+ After translating the .pot file, you must generate .po and .mo files.
1539+
1540+ Remember to set the UTF-8 charset.
1541+
1542+ % msginit -l es_MX -o example.po -i example.pot
1543+ % msgfmt -c -v -o example.mo example.po
1544+
1545+ And finally, move the .mo file to an appropriate location.
1546+
1547+ % mv example.mo examples/es_MX.utf8/LC_MESSAGES/example.mo
1548+
1549+*/
1550+
1551+func TestSpanishMexico(t *testing.T) {
1552+
1553+ os.Setenv("LANGUAGE", "es_MX.utf8")
1554+
1555+ SetLocale(LC_ALL, "")
1556+ BindTextdomain("example", "./examples/")
1557+ Textdomain("example")
1558+
1559+ t1 := Gettext("Hello, world!")
1560+
1561+ fmt.Println(t1)
1562+
1563+ if t1 != "¡Hola mundo!" {
1564+ t.Errorf("Failed translation.")
1565+ }
1566+
1567+ t2 := Sprintf(NGettext("An apple", "%d apples", 1), 1, "garbage")
1568+
1569+ fmt.Println(t2)
1570+
1571+ if t2 != "Una manzana" {
1572+ t.Errorf("Failed translation.")
1573+ }
1574+
1575+ t3 := Sprintf(NGettext("An apple", "%d apples", 3), 3)
1576+
1577+ fmt.Println(t3)
1578+
1579+ if t3 != "3 manzanas" {
1580+ t.Errorf("Failed translation.")
1581+ }
1582+
1583+ t4 := Gettext("Good morning")
1584+
1585+ fmt.Println(t4)
1586+
1587+ if t4 != "Buenos días" {
1588+ t.Errorf("Failed translation.")
1589+ }
1590+
1591+ t5 := Gettext("Good bye!")
1592+
1593+ fmt.Println(t5)
1594+
1595+ if t5 != "¡Hasta luego!" {
1596+ t.Errorf("Failed translation.")
1597+ }
1598+
1599+}
1600+
1601+func TestGermanDeutschland(t *testing.T) {
1602+
1603+ os.Setenv("LANGUAGE", "de_DE.utf8")
1604+
1605+ SetLocale(LC_ALL, "")
1606+ BindTextdomain("example", "./examples/")
1607+ Textdomain("example")
1608+
1609+ t1 := Gettext("Hello, world!")
1610+
1611+ fmt.Println(t1)
1612+
1613+ if t1 != "Hallo, Welt!" {
1614+ t.Errorf("Failed translation.")
1615+ }
1616+
1617+ t2 := Sprintf(NGettext("An apple", "%d apples", 1), 1, "garbage")
1618+
1619+ fmt.Println(t2)
1620+
1621+ if t2 != "Ein Apfel" {
1622+ t.Errorf("Failed translation.")
1623+ }
1624+
1625+ t3 := Sprintf(NGettext("An apple", "%d apples", 3), 3)
1626+
1627+ fmt.Println(t3)
1628+
1629+ if t3 != "3 Äpfel" {
1630+ t.Errorf("Failed translation.")
1631+ }
1632+
1633+ t4 := Gettext("Good morning")
1634+
1635+ fmt.Println(t4)
1636+
1637+ if t4 != "Guten morgen" {
1638+ t.Errorf("Failed translation.")
1639+ }
1640+
1641+ t5 := Gettext("Good bye!")
1642+
1643+ fmt.Println(t5)
1644+
1645+ if t5 != "Aufwiedersehen!" {
1646+ t.Errorf("Failed translation.")
1647+ }
1648+
1649+}
1650
1651=== added directory 'internal/github.com/mvo5'
1652=== added directory 'internal/github.com/mvo5/goconfigparser'
1653=== added file 'internal/github.com/mvo5/goconfigparser/COPYING'
1654--- internal/github.com/mvo5/goconfigparser/COPYING 1970-01-01 00:00:00 +0000
1655+++ internal/github.com/mvo5/goconfigparser/COPYING 2015-10-30 14:13:06 +0000
1656@@ -0,0 +1,19 @@
1657+Copyright (c) 2014 Canonical
1658+
1659+Permission is hereby granted, free of charge, to any person obtaining a copy
1660+of this software and associated documentation files (the "Software"), to deal
1661+in the Software without restriction, including without limitation the rights
1662+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1663+copies of the Software, and to permit persons to whom the Software is
1664+furnished to do so, subject to the following conditions:
1665+.
1666+The above copyright notice and this permission notice shall be included in
1667+all copies or substantial portions of the Software.
1668+.
1669+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1670+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1671+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1672+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1673+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1674+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1675+THE SOFTWARE.
1676
1677=== added file 'internal/github.com/mvo5/goconfigparser/README.md'
1678--- internal/github.com/mvo5/goconfigparser/README.md 1970-01-01 00:00:00 +0000
1679+++ internal/github.com/mvo5/goconfigparser/README.md 2015-10-30 14:13:06 +0000
1680@@ -0,0 +1,18 @@
1681+Config File Parser (INI style)
1682+==============================
1683+
1684+This parser is build as a go equivalent of the Python ConfigParser
1685+module and is aimed for maximum compatibility for both the file format
1686+and the API. This should make it easy to use existing python style
1687+configuration files from go and also ease the porting of existing
1688+python code.
1689+
1690+It implements most of RawConfigParser (i.e. no interpolation) at this
1691+point.
1692+
1693+Current Limitations:
1694+--------------------
1695+ * no interpolation
1696+ * no defaults
1697+ * no write support
1698+ * not all API is provided
1699\ No newline at end of file
1700
1701=== added file 'internal/github.com/mvo5/goconfigparser/configparser.go'
1702--- internal/github.com/mvo5/goconfigparser/configparser.go 1970-01-01 00:00:00 +0000
1703+++ internal/github.com/mvo5/goconfigparser/configparser.go 2015-10-30 14:13:06 +0000
1704@@ -0,0 +1,181 @@
1705+// A go implementation in the spirit of the python ConfigParser
1706+package goconfigparser
1707+
1708+import (
1709+ "bufio"
1710+ "errors"
1711+ "fmt"
1712+ "io"
1713+ "log"
1714+ "os"
1715+ "regexp"
1716+ "strconv"
1717+ "strings"
1718+)
1719+
1720+// see python3 configparser.py
1721+var sectionRE = regexp.MustCompile(`\[(?P<header>[^]]+)\]`)
1722+var optionRE = regexp.MustCompile(`^(?P<option>.*?)\s*(?P<vi>[=|:])\s*(?P<value>.*)$`)
1723+
1724+var booleanStates = map[string]bool{
1725+ "1": true, "yes": true, "true": true, "on": true,
1726+ "0": false, "no": false, "false": false, "off": false}
1727+
1728+type NoOptionError struct {
1729+ s string
1730+}
1731+
1732+func (e NoOptionError) Error() string {
1733+ return e.s
1734+}
1735+func newNoOptionError(section, option string) *NoOptionError {
1736+ return &NoOptionError{s: fmt.Sprintf("No option %s in section %s", option, section)}
1737+}
1738+
1739+type NoSectionError struct {
1740+ s string
1741+}
1742+
1743+func (e NoSectionError) Error() string {
1744+ return e.s
1745+}
1746+func newNoSectionError(section string) *NoSectionError {
1747+ return &NoSectionError{s: fmt.Sprintf("No section: %s", section)}
1748+}
1749+
1750+type ConfigParser struct {
1751+ sections map[string]Section
1752+
1753+ // allow data with no ["section"] header via Get("", key)
1754+ AllowNoSectionHeader bool
1755+}
1756+
1757+type Section struct {
1758+ options map[string]string
1759+}
1760+
1761+// Create a new empty ConfigParser
1762+func New() (cfg *ConfigParser) {
1763+ return &ConfigParser{
1764+ sections: make(map[string]Section)}
1765+}
1766+
1767+// Return a string slice of the sections available
1768+func (c *ConfigParser) Sections() (res []string) {
1769+ for k, _ := range c.sections {
1770+ res = append(res, k)
1771+ }
1772+ return res
1773+}
1774+
1775+// Return a string slice of the options available in the given section
1776+func (c *ConfigParser) Options(section string) (res []string, err error) {
1777+ sect, ok := c.sections[section]
1778+ if !ok {
1779+ return res, newNoSectionError(section)
1780+ }
1781+ for k, _ := range sect.options {
1782+ res = append(res, k)
1783+ }
1784+ return res, err
1785+}
1786+
1787+// Attempt to parse the given string as a configuration
1788+// It may return a error if the parsing fails
1789+func (c *ConfigParser) ReadString(s string) (err error) {
1790+ r := strings.NewReader(s)
1791+ return c.Read(r)
1792+}
1793+
1794+// Attempt to parse the given file as a configuration
1795+// It may return a error if the parsing fails
1796+func (c *ConfigParser) ReadFile(path string) (err error) {
1797+ f, err := os.Open(path)
1798+ if err != nil {
1799+ return err
1800+ }
1801+ return c.Read(f)
1802+}
1803+
1804+// Attempt to parse the given io.Reader as a configuration
1805+// It may return a error if the reading fails
1806+func (c *ConfigParser) Read(r io.Reader) (err error) {
1807+ scanner := bufio.NewScanner(r)
1808+
1809+ curSect := ""
1810+ // we allow files with no [section] header in this mode, by
1811+ // default its a error to be alinged with what python configparser
1812+ // is doing
1813+ if c.AllowNoSectionHeader {
1814+ c.sections[""] = Section{
1815+ options: make(map[string]string)}
1816+ }
1817+ for scanner.Scan() {
1818+ line := scanner.Text()
1819+ if sectionRE.MatchString(line) {
1820+ matches := sectionRE.FindStringSubmatch(line)
1821+ curSect = matches[1]
1822+ c.sections[curSect] = Section{
1823+ options: make(map[string]string)}
1824+ } else if optionRE.MatchString(line) {
1825+ matches := optionRE.FindStringSubmatch(line)
1826+ key := matches[1]
1827+ value := matches[3]
1828+ if _, ok := c.sections[curSect]; !ok {
1829+ return newNoSectionError(curSect)
1830+ }
1831+ c.sections[curSect].options[key] = value
1832+ }
1833+ }
1834+ if err := scanner.Err(); err != nil {
1835+ log.Printf("ConfigParser scan error %s from %s", err, r)
1836+ }
1837+ return err
1838+}
1839+
1840+// Return the option for the given section as string or an error
1841+func (c *ConfigParser) Get(section, option string) (val string, err error) {
1842+ if _, ok := c.sections[section]; !ok {
1843+ return val, newNoSectionError(section)
1844+ }
1845+ sec := c.sections[section]
1846+
1847+ if _, ok := sec.options[option]; !ok {
1848+ return val, newNoOptionError(section, option)
1849+ }
1850+
1851+ return sec.options[option], err
1852+}
1853+
1854+// Return the option for the given section as integer or an error
1855+func (c *ConfigParser) Getint(section, option string) (val int, err error) {
1856+ sv, err := c.Get(section, option)
1857+ if err != nil {
1858+ return val, err
1859+ }
1860+ return strconv.Atoi(sv)
1861+}
1862+
1863+// Return the option for the given section as float or an error
1864+func (c *ConfigParser) Getfloat(section, option string) (val float64, err error) {
1865+ sv, err := c.Get(section, option)
1866+ if err != nil {
1867+ return val, err
1868+ }
1869+ return strconv.ParseFloat(sv, 64)
1870+}
1871+
1872+// Return the option for the given section as boolean or an error
1873+func (c *ConfigParser) Getbool(section, option string) (val bool, err error) {
1874+ sv, err := c.Get(section, option)
1875+ if err != nil {
1876+ return val, err
1877+ }
1878+
1879+ val, ok := booleanStates[strings.ToLower(sv)]
1880+ if !ok {
1881+ return val, errors.New(fmt.Sprintf("No boolean: %s", sv))
1882+ }
1883+
1884+ return val, err
1885+}
1886
1887=== added file 'internal/github.com/mvo5/goconfigparser/configparser_test.go'
1888--- internal/github.com/mvo5/goconfigparser/configparser_test.go 1970-01-01 00:00:00 +0000
1889+++ internal/github.com/mvo5/goconfigparser/configparser_test.go 2015-10-30 14:13:06 +0000
1890@@ -0,0 +1,127 @@
1891+package goconfigparser
1892+
1893+import (
1894+ "io/ioutil"
1895+ "sort"
1896+ "strings"
1897+ "testing"
1898+
1899+ . "launchpad.net/crackly/internal/launchpad.net/gocheck"
1900+)
1901+
1902+// Hook up gocheck into the "go test" runner
1903+func Test(t *testing.T) { TestingT(t) }
1904+
1905+// partition specific testsuite
1906+type ConfigParserTestSuite struct {
1907+ cfg *ConfigParser
1908+}
1909+
1910+var _ = Suite(&ConfigParserTestSuite{})
1911+
1912+const SAMPLE_INI = `
1913+[service]
1914+base: system-image.ubuntu.com
1915+http_port: 80
1916+https_port: 443
1917+channel: ubuntu-core/devel-proposed
1918+device: generic_amd64
1919+build_number: 246
1920+version_detail: ubuntu=20150121,raw-device=20150121,version=246
1921+
1922+[foo]
1923+bar: baz
1924+yesbool: On
1925+nobool: off
1926+float: 3.14
1927+
1928+[testOptions]
1929+One: 1
1930+Two: 2
1931+`
1932+
1933+func (s *ConfigParserTestSuite) SetUpTest(c *C) {
1934+ s.cfg = New()
1935+ c.Assert(s.cfg, NotNil)
1936+ err := s.cfg.ReadString(SAMPLE_INI)
1937+ c.Assert(err, IsNil)
1938+}
1939+
1940+func (s *ConfigParserTestSuite) TestSection(c *C) {
1941+ sections := s.cfg.Sections()
1942+ sort.Strings(sections)
1943+ c.Assert(sections, DeepEquals, []string{"foo", "service", "testOptions"})
1944+}
1945+
1946+func (s *ConfigParserTestSuite) TestOptions(c *C) {
1947+ options, err := s.cfg.Options("testOptions")
1948+ c.Assert(err, IsNil)
1949+ sort.Strings(options)
1950+ c.Assert(options, DeepEquals, []string{"One", "Two"})
1951+}
1952+
1953+func (s *ConfigParserTestSuite) TestGet(c *C) {
1954+ val, err := s.cfg.Get("service", "base")
1955+ c.Assert(err, IsNil)
1956+ c.Assert(val, Equals, "system-image.ubuntu.com")
1957+}
1958+
1959+func (s *ConfigParserTestSuite) TestGetint(c *C) {
1960+ intval, err := s.cfg.Getint("service", "http_port")
1961+ c.Assert(err, IsNil)
1962+ c.Assert(intval, Equals, 80)
1963+}
1964+
1965+func (s *ConfigParserTestSuite) TestGetfloat(c *C) {
1966+ intval, err := s.cfg.Getfloat("foo", "float")
1967+ c.Assert(err, IsNil)
1968+ c.Assert(intval, Equals, 3.14)
1969+}
1970+
1971+func (s *ConfigParserTestSuite) TestGetbool(c *C) {
1972+ boolval, err := s.cfg.Getbool("foo", "yesbool")
1973+ c.Assert(err, IsNil)
1974+ c.Assert(boolval, Equals, true)
1975+
1976+ boolval, err = s.cfg.Getbool("foo", "nobool")
1977+ c.Assert(err, IsNil)
1978+ c.Assert(boolval, Equals, false)
1979+
1980+ boolval, err = s.cfg.Getbool("foo", "bar")
1981+ c.Assert(err.Error(), Equals, "No boolean: baz")
1982+}
1983+
1984+func (s *ConfigParserTestSuite) TestErrors(c *C) {
1985+ val, err := s.cfg.Get("foo", "bar")
1986+ c.Assert(err, IsNil)
1987+ c.Assert(val, Equals, "baz")
1988+
1989+ val, err = s.cfg.Get("foo", "no-such-option")
1990+ c.Assert(err, NotNil)
1991+ c.Assert(err.Error(), Equals, "No option no-such-option in section foo")
1992+
1993+ val, err = s.cfg.Get("no-such-section", "no-such-value")
1994+ c.Assert(err, NotNil)
1995+ c.Assert(err.Error(), Equals, "No section: no-such-section")
1996+}
1997+
1998+func (s *ConfigParserTestSuite) TestAllowNoSection(c *C) {
1999+ s.cfg = New()
2000+ s.cfg.AllowNoSectionHeader = true
2001+ err := s.cfg.Read(strings.NewReader(`foo=bar`))
2002+ c.Assert(err, IsNil)
2003+ val, err := s.cfg.Get("", "foo")
2004+ c.Assert(val, Equals, "bar")
2005+}
2006+
2007+func (s *ConfigParserTestSuite) TestReadFile(c *C) {
2008+ tmp, err := ioutil.TempFile("", "")
2009+ c.Assert(err, IsNil)
2010+ tmp.Write([]byte(SAMPLE_INI))
2011+
2012+ s.cfg = New()
2013+ err = s.cfg.ReadFile(tmp.Name())
2014+ c.Assert(err, IsNil)
2015+ val, err := s.cfg.Get("foo", "bar")
2016+ c.Assert(val, Equals, "baz")
2017+}
2018
2019=== added directory 'internal/github.com/mvo5/uboot-go'
2020=== added directory 'internal/github.com/mvo5/uboot-go/uenv'
2021=== added file 'internal/github.com/mvo5/uboot-go/uenv/env.go'
2022--- internal/github.com/mvo5/uboot-go/uenv/env.go 1970-01-01 00:00:00 +0000
2023+++ internal/github.com/mvo5/uboot-go/uenv/env.go 2015-10-30 14:13:06 +0000
2024@@ -0,0 +1,235 @@
2025+package uenv
2026+
2027+import (
2028+ "bufio"
2029+ "bytes"
2030+ "encoding/binary"
2031+ "fmt"
2032+ "hash/crc32"
2033+ "io"
2034+ "io/ioutil"
2035+ "os"
2036+ "sort"
2037+ "strings"
2038+)
2039+
2040+// FIXME: add config option for that so that the user can select if
2041+// he/she wants env with or without flags
2042+var headerSize = 5
2043+
2044+// Env contains the data of the uboot environment
2045+type Env struct {
2046+ fname string
2047+ size int
2048+ data map[string]string
2049+}
2050+
2051+// little endian helpers
2052+func readUint32(data []byte) uint32 {
2053+ var ret uint32
2054+ buf := bytes.NewBuffer(data)
2055+ binary.Read(buf, binary.LittleEndian, &ret)
2056+ return ret
2057+}
2058+
2059+func writeUint32(u uint32) []byte {
2060+ buf := bytes.NewBuffer(nil)
2061+ binary.Write(buf, binary.LittleEndian, &u)
2062+ return buf.Bytes()
2063+}
2064+
2065+// Create a new empty uboot env file with the given size
2066+func Create(fname string, size int) (*Env, error) {
2067+ f, err := os.Create(fname)
2068+ if err != nil {
2069+ return nil, err
2070+ }
2071+ defer f.Close()
2072+
2073+ env := &Env{
2074+ fname: fname,
2075+ size: size,
2076+ data: make(map[string]string),
2077+ }
2078+
2079+ return env, nil
2080+}
2081+
2082+// Open opens a existing uboot env file
2083+func Open(fname string) (*Env, error) {
2084+ f, err := os.Open(fname)
2085+ if err != nil {
2086+ return nil, err
2087+ }
2088+ defer f.Close()
2089+
2090+ contentWithHeader, err := ioutil.ReadAll(f)
2091+ if err != nil {
2092+ return nil, err
2093+ }
2094+ crc := readUint32(contentWithHeader)
2095+
2096+ payload := contentWithHeader[headerSize:]
2097+ actualCRC := crc32.ChecksumIEEE(payload)
2098+ if crc != actualCRC {
2099+ return nil, fmt.Errorf("bad CRC: %v != %v", crc, actualCRC)
2100+ }
2101+ eof := bytes.Index(payload, []byte{0, 0})
2102+
2103+ env := &Env{
2104+ fname: fname,
2105+ size: len(contentWithHeader),
2106+ data: parseData(payload[:eof]),
2107+ }
2108+
2109+ return env, nil
2110+}
2111+
2112+func parseData(data []byte) map[string]string {
2113+ out := make(map[string]string)
2114+
2115+ for _, envStr := range bytes.Split(data, []byte{0}) {
2116+ if len(envStr) == 0 || envStr[0] == 0 || envStr[0] == 255 {
2117+ continue
2118+ }
2119+ l := strings.SplitN(string(envStr), "=", 2)
2120+ if len(l) == 1 {
2121+ panic(fmt.Sprintf("invalid line %q (corrupted file?)", envStr))
2122+ }
2123+ key := l[0]
2124+ value := l[1]
2125+ out[key] = value
2126+ }
2127+
2128+ return out
2129+}
2130+
2131+func (env *Env) String() string {
2132+ out := ""
2133+
2134+ env.iterEnv(func(key, value string) {
2135+ out += fmt.Sprintf("%s=%s\n", key, value)
2136+ })
2137+
2138+ return out
2139+}
2140+
2141+// Get the value of the environment variable
2142+func (env *Env) Get(name string) string {
2143+ return env.data[name]
2144+}
2145+
2146+// Set an environment name to the given value, if the value is empty
2147+// the variable will be removed from the environment
2148+func (env *Env) Set(name, value string) {
2149+ if name == "" {
2150+ panic(fmt.Sprintf("Set() can not be called with empty key for value: %q", value))
2151+ }
2152+ if value == "" {
2153+ delete(env.data, name)
2154+ return
2155+ }
2156+ env.data[name] = value
2157+}
2158+
2159+// iterEnv calls the passed function f with key, value for environment
2160+// vars. The order is guaranteed (unlike just iterating over the map)
2161+func (env *Env) iterEnv(f func(key, value string)) {
2162+ keys := make([]string, 0, len(env.data))
2163+ for k := range env.data {
2164+ keys = append(keys, k)
2165+ }
2166+ sort.Strings(keys)
2167+
2168+ for _, k := range keys {
2169+ if k == "" {
2170+ panic("iterEnv iterating over a empty key")
2171+ }
2172+
2173+ f(k, env.data[k])
2174+ }
2175+}
2176+
2177+// Save will write out the environment data
2178+func (env *Env) Save() error {
2179+ w := bytes.NewBuffer(nil)
2180+ // will panic if the buffer can't grow, all writes to
2181+ // the buffer will be ok because we sized it correctly
2182+ w.Grow(env.size - headerSize)
2183+
2184+ // write the payload
2185+ env.iterEnv(func(key, value string) {
2186+ w.Write([]byte(fmt.Sprintf("%s=%s", key, value)))
2187+ w.Write([]byte{0})
2188+ })
2189+
2190+ // write double \0 to mark the end of the env
2191+ w.Write([]byte{0})
2192+
2193+ // no keys, so no previous \0 was written so we write one here
2194+ if len(env.data) == 0 {
2195+ w.Write([]byte{0})
2196+ }
2197+
2198+ // write ff into the remaining parts
2199+ writtenSoFar := w.Len()
2200+ for i := 0; i < env.size-headerSize-writtenSoFar; i++ {
2201+ w.Write([]byte{0xff})
2202+ }
2203+
2204+ // checksum
2205+ crc := crc32.ChecksumIEEE(w.Bytes())
2206+
2207+ // Note that we overwrite the existing file and do not do
2208+ // the usual write-rename. The rationale is that we want to
2209+ // minimize the amount of writes happening on a potential
2210+ // FAT partition where the env is loaded from. The file will
2211+ // always be of a fixed size so we know the writes will not
2212+ // fail because of ENOSPC.
2213+ //
2214+ // The size of the env file never changes so we do not
2215+ // truncate it.
2216+ //
2217+ // We also do not O_TRUNC to avoid reallocations on the FS
2218+ // to minimize risk of fs corruption.
2219+ f, err := os.OpenFile(env.fname, os.O_WRONLY, 0666)
2220+ if err != nil {
2221+ return err
2222+ }
2223+ defer f.Close()
2224+
2225+ if _, err := f.Write(writeUint32(crc)); err != nil {
2226+ return err
2227+ }
2228+ // padding bytes (e.g. for redundant header)
2229+ pad := make([]byte, headerSize-binary.Size(crc))
2230+ if _, err := f.Write(pad); err != nil {
2231+ return err
2232+ }
2233+ if _, err := f.Write(w.Bytes()); err != nil {
2234+ return err
2235+ }
2236+
2237+ return f.Sync()
2238+}
2239+
2240+// Import is a helper that imports a given text file that contains
2241+// "key=value" paris into the uboot env. Lines starting with ^# are
2242+// ignored (like the input file on mkenvimage)
2243+func (env *Env) Import(r io.Reader) error {
2244+ scanner := bufio.NewScanner(r)
2245+ for scanner.Scan() {
2246+ line := scanner.Text()
2247+ if strings.HasPrefix(line, "#") || len(line) == 0 {
2248+ continue
2249+ }
2250+ l := strings.SplitN(line, "=", 2)
2251+ if len(l) == 1 {
2252+ return fmt.Errorf("Invalid line: %q", line)
2253+ }
2254+ env.data[l[0]] = l[1]
2255+
2256+ }
2257+
2258+ return scanner.Err()
2259+}
2260
2261=== added file 'internal/github.com/mvo5/uboot-go/uenv/env_test.go'
2262--- internal/github.com/mvo5/uboot-go/uenv/env_test.go 1970-01-01 00:00:00 +0000
2263+++ internal/github.com/mvo5/uboot-go/uenv/env_test.go 2015-10-30 14:13:06 +0000
2264@@ -0,0 +1,203 @@
2265+package uenv
2266+
2267+import (
2268+ "bytes"
2269+ "hash/crc32"
2270+ "io/ioutil"
2271+ "os"
2272+ "path/filepath"
2273+ "strings"
2274+ "testing"
2275+
2276+ . "launchpad.net/crackly/internal/gopkg.in/check.v1"
2277+)
2278+
2279+// Hook up check.v1 into the "go test" runner
2280+func Test(t *testing.T) { TestingT(t) }
2281+
2282+type uenvTestSuite struct {
2283+ envFile string
2284+}
2285+
2286+var _ = Suite(&uenvTestSuite{})
2287+
2288+func (u *uenvTestSuite) SetUpTest(c *C) {
2289+ u.envFile = filepath.Join(c.MkDir(), "uboot.env")
2290+}
2291+
2292+func (u *uenvTestSuite) TestSetNoDuplicate(c *C) {
2293+ env, err := Create(u.envFile, 4096)
2294+ c.Assert(err, IsNil)
2295+ env.Set("foo", "bar")
2296+ env.Set("foo", "bar")
2297+ c.Assert(env.String(), Equals, "foo=bar\n")
2298+}
2299+
2300+func (u *uenvTestSuite) TestOpenEnv(c *C) {
2301+ env, err := Create(u.envFile, 4096)
2302+ c.Assert(err, IsNil)
2303+ env.Set("foo", "bar")
2304+ c.Assert(env.String(), Equals, "foo=bar\n")
2305+ err = env.Save()
2306+ c.Assert(err, IsNil)
2307+
2308+ env2, err := Open(u.envFile)
2309+ c.Assert(err, IsNil)
2310+ c.Assert(env2.String(), Equals, "foo=bar\n")
2311+}
2312+
2313+func (u *uenvTestSuite) TestGetSimple(c *C) {
2314+ env, err := Create(u.envFile, 4096)
2315+ c.Assert(err, IsNil)
2316+ env.Set("foo", "bar")
2317+ c.Assert(env.Get("foo"), Equals, "bar")
2318+}
2319+
2320+func (u *uenvTestSuite) TestGetNoSuchEntry(c *C) {
2321+ env, err := Create(u.envFile, 4096)
2322+ c.Assert(err, IsNil)
2323+ c.Assert(env.Get("no-such-entry"), Equals, "")
2324+}
2325+
2326+func (u *uenvTestSuite) TestImport(c *C) {
2327+ env, err := Create(u.envFile, 4096)
2328+ c.Assert(err, IsNil)
2329+
2330+ r := strings.NewReader("foo=bar\n#comment\n\nbaz=baz")
2331+ err = env.Import(r)
2332+ c.Assert(err, IsNil)
2333+ // order is alphabetic
2334+ c.Assert(env.String(), Equals, "baz=baz\nfoo=bar\n")
2335+}
2336+
2337+func (u *uenvTestSuite) TestImportHasError(c *C) {
2338+ env, err := Create(u.envFile, 4096)
2339+ c.Assert(err, IsNil)
2340+
2341+ r := strings.NewReader("foxy")
2342+ err = env.Import(r)
2343+ c.Assert(err, ErrorMatches, "Invalid line: \"foxy\"")
2344+}
2345+
2346+func (u *uenvTestSuite) TestSetEmptyUnsets(c *C) {
2347+ env, err := Create(u.envFile, 4096)
2348+ c.Assert(err, IsNil)
2349+
2350+ env.Set("foo", "bar")
2351+ c.Assert(env.String(), Equals, "foo=bar\n")
2352+ env.Set("foo", "")
2353+ c.Assert(env.String(), Equals, "")
2354+}
2355+
2356+func (u *uenvTestSuite) makeUbootEnvFromData(c *C, mockData []byte) {
2357+ w := bytes.NewBuffer(nil)
2358+ crc := crc32.ChecksumIEEE(mockData)
2359+ w.Write(writeUint32(crc))
2360+ w.Write([]byte{0})
2361+ w.Write(mockData)
2362+
2363+ f, err := os.Create(u.envFile)
2364+ c.Assert(err, IsNil)
2365+ defer f.Close()
2366+ _, err = f.Write(w.Bytes())
2367+ c.Assert(err, IsNil)
2368+}
2369+
2370+// ensure that the data after \0\0 is discarded (except for crc)
2371+func (u *uenvTestSuite) TestReadStopsAfterDoubleNull(c *C) {
2372+ mockData := []byte{
2373+ // foo=bar
2374+ 0x66, 0x6f, 0x6f, 0x3d, 0x62, 0x61, 0x72,
2375+ // eof
2376+ 0x00, 0x00,
2377+ // junk after eof as written by fw_setenv sometimes
2378+ // =b
2379+ 0x3d, 62,
2380+ // empty
2381+ 0xff, 0xff,
2382+ }
2383+ u.makeUbootEnvFromData(c, mockData)
2384+
2385+ env, err := Open(u.envFile)
2386+ c.Assert(err, IsNil)
2387+ c.Assert(env.String(), Equals, "foo=bar\n")
2388+}
2389+
2390+func (u *uenvTestSuite) TestReadEmptyFile(c *C) {
2391+ mockData := []byte{
2392+ // eof
2393+ 0x00, 0x00,
2394+ // empty
2395+ 0xff, 0xff,
2396+ }
2397+ u.makeUbootEnvFromData(c, mockData)
2398+
2399+ env, err := Open(u.envFile)
2400+ c.Assert(err, IsNil)
2401+ c.Assert(env.String(), Equals, "")
2402+}
2403+
2404+func (u *uenvTestSuite) TestWritesEmptyFileWithDoubleNewline(c *C) {
2405+ env, err := Create(u.envFile, 12)
2406+ c.Assert(err, IsNil)
2407+ err = env.Save()
2408+ c.Assert(err, IsNil)
2409+
2410+ r, err := os.Open(u.envFile)
2411+ c.Assert(err, IsNil)
2412+ defer r.Close()
2413+ content, err := ioutil.ReadAll(r)
2414+ c.Assert(err, IsNil)
2415+ c.Assert(content, DeepEquals, []byte{
2416+ // crc
2417+ 0x11, 0x38, 0xb3, 0x89,
2418+ // redundant
2419+ 0x0,
2420+ // eof
2421+ 0x0, 0x0,
2422+ // footer
2423+ 0xff, 0xff, 0xff, 0xff, 0xff,
2424+ })
2425+
2426+ env, err = Open(u.envFile)
2427+ c.Assert(err, IsNil)
2428+ c.Assert(env.String(), Equals, "")
2429+}
2430+
2431+func (u *uenvTestSuite) TestWritesContentCorrectly(c *C) {
2432+ totalSize := 16
2433+
2434+ env, err := Create(u.envFile, totalSize)
2435+ c.Assert(err, IsNil)
2436+ env.Set("a", "b")
2437+ env.Set("c", "d")
2438+ err = env.Save()
2439+ c.Assert(err, IsNil)
2440+
2441+ r, err := os.Open(u.envFile)
2442+ c.Assert(err, IsNil)
2443+ defer r.Close()
2444+ content, err := ioutil.ReadAll(r)
2445+ c.Assert(err, IsNil)
2446+ c.Assert(content, DeepEquals, []byte{
2447+ // crc
2448+ 0xc7, 0xd9, 0x6b, 0xc5,
2449+ // redundant
2450+ 0x0,
2451+ // a=b
2452+ 0x61, 0x3d, 0x62,
2453+ // eol
2454+ 0x0,
2455+ // c=d
2456+ 0x63, 0x3d, 0x64,
2457+ // eof
2458+ 0x0, 0x0,
2459+ // footer
2460+ 0xff, 0xff,
2461+ })
2462+
2463+ env, err = Open(u.envFile)
2464+ c.Assert(err, IsNil)
2465+ c.Assert(env.String(), Equals, "a=b\nc=d\n")
2466+ c.Assert(env.size, Equals, totalSize)
2467+}
2468
2469=== added directory 'internal/github.com/olekukonko'
2470=== added directory 'internal/github.com/olekukonko/ts'
2471=== added file 'internal/github.com/olekukonko/ts/LICENCE'
2472--- internal/github.com/olekukonko/ts/LICENCE 1970-01-01 00:00:00 +0000
2473+++ internal/github.com/olekukonko/ts/LICENCE 2015-10-30 14:13:06 +0000
2474@@ -0,0 +1,19 @@
2475+Copyright (C) 2014 by Oleku Konko
2476+
2477+Permission is hereby granted, free of charge, to any person obtaining a copy
2478+of this software and associated documentation files (the "Software"), to deal
2479+in the Software without restriction, including without limitation the rights
2480+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2481+copies of the Software, and to permit persons to whom the Software is
2482+furnished to do so, subject to the following conditions:
2483+
2484+The above copyright notice and this permission notice shall be included in
2485+all copies or substantial portions of the Software.
2486+
2487+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2488+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2489+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2490+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2491+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2492+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2493+THE SOFTWARE.
2494\ No newline at end of file
2495
2496=== added file 'internal/github.com/olekukonko/ts/README.md'
2497--- internal/github.com/olekukonko/ts/README.md 1970-01-01 00:00:00 +0000
2498+++ internal/github.com/olekukonko/ts/README.md 2015-10-30 14:13:06 +0000
2499@@ -0,0 +1,28 @@
2500+ts (Terminal Size)
2501+==
2502+
2503+[![Build Status](https://travis-ci.org/olekukonko/ts.png?branch=master)](https://travis-ci.org/olekukonko/ts) [![Total views](https://sourcegraph.com/api/repos/github.com/olekukonko/ts/counters/views.png)](https://sourcegraph.com/github.com/olekukonko/ts)
2504+
2505+Simple go Application to get Terminal Size. So Many Implementations do not support windows but `ts` has full windows support.
2506+Run `go get github.com/olekukonko/ts` to download and install
2507+
2508+#### Example
2509+
2510+```go
2511+package main
2512+
2513+import (
2514+ "fmt"
2515+ "github.com/olekukonko/ts"
2516+)
2517+
2518+func main() {
2519+ size, _ := ts.GetSize()
2520+ fmt.Println(size.Col()) // Get Width
2521+ fmt.Println(size.Row()) // Get Height
2522+ fmt.Println(size.PosX()) // Get X position
2523+ fmt.Println(size.PosY()) // Get Y position
2524+}
2525+```
2526+
2527+[See Documentation](http://godoc.org/github.com/olekukonko/ts)
2528
2529=== added file 'internal/github.com/olekukonko/ts/doc.go'
2530--- internal/github.com/olekukonko/ts/doc.go 1970-01-01 00:00:00 +0000
2531+++ internal/github.com/olekukonko/ts/doc.go 2015-10-30 14:13:06 +0000
2532@@ -0,0 +1,36 @@
2533+// Copyright 2014 Oleku Konko All rights reserved.
2534+// Use of this source code is governed by a MIT
2535+// license that can be found in the LICENSE file.
2536+
2537+// This module is a Terminal API for the Go Programming Language.
2538+// The protocols were written in pure Go and works on windows and unix systems
2539+
2540+/**
2541+
2542+Simple go Application to get Terminal Size. So Many Implementations do not support windows but `ts` has full windows support.
2543+Run `go get github.com/olekukonko/ts` to download and install
2544+
2545+Installation
2546+
2547+Minimum requirements are Go 1.1+ with fill Windows support
2548+
2549+Example
2550+
2551+ package main
2552+
2553+ import (
2554+ "fmt"
2555+ "github.com/olekukonko/ts"
2556+ )
2557+
2558+ func main() {
2559+ size, _ := ts.GetSize()
2560+ fmt.Println(size.Col()) // Get Width
2561+ fmt.Println(size.Row()) // Get Height
2562+ fmt.Println(size.PosX()) // Get X position
2563+ fmt.Println(size.PosY()) // Get Y position
2564+ }
2565+
2566+**/
2567+
2568+package ts
2569
2570=== added file 'internal/github.com/olekukonko/ts/ts.go'
2571--- internal/github.com/olekukonko/ts/ts.go 1970-01-01 00:00:00 +0000
2572+++ internal/github.com/olekukonko/ts/ts.go 2015-10-30 14:13:06 +0000
2573@@ -0,0 +1,36 @@
2574+// Copyright 2014 Oleku Konko All rights reserved.
2575+// Use of this source code is governed by a MIT
2576+// license that can be found in the LICENSE file.
2577+
2578+// This module is a Terminal API for the Go Programming Language.
2579+// The protocols were written in pure Go and works on windows and unix systems
2580+
2581+package ts
2582+
2583+// Return System Size
2584+type Size struct {
2585+ row uint16
2586+ col uint16
2587+ posX uint16
2588+ posY uint16
2589+}
2590+
2591+// Get Terminal Width
2592+func (w Size) Col() int {
2593+ return int(w.col)
2594+}
2595+
2596+// Get Terminal Height
2597+func (w Size) Row() int {
2598+ return int(w.row)
2599+}
2600+
2601+// Get Position X
2602+func (w Size) PosX() int {
2603+ return int(w.posX)
2604+}
2605+
2606+// Get Position Y
2607+func (w Size) PosY() int {
2608+ return int(w.posY)
2609+}
2610
2611=== added file 'internal/github.com/olekukonko/ts/ts_darwin.go'
2612--- internal/github.com/olekukonko/ts/ts_darwin.go 1970-01-01 00:00:00 +0000
2613+++ internal/github.com/olekukonko/ts/ts_darwin.go 2015-10-30 14:13:06 +0000
2614@@ -0,0 +1,14 @@
2615+// +build darwin
2616+
2617+// Copyright 2014 Oleku Konko All rights reserved.
2618+// Use of this source code is governed by a MIT
2619+// license that can be found in the LICENSE file.
2620+
2621+// This module is a Terminal API for the Go Programming Language.
2622+// The protocols were written in pure Go and works on windows and unix systems
2623+
2624+package ts
2625+
2626+const (
2627+ TIOCGWINSZ = 0x40087468
2628+)
2629
2630=== added file 'internal/github.com/olekukonko/ts/ts_linux.go'
2631--- internal/github.com/olekukonko/ts/ts_linux.go 1970-01-01 00:00:00 +0000
2632+++ internal/github.com/olekukonko/ts/ts_linux.go 2015-10-30 14:13:06 +0000
2633@@ -0,0 +1,13 @@
2634+// +build linux
2635+
2636+// Copyright 2014 Oleku Konko All rights reserved.
2637+// Use of this source code is governed by a MIT
2638+// license that can be found in the LICENSE file.
2639+
2640+// This module is a Terminal API for the Go Programming Language.
2641+// The protocols were written in pure Go and works on windows and unix systems
2642+package ts
2643+
2644+const (
2645+ TIOCGWINSZ = 0x5413
2646+)
2647
2648=== added file 'internal/github.com/olekukonko/ts/ts_other.go'
2649--- internal/github.com/olekukonko/ts/ts_other.go 1970-01-01 00:00:00 +0000
2650+++ internal/github.com/olekukonko/ts/ts_other.go 2015-10-30 14:13:06 +0000
2651@@ -0,0 +1,14 @@
2652+// +build !windows,!darwin,!freebsd,!netbsd,!openbsd,!linux
2653+
2654+// Copyright 2014 Oleku Konko All rights reserved.
2655+// Use of this source code is governed by a MIT
2656+// license that can be found in the LICENSE file.
2657+
2658+// This module is a Terminal API for the Go Programming Language.
2659+// The protocols were written in pure Go and works on windows and unix systems
2660+
2661+package ts
2662+
2663+const (
2664+ TIOCGWINSZ = 0
2665+)
2666
2667=== added file 'internal/github.com/olekukonko/ts/ts_test.go'
2668--- internal/github.com/olekukonko/ts/ts_test.go 1970-01-01 00:00:00 +0000
2669+++ internal/github.com/olekukonko/ts/ts_test.go 2015-10-30 14:13:06 +0000
2670@@ -0,0 +1,32 @@
2671+// Copyright 2014 Oleku Konko All rights reserved.
2672+// Use of this source code is governed by a MIT
2673+// license that can be found in the LICENSE file.
2674+
2675+// This module is a Terminal API for the Go Programming Language.
2676+// The protocols were written in pure Go and works on windows and unix systems
2677+
2678+package ts
2679+
2680+import (
2681+ "fmt"
2682+ "testing"
2683+)
2684+
2685+func ExampleGetSize() {
2686+ size, _ := GetSize()
2687+ fmt.Println(size.Col()) // Get Width
2688+ fmt.Println(size.Row()) // Get Height
2689+ fmt.Println(size.PosX()) // Get X position
2690+ fmt.Println(size.PosY()) // Get Y position
2691+}
2692+
2693+func TestSize(t *testing.T) {
2694+ size, err := GetSize()
2695+
2696+ if err != nil {
2697+ t.Fatal(err)
2698+ }
2699+ if size.Col() == 0 || size.Row() == 0 {
2700+ t.Fatalf("Screen Size Failed")
2701+ }
2702+}
2703
2704=== added file 'internal/github.com/olekukonko/ts/ts_unix.go'
2705--- internal/github.com/olekukonko/ts/ts_unix.go 1970-01-01 00:00:00 +0000
2706+++ internal/github.com/olekukonko/ts/ts_unix.go 2015-10-30 14:13:06 +0000
2707@@ -0,0 +1,14 @@
2708+// +build freebsd netbsd openbsd
2709+
2710+// Copyright 2014 Oleku Konko All rights reserved.
2711+// Use of this source code is governed by a MIT
2712+// license that can be found in the LICENSE file.
2713+
2714+// This module is a Terminal API for the Go Programming Language.
2715+// The protocols were written in pure Go and works on windows and unix systems
2716+
2717+package ts
2718+
2719+const (
2720+ TIOCGWINSZ = 0x40087468
2721+)
2722
2723=== added file 'internal/github.com/olekukonko/ts/ts_windows.go'
2724--- internal/github.com/olekukonko/ts/ts_windows.go 1970-01-01 00:00:00 +0000
2725+++ internal/github.com/olekukonko/ts/ts_windows.go 2015-10-30 14:13:06 +0000
2726@@ -0,0 +1,64 @@
2727+// +build windows
2728+
2729+// Copyright 2014 Oleku Konko All rights reserved.
2730+// Use of this source code is governed by a MIT
2731+// license that can be found in the LICENSE file.
2732+
2733+// This module is a Terminal API for the Go Programming Language.
2734+// The protocols were written in pure Go and works on windows and unix systems
2735+
2736+package ts
2737+
2738+import (
2739+ "syscall"
2740+ "unsafe"
2741+)
2742+
2743+var (
2744+ kernel32 = syscall.NewLazyDLL("kernel32.dll")
2745+
2746+ // Retrieves information about the specified console screen buffer.
2747+ // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx
2748+ screenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
2749+)
2750+
2751+// Contains information about a console screen buffer.
2752+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093(v=vs.85).aspx
2753+type CONSOLE_SCREEN_BUFFER_INFO struct {
2754+ DwSize COORD
2755+ DwCursorPosition COORD
2756+ WAttributes uint16
2757+ SrWindow SMALL_RECT
2758+ DwMaximumWindowSize COORD
2759+}
2760+
2761+// Defines the coordinates of a character cell in a console screen buffer.
2762+// The origin of the coordinate system (0,0) is at the top, left cell of the buffer.
2763+// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682119(v=vs.85).aspx
2764+type COORD struct {
2765+ X, Y uint16
2766+}
2767+
2768+// Defines the coordinates of the upper left and lower right corners of a rectangle.
2769+// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686311(v=vs.85).aspx
2770+type SMALL_RECT struct {
2771+ Left, Top, Right, Bottom uint16
2772+}
2773+
2774+func GetSize() (ws Size, err error) {
2775+ var info CONSOLE_SCREEN_BUFFER_INFO
2776+ rc, _, err := screenBufferInfo.Call(
2777+ uintptr(syscall.Stdout),
2778+ uintptr(unsafe.Pointer(&info)))
2779+
2780+ if rc == 0 {
2781+ return ws, err
2782+ }
2783+
2784+ ws = Size{info.SrWindow.Bottom,
2785+ info.SrWindow.Right,
2786+ info.DwCursorPosition.X,
2787+ info.DwCursorPosition.Y}
2788+
2789+ return ws, nil
2790+}
2791
2792=== added file 'internal/github.com/olekukonko/ts/ts_x.go'
2793--- internal/github.com/olekukonko/ts/ts_x.go 1970-01-01 00:00:00 +0000
2794+++ internal/github.com/olekukonko/ts/ts_x.go 2015-10-30 14:13:06 +0000
2795@@ -0,0 +1,46 @@
2796+// +build !windows
2797+
2798+// Copyright 2014 Oleku Konko All rights reserved.
2799+// Use of this source code is governed by a MIT
2800+// license that can be found in the LICENSE file.
2801+
2802+// This module is a Terminal API for the Go Programming Language.
2803+// The protocols were written in pure Go and works on windows and unix systems
2804+
2805+package ts
2806+
2807+import (
2808+ "syscall"
2809+ "unsafe"
2810+)
2811+
2812+// Get Windows Size
2813+func GetSize() (ws Size, err error) {
2814+ _, _, ec := syscall.Syscall(syscall.SYS_IOCTL,
2815+ uintptr(syscall.Stdout),
2816+ uintptr(TIOCGWINSZ),
2817+ uintptr(unsafe.Pointer(&ws)))
2818+
2819+ err = getError(ec)
2820+
2821+ if TIOCGWINSZ == 0 && err != nil {
2822+ ws = Size{80, 25, 0, 0}
2823+ }
2824+ return ws, err
2825+}
2826+
2827+func getError(ec interface{}) (err error) {
2828+ switch v := ec.(type) {
2829+
2830+ case syscall.Errno: // Some implementation return syscall.Errno number
2831+ if v != 0 {
2832+ err = syscall.Errno(v)
2833+ }
2834+
2835+ case error: // Some implementation return error
2836+ err = ec.(error)
2837+ default:
2838+ err = nil
2839+ }
2840+ return
2841+}
2842
2843=== added directory 'internal/gopkg.in'
2844=== added directory 'internal/gopkg.in/check.v1'
2845=== added file 'internal/gopkg.in/check.v1/LICENSE'
2846--- internal/gopkg.in/check.v1/LICENSE 1970-01-01 00:00:00 +0000
2847+++ internal/gopkg.in/check.v1/LICENSE 2015-10-30 14:13:06 +0000
2848@@ -0,0 +1,25 @@
2849+Gocheck - A rich testing framework for Go
2850+
2851+Copyright (c) 2010-2013 Gustavo Niemeyer <gustavo@niemeyer.net>
2852+
2853+All rights reserved.
2854+
2855+Redistribution and use in source and binary forms, with or without
2856+modification, are permitted provided that the following conditions are met:
2857+
2858+1. Redistributions of source code must retain the above copyright notice, this
2859+ list of conditions and the following disclaimer.
2860+2. Redistributions in binary form must reproduce the above copyright notice,
2861+ this list of conditions and the following disclaimer in the documentation
2862+ and/or other materials provided with the distribution.
2863+
2864+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2865+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2866+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2867+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
2868+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2869+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2870+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2871+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2872+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2873+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2874
2875=== added file 'internal/gopkg.in/check.v1/README.md'
2876--- internal/gopkg.in/check.v1/README.md 1970-01-01 00:00:00 +0000
2877+++ internal/gopkg.in/check.v1/README.md 2015-10-30 14:13:06 +0000
2878@@ -0,0 +1,20 @@
2879+Instructions
2880+============
2881+
2882+Install the package with:
2883+
2884+ go get gopkg.in/check.v1
2885+
2886+Import it with:
2887+
2888+ import "gopkg.in/check.v1"
2889+
2890+and use _check_ as the package name inside the code.
2891+
2892+For more details, visit the project page:
2893+
2894+* http://labix.org/gocheck
2895+
2896+and the API documentation:
2897+
2898+* https://gopkg.in/check.v1
2899
2900=== added file 'internal/gopkg.in/check.v1/TODO'
2901--- internal/gopkg.in/check.v1/TODO 1970-01-01 00:00:00 +0000
2902+++ internal/gopkg.in/check.v1/TODO 2015-10-30 14:13:06 +0000
2903@@ -0,0 +1,2 @@
2904+- Assert(slice, Contains, item)
2905+- Parallel test support
2906
2907=== added file 'internal/gopkg.in/check.v1/benchmark.go'
2908--- internal/gopkg.in/check.v1/benchmark.go 1970-01-01 00:00:00 +0000
2909+++ internal/gopkg.in/check.v1/benchmark.go 2015-10-30 14:13:06 +0000
2910@@ -0,0 +1,163 @@
2911+// Copyright 2009 The Go Authors. All rights reserved.
2912+// Use of this source code is governed by a BSD-style
2913+// license that can be found in the LICENSE file.
2914+
2915+package check
2916+
2917+import (
2918+ "fmt"
2919+ "runtime"
2920+ "time"
2921+)
2922+
2923+var memStats runtime.MemStats
2924+
2925+// testingB is a type passed to Benchmark functions to manage benchmark
2926+// timing and to specify the number of iterations to run.
2927+type timer struct {
2928+ start time.Time // Time test or benchmark started
2929+ duration time.Duration
2930+ N int
2931+ bytes int64
2932+ timerOn bool
2933+ benchTime time.Duration
2934+ // The initial states of memStats.Mallocs and memStats.TotalAlloc.
2935+ startAllocs uint64
2936+ startBytes uint64
2937+ // The net total of this test after being run.
2938+ netAllocs uint64
2939+ netBytes uint64
2940+}
2941+
2942+// StartTimer starts timing a test. This function is called automatically
2943+// before a benchmark starts, but it can also used to resume timing after
2944+// a call to StopTimer.
2945+func (c *C) StartTimer() {
2946+ if !c.timerOn {
2947+ c.start = time.Now()
2948+ c.timerOn = true
2949+
2950+ runtime.ReadMemStats(&memStats)
2951+ c.startAllocs = memStats.Mallocs
2952+ c.startBytes = memStats.TotalAlloc
2953+ }
2954+}
2955+
2956+// StopTimer stops timing a test. This can be used to pause the timer
2957+// while performing complex initialization that you don't
2958+// want to measure.
2959+func (c *C) StopTimer() {
2960+ if c.timerOn {
2961+ c.duration += time.Now().Sub(c.start)
2962+ c.timerOn = false
2963+ runtime.ReadMemStats(&memStats)
2964+ c.netAllocs += memStats.Mallocs - c.startAllocs
2965+ c.netBytes += memStats.TotalAlloc - c.startBytes
2966+ }
2967+}
2968+
2969+// ResetTimer sets the elapsed benchmark time to zero.
2970+// It does not affect whether the timer is running.
2971+func (c *C) ResetTimer() {
2972+ if c.timerOn {
2973+ c.start = time.Now()
2974+ runtime.ReadMemStats(&memStats)
2975+ c.startAllocs = memStats.Mallocs
2976+ c.startBytes = memStats.TotalAlloc
2977+ }
2978+ c.duration = 0
2979+ c.netAllocs = 0
2980+ c.netBytes = 0
2981+}
2982+
2983+// SetBytes informs the number of bytes that the benchmark processes
2984+// on each iteration. If this is called in a benchmark it will also
2985+// report MB/s.
2986+func (c *C) SetBytes(n int64) {
2987+ c.bytes = n
2988+}
2989+
2990+func (c *C) nsPerOp() int64 {
2991+ if c.N <= 0 {
2992+ return 0
2993+ }
2994+ return c.duration.Nanoseconds() / int64(c.N)
2995+}
2996+
2997+func (c *C) mbPerSec() float64 {
2998+ if c.bytes <= 0 || c.duration <= 0 || c.N <= 0 {
2999+ return 0
3000+ }
3001+ return (float64(c.bytes) * float64(c.N) / 1e6) / c.duration.Seconds()
3002+}
3003+
3004+func (c *C) timerString() string {
3005+ if c.N <= 0 {
3006+ return fmt.Sprintf("%3.3fs", float64(c.duration.Nanoseconds())/1e9)
3007+ }
3008+ mbs := c.mbPerSec()
3009+ mb := ""
3010+ if mbs != 0 {
3011+ mb = fmt.Sprintf("\t%7.2f MB/s", mbs)
3012+ }
3013+ nsop := c.nsPerOp()
3014+ ns := fmt.Sprintf("%10d ns/op", nsop)
3015+ if c.N > 0 && nsop < 100 {
3016+ // The format specifiers here make sure that
3017+ // the ones digits line up for all three possible formats.
3018+ if nsop < 10 {
3019+ ns = fmt.Sprintf("%13.2f ns/op", float64(c.duration.Nanoseconds())/float64(c.N))
3020+ } else {
3021+ ns = fmt.Sprintf("%12.1f ns/op", float64(c.duration.Nanoseconds())/float64(c.N))
3022+ }
3023+ }
3024+ memStats := ""
3025+ if c.benchMem {
3026+ allocedBytes := fmt.Sprintf("%8d B/op", int64(c.netBytes)/int64(c.N))
3027+ allocs := fmt.Sprintf("%8d allocs/op", int64(c.netAllocs)/int64(c.N))
3028+ memStats = fmt.Sprintf("\t%s\t%s", allocedBytes, allocs)
3029+ }
3030+ return fmt.Sprintf("%8d\t%s%s%s", c.N, ns, mb, memStats)
3031+}
3032+
3033+func min(x, y int) int {
3034+ if x > y {
3035+ return y
3036+ }
3037+ return x
3038+}
3039+
3040+func max(x, y int) int {
3041+ if x < y {
3042+ return y
3043+ }
3044+ return x
3045+}
3046+
3047+// roundDown10 rounds a number down to the nearest power of 10.
3048+func roundDown10(n int) int {
3049+ var tens = 0
3050+ // tens = floor(log_10(n))
3051+ for n > 10 {
3052+ n = n / 10
3053+ tens++
3054+ }
3055+ // result = 10^tens
3056+ result := 1
3057+ for i := 0; i < tens; i++ {
3058+ result *= 10
3059+ }
3060+ return result
3061+}
3062+
3063+// roundUp rounds x up to a number of the form [1eX, 2eX, 5eX].
3064+func roundUp(n int) int {
3065+ base := roundDown10(n)
3066+ if n < (2 * base) {
3067+ return 2 * base
3068+ }
3069+ if n < (5 * base) {
3070+ return 5 * base
3071+ }
3072+ return 10 * base
3073+}
3074
3075=== added file 'internal/gopkg.in/check.v1/benchmark_test.go'
3076--- internal/gopkg.in/check.v1/benchmark_test.go 1970-01-01 00:00:00 +0000
3077+++ internal/gopkg.in/check.v1/benchmark_test.go 2015-10-30 14:13:06 +0000
3078@@ -0,0 +1,91 @@
3079+// These tests verify the test running logic.
3080+
3081+package check_test
3082+
3083+import (
3084+ "time"
3085+ . "launchpad.net/crackly/internal/gopkg.in/check.v1"
3086+)
3087+
3088+var benchmarkS = Suite(&BenchmarkS{})
3089+
3090+type BenchmarkS struct{}
3091+
3092+func (s *BenchmarkS) TestCountSuite(c *C) {
3093+ suitesRun += 1
3094+}
3095+
3096+func (s *BenchmarkS) TestBasicTestTiming(c *C) {
3097+ helper := FixtureHelper{sleepOn: "Test1", sleep: 1000000 * time.Nanosecond}
3098+ output := String{}
3099+ runConf := RunConf{Output: &output, Verbose: true}
3100+ Run(&helper, &runConf)
3101+
3102+ expected := "PASS: check_test\\.go:[0-9]+: FixtureHelper\\.Test1\t0\\.001s\n" +
3103+ "PASS: check_test\\.go:[0-9]+: FixtureHelper\\.Test2\t0\\.000s\n"
3104+ c.Assert(output.value, Matches, expected)
3105+}
3106+
3107+func (s *BenchmarkS) TestStreamTestTiming(c *C) {
3108+ helper := FixtureHelper{sleepOn: "SetUpSuite", sleep: 1000000 * time.Nanosecond}
3109+ output := String{}
3110+ runConf := RunConf{Output: &output, Stream: true}
3111+ Run(&helper, &runConf)
3112+
3113+ expected := "(?s).*\nPASS: check_test\\.go:[0-9]+: FixtureHelper\\.SetUpSuite\t *0\\.001s\n.*"
3114+ c.Assert(output.value, Matches, expected)
3115+}
3116+
3117+func (s *BenchmarkS) TestBenchmark(c *C) {
3118+ helper := FixtureHelper{sleep: 100000}
3119+ output := String{}
3120+ runConf := RunConf{
3121+ Output: &output,
3122+ Benchmark: true,
3123+ BenchmarkTime: 10000000,
3124+ Filter: "Benchmark1",
3125+ }
3126+ Run(&helper, &runConf)
3127+ c.Check(helper.calls[0], Equals, "SetUpSuite")
3128+ c.Check(helper.calls[1], Equals, "SetUpTest")
3129+ c.Check(helper.calls[2], Equals, "Benchmark1")
3130+ c.Check(helper.calls[3], Equals, "TearDownTest")
3131+ c.Check(helper.calls[4], Equals, "SetUpTest")
3132+ c.Check(helper.calls[5], Equals, "Benchmark1")
3133+ c.Check(helper.calls[6], Equals, "TearDownTest")
3134+ // ... and more.
3135+
3136+ expected := "PASS: check_test\\.go:[0-9]+: FixtureHelper\\.Benchmark1\t *100\t *[12][0-9]{5} ns/op\n"
3137+ c.Assert(output.value, Matches, expected)
3138+}
3139+
3140+func (s *BenchmarkS) TestBenchmarkBytes(c *C) {
3141+ helper := FixtureHelper{sleep: 100000}
3142+ output := String{}
3143+ runConf := RunConf{
3144+ Output: &output,
3145+ Benchmark: true,
3146+ BenchmarkTime: 10000000,
3147+ Filter: "Benchmark2",
3148+ }
3149+ Run(&helper, &runConf)
3150+
3151+ expected := "PASS: check_test\\.go:[0-9]+: FixtureHelper\\.Benchmark2\t *100\t *[12][0-9]{5} ns/op\t *[4-9]\\.[0-9]{2} MB/s\n"
3152+ c.Assert(output.value, Matches, expected)
3153+}
3154+
3155+func (s *BenchmarkS) TestBenchmarkMem(c *C) {
3156+ helper := FixtureHelper{sleep: 100000}
3157+ output := String{}
3158+ runConf := RunConf{
3159+ Output: &output,
3160+ Benchmark: true,
3161+ BenchmarkMem: true,
3162+ BenchmarkTime: 10000000,
3163+ Filter: "Benchmark3",
3164+ }
3165+ Run(&helper, &runConf)
3166+
3167+ expected := "PASS: check_test\\.go:[0-9]+: FixtureHelper\\.Benchmark3\t *100\t *[12][0-9]{5} ns/op\t *[0-9]+ B/op\t *[1-9] allocs/op\n"
3168+ c.Assert(output.value, Matches, expected)
3169+}
3170
3171=== added file 'internal/gopkg.in/check.v1/bootstrap_test.go'
3172--- internal/gopkg.in/check.v1/bootstrap_test.go 1970-01-01 00:00:00 +0000
3173+++ internal/gopkg.in/check.v1/bootstrap_test.go 2015-10-30 14:13:06 +0000
3174@@ -0,0 +1,82 @@
3175+// These initial tests are for bootstrapping. They verify that we can
3176+// basically use the testing infrastructure itself to check if the test
3177+// system is working.
3178+//
3179+// These tests use will break down the test runner badly in case of
3180+// errors because if they simply fail, we can't be sure the developer
3181+// will ever see anything (because failing means the failing system
3182+// somehow isn't working! :-)
3183+//
3184+// Do not assume *any* internal functionality works as expected besides
3185+// what's actually tested here.
3186+
3187+package check_test
3188+
3189+import (
3190+ "fmt"
3191+ "launchpad.net/crackly/internal/gopkg.in/check.v1"
3192+ "strings"
3193+)
3194+
3195+type BootstrapS struct{}
3196+
3197+var boostrapS = check.Suite(&BootstrapS{})
3198+
3199+func (s *BootstrapS) TestCountSuite(c *check.C) {
3200+ suitesRun += 1
3201+}
3202+
3203+func (s *BootstrapS) TestFailedAndFail(c *check.C) {
3204+ if c.Failed() {
3205+ critical("c.Failed() must be false first!")
3206+ }
3207+ c.Fail()
3208+ if !c.Failed() {
3209+ critical("c.Fail() didn't put the test in a failed state!")
3210+ }
3211+ c.Succeed()
3212+}
3213+
3214+func (s *BootstrapS) TestFailedAndSucceed(c *check.C) {
3215+ c.Fail()
3216+ c.Succeed()
3217+ if c.Failed() {
3218+ critical("c.Succeed() didn't put the test back in a non-failed state")
3219+ }
3220+}
3221+
3222+func (s *BootstrapS) TestLogAndGetTestLog(c *check.C) {
3223+ c.Log("Hello there!")
3224+ log := c.GetTestLog()
3225+ if log != "Hello there!\n" {
3226+ critical(fmt.Sprintf("Log() or GetTestLog() is not working! Got: %#v", log))
3227+ }
3228+}
3229+
3230+func (s *BootstrapS) TestLogfAndGetTestLog(c *check.C) {
3231+ c.Logf("Hello %v", "there!")
3232+ log := c.GetTestLog()
3233+ if log != "Hello there!\n" {
3234+ critical(fmt.Sprintf("Logf() or GetTestLog() is not working! Got: %#v", log))
3235+ }
3236+}
3237+
3238+func (s *BootstrapS) TestRunShowsErrors(c *check.C) {
3239+ output := String{}
3240+ check.Run(&FailHelper{}, &check.RunConf{Output: &output})
3241+ if strings.Index(output.value, "Expected failure!") == -1 {
3242+ critical(fmt.Sprintf("RunWithWriter() output did not contain the "+
3243+ "expected failure! Got: %#v",
3244+ output.value))
3245+ }
3246+}
3247+
3248+func (s *BootstrapS) TestRunDoesntShowSuccesses(c *check.C) {
3249+ output := String{}
3250+ check.Run(&SuccessHelper{}, &check.RunConf{Output: &output})
3251+ if strings.Index(output.value, "Expected success!") != -1 {
3252+ critical(fmt.Sprintf("RunWithWriter() output contained a successful "+
3253+ "test! Got: %#v",
3254+ output.value))
3255+ }
3256+}
3257
3258=== added file 'internal/gopkg.in/check.v1/check.go'
3259--- internal/gopkg.in/check.v1/check.go 1970-01-01 00:00:00 +0000
3260+++ internal/gopkg.in/check.v1/check.go 2015-10-30 14:13:06 +0000
3261@@ -0,0 +1,945 @@
3262+// Package check is a rich testing extension for Go's testing package.
3263+//
3264+// For details about the project, see:
3265+//
3266+// http://labix.org/gocheck
3267+//
3268+package check
3269+
3270+import (
3271+ "bytes"
3272+ "errors"
3273+ "fmt"
3274+ "io"
3275+ "math/rand"
3276+ "os"
3277+ "path"
3278+ "path/filepath"
3279+ "reflect"
3280+ "regexp"
3281+ "runtime"
3282+ "strconv"
3283+ "strings"
3284+ "sync"
3285+ "time"
3286+)
3287+
3288+// -----------------------------------------------------------------------
3289+// Internal type which deals with suite method calling.
3290+
3291+const (
3292+ fixtureKd = iota
3293+ testKd
3294+)
3295+
3296+type funcKind int
3297+
3298+const (
3299+ succeededSt = iota
3300+ failedSt
3301+ skippedSt
3302+ panickedSt
3303+ fixturePanickedSt
3304+ missedSt
3305+)
3306+
3307+type funcStatus int
3308+
3309+// A method value can't reach its own Method structure.
3310+type methodType struct {
3311+ reflect.Value
3312+ Info reflect.Method
3313+}
3314+
3315+func newMethod(receiver reflect.Value, i int) *methodType {
3316+ return &methodType{receiver.Method(i), receiver.Type().Method(i)}
3317+}
3318+
3319+func (method *methodType) PC() uintptr {
3320+ return method.Info.Func.Pointer()
3321+}
3322+
3323+func (method *methodType) suiteName() string {
3324+ t := method.Info.Type.In(0)
3325+ if t.Kind() == reflect.Ptr {
3326+ t = t.Elem()
3327+ }
3328+ return t.Name()
3329+}
3330+
3331+func (method *methodType) String() string {
3332+ return method.suiteName() + "." + method.Info.Name
3333+}
3334+
3335+func (method *methodType) matches(re *regexp.Regexp) bool {
3336+ return (re.MatchString(method.Info.Name) ||
3337+ re.MatchString(method.suiteName()) ||
3338+ re.MatchString(method.String()))
3339+}
3340+
3341+type C struct {
3342+ method *methodType
3343+ kind funcKind
3344+ testName string
3345+ status funcStatus
3346+ logb *logger
3347+ logw io.Writer
3348+ done chan *C
3349+ reason string
3350+ mustFail bool
3351+ tempDir *tempDir
3352+ benchMem bool
3353+ startTime time.Time
3354+ timer
3355+}
3356+
3357+func (c *C) stopNow() {
3358+ runtime.Goexit()
3359+}
3360+
3361+// logger is a concurrency safe byte.Buffer
3362+type logger struct {
3363+ sync.Mutex
3364+ writer bytes.Buffer
3365+}
3366+
3367+func (l *logger) Write(buf []byte) (int, error) {
3368+ l.Lock()
3369+ defer l.Unlock()
3370+ return l.writer.Write(buf)
3371+}
3372+
3373+func (l *logger) WriteTo(w io.Writer) (int64, error) {
3374+ l.Lock()
3375+ defer l.Unlock()
3376+ return l.writer.WriteTo(w)
3377+}
3378+
3379+func (l *logger) String() string {
3380+ l.Lock()
3381+ defer l.Unlock()
3382+ return l.writer.String()
3383+}
3384+
3385+// -----------------------------------------------------------------------
3386+// Handling of temporary files and directories.
3387+
3388+type tempDir struct {
3389+ sync.Mutex
3390+ path string
3391+ counter int
3392+}
3393+
3394+func (td *tempDir) newPath() string {
3395+ td.Lock()
3396+ defer td.Unlock()
3397+ if td.path == "" {
3398+ var err error
3399+ for i := 0; i != 100; i++ {
3400+ path := fmt.Sprintf("%s%ccheck-%d", os.TempDir(), os.PathSeparator, rand.Int())
3401+ if err = os.Mkdir(path, 0700); err == nil {
3402+ td.path = path
3403+ break
3404+ }
3405+ }
3406+ if td.path == "" {
3407+ panic("Couldn't create temporary directory: " + err.Error())
3408+ }
3409+ }
3410+ result := filepath.Join(td.path, strconv.Itoa(td.counter))
3411+ td.counter += 1
3412+ return result
3413+}
3414+
3415+func (td *tempDir) removeAll() {
3416+ td.Lock()
3417+ defer td.Unlock()
3418+ if td.path != "" {
3419+ err := os.RemoveAll(td.path)
3420+ if err != nil {
3421+ fmt.Fprintf(os.Stderr, "WARNING: Error cleaning up temporaries: "+err.Error())
3422+ }
3423+ }
3424+}
3425+
3426+// Create a new temporary directory which is automatically removed after
3427+// the suite finishes running.
3428+func (c *C) MkDir() string {
3429+ path := c.tempDir.newPath()
3430+ if err := os.Mkdir(path, 0700); err != nil {
3431+ panic(fmt.Sprintf("Couldn't create temporary directory %s: %s", path, err.Error()))
3432+ }
3433+ return path
3434+}
3435+
3436+// -----------------------------------------------------------------------
3437+// Low-level logging functions.
3438+
3439+func (c *C) log(args ...interface{}) {
3440+ c.writeLog([]byte(fmt.Sprint(args...) + "\n"))
3441+}
3442+
3443+func (c *C) logf(format string, args ...interface{}) {
3444+ c.writeLog([]byte(fmt.Sprintf(format+"\n", args...)))
3445+}
3446+
3447+func (c *C) logNewLine() {
3448+ c.writeLog([]byte{'\n'})
3449+}
3450+
3451+func (c *C) writeLog(buf []byte) {
3452+ c.logb.Write(buf)
3453+ if c.logw != nil {
3454+ c.logw.Write(buf)
3455+ }
3456+}
3457+
3458+func hasStringOrError(x interface{}) (ok bool) {
3459+ _, ok = x.(fmt.Stringer)
3460+ if ok {
3461+ return
3462+ }
3463+ _, ok = x.(error)
3464+ return
3465+}
3466+
3467+func (c *C) logValue(label string, value interface{}) {
3468+ if label == "" {
3469+ if hasStringOrError(value) {
3470+ c.logf("... %#v (%q)", value, value)
3471+ } else {
3472+ c.logf("... %#v", value)
3473+ }
3474+ } else if value == nil {
3475+ c.logf("... %s = nil", label)
3476+ } else {
3477+ if hasStringOrError(value) {
3478+ fv := fmt.Sprintf("%#v", value)
3479+ qv := fmt.Sprintf("%q", value)
3480+ if fv != qv {
3481+ c.logf("... %s %s = %s (%s)", label, reflect.TypeOf(value), fv, qv)
3482+ return
3483+ }
3484+ }
3485+ if s, ok := value.(string); ok && isMultiLine(s) {
3486+ c.logf(`... %s %s = "" +`, label, reflect.TypeOf(value))
3487+ c.logMultiLine(s)
3488+ } else {
3489+ c.logf("... %s %s = %#v", label, reflect.TypeOf(value), value)
3490+ }
3491+ }
3492+}
3493+
3494+func (c *C) logMultiLine(s string) {
3495+ b := make([]byte, 0, len(s)*2)
3496+ i := 0
3497+ n := len(s)
3498+ for i < n {
3499+ j := i + 1
3500+ for j < n && s[j-1] != '\n' {
3501+ j++
3502+ }
3503+ b = append(b, "... "...)
3504+ b = strconv.AppendQuote(b, s[i:j])
3505+ if j < n {
3506+ b = append(b, " +"...)
3507+ }
3508+ b = append(b, '\n')
3509+ i = j
3510+ }
3511+ c.writeLog(b)
3512+}
3513+
3514+func isMultiLine(s string) bool {
3515+ for i := 0; i+1 < len(s); i++ {
3516+ if s[i] == '\n' {
3517+ return true
3518+ }
3519+ }
3520+ return false
3521+}
3522+
3523+func (c *C) logString(issue string) {
3524+ c.log("... ", issue)
3525+}
3526+
3527+func (c *C) logCaller(skip int) {
3528+ // This is a bit heavier than it ought to be.
3529+ skip += 1 // Our own frame.
3530+ pc, callerFile, callerLine, ok := runtime.Caller(skip)
3531+ if !ok {
3532+ return
3533+ }
3534+ var testFile string
3535+ var testLine int
3536+ testFunc := runtime.FuncForPC(c.method.PC())
3537+ if runtime.FuncForPC(pc) != testFunc {
3538+ for {
3539+ skip += 1
3540+ if pc, file, line, ok := runtime.Caller(skip); ok {
3541+ // Note that the test line may be different on
3542+ // distinct calls for the same test. Showing
3543+ // the "internal" line is helpful when debugging.
3544+ if runtime.FuncForPC(pc) == testFunc {
3545+ testFile, testLine = file, line
3546+ break
3547+ }
3548+ } else {
3549+ break
3550+ }
3551+ }
3552+ }
3553+ if testFile != "" && (testFile != callerFile || testLine != callerLine) {
3554+ c.logCode(testFile, testLine)
3555+ }
3556+ c.logCode(callerFile, callerLine)
3557+}
3558+
3559+func (c *C) logCode(path string, line int) {
3560+ c.logf("%s:%d:", nicePath(path), line)
3561+ code, err := printLine(path, line)
3562+ if code == "" {
3563+ code = "..." // XXX Open the file and take the raw line.
3564+ if err != nil {
3565+ code += err.Error()
3566+ }
3567+ }
3568+ c.log(indent(code, " "))
3569+}
3570+
3571+var valueGo = filepath.Join("reflect", "value.go")
3572+var asmGo = filepath.Join("runtime", "asm_")
3573+
3574+func (c *C) logPanic(skip int, value interface{}) {
3575+ skip++ // Our own frame.
3576+ initialSkip := skip
3577+ for ; ; skip++ {
3578+ if pc, file, line, ok := runtime.Caller(skip); ok {
3579+ if skip == initialSkip {
3580+ c.logf("... Panic: %s (PC=0x%X)\n", value, pc)
3581+ }
3582+ name := niceFuncName(pc)
3583+ path := nicePath(file)
3584+ if strings.Contains(path, "/gopkg.in/check.v") {
3585+ continue
3586+ }
3587+ if name == "Value.call" && strings.HasSuffix(path, valueGo) {
3588+ continue
3589+ }
3590+ if name == "call16" && strings.Contains(path, asmGo) {
3591+ continue
3592+ }
3593+ c.logf("%s:%d\n in %s", nicePath(file), line, name)
3594+ } else {
3595+ break
3596+ }
3597+ }
3598+}
3599+
3600+func (c *C) logSoftPanic(issue string) {
3601+ c.log("... Panic: ", issue)
3602+}
3603+
3604+func (c *C) logArgPanic(method *methodType, expectedType string) {
3605+ c.logf("... Panic: %s argument should be %s",
3606+ niceFuncName(method.PC()), expectedType)
3607+}
3608+
3609+// -----------------------------------------------------------------------
3610+// Some simple formatting helpers.
3611+
3612+var initWD, initWDErr = os.Getwd()
3613+
3614+func init() {
3615+ if initWDErr == nil {
3616+ initWD = strings.Replace(initWD, "\\", "/", -1) + "/"
3617+ }
3618+}
3619+
3620+func nicePath(path string) string {
3621+ if initWDErr == nil {
3622+ if strings.HasPrefix(path, initWD) {
3623+ return path[len(initWD):]
3624+ }
3625+ }
3626+ return path
3627+}
3628+
3629+func niceFuncPath(pc uintptr) string {
3630+ function := runtime.FuncForPC(pc)
3631+ if function != nil {
3632+ filename, line := function.FileLine(pc)
3633+ return fmt.Sprintf("%s:%d", nicePath(filename), line)
3634+ }
3635+ return "<unknown path>"
3636+}
3637+
3638+func niceFuncName(pc uintptr) string {
3639+ function := runtime.FuncForPC(pc)
3640+ if function != nil {
3641+ name := path.Base(function.Name())
3642+ if i := strings.Index(name, "."); i > 0 {
3643+ name = name[i+1:]
3644+ }
3645+ if strings.HasPrefix(name, "(*") {
3646+ if i := strings.Index(name, ")"); i > 0 {
3647+ name = name[2:i] + name[i+1:]
3648+ }
3649+ }
3650+ if i := strings.LastIndex(name, ".*"); i != -1 {
3651+ name = name[:i] + "." + name[i+2:]
3652+ }
3653+ if i := strings.LastIndex(name, "·"); i != -1 {
3654+ name = name[:i] + "." + name[i+2:]
3655+ }
3656+ return name
3657+ }
3658+ return "<unknown function>"
3659+}
3660+
3661+// -----------------------------------------------------------------------
3662+// Result tracker to aggregate call results.
3663+
3664+type Result struct {
3665+ Succeeded int
3666+ Failed int
3667+ Skipped int
3668+ Panicked int
3669+ FixturePanicked int
3670+ ExpectedFailures int
3671+ Missed int // Not even tried to run, related to a panic in the fixture.
3672+ RunError error // Houston, we've got a problem.
3673+ WorkDir string // If KeepWorkDir is true
3674+}
3675+
3676+type resultTracker struct {
3677+ result Result
3678+ _lastWasProblem bool
3679+ _waiting int
3680+ _missed int
3681+ _expectChan chan *C
3682+ _doneChan chan *C
3683+ _stopChan chan bool
3684+}
3685+
3686+func newResultTracker() *resultTracker {
3687+ return &resultTracker{_expectChan: make(chan *C), // Synchronous
3688+ _doneChan: make(chan *C, 32), // Asynchronous
3689+ _stopChan: make(chan bool)} // Synchronous
3690+}
3691+
3692+func (tracker *resultTracker) start() {
3693+ go tracker._loopRoutine()
3694+}
3695+
3696+func (tracker *resultTracker) waitAndStop() {
3697+ <-tracker._stopChan
3698+}
3699+
3700+func (tracker *resultTracker) expectCall(c *C) {
3701+ tracker._expectChan <- c
3702+}
3703+
3704+func (tracker *resultTracker) callDone(c *C) {
3705+ tracker._doneChan <- c
3706+}
3707+
3708+func (tracker *resultTracker) _loopRoutine() {
3709+ for {
3710+ var c *C
3711+ if tracker._waiting > 0 {
3712+ // Calls still running. Can't stop.
3713+ select {
3714+ // XXX Reindent this (not now to make diff clear)
3715+ case c = <-tracker._expectChan:
3716+ tracker._waiting += 1
3717+ case c = <-tracker._doneChan:
3718+ tracker._waiting -= 1
3719+ switch c.status {
3720+ case succeededSt:
3721+ if c.kind == testKd {
3722+ if c.mustFail {
3723+ tracker.result.ExpectedFailures++
3724+ } else {
3725+ tracker.result.Succeeded++
3726+ }
3727+ }
3728+ case failedSt:
3729+ tracker.result.Failed++
3730+ case panickedSt:
3731+ if c.kind == fixtureKd {
3732+ tracker.result.FixturePanicked++
3733+ } else {
3734+ tracker.result.Panicked++
3735+ }
3736+ case fixturePanickedSt:
3737+ // Track it as missed, since the panic
3738+ // was on the fixture, not on the test.
3739+ tracker.result.Missed++
3740+ case missedSt:
3741+ tracker.result.Missed++
3742+ case skippedSt:
3743+ if c.kind == testKd {
3744+ tracker.result.Skipped++
3745+ }
3746+ }
3747+ }
3748+ } else {
3749+ // No calls. Can stop, but no done calls here.
3750+ select {
3751+ case tracker._stopChan <- true:
3752+ return
3753+ case c = <-tracker._expectChan:
3754+ tracker._waiting += 1
3755+ case c = <-tracker._doneChan:
3756+ panic("Tracker got an unexpected done call.")
3757+ }
3758+ }
3759+ }
3760+}
3761+
3762+// -----------------------------------------------------------------------
3763+// The underlying suite runner.
3764+
3765+type suiteRunner struct {
3766+ suite interface{}
3767+ setUpSuite, tearDownSuite *methodType
3768+ setUpTest, tearDownTest *methodType
3769+ tests []*methodType
3770+ tracker *resultTracker
3771+ tempDir *tempDir
3772+ keepDir bool
3773+ output *outputWriter
3774+ reportedProblemLast bool
3775+ benchTime time.Duration
3776+ benchMem bool
3777+}
3778+
3779+type RunConf struct {
3780+ Output io.Writer
3781+ Stream bool
3782+ Verbose bool
3783+ Filter string
3784+ Benchmark bool
3785+ BenchmarkTime time.Duration // Defaults to 1 second
3786+ BenchmarkMem bool
3787+ KeepWorkDir bool
3788+}
3789+
3790+// Create a new suiteRunner able to run all methods in the given suite.
3791+func newSuiteRunner(suite interface{}, runConf *RunConf) *suiteRunner {
3792+ var conf RunConf
3793+ if runConf != nil {
3794+ conf = *runConf
3795+ }
3796+ if conf.Output == nil {
3797+ conf.Output = os.Stdout
3798+ }
3799+ if conf.Benchmark {
3800+ conf.Verbose = true
3801+ }
3802+
3803+ suiteType := reflect.TypeOf(suite)
3804+ suiteNumMethods := suiteType.NumMethod()
3805+ suiteValue := reflect.ValueOf(suite)
3806+
3807+ runner := &suiteRunner{
3808+ suite: suite,
3809+ output: newOutputWriter(conf.Output, conf.Stream, conf.Verbose),
3810+ tracker: newResultTracker(),
3811+ benchTime: conf.BenchmarkTime,
3812+ benchMem: conf.BenchmarkMem,
3813+ tempDir: &tempDir{},
3814+ keepDir: conf.KeepWorkDir,
3815+ tests: make([]*methodType, 0, suiteNumMethods),
3816+ }
3817+ if runner.benchTime == 0 {
3818+ runner.benchTime = 1 * time.Second
3819+ }
3820+
3821+ var filterRegexp *regexp.Regexp
3822+ if conf.Filter != "" {
3823+ if regexp, err := regexp.Compile(conf.Filter); err != nil {
3824+ msg := "Bad filter expression: " + err.Error()
3825+ runner.tracker.result.RunError = errors.New(msg)
3826+ return runner
3827+ } else {
3828+ filterRegexp = regexp
3829+ }
3830+ }
3831+
3832+ for i := 0; i != suiteNumMethods; i++ {
3833+ method := newMethod(suiteValue, i)
3834+ switch method.Info.Name {
3835+ case "SetUpSuite":
3836+ runner.setUpSuite = method
3837+ case "TearDownSuite":
3838+ runner.tearDownSuite = method
3839+ case "SetUpTest":
3840+ runner.setUpTest = method
3841+ case "TearDownTest":
3842+ runner.tearDownTest = method
3843+ default:
3844+ prefix := "Test"
3845+ if conf.Benchmark {
3846+ prefix = "Benchmark"
3847+ }
3848+ if !strings.HasPrefix(method.Info.Name, prefix) {
3849+ continue
3850+ }
3851+ if filterRegexp == nil || method.matches(filterRegexp) {
3852+ runner.tests = append(runner.tests, method)
3853+ }
3854+ }
3855+ }
3856+ return runner
3857+}
3858+
3859+// Run all methods in the given suite.
3860+func (runner *suiteRunner) run() *Result {
3861+ if runner.tracker.result.RunError == nil && len(runner.tests) > 0 {
3862+ runner.tracker.start()
3863+ if runner.checkFixtureArgs() {
3864+ c := runner.runFixture(runner.setUpSuite, "", nil)
3865+ if c == nil || c.status == succeededSt {
3866+ for i := 0; i != len(runner.tests); i++ {
3867+ c := runner.runTest(runner.tests[i])
3868+ if c.status == fixturePanickedSt {
3869+ runner.skipTests(missedSt, runner.tests[i+1:])
3870+ break
3871+ }
3872+ }
3873+ } else if c != nil && c.status == skippedSt {
3874+ runner.skipTests(skippedSt, runner.tests)
3875+ } else {
3876+ runner.skipTests(missedSt, runner.tests)
3877+ }
3878+ runner.runFixture(runner.tearDownSuite, "", nil)
3879+ } else {
3880+ runner.skipTests(missedSt, runner.tests)
3881+ }
3882+ runner.tracker.waitAndStop()
3883+ if runner.keepDir {
3884+ runner.tracker.result.WorkDir = runner.tempDir.path
3885+ } else {
3886+ runner.tempDir.removeAll()
3887+ }
3888+ }
3889+ return &runner.tracker.result
3890+}
3891+
3892+// Create a call object with the given suite method, and fork a
3893+// goroutine with the provided dispatcher for running it.
3894+func (runner *suiteRunner) forkCall(method *methodType, kind funcKind, testName string, logb *logger, dispatcher func(c *C)) *C {
3895+ var logw io.Writer
3896+ if runner.output.Stream {
3897+ logw = runner.output
3898+ }
3899+ if logb == nil {
3900+ logb = new(logger)
3901+ }
3902+ c := &C{
3903+ method: method,
3904+ kind: kind,
3905+ testName: testName,
3906+ logb: logb,
3907+ logw: logw,
3908+ tempDir: runner.tempDir,
3909+ done: make(chan *C, 1),
3910+ timer: timer{benchTime: runner.benchTime},
3911+ startTime: time.Now(),
3912+ benchMem: runner.benchMem,
3913+ }
3914+ runner.tracker.expectCall(c)
3915+ go (func() {
3916+ runner.reportCallStarted(c)
3917+ defer runner.callDone(c)
3918+ dispatcher(c)
3919+ })()
3920+ return c
3921+}
3922+
3923+// Same as forkCall(), but wait for call to finish before returning.
3924+func (runner *suiteRunner) runFunc(method *methodType, kind funcKind, testName string, logb *logger, dispatcher func(c *C)) *C {
3925+ c := runner.forkCall(method, kind, testName, logb, dispatcher)
3926+ <-c.done
3927+ return c
3928+}
3929+
3930+// Handle a finished call. If there were any panics, update the call status
3931+// accordingly. Then, mark the call as done and report to the tracker.
3932+func (runner *suiteRunner) callDone(c *C) {
3933+ value := recover()
3934+ if value != nil {
3935+ switch v := value.(type) {
3936+ case *fixturePanic:
3937+ if v.status == skippedSt {
3938+ c.status = skippedSt
3939+ } else {
3940+ c.logSoftPanic("Fixture has panicked (see related PANIC)")
3941+ c.status = fixturePanickedSt
3942+ }
3943+ default:
3944+ c.logPanic(1, value)
3945+ c.status = panickedSt
3946+ }
3947+ }
3948+ if c.mustFail {
3949+ switch c.status {
3950+ case failedSt:
3951+ c.status = succeededSt
3952+ case succeededSt:
3953+ c.status = failedSt
3954+ c.logString("Error: Test succeeded, but was expected to fail")
3955+ c.logString("Reason: " + c.reason)
3956+ }
3957+ }
3958+
3959+ runner.reportCallDone(c)
3960+ c.done <- c
3961+}
3962+
3963+// Runs a fixture call synchronously. The fixture will still be run in a
3964+// goroutine like all suite methods, but this method will not return
3965+// while the fixture goroutine is not done, because the fixture must be
3966+// run in a desired order.
3967+func (runner *suiteRunner) runFixture(method *methodType, testName string, logb *logger) *C {
3968+ if method != nil {
3969+ c := runner.runFunc(method, fixtureKd, testName, logb, func(c *C) {
3970+ c.ResetTimer()
3971+ c.StartTimer()
3972+ defer c.StopTimer()
3973+ c.method.Call([]reflect.Value{reflect.ValueOf(c)})
3974+ })
3975+ return c
3976+ }
3977+ return nil
3978+}
3979+
3980+// Run the fixture method with runFixture(), but panic with a fixturePanic{}
3981+// in case the fixture method panics. This makes it easier to track the
3982+// fixture panic together with other call panics within forkTest().
3983+func (runner *suiteRunner) runFixtureWithPanic(method *methodType, testName string, logb *logger, skipped *bool) *C {
3984+ if skipped != nil && *skipped {
3985+ return nil
3986+ }
3987+ c := runner.runFixture(method, testName, logb)
3988+ if c != nil && c.status != succeededSt {
3989+ if skipped != nil {
3990+ *skipped = c.status == skippedSt
3991+ }
3992+ panic(&fixturePanic{c.status, method})
3993+ }
3994+ return c
3995+}
3996+
3997+type fixturePanic struct {
3998+ status funcStatus
3999+ method *methodType
4000+}
4001+
4002+// Run the suite test method, together with the test-specific fixture,
4003+// asynchronously.
4004+func (runner *suiteRunner) forkTest(method *methodType) *C {
4005+ testName := method.String()
4006+ return runner.forkCall(method, testKd, testName, nil, func(c *C) {
4007+ var skipped bool
4008+ defer runner.runFixtureWithPanic(runner.tearDownTest, testName, nil, &skipped)
4009+ defer c.StopTimer()
4010+ benchN := 1
4011+ for {
4012+ runner.runFixtureWithPanic(runner.setUpTest, testName, c.logb, &skipped)
4013+ mt := c.method.Type()
4014+ if mt.NumIn() != 1 || mt.In(0) != reflect.TypeOf(c) {
4015+ // Rather than a plain panic, provide a more helpful message when
4016+ // the argument type is incorrect.
4017+ c.status = panickedSt
4018+ c.logArgPanic(c.method, "*check.C")
4019+ return
4020+ }
4021+ if strings.HasPrefix(c.method.Info.Name, "Test") {
4022+ c.ResetTimer()
4023+ c.StartTimer()
4024+ c.method.Call([]reflect.Value{reflect.ValueOf(c)})
4025+ return
4026+ }
4027+ if !strings.HasPrefix(c.method.Info.Name, "Benchmark") {
4028+ panic("unexpected method prefix: " + c.method.Info.Name)
4029+ }
4030+
4031+ runtime.GC()
4032+ c.N = benchN
4033+ c.ResetTimer()
4034+ c.StartTimer()
4035+ c.method.Call([]reflect.Value{reflect.ValueOf(c)})
4036+ c.StopTimer()
4037+ if c.status != succeededSt || c.duration >= c.benchTime || benchN >= 1e9 {
4038+ return
4039+ }
4040+ perOpN := int(1e9)
4041+ if c.nsPerOp() != 0 {
4042+ perOpN = int(c.benchTime.Nanoseconds() / c.nsPerOp())
4043+ }
4044+
4045+ // Logic taken from the stock testing package:
4046+ // - Run more iterations than we think we'll need for a second (1.5x).
4047+ // - Don't grow too fast in case we had timing errors previously.
4048+ // - Be sure to run at least one more than last time.
4049+ benchN = max(min(perOpN+perOpN/2, 100*benchN), benchN+1)
4050+ benchN = roundUp(benchN)
4051+
4052+ skipped = true // Don't run the deferred one if this panics.
4053+ runner.runFixtureWithPanic(runner.tearDownTest, testName, nil, nil)
4054+ skipped = false
4055+ }
4056+ })
4057+}
4058+
4059+// Same as forkTest(), but wait for the test to finish before returning.
4060+func (runner *suiteRunner) runTest(method *methodType) *C {
4061+ c := runner.forkTest(method)
4062+ <-c.done
4063+ return c
4064+}
4065+
4066+// Helper to mark tests as skipped or missed. A bit heavy for what
4067+// it does, but it enables homogeneous handling of tracking, including
4068+// nice verbose output.
4069+func (runner *suiteRunner) skipTests(status funcStatus, methods []*methodType) {
4070+ for _, method := range methods {
4071+ runner.runFunc(method, testKd, "", nil, func(c *C) {
4072+ c.status = status
4073+ })
4074+ }
4075+}
4076+
4077+// Verify if the fixture arguments are *check.C. In case of errors,
4078+// log the error as a panic in the fixture method call, and return false.
4079+func (runner *suiteRunner) checkFixtureArgs() bool {
4080+ succeeded := true
4081+ argType := reflect.TypeOf(&C{})
4082+ for _, method := range []*methodType{runner.setUpSuite, runner.tearDownSuite, runner.setUpTest, runner.tearDownTest} {
4083+ if method != nil {
4084+ mt := method.Type()
4085+ if mt.NumIn() != 1 || mt.In(0) != argType {
4086+ succeeded = false
4087+ runner.runFunc(method, fixtureKd, "", nil, func(c *C) {
4088+ c.logArgPanic(method, "*check.C")
4089+ c.status = panickedSt
4090+ })
4091+ }
4092+ }
4093+ }
4094+ return succeeded
4095+}
4096+
4097+func (runner *suiteRunner) reportCallStarted(c *C) {
4098+ runner.output.WriteCallStarted("START", c)
4099+}
4100+
4101+func (runner *suiteRunner) reportCallDone(c *C) {
4102+ runner.tracker.callDone(c)
4103+ switch c.status {
4104+ case succeededSt:
4105+ if c.mustFail {
4106+ runner.output.WriteCallSuccess("FAIL EXPECTED", c)
4107+ } else {
4108+ runner.output.WriteCallSuccess("PASS", c)
4109+ }
4110+ case skippedSt:
4111+ runner.output.WriteCallSuccess("SKIP", c)
4112+ case failedSt:
4113+ runner.output.WriteCallProblem("FAIL", c)
4114+ case panickedSt:
4115+ runner.output.WriteCallProblem("PANIC", c)
4116+ case fixturePanickedSt:
4117+ // That's a testKd call reporting that its fixture
4118+ // has panicked. The fixture call which caused the
4119+ // panic itself was tracked above. We'll report to
4120+ // aid debugging.
4121+ runner.output.WriteCallProblem("PANIC", c)
4122+ case missedSt:
4123+ runner.output.WriteCallSuccess("MISS", c)
4124+ }
4125+}
4126+
4127+// -----------------------------------------------------------------------
4128+// Output writer manages atomic output writing according to settings.
4129+
4130+type outputWriter struct {
4131+ m sync.Mutex
4132+ writer io.Writer
4133+ wroteCallProblemLast bool
4134+ Stream bool
4135+ Verbose bool
4136+}
4137+
4138+func newOutputWriter(writer io.Writer, stream, verbose bool) *outputWriter {
4139+ return &outputWriter{writer: writer, Stream: stream, Verbose: verbose}
4140+}
4141+
4142+func (ow *outputWriter) Write(content []byte) (n int, err error) {
4143+ ow.m.Lock()
4144+ n, err = ow.writer.Write(content)
4145+ ow.m.Unlock()
4146+ return
4147+}
4148+
4149+func (ow *outputWriter) WriteCallStarted(label string, c *C) {
4150+ if ow.Stream {
4151+ header := renderCallHeader(label, c, "", "\n")
4152+ ow.m.Lock()
4153+ ow.writer.Write([]byte(header))
4154+ ow.m.Unlock()
4155+ }
4156+}
4157+
4158+func (ow *outputWriter) WriteCallProblem(label string, c *C) {
4159+ var prefix string
4160+ if !ow.Stream {
4161+ prefix = "\n-----------------------------------" +
4162+ "-----------------------------------\n"
4163+ }
4164+ header := renderCallHeader(label, c, prefix, "\n\n")
4165+ ow.m.Lock()
4166+ ow.wroteCallProblemLast = true
4167+ ow.writer.Write([]byte(header))
4168+ if !ow.Stream {
4169+ c.logb.WriteTo(ow.writer)
4170+ }
4171+ ow.m.Unlock()
4172+}
4173+
4174+func (ow *outputWriter) WriteCallSuccess(label string, c *C) {
4175+ if ow.Stream || (ow.Verbose && c.kind == testKd) {
4176+ // TODO Use a buffer here.
4177+ var suffix string
4178+ if c.reason != "" {
4179+ suffix = " (" + c.reason + ")"
4180+ }
4181+ if c.status == succeededSt {
4182+ suffix += "\t" + c.timerString()
4183+ }
4184+ suffix += "\n"
4185+ if ow.Stream {
4186+ suffix += "\n"
4187+ }
4188+ header := renderCallHeader(label, c, "", suffix)
4189+ ow.m.Lock()
4190+ // Resist temptation of using line as prefix above due to race.
4191+ if !ow.Stream && ow.wroteCallProblemLast {
4192+ header = "\n-----------------------------------" +
4193+ "-----------------------------------\n" +
4194+ header
4195+ }
4196+ ow.wroteCallProblemLast = false
4197+ ow.writer.Write([]byte(header))
4198+ ow.m.Unlock()
4199+ }
4200+}
4201+
4202+func renderCallHeader(label string, c *C, prefix, suffix string) string {
4203+ pc := c.method.PC()
4204+ return fmt.Sprintf("%s%s: %s: %s%s", prefix, label, niceFuncPath(pc),
4205+ niceFuncName(pc), suffix)
4206+}
4207
4208=== added file 'internal/gopkg.in/check.v1/check_test.go'
4209--- internal/gopkg.in/check.v1/check_test.go 1970-01-01 00:00:00 +0000
4210+++ internal/gopkg.in/check.v1/check_test.go 2015-10-30 14:13:06 +0000
4211@@ -0,0 +1,207 @@
4212+// This file contains just a few generic helpers which are used by the
4213+// other test files.
4214+
4215+package check_test
4216+
4217+import (
4218+ "flag"
4219+ "fmt"
4220+ "os"
4221+ "regexp"
4222+ "runtime"
4223+ "testing"
4224+ "time"
4225+
4226+ "launchpad.net/crackly/internal/gopkg.in/check.v1"
4227+)
4228+
4229+// We count the number of suites run at least to get a vague hint that the
4230+// test suite is behaving as it should. Otherwise a bug introduced at the
4231+// very core of the system could go unperceived.
4232+const suitesRunExpected = 8
4233+
4234+var suitesRun int = 0
4235+
4236+func Test(t *testing.T) {
4237+ check.TestingT(t)
4238+ if suitesRun != suitesRunExpected && flag.Lookup("check.f").Value.String() == "" {
4239+ critical(fmt.Sprintf("Expected %d suites to run rather than %d",
4240+ suitesRunExpected, suitesRun))
4241+ }
4242+}
4243+
4244+// -----------------------------------------------------------------------
4245+// Helper functions.
4246+
4247+// Break down badly. This is used in test cases which can't yet assume
4248+// that the fundamental bits are working.
4249+func critical(error string) {
4250+ fmt.Fprintln(os.Stderr, "CRITICAL: "+error)
4251+ os.Exit(1)
4252+}
4253+
4254+// Return the file line where it's called.
4255+func getMyLine() int {
4256+ if _, _, line, ok := runtime.Caller(1); ok {
4257+ return line
4258+ }
4259+ return -1
4260+}
4261+
4262+// -----------------------------------------------------------------------
4263+// Helper type implementing a basic io.Writer for testing output.
4264+
4265+// Type implementing the io.Writer interface for analyzing output.
4266+type String struct {
4267+ value string
4268+}
4269+
4270+// The only function required by the io.Writer interface. Will append
4271+// written data to the String.value string.
4272+func (s *String) Write(p []byte) (n int, err error) {
4273+ s.value += string(p)
4274+ return len(p), nil
4275+}
4276+
4277+// Trivial wrapper to test errors happening on a different file
4278+// than the test itself.
4279+func checkEqualWrapper(c *check.C, obtained, expected interface{}) (result bool, line int) {
4280+ return c.Check(obtained, check.Equals, expected), getMyLine()
4281+}
4282+
4283+// -----------------------------------------------------------------------
4284+// Helper suite for testing basic fail behavior.
4285+
4286+type FailHelper struct {
4287+ testLine int
4288+}
4289+
4290+func (s *FailHelper) TestLogAndFail(c *check.C) {
4291+ s.testLine = getMyLine() - 1
4292+ c.Log("Expected failure!")
4293+ c.Fail()
4294+}
4295+
4296+// -----------------------------------------------------------------------
4297+// Helper suite for testing basic success behavior.
4298+
4299+type SuccessHelper struct{}
4300+
4301+func (s *SuccessHelper) TestLogAndSucceed(c *check.C) {
4302+ c.Log("Expected success!")
4303+}
4304+
4305+// -----------------------------------------------------------------------
4306+// Helper suite for testing ordering and behavior of fixture.
4307+
4308+type FixtureHelper struct {
4309+ calls []string
4310+ panicOn string
4311+ skip bool
4312+ skipOnN int
4313+ sleepOn string
4314+ sleep time.Duration
4315+ bytes int64
4316+}
4317+
4318+func (s *FixtureHelper) trace(name string, c *check.C) {
4319+ s.calls = append(s.calls, name)
4320+ if name == s.panicOn {
4321+ panic(name)
4322+ }
4323+ if s.sleep > 0 && s.sleepOn == name {
4324+ time.Sleep(s.sleep)
4325+ }
4326+ if s.skip && s.skipOnN == len(s.calls)-1 {
4327+ c.Skip("skipOnN == n")
4328+ }
4329+}
4330+
4331+func (s *FixtureHelper) SetUpSuite(c *check.C) {
4332+ s.trace("SetUpSuite", c)
4333+}
4334+
4335+func (s *FixtureHelper) TearDownSuite(c *check.C) {
4336+ s.trace("TearDownSuite", c)
4337+}
4338+
4339+func (s *FixtureHelper) SetUpTest(c *check.C) {
4340+ s.trace("SetUpTest", c)
4341+}
4342+
4343+func (s *FixtureHelper) TearDownTest(c *check.C) {
4344+ s.trace("TearDownTest", c)
4345+}
4346+
4347+func (s *FixtureHelper) Test1(c *check.C) {
4348+ s.trace("Test1", c)
4349+}
4350+
4351+func (s *FixtureHelper) Test2(c *check.C) {
4352+ s.trace("Test2", c)
4353+}
4354+
4355+func (s *FixtureHelper) Benchmark1(c *check.C) {
4356+ s.trace("Benchmark1", c)
4357+ for i := 0; i < c.N; i++ {
4358+ time.Sleep(s.sleep)
4359+ }
4360+}
4361+
4362+func (s *FixtureHelper) Benchmark2(c *check.C) {
4363+ s.trace("Benchmark2", c)
4364+ c.SetBytes(1024)
4365+ for i := 0; i < c.N; i++ {
4366+ time.Sleep(s.sleep)
4367+ }
4368+}
4369+
4370+func (s *FixtureHelper) Benchmark3(c *check.C) {
4371+ var x []int64
4372+ s.trace("Benchmark3", c)
4373+ for i := 0; i < c.N; i++ {
4374+ time.Sleep(s.sleep)
4375+ x = make([]int64, 5)
4376+ _ = x
4377+ }
4378+}
4379+
4380+// -----------------------------------------------------------------------
4381+// Helper which checks the state of the test and ensures that it matches
4382+// the given expectations. Depends on c.Errorf() working, so shouldn't
4383+// be used to test this one function.
4384+
4385+type expectedState struct {
4386+ name string
4387+ result interface{}
4388+ failed bool
4389+ log string
4390+}
4391+
4392+// Verify the state of the test. Note that since this also verifies if
4393+// the test is supposed to be in a failed state, no other checks should
4394+// be done in addition to what is being tested.
4395+func checkState(c *check.C, result interface{}, expected *expectedState) {
4396+ failed := c.Failed()
4397+ c.Succeed()
4398+ log := c.GetTestLog()
4399+ matched, matchError := regexp.MatchString("^"+expected.log+"$", log)
4400+ if matchError != nil {
4401+ c.Errorf("Error in matching expression used in testing %s",
4402+ expected.name)
4403+ } else if !matched {
4404+ c.Errorf("%s logged:\n----------\n%s----------\n\nExpected:\n----------\n%s\n----------",
4405+ expected.name, log, expected.log)
4406+ }
4407+ if result != expected.result {
4408+ c.Errorf("%s returned %#v rather than %#v",
4409+ expected.name, result, expected.result)
4410+ }
4411+ if failed != expected.failed {
4412+ if failed {
4413+ c.Errorf("%s has failed when it shouldn't", expected.name)
4414+ } else {
4415+ c.Errorf("%s has not failed when it should", expected.name)
4416+ }
4417+ }
4418+}
4419
4420=== added file 'internal/gopkg.in/check.v1/checkers.go'
4421--- internal/gopkg.in/check.v1/checkers.go 1970-01-01 00:00:00 +0000
4422+++ internal/gopkg.in/check.v1/checkers.go 2015-10-30 14:13:06 +0000
4423@@ -0,0 +1,458 @@
4424+package check
4425+
4426+import (
4427+ "fmt"
4428+ "reflect"
4429+ "regexp"
4430+)
4431+
4432+// -----------------------------------------------------------------------
4433+// CommentInterface and Commentf helper, to attach extra information to checks.
4434+
4435+type comment struct {
4436+ format string
4437+ args []interface{}
4438+}
4439+
4440+// Commentf returns an infomational value to use with Assert or Check calls.
4441+// If the checker test fails, the provided arguments will be passed to
4442+// fmt.Sprintf, and will be presented next to the logged failure.
4443+//
4444+// For example:
4445+//
4446+// c.Assert(v, Equals, 42, Commentf("Iteration #%d failed.", i))
4447+//
4448+// Note that if the comment is constant, a better option is to
4449+// simply use a normal comment right above or next to the line, as
4450+// it will also get printed with any errors:
4451+//
4452+// c.Assert(l, Equals, 8192) // Ensure buffer size is correct (bug #123)
4453+//
4454+func Commentf(format string, args ...interface{}) CommentInterface {
4455+ return &comment{format, args}
4456+}
4457+
4458+// CommentInterface must be implemented by types that attach extra
4459+// information to failed checks. See the Commentf function for details.
4460+type CommentInterface interface {
4461+ CheckCommentString() string
4462+}
4463+
4464+func (c *comment) CheckCommentString() string {
4465+ return fmt.Sprintf(c.format, c.args...)
4466+}
4467+
4468+// -----------------------------------------------------------------------
4469+// The Checker interface.
4470+
4471+// The Checker interface must be provided by checkers used with
4472+// the Assert and Check verification methods.
4473+type Checker interface {
4474+ Info() *CheckerInfo
4475+ Check(params []interface{}, names []string) (result bool, error string)
4476+}
4477+
4478+// See the Checker interface.
4479+type CheckerInfo struct {
4480+ Name string
4481+ Params []string
4482+}
4483+
4484+func (info *CheckerInfo) Info() *CheckerInfo {
4485+ return info
4486+}
4487+
4488+// -----------------------------------------------------------------------
4489+// Not checker logic inverter.
4490+
4491+// The Not checker inverts the logic of the provided checker. The
4492+// resulting checker will succeed where the original one failed, and
4493+// vice-versa.
4494+//
4495+// For example:
4496+//
4497+// c.Assert(a, Not(Equals), b)
4498+//
4499+func Not(checker Checker) Checker {
4500+ return &notChecker{checker}
4501+}
4502+
4503+type notChecker struct {
4504+ sub Checker
4505+}
4506+
4507+func (checker *notChecker) Info() *CheckerInfo {
4508+ info := *checker.sub.Info()
4509+ info.Name = "Not(" + info.Name + ")"
4510+ return &info
4511+}
4512+
4513+func (checker *notChecker) Check(params []interface{}, names []string) (result bool, error string) {
4514+ result, error = checker.sub.Check(params, names)
4515+ result = !result
4516+ return
4517+}
4518+
4519+// -----------------------------------------------------------------------
4520+// IsNil checker.
4521+
4522+type isNilChecker struct {
4523+ *CheckerInfo
4524+}
4525+
4526+// The IsNil checker tests whether the obtained value is nil.
4527+//
4528+// For example:
4529+//
4530+// c.Assert(err, IsNil)
4531+//
4532+var IsNil Checker = &isNilChecker{
4533+ &CheckerInfo{Name: "IsNil", Params: []string{"value"}},
4534+}
4535+
4536+func (checker *isNilChecker) Check(params []interface{}, names []string) (result bool, error string) {
4537+ return isNil(params[0]), ""
4538+}
4539+
4540+func isNil(obtained interface{}) (result bool) {
4541+ if obtained == nil {
4542+ result = true
4543+ } else {
4544+ switch v := reflect.ValueOf(obtained); v.Kind() {
4545+ case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
4546+ return v.IsNil()
4547+ }
4548+ }
4549+ return
4550+}
4551+
4552+// -----------------------------------------------------------------------
4553+// NotNil checker. Alias for Not(IsNil), since it's so common.
4554+
4555+type notNilChecker struct {
4556+ *CheckerInfo
4557+}
4558+
4559+// The NotNil checker verifies that the obtained value is not nil.
4560+//
4561+// For example:
4562+//
4563+// c.Assert(iface, NotNil)
4564+//
4565+// This is an alias for Not(IsNil), made available since it's a
4566+// fairly common check.
4567+//
4568+var NotNil Checker = &notNilChecker{
4569+ &CheckerInfo{Name: "NotNil", Params: []string{"value"}},
4570+}
4571+
4572+func (checker *notNilChecker) Check(params []interface{}, names []string) (result bool, error string) {
4573+ return !isNil(params[0]), ""
4574+}
4575+
4576+// -----------------------------------------------------------------------
4577+// Equals checker.
4578+
4579+type equalsChecker struct {
4580+ *CheckerInfo
4581+}
4582+
4583+// The Equals checker verifies that the obtained value is equal to
4584+// the expected value, according to usual Go semantics for ==.
4585+//
4586+// For example:
4587+//
4588+// c.Assert(value, Equals, 42)
4589+//
4590+var Equals Checker = &equalsChecker{
4591+ &CheckerInfo{Name: "Equals", Params: []string{"obtained", "expected"}},
4592+}
4593+
4594+func (checker *equalsChecker) Check(params []interface{}, names []string) (result bool, error string) {
4595+ defer func() {
4596+ if v := recover(); v != nil {
4597+ result = false
4598+ error = fmt.Sprint(v)
4599+ }
4600+ }()
4601+ return params[0] == params[1], ""
4602+}
4603+
4604+// -----------------------------------------------------------------------
4605+// DeepEquals checker.
4606+
4607+type deepEqualsChecker struct {
4608+ *CheckerInfo
4609+}
4610+
4611+// The DeepEquals checker verifies that the obtained value is deep-equal to
4612+// the expected value. The check will work correctly even when facing
4613+// slices, interfaces, and values of different types (which always fail
4614+// the test).
4615+//
4616+// For example:
4617+//
4618+// c.Assert(value, DeepEquals, 42)
4619+// c.Assert(array, DeepEquals, []string{"hi", "there"})
4620+//
4621+var DeepEquals Checker = &deepEqualsChecker{
4622+ &CheckerInfo{Name: "DeepEquals", Params: []string{"obtained", "expected"}},
4623+}
4624+
4625+func (checker *deepEqualsChecker) Check(params []interface{}, names []string) (result bool, error string) {
4626+ return reflect.DeepEqual(params[0], params[1]), ""
4627+}
4628+
4629+// -----------------------------------------------------------------------
4630+// HasLen checker.
4631+
4632+type hasLenChecker struct {
4633+ *CheckerInfo
4634+}
4635+
4636+// The HasLen checker verifies that the obtained value has the
4637+// provided length. In many cases this is superior to using Equals
4638+// in conjuction with the len function because in case the check
4639+// fails the value itself will be printed, instead of its length,
4640+// providing more details for figuring the problem.
4641+//
4642+// For example:
4643+//
4644+// c.Assert(list, HasLen, 5)
4645+//
4646+var HasLen Checker = &hasLenChecker{
4647+ &CheckerInfo{Name: "HasLen", Params: []string{"obtained", "n"}},
4648+}
4649+
4650+func (checker *hasLenChecker) Check(params []interface{}, names []string) (result bool, error string) {
4651+ n, ok := params[1].(int)
4652+ if !ok {
4653+ return false, "n must be an int"
4654+ }
4655+ value := reflect.ValueOf(params[0])
4656+ switch value.Kind() {
4657+ case reflect.Map, reflect.Array, reflect.Slice, reflect.Chan, reflect.String:
4658+ default:
4659+ return false, "obtained value type has no length"
4660+ }
4661+ return value.Len() == n, ""
4662+}
4663+
4664+// -----------------------------------------------------------------------
4665+// ErrorMatches checker.
4666+
4667+type errorMatchesChecker struct {
4668+ *CheckerInfo
4669+}
4670+
4671+// The ErrorMatches checker verifies that the error value
4672+// is non nil and matches the regular expression provided.
4673+//
4674+// For example:
4675+//
4676+// c.Assert(err, ErrorMatches, "perm.*denied")
4677+//
4678+var ErrorMatches Checker = errorMatchesChecker{
4679+ &CheckerInfo{Name: "ErrorMatches", Params: []string{"value", "regex"}},
4680+}
4681+
4682+func (checker errorMatchesChecker) Check(params []interface{}, names []string) (result bool, errStr string) {
4683+ if params[0] == nil {
4684+ return false, "Error value is nil"
4685+ }
4686+ err, ok := params[0].(error)
4687+ if !ok {
4688+ return false, "Value is not an error"
4689+ }
4690+ params[0] = err.Error()
4691+ names[0] = "error"
4692+ return matches(params[0], params[1])
4693+}
4694+
4695+// -----------------------------------------------------------------------
4696+// Matches checker.
4697+
4698+type matchesChecker struct {
4699+ *CheckerInfo
4700+}
4701+
4702+// The Matches checker verifies that the string provided as the obtained
4703+// value (or the string resulting from obtained.String()) matches the
4704+// regular expression provided.
4705+//
4706+// For example:
4707+//
4708+// c.Assert(err, Matches, "perm.*denied")
4709+//
4710+var Matches Checker = &matchesChecker{
4711+ &CheckerInfo{Name: "Matches", Params: []string{"value", "regex"}},
4712+}
4713+
4714+func (checker *matchesChecker) Check(params []interface{}, names []string) (result bool, error string) {
4715+ return matches(params[0], params[1])
4716+}
4717+
4718+func matches(value, regex interface{}) (result bool, error string) {
4719+ reStr, ok := regex.(string)
4720+ if !ok {
4721+ return false, "Regex must be a string"
4722+ }
4723+ valueStr, valueIsStr := value.(string)
4724+ if !valueIsStr {
4725+ if valueWithStr, valueHasStr := value.(fmt.Stringer); valueHasStr {
4726+ valueStr, valueIsStr = valueWithStr.String(), true
4727+ }
4728+ }
4729+ if valueIsStr {
4730+ matches, err := regexp.MatchString("^"+reStr+"$", valueStr)
4731+ if err != nil {
4732+ return false, "Can't compile regex: " + err.Error()
4733+ }
4734+ return matches, ""
4735+ }
4736+ return false, "Obtained value is not a string and has no .String()"
4737+}
4738+
4739+// -----------------------------------------------------------------------
4740+// Panics checker.
4741+
4742+type panicsChecker struct {
4743+ *CheckerInfo
4744+}
4745+
4746+// The Panics checker verifies that calling the provided zero-argument
4747+// function will cause a panic which is deep-equal to the provided value.
4748+//
4749+// For example:
4750+//
4751+// c.Assert(func() { f(1, 2) }, Panics, &SomeErrorType{"BOOM"}).
4752+//
4753+//
4754+var Panics Checker = &panicsChecker{
4755+ &CheckerInfo{Name: "Panics", Params: []string{"function", "expected"}},
4756+}
4757+
4758+func (checker *panicsChecker) Check(params []interface{}, names []string) (result bool, error string) {
4759+ f := reflect.ValueOf(params[0])
4760+ if f.Kind() != reflect.Func || f.Type().NumIn() != 0 {
4761+ return false, "Function must take zero arguments"
4762+ }
4763+ defer func() {
4764+ // If the function has not panicked, then don't do the check.
4765+ if error != "" {
4766+ return
4767+ }
4768+ params[0] = recover()
4769+ names[0] = "panic"
4770+ result = reflect.DeepEqual(params[0], params[1])
4771+ }()
4772+ f.Call(nil)
4773+ return false, "Function has not panicked"
4774+}
4775+
4776+type panicMatchesChecker struct {
4777+ *CheckerInfo
4778+}
4779+
4780+// The PanicMatches checker verifies that calling the provided zero-argument
4781+// function will cause a panic with an error value matching
4782+// the regular expression provided.
4783+//
4784+// For example:
4785+//
4786+// c.Assert(func() { f(1, 2) }, PanicMatches, `open.*: no such file or directory`).
4787+//
4788+//
4789+var PanicMatches Checker = &panicMatchesChecker{
4790+ &CheckerInfo{Name: "PanicMatches", Params: []string{"function", "expected"}},
4791+}
4792+
4793+func (checker *panicMatchesChecker) Check(params []interface{}, names []string) (result bool, errmsg string) {
4794+ f := reflect.ValueOf(params[0])
4795+ if f.Kind() != reflect.Func || f.Type().NumIn() != 0 {
4796+ return false, "Function must take zero arguments"
4797+ }
4798+ defer func() {
4799+ // If the function has not panicked, then don't do the check.
4800+ if errmsg != "" {
4801+ return
4802+ }
4803+ obtained := recover()
4804+ names[0] = "panic"
4805+ if e, ok := obtained.(error); ok {
4806+ params[0] = e.Error()
4807+ } else if _, ok := obtained.(string); ok {
4808+ params[0] = obtained
4809+ } else {
4810+ errmsg = "Panic value is not a string or an error"
4811+ return
4812+ }
4813+ result, errmsg = matches(params[0], params[1])
4814+ }()
4815+ f.Call(nil)
4816+ return false, "Function has not panicked"
4817+}
4818+
4819+// -----------------------------------------------------------------------
4820+// FitsTypeOf checker.
4821+
4822+type fitsTypeChecker struct {
4823+ *CheckerInfo
4824+}
4825+
4826+// The FitsTypeOf checker verifies that the obtained value is
4827+// assignable to a variable with the same type as the provided
4828+// sample value.
4829+//
4830+// For example:
4831+//
4832+// c.Assert(value, FitsTypeOf, int64(0))
4833+// c.Assert(value, FitsTypeOf, os.Error(nil))
4834+//
4835+var FitsTypeOf Checker = &fitsTypeChecker{
4836+ &CheckerInfo{Name: "FitsTypeOf", Params: []string{"obtained", "sample"}},
4837+}
4838+
4839+func (checker *fitsTypeChecker) Check(params []interface{}, names []string) (result bool, error string) {
4840+ obtained := reflect.ValueOf(params[0])
4841+ sample := reflect.ValueOf(params[1])
4842+ if !obtained.IsValid() {
4843+ return false, ""
4844+ }
4845+ if !sample.IsValid() {
4846+ return false, "Invalid sample value"
4847+ }
4848+ return obtained.Type().AssignableTo(sample.Type()), ""
4849+}
4850+
4851+// -----------------------------------------------------------------------
4852+// Implements checker.
4853+
4854+type implementsChecker struct {
4855+ *CheckerInfo
4856+}
4857+
4858+// The Implements checker verifies that the obtained value
4859+// implements the interface specified via a pointer to an interface
4860+// variable.
4861+//
4862+// For example:
4863+//
4864+// var e os.Error
4865+// c.Assert(err, Implements, &e)
4866+//
4867+var Implements Checker = &implementsChecker{
4868+ &CheckerInfo{Name: "Implements", Params: []string{"obtained", "ifaceptr"}},
4869+}
4870+
4871+func (checker *implementsChecker) Check(params []interface{}, names []string) (result bool, error string) {
4872+ obtained := reflect.ValueOf(params[0])
4873+ ifaceptr := reflect.ValueOf(params[1])
4874+ if !obtained.IsValid() {
4875+ return false, ""
4876+ }
4877+ if !ifaceptr.IsValid() || ifaceptr.Kind() != reflect.Ptr || ifaceptr.Elem().Kind() != reflect.Interface {
4878+ return false, "ifaceptr should be a pointer to an interface variable"
4879+ }
4880+ return obtained.Type().Implements(ifaceptr.Elem().Type()), ""
4881+}
4882
4883=== added file 'internal/gopkg.in/check.v1/checkers_test.go'
4884--- internal/gopkg.in/check.v1/checkers_test.go 1970-01-01 00:00:00 +0000
4885+++ internal/gopkg.in/check.v1/checkers_test.go 2015-10-30 14:13:06 +0000
4886@@ -0,0 +1,272 @@
4887+package check_test
4888+
4889+import (
4890+ "errors"
4891+ "launchpad.net/crackly/internal/gopkg.in/check.v1"
4892+ "reflect"
4893+ "runtime"
4894+)
4895+
4896+type CheckersS struct{}
4897+
4898+var _ = check.Suite(&CheckersS{})
4899+
4900+func testInfo(c *check.C, checker check.Checker, name string, paramNames []string) {
4901+ info := checker.Info()
4902+ if info.Name != name {
4903+ c.Fatalf("Got name %s, expected %s", info.Name, name)
4904+ }
4905+ if !reflect.DeepEqual(info.Params, paramNames) {
4906+ c.Fatalf("Got param names %#v, expected %#v", info.Params, paramNames)
4907+ }
4908+}
4909+
4910+func testCheck(c *check.C, checker check.Checker, result bool, error string, params ...interface{}) ([]interface{}, []string) {
4911+ info := checker.Info()
4912+ if len(params) != len(info.Params) {
4913+ c.Fatalf("unexpected param count in test; expected %d got %d", len(info.Params), len(params))
4914+ }
4915+ names := append([]string{}, info.Params...)
4916+ result_, error_ := checker.Check(params, names)
4917+ if result_ != result || error_ != error {
4918+ c.Fatalf("%s.Check(%#v) returned (%#v, %#v) rather than (%#v, %#v)",
4919+ info.Name, params, result_, error_, result, error)
4920+ }
4921+ return params, names
4922+}
4923+
4924+func (s *CheckersS) TestComment(c *check.C) {
4925+ bug := check.Commentf("a %d bc", 42)
4926+ comment := bug.CheckCommentString()
4927+ if comment != "a 42 bc" {
4928+ c.Fatalf("Commentf returned %#v", comment)
4929+ }
4930+}
4931+
4932+func (s *CheckersS) TestIsNil(c *check.C) {
4933+ testInfo(c, check.IsNil, "IsNil", []string{"value"})
4934+
4935+ testCheck(c, check.IsNil, true, "", nil)
4936+ testCheck(c, check.IsNil, false, "", "a")
4937+
4938+ testCheck(c, check.IsNil, true, "", (chan int)(nil))
4939+ testCheck(c, check.IsNil, false, "", make(chan int))
4940+ testCheck(c, check.IsNil, true, "", (error)(nil))
4941+ testCheck(c, check.IsNil, false, "", errors.New(""))
4942+ testCheck(c, check.IsNil, true, "", ([]int)(nil))
4943+ testCheck(c, check.IsNil, false, "", make([]int, 1))
4944+ testCheck(c, check.IsNil, false, "", int(0))
4945+}
4946+
4947+func (s *CheckersS) TestNotNil(c *check.C) {
4948+ testInfo(c, check.NotNil, "NotNil", []string{"value"})
4949+
4950+ testCheck(c, check.NotNil, false, "", nil)
4951+ testCheck(c, check.NotNil, true, "", "a")
4952+
4953+ testCheck(c, check.NotNil, false, "", (chan int)(nil))
4954+ testCheck(c, check.NotNil, true, "", make(chan int))
4955+ testCheck(c, check.NotNil, false, "", (error)(nil))
4956+ testCheck(c, check.NotNil, true, "", errors.New(""))
4957+ testCheck(c, check.NotNil, false, "", ([]int)(nil))
4958+ testCheck(c, check.NotNil, true, "", make([]int, 1))
4959+}
4960+
4961+func (s *CheckersS) TestNot(c *check.C) {
4962+ testInfo(c, check.Not(check.IsNil), "Not(IsNil)", []string{"value"})
4963+
4964+ testCheck(c, check.Not(check.IsNil), false, "", nil)
4965+ testCheck(c, check.Not(check.IsNil), true, "", "a")
4966+}
4967+
4968+type simpleStruct struct {
4969+ i int
4970+}
4971+
4972+func (s *CheckersS) TestEquals(c *check.C) {
4973+ testInfo(c, check.Equals, "Equals", []string{"obtained", "expected"})
4974+
4975+ // The simplest.
4976+ testCheck(c, check.Equals, true, "", 42, 42)
4977+ testCheck(c, check.Equals, false, "", 42, 43)
4978+
4979+ // Different native types.
4980+ testCheck(c, check.Equals, false, "", int32(42), int64(42))
4981+
4982+ // With nil.
4983+ testCheck(c, check.Equals, false, "", 42, nil)
4984+
4985+ // Slices
4986+ testCheck(c, check.Equals, false, "runtime error: comparing uncomparable type []uint8", []byte{1, 2}, []byte{1, 2})
4987+
4988+ // Struct values
4989+ testCheck(c, check.Equals, true, "", simpleStruct{1}, simpleStruct{1})
4990+ testCheck(c, check.Equals, false, "", simpleStruct{1}, simpleStruct{2})
4991+
4992+ // Struct pointers
4993+ testCheck(c, check.Equals, false, "", &simpleStruct{1}, &simpleStruct{1})
4994+ testCheck(c, check.Equals, false, "", &simpleStruct{1}, &simpleStruct{2})
4995+}
4996+
4997+func (s *CheckersS) TestDeepEquals(c *check.C) {
4998+ testInfo(c, check.DeepEquals, "DeepEquals", []string{"obtained", "expected"})
4999+
5000+ // The simplest.
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: