blob: 0fb07870ca5cfb7c0547a96b9794189e429209e0 [file] [log] [blame]
Mike Frysinger0e2cb7a2019-08-20 17:04:52 -04001#!/usr/bin/python2 -u
showard9d02fb52008-08-08 18:20:37 +00002
3"""
4Utility to upload or remove the packages from the packages repository.
5"""
6
Dale Curtis6ad33192011-07-06 18:04:50 -07007import logging, optparse, os, shutil, sys, tempfile
showard9d02fb52008-08-08 18:20:37 +00008import common
9from autotest_lib.client.common_lib import utils as client_utils
jadmanskic27c2312009-08-05 20:58:51 +000010from autotest_lib.client.common_lib import global_config, error
Allen Libf0c4412017-02-03 16:49:53 -080011from autotest_lib.client.common_lib import packages
showard9d02fb52008-08-08 18:20:37 +000012from autotest_lib.server import utils as server_utils
13
14c = global_config.global_config
showardf6547fe2009-07-08 22:58:53 +000015logging.basicConfig(level=logging.DEBUG)
mblighdbfc4e32008-08-22 18:08:07 +000016
Prashant Malani50287f92017-02-21 11:20:27 -080017ACTION_REMOVE = 'remove'
18ACTION_UPLOAD = 'upload'
19ACTION_TAR_ONLY = 'tar_only'
20
mblighdbfc4e32008-08-22 18:08:07 +000021def get_exclude_string(client_dir):
22 '''
23 Get the exclude string for the tar command to exclude specific
24 subdirectories inside client_dir.
Christopher Wiley8d357f12013-11-06 15:14:37 -080025 For profilers we need to exclude everything except the __init__.py
mblighdbfc4e32008-08-22 18:08:07 +000026 file so that the profilers can be imported.
27 '''
Prashant Malaniad5e10f2017-05-05 16:23:54 -070028 exclude_string = ('--exclude="deps/*" --exclude="tests/*" '
29 '--exclude="site_tests/*" --exclude="**.pyc"')
mblighdbfc4e32008-08-22 18:08:07 +000030
31 # Get the profilers directory
32 prof_dir = os.path.join(client_dir, 'profilers')
33
34 # Include the __init__.py file for the profilers and exclude all its
35 # subdirectories
36 for f in os.listdir(prof_dir):
37 if os.path.isdir(os.path.join(prof_dir, f)):
Prashant Malaniad5e10f2017-05-05 16:23:54 -070038 exclude_string += ' --exclude="profilers/%s"' % f
mblighdbfc4e32008-08-22 18:08:07 +000039
40 # The '.' here is needed to zip the files in the current
41 # directory. We use '-C' for tar to change to the required
42 # directory i.e. src_dir and then zip up the files in that
43 # directory(which is '.') excluding the ones in the exclude_dirs
44 exclude_string += " ."
45
Christopher Wileyef62ed42013-11-21 13:49:02 -080046 # TODO(milleral): This is sad and ugly. http://crbug.com/258161
47 # Surprisingly, |exclude_string| actually means argument list, and
48 # we'd like to package up the current global_config.ini also, so let's
49 # just tack it on here.
50 # Also note that this only works because tar prevents us from un-tarring
51 # files into parent directories.
52 exclude_string += " ../global_config.ini"
53
mblighdbfc4e32008-08-22 18:08:07 +000054 return exclude_string
55
showard9d02fb52008-08-08 18:20:37 +000056
57def parse_args():
58 parser = optparse.OptionParser()
59 parser.add_option("-d", "--dependency", help="package the dependency"
60 " from client/deps directory and upload to the repo",
61 dest="dep")
62 parser.add_option("-p", "--profiler", help="package the profiler "
63 "from client/profilers directory and upload to the repo",
64 dest="prof")
65 parser.add_option("-t", "--test", help="package the test from client/tests"
66 " or client/site_tests and upload to the repo.",
67 dest="test")
68 parser.add_option("-c", "--client", help="package the client "
69 "directory alone without the tests, deps and profilers",
70 dest="client", action="store_true", default=False)
71 parser.add_option("-f", "--file", help="simply uploads the specified"
72 "file on to the repo", dest="file")
73 parser.add_option("-r", "--repository", help="the URL of the packages"
74 "repository location to upload the packages to.",
75 dest="repo", default=None)
Prashant Malani50287f92017-02-21 11:20:27 -080076 parser.add_option("-o", "--output_dir", help="the output directory"
77 "to place tarballs and md5sum files in.",
78 dest="output_dir", default=None)
79 parser.add_option("-a", "--action", help="the action to perform",
80 dest="action", choices=(ACTION_UPLOAD, ACTION_REMOVE,
81 ACTION_TAR_ONLY), default=None)
showard9d02fb52008-08-08 18:20:37 +000082 parser.add_option("--all", help="Upload all the files locally "
83 "to all the repos specified in global_config.ini. "
84 "(includes the client, tests, deps and profilers)",
85 dest="all", action="store_true", default=False)
86
87 options, args = parser.parse_args()
88 return options, args
89
Prashant Malanif7b2f992017-04-05 11:08:08 -070090def get_build_dir(name, dest_dir, pkg_type):
91 """Method to generate the build directory where the tarball and checksum
92 is stored. The following package types are handled: test, dep, profiler.
93 Package type 'client' is not handled.
94 """
95 if pkg_type == 'client':
96 # NOTE: The "tar_only" action for pkg_type "client" has no use
97 # case yet. No known invocations of packager.py with
98 # --action=tar_only send in clients in the command line. Please
99 # confirm the behaviour is expected before this type is enabled for
100 # "tar_only" actions.
101 print ('Tar action not supported for pkg_type= %s, name = %s' %
102 pkg_type, name)
103 return None
104 # For all packages, the work-dir should have 'client' appended to it.
105 base_build_dir = os.path.join(dest_dir, 'client')
106 if pkg_type == 'test':
107 build_dir = os.path.join(get_test_dir(name, base_build_dir), name)
108 else:
109 # For profiler and dep, we append 's', and then append the name.
110 # TODO(pmalani): Make this less fiddly?
111 build_dir = os.path.join(base_build_dir, pkg_type + 's', name)
112 return build_dir
113
Eric Lid656d562011-04-20 11:48:29 -0700114def process_packages(pkgmgr, pkg_type, pkg_names, src_dir,
Prashant Malani50287f92017-02-21 11:20:27 -0800115 action, dest_dir=None):
116 """Method to upload or remove package depending on the flag passed to it.
117
118 If tar_only is set to True, this routine is solely used to generate a
119 tarball and compute the md5sum from that tarball.
120 If the tar_only flag is True, then the remove flag is ignored.
121 """
mblighdbfc4e32008-08-22 18:08:07 +0000122 exclude_string = ' .'
showard9d02fb52008-08-08 18:20:37 +0000123 names = [p.strip() for p in pkg_names.split(',')]
124 for name in names:
Prashant Malaniad5e10f2017-05-05 16:23:54 -0700125 print "process_packages: Processing %s ... " % name
Dale Curtis6ad33192011-07-06 18:04:50 -0700126 if pkg_type == 'client':
showard9d02fb52008-08-08 18:20:37 +0000127 pkg_dir = src_dir
Dale Curtis6ad33192011-07-06 18:04:50 -0700128 exclude_string = get_exclude_string(pkg_dir)
129 elif pkg_type == 'test':
showard9d02fb52008-08-08 18:20:37 +0000130 # if the package is a test then look whether it is in client/tests
131 # or client/site_tests
132 pkg_dir = os.path.join(get_test_dir(name, src_dir), name)
133 else:
134 # for the profilers and deps
135 pkg_dir = os.path.join(src_dir, name)
136
137 pkg_name = pkgmgr.get_tarball_name(name, pkg_type)
Prashant Malani50287f92017-02-21 11:20:27 -0800138
Prashant Malani7c580f12017-08-24 19:38:08 -0700139 exclude_string_tar = ((
140 ' --exclude="**%s" --exclude="**%s.checksum" ' %
141 (pkg_name, pkg_name)) + exclude_string)
Prashant Malani50287f92017-02-21 11:20:27 -0800142 if action == ACTION_TAR_ONLY:
Prashant Malaniad5e10f2017-05-05 16:23:54 -0700143 # We don't want any pre-existing tarballs and checksums to
144 # be repackaged, so we should purge these.
Prashant Malanif7b2f992017-04-05 11:08:08 -0700145 build_dir = get_build_dir(name, dest_dir, pkg_type)
Prashant Malani50287f92017-02-21 11:20:27 -0800146 try:
147 packages.check_diskspace(build_dir)
148 except error.RepoDiskFullError as e:
149 msg = ("Work_dir directory for packages %s does not have "
150 "enough space available: %s" % (build_dir, e))
151 raise error.RepoDiskFullError(msg)
152 tarball_path = pkgmgr.tar_package(pkg_name, pkg_dir,
Prashant Malaniad5e10f2017-05-05 16:23:54 -0700153 build_dir, exclude_string_tar)
Prashant Malani50287f92017-02-21 11:20:27 -0800154
155 # Create the md5 hash too.
156 md5sum = pkgmgr.compute_checksum(tarball_path)
Prashant Malani101485c2017-03-14 23:16:01 -0700157 md5sum_filepath = os.path.join(build_dir, pkg_name + '.checksum')
Prashant Malani50287f92017-02-21 11:20:27 -0800158 with open(md5sum_filepath, "w") as f:
159 f.write(md5sum)
160
161 elif action == ACTION_UPLOAD:
showard9d02fb52008-08-08 18:20:37 +0000162 # Tar the source and upload
mbligh982d13f2009-09-03 20:46:00 +0000163 temp_dir = tempfile.mkdtemp()
showard9d02fb52008-08-08 18:20:37 +0000164 try:
mblighe1836812009-04-17 18:25:14 +0000165 try:
Allen Libf0c4412017-02-03 16:49:53 -0800166 packages.check_diskspace(temp_dir)
mbligh6d7c5652009-11-06 03:00:55 +0000167 except error.RepoDiskFullError, e:
168 msg = ("Temporary directory for packages %s does not have "
169 "enough space available: %s" % (temp_dir, e))
jadmanskic27c2312009-08-05 20:58:51 +0000170 raise error.RepoDiskFullError(msg)
Prashant Malani101485c2017-03-14 23:16:01 -0700171
Prashant Malani7c580f12017-08-24 19:38:08 -0700172 # Check if tarball already exists. If it does, then don't
Prashant Malanie0e4d552017-05-16 15:18:46 -0700173 # create a tarball again.
Prashant Malani101485c2017-03-14 23:16:01 -0700174 tarball_path = os.path.join(pkg_dir, pkg_name);
Prashant Malani7c580f12017-08-24 19:38:08 -0700175 if os.path.exists(tarball_path):
Prashant Malaniad5e10f2017-05-05 16:23:54 -0700176 print("process_packages: Tarball %s already exists" %
177 tarball_path)
Prashant Malani101485c2017-03-14 23:16:01 -0700178 else:
179 tarball_path = pkgmgr.tar_package(pkg_name, pkg_dir,
Prashant Malani7c580f12017-08-24 19:38:08 -0700180 temp_dir,
181 exclude_string_tar)
182 # Compare the checksum with what packages.checksum has. If they
183 # match then we don't need to perform the upload.
184 if not pkgmgr.compare_checksum(tarball_path):
185 pkgmgr.upload_pkg(tarball_path, update_checksum=True)
Prashant Malani804808f2018-02-08 10:23:25 -0800186 else:
187 logging.warning('Checksum not changed for %s, not copied '
188 'in packages/ directory.', tarball_path)
showard9d02fb52008-08-08 18:20:37 +0000189 finally:
190 # remove the temporary directory
191 shutil.rmtree(temp_dir)
Prashant Malani50287f92017-02-21 11:20:27 -0800192 elif action == ACTION_REMOVE:
Eric Lid656d562011-04-20 11:48:29 -0700193 pkgmgr.remove_pkg(pkg_name, remove_checksum=True)
showard9d02fb52008-08-08 18:20:37 +0000194 print "Done."
195
196
mbligh9fc77972008-10-02 20:32:09 +0000197def tar_packages(pkgmgr, pkg_type, pkg_names, src_dir, temp_dir):
198 """Tar all packages up and return a list of each tar created"""
199 tarballs = []
200 exclude_string = ' .'
201 names = [p.strip() for p in pkg_names.split(',')]
202 for name in names:
Prashant Malaniad5e10f2017-05-05 16:23:54 -0700203 print "tar_packages: Processing %s ... " % name
Dale Curtis6ad33192011-07-06 18:04:50 -0700204 if pkg_type == 'client':
mbligh9fc77972008-10-02 20:32:09 +0000205 pkg_dir = src_dir
Dale Curtis6ad33192011-07-06 18:04:50 -0700206 exclude_string = get_exclude_string(pkg_dir)
207 elif pkg_type == 'test':
mbligh9fc77972008-10-02 20:32:09 +0000208 # if the package is a test then look whether it is in client/tests
209 # or client/site_tests
210 pkg_dir = os.path.join(get_test_dir(name, src_dir), name)
211 else:
212 # for the profilers and deps
213 pkg_dir = os.path.join(src_dir, name)
214
215 pkg_name = pkgmgr.get_tarball_name(name, pkg_type)
mbligh9fc77972008-10-02 20:32:09 +0000216
Prashant Malaniad5e10f2017-05-05 16:23:54 -0700217 # We don't want any pre-existing tarballs and checksums to
218 # be repackaged, so we should purge these.
219 exclude_string_tar = ((
220 ' --exclude="**%s" --exclude="**%s.checksum" ' %
221 (pkg_name, pkg_name)) + exclude_string)
Prashant Malani101485c2017-03-14 23:16:01 -0700222 # Check if tarball already exists. If it does, don't duplicate
223 # the effort.
224 tarball_path = os.path.join(pkg_dir, pkg_name);
225 if os.path.exists(tarball_path):
Prashant Malaniad5e10f2017-05-05 16:23:54 -0700226 print("tar_packages: Tarball %s already exists" % tarball_path);
Prashant Malani101485c2017-03-14 23:16:01 -0700227 else:
228 tarball_path = pkgmgr.tar_package(pkg_name, pkg_dir,
Prashant Malaniad5e10f2017-05-05 16:23:54 -0700229 temp_dir, exclude_string_tar)
mbligh9fc77972008-10-02 20:32:09 +0000230 tarballs.append(tarball_path)
mbligh9fc77972008-10-02 20:32:09 +0000231 return tarballs
232
233
Prashant Malani50287f92017-02-21 11:20:27 -0800234def process_all_packages(pkgmgr, client_dir, action):
mbligh9fc77972008-10-02 20:32:09 +0000235 """Process a full upload of packages as a directory upload."""
showard9d02fb52008-08-08 18:20:37 +0000236 dep_dir = os.path.join(client_dir, "deps")
237 prof_dir = os.path.join(client_dir, "profilers")
mbligh9fc77972008-10-02 20:32:09 +0000238 # Directory where all are kept
239 temp_dir = tempfile.mkdtemp()
mblighe1836812009-04-17 18:25:14 +0000240 try:
Allen Libf0c4412017-02-03 16:49:53 -0800241 packages.check_diskspace(temp_dir)
mbligh6d7c5652009-11-06 03:00:55 +0000242 except error.RepoDiskFullError, e:
243 print ("Temp destination for packages is full %s, aborting upload: %s"
244 % (temp_dir, e))
mblighe1836812009-04-17 18:25:14 +0000245 os.rmdir(temp_dir)
246 sys.exit(1)
showard9d02fb52008-08-08 18:20:37 +0000247
248 # process tests
249 tests_list = get_subdir_list('tests', client_dir)
showard9d02fb52008-08-08 18:20:37 +0000250 tests = ','.join(tests_list)
showard9d02fb52008-08-08 18:20:37 +0000251
252 # process site_tests
253 site_tests_list = get_subdir_list('site_tests', client_dir)
showard9d02fb52008-08-08 18:20:37 +0000254 site_tests = ','.join(site_tests_list)
showard9d02fb52008-08-08 18:20:37 +0000255
256 # process deps
257 deps_list = get_subdir_list('deps', client_dir)
258 deps = ','.join(deps_list)
showard9d02fb52008-08-08 18:20:37 +0000259
260 # process profilers
261 profilers_list = get_subdir_list('profilers', client_dir)
262 profilers = ','.join(profilers_list)
mbligh9fc77972008-10-02 20:32:09 +0000263
264 # Update md5sum
Prashant Malani50287f92017-02-21 11:20:27 -0800265 if action == ACTION_UPLOAD:
Dan Shi52d78892013-08-14 16:31:48 -0700266 all_packages = []
267 all_packages.extend(tar_packages(pkgmgr, 'profiler', profilers,
268 prof_dir, temp_dir))
269 all_packages.extend(tar_packages(pkgmgr, 'dep', deps, dep_dir,
270 temp_dir))
271 all_packages.extend(tar_packages(pkgmgr, 'test', site_tests,
272 client_dir, temp_dir))
273 all_packages.extend(tar_packages(pkgmgr, 'test', tests, client_dir,
274 temp_dir))
275 all_packages.extend(tar_packages(pkgmgr, 'client', 'autotest',
276 client_dir, temp_dir))
Dan Shi52d78892013-08-14 16:31:48 -0700277 for package in all_packages:
278 pkgmgr.upload_pkg(package, update_checksum=True)
mbligh9fc77972008-10-02 20:32:09 +0000279 client_utils.run('rm -rf ' + temp_dir)
Prashant Malani50287f92017-02-21 11:20:27 -0800280 elif action == ACTION_REMOVE:
281 process_packages(pkgmgr, 'test', tests, client_dir, action=action)
282 process_packages(pkgmgr, 'test', site_tests, client_dir, action=action)
Eric Lid656d562011-04-20 11:48:29 -0700283 process_packages(pkgmgr, 'client', 'autotest', client_dir,
Prashant Malani50287f92017-02-21 11:20:27 -0800284 action=action)
285 process_packages(pkgmgr, 'dep', deps, dep_dir, action=action)
Eric Lid656d562011-04-20 11:48:29 -0700286 process_packages(pkgmgr, 'profiler', profilers, prof_dir,
Prashant Malani50287f92017-02-21 11:20:27 -0800287 action=action)
mbligh9fc77972008-10-02 20:32:09 +0000288
289
showard9d02fb52008-08-08 18:20:37 +0000290# Get the list of sub directories present in a directory
291def get_subdir_list(name, client_dir):
292 dir_name = os.path.join(client_dir, name)
293 return [f for f in
294 os.listdir(dir_name)
295 if os.path.isdir(os.path.join(dir_name, f)) ]
296
297
298# Look whether the test is present in client/tests and client/site_tests dirs
299def get_test_dir(name, client_dir):
300 names_test = os.listdir(os.path.join(client_dir, 'tests'))
301 names_site_test = os.listdir(os.path.join(client_dir, 'site_tests'))
302 if name in names_test:
303 src_dir = os.path.join(client_dir, 'tests')
304 elif name in names_site_test:
305 src_dir = os.path.join(client_dir, 'site_tests')
306 else:
307 print "Test %s not found" % name
308 sys.exit(0)
309 return src_dir
310
311
showard9d02fb52008-08-08 18:20:37 +0000312def main():
mblighde613a92009-02-03 21:55:34 +0000313 # get options and args
314 options, args = parse_args()
315
showard9d02fb52008-08-08 18:20:37 +0000316 server_dir = server_utils.get_server_dir()
317 autotest_dir = os.path.abspath(os.path.join(server_dir, '..'))
318
319 # extract the pkg locations from global config
320 repo_urls = c.get_config_value('PACKAGES', 'fetch_location',
321 type=list, default=[])
322 upload_paths = c.get_config_value('PACKAGES', 'upload_location',
323 type=list, default=[])
Dale Curtis6ad33192011-07-06 18:04:50 -0700324
325 if options.repo:
326 upload_paths.append(options.repo)
327
showard9d02fb52008-08-08 18:20:37 +0000328 # Having no upload paths basically means you're not using packaging.
Dale Curtis6ad33192011-07-06 18:04:50 -0700329 if not upload_paths:
330 print("No upload locations found. Please set upload_location under"
331 " PACKAGES in the global_config.ini or provide a location using"
332 " the --repository option.")
showard9d02fb52008-08-08 18:20:37 +0000333 return
334
showard9d02fb52008-08-08 18:20:37 +0000335 client_dir = os.path.join(autotest_dir, "client")
336
337 # Bail out if the client directory does not exist
338 if not os.path.exists(client_dir):
339 sys.exit(0)
340
341 dep_dir = os.path.join(client_dir, "deps")
342 prof_dir = os.path.join(client_dir, "profilers")
343
Prashant Malani50287f92017-02-21 11:20:27 -0800344 # Due to the delayed uprev-ing of certain ebuilds, we need to support
345 # both the legacy command line and the new one.
346 # So, if the new "action" option isn't specified, try looking for the
347 # old style remove/upload argument
348 if options.action is None:
349 if len(args) == 0 or args[0] not in ['upload', 'remove']:
350 print("Either 'upload' or 'remove' needs to be specified "
351 "for the package")
352 sys.exit(0)
353 cur_action = args[0]
showard9d02fb52008-08-08 18:20:37 +0000354 else:
Prashant Malani50287f92017-02-21 11:20:27 -0800355 cur_action = options.action
356
357 if cur_action == ACTION_TAR_ONLY and options.output_dir is None:
358 print("An output dir has to be specified")
359 sys.exit(0)
showard9d02fb52008-08-08 18:20:37 +0000360
Eric Lid656d562011-04-20 11:48:29 -0700361 pkgmgr = packages.PackageManager(autotest_dir, repo_urls=repo_urls,
Dale Curtis6ad33192011-07-06 18:04:50 -0700362 upload_paths=upload_paths,
Eric Lid656d562011-04-20 11:48:29 -0700363 run_function_dargs={'timeout':600})
364
showard9d02fb52008-08-08 18:20:37 +0000365 if options.all:
Prashant Malani50287f92017-02-21 11:20:27 -0800366 process_all_packages(pkgmgr, client_dir, action=cur_action)
showard9d02fb52008-08-08 18:20:37 +0000367
368 if options.client:
369 process_packages(pkgmgr, 'client', 'autotest', client_dir,
Prashant Malani50287f92017-02-21 11:20:27 -0800370 action=cur_action)
showard9d02fb52008-08-08 18:20:37 +0000371
372 if options.dep:
373 process_packages(pkgmgr, 'dep', options.dep, dep_dir,
Prashant Malanif7b2f992017-04-05 11:08:08 -0700374 action=cur_action, dest_dir=options.output_dir)
showard9d02fb52008-08-08 18:20:37 +0000375
376 if options.test:
377 process_packages(pkgmgr, 'test', options.test, client_dir,
Prashant Malani50287f92017-02-21 11:20:27 -0800378 action=cur_action, dest_dir=options.output_dir)
showard9d02fb52008-08-08 18:20:37 +0000379
380 if options.prof:
381 process_packages(pkgmgr, 'profiler', options.prof, prof_dir,
Prashant Malanif7b2f992017-04-05 11:08:08 -0700382 action=cur_action, dest_dir=options.output_dir)
showard9d02fb52008-08-08 18:20:37 +0000383
384 if options.file:
Prashant Malani50287f92017-02-21 11:20:27 -0800385 if cur_action == ACTION_REMOVE:
Eric Lid656d562011-04-20 11:48:29 -0700386 pkgmgr.remove_pkg(options.file, remove_checksum=True)
Prashant Malani50287f92017-02-21 11:20:27 -0800387 elif cur_action == ACTION_UPLOAD:
Eric Lid656d562011-04-20 11:48:29 -0700388 pkgmgr.upload_pkg(options.file, update_checksum=True)
showard9d02fb52008-08-08 18:20:37 +0000389
390
391if __name__ == "__main__":
392 main()