Skip to content

Implement the command "ipfs repo has"#4541

Closed
MichaelMure wants to merge 5 commits intoipfs:masterfrom
MichaelMure:has2
Closed

Implement the command "ipfs repo has"#4541
MichaelMure wants to merge 5 commits intoipfs:masterfrom
MichaelMure:has2

Conversation

@MichaelMure
Copy link
Copy Markdown
Contributor

@MichaelMure MichaelMure commented Jan 3, 2018

Following #4028, I implemented a ipfs repo has command that tell if something is available locally or not.

USAGE
  ipfs repo has <key>... - Show if an object is available locally

SYNOPSIS
  ipfs repo has [--recursive | -r] [--] <key>...

ARGUMENTS

  <key>... - Key(s) to check for locality.

OPTIONS

  -r, --recursive bool - Check recursively the graph of objects to build more precise stats.

Results look like this:

non-recursive
$ ipfs repo has QmYGVhjTfVvBAAf2SAWMJsTDheo7UuyjQigGahmB8YU3ZH
QmYGVhjTfVvBAAf2SAWMJsTDheo7UuyjQigGahmB8YU3ZH	local
$ ipfs repo has QmPXvegq26x982cQjSfbTvSzZXn7GiaMwhhVPHkeTEhrPT
QmPXvegq26x982cQjSfbTvSzZXn7GiaMwhhVPHkeTEhrPT	non local

recursive
$ ipfs repo has -r QmQFnam7qMXfF8R1D3qrETCgESnVP8gt6iEnAbyG73gyqm
QmQFnam7qMXfF8R1D3qrETCgESnVP8gt6iEnAbyG73gyqm	unknow
$ ipfs repo has -r QmQLXHs7K98JNQdWrBB2cQLJahPhmupbDjRuH1b9ibmwVa
QmQLXHs7K98JNQdWrBB2cQLJahPhmupbDjRuH1b9ibmwVa	incomplete	4.1 MB of 6.9 MB (60.31%)
$ ipfs repo has -r QmeUKqHMr5r6wJzt3AVScnUAyC4TkdZGjYJNaFBCL1BmAv
QmeUKqHMr5r6wJzt3AVScnUAyC4TkdZGjYJNaFBCL1BmAv	complete	3.2 MB of 3.2 MB (100.00%)

License: MIT
Signed-off-by: Michael Muré batolettre@gmail.com

var repoHasCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Show if an object is available locally",
ShortDescription: ``,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some description would be nice

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

License: MIT
Signed-off-by: Michael Muré <batolettre@gmail.com>
License: MIT
Signed-off-by: Michael Muré <batolettre@gmail.com>
License: MIT
Signed-off-by: Michael Muré <batolettre@gmail.com>
Copy link
Copy Markdown
Member

@magik6k magik6k left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Other than few comments this looks mostly good.

