5 # The contents of this file are subject to the terms of the
6 # Common Development and Distribution License (the "License").
7 # You may not use this file except in compliance with the License.
9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 # or http://www.opensolaris.org/os/licensing.
11 # See the License for the specific language governing permissions
12 # and limitations under the License.
14 # When distributing Covered Code, include this CDDL HEADER in each
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 # If applicable, add the following below this CDDL HEADER, with the
17 # fields enclosed by brackets "[]" replaced with your own identifying
18 # information: Portions Copyright [yyyy] [name of copyright owner]
24 # Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
30 import xml
.parsers
.expat
as expat
34 import pkg
.client
.pkgdefs
as pkgdefs
36 # EmptyI for argument defaults; can't import from misc due to circular
40 class ApiException(Exception):
41 def __init__(self
, *args
):
42 Exception.__init
__(self
)
43 self
.__verbose
_info
= []
45 def __unicode__(self
):
46 # To workaround python issues 6108 and 2517, this provides a
47 # a standard wrapper for this class' exceptions so that they
48 # have a chance of being stringified correctly.
49 return unicode(str(self
))
51 def add_verbose_info(self
, info
):
52 self
.__verbose
_info
.extend(info
)
55 def verbose_info(self
):
56 return self
.__verbose
_info
58 class SuidUnsupportedError(ApiException
):
61 The pkg client api module can not be invoked from an setuid executable.""")
64 class HistoryException(ApiException
):
65 """Private base exception class for all History exceptions."""
67 def __init__(self
, *args
):
68 Exception.__init
__(self
, *args
)
72 return str(self
.error
)
75 class HistoryLoadException(HistoryException
):
76 """Used to indicate that an unexpected error occurred while loading
77 History operation information.
79 The first argument should be an exception object related to the
82 def __init__(self
, *args
):
83 HistoryException
.__init
__(self
, *args
)
84 self
.parse_failure
= isinstance(self
.error
, expat
.ExpatError
)
87 class HistoryRequestException(HistoryException
):
88 """Used to indicate that invalid time / range values were provided to
89 history API functions."""
93 class HistoryStoreException(HistoryException
):
94 """Used to indicate that an unexpected error occurred while storing
95 History operation information.
97 The first argument should be an exception object related to the
103 class HistoryPurgeException(HistoryException
):
104 """Used to indicate that an unexpected error occurred while purging
105 History operation information.
107 The first argument should be an exception object related to the
113 class ImageLockedError(ApiException
):
114 """Used to indicate that the image is currently locked by another thread
115 or process and cannot be modified."""
117 def __init__(self
, hostname
=None, pid
=None, pid_name
=None):
118 ApiException
.__init
__(self
)
119 self
.hostname
= hostname
121 self
.pid_name
= pid_name
124 if self
.pid
is not None and self
.pid_name
is not None and \
125 self
.hostname
is not None:
126 return _("The image cannot be modified as it is "
127 "currently in use by another package client: "
128 "{pid_name} on {host}, pid {pid}.").format(
129 pid_name
=self
.pid_name
, pid
=self
.pid
,
131 if self
.pid
is not None and self
.pid_name
is not None:
132 return _("The image cannot be modified as it is "
133 "currently in use by another package client: "
134 "{pid_name} on an unknown host, pid {pid}.").format(
135 pid_name
=self
.pid_name
, pid
=self
.pid
)
136 elif self
.pid
is not None:
137 return _("The image cannot be modified as it is "
138 "currently in use by another package client: "
139 "pid {pid} on {host}.").format(
140 pid
=self
.pid
, host
=self
.hostname
)
141 return _("The image cannot be modified as it is currently "
142 "in use by another package client.")
144 class ImageNotFoundException(ApiException
):
145 """Used when an image was not found"""
146 def __init__(self
, user_specified
, user_dir
, root_dir
):
147 ApiException
.__init
__(self
)
148 self
.user_specified
= user_specified
149 self
.user_dir
= user_dir
150 self
.root_dir
= root_dir
153 return _("No image rooted at '{0}'").format(self
.user_dir
)
156 class ImageFormatUpdateNeeded(ApiException
):
157 """Used to indicate that an image cannot be used until its format is
160 def __init__(self
, path
):
161 ApiException
.__init
__(self
)
165 return _("The image rooted at {0} is written in an older format "
166 "and must be updated before the requested operation can be "
167 "performed.").format(self
.path
)
169 class ImageInsufficentSpace(ApiException
):
170 """Used when insuffcient space exists for proposed operation"""
171 def __init__(self
, needed
, avail
, use
):
177 from pkg
.misc
import bytes_to_str
178 return _("Insufficient disk space available ({avail}) "
179 "for estimated need ({needed}) for {use}").format(
180 avail
=bytes_to_str(self
.avail
),
181 needed
=bytes_to_str(self
.needed
),
186 class VersionException(ApiException
):
187 def __init__(self
, expected_version
, received_version
):
188 ApiException
.__init
__(self
)
189 self
.expected_version
= expected_version
190 self
.received_version
= received_version
193 class PlanExistsException(ApiException
):
194 def __init__(self
, plan_type
):
195 ApiException
.__init
__(self
)
196 self
.plan_type
= plan_type
199 class PlanPrepareException(ApiException
):
200 """Base exception class for plan preparation errors."""
204 class InvalidPackageErrors(ApiException
):
205 """Used to indicate that the requested operation could not be completed
206 as one or more packages contained invalid metadata."""
208 def __init__(self
, errors
):
209 """'errors' should be a list of exceptions or strings
210 indicating what packages had errors and why."""
212 ApiException
.__init
__(self
)
216 return _("The requested operation cannot be completed due "
217 "to invalid package metadata. Details follow:\n\n"
218 "{0}").format("\n".join(str(e
) for e
in self
.errors
))
221 class LicenseAcceptanceError(ApiException
):
222 """Used to indicate that license-related errors occurred during
223 plan evaluation or execution."""
225 def __init__(self
, pfmri
, src
=None, dest
=None, accepted
=None,
227 ApiException
.__init
__(self
)
231 self
.accepted
= accepted
232 self
.displayed
= displayed
235 class PkgLicenseErrors(PlanPrepareException
):
236 """Used to indicate that plan evaluation or execution failed due
237 to license-related errors for a package."""
239 def __init__(self
, errors
):
240 """'errors' should be a list of LicenseAcceptanceError
243 PlanPrepareException
.__init
__(self
)
244 self
.__errors
= errors
248 """A list of LicenseAcceptanceError exceptions."""
252 class PlanLicenseErrors(PlanPrepareException
):
253 """Used to indicate that image plan evaluation or execution failed due
254 to license-related errors."""
256 def __init__(self
, pp_errors
):
257 """'errors' should be a list of PkgLicenseErrors exceptions."""
259 PlanPrepareException
.__init
__(self
)
260 self
.__errors
= pkgs
= {}
261 for pp_err
in pp_errors
:
262 for e
in pp_err
.errors
:
263 pkgs
.setdefault(str(e
.fmri
), []).append(e
)
267 """Returns a dictionary indexed by package FMRI string of
268 lists of LicenseAcceptanceError exceptions."""
273 """Returns a string representation of the license errors."""
276 for sfmri
in self
.__errors
:
277 output
+= ("-" * 40) + "\n"
278 output
+= _("Package: {0}\n\n").format(sfmri
)
279 for e
in self
.__errors
[sfmri
]:
280 lic_name
= e
.dest
.attrs
["license"]
281 output
+= _("License: {0}\n").format(lic_name
)
282 if e
.dest
.must_accept
and not e
.accepted
:
283 output
+= _(" License requires "
285 if e
.dest
.must_display
and not e
.displayed
:
286 output
+= _(" License must be viewed.")
291 class ActuatorException(ApiException
):
292 def __init__(self
, e
):
293 ApiException
.__init
__(self
)
297 return str(self
.exception
)
300 class PrematureExecutionException(ApiException
):
304 class AlreadyPreparedException(PlanPrepareException
):
308 class AlreadyExecutedException(ApiException
):
312 class ImageplanStateException(ApiException
):
313 def __init__(self
, state
):
314 ApiException
.__init
__(self
)
318 class InvalidPlanError(ApiException
):
319 """Used to indicate that the image plan is no longer valid, likely as a
320 result of an image state change since the plan was created."""
323 return _("The plan for the current operation is no longer "
324 "valid. The image has likely been modified by another "
325 "process or client. Please try the operation again.")
328 class ImagePkgStateError(ApiException
):
330 def __init__(self
, fmri
, states
):
331 ApiException
.__init
__(self
)
336 return _("Invalid package state change attempted '{states}' "
337 "for package '{fmri}'.").format(states
=self
.states
,
341 class IpkgOutOfDateException(ApiException
):
343 return _("pkg(5) out of date")
346 class ImageUpdateOnLiveImageException(ApiException
):
348 return _("Requested operation cannot be performed "
352 class RebootNeededOnLiveImageException(ApiException
):
354 return _("Requested operation cannot be performed "
358 class CanceledException(ApiException
):
361 class PlanMissingException(ApiException
):
364 class NoPackagesInstalledException(ApiException
):
367 class PermissionsException(ApiException
):
368 def __init__(self
, path
):
369 ApiException
.__init
__(self
)
374 return _("Could not operate on {0}\nbecause of "
375 "insufficient permissions. Please try the "
376 "command again as a privileged user.").format(
380 Could not complete the operation because of insufficient permissions.
381 Please try the command again as a privileged user.
384 class FileInUseException(PermissionsException
):
385 def __init__(self
, path
):
386 PermissionsException
.__init
__(self
, path
)
390 return _("Could not operate on {0}\nbecause the file is "
391 "in use. Please stop using the file and try the\n"
392 "operation again.").format(self
.path
)
395 class UnprivilegedUserError(PermissionsException
):
396 def __init__(self
, path
):
397 PermissionsException
.__init
__(self
, path
)
400 return _("Insufficient access to complete the requested "
401 "operation.\nPlease try the operation again as a "
405 class ReadOnlyFileSystemException(PermissionsException
):
406 """Used to indicate that the operation was attempted on a
407 read-only filesystem"""
409 def __init__(self
, path
):
410 ApiException
.__init
__(self
)
415 return _("Could not complete the operation on {0}: "
416 "read-only filesystem.").format(self
.path
)
417 return _("Could not complete the operation: read-only "
421 class InvalidLockException(ApiException
):
422 def __init__(self
, path
):
423 ApiException
.__init
__(self
)
427 return _("Unable to obtain or operate on lock at {0}.\n"
428 "Please try the operation again as a privileged "
429 "user.").format(self
.path
)
432 class PackageMatchErrors(ApiException
):
433 """Used to indicate which patterns were not matched or illegal during
434 a package name matching operation."""
436 def __init__(self
, unmatched_fmris
=EmptyI
, multiple_matches
=EmptyI
,
437 illegal
=EmptyI
, multispec
=EmptyI
):
438 ApiException
.__init
__(self
)
439 self
.unmatched_fmris
= unmatched_fmris
440 self
.multiple_matches
= multiple_matches
441 self
.illegal
= illegal
442 self
.multispec
= multispec
446 if self
.unmatched_fmris
:
447 s
= _("The following pattern(s) did not match any "
451 res
+= ["\t{0}".format(p
) for p
in self
.unmatched_fmris
]
453 if self
.multiple_matches
:
454 s
= _("'{0}' matches multiple packages")
455 for p
, lst
in self
.multiple_matches
:
456 res
.append(s
.format(p
))
458 res
.append("\t{0}".format(pfmri
))
461 s
= _("'{0}' is an illegal FMRI")
462 res
+= [ s
.format(p
) for p
in self
.illegal
]
465 s
= _("The following different patterns specify the "
468 for t
in self
.multispec
:
470 ", ".join([t
[i
] for i
in range(1, len(t
))])
471 + ": {0}".format(t
[0])
474 return "\n".join(res
)
477 class PlanExecutionError(InvalidPlanError
):
478 """Used to indicate that the requested operation could not be executed
479 due to unexpected changes in image state after planning was completed.
482 def __init__(self
, paths
):
486 return _("The files listed below were modified after operation "
487 "planning was complete or were missing during plan "
488 "execution; this may indicate an administrative issue or "
489 "system configuration issue:\n{0}".format(
490 "\n".join(list(self
.paths
))))
493 class PlanCreationException(ApiException
):
495 already_installed
=EmptyI
,
499 invalid_mediations
=EmptyI
,
500 linked_pub_error
=EmptyI
,
501 missing_dependency
=EmptyI
,
502 missing_matches
=EmptyI
,
503 multiple_matches
=EmptyI
,
506 no_tmp_origins
=False,
511 pkg_updates_required
=EmptyI
,
512 rejected_pats
=EmptyI
,
513 solver_errors
=EmptyI
,
515 unmatched_fmris
=EmptyI
,
516 would_install
=EmptyI
,
517 wrong_publishers
=EmptyI
,
518 wrong_variants
=EmptyI
):
520 ApiException
.__init
__(self
)
521 self
.already_installed
= already_installed
522 self
.badarch
= badarch
523 self
.illegal
= illegal
524 self
.installed
= installed
525 self
.invalid_mediations
= invalid_mediations
526 self
.linked_pub_error
= linked_pub_error
527 self
.missing_dependency
= missing_dependency
528 self
.missing_matches
= missing_matches
529 self
.multiple_matches
= multiple_matches
530 self
.multispec
= multispec
531 self
.no_solution
= no_solution
532 self
.no_tmp_origins
= no_tmp_origins
533 self
.no_version
= no_version
534 self
.not_avoided
= not_avoided
535 self
.nofiles
= nofiles
536 self
.obsolete
= obsolete
537 self
.pkg_updates_required
= pkg_updates_required
538 self
.rejected_pats
= rejected_pats
539 self
.solver_errors
= solver_errors
540 self
.unmatched_fmris
= unmatched_fmris
541 self
.no_repo_pubs
= no_repo_pubs
542 self
.would_install
= would_install
543 self
.wrong_publishers
= wrong_publishers
544 self
.wrong_variants
= wrong_variants
548 if self
.unmatched_fmris
:
550 The following pattern(s) did not match any allowable packages. Try
551 using a different matching pattern, or refreshing publisher information:
554 res
+= ["\t{0}".format(p
) for p
in self
.unmatched_fmris
]
556 if self
.rejected_pats
:
558 The following pattern(s) only matched packages rejected by user request. Try
559 using a different matching pattern, or refreshing publisher information:
562 res
+= ["\t{0}".format(p
) for p
in self
.rejected_pats
]
564 if self
.wrong_variants
:
566 The following pattern(s) only matched packages that are not available
567 for the current image's architecture, zone type, and/or other variant:""")
569 res
+= ["\t{0}".format(p
) for p
in self
.wrong_variants
]
571 if self
.wrong_publishers
:
572 s
= _("The following patterns only matched packages "
573 "that are from publishers other than that which "
574 "supplied the already installed version of this package")
576 res
+= ["\t{0}: {1}".format(p
[0], ", ".join(p
[1])) for p
in self
.wrong_publishers
]
578 if self
.multiple_matches
:
579 s
= _("'{0}' matches multiple packages")
580 for p
, lst
in self
.multiple_matches
:
581 res
.append(s
.format(p
))
583 res
.append("\t{0}".format(pfmri
))
585 if self
.missing_matches
:
586 s
= _("'{0}' matches no installed packages")
587 res
+= [ s
.format(p
) for p
in self
.missing_matches
]
590 s
= _("'{0}' is an illegal fmri")
591 res
+= [ s
.format(p
) for p
in self
.illegal
]
594 s
= _("'{p}' supports the following architectures: "
596 a
= _("Image architecture is defined as: {0}")
597 res
+= [ s
.format(p
=self
.badarch
[0],
598 archs
=", ".join(self
.badarch
[1]))]
599 res
+= [ a
.format(self
.badarch
[2])]
601 s
= _("'{p}' depends on obsolete package '{op}'")
602 res
+= [ s
.format(p
=p
, op
=op
) for p
, op
in self
.obsolete
]
605 s
= _("The proposed operation can not be performed for "
606 "the following package(s) as they are already "
609 res
+= ["\t{0}".format(p
) for p
in self
.installed
]
611 if self
.invalid_mediations
:
612 s
= _("The following mediations are not syntactically "
614 for m
, entries
in self
.invalid_mediations
.iteritems():
615 for value
, error
in entries
.values():
619 s
= _("The following patterns specify different "
620 "versions of the same package(s):")
622 for t
in self
.multispec
:
625 [t
[i
] for i
in range(1, len(t
))])
626 + ": {0}".format(t
[0])
629 res
+= [_("No solution was found to satisfy constraints")]
630 if isinstance(self
.no_solution
, list):
631 res
.extend(self
.no_solution
)
633 if self
.pkg_updates_required
:
635 Syncing this linked image would require the following package updates:
638 for (oldfmri
, newfmri
) in self
.pkg_updates_required
:
639 res
+= ["{oldfmri} -> {newfmri}\n".format(
640 oldfmri
=oldfmri
, newfmri
=newfmri
)]
643 res
+= self
.no_version
645 if self
.no_tmp_origins
:
647 The proposed operation on this parent image can not be performed because
648 temporary origins were specified and this image has children. Please either
649 retry the operation again without specifying any temporary origins, or if
650 packages from additional origins are required, please configure those origins
654 if self
.missing_dependency
:
655 res
+= [_("Package {pkg} is missing a dependency: "
657 pkg
=self
.missing_dependency
[0],
658 dep
=self
.missing_dependency
[1])]
660 res
+= [_("The following files are not packaged in this image:")]
661 res
+= ["\t{0}".format(f
) for f
in self
.nofiles
]
663 if self
.solver_errors
:
665 res
+= [_("Solver dependency errors:")]
666 res
.extend(self
.solver_errors
)
668 if self
.already_installed
:
669 res
+= [_("The following packages are already "
670 "installed in this image; use uninstall to "
672 res
+= [ "\t{0}".format(s
) for s
in self
.already_installed
]
674 if self
.would_install
:
675 res
+= [_("The following packages are a target "
676 "of group dependencies; use install to unavoid "
678 res
+= [ "\t{0}".format(s
) for s
in self
.would_install
]
681 res
+= [_("The following packages are not on the "
682 "avoid list, so they\ncannot be removed from it.")]
683 res
+= [ "\t{0}".format(s
) for s
in sorted(self
.not_avoided
)]
685 def __format_li_pubs(pubs
, res
):
687 for pub
, sticky
in pubs
:
688 s
= " {0} {1:d}: {2}".format(_("PUBLISHER"),
692 mod
.append(_("non-sticky"))
694 s
+= " ({0})".format(",".join(mod
))
698 if self
.linked_pub_error
:
700 (pubs
, parent_pubs
) = self
.linked_pub_error
703 Invalid child image publisher configuration. Child image publisher
704 configuration must be a superset of the parent image publisher configuration.
705 Please update the child publisher configuration to match the parent. If the
706 child image is a zone this can be done automatically by detaching and
709 The parent image has the following enabled publishers:"""))
710 __format_li_pubs(parent_pubs
, res
)
712 The child image has the following enabled publishers:"""))
713 __format_li_pubs(pubs
, res
)
715 if self
.no_repo_pubs
:
716 res
+= [_("The following publishers do not have any "
717 "configured package repositories and cannot be "
718 "used in package dehydration or rehydration "
720 res
+= ["\t{0}".format(s
) for s
in sorted(
723 return "\n".join(res
)
726 class ConflictingActionError(ApiException
):
727 """Used to indicate that the imageplan would result in one or more sets
728 of conflicting actions, meaning that more than one action would exist on
729 the system with the same key attribute value in the same namespace.
730 There are three categories, each with its own subclass:
732 - multiple files delivered to the same path or drivers, users, groups,
733 etc, delivered with the same key attribute;
735 - multiple objects delivered to the same path which aren't the same
738 - multiple directories, links, or hardlinks delivered to the same path
739 but with conflicting attributes.
742 def __init__(self
, data
):
745 class ConflictingActionErrors(ApiException
):
746 """A container for multiple ConflictingActionError exception objects
747 that can be raised as a single exception."""
749 def __init__(self
, errors
):
750 self
.__errors
= errors
753 return "\n\n".join((str(err
) for err
in self
.__errors
))
755 class DuplicateActionError(ConflictingActionError
):
756 """Multiple actions of the same type have been delivered with the same
757 key attribute (when not allowed)."""
760 pfmris
= set((a
[1] for a
in self
._data
))
761 kv
= self
._data
[0][0].attrs
[self
._data
[0][0].key_attr
]
762 action
= self
._data
[0][0].name
764 s
= _("The following packages all deliver {action} "
765 "actions to {kv}:\n").format(**locals())
766 for a
, p
in self
._data
:
767 s
+= "\n {0}".format(p
)
768 s
+= _("\n\nThese packages may not be installed together. "
769 "Any non-conflicting set may\nbe, or the packages "
770 "must be corrected before they can be installed.")
773 s
= _("The package {pfmri} delivers multiple copies "
774 "of {action} {kv}").format(**locals())
775 s
+= _("\nThis package must be corrected before it "
780 class InconsistentActionTypeError(ConflictingActionError
):
781 """Multiple actions of different types have been delivered with the same
782 'path' attribute. While this exception could represent other action
783 groups which share a single namespace, none such exist."""
788 kv
= self
._data
[0][0].attrs
[self
._data
[0][0].key_attr
]
789 for a
, p
in self
._data
:
790 ad
.setdefault(a
.name
, []).append(p
)
794 s
= _("The following packages deliver conflicting "
795 "action types to {0}:\n").format(kv
)
796 for name
, pl
in ad
.iteritems():
797 s
+= "\n {0}:".format(name
)
798 s
+= "".join("\n {0}".format(p
) for p
in pl
)
799 s
+= _("\n\nThese packages may not be installed together. "
800 "Any non-conflicting set may\nbe, or the packages "
801 "must be corrected before they can be installed.")
804 types
= list_to_lang(ad
.keys())
805 s
= _("The package {pfmri} delivers conflicting "
806 "action types ({types}) to {kv}").format(**locals())
807 s
+= _("\nThis package must be corrected before it "
811 class InconsistentActionAttributeError(ConflictingActionError
):
812 """Multiple actions of the same type representing the same object have
813 have been delivered, but with conflicting attributes, such as two
814 directories at /usr with groups 'root' and 'sys', or two 'root' users
815 with uids '0' and '7'."""
819 keyattr
= actions
[0][0].attrs
[actions
[0][0].key_attr
]
820 actname
= actions
[0][0].name
822 # Trim the action's attributes to only those required to be
827 for k
, v
in action
.attrs
.iteritems()
828 if ((k
in action
.unique_attrs
and
829 not (k
== "preserve" and "overlay" in action
.attrs
)) or
830 ((action
.name
== "link" or action
.name
== "hardlink") and
831 k
.startswith("mediator")))
838 if a
[0].attrs
.get("implicit", "false") == "false":
839 d
.setdefault(str(ou(a
[0])), set()).add(a
[1])
841 (len(pkglist
), action
, pkglist
)
842 for action
, pkglist
in d
.iteritems()
845 s
= _("The requested change to the system attempts to install "
846 "multiple actions\nfor {a} '{k}' with conflicting "
847 "attributes:\n\n").format(a
=actname
, k
=keyattr
)
849 for num
, action
, pkglist
in l
:
850 allpkgs
.update(pkglist
)
853 t
= _(" {n:d} package delivers '{a}':\n")
855 t
= _(" {n:d} packages deliver '{a}':\n")
856 s
+= t
.format(n
=num
, a
=action
)
857 for pkg
in sorted(pkglist
):
858 s
+= _(" {0}\n").format(pkg
)
860 t
= _(" {n:d} packages deliver '{a}', including:\n")
861 s
+= t
.format(n
=num
, a
=action
)
862 for pkg
in sorted(pkglist
)[:5]:
863 s
+= _(" {0}\n").format(pkg
)
865 if len(allpkgs
) == 1:
866 s
+= _("\nThis package must be corrected before it "
869 s
+= _("\nThese packages may not be installed together."
870 " Any non-conflicting set may\nbe, or the packages "
871 "must be corrected before they can be installed.")
876 """Takes a list of items and puts them into a string, with commas in
877 between items, and an "and" between the last two items. Special cases
878 for lists of two or fewer items, and uses the Oxford comma."""
885 # Used for a two-element list
886 return _("{penultimate} and {ultimate}").format(
890 # In order to properly i18n this construct, we create two templates:
891 # one for each element save the last, and one that tacks on the last
893 # 'elementtemplate' is for each element through the penultimate
894 elementtemplate
= _("{0}, ")
895 # 'listtemplate' concatenates the concatenation of non-ultimate elements
896 # and the ultimate element.
897 listtemplate
= _("{list}and {tail}")
898 return listtemplate
.format(
899 list="".join(elementtemplate
.format(i
) for i
in l
[:-1]),
903 class ActionExecutionError(ApiException
):
904 """Used to indicate that action execution (such as install, remove,
905 etc.) failed even though the action is valid.
907 In particular, this exception indicates that something went wrong in the
908 application (or unapplication) of the action to the system, and is most
909 likely not an error in the pkg(5) code."""
911 def __init__(self
, action
, details
=None, error
=None, fmri
=None,
913 """'action' is the object for the action that failed during the
916 'details' is an optional message explaining what operation
917 failed, why it failed, and why it cannot continue. It should
918 also include a suggestion as to how to resolve the situation
921 'error' is an optional exception object that may have been
922 raised when the operation failed.
924 'fmri' is an optional package FMRI indicating what package
925 was being operated on at the time the error occurred.
927 'use_errno' is an optional boolean value indicating whether
928 the strerror() text of the exception should be used. If
929 'details' is provided, the default value is False, otherwise
932 assert (details
or error
)
934 self
.details
= details
937 if use_errno
== None:
938 # If details were provided, don't use errno unless
939 # explicitly requested.
940 use_errno
= not details
941 self
.use_errno
= use_errno
945 if self
.use_errno
and self
.error
and \
946 hasattr(self
.error
, "errno"):
947 errno
= "[errno {0:d}: {1}]".format(self
.error
.errno
,
948 os
.strerror(self
.error
.errno
))
950 details
= self
.details
or ""
952 # Fall back on the wrapped exception if we don't have anything
954 if not errno
and not details
:
955 return str(self
.error
)
957 if errno
and details
:
958 details
= "{0}: {1}".format(errno
, details
)
960 if details
and not self
.fmri
:
961 details
= _("Requested operation failed for action "
962 "{action}:\n{details}").format(
966 details
= _("Requested operation failed for package "
967 "{fmri}:\n{details}").format(fmri
=self
.fmri
,
970 # If we only have one of the two, no need for the colon.
971 return "{0}{1}".format(errno
, details
)
974 class CatalogRefreshException(ApiException
):
975 def __init__(self
, failed
, total
, succeeded
, errmessage
=None):
976 ApiException
.__init
__(self
)
979 self
.succeeded
= succeeded
980 self
.errmessage
= errmessage
983 class CatalogError(ApiException
):
984 """Base exception class for all catalog exceptions."""
986 def __init__(self
, *args
, **kwargs
):
987 ApiException
.__init
__(self
)
995 return str(self
.data
)
998 class AnarchicalCatalogFMRI(CatalogError
):
999 """Used to indicate that the specified FMRI is not valid for catalog
1000 operations because it is missing publisher information."""
1003 return _("The FMRI '{0}' does not contain publisher information "
1004 "and cannot be used for catalog operations.").format(
1008 class BadCatalogMetaRoot(CatalogError
):
1009 """Used to indicate an operation on the catalog's meta_root failed
1010 because the meta_root is invalid."""
1013 return _("Catalog meta_root '{root}' is invalid; unable "
1014 "to complete operation: '{op}'.").format(root
=self
.data
,
1015 op
=self
._args
.get("operation", None))
1018 class BadCatalogPermissions(CatalogError
):
1019 """Used to indicate the server catalog files do not have the expected
1022 def __init__(self
, files
):
1023 """files should contain a list object with each entry consisting
1024 of a tuple of filename, expected_mode, received_mode."""
1027 CatalogError
.__init
__(self
, files
)
1030 msg
= _("The following catalog files have incorrect "
1033 fname
, emode
, fmode
= f
1034 msg
+= _("\t{fname}: expected mode: {emode}, found "
1035 "mode: {fmode}\n").format(fname
=fname
,
1036 emode
=emode
, fmode
=fmode
)
1040 class BadCatalogSignatures(CatalogError
):
1041 """Used to indicate that the Catalog signatures are not valid."""
1044 return _("The signature data for the '{0}' catalog file is not "
1045 "valid.").format(self
.data
)
1048 class BadCatalogUpdateIdentity(CatalogError
):
1049 """Used to indicate that the requested catalog updates could not be
1050 applied as the new catalog data is significantly different such that
1051 the old catalog cannot be updated to match it."""
1054 return _("Unable to determine the updates needed for "
1055 "the current catalog using the provided catalog "
1056 "update data in '{0}'.").format(self
.data
)
1059 class DuplicateCatalogEntry(CatalogError
):
1060 """Used to indicate that the specified catalog operation could not be
1061 performed since it would result in a duplicate catalog entry."""
1064 return _("Unable to perform '{op}' operation for catalog "
1065 "{name}; completion would result in a duplicate entry "
1066 "for package '{fmri}'.").format(op
=self
._args
.get(
1067 "operation", None), name
=self
._args
.get("catalog_name",
1068 None), fmri
=self
.data
)
1071 class CatalogUpdateRequirements(CatalogError
):
1072 """Used to indicate that an update request for the catalog could not
1073 be performed because update requirements were not satisfied."""
1076 return _("Catalog updates can only be applied to an on-disk "
1080 class InvalidCatalogFile(CatalogError
):
1081 """Used to indicate a Catalog file could not be loaded."""
1084 return _("Catalog file '{0}' is invalid.\nUse 'pkgrepo rebuild' "
1085 "to create a new package catalog.").format(self
.data
)
1088 class MismatchedCatalog(CatalogError
):
1089 """Used to indicate that a Catalog's attributes and parts do not
1090 match. This is likely the result of an attributes file being
1091 retrieved which doesn't match the parts that were retrieved such
1092 as in a misconfigured or stale cache case."""
1095 return _("The content of the catalog for publisher '{0}' "
1096 "doesn't match the catalog's attributes. This is "
1097 "likely the result of a mix of older and newer "
1098 "catalog files being provided for the publisher.").format(
1102 class ObsoleteCatalogUpdate(CatalogError
):
1103 """Used to indicate that the specified catalog updates are for an older
1104 version of the catalog and cannot be applied."""
1107 return _("Unable to determine the updates needed for the "
1108 "catalog using the provided catalog update data in '{0}'. "
1109 "The specified catalog updates are for an older version "
1110 "of the catalog and cannot be used.").format(self
.data
)
1113 class UnknownCatalogEntry(CatalogError
):
1114 """Used to indicate that an entry for the specified package FMRI or
1115 pattern could not be found in the catalog."""
1118 return _("'{0}' could not be found in the catalog.").format(
1122 class UnknownUpdateType(CatalogError
):
1123 """Used to indicate that the specified CatalogUpdate operation is
1127 return _("Unknown catalog update type '{0}'").format(self
.data
)
1130 class UnrecognizedCatalogPart(CatalogError
):
1131 """Raised when the catalog finds a CatalogPart that is unrecognized
1135 return _("Unrecognized, unknown, or invalid CatalogPart '{0}'").format(
1139 class InventoryException(ApiException
):
1140 """Used to indicate that some of the specified patterns to a catalog
1141 matching function did not match any catalog entries, or were invalid
1144 def __init__(self
, illegal
=EmptyI
, matcher
=EmptyI
, notfound
=EmptyI
,
1145 publisher
=EmptyI
, version
=EmptyI
):
1146 ApiException
.__init
__(self
)
1147 self
.illegal
= illegal
1148 self
.matcher
= matcher
1149 self
.notfound
= set(notfound
)
1150 self
.publisher
= publisher
1151 self
.version
= version
1153 self
.notfound
.update(matcher
)
1154 self
.notfound
.update(publisher
)
1155 self
.notfound
.update(version
)
1156 self
.notfound
= sorted(list(self
.notfound
))
1158 assert self
.illegal
or self
.notfound
1162 for x
in self
.illegal
:
1163 # Illegal FMRIs have their own __str__ method
1164 outstr
+= "{0}\n".format(x
)
1166 if self
.matcher
or self
.publisher
or self
.version
:
1167 outstr
+= _("No matching package could be found for "
1168 "the following FMRIs in any of the catalogs for "
1169 "the current publishers:\n")
1171 for x
in self
.matcher
:
1173 _("{0} (pattern did not match)\n").format(x
)
1174 for x
in self
.publisher
:
1175 outstr
+= _("{0} (publisher did not "
1176 "match)\n").format(x
)
1177 for x
in self
.version
:
1179 _("{0} (version did not match)\n").format(x
)
1185 class SearchException(ApiException
):
1186 """Based class used for all search-related api exceptions."""
1190 class MalformedSearchRequest(SearchException
):
1191 """Raised when the server cannot understand the format of the
1194 def __init__(self
, url
):
1195 SearchException
.__init
__(self
)
1199 return str(self
.url
)
1202 class NegativeSearchResult(SearchException
):
1203 """Returned when the search cannot find any matches."""
1205 def __init__(self
, url
):
1206 SearchException
.__init
__(self
)
1210 return _("The search at url {0} returned no results.").format(
1214 class ProblematicSearchServers(SearchException
):
1215 """This class wraps exceptions which could appear while trying to
1216 do a search request."""
1218 def __init__(self
, failed
=EmptyI
, invalid
=EmptyI
, unsupported
=EmptyI
):
1219 SearchException
.__init
__(self
)
1220 self
.failed_servers
= failed
1221 self
.invalid_servers
= invalid
1222 self
.unsupported_servers
= unsupported
1225 s
= _("Some repositories failed to respond appropriately:\n")
1226 for pub
, err
in self
.failed_servers
:
1227 s
+= _("{o}:\n{msg}\n").format(
1229 for pub
in self
.invalid_servers
:
1230 s
+= _("{0} did not return a valid "
1231 "response.\n".format(pub
))
1232 if len(self
.unsupported_servers
) > 0:
1233 s
+= _("Some repositories don't support requested "
1234 "search operation:\n")
1235 for pub
, err
in self
.unsupported_servers
:
1236 s
+= _("{o}:\n{msg}\n").format(
1242 class SlowSearchUsed(SearchException
):
1243 """This exception is thrown when a local search is performed without
1244 an index. It's raised after all results have been yielded."""
1247 return _("Search performance is degraded.\n"
1248 "Run 'pkg rebuild-index' to improve search speed.")
1251 class UnsupportedSearchError(SearchException
):
1252 """Returned when a search protocol is not supported by the
1255 def __init__(self
, url
=None, proto
=None):
1256 SearchException
.__init
__(self
)
1261 s
= _("Search repository does not support the requested "
1264 s
+= "\nRepository URL: {0}".format(self
.url
)
1266 s
+= "\nRequested operation: {0}".format(self
.proto
)
1269 def __cmp__(self
, other
):
1270 if not isinstance(other
, UnsupportedSearchError
):
1272 r
= cmp(self
.url
, other
.url
)
1275 return cmp(self
.proto
, other
.proto
)
1278 # IndexingExceptions.
1280 class IndexingException(SearchException
):
1281 """ The base class for all exceptions that can occur while indexing. """
1283 def __init__(self
, private_exception
):
1284 SearchException
.__init
__(self
)
1285 self
.cause
= private_exception
.cause
1288 class CorruptedIndexException(IndexingException
):
1289 """This is used when the index is not in a correct state."""
1291 return _("The search index appears corrupted.")
1294 class InconsistentIndexException(IndexingException
):
1295 """This is used when the existing index is found to have inconsistent
1297 def __init__(self
, e
):
1298 IndexingException
.__init
__(self
, e
)
1302 return str(self
.exception
)
1305 class IndexLockedException(IndexingException
):
1306 """This is used when an attempt to modify an index locked by another
1307 process or thread is made."""
1309 def __init__(self
, e
):
1310 IndexingException
.__init
__(self
, e
)
1314 return str(self
.exception
)
1317 class ProblematicPermissionsIndexException(IndexingException
):
1318 """ This is used when the indexer is unable to create, move, or remove
1319 files or directories it should be able to. """
1321 return "Could not remove or create " \
1322 "{0} because of incorrect " \
1323 "permissions. Please correct this issue then " \
1324 "rebuild the index.".format(self
.cause
)
1326 class WrapIndexingException(ApiException
):
1327 """This exception is used to wrap an indexing exception during install,
1328 uninstall, or update so that a more appropriate error message can be
1329 displayed to the user."""
1331 def __init__(self
, e
, tb
, stack
):
1332 ApiException
.__init
__(self
)
1338 tmp
= self
.tb
.split("\n")
1339 res
= tmp
[:1] + [s
.rstrip("\n") for s
in self
.stack
] + tmp
[1:]
1340 return "\n".join(res
)
1343 class WrapSuccessfulIndexingException(WrapIndexingException
):
1344 """This exception is used to wrap an indexing exception during install,
1345 uninstall, or update which was recovered from by performing a full
1350 # Query Parsing Exceptions
1351 class BooleanQueryException(ApiException
):
1352 """This exception is used when the children of a boolean operation
1353 have different return types. The command 'pkg search foo AND <bar>'
1354 is the simplest example of this."""
1356 def __init__(self
, e
):
1357 ApiException
.__init
__(self
)
1364 class ParseError(ApiException
):
1365 def __init__(self
, e
):
1366 ApiException
.__init
__(self
)
1373 class NonLeafPackageException(ApiException
):
1374 """Removal of a package which satisfies dependencies has been attempted.
1376 The first argument to the constructor is the FMRI which we tried to
1377 remove, and is available as the "fmri" member of the exception. The
1378 second argument is the list of dependent packages that prevent the
1379 removal of the package, and is available as the "dependents" member.
1382 def __init__(self
, *args
):
1383 ApiException
.__init
__(self
, *args
)
1386 self
.dependents
= args
[1]
1389 s
= _("Unable to remove '{0}' due to the following packages "
1390 "that depend on it:\n").format(self
.fmri
.get_short_fmri(
1391 anarchy
=True, include_scheme
=False))
1392 skey
= operator
.attrgetter('pkg_name')
1394 " {0}".format(f
.get_short_fmri(anarchy
=True,
1395 include_scheme
=False))
1396 for f
in sorted(self
.dependents
, key
=skey
)
1400 def _str_autofix(self
):
1402 if getattr(self
, "_autofix_pkgs", []):
1403 s
= _("\nThis is happening because the following "
1404 "packages needed to be repaired as\npart of this "
1406 s
+= "\n ".join(str(f
) for f
in self
._autofix
_pkgs
)
1407 s
+= _("\n\nYou will need to reestablish your access to the "
1408 "repository or remove the\npackages in the list above.")
1412 class InvalidDepotResponseException(ApiException
):
1413 """Raised when the depot doesn't have versions of operations
1414 that the client needs to operate successfully."""
1415 def __init__(self
, url
, data
):
1416 ApiException
.__init
__(self
)
1421 s
= _("Unable to contact valid package repository")
1423 s
+= _(": {0}").format(self
.url
)
1425 s
+= ("\nEncountered the following error(s):\n{0}").format(
1428 s
+= _str_autofix(self
)
1432 class DataError(ApiException
):
1433 """Base exception class used for all data related errors."""
1435 def __init__(self
, *args
, **kwargs
):
1436 ApiException
.__init
__(self
, *args
)
1444 class InvalidP5IFile(DataError
):
1445 """Used to indicate that the specified location does not contain a
1446 valid p5i-formatted file."""
1450 return _("The provided p5i data is in an unrecognized "
1451 "format or does not contain valid publisher "
1452 "information: {0}").format(self
.data
)
1453 return _("The provided p5i data is in an unrecognized format "
1454 "or does not contain valid publisher information.")
1457 class InvalidP5SFile(DataError
):
1458 """Used to indicate that the specified location does not contain a
1459 valid p5i-formatted file."""
1463 return _("The provided p5s data is in an unrecognized "
1464 "format or does not contain valid publisher "
1465 "information: {0}").format(self
.data
)
1466 return _("The provided p5s data is in an unrecognized format "
1467 "or does not contain valid publisher information.")
1470 class UnsupportedP5IFile(DataError
):
1471 """Used to indicate that an attempt to read an unsupported version
1472 of pkg(5) info file was attempted."""
1475 return _("Unsupported pkg(5) publisher information data "
1479 class UnsupportedP5SFile(DataError
):
1480 """Used to indicate that an attempt to read an unsupported version
1481 of pkg(5) info file was attempted."""
1484 return _("Unsupported pkg(5) publisher and image information "
1488 class UnsupportedP5SVersion(ApiException
):
1489 """Used to indicate that an attempt to read an unsupported version
1490 of pkg(5) info file was attempted."""
1492 def __init__(self
, v
):
1496 return _("{0} is not a supported version for creating a "
1497 "syspub response.").format(self
.version
)
1500 class TransportError(ApiException
):
1501 """Abstract exception class for all transport exceptions.
1502 Specific transport exceptions should be implemented in the
1503 transport code. Callers wishing to catch transport exceptions
1504 should use this class. Subclasses must implement all methods
1505 defined here that raise NotImplementedError."""
1508 raise NotImplementedError()
1510 def _str_autofix(self
):
1511 return _str_autofix(self
)
1514 class RetrievalError(ApiException
):
1515 """Used to indicate that a a requested resource could not be
1518 def __init__(self
, data
, location
=None):
1519 ApiException
.__init
__(self
)
1521 self
.location
= location
1525 return _("Error encountered while retrieving data from "
1526 "'{location}':\n{data}").format(
1527 location
=self
.location
, data
=self
.data
)
1528 return _("Error encountered while retrieving data from: {0}").format(
1532 class InvalidResourceLocation(ApiException
):
1533 """Used to indicate that an invalid transport location was provided."""
1535 def __init__(self
, data
):
1536 ApiException
.__init
__(self
)
1540 return _("'{0}' is not a valid location.").format(self
.data
)
1542 class BEException(ApiException
):
1544 ApiException
.__init
__(self
)
1546 class InvalidBENameException(BEException
):
1547 def __init__(self
, be_name
):
1548 BEException
.__init
__(self
)
1549 self
.be_name
= be_name
1552 return _("'{0}' is not a valid boot environment name.").format(
1555 class DuplicateBEName(BEException
):
1556 """Used to indicate that there is an existing boot environment
1559 def __init__(self
, be_name
):
1560 BEException
.__init
__(self
)
1561 self
.be_name
= be_name
1564 return _("The boot environment '{0}' already exists.").format(
1567 class BENamingNotSupported(BEException
):
1568 def __init__(self
, be_name
):
1569 BEException
.__init
__(self
)
1570 self
.be_name
= be_name
1574 Boot environment naming during package install is not supported on this
1575 version of OpenSolaris. Please update without the --be-name option.""")
1577 class UnableToCopyBE(BEException
):
1579 return _("Unable to clone the current boot environment.")
1581 class UnableToRenameBE(BEException
):
1582 def __init__(self
, orig
, dest
):
1583 BEException
.__init
__(self
)
1584 self
.original_name
= orig
1585 self
.destination_name
= dest
1589 "orig": self
.original_name
,
1590 "dest": self
.destination_name
1593 A problem occurred while attempting to rename the boot environment
1594 currently named {orig} to {dest}.""").format(**d
)
1596 class UnableToMountBE(BEException
):
1597 def __init__(self
, be_name
, be_dir
):
1598 BEException
.__init
__(self
)
1600 self
.mountpoint
= be_dir
1603 return _("Unable to mount {name} at {mt}").format(
1604 name
=self
.name
, mt
=self
.mountpoint
)
1606 class BENameGivenOnDeadBE(BEException
):
1607 def __init__(self
, be_name
):
1608 BEException
.__init
__(self
)
1613 Naming a boot environment when operating on a non-live image is
1617 class UnrecognizedOptionsToInfo(ApiException
):
1618 def __init__(self
, opts
):
1619 ApiException
.__init
__(self
)
1623 s
= _("Info does not recognize the following options:")
1624 for o
in self
._opts
:
1625 s
+= _(" '") + str(o
) + _("'")
1628 class IncorrectIndexFileHash(ApiException
):
1629 """This is used when the index hash value doesn't match the hash of the
1630 packages installed in the image."""
1634 class PublisherError(ApiException
):
1635 """Base exception class for all publisher exceptions."""
1637 def __init__(self
, *args
, **kwargs
):
1638 ApiException
.__init
__(self
, *args
)
1646 return str(self
.data
)
1649 class BadPublisherMetaRoot(PublisherError
):
1650 """Used to indicate an operation on the publisher's meta_root failed
1651 because the meta_root is invalid."""
1654 return _("Publisher meta_root '{root}' is invalid; unable "
1655 "to complete operation: '{op}'.").format(root
=self
.data
,
1656 op
=self
._args
.get("operation", None))
1659 class BadPublisherAlias(PublisherError
):
1660 """Used to indicate that a publisher alias is not valid."""
1663 return _("'{0}' is not a valid publisher alias.").format(
1667 class BadPublisherPrefix(PublisherError
):
1668 """Used to indicate that a publisher name is not valid."""
1671 return _("'{0}' is not a valid publisher name.").format(
1675 class ReservedPublisherPrefix(PublisherError
):
1676 """Used to indicate that a publisher name is not valid."""
1679 fmri
= self
._args
["fmri"]
1680 return _("'{pkg_pub}' is a reserved publisher and does not "
1681 "contain the requested package: pkg:/{pkg_name}").format(
1682 pkg_pub
=fmri
.publisher
, pkg_name
=fmri
.pkg_name
)
1685 class BadRepositoryAttributeValue(PublisherError
):
1686 """Used to indicate that the specified repository attribute value is
1690 return _("'{value}' is not a valid value for repository "
1691 "attribute '{attribute}'.").format(
1692 value
=self
._args
["value"], attribute
=self
.data
)
1695 class BadRepositoryCollectionType(PublisherError
):
1696 """Used to indicate that the specified repository collection type is
1699 def __init__(self
, *args
, **kwargs
):
1700 PublisherError
.__init
__(self
, *args
, **kwargs
)
1703 return _("'{0}' is not a valid repository collection type.").format(
1707 class BadRepositoryURI(PublisherError
):
1708 """Used to indicate that a repository URI is not syntactically valid."""
1711 return _("'{0}' is not a valid URI.").format(self
.data
)
1714 class BadRepositoryURIPriority(PublisherError
):
1715 """Used to indicate that the priority specified for a repository URI is
1719 return _("'{0}' is not a valid URI priority; integer value "
1720 "expected.").format(self
.data
)
1723 class BadRepositoryURISortPolicy(PublisherError
):
1724 """Used to indicate that the specified repository URI sort policy is
1727 def __init__(self
, *args
, **kwargs
):
1728 PublisherError
.__init
__(self
, *args
, **kwargs
)
1731 return _("'{0}' is not a valid repository URI sort policy.").format(
1735 class DisabledPublisher(PublisherError
):
1736 """Used to indicate that an attempt to use a disabled publisher occurred
1737 during an operation."""
1740 return _("Publisher '{0}' is disabled and cannot be used for "
1741 "packaging operations.").format(self
.data
)
1744 class DuplicatePublisher(PublisherError
):
1745 """Used to indicate that a publisher with the same name or alias already
1746 exists for an image."""
1749 return _("A publisher with the same name or alias as '{0}' "
1750 "already exists.").format(self
.data
)
1753 class DuplicateRepository(PublisherError
):
1754 """Used to indicate that a repository with the same origin uris
1755 already exists for a publisher."""
1758 return _("A repository with the same name or origin URIs "
1759 "already exists for publisher '{0}'.").format(self
.data
)
1762 class DuplicateRepositoryMirror(PublisherError
):
1763 """Used to indicate that a repository URI is already in use by another
1764 repository mirror."""
1767 return _("Mirror '{0}' already exists for the specified "
1768 "publisher.").format(self
.data
)
1771 class DuplicateSyspubMirror(PublisherError
):
1772 """Used to indicate that a repository URI is already in use by the
1773 system publisher."""
1776 return _("Mirror '{0}' is already accessible through the "
1777 "system repository.").format(self
.data
)
1780 class DuplicateRepositoryOrigin(PublisherError
):
1781 """Used to indicate that a repository URI is already in use by another
1782 repository origin."""
1785 return _("Origin '{0}' already exists for the specified "
1786 "publisher.").format(self
.data
)
1789 class DuplicateSyspubOrigin(PublisherError
):
1790 """Used to indicate that a repository URI is already in use by the
1791 system publisher."""
1794 return _("Origin '{0}' is already accessible through the "
1795 "system repository.").format(self
.data
)
1798 class RemoveSyspubOrigin(PublisherError
):
1799 """Used to indicate that a system publisher origin may not be
1803 return _("Unable to remove origin '{0}' since it is provided "
1804 "by the system repository.").format(self
.data
)
1806 class RemoveSyspubMirror(PublisherError
):
1807 """Used to indicate that a system publisher mirror may not be
1811 return _("Unable to remove mirror '{0}' since it is provided "
1812 "by the system repository.").format(self
.data
)
1815 class NoPublisherRepositories(TransportError
):
1816 """Used to indicate that a Publisher has no repository information
1817 configured and so transport operations cannot be performed."""
1819 def __init__(self
, prefix
):
1820 TransportError
.__init
__(self
)
1821 self
.publisher
= prefix
1825 The requested operation requires that one or more package repositories are
1826 configured for publisher '{0}'.
1828 Use 'pkg set-publisher' to add new package repositories or restore previously
1829 configured package repositories for publisher '{0}'.""").format(self
.publisher
)
1832 class MoveRelativeToSelf(PublisherError
):
1833 """Used to indicate an attempt to search a repo before or after itself"""
1836 return _("Cannot search a repository before or after itself")
1839 class MoveRelativeToUnknown(PublisherError
):
1840 """Used to indicate an attempt to order a publisher relative to an
1841 unknown publisher."""
1843 def __init__(self
, unknown_pub
):
1844 self
.__unknown
_pub
= unknown_pub
1847 return _("{0} is an unknown publisher; no other publishers can "
1848 "be ordered relative to it.").format(self
.__unknown
_pub
)
1851 class SelectedRepositoryRemoval(PublisherError
):
1852 """Used to indicate that an attempt to remove the selected repository
1853 for a publisher was made."""
1856 return _("Cannot remove the selected repository for a "
1860 class UnknownLegalURI(PublisherError
):
1861 """Used to indicate that no matching legal URI could be found using the
1862 provided criteria."""
1865 return _("Unknown legal URI '{0}'.").format(self
.data
)
1868 class UnknownPublisher(PublisherError
):
1869 """Used to indicate that no matching publisher could be found using the
1870 provided criteria."""
1873 return _("Unknown publisher '{0}'.").format(self
.data
)
1876 class UnknownRepositoryPublishers(PublisherError
):
1877 """Used to indicate that one or more publisher prefixes are unknown by
1878 the specified repository."""
1880 def __init__(self
, known
=EmptyI
, unknown
=EmptyI
, location
=None,
1882 ApiException
.__init
__(self
)
1884 self
.location
= location
1885 self
.origins
= origins
1886 self
.unknown
= unknown
1890 return _("The repository at {location} does not "
1891 "contain package data for {unknown}; only "
1892 "{known}.\n\nThis is either because the "
1893 "repository location is not valid, or because the "
1894 "provided publisher does not match those known by "
1895 "the repository.").format(
1896 unknown
=", ".join(self
.unknown
),
1897 location
=self
.location
,
1898 known
=", ".join(self
.known
))
1900 return _("One or more of the repository origin(s) "
1901 "listed below contains package data for "
1902 "{known}; not {unknown}:\n\n{origins}\n\n"
1903 "This is either because one of the repository "
1904 "origins is not valid for this publisher, or "
1905 "because the list of known publishers retrieved "
1906 "from the repository origin does not match the "
1907 "client.").format(unknown
=", ".join(self
.unknown
),
1908 known
=", ".join(self
.known
),
1909 origins
="\n".join(str(o
) for o
in self
.origins
))
1910 return _("The specified publisher repository does not "
1911 "contain any package data for {unknown}; only "
1912 "{known}.").format(unknown
=", ".join(self
.unknown
),
1913 known
=", ".join(self
.known
))
1916 class UnknownRelatedURI(PublisherError
):
1917 """Used to indicate that no matching related URI could be found using
1918 the provided criteria."""
1921 return _("Unknown related URI '{0}'.").format(self
.data
)
1924 class UnknownRepository(PublisherError
):
1925 """Used to indicate that no matching repository could be found using the
1926 provided criteria."""
1929 return _("Unknown repository '{0}'.").format(self
.data
)
1932 class UnknownRepositoryMirror(PublisherError
):
1933 """Used to indicate that a repository URI could not be found in the
1934 list of repository mirrors."""
1937 return _("Unknown repository mirror '{0}'.").format(self
.data
)
1939 class UnsupportedRepositoryOperation(TransportError
):
1940 """The publisher has no active repositories that support the
1941 requested operation."""
1943 def __init__(self
, pub
, operation
):
1944 ApiException
.__init
__(self
)
1951 return _("Publisher '{pub}' has no repositories that support "
1952 "the '{op}' operation.").format(**self
.__dict
__)
1955 class RepoPubConfigUnavailable(PublisherError
):
1956 """Used to indicate that the specified repository does not provide
1957 publisher configuration information."""
1959 def __init__(self
, location
=None, pub
=None):
1960 ApiException
.__init
__(self
)
1961 self
.location
= location
1965 if not self
.location
and not self
.pub
:
1966 return _("The specified package repository does not "
1967 "provide publisher configuration information.")
1969 return _("The package repository at {0} does not "
1970 "provide publisher configuration information or "
1971 "the information provided is incomplete.").format(
1973 return _("One of the package repository origins for {0} does "
1974 "not provide publisher configuration information or the "
1975 "information provided is incomplete.").format(self
.pub
)
1978 class UnknownRepositoryOrigin(PublisherError
):
1979 """Used to indicate that a repository URI could not be found in the
1980 list of repository origins."""
1983 return _("Unknown repository origin '{0}'").format(self
.data
)
1986 class UnsupportedRepositoryURI(PublisherError
):
1987 """Used to indicate that the specified repository URI uses an
1988 unsupported scheme."""
1990 def __init__(self
, uris
=[]):
1991 if isinstance(uris
, basestring
):
1994 assert isinstance(uris
, (list, tuple, set))
2002 assert isinstance(u
, basestring
)
2003 scheme
= urlparse
.urlsplit(u
,
2004 allow_fragments
=0)[0]
2005 illegals
.append((u
, scheme
))
2007 if len(illegals
) > 1:
2008 msg
= _("The follwing URIs use unsupported "
2009 "schemes. Supported schemes are "
2010 "file://, http://, and https://.")
2011 for i
, s
in illegals
:
2012 msg
+= _("\n {uri} (scheme: "
2013 "{scheme})").format(uri
=i
, scheme
=s
)
2015 elif len(illegals
) == 1:
2017 return _("The URI '{uri}' uses the unsupported "
2018 "scheme '{scheme}'. Supported schemes are "
2019 "file://, http://, and https://.").format(
2021 return _("The specified URI uses an unsupported scheme."
2022 " Supported schemes are: file://, http://, and "
2026 class UnsupportedRepositoryURIAttribute(PublisherError
):
2027 """Used to indicate that the specified repository URI attribute is not
2028 supported for the URI's scheme."""
2031 return _("'{attr}' is not supported for '{scheme}'.").format(
2032 attr
=self
.data
, scheme
=self
._args
["scheme"])
2035 class UnsupportedProxyURI(PublisherError
):
2036 """Used to indicate that the specified proxy URI is unsupported."""
2040 scheme
= urlparse
.urlsplit(self
.data
,
2041 allow_fragments
=0)[0]
2042 return _("The proxy URI '{uri}' uses the unsupported "
2043 "scheme '{scheme}'. Supported schemes are "
2044 "http://, and https://.").format(
2045 uri
=self
.data
, scheme
=scheme
)
2046 return _("The specified proxy URI uses an unsupported scheme."
2047 " Supported schemes are: http://, and https://.")
2049 class BadProxyURI(PublisherError
):
2050 """Used to indicate that a proxy URI is not syntactically valid."""
2053 return _("'{0}' is not a valid URI.").format(self
.data
)
2056 class UnknownSysrepoConfiguration(ApiException
):
2057 """Used when a pkg client needs to communicate with the system
2058 repository but can't find the configuration for it."""
2062 pkg is configured to use the system repository (via the use-system-repo
2063 property) but it could not get the host and port from
2064 svc:/application/pkg/zones-proxy-client nor svc:/application/pkg/system-repository, and
2065 the PKG_SYSREPO_URL environment variable was not set. Please try enabling one
2066 of those services or setting the PKG_SYSREPO_URL environment variable.
2070 class ModifyingSyspubException(ApiException
):
2071 """This exception is raised when a user attempts to modify a system
2074 def __init__(self
, s
):
2081 class SigningException(ApiException
):
2082 """The base class for exceptions related to manifest signing."""
2084 def __init__(self
, pfmri
=None, sig
=None):
2088 # This string method is used by subclasses to fill in the details
2089 # about the package and signature involved.
2093 return _("The relevant signature action is "
2094 "found in {pfmri} and has a hash of "
2096 pfmri
=self
.pfmri
, hsh
=self
.sig
.hash)
2097 return _("The package involved is {0}").format(
2100 return _("The relevant signature action's value "
2101 "attribute is {0}").format(self
.sig
.attrs
["value"])
2105 class BadFileFormat(SigningException
):
2106 """Exception used when a key, certificate or CRL file is not in a
2107 recognized format."""
2109 def __init__(self
, txt
):
2116 class UnsupportedSignatureVersion(SigningException
):
2117 """Exception used when a signature reports a version which this version
2118 of pkg(5) doesn't support."""
2120 def __init__(self
, version
, *args
, **kwargs
):
2121 SigningException
.__init
__(self
, *args
, **kwargs
)
2122 self
.version
= version
2125 return _("The signature action {act} was made using a "
2126 "version ({ver}) this version of pkg(5) doesn't "
2127 "understand.").format(act
=self
.sig
, ver
=self
.version
)
2130 class CertificateException(SigningException
):
2131 """Base class for exceptions encountered while establishing the chain
2134 def __init__(self
, cert
, pfmri
=None):
2135 SigningException
.__init
__(self
, pfmri
)
2139 class ModifiedCertificateException(CertificateException
):
2140 """Exception used when a certificate does not match its expected hash
2143 def __init__(self
, cert
, path
, pfmri
=None):
2144 CertificateException
.__init
__(self
, cert
, pfmri
)
2148 return _("Certificate {0} has been modified on disk. Its hash "
2149 "value is not what was expected.").format(self
.path
)
2152 class UntrustedSelfSignedCert(CertificateException
):
2153 """Exception used when a chain of trust is rooted in an untrusted
2154 self-signed certificate."""
2157 return _("Chain was rooted in an untrusted self-signed "
2158 "certificate.\n") + CertificateException
.__str
__(self
)
2161 class BrokenChain(CertificateException
):
2162 """Exception used when a chain of trust can not be established between
2163 the leaf certificate and a trust anchor."""
2165 def __init__(self
, cert
, cert_exceptions
, *args
, **kwargs
):
2166 CertificateException
.__init
__(self
, cert
, *args
, **kwargs
)
2167 self
.ext_exs
= cert_exceptions
2172 s
= _("The following problems were encountered:\n") + \
2173 "\n".join([str(e
) for e
in self
.ext_exs
])
2174 return _("The certificate which issued this "
2175 "certificate: {subj} could not be found. The issuer "
2176 "is: {issuer}\n").format(subj
="/".join("{0}={1}".format(
2177 sub
.oid
._name
, sub
.value
) for sub
in self
.cert
.subject
),
2178 issuer
="/".join("{0}={1}".format(i
.oid
._name
, i
.value
)
2179 for i
in self
.cert
.issuer
)) + s
+ "\n" + \
2180 CertificateException
.__str
__(self
)
2183 class RevokedCertificate(CertificateException
):
2184 """Exception used when a chain of trust contains a revoked certificate.
2187 def __init__(self
, cert
, reason
, *args
, **kwargs
):
2188 CertificateException
.__init
__(self
, cert
, *args
, **kwargs
)
2189 self
.reason
= reason
2192 return _("This certificate was revoked:{cert} for this "
2193 "reason:\n{reason}\n").format(cert
="/".join("{0}={1}".format(
2194 s
.oid
._name
, s
.value
) for s
in self
.cert
.subject
),
2195 reason
=self
.reason
) + CertificateException
.__str
__(self
)
2198 class UnverifiedSignature(SigningException
):
2199 """Exception used when a signature could not be verified by the
2200 expected certificate."""
2202 def __init__(self
, sig
, reason
, pfmri
=None):
2203 SigningException
.__init
__(self
, pfmri
)
2205 self
.reason
= reason
2209 return _("A signature in {pfmri} could not be "
2211 "this reason:\n{reason}\nThe signature's hash is "
2212 "{hash}").format(pfmri
=self
.pfmri
,
2215 return _("The signature with this signature value:\n"
2216 "{sigval}\n could not be verified for this reason:\n"
2217 "{reason}\n").format(reason
=self
.reason
,
2218 sigval
=self
.sig
.attrs
["value"])
2221 class RequiredSignaturePolicyException(SigningException
):
2222 """Exception used when signatures were required but none were found."""
2224 def __init__(self
, pub
, pfmri
=None):
2225 SigningException
.__init
__(self
, pfmri
)
2229 pub_str
= self
.pub
.prefix
2231 return _("The policy for {pub_str} requires "
2232 "signatures to be present but no signature was "
2233 "found in {fmri_str}.").format(
2234 pub_str
=pub_str
, fmri_str
=self
.pfmri
)
2235 return _("The policy for {pub_str} requires signatures to be "
2236 "present but no signature was found.").format(
2240 class MissingRequiredNamesException(SigningException
):
2241 """Exception used when a signature policy required names to be seen
2242 which weren't seen."""
2244 def __init__(self
, pub
, missing_names
, pfmri
=None):
2245 SigningException
.__init
__(self
, pfmri
)
2247 self
.missing_names
= missing_names
2250 pub_str
= self
.pub
.prefix
2252 return _("The policy for {pub_str} requires certain "
2253 "CNs to be seen in a chain of trust. The following "
2254 "required names couldn't be found for this "
2255 "package:{fmri_str}.\n{missing}").format(
2256 pub_str
=pub_str
, fmri_str
=self
.pfmri
,
2257 missing
="\n".join(self
.missing_names
))
2258 return _("The policy for {pub_str} requires certain CNs to "
2259 "be seen in a chain of trust. The following required names "
2260 "couldn't be found.\n{missing}").format(pub_str
=pub_str
,
2261 missing
="\n".join(self
.missing_names
))
2263 class UnsupportedCriticalExtension(SigningException
):
2264 """Exception used when a certificate in the chain of trust uses a
2265 critical extension pkg doesn't understand."""
2267 def __init__(self
, cert
, ext
):
2268 SigningException
.__init
__(self
)
2273 return _("The certificate whose subject is {cert} could not "
2274 "be verified because it uses an unsupported critical "
2275 "extension.\nExtension name: {name}\nExtension "
2276 "value: {val}").format(cert
="/".join("{0}={1}".format(
2277 s
.oid
._name
, s
.value
) for s
in self
.cert
.subject
),
2278 name
=self
.ext
.oid
._name
, val
=self
.ext
.value
)
2280 class UnsupportedExtensionValue(SigningException
):
2281 """Exception used when a certificate in the chain of trust has an
2282 extension with a value pkg doesn't understand."""
2284 def __init__(self
, cert
, ext
, val
, bad_val
=None):
2285 SigningException
.__init
__(self
)
2289 self
.bad_val
= bad_val
2292 s
= _("The certificate whose subject is {cert} could not be "
2293 "verified because it has an extension with a value that "
2294 "pkg(5) does not understand."
2295 "\nExtension name: {name}\nExtension value: {val}").format(
2296 cert
="/".join("{0}={1}".format(
2297 s
.oid
._name
, s
.value
) for s
in self
.cert
.subject
),
2298 name
=self
.ext
.oid
._name
, val
=self
.val
)
2300 s
+= _("\nProblematic value: {0}").format(self
.bad_val
)
2303 class InvalidCertificateExtensions(SigningException
):
2304 """Exception used when a certificate in the chain of trust has
2305 invalid extensions."""
2307 def __init__(self
, cert
, error
):
2308 SigningException
.__init
__(self
)
2313 s
= _("The certificate whose subject is {cert} could not be "
2314 "verified because it has invalid extensions:\n{error}"
2315 ).format(cert
="/".join("{0}={1}".format(
2316 s
.oid
._name
, s
.value
) for s
in self
.cert
.subject
),
2320 class InappropriateCertificateUse(SigningException
):
2321 """Exception used when a certificate in the chain of trust has been used
2322 inappropriately. An example would be a certificate which was only
2323 supposed to be used to sign code being used to sign other certificates.
2326 def __init__(self
, cert
, ext
, use
, val
):
2327 SigningException
.__init
__(self
)
2334 return _("The certificate whose subject is {cert} could not "
2335 "be verified because it has been used inappropriately. "
2336 "The way it is used means that the value for extension "
2337 "{name} must include '{use}' but the value was "
2338 "'{val}'.").format(cert
="/".join("{0}={1}".format(
2339 s
.oid
._name
, s
.value
) for s
in self
.cert
.subject
),
2340 use
=self
.use
, name
=self
.ext
.oid
._name
,
2343 class PathlenTooShort(InappropriateCertificateUse
):
2344 """Exception used when a certificate in the chain of trust has been used
2345 inappropriately. An example would be a certificate which was only
2346 supposed to be used to sign code being used to sign other certificates.
2349 def __init__(self
, cert
, actual_length
, cert_length
):
2350 SigningException
.__init
__(self
)
2352 self
.al
= actual_length
2353 self
.cl
= cert_length
2356 return _("The certificate whose subject is {cert} could not "
2357 "be verified because it has been used inappropriately. "
2358 "There can only be {cl} certificates between this "
2359 "certificate and the leaf certificate. There are {al} "
2360 "certificates between this certificate and the leaf in "
2361 "this chain.").format(
2362 cert
="/".join("{0}={1}".format(
2363 s
.oid
._name
, s
.value
) for s
in self
.cert
.subject
),
2369 class AlmostIdentical(ApiException
):
2370 """Exception used when a package already has a signature action which is
2371 nearly identical to the one being added but differs on some
2374 def __init__(self
, hsh
, algorithm
, version
, pkg
=None):
2376 self
.algorithm
= algorithm
2377 self
.version
= version
2381 s
= _("The signature to be added to the package has the same "
2382 "hash ({hash}), algorithm ({algorithm}), and "
2383 "version ({version}) as an existing signature, but "
2384 "doesn't match the signature exactly. For this signature "
2385 "to be added, the existing signature must be removed.").format(
2387 algorithm
=self
.algorithm
,
2388 version
=self
.version
2391 s
+= _("The package being signed was {pkg}").format(
2396 class DuplicateSignaturesAlreadyExist(ApiException
):
2397 """Exception used when a package already has a signature action which is
2398 nearly identical to the one being added but differs on some
2401 def __init__(self
, pfmri
):
2405 return _("{0} could not be signed because it already has two "
2406 "copies of this signature in it. One of those signature "
2407 "actions must be removed before the package is given to "
2408 "users.").format(self
.pfmri
)
2411 class InvalidPropertyValue(ApiException
):
2412 """Exception used when a property was set to an invalid value."""
2414 def __init__(self
, s
):
2415 ApiException
.__init
__(self
)
2422 class CertificateError(ApiException
):
2423 """Base exception class for all certificate exceptions."""
2425 def __init__(self
, *args
, **kwargs
):
2426 ApiException
.__init
__(self
, *args
)
2434 return str(self
.data
)
2437 class ExpiredCertificate(CertificateError
):
2438 """Used to indicate that a certificate has expired."""
2440 def __init__(self
, *args
, **kwargs
):
2441 CertificateError
.__init
__(self
, *args
, **kwargs
)
2442 self
.publisher
= self
._args
.get("publisher", None)
2443 self
.uri
= self
._args
.get("uri", None)
2448 return _("Certificate '{cert}' for publisher "
2449 "'{pub}' needed to access '{uri}', "
2450 "has expired. Please install a valid "
2451 "certificate.").format(cert
=self
.data
,
2452 pub
=self
.publisher
, uri
=self
.uri
)
2453 return _("Certificate '{cert}' for publisher "
2454 "'{pub}', has expired. Please install a valid "
2455 "certificate.").format(cert
=self
.data
,
2458 return _("Certificate '{cert}', needed to access "
2459 "'{uri}', has expired. Please install a valid "
2460 "certificate.").format(cert
=self
.data
,
2462 return _("Certificate '{0}' has expired. Please install a "
2463 "valid certificate.").format(self
.data
)
2466 class ExpiredCertificates(CertificateError
):
2467 """Used to collect ExpiredCertficate exceptions."""
2469 def __init__(self
, errors
):
2473 assert (isinstance(errors
, (list, tuple,
2474 set, ExpiredCertificate
)))
2476 if isinstance(errors
, ExpiredCertificate
):
2477 self
.errors
.append(errors
)
2479 self
.errors
= errors
2483 for e
in self
.errors
:
2484 if e
.publisher
in pdict
:
2485 pdict
[e
.publisher
].append(e
.uri
)
2487 pdict
[e
.publisher
] = [e
.uri
]
2490 for pub
, uris
in pdict
.items():
2491 msg
+= "\n{0}:".format(_("Publisher"))
2492 msg
+= " {0}".format(pub
)
2494 msg
+= "\n {0}:\n".format(_("Origin URI"))
2495 msg
+= " {0}\n".format(uri
)
2496 msg
+= " {0}:\n".format(_("Certificate"))
2497 msg
+= " {0}\n".format(uri
.ssl_cert
)
2498 msg
+= " {0}:\n".format(_("Key"))
2499 msg
+= " {0}\n".format(uri
.ssl_key
)
2500 return _("One or more client key and certificate files have "
2501 "expired. Please\nupdate the configuration for the "
2502 "publishers or origins listed below:\n {0}").format(msg
)
2505 class ExpiringCertificate(CertificateError
):
2506 """Used to indicate that a certificate has expired."""
2509 publisher
= self
._args
.get("publisher", None)
2510 uri
= self
._args
.get("uri", None)
2511 days
= self
._args
.get("days", 0)
2514 return _("Certificate '{cert}' for publisher "
2515 "'{pub}', needed to access '{uri}', "
2516 "will expire in '{days}' days.").format(
2517 cert
=self
.data
, pub
=publisher
,
2519 return _("Certificate '{cert}' for publisher "
2520 "'{pub}' will expire in '{days}' days.").format(
2521 cert
=self
.data
, pub
=publisher
, days
=days
)
2523 return _("Certificate '{cert}', needed to access "
2524 "'{uri}', will expire in '{days}' days.").format(
2525 cert
=self
.data
, uri
=uri
, days
=days
)
2526 return _("Certificate '{cert}' will expire in "
2527 "'{days}' days.").format(cert
=self
.data
, days
=days
)
2530 class InvalidCertificate(CertificateError
):
2531 """Used to indicate that a certificate is invalid."""
2534 publisher
= self
._args
.get("publisher", None)
2535 uri
= self
._args
.get("uri", None)
2538 return _("Certificate '{cert}' for publisher "
2539 "'{pub}', needed to access '{uri}', is "
2540 "invalid.").format(cert
=self
.data
,
2541 pub
=publisher
, uri
=uri
)
2542 return _("Certificate '{cert}' for publisher "
2543 "'{pub}' is invalid.").format(cert
=self
.data
,
2546 return _("Certificate '{cert}' needed to access "
2547 "'{uri}' is invalid.").format(cert
=self
.data
,
2549 return _("Invalid certificate '{0}'.").format(self
.data
)
2552 class NoSuchKey(CertificateError
):
2553 """Used to indicate that a key could not be found."""
2556 publisher
= self
._args
.get("publisher", None)
2557 uri
= self
._args
.get("uri", None)
2560 return _("Unable to locate key '{key}' for "
2561 "publisher '{pub}' needed to access "
2562 "'{uri}'.").format(key
=self
.data
,
2563 pub
=publisher
, uri
=uri
)
2564 return _("Unable to locate key '{key}' for publisher "
2565 "'{pub}'.").format(key
=self
.data
, pub
=publisher
2568 return _("Unable to locate key '{key}' needed to "
2569 "access '{uri}'.").format(key
=self
.data
,
2571 return _("Unable to locate key '{0}'.").format(self
.data
)
2574 class NoSuchCertificate(CertificateError
):
2575 """Used to indicate that a certificate could not be found."""
2578 publisher
= self
._args
.get("publisher", None)
2579 uri
= self
._args
.get("uri", None)
2582 return _("Unable to locate certificate "
2583 "'{cert}' for publisher '{pub}' needed "
2584 "to access '{uri}'.").format(
2585 cert
=self
.data
, pub
=publisher
,
2587 return _("Unable to locate certificate '{cert}' for "
2588 "publisher '{pub}'.").format(cert
=self
.data
,
2591 return _("Unable to locate certificate '{cert}' "
2592 "needed to access '{uri}'.").format(
2593 cert
=self
.data
, uri
=uri
)
2594 return _("Unable to locate certificate '{0}'.").format(
2598 class NotYetValidCertificate(CertificateError
):
2599 """Used to indicate that a certificate is not yet valid (future
2603 publisher
= self
._args
.get("publisher", None)
2604 uri
= self
._args
.get("uri", None)
2607 return _("Certificate '{cert}' for publisher "
2608 "'{pub}', needed to access '{uri}', "
2609 "has a future effective date.").format(
2610 cert
=self
.data
, pub
=publisher
,
2612 return _("Certificate '{cert}' for publisher "
2613 "'{pub}' has a future effective date.").format(
2614 cert
=self
.data
, pub
=publisher
)
2616 return _("Certificate '{cert}' needed to access "
2617 "'{uri}' has a future effective date.").format(
2618 cert
=self
.data
, uri
=uri
)
2619 return _("Certificate '{0}' has a future effective date.").format(
2623 class ServerReturnError(ApiException
):
2624 """This exception is used when the server returns a line which the
2625 client cannot parse correctly."""
2627 def __init__(self
, line
):
2628 ApiException
.__init
__(self
)
2632 return _("Gave a bad response:{0}").format(self
.line
)
2635 class MissingFileArgumentException(ApiException
):
2636 """This exception is used when a file was given as an argument but
2637 no such file could be found."""
2638 def __init__(self
, path
):
2639 ApiException
.__init
__(self
)
2643 return _("Could not find {0}").format(self
.path
)
2646 class ManifestError(ApiException
):
2647 """Base exception class for all manifest exceptions."""
2649 def __init__(self
, *args
, **kwargs
):
2650 ApiException
.__init
__(self
, *args
, **kwargs
)
2658 return str(self
.data
)
2661 class BadManifestSignatures(ManifestError
):
2662 """Used to indicate that the Manifest signatures are not valid."""
2666 return _("The signature data for the manifest of the "
2667 "'{0}' package is not valid.").format(self
.data
)
2668 return _("The signature data for the manifest is not valid.")
2671 class UnknownErrors(ApiException
):
2672 """Used to indicate that one or more exceptions were encountered.
2673 This is intended for use with where multiple exceptions for multiple
2674 files are encountered and the errors have been condensed into a
2675 single exception and re-raised. One example case would be rmtree()
2676 with shutil.Error."""
2678 def __init__(self
, msg
):
2679 ApiException
.__init
__(self
)
2686 # Image creation exceptions
2687 class ImageCreationException(ApiException
):
2688 def __init__(self
, path
):
2689 ApiException
.__init
__(self
)
2693 raise NotImplementedError()
2696 class ImageAlreadyExists(ImageCreationException
):
2698 return _("there is already an image at: {0}.\nTo override, use "
2699 "the -f (force) option.").format(self
.path
)
2702 class ImageCfgEmptyError(ApiException
):
2703 """Used to indicate that the image configuration is invalid."""
2706 return _("The configuration data for the image rooted at "
2707 "{0} is empty or missing.").format(self
.data
)
2710 class UnsupportedImageError(ApiException
):
2711 """Used to indicate that the image at a specific location is in a format
2712 not supported by this version of the pkg(5) API."""
2714 def __init__(self
, path
):
2715 ApiException
.__init
__(self
)
2719 return _("The image rooted at {0} is invalid or is not "
2720 "supported by this version of the packaging system.").format(
2724 class CreatingImageInNonEmptyDir(ImageCreationException
):
2726 return _("the specified image path is not empty: {0}.\nTo "
2727 "override, use the -f (force) option.").format(self
.path
)
2730 def _convert_error(e
, ignored_errors
=EmptyI
):
2731 """Converts the provided exception into an ApiException equivalent if
2732 possible. Returns a new exception object if converted or the original
2735 'ignored_errors' is an optional list of errno values for which None
2739 if not hasattr(e
, "errno"):
2741 if e
.errno
in ignored_errors
:
2743 if e
.errno
in (errno
.EACCES
, errno
.EPERM
):
2744 return PermissionsException(e
.filename
)
2745 if e
.errno
== errno
.EROFS
:
2746 return ReadOnlyFileSystemException(e
.filename
)
2749 class LinkedImageException(ApiException
):
2751 def __init__(self
, bundle
=None, lin
=None, exitrv
=None,
2752 attach_bad_prop
=None,
2753 attach_bad_prop_value
=None,
2754 attach_child_notsup
=None,
2755 attach_parent_notsup
=None,
2756 attach_root_as_child
=None,
2757 attach_with_curpath
=None,
2759 child_diverged
=None,
2761 child_not_in_altroot
=None,
2762 child_not_nested
=None,
2763 child_op_failed
=None,
2764 child_path_notabs
=None,
2767 cmd_output_invalid
=None,
2768 detach_child_notsup
=None,
2769 detach_from_parent
=None,
2770 detach_parent_notsup
=None,
2772 intermediate_image
=None,
2775 parent_bad_img
=None,
2776 parent_bad_notabs
=None,
2777 parent_bad_path
=None,
2779 parent_not_in_altroot
=None,
2782 self_not_child
=None,
2783 unparsable_output
=None):
2785 self
.attach_bad_prop
= attach_bad_prop
2786 self
.attach_bad_prop_value
= attach_bad_prop_value
2787 self
.attach_child_notsup
= attach_child_notsup
2788 self
.attach_parent_notsup
= attach_parent_notsup
2789 self
.attach_root_as_child
= attach_root_as_child
2790 self
.attach_with_curpath
= attach_with_curpath
2791 self
.child_bad_img
= child_bad_img
2792 self
.child_diverged
= child_diverged
2793 self
.child_dup
= child_dup
2794 self
.child_not_in_altroot
= child_not_in_altroot
2795 self
.child_not_nested
= child_not_nested
2796 self
.child_op_failed
= child_op_failed
2797 self
.child_path_notabs
= child_path_notabs
2798 self
.child_unknown
= child_unknown
2799 self
.cmd_failed
= cmd_failed
2800 self
.cmd_output_invalid
= cmd_output_invalid
2801 self
.detach_child_notsup
= detach_child_notsup
2802 self
.detach_from_parent
= detach_from_parent
2803 self
.detach_parent_notsup
= detach_parent_notsup
2804 self
.img_linked
= img_linked
2805 self
.intermediate_image
= intermediate_image
2806 self
.lin_malformed
= lin_malformed
2807 self
.link_to_self
= link_to_self
2808 self
.parent_bad_img
= parent_bad_img
2809 self
.parent_bad_notabs
= parent_bad_notabs
2810 self
.parent_bad_path
= parent_bad_path
2811 self
.parent_nested
= parent_nested
2812 self
.parent_not_in_altroot
= parent_not_in_altroot
2813 self
.pkg_op_failed
= pkg_op_failed
2814 self
.self_linked
= self_linked
2815 self
.self_not_child
= self_not_child
2816 self
.unparsable_output
= unparsable_output
2818 # first deal with an error bundle
2820 assert type(bundle
) in [tuple, list, set]
2822 assert isinstance(e
, LinkedImageException
)
2824 # set default error return value
2826 exitrv
= pkgdefs
.EXIT_OOPS
2829 self
.lix_bundle
= bundle
2830 self
.lix_exitrv
= exitrv
2835 if attach_bad_prop
is not None:
2836 err
= _("Invalid linked image attach property: {0}").format(
2839 if attach_bad_prop_value
is not None:
2840 assert type(attach_bad_prop_value
) in [tuple, list]
2841 assert len(attach_bad_prop_value
) == 2
2842 err
= _("Invalid linked image attach property "
2843 "value: {0}").format(
2844 "=".join(attach_bad_prop_value
))
2846 if attach_child_notsup
is not None:
2847 err
= _("Linked image type does not support child "
2848 "attach: {0}").format(attach_child_notsup
)
2850 if attach_parent_notsup
is not None:
2851 err
= _("Linked image type does not support parent "
2852 "attach: {0}").format(attach_parent_notsup
)
2854 if attach_root_as_child
is not None:
2855 err
= _("Cannot attach root image as child: {0}".format(
2856 attach_root_as_child
))
2858 if attach_with_curpath
is not None:
2859 path
, curpath
= attach_with_curpath
2860 err
= _("Cannot link images when an image is not at "
2861 "its default location. The image currently "
2862 "located at:\n {curpath}\n"
2863 "is normally located at:\n {path}\n").format(
2868 if child_bad_img
is not None:
2870 exitrv
= pkgdefs
.EXIT_EACCESS
2872 err
= _("Can't initialize child image "
2873 "({lin}) at path: {path}").format(
2878 err
= _("Can't initialize child image "
2879 "at path: {0}").format(child_bad_img
)
2881 if child_diverged
is not None:
2883 exitrv
= pkgdefs
.EXIT_DIVERGED
2884 err
= _("Linked image is diverged: {0}").format(
2887 if child_dup
is not None:
2888 err
= _("A linked child image with this name "
2889 "already exists: {0}").format(child_dup
)
2891 if child_not_in_altroot
is not None:
2892 path
, altroot
= child_not_in_altroot
2893 err
= _("Child image '{path}' is not located "
2894 "within the parent's altroot '{altroot}'").format(
2899 if child_not_nested
is not None:
2900 cpath
, ppath
= child_not_nested
2901 err
= _("Child image '{cpath}' is not nested "
2902 "within the parent image '{ppath}'").format(
2907 if child_op_failed
is not None:
2908 op
, cpath
, e
= child_op_failed
2910 exitrv
= pkgdefs
.EXIT_EACCESS
2912 err
= _("Failed '{op}' for child image "
2913 "({lin}) at path: {path}: "
2914 "{strerror}").format(
2921 err
= _("Failed '{op}' for child image "
2922 "at path: {path}: {strerror}").format(
2928 if child_path_notabs
is not None:
2929 err
= _("Child path not absolute: {0}").format(
2932 if child_unknown
is not None:
2933 err
= _("Unknown child linked image: {0}").format(
2936 if cmd_failed
is not None:
2937 (rv
, cmd
, errout
) = cmd_failed
2938 err
= _("The following subprocess returned an "
2939 "unexpected exit code of {rv:d}:\n {cmd}").format(
2943 err
+= _("\nAnd generated the following error "
2944 "message:\n{errout}".format(errout
=errout
))
2946 if cmd_output_invalid
is not None:
2947 (cmd
, output
) = cmd_output_invalid
2949 "The following subprocess:\n"
2951 "Generated the following unexpected output:\n"
2952 "{output}\n".format(
2953 cmd
=" ".join(cmd
), output
="\n".join(output
)))
2955 if detach_child_notsup
is not None:
2956 err
= _("Linked image type does not support "
2957 "child detach: {0}").format(detach_child_notsup
)
2959 if detach_from_parent
is not None:
2961 exitrv
= pkgdefs
.EXIT_PARENTOP
2962 err
= _("Parent linked to child, can not detach "
2963 "child: {0}").format(detach_from_parent
)
2965 if detach_parent_notsup
is not None:
2966 err
= _("Linked image type does not support "
2967 "parent detach: {0}").format(detach_parent_notsup
)
2969 if img_linked
is not None:
2970 err
= _("Image already a linked child: {0}").format(
2973 if intermediate_image
is not None:
2974 ppath
, cpath
, ipath
= intermediate_image
2976 "Intermediate image '{ipath}' found between "
2977 "child '{cpath}' and "
2978 "parent '{ppath}'").format(
2984 if lin_malformed
is not None:
2985 err
= _("Invalid linked image name '{0}'. "
2986 "Linked image names have the following format "
2987 "'<linked_image plugin>:<linked_image name>'").format(
2990 if link_to_self
is not None:
2991 err
= _("Can't link image to itself: {0}")
2993 if parent_bad_img
is not None:
2995 exitrv
= pkgdefs
.EXIT_EACCESS
2996 err
= _("Can't initialize parent image at path: {0}").format(
2999 if parent_bad_notabs
is not None:
3000 err
= _("Parent path not absolute: {0}").format(
3003 if parent_bad_path
is not None:
3005 exitrv
= pkgdefs
.EXIT_EACCESS
3006 err
= _("Can't access parent image at path: {0}").format(
3009 if parent_nested
is not None:
3010 ppath
, cpath
= parent_nested
3011 err
= _("A parent image '{ppath}' can not be nested "
3012 "within a child image '{cpath}'").format(
3017 if parent_not_in_altroot
is not None:
3018 path
, altroot
= parent_not_in_altroot
3019 err
= _("Parent image '{path}' is not located "
3020 "within the child's altroot '{altroot}'").format(
3025 if pkg_op_failed
is not None:
3027 (op
, exitrv
, errout
, e
) = pkg_op_failed
3028 assert op
is not None
3032 A '{op}' operation failed for child '{lin}' with an unexpected
3033 return value of {exitrv:d} and generated the following output:
3045 A '{op}' operation failed for child '{lin}' with an unexpected
3049 The child generated the following output:
3060 if self_linked
is not None:
3061 err
= _("Current image already a linked child: {0}").format(
3064 if self_not_child
is not None:
3066 exitrv
= pkgdefs
.EXIT_NOPARENT
3067 err
= _("Current image is not a linked child: {0}").format(
3070 if unparsable_output
is not None:
3071 (op
, errout
, e
) = unparsable_output
3073 A '{op}' operation for child '{lin}' generated non-json output.
3074 The json parser failed with the following error:
3077 The child generated the following output:
3088 # set default error return value
3090 exitrv
= pkgdefs
.EXIT_OOPS
3093 self
.lix_bundle
= None
3094 self
.lix_exitrv
= exitrv
3097 assert self
.lix_err
or self
.lix_bundle
3098 assert not (self
.lix_err
and self
.lix_bundle
), \
3099 "self.lix_err = {0}, self.lix_bundle = {1}".format(
3100 str(self
.lix_err
), str(self
.lix_bundle
))
3106 # concatenate multiple errors
3108 for e
in self
.lix_bundle
:
3109 bundle_str
.append(str(e
))
3110 return "\n".join(bundle_str
)
3113 class FreezePkgsException(ApiException
):
3114 """Used if an argument to pkg freeze isn't valid."""
3116 def __init__(self
, multiversions
=None, unmatched_wildcards
=None,
3117 version_mismatch
=None, versionless_uninstalled
=None):
3118 ApiException
.__init
__(self
)
3119 self
.multiversions
= multiversions
3120 self
.unmatched_wildcards
= unmatched_wildcards
3121 self
.version_mismatch
= version_mismatch
3122 self
.versionless_uninstalled
= versionless_uninstalled
3126 if self
.multiversions
:
3128 The following packages were frozen at two different versions by
3129 the patterns provided. The package stem and the versions it was frozen at are
3132 res
+= ["\t{0}\t{1}".format(stem
, " ".join([
3133 str(v
) for v
in versions
]))
3134 for stem
, versions
in sorted(self
.multiversions
)]
3136 if self
.unmatched_wildcards
:
3138 The following patterns contained wildcards but matched no
3139 installed packages.""")
3141 res
+= ["\t{0}".format(pat
) for pat
in sorted(
3142 self
.unmatched_wildcards
)]
3144 if self
.version_mismatch
:
3146 The following patterns attempted to freeze the listed packages
3147 at a version different from the version at which the packages are installed.""")
3149 for pat
in sorted(self
.version_mismatch
):
3150 res
+= ["\t{0}".format(pat
)]
3151 if len(self
.version_mismatch
[pat
]) > 1:
3153 "\t\t{0}".format(stem
)
3155 in self
.version_mismatch
[pat
]
3158 if self
.versionless_uninstalled
:
3160 The following patterns don't match installed packages and
3161 contain no version information. Uninstalled packages can only be frozen by
3162 providing a version at which to freeze them.""")
3164 res
+= ["\t{0}".format(p
) for p
in sorted(
3165 self
.versionless_uninstalled
)]
3166 return "\n".join(res
)
3168 class InvalidFreezeFile(ApiException
):
3169 """Used to indicate the freeze state file could not be loaded."""
3172 return _("The freeze state file '{0}' is invalid.").format(
3175 class UnknownFreezeFileVersion(ApiException
):
3176 """Used when the version on the freeze state file isn't the version
3179 def __init__(self
, found_ver
, expected_ver
, location
):
3180 self
.found
= found_ver
3181 self
.expected
= expected_ver
3185 return _("The freeze state file '{loc}' was expected to have "
3186 "a version of {exp}, but its version was {found}").format(
3192 class InvalidOptionError(ApiException
):
3193 """Used to indicate an issue with verifying options passed to a certain
3196 GENERIC
= "generic" # generic option violation
3197 OPT_REPEAT
= "opt_repeat" # option repetition is not allowed
3198 ARG_REPEAT
= "arg_repeat" # argument repetition is not allowed
3199 ARG_INVALID
= "arg_invalid" # argument is invalid
3200 INCOMPAT
= "incompat" # option 'a' can not be specified with option 'b'
3201 REQUIRED
= "required" # option 'a' requires option 'b'
3202 REQUIRED_ANY
= "required_any" # option 'a' requires option 'b', 'c' or more
3203 XOR
= "xor" # either option 'a' or option 'b' must be specified
3205 def __init__(self
, err_type
=GENERIC
, options
=[], msg
=None,
3208 self
.err_type
= err_type
3209 self
.options
= options
3211 self
.valid_args
= valid_args
3215 # In case the user provided a custom message we just take it and
3216 # append the according options.
3217 if self
.msg
is not None:
3220 self
.msg
+= " ".join(self
.options
)
3223 if self
.err_type
== self
.OPT_REPEAT
:
3224 assert len(self
.options
) == 1
3225 return _("Option '{option}' may not be repeated.").format(
3226 option
=self
.options
[0])
3227 elif self
.err_type
== self
.ARG_REPEAT
:
3228 assert len(self
.options
) == 2
3229 return _("Argument '{op1}' for option '{op2}' may "
3230 "not be repeated.").format(op1
=self
.options
[0],
3231 op2
=self
.options
[1])
3232 elif self
.err_type
== self
.ARG_INVALID
:
3233 assert len(self
.options
) == 2
3234 s
= _("Argument '{op1}' for option '{op2}' is "
3235 "invalid.").format(op1
=self
.options
[0],
3236 op2
=self
.options
[1])
3238 s
+= _("\nSupported: {0}").format(", ".join(
3241 elif self
.err_type
== self
.INCOMPAT
:
3242 assert len(self
.options
) == 2
3243 return _("The '{op1}' and '{op2}' option may "
3244 "not be combined.").format(op1
=self
.options
[0],
3245 op2
=self
.options
[1])
3246 elif self
.err_type
== self
.REQUIRED
:
3247 assert len(self
.options
) == 2
3248 return _("'{op1}' may only be used with "
3249 "'{op2}'.").format(op1
=self
.options
[0],
3250 op2
=self
.options
[1])
3251 elif self
.err_type
== self
.REQUIRED_ANY
:
3252 assert len(self
.options
) > 2
3253 return _("'{op1}' may only be used with "
3254 "'{op2}' or {op3}.").format(op1
=self
.options
[0],
3255 op2
=", ".join(self
.options
[1:-1]),
3256 op3
=self
.options
[-1])
3257 elif self
.err_type
== self
.XOR
:
3258 assert len(self
.options
) == 2
3259 return _("Either '{op1}' or '{op2}' must be "
3260 "specified").format(op1
=self
.options
[0],
3261 op2
=self
.options
[1])
3263 return _("invalid option(s): ") + " ".join(self
.options
)
3265 class InvalidOptionErrors(ApiException
):
3267 def __init__(self
, errors
):
3271 assert (isinstance(errors
, list) or isinstance(errors
, tuple) or
3272 isinstance(errors
, set) or
3273 isinstance(errors
, InvalidOptionError
))
3275 if isinstance(errors
, InvalidOptionError
):
3276 self
.errors
.append(errors
)
3278 self
.errors
= errors
3282 for e
in self
.errors
:
3284 return "\n".join(msgs
)
3286 class UnexpectedLinkError(ApiException
):
3287 """Used to indicate that an image state file has been replaced
3290 def __init__(self
, path
, filename
, errno
):
3292 self
.filename
= filename
3296 return _("Cannot update file: '{file}' at path "
3297 "'{path}', contains a symlink. "
3298 "[Error '{errno:d}': '{error}']").format(
3299 error
=os
.strerror(self
.errno
),
3306 class InvalidConfigFile(ApiException
):
3307 """Used to indicate that a configuration file is invalid
3310 def __init__(self
, path
):
3314 return _("Cannot parse configuration file "
3315 "{path}'.").format(path
=self
.path
)