Skip to content

Commit 40ca566

Browse files
committed
update pod versions in repo
Get latest versions of cocoapods from Cocoapods Specs repo and update podfiles in repo.
1 parent 4e5f8e4 commit 40ca566

File tree

1 file changed

+178
-0
lines changed

1 file changed

+178
-0
lines changed

scripts/update_pod_versions.py

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import argparse
2+
import logging
3+
import os
4+
import pprint
5+
import re
6+
import subprocess
7+
import sys
8+
import tempfile
9+
from collections import defaultdict
10+
from pkg_resources import packaging
11+
12+
PODSPEC_REPOSITORY = 'https://github.com/CocoaPods/Specs.git'
13+
14+
PODS = (
15+
'FirebaseCore',
16+
'FirebaseAdMob',
17+
'FirebaseAnalytics',
18+
'FirebaseAuth',
19+
'FirebaseCrashlytics',
20+
'FirebaseDatabase',
21+
'FirebaseDynamicLinks',
22+
'FirebaseFirestore',
23+
'FirebaseFunctions',
24+
'FirebaseInstallations',
25+
'FirebaseInstanceID',
26+
'FirebaseMessaging',
27+
'FirebaseRemoteConfig',
28+
'FirebaseStorage',
29+
)
30+
31+
PODS2 = (
32+
'FirebaseAuth',
33+
)
34+
35+
def scan_pod_versions(local_repo_dir, pods=PODS):
36+
all_versions = defaultdict(list)
37+
logging.info('Scanning podspecs in Specs repo...')
38+
specs_dir = os.path.join(local_repo_dir, 'Specs')
39+
podspec_extension = ".podspec.json"
40+
for dirpath, _, filenames in os.walk(local_repo_dir):
41+
for f in filenames:
42+
if not f.endswith(podspec_extension):
43+
continue
44+
# Example: FirebaseAuth.podspec.json
45+
podname = f.split('.')[0]
46+
if not podname in pods:
47+
continue
48+
logging.debug('Found matching pod {0} in "Specs" at {1}'.format(podname,
49+
dirpath))
50+
version = os.path.basename(dirpath)
51+
all_versions[podname].append(version)
52+
53+
return all_versions
54+
55+
56+
def get_latest_pod_versions(pods=PODS):
57+
logging.info('Cloning podspecs git repo...')
58+
# Create a temporary directory context to clone pod spec repo.
59+
# Automatically cleaned up on completion of context.
60+
with tempfile.TemporaryDirectory(suffix='pods') as local_specs_repo_dir:
61+
# git_clone_cmd = ['git', 'clone', '-q', '--depth', '1',
62+
# PODSPEC_REPOSITORY, local_specs_repo_dir]
63+
# subprocess.run(git_clone_cmd)
64+
local_specs_repo_dir = '/tmp/foo/Specs'
65+
all_versions = scan_pod_versions(local_specs_repo_dir, pods)
66+
latest_versions = {}
67+
for pod in all_versions:
68+
# all_versions map is in the following format:
69+
# { 'PodnameA' : ['1.0.1', '2.0.4'], 'PodnameB': ['3.0.4', '1.0.2'] }
70+
# Convert string version numbers to semantic version objects and get
71+
# latest version.
72+
latest_version = max([packaging.version.parse(v)
73+
for v in all_versions[pod]])
74+
# Replace the list of versions with just the latest version
75+
latest_versions[pod] = latest_version.base_version
76+
print("Latest pod versions retreived from cocoapods specs repo: \n")
77+
pprint.pprint(latest_versions)
78+
print()
79+
return latest_versions
80+
81+
82+
def get_pod_files(dirs_and_files):
83+
pod_files = []
84+
for entry in dirs_and_files:
85+
abspath = os.path.abspath(entry)
86+
if not os.path.exists(abspath):
87+
continue
88+
if os.path.isdir(abspath):
89+
for dirpath, _, filenames in os.walk(abspath):
90+
for f in filenames:
91+
if f == 'Podfile':
92+
pod_files.append(os.path.join(dirpath, f))
93+
elif os.path.isfile(abspath):
94+
pod_files.append(abspath)
95+
96+
return pod_files
97+
98+
99+
def update_pod_files(pod_files, pod_version_map, dryrun=True):
100+
pattern = re.compile("pod '(?P<pod_name>.+)', '(?P<version>.+)'\n")
101+
for pod_file in pod_files:
102+
to_update = False
103+
existing_lines = []
104+
with open(pod_file, "r") as podfile:
105+
existing_lines = podfile.readlines()
106+
if not existing_lines:
107+
continue
108+
if dryrun:
109+
print('Checking if update is required for {0}'.format(pod_file))
110+
else:
111+
logging.debug('Checking if update is required for {0}'.format(pod_file))
112+
113+
for idx, line in enumerate(existing_lines):
114+
match = re.match(pattern, line.lstrip())
115+
if match:
116+
pod_name = match['pod_name']
117+
pod_name_key = pod_name.replace('/', '')
118+
if pod_name_key in pod_version_map:
119+
latest_version = pod_version_map[pod_name_key]
120+
substituted_line = line.replace(match['version'], latest_version)
121+
if substituted_line != line:
122+
if dryrun:
123+
print('Replacing\n{0}with\n{1}'.format(line, substituted_line))
124+
else:
125+
logging.info('Replacing\n{0}with\n{1}'.format(line, substituted_line))
126+
existing_lines[idx] = substituted_line
127+
to_update = True
128+
129+
if not dryrun and to_update:
130+
print('Updating contents of {0}'.format(pod_file))
131+
with open(pod_file, "w") as podfile:
132+
podfile.writelines(existing_lines)
133+
print()
134+
135+
136+
def main():
137+
args = parse_cmdline_args()
138+
if not args.files_or_dirs:
139+
args.files_or_dirs = [os.getcwd()]
140+
#latest_versions_map = get_latest_pod_versions(PODS)
141+
latest_versions_map = {'FirebaseAuth': '8.0.0', 'FirebaseRemoteConfig':'9.9.9'}
142+
pod_files = get_pod_files(args.files_or_dirs)
143+
update_pod_files(pod_files, latest_versions_map, args.dryrun)
144+
145+
def parse_cmdline_args():
146+
parser = argparse.ArgumentParser(description='Update pod files with '
147+
'latest pod versions')
148+
parser.add_argument('--dryrun', action='store_true',
149+
help='Just print the replaced lines, '
150+
'DO NOT overwrite any files')
151+
parser.add_argument('files_or_dirs', nargs='*', metavar='file',
152+
help= 'List of pod files or directories containing podfiles')
153+
parser.add_argument( "--log_level", default="info",
154+
help="Logging level (debug, warning, info)")
155+
args = parser.parse_args()
156+
157+
# Special handling for log level argument
158+
log_levels = {
159+
'critical': logging.CRITICAL,
160+
'error': logging.ERROR,
161+
'warning': logging.WARNING,
162+
'info': logging.INFO,
163+
'debug': logging.DEBUG
164+
}
165+
166+
level = log_levels.get(args.log_level.lower())
167+
if level is None:
168+
raise ValueError('Please use one of the following as'
169+
'log levels:\n{0}'.format(','.join(log_levels.keys())))
170+
logging.basicConfig(level=level)
171+
logger = logging.getLogger(__name__)
172+
return args
173+
174+
if __name__ == '__main__':
175+
main()
176+
# from IPython import embed
177+
# embed()
178+

0 commit comments

Comments
 (0)