856 except (TypeError, ValueError): |
856 except (TypeError, ValueError): |
857 # i18n: "rev" is a keyword |
857 # i18n: "rev" is a keyword |
858 raise error.ParseError(_("rev expects a number")) |
858 raise error.ParseError(_("rev expects a number")) |
859 return [r for r in subset if r == l] |
859 return [r for r in subset if r == l] |
860 |
860 |
|
861 def matching(repo, subset, x): |
|
862 """``matching(revision [, field])`` |
|
863 Changesets in which a given set of fields match the set of fields in the |
|
864 selected revision or set. |
|
865 To match more than one field pass the list of fields to match separated |
|
866 by spaces (e.g. 'author description'). |
|
867 Valid fields are most regular revision fields and some special fields: |
|
868 * regular fields: |
|
869 - description, author, branch, date, files, phase, parents, |
|
870 substate, user. |
|
871 Note that author and user are synonyms. |
|
872 * special fields: summary, metadata. |
|
873 - summary: matches the first line of the description. |
|
874 - metatadata: It is equivalent to matching 'description user date' |
|
875 (i.e. it matches the main metadata fields). |
|
876 metadata is the default field which is used when no fields are specified. |
|
877 You can match more than one field at a time. |
|
878 """ |
|
879 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments")) |
|
880 |
|
881 revs = getset(repo, xrange(len(repo)), l[0]) |
|
882 |
|
883 fieldlist = ['metadata'] |
|
884 if len(l) > 1: |
|
885 fieldlist = getstring(l[1], |
|
886 _("matching requires a string " |
|
887 "as its second argument")).split() |
|
888 |
|
889 # Make sure that there are no repeated fields, and expand the |
|
890 # 'special' 'metadata' field type |
|
891 fields = [] |
|
892 for field in fieldlist: |
|
893 if field == 'metadata': |
|
894 fields += ['user', 'description', 'date'] |
|
895 else: |
|
896 if field == 'author': |
|
897 field = 'user' |
|
898 fields.append(field) |
|
899 fields = set(fields) |
|
900 |
|
901 # We may want to match more than one field |
|
902 # Each field will be matched with its own "getfield" function |
|
903 # which will be added to the getfieldfuncs array of functions |
|
904 getfieldfuncs = [] |
|
905 _funcs = { |
|
906 'user': lambda r: repo[r].user(), |
|
907 'branch': lambda r: repo[r].branch(), |
|
908 'date': lambda r: repo[r].date(), |
|
909 'description': lambda r: repo[r].description(), |
|
910 'files': lambda r: repo[r].files(), |
|
911 'parents': lambda r: repo[r].parents(), |
|
912 'phase': lambda r: repo[r].phase(), |
|
913 'substate': lambda r: repo[r].substate, |
|
914 'summary': lambda r: repo[r].description().splitlines()[0], |
|
915 } |
|
916 for info in fields: |
|
917 getfield = _funcs.get(info, None) |
|
918 if getfield is None: |
|
919 raise error.ParseError( |
|
920 _("unexpected field name passed to matching: %s") % info) |
|
921 getfieldfuncs.append(getfield) |
|
922 |
|
923 # convert the getfield array of functions into a "getinfo" function |
|
924 # which returns an array of field values (or a single value if there |
|
925 # is only one field to match) |
|
926 if len(getfieldfuncs) == 1: |
|
927 getinfo = getfieldfuncs[0] |
|
928 else: |
|
929 getinfo = lambda r: [f(r) for f in getfieldfuncs] |
|
930 |
|
931 matches = [] |
|
932 for rev in revs: |
|
933 target = getinfo(rev) |
|
934 matches += [r for r in subset if getinfo(r) == target] |
|
935 if len(revs) > 1: |
|
936 matches = sorted(set(matches)) |
|
937 return matches |
|
938 |
861 def reverse(repo, subset, x): |
939 def reverse(repo, subset, x): |
862 """``reverse(set)`` |
940 """``reverse(set)`` |
863 Reverse order of set. |
941 Reverse order of set. |
864 """ |
942 """ |
865 l = getset(repo, subset, x) |
943 l = getset(repo, subset, x) |