Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display cids with associated filename #124

Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,6 @@ dist

# TernJS port file
.tern-port

# IDE files
.idea/
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ $ ipfs-car --pack path/to/files --output path/to/write/a.car
# use --wrapWithDirectory false to avoid this.
$ ipfs-car --pack path/to/file --wrapWithDirectory false --output path/to/write/a.car

# displays which file is being packed
$ ipfs-car --pack path/to/files --verbose
```

`--unpack` files from a .car
Expand All @@ -83,6 +85,9 @@ $ ipfs-car --list-roots path/to/my.car

# list the cids for all the blocks.
$ ipfs-car --list-cids path/to/my.car

# list both the files and their CIDs.
$ ipfs-car --list-full path/to/my.car
```

## API
Expand All @@ -103,7 +108,7 @@ To unpack content-addressable archives to files, you can use the functions provi

### `ipfs-car/pack`

Takes an [ImportCandidateStream](/~https://github.com/ipfs/js-ipfs/blob/master/packages/ipfs-core-types/src/utils.ts#L21) and returns a a [CAR writer](/~https://github.com/ipld/js-car#carwriter) async iterable.
Takes an [ImportCandidateStream](/~https://github.com/ipfs/js-ipfs/blob/master/packages/ipfs-core-types/src/utils.ts#L21) and returns a [CAR writer](/~https://github.com/ipld/js-car#carwriter) async iterable.

```js
import { pack } from 'ipfs-car/pack'
Expand All @@ -112,7 +117,7 @@ import { MemoryBlockStore } from 'ipfs-car/blockstore/memory' // You can also us
const { root, out } = await pack({
input: [new Uint8Array([21, 31, 41])],
blockstore: new MemoryBlockStore(),
wrapWithDirectory: true // Wraps input into a directory. Defaults to `true`
wrapWithDirectory: true, // Wraps input into a directory. Defaults to `true`
maxChunkSize: 262144 // The maximum block size in bytes. Defaults to `262144`. Max safe value is < 1048576 (1MiB)
})

Expand Down Expand Up @@ -205,7 +210,7 @@ for await (const file of unpackStream(inStream)) {
`unpackStream` takes an options object, allowing you to pass in a `BlockStore` implementation. The blocks are unpacked from the stream in the order they appear, which may not be the order needed to reassemble them into the Files and Directories they represent. The blockstore is used to store the blocks as they are consumed from the stream. Once the stream is consumed, the blockstore provides the random access by CID to the blocks, needed to assemble the tree.

The default is a [`MemoryBlockStore`](./src/blockstore/memory.ts), that will store all the blocks in memory.
For larger CARs in the browser you can use IndexedDB by passing in an [IdbBlocksStore]('./src/blockstore/idb.ts'), and in Node.js you can provide a [FsBlockStore] instance to write blocks to the tmp dir.
For larger CARs in the browser you can use IndexedDB by passing in an [IdbBlocksStore](./src/blockstore/idb.ts), and in Node.js you can provide an [FsBlockStore] instance to write blocks to the tmp dir.

```js
/* browser */
Expand All @@ -224,7 +229,7 @@ for await (const file of unpackStream(res.body, { blockstore })) {
blockstore.destroy()
```

When providing a custom Blockstore, it is your responsibiltiy to call `blockstore.destroy()` when you're finished. Failing to do so will fill up the users storage.
When providing a custom Blockstore, it is your responsibility to call `blockstore.destroy()` when you're finished. Failing to do so will fill up the users' storage.

### `ipfs-car/unpack/fs`

Expand Down
24 changes: 22 additions & 2 deletions src/cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import meow from 'meow'
import { CID } from 'multiformats';
import { packToFs } from '../pack/fs'
import { unpackToFs, unpackStreamToFs } from '../unpack/fs'
import { listFilesInCar, listCidsInCar, listRootsInCar } from './lib'
import {listFilesInCar, listCidsInCar, listRootsInCar, listFilesAndCidsInCar} from './lib'
import {printUnixFsContent} from "./verbose-handler";

interface Flags {
output?: string,
Expand All @@ -14,7 +15,9 @@ interface Flags {
list?: string,
listCids?: string
listRoots?: string
listFull?: string
wrapWithDirectory?: boolean
verbose?: boolean
}

const options = {
Expand Down Expand Up @@ -45,10 +48,18 @@ const options = {
listRoots: {
type: 'string'
},
listFull: {
type: 'string'
},
wrapWithDirectory: {
type: 'boolean',
alias: 'w',
default: true
},
verbose: {
type: 'boolean',
alias: 'v',
default: false
}
}
} as const;
Expand All @@ -72,6 +83,9 @@ const cli = meow(`
# pack files without wrapping with top-level directory
$ ipfs-car --wrapWithDirectory false --pack path/to/files --output path/to/write/a.car

# pack files and display which one is being packed
$ ipfs-car --pack /path/to/files --verbose

Unpacking files from a .car

# write 1 or more files to the current working dir.
Expand All @@ -97,6 +111,9 @@ const cli = meow(`
# list the files.
$ ipfs-car --list path/to/my.car

# list both the files' path and their CIDs.
$ ipfs-car --list-full path/to/my.car

TL;DR
--pack <path> --output <my.car>
--unpack <my.car> --output <path>
Expand All @@ -105,7 +122,7 @@ const cli = meow(`

async function handleInput ({ flags }: { flags: Flags }) {
if (flags.pack) {
const { root, filename } = await packToFs({input: flags.pack, output: flags.output, wrapWithDirectory: flags.wrapWithDirectory})
const { root, filename } = await packToFs({input: flags.pack, output: flags.output, wrapWithDirectory: flags.wrapWithDirectory, customHandler: flags.verbose ? printUnixFsContent : undefined})
// tslint:disable-next-line: no-console
console.log(`root CID: ${root.toString()}`)
// tslint:disable-next-line: no-console
Expand All @@ -127,6 +144,9 @@ async function handleInput ({ flags }: { flags: Flags }) {
} else if (flags.listCids) {
return listCidsInCar({input: flags.listCids})

} else if (flags.listFull) {
return listFilesAndCidsInCar({input: flags.listFull})

} else if (!process.stdin.isTTY) {
// maybe stream?
// tslint:disable-next-line: no-console
Expand Down
8 changes: 8 additions & 0 deletions src/cli/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,12 @@ export async function listRootsInCar ({input}: {input: string}) {
// tslint:disable-next-line: no-console
console.log(root.toString())
}
}

export async function listFilesAndCidsInCar({input}: {input: string}) {
const carReader = await CarIndexedReader.fromFile(input)
for await (const file of unpack(carReader)) {
// tslint:disable-next-line: no-console
console.log(`${file.cid.toString()} ${file.path}`)
}
}
9 changes: 9 additions & 0 deletions src/cli/verbose-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {ImportResult} from "ipfs-unixfs-importer";

export async function *printUnixFsContent(root: AsyncGenerator<ImportResult, void, unknown>): AsyncGenerator<ImportResult, void, unknown> {
for await (const entry of root) {
// tslint:disable-next-line:no-console
console.log(`${entry.cid.toString()} ${entry.path}`)
yield entry
}
}
5 changes: 3 additions & 2 deletions src/pack/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export interface PackToFsProperties extends PackProperties {
output?: string
}

export async function packToFs ({ input, output, blockstore: userBlockstore, hasher, maxChunkSize, maxChildrenPerNode, wrapWithDirectory, rawLeaves }: PackToFsProperties) {
export async function packToFs ({ input, output, blockstore: userBlockstore, hasher, maxChunkSize, maxChildrenPerNode, wrapWithDirectory, rawLeaves, customHandler }: PackToFsProperties) {
const blockstore = userBlockstore ? userBlockstore : new FsBlockStore()
const location = output || `${os.tmpdir()}/${(parseInt(String(Math.random() * 1e9), 10)).toString() + Date.now()}`
const writable = fs.createWriteStream(location)
Expand All @@ -25,7 +25,8 @@ export async function packToFs ({ input, output, blockstore: userBlockstore, has
maxChunkSize,
maxChildrenPerNode,
wrapWithDirectory,
rawLeaves
rawLeaves,
customHandler
})

if (!userBlockstore) {
Expand Down
5 changes: 3 additions & 2 deletions src/pack/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import last from 'it-last'
import pipe from 'it-pipe'

import { CarWriter } from '@ipld/car'
import { importer } from 'ipfs-unixfs-importer'
import {importer, ImportResult} from 'ipfs-unixfs-importer'
import { getNormaliser } from './utils/normalise-input'
import type { ImportCandidateStream, ImportCandidate } from 'ipfs-core-types/src/utils'
import type { MultihashHasher } from 'multiformats/hashes/interface'
export type { ImportCandidateStream }

import { Blockstore } from '../blockstore/index'
import { Blockstore } from '../blockstore'
import { MemoryBlockStore } from '../blockstore/memory'
import { unixfsImporterOptionsDefault } from './constants'

Expand All @@ -19,6 +19,7 @@ export interface PackProperties {
maxChildrenPerNode?: number,
wrapWithDirectory?: boolean,
hasher?: MultihashHasher,
customHandler?: (sources: AsyncGenerator<ImportResult, void, unknown>) => AsyncGenerator<any, void, unknown>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's call this customStreamSink instead to better illustrate what it does

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No problem I'll change that on Monday

/**
* Use raw codec for leaf nodes. Default: true.
*/
Expand Down
7 changes: 4 additions & 3 deletions src/pack/stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import last from 'it-last'
import pipe from 'it-pipe'

import { CarWriter } from '@ipld/car'
import { importer } from 'ipfs-unixfs-importer'
import {importer, ImportResult} from 'ipfs-unixfs-importer'
import { normaliseInput } from 'ipfs-core-utils/files/normalise-input-multiple'
import globSource from 'ipfs-utils/src/files/glob-source.js'

Expand All @@ -21,7 +21,7 @@ export interface PackToStreamProperties extends PackProperties {
}

// Node version of toCar with Node Stream Writable
export async function packToStream ({ input, writable, blockstore: userBlockstore, hasher, maxChunkSize, maxChildrenPerNode, wrapWithDirectory, rawLeaves }: PackToStreamProperties) {
export async function packToStream ({ input, writable, blockstore: userBlockstore, hasher, maxChunkSize, maxChildrenPerNode, wrapWithDirectory, rawLeaves, customHandler }: PackToStreamProperties) {
if (!input || (Array.isArray(input) && !input.length)) {
throw new Error('given input could not be parsed correctly')
}
Expand All @@ -40,7 +40,8 @@ export async function packToStream ({ input, writable, blockstore: userBlockstor
maxChildrenPerNode: maxChildrenPerNode || unixfsImporterOptionsDefault.maxChildrenPerNode,
wrapWithDirectory: wrapWithDirectory === false ? false : unixfsImporterOptionsDefault.wrapWithDirectory,
rawLeaves: rawLeaves == null ? unixfsImporterOptionsDefault.rawLeaves : rawLeaves
})
}),
customHandler ? customHandler : (sources: AsyncGenerator<ImportResult, void, unknown>) => sources
))

if (!rootEntry || !rootEntry.cid) {
Expand Down