bzr-xmloutput-0.8.8+bzr162/LICENSE0000644000000000000000000004311010704262166014563 0ustar 00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. bzr-xmloutput-0.8.8+bzr162/MANIFEST.in0000644000000000000000000000022011536010356015303 0ustar 00000000000000include LICENSE recursive-include docs *.txt recursive-include tests *.py recursive-include extras *.py recursive-include installer *.nsi _lib bzr-xmloutput-0.8.8+bzr162/README0000644000000000000000000001301011333711205014422 0ustar 00000000000000== bzr-xmloutput == This plugin adds an --xml option to log command, an xml version of some builtins command and a xmlrpc service. === Supported commands === * log * xmlstatus * xmlannotate * xmlmissing * xmlinfo * xmlplugins * xmlversion * xmlls * start-xmlrpc * this starts the xmlrpc service, that provides the following functions: * run_bzr: allow to execute any bzr command * run_bzr_xml: similar to run_bzr, but report errors in xml format * search: provides integration with bzr-search (if it's available) * stop-xmlrpc === How to install === There are two main options to install Bazaar plugins, from source or directly from the branch. For further instructions visit: http://bazaar-vcs.org/UsingPlugins. For windows users using bzr standalone installed (bzr.exe), you should use the bzr-xmloutput-setup-x-x-x.exe installer. Notice: If you are installing bzr-xmloutput from the source tarball, the defaut install location is bzrlib/plugins/xmloutput. To change this look the available options running: python setup.py install --help === TODO === * tests for plugins and missing * tags? * testament? === Contributors === * Martin Albisetti * Vincent Ladeuil * Adrian Wilkins * Aaron Bentley * Renato Silva == XML formats == === Log === : contains '''''' entries : represents a commit which can contain: revno, revisionid, committer, branch-nick, timestamp, message, merge, affected-files. : contains '''''' entries. : can contain any of the elements present in '''''' example: {{{ 2872 Canonical.com Patch Queue Manager <fake@no-mail.net> +trunk Fri 2007-09-28 05:14:35 +0100 NEWS bzrlib/errors.py }}} === Status === : it has one attribute: '''workingtree_root''', which is the path to the workingtree root. It can contain: '''modified''', '''unknown''', '''renamed''', '''kind-changed''', '''removed''', '''conflicts''', '''added'''. , , , , , , : contain directory and/or file elements. : contains the relative path to the file, and can contain the following attributes: oldpath, oldkind and newkind, fid. : contains the relative path to the directory, and can contain the following attributes: oldpath, oldkind and newkind, suffix. {{{ !BazaarClient/src/main/org/vcs/bazaar/client/commandline/!CommandLineClient.java !BazaarClient/src/main/org/vcs/bazaar/client/IPlugin.java !BazaarClient/src/main/org/vcs/bazaar/client/commandline/commands/Plugins.java }}} === Missing === '''''': can contain: '''''', '''''' and ''''''. '''''' and '''''': contains a '''''' element. {{{ /Users/guillermo/Projects/BazaarEclipse/bzr-eclipse/trunk/ 116 Guillermo Gonzalez <nospam@mail.com> quickdiff-integration Fri 2007-12-21 19:34:45 -0300 * merge with quickdiff branch }}} === Annotate === : It has two attributes: '''workingtree_root''', which is the path to the workingtree root, and '''file''', which is the file being annotated. : Each represents a line. It has '''revno''', '''author''' and '''date''' as attributes, and contains the text as a value. {{{ This is a test file. It has multiple lines... ...just as an example :) }}} === Info === '''''' is the container for the information provided '''''' displays the current layout '''''' contains the formats the current branch has, '''''' contains the name of the storage format '''''' can contain '''''', '''''' and/or ''''''. These represent paths or URLs. '''''' contains '''''' and ''''''. These represent paths or URLs. Example output: {{{ Repository tree pack-0.92 /home/beuno/test_project . http://bazaar-vcs.org/bzr/bzr.dev/ }}} bzr-xmloutput-0.8.8+bzr162/__init__.py0000644000000000000000000000415711530035270015667 0ustar 00000000000000#!/usr/bin/env python # Copyright (C) 2007-2009 Guillermo Gonzalez # # The code taken from bzrlib is under: Copyright (C) 2005-2007 Canonical Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # # Contributors: # Martin Albisetti """ This plugin adds an option (--xml) to log and provides an xml version of some builtin commands. A xmlrpc service it's also provided, in order to keep bzr loaded in memory and avoid the startup overhead. (most of this is code was modified from bzrlib.cmd_status, bzrlib.status, bzrlib.delta.TreeDelta.show and bzrlib.log.LongLogFormatter) """ import info from bzrlib import ( log, ) from bzrlib.commands import plugin_cmds version_info = info.bzr_plugin_version plugin_name = info.bzr_plugin_name for cmd in [ "xmlstatus", "xmlannotate", "xmlmissing", "xmlinfo", "xmlplugins", "xmlversion", "start_xmlrpc", "stop_xmlrpc", "xmllog", "xmlls"]: plugin_cmds.register_lazy( "cmd_%s" % cmd, [], "bzrlib.plugins.xmloutput.cmds") log.log_formatter_registry.register_lazy('xml', "bzrlib.plugins.xmloutput.logxml", "XMLLogFormatter", 'Detailed XML log format') def load_tests(basic_tests, module, loader): try: testmod_names = [ 'tests', ] basic_tests.addTest(loader.loadTestsFromModuleNames( ["%s.%s" % (__name__, tmn) for tmn in testmod_names])) return basic_tests except ImportError: return None bzr-xmloutput-0.8.8+bzr162/annotatexml.py0000644000000000000000000000667511560251621016474 0ustar 00000000000000#!/usr/bin/env python # -*- encoding: utf-8 -*- # Copyright (C) 2007-2009 Guillermo Gonzalez # # The code taken from bzrlib is under: Copyright (C) 2005-2007 Canonical Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # # Contributors: # Martin Albisetti """ This code is a modified copy from bzrlib.annotate (see there for copyrights and licensing) """ import sys _annotate_file = None try: from bzrlib.annotate import _expand_annotations except ImportError: # to support bzr < 1.8 from bzrlib.annotate import _annotate_file from bzrlib.annotate import _annotations from bzrlib import osutils from writer import _escape_cdata empty_annotation = 'revno="" author="" date=""' def annotate_file_xml(branch, rev_id, file_id, to_file=None, show_ids=False, wt_root_path=None, file_path=None, full=False): """custom annotate_file that spits xml """ if to_file is None: to_file = sys.stdout encoding = getattr(to_file, 'encoding', None) or \ osutils.get_terminal_encoding() prevanno = '' last_rev_id = None to_file.write('') to_file.write(('' % \ (wt_root_path, 'file="%s"' % file_path)).encode(encoding, 'replace')) if _annotate_file: # bzr < 1.8 annotations = _annotations(branch.repository, file_id, rev_id) annotation = list(_annotate_file(branch, rev_id, file_id)) else: tree = branch.repository.revision_tree(rev_id) annotations = tree.annotate_iter(file_id) annotation = list(_expand_annotations(annotations, branch)) for (revno_str, author, date_str, line_rev_id, text, origin) in _annotation_iter(annotation, annotations): if not show_ids: origin = None prevanno = _show_entry(to_file, prevanno, revno_str, author, date_str, line_rev_id, text, origin) to_file.write('') def _annotation_iter(annotation, annotations): """a annotaion iterator """ for ((revno_str, author, date_str, line_rev_id, text), \ (origin, text_dup)) in zip(annotation, annotations): yield (revno_str, author, date_str, line_rev_id, text, origin) def _show_entry(to_file, prevanno, revno_str, author, date_str, line_rev_id, text, fid): """output one entry of the annotation""" anno = 'revno="%s" author="%s" date="%s"' % \ (_escape_cdata(revno_str), _escape_cdata(author), date_str) if anno.lstrip() == empty_annotation: anno = prevanno if fid: to_file.write('%s' % \ (anno, fid, _escape_cdata(text))) else: to_file.write('' % anno) to_file.write('%s' % _escape_cdata(text)) return anno bzr-xmloutput-0.8.8+bzr162/client.py0000755000000000000000000000424111066565624015422 0ustar 00000000000000#!/usr/bin/env python # -*- encoding: utf-8 -*- # Copyright (C) 2007 Guillermo Gonzalez # # The code taken from bzrlib is under: Copyright (C) 2005, 2006, 2007 Canonical Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # from xmlrpclib import Server, Error import os import sys from bzrlib import osutils def setup_outf(encoding_type='replace'): """Return a file linked to stdout, which has proper encoding.""" import codecs import bzrlib if encoding_type == 'exact': # force sys.stdout to be binary stream on win32 if sys.platform == 'win32': fileno = getattr(sys.stdout, 'fileno', None) if fileno: import msvcrt msvcrt.setmode(fileno(), os.O_BINARY) outf = sys.stdout return output_encoding = osutils.get_terminal_encoding() outf = codecs.getwriter(output_encoding)(sys.stdout, errors=encoding_type) outf.encoding = output_encoding return outf def main(argv=[]): server = Server("http://localhost:11111") try: args = ['bzr'] [args.append(arg) for arg in argv[1:]] exit_val, out, err = server.run_bzr_command(args, os.getcwd()) outf = setup_outf() outf.write(out.data.decode(osutils.get_terminal_encoding(), 'replace')) sys.stderr.write(err) outf.flush(); sys.stderr.flush(); sys.exit(exit_val) except Error, exc: sys.stderr.write(exc.__repr__()) raise if __name__ == '__main__': main(sys.argv)bzr-xmloutput-0.8.8+bzr162/cmds.py0000644000000000000000000003412611720666205015066 0ustar 00000000000000#!/usr/bin/env python # Copyright (C) 2007-2009 Guillermo Gonzalez # # The code taken from bzrlib is under: Copyright (C) 2005-2007 Canonical Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # # Contributors: # Martin Albisetti import info import bzrlib from bzrlib.option import Option from bzrlib.commands import ( Command, display_command, ) from bzrlib.lazy_import import lazy_import lazy_import(globals(), """ import sys from bzrlib import ( builtins, bzrdir, log, workingtree, errors ) from bzrlib.plugins.xmloutput import ( logxml, service, ) import socket """) from bzrlib.plugins.xmloutput.xml_errors import handle_error_xml version_info = info.bzr_plugin_version plugin_name = info.bzr_plugin_name null_option = Option('null', help='Write an ascii NUL (\\0) as the final char.') class cmd_xmlstatus(Command): """Display status summary. This reports on versioned and unknown files, reporting them grouped by state. Possible states are: added Versioned in the working copy but not in the previous revision. removed Versioned in the previous revision but removed or deleted in the working copy. renamed Path of this file changed from the previous revision; the text may also have changed. This includes files whose parent directory was renamed. modified Text has changed since the previous revision. kind changed File kind has been changed (e.g. from file to directory). unknown Not versioned and not matching an ignore pattern. To see ignored files use 'bzr ignored'. For details on the changes to file texts, use 'bzr diff'. Note that --short or -S gives status flags for each item, similar to Subversion's status command. To get output similar to svn -q, use bzr -SV. If no arguments are specified, the status of the entire working directory is shown. Otherwise, only the status of the specified files or directories is reported. If a directory is given, status is reported for everything inside that directory. If a revision argument is given, the status is calculated against that revision, or between two revisions if two are provided. """ hidden = True takes_args = ['file*'] takes_options = ['show-ids', 'revision', 'change', Option('versioned', help='Only show versioned files.', short_name='V'), null_option ] encoding_type = 'replace' @display_command @handle_error_xml def run(self, file_list=None, revision=None, versioned=False, null=False): from statusxml import show_tree_status_xml tree, file_list = builtins.tree_files(file_list) to_file = self.outf if to_file is None: to_file = sys.stdout show_tree_status_xml(tree, show_ids=True, specific_files=file_list, revision=revision, to_file=to_file, versioned=versioned) if null: to_file.write('\0') self.outf.write('\n') class cmd_xmlannotate(Command): """Show the origin of each line in a file. This prints out the given file with an annotation on the left side indicating which revision, author and date introduced the change. If the origin is the same for a run of consecutive lines, it is shown only at the top, unless the --all option is given. """ hidden = True takes_args = ['filename'] takes_options = ['revision', 'show-ids', null_option] encoding_type = 'exact' @display_command @handle_error_xml def run(self, filename, revision=None, show_ids=False, null=False): from annotatexml import annotate_file_xml wt, branch, relpath = \ bzrdir.BzrDir.open_containing_tree_or_branch(filename) if wt is not None: wt.lock_read() else: branch.lock_read() wt_root_path = wt.id2abspath(wt.get_root_id()) try: if revision is None: revision_id = branch.last_revision() elif len(revision) != 1: raise bzrlib.errors.BzrCommandError( 'xmlannotate --revision takes exactly 1 argument') else: revision_id = revision[0].in_history(branch).rev_id tree = branch.repository.revision_tree(revision_id) if wt is not None: file_id = wt.path2id(relpath) else: file_id = tree.path2id(relpath) if file_id is None: raise bzrlib.errors.NotVersionedError(filename) file_version = tree.get_file_revision(file_id) # always run with --all and --long options # to get the author of each line annotate_file_xml(branch=branch, rev_id=file_version, file_id=file_id, to_file=self.outf, show_ids=show_ids, wt_root_path=wt_root_path, file_path=relpath) if null: self.outf.write('\0') self.outf.write('\n') finally: if wt is not None: wt.unlock() else: branch.unlock() class cmd_xmlmissing(Command): """Show unmerged/unpulled revisions between two branches. OTHER_BRANCH may be local or remote. """ hidden = True takes_args = ['other_branch?'] takes_options = [ Option('reverse', 'Reverse the order of revisions.'), Option('mine-only', 'Display changes in the local branch only.'), Option('this' , 'Same as --mine-only.'), Option('theirs-only', 'Display changes in the remote branch only.'), Option('other', 'Same as --theirs-only.'), 'show-ids', 'verbose', null_option ] encoding_type = 'replace' @display_command @handle_error_xml def run(self, *args, **kwargs): from missingxml import show_missing_xml if self.outf is None: self.outf = sys.stdout show_missing_xml(self, log_format=logxml.XMLLogFormatter, *args, **kwargs) if getattr(kwargs, 'null', False): self.outf.write('\0') self.outf.write('\n') class cmd_xmlinfo(Command): """Show information about a working tree, branch or repository. This command will show all known locations and formats associated to the tree, branch or repository. Statistical information is included with each report. Branches and working trees will also report any missing revisions. """ hidden = True takes_args = ['location?'] takes_options = ['verbose', null_option] encoding_type = 'replace' @display_command @handle_error_xml def run(self, *args, **kwargs): location = None if kwargs.has_key('location'): location = kwargs['location'] if kwargs.has_key('verbose') and kwargs['verbose']: noise_level = 2 else: noise_level = 0 from infoxml import show_bzrdir_info_xml if location != None: from bzrlib.urlutils import normalize_url location = normalize_url(location) show_bzrdir_info_xml(bzrdir.BzrDir.open_containing(location)[0], verbose=noise_level, outfile=self.outf) if getattr(kwargs, 'null', False): self.outf.write('\0') self.outf.write('\n') class cmd_xmlplugins(Command): """List the installed plugins. This command displays the list of installed plugins including version of plugin and a short description of each. """ hidden = True takes_options = ['verbose', null_option] @display_command @handle_error_xml def run(self, *args, **kwargs): import bzrlib.plugin from inspect import getdoc if self.outf is None: self.outf = sys.stdout self.outf.write('' % \ bzrlib.osutils.get_user_encoding()) self.outf.write('') from writer import _escape_cdata for name, plugin in bzrlib.plugin.plugins().items(): self.outf.write('') self.outf.write('%s' % name) self.outf.write('%s' % plugin.__version__) self.outf.write('%s' % plugin.path()) d = getdoc(plugin.module) if d: self.outf.write('%s' % _escape_cdata(d)) self.outf.write('') self.outf.write('') if getattr(kwargs, 'null', False): self.outf.write('\0') self.outf.write('\n') class cmd_xmlversion(Command): """Show version of bzr.""" hidden = True encoding_type = 'replace' takes_options = [Option("short", help="Only print the version number."), null_option] @display_command @handle_error_xml def run(self, short=False, null=False): from versionxml import show_version_xml to_file = self.outf if to_file is None: to_file = sys.stdout self.outf.write('' % \ bzrlib.osutils.get_user_encoding()) if short: to_file.write("" + \ bzrlib.version_string + \ "") else: show_version_xml(to_file=to_file) if null: to_file.write('\0') to_file.write('\n') def xmllog_options(): # Take a copy of the log options before modifying it opts = builtins.cmd_log.takes_options[:] opts.append(null_option) # Remove log_format since we requires our own opts.remove('log-format') return opts class cmd_xmllog(builtins.cmd_log): """Show log of a branch, file, or directory as XML.""" hidden = True takes_options = xmllog_options() @display_command @handle_error_xml def run(self, *args, **kwargs): # Force our specific formatter kwargs['log_format'] = logxml.XMLLogFormatter # Filter out our specific option try: null = kwargs.pop('null') except KeyError: null = False exit_val = builtins.cmd_log.run(self, *args, **kwargs) if null: self.outf.write('\0') self.outf.write('\n') return exit_val class cmd_xmlls(builtins.cmd_ls): """XML representation of the list of files in a tree. """ hidden = True _see_also = ['xmlstatus'] takes_args = ['path?'] # TODO: Take a revision or remote path and list that tree instead. takes_options = [ 'verbose', 'revision', Option('non-recursive', help='Don\'t recurse into subdirectories.'), Option('from-root', help='Print paths relative to the root of the branch.'), Option('unknown', help='Print unknown files.'), Option('versioned', help='Print versioned files.', short_name='V'), Option('ignored', help='Print ignored files.'), Option('kind', help='List entries of a particular kind: file, ' + \ 'directory, symlink.', type=unicode), null_option ] encoding_type = 'replace' @display_command @handle_error_xml def run(self, *args, **kwargs): import lsxml null = kwargs.pop('null', False) self.outf.write('' % \ bzrlib.osutils.get_user_encoding()) lsxml.show_ls_xml(self.outf, *args, **kwargs) if null: self.outf.write('\0') self.outf.write('\n') class cmd_start_xmlrpc(Command): """Start the xmlrpc service.""" hidden = True takes_options = [ Option('hostname', argname='HOSTNAME', type=str, help='Use the specified hostname, defaults to localhost.'), Option('port', argname='PORT', type=int, help='Use the specified port, defaults to 11111.'), 'verbose', ] @display_command def run(self, port=11111, hostname='localhost', verbose=False): if hostname is None: hostname = socket.gethostname() if verbose: self.outf.write('Listening on http://'+hostname+':'+str(port)+'\n') self.outf.flush() self.server = service.BzrXMLRPCServer((hostname, port), logRequests=verbose, to_file=self.outf) try: self.server.serve_forever() finally: self.server.shutdown() class cmd_stop_xmlrpc(Command): """Stops a xmlrpc service.""" hidden = True takes_options = [ Option('hostname', argname='HOSTNAME', type=str, help='Use the specified hostname, defaults to localhost.'), Option('port', argname='PORT', type=int, help='Use the specified port, defaults to 11111.'), 'verbose', ] @display_command def run(self, port=11111, hostname='localhost', verbose=False): url = "http://"+hostname+":"+str(port) if verbose: self.outf.write('Stopping xmlrpc service on ' + url + '\n') self.outf.flush() from xmlrpclib import Server server = Server(url) server.quit() bzr-xmloutput-0.8.8+bzr162/docs/0000755000000000000000000000000011071267653014513 5ustar 00000000000000bzr-xmloutput-0.8.8+bzr162/extras/0000755000000000000000000000000011071267653015071 5ustar 00000000000000bzr-xmloutput-0.8.8+bzr162/info.py0000644000000000000000000000203411655143375015071 0ustar 00000000000000#!/usr/bin/env python # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ API Info for bzr-xmloutput """ bzr_plugin_name = "xmloutput" # See bzrlib/__init__.py for the definition of version tuple format bzr_plugin_version = (0, 8, 8, 'final', 0) bzr_commands = ['xmlannotate', 'xmlinfo', 'xmlmissing', 'xmllog', 'xmlls', 'xmlplugins', 'xmlversion', 'start-xmlrpc', 'stop-xmlrpc'] bzr-xmloutput-0.8.8+bzr162/infoxml.py0000644000000000000000000002574011720667621015621 0ustar 00000000000000#!/usr/bin/env python # -*- encoding: utf-8 -*- # Copyright (C) 2007-2009 Guillermo Gonzalez # # The code taken from bzrlib is under: Copyright (C) 2005-2007 Canonical Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # # Contributors: # Martin Albisetti """This code is a modified copy from bzrlib.info (see there for copyrights and licensing) """ __all__ = ['show_bzrdir_info_xml'] from bzrlib import info from bzrlib.lazy_import import lazy_import lazy_import(globals(), """ import os, sys, time from bzrlib import ( bzrdir, diff, errors, osutils, urlutils, missing, ) """) from bzrlib.errors import (NoWorkingTree, NotBranchError, NoRepositoryPresent, NotLocalUrl) def get_lines_xml(self): """Returns the locations lines as xml.""" return ["<%s>%s" % (l.replace(' ', '_'), u, l.replace(' ', '_')) \ for l, u in self.locs ] info.LocationList.get_lines_xml = get_lines_xml def show_bzrdir_info_xml(a_bzrdir, verbose=False, outfile=None): """Output to stdout the 'info' for a_bzrdir.""" if outfile is None: outfile = sys.stdout try: tree = a_bzrdir.open_workingtree( recommend_upgrade=False) except (NoWorkingTree, NotLocalUrl): tree = None try: branch = a_bzrdir.open_branch() except NotBranchError: branch = None try: repository = a_bzrdir.open_repository() except NoRepositoryPresent: # Return silently; cmd_info already returned NotBranchError # if no bzrdir could be opened. return else: lockable = repository else: repository = branch.repository lockable = branch else: branch = tree.branch repository = branch.repository lockable = tree lockable.lock_read() try: outfile.write('') outfile.write('') show_component_info_xml(a_bzrdir, repository, branch, tree, verbose, outfile) outfile.write('') finally: lockable.unlock() def show_component_info_xml(control, repository, branch=None, working=None, verbose=1, outfile=None): """Write info about all bzrdir components to stdout""" if outfile is None: outfile = sys.stdout if verbose is False: verbose = 1 if verbose is True: verbose = 2 layout = info.describe_layout(repository, branch, working, control) formats = info.describe_format(control, repository, branch, working).split(' or ') outfile.write('%s' % layout) outfile.write('') if len(formats) > 1: for format in formats: outfile.write('%s' % format) else: outfile.write('%s' % formats[0]) outfile.write('') _show_location_info_xml(info.gather_location_info(repository, branch, working), outfile) if branch is not None: _show_related_info_xml(branch, outfile) if verbose == 0: return _show_format_info_xml(control, repository, branch, working, outfile) _show_locking_info_xml(repository, branch, working, outfile) if branch is not None: _show_missing_revisions_branch_xml(branch, outfile) if working is not None: _show_working_stats_xml(working, outfile) elif branch is not None: _show_missing_revisions_branch_xml(branch, outfile) if branch is not None: stats = _show_branch_stats_xml(branch, verbose==2, outfile) else: stats = repository.gather_stats() if branch is None and working is None: _show_repository_info_xml(repository, outfile) _show_repository_stats_xml(stats, outfile) def _show_location_info_xml(locs, outfile): """Show known locations for working, branch and repository.""" outfile.write('') path_list = info.LocationList(osutils.getcwd()) for name, loc in locs: path_list.add_url(name, loc) outfile.writelines(path_list.get_lines_xml()) outfile.write('') def _show_related_info_xml(branch, outfile): """Show parent and push location of branch.""" locs = info._gather_related_branches(branch) if len(locs.locs) > 0: outfile.write('') outfile.writelines(locs.get_lines_xml()) outfile.write('') def _show_format_info_xml(control=None, repository=None, branch=None, working=None, outfile=None): """Show known formats for control, working, branch and repository.""" outfile.write('') if control: outfile.write('%s' % control._format.get_format_description()) if working: outfile.write('%s' % working._format.get_format_description()) if branch: outfile.write('%s' % branch._format.get_format_description()) if repository: outfile.write('%s' % repository._format.get_format_description()) outfile.write('') def _show_locking_info_xml(repository, branch=None, working=None, outfile=None): """Show locking status of working, branch and repository.""" if (repository.get_physical_lock_status() or (branch and branch.get_physical_lock_status()) or (working and working.get_physical_lock_status())): outfile.write('') if working: if working.get_physical_lock_status(): status = 'locked' else: status = 'unlocked' outfile.write('%s' % status) if branch: if branch.get_physical_lock_status(): status = 'locked' else: status = 'unlocked' outfile.write('%s' % status) if repository: if repository.get_physical_lock_status(): status = 'locked' else: status = 'unlocked' outfile.write('%s' % status) outfile.write('') def _show_missing_revisions_branch_xml(branch, outfile): """Show missing master revisions in branch.""" # Try with inaccessible branch ? master = branch.get_master_branch() if master: local_extra, remote_extra = missing.find_unmerged(branch, master) if remote_extra: outfile.write('') outfile.write('%d' % len(remote_extra)) outfile.write('') def _show_missing_revisions_working_xml(working, outfile): """Show missing revisions in working tree.""" branch = working.branch basis = working.basis_tree() branch_revno, branch_last_revision = branch.last_revision_info() try: tree_last_id = working.get_parent_ids()[0] except IndexError: tree_last_id = None if branch_revno and tree_last_id != branch_last_revision: tree_last_revno = branch.revision_id_to_revno(tree_last_id) missing_count = branch_revno - tree_last_revno outfile.write('%d' % missing_count) def _show_working_stats_xml(working, outfile): """Show statistics about a working tree.""" basis = working.basis_tree() delta = working.changes_from(basis, want_unchanged=True) outfile.write('') _show_missing_revisions_working_xml(working, outfile) outfile.write('%s' % len(delta.unchanged)) outfile.write('%d' % len(delta.modified)) outfile.write('%d' % len(delta.added)) outfile.write('%d' % len(delta.removed)) outfile.write('%d' % len(delta.renamed)) ignore_cnt = unknown_cnt = 0 for path in working.extras(): if working.is_ignored(path): ignore_cnt += 1 else: unknown_cnt += 1 outfile.write('%d' % unknown_cnt) outfile.write('%d' % ignore_cnt) dir_cnt = 0 for path, entry in working.iter_entries_by_dir(): if entry.kind == 'directory' and entry.parent_id is not None: dir_cnt += 1 outfile.write('%d' % (dir_cnt)) outfile.write('') def _show_branch_stats_xml(branch, verbose, outfile): """Show statistics about a branch.""" revno, head = branch.last_revision_info() outfile.write('') outfile.write('%d' % (revno)) stats = branch.repository.gather_stats(head, committers=verbose) if verbose: committers = stats['committers'] outfile.write('%d' % (committers)) if revno: timestamp, timezone = stats['firstrev'] age = int((time.time() - timestamp) / 3600 / 24) outfile.write('%d' % (age)) outfile.write('%s' % \ osutils.format_date(timestamp, timezone)) timestamp, timezone = stats['latestrev'] outfile.write('%s' % \ osutils.format_date(timestamp, timezone)) outfile.write('') return stats def _show_repository_info_xml(repository, outfile): """Show settings of a repository.""" ## FIXME/TODO: is this needed in the xml output? #if repository.make_working_trees(): # print 'Create working tree for new branches inside the repository.' def _show_repository_stats_xml(stats, outfile): """Show statistics about a repository.""" if 'revisions' in stats or 'size' in stats: outfile.write('') if 'revisions' in stats: revisions = stats['revisions'] outfile.write('%d' % (revisions)) if 'size' in stats: outfile.write('%d' % (stats['size']/1024)) if 'revisions' in stats or 'size' in stats: outfile.write('') bzr-xmloutput-0.8.8+bzr162/installer/0000755000000000000000000000000011071267653015560 5ustar 00000000000000bzr-xmloutput-0.8.8+bzr162/logxml.py0000644000000000000000000002253211671414652015442 0ustar 00000000000000# -*- encoding: utf-8 -*- from bzrlib import log from bzrlib.lazy_import import lazy_import lazy_import(globals(), """ import bzrlib from bzrlib import ( debug, osutils, ) """) from writer import _escape_cdata class XMLLogFormatter(log.LogFormatter): """ add a --xml format to 'bzr log'""" supports_merge_revisions = True supports_delta = True supports_tags = True def __init__(self, *args, **kwargs): super(XMLLogFormatter, self).__init__(*args, **kwargs) self.log_count = 0 self.start_with_merge = False self.nested_merge_count = 0 self.previous_merge_depth = 0 self.debug_enabled = 'debug' in debug.debug_flags self.open_logs = 0 self.open_merges = 0 self.stack = [] def show(self, revno, rev, delta, tags=None): lr = log.LogRevision(rev, revno, 0, delta, tags) return self.log_revision(lr) def show_merge_revno(self, rev, merge_depth, revno): """a call to self._show_helper, XML don't care about formatting """ lr = log.LogRevision(rev, merge_depth=merge_depth, revno=revno) return self.log_revision(lr) def log_revision(self, revision): """Log a revision, either merged or not.""" to_file = self.to_file if self.debug_enabled: self.__debug(revision) actions = [] # to handle merge revision as childs if revision.merge_depth > 0 and not self.start_with_merge: if self.previous_merge_depth < revision.merge_depth: if self.log_count > 0: merge_depth_diference = revision.merge_depth - \ self.previous_merge_depth for m in range(merge_depth_diference): actions.append(self.__open_merge) if merge_depth_diference > 1: self.nested_merge_count += 1 elif self.log_count == 0: # first log is inside a merge, we show it as a top level # we could support a merge tag without parent log. self.start_with_merge = True elif self.previous_merge_depth > revision.merge_depth: # TODO: testcase for more than one level of nested merges actions.append({self.__close_merge:self.previous_merge_depth - \ revision.merge_depth}) if self.nested_merge_count > 0: self.nested_merge_count -= 1 else: actions.append(self.__close_log) else: if self.open_logs > 0: actions.append(self.__close_log) elif self.previous_merge_depth < revision.merge_depth: actions.append({self.__close_merge:self.previous_merge_depth - \ revision.merge_depth}) if self.nested_merge_count > 0: self.nested_merge_count -= 1 else: actions.append(self.__close_log) elif self.open_merges > 0: actions.append({self.__close_merge:self.open_merges}) #actions.append(self.__close_merge) actions.append(self.__close_log) else: actions.append(self.__close_log) if self.start_with_merge: # we only care about the first log, the following logs are # handlend in the logic of nested merges self.start_with_merge = False for action in actions: if type(action) == dict: action.keys()[0](action[action.keys()[0]]) else: action() self.__open_log() self.__log_revision(revision) self.log_count = self.log_count + 1 self.previous_merge_depth = revision.merge_depth def __open_merge(self): self.to_file.write('') self.open_merges += 1 self.stack.append('merge') def __close_merge(self, num=1): for item in self.stack.__reversed__(): self.to_file.write('' % item) self.stack.pop() if item == 'merge': self.open_merges -= 1 num -= 1 if num == 0: return if item == 'log': self.open_logs -= 1 def __open_log(self): self.to_file.write('',) self.open_logs = self.open_logs + 1 self.stack.append('log') def __close_log(self): for item in self.stack.__reversed__(): self.to_file.write('' % item) self.stack.pop() if item == 'log': self.open_logs -= 1 return if item == 'merge': self.open_merges -= 1 def __log_revision(self, revision): if revision.revno is not None: self.to_file.write('%s' % revision.revno) if revision.tags: self.to_file.write('') for tag in revision.tags: self.to_file.write('%s' % tag) self.to_file.write('') if self.show_ids: self.to_file.write('%s' % revision.rev.revision_id) if len(revision.rev.parent_ids) > 0: self.to_file.write('') for parent_id in revision.rev.parent_ids: self.to_file.write('%s' % parent_id) if len(revision.rev.parent_ids) > 0: self.to_file.write('') self.to_file.write('%s' % \ _escape_cdata(revision.rev.committer)) try: self.to_file.write('%s' % \ _escape_cdata(revision.rev.properties['branch-nick'])) except KeyError: pass date_str = osutils.format_date(revision.rev.timestamp, revision.rev.timezone or 0, self.show_timezone) self.to_file.write('%s' % date_str) self.to_file.write('') if revision.delta is not None: from statusxml import show_tree_xml self.to_file.write('') show_tree_xml(revision.delta, self.to_file, self.show_ids) self.to_file.write('') def begin_log(self): self.to_file.write('' % \ osutils.get_user_encoding()) self.to_file.write('') def end_log(self): #if the last logged was inside a merge (and it was only one log) if self.open_logs > 1 and self.open_merges > 0: self.to_file.write('') self.open_logs = self.open_logs - 1 if not self.start_with_merge: # In case that the last log was inside a merge we need to close it if self.open_merges > 0: for merge in range(self.open_merges): self.to_file.write('') if self.open_logs > 0: self.to_file.write('') self.open_logs -= 1 self.open_merges = self.open_merges - 1 # to close the last opened log if self.open_logs > 0: self.to_file.write('') self.open_logs = self.open_logs - 1 else: if self.open_logs > 0: self.to_file.write('') self.open_logs = self.open_logs - 1 self.to_file.write('') class XMLLineLogFormatter(log.LineLogFormatter): def __init__(self, *args, **kwargs): super(XMLLineLogFormatter, self).__init__(*args, **kwargs) def log_string(self, revno, rev, max_chars=50): """Format log info into one string style. Don't truncate the string like LineLogFormatter because we are writting xml, and don't make sense to truncate the string. :param revno: revision number (int) or None. Revision numbers counts from 1. :param rev: revision info object :return: formatted truncated string """ out = [] out.append('') if revno: # show revno only when is not None out.append("%s" % revno) elif rev.revision_id: out.append("%s" % rev.revision_id) out.append('%s' % _escape_cdata(rev.committer)) date_str = osutils.format_date(rev.timestamp, rev.timezone or 0, show_offset=True) out.append('%s' % date_str) out.append('' % \ _format_message(rev.message)) out.append('') return " ".join(out).rstrip('\n') def line_log(rev): lf = XMLLineLogFormatter(None) return lf.log_string(None, rev) def _format_message(rev_message): return rev_message.rstrip('\n') bzr-xmloutput-0.8.8+bzr162/lsxml.py0000644000000000000000000000667611671414652015312 0ustar 00000000000000#!/usr/bin/env python # -*- encoding: utf-8 -*- # Copyright (C) 2008 Mirko Friedenhagen # # The code taken from bzrlib is under: Copyright (C) 2005, 2006, 2007 Canonical Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # from bzrlib.lazy_import import lazy_import lazy_import(globals(), """ from bzrlib import bzrdir, errors, osutils """) from writer import _escape_cdata def show_ls_xml(outf, revision=None, non_recursive=False, from_root=False, unknown=False, versioned=False, ignored=False, kind=None, path=None, verbose=False): if kind and kind not in ('file', 'directory', 'symlink'): raise errors.BzrCommandError('invalid kind specified') all = not (unknown or versioned or ignored) selection = {'I':ignored, '?':unknown, 'V':versioned} long_status_kind = {'I':'ignored', '?':'unknown', 'V':'versioned'} if path is None: fs_path = '.' else: if from_root: raise errors.BzrCommandError('cannot specify both --from-root' ' and PATH') fs_path = path tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch( fs_path) prefix = None if from_root: if relpath: prefix = relpath + '/' elif fs_path != '.': prefix = fs_path + '/' if revision is not None: tree = branch.repository.revision_tree( revision[0].as_revision_id(branch)) elif tree is None: tree = branch.basis_tree() tree.lock_read() try: outf.write('') for fp, fc, fkind, fid, entry in tree.list_files(include_root=False, from_dir=relpath, recursive=not non_recursive): if not all and not selection[fc]: continue if kind is not None and fkind != kind: continue if prefix: fp = osutils.pathjoin(prefix, fp) if fid is None: fid = '' else: fid = '%s' % _escape_cdata(fid) fkind = '%s' % fkind status_kind = '%s' % long_status_kind[fc] fpath = '%s' % _escape_cdata(fp) if fc == 'I' and ignored: # get the pattern if tree.basedir in fp: pat = tree.is_ignored(tree.relpath(fp)) else: pat = tree.is_ignored(fp) pattern = '%s' % _escape_cdata(pat) else: pattern = '' outstring = '%s%s%s%s%s' % (fid, fkind, fpath, status_kind, pattern) outf.write(outstring) finally: outf.write('') tree.unlock() bzr-xmloutput-0.8.8+bzr162/missingxml.py0000644000000000000000000001200011333712420016304 0ustar 00000000000000#!/usr/bin/env python # -*- encoding: utf-8 -*- # Copyright (C) 2007-2009 Martin Albisetti # # The code taken from bzrlib is under: Copyright (C) 2005-2007 Canonical Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # # Contributors: # Guillermo Gonzalez # (most of this code was modified from bzrlib.cmd_missing and bzrlib.missing) """Show unmerged/unpulled revisions between two branches. OTHER_BRANCH may be local or remote. """ from bzrlib import ui, urlutils, errors, osutils from bzrlib.branch import Branch from bzrlib.log import LogRevision, log_formatter, log_formatter_registry from bzrlib.missing import ( iter_log_revisions, find_unmerged) def show_missing_xml(self, other_branch=None, reverse=False, mine_only=False, theirs_only=False, log_format=None, long=False, short=False, line=False, show_ids=False, verbose=False, this=False, other=False): """output missing info as xml""" if this: mine_only = this if other: theirs_only = other local_branch = Branch.open_containing(u".")[0] parent = local_branch.get_parent() if other_branch is None: other_branch = parent if other_branch is None: raise errors.BzrCommandError("No peer location known" " or specified.") display_url = urlutils.unescape_for_display(parent, self.outf.encoding) remote_branch = Branch.open(other_branch) if remote_branch.base == local_branch.base: remote_branch = local_branch local_branch.lock_read() try: remote_branch.lock_read() self.outf.write('' % \ osutils.get_user_encoding()) self.outf.write('') try: self.outf.write('' + display_url + \ '') local_extra, remote_extra = find_unmerged(local_branch, remote_branch) if log_format is None: registry = log_formatter_registry log_format = registry.get_default(local_branch) if reverse is False: local_extra.reverse() remote_extra.reverse() if local_extra and not theirs_only: self.outf.write('' % len(local_extra)) if local_extra > 0: lf = log_format(to_file=self.outf, show_ids=show_ids, show_timezone='original') showlogs(self, iter_log_revisions(local_extra, local_branch.repository, verbose), lf) self.outf.write('') if remote_extra and not mine_only: self.outf.write('' % len(remote_extra)) if remote_extra > 0: lf = log_format(to_file=self.outf, show_ids=show_ids, show_timezone='original') showlogs(self, iter_log_revisions(remote_extra, remote_branch.repository, verbose), lf) self.outf.write('') if not remote_extra and not local_extra: status_code = 0 # self.outf.write("Branches are up to date.\n") else: status_code = 1 finally: remote_branch.unlock() finally: self.outf.write('') local_branch.unlock() if not status_code and parent is None and other_branch is not None: local_branch.lock_write() try: # handle race conditions - a parent might be set while we run. if local_branch.get_parent() is None: local_branch.set_parent(remote_branch.base) finally: local_branch.unlock() return status_code def showlogs(self, iterator, lf): """Show the logs for missing (using line)""" self.outf.write('') for revision in iterator: lf.log_revision(revision) lf.end_log() bzr-xmloutput-0.8.8+bzr162/search.py0000644000000000000000000000732111054434671015402 0ustar 00000000000000# Copyright (C) 2008 Martin Albisetti # Copyright (C) 2008 Robert Collins # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # import os, sys from service import redirect_output from xml_errors import XMLError from bzrlib.errors import EXIT_ERROR try: from bzrlib.plugins.search import errors from bzrlib.plugins.search import index as _mod_index from bzrlib.plugins.search.index import FileTextHit, RevisionHit, PathHit except ImportError: _mod_index = None is_available = _mod_index is not None @redirect_output def search(branch_location, query_list, suggest=False): """Search using bzr-search plugin to find revisions matching the query. param branch_location: location of the branch to search in param query_list: string to search param suggest: Optional flag to request suggestions instead of results return: A dict containing a list for each type of hit, i.e: {'file_hits':[], 'path_hits':[], 'revid_hits':[]} """ if _mod_index is None: return None # None indicates could-not-search try: index = _mod_index.open_index_url(branch_location) except errors.NoSearchIndex, e: sys.stderr.write(str(XMLError(e))) sys.stderr.flush(); sys.stdout.flush(); return (EXIT_ERROR, sys.stdout.getvalue(), sys.stderr.getvalue()) query = query_list query = [(term,) for term in query] file_hits = [] path_hits = [] revid_hits = [] index._branch.lock_read() try: if suggest: terms = index.suggest(query) terms = list(terms) terms.sort() return terms else: seen_count = 0 for result in index.search(query): if isinstance(result, FileTextHit): file_hits.append(get_file_text_hit_dict(result)) if isinstance(result, PathHit): path_hits.append(result.document_name()) elif isinstance(result, RevisionHit): revid_hits.append(get_revision_hit_dict(result)) seen_count += 1 if seen_count == 0: raise errors.NoMatch(query_list) finally: index._branch.unlock() return {'file_hits':file_hits, 'path_hits':path_hits, 'revid_hits':revid_hits} def get_file_text_hit_dict(file_text_hit): """Converts a TextHit into a dict conatining the revid and path""" path = file_text_hit.index.search((file_text_hit.text_key,)).next() revision_id = file_text_hit.text_key[1] return {'revid':revision_id, 'path':path.document_name()} def get_revision_hit_dict(revision_hit): """Converts a RevisionHit into a dict conatining: revid, author, message, timestamp, timezone and properties""" revision = revision_hit.repository.get_revision( revision_hit.revision_key[-1]) return {'revid':revision.revision_id, 'author':revision.get_apparent_author(), 'message':revision.message, 'timestamp':revision.timestamp, 'timezone':revision.timezone, 'properties':revision.properties} bzr-xmloutput-0.8.8+bzr162/service.py0000644000000000000000000001427511671414652015605 0ustar 00000000000000#!/usr/bin/env python # -*- encoding: utf-8 -*- # Copyright (C) 2008-2009 Guillermo Gonzalez # # The code taken from bzrlib is under: Copyright (C) 2005-2008 Canonical Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # """ xmlrpc service module """ import os from bzrlib.lazy_import import lazy_import lazy_import(globals(), """ import bzrlib from bzrlib import ( commands, trace, errors, osutils ) import sys import codecs import logging import traceback from cStringIO import StringIO """) from bzrlib.plugins.xmloutput.xml_errors import XMLError from xmlrpclib import Fault, Binary from SimpleXMLRPCServer import SimpleXMLRPCServer run_dir = os.getcwdu() class BzrXMLRPCServer(SimpleXMLRPCServer): """ Very simple xmlrpc server to handle bzr commands and search""" finished = False def __init__(self, addr, logRequests=False, to_file=None): SimpleXMLRPCServer.__init__(self, addr=addr, logRequests=logRequests) self.register_function(self.system_listMethods, 'list_methods') self.register_function(self.shutdown, 'quit') self.register_function(self.hello) register_functions(self) self.to_file = to_file if to_file is None: self.to_file = sys.stdout def register_signal(self, signum): """register a signal using self.signal_handler""" signal.signal(signum, self.signal_handler) def signal_handler(self, signum, frame): """signal handler, shutdown by default""" print "Caught signal", signum self.shutdown() def shutdown(self): """ stop serving and return 1 """ self.finished = True self.server_close() return 1 def serve_forever(self): """Start serving, and block""" import bzrlib.osutils default_encoding = 'UTF-8' if hasattr(bzrlib, 'user_encoding'): bzrlib.user_encoding = default_encoding bzrlib.osutils.bzrlib.user_encoding = default_encoding bzrlib.osutils._cached_user_encoding = default_encoding self.encoding = default_encoding # support new super lazy commands (bzr-1.17) if getattr(commands, 'install_bzr_command_hooks'): commands.install_bzr_command_hooks() while not self.finished: self.handle_request() def hello(self): """ simple reply to hello request, 'world!'""" return 'world!' class redirect_output(object): """decorator to redirect stdout/err to a StringIO""" def __init__(self, func): self.writer_factory = codecs.getwriter('utf8') self.func = func self.logger_removed = False def __call__(self, *args, **kwargs): if self.logger_removed: self.remove_logger() trace.mutter('%s arguments: %s' % (self.func.func_name, str(args))) sys.stdout = StringIO() sys.stderr = StringIO() self.set_logger() try: return self.func(*args, **kwargs) finally: self.remove_logger() sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ def set_logger(self): """add sys.stderr as a log handler""" encoded_stderr = self.writer_factory(sys.stderr, errors='replace') stderr_handler = logging.StreamHandler(encoded_stderr) stderr_handler.setLevel(logging.INFO) logging.getLogger('bzr').addHandler(stderr_handler) def remove_logger(self): """removes extra log handlers, only keeps the .bzr.log handler""" self.logger_removed = True del trace._bzr_logger.handlers[1:len(trace._bzr_logger.handlers)] @redirect_output def run_bzr(argv, workdir): """run a regular bzr command""" return _run_bzr(argv, workdir, commands.main) @redirect_output def run_bzr_xml(argv, workdir): """run a bzr command, but handle errors using XMLError""" return _run_bzr(argv, workdir, custom_commands_main) def _run_bzr(argv, workdir, func): """Actually executes the command and build the response.""" try: os.chdir(workdir) exitval = func(argv) sys.stderr.flush() sys.stdout.flush() if isinstance(exitval, Fault): return_val = exitval else: # use a Binary object to wrap the output to avoid NULL and other # non xmlrpc (or client xml parsers) friendly chars out = Binary(data=sys.stdout.getvalue()) return_val = (exitval, out, sys.stderr.getvalue()) os.chdir(run_dir) return return_val except: import traceback traceback.print_exc(file=sys.__stderr__) raise def custom_commands_main(argv): """custom commands.main that handle errors using XMLError""" import bzrlib.ui bzrlib.ui.ui_factory = bzrlib.ui.make_ui_for_terminal( sys.stdin, sys.stdout, sys.stderr) try: _argv = [] for a in argv[1:]: if isinstance(a, str): a = a.decode(bzrlib.osutils.get_user_encoding()) _argv.append(a) argv = _argv ret = commands.run_bzr(argv) return ret except errors.BzrError, e: raise Fault(42, str(XMLError(e))) except Exception, e: traceback.print_exc(file=sys.__stderr__) raise Fault(32, str(XMLError(e))) def register_functions(server): """register functions exposed via xmlrpc.""" server.register_function(run_bzr, 'run_bzr_command') server.register_function(run_bzr_xml, 'run_bzr') import search if search.is_available: server.register_function(search.search, 'search') bzr-xmloutput-0.8.8+bzr162/setup.py0000644000000000000000000000343211264033614015267 0ustar 00000000000000#!/usr/bin/env python # Copyright (C) 2007-2009 Guillermo Gonzalez # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # # Contributors: # Martin Albisetti """A Bazaar plugin that provides a option to generate XML output for builtins commands""" from info import * from distutils.core import setup from extras.bdist_nsis import bdist_nsis if __name__ == '__main__': cmdclass = { 'bdist_nsis': bdist_nsis, } setup( name='bzr-' + bzr_plugin_name, version='.'.join([str(i) for i in bzr_plugin_version]), maintainer='Guillermo Gonzalez', maintainer_email='guillo.gonzo@gmail.com', description="""A Bazaar plugin that provides a option to generate XML output for builtins commands""", license='GNU GPL', url='https://launchpad.net/bzr-xmloutput', packages=['bzrlib.plugins.xmloutput'], package_dir={'bzrlib.plugins.xmloutput': '.'}, long_description="""This plugin adds an option (--xml) to log and provides an xml version of some builtinss commands that generate XML output and a xmlrpc service.""", cmdclass={'bdist_nsis': bdist_nsis, }, ) bzr-xmloutput-0.8.8+bzr162/statusxml.py0000644000000000000000000003271611671414652016211 0ustar 00000000000000#!/usr/bin/env python # -*- encoding: utf-8 -*- # Copyright (C) 2007, 2008, 2009 Guillermo Gonzalez # # The code taken from bzrlib is under: Copyright (C) 2005-2007 Canonical Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # # Contributors: # Martin Albisetti from bzrlib.lazy_import import lazy_import lazy_import(globals(), """ import os, sys, time from bzrlib import ( diff, errors, osutils, revision as _mod_revision, status, trace, ) from bzrlib.plugins.xmloutput import logxml """) from writer import _escape_cdata def show_tree_status_xml(wt, show_unchanged=None, specific_files=None, show_ids=False, to_file=None, show_pending=True, revision=None, versioned=False): """Display summary of changes as XML. Almost equal to status.show_tree_status, except the --short option and the output is in xml format. This reports on versioned and unknown files, reporting them grouped by state. Possible states are: Each group can have multiple child's of this element's: A simple example: INSTALL.txt NEWS bzrlib/symbol_versioning.py .project bzrlib/dir/ By default this compares the working tree to a previous revision. If the revision argument is given, summarizes changes between the working tree and another, or between two revisions. The result is written out as Unicode and to_file should be able to encode that. If showing the status of a working tree, extra information is included about unknown files, conflicts, and pending merges. :param show_unchanged: Deprecated parameter. If set, includes unchanged files. :param specific_files: If set, a list of filenames whose status should be shown. It is an error to give a filename that is not in the working tree, or in the working inventory or in the basis inventory. :param show_ids: If set, includes each file's id. :param to_file: If set, write to this file (default stdout.) :param show_pending: If set, write pending merges. :param revision: If None the compare latest revision with working tree If not None it must be a RevisionSpec list. If one revision show compared it with working tree. If two revisions show status between first and second. :param versioned: If True, only shows versioned files. """ if show_unchanged is not None: warn("show_status_trees with show_unchanged has been deprecated " "since bzrlib 0.9", DeprecationWarning, stacklevel=2) if to_file is None: to_file = sys.stdout wt.lock_read() try: new_is_working_tree = True if revision is None: if wt.last_revision() != wt.branch.last_revision(): trace.warning("working tree is out of date, run 'bzr update'") new = wt old = new.basis_tree() elif len(revision) > 0: try: rev_id = revision[0].in_history(wt.branch).rev_id old = wt.branch.repository.revision_tree(rev_id) except errors.NoSuchRevision, e: raise errors.BzrCommandError(str(e)) if (len(revision) > 1) and (revision[1].spec is not None): try: rev_id = revision[1].in_history(wt.branch).rev_id new = wt.branch.repository.revision_tree(rev_id) new_is_working_tree = False except errors.NoSuchRevision, e: raise errors.BzrCommandError(str(e)) else: new = wt old.lock_read() new.lock_read() try: nonexistents = None try: specific_files, nonexistents \ = status._filter_nonexistent(specific_files, old, new) except AttributeError: try: diff._raise_if_nonexistent(specific_files, old, new) except AttributeError: status._raise_if_nonexistent(specific_files, old, new) want_unversioned = not versioned to_file.write('' % \ osutils.get_user_encoding()) to_file.write('' % \ wt.id2abspath(wt.get_root_id())) delta = new.changes_from(old, want_unchanged=show_unchanged, specific_files=specific_files, want_unversioned=want_unversioned) # filter out unknown files. We may want a tree method for # this delta.unversioned = [unversioned for unversioned in delta.unversioned if not new.is_ignored(unversioned[0])] show_tree_xml(delta, to_file, show_ids=show_ids, show_unchanged=show_unchanged, show_unversioned=want_unversioned) # show the new conflicts only for now. XXX: get them from the # delta. conflicts = new.conflicts() if specific_files is not None: conflicts = conflicts.select_conflicts(new, specific_files, ignore_misses=True, recurse=True)[1] if len(conflicts) > 0: to_file.write("") for conflict in conflicts: to_file.write('%s' % (conflict.typestring, _escape_cdata(conflict.path))) to_file.write("") if nonexistents: to_file.write('') tag = 'nonexistent' for nonexistent in nonexistents: to_file.write('<%s>%s' % (tag, nonexistent, tag)) to_file.write('') if new_is_working_tree and show_pending: show_pending_merges(new, to_file) to_file.write('') finally: old.unlock() new.unlock() finally: wt.unlock() def show_pending_merges(new, to_file): """Write out a display of pending merges in a working tree.""" parents = new.get_parent_ids() if len(parents) < 2: return pending = parents[1:] branch = new.branch last_revision = parents[0] to_file.write('') # TODO: this could be improved using merge_sorted - we'd get the same # output rather than one level of indent. graph = branch.repository.get_graph() other_revisions = [last_revision] for merge in pending: try: rev = branch.repository.get_revisions([merge])[0] except errors.NoSuchRevision: # If we are missing a revision, just print out the revision id show_ghost(to_file, merge) other_revisions.append(merge) continue # Log the merge, as it gets a slightly different formatting to_file.write(logxml.line_log(rev)) # Find all of the revisions in the merge source, which are not in the # last committed revision. merge_extra = graph.find_unique_ancestors(merge, other_revisions) other_revisions.append(merge) merge_extra.discard(_mod_revision.NULL_REVISION) # Get a handle to all of the revisions we will need try: revisions = dict((rev.revision_id, rev) for rev in branch.repository.get_revisions(merge_extra)) except errors.NoSuchRevision: # One of the sub nodes is a ghost, check each one revisions = {} for revision_id in merge_extra: try: rev = branch.repository.get_revisions([revision_id])[0] except errors.NoSuchRevision: revisions[revision_id] = None else: revisions[revision_id] = rev # Display the revisions brought in by this merge. rev_id_iterator = status._get_sorted_revisions(merge, merge_extra, branch.repository.get_parent_map(merge_extra)) # Skip the first node num, first, depth, eom = rev_id_iterator.next() if first != merge: raise AssertionError('Somehow we misunderstood how' ' iter_topo_order works %s != %s' % (first, merge)) for num, sub_merge, depth, eom in rev_id_iterator: rev = revisions[sub_merge] if rev is None: show_ghost(to_file, sub_merge) continue to_file.write(logxml.line_log(revisions[sub_merge])) to_file.write('') def show_ghost(to_file, merge): to_file.write('' '%s' \ % merge) def show_tree_xml(delta, to_file, show_ids=False, show_unchanged=False, short_status=False, show_unversioned=False): """output this delta in a (xml) status-like form to to_file.""" def show_list(files): for item in files: path, fid, kind = item[:3] if kind == 'directory': path += '/' elif kind == 'symlink': path += '@' if len(item) == 5 and item[4]: path += '*' if show_ids: kind_id = '' if fid: kind_id = get_kind_id_element(kind, fid) to_file.write('<%s %s>%s' % (kind, kind_id, _escape_cdata(path), kind)) else: to_file.write('<%s>%s' % (kind, _escape_cdata(path), kind)) if delta.removed: to_file.write('') show_list(delta.removed) to_file.write('') if delta.added: to_file.write('') show_list(delta.added) to_file.write('') extra_modified = [] if delta.renamed: to_file.write('') for (oldpath, newpath, fid, kind, text_modified, meta_modified) in delta.renamed: if text_modified or meta_modified: extra_modified.append((newpath, fid, kind, text_modified, meta_modified)) metamodified = '' if meta_modified: metamodified = 'meta_modified="true"' if show_ids: kind_id = '' if fid: kind_id = get_kind_id_element(kind, fid) to_file.write('<%s oldpath="%s" %s %s>%s' % \ (kind, _escape_cdata(oldpath), metamodified, kind_id, _escape_cdata(newpath), kind)) else: to_file.write('<%s oldpath="%s" %s >%s' % \ (kind, _escape_cdata(oldpath), metamodified, _escape_cdata(newpath), kind)) to_file.write('') if delta.kind_changed: to_file.write('') for (path, fid, old_kind, new_kind) in delta.kind_changed: if show_ids: suffix = 'suffix="%s"' % fid else: suffix = '' to_file.write('<%s oldkind="%s" %s>%s' % \ (new_kind, old_kind, suffix, _escape_cdata(path), new_kind)) to_file.write('') if delta.modified or extra_modified: to_file.write('') show_list(delta.modified) show_list(extra_modified) to_file.write('') if show_unchanged and delta.unchanged: to_file.write('') show_list(delta.unchanged) to_file.write('') if show_unversioned and delta.unversioned: to_file.write('') show_list(delta.unversioned) to_file.write('') def get_kind_id_element(kind, fid): kind_id = '' if kind == 'directory': kind_id = 'suffix="%s"' % fid elif kind == 'symlink': kind_id = '' else: kind_id = 'fid="%s"' % fid return kind_id bzr-xmloutput-0.8.8+bzr162/tests/0000755000000000000000000000000010705043210014705 5ustar 00000000000000bzr-xmloutput-0.8.8+bzr162/versionxml.py0000644000000000000000000001132711502204200016321 0ustar 00000000000000#!/usr/bin/env python # -*- encoding: utf-8 -*- # Copyright (C) 2007-2009 Guillermo Gonzalez # # The code taken from bzrlib is under: Copyright (C) 2005-2007 Canonical Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # # Contributors: # Radim Kolam # This code is a modified copy from bzrlib.version (see there for copyrights # and licensing) """modified (and refactored) from bzrlib.version to generate xml output""" import os import sys import bzrlib from bzrlib import ( config, trace, ) from bzrlib.version import _get_bzr_source_tree from writer import _escape_cdata def show_version_xml(show_config=True, show_copyright=True, to_file=None): if to_file is None: to_file = sys.stdout to_file.write(u'') _show_bazaar_version(to_file=to_file) _show_python_version(to_file=to_file) print >> to_file to_file.write(u'') def _show_python_version(to_file): to_file.write(u'') # show path to python interpreter # (bzr.exe use python interpreter from pythonXY.dll # but sys.executable point to bzr.exe itself) if not hasattr(sys, u'frozen'): # check for bzr.exe # python executable to_file.write(u'%s' % sys.executable) else: # pythonXY.dll basedir = os.path.dirname(sys.executable) python_dll = u'python%d%d.dll' % sys.version_info[:2] to_file.write(u'%s' % os.path.join(basedir, python_dll)) # and now version of python interpreter to_file.write(u'%s' % \ '.'.join(map(str, sys.version_info))) to_file.write(u'%s' % \ os.path.dirname(os.__file__)) to_file.write(u'') def _show_bazaar_version(show_config=True, show_copyright=True, to_file=None): to_file.write('') to_file.write('%s' % bzrlib.__version__) # is bzrlib itself in a branch? _show_source_tree(to_file) to_file.write('%s' % _get_bzrlib_path()) if show_config: _show_bzr_config(to_file) if show_copyright: to_file.write('') _show_copyright(to_file) to_file.write('') to_file.write('') def _get_bzrlib_path(): if len(bzrlib.__path__) > 1: # print repr, which is a good enough way of making it clear it's # more than one element (eg ['/foo/bar', '/foo/bzr']) return repr(bzrlib.__path__) else: return bzrlib.__path__[0] def _show_source_tree(to_file): src_tree = _get_bzr_source_tree() if src_tree: src_revision_id = src_tree.last_revision() revno = src_tree.branch.revision_id_to_revno(src_revision_id) to_file.write(u'') to_file.write(u'%s' % src_tree.basedir) to_file.write(u'%s' % revno) to_file.write(u'%s' % src_revision_id) to_file.write(u'%s' % \ _escape_cdata(src_tree.branch.nick)) to_file.write(u'') def _show_bzr_config(to_file): config_dir = os.path.normpath(config.config_dir()) # use native slashes if not isinstance(config_dir, unicode): config_dir = config_dir.decode(bzrlib.osutils.get_user_encoding()) bzr_log_filename = trace._bzr_log_filename if not isinstance(bzr_log_filename, unicode): bzr_log_filename = trace._bzr_log_filename.decode( bzrlib.osutils.get_user_encoding()) to_file.write('%s' % config_dir) to_file.write('%s' % bzr_log_filename) def _show_copyright(to_file): to_file.write(bzrlib.__copyright__) to_file.write("http://bazaar-vcs.org/") to_file.write('') to_file.write("bzr comes with ABSOLUTELY NO WARRANTY. bzr is free " "software, and") to_file.write("you may use, modify and redistribute it under the terms " "of the GNU") to_file.write("General Public License version 2 or later.") bzr-xmloutput-0.8.8+bzr162/writer.py0000644000000000000000000000072011502204200015422 0ustar 00000000000000"""Tools for writing xml Suggestion for this module: create a simple xml writer here and expurgate all other modules of angle brackets entirely. """ def _escape_cdata(text): """Escape special characters in cdata. :note: This does not care about the input encoding, and supports both unicode and byte strings. """ text = text.replace("&", "&") text = text.replace("<", "<") text = text.replace(">", ">") return text bzr-xmloutput-0.8.8+bzr162/xml_errors.py0000644000000000000000000000461211502204200016306 0ustar 00000000000000""" XMLError handling module """ from bzrlib.lazy_import import lazy_import lazy_import(globals(), """ from bzrlib import ( errors, osutils, trace, ) """) from writer import _escape_cdata class XMLError(errors.BzrError): """ A class that wraps an BzrError and 'serialize' it as xml.""" internal_error = False def __init__(self, error): self.error = error def __str__(self): """__str__""" xml = '' % \ osutils.get_user_encoding() try: xml += '%s' % self.get_cause_xml() except Exception, e: xml += '%s' % \ _escape_cdata(str(e)) return xml def get_cause_xml(self): """return the cause as an xml string: class, dict and message""" s = '%s%s' \ '%s' \ % (self.error.__class__.__name__, self._get_dict_as_xml(self.error.__dict__), _escape_cdata(str(self.error))) return s def _get_dict_as_xml(self, dict): """returns a dict as xml using and tags""" return ''.join(['%s%s' % \ (_escape_cdata(key), _escape_cdata(str(val))) \ for key, val in dict.iteritems() if val is not None]) def report_exception(exc_info, err_file): """ replace the default report_exception with a custom one that returns a xml representation of the error. :return: The appropriate exit code for this error. """ exc_type, exc_object, exc_tb = exc_info # Log the full traceback to ~/.bzr.log trace.log_exception_quietly() err_file.write(str(XMLError(exc_object))) return errors.EXIT_ERROR def handle_error_xml(func): """ a decorator that handle errors using our custom report_exception""" def xml_error_handling(*args, **kwargs): """ the wrapper""" try: return func(*args, **kwargs) except: import sys, os exitcode = report_exception(sys.exc_info(), sys.stderr) if os.environ.get('BZR_PDB'): print '**** entering debugger' import pdb pdb.post_mortem(sys.exc_traceback) return exitcode return xml_error_handling bzr-xmloutput-0.8.8+bzr162/docs/nsis-installer.txt0000644000000000000000000000126011071267653020222 0ustar 00000000000000Building NSIS installer for using bzr-xmloutput with standalone bzr.exe ============================================================== To build NSIS installer you need NSIS program itself. To build installer you need to run command from tree root:: python setup.py bdist_nsis NSIS is able to run on Linux platform, so in theory this command should work even on Linux. Resulting installer will appear in tree root with name ``bzr-xmloutput-setup-X.Y.Z.exe``. SimpleXMLRPCServer (mandatory) ***************** SimpleXMLRPCServer.py should be placed in ``./installer/_lib`` directory. Usually you can copy them from your Python 2.5 ``site-packages`` directory. bzr-xmloutput-0.8.8+bzr162/extras/__init__.py0000644000000000000000000000153211071267653017203 0ustar 00000000000000# -*- coding: utf-8 -*- # # Copyright (C) 2008 Guillermo Gonzalez # Copyright (C) 2007 Lukáš Lalinský # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. bzr-xmloutput-0.8.8+bzr162/extras/bdist_nsis.py0000644000000000000000000001045711071267653017613 0ustar 00000000000000# -*- coding: utf-8 -*- # # Copyright (C) 2008 Guillermo Gonzalez # Copyright (C) 2007 Lukáš Lalinský # Copyright (C) 2007 Alexander Belchenko # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """bdist_nsis command for setup.py (create windows installer with NSIS)""" from distutils.command.bdist import bdist from distutils.core import Command from distutils.errors import DistutilsPlatformError from distutils import log import os import shutil import sys class bdist_nsis(Command): description = "create an executable installer for MS Windows with NSIS" user_options = [ ('nsi-script', None, "NSIS script to compile"), ('skip-build', None, "skip rebuilding everything (for testing/debugging)"), ('nsis-compiler', None, "full path to NSIS compiler executable"), ('dry-run', 'n', "copy libs (if required) but don't run makensis"), ('copy-all', 'A', "copy all additional libs from Python 2.5 site-packages"), ] boolean_options = [ 'skip-build', 'copy-all', 'dry-run', ] def initialize_options(self): self.nsi_script = None self.skip_build = False self.nsis_compiler = None self.copy_all = False self.dry_run = False def finalize_options(self): if not self.nsi_script: name = self.distribution.get_name() or '' if name: script_name = 'installer/%s-setup.nsi' % name else: script_name = 'installer/setup.nsi' print 'NOTE: will use %s script' % script_name self.nsi_script = script_name if not self.nsis_compiler: # auto-detect NSIS if sys.platform == 'win32': # read path from registry import _winreg nsis_dir = None try: hkey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\NSIS') try: nsis_dir = _winreg.QueryValue(hkey, '') finally: _winreg.CloseKey(hkey) except (EnvironmentError, WindowsError): pass if nsis_dir: self.nsis_compiler = os.path.join(nsis_dir, 'makensis.exe') else: self.nsis_compiler = 'makensis.exe' else: self.nsis_compiler = 'makensis' def _copy_python_package(self, pkg): sitedir = os.path.join(os.path.dirname(os.__file__), 'site-packages') prefix = len(sitedir) + 1 for root, dirs, files in os.walk(pkg): for i in files: ext = os.path.splitext(i)[1] if ext in ('.py', '.pyd'): src = os.path.join(root, i) dst = os.path.join('installer', '_lib', root[prefix:], i) dstdir = os.path.dirname(dst) if not os.path.isdir(dstdir): log.info('Creating directory %s', dstdir) os.mkdir(dstdir) log.info('Copying %s -> %s', src, dst) shutil.copyfile(src, dst) def run(self): if not self.skip_build: self.run_command('build') if not self.dry_run: print 'Run NSIS compiler' self.spawn([self.nsis_compiler, self.nsi_script]) # plug-in our bdist builder to distutils collection bdist.format_commands.append('nsis') bdist.format_command['nsis'] = ('bdist_nsis', 'Windows NSIS-based installer') bzr-xmloutput-0.8.8+bzr162/installer/_lib/0000755000000000000000000000000011071267653016465 5ustar 00000000000000bzr-xmloutput-0.8.8+bzr162/installer/bzr-xmloutput-setup.nsi0000644000000000000000000000423711655143375022315 0ustar 00000000000000!define PRODUCT_NAME "bzr-xmloutput" !define PRODUCT_VERSION "0.8.8" !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" !define PRODUCT_UNINST_ROOT_KEY "HKLM" SetCompressor /SOLID lzma Name "${PRODUCT_NAME} ${PRODUCT_VERSION}" OutFile "..\bzr-xmloutput-setup-${PRODUCT_VERSION}.exe" ShowInstDetails show ShowUnInstDetails show ; The default installation directory InstallDir "$APPDATA\bazaar\2.0\plugins\xmloutput" ; The default installation directory InstallDirRegKey HKLM "Software\bzr-xmloutput\${PRODUCT_NAME}" "InstallDir" !include "MUI.nsh" ; MUI Settings !define MUI_ABORTWARNING ; Welcome page !define MUI_WELCOMEPAGE_TITLE_3LINES !insertmacro MUI_PAGE_WELCOME ; Directory page !insertmacro MUI_PAGE_DIRECTORY ; Instfiles page !insertmacro MUI_PAGE_INSTFILES ; Finish page !define MUI_FINISHPAGE_TITLE_3LINES !insertmacro MUI_PAGE_FINISH ; Uninstaller pages !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES !define MUI_UNPAGE_FINISH_TITLE_3LINES !insertmacro MUI_UNPAGE_FINISH ; Language files !insertmacro MUI_LANGUAGE "English" ; Install Section "MainSection" SEC01 ; Files SetOutPath "$INSTDIR" File "..\__init__.py" "..\*.py" "..\README" "..\LICENSE" File /r "_lib\*.py" SetOutPath "$INSTDIR\tests" File "..\tests\*" ; Write the installation path into the registry WriteRegStr HKLM "Software\bzr-xmloutput\${PRODUCT_NAME}" "InstallDir" "$INSTDIR" ; Create uninstaller WriteUninstaller "$INSTDIR\uninst.exe" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)" ;WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\picard.exe" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe" SectionEnd ; Uninstall Section Uninstall RMDir /r "$INSTDIR" DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" DeleteRegKey HKLM "Software\bzr-xmloutput\${PRODUCT_NAME}" SectionEnd bzr-xmloutput-0.8.8+bzr162/tests/__init__.py0000644000000000000000000000233011277703251017031 0ustar 00000000000000# Copyright (C) 2005, 2006, 2007 Canonical Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """Black-box tests for xmloutput plugin.""" import sys from bzrlib import tests def load_tests(basic_tests, module, loader): testmod_names = [ 'test_ls_xml', 'test_version_xml', 'test_status_xml', 'test_log_xml', 'test_annotate_xml', 'test_info_xml', 'test_service', ] basic_tests.addTest(loader.loadTestsFromModuleNames( ["%s.%s" % (__name__, tmn) for tmn in testmod_names])) return basic_tests bzr-xmloutput-0.8.8+bzr162/tests/elementtree_builder.py0000644000000000000000000000146311720667170021321 0ustar 00000000000000 from bzrlib.xml_serializer import elementtree ET = elementtree class _E(object): """ This is the E factory, taken from http://effbot.org/zone/element-builder.htm """ def __call__(self, tag, *children, **attrib): elem = ET.Element(tag, attrib) for item in children: if isinstance(item, dict): elem.attrib.update(item) elif isinstance(item, basestring): if len(elem): elem[-1].tail = (elem[-1].tail or "") + item else: elem.text = (elem.text or "") + item elif ET.iselement(item): elem.append(item) else: raise TypeError("bad argument: %r" % item) return elem def __getattr__(self, tag): return self(tag) bzr-xmloutput-0.8.8+bzr162/tests/test_annotate_xml.py0000644000000000000000000002571011720667170021033 0ustar 00000000000000# Copyright (C) 2005 Canonical Ltd # -*- coding: utf-8 -*- # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """Black-box tests for bzr. These check that it behaves properly when it's invoked through the regular command-line interface. This doesn't actually run a new interpreter but rather starts again from the run_bzr function. """ import os import time import bzrlib from bzrlib.tests import TestCaseWithTransport from bzrlib.xml_serializer import elementtree as elementtree fromstring = elementtree.fromstring class TestXmlAnnotate(TestCaseWithTransport): def setUp(self): super(TestXmlAnnotate, self).setUp() self.wt = self.make_branch_and_tree('.') b = self.wt.branch self.build_tree_contents([('hello.txt', 'my helicopter\n'), ('nomail.txt', 'nomail\n')]) self.wt.add(['hello.txt']) self.revision_id_1 = self.wt.commit('add hello', committer='test@user', timestamp=1165960000.00, timezone=0) self.wt.add(['nomail.txt']) self.revision_id_2 = self.wt.commit('add nomail', committer='no mail', timestamp=1165970000.00, timezone=0) self.build_tree_contents([('hello.txt', 'my helicopter\n' 'your helicopter\n')]) self.revision_id_3 = self.wt.commit('mod hello', committer='user@test', timestamp=1166040000.00, timezone=0) self.build_tree_contents([('hello.txt', 'my helicopter\n' 'your helicopter\n' 'all of\n' 'our helicopters\n' )]) self.revision_id_4 = self.wt.commit('mod hello', committer='user@test', timestamp=1166050000.00, timezone=0) self.time_revision_id_1 = date_str = time.strftime('%Y%m%d', time.gmtime(1165960000.00)) self.time_revision_id_2 = date_str = time.strftime('%Y%m%d', time.gmtime(1165970000.00)) self.time_revision_id_3 = date_str = time.strftime('%Y%m%d', time.gmtime(1166040000.00)) self.time_revision_id_4 = date_str = time.strftime('%Y%m%d', time.gmtime(1166050000.00)) def test_help_xmlannotate(self): """XmlAnnotate command exists""" out, err = self.run_bzr('xmlannotate --help') def test_xmlannotate_cmd(self): out, err = self.run_bzr('xmlannotate hello.txt') wt_root_path = self.wt.id2abspath(self.wt.get_root_id()) expected_xml = (''.join(['', '', 'my helicopter', 'your helicopter', 'all of', 'our helicopters', '\n',]) % (wt_root_path, self.time_revision_id_1, self.time_revision_id_3, self.time_revision_id_4, self.time_revision_id_4)) #TODO: assert xml and elementree (including attributes) self.assertEqual('', err) self.assertEqualDiff(expected_xml, out) expected_elementtree = fromstring(expected_xml) current_elementtree = fromstring(out) self.assertEquals(elementtree.tostring(expected_elementtree), elementtree.tostring(current_elementtree)) def test_xmlannotate_cmd_show_ids(self): out, err = self.run_bzr('xmlannotate hello.txt --show-ids') wt_root_path = self.wt.id2abspath(self.wt.get_root_id()) expected_xml = (''.join(['', '', 'my helicopter', 'your helicopter', 'all of', 'our helicopters', '\n',]) % (wt_root_path, self.time_revision_id_1, self.revision_id_1, self.time_revision_id_3, self.revision_id_3, self.time_revision_id_4, self.revision_id_4, self.time_revision_id_4, self.revision_id_4)) #TODO: assert xml and elementree (including attributes) max_len = max([len(self.revision_id_1), len(self.revision_id_3), len(self.revision_id_4)]) self.assertEqual('', err) self.assertEqualDiff(expected_xml, out) # self.assertEqualDiff('''\ #%*s | my helicopter #%*s | your helicopter #%*s | all of #%*s | our helicopters #''' % (max_len, self.revision_id_1, #max_len, self.revision_id_3, #max_len, self.revision_id_4, #max_len, '', #) #, out) def test_no_mail(self): out, err = self.run_bzr('xmlannotate nomail.txt') wt_root_path = self.wt.id2abspath(self.wt.get_root_id()) expected_xml = (''.join(['', '', 'nomail', '\n']) % (wt_root_path, self.time_revision_id_2)) #TODO: assert xml and elementree (including attributes) self.assertEqual('', err) self.assertEqualDiff(expected_xml, out) # self.assertEqualDiff('''\ #2 no mail | nomail #''', out) def test_xmlannotate_cmd_revision(self): out, err = self.run_bzr('xmlannotate hello.txt -r1') wt_root_path = self.wt.id2abspath(self.wt.get_root_id()) expected_xml = (''.join(['', '', 'my helicopter', '\n']) % (wt_root_path, self.time_revision_id_1)) #TODO: assert xml and elementree (including attributes) self.assertEqual('', err) self.assertEqualDiff(expected_xml, out) #self.assertEqualDiff('''\ #1 test@us | my helicopter #''', out) def test_xmlannotate_cmd_revision3(self): out, err = self.run_bzr('xmlannotate hello.txt -r3') wt_root_path = self.wt.id2abspath(self.wt.get_root_id()) expected_xml = (''.join(['', '', 'my helicopter', 'your helicopter', '\n']) % (wt_root_path, self.time_revision_id_1, self.time_revision_id_3)) #TODO: assert xml and elementree (including attributes) self.assertEqual('', err) self.assertEqualDiff(expected_xml, out) # self.assertEqualDiff('''\ #1 test@us | my helicopter #3 user@te | your helicopter #''', out) def test_xmlannotate_cmd_unknown_revision(self): out, err = self.run_bzr('xmlannotate hello.txt -r 10', retcode=3) self.assertEqual('', out) self.assertContainsRe(err, 'Requested revision: \'10\' does not exist') def test_xmlannotate_cmd_two_revisions(self): out, err = self.run_bzr('xmlannotate hello.txt -r1..2', retcode=3) self.assertEqual('', out) self.assertEqual('' 'BzrCommandError_preformatted_stringxmlannotate' ' --revision takes exactly 1 argument' 'xmlannotate --revision takes exactly 1 argument' '' % bzrlib.osutils.get_user_encoding(), err) def test_xmlannotate_empty_file(self): tree = self.make_branch_and_tree('tree') self.build_tree_contents([('tree/empty', '')]) tree.add('empty') tree.commit('add empty file') os.chdir('tree') out, err = self.run_bzr('xmlannotate empty') wt_root_path = self.wt.id2abspath(self.wt.get_root_id()) #TODO: assert xml and elementree (including attributes)' expected_xml = (''.join(['', '', '\n']) % (wt_root_path+'tree/',)) self.assertEqual(expected_xml, out) def test_xmlannotate_nonexistant_file(self): tree = self.make_branch_and_tree('tree') self.build_tree(['tree/file']) tree.add(['file']) tree.commit('add a file') os.chdir('tree') out, err = self.run_bzr("xmlannotate doesnotexist", retcode=3) self.assertEqual('', out) self.assertContainsRe(err, 'NotVersionedError.*' 'path.*doesnotexist' '.*doesnotexist is not versioned.') bzr-xmloutput-0.8.8+bzr162/tests/test_info_xml.py0000644000000000000000000014461311720670363020157 0ustar 00000000000000# -*- encoding: utf-8 -*- # # Copyright (C) 2006, 2007 Canonical Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """Tests for the info command of bzr.""" import sys import bzrlib from bzrlib import ( bzrdir, errors, osutils, tests, urlutils, ) from bzrlib.tests import blackbox import bzrlib.upgrade class TestInfoXml(blackbox.ExternalBase): def test_should_normalize_non_ascii_url(self): # we disable isolation because the error we want to catch is triggered # outside of the jail self.disable_directory_isolation() root = '/C:' if sys.platform == 'win32' else '' url = u'file://%s/Maçã/does/not/exist' % root out, err = self.run_bzr(['xmlinfo', url], retcode=3) from bzrlib.urlutils import normalize_url nurl = normalize_url(url) self.assertEqual( '' 'NotBranchErrorpath' '%s/extra' 'detail' 'Not a branch: "%s/".' '' % (osutils.get_user_encoding(), nurl, nurl), err) def test_info_non_existing(self): # we disable isolation because the error we want to catch is triggered # outside of the jail self.disable_directory_isolation() if sys.platform == "win32": location = "C:/i/do/not/exist/" else: location = "/i/do/not/exist/" out, err = self.run_bzr('xmlinfo '+location, retcode=3) self.assertEqual(out, '') self.assertEqual( '' 'NotBranchErrorpath' '%sextra' 'detail' 'Not a branch: "%s".' '' % (osutils.get_user_encoding(), location, location), err) def test_info_standalone(self): transport = self.get_transport() # Create initial standalone branch tree1 = self.make_branch_and_tree('standalone', 'weave') self.build_tree(['standalone/a']) tree1.add('a') branch1 = tree1.branch out, err = self.run_bzr('xmlinfo standalone') expected_xml = ''' Standalone tree weave standalone ''' expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) out, err = self.run_bzr('xmlinfo standalone -v') expected_xml = ''' Standalone tree weave standalone All-in-one format 6 Working tree format 2 Branch format 4 Weave repository format 6 0 0 1 0 0 0 0 0 0 0 0 ''' expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) tree1.commit('commit one') rev = branch1.repository.get_revision(branch1.last_revision()) datestring_first = osutils.format_date(rev.timestamp, rev.timezone) # Branch standalone with push location branch2 = branch1.bzrdir.sprout('branch').open_branch() branch2.set_push_location(branch1.bzrdir.root_transport.base) out, err = self.run_bzr('xmlinfo branch') expected_xml = ''' Standalone tree weave branch standalonestandalone ''' expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) out, err = self.run_bzr('xmlinfo branch --verbose') expected_xml = ''' Standalone tree weave branch standalonestandalone All-in-one format 6 Working tree format 2 Branch format 4 Weave repository format 6 1 0 0 0 0 0 0 0 1 1 0 %s %s 1 ''' % (datestring_first, datestring_first, ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) # Branch and bind to standalone, needs upgrade to metadir # (creates backup as unknown) branch1.bzrdir.sprout('bound') knit1_format = bzrdir.format_registry.make_bzrdir('knit') bzrlib.upgrade.upgrade('bound', knit1_format) branch3 = bzrlib.bzrdir.BzrDir.open('bound').open_branch() branch3.bind(branch1) bound_tree = branch3.bzrdir.open_workingtree() out, err = self.run_bzr('xmlinfo -v bound') expected_xml = ''' Checkout knit boundstandalone standalone Meta directory format 1 %s %s %s 1 0 0 0 0 0 1 0 1 1 0 %s %s 1 ''' % (bound_tree._format.get_format_description(), branch3._format.get_format_description(), branch3.repository._format.get_format_description(), datestring_first, datestring_first, ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) # Checkout standalone (same as above, but does not have parent set) branch4 = bzrlib.bzrdir.BzrDir.create_branch_convenience('checkout', format=knit1_format) branch4.bind(branch1) branch4.bzrdir.open_workingtree().update() out, err = self.run_bzr('xmlinfo checkout --verbose') expected_xml = ''' Checkout knit checkoutstandalone Meta directory format 1 Working tree format 3 Branch format 5 %s 1 0 0 0 0 0 0 0 1 1 0 %s %s 1 ''' % (branch4.repository._format.get_format_description(), datestring_first, datestring_first, ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml , out) self.assertEqual('', err) # Lightweight checkout (same as above, different branch and repository) tree5 = branch1.create_checkout('lightcheckout', lightweight=True) branch5 = tree5.branch out, err = self.run_bzr('xmlinfo -v lightcheckout') expected_xml = ''' Lightweight checkout 2a lightcheckoutstandalone Meta directory format 1 Working tree format 6 Branch format 4 Weave repository format 6 1 0 0 0 0 0 0 0 1 1 0 %s %s 1 ''' % (datestring_first, datestring_first) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) # Update initial standalone branch self.build_tree(['standalone/b']) tree1.add('b') tree1.commit('commit two') rev = branch1.repository.get_revision(branch1.last_revision()) datestring_last = osutils.format_date(rev.timestamp, rev.timezone) # Out of date branched standalone branch will not be detected out, err = self.run_bzr('xmlinfo -v branch') expected_xml = ''' Standalone tree weave branch standalonestandalone All-in-one format 6 Working tree format 2 Branch format 4 Weave repository format 6 1 0 0 0 0 0 0 0 1 1 0 %s %s 1 ''' % (datestring_first, datestring_first,) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) # Out of date bound branch out, err = self.run_bzr('xmlinfo -v bound') expected_xml = ''' Checkout knit boundstandalone standalone Meta directory format 1 Working tree format 3 Branch format 5 %s 1 1 0 0 0 0 0 1 0 1 1 0 %s %s 1 ''' % (branch3.repository._format.get_format_description(), datestring_first, datestring_first, ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) # Out of date checkout out, err = self.run_bzr('xmlinfo -v checkout') expected_xml = ''' Checkout knit checkoutstandalone Meta directory format 1 Working tree format 3 Branch format 5 %s 1 1 0 0 0 0 0 0 0 1 1 0 %s %s 1 ''' % (branch4.repository._format.get_format_description(), datestring_first, datestring_first, ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) # Out of date lightweight checkout out, err = self.run_bzr('xmlinfo lightcheckout --verbose') expected_xml = ''' Lightweight checkout 2a lightcheckoutstandalone Meta directory format 1 Working tree format 6 Branch format 4 Weave repository format 6 1 1 0 0 0 0 0 0 0 2 1 0 %s %s 2 ''' % (datestring_first, datestring_last,) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) def test_info_standalone_no_tree(self): # create standalone branch without a working tree format = bzrdir.format_registry.make_bzrdir('default') branch = self.make_branch('branch') repo = branch.repository out, err = self.run_bzr('xmlinfo branch -v') expected_xml = ''' Standalone branch 2a branch Meta directory format 1 %s %s 0 0 0 ''' % (format.get_branch_format().get_format_description(), format.repository_format.get_format_description(), ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) def test_info_shared_repository(self): format = bzrdir.format_registry.make_bzrdir('knit') transport = self.get_transport() # Create shared repository repo = self.make_repository('repo', shared=True, format=format) repo.set_make_working_trees(False) out, err = self.run_bzr('xmlinfo -v repo') expected_xml = ''' Shared repository dirstate dirstate-tags knit %s Meta directory format 1 %s 0 ''' % ('repo', format.repository_format.get_format_description(), ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) # Create branch inside shared repository repo.bzrdir.root_transport.mkdir('branch') branch1 = bzrdir.BzrDir.create_branch_convenience('repo/branch', format=format) out, err = self.run_bzr('xmlinfo -v repo/branch') expected_xml = ''' Repository branch dirstate knit reporepo/branch Meta directory format 1 %s %s 0 0 0 ''' % (format.get_branch_format().get_format_description(), format.repository_format.get_format_description(), ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) # Create lightweight checkout transport.mkdir('tree') transport.mkdir('tree/lightcheckout') tree2 = branch1.create_checkout('tree/lightcheckout', lightweight=True) branch2 = tree2.branch self.assertCheckoutStatusOutput('-v tree/lightcheckout', tree2, shared_repo=repo, repo_branch=branch1, verbose=True) # Create normal checkout tree3 = branch1.create_checkout('tree/checkout') self.assertCheckoutStatusOutput('tree/checkout --verbose', tree3, verbose=True, light_checkout=False, repo_branch=branch1) # Update lightweight checkout self.build_tree(['tree/lightcheckout/a']) tree2.add('a') tree2.commit('commit one') rev = repo.get_revision(branch2.last_revision()) datestring_first = osutils.format_date(rev.timestamp, rev.timezone) out, err = self.run_bzr('xmlinfo tree/lightcheckout --verbose') expected_xml = ''' Lightweight checkout 2a tree/lightcheckoutrepo/branchrepo Meta directory format 1 Working tree format 6 %s %s 1 0 0 0 0 0 0 0 1 1 0 %s %s 1 ''' % (format.get_branch_format().get_format_description(), format.repository_format.get_format_description(), datestring_first, datestring_first, ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) # Out of date checkout out, err = self.run_bzr('xmlinfo -v tree/checkout') expected_xml = ''' Checkout unnamed tree/checkoutrepo/branch Meta directory format 1 Working tree format 6 %s %s 1 0 0 0 0 0 0 0 0 0 0 0 ''' % (format.get_branch_format().get_format_description(), format.repository_format.get_format_description(), ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) # Update checkout tree3.update() self.build_tree(['tree/checkout/b']) tree3.add('b') out, err = self.run_bzr('xmlinfo tree/checkout --verbose') expected_xml = ''' Checkout unnamed tree/checkoutrepo/branch Meta directory format 1 Working tree format 6 %s %s 1 0 1 0 0 0 0 0 1 1 0 %s %s 1 ''' % (format.get_branch_format().get_format_description(), format.repository_format.get_format_description(), datestring_first, datestring_first, ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) tree3.commit('commit two') # Out of date lightweight checkout rev = repo.get_revision(branch1.last_revision()) datestring_last = osutils.format_date(rev.timestamp, rev.timezone) out, err = self.run_bzr('xmlinfo tree/lightcheckout --verbose') expected_xml = ''' Lightweight checkout 2a tree/lightcheckoutrepo/branchrepo Meta directory format 1 Working tree format 6 %s %s 1 1 0 0 0 0 0 0 0 2 1 0 %s %s 2 ''' % (format.get_branch_format().get_format_description(), format.repository_format.get_format_description(), datestring_first, datestring_last, ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) # Show info about shared branch out, err = self.run_bzr('xmlinfo repo/branch --verbose') expected_xml = ''' Repository branch dirstate knit reporepo/branch Meta directory format 1 %s %s 2 1 0 %s %s 2 ''' % (format.get_branch_format().get_format_description(), format.repository_format.get_format_description(), datestring_first, datestring_last, ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) # Show info about repository with revisions out, err = self.run_bzr('xmlinfo -v repo') expected_xml = ''' Shared repository dirstate dirstate-tags knit repo Meta directory format 1 %s 2 ''' % (format.repository_format.get_format_description(), ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) def test_info_shared_repository_with_trees(self): format = bzrdir.format_registry.make_bzrdir('knit') transport = self.get_transport() # Create shared repository with working trees repo = self.make_repository('repo', shared=True, format=format) repo.set_make_working_trees(True) out, err = self.run_bzr('xmlinfo -v repo') expected_xml = ''' Shared repository with trees dirstate dirstate-tags knit repo Meta directory format 1 %s 0 ''' % (format.repository_format.get_format_description(), ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) # Create two branches repo.bzrdir.root_transport.mkdir('branch1') branch1 = bzrdir.BzrDir.create_branch_convenience('repo/branch1', format=format) branch2 = branch1.bzrdir.sprout('repo/branch2').open_branch() # Empty first branch out, err = self.run_bzr('xmlinfo repo/branch1 --verbose') expected_xml = ''' Repository tree knit reporepo/branch1 Meta directory format 1 Working tree format 3 %s %s 0 0 0 0 0 0 0 0 0 0 0 ''' % (format.get_branch_format().get_format_description(), format.repository_format.get_format_description(), ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) # Update first branch self.build_tree(['repo/branch1/a']) tree1 = branch1.bzrdir.open_workingtree() tree1.add('a') tree1.commit('commit one') rev = repo.get_revision(branch1.last_revision()) datestring_first = osutils.format_date(rev.timestamp, rev.timezone) out, err = self.run_bzr('xmlinfo -v repo/branch1') expected_xml = ''' Repository tree knit reporepo/branch1 Meta directory format 1 Working tree format 3 %s %s 1 0 0 0 0 0 0 0 1 1 0 %s %s 1 ''' % (format.get_branch_format().get_format_description(), format.repository_format.get_format_description(), datestring_first, datestring_first, ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) # Out of date second branch out, err = self.run_bzr('xmlinfo repo/branch2 --verbose') expected_xml = ''' Repository tree knit reporepo/branch2 repo/branch1 Meta directory format 1 Working tree format 3 %s %s 0 0 0 0 0 0 0 0 0 0 1 ''' % (format.get_branch_format().get_format_description(), format.repository_format.get_format_description(), ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) # Update second branch tree2 = branch2.bzrdir.open_workingtree() tree2.pull(branch1) out, err = self.run_bzr('xmlinfo -v repo/branch2') expected_xml = ''' Repository tree knit reporepo/branch2 repo/branch1 Meta directory format 1 Working tree format 3 %s %s 1 0 0 0 0 0 0 0 1 1 0 %s %s 1 ''' % (format.get_branch_format().get_format_description(), format.repository_format.get_format_description(), datestring_first, datestring_first, ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) # Show info about repository with revisions out, err = self.run_bzr('xmlinfo -v repo') expected_xml = ''' Shared repository with trees dirstate dirstate-tags knit repo Meta directory format 1 %s 1 ''' % (format.repository_format.get_format_description(), ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) def test_info_shared_repository_with_tree_in_root(self): format = bzrdir.format_registry.make_bzrdir('knit') transport = self.get_transport() # Create shared repository with working trees repo = self.make_repository('repo', shared=True, format=format) repo.set_make_working_trees(True) out, err = self.run_bzr('xmlinfo -v repo') expected_xml = ''' Shared repository with trees dirstate dirstate-tags knit repo Meta directory format 1 %s 0 ''' % (format.repository_format.get_format_description(),) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) # Create branch in root of repository control = repo.bzrdir branch = control.create_branch() control.create_workingtree() out, err = self.run_bzr('xmlinfo -v repo') expected_xml = ''' Repository tree knit reporepo Meta directory format 1 Working tree format 3 %s %s 0 0 0 0 0 0 0 0 0 0 0 ''' % (format.get_branch_format().get_format_description(), format.repository_format.get_format_description(), ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) def assertCheckoutStatusOutput(self, command_string, lco_tree, shared_repo=None, repo_branch=None, tree_locked=False, branch_locked=False, repo_locked=False, verbose=False, light_checkout=True, checkout_root=None): """Check the output of info in a checkout. This is not quite a mirror of the info code: rather than using the tree being examined to predict output, it uses a bunch of flags which allow us, the test writers, to document what *should* be present in the output. Removing this separation would remove the value of the tests. :param path: the path to the light checkout. :param lco_tree: the tree object for the light checkout. :param shared_repo: A shared repository is in use, expect that in the output. :param repo_branch: A branch in a shared repository for non light checkouts. :param tree_locked: If true, expect the tree to be locked. :param branch_locked: If true, expect the branch to be locked. :param repo_locked: If true, expect the repository to be locked. :param verbose: If true, expect verbose output """ def friendly_location(url): path = urlutils.unescape_for_display(url, 'ascii') try: return osutils.relpath(osutils.getcwd(), path) except errors.PathNotChild: return path if tree_locked: # We expect this to fail because of locking errors, dirstate # can't be read locked while a write lock is open. self.run_bzr_error([], 'xmlinfo ' + command_string) return out, err = self.run_bzr('xmlinfo %s' % command_string) description = { (True, True): 'Lightweight checkout', (True, False): 'Repository checkout', (False, True): 'Lightweight checkout', (False, False): 'Checkout', }[(shared_repo is not None, light_checkout)] format = {True: '2a\n', False: 'unnamed'}[light_checkout] if repo_locked: repo_locked = lco_tree.branch.repository.get_physical_lock_status() if repo_locked or branch_locked or tree_locked: def locked_message(a_bool): if a_bool: return 'locked' else: return 'unlocked' expected_lock_output = ( "\n\n" "%s\n" "%s\n" "%s\n" "" % ( locked_message(tree_locked), locked_message(branch_locked), locked_message(repo_locked))) else: expected_lock_output = '' tree_data = '' extra_space = '' if light_checkout: tree_data = ("%s" % friendly_location(lco_tree.bzrdir.root_transport.base)) extra_space = ' ' if lco_tree.branch.get_bound_location() is not None: tree_data += ("%s" % ( friendly_location(lco_tree.branch.bzrdir.root_transport.base))) if shared_repo is not None: branch_data = ( "%s" "%s" % (friendly_location(repo_branch.bzrdir.root_transport.base), friendly_location(shared_repo.bzrdir.root_transport.base))) elif repo_branch is not None: branch_data = ("%s" % (friendly_location(repo_branch.bzrdir.root_transport.base))) else: branch_data = ("%s" % lco_tree.branch.bzrdir.root_transport.base) if verbose: verbose_info = '0' else: verbose_info = '' expected_xml = ''' %s %s %s%s Meta directory format 1 %s %s %s %s 0 0 0 0 0 0 0 0 0 %s 0 ''' % (description, format, tree_data, branch_data, lco_tree._format.get_format_description(), lco_tree.branch._format.get_format_description(), lco_tree.branch.repository._format.get_format_description(), expected_lock_output, verbose_info, ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) def test_info_locking(self): transport = self.get_transport() # Create shared repository with a branch repo = self.make_repository('repo', shared=True, format=bzrlib.bzrdir.BzrDirMetaFormat1()) repo.set_make_working_trees(False) repo.bzrdir.root_transport.mkdir('branch') repo_branch = bzrdir.BzrDir.create_branch_convenience( 'repo/branch', format=bzrlib.bzrdir.BzrDirMetaFormat1()) # Do a heavy checkout transport.mkdir('tree') transport.mkdir('tree/checkout') co_branch = bzrlib.bzrdir.BzrDir.create_branch_convenience('tree/checkout', format=bzrlib.bzrdir.BzrDirMetaFormat1()) co_branch.bind(repo_branch) # Do a light checkout of the heavy one transport.mkdir('tree/lightcheckout') lco_dir = bzrlib.bzrdir.BzrDirMetaFormat1().initialize('tree/lightcheckout') bzrlib.branch.BranchReferenceFormat().initialize(lco_dir, target_branch=co_branch) lco_dir.create_workingtree() lco_tree = lco_dir.open_workingtree() # Test all permutations of locking the working tree, branch and repository # W B R # U U U self.assertCheckoutStatusOutput('-v tree/lightcheckout', lco_tree, repo_branch=repo_branch, verbose=True, light_checkout=True) # U U L lco_tree.branch.repository.lock_write() try: self.assertCheckoutStatusOutput('-v tree/lightcheckout', lco_tree, repo_branch=repo_branch, repo_locked=True, verbose=True, light_checkout=True) finally: lco_tree.branch.repository.unlock() # U L L lco_tree.branch.lock_write() try: self.assertCheckoutStatusOutput('-v tree/lightcheckout', lco_tree, branch_locked=True, repo_locked=True, repo_branch=repo_branch, verbose=True) finally: lco_tree.branch.unlock() # L L L lco_tree.lock_write() try: self.assertCheckoutStatusOutput('-v tree/lightcheckout', lco_tree, repo_branch=repo_branch, tree_locked=True, branch_locked=True, repo_locked=True, verbose=True) finally: lco_tree.unlock() # L L U lco_tree.lock_write() lco_tree.branch.repository.unlock() try: self.assertCheckoutStatusOutput('-v tree/lightcheckout', lco_tree, repo_branch=repo_branch, tree_locked=True, branch_locked=True, verbose=True) finally: lco_tree.branch.repository.lock_write() lco_tree.unlock() # L U U lco_tree.lock_write() lco_tree.branch.unlock() try: self.assertCheckoutStatusOutput('-v tree/lightcheckout', lco_tree, repo_branch=repo_branch, tree_locked=True, verbose=True) finally: lco_tree.branch.lock_write() lco_tree.unlock() # L U L lco_tree.lock_write() lco_tree.branch.unlock() lco_tree.branch.repository.lock_write() try: self.assertCheckoutStatusOutput('-v tree/lightcheckout', lco_tree, repo_branch=repo_branch, tree_locked=True, repo_locked=True, verbose=True) finally: lco_tree.branch.repository.unlock() lco_tree.branch.lock_write() lco_tree.unlock() # U L U lco_tree.branch.lock_write() lco_tree.branch.repository.unlock() try: self.assertCheckoutStatusOutput('-v tree/lightcheckout', lco_tree, repo_branch=repo_branch, branch_locked=True, verbose=True) finally: lco_tree.branch.repository.lock_write() lco_tree.branch.unlock() if sys.platform == 'win32': self.knownFailure('Win32 cannot run "bzr info"' ' when the tree is locked.') def test_info_locking_oslocks(self): if sys.platform == "win32": raise tests.TestSkipped("don't use oslocks on win32 in unix manner") # This test tests old (all-in-one, OS lock using) behaviour which # simply cannot work on windows (and is indeed why we changed our # design. As such, don't try to remove the thisFailsStrictLockCheck # call here. self.thisFailsStrictLockCheck() tree = self.make_branch_and_tree('branch', format='weave') # Test all permutations of locking the working tree, branch and repository # XXX: Well not yet, as we can't query oslocks yet. Currently, it's # implemented by raising NotImplementedError and get_physical_lock_status() # always returns false. This makes bzr info hide the lock status. (Olaf) # W B R # U U U out, err = self.run_bzr('xmlinfo -v branch') expected_xml = ''' Standalone tree weave %s All-in-one format 6 Working tree format 2 Branch format 4 %s 0 0 0 0 0 0 0 0 0 0 0 ''' % ('branch', tree.branch.repository._format.get_format_description(), ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) # L L L tree.lock_write() out, err = self.run_bzr('xmlinfo -v branch') expected_xml = ''' Standalone tree weave %s All-in-one format 6 Working tree format 2 Branch format 4 %s 0 0 0 0 0 0 0 0 0 0 0 '''% ('branch', tree.branch.repository._format.get_format_description(), ) expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqualDiff(expected_xml, out) self.assertEqual('', err) tree.unlock() def test_info_stacked(self): # We have a mainline trunk_tree = self.make_branch_and_tree('mainline', format='1.6') trunk_tree.commit('mainline') # and a branch from it which is stacked new_dir = trunk_tree.bzrdir.sprout('newbranch', stacked=True) out, err = self.run_bzr('xmlinfo newbranch') expected_xml = ''' Standalone tree 1.6 newbranch mainline mainline ''' expected_xml = ''.join(expected_xml.split('\n'))+'\n' self.assertEqual(expected_xml, out) self.assertEqual("", err) bzr-xmloutput-0.8.8+bzr162/tests/test_log_xml.py0000644000000000000000000007245011720667170020006 0ustar 00000000000000# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd # Copyright (C) 2008, 2009 Guillermo Gonzalez # -*- coding: utf-8 -*- # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """Black-box tests for bzr log.""" import os import bzrlib from bzrlib import osutils from bzrlib.tests.blackbox import ExternalBase from bzrlib.tests import TestCaseInTempDir, TestCaseWithTransport from bzrlib.xml_serializer import elementtree as elementtree fromstring = elementtree.fromstring elementtree_tostring = elementtree.tostring class TestLog(ExternalBase): def _prepare(self, path='.', format=None): tree = self.make_branch_and_tree(path, format=format) self.build_tree( [path + '/hello.txt', path + '/goodbye.txt', path + '/meep.txt']) tree.add('hello.txt') tree.commit(message='message1') tree.add('goodbye.txt') tree.commit(message='message2') tree.add('meep.txt') tree.commit(message='message3') self.full_log_xml = fromstring(self.run_bzr(["xmllog", path])[0]) return tree def test_log_null_end_revspec(self): self._prepare() for revno in self.full_log_xml.findall('log/revno'): self.assertTrue(revno.text in ['1', '2', '3']) for message in self.full_log_xml.findall('log/message'): self.assertTrue(message.text.strip() in ['message1', 'message2', 'message3']) log_xml = fromstring(self.run_bzr("xmllog -r 1..")[0]) for elem1, elem2 in zip(log_xml.getiterator(), self.full_log_xml.getiterator()): self.assertEquals(elem1.tag, elem2.tag) self.assertEquals(elem1.text, elem2.text) #self.assertEqualDiff(log_xml, self.full_log_xml) def test_log_null_begin_revspec(self): self._prepare() log_xml = fromstring(self.run_bzr("xmllog -r ..3")[0]) #self.assertEqualDiff(self.full_log, log) for elem1, elem2 in zip(log_xml.getiterator(), self.full_log_xml.getiterator()): self.assertEquals(elem1.tag, elem2.tag) self.assertEquals(elem1.text, elem2.text) def test_log_null_both_revspecs(self): self._prepare() log_xml = fromstring(self.run_bzr("xmllog -r ..")[0]) #self.assertEquals(self.full_log, log) #self.assertEqualDiff(self.full_log, log) for elem1, elem2 in zip(log_xml.getiterator(), self.full_log_xml.getiterator()): self.assertEquals(elem1.tag, elem2.tag) self.assertEquals(elem1.text, elem2.text) def test_log_negative_begin_revspec_full_log(self): self._prepare() log_xml = fromstring(self.run_bzr("xmllog -r -3..")[0]) #self.assertEqualDiff(self.full_log, log) for elem1, elem2 in zip(log_xml.getiterator(), self.full_log_xml.getiterator()): self.assertEquals(elem1.tag, elem2.tag) self.assertEquals(elem1.text, elem2.text) def test_log_negative_both_revspec_full_log(self): self._prepare() log_xml = fromstring(self.run_bzr("xmllog -r -3..-1")[0]) #self.assertEqualDiff(self.full_log, log) for elem1, elem2 in zip(log_xml.getiterator(), self.full_log_xml.getiterator()): self.assertEquals(elem1.tag, elem2.tag) self.assertEquals(elem1.text, elem2.text) def test_log_negative_both_revspec_partial(self): self._prepare() log_xml = fromstring(self.run_bzr("xmllog -r -3..-2")[0]) #self.assertTrue('revno: 1\n' in log) #self.assertTrue('revno: 2\n' in log) #self.assertTrue('revno: 3\n' not in log) for revno in log_xml.findall('log/revno'): self.assertTrue(revno.text in ['1', '2']) self.assertTrue(revno.text not in ['3']) def test_log_negative_begin_revspec(self): self._prepare() log_xml = fromstring(self.run_bzr("xmllog -r -2..")[0]) for revno in log_xml.findall('log/revno'): self.assertTrue(revno.text in ['2', '3']) self.assertTrue(revno.text not in ['1']) #self.assertTrue('revno: 1\n' not in log) #self.assertTrue('revno: 2\n' in log) #self.assertTrue('revno: 3\n' in log) def test_log_postive_revspecs(self): self._prepare() log_xml = fromstring(self.run_bzr("xmllog -r 1..3")[0]) #self.assertEqualDiff(self.full_log, log) for elem1, elem2 in zip(log_xml.getiterator(), \ self.full_log_xml.getiterator()): self.assertEquals(elem1.tag, elem2.tag) self.assertEquals(elem1.text, elem2.text) def test_log_reversed_revspecs(self): self._prepare() #self.run_bzr_error(('' # 'BzrCommandErrormsg' # 'Start revision must be older than the end revision.' # 'Start revision must be older than the end ' # 'revision.',), self.run_bzr_error(('Start revision must be older than ' 'the end revision.',), ['xmllog', '-r3..1']) def test_log_revno_n_path(self): self._prepare(path='branch1') self._prepare(path='branch2') log = self.run_bzr("xmllog -r revno:2:branch1..revno:3:branch2", retcode=3)[0] log_xml = fromstring(self.run_bzr("xmllog -r revno:1:branch2..revno:3:branch2")[0]) self.assertEqualDiff(elementtree_tostring(self.full_log_xml), elementtree_tostring(log_xml)) log_xml = fromstring(self.run_bzr("xmllog -r revno:1:branch2")[0]) for revno in log_xml.findall('log/revno'): self.assertTrue(revno.text in ['1']) self.assertTrue(revno.text not in ['2']) for branch_nick in log_xml.findall('log/branch-nick'): self.assertTrue(branch_nick.text in ['branch2']) self.assertTrue(branch_nick.text not in ['branch1']) def test_log_nonexistent_file(self): # files that don't exist in either the basis tree or working tree # should give an error wt = self.make_branch_and_tree('.') out, err = self.run_bzr('xmllog does-not-exist', retcode=3) self.assertContainsRe( err, 'Path unknown at end or start of revision range: does-not-exist') def test_log_with_tags(self): tree = self._prepare(format='dirstate-tags') branch = tree.branch branch.tags.set_tag('tag1', branch.get_rev_id(1)) branch.tags.set_tag('tag1.1', branch.get_rev_id(1)) branch.tags.set_tag('tag3', branch.last_revision()) log_xml = fromstring(self.run_bzr("xmllog -r-1")[0]) for tag in log_xml.findall('log/tags/tag'): self.assertEquals(tag.text, 'tag3') #self.assertTrue('tags: tag3' in log) log_xml = fromstring(self.run_bzr("xmllog -r1")[0]) for tag in log_xml.findall('log/tags/tag'): self.assertTrue(tag.text in ['tag1', 'tag1.1']) # I guess that we can't know the order of tags in the output # since dicts are unordered, need to check both possibilities #self.assertContainsRe(log, r'tags: (tag1, tag1\.1|tag1\.1, tag1)') def test_merged_log_with_tags(self): branch1_tree = self._prepare(path='branch1', format='dirstate-tags') branch1 = branch1_tree.branch branch2_tree = branch1_tree.bzrdir.sprout('branch2').open_workingtree() branch1_tree.commit(message='foobar', allow_pointless=True) branch1.tags.set_tag('tag1', branch1.last_revision()) os.chdir('branch2') self.run_bzr('merge ../branch1') # tags don't propagate otherwise branch2_tree.commit(message='merge branch 1') log_xml = fromstring(self.run_bzr("xmllog -r-1")[0]) for tag in log_xml.findall('log/merge/log/tags/tag'): self.assertEquals(tag.text, 'tag1') #self.assertContainsRe(log, r' tags: tag1') log_xml = fromstring(self.run_bzr("xmllog -r3.1.1")[0]) for tag in log_xml.findall('log/tags/tag'): self.assertEquals(tag.text, 'tag1') #self.assertContainsRe(log, r'tags: tag1') def test_log_limit(self): self._prepare() log_xml = fromstring(self.run_bzr("xmllog --limit 2")[0]) for revno in log_xml.findall('log/revno'): self.assertTrue(revno.text in ['2', '3']) self.assertTrue(revno.text not in ['1']) #self.assertTrue('revno: 1\n' not in log) #self.assertTrue('revno: 2\n' in log) #self.assertTrue('revno: 3\n' in log) class TestLogMerges(ExternalBase): def _prepare(self): parent_tree = self.make_branch_and_tree('parent') parent_tree.commit(message='first post', allow_pointless=True) child_tree = parent_tree.bzrdir.sprout('child').open_workingtree() child_tree.commit(message='branch 1', allow_pointless=True) smaller_tree = \ child_tree.bzrdir.sprout('smallerchild').open_workingtree() smaller_tree.commit(message='branch 2', allow_pointless=True) child_tree.merge_from_branch(smaller_tree.branch) child_tree.commit(message='merge branch 2') parent_tree.merge_from_branch(child_tree.branch) parent_tree.commit(message='merge branch 1') smaller_tree.merge_from_branch(child_tree.branch) smaller_tree.commit(message="merge branch 1 (in smallertree)") os.chdir('parent') def test_merges_are_indented_by_level(self): self._prepare() out,err = self.run_bzr('xmllog') # the log will look something like: # self.assertEqual("""\ #------------------------------------------------------------ #revno: 2 #committer: Robert Collins #branch nick: parent #timestamp: Tue 2006-03-28 22:31:40 +1100 #message: # merge branch 1 # ------------------------------------------------------------ # revno: 1.1.2 # committer: Robert Collins # branch nick: child # timestamp: Tue 2006-03-28 22:31:40 +1100 # message: # merge branch 2 # ------------------------------------------------------------ # revno: 1.1.1.1 # committer: Robert Collins # branch nick: smallerchild # timestamp: Tue 2006-03-28 22:31:40 +1100 # message: # branch 2 # ------------------------------------------------------------ # revno: 1.1.1 # committer: Robert Collins # branch nick: child # timestamp: Tue 2006-03-28 22:31:40 +1100 # message: # branch 1 #------------------------------------------------------------ #revno: 1 #committer: Robert Collins #branch nick: parent #timestamp: Tue 2006-03-28 22:31:39 +1100 #message: # first post #""", out) # but we dont have a nice pattern matcher hooked up yet, so: # we check for the indenting of the commit message and the # revision numbers #self.assertTrue('revno: 2' in out) #self.assertTrue(' merge branch 1' in out) #self.assertTrue(' revno: 1.1.2' in out) #self.assertTrue(' merge branch 2' in out) #self.assertTrue(' revno: 1.1.1.1' in out) #self.assertTrue(' branch 2' in out) #self.assertTrue(' revno: 1.1.1' in out) #self.assertTrue(' branch 1' in out) #self.assertTrue('revno: 1\n' in out) #self.assertTrue(' first post' in out) log_xml = fromstring(out) for revno in log_xml.findall('log/revno'): self.assertTrue(revno.text in ['1', '2']) for message in log_xml.findall('log/message'): self.assertTrue(message.text.strip() in ['merge branch 1', 'first post']) for revno in log_xml.findall('log/merge/log/revno'): self.assertTrue(revno.text in ['1.1.2', '1.1.1']) for message in log_xml.findall('log/merge/log/message'): self.assertTrue(message.text.strip() in ['merge branch 2', 'branch 1']) for revno in log_xml.findall('log/merge/log/merge/log/revno'): self.assertEquals(revno.text, '1.2.1') for message in log_xml.findall('log/merge/log/merge/log/message'): self.assertEquals(message.text.strip(), 'branch 2') self.assertEqual('', err) def test_merges_single_merge_rev(self): self._prepare() out,err = self.run_bzr('xmllog -r1.1.2') # the log will look something like: # self.assertEqual("""\ #------------------------------------------------------------ #revno: 1.1.2 #committer: Robert Collins #branch nick: child #timestamp: Tue 2006-03-28 22:31:40 +1100 #message: # merge branch 2 # ------------------------------------------------------------ # revno: 1.1.1.1 # committer: Robert Collins # branch nick: smallerchild # timestamp: Tue 2006-03-28 22:31:40 +1100 # message: # branch 2 #""", out) # but we dont have a nice pattern matcher hooked up yet, so: # we check for the indenting of the commit message and the # revision numbers #self.assertTrue('revno: 2' not in out) #self.assertTrue(' merge branch 1' not in out) #self.assertTrue('revno: 1.1.2' in out) #self.assertTrue(' merge branch 2' in out) #self.assertTrue(' revno: 1.1.1.1' in out) #self.assertTrue(' branch 2' in out) #self.assertTrue('revno: 1.1.1\n' not in out) #self.assertTrue(' branch 1' not in out) #self.assertTrue('revno: 1\n' not in out) #self.assertTrue(' first post' not in out) #out,err = self.run_bzr('xmllog -r1.1.2') log_xml = fromstring(out) for revno in log_xml.findall('log/revno'): self.assertEquals(revno.text, '1.1.2') self.assertTrue(revno.text not in ['1.1.1', '2', '1']) for message in log_xml.findall('log/message'): self.assertEquals(message.text.strip(), 'merge branch 2') self.assertTrue(message.text.strip() not in ['merge branch 1', 'first post', 'branch 1']) for revno in log_xml.findall('log/merge/log/revno'): self.assertEquals(revno.text, '1.2.1') for message in log_xml.findall('log/merge/log/message'): self.assertEquals(message.text.strip(), 'branch 2') self.assertEqual('', err) def test_merges_partial_range(self): self._prepare() out,err = self.run_bzr('xmllog -r1.1.1..1.1.2') # the log will look something like: # self.assertEqual("""\ #------------------------------------------------------------ #revno: 1.1.2 #committer: Robert Collins #branch nick: child #timestamp: Tue 2006-03-28 22:31:40 +1100 #message: # merge branch 2 # ------------------------------------------------------------ # revno: 1.1.1.1 # committer: Robert Collins # branch nick: smallerchild # timestamp: Tue 2006-03-28 22:31:40 +1100 # message: # branch 2 #------------------------------------------------------------ #revno: 1.1.1 #committer: Robert Collins #branch nick: child #timestamp: Tue 2006-03-28 22:31:40 +1100 #message: # branch 1 #""", out) # but we dont have a nice pattern matcher hooked up yet, so: # we check for the indenting of the commit message and the # revision numbers #self.assertTrue('revno: 2' not in out) #self.assertTrue(' merge branch 1' not in out) #self.assertTrue('revno: 1.1.2' in out) #self.assertTrue(' merge branch 2' in out) #self.assertTrue(' revno: 1.1.1.1' in out) #self.assertTrue(' branch 2' in out) #self.assertTrue('revno: 1.1.1' in out) #self.assertTrue(' branch 1' in out) #self.assertTrue('revno: 1\n' not in out) #self.assertTrue(' first post' not in out) log_xml = fromstring(out) for revno in log_xml.findall('log/revno'): self.assertTrue(revno.text in ['1.1.2', '1.1.1']) self.assertTrue(revno.text not in ['2', '1']) for message in log_xml.findall('log/message'): self.assertTrue(message.text.strip() in ['branch 1', 'merge branch 2']) self.assertTrue(message.text.strip() not in ['merge branch 1', 'first post']) for revno in log_xml.findall('log/merge/log/revno'): self.assertEquals(revno.text, '1.2.1') for message in log_xml.findall('log/merge/log/message'): self.assertEquals(message.text.strip(), 'branch 2') self.assertEqual('', err) class TestLogNestedMerges(ExternalBase): def _prepare(self): # TODO: find the correct command secuence to get the xml # This is a home-made xml because I don't know how to generate # this particular case of nested merges (which I found that happen # in bzr.dev itself) xml = (''' 1 guillo <guillo@shire> parent Mon 2007-11-05 00:37:20 -0300 first post 2 guillo <guillo@shire> parent Mon 2007-11-05 00:37:21 -0300 merge branch 1 1.1.1 guillo <guillo@shire> smallerchild Mon 2007-11-05 00:37:21 -0300 merge first post 1.1 guillo <guillo@shire> child Mon 2007-11-05 00:37:21 -0300 merge branch 2 ''' % bzrlib.osutils.get_user_encoding()) return xml def test_nested_merges(self): log_xml = fromstring(self._prepare()) for revno in log_xml.findall('log/revno'): self.assertTrue(revno.text in ['1', '2']) for message in log_xml.findall('log/message'): self.assertTrue(message.text.strip() in ['first post', 'merge branch 1']) for revno in log_xml.findall('log/merge/log/revno'): self.assertEquals(revno.text, '1.1') for message in log_xml.findall('log/merge/log/message'): self.assertEquals(message.text.strip(), 'merge branch 2') for revno in log_xml.findall('log/merge/merge/log/revno'): self.assertEquals(revno.text, '1.1.1') for message in log_xml.findall('log/merge/merge/log/message'): self.assertEquals(message.text.strip(), 'merge first post') class TestLogEncodings(TestCaseInTempDir): _mu = u'\xb5' _message = u'Message with \xb5' # Encodings which can encode mu good_encodings = [ 'utf-8', 'latin-1', 'iso-8859-1', 'cp437', # Common windows encoding 'cp1251', # Alexander Belchenko's windows encoding 'cp1258', # Common windows encoding ] # Encodings which cannot encode mu bad_encodings = [ 'ascii', 'iso-8859-2', 'koi8_r', ] def setUp(self): TestCaseInTempDir.setUp(self) self.old_user_encoding = osutils._cached_user_encoding self.old_get_user_encoding = osutils.get_user_encoding def tearDown(self): osutils._cached_user_encoding = self.old_user_encoding if hasattr(bzrlib, 'user_encoding'): bzrlib.user_encoding = self.old_user_encoding osutils._cached_user_encoding = self.old_user_encoding osutils.get_user_encoding = self.old_get_user_encoding TestCaseInTempDir.tearDown(self) def create_branch(self): bzr = self.run_bzr bzr('init') open('a', 'wb').write('some stuff\n') bzr('add a') bzr(['commit', '-m', self._message]) def try_encoding(self, encoding, fail=False): bzr = self.run_bzr if fail: self.assertRaises(UnicodeEncodeError, self._mu.encode, encoding) encoded_msg = self._message.encode(encoding, 'replace') else: encoded_msg = self._message.encode(encoding) old_encoding = osutils._cached_user_encoding # This test requires that 'run_bzr' uses the current # bzrlib, because we override user_encoding, and expect # it to be used try: osutils._cached_user_encoding = 'ascii' bzrlib.osutils.get_user_encoding = lambda: 'ascii' if hasattr(bzrlib, 'user_encoding'): bzrlib.user_encoding = 'ascii' # We should be able to handle any encoding out, err = bzr('xmllog', encoding=encoding) if not fail: # Make sure we wrote mu as we expected it to exist self.assertNotEqual(-1, out.find(encoded_msg)) out_unicode = out.decode(encoding) self.assertNotEqual(-1, out_unicode.find(self._message)) else: self.assertNotEqual(-1, out.find('Message with ?')) finally: osutils._cached_user_encoding = old_encoding if hasattr(bzrlib, 'user_encoding'): bzrlib.user_encoding = old_encoding def test_log_handles_encoding(self): self.create_branch() for encoding in self.good_encodings: self.try_encoding(encoding) def test_log_handles_bad_encoding(self): self.create_branch() for encoding in self.bad_encodings: self.try_encoding(encoding, fail=True) def test_stdout_encoding(self): bzr = self.run_bzr osutils._cached_user_encoding = 'cp1251' bzrlib.osutils.get_user_encoding = lambda: 'cp1251' if hasattr(bzrlib, 'user_encoding'): bzrlib.user_encoding = 'cp1251' bzr('init') self.build_tree(['a']) bzr('add a') bzr(['commit', '-m', u'\u0422\u0435\u0441\u0442']) stdout, stderr = self.run_bzr('xmllog', encoding='cp866') #message = stdout.splitlines()[-1] #log_xml = fromstring(stdout) #message = log_xml.findall('log/message')[0] # FIXME: little hack to get the message in the correct encoding. # Because if we generate the xml with 'fromstring', it's generated # using the the user encoding (which is cp1251) message = stdout.split('message')[1].strip(' ') # explanation of the check: # u'\u0422\u0435\u0441\u0442' is word 'Test' in russian # in cp866 encoding this is string '\x92\xa5\xe1\xe2' # in cp1251 encoding this is string '\xd2\xe5\xf1\xf2' # This test should check that output of log command # encoded to sys.stdout.encoding test_in_cp866 = '\x92\xa5\xe1\xe2' test_in_cp1251 = '\xd2\xe5\xf1\xf2' # Make sure the log string is encoded in cp866 cdata = '_Mundo']) self.wt.commit('add') self.build_tree(['subdir/']) # Check what happens if the id contains <, @ and > expected_items = [{'id': 'Hola__Mundo', 'kind': 'file', 'path': 'a', 'status_kind': 'versioned'}] self.assertEquals(expected_items, self.run_xmlls('--revision 1')) bzr-xmloutput-0.8.8+bzr162/tests/test_service.py0000644000000000000000000000320711353026034017765 0ustar 00000000000000# -*- encoding: utf-8 -*- import xmlrpclib import threading from bzrlib import ( tests, ui, ) from bzrlib.plugins.xmloutput.service import * class TestXmlRpcServer(tests.TestCase): def setUp(self): tests.TestCase.setUp(self) self.host = 'localhost' self.port = 0 self._start_server() self.client = xmlrpclib.Server("http://%s:%s" % (self.host, str(self.port))) def _start_server(self): self.server = BzrXMLRPCServer((self.host, self.port)) self.thread = threading.Thread(target=self.server.serve_forever) self.thread.setDaemon(True) self.thread.start() self.host, self.port = self.server.socket.getsockname() def tearDown(self): response = self.client.quit() self.thread.join() tests.TestCase.tearDown(self) def test_hello(self): response = self.client.hello() self.assertEquals(response, "world!") def test_run_bzr(self): self.permit_source_tree_branch_repo() exit, out, err = self.client.run_bzr(['bzr', 'xmlversion'], '.') self.assertEquals(exit, 0) self.assertEquals(err, "") self.assertNotEquals(out.data, "") def test_custom_commands_main__should_support_non_ascii_unicode(self): from xmlrpclib import Fault try: response = custom_commands_main([u'bzr', u'log', u'Maçã']) except Fault, f: if (f.faultCode == 32): # Not a Bazaar Error self.assertNotContainsRe(f.faultString, 'UnicodeEncodeError') else: pass bzr-xmloutput-0.8.8+bzr162/tests/test_status_xml.py0000644000000000000000000004276511720667170020556 0ustar 00000000000000# Copyright (C) 2005, 2006 Canonical Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """Tests of status command. Most of these depend on the particular formatting used. As such they really are blackbox tests even though some of the tests are not using self.capture. If we add tests for the programmatic interface later, they will be non blackbox tests. """ from cStringIO import StringIO import codecs from os import mkdir, chdir, rmdir, unlink import sys from tempfile import TemporaryFile from bzrlib import ( bzrdir, conflicts, errors, osutils, ) import bzrlib.branch from bzrlib.osutils import pathjoin from bzrlib.revisionspec import RevisionSpec from bzrlib.tests import TestCaseWithTransport, TestSkipped from bzrlib.xml_serializer import elementtree as elementtree import bzrlib.plugin fromstring = elementtree.fromstring from elementtree_builder import _E ## little hack to load functions from parent module show_tree_status_xml = None plugins = bzrlib.plugin.plugins() for p in plugins: if getattr(plugins[p].module, 'plugin_name', None) is not None \ and plugins[p].module.plugin_name == 'xmloutput': from sys import path import imp path.append(plugins[p].module.__path__[0]) fp, pathname, description = imp.find_module('statusxml') show_tree_status_xml = imp.load_module('statusxml', fp, pathname, description).show_tree_status_xml def create_xml(wt, status_dict): E = _E() status = E('status') status.attrib["workingtree_root"] = wt.id2abspath(wt.get_root_id()) for key in status_dict.keys(): status_kind = E(key) for file_kind, name, attributes in status_dict[key]: kind = E(file_kind, name) for attrib in attributes.keys(): kind.attrib[attrib] = attributes[attrib] status_kind.append(kind) status.append(status_kind) return status class TestXmlStatus(TestCaseWithTransport): def assertStatus(self, expected_xml_element, working_tree, revision=None, specific_files=None): """Run status in working_tree and look for output. :param expected_lines: The lines to look for. :param working_tree: The tree to run status in. """ output_string = self.status_string(working_tree, revision, specific_files) output_elem = fromstring(output_string) self.assertEqual(len(output_elem.findall('added/*')), len(expected_xml_element.findall('added/*'))) self.assertEqual(len(output_elem.findall('modified')), len(expected_xml_element.findall('modified'))) self.assertEqual(len(output_elem.findall('unknown')), len(expected_xml_element.findall('unknown'))) self.assertEqual(len(output_elem.findall('deleted')), len(expected_xml_element.findall('deleted'))) self.assertEqual(len(output_elem.findall('renamed')), len(expected_xml_element.findall('renamed'))) self.assertEqual(len(output_elem.findall('kind_changed')), len(expected_xml_element.findall('kind_changed'))) self.assertEqual(len(output_elem.findall('removed')), len(expected_xml_element.findall('removed'))) self.assertEqual(len(output_elem.findall('pending_merges')), len(expected_xml_element.findall('pending_merges'))) self.assertEqual(len(output_elem.findall('conflicts')), len(expected_xml_element.findall('conflicts'))) def status_string(self, wt, revision=None, specific_files=None): # use a real file rather than StringIO because it doesn't handle # Unicode very well. tof = codecs.getwriter('utf-8')(TemporaryFile()) show_tree_status_xml(wt, to_file=tof, revision=revision, specific_files=specific_files) tof.seek(0) return tof.read().decode('utf-8') class BranchStatus(TestXmlStatus): def test_branch_statusxml(self): """Test basic branch status""" wt = self.make_branch_and_tree('.') # status with no commits or files - it must # work and show no output. We do this with no # commits to be sure that it's not going to fail # as a corner case. self.assertStatus(create_xml(wt, {}), wt) self.build_tree(['hello.c', 'bye.c']) two_unknowns = create_xml(wt, {'unknown':[('file','bye.c', {}), ('file','hello.c', {})]}) self.assertStatus(two_unknowns, wt) # add a commit to allow showing pending merges. wt.commit('create a parent to allow testing merge output') wt.add_parent_tree_id('pending@pending-0-0') with_pending_merges = create_xml(wt, {'unknown':[('file', 'bye.c', {}), ('file', 'hello.c', {})], 'pending_merges':[('pending_merge','pending@pending-0-0', {})]}) self.assertStatus(with_pending_merges, wt) def test_branch_statusxml_revisions(self): """Tests branch status with revisions""" wt = self.make_branch_and_tree('.') self.build_tree(['hello.c', 'bye.c']) wt.add('hello.c') wt.add('bye.c') wt.commit('Test message') revs = [RevisionSpec.from_string('0')] two_added = create_xml(wt, {'added':[('file', 'bye.c', {}), ('file', 'hello.c', {})]}) self.assertStatus(two_added, wt, revision=revs) self.build_tree(['more.c']) wt.add('more.c') wt.commit('Another test message') revs.append(RevisionSpec.from_string('1')) self.assertStatus(two_added, wt, revision=revs) def test_pending_xml(self): """Pending merges display works, including Unicode""" mkdir("./branch") wt = self.make_branch_and_tree('branch') b = wt.branch wt.commit("Empty commit 1") b_2_dir = b.bzrdir.sprout('./copy') b_2 = b_2_dir.open_branch() wt2 = b_2_dir.open_workingtree() wt.commit(u"\N{TIBETAN DIGIT TWO} Empty commit 2") wt2.merge_from_branch(wt.branch) message = self.status_string(wt2) messageElem = fromstring(message.encode('utf-8','replace')) self.assertEquals(1, len(messageElem.findall('pending_merges'))) self.assertEquals(1, len(messageElem.findall('pending_merges/log'))) self.assertEndsWith( messageElem.findall('pending_merges/log/message')[0].text, "Empty commit 2") wt2.commit("merged") # must be long to make sure we see elipsis at the end wt.commit("Empty commit 3 " + "blah blah blah blah " * 100) wt2.merge_from_branch(wt.branch) message = self.status_string(wt2) messageElem = fromstring(message) self.assertEquals(1, len(messageElem.findall('pending_merges'))) self.assert_("Empty commit 3" in \ messageElem.findall('pending_merges/log/message')[0].text) def test_tree_statusxml_ignores(self): """Tests branch status with ignores""" wt = self.make_branch_and_tree('.') self.run_bzr('ignore *~') wt.commit('commit .bzrignore') self.build_tree(['foo.c', 'foo.c~']) one_unknown = create_xml(wt, {'unknown':[('file','foo.c', {})]}) self.assertStatus(one_unknown, wt) def test_tree_statusxml_specific_files(self): """Tests branch status with given specific files""" wt = self.make_branch_and_tree('.') b = wt.branch self.build_tree(['directory/','directory/hello.c', 'bye.c','test.c','dir2/']) wt.add('directory') wt.add('test.c') wt.commit('testing') xml_status = create_xml(wt, {'unknown':[('file','bye.c', {}), ('directory', 'dir2', {}), ('file', 'directory/hello.c', {})]}) self.assertStatus(xml_status, wt) tof = StringIO() show_tree_status_xml(wt, specific_files=['bye.c','test.c','absent.c'], to_file=tof) log_xml = fromstring(tof.getvalue()) nonexistents = log_xml.findall('nonexistents/nonexistent') unknowns = log_xml.findall('unknown') self.assertEquals(1, len(nonexistents)) self.assertEquals(1, len(unknowns)) self.assertStatus(create_xml(wt, {'unknown':[('file', 'directory/hello.c', {})]}), wt, specific_files=['directory']) self.assertStatus(create_xml(wt, {'unknown':[('directory', 'dir2', {})]}), wt, specific_files=['dir2']) revs = [RevisionSpec.from_string('0'), RevisionSpec.from_string('1')] self.assertStatus(create_xml(wt, {'added':[('file', 'test.c', {})]}), wt, revs, specific_files=['test.c']) def test_specific_files_conflicts_xml(self): tree = self.make_branch_and_tree('.') self.build_tree(['dir2/']) tree.add('dir2') tree.commit('added dir2') tree.set_conflicts(conflicts.ConflictList( [conflicts.ContentsConflict('foo')])) self.assertStatus(create_xml(tree, {}), tree, specific_files=['dir2']) tree.set_conflicts(conflicts.ConflictList( [conflicts.ContentsConflict('dir2')])) self.assertStatus(create_xml(tree, {'conflicts':[('directory','dir2', {})]}), tree, specific_files=['dir2']) tree.set_conflicts(conflicts.ConflictList( [conflicts.ContentsConflict('dir2/file1')])) self.assertStatus(create_xml(tree, {'conflicts':[('file','dir2/file1', {})]}), tree, specific_files=['dir2']) def test_statusxml_nonexistent_file(self): # files that don't exist in either the basis tree or working tree # should give an error wt = self.make_branch_and_tree('.') out, err = self.run_bzr('xmlstatus does-not-exist') log_xml = fromstring(out) status = log_xml.findall('nonexistents/nonexistent') self.assertEquals(1, len([elem for elem in status])) self.assertEquals(status[0].text, 'does-not-exist') def test_statusxml_out_of_date(self): """Simulate status of out-of-date tree after remote push""" # TODO: implement this error handling in xml specific way? tree = self.make_branch_and_tree('.') self.build_tree_contents([('a', 'foo\n')]) tree.lock_write() try: tree.add(['a']) tree.commit('add test file') # simulate what happens after a remote push tree.set_last_revision("0") finally: # before run another commands we should unlock tree tree.unlock() out, err = self.run_bzr('status') self.assertEqual("working tree is out of date, run 'bzr update'\n", err) class CheckoutStatus(BranchStatus): def setUp(self): super(CheckoutStatus, self).setUp() mkdir('codir') chdir('codir') def make_branch_and_tree(self, relpath): source = self.make_branch(pathjoin('..', relpath)) checkout = bzrdir.BzrDirMetaFormat1().initialize(relpath) bzrlib.branch.BranchReferenceFormat().initialize(checkout, target_branch=source) return checkout.create_workingtree() class TestStatus(TestCaseWithTransport): def test_statusxml_plain(self): tree = self.make_branch_and_tree('.') self.build_tree(['hello.txt']) result = fromstring(self.run_bzr("xmlstatus")[0]) self.assertEquals(result.findall('unknown/file')[0].text, "hello.txt") tree.add("hello.txt") result = fromstring(self.run_bzr("xmlstatus")[0]) self.assertEquals(result.findall('added/file')[0].text, "hello.txt") tree.commit(message="added") result = fromstring(self.run_bzr("xmlstatus -r 0..1")[0]) self.assertEquals(result.findall('added/file')[0].text, "hello.txt") result = fromstring(self.run_bzr("xmlstatus -c 1")[0]) self.assertEquals(result.findall('added/file')[0].text, "hello.txt") self.build_tree(['world.txt']) result = fromstring(self.run_bzr("xmlstatus -r 0")[0]) self.assertEquals(result.findall('added/file')[0].text, "hello.txt") self.assertEquals(result.findall('unknown/file')[0].text, "world.txt") result2 = fromstring(self.run_bzr("xmlstatus -r 0..")[0]) self.assertEquals( elementtree.tostring(result2), elementtree.tostring(result)) def test_statusxml_versioned(self): tree = self.make_branch_and_tree('.') self.build_tree(['hello.txt']) result = fromstring(self.run_bzr("xmlstatus --versioned")[0]) self.assert_(len(result.findall('unknown/*')) == 0) tree.add("hello.txt") result = fromstring(self.run_bzr("xmlstatus --versioned")[0]) self.assertEquals(result.findall('added/file')[0].text, "hello.txt") tree.commit("added") result = fromstring(self.run_bzr("xmlstatus --versioned -r 0..1")[0]) self.assertEquals(result.findall('added/file')[0].text, "hello.txt") self.build_tree(['world.txt']) result = fromstring(self.run_bzr("xmlstatus --versioned -r 0")[0]) self.assertEquals(result.findall('added/file')[0].text, "hello.txt") self.assert_(len(result.findall('unknown/*')) == 0) result2 = fromstring(self.run_bzr("xmlstatus --versioned -r 0..")[0]) self.assertEquals( elementtree.tostring(result2), elementtree.tostring(result)) # Not yet implemneted #def assertStatusContains(self, xpath): # """Run status, and assert it contains the given attribute at the # given element""" # for key in changes.keys(): # status_kind = E(key) # for file_kind, name, attributes in status_dict[key]: # kind = E(file_kind, name) # for attrib in attributes.keys(): # kind.attrib[attrib] = attributes[attrib] # status_kind.append(kind) # status.append(status_kind) # return status # result = fromstring(self.run_bzr("xmlstatus")[0]) # result = self.run_bzr("xmlstatus")[0] # self.assertContainsRe(result, pattern) def test_kind_change_xml(self): tree = self.make_branch_and_tree('.') self.build_tree(['file']) tree.add('file') tree.commit('added file') unlink('file') self.build_tree(['file/']) #self.assertStatusContains('K file => file/') result = fromstring(self.run_bzr("xmlstatus")[0]) self.assert_(result.findall('kind_changed/*')[0].attrib['oldkind'] == 'file') self.assert_(result.findall('kind_changed/*')[0].tag == 'directory') tree.rename_one('file', 'directory') result = fromstring(self.run_bzr("xmlstatus")[0]) self.assert_(result.findall('renamed/directory')[0].attrib['oldpath'] == 'file') self.assert_(result.findall('renamed/directory')[0].text == 'directory') #self.assertStatusContains('RK file => directory/') rmdir('directory') result = fromstring(self.run_bzr("xmlstatus")[0]) self.assert_(result.findall('removed/*')[0].text == 'file') #self.assertStatusContains('RD file => directory') def test_statusxml_illegal_revision_specifiers(self): out, err = self.run_bzr('status -r 1..23..123', retcode=3) self.assertContainsRe(err, 'one or two revision specifiers') class TestXmlStatusEncodings(TestXmlStatus): def setUp(self): TestCaseWithTransport.setUp(self) self.old_user_encoding = osutils._cached_user_encoding self.old_get_user_encoding = osutils.get_user_encoding self.stdout = sys.stdout def tearDown(self): osutils._cached_user_encoding = self.old_user_encoding if hasattr(bzrlib, 'user_encoding'): bzrlib.user_encoding = self.old_user_encoding osutils._cached_user_encoding = self.old_user_encoding osutils.get_user_encoding = self.old_get_user_encoding sys.stdout = self.stdout TestCaseWithTransport.tearDown(self) def make_uncommitted_tree(self): """Build a branch with uncommitted unicode named changes in the cwd.""" working_tree = self.make_branch_and_tree(u'.') filename = u'hell\u00d8' try: self.build_tree_contents([(filename, 'contents of hello')]) except UnicodeEncodeError: raise TestSkipped("can't build unicode working tree in " "filesystem encoding %s" % sys.getfilesystemencoding()) working_tree.add(filename) return working_tree def test_stdout_ascii_xml(self): sys.stdout = StringIO() osutils._cached_user_encoding = 'ascii' bzrlib.osutils.get_user_encoding = lambda: 'ascii' if hasattr(bzrlib, 'user_encoding'): bzrlib.user_encoding = 'ascii' working_tree = self.make_uncommitted_tree() stdout, stderr = self.run_bzr("xmlstatus") messageElem = fromstring(stdout) self.assertEquals(messageElem.findall('added/file')[0].text, "hell?") bzr-xmloutput-0.8.8+bzr162/tests/test_version_xml.py0000644000000000000000000001101111720667170020674 0ustar 00000000000000# Copyright (C) 2007 Canonical Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """Black-box tests for bzr version.""" import sys import bzrlib from bzrlib import osutils, trace from bzrlib.tests import ( probe_unicode_in_user_encoding, TestCaseInTempDir, TestSkipped, ) from bzrlib.xml_serializer import elementtree as elementtree fromstring = elementtree.fromstring from bzrlib.plugins.xmloutput import versionxml class BaseVersionXMLTestCase(TestCaseInTempDir): """Base versionxml testcase.""" def setUp(self): TestCaseInTempDir.setUp(self) # versionxml tries to call bzrlib.version._get_bzr_source_tree(), which # tries an open_containing within the bzr installation. This will cause # a test isolation failure. You might hope that you could avoid this # with TestCase.permit_source_tree_branch_repo(), but this does not # work when running against a bzr installation that has no source tree, # as in this case, the open_containing operation needs to recurse # upwards to the filesystem root before it knows that it is finished. # Therefore we just stub out the relevant function so that it does not # call the problem method. self.old_show_source_tree = versionxml._show_source_tree versionxml._show_source_tree = lambda _: None def tearDown(self): # restore the patched function. versionxml._show_source_tree = self.old_show_source_tree TestCaseInTempDir.tearDown(self) class TestVersionXML(BaseVersionXMLTestCase): def test_version(self): out = self.run_bzr("xmlversion")[0] versionElem = fromstring(out) self.assertTrue(len(out) > 0) self.assertEquals(1, len(versionElem.findall('bazaar/version'))) self.assertEquals(1, len(versionElem.findall('bazaar/bzrlib'))) self.assertEquals(1, len(versionElem.findall('bazaar/configuration'))) self.assertEquals(1, len(versionElem.findall('bazaar/log_file'))) self.assertEquals(1, len(versionElem.findall('bazaar/copyright'))) if sys.platform == "win32": self.assertEquals(1, len(versionElem.findall('python/dll'))) else: self.assertEquals(1, len(versionElem.findall('python/executable'))) self.assertEquals(1, len(versionElem.findall('python/version'))) self.assertEquals(1, len(versionElem.findall('python/standard_library'))) class TestVersionXMLUnicodeOutput(BaseVersionXMLTestCase): def _check(self, args): # Even though trace._bzr_log_filename variable # is used only to keep actual log filename # and changing this variable in selftest # don't change main .bzr.log location, # and therefore pretty safe, # but we run these tests in separate temp dir # with relative unicoded path old_trace_file = trace._bzr_log_filename trace._bzr_log_filename = u'\u1234/.bzr.log' try: out = self.run_bzr(args)[0] finally: trace._bzr_log_filename = old_trace_file versionElem = fromstring(out) self.assertTrue(len(out) > 0) self.assertEquals(1, len(versionElem.findall('bazaar/log_file'))) def test_command(self): self._check("xmlversion") def test_unicode_bzr_home(self): uni_val, str_val = probe_unicode_in_user_encoding() if uni_val is None: raise TestSkipped('Cannot find a unicode character that works in' ' encoding %s' % \ bzrlib.osutils.get_user_encoding()) osutils.set_or_unset_env('BZR_HOME', str_val) out = self.run_bzr("xmlversion")[0] self.assertTrue(len(out) > 0) versionElem = fromstring(out) self.assertEquals(1, len(versionElem.findall('bazaar/configuration'))) self.assertContainsRe(out, r"" + str_val)