58 import urlparse
59
60 import pkg
61 import pkg.actions as actions
62 import pkg.client.api as api
63 import pkg.client.api_errors as api_errors
64 import pkg.client.bootenv as bootenv
65 import pkg.client.history as history
66 import pkg.client.image as image
67 import pkg.client.imagetypes as imgtypes
68 import pkg.client.progress as progress
69 import pkg.client.publisher as publisher
70 import pkg.fmri as fmri
71 import pkg.misc as misc
72
73 from pkg.client import global_settings
74 from pkg.client.debugvalues import DebugValues
75 from pkg.client.history import (RESULT_CANCELED, RESULT_FAILED_BAD_REQUEST,
76 RESULT_FAILED_CONFIGURATION, RESULT_FAILED_TRANSPORT, RESULT_FAILED_UNKNOWN,
77 RESULT_FAILED_OUTOFMEMORY)
78 from pkg.client.filelist import FileListRetrievalError
79 from pkg.client.retrieve import (CatalogRetrievalError,
80 DatastreamRetrievalError, ManifestRetrievalError)
81 from pkg.misc import EmptyI, msg, emsg, PipeError
82
83 CLIENT_API_VERSION = 15
84 PKG_CLIENT_NAME = "pkg"
85
86 def error(text, cmd=None):
87 """Emit an error message prefixed by the command name """
88
89 if cmd:
90 text = "%s: %s" % (cmd, text)
91 else:
92 # If we get passed something like an Exception, we can convert
93 # it down to a string.
94 text = str(text)
95
96 # If the message starts with whitespace, assume that it should come
97 # *before* the command-name prefix.
98 text_nows = text.lstrip()
99 ws = text[:len(text) - len(text_nows)]
100
557 raise RuntimeError("Catalog refresh failed during"
558 " image-update.")
559 if not stuff_to_do:
560 msg(_("No updates available for this image."))
561 return 0
562 except api_errors.InventoryException, e:
563 error(_("image-update failed (inventory exception):\n%s") % e)
564 return 1
565 except api_errors.CatalogRefreshException, e:
566 if display_catalog_failures(e) == 0:
567 if not noexecute:
568 return 1
569 else:
570 raise RuntimeError("Catalog refresh failed during"
571 " image-update.")
572 except api_errors.BEException, e:
573 error(_(e))
574 return 1
575 except (api_errors.CertificateError,
576 api_errors.PlanCreationException,
577 api_errors.NetworkUnavailableException,
578 api_errors.PermissionsException), e:
579 # Prepend a newline because otherwise the exception will
580 # be printed on the same line as the spinner.
581 error("\n" + str(e))
582 return 1
583 except api_errors.IpkgOutOfDateException:
584 msg(_("WARNING: pkg(5) appears to be out of date, and should " \
585 "be updated before\nrunning image-update.\n"))
586 msg(_("Please update pkg(5) using 'pfexec pkg install " \
587 "SUNWipkg' and then retry\nthe image-update."))
588 return 1
589 except api_errors.ImageNotFoundException, e:
590 error(_("No image rooted at '%s'") % e.user_dir)
591 return 1
592 if noexecute:
593 return 0
594
595 ret_code = 0
596
597 # Exceptions which happen here are printed in the above level, with
598 # or without some extra decoration done here.
599 # XXX would be nice to kick the progress tracker.
600 try:
601 api_inst.prepare()
602 except misc.TransportException:
603 # move past the progress tracker line.
604 msg("\n")
605 raise
606 except KeyboardInterrupt:
607 raise
608 except api_errors.PermissionsException, e:
609 # Prepend a newline because otherwise the exception will
610 # be printed on the same line as the spinner.
611 error("\n" + str(e))
612 return 1
613 except:
614 error(_("\nAn unexpected error happened while preparing for " \
615 "image-update:"))
616 raise
617
618 try:
619 api_inst.execute_plan()
620 except RuntimeError, e:
621 error(_("image-update failed: %s") % e)
622 ret_code = 1
623 except api_errors.ImageUpdateOnLiveImageException:
624 error(_("image-update cannot be done on live image"))
625 ret_code = 1
719 # caught while planning.
720 stuff_to_do, cre = api_inst.plan_install(pkg_list, filters,
721 refresh_catalogs, noexecute, verbose=verbose,
722 update_index=update_index)
723 if cre and not display_catalog_failures(cre):
724 raise RuntimeError("Catalog refresh failed during"
725 " install.")
726 if not stuff_to_do:
727 msg(_("No updates available for this image."))
728 return 0
729 except api_errors.CatalogRefreshException, e:
730 if display_catalog_failures(e) == 0:
731 if not noexecute:
732 return 1
733 else:
734 error(_("Catalog refresh failed during install."),
735 cmd="install")
736 return 1
737 except (api_errors.CertificateError,
738 api_errors.PlanCreationException,
739 api_errors.NetworkUnavailableException,
740 api_errors.PermissionsException), e:
741 # Prepend a newline because otherwise the exception will
742 # be printed on the same line as the spinner.
743 error("\n" + str(e), cmd="install")
744 return 1
745 except api_errors.InventoryException, e:
746 error(_("install failed (inventory exception):\n%s") % e,
747 cmd="install")
748 return 1
749 except fmri.IllegalFmri, e:
750 error(e, cmd="install")
751 return 1
752
753 if noexecute:
754 return 0
755
756 # Exceptions which happen here are printed in the above level, with
757 # or without some extra decoration done here.
758 # XXX would be nice to kick the progress tracker.
759 try:
760 api_inst.prepare()
761 except misc.TransportException:
762 # move past the progress tracker line.
763 msg("\n")
764 raise
765 except KeyboardInterrupt:
766 raise
767 except api_errors.PermissionsException, e:
768 # Prepend a newline because otherwise the exception will
769 # be printed on the same line as the spinner.
770 error("\n" + str(e))
771 return 1
772 except:
773 error(_("\nAn unexpected error happened while preparing for " \
774 "install:"))
775 raise
776
777 ret_code = 0
778
779 try:
780 api_inst.execute_plan()
781 except RuntimeError, e:
782 error(_("installation failed: %s") % e)
783 ret_code = 1
784 except api_errors.CorruptedIndexException, e:
862 error("""Cannot remove '%s' due to
863 the following packages that depend on it:""" % e[0])
864 for d in e[1]:
865 emsg(" %s" % d)
866 return 1
867 except (api_errors.PlanCreationException,
868 api_errors.PermissionsException), e:
869 # Prepend a newline because otherwise the exception will
870 # be printed on the same line as the spinner.
871 error("\n" + str(e))
872 return 1
873
874 if noexecute:
875 return 0
876
877 # Exceptions which happen here are printed in the above level, with
878 # or without some extra decoration done here.
879 # XXX would be nice to kick the progress tracker.
880 try:
881 api_inst.prepare()
882 except misc.TransportException:
883 # move past the progress tracker line.
884 msg("\n")
885 raise
886 except api_errors.FileInUseException, e:
887 error("\n" + str(e))
888 return 1
889 except KeyboardInterrupt:
890 raise
891 except:
892 error(_("\nAn unexpected error happened while preparing for " \
893 "install:"))
894 raise
895
896 ret_code = 0
897
898 try:
899 api_inst.execute_plan()
900 except RuntimeError, e:
901 error(_("uninstallation failed: %s") % e)
902 ret_code = 1
903 except api_errors.CorruptedIndexException, e:
904 error(INCONSISTENT_INDEX_ERROR_MESSAGE)
905 ret_code = 1
916 ret_code = 1
917 except KeyboardInterrupt:
918 raise
919 except Exception, e:
920 error(_("An unexpected error happened during " \
921 "uninstallation: %s") % e)
922 raise
923
924 return ret_code
925
926 def freeze(img, args):
927 """Attempt to take package specified to FROZEN state, with given
928 restrictions. Package must have been in the INSTALLED state."""
929 return 0
930
931 def unfreeze(img, args):
932 """Attempt to return package specified to INSTALLED state from FROZEN
933 state."""
934 return 0
935
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 def __convert_output(a_str, match):
961 """Converts a string to a three tuple with the information to fill
962 the INDEX, ACTION, and VALUE columns.
963
964 The "a_str" parameter is the string representation of an action.
965
966 The "match" parameter is a string whose precise interpretation is given
967 below.
968
969 For most action types, match defines which attribute the query matched
970 with. For example, it states whether the basename or path attribute of
971 a file action matched the query. Attribute (set) actions are treated
972 differently because they only have one attribute, and many values
973 associated with that attribute. For those actions, the match parameter
974 states which value matched the query."""
975
976 a = actions.fromstr(a_str.rstrip())
977 if isinstance(a, actions.attribute.AttributeAction):
978 return a.attrs.get(a.key_attr), a.name, match
979 return match, a.name, a.attrs.get(a.key_attr)
1003 "The problematic structure:%r") % (tup,))
1004 return False
1005 if first:
1006 msg("%-10s %-9s %-25s %s" %
1007 ("INDEX", "ACTION", "VALUE", "PACKAGE"))
1008 try:
1009 out1, out2, out3 = __convert_output(action, match)
1010 except (actions.UnknownActionError,
1011 actions.MalformedActionError), e:
1012 error(_("The server returned a malformed action.\n%s") %
1013 e)
1014 return False
1015 msg("%-10s %-9s %-25s %s" %
1016 (out1, out2, out3,
1017 fmri.PkgFmri(str(pfmri)).get_short_fmri()))
1018 else:
1019 pfmri = tup
1020 if first:
1021 msg("%s" % ("PACKAGE"))
1022 pub_name = ''
1023 if pub is not None and "prefix" in pub:
1024 pub_name = " (%s)" % pub.prefix
1025 msg("%s%s" %
1026 (fmri.PkgFmri(str(pfmri)).get_short_fmri(), pub_name))
1027 return True
1028
1029 def search(img_dir, args):
1030 """Search for the given query."""
1031
1032 opts, pargs = getopt.getopt(args, "alprs:I")
1033
1034 local = remote = case_sensitive = False
1035 servers = []
1036 return_actions = True
1037 for opt, arg in opts:
1038 if opt == "-a":
1039 return_actions = True
1040 elif opt == "-l":
1041 local = True
1042 elif opt == "-p":
1043 return_actions = False
1044 elif opt == "-r":
1083
1084 try:
1085 if local:
1086 searches.append(api_inst.local_search(query))
1087 if remote:
1088 searches.append(api_inst.remote_search(query,
1089 servers=servers))
1090
1091 # By default assume we don't find anything.
1092 retcode = 1
1093
1094 for raw_value in itertools.chain(*searches):
1095 try:
1096 query_num, pub, (v, return_type, tmp) = \
1097 raw_value
1098 except ValueError, e:
1099 error(_("The server returned a malformed "
1100 "result:%r") % (raw_value,))
1101 bad_res = True
1102 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)
1108 good_res |= ret
1109 bad_res |= not ret
1110 first = False
1111 except (api_errors.IncorrectIndexFileHash,
1112 api_errors.InconsistentIndexException):
1113 error(_("The search index appears corrupted. Please "
1114 "rebuild the index with 'pkg rebuild-index'."))
1115 return 1
1116 except api_errors.ProblematicSearchServers, e:
1117 error(e)
1118 bad_res = True
1119 except api_errors.SlowSearchUsed, e:
1120 error(e)
1121 except (api_errors.IncorrectIndexFileHash,
1122 api_errors.InconsistentIndexException):
1123 error(_("The search index appears corrupted. Please "
1124 "rebuild the index with 'pkg rebuild-index'."))
1125 return 1
1596 else:
1597 msg(txt)
1598
1599 for pub, err in cre.failed:
1600 if isinstance(err, urllib2.HTTPError):
1601 emsg(" %s: %s - %s" % \
1602 (err.filename, err.code, err.msg))
1603 elif isinstance(err, urllib2.URLError):
1604 if err.args[0][0] == 8:
1605 emsg(" %s: %s" % \
1606 (urlparse.urlsplit(
1607 pub["origin"])[1].split(":")[0],
1608 err.args[0][1]))
1609 else:
1610 if isinstance(err.args[0], socket.timeout):
1611 emsg(" %s: %s" % \
1612 (pub["origin"], "timeout"))
1613 else:
1614 emsg(" %s: %s" % \
1615 (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 else:
1631 emsg(" ", err)
1632
1633 if cre.message:
1634 emsg(cre.message)
1635
1636 return succeeded
1637
1638 def publisher_refresh(img_dir, args):
1639 """Update metadata for the image's publishers."""
1640
1641 # XXX will need to show available content series for each package
1642 full_refresh = False
1643 opts, pargs = getopt.getopt(args, "", ["full"])
1644 for opt, arg in opts:
1645 if opt == "--full":
1646 full_refresh = True
1647
1648 try:
1649 api_inst = api.ImageInterface(img_dir, CLIENT_API_VERSION,
1650 get_tracker(), None, PKG_CLIENT_NAME)
1651 except api_errors.ImageNotFoundException, e:
1652 error(_("'%s' is not an install image") % e.user_dir)
1653 return 1
1654
1655 try:
1656 # The user explicitly requested this refresh, so set the
1657 # refresh to occur immediately.
1658 api_inst.refresh(full_refresh=full_refresh, immediate=True,
1659 pubs=pargs)
1660 except api_errors.PublisherError, e:
1661 error(e)
1662 error(_("'pkg publisher' will show a list of publishers."))
1663 return 1
1664 except (api_errors.PermissionsException,
1665 api_errors.NetworkUnavailableException), e:
1666 # Prepend a newline because otherwise the exception will
1667 # be printed on the same line as the spinner.
1668 error("\n" + str(e))
1669 return 1
1670 except api_errors.CatalogRefreshException, e:
1671 if display_catalog_failures(e) == 0:
1672 return 1
1673 else:
1674 return 3
1675 else:
1676 return 0
1677
1678 def publisher_set(img, img_dir, args):
1679 """pkg set-publisher [-Ped] [-k ssl_key] [-c ssl_cert] [--reset-uuid]
1680 [-O origin_url] [-m mirror to add] [-M mirror to remove]
1681 [--enable] [--disable] [--no-refresh] publisher"""
1682
1683 preferred = False
1684 ssl_key = None
1685 ssl_cert = None
2272 except OSError, e:
2273 # Ensure messages are displayed after the spinner.
2274 emsg("\n")
2275 error(_("cannot create image at %(image_dir)s: %(reason)s") %
2276 { "image_dir": image_dir, "reason": e.args[1] })
2277 return 1
2278 except api_errors.PermissionsException, e:
2279 # Ensure messages are displayed after the spinner.
2280 emsg("")
2281 error(e, cmd="image-create")
2282 return 1
2283 except api_errors.InvalidDepotResponseException, e:
2284 # Ensure messages are displayed after the spinner.
2285 emsg("\n")
2286 error(_("The URI '%(pub_url)s' does not appear to point to a "
2287 "valid pkg server.\nPlease check the server's "
2288 "address and client's network configuration."
2289 "\nAdditional details:\n\n%(error)s") %
2290 { "pub_url": pub_url, "error": e },
2291 cmd="image-create")
2292 return 1
2293 except api_errors.CatalogRefreshException, cre:
2294 # Ensure messages are displayed after the spinner.
2295 error("", cmd="image-create")
2296 if display_catalog_failures(cre) == 0:
2297 return 1
2298 else:
2299 return 3
2300 return 0
2301
2302
2303 def rebuild_index(img_dir, pargs):
2304 """pkg rebuild-index
2305
2306 Forcibly rebuild the search indexes. Will remove existing indexes
2307 and build new ones from scratch."""
2308 quiet = False
2309
2310 if pargs:
2311 usage(_("rebuild-index: command does not take operands " \
2411
2412 state = he.operation_end_state
2413 if state:
2414 data.append(("End State", "\n" + state))
2415
2416 errors = "\n".join(he.operation_errors)
2417 if errors:
2418 data.append(("Errors", "\n" + errors))
2419
2420 for field, value in data:
2421 msg("%15s: %s" % (_(field), value))
2422
2423 # Separate log entries with a blank line.
2424 msg("")
2425 else:
2426 msg("%-19s %-25s %-15s %s" % (start_time,
2427 he.operation_name, he.client_name, outcome))
2428
2429 return 0
2430
2431 # To allow exception handler access to the image.
2432 __img = None
2433
2434 def main_func():
2435 global_settings.client_name = PKG_CLIENT_NAME
2436
2437 global __img
2438 __img = img = image.Image()
2439
2440 misc.setlocale(locale.LC_ALL, "", error)
2441 gettext.install("pkg", "/usr/share/locale")
2442
2443 try:
2444 opts, pargs = getopt.getopt(sys.argv[1:], "R:D:?",
2445 ["debug=", "help"])
2446 except getopt.GetoptError, e:
2447 usage(_("illegal global option -- %s") % e.opt)
2448
2449 show_usage = False
2450 for opt, arg in opts:
2455 usage(_("%(opt)s takes argument of form "
2456 "name=value, not %(arg)s") % { "opt": opt,
2457 "arg": arg })
2458 DebugValues.set_value(key, value)
2459 elif opt == "-R":
2460 mydir = arg
2461 elif opt in ("--help", "-?"):
2462 show_usage = True
2463
2464 subcommand = None
2465 if pargs:
2466 subcommand = pargs.pop(0)
2467 if subcommand == "help":
2468 show_usage = True
2469
2470 if show_usage:
2471 usage(retcode=0)
2472 elif not subcommand:
2473 usage()
2474
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.
2480 global_settings.PKG_TIMEOUT_MAX = int(os.environ.get("PKG_TIMEOUT_MAX",
2481 global_settings.PKG_TIMEOUT_MAX))
2482
2483 if subcommand == "image-create":
2484 if "mydir" in locals():
2485 usage(_("-R not allowed for %s subcommand") %
2486 subcommand)
2487 try:
2488 ret = image_create(img, pargs)
2489 except getopt.GetoptError, e:
2490 usage(_("illegal %s option -- %s") % \
2491 (subcommand, e.opt))
2492 return ret
2493 elif subcommand == "version":
2494 if "mydir" in locals():
2495 usage(_("-R not allowed for %s subcommand") %
2496 subcommand)
2497 if pargs:
2498 usage(_("version: command does not take operands " \
2499 "('%s')") % " ".join(pargs))
2500 msg(pkg.VERSION)
2501 return 0
2502
2620 except SystemExit, __e:
2621 if __img:
2622 __img.history.abort(RESULT_FAILED_UNKNOWN)
2623 raise __e
2624 except (PipeError, KeyboardInterrupt):
2625 if __img:
2626 __img.history.abort(RESULT_CANCELED)
2627 # We don't want to display any messages here to prevent
2628 # possible further broken pipe (EPIPE) errors.
2629 __ret = 1
2630 except api_errors.CertificateError, __e:
2631 if __img:
2632 __img.history.abort(RESULT_FAILED_CONFIGURATION)
2633 error(__e)
2634 __ret = 1
2635 except api_errors.PublisherError, __e:
2636 if __img:
2637 __img.history.abort(RESULT_FAILED_BAD_REQUEST)
2638 error(__e)
2639 __ret = 1
2640 except misc.TransportException, __e:
2641 if __img:
2642 __img.history.abort(RESULT_FAILED_TRANSPORT)
2643 error(_("\nMaximum number of network retries exceeded during "
2644 "download. Details follow:\n%s") % __e)
2645 __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 except api_errors.InvalidDepotResponseException, __e:
2655 if __img:
2656 __img.history.abort(RESULT_FAILED_TRANSPORT)
2657 error(_("\nUnable to contact a valid package depot. "
2658 "This may be due to a problem with the server, "
2659 "network misconfiguration, or an incorrect pkg client "
2660 "configuration. Please check your network settings and "
2661 "attempt to contact the server using a web browser."))
2662 error(_("\nAdditional details:\n\n%s") % __e)
2663 __ret = 1
2664 except history.HistoryLoadException, __e:
2665 # Since a history related error occurred, discard all
2666 # information about the current operation(s) in progress.
2667 if __img:
2668 __img.history.clear()
2669 error(_("An error was encountered while attempting to load "
2670 "history information\nabout past client operations."))
2671 error(__e)
2672 __ret = 1
2673 except history.HistoryStoreException, __e:
2674 # Since a history related error occurred, discard all
2675 # information about the current operation(s) in progress.
2676 if __img:
2677 __img.history.clear()
2678 error(_("An error was encountered while attempting to store "
2679 "information about the\ncurrent operation in client "
2680 "history."))
2681 error(__e)
2682 __ret = 1
|
58 import urlparse
59
60 import pkg
61 import pkg.actions as actions
62 import pkg.client.api as api
63 import pkg.client.api_errors as api_errors
64 import pkg.client.bootenv as bootenv
65 import pkg.client.history as history
66 import pkg.client.image as image
67 import pkg.client.imagetypes as imgtypes
68 import pkg.client.progress as progress
69 import pkg.client.publisher as publisher
70 import pkg.fmri as fmri
71 import pkg.misc as misc
72
73 from pkg.client import global_settings
74 from pkg.client.debugvalues import DebugValues
75 from pkg.client.history import (RESULT_CANCELED, RESULT_FAILED_BAD_REQUEST,
76 RESULT_FAILED_CONFIGURATION, RESULT_FAILED_TRANSPORT, RESULT_FAILED_UNKNOWN,
77 RESULT_FAILED_OUTOFMEMORY)
78 from pkg.misc import EmptyI, msg, emsg, PipeError
79
80 CLIENT_API_VERSION = 15
81 PKG_CLIENT_NAME = "pkg"
82
83 def error(text, cmd=None):
84 """Emit an error message prefixed by the command name """
85
86 if cmd:
87 text = "%s: %s" % (cmd, text)
88 else:
89 # If we get passed something like an Exception, we can convert
90 # it down to a string.
91 text = str(text)
92
93 # If the message starts with whitespace, assume that it should come
94 # *before* the command-name prefix.
95 text_nows = text.lstrip()
96 ws = text[:len(text) - len(text_nows)]
97
554 raise RuntimeError("Catalog refresh failed during"
555 " image-update.")
556 if not stuff_to_do:
557 msg(_("No updates available for this image."))
558 return 0
559 except api_errors.InventoryException, e:
560 error(_("image-update failed (inventory exception):\n%s") % e)
561 return 1
562 except api_errors.CatalogRefreshException, e:
563 if display_catalog_failures(e) == 0:
564 if not noexecute:
565 return 1
566 else:
567 raise RuntimeError("Catalog refresh failed during"
568 " image-update.")
569 except api_errors.BEException, e:
570 error(_(e))
571 return 1
572 except (api_errors.CertificateError,
573 api_errors.PlanCreationException,
574 api_errors.PermissionsException), e:
575 # Prepend a newline because otherwise the exception will
576 # be printed on the same line as the spinner.
577 error("\n" + str(e))
578 return 1
579 except api_errors.IpkgOutOfDateException:
580 msg(_("WARNING: pkg(5) appears to be out of date, and should " \
581 "be updated before\nrunning image-update.\n"))
582 msg(_("Please update pkg(5) using 'pfexec pkg install " \
583 "SUNWipkg' and then retry\nthe image-update."))
584 return 1
585 except api_errors.ImageNotFoundException, e:
586 error(_("No image rooted at '%s'") % e.user_dir)
587 return 1
588 if noexecute:
589 return 0
590
591 ret_code = 0
592
593 # Exceptions which happen here are printed in the above level, with
594 # or without some extra decoration done here.
595 # XXX would be nice to kick the progress tracker.
596 try:
597 api_inst.prepare()
598 except api_errors.TransportError, e:
599 # move past the progress tracker line.
600 msg("\n")
601 if verbose:
602 e.verbose = True
603 raise e
604 except KeyboardInterrupt:
605 raise
606 except api_errors.PermissionsException, e:
607 # Prepend a newline because otherwise the exception will
608 # be printed on the same line as the spinner.
609 error("\n" + str(e))
610 return 1
611 except:
612 error(_("\nAn unexpected error happened while preparing for " \
613 "image-update:"))
614 raise
615
616 try:
617 api_inst.execute_plan()
618 except RuntimeError, e:
619 error(_("image-update failed: %s") % e)
620 ret_code = 1
621 except api_errors.ImageUpdateOnLiveImageException:
622 error(_("image-update cannot be done on live image"))
623 ret_code = 1
717 # caught while planning.
718 stuff_to_do, cre = api_inst.plan_install(pkg_list, filters,
719 refresh_catalogs, noexecute, verbose=verbose,
720 update_index=update_index)
721 if cre and not display_catalog_failures(cre):
722 raise RuntimeError("Catalog refresh failed during"
723 " install.")
724 if not stuff_to_do:
725 msg(_("No updates available for this image."))
726 return 0
727 except api_errors.CatalogRefreshException, e:
728 if display_catalog_failures(e) == 0:
729 if not noexecute:
730 return 1
731 else:
732 error(_("Catalog refresh failed during install."),
733 cmd="install")
734 return 1
735 except (api_errors.CertificateError,
736 api_errors.PlanCreationException,
737 api_errors.PermissionsException), e:
738 # Prepend a newline because otherwise the exception will
739 # be printed on the same line as the spinner.
740 error("\n" + str(e), cmd="install")
741 return 1
742 except api_errors.InventoryException, e:
743 error(_("install failed (inventory exception):\n%s") % e,
744 cmd="install")
745 return 1
746 except fmri.IllegalFmri, e:
747 error(e, cmd="install")
748 return 1
749
750 if noexecute:
751 return 0
752
753 # Exceptions which happen here are printed in the above level, with
754 # or without some extra decoration done here.
755 # XXX would be nice to kick the progress tracker.
756 try:
757 api_inst.prepare()
758 except api_errors.TransportError, e:
759 # move past the progress tracker line.
760 msg("\n")
761 if verbose:
762 e.verbose = True
763 raise e
764 except KeyboardInterrupt:
765 raise
766 except api_errors.PermissionsException, e:
767 # Prepend a newline because otherwise the exception will
768 # be printed on the same line as the spinner.
769 error("\n" + str(e))
770 return 1
771 except:
772 error(_("\nAn unexpected error happened while preparing for " \
773 "install:"))
774 raise
775
776 ret_code = 0
777
778 try:
779 api_inst.execute_plan()
780 except RuntimeError, e:
781 error(_("installation failed: %s") % e)
782 ret_code = 1
783 except api_errors.CorruptedIndexException, e:
861 error("""Cannot remove '%s' due to
862 the following packages that depend on it:""" % e[0])
863 for d in e[1]:
864 emsg(" %s" % d)
865 return 1
866 except (api_errors.PlanCreationException,
867 api_errors.PermissionsException), e:
868 # Prepend a newline because otherwise the exception will
869 # be printed on the same line as the spinner.
870 error("\n" + str(e))
871 return 1
872
873 if noexecute:
874 return 0
875
876 # Exceptions which happen here are printed in the above level, with
877 # or without some extra decoration done here.
878 # XXX would be nice to kick the progress tracker.
879 try:
880 api_inst.prepare()
881 except api_errors.TransportError, e:
882 # move past the progress tracker line.
883 msg("\n")
884 if verbose:
885 e.verbose = True
886 raise e
887 except api_errors.FileInUseException, e:
888 error("\n" + str(e))
889 return 1
890 except KeyboardInterrupt:
891 raise
892 except:
893 error(_("\nAn unexpected error happened while preparing for " \
894 "install:"))
895 raise
896
897 ret_code = 0
898
899 try:
900 api_inst.execute_plan()
901 except RuntimeError, e:
902 error(_("uninstallation failed: %s") % e)
903 ret_code = 1
904 except api_errors.CorruptedIndexException, e:
905 error(INCONSISTENT_INDEX_ERROR_MESSAGE)
906 ret_code = 1
917 ret_code = 1
918 except KeyboardInterrupt:
919 raise
920 except Exception, e:
921 error(_("An unexpected error happened during " \
922 "uninstallation: %s") % e)
923 raise
924
925 return ret_code
926
927 def freeze(img, args):
928 """Attempt to take package specified to FROZEN state, with given
929 restrictions. Package must have been in the INSTALLED state."""
930 return 0
931
932 def unfreeze(img, args):
933 """Attempt to return package specified to INSTALLED state from FROZEN
934 state."""
935 return 0
936
937 def __convert_output(a_str, match):
938 """Converts a string to a three tuple with the information to fill
939 the INDEX, ACTION, and VALUE columns.
940
941 The "a_str" parameter is the string representation of an action.
942
943 The "match" parameter is a string whose precise interpretation is given
944 below.
945
946 For most action types, match defines which attribute the query matched
947 with. For example, it states whether the basename or path attribute of
948 a file action matched the query. Attribute (set) actions are treated
949 differently because they only have one attribute, and many values
950 associated with that attribute. For those actions, the match parameter
951 states which value matched the query."""
952
953 a = actions.fromstr(a_str.rstrip())
954 if isinstance(a, actions.attribute.AttributeAction):
955 return a.attrs.get(a.key_attr), a.name, match
956 return match, a.name, a.attrs.get(a.key_attr)
980 "The problematic structure:%r") % (tup,))
981 return False
982 if first:
983 msg("%-10s %-9s %-25s %s" %
984 ("INDEX", "ACTION", "VALUE", "PACKAGE"))
985 try:
986 out1, out2, out3 = __convert_output(action, match)
987 except (actions.UnknownActionError,
988 actions.MalformedActionError), e:
989 error(_("The server returned a malformed action.\n%s") %
990 e)
991 return False
992 msg("%-10s %-9s %-25s %s" %
993 (out1, out2, out3,
994 fmri.PkgFmri(str(pfmri)).get_short_fmri()))
995 else:
996 pfmri = tup
997 if first:
998 msg("%s" % ("PACKAGE"))
999 pub_name = ''
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"):
1004 pub_name = " (%s)" % pub.prefix
1005 elif pub is not None and hasattr(pub, "uri"):
1006 pub_name = " (%s)" % pub.uri
1007 msg("%s%s" %
1008 (fmri.PkgFmri(str(pfmri)).get_short_fmri(), pub_name))
1009 return True
1010
1011 def search(img_dir, args):
1012 """Search for the given query."""
1013
1014 opts, pargs = getopt.getopt(args, "alprs:I")
1015
1016 local = remote = case_sensitive = False
1017 servers = []
1018 return_actions = True
1019 for opt, arg in opts:
1020 if opt == "-a":
1021 return_actions = True
1022 elif opt == "-l":
1023 local = True
1024 elif opt == "-p":
1025 return_actions = False
1026 elif opt == "-r":
1065
1066 try:
1067 if local:
1068 searches.append(api_inst.local_search(query))
1069 if remote:
1070 searches.append(api_inst.remote_search(query,
1071 servers=servers))
1072
1073 # By default assume we don't find anything.
1074 retcode = 1
1075
1076 for raw_value in itertools.chain(*searches):
1077 try:
1078 query_num, pub, (v, return_type, tmp) = \
1079 raw_value
1080 except ValueError, e:
1081 error(_("The server returned a malformed "
1082 "result:%r") % (raw_value,))
1083 bad_res = True
1084 continue
1085 ret = process_v_1_search(tmp, first,
1086 return_type, pub)
1087 good_res |= ret
1088 bad_res |= not ret
1089 first = False
1090 except (api_errors.IncorrectIndexFileHash,
1091 api_errors.InconsistentIndexException):
1092 error(_("The search index appears corrupted. Please "
1093 "rebuild the index with 'pkg rebuild-index'."))
1094 return 1
1095 except api_errors.ProblematicSearchServers, e:
1096 error(e)
1097 bad_res = True
1098 except api_errors.SlowSearchUsed, e:
1099 error(e)
1100 except (api_errors.IncorrectIndexFileHash,
1101 api_errors.InconsistentIndexException):
1102 error(_("The search index appears corrupted. Please "
1103 "rebuild the index with 'pkg rebuild-index'."))
1104 return 1
1575 else:
1576 msg(txt)
1577
1578 for pub, err in cre.failed:
1579 if isinstance(err, urllib2.HTTPError):
1580 emsg(" %s: %s - %s" % \
1581 (err.filename, err.code, err.msg))
1582 elif isinstance(err, urllib2.URLError):
1583 if err.args[0][0] == 8:
1584 emsg(" %s: %s" % \
1585 (urlparse.urlsplit(
1586 pub["origin"])[1].split(":")[0],
1587 err.args[0][1]))
1588 else:
1589 if isinstance(err.args[0], socket.timeout):
1590 emsg(" %s: %s" % \
1591 (pub["origin"], "timeout"))
1592 else:
1593 emsg(" %s: %s" % \
1594 (pub["origin"], err.args[0][1]))
1595 else:
1596 emsg(" ", err)
1597
1598 if cre.message:
1599 emsg(cre.message)
1600
1601 return succeeded
1602
1603 def publisher_refresh(img_dir, args):
1604 """Update metadata for the image's publishers."""
1605
1606 # XXX will need to show available content series for each package
1607 full_refresh = False
1608 opts, pargs = getopt.getopt(args, "", ["full"])
1609 for opt, arg in opts:
1610 if opt == "--full":
1611 full_refresh = True
1612
1613 try:
1614 api_inst = api.ImageInterface(img_dir, CLIENT_API_VERSION,
1615 get_tracker(), None, PKG_CLIENT_NAME)
1616 except api_errors.ImageNotFoundException, e:
1617 error(_("'%s' is not an install image") % e.user_dir)
1618 return 1
1619
1620 try:
1621 # The user explicitly requested this refresh, so set the
1622 # refresh to occur immediately.
1623 api_inst.refresh(full_refresh=full_refresh, immediate=True,
1624 pubs=pargs)
1625 except api_errors.PublisherError, e:
1626 error(e)
1627 error(_("'pkg publisher' will show a list of publishers."))
1628 return 1
1629 except (api_errors.PermissionsException), e:
1630 # Prepend a newline because otherwise the exception will
1631 # be printed on the same line as the spinner.
1632 error("\n" + str(e))
1633 return 1
1634 except api_errors.CatalogRefreshException, e:
1635 if display_catalog_failures(e) == 0:
1636 return 1
1637 else:
1638 return 3
1639 else:
1640 return 0
1641
1642 def publisher_set(img, img_dir, args):
1643 """pkg set-publisher [-Ped] [-k ssl_key] [-c ssl_cert] [--reset-uuid]
1644 [-O origin_url] [-m mirror to add] [-M mirror to remove]
1645 [--enable] [--disable] [--no-refresh] publisher"""
1646
1647 preferred = False
1648 ssl_key = None
1649 ssl_cert = None
2236 except OSError, e:
2237 # Ensure messages are displayed after the spinner.
2238 emsg("\n")
2239 error(_("cannot create image at %(image_dir)s: %(reason)s") %
2240 { "image_dir": image_dir, "reason": e.args[1] })
2241 return 1
2242 except api_errors.PermissionsException, e:
2243 # Ensure messages are displayed after the spinner.
2244 emsg("")
2245 error(e, cmd="image-create")
2246 return 1
2247 except api_errors.InvalidDepotResponseException, e:
2248 # Ensure messages are displayed after the spinner.
2249 emsg("\n")
2250 error(_("The URI '%(pub_url)s' does not appear to point to a "
2251 "valid pkg server.\nPlease check the server's "
2252 "address and client's network configuration."
2253 "\nAdditional details:\n\n%(error)s") %
2254 { "pub_url": pub_url, "error": e },
2255 cmd="image-create")
2256 print_proxy_config()
2257 return 1
2258 except api_errors.CatalogRefreshException, cre:
2259 # Ensure messages are displayed after the spinner.
2260 error("", cmd="image-create")
2261 if display_catalog_failures(cre) == 0:
2262 return 1
2263 else:
2264 return 3
2265 return 0
2266
2267
2268 def rebuild_index(img_dir, pargs):
2269 """pkg rebuild-index
2270
2271 Forcibly rebuild the search indexes. Will remove existing indexes
2272 and build new ones from scratch."""
2273 quiet = False
2274
2275 if pargs:
2276 usage(_("rebuild-index: command does not take operands " \
2376
2377 state = he.operation_end_state
2378 if state:
2379 data.append(("End State", "\n" + state))
2380
2381 errors = "\n".join(he.operation_errors)
2382 if errors:
2383 data.append(("Errors", "\n" + errors))
2384
2385 for field, value in data:
2386 msg("%15s: %s" % (_(field), value))
2387
2388 # Separate log entries with a blank line.
2389 msg("")
2390 else:
2391 msg("%-19s %-25s %-15s %s" % (start_time,
2392 he.operation_name, he.client_name, outcome))
2393
2394 return 0
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
2415 # To allow exception handler access to the image.
2416 __img = None
2417
2418 def main_func():
2419 global_settings.client_name = PKG_CLIENT_NAME
2420
2421 global __img
2422 __img = img = image.Image()
2423
2424 misc.setlocale(locale.LC_ALL, "", error)
2425 gettext.install("pkg", "/usr/share/locale")
2426
2427 try:
2428 opts, pargs = getopt.getopt(sys.argv[1:], "R:D:?",
2429 ["debug=", "help"])
2430 except getopt.GetoptError, e:
2431 usage(_("illegal global option -- %s") % e.opt)
2432
2433 show_usage = False
2434 for opt, arg in opts:
2439 usage(_("%(opt)s takes argument of form "
2440 "name=value, not %(arg)s") % { "opt": opt,
2441 "arg": arg })
2442 DebugValues.set_value(key, value)
2443 elif opt == "-R":
2444 mydir = arg
2445 elif opt in ("--help", "-?"):
2446 show_usage = True
2447
2448 subcommand = None
2449 if pargs:
2450 subcommand = pargs.pop(0)
2451 if subcommand == "help":
2452 show_usage = True
2453
2454 if show_usage:
2455 usage(retcode=0)
2456 elif not subcommand:
2457 usage()
2458
2459 # Override default PKG_TIMEOUT_MAX and PKG_CLIENT_TIMEOUT
2460 # if a value has been specified in the environment.
2461 global_settings.PKG_TIMEOUT_MAX = int(os.environ.get("PKG_TIMEOUT_MAX",
2462 global_settings.PKG_TIMEOUT_MAX))
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
2471 if subcommand == "image-create":
2472 if "mydir" in locals():
2473 usage(_("-R not allowed for %s subcommand") %
2474 subcommand)
2475 try:
2476 ret = image_create(img, pargs)
2477 except getopt.GetoptError, e:
2478 usage(_("illegal %s option -- %s") % \
2479 (subcommand, e.opt))
2480 return ret
2481 elif subcommand == "version":
2482 if "mydir" in locals():
2483 usage(_("-R not allowed for %s subcommand") %
2484 subcommand)
2485 if pargs:
2486 usage(_("version: command does not take operands " \
2487 "('%s')") % " ".join(pargs))
2488 msg(pkg.VERSION)
2489 return 0
2490
2608 except SystemExit, __e:
2609 if __img:
2610 __img.history.abort(RESULT_FAILED_UNKNOWN)
2611 raise __e
2612 except (PipeError, KeyboardInterrupt):
2613 if __img:
2614 __img.history.abort(RESULT_CANCELED)
2615 # We don't want to display any messages here to prevent
2616 # possible further broken pipe (EPIPE) errors.
2617 __ret = 1
2618 except api_errors.CertificateError, __e:
2619 if __img:
2620 __img.history.abort(RESULT_FAILED_CONFIGURATION)
2621 error(__e)
2622 __ret = 1
2623 except api_errors.PublisherError, __e:
2624 if __img:
2625 __img.history.abort(RESULT_FAILED_BAD_REQUEST)
2626 error(__e)
2627 __ret = 1
2628 except api_errors.TransportError, __e:
2629 if __img:
2630 __img.history.abort(RESULT_FAILED_TRANSPORT)
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()
2635 __ret = 1
2636 except api_errors.InvalidDepotResponseException, __e:
2637 if __img:
2638 __img.history.abort(RESULT_FAILED_TRANSPORT)
2639 emsg(_("\nUnable to contact a valid package depot. "
2640 "This may be due to a problem with the server, "
2641 "network misconfiguration, or an incorrect pkg client "
2642 "configuration. Please check your network settings and "
2643 "attempt to contact the server using a web browser."))
2644 emsg(_("\nAdditional details:\n\n%s") % __e)
2645 print_proxy_config()
2646 __ret = 1
2647 except history.HistoryLoadException, __e:
2648 # Since a history related error occurred, discard all
2649 # information about the current operation(s) in progress.
2650 if __img:
2651 __img.history.clear()
2652 error(_("An error was encountered while attempting to load "
2653 "history information\nabout past client operations."))
2654 error(__e)
2655 __ret = 1
2656 except history.HistoryStoreException, __e:
2657 # Since a history related error occurred, discard all
2658 # information about the current operation(s) in progress.
2659 if __img:
2660 __img.history.clear()
2661 error(_("An error was encountered while attempting to store "
2662 "information about the\ncurrent operation in client "
2663 "history."))
2664 error(__e)
2665 __ret = 1
|