gitlane 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gitlane-0.1.0/LICENSE +21 -0
- gitlane-0.1.0/PKG-INFO +156 -0
- gitlane-0.1.0/README.md +126 -0
- gitlane-0.1.0/pyproject.toml +50 -0
- gitlane-0.1.0/setup.cfg +4 -0
- gitlane-0.1.0/src/gitlane/__init__.py +3 -0
- gitlane-0.1.0/src/gitlane/__main__.py +7 -0
- gitlane-0.1.0/src/gitlane/blobs.py +77 -0
- gitlane-0.1.0/src/gitlane/branches.py +267 -0
- gitlane-0.1.0/src/gitlane/cli.py +130 -0
- gitlane-0.1.0/src/gitlane/git_ops.py +523 -0
- gitlane-0.1.0/src/gitlane/graph.py +319 -0
- gitlane-0.1.0/src/gitlane/launcher.py +71 -0
- gitlane-0.1.0/src/gitlane/server.py +1039 -0
- gitlane-0.1.0/src/gitlane/stash.py +181 -0
- gitlane-0.1.0/src/gitlane/static/app.css +643 -0
- gitlane-0.1.0/src/gitlane/static/gitlane.svg +15 -0
- gitlane-0.1.0/src/gitlane/static/htmx.min.js +1 -0
- gitlane-0.1.0/src/gitlane/static/index.html +822 -0
- gitlane-0.1.0/src/gitlane/workspace.py +211 -0
- gitlane-0.1.0/src/gitlane.egg-info/PKG-INFO +156 -0
- gitlane-0.1.0/src/gitlane.egg-info/SOURCES.txt +36 -0
- gitlane-0.1.0/src/gitlane.egg-info/dependency_links.txt +1 -0
- gitlane-0.1.0/src/gitlane.egg-info/entry_points.txt +2 -0
- gitlane-0.1.0/src/gitlane.egg-info/requires.txt +10 -0
- gitlane-0.1.0/src/gitlane.egg-info/top_level.txt +1 -0
- gitlane-0.1.0/tests/test_blobs.py +90 -0
- gitlane-0.1.0/tests/test_branches.py +358 -0
- gitlane-0.1.0/tests/test_changes.py +262 -0
- gitlane-0.1.0/tests/test_cli.py +130 -0
- gitlane-0.1.0/tests/test_compat.py +55 -0
- gitlane-0.1.0/tests/test_e2e.py +716 -0
- gitlane-0.1.0/tests/test_graph.py +336 -0
- gitlane-0.1.0/tests/test_server.py +619 -0
- gitlane-0.1.0/tests/test_stash.py +195 -0
- gitlane-0.1.0/tests/test_status.py +144 -0
- gitlane-0.1.0/tests/test_sync.py +253 -0
- gitlane-0.1.0/tests/test_workspace.py +280 -0
gitlane-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Gustavo Leite
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
gitlane-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gitlane
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A free, open-source Git client that runs in your browser.
|
|
5
|
+
Author: Gustavo Leite
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/gustavojoseleite/gitlane
|
|
8
|
+
Project-URL: Issues, https://github.com/gustavojoseleite/gitlane/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/gustavojoseleite/gitlane/blob/main/CHANGELOG.md
|
|
10
|
+
Keywords: git,git-client,gui,commit-graph,browser,version-control
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Web Environment
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: fastapi>=0.110
|
|
22
|
+
Requires-Dist: uvicorn>=0.29
|
|
23
|
+
Requires-Dist: GitPython>=3.1.40
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
26
|
+
Requires-Dist: httpx>=0.27; extra == "dev"
|
|
27
|
+
Provides-Extra: e2e
|
|
28
|
+
Requires-Dist: playwright>=1.40; extra == "e2e"
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# gitlane
|
|
32
|
+
|
|
33
|
+
**A free, open-source Git client that runs in your browser.** Commit, push, pull, see the
|
|
34
|
+
commit graph, manage branches and stashes — in a clean local web app, with one command.
|
|
35
|
+
|
|
36
|
+
<picture>
|
|
37
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/gustavojoseleite/gitlane/main/docs/screenshots/main-dark.png">
|
|
38
|
+
<img alt="gitlane showing a repository: changed files on the left, the commit graph in the middle, a commit with its diff on the right" src="https://raw.githubusercontent.com/gustavojoseleite/gitlane/main/docs/screenshots/main-light.png">
|
|
39
|
+
</picture>
|
|
40
|
+
|
|
41
|
+
## Features
|
|
42
|
+
|
|
43
|
+
- **Changes** — see changed, staged and untracked files; stage, unstage or discard whole files; commit with a summary and description
|
|
44
|
+
- **Diffs** — for your working files and any commit, with **before/after previews for images**
|
|
45
|
+
- **Commit graph** — all branches with colored lanes, branch/tag labels and your stashes; fast on repositories with tens of thousands of commits
|
|
46
|
+
- **Right-click menus** — checkout, create a branch, cherry-pick, revert, reset (soft / mixed / hard), merge, delete branches (also on the remote)
|
|
47
|
+
- **Sync** — fetch, pull, push, and force push that always uses `--force-with-lease`
|
|
48
|
+
- **Stash** — save (including untracked files), apply, pop, drop, and look inside a stash
|
|
49
|
+
- **Merge conflicts** — see the conflicted files, then *abort* or *mark resolved and commit*
|
|
50
|
+
- **Tabs** — several repositories at once; recent repos and a folder browser to open more
|
|
51
|
+
- **Safe by default** — dangerous actions ask first; runs only on your computer (see [Security](#security))
|
|
52
|
+
- Light and dark theme (follows your system)
|
|
53
|
+
|
|
54
|
+

|
|
55
|
+
|
|
56
|
+
## Install
|
|
57
|
+
|
|
58
|
+
You need **Python 3.10+** and **Git 2.23+** (most systems already have both).
|
|
59
|
+
|
|
60
|
+
The recommended way is [pipx](https://pipx.pypa.io/) or [uv](https://docs.astral.sh/uv/). They
|
|
61
|
+
install gitlane in its own environment, so it never conflicts with your other Python projects:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pipx install gitlane
|
|
65
|
+
# or
|
|
66
|
+
uv tool install gitlane
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Just want to try it, without installing anything? With uv:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
uvx gitlane
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
<details>
|
|
76
|
+
<summary>Don't have pipx or uv yet?</summary>
|
|
77
|
+
|
|
78
|
+
| System | Install pipx |
|
|
79
|
+
|---|---|
|
|
80
|
+
| Ubuntu / Debian | `sudo apt install pipx && pipx ensurepath` |
|
|
81
|
+
| Fedora | `sudo dnf install pipx && pipx ensurepath` |
|
|
82
|
+
| macOS | `brew install pipx && pipx ensurepath` |
|
|
83
|
+
| Windows | `py -m pip install --user pipx` then `py -m pipx ensurepath` |
|
|
84
|
+
|
|
85
|
+
Open a new terminal afterwards so the `gitlane` command is found.
|
|
86
|
+
</details>
|
|
87
|
+
|
|
88
|
+
<details>
|
|
89
|
+
<summary>Install the latest development version from GitHub</summary>
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
pipx install git+https://github.com/gustavojoseleite/gitlane
|
|
93
|
+
```
|
|
94
|
+
</details>
|
|
95
|
+
|
|
96
|
+
**Update:** `pipx upgrade gitlane` (or `uv tool upgrade gitlane`)
|
|
97
|
+
**Uninstall:** `pipx uninstall gitlane` (or `uv tool uninstall gitlane`)
|
|
98
|
+
|
|
99
|
+
## Usage
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
gitlane # inside a repository: open it
|
|
103
|
+
gitlane ~/dev/my-project # open a specific repository
|
|
104
|
+
gitlane # anywhere else: reopen your tabs, or pick a repository
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
gitlane starts a small server on your computer and opens it in your browser. Keep the terminal
|
|
108
|
+
open while you use it; press **Ctrl+C** to stop. Use **+** next to the tabs to open more
|
|
109
|
+
repositories. Open tabs and recent repos are remembered.
|
|
110
|
+
|
|
111
|
+
| Option | What it does |
|
|
112
|
+
|---|---|
|
|
113
|
+
| `--port 8000` | use a fixed port (default: a free one) |
|
|
114
|
+
| `--no-browser` | only print the link, don't open the browser |
|
|
115
|
+
| `--install-launcher` | add gitlane to your app menu (Linux) |
|
|
116
|
+
| `--remove-launcher` | remove it from the app menu |
|
|
117
|
+
| `--version` | show the version |
|
|
118
|
+
|
|
119
|
+
**Keyboard:** `↑` `↓` move through commits · `Enter` open · `R` refresh · `Ctrl+Enter` commit ·
|
|
120
|
+
`Esc` close menus and dialogs. Drag the dividers between panels to resize them (double-click to reset).
|
|
121
|
+
|
|
122
|
+
### Push and pull: logging in
|
|
123
|
+
|
|
124
|
+
gitlane uses **your own Git setup** and never asks for or stores passwords. If `git push` works in
|
|
125
|
+
your terminal without typing a password, it works in gitlane too.
|
|
126
|
+
|
|
127
|
+
- **SSH remotes** (`git@github.com:you/repo.git`) — recommended. Set up an SSH key once:
|
|
128
|
+
[GitHub guide](https://docs.github.com/en/authentication/connecting-to-github-with-ssh).
|
|
129
|
+
- **HTTPS remotes** (`https://github.com/you/repo.git`) — need a credential helper, for example
|
|
130
|
+
`gh auth setup-git` ([GitHub CLI](https://cli.github.com/)) or
|
|
131
|
+
[Git Credential Manager](https://github.com/git-ecosystem/git-credential-manager).
|
|
132
|
+
Or switch the remote to SSH: `git remote set-url origin git@github.com:you/repo.git`
|
|
133
|
+
|
|
134
|
+
## Security
|
|
135
|
+
|
|
136
|
+
gitlane is a local app, but a web server on your computer still needs care:
|
|
137
|
+
|
|
138
|
+
- It listens **only on `127.0.0.1`** — other computers can't reach it.
|
|
139
|
+
- Every start creates a **secret token** in the link; without it every request is refused.
|
|
140
|
+
The token is then kept in a cookie that other websites can't use.
|
|
141
|
+
- It rejects requests from other websites (Origin and Host checks, which also block DNS rebinding).
|
|
142
|
+
- Changes are only made with `POST` requests; dangerous actions ask you first.
|
|
143
|
+
- Image previews are served so that an SVG from a repository can never run scripts.
|
|
144
|
+
|
|
145
|
+
Found a security problem? Please open an issue without the details first, and we'll find a private way to talk.
|
|
146
|
+
|
|
147
|
+
## Contributing
|
|
148
|
+
|
|
149
|
+
Bug reports, ideas and pull requests are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for how to
|
|
150
|
+
set up the project, run the tests and send a change.
|
|
151
|
+
|
|
152
|
+
## License
|
|
153
|
+
|
|
154
|
+
[MIT](LICENSE) © 2026 Gustavo Leite — free to use, change and share, including for commercial work.
|
|
155
|
+
|
|
156
|
+
gitlane includes [htmx](https://htmx.org/) (Zero-Clause BSD license).
|
gitlane-0.1.0/README.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# gitlane
|
|
2
|
+
|
|
3
|
+
**A free, open-source Git client that runs in your browser.** Commit, push, pull, see the
|
|
4
|
+
commit graph, manage branches and stashes — in a clean local web app, with one command.
|
|
5
|
+
|
|
6
|
+
<picture>
|
|
7
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/gustavojoseleite/gitlane/main/docs/screenshots/main-dark.png">
|
|
8
|
+
<img alt="gitlane showing a repository: changed files on the left, the commit graph in the middle, a commit with its diff on the right" src="https://raw.githubusercontent.com/gustavojoseleite/gitlane/main/docs/screenshots/main-light.png">
|
|
9
|
+
</picture>
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Changes** — see changed, staged and untracked files; stage, unstage or discard whole files; commit with a summary and description
|
|
14
|
+
- **Diffs** — for your working files and any commit, with **before/after previews for images**
|
|
15
|
+
- **Commit graph** — all branches with colored lanes, branch/tag labels and your stashes; fast on repositories with tens of thousands of commits
|
|
16
|
+
- **Right-click menus** — checkout, create a branch, cherry-pick, revert, reset (soft / mixed / hard), merge, delete branches (also on the remote)
|
|
17
|
+
- **Sync** — fetch, pull, push, and force push that always uses `--force-with-lease`
|
|
18
|
+
- **Stash** — save (including untracked files), apply, pop, drop, and look inside a stash
|
|
19
|
+
- **Merge conflicts** — see the conflicted files, then *abort* or *mark resolved and commit*
|
|
20
|
+
- **Tabs** — several repositories at once; recent repos and a folder browser to open more
|
|
21
|
+
- **Safe by default** — dangerous actions ask first; runs only on your computer (see [Security](#security))
|
|
22
|
+
- Light and dark theme (follows your system)
|
|
23
|
+
|
|
24
|
+

|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
You need **Python 3.10+** and **Git 2.23+** (most systems already have both).
|
|
29
|
+
|
|
30
|
+
The recommended way is [pipx](https://pipx.pypa.io/) or [uv](https://docs.astral.sh/uv/). They
|
|
31
|
+
install gitlane in its own environment, so it never conflicts with your other Python projects:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pipx install gitlane
|
|
35
|
+
# or
|
|
36
|
+
uv tool install gitlane
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Just want to try it, without installing anything? With uv:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
uvx gitlane
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
<details>
|
|
46
|
+
<summary>Don't have pipx or uv yet?</summary>
|
|
47
|
+
|
|
48
|
+
| System | Install pipx |
|
|
49
|
+
|---|---|
|
|
50
|
+
| Ubuntu / Debian | `sudo apt install pipx && pipx ensurepath` |
|
|
51
|
+
| Fedora | `sudo dnf install pipx && pipx ensurepath` |
|
|
52
|
+
| macOS | `brew install pipx && pipx ensurepath` |
|
|
53
|
+
| Windows | `py -m pip install --user pipx` then `py -m pipx ensurepath` |
|
|
54
|
+
|
|
55
|
+
Open a new terminal afterwards so the `gitlane` command is found.
|
|
56
|
+
</details>
|
|
57
|
+
|
|
58
|
+
<details>
|
|
59
|
+
<summary>Install the latest development version from GitHub</summary>
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pipx install git+https://github.com/gustavojoseleite/gitlane
|
|
63
|
+
```
|
|
64
|
+
</details>
|
|
65
|
+
|
|
66
|
+
**Update:** `pipx upgrade gitlane` (or `uv tool upgrade gitlane`)
|
|
67
|
+
**Uninstall:** `pipx uninstall gitlane` (or `uv tool uninstall gitlane`)
|
|
68
|
+
|
|
69
|
+
## Usage
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
gitlane # inside a repository: open it
|
|
73
|
+
gitlane ~/dev/my-project # open a specific repository
|
|
74
|
+
gitlane # anywhere else: reopen your tabs, or pick a repository
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
gitlane starts a small server on your computer and opens it in your browser. Keep the terminal
|
|
78
|
+
open while you use it; press **Ctrl+C** to stop. Use **+** next to the tabs to open more
|
|
79
|
+
repositories. Open tabs and recent repos are remembered.
|
|
80
|
+
|
|
81
|
+
| Option | What it does |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `--port 8000` | use a fixed port (default: a free one) |
|
|
84
|
+
| `--no-browser` | only print the link, don't open the browser |
|
|
85
|
+
| `--install-launcher` | add gitlane to your app menu (Linux) |
|
|
86
|
+
| `--remove-launcher` | remove it from the app menu |
|
|
87
|
+
| `--version` | show the version |
|
|
88
|
+
|
|
89
|
+
**Keyboard:** `↑` `↓` move through commits · `Enter` open · `R` refresh · `Ctrl+Enter` commit ·
|
|
90
|
+
`Esc` close menus and dialogs. Drag the dividers between panels to resize them (double-click to reset).
|
|
91
|
+
|
|
92
|
+
### Push and pull: logging in
|
|
93
|
+
|
|
94
|
+
gitlane uses **your own Git setup** and never asks for or stores passwords. If `git push` works in
|
|
95
|
+
your terminal without typing a password, it works in gitlane too.
|
|
96
|
+
|
|
97
|
+
- **SSH remotes** (`git@github.com:you/repo.git`) — recommended. Set up an SSH key once:
|
|
98
|
+
[GitHub guide](https://docs.github.com/en/authentication/connecting-to-github-with-ssh).
|
|
99
|
+
- **HTTPS remotes** (`https://github.com/you/repo.git`) — need a credential helper, for example
|
|
100
|
+
`gh auth setup-git` ([GitHub CLI](https://cli.github.com/)) or
|
|
101
|
+
[Git Credential Manager](https://github.com/git-ecosystem/git-credential-manager).
|
|
102
|
+
Or switch the remote to SSH: `git remote set-url origin git@github.com:you/repo.git`
|
|
103
|
+
|
|
104
|
+
## Security
|
|
105
|
+
|
|
106
|
+
gitlane is a local app, but a web server on your computer still needs care:
|
|
107
|
+
|
|
108
|
+
- It listens **only on `127.0.0.1`** — other computers can't reach it.
|
|
109
|
+
- Every start creates a **secret token** in the link; without it every request is refused.
|
|
110
|
+
The token is then kept in a cookie that other websites can't use.
|
|
111
|
+
- It rejects requests from other websites (Origin and Host checks, which also block DNS rebinding).
|
|
112
|
+
- Changes are only made with `POST` requests; dangerous actions ask you first.
|
|
113
|
+
- Image previews are served so that an SVG from a repository can never run scripts.
|
|
114
|
+
|
|
115
|
+
Found a security problem? Please open an issue without the details first, and we'll find a private way to talk.
|
|
116
|
+
|
|
117
|
+
## Contributing
|
|
118
|
+
|
|
119
|
+
Bug reports, ideas and pull requests are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for how to
|
|
120
|
+
set up the project, run the tests and send a change.
|
|
121
|
+
|
|
122
|
+
## License
|
|
123
|
+
|
|
124
|
+
[MIT](LICENSE) © 2026 Gustavo Leite — free to use, change and share, including for commercial work.
|
|
125
|
+
|
|
126
|
+
gitlane includes [htmx](https://htmx.org/) (Zero-Clause BSD license).
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "gitlane"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A free, open-source Git client that runs in your browser."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
authors = [{ name = "Gustavo Leite" }]
|
|
14
|
+
keywords = ["git", "git-client", "gui", "commit-graph", "browser", "version-control"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Environment :: Web Environment",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
22
|
+
"Topic :: Software Development :: Version Control :: Git",
|
|
23
|
+
]
|
|
24
|
+
dependencies = [
|
|
25
|
+
"fastapi>=0.110",
|
|
26
|
+
"uvicorn>=0.29",
|
|
27
|
+
"GitPython>=3.1.40",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
dev = ["pytest>=8", "httpx>=0.27"]
|
|
32
|
+
# Browser tests (tests/test_e2e.py) use your installed Chrome; skipped if missing.
|
|
33
|
+
e2e = ["playwright>=1.40"]
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Homepage = "https://github.com/gustavojoseleite/gitlane"
|
|
37
|
+
Issues = "https://github.com/gustavojoseleite/gitlane/issues"
|
|
38
|
+
Changelog = "https://github.com/gustavojoseleite/gitlane/blob/main/CHANGELOG.md"
|
|
39
|
+
|
|
40
|
+
[project.scripts]
|
|
41
|
+
gitlane = "gitlane.cli:main"
|
|
42
|
+
|
|
43
|
+
[tool.setuptools.packages.find]
|
|
44
|
+
where = ["src"]
|
|
45
|
+
|
|
46
|
+
[tool.setuptools.package-data]
|
|
47
|
+
gitlane = ["static/*"]
|
|
48
|
+
|
|
49
|
+
[tool.pytest.ini_options]
|
|
50
|
+
testpaths = ["tests"]
|
gitlane-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Reading file contents at a given version, used for image previews."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path, PurePosixPath
|
|
6
|
+
|
|
7
|
+
import git
|
|
8
|
+
|
|
9
|
+
from .git_ops import GitError, check_paths
|
|
10
|
+
from .graph import resolve_commit
|
|
11
|
+
|
|
12
|
+
MAX_BLOB_BYTES = 20 * 1024 * 1024
|
|
13
|
+
|
|
14
|
+
IMAGE_TYPES = {
|
|
15
|
+
".png": "image/png",
|
|
16
|
+
".jpg": "image/jpeg",
|
|
17
|
+
".jpeg": "image/jpeg",
|
|
18
|
+
".gif": "image/gif",
|
|
19
|
+
".webp": "image/webp",
|
|
20
|
+
".avif": "image/avif",
|
|
21
|
+
".bmp": "image/bmp",
|
|
22
|
+
".ico": "image/x-icon",
|
|
23
|
+
".svg": "image/svg+xml",
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# Special revisions besides commit ids.
|
|
27
|
+
WORKTREE = "WORKTREE" # the file on disk
|
|
28
|
+
INDEX = "INDEX" # the staged version
|
|
29
|
+
HEAD = "HEAD" # the last commit
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def image_type(path: str) -> str | None:
|
|
33
|
+
return IMAGE_TYPES.get(PurePosixPath(path).suffix.lower())
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _spec(repo: git.Repo, rev: str, path: str) -> str:
|
|
37
|
+
if rev == INDEX:
|
|
38
|
+
return f":0:{path}"
|
|
39
|
+
if rev == HEAD:
|
|
40
|
+
return f"HEAD:{path}"
|
|
41
|
+
return f"{resolve_commit(repo, rev)}:{path}"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _worktree_file(repo: git.Repo, path: str) -> Path | None:
|
|
45
|
+
root = Path(repo.working_tree_dir).resolve()
|
|
46
|
+
f = (root / path).resolve()
|
|
47
|
+
if not f.is_relative_to(root) or not f.is_file(): # also blocks symlinks pointing outside
|
|
48
|
+
return None
|
|
49
|
+
return f
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def blob_exists(repo: git.Repo, rev: str, path: str) -> bool:
|
|
53
|
+
(path,) = check_paths([path])
|
|
54
|
+
if rev == WORKTREE:
|
|
55
|
+
return _worktree_file(repo, path) is not None
|
|
56
|
+
code, _, _ = repo.git.cat_file("-e", _spec(repo, rev, path),
|
|
57
|
+
with_extended_output=True, with_exceptions=False)
|
|
58
|
+
return code == 0
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def read_blob(repo: git.Repo, rev: str, path: str) -> bytes | None:
|
|
62
|
+
"""Contents of ``path`` at ``rev``; None if the file does not exist there."""
|
|
63
|
+
(path,) = check_paths([path])
|
|
64
|
+
if rev == WORKTREE:
|
|
65
|
+
f = _worktree_file(repo, path)
|
|
66
|
+
if f is None:
|
|
67
|
+
return None
|
|
68
|
+
if f.stat().st_size > MAX_BLOB_BYTES:
|
|
69
|
+
raise GitError("File is too large to preview.")
|
|
70
|
+
return f.read_bytes()
|
|
71
|
+
spec = _spec(repo, rev, path)
|
|
72
|
+
code, size, _ = repo.git.cat_file("-s", spec, with_extended_output=True, with_exceptions=False)
|
|
73
|
+
if code != 0:
|
|
74
|
+
return None
|
|
75
|
+
if int(size) > MAX_BLOB_BYTES:
|
|
76
|
+
raise GitError("File is too large to preview.")
|
|
77
|
+
return repo.git.cat_file("blob", spec, stdout_as_string=False, strip_newline_in_stdout=False)
|