# configrepo Copies a project's editor directory — `.turbo-go`, `.turbo-rust` — out of a repository somebody shares, from the URL a forge shows for the directory holding it. ``` turbo-go -load-config https://rickub.com/turbo-editors/configs/tree/main/golang-init ``` fetches `golang-init/.turbo-go` into the working directory. ## Why git, not an API The URL can be on rickub, GitHub, GitLab or Codeberg. Each has a JSON API for reading a directory, each API is different, and rickub's wants a personal access token even to read a public repository. Git is the one thing all of them speak the same way, with no token: the fetch is `git ls-remote` to find the repository and its branches, then `git clone --depth 1 --branch ` into a temporary directory, then a copy. The price is that `git` must be installed, which on the machine of somebody running a terminal IDE it is. `ErrNoGit` is what you get otherwise. ## Reading the URL `Parse` understands what the browsers show: | Shape | Forge | | --- | --- | | `https://host/owner/repo/tree/main/dir` | rickub, GitHub | | `https://host/group/sub/repo/-/tree/main/dir` | GitLab — the owner keeps its slashes | | `https://host/owner/repo/src/branch/main/dir` | Codeberg, Forgejo, Gitea — also `src/tag/`, `src/commit/` | | `https://host/owner/repo` | a repository: default branch, root | `blob/` is taken like `tree/`, so a URL to a file inside the directory works too. **A branch with a slash in it** — `feature/x` — cannot be told from the path by the URL alone. `Parse` takes the first segment as the ref and the rest as the path; `Load` then asks the repository for its branches and tags (`git ls-remote`) and `resolveRef` picks the **longest** one that begins `ref/path`, giving the rest back to the path. Nothing matching leaves both as they were and the clone reports the missing branch in git's own words. **Where to clone from.** GitHub, GitLab and Codeberg serve git at the address the browser shows. rickub does not — pages on `rickub.com`, repositories on `git.rickub.com` — so `CloneURLs` offers `https://host/owner/repo.git` and then `https://git.host/owner/repo.git`, and `firstAnswering` takes the first whose `ls-remote` answers. The listing does two jobs at once: telling the candidates apart, and being what a slashed ref is resolved against. ## What is copied, and where Inside the checkout, `locate` looks for `/.turbo-go`, or takes `` itself when its last segment already is `.turbo-go`. Every regular file under it is copied with `projectfile.Write` — same mode, same atomic rename, directories made on the way — so a loaded configuration is created exactly as the editor creates one itself. Symbolic links and anything else that is not a regular file stay behind: a configuration is files. The destination is `dest/.turbo-go`, `dest` being the working directory. **If it already exists, nothing is done and `ErrExists` says so.** A project's configuration is a decision the project made; the editor does not overwrite it because a URL was typed. Move it away first. `GIT_TERMINAL_PROMPT=0` is set on every git call: this runs from a command line that asked for a URL, and a private repository is reported, not waited on. ## Public API | Name | What it does | | --- | --- | | `Parse(url) (Source, error)` | Reads a forge's URL into host, owner, repo, ref, path | | `Source.CloneURLs() []string` | The clone addresses to try, most likely first | | `Load(ctx, profile, url, dest) (Result, error)` | Parse, find the repository, clone the ref, copy the editor's directory into dest | | `Result` | The remote that answered, the ref, the directory created, the files in it | | `ErrNoGit`, `ErrExists`, `ErrNotFound` | No git; the project already has the directory; the repository has none where the URL points | ## Tests ```sh go test ./configrepo/ TURBO_CORE_NETWORK=1 go test ./configrepo/ # also the real thing, against rickub ``` `sampleRepo` builds a repository on disk with `git init` — two branches, one of them `feature/x` — and `loadFrom` is pointed at it as a remote, which git accepts as readily as a URL. The network test is skipped unless asked for: the suite must pass on a machine with no network.