mirror of
https://github.com/taoky/shadowmire.git
synced 2025-07-08 09:12:43 +00:00
Config file support and other fixes
- Write JSON every 100 iterations instead of 1000 iterations - Write plan.json with indent=2
This commit is contained in:
parent
a6358aad8d
commit
c8a11d3d1f
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
Shadowmire syncs PyPI (or plain HTTP(S) PyPI mirrors using Shadowmire) with a lightweight and easy approach.
|
Shadowmire syncs PyPI (or plain HTTP(S) PyPI mirrors using Shadowmire) with a lightweight and easy approach.
|
||||||
|
|
||||||
|
Requires Python 3.11+.
|
||||||
|
|
||||||
## Docs
|
## Docs
|
||||||
|
|
||||||
### Background
|
### Background
|
||||||
@ -89,6 +91,12 @@ Verify command could be used if you believe that something is wrong (inconsisten
|
|||||||
|
|
||||||
Verify command accepts same arguments as sync.
|
Verify command accepts same arguments as sync.
|
||||||
|
|
||||||
|
If you don't like appending a long argument list, you could use `--config` ([example](./config.example.toml)):
|
||||||
|
|
||||||
|
```shell
|
||||||
|
./shadowmire.py --config config.toml sync
|
||||||
|
```
|
||||||
|
|
||||||
Also, if you need debugging, you could use `do-update` and `do-remove` command to operate on a single package.
|
Also, if you need debugging, you could use `do-update` and `do-remove` command to operate on a single package.
|
||||||
|
|
||||||
## Acknowledgements
|
## Acknowledgements
|
||||||
|
9
config.example.toml
Normal file
9
config.example.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[options]
|
||||||
|
sync_packages = true
|
||||||
|
# shadowmire_upstream = http://example.com/pypi/web/
|
||||||
|
exclude = [
|
||||||
|
"[a-z]"
|
||||||
|
]
|
||||||
|
prerelease_exclude = [
|
||||||
|
".+"
|
||||||
|
]
|
@ -15,6 +15,7 @@ from contextlib import contextmanager
|
|||||||
import sqlite3
|
import sqlite3
|
||||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
import signal
|
import signal
|
||||||
|
import tomllib
|
||||||
import requests
|
import requests
|
||||||
import click
|
import click
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
@ -481,7 +482,7 @@ class SyncBase:
|
|||||||
logger.warning(
|
logger.warning(
|
||||||
"%s generated an exception", package_name, exc_info=True
|
"%s generated an exception", package_name, exc_info=True
|
||||||
)
|
)
|
||||||
if idx % 1000 == 0:
|
if idx % 100 == 0:
|
||||||
self.local_db.dump_json()
|
self.local_db.dump_json()
|
||||||
except (ExitProgramException, KeyboardInterrupt):
|
except (ExitProgramException, KeyboardInterrupt):
|
||||||
logger.info("Get ExitProgramException or KeyboardInterrupt, exiting...")
|
logger.info("Get ExitProgramException or KeyboardInterrupt, exiting...")
|
||||||
@ -704,8 +705,8 @@ class SyncPlainHTTP(SyncBase):
|
|||||||
package_simple_path = self.simple_dir / package_name
|
package_simple_path = self.simple_dir / package_name
|
||||||
package_simple_path.mkdir(exist_ok=True)
|
package_simple_path.mkdir(exist_ok=True)
|
||||||
if self.sync_packages:
|
if self.sync_packages:
|
||||||
existing_hrefs = get_existing_hrefs(package_simple_path)
|
hrefs = get_existing_hrefs(package_simple_path)
|
||||||
existing_hrefs = [] if existing_hrefs is None else existing_hrefs
|
existing_hrefs = [] if hrefs is None else hrefs
|
||||||
# Download JSON meta
|
# Download JSON meta
|
||||||
file_url = urljoin(self.upstream, f"/json/{package_name}")
|
file_url = urljoin(self.upstream, f"/json/{package_name}")
|
||||||
success, resp = download(
|
success, resp = download(
|
||||||
@ -781,9 +782,9 @@ def get_local_serial(package_meta_path: Path) -> Optional[int]:
|
|||||||
def sync_shared_args(func):
|
def sync_shared_args(func):
|
||||||
shared_options = [
|
shared_options = [
|
||||||
click.option(
|
click.option(
|
||||||
"--sync-packages",
|
"--sync-packages/--no-sync-packages",
|
||||||
is_flag=True,
|
default=False,
|
||||||
help="Sync packages instead of just indexes",
|
help="Sync packages instead of just indexes, by default it's --no-sync-packages",
|
||||||
),
|
),
|
||||||
click.option(
|
click.option(
|
||||||
"--shadowmire-upstream",
|
"--shadowmire-upstream",
|
||||||
@ -805,7 +806,33 @@ def sync_shared_args(func):
|
|||||||
return func
|
return func
|
||||||
|
|
||||||
|
|
||||||
|
def read_config(
|
||||||
|
ctx: click.Context, param: click.Option, filename: Optional[str]
|
||||||
|
) -> None:
|
||||||
|
if filename is None:
|
||||||
|
return
|
||||||
|
with open(filename, "rb") as f:
|
||||||
|
data = tomllib.load(f)
|
||||||
|
try:
|
||||||
|
options = dict(data["options"])
|
||||||
|
except KeyError:
|
||||||
|
options = {}
|
||||||
|
ctx.default_map = {
|
||||||
|
"sync": options,
|
||||||
|
"verify": options,
|
||||||
|
"do-update": options,
|
||||||
|
"do-remove": options,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@click.group()
|
@click.group()
|
||||||
|
@click.option(
|
||||||
|
"--config",
|
||||||
|
type=click.Path(dir_okay=False),
|
||||||
|
help="Read option defaults from specified TOML file",
|
||||||
|
callback=read_config,
|
||||||
|
expose_value=False,
|
||||||
|
)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def cli(ctx: click.Context) -> None:
|
def cli(ctx: click.Context) -> None:
|
||||||
log_level = logging.DEBUG if os.environ.get("DEBUG") else logging.INFO
|
log_level = logging.DEBUG if os.environ.get("DEBUG") else logging.INFO
|
||||||
@ -869,7 +896,7 @@ def sync(
|
|||||||
plan = syncer.determine_sync_plan(local, excludes)
|
plan = syncer.determine_sync_plan(local, excludes)
|
||||||
# save plan for debugging
|
# save plan for debugging
|
||||||
with overwrite(basedir / "plan.json") as f:
|
with overwrite(basedir / "plan.json") as f:
|
||||||
json.dump(plan, f, default=vars)
|
json.dump(plan, f, default=vars, indent=2)
|
||||||
syncer.do_sync_plan(plan, prerelease_excludes)
|
syncer.do_sync_plan(plan, prerelease_excludes)
|
||||||
syncer.finalize()
|
syncer.finalize()
|
||||||
|
|
||||||
@ -922,8 +949,10 @@ def verify(
|
|||||||
for package_name in plan.remove:
|
for package_name in plan.remove:
|
||||||
# We only take the plan.remove part here
|
# We only take the plan.remove part here
|
||||||
syncer.do_remove(package_name)
|
syncer.do_remove(package_name)
|
||||||
|
|
||||||
logger.info("make sure all local indexes are valid, and (if --sync-packages) have valid local package files")
|
logger.info(
|
||||||
|
"make sure all local indexes are valid, and (if --sync-packages) have valid local package files"
|
||||||
|
)
|
||||||
syncer.check_and_update(list(local_names))
|
syncer.check_and_update(list(local_names))
|
||||||
syncer.finalize()
|
syncer.finalize()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user