Skip to content

Commit 0d4d34b

Browse files
committed
add version
1 parent 4177974 commit 0d4d34b

File tree

2 files changed

+171
-1
lines changed

2 files changed

+171
-1
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
from .git import Git
2+
from .version import Version
23

3-
__all__ = ['Git']
4+
__all__ = ["Git", "Version"]
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
import re
2+
import subprocess
3+
from datetime import datetime, timezone
4+
import requests
5+
from pathlib import Path
6+
7+
from .logger import LoggerSetup
8+
from .features.parse_features import get_features
9+
10+
11+
class Version:
12+
"""Handles version-related operations for Garden Linux."""
13+
14+
def __init__(self, git_root: Path, logger=None):
15+
"""Initialize Version handler.
16+
17+
Args:
18+
git_root: Path to the Git repository root
19+
logger: Optional logger instance
20+
"""
21+
self.git_root = git_root
22+
self.log = logger or LoggerSetup.get_logger("gardenlinux.version")
23+
self.start_date = "Mar 31 00:00:00 UTC 2020"
24+
25+
def get_minor_from_repo(self, major):
26+
"""Check repo.gardenlinux.io for highest available suite minor for given major.
27+
28+
Args:
29+
major: major version
30+
Returns:
31+
minor version
32+
"""
33+
minor = 0
34+
limit = 100 # Hard limit the search
35+
repo_url = f"https://repo.gardenlinux.io/gardenlinux/dists/{major}.{{}}/Release"
36+
37+
while minor <= limit:
38+
try:
39+
check_url = repo_url.format(minor)
40+
response = requests.get(check_url)
41+
if response.status_code != 200:
42+
# No more versions found, return last successful minor
43+
return minor - 1
44+
minor += 1
45+
except requests.RequestException as e:
46+
self.log.debug(f"Error checking repo URL {check_url}: {e}")
47+
return minor - 1
48+
49+
# If we hit the limit, return the last minor
50+
return minor - 1
51+
52+
def get_version(self):
53+
"""Get version using same logic as garden-version bash script.
54+
55+
Args:
56+
version: version string
57+
Returns:
58+
version string
59+
"""
60+
61+
try:
62+
# Check VERSION file
63+
version_file = self.git_root / "VERSION"
64+
if version_file.exists():
65+
version = version_file.read_text().strip()
66+
# Remove comments and empty lines
67+
version = re.sub(r"#.*$", "", version, flags=re.MULTILINE)
68+
version = "\n".join(
69+
line for line in version.splitlines() if line.strip()
70+
)
71+
version = version.strip()
72+
else:
73+
version = "today"
74+
75+
if not version:
76+
version = "today"
77+
78+
# Handle numeric versions (e.g., "27.1")
79+
if re.match(r"^[0-9\.]*$", version):
80+
major = version.split(".")[0]
81+
if int(major) < 10000000: # Sanity check for major version
82+
if "." in version:
83+
return version # Return full version if minor is specified
84+
else:
85+
# Get latest minor version from repo
86+
minor = self.get_minor_from_repo(major)
87+
return f"{major}.{minor}"
88+
89+
# Handle 'today' or 'experimental'
90+
if version in ["today", "experimental"]:
91+
# Calculate days since start date
92+
start_timestamp = datetime.strptime(
93+
self.start_date, "%b %d %H:%M:%S %Z %Y"
94+
).timestamp()
95+
today_timestamp = datetime.now(timezone.utc).timestamp()
96+
major = int((today_timestamp - start_timestamp) / (24 * 60 * 60))
97+
return version
98+
99+
# Handle date input
100+
try:
101+
# Try to parse as date
102+
input_date = datetime.strptime(version, "%Y%m%d")
103+
start_date = datetime.strptime(self.start_date, "%b %d %H:%M:%S %Z %Y")
104+
days_diff = (input_date - start_date).days
105+
return f"{days_diff}.0"
106+
except ValueError:
107+
pass
108+
109+
return version
110+
111+
except Exception as e:
112+
self.log.error(f"Error determining version: {e}")
113+
return "local"
114+
115+
def get_short_commit(self):
116+
"""Get short commit using same logic as the get_commit bash script.
117+
118+
Returns:
119+
short commit string
120+
"""
121+
try:
122+
# Check if COMMIT file exists in git root
123+
commit_file = self.git_root / "COMMIT"
124+
if commit_file.exists():
125+
return commit_file.read_text().strip()
126+
127+
# Check if git repo is clean
128+
status_output = (
129+
subprocess.check_output(
130+
["git", "status", "--porcelain"], stderr=subprocess.DEVNULL
131+
)
132+
.decode()
133+
.strip()
134+
)
135+
136+
if status_output:
137+
self.log.info(f"git status:\n {status_output}")
138+
# Dirty repo or not a git repo
139+
return "local"
140+
else:
141+
# Clean repo - use git commit hash
142+
return (
143+
subprocess.check_output(
144+
["git", "rev-parse", "--short", "HEAD"],
145+
stderr=subprocess.DEVNULL,
146+
)
147+
.decode()
148+
.strip()
149+
)
150+
151+
except subprocess.CalledProcessError:
152+
return "local"
153+
154+
def get_cname(self, platform, features, arch):
155+
"""Get canonical name (cname) for Garden Linux image.
156+
157+
Args:
158+
platform: Platform identifier (e.g., 'kvm', 'aws')
159+
features: List of features
160+
arch: Architecture ('amd64' or 'arm64')
161+
162+
Returns:
163+
Generated cname string
164+
"""
165+
# Get version and commit
166+
version = self.get_version()
167+
commit = self.get_short_commit()
168+
169+
return f"{platform}-{features}-{arch}-{version}-{commit}"

0 commit comments

Comments
 (0)