state = "incomplete"
}
if lo.SizeTotal <= 0 {
state = "unknow"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: "unknown"

if lo.Local {
state = "local"
} else {
state = "non local"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

local/non local sounds a bit weird to me, not sure what would sound better though.

Copy link
Copy Markdown
Contributor Author

@MichaelMure MichaelMure Jan 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm open to suggestion ¯\_(ツ)_/¯

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think unknown instead of non local would be appropriate as we do not have any guarantees the key exists elsewhere/remotely.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But that's the point of this command, to tell if something is stored in the node, regardless of what happen elsewhere.
To illustrate, my usecase is a file sharing application. I want to know if this particular data has finished downloading or if the data the user want to share is still properly available locally.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"found", "missing"?

Type: localityOutput{},
}

func walkBlock(ctx context.Context, dagserv dag.DAGService, merkleNode node.Node) (bool, int, int, error) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd just call merkleNode a nd as that's what it's usually called

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should also probably get recursive or depth pram as it looks like that we traverse the tree even if --recursive is not specified

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this function is not called without recursive


Subcommands: map[string]*cmds.Command{
"stat": repoStatCmd,
"has": repoHasCmd,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imo this doesn't fit into ipfs repo. ipfs block or ipfs dag would be a better place (I'm not sure which one is better)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I choose ipfs repo because we are interested about what is inside the repo and nothing else. The question is 'is this stored on my node ?'.

Both ipfs block and ipfs dag will do network request and treat the graph of object as something that exist somewhere, regardless of the repo state.

License: MIT
Signed-off-by: Michael Muré <batolettre@gmail.com>
@MichaelMure
Copy link
Copy Markdown
Contributor Author

Some tests would be nice, but I'm not sure how. Is there some graph of file/directory that I could use ? The webui ?

@whyrusleeping
Copy link
Copy Markdown
Member

@MichaelMure you should just be able to add stuff in a sharness test and test the command out. You can also manually craft a dag that you don't have parts of

@whyrusleeping whyrusleeping requested review from a user and Stebalien January 4, 2018 04:04
Copy link
Copy Markdown
Member

@Stebalien Stebalien left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, I'm going to raise a bit of a fuss here. This is unixfs specific (download sizes) and should probably be a part of ipfs files ls and ipfs ls. (with --local, --size, and --tree flags). See my comment below.

It would be useful to also have a dag specific command (although I'd put that under ipfs dag but that wouldn't be able to give you all the information you want.

}

// Decode all the keys
var keys []*cid.Cid
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might as well preallocate this.

cmdkit.StringArg("key", true, true, "Key(s) to check for locality.").EnableStdin(),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("recursive", "r", "Check recursively the graph of objects to build more precise stats"),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably have a quiet option (exits with a zero status if we have everything).

`,
},
Arguments: []cmdkit.Argument{
cmdkit.StringArg("key", true, true, "Key(s) to check for locality.").EnableStdin(),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CID.

}

func walkBlock(ctx context.Context, dagserv dag.DAGService, nd node.Node) (bool, int, int, error) {
stat, err := nd.Stat()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So... time to air a dirty secret... This only exists for unixfs. Don't use it. You can't know how much of a dag is missing (only how much of a unixfs filesystem is missing).

Have you considered using the ipfs files feature and extending the ls command? I think this functionality may fit better there. Also, MFS (ipfs files) is a much nicer way to work with IPFS.

Example:

> ipfs files cp /ipfs/QmId /some/path
> ipfs files ls --local --tree --size /some/path
/some/path
└── (1MiB/2MiB) foo
    ├── (2MiB) bar.go
    └── (2MiB) baz

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, i'm on-board with this functionality being in ipfs files. Especially since we should be able to do: ipfs files ls --local --tree --size /ipfs/QmFooBar (skipping the copy step)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(really, we should merge ipfs files {ls,etc.} and ipfs {ls,}.

Especially since we should be able to do...

I agree but we can't currently. Is there an issue for this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So... time to air a dirty secret... This only exists for unixfs. Don't use it. You can't know how much of a dag is missing (only how much of a unixfs filesystem is missing).

I'm confused. If I'm looking at the code of Stat(), I don't see anything specific to unixfs. This does works as well:

$ echo 'test' | ipfs add
added QmeomffUNfmQy76CQGy9NdmqEnnHU9soCexBnGU3ezPHVH QmeomffUNfmQy76CQGy9NdmqEnnHU9soCexBnGU3ezPHVH
$ ipfs object stat QmeomffUNfmQy76CQGy9NdmqEnnHU9soCexBnGU3ezPHVH
NumLinks: 0
BlockSize: 13
LinksSize: 2
DataSize: 11
CumulativeSize: 13

What am I missing ?
Do you mean that Stat() is not implemented properly for every kind of ipld block ? If so, why ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More questions:

  • ipfs files is supposed to be MFS, right ? So if ipfs repo has is moved to ipfs files ls --local --tree --size, it will only works inside MFS. I'm not using mfs for my project so it's not helpful for me.
  • what would the --size parameter really mean ? Using it alone would intuitively means 'give me various size information you have'. But adding --local would somehow change it's meaning to 'check that everything is local properly and report how much if not' ?

Moving the feature to 'ipfs files ls' feels like shoe-horning to me. I think there is space for a proper 'node administrator' command to inspect what is inside a repository (and in my case help me drive ipfs properly).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean that Stat() is not implemented properly for every kind of ipld block ? If so, why ?

Yes. To be precise, Stat, etc. only apply to DagPB IPLD nodes (so, technically not only unixfs). One thing on my todo list is to fix the go interfaces and get rid of that method.

Why? IPLD came after unixfs and the merkledag (DagPB). We wanted to generalize the concept and create a system that:

  1. Allowed structured linked data. DagPB does not allow much structure. We wanted something more like JSON.
  2. Allowed us to interpret and treat all existing existing merkledags (like Ethereum and git) as one big merkleforest. That way, we could write one set of tools to work with any merkle-linked data.

That means we couldn't require any metadata fields like Size. We wouldn't have, e.g., been able to interpret a git repo as an IPLD dag if we did that.


I'm not using mfs for my project so it's not helpful for me.

Aside: IMO, you should. It makes managing files much simpler. Eventually, we'd like to using MFS for all local file management (where /ipfs and /ipns would be "virtual" directories within the MFS tree. Eventually, ipfs CMD will probably be aliases for ipfs files CMD (possibly with some path restrictions).

However, for now, it would probably be simpler to just add the flags to the ipfs ls command (we can work on unifying the commands later). That should work for your purpose.

what would the --size parameter really mean ? Using it alone would intuitively means 'give me various size information you have'. But adding --local would somehow change it's meaning to 'check that everything is local properly and report how much if not' ?

Sorry, that was poorly explained.

  • --size would mean "report the size of the file and how much has been downloaded so far". We could also just add a separate --local-size flag for that.
  • --local would mean "don't fetch anything when running this command". Ideally, we'd provide that as an argument to all commands. Otherwise, ls --tree would block until all directories (but not their files) have been fetched.

I think there is space for a proper 'node administrator' command to inspect what is inside a repository (and in my case help me drive ipfs properly).

It would be useful to have a command to check and see if we have locally something without fetching it. However, we can't make a general purpose command for getting size information about arbitrary IPLD nodes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, that's helpful.

Aside: IMO, you should. It makes managing files much simpler. Eventually, we'd like to using MFS for all local file management (where /ipfs and /ipns would be "virtual" directories within the MFS tree. Eventually, ipfs CMD will probably be aliases for ipfs files CMD (possibly with some path restrictions).

For some context, my project is https://github.com/MichaelMure/Arbore. It's a social file sharing app. For a broader view on how I use IPFS, see #3866

Unless I miss something (entirely possible), I see MFS as more a problem than a help for me. I'm using the IPFS repository as a black box / buffer area. In particular, I need to:

  • import easily files/directory (ipfs add -r). I get a nice progress from the API. I don't understand how to do that with MFS. On top of that I would need to manage path inside of MFS where I really don't need to.
  • be able to trigger a download (ipfs pin add). MFS doesn't seems to support that (?). Each share in Arbore has it's own root CID, so it's very easy to manage. If I want to remove a share from IPFS, I just pin rm the root, trigger a garbage collect and IPFS will deal with everything.
  • be able to use the filestore. Not using twice the disk size when you handle big files is a nice touch. I don't think MFS is able to do that.
  • be able to encrypt files. Ideally it will be done by IPFS when encryption support is added. Will that be supported by MFS ?

It would be useful to have a command to check and see if we have locally something without fetching it. However, we can't make a general purpose command for getting size information about arbitrary IPLD nodes.

What about a command that return detailed size information only if the nodes are compatible ? If the cumulative size is not available, we are still able to tell if everything is local or not, and how much data is here (using Node.Size() recursively).


So, unless I got it wrong, MFS is not an option for me. I see two viable options for me:

  • move the feature to ipfs ls
  • fix the current PR for ipfs repo has to not use Node.Stat()

@Stebalien @whyrusleeping Thoughts ?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MichaelMure

  • import easily files/directory (ipfs add -r). I get a nice progress from the API. I don't understand how to do that with MFS. On top of that I would need to manage path inside of MFS where I really don't need to.

Keep using ipfs add, Its really supposed to just be an alias for ipfs files add but that command doesnt exist yet (see the javascript api).

  • be able to trigger a download (ipfs pin add). MFS doesn't seems to support that (?). Each share in Arbore has it's own root CID, so it's very easy to manage. If I want to remove a share from IPFS, I just pin rm the root, trigger a garbage collect and IPFS will deal with everything.

For now, keep that flow. We need to add a command to ipfs files that lets you fully sync a given bit of content. Like ipfs files cp —full-sync /ipfs/QmFooBar /path/to/thing

  • be able to use the filestore. Not using twice the disk size when you handle big files is a nice touch. I don't think MFS is able to do that.

Keep using the filestore, ipfs files doesnt care where the blocks are.

  • be able to encrypt files. Ideally it will be done by IPFS when encryption support is added. Will that be supported by MFS ?

Yeah, It really won't get in your way at all for any of these concerns.

To be clear, what we're recommending (and as I said in my previous comment) the command would look like:

ipfs files ls —local —tree —size /ipfs/QmFooBar

Note that the content in question is not explicitly within the mfs namespace.

if lo.Local {
state = "local"
} else {
state = "non local"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"found", "missing"?

License: MIT
Signed-off-by: Michael Muré <batolettre@gmail.com>
@whyrusleeping
Copy link
Copy Markdown
Member

@Stebalien Heres a proposal:

USAGE
  ipfs files tree <path>... - Show information about a given subtree

SYNOPSIS
  ipfs files tree [--summary | --local] [--] <key>...

ARGUMENTS

  <path>... - Path to print information about.

OPTIONS

  --summary bool - Print a summary of tree's information.
  --local bool - Provide information about locality of data.

@Stebalien
Copy link
Copy Markdown
Member

@whyrusleeping 👍 for not overloading the ls command.

What exactly would the summary include? Would the tree always include file sizes, types, etc?

@eingenito
Copy link
Copy Markdown
Contributor

I think this PR was superseded by #4638. Closing and feel free to reopen if I got that wrong.

@eingenito eingenito closed this Dec 5, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants