Print this page
305 http_proxy value needs more checking for valid url syntax
2341 Client should be more conservative about closing sockets
4235 Misleading "node name" unknown messages when http_proxy set incorrectly
4495 Want ability to cancel individual file downloads
8902 Need a transport that downloads files by GET
9508 Captive portal test only run during catalog refresh
9613 Implicit refresh should raise InvalidDepotResponseException
9615 EOL clientside search v0
9629 EOL clientside support for filelist
9630 Hostile depot should live with other depot code
9631 HTTPS transport should be more rigorous in verification
9670 More specific error exceptions requested from search
9686 network operations should use accept-encoding when appropriate
9715 The info() operation should use the activity_lock
| Split |
Close |
| Expand all |
| Collapse all |
--- old/src/client.py
+++ new/src/client.py
1 1 #!/usr/bin/python2.4
2 2 #
3 3 # CDDL HEADER START
4 4 #
5 5 # The contents of this file are subject to the terms of the
6 6 # Common Development and Distribution License (the "License").
7 7 # You may not use this file except in compliance with the License.
8 8 #
9 9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 10 # or http://www.opensolaris.org/os/licensing.
11 11 # See the License for the specific language governing permissions
12 12 # and limitations under the License.
13 13 #
14 14 # When distributing Covered Code, include this CDDL HEADER in each
15 15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 16 # If applicable, add the following below this CDDL HEADER, with the
17 17 # fields enclosed by brackets "[]" replaced with your own identifying
18 18 # information: Portions Copyright [yyyy] [name of copyright owner]
19 19 #
20 20 # CDDL HEADER END
21 21 #
22 22 # Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 # Use is subject to license terms.
24 24 #
25 25 # pkg - package system client utility
26 26 #
27 27 # We use urllib2 for GET and POST operations, but httplib for PUT and DELETE
28 28 # operations.
29 29 #
30 30 # The client is going to maintain an on-disk cache of its state, so that
31 31 # startup assembly of the graph is reduced.
32 32 #
33 33 # Client graph is of the entire local catalog. As operations progress, package
34 34 # states will change.
35 35 #
36 36 # Deduction operation allows the compilation of the local component of the
37 37 # catalog, only if an authoritative repository can identify critical files.
38 38 #
39 39 # Environment variables
40 40 #
41 41 # PKG_IMAGE - root path of target image
42 42 # PKG_IMAGE_TYPE [entire, partial, user] - type of image
43 43 # XXX or is this in the Image configuration?
44 44
45 45 import calendar
46 46 import datetime
47 47 import errno
48 48 import getopt
49 49 import gettext
50 50 import itertools
51 51 import locale
52 52 import os
53 53 import socket
54 54 import sys
55 55 import time
56 56 import traceback
57 57 import urllib2
58 58 import urlparse
59 59
60 60 import pkg
61 61 import pkg.actions as actions
62 62 import pkg.client.api as api
63 63 import pkg.client.api_errors as api_errors
64 64 import pkg.client.bootenv as bootenv
65 65 import pkg.client.history as history
66 66 import pkg.client.image as image
67 67 import pkg.client.imagetypes as imgtypes
|
↓ open down ↓ |
67 lines elided |
↑ open up ↑ |
68 68 import pkg.client.progress as progress
69 69 import pkg.client.publisher as publisher
70 70 import pkg.fmri as fmri
71 71 import pkg.misc as misc
72 72
73 73 from pkg.client import global_settings
74 74 from pkg.client.debugvalues import DebugValues
75 75 from pkg.client.history import (RESULT_CANCELED, RESULT_FAILED_BAD_REQUEST,
76 76 RESULT_FAILED_CONFIGURATION, RESULT_FAILED_TRANSPORT, RESULT_FAILED_UNKNOWN,
77 77 RESULT_FAILED_OUTOFMEMORY)
78 -from pkg.client.filelist import FileListRetrievalError
79 -from pkg.client.retrieve import (CatalogRetrievalError,
80 - DatastreamRetrievalError, ManifestRetrievalError)
81 78 from pkg.misc import EmptyI, msg, emsg, PipeError
82 79
83 80 CLIENT_API_VERSION = 15
84 81 PKG_CLIENT_NAME = "pkg"
85 82
86 83 def error(text, cmd=None):
87 84 """Emit an error message prefixed by the command name """
88 85
89 86 if cmd:
90 87 text = "%s: %s" % (cmd, text)
91 88 else:
92 89 # If we get passed something like an Exception, we can convert
93 90 # it down to a string.
94 91 text = str(text)
95 92
96 93 # If the message starts with whitespace, assume that it should come
97 94 # *before* the command-name prefix.
98 95 text_nows = text.lstrip()
99 96 ws = text[:len(text) - len(text_nows)]
100 97
101 98 # This has to be a constant value as we can't reliably get our actual
102 99 # program name on all platforms.
103 100 emsg(ws + "pkg: " + text_nows)
104 101
105 102 def usage(usage_error=None, cmd=None, retcode=2):
106 103 """Emit a usage message and optionally prefix it with a more
107 104 specific error message. Causes program to exit. """
108 105
109 106 if usage_error:
110 107 error(usage_error, cmd=cmd)
111 108
112 109 emsg(_("""\
113 110 Usage:
114 111 pkg [options] command [cmd_options] [operands]
115 112
116 113 Basic subcommands:
117 114 pkg install [-nvq] [--no-refresh] [--no-index] package...
118 115 pkg uninstall [-nrvq] [--no-index] package...
119 116 pkg list [-Hafsuv] [--no-refresh] [package...]
120 117 pkg image-update [-fnvq] [--be-name name] [--no-refresh] [--no-index]
121 118 pkg refresh [--full] [publisher ...]
122 119 pkg version
123 120
124 121 Advanced subcommands:
125 122 pkg info [-lr] [--license] [pkg_fmri_pattern ...]
126 123 pkg search [-alprI] [-s server] query
127 124 pkg verify [-Hqv] [pkg_fmri_pattern ...]
128 125 pkg fix [pkg_fmri_pattern ...]
129 126 pkg contents [-Hmr] [-o attribute ...] [-s sort_key]
130 127 [-t action_type ... ] [pkg_fmri_pattern ...]
131 128 pkg image-create [-fFPUz] [--force] [--full|--partial|--user] [--zone]
132 129 [-k ssl_key] [-c ssl_cert] [--no-refresh]
133 130 [--variant <variant_spec>=<instance>]
134 131 (-p|--publisher) name=uri dir
135 132
136 133 pkg set-property propname propvalue
137 134 pkg unset-property propname ...
138 135 pkg property [-H] [propname ...]
139 136
140 137 pkg set-publisher [-Ped] [-k ssl_key] [-c ssl_cert]
141 138 [-O origin_uri] [-m mirror_to_add | --add-mirror=mirror_to_add]
142 139 [-M mirror_to_remove | --remove-mirror=mirror_to_remove]
143 140 [--enable] [--disable] [--no-refresh] [--reset-uuid] publisher
144 141 pkg unset-publisher publisher ...
145 142 pkg publisher [-HPa] [publisher ...]
146 143 pkg history [-Hl]
147 144 pkg purge-history
148 145 pkg rebuild-index
149 146
150 147 Options:
151 148 -R dir
152 149 --help or -?
153 150
154 151 Environment:
155 152 PKG_IMAGE"""))
156 153 sys.exit(retcode)
157 154
158 155 # XXX Subcommands to implement:
159 156 # pkg image-set name value
160 157 # pkg image-unset name
161 158 # pkg image-get [name ...]
162 159
163 160 INCONSISTENT_INDEX_ERROR_MESSAGE = "The search index appears corrupted. " + \
164 161 "Please rebuild the index with 'pkg rebuild-index'."
165 162
166 163 PROBLEMATIC_PERMISSIONS_ERROR_MESSAGE = "\n(Failure of consistent use " + \
167 164 "of pfexec when executing pkg commands is often a\nsource of this problem.)"
168 165
169 166 def check_fmri_args(args):
170 167 """ Convenience routine to check that input args are valid fmris. """
171 168 ret = True
172 169 for x in args:
173 170 try:
174 171 #
175 172 # Pass a bogus build release-- needed to satisfy
176 173 # fmri's checks in the common case that a version but
177 174 # no build release was specified by the user.
178 175 #
179 176 fmri.MatchingPkgFmri(x, build_release="1.0")
180 177 except fmri.IllegalFmri, e:
181 178 error(e)
182 179 ret = False
183 180 return ret
184 181
185 182 def list_inventory(img, args):
186 183 """List packages."""
187 184
188 185 all_known = False
189 186 all_versions = True
190 187 display_headers = True
191 188 refresh_catalogs = True
192 189 summary = False
193 190 upgradable_only = False
194 191 verbose = False
195 192
196 193 opts, pargs = getopt.getopt(args, "Hafsuv", ["no-refresh"])
197 194
198 195 for opt, arg in opts:
199 196 if opt == "-a":
200 197 all_known = True
201 198 elif opt == "-H":
202 199 display_headers = False
203 200 elif opt == "-s":
204 201 summary = True
205 202 elif opt == "-u":
206 203 upgradable_only = True
207 204 elif opt == "-v":
208 205 verbose = True
209 206 elif opt == "-f":
210 207 all_versions = False
211 208 elif opt == "--no-refresh":
212 209 refresh_catalogs = False
213 210
214 211 if summary and verbose:
215 212 usage(_("-s and -v may not be combined"))
216 213
217 214 if verbose:
218 215 fmt_str = "%-64s %-10s %s"
219 216 elif summary:
220 217 fmt_str = "%-30s %s"
221 218 else:
222 219 fmt_str = "%-45s %-15s %-10s %s"
223 220
224 221 if not check_fmri_args(pargs):
225 222 return 1
226 223
227 224 img.history.operation_name = "list"
228 225 img.load_catalogs(progress.NullProgressTracker())
229 226
230 227 api_inst = api.ImageInterface(img.get_root(), CLIENT_API_VERSION,
231 228 get_tracker(quiet=True), None, PKG_CLIENT_NAME)
232 229 info_needed = frozenset([api.PackageInfo.SUMMARY])
233 230
234 231 seen_one_pkg = False
235 232 found = False
236 233 try:
237 234 if all_known and refresh_catalogs:
238 235 # If the user requested all known packages, ensure that
239 236 # a publisher metadata refresh is performed if needed
240 237 # since the catalog may be out of date or invalid as
241 238 # a result of publisher information changing (such as
242 239 # an origin uri, etc.).
243 240 tracker = get_tracker(quiet=not display_headers)
244 241 try:
245 242 img.refresh_publishers(progtrack=tracker)
246 243 except KeyboardInterrupt:
247 244 raise
248 245 except:
249 246 # Ignore the above error and just use what
250 247 # already exists.
251 248 pass
252 249
253 250 res = misc.get_inventory_list(img, pargs,
254 251 all_known, all_versions)
255 252 prev_pfmri_str = ""
256 253 prev_state = None
257 254 for pfmri, state in res:
258 255 if all_versions and prev_pfmri_str and \
259 256 prev_pfmri_str == pfmri.get_short_fmri() and \
260 257 prev_state == state:
261 258 continue
262 259 prev_pfmri_str = pfmri.get_short_fmri()
263 260 prev_state = state
264 261 seen_one_pkg = True
265 262 if upgradable_only and not state["upgradable"]:
266 263 continue
267 264
268 265 if not found:
269 266 if display_headers:
270 267 if verbose:
271 268 msg(fmt_str % \
272 269 ("FMRI", "STATE", "UFIX"))
273 270 elif summary:
274 271 msg(fmt_str % \
275 272 ("NAME (PUBLISHER)",
276 273 "SUMMARY"))
277 274 else:
278 275 msg(fmt_str % \
279 276 ("NAME (PUBLISHER)",
280 277 "VERSION", "STATE", "UFIX"))
281 278 found = True
282 279 ufix = "%c%c%c%c" % \
283 280 (state["upgradable"] and "u" or "-",
284 281 state["frozen"] and "f" or "-",
285 282 state["incorporated"] and "i" or "-",
286 283 state["excludes"] and "x" or "-")
287 284
288 285 if pfmri.preferred_publisher():
289 286 pub = ""
290 287 else:
291 288 pub = " (" + pfmri.get_publisher() + ")"
292 289
293 290 if verbose:
294 291 pf = pfmri.get_fmri(
295 292 img.get_preferred_publisher())
296 293 msg("%-64s %-10s %s" % (pf, state["state"],
297 294 ufix))
298 295 elif summary:
299 296 pf = pfmri.get_name() + pub
300 297
301 298 try:
302 299 ret = api_inst.info([pfmri], False,
303 300 info_needed)
304 301 pis = ret[api.ImageInterface.INFO_FOUND]
305 302 except api_errors.ApiException, e:
306 303 error(e)
307 304 return 1
308 305
309 306 msg(fmt_str % (pf, pis[0].summary))
310 307
311 308 else:
312 309 pf = pfmri.get_name() + pub
313 310 msg(fmt_str % (pf, pfmri.get_version(),
314 311 state["state"], ufix))
315 312
316 313 if not found:
317 314 if not seen_one_pkg and not all_known:
318 315 emsg(_("no packages installed"))
319 316 img.history.operation_result = \
320 317 history.RESULT_NOTHING_TO_DO
321 318 return 1
322 319
323 320 if upgradable_only:
324 321 if pargs:
325 322 emsg(_("No specified packages have " \
326 323 "available updates"))
327 324 else:
328 325 emsg(_("No installed packages have " \
329 326 "available updates"))
330 327 img.history.operation_result = \
331 328 history.RESULT_NOTHING_TO_DO
332 329 return 1
333 330
334 331 img.history.operation_result = \
335 332 history.RESULT_NOTHING_TO_DO
336 333 return 1
337 334
338 335 img.history.operation_result = history.RESULT_SUCCEEDED
339 336 return 0
340 337
341 338 except api_errors.InventoryException, e:
342 339 if e.illegal:
343 340 for i in e.illegal:
344 341 error(i)
345 342 img.history.operation_result = \
346 343 history.RESULT_FAILED_BAD_REQUEST
347 344 return 1
348 345
349 346 if all_known:
350 347 state = image.PKG_STATE_KNOWN
351 348 else:
352 349 state = image.PKG_STATE_INSTALLED
353 350 for pat in e.notfound:
354 351 error(_("no packages matching "
355 352 "'%(pattern)s' %(state)s") %
356 353 { "pattern": pat, "state": state })
357 354 img.history.operation_result = history.RESULT_NOTHING_TO_DO
358 355 return 1
359 356
360 357 def get_tracker(quiet=False):
361 358 if quiet:
362 359 progresstracker = progress.QuietProgressTracker()
363 360 else:
364 361 try:
365 362 progresstracker = \
366 363 progress.FancyUNIXProgressTracker()
367 364 except progress.ProgressTrackerException:
368 365 progresstracker = progress.CommandLineProgressTracker()
369 366 return progresstracker
370 367
371 368 def fix_image(img, args):
372 369 progresstracker = get_tracker(False)
373 370 img.load_catalogs(progresstracker)
374 371 fmris, notfound, illegals = img.installed_fmris_from_args(args)
375 372
376 373 any_errors = False
377 374 repairs = []
378 375 for f in fmris:
379 376 failed_actions = []
380 377 for err in img.verify(f, progresstracker,
381 378 verbose=True, forever=True):
382 379 if not failed_actions:
383 380 msg("Verifying: %-50s %7s" %
384 381 (f.get_pkg_stem(), "ERROR"))
385 382 act = err[0]
386 383 failed_actions.append(act)
387 384 msg("\t%s" % act.distinguished_name())
388 385 for x in err[1]:
389 386 msg("\t\t%s" % x)
390 387 if failed_actions:
391 388 repairs.append((f, failed_actions))
392 389
393 390 # Repair anything we failed to verify
394 391 if repairs:
395 392 # Create a snapshot in case they want to roll back
396 393 try:
397 394 be = bootenv.BootEnv(img.get_root())
398 395 if be.exists():
399 396 msg(_("Created ZFS snapshot: %s" %
400 397 be.snapshot_name))
401 398 except RuntimeError:
402 399 pass # Error is printed by the BootEnv call.
403 400 success = img.repair(repairs, progresstracker)
404 401 if not success:
405 402 progresstracker.verify_done()
406 403 return 1
407 404 progresstracker.verify_done()
408 405 return 0
409 406
410 407 def verify_image(img, args):
411 408 opts, pargs = getopt.getopt(args, "vfqH")
412 409
413 410 quiet = verbose = False
414 411 # for now, always check contents of files
415 412 forever = display_headers = True
416 413
417 414 for opt, arg in opts:
418 415 if opt == "-H":
419 416 display_headers = False
420 417 if opt == "-v":
421 418 verbose = True
422 419 elif opt == "-f":
423 420 forever = True
424 421 elif opt == "-q":
425 422 quiet = True
426 423 display_headers = False
427 424
428 425 if verbose and quiet:
429 426 usage(_("verify: -v and -q may not be combined"))
430 427
431 428 progresstracker = get_tracker(quiet)
432 429
433 430 if not check_fmri_args(pargs):
434 431 return 1
435 432
436 433 img.load_catalogs(progresstracker)
437 434
438 435 fmris, notfound, illegals = img.installed_fmris_from_args(pargs)
439 436
440 437 if illegals:
441 438 for i in illegals:
442 439 emsg(str(i))
443 440 return 1
444 441
445 442 any_errors = False
446 443
447 444 header = False
448 445 for f in fmris:
449 446 pkgerr = False
450 447 for err in img.verify(f, progresstracker,
451 448 verbose=verbose, forever=forever):
452 449 #
453 450 # Eventually this code should probably
454 451 # move into the progresstracker
455 452 #
456 453 if not pkgerr:
457 454 if display_headers and not header:
458 455 msg("%-50s %7s" % ("PACKAGE", "STATUS"))
459 456 header = True
460 457
461 458 if not quiet:
462 459 msg("%-50s %7s" % (f.get_pkg_stem(),
463 460 "ERROR"))
464 461 pkgerr = True
465 462
466 463 if not quiet:
467 464 msg("\t%s" % err[0].distinguished_name())
468 465 for x in err[1]:
469 466 msg("\t\t%s" % x)
470 467 if verbose and not pkgerr:
471 468 if display_headers and not header:
472 469 msg("%-50s %7s" % ("PACKAGE", "STATUS"))
473 470 header = True
474 471 msg("%-50s %7s" % (f.get_pkg_stem(), "OK"))
475 472
476 473 any_errors = any_errors or pkgerr
477 474
478 475 if fmris:
479 476 progresstracker.verify_done()
480 477
481 478 if notfound:
482 479 if fmris:
483 480 emsg()
484 481 emsg(_("""\
485 482 pkg: no packages matching the following patterns you specified are
486 483 installed on the system.\n"""))
487 484 for p in notfound:
488 485 emsg(" %s" % p)
489 486 if fmris:
490 487 if any_errors:
491 488 msg2 = "See above for\nverification failures."
492 489 else:
493 490 msg2 = "No packages failed\nverification."
494 491 emsg(_("\nAll other patterns matched installed "
495 492 "packages. %s" % msg2))
496 493 any_errors = True
497 494
498 495 if any_errors:
499 496 return 1
500 497 return 0
501 498
502 499 def image_update(img_dir, args):
503 500 """Attempt to take all installed packages specified to latest
504 501 version."""
505 502
506 503 # XXX Publisher-catalog issues.
507 504 # XXX Are filters appropriate for an image update?
508 505 # XXX Leaf package refinements.
509 506
510 507 opts, pargs = getopt.getopt(args, "fnvq", ["be-name=", "no-refresh",
511 508 "no-index"])
512 509
513 510 force = quiet = noexecute = verbose = False
514 511 refresh_catalogs = update_index = True
515 512 be_name = None
516 513 for opt, arg in opts:
517 514 if opt == "-n":
518 515 noexecute = True
519 516 elif opt == "-v":
520 517 verbose = True
521 518 elif opt == "-q":
522 519 quiet = True
523 520 elif opt == "-f":
524 521 force = True
525 522 elif opt == "--no-refresh":
526 523 refresh_catalogs = False
527 524 elif opt == "--no-index":
528 525 update_index = False
529 526 elif opt == "--be-name":
530 527 be_name = arg
531 528
532 529 if verbose and quiet:
533 530 usage(_("image-update: -v and -q may not be combined"))
534 531
535 532 if pargs:
536 533 usage(_("image-update: command does not take operands " \
537 534 "('%s')") % " ".join(pargs))
538 535
539 536 progresstracker = get_tracker(quiet)
540 537
541 538 try:
542 539 api_inst = api.ImageInterface(img_dir, CLIENT_API_VERSION,
543 540 progresstracker, cancel_state_callable=None,
544 541 pkg_client_name=PKG_CLIENT_NAME)
545 542 except api_errors.ImageNotFoundException, e:
546 543 error(_("No image rooted at '%s'") % e.user_dir)
547 544 return 1
548 545
549 546 try:
550 547 # cre is either None or a catalog refresh exception which was
551 548 # caught while planning.
552 549 stuff_to_do, opensolaris_image, cre = \
553 550 api_inst.plan_update_all(sys.argv[0], refresh_catalogs,
554 551 noexecute, force=force, verbose=verbose,
555 552 update_index=update_index, be_name=be_name)
556 553 if cre and not display_catalog_failures(cre):
557 554 raise RuntimeError("Catalog refresh failed during"
558 555 " image-update.")
559 556 if not stuff_to_do:
560 557 msg(_("No updates available for this image."))
561 558 return 0
562 559 except api_errors.InventoryException, e:
563 560 error(_("image-update failed (inventory exception):\n%s") % e)
564 561 return 1
565 562 except api_errors.CatalogRefreshException, e:
566 563 if display_catalog_failures(e) == 0:
|
↓ open down ↓ |
476 lines elided |
↑ open up ↑ |
567 564 if not noexecute:
568 565 return 1
569 566 else:
570 567 raise RuntimeError("Catalog refresh failed during"
571 568 " image-update.")
572 569 except api_errors.BEException, e:
573 570 error(_(e))
574 571 return 1
575 572 except (api_errors.CertificateError,
576 573 api_errors.PlanCreationException,
577 - api_errors.NetworkUnavailableException,
578 574 api_errors.PermissionsException), e:
579 575 # Prepend a newline because otherwise the exception will
580 576 # be printed on the same line as the spinner.
581 577 error("\n" + str(e))
582 578 return 1
583 579 except api_errors.IpkgOutOfDateException:
584 580 msg(_("WARNING: pkg(5) appears to be out of date, and should " \
585 581 "be updated before\nrunning image-update.\n"))
586 582 msg(_("Please update pkg(5) using 'pfexec pkg install " \
587 583 "SUNWipkg' and then retry\nthe image-update."))
588 584 return 1
589 585 except api_errors.ImageNotFoundException, e:
590 586 error(_("No image rooted at '%s'") % e.user_dir)
591 587 return 1
|
↓ open down ↓ |
4 lines elided |
↑ open up ↑ |
592 588 if noexecute:
593 589 return 0
594 590
595 591 ret_code = 0
596 592
597 593 # Exceptions which happen here are printed in the above level, with
598 594 # or without some extra decoration done here.
599 595 # XXX would be nice to kick the progress tracker.
600 596 try:
601 597 api_inst.prepare()
602 - except misc.TransportException:
598 + except api_errors.TransportError, e:
603 599 # move past the progress tracker line.
604 600 msg("\n")
605 - raise
601 + if verbose:
602 + e.verbose = True
603 + raise e
606 604 except KeyboardInterrupt:
607 605 raise
608 606 except api_errors.PermissionsException, e:
609 607 # Prepend a newline because otherwise the exception will
610 608 # be printed on the same line as the spinner.
611 609 error("\n" + str(e))
612 610 return 1
613 611 except:
614 612 error(_("\nAn unexpected error happened while preparing for " \
615 613 "image-update:"))
616 614 raise
617 615
618 616 try:
619 617 api_inst.execute_plan()
620 618 except RuntimeError, e:
621 619 error(_("image-update failed: %s") % e)
622 620 ret_code = 1
623 621 except api_errors.ImageUpdateOnLiveImageException:
624 622 error(_("image-update cannot be done on live image"))
625 623 ret_code = 1
626 624 except api_errors.CorruptedIndexException, e:
627 625 error(INCONSISTENT_INDEX_ERROR_MESSAGE)
628 626 ret_code = 1
629 627 except api_errors.ProblematicPermissionsIndexException, e:
630 628 error(str(e) + PROBLEMATIC_PERMISSIONS_ERROR_MESSAGE)
631 629 ret_code = 1
632 630 except api_errors.PermissionsException, e:
633 631 # Prepend a newline because otherwise the exception will
634 632 # be printed on the same line as the spinner.
635 633 error("\n" + str(e))
636 634 ret_code = 1
637 635 except api_errors.MainDictParsingException, e:
638 636 error(str(e))
639 637 ret_code = 1
640 638 except api_errors.BEException, e:
641 639 error(_(e))
642 640 return 1
643 641 except KeyboardInterrupt:
644 642 raise
645 643 except Exception, e:
646 644 error(_("\nAn unexpected error happened during " \
647 645 "image-update: %s") % e)
648 646 raise
649 647
650 648 if ret_code == 0 and opensolaris_image:
651 649 msg("\n" + "-" * 75)
652 650 msg(_("NOTE: Please review release notes posted at:\n" ))
653 651 msg(misc.get_release_notes_url())
654 652 msg("-" * 75 + "\n")
655 653
656 654 if bool(os.environ.get("PKG_MIRROR_STATS", False)):
657 655 print_mirror_stats(api_inst)
658 656
659 657 return ret_code
660 658
661 659 def print_mirror_stats(api_inst):
662 660 """Given an api_inst object, print depot status information."""
663 661
664 662 status_fmt = "%-10s %-35s %10s %10s"
665 663 print status_fmt % ("Publisher", "URI", "Success", "Failure")
666 664
667 665 for ds in api_inst.img.gen_depot_status():
668 666 print status_fmt % (ds.prefix, ds.url, ds.good_tx, ds.errors)
669 667
670 668 def install(img_dir, args):
671 669 """Attempt to take package specified to INSTALLED state. The operands
672 670 are interpreted as glob patterns."""
673 671
674 672 # XXX Publisher-catalog issues.
675 673
676 674 opts, pargs = getopt.getopt(args, "nvf:q", ["no-refresh", "no-index"])
677 675
678 676 quiet = noexecute = verbose = False
679 677 refresh_catalogs = update_index = True
680 678 filters = []
681 679 for opt, arg in opts:
682 680 if opt == "-n":
683 681 noexecute = True
684 682 elif opt == "-v":
685 683 verbose = True
686 684 elif opt == "-f":
687 685 filters += [ arg ]
688 686 elif opt == "-q":
689 687 quiet = True
690 688 elif opt == "--no-refresh":
691 689 refresh_catalogs = False
692 690 elif opt == "--no-index":
693 691 update_index = False
694 692
695 693 if not pargs:
696 694 usage(_("install: at least one package name required"))
697 695
698 696 if verbose and quiet:
699 697 usage(_("install: -v and -q may not be combined"))
700 698
701 699 progresstracker = get_tracker(quiet)
702 700
703 701 if not check_fmri_args(pargs):
704 702 return 1
705 703
706 704 # XXX not sure where this should live
707 705 pkg_list = [ pat.replace("*", ".*").replace("?", ".")
708 706 for pat in pargs ]
709 707
710 708 try:
711 709 api_inst = api.ImageInterface(img_dir, CLIENT_API_VERSION,
712 710 progresstracker, None, PKG_CLIENT_NAME)
713 711 except api_errors.ImageNotFoundException, e:
714 712 error(_("'%s' is not an install image") % e.user_dir)
715 713 return 1
716 714
717 715 try:
718 716 # cre is either None or a catalog refresh exception which was
719 717 # caught while planning.
720 718 stuff_to_do, cre = api_inst.plan_install(pkg_list, filters,
721 719 refresh_catalogs, noexecute, verbose=verbose,
722 720 update_index=update_index)
723 721 if cre and not display_catalog_failures(cre):
724 722 raise RuntimeError("Catalog refresh failed during"
725 723 " install.")
726 724 if not stuff_to_do:
727 725 msg(_("No updates available for this image."))
728 726 return 0
|
↓ open down ↓ |
113 lines elided |
↑ open up ↑ |
729 727 except api_errors.CatalogRefreshException, e:
730 728 if display_catalog_failures(e) == 0:
731 729 if not noexecute:
732 730 return 1
733 731 else:
734 732 error(_("Catalog refresh failed during install."),
735 733 cmd="install")
736 734 return 1
737 735 except (api_errors.CertificateError,
738 736 api_errors.PlanCreationException,
739 - api_errors.NetworkUnavailableException,
740 737 api_errors.PermissionsException), e:
741 738 # Prepend a newline because otherwise the exception will
742 739 # be printed on the same line as the spinner.
743 740 error("\n" + str(e), cmd="install")
744 741 return 1
745 742 except api_errors.InventoryException, e:
746 743 error(_("install failed (inventory exception):\n%s") % e,
747 744 cmd="install")
748 745 return 1
749 746 except fmri.IllegalFmri, e:
750 747 error(e, cmd="install")
|
↓ open down ↓ |
1 lines elided |
↑ open up ↑ |
751 748 return 1
752 749
753 750 if noexecute:
754 751 return 0
755 752
756 753 # Exceptions which happen here are printed in the above level, with
757 754 # or without some extra decoration done here.
758 755 # XXX would be nice to kick the progress tracker.
759 756 try:
760 757 api_inst.prepare()
761 - except misc.TransportException:
758 + except api_errors.TransportError, e:
762 759 # move past the progress tracker line.
763 760 msg("\n")
764 - raise
761 + if verbose:
762 + e.verbose = True
763 + raise e
765 764 except KeyboardInterrupt:
766 765 raise
767 766 except api_errors.PermissionsException, e:
768 767 # Prepend a newline because otherwise the exception will
769 768 # be printed on the same line as the spinner.
770 769 error("\n" + str(e))
771 770 return 1
772 771 except:
773 772 error(_("\nAn unexpected error happened while preparing for " \
774 773 "install:"))
775 774 raise
776 775
777 776 ret_code = 0
778 777
779 778 try:
780 779 api_inst.execute_plan()
781 780 except RuntimeError, e:
782 781 error(_("installation failed: %s") % e)
783 782 ret_code = 1
784 783 except api_errors.CorruptedIndexException, e:
785 784 error(INCONSISTENT_INDEX_ERROR_MESSAGE)
786 785 ret_code = 1
787 786 except api_errors.ProblematicPermissionsIndexException, e:
788 787 error(str(e) + PROBLEMATIC_PERMISSIONS_ERROR_MESSAGE)
789 788 ret_code = 1
790 789 except api_errors.PermissionsException, e:
791 790 # Prepend a newline because otherwise the exception will
792 791 # be printed on the same line as the spinner.
793 792 error("\n" + str(e))
794 793 ret_code = 1
795 794 except api_errors.MainDictParsingException, e:
796 795 error(str(e))
797 796 ret_code = 1
798 797 except KeyboardInterrupt:
799 798 raise
800 799 except api_errors.ActionExecutionError:
801 800 ret_code = 1
802 801 except Exception, e:
803 802 error(_("An unexpected error happened during " \
804 803 "installation: %s") % e)
805 804 raise
806 805
807 806 if bool(os.environ.get("PKG_MIRROR_STATS", False)):
808 807 print_mirror_stats(api_inst)
809 808
810 809 return ret_code
811 810
812 811
813 812 def uninstall(img_dir, args):
814 813 """Attempt to take package specified to DELETED state."""
815 814
816 815 opts, pargs = getopt.getopt(args, "nrvq", ["no-index"])
817 816
818 817 quiet = noexecute = recursive_removal = verbose = False
819 818 update_index = True
820 819 for opt, arg in opts:
821 820 if opt == "-n":
822 821 noexecute = True
823 822 elif opt == "-r":
824 823 recursive_removal = True
825 824 elif opt == "-v":
826 825 verbose = True
827 826 elif opt == "-q":
828 827 quiet = True
829 828 elif opt == "--no-index":
830 829 update_index = False
831 830
832 831 if not pargs:
833 832 usage(_("uninstall: at least one package name required"))
834 833
835 834 if verbose and quiet:
836 835 usage(_("uninstall: -v and -q may not be combined"))
837 836
838 837 progresstracker = get_tracker(quiet)
839 838
840 839 if not check_fmri_args(pargs):
841 840 return 1
842 841
843 842 # XXX not sure where this should live
844 843 pkg_list = [ pat.replace("*", ".*").replace("?", ".")
845 844 for pat in pargs ]
846 845
847 846 try:
848 847 api_inst = api.ImageInterface(img_dir, CLIENT_API_VERSION,
849 848 progresstracker, None, PKG_CLIENT_NAME)
850 849 except api_errors.ImageNotFoundException, e:
851 850 error(_("'%s' is not an install image") % e.user_dir)
852 851 return 1
853 852
854 853 try:
855 854 if not api_inst.plan_uninstall(pkg_list, recursive_removal,
856 855 noexecute, verbose=verbose, update_index=update_index):
857 856 assert 0
858 857 except api_errors.InventoryException, e:
859 858 error(_("uninstall failed (inventory exception):\n%s") % e)
860 859 return 1
861 860 except api_errors.NonLeafPackageException, e:
862 861 error("""Cannot remove '%s' due to
863 862 the following packages that depend on it:""" % e[0])
864 863 for d in e[1]:
865 864 emsg(" %s" % d)
866 865 return 1
867 866 except (api_errors.PlanCreationException,
868 867 api_errors.PermissionsException), e:
869 868 # Prepend a newline because otherwise the exception will
870 869 # be printed on the same line as the spinner.
871 870 error("\n" + str(e))
|
↓ open down ↓ |
97 lines elided |
↑ open up ↑ |
872 871 return 1
873 872
874 873 if noexecute:
875 874 return 0
876 875
877 876 # Exceptions which happen here are printed in the above level, with
878 877 # or without some extra decoration done here.
879 878 # XXX would be nice to kick the progress tracker.
880 879 try:
881 880 api_inst.prepare()
882 - except misc.TransportException:
881 + except api_errors.TransportError, e:
883 882 # move past the progress tracker line.
884 883 msg("\n")
885 - raise
884 + if verbose:
885 + e.verbose = True
886 + raise e
886 887 except api_errors.FileInUseException, e:
887 888 error("\n" + str(e))
888 889 return 1
889 890 except KeyboardInterrupt:
890 891 raise
891 892 except:
892 893 error(_("\nAn unexpected error happened while preparing for " \
893 894 "install:"))
894 895 raise
895 896
896 897 ret_code = 0
897 898
898 899 try:
899 900 api_inst.execute_plan()
900 901 except RuntimeError, e:
901 902 error(_("uninstallation failed: %s") % e)
902 903 ret_code = 1
903 904 except api_errors.CorruptedIndexException, e:
904 905 error(INCONSISTENT_INDEX_ERROR_MESSAGE)
905 906 ret_code = 1
906 907 except api_errors.ProblematicPermissionsIndexException, e:
907 908 error(str(e) + PROBLEMATIC_PERMISSIONS_ERROR_MESSAGE)
908 909 ret_code = 1
909 910 except api_errors.PermissionsException, e:
910 911 # Prepend a newline because otherwise the exception will
911 912 # be printed on the same line as the spinner.
912 913 error("\n" + str(e))
913 914 ret_code = 1
914 915 except api_errors.MainDictParsingException, e:
915 916 error(str(e))
916 917 ret_code = 1
917 918 except KeyboardInterrupt:
918 919 raise
919 920 except Exception, e:
920 921 error(_("An unexpected error happened during " \
921 922 "uninstallation: %s") % e)
922 923 raise
923 924
924 925 return ret_code
925 926
|
↓ open down ↓ |
30 lines elided |
↑ open up ↑ |
926 927 def freeze(img, args):
927 928 """Attempt to take package specified to FROZEN state, with given
928 929 restrictions. Package must have been in the INSTALLED state."""
929 930 return 0
930 931
931 932 def unfreeze(img, args):
932 933 """Attempt to return package specified to INSTALLED state from FROZEN
933 934 state."""
934 935 return 0
935 936
936 -def process_v_0_search(tup, first):
937 - """Transforms the tuples returned by search v1 into the four column
938 - output format.
939 -
940 - The "tup" parameter is a four tuple with the each entry corresponding
941 - to a column of the output.
942 -
943 - The "first" parameter is a boolean stating whether this is the first
944 - time this function has been called. This controls the printing of the
945 - header information."""
946 -
947 - try:
948 - index, mfmri, action, value = tup
949 - except ValueError:
950 - error(_("The server returned a malformed result.\n"
951 - "The problematic structure: %r") % (tup,))
952 - return False
953 - if first:
954 - msg("%-10s %-9s %-25s %s" %
955 - ("INDEX", "ACTION", "VALUE", "PACKAGE"))
956 - msg("%-10s %-9s %-25s %s" % (index, action, value,
957 - fmri.PkgFmri(str(mfmri)).get_short_fmri()))
958 - return True
959 -
960 937 def __convert_output(a_str, match):
961 938 """Converts a string to a three tuple with the information to fill
962 939 the INDEX, ACTION, and VALUE columns.
963 940
964 941 The "a_str" parameter is the string representation of an action.
965 942
966 943 The "match" parameter is a string whose precise interpretation is given
967 944 below.
968 945
969 946 For most action types, match defines which attribute the query matched
970 947 with. For example, it states whether the basename or path attribute of
971 948 a file action matched the query. Attribute (set) actions are treated
972 949 differently because they only have one attribute, and many values
973 950 associated with that attribute. For those actions, the match parameter
974 951 states which value matched the query."""
975 952
976 953 a = actions.fromstr(a_str.rstrip())
977 954 if isinstance(a, actions.attribute.AttributeAction):
978 955 return a.attrs.get(a.key_attr), a.name, match
979 956 return match, a.name, a.attrs.get(a.key_attr)
980 957
981 958 def process_v_1_search(tup, first, return_type, pub):
982 959 """Transforms the tuples returned by search v1 into the four column
983 960 output format.
984 961
985 962 The "first" parameter is a boolean stating whether this is the first
986 963 time this function has been called. This controls the printing of the
987 964 header information.
988 965
989 966 The "return_type" parameter is an enumeration that describes the type
990 967 of the information that will be converted.
991 968
992 969 The type of the "tup" parameter depends on the value of "return_type".
993 970 If "return_type" is action information, "tup" is a three-tuple of the fmri
994 971 name, the match, and a string representation of the action. In the case
995 972 where "return_type" is package information, "tup" is a one-tuple containing
996 973 the fmri name."""
997 974
998 975 if return_type == api.Query.RETURN_ACTIONS:
999 976 try:
1000 977 pfmri, match, action = tup
1001 978 except ValueError:
1002 979 error(_("The server returned a malformed result.\n"
1003 980 "The problematic structure:%r") % (tup,))
1004 981 return False
1005 982 if first:
1006 983 msg("%-10s %-9s %-25s %s" %
1007 984 ("INDEX", "ACTION", "VALUE", "PACKAGE"))
1008 985 try:
1009 986 out1, out2, out3 = __convert_output(action, match)
1010 987 except (actions.UnknownActionError,
1011 988 actions.MalformedActionError), e:
1012 989 error(_("The server returned a malformed action.\n%s") %
|
↓ open down ↓ |
43 lines elided |
↑ open up ↑ |
1013 990 e)
1014 991 return False
1015 992 msg("%-10s %-9s %-25s %s" %
1016 993 (out1, out2, out3,
1017 994 fmri.PkgFmri(str(pfmri)).get_short_fmri()))
1018 995 else:
1019 996 pfmri = tup
1020 997 if first:
1021 998 msg("%s" % ("PACKAGE"))
1022 999 pub_name = ''
1023 - if pub is not None and "prefix" in pub:
1000 + # If pub is not None, it's either a RepositoryURI or a Publisher
1001 + # object. If it's a Publisher, it has a prefix. Otherwise,
1002 + # use the uri.
1003 + if pub is not None and hasattr(pub, "prefix"):
1024 1004 pub_name = " (%s)" % pub.prefix
1005 + elif pub is not None and hasattr(pub, "uri"):
1006 + pub_name = " (%s)" % pub.uri
1025 1007 msg("%s%s" %
1026 1008 (fmri.PkgFmri(str(pfmri)).get_short_fmri(), pub_name))
1027 1009 return True
1028 1010
1029 1011 def search(img_dir, args):
1030 1012 """Search for the given query."""
1031 1013
1032 1014 opts, pargs = getopt.getopt(args, "alprs:I")
1033 1015
1034 1016 local = remote = case_sensitive = False
1035 1017 servers = []
1036 1018 return_actions = True
1037 1019 for opt, arg in opts:
1038 1020 if opt == "-a":
1039 1021 return_actions = True
1040 1022 elif opt == "-l":
1041 1023 local = True
1042 1024 elif opt == "-p":
1043 1025 return_actions = False
1044 1026 elif opt == "-r":
1045 1027 remote = True
1046 1028 elif opt == "-s":
1047 1029 if not misc.valid_pub_url(arg):
1048 1030 orig_arg = arg
1049 1031 arg = "http://" + arg
1050 1032 if not misc.valid_pub_url(arg):
1051 1033 error(_("%s is not a valid "
1052 1034 "server URL.") % orig_arg)
1053 1035 return 1
1054 1036 remote = True
1055 1037 servers.append({"origin": arg})
1056 1038 elif opt == "-I":
1057 1039 case_sensitive = True
1058 1040
1059 1041 if not local and not remote:
1060 1042 remote = True
1061 1043
1062 1044 if not pargs:
1063 1045 usage()
1064 1046
1065 1047 searches = []
1066 1048
1067 1049 try:
1068 1050 api_inst = api.ImageInterface(img_dir, CLIENT_API_VERSION,
1069 1051 get_tracker(), None, PKG_CLIENT_NAME)
1070 1052 except api_errors.ImageNotFoundException, e:
1071 1053 error(_("'%s' is not an install image") % e.user_dir)
1072 1054 return 1
1073 1055 try:
1074 1056 query = [api.Query(" ".join(pargs), case_sensitive,
1075 1057 return_actions)]
1076 1058 except api_errors.BooleanQueryException, e:
1077 1059 error(e)
1078 1060 return 1
1079 1061
1080 1062 first = True
1081 1063 good_res = False
1082 1064 bad_res = False
1083 1065
1084 1066 try:
1085 1067 if local:
1086 1068 searches.append(api_inst.local_search(query))
1087 1069 if remote:
1088 1070 searches.append(api_inst.remote_search(query,
1089 1071 servers=servers))
1090 1072
1091 1073 # By default assume we don't find anything.
1092 1074 retcode = 1
|
↓ open down ↓ |
58 lines elided |
↑ open up ↑ |
1093 1075
1094 1076 for raw_value in itertools.chain(*searches):
1095 1077 try:
1096 1078 query_num, pub, (v, return_type, tmp) = \
1097 1079 raw_value
1098 1080 except ValueError, e:
1099 1081 error(_("The server returned a malformed "
1100 1082 "result:%r") % (raw_value,))
1101 1083 bad_res = True
1102 1084 continue
1103 - if v == 0:
1104 - ret = process_v_0_search(tmp, first)
1105 - else:
1106 - ret = process_v_1_search(tmp, first,
1107 - return_type, pub)
1085 + ret = process_v_1_search(tmp, first,
1086 + return_type, pub)
1108 1087 good_res |= ret
1109 1088 bad_res |= not ret
1110 1089 first = False
1111 1090 except (api_errors.IncorrectIndexFileHash,
1112 1091 api_errors.InconsistentIndexException):
1113 1092 error(_("The search index appears corrupted. Please "
1114 1093 "rebuild the index with 'pkg rebuild-index'."))
1115 1094 return 1
1116 1095 except api_errors.ProblematicSearchServers, e:
1117 1096 error(e)
1118 1097 bad_res = True
1119 1098 except api_errors.SlowSearchUsed, e:
1120 1099 error(e)
1121 1100 except (api_errors.IncorrectIndexFileHash,
1122 1101 api_errors.InconsistentIndexException):
1123 1102 error(_("The search index appears corrupted. Please "
1124 1103 "rebuild the index with 'pkg rebuild-index'."))
1125 1104 return 1
1126 1105 except api_errors.ApiException, e:
1127 1106 error(e)
1128 1107 return 1
1129 1108 if good_res and bad_res:
1130 1109 retcode = 4
1131 1110 elif bad_res:
1132 1111 retcode = 1
1133 1112 elif not first:
1134 1113 retcode = 0
1135 1114 return retcode
1136 1115
1137 1116 def info(img_dir, args):
1138 1117 """Display information about a package or packages.
1139 1118 """
1140 1119
1141 1120 display_license = False
1142 1121 info_local = False
1143 1122 info_remote = False
1144 1123
1145 1124 opts, pargs = getopt.getopt(args, "lr", ["license"])
1146 1125 for opt, arg in opts:
1147 1126 if opt == "-l":
1148 1127 info_local = True
1149 1128 elif opt == "-r":
1150 1129 info_remote = True
1151 1130 elif opt == "--license":
1152 1131 display_license = True
1153 1132
1154 1133 if not info_local and not info_remote:
1155 1134 info_local = True
1156 1135 elif info_local and info_remote:
1157 1136 usage(_("info: -l and -r may not be combined"))
1158 1137
1159 1138 if info_remote and not pargs:
1160 1139 usage(_("info: must request remote info for specific packages"))
1161 1140
1162 1141 if not check_fmri_args(pargs):
1163 1142 return 1
1164 1143
1165 1144 err = 0
1166 1145
1167 1146 api_inst = api.ImageInterface(img_dir, CLIENT_API_VERSION,
1168 1147 get_tracker(quiet=True), None, PKG_CLIENT_NAME)
1169 1148
1170 1149 try:
1171 1150 info_needed = api.PackageInfo.ALL_OPTIONS
1172 1151 if not display_license:
1173 1152 info_needed = api.PackageInfo.ALL_OPTIONS - \
1174 1153 frozenset([api.PackageInfo.LICENSES])
1175 1154 try:
1176 1155 ret = api_inst.info(pargs, info_local, info_needed)
1177 1156 except api_errors.UnrecognizedOptionsToInfo, e:
1178 1157 error(e)
1179 1158 return 1
1180 1159 pis = ret[api.ImageInterface.INFO_FOUND]
1181 1160 notfound = ret[api.ImageInterface.INFO_MISSING]
1182 1161 illegals = ret[api.ImageInterface.INFO_ILLEGALS]
1183 1162 multi_match = ret[api.ImageInterface.INFO_MULTI_MATCH]
1184 1163
1185 1164 except api_errors.PermissionsException, e:
1186 1165 error(e)
1187 1166 return 1
1188 1167 except api_errors.NoPackagesInstalledException:
1189 1168 error(_("no packages installed"))
1190 1169 return 1
1191 1170
1192 1171 no_licenses = []
1193 1172 for i, pi in enumerate(pis):
1194 1173 if i > 0:
1195 1174 msg("")
1196 1175
1197 1176 if display_license:
1198 1177 if not pi.licenses:
1199 1178 no_licenses.append(pi.fmri)
1200 1179 else:
1201 1180 for lic in pi.licenses:
1202 1181 msg(lic)
1203 1182 continue
1204 1183
1205 1184 if pi.state == api.PackageInfo.INSTALLED:
1206 1185 state = _("Installed")
1207 1186 elif pi.state == api.PackageInfo.NOT_INSTALLED:
1208 1187 state = _("Not installed")
1209 1188 else:
1210 1189 raise RuntimeError("Encountered unknown package "
1211 1190 "information state: %d" % pi.state )
1212 1191 name_str = _(" Name:")
1213 1192 msg(name_str, pi.pkg_stem)
1214 1193 msg(_(" Summary:"), pi.summary)
1215 1194 if pi.category_info_list:
1216 1195 verbose = len(pi.category_info_list) > 1
1217 1196 msg(_(" Category:"),
1218 1197 pi.category_info_list[0].__str__(verbose))
1219 1198 if len(pi.category_info_list) > 1:
1220 1199 for ci in pi.category_info_list[1:]:
1221 1200 msg(" " * len(name_str),
1222 1201 ci.__str__(verbose))
1223 1202
1224 1203 msg(_(" State:"), state)
1225 1204
1226 1205 # XXX even more info on the publisher would be nice?
1227 1206 msg(_(" Publisher:"), pi.publisher)
1228 1207 msg(_(" Version:"), pi.version)
1229 1208 msg(_(" Build Release:"), pi.build_release)
1230 1209 msg(_(" Branch:"), pi.branch)
1231 1210 msg(_("Packaging Date:"), pi.packaging_date)
1232 1211 msg(_(" Size:"), misc.bytes_to_str(pi.size))
1233 1212 msg(_(" FMRI:"), pi.fmri)
1234 1213 # XXX add license/copyright info here?
1235 1214
1236 1215 if notfound:
1237 1216 err = 1
1238 1217 if pis:
1239 1218 emsg()
1240 1219 if info_local:
1241 1220 emsg(_("""\
1242 1221 pkg: no packages matching the following patterns you specified are
1243 1222 installed on the system. Try specifying -r to query remotely:"""))
1244 1223 elif info_remote:
1245 1224 emsg(_("""\
1246 1225 pkg: no packages matching the following patterns you specified were
1247 1226 found in the catalog. Try relaxing the patterns, refreshing, and/or
1248 1227 examining the catalogs:"""))
1249 1228 emsg()
1250 1229 for p in notfound:
1251 1230 emsg(" %s" % p)
1252 1231
1253 1232 if illegals:
1254 1233 err = 1
1255 1234 for i in illegals:
1256 1235 emsg(str(i))
1257 1236
1258 1237 if multi_match:
1259 1238 err = 1
1260 1239 for pfmri, matches in multi_match:
1261 1240 error(_("'%s' matches multiple packages") % pfmri)
1262 1241 for k in matches:
1263 1242 emsg("\t%s" % k)
1264 1243
1265 1244 if no_licenses:
1266 1245 err = 1
1267 1246 error(_("no license information could be found for the "
1268 1247 "following packages:"))
1269 1248 for pfmri in no_licenses:
1270 1249 emsg("\t%s" % pfmri)
1271 1250
1272 1251 return err
1273 1252
1274 1253 def display_contents_results(actionlist, attrs, sort_attrs, action_types,
1275 1254 display_headers):
1276 1255 """Print results of a "list" operation """
1277 1256
1278 1257 # widths is a list of tuples of column width and justification. Start
1279 1258 # with the widths of the column headers.
1280 1259 JUST_UNKN = 0
1281 1260 JUST_LEFT = -1
1282 1261 JUST_RIGHT = 1
1283 1262 widths = [ (len(attr) - attr.find(".") - 1, JUST_UNKN)
1284 1263 for attr in attrs ]
1285 1264 lines = []
1286 1265
1287 1266 for manifest, action in actionlist:
1288 1267 if action_types and action.name not in action_types:
1289 1268 continue
1290 1269 line = []
1291 1270 for i, attr in enumerate(attrs):
1292 1271 just = JUST_UNKN
1293 1272 # As a first approximation, numeric attributes
1294 1273 # are right justified, non-numerics left.
1295 1274 try:
1296 1275 int(action.attrs[attr])
1297 1276 just = JUST_RIGHT
1298 1277 # attribute is non-numeric or is something like
1299 1278 # a list.
1300 1279 except (ValueError, TypeError):
1301 1280 just = JUST_LEFT
1302 1281 # attribute isn't in the list, so we don't know
1303 1282 # what it might be
1304 1283 except KeyError:
1305 1284 pass
1306 1285
1307 1286 if attr in action.attrs:
1308 1287 a = action.attrs[attr]
1309 1288 elif attr == "action.name":
1310 1289 a = action.name
1311 1290 just = JUST_LEFT
1312 1291 elif attr == "action.key":
1313 1292 a = action.attrs[action.key_attr]
1314 1293 just = JUST_LEFT
1315 1294 elif attr == "action.raw":
1316 1295 a = action
1317 1296 just = JUST_LEFT
1318 1297 elif attr == "pkg.name":
1319 1298 a = manifest.fmri.get_name()
1320 1299 just = JUST_LEFT
1321 1300 elif attr == "pkg.fmri":
1322 1301 a = manifest.fmri
1323 1302 just = JUST_LEFT
1324 1303 elif attr == "pkg.shortfmri":
1325 1304 a = manifest.fmri.get_short_fmri()
1326 1305 just = JUST_LEFT
1327 1306 elif attr == "pkg.publisher":
1328 1307 a = manifest.fmri.get_publisher()
1329 1308 just = JUST_LEFT
1330 1309 else:
1331 1310 a = ""
1332 1311
1333 1312 line.append(a)
1334 1313
1335 1314 # XXX What to do when a column's justification
1336 1315 # changes?
1337 1316 if just != JUST_UNKN:
1338 1317 widths[i] = \
1339 1318 (max(widths[i][0], len(str(a))), just)
1340 1319
1341 1320 if line and [l for l in line if str(l) != ""]:
1342 1321 lines.append(line)
1343 1322
1344 1323 sortidx = 0
1345 1324 for i, attr in enumerate(attrs):
1346 1325 if attr == sort_attrs[0]:
1347 1326 sortidx = i
1348 1327 break
1349 1328
1350 1329 # Sort numeric columns numerically.
1351 1330 if widths[sortidx][1] == JUST_RIGHT:
1352 1331 def key_extract(x):
1353 1332 try:
1354 1333 return int(x[sortidx])
1355 1334 except (ValueError, TypeError):
1356 1335 return 0
1357 1336 else:
1358 1337 key_extract = lambda x: x[sortidx]
1359 1338
1360 1339 if display_headers:
1361 1340 headers = []
1362 1341 for i, attr in enumerate(attrs):
1363 1342 headers.append(str(attr.upper()))
1364 1343 widths[i] = \
1365 1344 (max(widths[i][0], len(attr)), widths[i][1])
1366 1345
1367 1346 # Now that we know all the widths, multiply them by the
1368 1347 # justification values to get positive or negative numbers to
1369 1348 # pass to the %-expander.
1370 1349 widths = [ e[0] * e[1] for e in widths ]
1371 1350 fmt = ("%%%ss " * len(widths)) % tuple(widths)
1372 1351
1373 1352 msg((fmt % tuple(headers)).rstrip())
1374 1353 else:
1375 1354 fmt = "%s\t" * len(widths)
1376 1355 fmt.rstrip("\t")
1377 1356
1378 1357 for line in sorted(lines, key=key_extract):
1379 1358 msg((fmt % tuple(line)).rstrip())
1380 1359
1381 1360 def list_contents(img, args):
1382 1361 """List package contents.
1383 1362
1384 1363 If no arguments are given, display for all locally installed packages.
1385 1364 With -H omit headers and use a tab-delimited format; with -o select
1386 1365 attributes to display; with -s, specify attributes to sort on; with -t,
1387 1366 specify which action types to list."""
1388 1367
1389 1368 # XXX Need remote-info option, to request equivalent information
1390 1369 # from repository.
1391 1370
1392 1371 opts, pargs = getopt.getopt(args, "Ho:s:t:mfr")
1393 1372
1394 1373 valid_special_attrs = [ "action.name", "action.key", "action.raw",
1395 1374 "pkg.name", "pkg.fmri", "pkg.shortfmri", "pkg.publisher",
1396 1375 "pkg.size", "pkg.csize" ]
1397 1376
1398 1377 display_headers = True
1399 1378 display_raw = False
1400 1379 remote = False
1401 1380 local = False
1402 1381 attrs = []
1403 1382 sort_attrs = []
1404 1383 action_types = []
1405 1384 for opt, arg in opts:
1406 1385 if opt == "-H":
1407 1386 display_headers = False
1408 1387 elif opt == "-o":
1409 1388 attrs.extend(arg.split(","))
1410 1389 elif opt == "-s":
1411 1390 sort_attrs.append(arg)
1412 1391 elif opt == "-t":
1413 1392 action_types.extend(arg.split(","))
1414 1393 elif opt == "-r":
1415 1394 remote = True
1416 1395 elif opt == "-m":
1417 1396 display_raw = True
1418 1397
1419 1398 if not remote and not local:
1420 1399 local = True
1421 1400 elif local and remote:
1422 1401 usage(_("contents: -l and -r may not be combined"))
1423 1402
1424 1403 if remote and not pargs:
1425 1404 usage(_("contents: must request remote contents for specific "
1426 1405 "packages"))
1427 1406
1428 1407 if not check_fmri_args(pargs):
1429 1408 return 1
1430 1409
1431 1410 if display_raw:
1432 1411 display_headers = False
1433 1412 attrs = [ "action.raw" ]
1434 1413
1435 1414 invalid = set(("-H", "-o", "-t")). \
1436 1415 intersection(set([x[0] for x in opts]))
1437 1416
1438 1417 if len(invalid) > 0:
1439 1418 usage(_("contents: -m and %s may not be specified " \
1440 1419 "at the same time") % invalid.pop())
1441 1420
1442 1421 for a in attrs:
1443 1422 if a.startswith("action.") and not a in valid_special_attrs:
1444 1423 usage(_("Invalid attribute '%s'") % a)
1445 1424
1446 1425 if a.startswith("pkg.") and not a in valid_special_attrs:
1447 1426 usage(_("Invalid attribute '%s'") % a)
1448 1427
1449 1428 img.history.operation_name = "contents"
1450 1429 img.load_catalogs(progress.QuietProgressTracker())
1451 1430
1452 1431 err = 0
1453 1432
1454 1433 if local:
1455 1434 fmris, notfound, illegals = \
1456 1435 img.installed_fmris_from_args(pargs)
1457 1436
1458 1437 if illegals:
1459 1438 for i in illegals:
1460 1439 emsg(i)
1461 1440 img.history.operation_result = \
1462 1441 history.RESULT_FAILED_BAD_REQUEST
1463 1442 return 1
1464 1443
1465 1444 if not fmris and not notfound:
1466 1445 error(_("no packages installed"))
1467 1446 img.history.operation_result = \
1468 1447 history.RESULT_NOTHING_TO_DO
1469 1448 return 1
1470 1449 elif remote:
1471 1450 # Verify validity of certificates before attempting network
1472 1451 # operations
1473 1452 try:
1474 1453 img.check_cert_validity()
1475 1454 except (api_errors.CertificateError,
1476 1455 api_errors.PermissionsException), e:
1477 1456 img.history.log_operation_end(error=e)
1478 1457 return 1
1479 1458
1480 1459 fmris = []
1481 1460 notfound = []
1482 1461
1483 1462 # XXX This loop really needs not to be copied from
1484 1463 # Image.make_install_plan()!
1485 1464 for p in pargs:
1486 1465 try:
1487 1466 matches = list(img.inventory([ p ],
1488 1467 all_known = True))
1489 1468 except api_errors.InventoryException, e:
1490 1469 assert(len(e.notfound) == 1)
1491 1470 notfound.append(e.notfound[0])
1492 1471 continue
1493 1472
1494 1473 pnames = {}
1495 1474 pmatch = []
1496 1475 npnames = {}
1497 1476 npmatch = []
1498 1477 for m, state in matches:
1499 1478 if m.preferred_publisher():
1500 1479 pnames[m.get_pkg_stem()] = 1
1501 1480 pmatch.append(m)
1502 1481 else:
1503 1482 npnames[m.get_pkg_stem()] = 1
1504 1483 npmatch.append(m)
1505 1484
1506 1485 if len(pnames.keys()) > 1:
1507 1486 msg(_("pkg: '%s' matches multiple packages") % \
1508 1487 p)
1509 1488 for k in pnames.keys():
1510 1489 msg("\t%s" % k)
1511 1490 continue
1512 1491 elif len(pnames.keys()) < 1 and len(npnames.keys()) > 1:
1513 1492 msg(_("pkg: '%s' matches multiple packages") % \
1514 1493 p)
1515 1494 for k in npnames.keys():
1516 1495 msg("\t%s" % k)
1517 1496 continue
1518 1497
1519 1498 # matches is a list reverse sorted by version, so take
1520 1499 # the first; i.e., the latest.
1521 1500 if len(pmatch) > 0:
1522 1501 fmris.append(pmatch[0])
1523 1502 else:
1524 1503 fmris.append(npmatch[0])
1525 1504
1526 1505 #
1527 1506 # If the user specifies no specific attrs, and no specific
1528 1507 # sort order, then we fill in some defaults.
1529 1508 #
1530 1509 if not attrs:
1531 1510 # XXX Possibly have multiple exclusive attributes per column?
1532 1511 # If listing dependencies and files, you could have a path/fmri
1533 1512 # column which would list paths for files and fmris for
1534 1513 # dependencies.
1535 1514 attrs = [ "path" ]
1536 1515
1537 1516 if not sort_attrs:
1538 1517 # XXX reverse sorting
1539 1518 # Most likely want to sort by path, so don't force people to
1540 1519 # make it explicit
1541 1520 if "path" in attrs:
1542 1521 sort_attrs = [ "path" ]
1543 1522 else:
1544 1523 sort_attrs = attrs[:1]
1545 1524
1546 1525 # if we want a raw display (contents -m), disable the automatic
1547 1526 # variant filtering that normally limits working set.
1548 1527
1549 1528 if display_raw:
1550 1529 excludes = EmptyI
1551 1530 else:
1552 1531 excludes = img.list_excludes()
1553 1532
1554 1533 manifests = ( img.get_manifest(f, all_arch=display_raw) for f in fmris )
1555 1534
1556 1535 actionlist = [
1557 1536 (m, a)
1558 1537 for m in manifests
1559 1538 for a in m.gen_actions(excludes)
1560 1539 ]
1561 1540
1562 1541 if fmris:
1563 1542 display_contents_results(actionlist, attrs, sort_attrs,
1564 1543 action_types, display_headers)
1565 1544
1566 1545 if notfound:
1567 1546 err = 1
1568 1547 if fmris:
1569 1548 emsg()
1570 1549 if local:
1571 1550 emsg(_("""\
1572 1551 pkg: no packages matching the following patterns you specified are
1573 1552 installed on the system. Try specifying -r to query remotely:"""))
1574 1553 elif remote:
1575 1554 emsg(_("""\
1576 1555 pkg: no packages matching the following patterns you specified were
1577 1556 found in the catalog. Try relaxing the patterns, refreshing, and/or
1578 1557 examining the catalogs:"""))
1579 1558 emsg()
1580 1559 for p in notfound:
1581 1560 emsg(" %s" % p)
1582 1561 img.history.operation_result = history.RESULT_NOTHING_TO_DO
1583 1562 else:
1584 1563 img.history.operation_result = history.RESULT_SUCCEEDED
1585 1564 return err
1586 1565
1587 1566 def display_catalog_failures(cre):
1588 1567 total = cre.total
1589 1568 succeeded = cre.succeeded
1590 1569
1591 1570 txt = _("pkg: %s/%s catalogs successfully updated:") % (succeeded,
1592 1571 total)
1593 1572 if cre.failed:
1594 1573 # This ensures that the text gets printed before the errors.
1595 1574 emsg(txt)
1596 1575 else:
1597 1576 msg(txt)
1598 1577
1599 1578 for pub, err in cre.failed:
1600 1579 if isinstance(err, urllib2.HTTPError):
1601 1580 emsg(" %s: %s - %s" % \
1602 1581 (err.filename, err.code, err.msg))
1603 1582 elif isinstance(err, urllib2.URLError):
1604 1583 if err.args[0][0] == 8:
1605 1584 emsg(" %s: %s" % \
|
↓ open down ↓ |
488 lines elided |
↑ open up ↑ |
1606 1585 (urlparse.urlsplit(
1607 1586 pub["origin"])[1].split(":")[0],
1608 1587 err.args[0][1]))
1609 1588 else:
1610 1589 if isinstance(err.args[0], socket.timeout):
1611 1590 emsg(" %s: %s" % \
1612 1591 (pub["origin"], "timeout"))
1613 1592 else:
1614 1593 emsg(" %s: %s" % \
1615 1594 (pub["origin"], err.args[0][1]))
1616 - elif isinstance(err, CatalogRetrievalError) and \
1617 - isinstance(err.exc, EnvironmentError) and \
1618 - err.exc.errno == errno.EACCES:
1619 - if err.prefix:
1620 - emsg(" ", _("Could not update catalog "
1621 - "for '%s' due to insufficient "
1622 - "permissions.") % err.prefix)
1623 - else:
1624 - emsg(" ", _("Could not update a catalog "
1625 - "due to insufficient permissions."))
1626 -
1627 - emsg(" ", _("Please try the command again "
1628 - "using pfexec, or otherwise increase \n your "
1629 - "permissions."))
1630 1595 else:
1631 1596 emsg(" ", err)
1632 1597
1633 1598 if cre.message:
1634 1599 emsg(cre.message)
1635 1600
1636 1601 return succeeded
1637 1602
1638 1603 def publisher_refresh(img_dir, args):
1639 1604 """Update metadata for the image's publishers."""
1640 1605
1641 1606 # XXX will need to show available content series for each package
1642 1607 full_refresh = False
1643 1608 opts, pargs = getopt.getopt(args, "", ["full"])
1644 1609 for opt, arg in opts:
1645 1610 if opt == "--full":
1646 1611 full_refresh = True
1647 1612
1648 1613 try:
1649 1614 api_inst = api.ImageInterface(img_dir, CLIENT_API_VERSION,
1650 1615 get_tracker(), None, PKG_CLIENT_NAME)
1651 1616 except api_errors.ImageNotFoundException, e:
1652 1617 error(_("'%s' is not an install image") % e.user_dir)
1653 1618 return 1
|
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
1654 1619
1655 1620 try:
1656 1621 # The user explicitly requested this refresh, so set the
1657 1622 # refresh to occur immediately.
1658 1623 api_inst.refresh(full_refresh=full_refresh, immediate=True,
1659 1624 pubs=pargs)
1660 1625 except api_errors.PublisherError, e:
1661 1626 error(e)
1662 1627 error(_("'pkg publisher' will show a list of publishers."))
1663 1628 return 1
1664 - except (api_errors.PermissionsException,
1665 - api_errors.NetworkUnavailableException), e:
1629 + except (api_errors.PermissionsException), e:
1666 1630 # Prepend a newline because otherwise the exception will
1667 1631 # be printed on the same line as the spinner.
1668 1632 error("\n" + str(e))
1669 1633 return 1
1670 1634 except api_errors.CatalogRefreshException, e:
1671 1635 if display_catalog_failures(e) == 0:
1672 1636 return 1
1673 1637 else:
1674 1638 return 3
1675 1639 else:
1676 1640 return 0
1677 1641
1678 1642 def publisher_set(img, img_dir, args):
1679 1643 """pkg set-publisher [-Ped] [-k ssl_key] [-c ssl_cert] [--reset-uuid]
1680 1644 [-O origin_url] [-m mirror to add] [-M mirror to remove]
1681 1645 [--enable] [--disable] [--no-refresh] publisher"""
1682 1646
1683 1647 preferred = False
1684 1648 ssl_key = None
1685 1649 ssl_cert = None
1686 1650 origin_url = None
1687 1651 reset_uuid = False
1688 1652 add_mirror = None
1689 1653 remove_mirror = None
1690 1654 refresh_catalogs = True
1691 1655 disable = None
1692 1656
1693 1657 opts, pargs = getopt.getopt(args, "Pedk:c:O:M:m:",
1694 1658 ["add-mirror=", "remove-mirror=", "no-refresh", "reset-uuid",
1695 1659 "enable", "disable"])
1696 1660
1697 1661 for opt, arg in opts:
1698 1662 if opt == "-P":
1699 1663 preferred = True
1700 1664 if opt == "-k":
1701 1665 ssl_key = arg
1702 1666 if opt == "-c":
1703 1667 ssl_cert = arg
1704 1668 if opt == "-O":
1705 1669 origin_url = arg
1706 1670 if opt == "-m" or opt == "--add-mirror":
1707 1671 add_mirror = arg
1708 1672 if opt == "-M" or opt == "--remove-mirror":
1709 1673 remove_mirror = arg
1710 1674 if opt == "--no-refresh":
1711 1675 refresh_catalogs = False
1712 1676 if opt == "--reset-uuid":
1713 1677 reset_uuid = True
1714 1678 if opt == "-e" or opt == "--enable":
1715 1679 disable = False
1716 1680 if opt == "-d" or opt == "--disable":
1717 1681 disable = True
1718 1682
1719 1683 if len(pargs) == 0:
1720 1684 usage(_("requires a publisher name"), cmd="set-publisher")
1721 1685 elif len(pargs) > 1:
1722 1686 usage( _("only one publisher name may be specified"),
1723 1687 cmd="set-publisher",)
1724 1688
1725 1689 name = pargs[0]
1726 1690
1727 1691 if preferred and disable:
1728 1692 usage(_("the -p and -d options may not be combined"),
1729 1693 cmd="set-publisher")
1730 1694
1731 1695 try:
1732 1696 api_inst = api.ImageInterface(img_dir, CLIENT_API_VERSION,
1733 1697 get_tracker(), None, PKG_CLIENT_NAME)
1734 1698 except api_errors.ImageNotFoundException, e:
1735 1699 error(_("'%s' is not an install image") % e.user_dir,
1736 1700 cmd="set-publisher")
1737 1701 return 1
1738 1702
1739 1703 new_pub = False
1740 1704 try:
1741 1705 pub = api_inst.get_publisher(prefix=name, alias=name,
1742 1706 duplicate=True)
1743 1707 if reset_uuid:
1744 1708 pub.reset_client_uuid()
1745 1709 repo = pub.selected_repository
1746 1710 except api_errors.PermissionsException, e:
1747 1711 error(e, cmd="set-publisher")
1748 1712 return 1
1749 1713 except api_errors.UnknownPublisher:
1750 1714 if not origin_url:
1751 1715 error(_("publisher does not exist. Use -O to define "
1752 1716 "origin URI for new publisher."),
1753 1717 cmd="set-publisher")
1754 1718 return 1
1755 1719 # No pre-existing, so create a new one.
1756 1720 repo = publisher.Repository()
1757 1721 pub = publisher.Publisher(name, repositories=[repo])
1758 1722 new_pub = True
1759 1723
1760 1724 if disable is not None:
1761 1725 # Set disabled property only if provided.
1762 1726 pub.disabled = disable
1763 1727
1764 1728 if origin_url:
1765 1729 try:
1766 1730 if not repo.origins:
1767 1731 # New publisher case.
1768 1732 repo.add_origin(origin_url)
1769 1733 origin = repo.origins[0]
1770 1734 else:
1771 1735 origin = repo.origins[0]
1772 1736 origin.uri = origin_url
1773 1737
1774 1738 # XXX once image configuration supports storing this
1775 1739 # information at the uri level, ssl info should be set
1776 1740 # here.
1777 1741 except api_errors.PublisherError, e:
1778 1742 error(e, cmd="set-publisher")
1779 1743 return 1
1780 1744
1781 1745 if add_mirror:
1782 1746 try:
1783 1747 # XXX once image configuration supports storing this
1784 1748 # information at the uri level, ssl info should be set
1785 1749 # here.
1786 1750 repo.add_mirror(add_mirror)
1787 1751 except (api_errors.PublisherError,
1788 1752 api_errors.CertificateError), e:
1789 1753 error(e, cmd="set-publisher")
1790 1754 return 1
1791 1755
1792 1756 if remove_mirror:
1793 1757 try:
1794 1758 repo.remove_mirror(remove_mirror)
1795 1759 except api_errors.PublisherError, e:
1796 1760 error(e, cmd="set-publisher")
1797 1761 return 1
1798 1762
1799 1763 # None is checked for here so that a client can unset a ssl_cert or
1800 1764 # ssl_key by using -k "" or -c "".
1801 1765 if ssl_cert is not None or ssl_key is not None:
1802 1766 #
1803 1767 # In the case of zones, the ssl cert given is assumed to
1804 1768 # be relative to the root of the image, not truly absolute.
1805 1769 #
1806 1770 if img.is_zone():
1807 1771 if ssl_cert is not None:
1808 1772 ssl_cert = os.path.abspath(
1809 1773 img.get_root() + os.sep + ssl_cert)
1810 1774 if ssl_key is not None:
1811 1775 ssl_key = os.path.abspath(
1812 1776 img.get_root() + os.sep + ssl_key)
1813 1777
1814 1778 # Assume the user wanted to update the ssl_cert or ssl_key
1815 1779 # information for *all* of the currently selected
1816 1780 # repository's origins and mirrors.
1817 1781 try:
1818 1782 for uri in repo.origins:
1819 1783 if ssl_cert is not None:
1820 1784 uri.ssl_cert = ssl_cert
1821 1785 if ssl_key is not None:
1822 1786 uri.ssl_key = ssl_key
1823 1787 for uri in repo.mirrors:
1824 1788 if ssl_cert is not None:
1825 1789 uri.ssl_cert = ssl_cert
1826 1790 if ssl_key is not None:
1827 1791 uri.ssl_key = ssl_key
1828 1792 except (api_errors.PublisherError,
1829 1793 api_errors.CertificateError), e:
1830 1794 error(e, cmd="set-publisher")
1831 1795 return 1
1832 1796
1833 1797 try:
1834 1798 if new_pub:
1835 1799 api_inst.add_publisher(pub,
1836 1800 refresh_allowed=refresh_catalogs)
1837 1801 else:
1838 1802 api_inst.update_publisher(pub,
1839 1803 refresh_allowed=refresh_catalogs)
1840 1804 except api_errors.CatalogRefreshException, e:
1841 1805 text = "Could not refresh the catalog for %s"
1842 1806 error(_(text) % pub)
1843 1807 return 1
1844 1808 except api_errors.InvalidDepotResponseException, e:
1845 1809 error(_("The origin URIs for '%(pubname)s' do not appear to "
1846 1810 "point to a valid pkg server.\nPlease check the server's "
1847 1811 "address and client's network configuration."
1848 1812 "\nAdditional details:\n\n%(details)s") %
1849 1813 { "pubname": pub.prefix, "details": e })
1850 1814 return 1
1851 1815 except api_errors.PermissionsException, e:
1852 1816 # Prepend a newline because otherwise the exception will
1853 1817 # be printed on the same line as the spinner.
1854 1818 error("\n" + str(e))
1855 1819 return 1
1856 1820
1857 1821 if preferred:
1858 1822 api_inst.set_preferred_publisher(prefix=pub.prefix)
1859 1823
1860 1824 return 0
1861 1825
1862 1826 def publisher_unset(img_dir, args):
1863 1827 """pkg unset-publisher publisher ..."""
1864 1828
1865 1829 if len(args) == 0:
1866 1830 usage()
1867 1831
1868 1832 try:
1869 1833 api_inst = api.ImageInterface(img_dir, CLIENT_API_VERSION,
1870 1834 get_tracker(), None, PKG_CLIENT_NAME)
1871 1835 except api_errors.ImageNotFoundException, e:
1872 1836 error(_("'%s' is not an install image") % e.user_dir)
1873 1837 return 1
1874 1838
1875 1839 errors = []
1876 1840 for name in args:
1877 1841 try:
1878 1842 api_inst.remove_publisher(prefix=name, alias=name)
1879 1843 except (api_errors.PermissionsException,
1880 1844 api_errors.PublisherError), e:
1881 1845 errors.append((name, e))
1882 1846
1883 1847 retcode = 0
1884 1848 if errors:
1885 1849 if len(errors) == len(args):
1886 1850 # If the operation failed for every provided publisher
1887 1851 # prefix or alias, complete failure occurred.
1888 1852 retcode = 1
1889 1853 else:
1890 1854 # If the operation failed for only some of the provided
1891 1855 # publisher prefixes or aliases, then partial failure
1892 1856 # occurred.
1893 1857 retcode = 3
1894 1858
1895 1859 txt = ""
1896 1860 for name, err in errors:
1897 1861 txt += "\n"
1898 1862 txt += _("Removal failed for '%(pub)s': %(msg)s") % {
1899 1863 "pub": name, "msg": err }
1900 1864 txt += "\n"
1901 1865 error(txt, cmd="unset-publisher")
1902 1866
1903 1867 return retcode
1904 1868
1905 1869 def publisher_list(img_dir, args):
1906 1870 """pkg publishers"""
1907 1871 omit_headers = False
1908 1872 preferred_only = False
1909 1873 inc_disabled = False
1910 1874
1911 1875 opts, pargs = getopt.getopt(args, "HPa")
1912 1876 for opt, arg in opts:
1913 1877 if opt == "-H":
1914 1878 omit_headers = True
1915 1879 if opt == "-P":
1916 1880 preferred_only = True
1917 1881 if opt == "-a":
1918 1882 inc_disabled = True
1919 1883
1920 1884 progresstracker = get_tracker(True)
1921 1885
1922 1886 try:
1923 1887 api_inst = api.ImageInterface(img_dir, CLIENT_API_VERSION,
1924 1888 progresstracker, None, PKG_CLIENT_NAME)
1925 1889 except api_errors.ImageNotFoundException, e:
1926 1890 error(_("'%s' is not an install image") % e.user_dir)
1927 1891 return 1
1928 1892
1929 1893 cert_cache = {}
1930 1894 def get_cert_info(ssl_cert):
1931 1895 if not ssl_cert:
1932 1896 return None
1933 1897 if ssl_cert not in cert_cache:
1934 1898 c = cert_cache[ssl_cert] = {}
1935 1899 errors = c["errors"] = []
1936 1900 times = c["info"] = {
1937 1901 "effective": "",
1938 1902 "expiration": "",
1939 1903 }
1940 1904
1941 1905 try:
1942 1906 cert = misc.validate_ssl_cert(ssl_cert)
1943 1907 except (EnvironmentError,
1944 1908 api_errors.CertificateError,
1945 1909 api_errors.PermissionsException), e:
1946 1910 # If the cert information can't be retrieved,
1947 1911 # add the errors to a list and continue on.
1948 1912 errors.append(e)
1949 1913 c["valid"] = False
1950 1914 else:
1951 1915 nb = cert.get_notBefore()
1952 1916 t = time.strptime(nb, "%Y%m%d%H%M%SZ")
1953 1917 nb = datetime.datetime.utcfromtimestamp(
1954 1918 calendar.timegm(t))
1955 1919 times["effective"] = nb.strftime("%c")
1956 1920
1957 1921 na = cert.get_notAfter()
1958 1922 t = time.strptime(na, "%Y%m%d%H%M%SZ")
1959 1923 na = datetime.datetime.utcfromtimestamp(
1960 1924 calendar.timegm(t))
1961 1925 times["expiration"] = na.strftime("%c")
1962 1926 c["valid"] = True
1963 1927
1964 1928 return cert_cache[ssl_cert]
1965 1929
1966 1930 retcode = 0
1967 1931 if len(pargs) == 0:
1968 1932 fmt = "%-24s %-12s %-8s %-8s %s"
1969 1933 if not omit_headers:
1970 1934 msg(fmt % (_("PUBLISHER"), "", _("TYPE"), _("STATUS"),
1971 1935 _("URI")))
1972 1936
1973 1937 pref_pub = api_inst.get_preferred_publisher()
1974 1938 if preferred_only:
1975 1939 pubs = [pref_pub]
1976 1940 else:
1977 1941 pubs = [
1978 1942 p for p in api_inst.get_publishers()
1979 1943 if inc_disabled or not p.disabled
1980 1944 ]
1981 1945
1982 1946 for p in pubs:
1983 1947 pfx = p.prefix
1984 1948 pstatus = ""
1985 1949 if not preferred_only and p == pref_pub:
1986 1950 pstatus = _("(preferred)")
1987 1951 if p.disabled:
1988 1952 pstatus = _("(disabled)")
1989 1953
1990 1954 # Only show the selected repository's information in
1991 1955 # summary view.
1992 1956 r = p.selected_repository
1993 1957 for uri in r.origins:
1994 1958 # XXX get the real origin status
1995 1959 msg(fmt % (pfx, pstatus, _("origin"), "online",
1996 1960 uri))
1997 1961 for uri in r.mirrors:
1998 1962 # XXX get the real mirror status
1999 1963 msg(fmt % (pfx, pstatus, _("mirror"), "online",
2000 1964 uri))
2001 1965 else:
2002 1966 def display_ssl_info(uri):
2003 1967 retcode = 0
2004 1968 c = get_cert_info(uri.ssl_cert)
2005 1969 msg(_(" SSL Key:"), uri.ssl_key)
2006 1970 msg(_(" SSL Cert:"), uri.ssl_cert)
2007 1971
2008 1972 if not c:
2009 1973 return retcode
2010 1974
2011 1975 if c["errors"]:
2012 1976 retcode = 1
2013 1977
2014 1978 for e in c["errors"]:
2015 1979 emsg("\n" + str(e) + "\n")
2016 1980
2017 1981 if c["valid"]:
2018 1982 msg(_(" Cert. Effective Date:"),
2019 1983 c["info"]["effective"])
2020 1984 msg(_("Cert. Expiration Date:"),
2021 1985 c["info"]["expiration"])
2022 1986 return retcode
2023 1987
2024 1988 def display_repository(r):
2025 1989 retcode = 0
2026 1990 for uri in r.origins:
2027 1991 msg(_(" Origin URI:"), uri)
2028 1992 rval = display_ssl_info(uri)
2029 1993 if rval == 1:
2030 1994 retcode = 3
2031 1995
2032 1996 for uri in r.mirrors:
2033 1997 msg(_(" Mirror URI:"), uri)
2034 1998 rval = display_ssl_info(uri)
2035 1999 if rval == 1:
2036 2000 retcode = 3
2037 2001 return retcode
2038 2002
2039 2003 for name in pargs:
2040 2004 # detailed print
2041 2005 pub = api_inst.get_publisher(prefix=name, alias=name)
2042 2006 dt = api_inst.get_publisher_last_update_time(pub.prefix)
2043 2007 if dt:
2044 2008 dt = dt.strftime("%c")
2045 2009
2046 2010 msg("")
2047 2011 msg(_(" Publisher:"), pub.prefix)
2048 2012 msg(_(" Alias:"), pub.alias)
2049 2013
2050 2014 for r in pub.repositories:
2051 2015 rval = display_repository(r)
2052 2016 if rval != 0:
2053 2017 # There was an error in displaying some
2054 2018 # of the information about a repository.
2055 2019 # However, continue on.
2056 2020 retcode = rval
2057 2021
2058 2022 msg(_(" Client UUID:"), pub.client_uuid)
2059 2023 msg(_(" Catalog Updated:"), dt)
2060 2024 if pub.disabled:
2061 2025 msg(_(" Enabled:"), _("No"))
2062 2026 else:
2063 2027 msg(_(" Enabled:"), _("Yes"))
2064 2028 return retcode
2065 2029
2066 2030 def property_set(img, args):
2067 2031 """pkg set-property propname propvalue"""
2068 2032
2069 2033 # ensure no options are passed in
2070 2034 opts, pargs = getopt.getopt(args, "")
2071 2035 try:
2072 2036 propname, propvalue = pargs
2073 2037 except ValueError:
2074 2038 usage(_("set-property: requires a property name and value"))
2075 2039
2076 2040 if propname == "preferred-publisher":
2077 2041 error(_("set-property: set-publisher must be used to change "
2078 2042 "the preferred publisher"))
2079 2043 return 1
2080 2044
2081 2045 try:
2082 2046 img.set_property(propname, propvalue)
2083 2047 except api_errors.PermissionsException, e:
2084 2048 # Prepend a newline because otherwise the exception will
2085 2049 # be printed on the same line as the spinner.
2086 2050 error("\nset-property failed:\n" + str(e))
2087 2051 return 1
2088 2052
2089 2053 return 0
2090 2054
2091 2055 def property_unset(img, args):
2092 2056 """pkg unset-property propname ..."""
2093 2057
2094 2058 # is this an existing property in our image?
2095 2059 # if so, delete it
2096 2060 # if not, error
2097 2061
2098 2062 # ensure no options are passed in
2099 2063 opts, pargs = getopt.getopt(args, "")
2100 2064 if not pargs:
2101 2065 usage(_("unset-property: requires at least one property name"))
2102 2066
2103 2067 for p in pargs:
2104 2068 if p == "preferred-publisher":
2105 2069 error(_("unset-property: set-publisher must be used to "
2106 2070 "change the preferred publisher"))
2107 2071 return 1
2108 2072
2109 2073 try:
2110 2074 img.delete_property(p)
2111 2075 except KeyError:
2112 2076 error(_("unset-property: no such property: %s") % p)
2113 2077 return 1
2114 2078 except api_errors.PermissionsException, e:
2115 2079 # Prepend a newline because otherwise the exception
2116 2080 # will be printed on the same line as the spinner.
2117 2081 error("\n" + str(e))
2118 2082 return 1
2119 2083
2120 2084 return 0
2121 2085
2122 2086 def property_list(img, args):
2123 2087 """pkg property [-H] [propname ...]"""
2124 2088 omit_headers = False
2125 2089
2126 2090 opts, pargs = getopt.getopt(args, "H")
2127 2091 for opt, arg in opts:
2128 2092 if opt == "-H":
2129 2093 omit_headers = True
2130 2094
2131 2095 for p in pargs:
2132 2096 if not img.has_property(p):
2133 2097 error(_("property: no such property: %s") % p)
2134 2098 return 1
2135 2099
2136 2100 if not pargs:
2137 2101 pargs = list(img.properties())
2138 2102
2139 2103 width = max(max([len(p) for p in pargs]), 8)
2140 2104 fmt = "%%-%ss %%s" % width
2141 2105 if not omit_headers:
2142 2106 msg(fmt % ("PROPERTY", "VALUE"))
2143 2107
2144 2108 for p in pargs:
2145 2109 msg(fmt % (p, img.get_property(p)))
2146 2110
2147 2111 return 0
2148 2112
2149 2113 def image_create(img, args):
2150 2114 """Create an image of the requested kind, at the given path. Load
2151 2115 catalog for initial publisher for convenience.
2152 2116
2153 2117 At present, it is legitimate for a user image to specify that it will be
2154 2118 deployed in a zone. An easy example would be a program with an optional
2155 2119 component that consumes global zone-only information, such as various
2156 2120 kernel statistics or device information."""
2157 2121
2158 2122 imgtype = image.IMG_USER
2159 2123 is_zone = False
2160 2124 ssl_key = None
2161 2125 ssl_cert = None
2162 2126 pub_name = None
2163 2127 pub_url = None
2164 2128 refresh_catalogs = True
2165 2129 force = False
2166 2130 variants = {}
2167 2131
2168 2132 opts, pargs = getopt.getopt(args, "fFPUza:p:k:c:",
2169 2133 ["force", "full", "partial", "user", "zone", "authority=",
2170 2134 "publisher=", "no-refresh", "variant="])
2171 2135
2172 2136 for opt, arg in opts:
2173 2137 if opt == "-f" or opt == "--force":
2174 2138 force = True
2175 2139 if opt == "-F" or opt == "--full":
2176 2140 imgtype = imgtypes.IMG_ENTIRE
2177 2141 if opt == "-P" or opt == "--partial":
2178 2142 imgtype = imgtypes.IMG_PARTIAL
2179 2143 if opt == "-U" or opt == "--user":
2180 2144 imgtype = imgtypes.IMG_USER
2181 2145 if opt == "-z" or opt == "--zone":
2182 2146 is_zone = True
2183 2147 imgtype = image.IMG_ENTIRE
2184 2148 if opt == "--no-refresh":
2185 2149 refresh_catalogs = False
2186 2150 if opt == "-k":
2187 2151 ssl_key = arg
2188 2152 if opt == "-c":
2189 2153 ssl_cert = arg
2190 2154
2191 2155 # -a is deprecated and will be removed at a future date.
2192 2156 if opt in ("-a", "-p", "--publisher"):
2193 2157 try:
2194 2158 pub_name, pub_url = arg.split("=", 1)
2195 2159 except ValueError:
2196 2160 usage(_("image-create requires publisher "
2197 2161 "argument to be of the form "
2198 2162 "'<prefix>=<url>'."))
2199 2163 if opt == "--variant":
2200 2164 try:
2201 2165 v_name, v_value = arg.split("=", 1)
2202 2166 if not v_name.startswith("variant."):
2203 2167 v_name = "variant.%s" % v_name
2204 2168 except ValueError:
2205 2169 usage(_("image-create requires variant "
2206 2170 "arguments to be of the form "
2207 2171 "'<name>=<value>'."))
2208 2172 variants[v_name] = v_value
2209 2173
2210 2174 if len(pargs) != 1:
2211 2175 usage(_("image-create requires a single image directory path"))
2212 2176 image_dir = pargs[0]
2213 2177
2214 2178 if ssl_key:
2215 2179 # When creating zones, the path is image-root-relative.
2216 2180 if is_zone:
2217 2181 ssl_key = os.path.normpath(image_dir + os.sep + \
2218 2182 ssl_key)
2219 2183 else:
2220 2184 ssl_key = os.path.abspath(ssl_key)
2221 2185 if not os.path.exists(ssl_key):
2222 2186 msg(_("pkg: set-publisher: SSL key file '%s' does " \
2223 2187 "not exist") % ssl_key)
2224 2188 return 1
2225 2189
2226 2190 if ssl_cert:
2227 2191 # When creating zones, the path is image-root-relative.
2228 2192 if is_zone:
2229 2193 ssl_cert = os.path.normpath(image_dir + os.sep + \
2230 2194 ssl_cert)
2231 2195 else:
2232 2196 ssl_cert = os.path.abspath(ssl_cert)
2233 2197 if not os.path.exists(ssl_cert):
2234 2198 msg(_("pkg: set-publisher: SSL key cert '%s' does " \
2235 2199 "not exist") % ssl_cert)
2236 2200 return 1
2237 2201
2238 2202 if not pub_name and not pub_url:
2239 2203 usage(_("image-create requires a publisher argument"))
2240 2204
2241 2205 if not pub_name or not pub_url:
2242 2206 usage(_("image-create requires publisher argument to be of "
2243 2207 "the form '<prefix>=<url>'."))
2244 2208
2245 2209 if pub_name.startswith(fmri.PREF_PUB_PFX):
2246 2210 error(_("image-create requires that a prefix not match: %s"
2247 2211 % fmri.PREF_PUB_PFX))
2248 2212 return 1
2249 2213
2250 2214 if not misc.valid_pub_prefix(pub_name):
2251 2215 error(_("image-create: publisher prefix has invalid " \
2252 2216 "characters"))
2253 2217 return 1
2254 2218
2255 2219 # Bail if there is already an image there
2256 2220 if img.image_type(image_dir) != None and not force:
2257 2221 error(_("there is already an image at: %s") % image_dir)
2258 2222 error(_("To override, use the -f (force) option."))
2259 2223 return 1
2260 2224
2261 2225 # Bail if the directory exists but isn't empty
2262 2226 if os.path.exists(image_dir) and \
2263 2227 len(os.listdir(image_dir)) > 0 and not force:
2264 2228 error(_("Non-empty directory: %s") % image_dir)
2265 2229 error(_("To override, use the -f (force) option."))
2266 2230 return 1
2267 2231
2268 2232 try:
2269 2233 img.set_attrs(imgtype, image_dir, is_zone, pub_name, pub_url,
2270 2234 ssl_key=ssl_key, ssl_cert=ssl_cert, variants=variants,
2271 2235 refresh_allowed=refresh_catalogs, progtrack=get_tracker())
2272 2236 except OSError, e:
2273 2237 # Ensure messages are displayed after the spinner.
2274 2238 emsg("\n")
2275 2239 error(_("cannot create image at %(image_dir)s: %(reason)s") %
2276 2240 { "image_dir": image_dir, "reason": e.args[1] })
2277 2241 return 1
2278 2242 except api_errors.PermissionsException, e:
2279 2243 # Ensure messages are displayed after the spinner.
2280 2244 emsg("")
2281 2245 error(e, cmd="image-create")
|
↓ open down ↓ |
606 lines elided |
↑ open up ↑ |
2282 2246 return 1
2283 2247 except api_errors.InvalidDepotResponseException, e:
2284 2248 # Ensure messages are displayed after the spinner.
2285 2249 emsg("\n")
2286 2250 error(_("The URI '%(pub_url)s' does not appear to point to a "
2287 2251 "valid pkg server.\nPlease check the server's "
2288 2252 "address and client's network configuration."
2289 2253 "\nAdditional details:\n\n%(error)s") %
2290 2254 { "pub_url": pub_url, "error": e },
2291 2255 cmd="image-create")
2256 + print_proxy_config()
2292 2257 return 1
2293 2258 except api_errors.CatalogRefreshException, cre:
2294 2259 # Ensure messages are displayed after the spinner.
2295 2260 error("", cmd="image-create")
2296 2261 if display_catalog_failures(cre) == 0:
2297 2262 return 1
2298 2263 else:
2299 2264 return 3
2300 2265 return 0
2301 2266
2302 2267
2303 2268 def rebuild_index(img_dir, pargs):
2304 2269 """pkg rebuild-index
2305 2270
2306 2271 Forcibly rebuild the search indexes. Will remove existing indexes
2307 2272 and build new ones from scratch."""
2308 2273 quiet = False
2309 2274
2310 2275 if pargs:
2311 2276 usage(_("rebuild-index: command does not take operands " \
2312 2277 "('%s')") % " ".join(pargs))
2313 2278 try:
2314 2279 api_inst = api.ImageInterface(img_dir, CLIENT_API_VERSION,
2315 2280 get_tracker(quiet), None, PKG_CLIENT_NAME)
2316 2281 except api_errors.ImageNotFoundException, e:
2317 2282 error(_("'%s' is not an install image") % e.user_dir)
2318 2283 return 1
2319 2284
2320 2285 try:
2321 2286 api_inst.rebuild_search_index()
2322 2287 except api_errors.CorruptedIndexException:
2323 2288 error(INCONSISTENT_INDEX_ERROR_MESSAGE)
2324 2289 return 1
2325 2290 except api_errors.ProblematicPermissionsIndexException, e:
2326 2291 error(str(e) + PROBLEMATIC_PERMISSIONS_ERROR_MESSAGE)
2327 2292 return 1
2328 2293 except api_errors.MainDictParsingException, e:
2329 2294 error(str(e))
2330 2295 return 1
2331 2296 else:
2332 2297 return 0
2333 2298
2334 2299 def history_list(img, args):
2335 2300 """Display history about the current image.
2336 2301 """
2337 2302
2338 2303 omit_headers = False
2339 2304 long_format = False
2340 2305
2341 2306 opts, pargs = getopt.getopt(args, "Hl")
2342 2307 for opt, arg in opts:
2343 2308 if opt == "-H":
2344 2309 omit_headers = True
2345 2310 elif opt == "-l":
2346 2311 long_format = True
2347 2312
2348 2313 if omit_headers and long_format:
2349 2314 usage(_("history: -H and -l may not be combined"))
2350 2315
2351 2316 if not long_format:
2352 2317 if not omit_headers:
2353 2318 msg("%-19s %-25s %-15s %s" % (_("TIME"),
2354 2319 _("OPERATION"), _("CLIENT"), _("OUTCOME")))
2355 2320
2356 2321 if not os.path.exists(img.history.path):
2357 2322 # Nothing to display.
2358 2323 return 0
2359 2324
2360 2325 for entry in sorted(os.listdir(img.history.path)):
2361 2326 # Load the history entry.
2362 2327 try:
2363 2328 he = history.History(root_dir=img.history.root_dir,
2364 2329 filename=entry)
2365 2330 except api_errors.PermissionsException, e:
2366 2331 error(e, cmd="history")
2367 2332 return 1
2368 2333 except history.HistoryLoadException, e:
2369 2334 if e.parse_failure:
2370 2335 # Ignore corrupt entries.
2371 2336 continue
2372 2337 raise
2373 2338
2374 2339 # Retrieve and format some of the data shared between each
2375 2340 # output format.
2376 2341 start_time = misc.timestamp_to_time(
2377 2342 he.operation_start_time)
2378 2343 start_time = datetime.datetime.fromtimestamp(
2379 2344 start_time).isoformat()
2380 2345
2381 2346 res = he.operation_result
2382 2347 if len(res) > 1:
2383 2348 outcome = "%s (%s)" % (_(res[0]), _(res[1]))
2384 2349 else:
2385 2350 outcome = _(res[0])
2386 2351
2387 2352 if long_format:
2388 2353 data = []
2389 2354 data.append(("Operation", he.operation_name))
2390 2355
2391 2356 data.append(("Outcome", outcome))
2392 2357 data.append(("Client", he.client_name))
2393 2358 data.append(("Version", he.client_version))
2394 2359
2395 2360 data.append(("User", "%s (%s)" % \
2396 2361 (he.operation_username, he.operation_userid)))
2397 2362
2398 2363 data.append(("Start Time", start_time))
2399 2364
2400 2365 end_time = misc.timestamp_to_time(
2401 2366 he.operation_end_time)
2402 2367 end_time = datetime.datetime.fromtimestamp(
2403 2368 end_time).isoformat()
2404 2369 data.append(("End Time", end_time))
2405 2370
2406 2371 data.append(("Command", " ".join(he.client_args)))
2407 2372
2408 2373 state = he.operation_start_state
2409 2374 if state:
2410 2375 data.append(("Start State", "\n" + state))
2411 2376
2412 2377 state = he.operation_end_state
2413 2378 if state:
2414 2379 data.append(("End State", "\n" + state))
2415 2380
2416 2381 errors = "\n".join(he.operation_errors)
2417 2382 if errors:
2418 2383 data.append(("Errors", "\n" + errors))
2419 2384
2420 2385 for field, value in data:
|
↓ open down ↓ |
119 lines elided |
↑ open up ↑ |
2421 2386 msg("%15s: %s" % (_(field), value))
2422 2387
2423 2388 # Separate log entries with a blank line.
2424 2389 msg("")
2425 2390 else:
2426 2391 msg("%-19s %-25s %-15s %s" % (start_time,
2427 2392 he.operation_name, he.client_name, outcome))
2428 2393
2429 2394 return 0
2430 2395
2396 +def print_proxy_config():
2397 + """If the user has configured http_proxy or https_proxy in the
2398 + environment, print out the values. Some transport errors are
2399 + not debuggable without this information handy."""
2400 +
2401 + http_proxy = os.environ.get("http_proxy", None)
2402 + https_proxy = os.environ.get("https_proxy", None)
2403 +
2404 + if not http_proxy and not https_proxy:
2405 + return
2406 +
2407 + emsg(_("\nThe following proxy configuration is set in the"
2408 + " environment:\n"))
2409 + if http_proxy:
2410 + emsg(_("http_proxy: %s\n") % http_proxy)
2411 + if https_proxy:
2412 + emsg(_("https_proxy: %s\n") % https_proxy)
2413 +
2414 +
2431 2415 # To allow exception handler access to the image.
2432 2416 __img = None
2433 2417
2434 2418 def main_func():
2435 2419 global_settings.client_name = PKG_CLIENT_NAME
2436 2420
2437 2421 global __img
2438 2422 __img = img = image.Image()
2439 2423
2440 2424 misc.setlocale(locale.LC_ALL, "", error)
2441 2425 gettext.install("pkg", "/usr/share/locale")
2442 2426
2443 2427 try:
2444 2428 opts, pargs = getopt.getopt(sys.argv[1:], "R:D:?",
2445 2429 ["debug=", "help"])
2446 2430 except getopt.GetoptError, e:
2447 2431 usage(_("illegal global option -- %s") % e.opt)
2448 2432
2449 2433 show_usage = False
2450 2434 for opt, arg in opts:
2451 2435 if opt == "-D" or opt == "--debug":
2452 2436 try:
2453 2437 key, value = arg.split("=", 1)
2454 2438 except (AttributeError, ValueError):
2455 2439 usage(_("%(opt)s takes argument of form "
2456 2440 "name=value, not %(arg)s") % { "opt": opt,
2457 2441 "arg": arg })
2458 2442 DebugValues.set_value(key, value)
2459 2443 elif opt == "-R":
2460 2444 mydir = arg
2461 2445 elif opt in ("--help", "-?"):
2462 2446 show_usage = True
2463 2447
2464 2448 subcommand = None
|
↓ open down ↓ |
24 lines elided |
↑ open up ↑ |
2465 2449 if pargs:
2466 2450 subcommand = pargs.pop(0)
2467 2451 if subcommand == "help":
2468 2452 show_usage = True
2469 2453
2470 2454 if show_usage:
2471 2455 usage(retcode=0)
2472 2456 elif not subcommand:
2473 2457 usage()
2474 2458
2475 - socket.setdefaulttimeout(
2476 - int(os.environ.get("PKG_CLIENT_TIMEOUT", "30"))) # in seconds
2477 -
2478 - # Override default PKG_TIMEOUT_MAX if a value has been specified
2479 - # in the environment.
2459 + # Override default PKG_TIMEOUT_MAX and PKG_CLIENT_TIMEOUT
2460 + # if a value has been specified in the environment.
2480 2461 global_settings.PKG_TIMEOUT_MAX = int(os.environ.get("PKG_TIMEOUT_MAX",
2481 2462 global_settings.PKG_TIMEOUT_MAX))
2482 2463
2464 + global_settings.PKG_CLIENT_TIMEOUT = int(os.environ.get(
2465 + "PKG_CLIENT_TIMEOUT", global_settings.PKG_CLIENT_TIMEOUT))
2466 +
2467 + # This call only affects sockets created by Python. The transport
2468 + # framework must set the timeout value internally.
2469 + socket.setdefaulttimeout(global_settings.PKG_TIMEOUT_MAX) # in seconds
2470 +
2483 2471 if subcommand == "image-create":
2484 2472 if "mydir" in locals():
2485 2473 usage(_("-R not allowed for %s subcommand") %
2486 2474 subcommand)
2487 2475 try:
2488 2476 ret = image_create(img, pargs)
2489 2477 except getopt.GetoptError, e:
2490 2478 usage(_("illegal %s option -- %s") % \
2491 2479 (subcommand, e.opt))
2492 2480 return ret
2493 2481 elif subcommand == "version":
2494 2482 if "mydir" in locals():
2495 2483 usage(_("-R not allowed for %s subcommand") %
2496 2484 subcommand)
2497 2485 if pargs:
2498 2486 usage(_("version: command does not take operands " \
2499 2487 "('%s')") % " ".join(pargs))
2500 2488 msg(pkg.VERSION)
2501 2489 return 0
2502 2490
2503 2491 provided_image_dir = True
2504 2492 pkg_image_used = False
2505 2493
2506 2494 if "mydir" not in locals():
2507 2495 try:
2508 2496 mydir = os.environ["PKG_IMAGE"]
2509 2497 pkg_image_used = True
2510 2498 except KeyError:
2511 2499 try:
2512 2500 provided_image_dir = False
2513 2501 mydir = os.getcwd()
2514 2502 except OSError, e:
2515 2503 try:
2516 2504 mydir = os.environ["PWD"]
2517 2505 if not mydir or mydir[0] != "/":
2518 2506 mydir = None
2519 2507 except KeyError:
2520 2508 mydir = None
2521 2509
2522 2510 if mydir == None:
2523 2511 error(_("Could not find image. Use the -R option or set "
2524 2512 "$PKG_IMAGE to point\nto an image, or change the working "
2525 2513 "directory to one inside the image."))
2526 2514 return 1
2527 2515
2528 2516 try:
2529 2517 img.find_root(mydir, provided_image_dir)
2530 2518 except api_errors.ImageNotFoundException, e:
2531 2519 if e.user_specified:
2532 2520 m = "No image rooted at '%s'"
2533 2521 if pkg_image_used:
2534 2522 m += " (set by $PKG_IMAGE)"
2535 2523 error(_(m) % e.user_dir)
2536 2524 else:
2537 2525 error(_("No image found."))
2538 2526 return 1
2539 2527
2540 2528 try:
2541 2529 img.load_config()
2542 2530 except api_errors.ApiException, e:
2543 2531 error(_("client configuration error: %s") % e)
2544 2532 return 1
2545 2533
2546 2534 try:
2547 2535 if subcommand == "refresh":
2548 2536 return publisher_refresh(mydir, pargs)
2549 2537 elif subcommand == "list":
2550 2538 return list_inventory(img, pargs)
2551 2539 elif subcommand == "image-update":
2552 2540 return image_update(mydir, pargs)
2553 2541 elif subcommand == "install":
2554 2542 return install(mydir, pargs)
2555 2543 elif subcommand == "uninstall":
2556 2544 return uninstall(mydir, pargs)
2557 2545 elif subcommand == "freeze":
2558 2546 return freeze(img, pargs)
2559 2547 elif subcommand == "unfreeze":
2560 2548 return unfreeze(img, pargs)
2561 2549 elif subcommand == "search":
2562 2550 return search(mydir, pargs)
2563 2551 elif subcommand == "info":
2564 2552 return info(mydir, pargs)
2565 2553 elif subcommand == "contents":
2566 2554 return list_contents(img, pargs)
2567 2555 elif subcommand == "fix":
2568 2556 return fix_image(img, pargs)
2569 2557 elif subcommand == "verify":
2570 2558 return verify_image(img, pargs)
2571 2559 elif subcommand in ("set-authority", "set-publisher"):
2572 2560 return publisher_set(img, mydir, pargs)
2573 2561 elif subcommand in ("unset-authority", "unset-publisher"):
2574 2562 return publisher_unset(mydir, pargs)
2575 2563 elif subcommand in ("authority", "publisher"):
2576 2564 return publisher_list(mydir, pargs)
2577 2565 elif subcommand == "set-property":
2578 2566 return property_set(img, pargs)
2579 2567 elif subcommand == "unset-property":
2580 2568 return property_unset(img, pargs)
2581 2569 elif subcommand == "property":
2582 2570 return property_list(img, pargs)
2583 2571 elif subcommand == "history":
2584 2572 return history_list(img, pargs)
2585 2573 elif subcommand == "purge-history":
2586 2574 ret_code = img.history.purge()
2587 2575 if ret_code == 0:
2588 2576 msg(_("History purged."))
2589 2577 return ret_code
2590 2578 elif subcommand == "rebuild-index":
2591 2579 return rebuild_index(mydir, pargs)
2592 2580 else:
2593 2581 usage(_("unknown subcommand '%s'") % subcommand)
2594 2582
2595 2583 except getopt.GetoptError, e:
2596 2584 usage(_("illegal %(cmd)s option -- %(error)s") %
2597 2585 { "cmd": subcommand, "error": e.opt })
2598 2586
2599 2587
2600 2588 #
2601 2589 # Establish a specific exit status which means: "python barfed an exception"
2602 2590 # so that we can more easily detect these in testing of the CLI commands.
2603 2591 #
2604 2592 if __name__ == "__main__":
2605 2593 try:
2606 2594 # Out of memory errors can be raised as EnvironmentErrors with
2607 2595 # an errno of ENOMEM, so in order to handle those exceptions
2608 2596 # with other errnos, we nest this try block and have the outer
2609 2597 # one handle the other instances.
2610 2598 try:
2611 2599 __ret = main_func()
2612 2600 except (MemoryError, EnvironmentError), __e:
2613 2601 if isinstance(__e, EnvironmentError) and \
2614 2602 __e.errno != errno.ENOMEM:
2615 2603 raise
2616 2604 if __img:
2617 2605 __img.history.abort(RESULT_FAILED_OUTOFMEMORY)
2618 2606 error("\n" + misc.out_of_memory())
2619 2607 __ret = 1
2620 2608 except SystemExit, __e:
2621 2609 if __img:
2622 2610 __img.history.abort(RESULT_FAILED_UNKNOWN)
2623 2611 raise __e
2624 2612 except (PipeError, KeyboardInterrupt):
2625 2613 if __img:
2626 2614 __img.history.abort(RESULT_CANCELED)
2627 2615 # We don't want to display any messages here to prevent
2628 2616 # possible further broken pipe (EPIPE) errors.
2629 2617 __ret = 1
|
↓ open down ↓ |
137 lines elided |
↑ open up ↑ |
2630 2618 except api_errors.CertificateError, __e:
2631 2619 if __img:
2632 2620 __img.history.abort(RESULT_FAILED_CONFIGURATION)
2633 2621 error(__e)
2634 2622 __ret = 1
2635 2623 except api_errors.PublisherError, __e:
2636 2624 if __img:
2637 2625 __img.history.abort(RESULT_FAILED_BAD_REQUEST)
2638 2626 error(__e)
2639 2627 __ret = 1
2640 - except misc.TransportException, __e:
2628 + except api_errors.TransportError, __e:
2641 2629 if __img:
2642 2630 __img.history.abort(RESULT_FAILED_TRANSPORT)
2643 - error(_("\nMaximum number of network retries exceeded during "
2644 - "download. Details follow:\n%s") % __e)
2631 + emsg(_("\nErrors were encountered while attempting to retrieve"
2632 + " package or file data for\nthe requested operation."))
2633 + emsg(_("Details follow:\n\n%s") % __e)
2634 + print_proxy_config()
2645 2635 __ret = 1
2646 - except (ManifestRetrievalError,
2647 - DatastreamRetrievalError, FileListRetrievalError), __e:
2648 - if __img:
2649 - __img.history.abort(RESULT_FAILED_TRANSPORT)
2650 - error(_("An error was encountered while attempting to retrieve"
2651 - " package or file data for the requested operation."))
2652 - error(__e)
2653 - __ret = 1
2654 2636 except api_errors.InvalidDepotResponseException, __e:
2655 2637 if __img:
2656 2638 __img.history.abort(RESULT_FAILED_TRANSPORT)
2657 - error(_("\nUnable to contact a valid package depot. "
2639 + emsg(_("\nUnable to contact a valid package depot. "
2658 2640 "This may be due to a problem with the server, "
2659 2641 "network misconfiguration, or an incorrect pkg client "
2660 2642 "configuration. Please check your network settings and "
2661 2643 "attempt to contact the server using a web browser."))
2662 - error(_("\nAdditional details:\n\n%s") % __e)
2644 + emsg(_("\nAdditional details:\n\n%s") % __e)
2645 + print_proxy_config()
2663 2646 __ret = 1
2664 2647 except history.HistoryLoadException, __e:
2665 2648 # Since a history related error occurred, discard all
2666 2649 # information about the current operation(s) in progress.
2667 2650 if __img:
2668 2651 __img.history.clear()
2669 2652 error(_("An error was encountered while attempting to load "
2670 2653 "history information\nabout past client operations."))
2671 2654 error(__e)
2672 2655 __ret = 1
2673 2656 except history.HistoryStoreException, __e:
2674 2657 # Since a history related error occurred, discard all
2675 2658 # information about the current operation(s) in progress.
2676 2659 if __img:
2677 2660 __img.history.clear()
2678 2661 error(_("An error was encountered while attempting to store "
2679 2662 "information about the\ncurrent operation in client "
2680 2663 "history."))
2681 2664 error(__e)
2682 2665 __ret = 1
2683 2666 except history.HistoryPurgeException, __e:
2684 2667 # Since a history related error occurred, discard all
2685 2668 # information about the current operation(s) in progress.
2686 2669 if __img:
2687 2670 __img.history.clear()
2688 2671 error(_("An error was encountered while attempting to purge "
2689 2672 "client history."))
2690 2673 error(__e)
2691 2674 __ret = 1
2692 2675 except api_errors.VersionException, __e:
2693 2676 if __img:
2694 2677 __img.history.abort(RESULT_FAILED_UNKNOWN)
2695 2678 error(_("The pkg command appears out of sync with the "
2696 2679 "libraries provided \nby SUNWipkg. The client version is "
2697 2680 "%(client)s while the library API version is %(api)s") %
2698 2681 {'client': __e.received_version,
2699 2682 'api': __e.expected_version
2700 2683 })
2701 2684 __ret = 1
2702 2685 except:
2703 2686 if __img:
2704 2687 __img.history.abort(RESULT_FAILED_UNKNOWN)
2705 2688 traceback.print_exc()
2706 2689 error(
2707 2690 _("\n\nThis is an internal error. Please let the "
2708 2691 "developers know about this\nproblem by filing a bug at "
2709 2692 "http://defect.opensolaris.org and including the\nabove "
2710 2693 "traceback and this message. The version of pkg(5) is "
2711 2694 "'%s'.") % pkg.VERSION)
2712 2695 __ret = 99
2713 2696
2714 2697 sys.exit(__ret)
|
↓ open down ↓ |
42 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX