Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go123
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
go123
Commits
66a27966
Commit
66a27966
authored
Dec 13, 2016
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
~gofmt
parent
ad78da1b
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
325 additions
and
326 deletions
+325
-326
exc/error.go
exc/error.go
+89
-89
exc/error_test.go
exc/error_test.go
+76
-77
mem/mem.go
mem/mem.go
+13
-13
mem/mem_test.go
mem/mem_test.go
+12
-12
myname/myname.go
myname/myname.go
+27
-27
myname/myname_test.go
myname/myname_test.go
+9
-9
xerr/xerr.go
xerr/xerr.go
+9
-9
xruntime/xruntime.go
xruntime/xruntime.go
+26
-26
xstrings/xstrings.go
xstrings/xstrings.go
+18
-18
xstrings/xstrings_test.go
xstrings/xstrings_test.go
+46
-46
No files found.
exc/error.go
View file @
66a27966
...
@@ -14,56 +14,56 @@
...
@@ -14,56 +14,56 @@
package
exc
package
exc
import
(
import
(
"fmt"
"fmt"
"strings"
"strings"
"lab.nexedi.com/kirr/go123/myname"
"lab.nexedi.com/kirr/go123/myname"
"lab.nexedi.com/kirr/go123/xruntime"
"lab.nexedi.com/kirr/go123/xruntime"
)
)
// error type which is raised by Raise(arg)
// error type which is raised by Raise(arg)
type
Error
struct
{
type
Error
struct
{
arg
interface
{}
arg
interface
{}
link
*
Error
// chain of linked Error(s) - see e.g. Context()
link
*
Error
// chain of linked Error(s) - see e.g. Context()
}
}
func
(
e
*
Error
)
Error
()
string
{
func
(
e
*
Error
)
Error
()
string
{
msgv
:=
[]
string
{}
msgv
:=
[]
string
{}
msg
:=
""
msg
:=
""
for
e
!=
nil
{
for
e
!=
nil
{
// TODO(go1.7) -> runtime.Frame (see xruntime.Traceback())
// TODO(go1.7) -> runtime.Frame (see xruntime.Traceback())
if
f
,
ok
:=
e
.
arg
.
(
xruntime
.
Frame
);
ok
{
if
f
,
ok
:=
e
.
arg
.
(
xruntime
.
Frame
);
ok
{
//msg = f.Function
//msg = f.Function
//msg = fmt.Sprintf("%s (%s:%d)", f.Function, f.File, f.Line)
//msg = fmt.Sprintf("%s (%s:%d)", f.Function, f.File, f.Line)
msg
=
strings
.
TrimPrefix
(
f
.
Name
(),
_errorpkgdot
)
// XXX -> better prettyfunc
msg
=
strings
.
TrimPrefix
(
f
.
Name
(),
_errorpkgdot
)
// XXX -> better prettyfunc
}
else
{
}
else
{
msg
=
fmt
.
Sprint
(
e
.
arg
)
msg
=
fmt
.
Sprint
(
e
.
arg
)
}
}
msgv
=
append
(
msgv
,
msg
)
msgv
=
append
(
msgv
,
msg
)
e
=
e
.
link
e
=
e
.
link
}
}
return
strings
.
Join
(
msgv
,
": "
)
return
strings
.
Join
(
msgv
,
": "
)
}
}
// turn any value into Error
// turn any value into Error
// if v is already Error - it stays the same
// if v is already Error - it stays the same
// otherwise new Error is created
// otherwise new Error is created
func
Aserror
(
v
interface
{})
*
Error
{
func
Aserror
(
v
interface
{})
*
Error
{
if
e
,
ok
:=
v
.
(
*
Error
);
ok
{
if
e
,
ok
:=
v
.
(
*
Error
);
ok
{
return
e
return
e
}
}
return
&
Error
{
v
,
nil
}
return
&
Error
{
v
,
nil
}
}
}
// raise error to upper level
// raise error to upper level
func
Raise
(
arg
interface
{})
{
func
Raise
(
arg
interface
{})
{
panic
(
Aserror
(
arg
))
panic
(
Aserror
(
arg
))
}
}
// raise formatted string
// raise formatted string
func
Raisef
(
format
string
,
a
...
interface
{})
{
func
Raisef
(
format
string
,
a
...
interface
{})
{
panic
(
Aserror
(
fmt
.
Sprintf
(
format
,
a
...
)))
panic
(
Aserror
(
fmt
.
Sprintf
(
format
,
a
...
)))
}
}
// raise if err != nil
// raise if err != nil
...
@@ -72,32 +72,32 @@ func Raisef(format string, a ...interface{}) {
...
@@ -72,32 +72,32 @@ func Raisef(format string, a ...interface{}) {
// err = obj
// err = obj
// err != nil is true
// err != nil is true
func
Raiseif
(
err
error
)
{
func
Raiseif
(
err
error
)
{
//if err != nil && !reflect.ValueOf(err).IsNil() {
//if err != nil && !reflect.ValueOf(err).IsNil() {
if
err
!=
nil
{
if
err
!=
nil
{
panic
(
Aserror
(
err
))
panic
(
Aserror
(
err
))
}
}
}
}
// checks recovered value to be of *Error
// checks recovered value to be of *Error
// if there is non-Error error - repanic it
// if there is non-Error error - repanic it
// otherwise return Error either nil (no panic), or actual value
// otherwise return Error either nil (no panic), or actual value
func
_errcatch
(
r
interface
{})
*
Error
{
func
_errcatch
(
r
interface
{})
*
Error
{
e
,
_
:=
r
.
(
*
Error
)
e
,
_
:=
r
.
(
*
Error
)
if
e
==
nil
&&
r
!=
nil
{
if
e
==
nil
&&
r
!=
nil
{
panic
(
r
)
panic
(
r
)
}
}
return
e
return
e
}
}
// catch error and call f(e) if it was caught.
// catch error and call f(e) if it was caught.
// must be called under defer
// must be called under defer
func
Catch
(
f
func
(
e
*
Error
))
{
func
Catch
(
f
func
(
e
*
Error
))
{
e
:=
_errcatch
(
recover
())
e
:=
_errcatch
(
recover
())
if
e
==
nil
{
if
e
==
nil
{
return
return
}
}
f
(
e
)
f
(
e
)
}
}
// be notified when error unwinding is being happening.
// be notified when error unwinding is being happening.
...
@@ -105,15 +105,15 @@ func Catch(f func(e *Error)) {
...
@@ -105,15 +105,15 @@ func Catch(f func(e *Error)) {
// see also: Context()
// see also: Context()
// must be called under defer
// must be called under defer
func
Onunwind
(
f
func
(
e
*
Error
)
*
Error
)
{
func
Onunwind
(
f
func
(
e
*
Error
)
*
Error
)
{
// cannot do Catch(...)
// cannot do Catch(...)
// as recover() works only in first-level called functions
// as recover() works only in first-level called functions
e
:=
_errcatch
(
recover
())
e
:=
_errcatch
(
recover
())
if
e
==
nil
{
if
e
==
nil
{
return
return
}
}
e
=
f
(
e
)
e
=
f
(
e
)
panic
(
e
)
panic
(
e
)
}
}
// provide error context to automatically add on unwinding.
// provide error context to automatically add on unwinding.
...
@@ -121,59 +121,59 @@ func Onunwind(f func(e *Error) *Error) {
...
@@ -121,59 +121,59 @@ func Onunwind(f func(e *Error) *Error) {
// call result is added to raised error as "prefix" context
// call result is added to raised error as "prefix" context
// must be called under defer
// must be called under defer
func
Context
(
f
func
()
interface
{})
{
func
Context
(
f
func
()
interface
{})
{
e
:=
_errcatch
(
recover
())
e
:=
_errcatch
(
recover
())
if
e
==
nil
{
if
e
==
nil
{
return
return
}
}
arg
:=
f
()
arg
:=
f
()
panic
(
Addcontext
(
e
,
arg
))
panic
(
Addcontext
(
e
,
arg
))
}
}
// add "prefix" context to error
// add "prefix" context to error
func
Addcontext
(
e
*
Error
,
arg
interface
{})
*
Error
{
func
Addcontext
(
e
*
Error
,
arg
interface
{})
*
Error
{
return
&
Error
{
arg
,
e
}
return
&
Error
{
arg
,
e
}
}
}
var
(
var
(
_errorpkgname
string
// package name under which error.go lives
_errorpkgname
string
// package name under which error.go lives
_errorpkgdot
string
// errorpkg.
_errorpkgdot
string
// errorpkg.
_errorraise
string
// errorpkg.Raise
_errorraise
string
// errorpkg.Raise
)
)
func
init
()
{
func
init
()
{
_errorpkgname
=
myname
.
Pkg
()
_errorpkgname
=
myname
.
Pkg
()
_errorpkgdot
=
_errorpkgname
+
"."
_errorpkgdot
=
_errorpkgname
+
"."
_errorraise
=
_errorpkgname
+
".Raise"
_errorraise
=
_errorpkgname
+
".Raise"
}
}
// add calling context to error.
// add calling context to error.
// Add calling function names as error context up-to topfunc not including.
// Add calling function names as error context up-to topfunc not including.
// see also: Addcontext()
// see also: Addcontext()
func
Addcallingcontext
(
topfunc
string
,
e
*
Error
)
*
Error
{
func
Addcallingcontext
(
topfunc
string
,
e
*
Error
)
*
Error
{
seenraise
:=
false
seenraise
:=
false
for
_
,
f
:=
range
xruntime
.
Traceback
(
2
)
{
for
_
,
f
:=
range
xruntime
.
Traceback
(
2
)
{
// do not show anything after raise*()
// do not show anything after raise*()
if
!
seenraise
&&
strings
.
HasPrefix
(
f
.
Name
(),
_errorraise
)
{
if
!
seenraise
&&
strings
.
HasPrefix
(
f
.
Name
(),
_errorraise
)
{
seenraise
=
true
seenraise
=
true
continue
continue
}
}
if
!
seenraise
{
if
!
seenraise
{
continue
continue
}
}
// do not go beyond topfunc
// do not go beyond topfunc
if
topfunc
!=
""
&&
f
.
Name
()
==
topfunc
{
if
topfunc
!=
""
&&
f
.
Name
()
==
topfunc
{
break
break
}
}
// skip intermediates
// skip intermediates
if
strings
.
HasSuffix
(
f
.
Name
(),
"_"
)
{
// XXX -> better skipfunc
if
strings
.
HasSuffix
(
f
.
Name
(),
"_"
)
{
// XXX -> better skipfunc
continue
continue
}
}
e
=
&
Error
{
f
,
e
}
e
=
&
Error
{
f
,
e
}
}
}
return
e
return
e
}
}
exc/error_test.go
View file @
66a27966
...
@@ -13,129 +13,128 @@
...
@@ -13,129 +13,128 @@
package
exc
package
exc
import
(
import
(
"errors"
"errors"
"testing"
"testing"
"lab.nexedi.com/kirr/go123/myname"
"lab.nexedi.com/kirr/go123/myname"
)
)
func
do_raise1
()
{
func
do_raise1
()
{
Raise
(
1
)
Raise
(
1
)
}
}
func
TestErrRaiseCatch
(
t
*
testing
.
T
)
{
func
TestErrRaiseCatch
(
t
*
testing
.
T
)
{
defer
Catch
(
func
(
e
*
Error
)
{
defer
Catch
(
func
(
e
*
Error
)
{
if
!
(
e
.
arg
==
1
&&
e
.
link
==
nil
)
{
if
!
(
e
.
arg
==
1
&&
e
.
link
==
nil
)
{
t
.
Fatalf
(
"error caught but unexpected: %#v ; want {1, nil}"
,
e
)
t
.
Fatalf
(
"error caught but unexpected: %#v ; want {1, nil}"
,
e
)
}
}
})
})
do_raise1
()
do_raise1
()
t
.
Fatal
(
"error not caught"
)
t
.
Fatal
(
"error not caught"
)
}
}
// verify err chain has .arg(s) as expected
// verify err chain has .arg(s) as expected
func
verifyErrChain
(
t
*
testing
.
T
,
e
*
Error
,
argv
...
interface
{})
{
func
verifyErrChain
(
t
*
testing
.
T
,
e
*
Error
,
argv
...
interface
{})
{
i
:=
0
i
:=
0
for
;
e
!=
nil
;
i
,
e
=
i
+
1
,
e
.
link
{
for
;
e
!=
nil
;
i
,
e
=
i
+
1
,
e
.
link
{
if
i
>=
len
(
argv
)
{
if
i
>=
len
(
argv
)
{
t
.
Fatal
(
"too long error chain"
)
t
.
Fatal
(
"too long error chain"
)
}
}
if
e
.
arg
!=
argv
[
i
]
{
if
e
.
arg
!=
argv
[
i
]
{
t
.
Fatalf
(
"error caught but unexpected %vth arg: %v ; want %v"
,
i
,
e
.
arg
,
argv
[
i
])
t
.
Fatalf
(
"error caught but unexpected %vth arg: %v ; want %v"
,
i
,
e
.
arg
,
argv
[
i
])
}
}
}
}
if
i
<
len
(
argv
)
{
if
i
<
len
(
argv
)
{
t
.
Fatal
(
"too small error chain"
)
t
.
Fatal
(
"too small error chain"
)
}
}
}
}
func
do_onunwind1
(
t
*
testing
.
T
)
{
func
do_onunwind1
(
t
*
testing
.
T
)
{
defer
Onunwind
(
func
(
e
*
Error
)
*
Error
{
defer
Onunwind
(
func
(
e
*
Error
)
*
Error
{
t
.
Fatal
(
"on unwind called without raise"
)
t
.
Fatal
(
"on unwind called without raise"
)
return
nil
return
nil
})
})
}
}
func
do_onunwind2
()
{
func
do_onunwind2
()
{
defer
Onunwind
(
func
(
e
*
Error
)
*
Error
{
defer
Onunwind
(
func
(
e
*
Error
)
*
Error
{
return
&
Error
{
2
,
e
}
return
&
Error
{
2
,
e
}
})
})
do_raise1
()
do_raise1
()
}
}
func
TestErrOnUnwind
(
t
*
testing
.
T
)
{
func
TestErrOnUnwind
(
t
*
testing
.
T
)
{
defer
Catch
(
func
(
e
*
Error
)
{
defer
Catch
(
func
(
e
*
Error
)
{
verifyErrChain
(
t
,
e
,
2
,
1
)
verifyErrChain
(
t
,
e
,
2
,
1
)
})
})
do_onunwind1
(
t
)
do_onunwind1
(
t
)
do_onunwind2
()
do_onunwind2
()
t
.
Fatal
(
"error not caught"
)
t
.
Fatal
(
"error not caught"
)
}
}
func
do_context1
(
t
*
testing
.
T
)
{
func
do_context1
(
t
*
testing
.
T
)
{
defer
Context
(
func
()
interface
{}
{
defer
Context
(
func
()
interface
{}
{
t
.
Fatal
(
"on context called without raise"
)
t
.
Fatal
(
"on context called without raise"
)
return
nil
return
nil
})
})
}
}
func
do_context2
()
{
func
do_context2
()
{
defer
Context
(
func
()
interface
{}
{
defer
Context
(
func
()
interface
{}
{
return
3
return
3
})
})
do_raise1
()
do_raise1
()
}
}
func
TestErrContext
(
t
*
testing
.
T
)
{
func
TestErrContext
(
t
*
testing
.
T
)
{
defer
Catch
(
func
(
e
*
Error
)
{
defer
Catch
(
func
(
e
*
Error
)
{
verifyErrChain
(
t
,
e
,
3
,
1
)
verifyErrChain
(
t
,
e
,
3
,
1
)
})
})
do_context1
(
t
)
do_context1
(
t
)
do_context2
()
do_context2
()
t
.
Fatal
(
"error not caught"
)
t
.
Fatal
(
"error not caught"
)
}
}
func
do_raise11
()
{
func
do_raise11
()
{
do_raise1
()
do_raise1
()
}
}
func
do_raise3if
()
{
func
do_raise3if
()
{
Raiseif
(
errors
.
New
(
"3"
))
Raiseif
(
errors
.
New
(
"3"
))
}
}
func
do_raise3if1
()
{
func
do_raise3if1
()
{
do_raise3if
()
do_raise3if
()
}
}
func
do_raise4f
()
{
func
do_raise4f
()
{
Raisef
(
"%d"
,
4
)
Raisef
(
"%d"
,
4
)
}
}
func
do_raise4f1
()
{
func
do_raise4f1
()
{
do_raise4f
()
do_raise4f
()
}
}
func
TestErrAddCallingContext
(
t
*
testing
.
T
)
{
func
TestErrAddCallingContext
(
t
*
testing
.
T
)
{
var
tests
=
[]
struct
{
f
func
();
wanterrcontext
string
}
{
var
tests
=
[]
struct
{
f
func
();
wanterrcontext
string
}
{
{
do_raise11
,
"do_raise11: do_raise1: 1"
},
{
do_raise11
,
"do_raise11: do_raise1: 1"
},
{
do_raise3if1
,
"do_raise3if1: do_raise3if: 3"
},
{
do_raise3if1
,
"do_raise3if1: do_raise3if: 3"
},
{
do_raise4f1
,
"do_raise4f1: do_raise4f: 4"
},
{
do_raise4f1
,
"do_raise4f1: do_raise4f: 4"
},
}
}
for
_
,
tt
:=
range
tests
{
for
_
,
tt
:=
range
tests
{
func
()
{
func
()
{
myfunc
:=
myname
.
Func
()
myfunc
:=
myname
.
Func
()
defer
Catch
(
func
(
e
*
Error
)
{
defer
Catch
(
func
(
e
*
Error
)
{
e
=
Addcallingcontext
(
myfunc
,
e
)
e
=
Addcallingcontext
(
myfunc
,
e
)
msg
:=
e
.
Error
()
msg
:=
e
.
Error
()
if
msg
!=
tt
.
wanterrcontext
{
if
msg
!=
tt
.
wanterrcontext
{
t
.
Fatalf
(
"err + calling context: %q ; want %q"
,
msg
,
tt
.
wanterrcontext
)
t
.
Fatalf
(
"err + calling context: %q ; want %q"
,
msg
,
tt
.
wanterrcontext
)
}
}
})
})
tt
.
f
()
tt
.
f
()
t
.
Fatal
(
"error not caught"
)
t
.
Fatal
(
"error not caught"
)
}()
}()
}
}
}
}
mem/mem.go
View file @
66a27966
...
@@ -14,25 +14,25 @@
...
@@ -14,25 +14,25 @@
package
mem
package
mem
import
(
import
(
"reflect"
"reflect"
"unsafe"
"unsafe"
)
)
// string -> []byte without copying
// string -> []byte without copying
func
Bytes
(
s
string
)
[]
byte
{
func
Bytes
(
s
string
)
[]
byte
{
var
b
[]
byte
var
b
[]
byte
bp
:=
(
*
reflect
.
SliceHeader
)(
unsafe
.
Pointer
(
&
b
))
bp
:=
(
*
reflect
.
SliceHeader
)(
unsafe
.
Pointer
(
&
b
))
bp
.
Data
=
(
*
reflect
.
StringHeader
)(
unsafe
.
Pointer
(
&
s
))
.
Data
bp
.
Data
=
(
*
reflect
.
StringHeader
)(
unsafe
.
Pointer
(
&
s
))
.
Data
bp
.
Cap
=
len
(
s
)
bp
.
Cap
=
len
(
s
)
bp
.
Len
=
len
(
s
)
bp
.
Len
=
len
(
s
)
return
b
return
b
}
}
// []byte -> string without copying
// []byte -> string without copying
func
String
(
b
[]
byte
)
string
{
func
String
(
b
[]
byte
)
string
{
var
s
string
var
s
string
sp
:=
(
*
reflect
.
StringHeader
)(
unsafe
.
Pointer
(
&
s
))
sp
:=
(
*
reflect
.
StringHeader
)(
unsafe
.
Pointer
(
&
s
))
sp
.
Data
=
(
*
reflect
.
SliceHeader
)(
unsafe
.
Pointer
(
&
b
))
.
Data
sp
.
Data
=
(
*
reflect
.
SliceHeader
)(
unsafe
.
Pointer
(
&
b
))
.
Data
sp
.
Len
=
len
(
b
)
sp
.
Len
=
len
(
b
)
return
s
return
s
}
}
mem/mem_test.go
View file @
66a27966
...
@@ -13,21 +13,21 @@
...
@@ -13,21 +13,21 @@
package
mem
package
mem
import
(
import
(
"reflect"
"reflect"
"testing"
"testing"
)
)
// check that String() and Bytes() create correct objects which alias original object memory
// check that String() and Bytes() create correct objects which alias original object memory
func
TestStringBytes
(
t
*
testing
.
T
)
{
func
TestStringBytes
(
t
*
testing
.
T
)
{
s
:=
"Hello"
s
:=
"Hello"
b
:=
[]
byte
(
s
)
b
:=
[]
byte
(
s
)
s1
:=
String
(
b
)
s1
:=
String
(
b
)
b1
:=
Bytes
(
s1
)
b1
:=
Bytes
(
s1
)
if
s1
!=
s
{
t
.
Error
(
"string -> []byte -> String != Identity"
)
}
if
s1
!=
s
{
t
.
Error
(
"string -> []byte -> String != Identity"
)
}
if
!
reflect
.
DeepEqual
(
b1
,
b
)
{
t
.
Error
(
"[]byte -> String -> Bytes != Identity"
)
}
if
!
reflect
.
DeepEqual
(
b1
,
b
)
{
t
.
Error
(
"[]byte -> String -> Bytes != Identity"
)
}
b
[
0
]
=
'I'
b
[
0
]
=
'I'
if
s
!=
"Hello"
{
t
.
Error
(
"string -> []byte not copied"
)
}
if
s
!=
"Hello"
{
t
.
Error
(
"string -> []byte not copied"
)
}
if
s1
!=
"Iello"
{
t
.
Error
(
"[]byte -> String not aliased"
)
}
if
s1
!=
"Iello"
{
t
.
Error
(
"[]byte -> String not aliased"
)
}
if
!
reflect
.
DeepEqual
(
b1
,
b
)
{
t
.
Error
(
"string -> Bytes not aliased"
)
}
if
!
reflect
.
DeepEqual
(
b1
,
b
)
{
t
.
Error
(
"string -> Bytes not aliased"
)
}
}
}
myname/myname.go
View file @
66a27966
...
@@ -14,44 +14,44 @@
...
@@ -14,44 +14,44 @@
package
myname
package
myname
import
(
import
(
"fmt"
"fmt"
"runtime"
"runtime"
"strings"
"strings"
)
)
func
_myfuncname
(
nskip
int
)
string
{
func
_myfuncname
(
nskip
int
)
string
{
pcv
:=
[
1
]
uintptr
{}
pcv
:=
[
1
]
uintptr
{}
runtime
.
Callers
(
nskip
,
pcv
[
:
])
runtime
.
Callers
(
nskip
,
pcv
[
:
])
f
:=
runtime
.
FuncForPC
(
pcv
[
0
])
f
:=
runtime
.
FuncForPC
(
pcv
[
0
])
if
f
==
nil
{
if
f
==
nil
{
return
""
return
""
}
}
return
f
.
Name
()
return
f
.
Name
()
}
}
// get name of currently running function (caller of Func())
// get name of currently running function (caller of Func())
// name is fully qualified package/name.function(.x)
// name is fully qualified package/name.function(.x)
func
Func
()
string
{
func
Func
()
string
{
return
_myfuncname
(
3
)
return
_myfuncname
(
3
)
}
}
// get name of currently running function's package
// get name of currently running function's package
// package is fully qualified package/name
// package is fully qualified package/name
func
Pkg
()
string
{
func
Pkg
()
string
{
myfunc
:=
_myfuncname
(
3
)
myfunc
:=
_myfuncname
(
3
)
if
myfunc
==
""
{
if
myfunc
==
""
{
return
""
return
""
}
}
// NOTE dots in package name are after last slash are escaped by go as %2e
// NOTE dots in package name are after last slash are escaped by go as %2e
// this way the first '.' after last '/' is delimiter between package and function
// this way the first '.' after last '/' is delimiter between package and function
//
//
// lab.nexedi.com/kirr/git-backup/package%2ename.Function
// lab.nexedi.com/kirr/git-backup/package%2ename.Function
// lab.nexedi.com/kirr/git-backup/pkg2.qqq/name%2ezzz.Function
// lab.nexedi.com/kirr/git-backup/pkg2.qqq/name%2ezzz.Function
islash
:=
strings
.
LastIndexByte
(
myfunc
,
'/'
)
islash
:=
strings
.
LastIndexByte
(
myfunc
,
'/'
)
iafterslash
:=
islash
+
1
// NOTE if '/' not found iafterslash = 0
iafterslash
:=
islash
+
1
// NOTE if '/' not found iafterslash = 0
idot
:=
strings
.
IndexByte
(
myfunc
[
iafterslash
:
],
'.'
)
idot
:=
strings
.
IndexByte
(
myfunc
[
iafterslash
:
],
'.'
)
if
idot
==
-
1
{
if
idot
==
-
1
{
panic
(
fmt
.
Errorf
(
"funcname %q is not fully qualified"
,
myfunc
))
panic
(
fmt
.
Errorf
(
"funcname %q is not fully qualified"
,
myfunc
))
}
}
return
myfunc
[
:
iafterslash
+
idot
]
return
myfunc
[
:
iafterslash
+
idot
]
}
}
myname/myname_test.go
View file @
66a27966
...
@@ -13,16 +13,16 @@
...
@@ -13,16 +13,16 @@
package
myname
package
myname
import
(
import
(
"strings"
"strings"
"testing"
"testing"
)
)
func
TestMyFuncName
(
t
*
testing
.
T
)
{
func
TestMyFuncName
(
t
*
testing
.
T
)
{
myfunc
:=
Func
()
myfunc
:=
Func
()
// go test changes full package name (putting filesystem of the tree into ti)
// go test changes full package name (putting filesystem of the tree into ti)
// thus we check only for suffix
// thus we check only for suffix
wantsuffix
:=
".TestMyFuncName"
wantsuffix
:=
".TestMyFuncName"
if
!
strings
.
HasSuffix
(
myfunc
,
wantsuffix
)
{
if
!
strings
.
HasSuffix
(
myfunc
,
wantsuffix
)
{
t
.
Errorf
(
"myname.Func() -> %v ; want *%v"
,
myfunc
,
wantsuffix
)
t
.
Errorf
(
"myname.Func() -> %v ; want *%v"
,
myfunc
,
wantsuffix
)
}
}
}
}
xerr/xerr.go
View file @
66a27966
...
@@ -14,20 +14,20 @@
...
@@ -14,20 +14,20 @@
package
xerr
package
xerr
import
(
import
(
"fmt"
"fmt"
)
)
// error merging multiple errors (e.g. after collecting them from several parallel workers)
// error merging multiple errors (e.g. after collecting them from several parallel workers)
type
Errorv
[]
error
type
Errorv
[]
error
func
(
ev
Errorv
)
Error
()
string
{
func
(
ev
Errorv
)
Error
()
string
{
if
len
(
ev
)
==
1
{
if
len
(
ev
)
==
1
{
return
ev
[
0
]
.
Error
()
return
ev
[
0
]
.
Error
()
}
}
msg
:=
fmt
.
Sprintf
(
"%d errors:
\n
"
,
len
(
ev
))
msg
:=
fmt
.
Sprintf
(
"%d errors:
\n
"
,
len
(
ev
))
for
_
,
e
:=
range
ev
{
for
_
,
e
:=
range
ev
{
msg
+=
fmt
.
Sprintf
(
"
\t
- %s
\n
"
,
e
)
msg
+=
fmt
.
Sprintf
(
"
\t
- %s
\n
"
,
e
)
}
}
return
msg
return
msg
}
}
xruntime/xruntime.go
View file @
66a27966
...
@@ -14,44 +14,44 @@
...
@@ -14,44 +14,44 @@
package
xruntime
package
xruntime
import
(
import
(
"runtime"
"runtime"
)
)
// TODO(go1.7) goes away in favour of runtime.Frame
// TODO(go1.7) goes away in favour of runtime.Frame
type
Frame
struct
{
type
Frame
struct
{
*
runtime
.
Func
*
runtime
.
Func
Pc
uintptr
Pc
uintptr
}
}
// get current calling traceback as []Frame
// get current calling traceback as []Frame
// nskip meaning: the same as in runtime.Callers()
// nskip meaning: the same as in runtime.Callers()
// TODO(go1.7) []Frame -> []runtime.Frame
// TODO(go1.7) []Frame -> []runtime.Frame
func
Traceback
(
nskip
int
)
[]
Frame
{
func
Traceback
(
nskip
int
)
[]
Frame
{
// all callers
// all callers
var
pcv
=
[]
uintptr
{
0
}
var
pcv
=
[]
uintptr
{
0
}
for
{
for
{
pcv
=
make
([]
uintptr
,
2
*
len
(
pcv
))
pcv
=
make
([]
uintptr
,
2
*
len
(
pcv
))
n
:=
runtime
.
Callers
(
nskip
+
1
,
pcv
)
n
:=
runtime
.
Callers
(
nskip
+
1
,
pcv
)
if
n
<
len
(
pcv
)
{
if
n
<
len
(
pcv
)
{
pcv
=
pcv
[
:
n
]
pcv
=
pcv
[
:
n
]
break
break
}
}
}
}
// pcv -> frames
// pcv -> frames
/*
/*
framev := make([]runtime.Frame, 0, len(pcv))
framev := make([]runtime.Frame, 0, len(pcv))
frames := runtime.CallersFrames(pcv)
frames := runtime.CallersFrames(pcv)
for more := true; more; {
for more := true; more; {
var frame runtime.Frame
var frame runtime.Frame
frame, more = frames.Next()
frame, more = frames.Next()
framev = append(framev, frame)
framev = append(framev, frame)
}
}
*/
*/
framev
:=
make
([]
Frame
,
0
,
len
(
pcv
))
framev
:=
make
([]
Frame
,
0
,
len
(
pcv
))
for
_
,
pc
:=
range
pcv
{
for
_
,
pc
:=
range
pcv
{
framev
=
append
(
framev
,
Frame
{
runtime
.
FuncForPC
(
pc
),
pc
})
framev
=
append
(
framev
,
Frame
{
runtime
.
FuncForPC
(
pc
),
pc
})
}
}
return
framev
return
framev
}
}
xstrings/xstrings.go
View file @
66a27966
...
@@ -14,35 +14,35 @@
...
@@ -14,35 +14,35 @@
package
xstrings
package
xstrings
import
(
import
(
"fmt"
"fmt"
"strings"
"strings"
)
)
// split string into lines. The last line, if it is empty, is omitted from the result
// split string into lines. The last line, if it is empty, is omitted from the result
// (rationale is: string.Split("hello\nworld\n", "\n") -> ["hello", "world", ""])
// (rationale is: string.Split("hello\nworld\n", "\n") -> ["hello", "world", ""])
func
SplitLines
(
s
,
sep
string
)
[]
string
{
func
SplitLines
(
s
,
sep
string
)
[]
string
{
sv
:=
strings
.
Split
(
s
,
sep
)
sv
:=
strings
.
Split
(
s
,
sep
)
l
:=
len
(
sv
)
l
:=
len
(
sv
)
if
l
>
0
&&
sv
[
l
-
1
]
==
""
{
if
l
>
0
&&
sv
[
l
-
1
]
==
""
{
sv
=
sv
[
:
l
-
1
]
sv
=
sv
[
:
l
-
1
]
}
}
return
sv
return
sv
}
}
// split string by sep and expect exactly 2 parts
// split string by sep and expect exactly 2 parts
func
Split2
(
s
,
sep
string
)
(
s1
,
s2
string
,
err
error
)
{
func
Split2
(
s
,
sep
string
)
(
s1
,
s2
string
,
err
error
)
{
parts
:=
strings
.
Split
(
s
,
sep
)
parts
:=
strings
.
Split
(
s
,
sep
)
if
len
(
parts
)
!=
2
{
if
len
(
parts
)
!=
2
{
return
""
,
""
,
fmt
.
Errorf
(
"split2: %q has %v parts (expected 2, sep: %q)"
,
s
,
len
(
parts
),
sep
)
return
""
,
""
,
fmt
.
Errorf
(
"split2: %q has %v parts (expected 2, sep: %q)"
,
s
,
len
(
parts
),
sep
)
}
}
return
parts
[
0
],
parts
[
1
],
nil
return
parts
[
0
],
parts
[
1
],
nil
}
}
// (head+sep+tail) -> head, tail
// (head+sep+tail) -> head, tail
func
HeadTail
(
s
,
sep
string
)
(
head
,
tail
string
,
err
error
)
{
func
HeadTail
(
s
,
sep
string
)
(
head
,
tail
string
,
err
error
)
{
parts
:=
strings
.
SplitN
(
s
,
sep
,
2
)
parts
:=
strings
.
SplitN
(
s
,
sep
,
2
)
if
len
(
parts
)
!=
2
{
if
len
(
parts
)
!=
2
{
return
""
,
""
,
fmt
.
Errorf
(
"headtail: %q has no %q"
,
s
,
sep
)
return
""
,
""
,
fmt
.
Errorf
(
"headtail: %q has no %q"
,
s
,
sep
)
}
}
return
parts
[
0
],
parts
[
1
],
nil
return
parts
[
0
],
parts
[
1
],
nil
}
}
xstrings/xstrings_test.go
View file @
66a27966
...
@@ -13,62 +13,62 @@
...
@@ -13,62 +13,62 @@
package
xstrings
package
xstrings
import
(
import
(
"reflect"
"reflect"
"testing"
"testing"
)
)
func
TestSplitLines
(
t
*
testing
.
T
)
{
func
TestSplitLines
(
t
*
testing
.
T
)
{
var
tests
=
[]
struct
{
input
,
sep
string
;
output
[]
string
}
{
var
tests
=
[]
struct
{
input
,
sep
string
;
output
[]
string
}
{
{
""
,
"
\n
"
,
[]
string
{}},
{
""
,
"
\n
"
,
[]
string
{}},
{
"hello"
,
"
\n
"
,
[]
string
{
"hello"
}},
{
"hello"
,
"
\n
"
,
[]
string
{
"hello"
}},
{
"hello
\n
"
,
"
\n
"
,
[]
string
{
"hello"
}},
{
"hello
\n
"
,
"
\n
"
,
[]
string
{
"hello"
}},
{
"hello
\n
world"
,
"
\n
"
,
[]
string
{
"hello"
,
"world"
}},
{
"hello
\n
world"
,
"
\n
"
,
[]
string
{
"hello"
,
"world"
}},
{
"hello
\n
world
\n
"
,
"
\n
"
,
[]
string
{
"hello"
,
"world"
}},
{
"hello
\n
world
\n
"
,
"
\n
"
,
[]
string
{
"hello"
,
"world"
}},
{
"hello
\x00
world
\x00
"
,
"
\n
"
,
[]
string
{
"hello
\x00
world
\x00
"
}},
{
"hello
\x00
world
\x00
"
,
"
\n
"
,
[]
string
{
"hello
\x00
world
\x00
"
}},
{
"hello
\x00
world
\x00
"
,
"
\x00
"
,
[]
string
{
"hello"
,
"world"
}},
{
"hello
\x00
world
\x00
"
,
"
\x00
"
,
[]
string
{
"hello"
,
"world"
}},
}
}
for
_
,
tt
:=
range
tests
{
for
_
,
tt
:=
range
tests
{
sv
:=
SplitLines
(
tt
.
input
,
tt
.
sep
)
sv
:=
SplitLines
(
tt
.
input
,
tt
.
sep
)
if
!
reflect
.
DeepEqual
(
sv
,
tt
.
output
)
{
if
!
reflect
.
DeepEqual
(
sv
,
tt
.
output
)
{
t
.
Errorf
(
"splitlines(%q, %q) -> %q ; want %q"
,
tt
.
input
,
tt
.
sep
,
sv
,
tt
.
output
)
t
.
Errorf
(
"splitlines(%q, %q) -> %q ; want %q"
,
tt
.
input
,
tt
.
sep
,
sv
,
tt
.
output
)
}
}
}
}
}
}
func
TestSplit2
(
t
*
testing
.
T
)
{
func
TestSplit2
(
t
*
testing
.
T
)
{
var
tests
=
[]
struct
{
input
,
s1
,
s2
string
;
ok
bool
}
{
var
tests
=
[]
struct
{
input
,
s1
,
s2
string
;
ok
bool
}
{
{
""
,
""
,
""
,
false
},
{
""
,
""
,
""
,
false
},
{
" "
,
""
,
""
,
true
},
{
" "
,
""
,
""
,
true
},
{
"hello"
,
""
,
""
,
false
},
{
"hello"
,
""
,
""
,
false
},
{
"hello world"
,
"hello"
,
"world"
,
true
},
{
"hello world"
,
"hello"
,
"world"
,
true
},
{
"hello world 1"
,
""
,
""
,
false
},
{
"hello world 1"
,
""
,
""
,
false
},
}
}
for
_
,
tt
:=
range
tests
{
for
_
,
tt
:=
range
tests
{
s1
,
s2
,
err
:=
Split2
(
tt
.
input
,
" "
)
s1
,
s2
,
err
:=
Split2
(
tt
.
input
,
" "
)
ok
:=
err
==
nil
ok
:=
err
==
nil
if
s1
!=
tt
.
s1
||
s2
!=
tt
.
s2
||
ok
!=
tt
.
ok
{
if
s1
!=
tt
.
s1
||
s2
!=
tt
.
s2
||
ok
!=
tt
.
ok
{
t
.
Errorf
(
"split2(%q) -> %q %q %v ; want %q %q %v"
,
tt
.
input
,
s1
,
s2
,
ok
,
tt
.
s1
,
tt
.
s2
,
tt
.
ok
)
t
.
Errorf
(
"split2(%q) -> %q %q %v ; want %q %q %v"
,
tt
.
input
,
s1
,
s2
,
ok
,
tt
.
s1
,
tt
.
s2
,
tt
.
ok
)
}
}
}
}
}
}
func
TestHeadtail
(
t
*
testing
.
T
)
{
func
TestHeadtail
(
t
*
testing
.
T
)
{
var
tests
=
[]
struct
{
input
,
head
,
tail
string
;
ok
bool
}
{
var
tests
=
[]
struct
{
input
,
head
,
tail
string
;
ok
bool
}
{
{
""
,
""
,
""
,
false
},
{
""
,
""
,
""
,
false
},
{
" "
,
""
,
""
,
true
},
{
" "
,
""
,
""
,
true
},
{
" "
,
""
,
" "
,
true
},
{
" "
,
""
,
" "
,
true
},
{
"hello world"
,
"hello"
,
"world"
,
true
},
{
"hello world"
,
"hello"
,
"world"
,
true
},
{
"hello world 1"
,
"hello"
,
"world 1"
,
true
},
{
"hello world 1"
,
"hello"
,
"world 1"
,
true
},
{
"hello world 2"
,
"hello"
,
" world 2"
,
true
},
{
"hello world 2"
,
"hello"
,
" world 2"
,
true
},
}
}
for
_
,
tt
:=
range
tests
{
for
_
,
tt
:=
range
tests
{
head
,
tail
,
err
:=
HeadTail
(
tt
.
input
,
" "
)
head
,
tail
,
err
:=
HeadTail
(
tt
.
input
,
" "
)
ok
:=
err
==
nil
ok
:=
err
==
nil
if
head
!=
tt
.
head
||
tail
!=
tt
.
tail
||
ok
!=
tt
.
ok
{
if
head
!=
tt
.
head
||
tail
!=
tt
.
tail
||
ok
!=
tt
.
ok
{
t
.
Errorf
(
"headtail(%q) -> %q %q %v ; want %q %q %v"
,
tt
.
input
,
head
,
tail
,
ok
,
tt
.
head
,
tt
.
tail
,
tt
.
ok
)
t
.
Errorf
(
"headtail(%q) -> %q %q %v ; want %q %q %v"
,
tt
.
input
,
head
,
tail
,
ok
,
tt
.
head
,
tt
.
tail
,
tt
.
ok
)
}
}
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment