Implement the command "ipfs repo has"#4541
Conversation
core/commands/repo.go
Outdated
| var repoHasCmd = &cmds.Command{ | ||
| Helptext: cmdkit.HelpText{ | ||
| Tagline: "Show if an object is available locally", | ||
| ShortDescription: ``, |
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>
magik6k
left a comment
There was a problem hiding this comment.
Thanks! Other than few comments this looks mostly good.
core/commands/repo.go
Outdated
| state = "incomplete" | ||
| } | ||
| if lo.SizeTotal <= 0 { | ||
| state = "unknow" |
core/commands/repo.go
Outdated
| if lo.Local { | ||
| state = "local" | ||
| } else { | ||
| state = "non local" |
There was a problem hiding this comment.
local/non local sounds a bit weird to me, not sure what would sound better though.
There was a problem hiding this comment.
I'm open to suggestion ¯\_(ツ)_/¯
There was a problem hiding this comment.
I think unknown instead of non local would be appropriate as we do not have any guarantees the key exists elsewhere/remotely.
There was a problem hiding this comment.
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.
core/commands/repo.go
Outdated
| Type: localityOutput{}, | ||
| } | ||
|
|
||
| func walkBlock(ctx context.Context, dagserv dag.DAGService, merkleNode node.Node) (bool, int, int, error) { |
There was a problem hiding this comment.
I'd just call merkleNode a nd as that's what it's usually called
There was a problem hiding this comment.
This should also probably get recursive or depth pram as it looks like that we traverse the tree even if --recursive is not specified
There was a problem hiding this comment.
No, this function is not called without recursive
|
|
||
| Subcommands: map[string]*cmds.Command{ | ||
| "stat": repoStatCmd, | ||
| "has": repoHasCmd, |
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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>
|
Some tests would be nice, but I'm not sure how. Is there some graph of file/directory that I could use ? The webui ? |
|
@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 |
Stebalien
left a comment
There was a problem hiding this comment.
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.
core/commands/repo.go
Outdated
| } | ||
|
|
||
| // Decode all the keys | ||
| var keys []*cid.Cid |
There was a problem hiding this comment.
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"), |
There was a problem hiding this comment.
Should probably have a quiet option (exits with a zero status if we have everything).
core/commands/repo.go
Outdated
| `, | ||
| }, | ||
| Arguments: []cmdkit.Argument{ | ||
| cmdkit.StringArg("key", true, true, "Key(s) to check for locality.").EnableStdin(), |
| } | ||
|
|
||
| func walkBlock(ctx context.Context, dagserv dag.DAGService, nd node.Node) (bool, int, int, error) { | ||
| stat, err := nd.Stat() |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
(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?
There was a problem hiding this comment.
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 ?
There was a problem hiding this comment.
More questions:
ipfs filesis supposed to be MFS, right ? So ifipfs repo hasis moved toipfs 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
--sizeparameter really mean ? Using it alone would intuitively means 'give me various size information you have'. But adding--localwould 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).
There was a problem hiding this comment.
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:
- Allowed structured linked data. DagPB does not allow much structure. We wanted something more like JSON.
- 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.
--sizewould mean "report the size of the file and how much has been downloaded so far". We could also just add a separate--local-sizeflag for that.--localwould mean "don't fetch anything when running this command". Ideally, we'd provide that as an argument to all commands. Otherwise,ls --treewould 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.
There was a problem hiding this comment.
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 justpin rmthe 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 hasto not useNode.Stat()
@Stebalien @whyrusleeping Thoughts ?
There was a problem hiding this comment.
- 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 justpin rmthe 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.
core/commands/repo.go
Outdated
| if lo.Local { | ||
| state = "local" | ||
| } else { | ||
| state = "non local" |
License: MIT Signed-off-by: Michael Muré <batolettre@gmail.com>
|
@Stebalien Heres a proposal: |
|
@whyrusleeping 👍 for not overloading the What exactly would the summary include? Would the tree always include file sizes, types, etc? |
|
I think this PR was superseded by #4638. Closing and feel free to reopen if I got that wrong. |
Following #4028, I implemented a
ipfs repo hascommand that tell if something is available locally or not.Results look like this:
License: MIT
Signed-off-by: Michael Muré batolettre@gmail.com