|
10 | 10 | 'inputFile': '.env.default', |
11 | 11 | 'overrideFile': '.env.override', |
12 | 12 | 'outputFile': '.env', |
| 13 | + |
| 14 | + # Mapping of env variable → API version key |
13 | 15 | 'overrideVarMap': { |
14 | 16 | 'ANY_SYNC_NODE_VERSION': 'pkg::any-sync-node', |
15 | 17 | 'ANY_SYNC_FILENODE_VERSION': 'pkg::any-sync-filenode', |
16 | 18 | 'ANY_SYNC_COORDINATOR_VERSION': 'pkg::any-sync-coordinator', |
17 | 19 | 'ANY_SYNC_CONSENSUSNODE_VERSION': 'pkg::any-sync-consensusnode', |
18 | 20 | }, |
| 21 | + |
| 22 | + # Default versions to use if API is unavailable (values without leading 'v') |
| 23 | + 'defaultVersions': { |
| 24 | + 'ANY_SYNC_NODE_VERSION': '0.10.1', |
| 25 | + 'ANY_SYNC_FILENODE_VERSION': '0.10.0', |
| 26 | + 'ANY_SYNC_COORDINATOR_VERSION': '0.8.0', |
| 27 | + 'ANY_SYNC_CONSENSUSNODE_VERSION': '0.5.0', |
| 28 | + }, |
| 29 | + |
| 30 | + # API endpoints for version maps |
19 | 31 | 'versionsUrlMap': { |
20 | 32 | 'prod': 'https://puppetdoc.anytype.io/api/v1/prod-any-sync-compatible-versions/', |
21 | 33 | 'stage1': 'https://puppetdoc.anytype.io/api/v1/stage1-any-sync-compatible-versions/', |
22 | 34 | }, |
| 35 | + |
| 36 | + # Header to prepend to the generated output file |
23 | 37 | 'outputFileHeader': '''# !!! PLEASE DO NOT EDIT THIS FILE !!! |
24 | 38 | # To make changes to the '.env', use the '.env.override' file |
25 | 39 | # https://github.com/anyproto/any-sync-dockercompose/wiki/Configuration |
26 | 40 |
|
27 | 41 | ''', |
28 | 42 | } |
29 | 43 |
|
30 | | -# load variables from inputFile |
| 44 | +# Load variables from inputFile |
31 | 45 | envVars = dict() |
32 | 46 | if os.path.exists(cfg['inputFile']) and os.path.getsize(cfg['inputFile']) > 0: |
33 | 47 | with open(cfg['inputFile']) as file: |
34 | 48 | for line in file: |
| 49 | + # Skip comments and empty lines |
35 | 50 | if line.startswith('#') or not line.strip(): |
36 | 51 | continue |
| 52 | + |
| 53 | + # Parse KEY=VALUE pairs |
37 | 54 | key, value = line.strip().split('=', 1) |
38 | 55 | if key in envVars: |
39 | | - print(f"WARNING: dublicate key={key} in env file={cfg['inputFile']}") |
| 56 | + print(f"WARNING: duplicate key={key} in env file={cfg['inputFile']}") |
40 | 57 | envVars[key] = value |
41 | 58 | else: |
42 | 59 | print(f"ERROR: file={cfg['inputFile']} not found or size=0") |
43 | 60 | exit(1) |
44 | 61 |
|
45 | | -# override variables from overrideFile |
| 62 | +# Override variables from overrideFile (if present) |
46 | 63 | if os.path.exists(cfg['overrideFile']) and os.path.getsize(cfg['overrideFile']) > 0: |
47 | 64 | with open(cfg['overrideFile']) as file: |
48 | 65 | for line in file: |
| 66 | + # Skip comments and empty lines |
49 | 67 | if line.startswith('#') or not line.strip(): |
50 | 68 | continue |
| 69 | + |
51 | 70 | key, value = line.strip().split('=', 1) |
52 | 71 | envVars[key] = value |
53 | 72 |
|
54 | | -# api request |
| 73 | +# Perform API request; return None on failure |
55 | 74 | def apiRequest(url): |
56 | 75 | try: |
57 | 76 | response = requests.get(url, timeout=(3.05, 5)) |
58 | | - jsonResponse = response.json() |
59 | 77 | except Exception as e: |
60 | 78 | print(f"failed response url={url}, error={str(e)}") |
61 | | - exit(1) |
| 79 | + return None |
| 80 | + |
62 | 81 | if response.status_code != 200: |
63 | 82 | print(f"failed response url={url}, status_code={response.status_code}, text={response.text}") |
64 | | - exit(1) |
| 83 | + return None |
| 84 | + |
| 85 | + try: |
| 86 | + jsonResponse = response.json() |
| 87 | + except Exception as e: |
| 88 | + print(f"failed parse json url={url}, error={str(e)}") |
| 89 | + return None |
| 90 | + |
65 | 91 | return jsonResponse |
66 | 92 |
|
67 | | -# get latest version |
| 93 | +# Fetch latest compatible versions for a given environment ("prod", "stage1") |
68 | 94 | def getLatestVersions(role): |
69 | 95 | versions = apiRequest(cfg['versionsUrlMap'][role]) |
70 | | - sortedVersions = dict(sorted(versions.items(), key=lambda x: int(x[0]))) |
71 | | - lastVersionsTimestamp, lastVersions = next(reversed(sortedVersions.items())) |
| 96 | + if not versions: |
| 97 | + return None |
| 98 | + |
| 99 | + try: |
| 100 | + # API returns timestamps as string keys; sort numerically |
| 101 | + sortedVersions = dict(sorted(versions.items(), key=lambda x: int(x[0]))) |
| 102 | + |
| 103 | + # Take the last (latest) timestamp entry |
| 104 | + lastVersionsTimestamp, lastVersions = next(reversed(sortedVersions.items())) |
| 105 | + except Exception as e: |
| 106 | + print(f"failed to process versions for role={role}, error={str(e)}") |
| 107 | + return None |
| 108 | + |
72 | 109 | return lastVersions |
73 | 110 |
|
74 | | -# process variables |
75 | | -for key,value in envVars.items(): |
| 111 | +# Process variables that may require version substitution |
| 112 | +for key, value in envVars.items(): |
76 | 113 | if key in cfg['overrideVarMap'].keys(): |
| 114 | + # value must match an API environment key ("prod", "stage1") |
77 | 115 | if value in cfg['versionsUrlMap'].keys(): |
78 | 116 | latestVersions = getLatestVersions(value) |
79 | | - lastVersionKey = cfg['overrideVarMap'].get(key) |
80 | | - lastVersionValue = latestVersions.get(lastVersionKey) |
81 | | - if lastVersionKey and lastVersionValue: |
82 | | - envVars[key] = 'v'+str(lastVersionValue) |
83 | 117 |
|
84 | | -# save in output file |
| 118 | + if latestVersions: |
| 119 | + lastVersionKey = cfg['overrideVarMap'].get(key) |
| 120 | + lastVersionValue = latestVersions.get(lastVersionKey) |
| 121 | + |
| 122 | + # If API returned a valid version → use it |
| 123 | + if lastVersionKey and lastVersionValue: |
| 124 | + envVars[key] = 'v' + str(lastVersionValue) |
| 125 | + continue # Continue to next env variable |
| 126 | + |
| 127 | + # Fallback: use default version from config if API failed |
| 128 | + defaultVersion = cfg.get('defaultVersions', {}).get(key) |
| 129 | + if defaultVersion: |
| 130 | + print(f"using default version for {key}: {defaultVersion}") |
| 131 | + envVars[key] = 'v' + str(defaultVersion) |
| 132 | + |
| 133 | +# Write final env file |
85 | 134 | with open(cfg['outputFile'], 'w') as file: |
86 | 135 | file.write(cfg['outputFileHeader']) |
87 | 136 | for key, value in envVars.items(): |
|
0 commit comments