mirror of
https://github.com/HeyPuter/puter
synced 2024-11-15 06:15:47 +00:00
94 lines
4.7 KiB
Markdown
94 lines
4.7 KiB
Markdown
# Puter Git Client
|
|
|
|
This is a JavaScript in-browser git client running on the Puter filesystem, using [isomorphic-git](https://isomorphic-git.org).
|
|
|
|
It aims to match `git`'s interface, so that running a command behaves the same way as it would there.
|
|
Of course, `git` has a large variety of subcommands and options, some of which are obscure, so many will be missing.
|
|
Consider adding them if you are interested! :^)
|
|
|
|
While this is built for Puter, the only Puter-specific parts are:
|
|
- `src/filesystem.js` which integrates with Puter's filesystem.
|
|
- `src/main.js` which uses the Puter SDK to connect to the parent Phoenix shell.
|
|
|
|
By modifying these, and the values in `config/`, you should be able to port it to other environments.
|
|
|
|
## Subcommand structure
|
|
|
|
The `git` CLI is structured as a series of sub-commands - `git branch` has nothing in common with `git version`, for example. Each of these is modelled as its own file in `src/subcommands`, and should export a default object with the following structure:
|
|
|
|
```js
|
|
export default {
|
|
// The subcommand's name
|
|
name: 'help',
|
|
// A string or array of strings, for how the subcommand is run. Shown in the help.
|
|
usage: [
|
|
'git help [-a|--all]',
|
|
'git help <command>',
|
|
],
|
|
// A description, shown in the help.
|
|
description: `Display help information for git itself, or a subcommand.`,
|
|
// Arguments object, passed to `parseArgs()`
|
|
args: {
|
|
allowPositionals: true,
|
|
options: {
|
|
all: {
|
|
// The one deviation from parseArgs() is that each option gets a description,
|
|
// which is shown in the help output.
|
|
description: 'List all available subcommands.',
|
|
type: 'boolean',
|
|
}
|
|
},
|
|
},
|
|
// Function to actually run the subcommand.
|
|
// The return value can be a posix-style exit code, or a plain `return` as a shorthand for 0.
|
|
// Throwing errors is allowed.
|
|
// Throwing the special `SHOW_USAGE` value defined in `src/help.js` can be used to print the command usage text.
|
|
execute: async (ctx) => {
|
|
// ctx has the following structure:
|
|
ctx = {
|
|
io: {
|
|
stdout, // Function that takes a string, and prints it to stdout
|
|
stderr, // Function that takes a string, and prints it to stderr
|
|
},
|
|
fs, // A filesystem implementation, for isomorphic-git
|
|
args, // An object returned from `parseArgs()`.
|
|
env, // Object containing environment variables, such as PWD for the current working directory.
|
|
}
|
|
}
|
|
}
|
|
```
|
|
These are them listed in `src/subcommands/__exports__.js`, which can be automatically generated by running `packages/phoenix/tools/gen.js packages/git/src/subcommands` from the Puter repo root. But it's not hard to modify manually.
|
|
|
|
## Common patterns
|
|
|
|
### Shared options
|
|
|
|
It's common in a few places that options are shared between commands, for example options related to formatting commits are shared by `git log` and `git show`.
|
|
In these cases, those options are defined in an object in `src/format.js` with an accompanying function to process their results into a more convenient format.
|
|
For example, `diff_formatting_options` and `process_diff_formatting_options(options)`:
|
|
Some of the options are shorthands for others; some "imply" another; and some are set by default under certain conditions.
|
|
All this is handled in one place instead of in each subcommand that needs them.
|
|
|
|
### Repo root
|
|
|
|
Since the `git` command may be run from a repository, a subdirectory, or a non-repository, you can locate the git directory like so:
|
|
```js
|
|
const { dir, gitdir } = await find_repo_root(fs, env.PWD);
|
|
```
|
|
The `dir` and `gitdir` variables can then be passed to isomorphic-git methods that expect them.
|
|
If no repository is found, this will throw an error, which is then printed to stderr.
|
|
(isomorphic-git's `git.findRoot()` does not implement checks for a `.git` text file that points to an alternative directory that git's metadata is stored in. We should maybe upstream this.)
|
|
|
|
## Isomorphic-git
|
|
|
|
The library we use for most interaction with git's files is [isomorphic-git](https://isomorphic-git.org).
|
|
|
|
It handles most of the basics, but because we want to do everything that [git](https://git-scm.com) does, a lot has to
|
|
be implemented manually. For example, it has a `git.add()` method for adding files, but whereas `git add deleted_file`
|
|
will stage that deletion, `git.add({ filepath: 'deleted_file', ... })` will complain that the file does not exist. So
|
|
our implementation of `git add` manually iterates the changed files and either calls `git.add()` or `git.remove()` as
|
|
appropriate.
|
|
|
|
### Troubleshooting tips:
|
|
- File paths given to isomorphic-git need to be relative to the repo root. Absolute paths often silently do nothing!
|