Skip to content
This repository has been archived by the owner on Jul 6, 2022. It is now read-only.

Add stream event listener argument to resolveInput() #29

Merged
merged 1 commit into from
Feb 18, 2019

Conversation

pdcastro
Copy link
Contributor

@pdcastro pdcastro commented Feb 4, 2019

Resolves: #28
Change-type: major
Signed-off-by: Paulo Castro paulo@balena.io

Copy link
Contributor Author

@pdcastro pdcastro left a comment

Choose a reason for hiding this comment

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

See issue #28 for a description of what this PR intends to achieve.

@@ -0,0 +1,4009 @@
{
Copy link
Contributor Author

Choose a reason for hiding this comment

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

To recap / confirm the recommended practice, it is desirable to add package-lock files to libraries (such as resin-bundle-resolve) but not to "apps" installed by users (such as balena-cli); is this right?

Copy link
Contributor

Choose a reason for hiding this comment

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

It's the opposite @pdcastro , we definitely want them in apps, but we don't care as much in libraries. That being said, having them in libraries too can be useful to ensure a consistent CI build.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But there was a good reason why balena-cli does not commit package-lock.json (it is in .gitignore), while the libs imported by the CLI can/should have package-lock.json files. @thgreasi, you might remember what the reason was... I think it was to do with we not having control over the customer's environment -- like, package-lock.json was ignored (?) in some cases or platforms (?), so we wanted the CI to try installing the latest versions of whatever is in package.json -- but I am not able to fully justify it to myself. :-)

Copy link
Contributor

Choose a reason for hiding this comment

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

I believe @Page- also has some theories on this too.

dockerfile?: string,
): Readable {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

tar.Pack implements the Readable interface, so this should be a "safe" change. Some callers of resolveInput were doing explicit cast from Pack to Readable, and this change avoids the need for that.

Copy link
Contributor

Choose a reason for hiding this comment

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

It used to be that the typings were incompatible iirc, but if it's all working well now then I agree this is worth it.

@@ -7,7 +7,7 @@
"declaration": true,
"pretty": true,
"removeComments": true,
"skipLibCheck": true,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Needed because tsc was failing in type checks for the strict-event-emitter-types package. The skipLibCheck flag is used in many other balena packages.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yep, should definitely be included.

const extract = tar.extract();
const pack = tar.pack();
for (const event of Object.keys(resolveListeners) as Array<
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you should be able to do:

Suggested change
for (const event of Object.keys(resolveListeners) as Array<
for (const event in resolveListeners)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If I write it like that (in and no type cast), then on the following line I get a compiler error:

src/index.ts:75:21 - error TS7017: Element implicitly has an 'any' type because type 'ResolveListeners' has no index signature.
75  	const listeners = resolveListeners[event] || [];

Also, the in operator iterates over all of the object's prototype chain's properties (which in some cases results in the linter warning that the for loop needs an if test for "own properties"), while Object.keys() returns the keys for the object's own properties only.

const listeners = resolveListeners[event] || [];
for (const listener of listeners) {
pack.on(event, listener);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

We already have lodash imported here so this could be

_.each(resolveListeners, (cbs, event) => _.each(cbs, cb => pack.on(event, cb)))

Copy link
Contributor Author

@pdcastro pdcastro Feb 4, 2019

Choose a reason for hiding this comment

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

If I do it like that, then the compiler errors:

src/index.ts:83:36 - error TS2345: Argument of type 'number | ((chunk: string | Buffer) => void) | ((e: Error) => void) | ((...items: (() => void)[]) ...' is not assignable to parameter of type 'Function'.
  Type 'number' is not assignable to type 'Function'.

83  	_.each(cbs, cb => pack.on(event, cb)),

Also:

  • npm run prettify expands it to a minimum of 3 lines of code, so the one-liner temptation is partially spoiled.
  • I find the nested callbacks slightly harder to read than the nested for loops (one needs to be familiar with lodash's callback arguments...).

I can however reduce one line of code by removing the const listeners variable declaration:

	for (const event of Object.keys(resolveListeners) as Array<
		keyof ResolveListeners
	>) {
		for (const listener of resolveListeners[event] || []) {
			pack.on(event, listener);
		}
	}

export function resolveInput(
bundle: Bundle,
resolvers: Resolver[],
resolveListeners: ResolveListeners,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This added argument is the reason for a major version bump.

Copy link
Contributor

Choose a reason for hiding this comment

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

Why not put it last and make it optional?

Copy link
Contributor Author

@pdcastro pdcastro Feb 4, 2019

Choose a reason for hiding this comment

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

Yes, I thought about making it optional, it could be done. But then I considered that not providing this argument and thus potentially ignoring error events is "almost certainly a bug" and the function interface should discourage it. Adding this argument is the main purpose of this PR. Before this change, there wasn't a foolproof way of providing an error handler for the stream events. Making this arg optional would be like making the improvement optional...

@pdcastro pdcastro force-pushed the 28-add-resolveInput-listeners branch from e3df60b to a61834b Compare February 7, 2019 11:57
src/index.ts Outdated
});
});
entry.stream.pipe(newEntryStream);
await newEntryStreamPromise;
Copy link
Contributor Author

@pdcastro pdcastro Feb 7, 2019

Choose a reason for hiding this comment

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

The ~10 lines above (newEntryStreamPromise) were necessary to avoid a tar-stream limitation by which it is only possible to pipe to one pack.entry at a time -- so it's necessary to wait for the 'finish' event on one entry before moving on to the next entry. Some resin-builder tests were failing with the tar-stream error "Error: already piping an entry". More details here: mafintosh/tar-stream#24 (comment)

)) || specifiedFileResolver;
} catch (error) {
console.log('resin-bundle-resolve extract entry -> error', error);
pack.emit('error', error);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Some errors thrown in stream listeners were not being caught, so I added the try-catch above and "forwarded" the errors through pack.emit('error').

'resin-bundle-resolve extract on finish calling pack.finalize()',
);
pack.finalize();
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Some errors thrown in stream listeners were not being caught and pack.finalize() not called, so I added the try-catch-finally above and "forwarded" the errors through pack.emit('error').

@pdcastro pdcastro force-pushed the 28-add-resolveInput-listeners branch from a61834b to f5c2d7b Compare February 8, 2019 14:07
@pdcastro pdcastro force-pushed the 28-add-resolveInput-listeners branch 2 times, most recently from 0142f33 to f8de286 Compare February 17, 2019 13:39
(semver 'major' change because this commit makes the resolveInput
function incompatible with previous major versions by adding a
new required argument.)

Change-type: major
Signed-off-by: Paulo Castro <paulo@balena.io>
@pdcastro pdcastro force-pushed the 28-add-resolveInput-listeners branch from f8de286 to 811ceba Compare February 18, 2019 16:24
@pdcastro pdcastro merged commit e625223 into master Feb 18, 2019
@pdcastro pdcastro deleted the 28-add-resolveInput-listeners branch February 18, 2019 16:32
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants