Skip to content

Commit

Permalink
Merge pull request #31 from NeQuissimus/version_extract
Browse files Browse the repository at this point in the history
  • Loading branch information
Mic92 authored Dec 25, 2020
2 parents 75dc3ab + 7d487d2 commit 8fb6c5e
Show file tree
Hide file tree
Showing 10 changed files with 75 additions and 29 deletions.
12 changes: 11 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Features
- update buildGoModule's vendorSha256/modSha256
- build and run the resulting package (see `--build`, `--run` or `--shell` flag)
- commit updated files (see `--commit` flag)
- run package tests (see `--test` flag)

Installation
------------
Expand Down Expand Up @@ -85,12 +86,21 @@ To only update sources hashes without updating the version:

$ nix-update --version=skip nixpkgs-review

With the `--shell`, `--build` and `--run` flags the update can be tested
To extract version information from versions with prefixes or suffixes, a regex
can be used

::

$ nix-update jq --version-regex 'jq-(.*)'

With the `--shell`, `--build`, `--test` and `--run` flags the update can be tested

::

# Also runs nix-build
$ nix-update --build nixpkgs-review
# Also runs nix-build nixpkgs-review.tests
$ nix-update --test nixpkgs-review
# Also runs nix-shell
$ nix-update --shell nixpkgs-review
# Also runs nix run
Expand Down
7 changes: 7 additions & 0 deletions nix_update/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ def parse_args() -> Options:
parser.add_argument(
"--commit", action="store_true", help="Commit the updated package"
)
parser.add_argument(
"-vr",
"--version-regex",
help="Regex to extract version with, i.e. 'jq-(.*)'",
default="(.*)",
)
parser.add_argument(
"--run",
action="store_true",
Expand All @@ -48,6 +54,7 @@ def parse_args() -> Options:
version=args.version,
attribute=args.attribute,
test=args.test,
version_regex=args.version_regex,
)


Expand Down
1 change: 1 addition & 0 deletions nix_update/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ class Options:
run: bool
build: bool
test: bool
version_regex: str
6 changes: 3 additions & 3 deletions nix_update/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def update_cargo_sha256_hash(opts: Options, filename: str, current_hash: str) ->
replace_hash(filename, current_hash, target_hash)


def update_version(package: Package, version: str) -> bool:
def update_version(package: Package, version: str, version_regex: str) -> bool:
if version == "auto":
if not package.url:
if package.urls:
Expand All @@ -101,7 +101,7 @@ def update_version(package: Package, version: str) -> bool:
raise UpdateError(
"Could not find a url in the derivations src attribute"
)
new_version = fetch_latest_version(url)
new_version = fetch_latest_version(url, version_regex)
else:
new_version = version
package.new_version = new_version
Expand All @@ -122,7 +122,7 @@ def update(opts: Options) -> Package:
update_hash = True

if opts.version != "skip":
update_hash = update_version(package, opts.version)
update_hash = update_version(package, opts.version, opts.version_regex)

if update_hash:
update_src_hash(opts, package.filename, package.hash)
Expand Down
11 changes: 11 additions & 0 deletions nix_update/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import re
import subprocess
import sys
from pathlib import Path
Expand Down Expand Up @@ -30,3 +31,13 @@ def run(
) -> "subprocess.CompletedProcess[str]":
info("$ " + " ".join(command))
return subprocess.run(command, cwd=cwd, check=check, text=True, stdout=stdout)


def extract_version(version: str, version_regex: str) -> Optional[str]:
pattern = re.compile(version_regex)
match = re.match(pattern, version)
if match is not None:
group = match.group(1)
if group is not None:
return group
return None
11 changes: 7 additions & 4 deletions nix_update/version/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from urllib.parse import urlparse

from ..errors import VersionError
from ..utils import extract_version
from .github import fetch_github_version
from .gitlab import fetch_gitlab_version
from .pypi import fetch_pypi_version
Expand All @@ -24,14 +25,16 @@
]


def fetch_latest_version(url_str: str) -> str:
def fetch_latest_version(url_str: str, version_regex: str) -> str:
url = urlparse(url_str)

for fetcher in fetchers:
version = fetcher(url)
version = fetcher(url, version_regex)
if version is not None:
return version
extracted = extract_version(version, version_regex)
if extracted is not None:
return extracted

raise VersionError(
"Please specify the version. We can only get the latest version from github/gitlab/pypi projects right now"
"Please specify the version. We can only get the latest version from github/gitlab/pypi/rubygems projects right now"
)
30 changes: 20 additions & 10 deletions nix_update/version/github.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
import re
import urllib.request
import xml.etree.ElementTree as ET
from xml.etree.ElementTree import Element
from typing import Optional
from urllib.parse import ParseResult, urlparse

from ..errors import VersionError
from ..utils import info
from ..utils import extract_version, info


def fetch_github_version(url: ParseResult) -> Optional[str]:
def version_from_entry(entry: Element) -> Optional[str]:
if entry is None:
raise VersionError("No release found")
link = entry.find("{http://www.w3.org/2005/Atom}link")
assert link is not None
href = link.attrib["href"]
url = urlparse(href)
return url.path.split("/")[-1]


def fetch_github_version(url: ParseResult, version_regex: str) -> Optional[str]:
if url.netloc != "github.com":
return None
parts = url.path.split("/")
Expand All @@ -19,11 +30,10 @@ def fetch_github_version(url: ParseResult) -> Optional[str]:
info(f"fetch {feed_url}")
resp = urllib.request.urlopen(feed_url)
tree = ET.fromstring(resp.read())
release = tree.find(".//{http://www.w3.org/2005/Atom}entry")
if release is None:
raise VersionError("No release found")
link = release.find("{http://www.w3.org/2005/Atom}link")
assert link is not None
href = link.attrib["href"]
url = urlparse(href)
return url.path.split("/")[-1]
releases = tree.findall(".//{http://www.w3.org/2005/Atom}entry")
entries = [version_from_entry(x) for x in releases]
filtered = [
x for x in entries if x is not None and extract_version(x, version_regex)
]

return filtered[0]
10 changes: 6 additions & 4 deletions nix_update/version/gitlab.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
from urllib.parse import ParseResult

from ..errors import VersionError
from ..utils import info
from ..utils import extract_version, info

GITLAB_API = re.compile(
r"http(s)?://(?P<domain>[^/]+)/api/v4/projects/(?P<project_id>[^/]*)/repository/archive.tar.gz\?sha=(?P<version>.+)"
)


def fetch_gitlab_version(url: ParseResult) -> Optional[str]:
def fetch_gitlab_version(url: ParseResult, version_regex: str) -> Optional[str]:
match = GITLAB_API.match(url.geturl())
if not match:
return None
Expand All @@ -28,8 +28,10 @@ def fetch_gitlab_version(url: ParseResult) -> Optional[str]:
if tag["release"]:
name = tag["name"]
assert isinstance(name, str)
return name
extracted = extract_version(name, version_regex)
if extracted is not None:
return extracted
# if no release is found, use latest tag
name = tags[0]["name"]
assert isinstance(name, str)
return name
return extract_version(name, version_regex)
6 changes: 3 additions & 3 deletions nix_update/version/pypi.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
from typing import Optional
from urllib.parse import ParseResult

from ..utils import info
from ..utils import extract_version, info


def fetch_pypi_version(url: ParseResult) -> Optional[str]:
def fetch_pypi_version(url: ParseResult, version_regex: str) -> Optional[str]:
if url.netloc != "pypi":
return None
parts = url.path.split("/")
Expand All @@ -17,4 +17,4 @@ def fetch_pypi_version(url: ParseResult) -> Optional[str]:
data = json.loads(resp.read())
version = data["info"]["version"]
assert isinstance(version, str)
return version
return extract_version(version, version_regex)
10 changes: 6 additions & 4 deletions nix_update/version/rubygems.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
import json

from ..errors import VersionError
from ..utils import info
from ..utils import extract_version, info


def fetch_rubygem_version(url: ParseResult) -> Optional[str]:
def fetch_rubygem_version(url: ParseResult, version_regex: str) -> Optional[str]:
if url.netloc != "rubygems.org":
return None
parts = url.path.split("/")
Expand All @@ -23,7 +23,9 @@ def fetch_rubygem_version(url: ParseResult) -> Optional[str]:
if not version["prerelease"]:
number = version["number"]
assert isinstance(number, str)
return number
extracted = extract_version(number, version_regex)
if extracted is not None:
return extracted
number = versions[0]["number"]
assert isinstance(number, str)
return number
return extract_version(number, version_regex)

0 comments on commit 8fb6c5e

Please sign in to comment.