updater-gitplucker
A modular, pluggable GitHub updater library for Python-glued projects. Drop it into any of your apps to keep them up to date from GitHub — with a safety allowlist, a 3-way merge that preserves your local edits, and automatic Python dependency detection/installation.
- Import name:
gitplucker· Package:updater-gitplucker - Zero required dependencies — the core runs on the Python standard library.
- Passive by design — it hands you an inspectable plan; you decide when to apply. Trigger it manually, at startup, or from a background thread.
from gitplucker import Updater, UpdaterConfig, RepoSubscription, Channel
from pathlib import Path
config = UpdaterConfig(
install_root=Path("/path/to/your/app"), # where the app lives on disk
allowed_repos=["your-org/your-app"], # nothing outside this is ever fetched
subscriptions=[
RepoSubscription("your-org/your-app", branches=["main"],
channel=Channel.PYTHON_SOURCE),
],
token="ghp_...", # optional (private repos / rate limits)
)
updater = Updater(config)
for plan in updater.check(): # dry run — nothing written yet
print(plan.summary())
if plan.has_update and not plan.conflicts:
updater.apply(plan) # backup → write → install deps
else:
updater.discard(plan)
Install
pip install updater-gitplucker
Or the latest from source:
pip install "git+https://github.com/uukjtisa/updater-gitplucker.git"
Concepts
Allowlist (security boundary)
allowed_repos is enforced at the network layer: any repo not listed is
rejected before any request. Every subscription's repo must be allowlisted.
Channels — how a repo is updated
| Channel | Source | Best for |
|---|---|---|
Channel.RELEASE |
Latest GitHub Release + assets (.zip, .whl, …) |
Versioned/shipped builds |
Channel.SOURCE |
Raw source at a branch tip (zipball) | Repos without formal releases |
Channel.PYTHON_SOURCE |
SOURCE + 3-way merge + dependency auto-detect |
Python apps held together by scripts (the main use case) |
Apply strategies — what an update replaces (config.apply_strategy)
| Strategy | Effect |
|---|---|
ApplyStrategy.WHOLE_APP (default) |
Add/modify/merge/delete the tracked tree, with backup + rollback |
ApplyStrategy.SELECTIVE |
Only paths matching selective_globs; never deletes |
ApplyStrategy.PACKAGE |
pip install the downloaded wheel/sdist (RELEASE channel) |
Triggers — when it runs
- Manual — just call
updater.check()/updater.apply()(orManualTrigger). - Startup —
StartupTrigger(updater).run(on_update=prompt_fn). - Background —
BackgroundTrigger(updater, interval_seconds=3600).start(...).
All three are optional wrappers; the library never acts on its own.
3-way merge (PYTHON_SOURCE)
After each apply, gitplucker snapshots the exact files it pulled (the base).
On the next update it merges base → your local edits with base → upstream.
Non-overlapping changes merge cleanly; only edits to the same lines produce a
conflict. config.conflict_policy decides what happens then: mark (git-style
markers, default), local, remote, or abort.
Dependency auto-detection (PYTHON_SOURCE)
Every incoming .py is scanned for imports; standard-library and the app's own
packages are filtered out; anything left that isn't installed is surfaced in
plan.dependency_changes and (if auto_install_deps=True) pip install-ed on
apply. Version pins in your requirements.txt are honored. Newly-added modules
are flagged is_new.
Inspecting a plan
plan.summary() # one-line human summary
plan.has_update # bool
plan.file_changes # list[FileChange] (added/modified/merged/conflict/deleted)
plan.conflicts # list[FileChange] (subset needing attention)
plan.dependency_changes # list[DependencyChange]
plan.new_dependencies # subset that are newly referenced
plan.warnings # e.g. "local changes overwritten (no merge available)"
plan.release_notes # release body / source stamp
Events
updater.events.on(lambda name, payload: print(name, payload))
Emitted: check.start/done, download.progress, dep.detected/install,
apply.file, backup, rollback, apply.done. A throwing listener can never
break an update.
State & rollback
Everything lives in install_root/.gitplucker/ (override via state_dir):
manifest.json (installed version + known modules per repo/branch), base/
(merge snapshots), backups/ (timestamped pre-apply copies for manual
rollback). A failed apply auto-rolls-back the current batch.
See docs/INTEGRATION.md for a step-by-step wiring guide
and examples/basic.py for a runnable script.
Metadata
Release files for updater-gitplucker 0.7.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| updater_gitplucker-0.7.1.tar.gz | 50.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| updater_gitplucker-0.7.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 97.4 kB
Release files / updater_gitplucker-0.7.1.tar.gz
| Download URL | updater_gitplucker-0.7.1.tar.gz |
|---|---|
| Size | 50.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
11d8958c3961adaf81fa0e220206554ab870ffc3a43c98d5a5158d4c6adaa5a5
|
|
BLAKE2b-256 checksum How to use checksums |
bc7da572bc4a9db5d78cd76f668643d9ab5009a669e652537553fa489da9c7ae
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.11
|
Release files / updater_gitplucker-0.7.1-py3-none-any.whl
| Download URL | updater_gitplucker-0.7.1-py3-none-any.whl |
|---|---|
| Size | 47.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a180b27adcb8280869fd6dc98778d7fce6eeafbd15000fd64d223d6b5889e91a
|
|
BLAKE2b-256 checksum How to use checksums |
b51e9c6d23f7d1a189bcb851d944a649ed4c35dab2b2d07f109b2ce22f756500
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.11
|