提交 cf1f17cf 作者: Jeromy

add: Allow proper adding of multiple directories with a single add invocation

License: MIT
Signed-off-by: 's avatarJeromy <why@ipfs.io>
上级 edf2b52f
......@@ -424,7 +424,7 @@ func appendFile(fpath string, argDef *cmds.Argument, recursive, hidden bool) (fi
}
}
return files.NewSerialFile(path.Base(fpath), fpath, hidden, stat)
return files.NewSerialFile(path.Base(fpath), fpath, hidden, true, stat)
}
// Inform the user if a file is waiting on input
......
......@@ -30,6 +30,10 @@ type File interface {
// (and therefor supports calling `Read` and `Close`)
IsDirectory() bool
// IsRoot returns whether or not this file (or directory) is the 'root' of
// a given operation.
IsRoot() bool
// NextFile returns the next child file available (if the File is a
// directory). It will return (nil, io.EOF) if no more files are
// available. If the file is a regular file (not a directory), NextFile
......
......@@ -11,11 +11,12 @@ type Symlink struct {
path string
Target string
stat os.FileInfo
root bool
reader io.Reader
}
func NewLinkFile(name, path, target string, stat os.FileInfo) File {
func NewLinkFile(name, path, target string, stat os.FileInfo) *Symlink {
return &Symlink{
name: name,
path: path,
......@@ -48,3 +49,7 @@ func (f *Symlink) FullPath() string {
func (f *Symlink) Read(b []byte) (int, error) {
return f.reader.Read(b)
}
func (f *Symlink) IsRoot() bool {
return f.root
}
......@@ -26,6 +26,7 @@ type MultipartFile struct {
Part *multipart.Part
Reader *multipart.Reader
Mediatype string
Root bool
}
func NewFileFromPart(part *multipart.Part) (File, error) {
......@@ -105,3 +106,7 @@ func (f *MultipartFile) Close() error {
}
return f.Part.Close()
}
func (f *MultipartFile) IsRoot() bool {
return f.Root
}
......@@ -13,10 +13,16 @@ type ReaderFile struct {
fullpath string
reader io.ReadCloser
stat os.FileInfo
root bool
}
func NewReaderFile(filename, path string, reader io.ReadCloser, stat os.FileInfo) *ReaderFile {
return &ReaderFile{filename, path, reader, stat}
return &ReaderFile{
filename: filename,
fullpath: path,
reader: reader,
stat: stat,
}
}
func (f *ReaderFile) IsDirectory() bool {
......@@ -53,3 +59,7 @@ func (f *ReaderFile) Size() (int64, error) {
}
return f.stat.Size(), nil
}
func (f *ReaderFile) IsRoot() bool {
return f.root
}
......@@ -20,16 +20,22 @@ type serialFile struct {
stat os.FileInfo
current *File
handleHiddenFiles bool
root bool
}
func NewSerialFile(name, path string, hidden bool, stat os.FileInfo) (File, error) {
func NewSerialFile(name, path string, hidden, root bool, stat os.FileInfo) (File, error) {
if root {
name = path
}
switch mode := stat.Mode(); {
case mode.IsRegular():
file, err := os.Open(path)
if err != nil {
return nil, err
}
return NewReaderFile(name, path, file, stat), nil
rf := NewReaderFile(name, path, file, stat)
rf.root = root
return rf, nil
case mode.IsDir():
// for directories, stat all of the contents first, so we know what files to
// open when NextFile() is called
......@@ -37,13 +43,16 @@ func NewSerialFile(name, path string, hidden bool, stat os.FileInfo) (File, erro
if err != nil {
return nil, err
}
return &serialFile{name, path, contents, stat, nil, hidden}, nil
return &serialFile{name, path, contents, stat, nil, hidden, root}, nil
case mode&os.ModeSymlink != 0:
target, err := os.Readlink(path)
if err != nil {
return nil, err
}
return NewLinkFile(name, path, target, stat), nil
lf := NewLinkFile(name, path, target, stat)
lf.root = root
return lf, nil
default:
return nil, fmt.Errorf("Unrecognized file type for %s: %s", name, mode.String())
}
......@@ -55,6 +64,10 @@ func (f *serialFile) IsDirectory() bool {
return true
}
func (f *serialFile) IsRoot() bool {
return f.root
}
func (f *serialFile) NextFile() (File, error) {
// if a file was opened previously, close it
err := f.Close()
......@@ -86,7 +99,7 @@ func (f *serialFile) NextFile() (File, error) {
// recursively call the constructor on the next file
// if it's a regular file, we will open it as a ReaderFile
// if it's a directory, files in it will be opened serially
sf, err := NewSerialFile(fileName, filePath, f.handleHiddenFiles, stat)
sf, err := NewSerialFile(fileName, filePath, f.handleHiddenFiles, false, stat)
if err != nil {
return nil, err
}
......
......@@ -13,10 +13,15 @@ type SliceFile struct {
path string
files []File
n int
root bool
}
func NewSliceFile(filename, path string, files []File) *SliceFile {
return &SliceFile{filename, path, files, 0}
return &SliceFile{
filename: filename,
path: path,
files: files,
}
}
func (f *SliceFile) IsDirectory() bool {
......@@ -74,3 +79,7 @@ func (f *SliceFile) Size() (int64, error) {
return size, nil
}
func (f *SliceFile) IsRoot() bool {
return f.root
}
......@@ -187,24 +187,30 @@ func (adder *Adder) Finalize() (*dag.Node, error) {
return nil, err
}
var name string
if !adder.Wrap {
name = rootNode.Links[0].Name
dir, ok := adder.mr.GetValue().(*mfs.Directory)
if !ok {
return nil, fmt.Errorf("root is not a directory")
}
root, err = dir.Child(name)
if adder.Wrap {
err = adder.outputDirs("", root)
if err != nil {
return nil, err
}
}
} else {
for _, lnk := range rootNode.Links {
name := lnk.Name
err = adder.outputDirs(name, root)
if err != nil {
return nil, err
dir, ok := adder.mr.GetValue().(*mfs.Directory)
if !ok {
return nil, fmt.Errorf("root is not a directory")
}
root, err = dir.Child(name)
if err != nil {
return nil, err
}
err = adder.outputDirs(name, root)
if err != nil {
return nil, err
}
}
}
err = adder.mr.Close()
......@@ -272,7 +278,7 @@ func AddR(n *core.IpfsNode, root string) (key string, err error) {
return "", err
}
f, err := files.NewSerialFile(root, root, false, stat)
f, err := files.NewSerialFile(root, root, false, true, stat)
if err != nil {
return "", err
}
......
......@@ -29,7 +29,7 @@ func BuildDagFromFile(fpath string, ds dag.DAGService) (*dag.Node, error) {
return nil, fmt.Errorf("`%s` is a directory", fpath)
}
f, err := files.NewSerialFile(fpath, fpath, false, stat)
f, err := files.NewSerialFile(fpath, fpath, false, true, stat)
if err != nil {
return nil, err
}
......
......@@ -306,12 +306,14 @@ test_expect_success "'ipfs add -r' succeeds" '
'
test_expect_success "'ipfs add -r' output looks good" '
MOUNTDIR="QmcgF3bEc3q9G9YfxCXWYaV5H7bDyDD1CrsmUDgSQPdY4n" &&
PLANETS="QmWSgS32xQEcXMeqd3YPJLrNBLSdsfYCep2U7CFkyrjXwY" &&
MARS="QmPrrHqJzto9m7SyiRzarwkqPcCSsKR2EB1AyqJfe8L8tN" &&
VENUS="QmU5kp3BH3B8tnWUU2Pikdb2maksBNkb92FHRr56hyghh4" &&
echo "added $MARS planets/mars.txt" >expected &&
echo "added $VENUS planets/venus.txt" >>expected &&
echo "added $PLANETS planets" >>expected &&
echo "added $MARS mountdir/planets/mars.txt" >expected &&
echo "added $VENUS mountdir/planets/venus.txt" >>expected &&
echo "added $PLANETS mountdir/planets" >>expected &&
echo "added $MOUNTDIR mountdir" >>expected &&
test_cmp expected actual
'
......@@ -325,18 +327,20 @@ test_expect_success "'ipfs add -rn' succeeds" '
'
test_expect_success "'ipfs add -rn' output looks good" '
MDMOONS="QmT8p74vZ2WUmN5bV6DThsEvVkiCESz5ZTT4xoFuF9r1My" &&
MOONS="QmVKvomp91nMih5j6hYBA8KjbiaYvEetU2Q7KvtZkLe9nQ" &&
EUROPA="Qmbjg7zWdqdMaK2BucPncJQDxiALExph5k3NkQv5RHpccu" &&
JUPITER="QmS5mZddhFPLWFX3w6FzAy9QxyYkaxvUpsWCtZ3r7jub9J" &&
SATURN="QmaMagZT4rTE7Nonw8KGSK4oe1bh533yhZrCo1HihSG8FK" &&
TITAN="QmZzppb9WHn552rmRqpPfgU5FEiHH6gDwi3MrB9cTdPwdb" &&
MERCURY="QmUJjVtnN8YEeYcS8VmUeWffTWhnMQAkk5DzZdKnPhqUdK" &&
echo "added $EUROPA moons/jupiter/europa.txt" >expected &&
echo "added $MERCURY moons/mercury.txt" >>expected &&
echo "added $TITAN moons/saturn/titan.txt" >>expected &&
echo "added $JUPITER moons/jupiter" >>expected &&
echo "added $SATURN moons/saturn" >>expected &&
echo "added $MOONS moons" >>expected &&
echo "added $EUROPA mountdir/moons/jupiter/europa.txt" >expected &&
echo "added $MERCURY mountdir/moons/mercury.txt" >>expected &&
echo "added $TITAN mountdir/moons/saturn/titan.txt" >>expected &&
echo "added $JUPITER mountdir/moons/jupiter" >>expected &&
echo "added $SATURN mountdir/moons/saturn" >>expected &&
echo "added $MOONS mountdir/moons" >>expected &&
echo "added $MDMOONS mountdir" >>expected &&
test_cmp expected actual
'
......
......@@ -23,9 +23,10 @@ test_add_skip() {
test_expect_success "'ipfs add -r' did not include . files" '
cat >expected <<-\EOF &&
added QmZy3khu7qf696i5HtkgL2NotsCZ8wzvNZJ1eUdA5n8KaV planets/mars.txt
added QmQnv4m3Q5512zgVtpbJ9z85osQrzZzGRn934AGh6iVEXz planets/venus.txt
added QmR8nD1Vzk5twWVC6oShTHvv7mMYkVh6dApCByBJyV2oj3 planets
added QmZy3khu7qf696i5HtkgL2NotsCZ8wzvNZJ1eUdA5n8KaV mountdir/planets/mars.txt
added QmQnv4m3Q5512zgVtpbJ9z85osQrzZzGRn934AGh6iVEXz mountdir/planets/venus.txt
added QmR8nD1Vzk5twWVC6oShTHvv7mMYkVh6dApCByBJyV2oj3 mountdir/planets
added QmPpwRvA6mWE13tFuHNVCZHvUULbhZ1fZFGwtti9BLkwKh mountdir
EOF
test_cmp expected actual
'
......@@ -36,14 +37,15 @@ test_add_skip() {
test_expect_success "'ipfs add -r --hidden' did include . files" '
cat >expected <<-\EOF &&
added QmcAREBcjgnUpKfyFmUGnfajA1NQS5ydqRp7WfqZ6JF8Dx planets/.asteroids/ceres.txt
added QmZ5eaLybJ5GUZBNwy24AA9EEDTDpA4B8qXnuN3cGxu2uF planets/.asteroids/pallas.txt
added QmaowqjedBkUrMUXgzt9c2ZnAJncM9jpJtkFfgdFstGr5a planets/.charon.txt
added QmU4zFD5eJtRBsWC63AvpozM9Atiadg9kPVTuTrnCYJiNF planets/.pluto.txt
added QmZy3khu7qf696i5HtkgL2NotsCZ8wzvNZJ1eUdA5n8KaV planets/mars.txt
added QmQnv4m3Q5512zgVtpbJ9z85osQrzZzGRn934AGh6iVEXz planets/venus.txt
added Qmf6rbs5GF85anDuoxpSAdtuZPM9D2Yt3HngzjUVSQ7kDV planets/.asteroids
added QmetajtFdmzhWYodAsZoVZSiqpeJDAiaw2NwbM3xcWcpDj planets
added QmcAREBcjgnUpKfyFmUGnfajA1NQS5ydqRp7WfqZ6JF8Dx mountdir/planets/.asteroids/ceres.txt
added QmZ5eaLybJ5GUZBNwy24AA9EEDTDpA4B8qXnuN3cGxu2uF mountdir/planets/.asteroids/pallas.txt
added QmaowqjedBkUrMUXgzt9c2ZnAJncM9jpJtkFfgdFstGr5a mountdir/planets/.charon.txt
added QmU4zFD5eJtRBsWC63AvpozM9Atiadg9kPVTuTrnCYJiNF mountdir/planets/.pluto.txt
added QmZy3khu7qf696i5HtkgL2NotsCZ8wzvNZJ1eUdA5n8KaV mountdir/planets/mars.txt
added QmQnv4m3Q5512zgVtpbJ9z85osQrzZzGRn934AGh6iVEXz mountdir/planets/venus.txt
added Qmf6rbs5GF85anDuoxpSAdtuZPM9D2Yt3HngzjUVSQ7kDV mountdir/planets/.asteroids
added QmetajtFdmzhWYodAsZoVZSiqpeJDAiaw2NwbM3xcWcpDj mountdir/planets
added QmXFvBR9SCSEeBeAAvvv8pWzb6ejehsGx7g6XKYg1uYmd5 mountdir
EOF
test_cmp expected actual
'
......
......@@ -8,40 +8,48 @@ test_description="Test add -w"
add_w_m='QmazHkwx6mPmmCEi1jR5YzjjQd1g5XzKfYQLzRAg7x5uUk'
add_w_1='added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu 4r93
added Qmf82PSsMpUHcrqxa69KG6Qp5yeK7K9BTizXgG3nvzWcNG '
add_w_12='added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu 4r93
added QmVb4ntSZZnT2J2zvCmXKMJc52cmZYH6AB37MzeYewnkjs 4u6ead
added QmZPASVB6EsADrLN8S2sak34zEHL8mx4TAVsPJU9cNnQQJ '
add_w_21='added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu 4r93
added QmVb4ntSZZnT2J2zvCmXKMJc52cmZYH6AB37MzeYewnkjs 4u6ead
added QmZPASVB6EsADrLN8S2sak34zEHL8mx4TAVsPJU9cNnQQJ '
add_w_d1='added QmPcaX84tDiTfzdTn8GQxexodgeWH6mHjSss5Zfr5ojssb _jo7/-s782qgs
added QmaVBqquUuXKjkyWHXaXfsaQUxAnsCKS95VRDHU8PzGA4K _jo7/15totauzkak-
added QmaAHFG8cmhW3WLjofx5siSp44VV25ETN6ThzrU8iAqpkR _jo7/galecuirrj4r
added QmeuSfhJNKwBESp1W9H8cfoMdBfW3AeHQDWXbNXQJYWp53 _jo7/mzo50r-1xidf5zx
added QmYC3u5jGWuyFwvTxtvLYm2K3SpWZ31tg3NjpVVvh9cJaJ _jo7/wzvsihy
added QmQkib3f9XNX5sj6WEahLUPFpheTcwSRJwUCSvjcv8b9by _jo7
added QmNQoesMj1qp8ApE51NbtTjFYksyzkezPD4cat7V2kzbKN '
add_w_d2='added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu 4r93
added QmU9Jqks8TPu4vFr6t7EKkAKQrSJuEujNj1AkzoCeTEDFJ gnz66h/1k0xpx34
added QmSLYZycXAufRw3ePMVH2brbtYWCcWsmksGLbHcT8ia9Ke gnz66h/9cwudvacx
added QmfYmpCCAMU9nLe7xbrYsHf5z2R2GxeQnsm4zavUhX9vq2 gnz66h/9ximv51cbo8
added QmWgEE4e2kfx3b8HZcBk5cLrfhoi8kTMQP2MipgPhykuV3 gnz66h/b54ygh6gs
added QmcLbqEqhREGednc6mrVtanee4WHKp5JnUfiwTTHCJwuDf gnz66h/lbl5
added QmPcaX84tDiTfzdTn8GQxexodgeWH6mHjSss5Zfr5ojssb _jo7/-s782qgs
added QmaVBqquUuXKjkyWHXaXfsaQUxAnsCKS95VRDHU8PzGA4K _jo7/15totauzkak-
added QmaAHFG8cmhW3WLjofx5siSp44VV25ETN6ThzrU8iAqpkR _jo7/galecuirrj4r
added QmeuSfhJNKwBESp1W9H8cfoMdBfW3AeHQDWXbNXQJYWp53 _jo7/mzo50r-1xidf5zx
added QmYC3u5jGWuyFwvTxtvLYm2K3SpWZ31tg3NjpVVvh9cJaJ _jo7/wzvsihy
added QmVaKAt2eVftNKFfKhiBV7Mu5HjCugffuLqWqobSSFgiA7 h3qpecj0
added QmQkib3f9XNX5sj6WEahLUPFpheTcwSRJwUCSvjcv8b9by _jo7
added QmVPwNy8pZegpsNmsjjZvdTQn4uCeuZgtzhgWhRSQWjK9x gnz66h
added QmTmc46fhKC8Liuh5soy1VotdnHcqLu3r6HpPGwDZCnqL1 '
add_w_1='added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu m/4r93
added Qmf82PSsMpUHcrqxa69KG6Qp5yeK7K9BTizXgG3nvzWcNG m
added QmQGVuCh32abrs27LTywHXJoKpDAomhMdtjpLift14saFu '
add_w_12='added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu m/4r93
added QmVb4ntSZZnT2J2zvCmXKMJc52cmZYH6AB37MzeYewnkjs m/4u6ead
added QmZPASVB6EsADrLN8S2sak34zEHL8mx4TAVsPJU9cNnQQJ m
added QmSCjKU1Zco99eEVqsV2b6J3qToXHFMjpGS2GivGzbWTaY '
add_w_21='added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu m/4r93
added QmVb4ntSZZnT2J2zvCmXKMJc52cmZYH6AB37MzeYewnkjs m/4u6ead
added QmZPASVB6EsADrLN8S2sak34zEHL8mx4TAVsPJU9cNnQQJ m
added QmSCjKU1Zco99eEVqsV2b6J3qToXHFMjpGS2GivGzbWTaY '
add_w_d1='added QmPcaX84tDiTfzdTn8GQxexodgeWH6mHjSss5Zfr5ojssb m/t_1wp-8a2/_jo7/-s782qgs
added QmaVBqquUuXKjkyWHXaXfsaQUxAnsCKS95VRDHU8PzGA4K m/t_1wp-8a2/_jo7/15totauzkak-
added QmaAHFG8cmhW3WLjofx5siSp44VV25ETN6ThzrU8iAqpkR m/t_1wp-8a2/_jo7/galecuirrj4r
added QmeuSfhJNKwBESp1W9H8cfoMdBfW3AeHQDWXbNXQJYWp53 m/t_1wp-8a2/_jo7/mzo50r-1xidf5zx
added QmYC3u5jGWuyFwvTxtvLYm2K3SpWZ31tg3NjpVVvh9cJaJ m/t_1wp-8a2/_jo7/wzvsihy
added QmQkib3f9XNX5sj6WEahLUPFpheTcwSRJwUCSvjcv8b9by m/t_1wp-8a2/_jo7
added QmNQoesMj1qp8ApE51NbtTjFYksyzkezPD4cat7V2kzbKN m/t_1wp-8a2
added QmTB438mCvS1o7AYrZN1HiWb327XYDgdbsURhE8XbETFJs m
added QmV7z1Ew9dECFkBnynX2RgsnhLUthS8me4spL9oyXr6tF4 '
add_w_d2='added Qme987pqNBhZZXy4ckeXiR7zaRQwBabB7fTgHurW2yJfNu m/4r93
added QmU9Jqks8TPu4vFr6t7EKkAKQrSJuEujNj1AkzoCeTEDFJ m/ha6f0x7su6/gnz66h/1k0xpx34
added QmSLYZycXAufRw3ePMVH2brbtYWCcWsmksGLbHcT8ia9Ke m/ha6f0x7su6/gnz66h/9cwudvacx
added QmfYmpCCAMU9nLe7xbrYsHf5z2R2GxeQnsm4zavUhX9vq2 m/ha6f0x7su6/gnz66h/9ximv51cbo8
added QmWgEE4e2kfx3b8HZcBk5cLrfhoi8kTMQP2MipgPhykuV3 m/ha6f0x7su6/gnz66h/b54ygh6gs
added QmcLbqEqhREGednc6mrVtanee4WHKp5JnUfiwTTHCJwuDf m/ha6f0x7su6/gnz66h/lbl5
added QmPcaX84tDiTfzdTn8GQxexodgeWH6mHjSss5Zfr5ojssb m/t_1wp-8a2/_jo7/-s782qgs
added QmaVBqquUuXKjkyWHXaXfsaQUxAnsCKS95VRDHU8PzGA4K m/t_1wp-8a2/_jo7/15totauzkak-
added QmaAHFG8cmhW3WLjofx5siSp44VV25ETN6ThzrU8iAqpkR m/t_1wp-8a2/_jo7/galecuirrj4r
added QmeuSfhJNKwBESp1W9H8cfoMdBfW3AeHQDWXbNXQJYWp53 m/t_1wp-8a2/_jo7/mzo50r-1xidf5zx
added QmYC3u5jGWuyFwvTxtvLYm2K3SpWZ31tg3NjpVVvh9cJaJ m/t_1wp-8a2/_jo7/wzvsihy
added QmVaKAt2eVftNKFfKhiBV7Mu5HjCugffuLqWqobSSFgiA7 m/t_1wp-8a2/h3qpecj0
added QmQkib3f9XNX5sj6WEahLUPFpheTcwSRJwUCSvjcv8b9by m/t_1wp-8a2/_jo7
added QmaTZY4aC4BPvDnaYrLYDGzTyPhDgrgp7HQvdtzanUbTEj m/t_1wp-8a2
added QmVPwNy8pZegpsNmsjjZvdTQn4uCeuZgtzhgWhRSQWjK9x m/ha6f0x7su6/gnz66h
added Qmca84ppqG7WVwSEQKpqxjvsXiZXdtmn4e8sewg5bxUDCf m/ha6f0x7su6
added QmNygffraYdhSoNBSkG1CgRfd7hvrSsYZiijktX6Zme4vQ m
added QmdTgtGsMb8gpGfzaTAhsBnYwNc7KSXptp9zyzrP4Ed1Nt '
add_w_r='QmcCksBMDuuyuyfAMMNzEAx6Z7jTrdRy9a23WpufAhG9ji'
......
#!/bin/sh
#
# Copyright (c) 2016 Jeromy Johnson
# MIT Licensed; see the LICENSE file in this repository.
#
test_description="Test adding multiple directories"
. lib/test-lib.sh
test_expect_success "make some setup directories" '
mkdir -p a/foo/bar/fish &&
mkdir -p a/foo/cats &&
mkdir -p a/dogs/baz &&
echo "stuff" > a/foo/bar/fish/food &&
echo "blah blah" > a/foo/cats/meow &&
echo "ipfs is cool" > a/dogs/baz/bazbaz &&
mkdir -p other/a/foo/cats &&
mkdir -p other/a/ipfs &&
echo "meoooowwww" > other/a/foo/cats/meow &&
echo "hashing hashing" > other/a/ipfs/blah &&
mkdir -p something/example &&
echo "example" > something/example/text
'
test_add_many_r() {
test_expect_success "add multiple directories at the same time" '
ipfs add -r a other/a something > add_out
'
test_expect_success "output looks correct" '
grep "added QmU5Ekbnb9H8bLz6ECEnMDnkEZh5JoY9tXHGCBxnsLqsDg a/foo/cats/meow" add_out &&
grep "added QmNwTsPq4BEBwuQ1aFUPZ6ux3P7GnupfQd1mBre19iSej5 other/a/foo/cats/meow" add_out &&
grep "added QmTHApDiVaLa2yc8G6Jg6booheoFGffWuSKTqwQ4zjP6fQ a" add_out &&
grep "added QmSsiWzY9yxtcRMsKvYivDKzBN8kftAgsVjpyGAxstj4Aw other" add_out &&
grep "added QmWGDSqhr53etAVa35XBCmknWvMuuUU5VMS7zf3TYNnm89 something" add_out
'
}
test_init_ipfs
test_add_many_r
test_launch_ipfs_daemon
test_add_many_r
test_kill_ipfs_daemon
test_done
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论