mirror of
https://github.com/ipfs/kubo.git
synced 2026-02-23 19:37:46 +08:00
commit
4334f6fda3
4
Godeps/Godeps.json
generated
4
Godeps/Godeps.json
generated
@ -68,6 +68,10 @@
|
||||
"ImportPath": "github.com/cenkalti/backoff",
|
||||
"Rev": "9831e1e25c874e0a0601b6dc43641071414eec7a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/cheggaaa/pb",
|
||||
"Rev": "e8c7cc515bfde3e267957a3b110080ceed51354e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/coreos/go-semver/semver",
|
||||
"Rev": "6fe83ccda8fb9b7549c9ab4ba47f47858bc950aa"
|
||||
|
||||
12
Godeps/_workspace/src/github.com/cheggaaa/pb/LICENSE
generated
vendored
Normal file
12
Godeps/_workspace/src/github.com/cheggaaa/pb/LICENSE
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
Copyright (c) 2012, Sergey Cherepanov
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of 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.
|
||||
|
||||
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.
|
||||
98
Godeps/_workspace/src/github.com/cheggaaa/pb/README.md
generated
vendored
Normal file
98
Godeps/_workspace/src/github.com/cheggaaa/pb/README.md
generated
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
## Terminal progress bar for Go
|
||||
|
||||
Simple progress bar for console programms.
|
||||
|
||||
|
||||
### Installation
|
||||
```
|
||||
go get github.com/cheggaaa/pb
|
||||
```
|
||||
|
||||
### Usage
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/cheggaaa/pb"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
count := 100000
|
||||
bar := pb.StartNew(count)
|
||||
for i := 0; i < count; i++ {
|
||||
bar.Increment()
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
bar.FinishPrint("The End!")
|
||||
}
|
||||
```
|
||||
Result will be like this:
|
||||
```
|
||||
> go run test.go
|
||||
37158 / 100000 [================>_______________________________] 37.16% 1m11s
|
||||
```
|
||||
|
||||
|
||||
More functions?
|
||||
```Go
|
||||
// create bar
|
||||
bar := pb.New(count)
|
||||
|
||||
// refresh info every second (default 200ms)
|
||||
bar.SetRefreshRate(time.Second)
|
||||
|
||||
// show percents (by default already true)
|
||||
bar.ShowPercent = true
|
||||
|
||||
// show bar (by default already true)
|
||||
bar.ShowBar = true
|
||||
|
||||
// no need counters
|
||||
bar.ShowCounters = false
|
||||
|
||||
// show "time left"
|
||||
bar.ShowTimeLeft = true
|
||||
|
||||
// show average speed
|
||||
bar.ShowSpeed = true
|
||||
|
||||
// sets the width of the progress bar
|
||||
bar.SetWith(80)
|
||||
|
||||
// sets the width of the progress bar, but if terminal size smaller will be ignored
|
||||
bar.SetMaxWith(80)
|
||||
|
||||
// convert output to readable format (like KB, MB)
|
||||
bar.SetUnits(pb.U_BYTES)
|
||||
|
||||
// and start
|
||||
bar.Start()
|
||||
```
|
||||
|
||||
Want handle progress of io operations?
|
||||
```Go
|
||||
// create and start bar
|
||||
bar := pb.New(myDataLen).SetUnits(pb.U_BYTES)
|
||||
bar.Start()
|
||||
|
||||
// my io.Reader
|
||||
r := myReader
|
||||
|
||||
// my io.Writer
|
||||
w := myWriter
|
||||
|
||||
// create multi writer
|
||||
writer := io.MultiWriter(w, bar)
|
||||
|
||||
// and copy
|
||||
io.Copy(writer, r)
|
||||
|
||||
// show example/copy/copy.go for advanced example
|
||||
|
||||
```
|
||||
|
||||
Not like the looks?
|
||||
```Go
|
||||
bar.Format("<.- >")
|
||||
```
|
||||
81
Godeps/_workspace/src/github.com/cheggaaa/pb/example/copy/copy.go
generated
vendored
Normal file
81
Godeps/_workspace/src/github.com/cheggaaa/pb/example/copy/copy.go
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/cheggaaa/pb"
|
||||
"os"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
"strings"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// check args
|
||||
if len(os.Args) < 3 {
|
||||
printUsage()
|
||||
return
|
||||
}
|
||||
sourceName, destName := os.Args[1], os.Args[2]
|
||||
|
||||
// check source
|
||||
var source io.Reader
|
||||
var sourceSize int64
|
||||
if strings.HasPrefix(sourceName, "http://") {
|
||||
// open as url
|
||||
resp, err := http.Get(sourceName)
|
||||
if err != nil {
|
||||
fmt.Printf("Can't get %s: %v\n", sourceName, err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
fmt.Printf("Server return non-200 status: %v\n", resp.Status)
|
||||
return
|
||||
}
|
||||
i, _ := strconv.Atoi(resp.Header.Get("Content-Length"))
|
||||
sourceSize = int64(i)
|
||||
source = resp.Body
|
||||
} else {
|
||||
// open as file
|
||||
s, err := os.Open(sourceName)
|
||||
if err != nil {
|
||||
fmt.Printf("Can't open %s: %v\n", sourceName, err)
|
||||
return
|
||||
}
|
||||
defer s.Close()
|
||||
// get source size
|
||||
sourceStat, err := s.Stat()
|
||||
if err != nil {
|
||||
fmt.Printf("Can't stat %s: %v\n", sourceName, err)
|
||||
return
|
||||
}
|
||||
sourceSize = sourceStat.Size()
|
||||
source = s
|
||||
}
|
||||
|
||||
// create dest
|
||||
dest, err := os.Create(destName)
|
||||
if err != nil {
|
||||
fmt.Printf("Can't create %s: %v\n", destName, err)
|
||||
return
|
||||
}
|
||||
defer dest.Close()
|
||||
|
||||
// create bar
|
||||
bar := pb.New(int(sourceSize)).SetUnits(pb.U_BYTES).SetRefreshRate(time.Millisecond * 10)
|
||||
bar.ShowSpeed = true
|
||||
bar.Start()
|
||||
|
||||
// create multi writer
|
||||
writer := io.MultiWriter(dest, bar)
|
||||
|
||||
// and copy
|
||||
io.Copy(writer, source)
|
||||
bar.Finish()
|
||||
}
|
||||
|
||||
func printUsage() {
|
||||
fmt.Println("copy [source file or url] [dest file]")
|
||||
}
|
||||
30
Godeps/_workspace/src/github.com/cheggaaa/pb/example/pb.go
generated
vendored
Normal file
30
Godeps/_workspace/src/github.com/cheggaaa/pb/example/pb.go
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/cheggaaa/pb"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
count := 5000
|
||||
bar := pb.New(count)
|
||||
|
||||
// show percents (by default already true)
|
||||
bar.ShowPercent = true
|
||||
|
||||
// show bar (by default already true)
|
||||
bar.ShowPercent = true
|
||||
|
||||
// no need counters
|
||||
bar.ShowCounters = true
|
||||
|
||||
bar.ShowTimeLeft = true
|
||||
|
||||
// and start
|
||||
bar.Start()
|
||||
for i := 0; i < count; i++ {
|
||||
bar.Increment()
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
bar.FinishPrint("The End!")
|
||||
}
|
||||
42
Godeps/_workspace/src/github.com/cheggaaa/pb/format.go
generated
vendored
Normal file
42
Godeps/_workspace/src/github.com/cheggaaa/pb/format.go
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
package pb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// By default, without type handle
|
||||
U_NO = 0
|
||||
// Handle as b, Kb, Mb, etc
|
||||
U_BYTES = 1
|
||||
)
|
||||
|
||||
// Format integer
|
||||
func Format(i int64, units int) string {
|
||||
switch units {
|
||||
case U_BYTES:
|
||||
return FormatBytes(i)
|
||||
}
|
||||
// by default just convert to string
|
||||
return strconv.Itoa(int(i))
|
||||
}
|
||||
|
||||
// Convert bytes to human readable string. Like a 2 MB, 64.2 KB, 52 B
|
||||
func FormatBytes(i int64) (result string) {
|
||||
switch {
|
||||
case i > (1024 * 1024 * 1024 * 1024):
|
||||
result = fmt.Sprintf("%#.02f TB", float64(i)/1024/1024/1024/1024)
|
||||
case i > (1024 * 1024 * 1024):
|
||||
result = fmt.Sprintf("%#.02f GB", float64(i)/1024/1024/1024)
|
||||
case i > (1024 * 1024):
|
||||
result = fmt.Sprintf("%#.02f MB", float64(i)/1024/1024)
|
||||
case i > 1024:
|
||||
result = fmt.Sprintf("%#.02f KB", float64(i)/1024)
|
||||
default:
|
||||
result = fmt.Sprintf("%d B", i)
|
||||
}
|
||||
result = strings.Trim(result, " ")
|
||||
return
|
||||
}
|
||||
37
Godeps/_workspace/src/github.com/cheggaaa/pb/format_test.go
generated
vendored
Normal file
37
Godeps/_workspace/src/github.com/cheggaaa/pb/format_test.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
package pb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_DefaultsToInteger(t *testing.T) {
|
||||
value := int64(1000)
|
||||
expected := strconv.Itoa(int(value))
|
||||
actual := Format(value, -1)
|
||||
|
||||
if actual != expected {
|
||||
t.Error(fmt.Sprintf("Expected {%s} was {%s}", expected, actual))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_CanFormatAsInteger(t *testing.T) {
|
||||
value := int64(1000)
|
||||
expected := strconv.Itoa(int(value))
|
||||
actual := Format(value, U_NO)
|
||||
|
||||
if actual != expected {
|
||||
t.Error(fmt.Sprintf("Expected {%s} was {%s}", expected, actual))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_CanFormatAsBytes(t *testing.T) {
|
||||
value := int64(1000)
|
||||
expected := "1000 B"
|
||||
actual := Format(value, U_BYTES)
|
||||
|
||||
if actual != expected {
|
||||
t.Error(fmt.Sprintf("Expected {%s} was {%s}", expected, actual))
|
||||
}
|
||||
}
|
||||
341
Godeps/_workspace/src/github.com/cheggaaa/pb/pb.go
generated
vendored
Normal file
341
Godeps/_workspace/src/github.com/cheggaaa/pb/pb.go
generated
vendored
Normal file
@ -0,0 +1,341 @@
|
||||
package pb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// Default refresh rate - 200ms
|
||||
DEFAULT_REFRESH_RATE = time.Millisecond * 200
|
||||
FORMAT = "[=>-]"
|
||||
)
|
||||
|
||||
// DEPRECATED
|
||||
// variables for backward compatibility, from now do not work
|
||||
// use pb.Format and pb.SetRefreshRate
|
||||
var (
|
||||
DefaultRefreshRate = DEFAULT_REFRESH_RATE
|
||||
BarStart, BarEnd, Empty, Current, CurrentN string
|
||||
)
|
||||
|
||||
// Create new progress bar object
|
||||
func New(total int) (pb *ProgressBar) {
|
||||
return New64(int64(total))
|
||||
}
|
||||
|
||||
// Create new progress bar object uding int64 as total
|
||||
func New64(total int64) (pb *ProgressBar) {
|
||||
pb = &ProgressBar{
|
||||
Total: total,
|
||||
RefreshRate: DEFAULT_REFRESH_RATE,
|
||||
ShowPercent: true,
|
||||
ShowCounters: true,
|
||||
ShowBar: true,
|
||||
ShowTimeLeft: true,
|
||||
ShowFinalTime: true,
|
||||
ManualUpdate: false,
|
||||
currentValue: -1,
|
||||
}
|
||||
pb.Format(FORMAT)
|
||||
return
|
||||
}
|
||||
|
||||
// Create new object and start
|
||||
func StartNew(total int) (pb *ProgressBar) {
|
||||
pb = New(total)
|
||||
pb.Start()
|
||||
return
|
||||
}
|
||||
|
||||
// Callback for custom output
|
||||
// For example:
|
||||
// bar.Callback = func(s string) {
|
||||
// mySuperPrint(s)
|
||||
// }
|
||||
//
|
||||
type Callback func(out string)
|
||||
|
||||
type ProgressBar struct {
|
||||
current int64 // current must be first member of struct (https://code.google.com/p/go/issues/detail?id=5278)
|
||||
|
||||
Total int64
|
||||
RefreshRate time.Duration
|
||||
ShowPercent, ShowCounters bool
|
||||
ShowSpeed, ShowTimeLeft, ShowBar bool
|
||||
ShowFinalTime bool
|
||||
Output io.Writer
|
||||
Callback Callback
|
||||
NotPrint bool
|
||||
Units int
|
||||
Width int
|
||||
ForceWidth bool
|
||||
ManualUpdate bool
|
||||
|
||||
isFinish bool
|
||||
startTime time.Time
|
||||
currentValue int64
|
||||
|
||||
prefix, postfix string
|
||||
|
||||
BarStart string
|
||||
BarEnd string
|
||||
Empty string
|
||||
Current string
|
||||
CurrentN string
|
||||
}
|
||||
|
||||
// Start print
|
||||
func (pb *ProgressBar) Start() {
|
||||
pb.startTime = time.Now()
|
||||
if pb.Total == 0 {
|
||||
pb.ShowBar = false
|
||||
pb.ShowTimeLeft = false
|
||||
pb.ShowPercent = false
|
||||
}
|
||||
if !pb.ManualUpdate {
|
||||
go pb.writer()
|
||||
}
|
||||
}
|
||||
|
||||
// Increment current value
|
||||
func (pb *ProgressBar) Increment() int {
|
||||
return pb.Add(1)
|
||||
}
|
||||
|
||||
// Set current value
|
||||
func (pb *ProgressBar) Set(current int) {
|
||||
atomic.StoreInt64(&pb.current, int64(current))
|
||||
}
|
||||
|
||||
// Add to current value
|
||||
func (pb *ProgressBar) Add(add int) int {
|
||||
return int(pb.Add64(int64(add)))
|
||||
}
|
||||
|
||||
func (pb *ProgressBar) Add64(add int64) int64 {
|
||||
return atomic.AddInt64(&pb.current, add)
|
||||
}
|
||||
|
||||
// Set prefix string
|
||||
func (pb *ProgressBar) Prefix(prefix string) (bar *ProgressBar) {
|
||||
pb.prefix = prefix
|
||||
return pb
|
||||
}
|
||||
|
||||
// Set postfix string
|
||||
func (pb *ProgressBar) Postfix(postfix string) (bar *ProgressBar) {
|
||||
pb.postfix = postfix
|
||||
return pb
|
||||
}
|
||||
|
||||
// Set custom format for bar
|
||||
// Example: bar.Format("[=>_]")
|
||||
func (pb *ProgressBar) Format(format string) (bar *ProgressBar) {
|
||||
bar = pb
|
||||
formatEntries := strings.Split(format, "")
|
||||
if len(formatEntries) != 5 {
|
||||
return
|
||||
}
|
||||
pb.BarStart = formatEntries[0]
|
||||
pb.BarEnd = formatEntries[4]
|
||||
pb.Empty = formatEntries[3]
|
||||
pb.Current = formatEntries[1]
|
||||
pb.CurrentN = formatEntries[2]
|
||||
return
|
||||
}
|
||||
|
||||
// Set bar refresh rate
|
||||
func (pb *ProgressBar) SetRefreshRate(rate time.Duration) (bar *ProgressBar) {
|
||||
bar = pb
|
||||
pb.RefreshRate = rate
|
||||
return
|
||||
}
|
||||
|
||||
// Set units
|
||||
// bar.SetUnits(U_NO) - by default
|
||||
// bar.SetUnits(U_BYTES) - for Mb, Kb, etc
|
||||
func (pb *ProgressBar) SetUnits(units int) (bar *ProgressBar) {
|
||||
bar = pb
|
||||
switch units {
|
||||
case U_NO, U_BYTES:
|
||||
pb.Units = units
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Set max width, if width is bigger than terminal width, will be ignored
|
||||
func (pb *ProgressBar) SetMaxWidth(width int) (bar *ProgressBar) {
|
||||
bar = pb
|
||||
pb.Width = width
|
||||
pb.ForceWidth = false
|
||||
return
|
||||
}
|
||||
|
||||
// Set bar width
|
||||
func (pb *ProgressBar) SetWidth(width int) (bar *ProgressBar) {
|
||||
bar = pb
|
||||
pb.Width = width
|
||||
pb.ForceWidth = true
|
||||
return
|
||||
}
|
||||
|
||||
// End print
|
||||
func (pb *ProgressBar) Finish() {
|
||||
pb.isFinish = true
|
||||
pb.write(atomic.LoadInt64(&pb.current))
|
||||
if !pb.NotPrint {
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
// End print and write string 'str'
|
||||
func (pb *ProgressBar) FinishPrint(str string) {
|
||||
pb.Finish()
|
||||
fmt.Println(str)
|
||||
}
|
||||
|
||||
// implement io.Writer
|
||||
func (pb *ProgressBar) Write(p []byte) (n int, err error) {
|
||||
n = len(p)
|
||||
pb.Add(n)
|
||||
return
|
||||
}
|
||||
|
||||
// implement io.Reader
|
||||
func (pb *ProgressBar) Read(p []byte) (n int, err error) {
|
||||
n = len(p)
|
||||
pb.Add(n)
|
||||
return
|
||||
}
|
||||
|
||||
// Create new proxy reader over bar
|
||||
func (pb *ProgressBar) NewProxyReader(r io.Reader) *Reader {
|
||||
return &Reader{r, pb}
|
||||
}
|
||||
|
||||
func (pb *ProgressBar) write(current int64) {
|
||||
width := pb.getWidth()
|
||||
|
||||
var percentBox, countersBox, timeLeftBox, speedBox, barBox, end, out string
|
||||
|
||||
// percents
|
||||
if pb.ShowPercent {
|
||||
percent := float64(current) / (float64(pb.Total) / float64(100))
|
||||
percentBox = fmt.Sprintf(" %#.02f %% ", percent)
|
||||
}
|
||||
|
||||
// counters
|
||||
if pb.ShowCounters {
|
||||
if pb.Total > 0 {
|
||||
countersBox = fmt.Sprintf("%s / %s ", Format(current, pb.Units), Format(pb.Total, pb.Units))
|
||||
} else {
|
||||
countersBox = Format(current, pb.Units) + " "
|
||||
}
|
||||
}
|
||||
|
||||
// time left
|
||||
fromStart := time.Now().Sub(pb.startTime)
|
||||
if pb.isFinish {
|
||||
if pb.ShowFinalTime {
|
||||
left := (fromStart / time.Second) * time.Second
|
||||
timeLeftBox = left.String()
|
||||
}
|
||||
} else if pb.ShowTimeLeft && current > 0 {
|
||||
perEntry := fromStart / time.Duration(current)
|
||||
left := time.Duration(pb.Total-current) * perEntry
|
||||
left = (left / time.Second) * time.Second
|
||||
timeLeftBox = left.String()
|
||||
}
|
||||
|
||||
// speed
|
||||
if pb.ShowSpeed && current > 0 {
|
||||
fromStart := time.Now().Sub(pb.startTime)
|
||||
speed := float64(current) / (float64(fromStart) / float64(time.Second))
|
||||
speedBox = Format(int64(speed), pb.Units) + "/s "
|
||||
}
|
||||
|
||||
// bar
|
||||
if pb.ShowBar {
|
||||
size := width - len(countersBox+pb.BarStart+pb.BarEnd+percentBox+timeLeftBox+speedBox+pb.prefix+pb.postfix)
|
||||
if size > 0 {
|
||||
curCount := int(math.Ceil((float64(current) / float64(pb.Total)) * float64(size)))
|
||||
emptCount := size - curCount
|
||||
barBox = pb.BarStart
|
||||
if emptCount < 0 {
|
||||
emptCount = 0
|
||||
}
|
||||
if curCount > size {
|
||||
curCount = size
|
||||
}
|
||||
if emptCount <= 0 {
|
||||
barBox += strings.Repeat(pb.Current, curCount)
|
||||
} else if curCount > 0 {
|
||||
barBox += strings.Repeat(pb.Current, curCount-1) + pb.CurrentN
|
||||
}
|
||||
|
||||
barBox += strings.Repeat(pb.Empty, emptCount) + pb.BarEnd
|
||||
}
|
||||
}
|
||||
|
||||
// check len
|
||||
out = pb.prefix + countersBox + barBox + percentBox + speedBox + timeLeftBox + pb.postfix
|
||||
if len(out) < width {
|
||||
end = strings.Repeat(" ", width-len(out))
|
||||
}
|
||||
|
||||
// and print!
|
||||
switch {
|
||||
case pb.Output != nil:
|
||||
fmt.Fprint(pb.Output, "\r"+out+end)
|
||||
case pb.Callback != nil:
|
||||
pb.Callback(out + end)
|
||||
case !pb.NotPrint:
|
||||
fmt.Print("\r" + out + end)
|
||||
}
|
||||
}
|
||||
|
||||
func (pb *ProgressBar) getWidth() int {
|
||||
if pb.ForceWidth {
|
||||
return pb.Width
|
||||
}
|
||||
|
||||
width := pb.Width
|
||||
termWidth, _ := terminalWidth()
|
||||
if width == 0 || termWidth <= width {
|
||||
width = termWidth
|
||||
}
|
||||
|
||||
return width
|
||||
}
|
||||
|
||||
// Write the current state of the progressbar
|
||||
func (pb *ProgressBar) Update() {
|
||||
c := atomic.LoadInt64(&pb.current)
|
||||
if c != pb.currentValue {
|
||||
pb.write(c)
|
||||
pb.currentValue = c
|
||||
}
|
||||
}
|
||||
|
||||
// Internal loop for writing progressbar
|
||||
func (pb *ProgressBar) writer() {
|
||||
for {
|
||||
if pb.isFinish {
|
||||
break
|
||||
}
|
||||
pb.Update()
|
||||
time.Sleep(pb.RefreshRate)
|
||||
}
|
||||
}
|
||||
|
||||
type window struct {
|
||||
Row uint16
|
||||
Col uint16
|
||||
Xpixel uint16
|
||||
Ypixel uint16
|
||||
}
|
||||
7
Godeps/_workspace/src/github.com/cheggaaa/pb/pb_nix.go
generated
vendored
Normal file
7
Godeps/_workspace/src/github.com/cheggaaa/pb/pb_nix.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
// +build linux darwin freebsd openbsd
|
||||
|
||||
package pb
|
||||
|
||||
import "syscall"
|
||||
|
||||
const sys_ioctl = syscall.SYS_IOCTL
|
||||
5
Godeps/_workspace/src/github.com/cheggaaa/pb/pb_solaris.go
generated
vendored
Normal file
5
Godeps/_workspace/src/github.com/cheggaaa/pb/pb_solaris.go
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
// +build solaris
|
||||
|
||||
package pb
|
||||
|
||||
const sys_ioctl = 54
|
||||
30
Godeps/_workspace/src/github.com/cheggaaa/pb/pb_test.go
generated
vendored
Normal file
30
Godeps/_workspace/src/github.com/cheggaaa/pb/pb_test.go
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
package pb
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_IncrementAddsOne(t *testing.T) {
|
||||
count := 5000
|
||||
bar := New(count)
|
||||
expected := 1
|
||||
actual := bar.Increment()
|
||||
|
||||
if actual != expected {
|
||||
t.Errorf("Expected {%d} was {%d}", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Width(t *testing.T) {
|
||||
count := 5000
|
||||
bar := New(count)
|
||||
width := 100
|
||||
bar.SetWidth(100).Callback = func(out string) {
|
||||
if len(out) != width {
|
||||
t.Errorf("Bar width expected {%d} was {%d}", len(out), width)
|
||||
}
|
||||
}
|
||||
bar.Start()
|
||||
bar.Increment()
|
||||
bar.Finish()
|
||||
}
|
||||
16
Godeps/_workspace/src/github.com/cheggaaa/pb/pb_win.go
generated
vendored
Normal file
16
Godeps/_workspace/src/github.com/cheggaaa/pb/pb_win.go
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
// +build windows
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
"github.com/olekukonko/ts"
|
||||
)
|
||||
|
||||
func bold(str string) string {
|
||||
return str
|
||||
}
|
||||
|
||||
func terminalWidth() (int, error) {
|
||||
size, err := ts.GetSize()
|
||||
return size.Col(), err
|
||||
}
|
||||
46
Godeps/_workspace/src/github.com/cheggaaa/pb/pb_x.go
generated
vendored
Normal file
46
Godeps/_workspace/src/github.com/cheggaaa/pb/pb_x.go
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
// +build linux darwin freebsd openbsd solaris
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
TIOCGWINSZ = 0x5413
|
||||
TIOCGWINSZ_OSX = 1074295912
|
||||
)
|
||||
|
||||
var tty *os.File
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
tty, err = os.Open("/dev/tty")
|
||||
if err != nil {
|
||||
tty = os.Stdin
|
||||
}
|
||||
}
|
||||
|
||||
func bold(str string) string {
|
||||
return "\033[1m" + str + "\033[0m"
|
||||
}
|
||||
|
||||
func terminalWidth() (int, error) {
|
||||
w := new(window)
|
||||
tio := syscall.TIOCGWINSZ
|
||||
if runtime.GOOS == "darwin" {
|
||||
tio = TIOCGWINSZ_OSX
|
||||
}
|
||||
res, _, err := syscall.Syscall(sys_ioctl,
|
||||
tty.Fd(),
|
||||
uintptr(tio),
|
||||
uintptr(unsafe.Pointer(w)),
|
||||
)
|
||||
if int(res) == -1 {
|
||||
return 0, err
|
||||
}
|
||||
return int(w.Col), nil
|
||||
}
|
||||
17
Godeps/_workspace/src/github.com/cheggaaa/pb/reader.go
generated
vendored
Normal file
17
Godeps/_workspace/src/github.com/cheggaaa/pb/reader.go
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
package pb
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// It's proxy reader, implement io.Reader
|
||||
type Reader struct {
|
||||
io.Reader
|
||||
bar *ProgressBar
|
||||
}
|
||||
|
||||
func (r *Reader) Read(p []byte) (n int, err error) {
|
||||
n, err = r.Reader.Read(p)
|
||||
r.bar.Add(n)
|
||||
return
|
||||
}
|
||||
@ -47,13 +47,14 @@ the daemon.
|
||||
Run: daemonFunc,
|
||||
}
|
||||
|
||||
func daemonFunc(req cmds.Request) (interface{}, error) {
|
||||
func daemonFunc(req cmds.Request, res cmds.Response) {
|
||||
|
||||
// first, whether user has provided the initialization flag. we may be
|
||||
// running in an uninitialized state.
|
||||
initialize, _, err := req.Option(initOptionKwd).Bool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
if initialize {
|
||||
|
||||
@ -64,7 +65,8 @@ func daemonFunc(req cmds.Request) (interface{}, error) {
|
||||
if !util.FileExists(req.Context().ConfigRoot) {
|
||||
err := initWithDefaults(req.Context().ConfigRoot)
|
||||
if err != nil {
|
||||
return nil, debugerror.Wrap(err)
|
||||
res.SetError(debugerror.Wrap(err), cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -77,14 +79,16 @@ func daemonFunc(req cmds.Request) (interface{}, error) {
|
||||
ctx := req.Context()
|
||||
cfg, err := ctx.GetConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
// acquire the repo lock _before_ constructing a node. we need to make
|
||||
// sure we are permitted to access the resources (datastore, etc.)
|
||||
repo := fsrepo.At(req.Context().ConfigRoot)
|
||||
if err := repo.Open(); err != nil {
|
||||
return nil, debugerror.Errorf("Couldn't obtain lock. Is another daemon already running?")
|
||||
res.SetError(debugerror.Errorf("Couldn't obtain lock. Is another daemon already running?"), cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
defer repo.Close()
|
||||
|
||||
@ -93,13 +97,15 @@ func daemonFunc(req cmds.Request) (interface{}, error) {
|
||||
ctx.Online = true
|
||||
node, err := ctx.GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
// verify api address is valid multiaddr
|
||||
apiMaddr, err := ma.NewMultiaddr(cfg.Addresses.API)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
var gatewayMaddr ma.Multiaddr
|
||||
@ -115,12 +121,14 @@ func daemonFunc(req cmds.Request) (interface{}, error) {
|
||||
// mount if the user provided the --mount flag
|
||||
mount, _, err := req.Option(mountKwd).Bool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
if mount {
|
||||
fsdir, found, err := req.Option(ipfsMountKwd).String()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
if !found {
|
||||
fsdir = cfg.Mounts.IPFS
|
||||
@ -128,7 +136,8 @@ func daemonFunc(req cmds.Request) (interface{}, error) {
|
||||
|
||||
nsdir, found, err := req.Option(ipnsMountKwd).String()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
if !found {
|
||||
nsdir = cfg.Mounts.IPNS
|
||||
@ -136,7 +145,8 @@ func daemonFunc(req cmds.Request) (interface{}, error) {
|
||||
|
||||
err = commands.Mount(node, fsdir, nsdir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
fmt.Printf("IPFS mounted at: %s\n", fsdir)
|
||||
fmt.Printf("IPNS mounted at: %s\n", nsdir)
|
||||
@ -156,5 +166,9 @@ func daemonFunc(req cmds.Request) (interface{}, error) {
|
||||
corehttp.WebUIOption,
|
||||
corehttp.GatewayOption,
|
||||
}
|
||||
return nil, corehttp.ListenAndServe(node, apiMaddr, opts...)
|
||||
err = corehttp.ListenAndServe(node, apiMaddr, opts...)
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,22 +39,29 @@ var initCmd = &cmds.Command{
|
||||
// name of the file?
|
||||
// TODO cmds.StringOption("event-logs", "l", "Location for machine-readable event logs"),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
|
||||
force, _, err := req.Option("f").Bool() // if !found, it's okay force == false
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
nBitsForKeypair, bitsOptFound, err := req.Option("b").Int()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
if !bitsOptFound {
|
||||
nBitsForKeypair = nBitsForKeypairDefault
|
||||
}
|
||||
|
||||
return doInit(req.Context().ConfigRoot, force, nBitsForKeypair)
|
||||
output, err := doInit(req.Context().ConfigRoot, force, nBitsForKeypair)
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
res.SetOutput(output)
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -158,7 +158,7 @@ func (i *cmdInvocation) Run(ctx context.Context) (output io.Reader, err error) {
|
||||
defer stopProfilingFunc() // to be executed as late as possible
|
||||
}
|
||||
|
||||
res, err := callCommand(ctx, i.req, Root)
|
||||
res, err := callCommand(ctx, i.req, Root, i.cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -296,7 +296,7 @@ func callPreCommandHooks(ctx context.Context, details cmdDetails, req cmds.Reque
|
||||
return nil
|
||||
}
|
||||
|
||||
func callCommand(ctx context.Context, req cmds.Request, root *cmds.Command) (cmds.Response, error) {
|
||||
func callCommand(ctx context.Context, req cmds.Request, root *cmds.Command, cmd *cmds.Command) (cmds.Response, error) {
|
||||
var res cmds.Response
|
||||
|
||||
details, err := commandDetails(req.Path(), root)
|
||||
@ -315,6 +315,13 @@ func callCommand(ctx context.Context, req cmds.Request, root *cmds.Command) (cmd
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cmd.PreRun != nil {
|
||||
err = cmd.PreRun(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if useDaemon {
|
||||
|
||||
cfg, err := req.Context().GetConfig()
|
||||
@ -347,6 +354,11 @@ func callCommand(ctx context.Context, req cmds.Request, root *cmds.Command) (cmd
|
||||
res = root.Call(req)
|
||||
|
||||
}
|
||||
|
||||
if cmd.PostRun != nil {
|
||||
cmd.PostRun(req, res)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
|
||||
@ -36,11 +36,12 @@ IPFS very quickly. To start, run:
|
||||
Run: tourRunFunc,
|
||||
}
|
||||
|
||||
func tourRunFunc(req cmds.Request) (interface{}, error) {
|
||||
func tourRunFunc(req cmds.Request, res cmds.Response) {
|
||||
|
||||
cfg, err := req.Context().GetConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
id := tour.TopicID(cfg.Tour.Last)
|
||||
@ -64,11 +65,10 @@ func tourRunFunc(req cmds.Request) (interface{}, error) {
|
||||
fmt.Fprintln(&w, "")
|
||||
fprintTourList(&w, tour.TopicID(cfg.Tour.Last))
|
||||
|
||||
return nil, nil
|
||||
return
|
||||
}
|
||||
|
||||
fprintTourShow(&w, t)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var cmdIpfsTourNext = &cmds.Command{
|
||||
@ -76,21 +76,24 @@ var cmdIpfsTourNext = &cmds.Command{
|
||||
Tagline: "Show the next IPFS Tour topic",
|
||||
},
|
||||
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
var w bytes.Buffer
|
||||
path := req.Context().ConfigRoot
|
||||
cfg, err := req.Context().GetConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
id := tour.NextTopic(tour.TopicID(cfg.Tour.Last))
|
||||
topic, err := tourGet(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
if err := fprintTourShow(&w, topic); err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
// topic changed, not last. write it out.
|
||||
@ -98,12 +101,12 @@ var cmdIpfsTourNext = &cmds.Command{
|
||||
cfg.Tour.Last = string(id)
|
||||
err := writeConfig(path, cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
w.WriteTo(os.Stdout)
|
||||
return nil, nil
|
||||
},
|
||||
}
|
||||
|
||||
@ -112,19 +115,20 @@ var cmdIpfsTourRestart = &cmds.Command{
|
||||
Tagline: "Restart the IPFS Tour",
|
||||
},
|
||||
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
path := req.Context().ConfigRoot
|
||||
cfg, err := req.Context().GetConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
cfg.Tour.Last = ""
|
||||
err = writeConfig(path, cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
return nil, nil
|
||||
},
|
||||
}
|
||||
|
||||
@ -133,16 +137,16 @@ var cmdIpfsTourList = &cmds.Command{
|
||||
Tagline: "Show a list of IPFS Tour topics",
|
||||
},
|
||||
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
cfg, err := req.Context().GetConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
var w bytes.Buffer
|
||||
fprintTourList(&w, tour.TopicID(cfg.Tour.Last))
|
||||
w.WriteTo(os.Stdout)
|
||||
return nil, nil
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -64,7 +64,7 @@ func Parse(input []string, stdin *os.File, root *cmds.Command) (cmds.Request, *c
|
||||
}
|
||||
req.SetArguments(stringArgs)
|
||||
|
||||
file := &files.SliceFile{"", fileArgs}
|
||||
file := files.NewSliceFile("", fileArgs)
|
||||
req.SetFiles(file)
|
||||
|
||||
err = cmd.CheckArguments(req)
|
||||
@ -298,7 +298,7 @@ func appendFile(args []files.File, inputs []string, argDef *cmds.Argument, recur
|
||||
}
|
||||
|
||||
func appendStdinAsFile(args []files.File, stdin *os.File) ([]files.File, *os.File) {
|
||||
arg := &files.ReaderFile{"", stdin}
|
||||
arg := files.NewReaderFile("", stdin, nil)
|
||||
return append(args, arg), nil
|
||||
}
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ var log = u.Logger("command")
|
||||
|
||||
// Function is the type of function that Commands use.
|
||||
// It reads from the Request, and writes results to the Response.
|
||||
type Function func(Request) (interface{}, error)
|
||||
type Function func(Request, Response)
|
||||
|
||||
// Marshaler is a function that takes in a Response, and returns an io.Reader
|
||||
// (or an error on failure)
|
||||
@ -40,18 +40,14 @@ type HelpText struct {
|
||||
Subcommands string // overrides SUBCOMMANDS section
|
||||
}
|
||||
|
||||
// TODO: check Argument definitions when creating a Command
|
||||
// (might need to use a Command constructor)
|
||||
// * make sure any variadic args are at the end
|
||||
// * make sure there aren't duplicate names
|
||||
// * make sure optional arguments aren't followed by required arguments
|
||||
|
||||
// Command is a runnable command, with input arguments and options (flags).
|
||||
// It can also have Subcommands, to group units of work into sets.
|
||||
type Command struct {
|
||||
Options []Option
|
||||
Arguments []Argument
|
||||
PreRun func(req Request) error
|
||||
Run Function
|
||||
PostRun Function
|
||||
Marshalers map[EncodingType]Marshaler
|
||||
Helptext HelpText
|
||||
|
||||
@ -99,21 +95,12 @@ func (c *Command) Call(req Request) Response {
|
||||
return res
|
||||
}
|
||||
|
||||
output, err := cmd.Run(req)
|
||||
if err != nil {
|
||||
// if returned error is a commands.Error, use its error code
|
||||
// otherwise, just default the code to ErrNormal
|
||||
switch e := err.(type) {
|
||||
case *Error:
|
||||
res.SetError(e, e.Code)
|
||||
case Error:
|
||||
res.SetError(e, e.Code)
|
||||
default:
|
||||
res.SetError(err, ErrNormal)
|
||||
}
|
||||
cmd.Run(req, res)
|
||||
if res.Error() != nil {
|
||||
return res
|
||||
}
|
||||
|
||||
output := res.Output()
|
||||
isChan := false
|
||||
actualType := reflect.TypeOf(output)
|
||||
if actualType != nil {
|
||||
@ -144,7 +131,6 @@ func (c *Command) Call(req Request) Response {
|
||||
}
|
||||
}
|
||||
|
||||
res.SetOutput(output)
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
@ -2,8 +2,8 @@ package commands
|
||||
|
||||
import "testing"
|
||||
|
||||
func noop(req Request) (interface{}, error) {
|
||||
return nil, nil
|
||||
func noop(req Request, res Response) {
|
||||
return
|
||||
}
|
||||
|
||||
func TestOptionValidation(t *testing.T) {
|
||||
|
||||
@ -3,6 +3,7 @@ package files
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -29,3 +30,22 @@ type File interface {
|
||||
// If the file is a regular file (not a directory), NextFile will return a non-nil error.
|
||||
NextFile() (File, error)
|
||||
}
|
||||
|
||||
type StatFile interface {
|
||||
File
|
||||
|
||||
Stat() os.FileInfo
|
||||
}
|
||||
|
||||
type PeekFile interface {
|
||||
SizeFile
|
||||
|
||||
Peek(n int) File
|
||||
Length() int
|
||||
}
|
||||
|
||||
type SizeFile interface {
|
||||
File
|
||||
|
||||
Size() (int64, error)
|
||||
}
|
||||
|
||||
@ -11,13 +11,13 @@ import (
|
||||
func TestSliceFiles(t *testing.T) {
|
||||
name := "testname"
|
||||
files := []File{
|
||||
&ReaderFile{"file.txt", ioutil.NopCloser(strings.NewReader("Some text!\n"))},
|
||||
&ReaderFile{"beep.txt", ioutil.NopCloser(strings.NewReader("beep"))},
|
||||
&ReaderFile{"boop.txt", ioutil.NopCloser(strings.NewReader("boop"))},
|
||||
NewReaderFile("file.txt", ioutil.NopCloser(strings.NewReader("Some text!\n")), nil),
|
||||
NewReaderFile("beep.txt", ioutil.NopCloser(strings.NewReader("beep")), nil),
|
||||
NewReaderFile("boop.txt", ioutil.NopCloser(strings.NewReader("boop")), nil),
|
||||
}
|
||||
buf := make([]byte, 20)
|
||||
|
||||
sf := &SliceFile{name, files}
|
||||
sf := NewSliceFile(name, files)
|
||||
|
||||
if !sf.IsDirectory() {
|
||||
t.Error("SliceFile should always be a directory")
|
||||
@ -55,7 +55,7 @@ func TestSliceFiles(t *testing.T) {
|
||||
|
||||
func TestReaderFiles(t *testing.T) {
|
||||
message := "beep boop"
|
||||
rf := &ReaderFile{"file.txt", ioutil.NopCloser(strings.NewReader(message))}
|
||||
rf := NewReaderFile("file.txt", ioutil.NopCloser(strings.NewReader(message)), nil)
|
||||
buf := make([]byte, len(message))
|
||||
|
||||
if rf.IsDirectory() {
|
||||
|
||||
@ -1,12 +1,21 @@
|
||||
package files
|
||||
|
||||
import "io"
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// ReaderFile is a implementation of File created from an `io.Reader`.
|
||||
// ReaderFiles are never directories, and can be read from and closed.
|
||||
type ReaderFile struct {
|
||||
Filename string
|
||||
Reader io.ReadCloser
|
||||
filename string
|
||||
reader io.ReadCloser
|
||||
stat os.FileInfo
|
||||
}
|
||||
|
||||
func NewReaderFile(filename string, reader io.ReadCloser, stat os.FileInfo) *ReaderFile {
|
||||
return &ReaderFile{filename, reader, stat}
|
||||
}
|
||||
|
||||
func (f *ReaderFile) IsDirectory() bool {
|
||||
@ -18,13 +27,24 @@ func (f *ReaderFile) NextFile() (File, error) {
|
||||
}
|
||||
|
||||
func (f *ReaderFile) FileName() string {
|
||||
return f.Filename
|
||||
return f.filename
|
||||
}
|
||||
|
||||
func (f *ReaderFile) Read(p []byte) (int, error) {
|
||||
return f.Reader.Read(p)
|
||||
return f.reader.Read(p)
|
||||
}
|
||||
|
||||
func (f *ReaderFile) Close() error {
|
||||
return f.Reader.Close()
|
||||
return f.reader.Close()
|
||||
}
|
||||
|
||||
func (f *ReaderFile) Stat() os.FileInfo {
|
||||
return f.stat
|
||||
}
|
||||
|
||||
func (f *ReaderFile) Size() (int64, error) {
|
||||
if f.stat == nil {
|
||||
return 0, errors.New("File size unknown")
|
||||
}
|
||||
return f.stat.Size(), nil
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@ func (es sortFIByName) Less(i, j int) bool { return es[i].Name() < es[j].Name()
|
||||
type serialFile struct {
|
||||
path string
|
||||
files []os.FileInfo
|
||||
stat os.FileInfo
|
||||
current *os.File
|
||||
}
|
||||
|
||||
@ -35,7 +36,7 @@ func NewSerialFile(path string, file *os.File) (File, error) {
|
||||
func newSerialFile(path string, file *os.File, stat os.FileInfo) (File, error) {
|
||||
// for non-directories, return a ReaderFile
|
||||
if !stat.IsDir() {
|
||||
return &ReaderFile{path, file}, nil
|
||||
return &ReaderFile{path, file, stat}, nil
|
||||
}
|
||||
|
||||
// for directories, stat all of the contents first, so we know what files to
|
||||
@ -55,7 +56,7 @@ func newSerialFile(path string, file *os.File, stat os.FileInfo) (File, error) {
|
||||
// make sure contents are sorted so -- repeatably -- we get the same inputs.
|
||||
sort.Sort(sortFIByName(contents))
|
||||
|
||||
return &serialFile{path, contents, nil}, nil
|
||||
return &serialFile{path, contents, stat, nil}, nil
|
||||
}
|
||||
|
||||
func (f *serialFile) IsDirectory() bool {
|
||||
@ -113,3 +114,37 @@ func (f *serialFile) Close() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *serialFile) Stat() os.FileInfo {
|
||||
return f.stat
|
||||
}
|
||||
|
||||
func (f *serialFile) Size() (int64, error) {
|
||||
return size(f.stat, f.FileName())
|
||||
}
|
||||
|
||||
func size(stat os.FileInfo, filename string) (int64, error) {
|
||||
if !stat.IsDir() {
|
||||
return stat.Size(), nil
|
||||
}
|
||||
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
files, err := file.Readdir(0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
file.Close()
|
||||
|
||||
var output int64
|
||||
for _, child := range files {
|
||||
s, err := size(child, fp.Join(filename, child.Name()))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
output += s
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
@ -1,13 +1,21 @@
|
||||
package files
|
||||
|
||||
import "io"
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
// SliceFile implements File, and provides simple directory handling.
|
||||
// It contains children files, and is created from a `[]File`.
|
||||
// SliceFiles are always directories, and can't be read from or closed.
|
||||
type SliceFile struct {
|
||||
Filename string
|
||||
Files []File
|
||||
filename string
|
||||
files []File
|
||||
n int
|
||||
}
|
||||
|
||||
func NewSliceFile(filename string, files []File) *SliceFile {
|
||||
return &SliceFile{filename, files, 0}
|
||||
}
|
||||
|
||||
func (f *SliceFile) IsDirectory() bool {
|
||||
@ -15,16 +23,16 @@ func (f *SliceFile) IsDirectory() bool {
|
||||
}
|
||||
|
||||
func (f *SliceFile) NextFile() (File, error) {
|
||||
if len(f.Files) == 0 {
|
||||
if f.n >= len(f.files) {
|
||||
return nil, io.EOF
|
||||
}
|
||||
file := f.Files[0]
|
||||
f.Files = f.Files[1:]
|
||||
file := f.files[f.n]
|
||||
f.n++
|
||||
return file, nil
|
||||
}
|
||||
|
||||
func (f *SliceFile) FileName() string {
|
||||
return f.Filename
|
||||
return f.filename
|
||||
}
|
||||
|
||||
func (f *SliceFile) Read(p []byte) (int, error) {
|
||||
@ -34,3 +42,30 @@ func (f *SliceFile) Read(p []byte) (int, error) {
|
||||
func (f *SliceFile) Close() error {
|
||||
return ErrNotReader
|
||||
}
|
||||
|
||||
func (f *SliceFile) Peek(n int) File {
|
||||
return f.files[n]
|
||||
}
|
||||
|
||||
func (f *SliceFile) Length() int {
|
||||
return len(f.files)
|
||||
}
|
||||
|
||||
func (f *SliceFile) Size() (int64, error) {
|
||||
var size int64
|
||||
|
||||
for _, file := range f.files {
|
||||
sizeFile, ok := file.(SizeFile)
|
||||
if !ok {
|
||||
return 0, errors.New("Could not get size of child file")
|
||||
}
|
||||
|
||||
s, err := sizeFile.Size()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
size += s
|
||||
}
|
||||
|
||||
return size, nil
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
cmds "github.com/jbenet/go-ipfs/commands"
|
||||
@ -137,9 +138,18 @@ func getResponse(httpRes *http.Response, req cmds.Request) (cmds.Response, error
|
||||
var err error
|
||||
res := cmds.NewResponse(req)
|
||||
|
||||
contentType := httpRes.Header["Content-Type"][0]
|
||||
contentType := httpRes.Header.Get(contentTypeHeader)
|
||||
contentType = strings.Split(contentType, ";")[0]
|
||||
|
||||
lengthHeader := httpRes.Header.Get(contentLengthHeader)
|
||||
if len(lengthHeader) > 0 {
|
||||
length, err := strconv.ParseUint(lengthHeader, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res.SetLength(length)
|
||||
}
|
||||
|
||||
if len(httpRes.Header.Get(streamHeader)) > 0 {
|
||||
// if output is a stream, we can just use the body reader
|
||||
res.SetOutput(httpRes.Body)
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
|
||||
|
||||
@ -92,6 +93,11 @@ func (i Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set(contentTypeHeader, mime)
|
||||
}
|
||||
|
||||
// set the Content-Length from the response length
|
||||
if res.Length() > 0 {
|
||||
w.Header().Set(contentLengthHeader, strconv.FormatUint(res.Length(), 10))
|
||||
}
|
||||
|
||||
// if response contains an error, write an HTTP error status code
|
||||
if e := res.Error(); e != nil {
|
||||
if e.Code == cmds.ErrClient {
|
||||
|
||||
@ -13,14 +13,14 @@ import (
|
||||
func TestOutput(t *testing.T) {
|
||||
text := "Some text! :)"
|
||||
fileset := []files.File{
|
||||
&files.ReaderFile{"file.txt", ioutil.NopCloser(strings.NewReader(text))},
|
||||
&files.SliceFile{"boop", []files.File{
|
||||
&files.ReaderFile{"boop/a.txt", ioutil.NopCloser(strings.NewReader("bleep"))},
|
||||
&files.ReaderFile{"boop/b.txt", ioutil.NopCloser(strings.NewReader("bloop"))},
|
||||
}},
|
||||
&files.ReaderFile{"beep.txt", ioutil.NopCloser(strings.NewReader("beep"))},
|
||||
files.NewReaderFile("file.txt", ioutil.NopCloser(strings.NewReader(text)), nil),
|
||||
files.NewSliceFile("boop", []files.File{
|
||||
files.NewReaderFile("boop/a.txt", ioutil.NopCloser(strings.NewReader("bleep")), nil),
|
||||
files.NewReaderFile("boop/b.txt", ioutil.NopCloser(strings.NewReader("bloop")), nil),
|
||||
}),
|
||||
files.NewReaderFile("beep.txt", ioutil.NopCloser(strings.NewReader("beep")), nil),
|
||||
}
|
||||
sf := &files.SliceFile{"", fileset}
|
||||
sf := files.NewSliceFile("", fileset)
|
||||
buf := make([]byte, 20)
|
||||
|
||||
// testing output by reading it with the go stdlib "mime/multipart" Reader
|
||||
|
||||
@ -3,6 +3,8 @@ package commands
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
@ -77,6 +79,8 @@ type Request interface {
|
||||
Context() *Context
|
||||
SetContext(Context)
|
||||
Command() *Command
|
||||
Values() map[string]interface{}
|
||||
Stdin() io.Reader
|
||||
|
||||
ConvertOptions() error
|
||||
}
|
||||
@ -89,6 +93,8 @@ type request struct {
|
||||
cmd *Command
|
||||
ctx Context
|
||||
optionDefs map[string]Option
|
||||
values map[string]interface{}
|
||||
stdin io.Reader
|
||||
}
|
||||
|
||||
// Path returns the command path of this request
|
||||
@ -208,6 +214,14 @@ var converters = map[reflect.Kind]converter{
|
||||
},
|
||||
}
|
||||
|
||||
func (r *request) Values() map[string]interface{} {
|
||||
return r.values
|
||||
}
|
||||
|
||||
func (r *request) Stdin() io.Reader {
|
||||
return r.stdin
|
||||
}
|
||||
|
||||
func (r *request) ConvertOptions() error {
|
||||
for k, v := range r.options {
|
||||
opt, ok := r.optionDefs[k]
|
||||
@ -275,7 +289,8 @@ func NewRequest(path []string, opts optMap, args []string, file files.File, cmd
|
||||
}
|
||||
|
||||
ctx := Context{Context: context.TODO()}
|
||||
req := &request{path, opts, args, file, cmd, ctx, optDefs}
|
||||
values := make(map[string]interface{})
|
||||
req := &request{path, opts, args, file, cmd, ctx, optDefs, values, os.Stdin}
|
||||
err := req.ConvertOptions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -95,19 +96,30 @@ type Response interface {
|
||||
SetOutput(interface{})
|
||||
Output() interface{}
|
||||
|
||||
// Sets/Returns the length of the output
|
||||
SetLength(uint64)
|
||||
Length() uint64
|
||||
|
||||
// Marshal marshals out the response into a buffer. It uses the EncodingType
|
||||
// on the Request to chose a Marshaler (Codec).
|
||||
Marshal() (io.Reader, error)
|
||||
|
||||
// Gets a io.Reader that reads the marshalled output
|
||||
Reader() (io.Reader, error)
|
||||
|
||||
// Gets Stdout and Stderr, for writing to console without using SetOutput
|
||||
Stdout() io.Writer
|
||||
Stderr() io.Writer
|
||||
}
|
||||
|
||||
type response struct {
|
||||
req Request
|
||||
err *Error
|
||||
value interface{}
|
||||
out io.Reader
|
||||
req Request
|
||||
err *Error
|
||||
value interface{}
|
||||
out io.Reader
|
||||
length uint64
|
||||
stdout io.Writer
|
||||
stderr io.Writer
|
||||
}
|
||||
|
||||
func (r *response) Request() Request {
|
||||
@ -122,6 +134,14 @@ func (r *response) SetOutput(v interface{}) {
|
||||
r.value = v
|
||||
}
|
||||
|
||||
func (r *response) Length() uint64 {
|
||||
return r.length
|
||||
}
|
||||
|
||||
func (r *response) SetLength(l uint64) {
|
||||
r.length = l
|
||||
}
|
||||
|
||||
func (r *response) Error() *Error {
|
||||
return r.err
|
||||
}
|
||||
@ -193,7 +213,19 @@ func (r *response) Reader() (io.Reader, error) {
|
||||
return r.out, nil
|
||||
}
|
||||
|
||||
func (r *response) Stdout() io.Writer {
|
||||
return r.stdout
|
||||
}
|
||||
|
||||
func (r *response) Stderr() io.Writer {
|
||||
return r.stderr
|
||||
}
|
||||
|
||||
// NewResponse returns a response to match given Request
|
||||
func NewResponse(req Request) Response {
|
||||
return &response{req: req}
|
||||
return &response{
|
||||
req: req,
|
||||
stdout: os.Stdout,
|
||||
stderr: os.Stderr,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
cmds "github.com/jbenet/go-ipfs/commands"
|
||||
files "github.com/jbenet/go-ipfs/commands/files"
|
||||
@ -16,14 +16,22 @@ import (
|
||||
pinning "github.com/jbenet/go-ipfs/pin"
|
||||
ft "github.com/jbenet/go-ipfs/unixfs"
|
||||
u "github.com/jbenet/go-ipfs/util"
|
||||
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/cheggaaa/pb"
|
||||
)
|
||||
|
||||
// Error indicating the max depth has been exceded.
|
||||
var ErrDepthLimitExceeded = fmt.Errorf("depth limit exceeded")
|
||||
|
||||
// how many bytes of progress to wait before sending a progress update message
|
||||
const progressReaderIncrement = 1024 * 256
|
||||
|
||||
const progressOptionName = "progress"
|
||||
|
||||
type AddedObject struct {
|
||||
Name string
|
||||
Hash string
|
||||
Name string
|
||||
Hash string `json:",omitempty"`
|
||||
Bytes int64 `json:",omitempty"`
|
||||
}
|
||||
|
||||
var AddCmd = &cmds.Command{
|
||||
@ -43,14 +51,42 @@ remains to be implemented.
|
||||
Options: []cmds.Option{
|
||||
cmds.OptionRecursivePath, // a builtin option that allows recursive paths (-r, --recursive)
|
||||
cmds.BoolOption("quiet", "q", "Write minimal output"),
|
||||
cmds.BoolOption(progressOptionName, "p", "Stream progress data"),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
PreRun: func(req cmds.Request) error {
|
||||
if quiet, _, _ := req.Option("quiet").Bool(); quiet {
|
||||
return nil
|
||||
}
|
||||
|
||||
req.SetOption(progressOptionName, true)
|
||||
|
||||
sizeFile, ok := req.Files().(files.SizeFile)
|
||||
if !ok {
|
||||
// we don't need to error, the progress bar just won't know how big the files are
|
||||
return nil
|
||||
}
|
||||
|
||||
size, err := sizeFile.Size()
|
||||
if err != nil {
|
||||
// see comment above
|
||||
return nil
|
||||
}
|
||||
log.Debugf("Total size of file being added: %v\n", size)
|
||||
req.Values()["size"] = size
|
||||
|
||||
return nil
|
||||
},
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
progress, _, _ := req.Option(progressOptionName).Bool()
|
||||
|
||||
outChan := make(chan interface{})
|
||||
res.SetOutput((<-chan interface{})(outChan))
|
||||
|
||||
go func() {
|
||||
defer close(outChan)
|
||||
@ -61,47 +97,92 @@ remains to be implemented.
|
||||
return
|
||||
}
|
||||
|
||||
_, err = addFile(n, file, outChan)
|
||||
_, err = addFile(n, file, outChan, progress)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return outChan, nil
|
||||
},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
cmds.Text: func(res cmds.Response) (io.Reader, error) {
|
||||
outChan, ok := res.Output().(<-chan interface{})
|
||||
if !ok {
|
||||
return nil, u.ErrCast()
|
||||
}
|
||||
PostRun: func(req cmds.Request, res cmds.Response) {
|
||||
outChan, ok := res.Output().(<-chan interface{})
|
||||
if !ok {
|
||||
res.SetError(u.ErrCast(), cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
res.SetOutput(nil)
|
||||
|
||||
quiet, _, err := res.Request().Option("quiet").Bool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
quiet, _, err := req.Option("quiet").Bool()
|
||||
if err != nil {
|
||||
res.SetError(u.ErrCast(), cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
marshal := func(v interface{}) (io.Reader, error) {
|
||||
obj, ok := v.(*AddedObject)
|
||||
if !ok {
|
||||
return nil, u.ErrCast()
|
||||
size := int64(0)
|
||||
s, found := req.Values()["size"]
|
||||
if found {
|
||||
size = s.(int64)
|
||||
}
|
||||
showProgressBar := !quiet && size >= progressBarMinSize
|
||||
|
||||
var bar *pb.ProgressBar
|
||||
var terminalWidth int
|
||||
if showProgressBar {
|
||||
bar = pb.New64(size).SetUnits(pb.U_BYTES)
|
||||
bar.ManualUpdate = true
|
||||
bar.Start()
|
||||
|
||||
// the progress bar lib doesn't give us a way to get the width of the output,
|
||||
// so as a hack we just use a callback to measure the output, then git rid of it
|
||||
terminalWidth = 0
|
||||
bar.Callback = func(line string) {
|
||||
terminalWidth = len(line)
|
||||
bar.Callback = nil
|
||||
bar.Output = res.Stderr()
|
||||
log.Infof("terminal width: %v\n", terminalWidth)
|
||||
}
|
||||
bar.Update()
|
||||
}
|
||||
|
||||
lastFile := ""
|
||||
var totalProgress, prevFiles, lastBytes int64
|
||||
|
||||
for out := range outChan {
|
||||
output := out.(*AddedObject)
|
||||
if len(output.Hash) > 0 {
|
||||
if showProgressBar {
|
||||
// clear progress bar line before we print "added x" output
|
||||
fmt.Fprintf(res.Stderr(), "\r%s\r", strings.Repeat(" ", terminalWidth))
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if quiet {
|
||||
buf.WriteString(fmt.Sprintf("%s\n", obj.Hash))
|
||||
fmt.Fprintf(res.Stdout(), "%s\n", output.Hash)
|
||||
} else {
|
||||
buf.WriteString(fmt.Sprintf("added %s %s\n", obj.Hash, obj.Name))
|
||||
fmt.Fprintf(res.Stdout(), "added %s %s\n", output.Hash, output.Name)
|
||||
}
|
||||
return &buf, nil
|
||||
|
||||
} else {
|
||||
log.Debugf("add progress: %v %v\n", output.Name, output.Bytes)
|
||||
|
||||
if !showProgressBar {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(lastFile) == 0 {
|
||||
lastFile = output.Name
|
||||
}
|
||||
if output.Name != lastFile || output.Bytes < lastBytes {
|
||||
prevFiles += lastBytes
|
||||
lastFile = output.Name
|
||||
}
|
||||
lastBytes = output.Bytes
|
||||
delta := prevFiles + lastBytes - totalProgress
|
||||
totalProgress = bar.Add64(delta)
|
||||
}
|
||||
|
||||
return &cmds.ChannelMarshaler{
|
||||
Channel: outChan,
|
||||
Marshaler: marshal,
|
||||
}, nil
|
||||
},
|
||||
if showProgressBar {
|
||||
bar.Update()
|
||||
}
|
||||
}
|
||||
},
|
||||
Type: AddedObject{},
|
||||
}
|
||||
@ -144,12 +225,19 @@ func addNode(n *core.IpfsNode, node *dag.Node) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func addFile(n *core.IpfsNode, file files.File, out chan interface{}) (*dag.Node, error) {
|
||||
func addFile(n *core.IpfsNode, file files.File, out chan interface{}, progress bool) (*dag.Node, error) {
|
||||
if file.IsDirectory() {
|
||||
return addDir(n, file, out)
|
||||
return addDir(n, file, out, progress)
|
||||
}
|
||||
|
||||
dns, err := add(n, []io.Reader{file})
|
||||
// if the progress flag was specified, wrap the file so that we can send
|
||||
// progress updates to the client (over the output channel)
|
||||
var reader io.Reader = file
|
||||
if progress {
|
||||
reader = &progressReader{file: file, out: out}
|
||||
}
|
||||
|
||||
dns, err := add(n, []io.Reader{reader})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -161,7 +249,7 @@ func addFile(n *core.IpfsNode, file files.File, out chan interface{}) (*dag.Node
|
||||
return dns[len(dns)-1], nil // last dag node is the file.
|
||||
}
|
||||
|
||||
func addDir(n *core.IpfsNode, dir files.File, out chan interface{}) (*dag.Node, error) {
|
||||
func addDir(n *core.IpfsNode, dir files.File, out chan interface{}, progress bool) (*dag.Node, error) {
|
||||
log.Infof("adding directory: %s", dir.FileName())
|
||||
|
||||
tree := &dag.Node{Data: ft.FolderPBData()}
|
||||
@ -175,7 +263,7 @@ func addDir(n *core.IpfsNode, dir files.File, out chan interface{}) (*dag.Node,
|
||||
break
|
||||
}
|
||||
|
||||
node, err := addFile(n, file, out)
|
||||
node, err := addFile(n, file, out, progress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -215,3 +303,25 @@ func outputDagnode(out chan interface{}, name string, dn *dag.Node) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type progressReader struct {
|
||||
file files.File
|
||||
out chan interface{}
|
||||
bytes int64
|
||||
lastProgress int64
|
||||
}
|
||||
|
||||
func (i *progressReader) Read(p []byte) (int, error) {
|
||||
n, err := i.file.Read(p)
|
||||
|
||||
i.bytes += int64(n)
|
||||
if i.bytes-i.lastProgress >= progressReaderIncrement || err == io.EOF {
|
||||
i.lastProgress = i.bytes
|
||||
i.out <- &AddedObject{
|
||||
Name: i.file.FileName(),
|
||||
Bytes: i.bytes,
|
||||
}
|
||||
}
|
||||
|
||||
return n, err
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ package commands
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@ -57,16 +58,17 @@ on raw ipfs blocks. It outputs the following to stdout:
|
||||
Arguments: []cmds.Argument{
|
||||
cmds.StringArg("key", true, false, "The base58 multihash of an existing block to get").EnableStdin(),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
b, err := getBlockForKey(req, req.Arguments()[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
return &BlockStat{
|
||||
res.SetOutput(&BlockStat{
|
||||
Key: b.Key().Pretty(),
|
||||
Size: len(b.Data),
|
||||
}, nil
|
||||
})
|
||||
},
|
||||
Type: BlockStat{},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
@ -89,13 +91,14 @@ It outputs to stdout, and <key> is a base58 encoded multihash.
|
||||
Arguments: []cmds.Argument{
|
||||
cmds.StringArg("key", true, false, "The base58 multihash of an existing block to get").EnableStdin(),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
b, err := getBlockForKey(req, req.Arguments()[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
return bytes.NewReader(b.Data), nil
|
||||
res.SetOutput(bytes.NewReader(b.Data))
|
||||
},
|
||||
}
|
||||
|
||||
@ -111,25 +114,29 @@ It reads from stdin, and <key> is a base58 encoded multihash.
|
||||
Arguments: []cmds.Argument{
|
||||
cmds.FileArg("data", true, false, "The data to be stored as an IPFS block").EnableStdin(),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
file, err := req.Files().NextFile()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
err = file.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
b := blocks.NewBlock(data)
|
||||
@ -137,13 +144,14 @@ It reads from stdin, and <key> is a base58 encoded multihash.
|
||||
|
||||
k, err := n.Blocks.AddBlock(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
return &BlockStat{
|
||||
res.SetOutput(&BlockStat{
|
||||
Key: k.String(),
|
||||
Size: len(data),
|
||||
}, nil
|
||||
})
|
||||
},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
cmds.Text: func(res cmds.Response) (io.Reader, error) {
|
||||
@ -160,7 +168,7 @@ func getBlockForKey(req cmds.Request, key string) (*blocks.Block, error) {
|
||||
}
|
||||
|
||||
if !u.IsValidHash(key) {
|
||||
return nil, cmds.Error{"Not a valid hash", cmds.ErrClient}
|
||||
return nil, errors.New("Not a valid hash")
|
||||
}
|
||||
|
||||
h, err := mh.FromB58String(key)
|
||||
@ -173,6 +181,7 @@ func getBlockForKey(req cmds.Request, key string) (*blocks.Block, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugf("ipfs block: got block with key: %q", b.Key())
|
||||
return b, nil
|
||||
}
|
||||
|
||||
@ -76,29 +76,33 @@ in the bootstrap list).
|
||||
cmds.BoolOption("default", "add default bootstrap nodes"),
|
||||
},
|
||||
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
inputPeers, err := config.ParseBootstrapPeers(req.Arguments())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
r := fsrepo.At(req.Context().ConfigRoot)
|
||||
if err := r.Open(); err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
defer r.Close()
|
||||
cfg := r.Config()
|
||||
|
||||
deflt, _, err := req.Option("default").Bool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
if deflt {
|
||||
// parse separately for meaningful, correct error.
|
||||
defltPeers, err := DefaultBootstrapPeers()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
inputPeers = append(inputPeers, defltPeers...)
|
||||
@ -106,14 +110,16 @@ in the bootstrap list).
|
||||
|
||||
added, err := bootstrapAdd(r, cfg, inputPeers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
if len(inputPeers) == 0 {
|
||||
return nil, cmds.ClientError("no bootstrap peers to add")
|
||||
res.SetError(errors.New("no bootstrap peers to add"), cmds.ErrClient)
|
||||
return
|
||||
}
|
||||
|
||||
return &BootstrapOutput{added}, nil
|
||||
res.SetOutput(&BootstrapOutput{added})
|
||||
},
|
||||
Type: BootstrapOutput{},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
@ -125,7 +131,11 @@ in the bootstrap list).
|
||||
|
||||
var buf bytes.Buffer
|
||||
err := bootstrapWritePeers(&buf, "added ", v.Peers)
|
||||
return &buf, err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &buf, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -143,22 +153,25 @@ var bootstrapRemoveCmd = &cmds.Command{
|
||||
Options: []cmds.Option{
|
||||
cmds.BoolOption("all", "Remove all bootstrap peers."),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
input, err := config.ParseBootstrapPeers(req.Arguments())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
r := fsrepo.At(req.Context().ConfigRoot)
|
||||
if err := r.Open(); err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
defer r.Close()
|
||||
cfg := r.Config()
|
||||
|
||||
all, _, err := req.Option("all").Bool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
var removed []config.BootstrapPeer
|
||||
@ -168,10 +181,11 @@ var bootstrapRemoveCmd = &cmds.Command{
|
||||
removed, err = bootstrapRemove(r, cfg, input)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
return &BootstrapOutput{removed}, nil
|
||||
res.SetOutput(&BootstrapOutput{removed})
|
||||
},
|
||||
Type: BootstrapOutput{},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
@ -194,14 +208,15 @@ var bootstrapListCmd = &cmds.Command{
|
||||
ShortDescription: "Peers are output in the format '<multiaddr>/<peerID>'.",
|
||||
},
|
||||
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
cfg, err := req.Context().GetConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
peers := cfg.Bootstrap
|
||||
return &BootstrapOutput{peers}, nil
|
||||
res.SetOutput(&BootstrapOutput{peers})
|
||||
},
|
||||
Type: BootstrapOutput{},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
|
||||
@ -6,8 +6,12 @@ import (
|
||||
cmds "github.com/jbenet/go-ipfs/commands"
|
||||
core "github.com/jbenet/go-ipfs/core"
|
||||
uio "github.com/jbenet/go-ipfs/unixfs/io"
|
||||
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/cheggaaa/pb"
|
||||
)
|
||||
|
||||
const progressBarMinSize = 1024 * 1024 * 8 // show progress bar for outputs > 8MiB
|
||||
|
||||
var CatCmd = &cmds.Command{
|
||||
Helptext: cmds.HelpText{
|
||||
Tagline: "Show IPFS object data",
|
||||
@ -20,36 +24,60 @@ it contains.
|
||||
Arguments: []cmds.Argument{
|
||||
cmds.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to be outputted").EnableStdin(),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
node, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
readers := make([]io.Reader, 0, len(req.Arguments()))
|
||||
|
||||
readers, err = cat(node, req.Arguments())
|
||||
readers, length, err := cat(node, req.Arguments())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
res.SetLength(length)
|
||||
|
||||
reader := io.MultiReader(readers...)
|
||||
return reader, nil
|
||||
res.SetOutput(reader)
|
||||
},
|
||||
PostRun: func(req cmds.Request, res cmds.Response) {
|
||||
if res.Length() < progressBarMinSize {
|
||||
return
|
||||
}
|
||||
|
||||
bar := pb.New(int(res.Length())).SetUnits(pb.U_BYTES)
|
||||
bar.Output = res.Stderr()
|
||||
bar.Start()
|
||||
|
||||
reader := bar.NewProxyReader(res.Output().(io.Reader))
|
||||
res.SetOutput(reader)
|
||||
},
|
||||
}
|
||||
|
||||
func cat(node *core.IpfsNode, paths []string) ([]io.Reader, error) {
|
||||
func cat(node *core.IpfsNode, paths []string) ([]io.Reader, uint64, error) {
|
||||
readers := make([]io.Reader, 0, len(paths))
|
||||
length := uint64(0)
|
||||
for _, path := range paths {
|
||||
dagnode, err := node.Resolver.ResolvePath(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
nodeLength, err := dagnode.Size()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
length += nodeLength
|
||||
|
||||
read, err := uio.NewDagReader(dagnode, node.DAG)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
readers = append(readers, read)
|
||||
}
|
||||
return readers, nil
|
||||
return readers, length, nil
|
||||
}
|
||||
|
||||
@ -22,9 +22,9 @@ func CommandsCmd(root *cmds.Command) *cmds.Command {
|
||||
ShortDescription: `Lists all available commands (and subcommands) and exits.`,
|
||||
},
|
||||
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
root := cmd2outputCmd("ipfs", root)
|
||||
return &root, nil
|
||||
res.SetOutput(&root)
|
||||
},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
cmds.Text: func(res cmds.Response) (io.Reader, error) {
|
||||
|
||||
@ -57,24 +57,30 @@ Set the value of the 'datastore.path' key:
|
||||
cmds.StringArg("key", true, false, "The key of the config entry (e.g. \"Addresses.API\")"),
|
||||
cmds.StringArg("value", false, false, "The value to set the config entry to"),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
args := req.Arguments()
|
||||
key := args[0]
|
||||
|
||||
r := fsrepo.At(req.Context().ConfigRoot)
|
||||
if err := r.Open(); err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
var value string
|
||||
var err error
|
||||
var output *ConfigField
|
||||
if len(args) == 2 {
|
||||
value = args[1]
|
||||
return setConfig(r, key, value)
|
||||
|
||||
value := args[1]
|
||||
output, err = setConfig(r, key, value)
|
||||
} else {
|
||||
return getConfig(r, key)
|
||||
output, err = getConfig(r, key)
|
||||
}
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
res.SetOutput(output)
|
||||
},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
cmds.Text: func(res cmds.Response) (io.Reader, error) {
|
||||
@ -117,13 +123,19 @@ included in the output of this command.
|
||||
`,
|
||||
},
|
||||
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
filename, err := config.Filename(req.Context().ConfigRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
return showConfig(filename)
|
||||
output, err := showConfig(filename)
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
res.SetOutput(output)
|
||||
},
|
||||
}
|
||||
|
||||
@ -136,19 +148,23 @@ variable set to your preferred text editor.
|
||||
`,
|
||||
},
|
||||
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
filename, err := config.Filename(req.Context().ConfigRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
return nil, editConfig(filename)
|
||||
err = editConfig(filename)
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var configReplaceCmd = &cmds.Command{
|
||||
Helptext: cmds.HelpText{
|
||||
Tagline: "Replaces the config with <file>",
|
||||
Tagline: "Replaces the config with `file>",
|
||||
ShortDescription: `
|
||||
Make sure to back up the config file first if neccessary, this operation
|
||||
can't be undone.
|
||||
@ -158,20 +174,26 @@ can't be undone.
|
||||
Arguments: []cmds.Argument{
|
||||
cmds.FileArg("file", true, false, "The file to use as the new config"),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
r := fsrepo.At(req.Context().ConfigRoot)
|
||||
if err := r.Open(); err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
file, err := req.Files().NextFile()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
return nil, replaceConfig(r, file)
|
||||
err = replaceConfig(r, file)
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ package commands
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
"text/template"
|
||||
@ -63,50 +64,65 @@ connected peers and latencies between them.
|
||||
cmds.StringOption("vis", "output vis. one of: "+strings.Join(visFmts, ", ")),
|
||||
},
|
||||
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
if !n.OnlineMode() {
|
||||
return nil, errNotOnline
|
||||
res.SetError(errNotOnline, cmds.ErrClient)
|
||||
return
|
||||
}
|
||||
|
||||
vis, _, err := req.Option("vis").String()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
timeoutS, _, err := req.Option("timeout").String()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
timeout := DefaultDiagnosticTimeout
|
||||
if timeoutS != "" {
|
||||
t, err := time.ParseDuration(timeoutS)
|
||||
if err != nil {
|
||||
return nil, cmds.ClientError("error parsing timeout")
|
||||
res.SetError(errors.New("error parsing timeout"), cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
timeout = t
|
||||
}
|
||||
|
||||
info, err := n.Diagnostics.GetDiagnostic(timeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
switch vis {
|
||||
case visD3:
|
||||
return bytes.NewReader(diag.GetGraphJson(info)), nil
|
||||
res.SetOutput(bytes.NewReader(diag.GetGraphJson(info)))
|
||||
case visDot:
|
||||
var buf bytes.Buffer
|
||||
w := diag.DotWriter{W: &buf}
|
||||
err := w.WriteGraph(info)
|
||||
return io.Reader(&buf), err
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
res.SetOutput(io.Reader(&buf))
|
||||
}
|
||||
|
||||
return stdDiagOutputMarshal(standardDiagOutput(info))
|
||||
output, err := stdDiagOutputMarshal(standardDiagOutput(info))
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
res.SetOutput(output)
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -45,37 +45,54 @@ if no peer is specified, prints out local peers info.
|
||||
Arguments: []cmds.Argument{
|
||||
cmds.StringArg("peerid", false, false, "peer.ID of node to look up").EnableStdin(),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
node, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.Arguments()) == 0 {
|
||||
return printPeer(node.Peerstore, node.Identity)
|
||||
output, err := printPeer(node.Peerstore, node.Identity)
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
res.SetOutput(output)
|
||||
return
|
||||
}
|
||||
|
||||
pid := req.Arguments()[0]
|
||||
|
||||
id := peer.ID(b58.Decode(pid))
|
||||
if len(id) == 0 {
|
||||
return nil, cmds.ClientError("Invalid peer id")
|
||||
res.SetError(cmds.ClientError("Invalid peer id"), cmds.ErrClient)
|
||||
return
|
||||
}
|
||||
|
||||
ctx, _ := context.WithTimeout(context.TODO(), time.Second*5)
|
||||
// TODO handle offline mode with polymorphism instead of conditionals
|
||||
if !node.OnlineMode() {
|
||||
return nil, errors.New(offlineIdErrorMessage)
|
||||
res.SetError(errors.New(offlineIdErrorMessage), cmds.ErrClient)
|
||||
return
|
||||
}
|
||||
|
||||
p, err := node.Routing.FindPeer(ctx, id)
|
||||
if err == kb.ErrLookupFailure {
|
||||
return nil, errors.New(offlineIdErrorMessage)
|
||||
res.SetError(errors.New(offlineIdErrorMessage), cmds.ErrClient)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
return printPeer(node.Peerstore, p.ID)
|
||||
|
||||
output, err := printPeer(node.Peerstore, p.ID)
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
res.SetOutput(output)
|
||||
},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
cmds.Text: func(res cmds.Response) (io.Reader, error) {
|
||||
|
||||
@ -47,7 +47,7 @@ output of a running daemon.
|
||||
cmds.StringArg("subsystem", true, false, fmt.Sprintf("the subsystem logging identifier. Use '%s' for all subsystems.", logAllKeyword)),
|
||||
cmds.StringArg("level", true, false, "one of: debug, info, notice, warning, error, critical"),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
|
||||
args := req.Arguments()
|
||||
subsystem, level := args[0], args[1]
|
||||
@ -57,12 +57,13 @@ output of a running daemon.
|
||||
}
|
||||
|
||||
if err := u.SetLogLevel(subsystem, level); err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
s := fmt.Sprintf("Changed log level of '%s' to '%s'", subsystem, level)
|
||||
log.Info(s)
|
||||
return &MessageOutput{s}, nil
|
||||
res.SetOutput(&MessageOutput{s})
|
||||
},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
cmds.Text: MessageTextMarshaler,
|
||||
@ -78,7 +79,7 @@ var logTailCmd = &cmds.Command{
|
||||
`,
|
||||
},
|
||||
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
path := fmt.Sprintf("%s/logs/events.log", req.Context().ConfigRoot)
|
||||
|
||||
outChan := make(chan interface{})
|
||||
@ -108,7 +109,7 @@ var logTailCmd = &cmds.Command{
|
||||
}
|
||||
}()
|
||||
|
||||
return (<-chan interface{})(outChan), nil
|
||||
res.SetOutput((<-chan interface{})(outChan))
|
||||
},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
cmds.Text: func(res cmds.Response) (io.Reader, error) {
|
||||
|
||||
@ -37,10 +37,11 @@ it contains, with the following format:
|
||||
Arguments: []cmds.Argument{
|
||||
cmds.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to list links from").EnableStdin(),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
node, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
paths := req.Arguments()
|
||||
@ -49,7 +50,8 @@ it contains, with the following format:
|
||||
for _, path := range paths {
|
||||
dagnode, err := node.Resolver.ResolvePath(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
dagnodes = append(dagnodes, dagnode)
|
||||
}
|
||||
@ -69,7 +71,7 @@ it contains, with the following format:
|
||||
}
|
||||
}
|
||||
|
||||
return &LsOutput{output}, nil
|
||||
res.SetOutput(&LsOutput{output})
|
||||
},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
cmds.Text: func(res cmds.Response) (io.Reader, error) {
|
||||
|
||||
@ -90,25 +90,29 @@ baz
|
||||
// TODO longform
|
||||
cmds.StringOption("n", "The path where IPNS should be mounted"),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
cfg, err := req.Context().GetConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
node, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
// error if we aren't running node in online mode
|
||||
if !node.OnlineMode() {
|
||||
return nil, errNotOnline
|
||||
res.SetError(errNotOnline, cmds.ErrClient)
|
||||
return
|
||||
}
|
||||
|
||||
fsdir, found, err := req.Option("f").String()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
if !found {
|
||||
fsdir = cfg.Mounts.IPFS // use default value
|
||||
@ -117,7 +121,8 @@ baz
|
||||
// get default mount points
|
||||
nsdir, found, err := req.Option("n").String()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
if !found {
|
||||
nsdir = cfg.Mounts.IPNS // NB: be sure to not redeclare!
|
||||
@ -125,13 +130,14 @@ baz
|
||||
|
||||
err = Mount(node, fsdir, nsdir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
var output config.Mounts
|
||||
output.IPFS = fsdir
|
||||
output.IPNS = nsdir
|
||||
return &output, nil
|
||||
res.SetOutput(&output)
|
||||
},
|
||||
Type: config.Mounts{},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
|
||||
@ -13,8 +13,8 @@ var MountCmd = &cmds.Command{
|
||||
ShortDescription: "Not yet implemented on Windows. :(",
|
||||
},
|
||||
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
return errors.New("Mount isn't compatible with Windows yet"), nil
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
res.SetError(errors.New("Mount isn't compatible with Windows yet"), cmds.ErrNormal)
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -71,14 +71,20 @@ output is the raw data of the object.
|
||||
Arguments: []cmds.Argument{
|
||||
cmds.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format").EnableStdin(),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
key := req.Arguments()[0]
|
||||
return objectData(n, key)
|
||||
output, err := objectData(n, key)
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
res.SetOutput(output)
|
||||
},
|
||||
}
|
||||
|
||||
@ -95,14 +101,20 @@ multihash.
|
||||
Arguments: []cmds.Argument{
|
||||
cmds.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format").EnableStdin(),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
key := req.Arguments()[0]
|
||||
return objectLinks(n, key)
|
||||
output, err := objectLinks(n, key)
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
res.SetOutput(output)
|
||||
},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
cmds.Text: func(res cmds.Response) (io.Reader, error) {
|
||||
@ -137,17 +149,19 @@ This command outputs data in the following encodings:
|
||||
Arguments: []cmds.Argument{
|
||||
cmds.StringArg("key", true, false, "Key of the object to retrieve (in base58-encoded multihash format)").EnableStdin(),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
key := req.Arguments()[0]
|
||||
|
||||
object, err := objectGet(n, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
node := &Node{
|
||||
@ -163,7 +177,7 @@ This command outputs data in the following encodings:
|
||||
}
|
||||
}
|
||||
|
||||
return node, nil
|
||||
res.SetOutput(node)
|
||||
},
|
||||
Type: Node{},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
@ -201,25 +215,28 @@ var objectStatCmd = &cmds.Command{
|
||||
Arguments: []cmds.Argument{
|
||||
cmds.StringArg("key", true, false, "Key of the object to retrieve (in base58-encoded multihash format)").EnableStdin(),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
key := req.Arguments()[0]
|
||||
|
||||
object, err := objectGet(n, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
ns, err := object.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
return ns, nil
|
||||
res.SetOutput(ns)
|
||||
},
|
||||
Type: dag.NodeStat{},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
@ -263,15 +280,17 @@ Data should be in the format specified by <encoding>.
|
||||
cmds.FileArg("data", true, false, "Data to be stored as a DAG object"),
|
||||
cmds.StringArg("encoding", true, false, "Encoding type of <data>, either \"protobuf\" or \"json\""),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
input, err := req.Files().NextFile()
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
encoding := req.Arguments()[0]
|
||||
@ -282,10 +301,11 @@ Data should be in the format specified by <encoding>.
|
||||
if err == ErrUnknownObjectEnc {
|
||||
errType = cmds.ErrClient
|
||||
}
|
||||
return nil, cmds.Error{err.Error(), errType}
|
||||
res.SetError(err, errType)
|
||||
return
|
||||
}
|
||||
|
||||
return output, nil
|
||||
res.SetOutput(output)
|
||||
},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
cmds.Text: func(res cmds.Response) (io.Reader, error) {
|
||||
|
||||
@ -42,16 +42,18 @@ on disk.
|
||||
cmds.BoolOption("recursive", "r", "Recursively pin the object linked to by the specified object(s)"),
|
||||
},
|
||||
Type: PinOutput{},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
// set recursive flag
|
||||
recursive, found, err := req.Option("recursive").Bool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
if !found {
|
||||
recursive = false
|
||||
@ -59,10 +61,11 @@ on disk.
|
||||
|
||||
added, err := corerepo.Pin(n, req.Arguments(), recursive)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
return &PinOutput{added}, nil
|
||||
res.SetOutput(&PinOutput{added})
|
||||
},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
cmds.Text: func(res cmds.Response) (io.Reader, error) {
|
||||
@ -104,16 +107,18 @@ collected if needed.
|
||||
cmds.BoolOption("recursive", "r", "Recursively unpin the object linked to by the specified object(s)"),
|
||||
},
|
||||
Type: PinOutput{},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
// set recursive flag
|
||||
recursive, found, err := req.Option("recursive").Bool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
if !found {
|
||||
recursive = false // default
|
||||
@ -121,10 +126,11 @@ collected if needed.
|
||||
|
||||
removed, err := corerepo.Unpin(n, req.Arguments(), recursive)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
return &PinOutput{removed}, nil
|
||||
res.SetOutput(&PinOutput{removed})
|
||||
},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
cmds.Text: func(res cmds.Response) (io.Reader, error) {
|
||||
@ -165,15 +171,17 @@ Use --type=<type> to specify the type of pinned keys to list. Valid values are:
|
||||
Options: []cmds.Option{
|
||||
cmds.StringOption("type", "t", "The type of pinned keys to list. Can be \"direct\", \"indirect\", \"recursive\", or \"all\". Defaults to \"direct\""),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
typeStr, found, err := req.Option("type").String()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
if !found {
|
||||
typeStr = "direct"
|
||||
@ -182,7 +190,8 @@ Use --type=<type> to specify the type of pinned keys to list. Valid values are:
|
||||
switch typeStr {
|
||||
case "all", "direct", "indirect", "recursive":
|
||||
default:
|
||||
return nil, cmds.ClientError("Invalid type '" + typeStr + "', must be one of {direct, indirect, recursive, all}")
|
||||
err = fmt.Errorf("Invalid type '%s', must be one of {direct, indirect, recursive, all}", typeStr)
|
||||
res.SetError(err, cmds.ErrClient)
|
||||
}
|
||||
|
||||
keys := make([]u.Key, 0)
|
||||
@ -196,7 +205,7 @@ Use --type=<type> to specify the type of pinned keys to list. Valid values are:
|
||||
keys = append(keys, n.Pinning.RecursiveKeys()...)
|
||||
}
|
||||
|
||||
return &KeyList{Keys: keys}, nil
|
||||
res.SetOutput(&KeyList{Keys: keys})
|
||||
},
|
||||
Type: KeyList{},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
|
||||
@ -74,21 +74,24 @@ trip latency information.
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
ctx := req.Context().Context
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
// Must be online!
|
||||
if !n.OnlineMode() {
|
||||
return nil, errNotOnline
|
||||
res.SetError(errNotOnline, cmds.ErrClient)
|
||||
return
|
||||
}
|
||||
|
||||
addr, peerID, err := ParsePeerParam(req.Arguments()[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
if addr != nil {
|
||||
@ -99,14 +102,15 @@ trip latency information.
|
||||
numPings := 10
|
||||
val, found, err := req.Option("count").Int()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
if found {
|
||||
numPings = val
|
||||
}
|
||||
|
||||
outChan := pingPeer(ctx, n, peerID, numPings)
|
||||
return outChan, nil
|
||||
res.SetOutput(outChan)
|
||||
},
|
||||
Type: PingResult{},
|
||||
}
|
||||
|
||||
@ -46,21 +46,23 @@ Publish a <ref> to another public key:
|
||||
cmds.StringArg("name", false, false, "The IPNS name to publish to. Defaults to your node's peerID"),
|
||||
cmds.StringArg("ipfs-path", true, false, "IPFS path of the obejct to be published at <name>").EnableStdin(),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
log.Debug("Begin Publish")
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
args := req.Arguments()
|
||||
|
||||
if n.PeerHost == nil {
|
||||
return nil, errNotOnline
|
||||
res.SetError(errNotOnline, cmds.ErrClient)
|
||||
}
|
||||
|
||||
if n.Identity == "" {
|
||||
return nil, errors.New("Identity not loaded!")
|
||||
res.SetError(errors.New("Identity not loaded!"), cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
// name := ""
|
||||
@ -70,14 +72,19 @@ Publish a <ref> to another public key:
|
||||
case 2:
|
||||
// name = args[0]
|
||||
ref = args[1]
|
||||
return nil, errors.New("keychains not yet implemented")
|
||||
res.SetError(errors.New("keychains not yet implemented"), cmds.ErrNormal)
|
||||
case 1:
|
||||
// name = n.Identity.ID.String()
|
||||
ref = args[0]
|
||||
}
|
||||
|
||||
// TODO n.Keychain.Get(name).PrivKey
|
||||
return publish(n, n.PrivateKey, ref)
|
||||
output, err := publish(n, n.PrivateKey, ref)
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
res.SetOutput(output)
|
||||
},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
cmds.Text: func(res cmds.Response) (io.Reader, error) {
|
||||
|
||||
@ -53,36 +53,42 @@ Note: list all refs recursively with -r.
|
||||
cmds.BoolOption("unique", "u", "Omit duplicate refs from output"),
|
||||
cmds.BoolOption("recursive", "r", "Recursively list links of child nodes"),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
ctx := req.Context().Context
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
unique, _, err := req.Option("unique").Bool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
recursive, _, err := req.Option("recursive").Bool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
edges, _, err := req.Option("edges").Bool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
format, _, err := req.Option("format").String()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
objs, err := objectsForPaths(n, req.Arguments())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
piper, pipew := io.Pipe()
|
||||
@ -110,7 +116,7 @@ Note: list all refs recursively with -r.
|
||||
}
|
||||
}()
|
||||
|
||||
return eptr, nil
|
||||
res.SetOutput(eptr)
|
||||
},
|
||||
}
|
||||
|
||||
@ -122,17 +128,19 @@ Displays the hashes of all local objects.
|
||||
`,
|
||||
},
|
||||
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
ctx := req.Context().Context
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
// todo: make async
|
||||
allKeys, err := n.Blockstore.AllKeysChan(ctx, 0, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
piper, pipew := io.Pipe()
|
||||
@ -151,7 +159,7 @@ Displays the hashes of all local objects.
|
||||
}
|
||||
}()
|
||||
|
||||
return eptr, nil
|
||||
res.SetOutput(eptr)
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -36,26 +36,28 @@ order to reclaim hard disk space.
|
||||
Options: []cmds.Option{
|
||||
cmds.BoolOption("quiet", "q", "Write minimal output"),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
gcOutChan, err := corerepo.GarbageCollectBlockstore(n, req.Context().Context)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
outChan := make(chan interface{})
|
||||
res.SetOutput((<-chan interface{})(outChan))
|
||||
|
||||
go func() {
|
||||
defer close(outChan)
|
||||
for k := range gcOutChan {
|
||||
outChan <- k
|
||||
}
|
||||
}()
|
||||
|
||||
return outChan, nil
|
||||
},
|
||||
Type: corerepo.KeyRemoved{},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
|
||||
@ -40,22 +40,25 @@ Resolve te value of another name:
|
||||
Arguments: []cmds.Argument{
|
||||
cmds.StringArg("name", false, false, "The IPNS name to resolve. Defaults to your node's peerID.").EnableStdin(),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
var name string
|
||||
|
||||
if n.PeerHost == nil {
|
||||
return nil, errNotOnline
|
||||
res.SetError(errNotOnline, cmds.ErrClient)
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.Arguments()) == 0 {
|
||||
if n.Identity == "" {
|
||||
return nil, errors.New("Identity not loaded!")
|
||||
res.SetError(errors.New("Identity not loaded!"), cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
name = n.Identity.Pretty()
|
||||
|
||||
@ -65,12 +68,13 @@ Resolve te value of another name:
|
||||
|
||||
output, err := n.Namesys.Resolve(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: better errors (in the case of not finding the name, we get "failed to find any peer in table")
|
||||
|
||||
return output, nil
|
||||
res.SetOutput(output)
|
||||
},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
cmds.Text: func(res cmds.Response) (io.Reader, error) {
|
||||
|
||||
@ -45,16 +45,18 @@ var swarmPeersCmd = &cmds.Command{
|
||||
ipfs swarm peers lists the set of peers this node is connected to.
|
||||
`,
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
|
||||
log.Debug("ipfs swarm peers")
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
if n.PeerHost == nil {
|
||||
return nil, errNotOnline
|
||||
res.SetError(errNotOnline, cmds.ErrClient)
|
||||
return
|
||||
}
|
||||
|
||||
conns := n.PeerHost.Network().Conns()
|
||||
@ -66,7 +68,7 @@ ipfs swarm peers lists the set of peers this node is connected to.
|
||||
}
|
||||
|
||||
sort.Sort(sort.StringSlice(addrs))
|
||||
return &stringList{addrs}, nil
|
||||
res.SetOutput(&stringList{addrs})
|
||||
},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
cmds.Text: stringListMarshaler,
|
||||
@ -87,24 +89,27 @@ ipfs swarm connect /ip4/104.131.131.82/tcp/4001/QmaCpDMGvV2BGHeYERUEnRQAwe3N8Szb
|
||||
Arguments: []cmds.Argument{
|
||||
cmds.StringArg("address", true, true, "address of peer to connect to").EnableStdin(),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
ctx := context.TODO()
|
||||
|
||||
log.Debug("ipfs swarm connect")
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
addrs := req.Arguments()
|
||||
|
||||
if n.PeerHost == nil {
|
||||
return nil, errNotOnline
|
||||
res.SetError(errNotOnline, cmds.ErrClient)
|
||||
return
|
||||
}
|
||||
|
||||
peers, err := peersWithAddresses(n.Peerstore, addrs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
output := make([]string, len(peers))
|
||||
@ -119,7 +124,7 @@ ipfs swarm connect /ip4/104.131.131.82/tcp/4001/QmaCpDMGvV2BGHeYERUEnRQAwe3N8Szb
|
||||
}
|
||||
}
|
||||
|
||||
return &stringList{output}, nil
|
||||
res.SetOutput(&stringList{output})
|
||||
},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
cmds.Text: stringListMarshaler,
|
||||
|
||||
@ -22,12 +22,19 @@ var UpdateCmd = &cmds.Command{
|
||||
ShortDescription: "ipfs update is a utility command used to check for updates and apply them.",
|
||||
},
|
||||
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
return updateApply(n)
|
||||
|
||||
output, err := updateApply(n)
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
res.SetOutput(output)
|
||||
},
|
||||
Type: UpdateOutput{},
|
||||
Subcommands: map[string]*cmds.Command{
|
||||
@ -55,12 +62,19 @@ var UpdateCheckCmd = &cmds.Command{
|
||||
ShortDescription: "'ipfs update check' checks if any updates are available for IPFS.\nNothing will be downloaded or installed.",
|
||||
},
|
||||
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
return updateCheck(n)
|
||||
|
||||
output, err := updateCheck(n)
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
res.SetOutput(output)
|
||||
},
|
||||
Type: UpdateOutput{},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
@ -84,12 +98,19 @@ var UpdateLogCmd = &cmds.Command{
|
||||
ShortDescription: "This command is not yet implemented.",
|
||||
},
|
||||
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
return updateLog(n)
|
||||
|
||||
output, err := updateLog(n)
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
res.SetOutput(output)
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -22,10 +22,10 @@ var VersionCmd = &cmds.Command{
|
||||
Options: []cmds.Option{
|
||||
cmds.BoolOption("number", "n", "Only show the version number"),
|
||||
},
|
||||
Run: func(req cmds.Request) (interface{}, error) {
|
||||
return &VersionOutput{
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
res.SetOutput(&VersionOutput{
|
||||
Version: config.CurrentVersionNumber,
|
||||
}, nil
|
||||
})
|
||||
},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
cmds.Text: func(res cmds.Response) (io.Reader, error) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user