From cd9e903c2ccac61372eaa64a61b4a8f3d79f9d4a Mon Sep 17 00:00:00 2001 From: Alex Potsides Date: Sun, 3 Dec 2023 08:17:42 +0000 Subject: [PATCH] fix: convert date to mtime in glob source (#106) The UnixFS importer requires mtimes to follow the `Mtime` interface so convert files/folders read from glob source. --- packages/interop/.aegir.js | 2 +- packages/interop/package.json | 5 +- .../test/fixtures/create-helia.browser.ts | 6 +- .../interop/test/fixtures/create-helia.ts | 6 +- packages/interop/test/fixtures/create-kubo.ts | 3 +- packages/unixfs/src/utils/glob-source.ts | 3 +- packages/unixfs/src/utils/to-mtime.ts | 57 +++++++++++++++++ .../unixfs/test/utils/glob-source.spec.ts | 24 ++++---- packages/unixfs/test/utils/to-mtime.spec.ts | 61 +++++++++++++++++++ 9 files changed, 147 insertions(+), 20 deletions(-) create mode 100644 packages/unixfs/src/utils/to-mtime.ts create mode 100644 packages/unixfs/test/utils/to-mtime.spec.ts diff --git a/packages/interop/.aegir.js b/packages/interop/.aegir.js index 498799ac..35da9fa6 100644 --- a/packages/interop/.aegir.js +++ b/packages/interop/.aegir.js @@ -12,7 +12,7 @@ export default { host: '127.0.0.1', port: ipfsdPort }, { - ipfsBin: (await import('go-ipfs')).default.path(), + ipfsBin: (await import('kubo')).default.path(), kuboRpcModule: kuboRpcClient, ipfsOptions: { config: { diff --git a/packages/interop/package.json b/packages/interop/package.json index 7ee17a56..c75c60f4 100644 --- a/packages/interop/package.json +++ b/packages/interop/package.json @@ -44,7 +44,6 @@ "test:chrome": "aegir test -t browser --cov", "test:chrome-webworker": "aegir test -t webworker", "test:firefox": "aegir test -t browser -- --browser firefox", - "test:firefox-webworker": "aegir test -t webworker -- --browser firefox", "test:node": "aegir test -t node --cov", "test:electron-main": "aegir test -t electron-main" }, @@ -58,7 +57,7 @@ "aegir": "^41.0.0", "blockstore-core": "^4.0.1", "datastore-core": "^9.0.3", - "go-ipfs": "^0.22.0", + "kubo": "^0.24.0", "helia": "^2.0.1", "ipfs-core-types": "^0.14.0", "ipfs-unixfs-importer": "^15.1.0", @@ -72,7 +71,7 @@ }, "browser": { "./dist/test/fixtures/create-helia.js": "./dist/test/fixtures/create-helia.browser.js", - "go-ipfs": false + "kubo": false }, "private": true } diff --git a/packages/interop/test/fixtures/create-helia.browser.ts b/packages/interop/test/fixtures/create-helia.browser.ts index 867de492..f94bc9df 100644 --- a/packages/interop/test/fixtures/create-helia.browser.ts +++ b/packages/interop/test/fixtures/create-helia.browser.ts @@ -5,6 +5,7 @@ import { all } from '@libp2p/websockets/filters' import { MemoryBlockstore } from 'blockstore-core' import { MemoryDatastore } from 'datastore-core' import { createHelia } from 'helia' +import { bitswap } from 'helia/block-brokers' import { createLibp2p, type Libp2pOptions } from 'libp2p' import { identifyService } from 'libp2p/identify' import type { Helia } from '@helia/interface' @@ -39,7 +40,10 @@ export async function createHeliaNode (config: Libp2pOptions = {}): Promise 1) { + output.nsecs = mtimeLike[1] + } + + return output + } + + if (typeof mtimeLike.Seconds === 'number') { + const output: Mtime = { + secs: BigInt(mtimeLike.Seconds) + } + + if (mtimeLike.FractionalNanoseconds != null) { + output.nsecs = mtimeLike.FractionalNanoseconds + } + + return output + } + + throw new Error('Cannot convert object to mtime') +} + +function dateToTimespec (date: Date): Mtime { + const ms = date.getTime() + const secs = Math.floor(ms / 1000) + + return { + secs: BigInt(secs), + nsecs: (ms - (secs * 1000)) * 1000 + } +} + +function isMtime (obj: any): obj is Mtime { + return typeof obj.secs === 'bigint' +} diff --git a/packages/unixfs/test/utils/glob-source.spec.ts b/packages/unixfs/test/utils/glob-source.spec.ts index ebb09c9c..0021597f 100644 --- a/packages/unixfs/test/utils/glob-source.spec.ts +++ b/packages/unixfs/test/utils/glob-source.spec.ts @@ -7,6 +7,8 @@ import { expect } from 'aegir/chai' import all from 'it-all' import { isNode } from 'wherearewe' import { globSource } from '../../src/utils/glob-source.js' +import { toMtime } from '../../src/utils/to-mtime.js' +import type { Mtime } from 'ipfs-unixfs' function fixtureDir (): string { const filename = fileURLToPath(import.meta.url) @@ -23,8 +25,8 @@ function findMode (file: string): number { return fs.statSync(fixture(file)).mode } -function findMtime (file: string): Date { - return fs.statSync(fixture(file)).mtime +function findMtime (file: string): Mtime { + return toMtime(fs.statSync(fixture(file)).mtime) } describe('glob-source', () => { @@ -228,28 +230,28 @@ describe('glob-source', () => { } const result = await all(globSource(fixtureDir(), '{dir,dir/**/*}', { - mtime: new Date(5) + mtime: toMtime(new Date(5)) })) expect(result).to.have.lengthOf(6) expect(result).to.containSubset([{ path: '/dir', - mtime: new Date(5) + mtime: toMtime(new Date(5)) }, { path: '/dir/file-1.txt', - mtime: new Date(5) + mtime: toMtime(new Date(5)) }, { path: '/dir/file-2.js', - mtime: new Date(5) + mtime: toMtime(new Date(5)) }, { path: '/dir/file-3.css', - mtime: new Date(5) + mtime: toMtime(new Date(5)) }, { path: '/dir/nested-dir', - mtime: new Date(5) + mtime: toMtime(new Date(5)) }, { path: '/dir/nested-dir/other.txt', - mtime: new Date(5) + mtime: toMtime(new Date(5)) }]) }) @@ -274,7 +276,7 @@ describe('glob-source', () => { mtime: [5, 0] })) - expect(result).to.have.deep.nested.property('[0].mtime', [5, 0]) + expect(result).to.have.deep.nested.property('[0].mtime', toMtime([5, 0])) }) it('overrides mtime for file with UnixFS timespec', async function () { @@ -286,6 +288,6 @@ describe('glob-source', () => { mtime: { Seconds: 5, FractionalNanoseconds: 0 } })) - expect(result).to.have.deep.nested.property('[0].mtime', { Seconds: 5, FractionalNanoseconds: 0 }) + expect(result).to.have.deep.nested.property('[0].mtime', toMtime({ Seconds: 5, FractionalNanoseconds: 0 })) }) }) diff --git a/packages/unixfs/test/utils/to-mtime.spec.ts b/packages/unixfs/test/utils/to-mtime.spec.ts new file mode 100644 index 00000000..d670497b --- /dev/null +++ b/packages/unixfs/test/utils/to-mtime.spec.ts @@ -0,0 +1,61 @@ +/* eslint-env mocha */ + +import { expect } from 'aegir/chai' +import { toMtime } from '../../src/utils/to-mtime.js' + +describe('to-mtime', () => { + it('should survive undefined', async function () { + const result = toMtime() + + expect(result).to.equal(undefined) + }) + + it('should convert a date', async function () { + const input = new Date() + const result = toMtime(input) + + expect(result?.secs).to.equal(BigInt(Math.floor(input.getTime() / 1000))) + }) + + it('should convert a timespec', async function () { + const input = { + Seconds: 100 + } + const result = toMtime(input) + + expect(result?.secs).to.equal(BigInt(input.Seconds)) + expect(result?.nsecs).to.be.undefined() + }) + + it('should convert a timespec with fractional nanoseconds', async function () { + const input = { + Seconds: 100, + FractionalNanoseconds: 5 + } + const result = toMtime(input) + + expect(result?.secs).to.equal(BigInt(input.Seconds)) + expect(result?.nsecs).to.equal(input.FractionalNanoseconds) + }) + + it('should convert a mtime', async function () { + const input = { + secs: 100n + } + const result = toMtime(input) + + expect(result?.secs).to.equal(input.secs) + expect(result?.nsecs).to.be.undefined() + }) + + it('should convert a mtime with fractional nanoseconds', async function () { + const input = { + secs: 100n, + nsecs: 5 + } + const result = toMtime(input) + + expect(result?.secs).to.equal(input.secs) + expect(result?.nsecs).to.equal(input.nsecs) + }) +})