Plugin Architecture
See original GitHub issueI thought I’d start collecting my notes on the various hooks the plugin architecture will need to support.
☑ fs provider (added in #382)
Note: only one fs
provider can be registered at a time.
For Node, the homedir function should return the same value as os.homedir()
and for Browsers it should return '/'
.
name: stringfor simplicity, ‘name’ will not required for fs. maybe not for any singleton pluginhomedir() -> stringfiguring out how homedir should work in the browser has been postponed A subset of node’sfs
interface needs to be implemented:- readFile
- writeFile
- mkdir
- rmdir
- unlink
- stat
- lstat
- readdir They use regular node-style callbacks.
☑ credential provider
see #396
~☐ http_proxy provider~ Superceded by the more powerful http plugin
This is a Node specific provider that would allow isomorphic-git to work behind corporate firewalls (see #202). Note: It will NOT be automatically activated. Instead isomorphic-git will respect the git config http.proxy
value to decide whether to use this.
- name: string
- async httpProxy ({ url }) -> Promise<node::http.Agent>
☑ pgp provider
see #544
☐ pgp keyring provider
Will provide a way to sign keys without passing the secretKey
around all the time, and a way to intelligently retrieve publicKey
based on the commiter’s email address.
Note: this will also allow us to support the user.signingKey
and commit.gpgSign
parameters.
Note: If signingKey
is set via gitconfig e.g.
[user]
email = wmhilton@gmail.com
name = Will Hilton
signingKey = 9609B8A5928BA6B9
[commit]
gpgSign = true
☐ remote provider
Note: multiple remote
providers can be registered, as long as their supported protocols
do not conflict and they have different name
. See https://git-scm.com/docs/git-remote-helpers for details of what the functions mean.
- name: string
- protocols: string[]
- session ({ remote, url }) -> {
- async capabilities () -> Promise<{capabilities: string[]}>
- async connect ({ service: string }) -> Promise<{stream: DuplexStream}>
- async list () -> Promise<{ refs: Array<{ oid: string, name: string }> }>
- async listForPush () -> Promise<{ refs: Array<{ oid: string, name: string }> }>
- async option ({ name: string, value: string }) -> Promise<{ ok: boolean } | { error: string }>
- async fetch ({ emitter: EventEmitter, refs: Array<{ oid: string, name: string }> }) -> Promise<{ lock: string }>
- async push ({ emitter: EventEmitter, refs: Array<{ force: boolean, src: string, dst: string }> }) -> Promise<{ status: Array<{ dst: string, ok: true } | { dst: string, error: string }> }>
- }
☐ filter provider
Note: multiple filter
providers can be registered as long as they have different name
. Usage is determined by .gitattributes
file.
- name: string
- async clean ({ filepath }) -> Promise<{stream: TransformStream}>
- async smudge ({ filepath }) -> Promise<{stream: TransformStream}>
☐ merge provider
Note: multiple merge
providers can be registered as long as they have different name
. Usage is determined by .gitattributes
file.
- name: string
async merge ({
ours: string, base: string, theirs: string,
ourName: string, baseName: string, theirName: string,
format: 'diff'|'diff3', markerSize: number, filepath: string
}) -> Promise<{cleanMerge: boolean, mergedText: string}>
☐ diff provider
Note: multiple diff
providers can be registered as long as they have different name
. Usage is determined by .gitattributes
file. API is based on external diff
- name: string
- async diff ({ path, oldFile, oldHex, oldMode, newFile, newHex, newMode }) -> Promise<TBD>
What it looks like to implementer
To implement a plugin, you create an object (or class) with one or more of the properties listed above. E.g.
export const GitOpenPGPjs = {
name: 'OpenPGP.js',
async sign ({ payload }) {
// stuff
return signature
},
async verify ({ payload, signature }) {
// stuff
return {
valid,
signers
}
}
export const GitLFS = {
name: 'lfs',
clean () => new TransformStream(),
smudge () => new TransformStream()
}
Then you register the plugin by adding it to the appropriate plugin Set. *
import { plugins, commit, log } from 'isomorphic-git';
import { GitOpenPGPjs, GitLFS } from './file-above.js';
plugins.pgp.add(GitOpenPGPjs);
plugins.filter.add(GitLFS);
// do stuff like commit, log
Or if you’re not bothering with tree-shaking:
const git = require('isomorphic-git')
git.plugins.pgp.add(GitOpenPGPjs);
git.plugins.filter.add(GitLFS);
// do stuff like git.commit, git.log
* I thought about using a Map, but...
using Set leaves the door open for anonymous plugins or dynamically generated (higher-ordered) plugins, whatever. For now I'd still like them to have names, but a Set would let you add plugins with the same name, which could be detected and handled intelligently. With a Map it would just overwrite whatever plugin had a name conflict.Issue Analytics
- State:
- Created 5 years ago
- Reactions:5
- Comments:31 (29 by maintainers)
Top GitHub Comments
@mojavelinux IndexPack has them. https://github.com/isomorphic-git/isomorphic-git/blob/master/src/models/GitPackIndex.js#L153 and https://github.com/isomorphic-git/isomorphic-git/blob/master/src/models/GitPackIndex.js#L251
I’ve started to use some of the plugins (credentialsManager, fs, and emitter) and they are working great. Very simple design that just works.