summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore8
-rw-r--r--COPYING661
-rw-r--r--HACKING295
-rw-r--r--Makefile33
-rw-r--r--README95
-rw-r--r--common.each.head.mk16
-rw-r--r--common.each.tail.mk42
-rw-r--r--common.once.head.mk27
-rw-r--r--common.once.tail.mk19
-rwxr-xr-xconfigure63
-rw-r--r--modules/.gitignore5
-rw-r--r--modules/Makefile24
l---------modules/blobs/.#get.f.sh1
l---------modules/blobs/Makefile1
-rw-r--r--modules/blobs/Makefile.inc.mk8
-rw-r--r--modules/blobs/Module.mk0
-rw-r--r--modules/blobs/_stdio.sh74
-rw-r--r--modules/blobs/commit.d.sh34
-rw-r--r--modules/blobs/commit.f.sh37
-rw-r--r--modules/blobs/commit.sh39
-rw-r--r--modules/blobs/get.d.sh37
-rw-r--r--modules/blobs/get.f.sh31
-rw-r--r--modules/blobs/get.sh28
-rw-r--r--modules/blobs/ls.sh50
-rw-r--r--modules/blobs/print.sh41
-rw-r--r--modules/blobs/tree.sh40
l---------modules/comments/Makefile1
-rw-r--r--modules/comments/Makefile.inc.mk2
-rw-r--r--modules/comments/Module.mk1
-rw-r--r--modules/comments/comment.sh26
-rw-r--r--modules/comments/commit.sh24
-rw-r--r--modules/comments/print.sh28
-rw-r--r--modules/comments/showcomment.sh27
l---------modules/date.author/Makefile1
-rw-r--r--modules/date.author/Makefile.inc.mk2
-rw-r--r--modules/date.author/Module.mk1
-rw-r--r--modules/date.author/commit.sh28
-rw-r--r--modules/git-fast-import/gen-parser.mk154
-rw-r--r--modules/git-fast-import/parse.sh1077
-rw-r--r--modules/module.mk36
l---------modules/tags/Makefile1
-rw-r--r--modules/tags/Makefile.inc.mk2
-rw-r--r--modules/tags/Module.mk1
-rw-r--r--modules/tags/commit.sh24
-rw-r--r--modules/tags/get-tag.sh25
-rw-r--r--modules/tags/print.sh30
-rw-r--r--modules/tags/tag-id.sh33
-rw-r--r--modules/tags/tag.sh28
l---------modules/tree/Makefile1
-rw-r--r--modules/tree/Makefile.inc.mk2
-rw-r--r--modules/tree/Module.mk1
-rw-r--r--modules/tree/addparent.d.sh44
-rw-r--r--modules/tree/addparent.f.sh27
-rw-r--r--modules/tree/addparent.sh35
-rw-r--r--modules/tree/commit.sh27
-rw-r--r--modules/tree/delparent.f.sh34
-rw-r--r--modules/tree/getchildren.sh28
-rw-r--r--modules/tree/getparents.sh27
-rw-r--r--modules/tree/print.sh27
-rw-r--r--wrapper/.gitignore3
-rw-r--r--wrapper/Makefile36
-rw-r--r--wrapper/inner.sh.m4156
-rw-r--r--wrapper/outer.c63
-rw-r--r--wrapper/runcmd.mk15
64 files changed, 3787 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2af088f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+/config.mk
+/config.h
+/config.sh
+*.o
+.*.mk
+/*.tar.*
+/*-[0-9]*/
+tmp.*
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..dba13ed
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,661 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ 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
+them 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.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey 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;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If 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 convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero 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 that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ 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.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+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.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ 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
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
diff --git a/HACKING b/HACKING
new file mode 100644
index 0000000..773d247
--- /dev/null
+++ b/HACKING
@@ -0,0 +1,295 @@
+#!/bin/less
+
+ Version 0.8c re-implements the wrapper in C, to allow better
+ cooperation between plugins via dependencies. This probably makes
+ a lot of this document out-dated, but a lot of it is still good, it
+ describes the workings of the plugins, and the repo structure.
+
+ I know this file is long* and boring. I try to keep it preened and
+ informative, but would rather spend my time actually hacking. If
+ you think you can help this file, have at it! ~ Luke Shumaker
+
+ * at 200+ lines, it's longer than any rvs source file
+
+- - -cut-here- - 8< - - - - - - - - - - - - - - - - - - - - - - - - -
+//////////////////////////////////////////////////////////////////////
+ rvs 0.7.0
+ retroactive versioning system
+ a versioning system that allows you to check
+ in commit 2 before commit 1
+//////////////////////////////////////////////////////////////////////
+
+ hacking
+
+ build basics
+
+ One of the coolest things about rvs (IMO) is how modular and
+ customizable it is. If you wish to create a fork of rvs, it would
+ be a good idea to give it a different name. This can be done
+ without even changing a single source file! Simply run configure
+ with `--name=NAME' option (variables that have `rvs' in the name
+ will not be renamed, but the user will never know this unless they
+ peek at the code).
+
+ Other options to configure and their default values are:
+
+ name='rvs'
+ The name of the program. Note that unlike most
+ variables, you should NOT call this in Makefiles
+ (`$(name)'), but use `$(rvs)' instead.
+ RVS='$(bindir)/$(rvs)'
+ Where the executable will be. `$(rvs)' is the same as
+ `$(name)' (see above). In this document it is
+ sometimes referred to as the `wrapper'.
+ SHELL='/bin/sh'
+ The shell that will be used by make, and the shell
+ that scripts will run in. (Perhaps we should make
+ these separate variables?)
+ prefix='/usr/local'
+ Standard GNU variable. Many of you will want to
+ change this to `/usr', or `/home/USER_NAME'
+ exec_prefix='$(prefix)'
+ Standard GNU variable.
+ bindir='$(exec_prefix)/bin'
+ Standard GNU variable.
+ sbindir='$(exec_prefix)/sbin'
+ Standard GNU variable.
+ libexecdir='$(exec_prefix)/libexec'
+ Standard GNU variable. The plugins will be installed
+ at $(libexecdir)/$(name)
+ srcdir=$(readlink -f `dirname "$0"`)
+ Where the source code is. The default value evaluates
+ to the directory of the `configure' script.
+
+ These can either be changed by manually changing `configure' or by
+ running it like:
+ ./configure --VAR_NAME=VALUE
+
+ In this document, the `$(VAR_NAME)' refers to whatever you set the
+ value to.
+
+ The configure script will run on any instance of `Makefile.in' in
+ $(srcdir).
+
+ Currently, rvs is distributed with 2 plugins. `repo'[sitory] is
+ the core of the rvs file database. `users' handles all usernames,
+ settings, and other info.
+
+ commands
+
+ By itself, rvs does almost nothing. All real functionality is
+ provided by plugins. When you invoke rvs, you do so in the format
+ `rvs COMMAND'. Plugins work by adding new commands.
+
+ Most commands are provided by plugins, however, a few are built in:
+ init
+ Initializes a repository in the current directory. It creates
+ `./.$(name)', and runs any initalizers for
+ plugins.
+ install PLUGIN DIR
+ Installs PLUGIN, for which the files are found in DIR. Unless
+ an older version is already installed, it adds the plugin to
+ have lowest priority (see `$(libexecdir)/$(rvs)/plugins').
+ uninstall PLUGIN
+ Uninstalls PLUGIN. Did that really need to be said?
+
+ A plugin is simply a collection of independent executable files.
+ When rvs is invoked, it looks for the COMMAND in a few places:
+ 1) checks if COMMAND is an built-in command
+ 2) looks at the file `$(libexecdir)/$(rvs)/plugins'. This is a
+ newline-delimited list of plugin names.
+ 3) loops through the directories `$(libexecdir)/$(rvs)/PLUGIN',
+ where PLUGIN is one of the values in
+ `$(libexecdir)/$(rvs)/plugins', in the order they appear in
+ the file.
+ 4) if rvs does not find the command, it reports an error
+
+ If you would like to contribute a plugin, or distribute one with a
+ fork, all you have to do is put it in `$(srcdir)/plugins/NAME'. The
+ main Makefile will recognize any directory in `$(srcdir)/plugins/'
+ as a plugin, and will run `make -C `plugins/NAME/Makefile'. It
+ should create a directory (mine use `plugins/NAME/out') to put ALL,
+ and ONLY the final files to be used by that plugin.
+
+========this is outdated but I don't really want to keep editing it ==
+
+ build system
+
+ The build system rvs uses is rather simple.
+ `./configure' does two things:
+ * create a sed script (`var.sed')
+ * run every instance of `$(srcdir)/Makefile.in' through
+ `var.sed' to generate a proper `Makefile'
+
+ `var.sed' contains all configuration variables. When it processes
+ a file every instance of `@VAR_NAME@' is replaced by that
+ variable's value. This makes `configure' act much like a GNU
+ package `configure'. Note that this replacement only happens for
+ defined variables.
+
+ Most of these can easily be changed _after_ `compilation' also:
+ VER line 4 of the wrapper
+ SHELL line 1 of each shell script
+ prefix simply move the wrapper
+ bindir simply move the wrapper
+ libexecdir move the directory, then update the line
+ `RVSDIR=...' in the wrapper
+
+ I have designed this system to be extremely modular. As you may
+ have figured out, each bit on functionality is in it's own
+ executable, and the file you call when you type `rvs' is just a
+ wrapper for them.
+
+ The wrapper is quite simple in mechanism. It simply checks if
+ `$$libdir$$/COMMAND_NAME' exists, and if so, runs that file.
+
+ The `rvs commit' command is also quite simple in design. It takes a
+ single argument; the file to commit. If no target is specified, it
+ defaults to `./'. It checks which type of file the target is, and
+ runs `rvs commit.FILE_CODE TARGET'. The file codes are as follows:
+
+ block (buffered) special b
+ character (unbuffered) special c
+ directory d
+ named pipe (FIFO) p
+ regular file f
+ symbolic link l
+ socket s
+ door (Solaris only) D
+
+ As you probably noticed (if you've looked at the blueprints or
+ source files), only directories and regular files have been
+ implemented as of rvs 0.7.0.
+
+ After `rvs commit' has done this, it creates a meta-file for that
+ commit. The meta file contains author, copyright owner, license
+ data, file permissions, timestamps, etc. The id of the meta-file is
+ written to stdout, and used to later check out that commit.
+
+ get works in much the same way as commit, only it reads the file
+ type from the meta-file, then runs `rvs get.FILE_CODE COMMIT_ID'.
+
+ If you implement any other file types, save the commit and get
+ functions in the proper locations.
+
+ Any commit function should take a filename as an argument and
+ output the according commit id to stdout. stderr should be used
+ for all messages.
+
+ Any get function should take the commit id as an argument and
+ uses stdout only if verbose, or to report errors.
+
+ To summarize, the modules are separate programs and communicate via
+ pipes, which is generally considered bad-design, and libraries
+ should be used instead. I deliberately broke this because:
+
+ 1. incompatible licenses can be used for different modules
+ 2. modules can be added/removed on the fly
+ 3. one can use any language to write new modules, without
+ having to worry about bindings`$(libexecdir)/$(rvs)
+
+ $$libdir$$/lib/
+
+ THIS WAS WRITTEN FOR rvs 0.6.2
+ THIS PORTION OF THE CODE IS BEING REVISED IN rvs 0.6.3
+
+ I have created two 'libraries' for use by rvs components. They
+ provide several functions that can be accessed by shell script by
+ using the code:
+ source "`rvs -d`/lib/stdio"
+ or
+ source "`rvs -d`/lib/rvsdb"
+ (`rvs -d' returns $$libdir$$)
+ stdio provides several functions for printing messages:
+ verbose MESSAGE
+ print MESSAGE to stdout only if $verbose is set to '-v'
+ out MESSAGE
+ print MESSAGE to stdout if $verbose isn't set to '-q'
+ warn MESSAGE
+ print "rvs: MESSAGE" to stderr
+ error MESSAGE
+ print "rvs: MESSAGE" and a quick message about `rvs --help'
+ (hinting at user error) to stderr, then exit with error
+ fatal MESSAGE
+ For internal error. Print "rvs: MESSAGE" to stderr and exit
+ with error
+ version
+ print the version information and exit with success
+
+ rvsdb provides several functions and variables for dealing with the
+ rvs database:
+ getid FILE
+ returns what the id of a given file would be if it were in
+ the database. This is used to know where to put files when
+ committing them. In 0.5.8-0.6.3 this is just the sha1sum of
+ the file
+ NOTE: the "log*" functions aren't very stable or developed
+ loginit FILE
+ initialize an rvs log at FILE. These logs are used for
+ metafiles, directory listings, and (probably) eventually
+ checkout logs
+ lograw LOG
+ prepare LOG for reading, and write the output to stdout (to
+ pipe into another function). This is mostly for internal
+ use by rvsdb
+ logread LOG VAR
+ read variable VAR from the logfile LOG
+ logwrite LOG VAR VAL
+ set variable VAR to VAL in the logfile LOG
+ logfind LOG VAL
+ return all the names of variables in logfile LOG who have
+ the value VAL
+
+ the database (.rvs/*)
+
+ So, what are all these files doing in this database? The scheme is
+ fairly simple. In the `.rvs' directory there is 1 directory, the
+ `files' directory. There used to be a folder for tmpfiles (0.5.8-
+ 0.6.2), but no more (0.6.3+). If you need a tmpfile, just run:
+ FILENAME=$(mktemp -t)
+ The `files' directory is where all the data is kept.
+
+ When any file is committed, whether it be a regular file, a
+ directory, a link, or any other type of file, 2 files are created
+ in `.rvs/files', the "raw-file" and the "meta-file". When we speak
+ of file IDs, we mean the filename of the corresponding file in
+ `.rvs/files' in rvs 0.5.8-0.6.3 this is just the sha1sum of the
+ file. The meta-file stores everything not part of the file itself;
+ the filename, file-type, author, copyright owner, file permissions,
+ timestamps, etc, and the ID of the corresponding raw-file. In the
+ case of an regular file, the raw-file contains the file itself. For
+ directories, it contains pointers to each file inside the
+ directory.
+
+ $$libdir$$/commit calls $$libdir$$/commit.FILETYPE to generate the
+ raw-file, but generates the meta-file itself (in `.rvs/tmp', then
+ calls commit.f to commit the meta-file). It then returns the ID of
+ the meta-file. Therefore, the user never deals with the IDs of
+ raw-files, and doesn't need to. The metafiles contain pointers to
+ the corresponding raw-files.
+
+ To keep things modular, commit.f is the ONLY thing that should
+ actually put files in `.rvs/files', and get.f the only thing that
+ should get them. Everything else should call them.
+
+ The repo and init are the ONLY things that should have `.rvs'
+ hardcoded into them. If the repository directory is needed, then
+ use `rvs repo'. Again, in the core, these should only be the .f
+ functions, however, it will be useful to plugins.
+
+ Why do we have the `files' directory, why don't we just put
+ everything in `.rvs'? This way:
+ * There is a spot to put user data, when we get around to writing
+ it
+
+ final thoughts
+
+ I have set up bazaar repository at Launchpad:
+ https://launchpad.net/rvs
+ Only until rvs becomes self-hosting.
+
+ If anyone needs any help, let me know, either via email, or via
+ Launchpad, I'll be happy to help/would love to have your help!
+
+~ Luke Shumaker <LukeShu@sbcglobal.net>
+Happy Hacking!
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..c939ea9
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,33 @@
+#!/usr/bin/make -f
+# Copyright (C) 2015 Luke Shumaker
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+include $(dir $(lastword $(MAKEFILE_LIST)))/config.mk
+include $(topsrcdir)/automake.head.mk
+
+am_subdirs = wrapper modules
+
+makefiles = Makefile automake.head.mk automake.tail.mk automake.txt common.once.head.mk common.once.tail.mk common.each.head.mk common.each.tail.mk
+am_src_files = COPYING HACKING README configure config.mk.in
+am_cfg_files = config.mk
+am_out_files = config.sh config.h
+
+config_vars = $(filter-out topsrcdir,$(shell $(SED) -n 's/^\s*\([a-z][^ !?:=]*\).*=.*/\1/p' $(topoutdir)/config.mk) PACKAGE VERSION)
+$(outdir)/config.sh: $(outdir)/config.mk
+ $(PRINTF) '%s=%s\n' $(foreach v,$(config_vars),$v $($v)) | LC_ALL=C $(SORT) > $@
+$(outdir)/config.h: $(outdir)/config.sh
+ . $(abspath $<) && $(PRINTF) '#define %s "%s"\n' $(foreach v,$(config_vars),$v '$($v)') PACKAGE_UPPER $${PACKAGE^^} | LC_ALL=C $(SORT) > $@
+
+include $(topsrcdir)/automake.tail.mk
diff --git a/README b/README
new file mode 100644
index 0000000..c245a78
--- /dev/null
+++ b/README
@@ -0,0 +1,95 @@
+//////////////////////////////////////////////////////////////////////
+ rvs 0.8c r54
+ retroactive versioning system
+ a versioning system that allows you to check
+ in commit 2 before commit 1
+//////////////////////////////////////////////////////////////////////
+
+introduction
+
+ rvs is about being able to go back and edit *anything* that has
+ already been committed. Yes, some other SCMs do this, but get
+ nasty if someone else has a copy of the old version.
+
+ Why would you want to do this? Take for example the Bazaar
+ repository rvs is hosted on: It starts at 0.6.0, what if I later
+ want to import 0.0.0 - 0.5.10? Or if I'm trying to construct a
+ history of BSD, and import all the BSDs I can find, such as 1,3,4,
+ then latter find 2?
+
+system requirements
+
+ Pretty much any *nix system should be able to run rvs. If you need
+ to use a shell other than `/bin/sh`, run `./configure` with the
+ `--SHELL=YOUR_SHELL` option. rvs is not designed for Windows, but
+ should be able to run in bash if you have some *nix pack installed.
+
+ To my knowledge, this is the absolute requirements (all but the
+ shell need to be in your PATH):
+ * a POSIX shell (tested with dash, and GNU BASH)
+ * cat (included in GNU Core Utils)
+ * cp (included in GNU Core Utils)
+ * cut (included in GNU Core Utils)
+ * echo (included in GNU Core Utils)
+ * mkdir (included in GNU Core Utils)
+ * rm (included in GNU Core Utils)
+ * sed (included in GNU Core Utils)
+ * sha1sum (included in GNU Core Utils)
+ * tempfile (included in GNU Core Utils)
+ * tr (included in GNU Core Utils)
+
+building
+
+ rvs doesn't exactly use the GNU build system, but acts much like it
+ does. To build rvs with default configuration, simply run:
+
+ $ ./configure
+ $ make
+ # make install
+
+ It's generally considered good practice to build in another
+ directory than the source directory. If you would like to do this,
+ it can be done in rvs-0.6.1 and up.
+
+ Configuration
+
+ There are several configuration variables that can be set. You can
+ modify these configuration variables by running `./configure` such
+ as:
+
+ $ ./configure --VAR_NAME=VALUE
+
+ The different configuration variables are as follows:
+
+ name='rvs'
+ The name of the program. Note that unlike most
+ variables, you should NOT call this in Makefiles
+ (`$(name)'), but use `$(rvs)'s instead.
+ CC='gcc'
+ The C language compiler to use.
+ RVS='$(bindir)/$(rvs)'
+ Where the executable will be. `$(rvs)' is the same as
+ `$(name)' (see above)
+ SHELL='/bin/sh'
+ The shell that will be used by make, and the shell
+ that scripts will run in. (Perhaps we should make
+ these separate variables?)
+ prefix='/usr/local'
+ Standard GNU variable. Many of you will want to
+ change this to `/usr', or `/home/USER_NAME'
+ exec_prefix='$(prefix)'
+ Standard GNU variable.
+ bindir='$(exec_prefix)/bin'
+ Standard GNU variable.
+ sbindir='$(exec_prefix)/sbin'
+ Standard GNU variable.
+ libexecdir='$(exec_prefix)/libexec'
+ Standard GNU variable. The plugins will be installed
+ at $(libexecdir)/$(name)
+ srcdir=$(readlink -f `dirname "$0"`)
+ Where the source code is. The default value evaluates
+ to the directory of the `configure' script.
+
+--
+Happy hacking!
+~ Luke Shumaker <LukeShu@sbcglobal.net>
diff --git a/common.each.head.mk b/common.each.head.mk
new file mode 100644
index 0000000..596e4f0
--- /dev/null
+++ b/common.each.head.mk
@@ -0,0 +1,16 @@
+# Copyright (C) 2016 Luke Shumaker
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+makefiles =
diff --git a/common.each.tail.mk b/common.each.tail.mk
new file mode 100644
index 0000000..d649602
--- /dev/null
+++ b/common.each.tail.mk
@@ -0,0 +1,42 @@
+# Copyright (C) 2015 Luke Shumaker
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+dirs := $(dirs)
+
+am_clean_files += .*.mk *.o
+ifneq ($(AUTODEPS),)
+-include $(wildcard $(outdir)/.*.mk)
+endif
+
+$(outdir)/% : $(srcdir)/%.m4
+ $(M4) -P $(M4FLAGS) $< > $@
+
+$(outdir)/% : $(srcdir)/%.sh
+ $(INSTALL_PROGRAM) $< $@
+$(outdir)/% : $(outdir)/%.sh
+ $(INSTALL_PROGRAM) $< $@
+
+$(outdir)/%.o : $(srcdir)/%.c $(topoutdir)/config.mk
+ $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $<
+
+$(outdir)/% : $(outdir)/%.o
+ $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
+
+ifneq ($(srcdir),$(outdir))
+$(addprefix $(outdir)/,$(makefiles)): $(outdir)/%: $(srcdir)/%
+ cp -Tf -- $< $@
+endif
+am_src_files += $(makefiles)
+am_cfg_files += $(makefiles)
diff --git a/common.once.head.mk b/common.once.head.mk
new file mode 100644
index 0000000..d50c639
--- /dev/null
+++ b/common.once.head.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2015-2016 Luke Shumaker
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+MAKEFLAGS += -rR
+.SECONDARY:
+.DELETE_ON_ERROR:
+
+# Have GCC generate header dependency info (pair this with `-include`
+# in common.each.mk
+ifneq ($(AUTODEPS),)
+CFLAGS += -MD -MF $(patsubst $(@D)/%.o,$(@D)/.%.mk,$@) -MP
+endif
+
+CPPFLAGS += -I$(topoutdir)
+M4FLAGS += -I$(topoutdir) -I$(<D) -I$(@D)
diff --git a/common.once.tail.mk b/common.once.tail.mk
new file mode 100644
index 0000000..f326c6b
--- /dev/null
+++ b/common.once.tail.mk
@@ -0,0 +1,19 @@
+# Copyright (C) 2015-2016 Luke Shumaker
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Make directories
+dirs += $(addprefix $(DESTDIR),$(bindir) $(libexedir) $(datarootdir) $(datadir) $(sysconfdir) $(sharedstatedir) $(localstatedir) $(runstatedir) $(pkgdatadir) $(pkglibexecdir))
+$(sort $(dirs)):
+ $(MKDIRS) $@
diff --git a/configure b/configure
new file mode 100755
index 0000000..9683b68
--- /dev/null
+++ b/configure
@@ -0,0 +1,63 @@
+#!/usr/bin/env bash
+name='configure' # Luke's configuration script
+#version='1.0'
+# Copyright (C) 2009, 2016 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+srcdir="$(dirname -- "$0")"
+outdir="."
+
+error() {
+ echo "$name: $1" >&2
+ exit 1
+}
+
+edit=(sed -E -e '')
+setvar() {
+ edit+=(-e "s@^(\s*$1\s*:?=).*@\1 $2@")
+}
+setvar topsrcdir "$srcdir"
+
+vars=($(<"$srcdir/config.mk.in" sed -n 's/^\([ a-z_-]*\)=.*/\1/p'))
+
+printf -v lopt '%s:,' "${vars[@]}"
+lopt+='enable-autodeps,disable-autodeps'
+
+sopt=''
+
+args=$(getopt -n "$name" -o "${sopt}" -l "${lopt}" -- "$@") || exit $?
+eval set -- "$args"
+while [ $# -gt 0 ]; do
+ case "$1" in
+ --) break;;
+ --enable-autodeps) setvar AUTODEPS t;;
+ --disable-autodeps) setvar AUTODEPS '';;
+ --*) setvar "${1#--}" "$2" shift;;
+ *) error "unrecognized option \`$1'";
+ esac
+ shift
+done
+
+"${edit[@]}" < "$srcdir/config.mk.in" > "$outdir/config.mk"
+
+Makefiles=($(find "$srcdir/" -name 'Makefile') "$srcdir"/*.mk "$srcdir"/modules/module.mk "$srcdir"/modules/*/Makefile.inc.mk)
+for src in "${Makefiles[@]}"; do
+ out="$outdir/${src#$srcdir/}"
+ mkdir -p -- $(dirname -- "$out")
+ if ! test "$src" -ef "$out"; then
+ cp -fTv -- "$src" "$out"
+ fi
+done
diff --git a/modules/.gitignore b/modules/.gitignore
new file mode 100644
index 0000000..3c197bc
--- /dev/null
+++ b/modules/.gitignore
@@ -0,0 +1,5 @@
+*/*
+!*/Makefile
+!*/.gitignore
+!*/*.mk
+!*/*.sh
diff --git a/modules/Makefile b/modules/Makefile
new file mode 100644
index 0000000..d9de6c0
--- /dev/null
+++ b/modules/Makefile
@@ -0,0 +1,24 @@
+#!/usr/bin/make -f
+# Copyright (C) 2015 Luke Shumaker
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+include $(dir $(lastword $(MAKEFILE_LIST)))/../config.mk
+include $(topsrcdir)/automake.head.mk
+
+dirs += $(DESTDIR)$(pkglibexecdir)/modules
+makefiles = Makefile module.mk
+am_subdirs = comments date.author blobs tags tree
+
+include $(topsrcdir)/automake.tail.mk
diff --git a/modules/blobs/.#get.f.sh b/modules/blobs/.#get.f.sh
new file mode 120000
index 0000000..c2c97da
--- /dev/null
+++ b/modules/blobs/.#get.f.sh
@@ -0,0 +1 @@
+luke@build64-par.lan.670:1436421582 \ No newline at end of file
diff --git a/modules/blobs/Makefile b/modules/blobs/Makefile
new file mode 120000
index 0000000..fa7273c
--- /dev/null
+++ b/modules/blobs/Makefile
@@ -0,0 +1 @@
+../module.mk \ No newline at end of file
diff --git a/modules/blobs/Makefile.inc.mk b/modules/blobs/Makefile.inc.mk
new file mode 100644
index 0000000..9f3f112
--- /dev/null
+++ b/modules/blobs/Makefile.inc.mk
@@ -0,0 +1,8 @@
+am_src_files += commit.d.sh commit.f.sh commit.sh get.d.sh get.f.sh get.sh ls.sh print.sh tree.sh
+am_out_files += commit.d commit.f commit get.d get.f get ls print tree
+
+am_src_files += _stdio.sh
+am_sys_files += $(pkglibexecdir)/modules/$(name)/_stdio.sh
+
+$(DESTDIR)$(pkglibexecdir)/modules/$(name)/_stdio.sh: $(srcdir)/_stdio.sh | $(DESTDIR)$(pkglibexecdir)/modules/$(name)
+ $(INSTALL_DATA) $< $@
diff --git a/modules/blobs/Module.mk b/modules/blobs/Module.mk
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/modules/blobs/Module.mk
diff --git a/modules/blobs/_stdio.sh b/modules/blobs/_stdio.sh
new file mode 100644
index 0000000..0da03f0
--- /dev/null
+++ b/modules/blobs/_stdio.sh
@@ -0,0 +1,74 @@
+#!/bin/sh
+#name='stdio'
+#ver=0.9
+# Copyright (C) 2009-2010 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+verbose() {
+ if [ "$volume" == '-v' ]; then
+ echo $@ >> /dev/stderr
+ fi
+}
+
+out() {
+ if [ "$volume" != '-q' ]; then
+ echo $@ >> /dev/stderr
+ fi
+}
+
+warn () {
+ echo "$name: $1" >> /dev/stderr
+}
+
+fatal () {
+ warn "$1"
+ exit 1
+}
+
+error() {
+ warn "$1"
+ cat << __error__ >> /dev/stderr
+Usage: $RVS $name $usage
+
+Try \`$RVS help $name' for more options.
+__error__
+ exit 1
+}
+
+getvar() {
+ if [ -z "$1" ]; then
+ error
+ else
+ echo $1
+ fi
+}
+
+version() {
+ echo "$name $ver"
+ if [ "$volume" != '-q' ]; then
+ cat << __disclaimer__
+$name is copyright (C) 2009-2010 Luke Shumaker
+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.
+
+Originally written by Luke Shumaker <LukeShu@sbcglobal.net>.
+__disclaimer__
+ fi
+ exit 0
+}
+
diff --git a/modules/blobs/commit.d.sh b/modules/blobs/commit.d.sh
new file mode 100644
index 0000000..620a88f
--- /dev/null
+++ b/modules/blobs/commit.d.sh
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+# rvs blobs/commit.d - add a directory to the repository
+# Copyright (C) 2009-2010, 2015 Luke Shumaker
+#
+# This file is part of rvs.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+. "${0%/*}/_stdio.sh"
+
+usage='DIRECTORY'
+[[ $# -eq 1 ]] || errusage
+dir="$1"
+
+shopt -s dotglob
+cd "$dir"
+tmpfile="$(mktemp -t "${0##*/}.XXXXXXXXXX")"
+for file in *; do
+ id="$("$RVS" commit "$file")"
+ stat -c $'%a\t%u (%U)\t%g (%G)\t' -- "$file"
+ printf $'%s\t%s\n' "$id" "$file"
+done > "$tmpfile"
+"$RVS" commit.f "$tmpfile" d
diff --git a/modules/blobs/commit.f.sh b/modules/blobs/commit.f.sh
new file mode 100644
index 0000000..8a97c2a
--- /dev/null
+++ b/modules/blobs/commit.f.sh
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+# rvs blobs/commit.f - add a plain file to the repository
+# Copyright (C) 2009-2010, 2015 Luke Shumaker
+#
+# This file is part of rvs.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+. "${0%/*}/_stdio.sh"
+
+usage='FILENAME [TYPE]'
+case $# in
+ 0) errusage;;
+ 1) infile=$1; type=f;;
+ 2) infile=$1; type=$2;;
+ *) errusage;;
+esac
+
+hash="$(<"$file" sha1sum | cut -d ' ' -f1)"
+outfile="$RVS_REPO/blobs/$hash"
+if [ ! -f "$outfile" ]; then
+ mkdir -p -- "${outfile%/*}"
+ < "$infile" gzip -9 > "$outfile"
+fi
+printf '%s:%s\n' "$type" "$hash"
+
diff --git a/modules/blobs/commit.sh b/modules/blobs/commit.sh
new file mode 100644
index 0000000..e23af27
--- /dev/null
+++ b/modules/blobs/commit.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+# rvs blobs/commit - add a file to the repository
+# Copyright (C) 2009-2010, 2015 Luke Shumaker
+#
+# This file is part of rvs.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+. "${0%/*}/_stdio.sh"
+
+usage='[FILES...]'
+if [[ $# -lt 1 ]]; then
+ set -- .
+fi
+
+for file in "$@"; do
+ local type
+ if test -L "$file"; then
+ type=l
+ elif test -f "$file"; then
+ type=f
+ elif test -d "$file"; then
+ type=d
+ else
+ error 'Unsupported file type: %s' "$file"
+ fi
+ "$RVS" "commit.$type" "$file"
+done
diff --git a/modules/blobs/get.d.sh b/modules/blobs/get.d.sh
new file mode 100644
index 0000000..989dbe8
--- /dev/null
+++ b/modules/blobs/get.d.sh
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+# rvs blobs/get.d - get a directory from the repository
+# Copyright (C) 2009-2010, 2015 Luke Shumaker
+#
+# This file is part of rvs.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+. "${0%/*}/_stdio.sh"
+
+usage="DIRNAME ID"
+[[ $# -eq 2 ]] || errusage
+name=$1
+id=$2
+
+tmpfile="$(mktemp -t "${0##*/}.XXXXXXXXXX")"
+"$RVS" get.f "$tmpfile" "$id"
+
+mkdir -p -- "$name"
+cd "$name"
+
+IFS=$'\t'
+while read -r perm user group id name; do
+ "$RVS" get "$name" "$id"
+ chmod "$perm" "$name"
+done < "$tmpfile"
diff --git a/modules/blobs/get.f.sh b/modules/blobs/get.f.sh
new file mode 100644
index 0000000..02185a6
--- /dev/null
+++ b/modules/blobs/get.f.sh
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+# rvs blobs/get.f - get a plain file from the repository
+# Copyright (C) 2009-2010, 2015 Luke Shumaker
+#
+# This file is part of rvs.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+. "${0%/*}/_stdio.sh"
+
+. "$LIBDIR/@ID@/stdio"
+
+usage="FILENAME ID"
+[[ $# -eq 2 ]] || errusage
+name=$1
+id=$2
+
+mkdir -p -- "${name%/*}"
+< "$REPO/blobs/${id#*:}" gunzip > "$name"
+
diff --git a/modules/blobs/get.sh b/modules/blobs/get.sh
new file mode 100644
index 0000000..4be2732
--- /dev/null
+++ b/modules/blobs/get.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+# rvs blobs/get - get a file from the repository
+# Copyright (C) 2009-2010, 2015 Luke Shumaker
+#
+# This file is part of rvs.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+. "${0%/*}/_stdio.sh"
+
+usage="FILENAME ID"
+[[ $# -eq 2 ]] || errusage
+name=$1
+id=$2
+
+"$RVS" "get.${id%%:*}" "$name" "$id"
+
diff --git a/modules/blobs/ls.sh b/modules/blobs/ls.sh
new file mode 100644
index 0000000..1c4d620
--- /dev/null
+++ b/modules/blobs/ls.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+name='ls'
+ver=0.1
+# Copyright (C) 2010 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+. "$LIBDIR/@ID@/stdio"
+
+usage="DIR_ID [FORMAT]"
+id="`getvar "$1"`"
+form="${2-%p\t%o\t%g\t%n\t%i}"
+
+# %p - permissions
+# %o - owner
+# %g - group
+# %i - blob id
+# %n - name
+# \t - a tab char
+
+tmp="`mktemp`"
+"$RVS" get.f "$tmp" "$id"
+
+while read line; do
+ p="`echo "$line" | cut -f1`"
+ o="`echo "$line" | cut -f2`"
+ g="`echo "$line" | cut -f3`"
+ i="`echo "$line" | cut -f4`"
+ n="`echo "$line" | cut -f5-`"
+ echo "$form" | sed \
+ -e 's:\\t:\t:g' \
+ -e "s:%p:${p/:/\\:}:g" \
+ -e "s:%o:${o/:/\\:}:g" \
+ -e "s:%g:${g/:/\\:}:g" \
+ -e "s:%i:${i/:/\\:}:g" \
+ -e "s:%n:${n/:/\\:}:g"
+done < "$tmp"
+
diff --git a/modules/blobs/print.sh b/modules/blobs/print.sh
new file mode 100644
index 0000000..0e23adc
--- /dev/null
+++ b/modules/blobs/print.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+# rvs files/print - ???
+# Copyright (C) 2010, 2015 Luke Shumaker
+#
+# This file is part of rvs.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+. "${0%/*}/_stdio.sh"
+
+usage='ID'
+[[ $# -eq 1 ]] || errusage
+id=$1
+
+hash="${id#*:}"
+file="$REPO/blobs/$hash"
+
+if [ -e "$file" ]; then
+ t="${id%%:*}"
+ type=''
+ case "$t" in
+ f) type='regular file';;
+ d) type='directory';;
+ l) type='link';;
+ esac
+ printf 'File Type: %s (%s)\n' "$t" "$type"
+else
+ fatal 'no object with ID `%s'\' "$id"
+fi
+
diff --git a/modules/blobs/tree.sh b/modules/blobs/tree.sh
new file mode 100644
index 0000000..80202ea
--- /dev/null
+++ b/modules/blobs/tree.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+name='tree'
+ver=0.1
+# Copyright (C) 2010 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+. "${0%/*}/_stdio.sh"
+
+usage="DIR_ID [NAME] [PREFIX] [LAST]"
+id="`getvar "$1"`"
+name="${2-.}"
+pref="$3"
+last="$4"
+
+echo "$pref $name $id"
+pref=' | '
+"$RVS" ls "$id" '%i\t%n' | while read line; do
+ i="`echo "$line" | cut -f1`"
+ n="`echo "$line" | cut -f2-`"
+ t="`"$RVS" blob-gettype "$i"`"
+ if [ "$t" = 'd' ]
+ "$RVS" tree "$i" "$n" "$pref"
+ else
+ echo "$pref $n $i"
+ fi
+done
+
diff --git a/modules/comments/Makefile b/modules/comments/Makefile
new file mode 120000
index 0000000..fa7273c
--- /dev/null
+++ b/modules/comments/Makefile
@@ -0,0 +1 @@
+../module.mk \ No newline at end of file
diff --git a/modules/comments/Makefile.inc.mk b/modules/comments/Makefile.inc.mk
new file mode 100644
index 0000000..d5632d7
--- /dev/null
+++ b/modules/comments/Makefile.inc.mk
@@ -0,0 +1,2 @@
+am_src_files += comment.sh commit.sh print.sh showcomment.sh
+sm_out_files += comment commit print showcomment
diff --git a/modules/comments/Module.mk b/modules/comments/Module.mk
new file mode 100644
index 0000000..3fa49ac
--- /dev/null
+++ b/modules/comments/Module.mk
@@ -0,0 +1 @@
+commit/comments : commit/blobs
diff --git a/modules/comments/comment.sh b/modules/comments/comment.sh
new file mode 100644
index 0000000..aa615ca
--- /dev/null
+++ b/modules/comments/comment.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+name='comment'
+ver=0.1
+# Copyright (C) 2010 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+usage="usage: $RVS $name ID"
+id="${1?"$usage"}"
+
+file="$REPO/@ID@/$id"
+mkdir -p "`dirname "$file"`"
+editor "$file" >> /dev/stderr
+
diff --git a/modules/comments/commit.sh b/modules/comments/commit.sh
new file mode 100644
index 0000000..4163387
--- /dev/null
+++ b/modules/comments/commit.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+name='rvs @ID@ commit'
+ver=0.1
+# Copyright (C) 2010 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+if [ "$RVS_LEVEL" = '0' ]; then
+ id=`cat "$TMPDIR/commit/files"`
+ "$RVS" comment "$id"
+fi
+
diff --git a/modules/comments/print.sh b/modules/comments/print.sh
new file mode 100644
index 0000000..bef8e87
--- /dev/null
+++ b/modules/comments/print.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+name='print'
+ver=0.1
+# Copyright (C) 2010 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+usage="Usage: $RVS $name ID"
+id="${1?"$usage"}"
+
+file="$REPO/@ID@/$id"
+if [ -e "$file" ]; then
+ echo "Comment:"
+ sed 's/\(.*\)/ > \1/' "$file"
+fi
+
diff --git a/modules/comments/showcomment.sh b/modules/comments/showcomment.sh
new file mode 100644
index 0000000..3e4e943
--- /dev/null
+++ b/modules/comments/showcomment.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+name='showcomment'
+ver=0.1
+# Copyright (C) 2010 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+usage="Usage: $RVS $name ID"
+id="${1?"$usage"}"
+
+file="$REPO/@ID@/$id"
+if [ -e "$file" ]; then
+ cat "$file"
+fi
+
diff --git a/modules/date.author/Makefile b/modules/date.author/Makefile
new file mode 120000
index 0000000..fa7273c
--- /dev/null
+++ b/modules/date.author/Makefile
@@ -0,0 +1 @@
+../module.mk \ No newline at end of file
diff --git a/modules/date.author/Makefile.inc.mk b/modules/date.author/Makefile.inc.mk
new file mode 100644
index 0000000..ac9d0df
--- /dev/null
+++ b/modules/date.author/Makefile.inc.mk
@@ -0,0 +1,2 @@
+am_src_files += commit.sh
+am_out_files += commit
diff --git a/modules/date.author/Module.mk b/modules/date.author/Module.mk
new file mode 100644
index 0000000..30cd2e0
--- /dev/null
+++ b/modules/date.author/Module.mk
@@ -0,0 +1 @@
+commit/date.author : commit/blobs
diff --git a/modules/date.author/commit.sh b/modules/date.author/commit.sh
new file mode 100644
index 0000000..8079fda
--- /dev/null
+++ b/modules/date.author/commit.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+name='rvs @ID@ commit'
+ver=0.1
+# Copyright (C) 2010 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+if [ "$RVS_LEVEL" = '0' ]; then
+ id=`cat "$TMPDIR/commit/files"`
+ time=`date +%s`
+ file="$REPO/@ID@/$time"
+ if [ -n "$wch" ]; then
+ "$RVS" addparent "$id" "$wch"
+ fi
+fi
+
diff --git a/modules/git-fast-import/gen-parser.mk b/modules/git-fast-import/gen-parser.mk
new file mode 100644
index 0000000..7837e5c
--- /dev/null
+++ b/modules/git-fast-import/gen-parser.mk
@@ -0,0 +1,154 @@
+# (See Documentation/git-fast-import.txt for maintained documentation.)
+# Format of STDIN stream:
+#
+# stream ::= cmd*;
+#
+# cmd ::= new_blob
+# | new_commit
+# | new_tag
+# | reset_branch
+# | checkpoint
+# | progress
+# ;
+#
+# new_blob ::= 'blob' lf
+# mark?
+# file_content;
+# file_content ::= data;
+#
+# new_commit ::= 'commit' sp ref_str lf
+# mark?
+# ('author' (sp name)? sp '<' email '>' sp when lf)?
+# 'committer' (sp name)? sp '<' email '>' sp when lf
+# commit_msg
+# ('from' sp commit-ish lf)?
+# ('merge' sp commit-ish lf)*
+# (file_change | ls)*
+# lf?;
+# commit_msg ::= data;
+#
+# ls ::= 'ls' sp '"' quoted(path) '"' lf;
+#
+# file_change ::= file_clr
+# | file_del
+# | file_rnm
+# | file_cpy
+# | file_obm
+# | file_inm;
+# file_clr ::= 'deleteall' lf;
+# file_del ::= 'D' sp path_str lf;
+# file_rnm ::= 'R' sp path_str sp path_str lf;
+# file_cpy ::= 'C' sp path_str sp path_str lf;
+# file_obm ::= 'M' sp mode sp (hexsha1 | idnum) sp path_str lf;
+# file_inm ::= 'M' sp mode sp 'inline' sp path_str lf
+# data;
+# note_obm ::= 'N' sp (hexsha1 | idnum) sp commit-ish lf;
+# note_inm ::= 'N' sp 'inline' sp commit-ish lf
+# data;
+#
+# new_tag ::= 'tag' sp tag_str lf
+# 'from' sp commit-ish lf
+# ('tagger' (sp name)? sp '<' email '>' sp when lf)?
+# tag_msg;
+# tag_msg ::= data;
+#
+# reset_branch ::= 'reset' sp ref_str lf
+# ('from' sp commit-ish lf)?
+# lf?;
+#
+# checkpoint ::= 'checkpoint' lf
+# lf?;
+#
+# progress ::= 'progress' sp not_lf* lf
+# lf?;
+#
+# # note: the first idnum in a stream should be 1 and subsequent
+# # idnums should not have gaps between values as this will cause
+# # the stream parser to reserve space for the gapped values. An
+# # idnum can be updated in the future to a new object by issuing
+# # a new mark directive with the old idnum.
+# #
+# mark ::= 'mark' sp idnum lf;
+# data ::= (delimited_data | exact_data)
+# lf?;
+#
+# # note: delim may be any string but must not contain lf.
+# # data_line may contain any data but must not be exactly
+# # delim.
+# delimited_data ::= 'data' sp '<<' delim lf
+# (data_line lf)*
+# delim lf;
+#
+# # note: declen indicates the length of binary_data in bytes.
+# # declen does not include the lf preceding the binary data.
+# #
+# exact_data ::= 'data' sp declen lf
+# binary_data;
+#
+# # note: quoted strings are C-style quoting supporting \c for
+# # common escapes of 'c' (e..g \n, \t, \\, \") or \nnn where nnn
+# # is the signed byte value in octal. Note that the only
+# # characters which must actually be escaped to protect the
+# # stream formatting is: \, " and LF. Otherwise these values
+# # are UTF8.
+# #
+# commit-ish ::= (ref_str | hexsha1 | sha1exp_str | idnum);
+# ref_str ::= ref;
+# sha1exp_str ::= sha1exp;
+# tag_str ::= tag;
+# path_str ::= path | '"' quoted(path) '"' ;
+# mode ::= '100644' | '644'
+# | '100755' | '755'
+# | '120000'
+# ;
+#
+# declen ::= # unsigned 32 bit value, ascii base10 notation;
+# bigint ::= # unsigned integer value, ascii base10 notation;
+# binary_data ::= # file content, not interpreted;
+#
+# when ::= raw_when | rfc2822_when;
+# raw_when ::= ts sp tz;
+# rfc2822_when ::= # Valid RFC 2822 date and time;
+#
+# sp ::= # ASCII space character;
+# lf ::= # ASCII newline (LF) character;
+#
+# # note: a colon (':') must precede the numerical value assigned to
+# # an idnum. This is to distinguish it from a ref or tag name as
+# # GIT does not permit ':' in ref or tag strings.
+# #
+# idnum ::= ':' bigint;
+# path ::= # GIT style file path, e.g. "a/b/c";
+# ref ::= # GIT ref name, e.g. "refs/heads/MOZ_GECKO_EXPERIMENT";
+# tag ::= # GIT tag name, e.g. "FIREFOX_1_5";
+# sha1exp ::= # Any valid GIT SHA1 expression;
+# hexsha1 ::= # SHA1 in hexadecimal format;
+#
+# # note: name and email are UTF8 strings, however name must not
+# # contain '<' or lf and email must not contain any of the
+# # following: '<', '>', lf.
+# #
+# name ::= # valid GIT author/committer name;
+# email ::= # valid GIT author/committer email;
+# ts ::= # time since the epoch in seconds, ascii base10 notation;
+# tz ::= # GIT style timezone;
+#
+# # note: comments, ls and cat requests may appear anywhere
+# # in the input, except within a data command. Any form
+# # of the data command always escapes the related input
+# # from comment processing.
+# #
+# # In case it is not clear, the '#' that starts the comment
+# # must be the first character on that line (an lf
+# # preceded it).
+# #
+#
+# cat_blob ::= 'cat-blob' sp (hexsha1 | idnum) lf;
+cat_blob = cat-blob${sp}(${hexsha1}|${idnum})${lf}
+# ls_tree ::= 'ls' sp (hexsha1 | idnum) sp path_str lf;
+ls_tree = ls${sp}(${hexsha1}|${idnum})${sp}${path_str}${lf}
+#
+# comment ::= '#' not_lf* lf;
+comment = \#$(not_lf)
+# not_lf ::= # Any byte that is not ASCII newline (LF);
+not_lf = [^\n]
diff --git a/modules/git-fast-import/parse.sh b/modules/git-fast-import/parse.sh
new file mode 100644
index 0000000..16bc5d2
--- /dev/null
+++ b/modules/git-fast-import/parse.sh
@@ -0,0 +1,1077 @@
+#!/bin/bash
+
+program_invocation_name=$0
+if type gettext &>/dev/null; then
+ _() { gettext -- "$@"; }
+else
+ _() { echo "$*"; }
+fi
+
+IFS=
+
+die() {
+ printf "$(_ "$1")" "${@:2}"
+ exit 2
+}
+
+
+# Input Format
+# ------------
+# With the exception of raw file data (which Git does not interpret)
+# the fast-import input format is text (ASCII) based. This text based
+# format simplifies development and debugging of frontend programs,
+# especially when a higher level language such as Perl, Python or
+# Ruby is being used.
+#
+# fast-import is very strict about its input. Where we say SP below we mean
+# *exactly* one space. Likewise LF means one (and only one) linefeed
+# and HT one (and only one) horizontal tab.
+# Supplying additional whitespace characters will cause unexpected
+# results, such as branch names or file names with leading or trailing
+# spaces in their name, or early termination of fast-import when it encounters
+# unexpected input.
+#
+# Stream Comments
+# ~~~~~~~~~~~~~~~
+# To aid in debugging frontends fast-import ignores any line that
+# begins with `#` (ASCII pound/hash) up to and including the line
+# ending `LF`. A comment line may contain any sequence of bytes
+# that does not contain an LF and therefore may be used to include
+# any detailed debugging information that might be specific to the
+# frontend and useful when inspecting a fast-import data stream.
+
+get_line() {
+ line='#'
+ while [[ ${line:0:1} == '#' ]]; do
+ read -r line || break
+ done
+}
+
+#
+# Date Formats
+# ~~~~~~~~~~~~
+# The following date formats are supported. A frontend should select
+# the format it will use for this import by passing the format name
+# in the --date-format=<fmt> command-line option.
+#
+# `raw`::
+# This is the Git native format and is `<time> SP <offutc>`.
+# It is also fast-import's default format, if --date-format was
+# not specified.
+# +
+# The time of the event is specified by `<time>` as the number of
+# seconds since the UNIX epoch (midnight, Jan 1, 1970, UTC) and is
+# written as an ASCII decimal integer.
+# +
+# The local offset is specified by `<offutc>` as a positive or negative
+# offset from UTC. For example EST (which is 5 hours behind UTC)
+# would be expressed in `<tz>` by ``-0500'' while UTC is ``+0000''.
+# The local offset does not affect `<time>`; it is used only as an
+# advisement to help formatting routines display the timestamp.
+# +
+# If the local offset is not available in the source material, use
+# ``+0000'', or the most common local offset. For example many
+# organizations have a CVS repository which has only ever been accessed
+# by users who are located in the same location and time zone. In this
+# case a reasonable offset from UTC could be assumed.
+# +
+# Unlike the `rfc2822` format, this format is very strict. Any
+# variation in formatting will cause fast-import to reject the value.
+#
+# `rfc2822`::
+# This is the standard email format as described by RFC 2822.
+# +
+# An example value is ``Tue Feb 6 11:22:18 2007 -0500''. The Git
+# parser is accurate, but a little on the lenient side. It is the
+# same parser used by 'git am' when applying patches
+# received from email.
+# +
+# Some malformed strings may be accepted as valid dates. In some of
+# these cases Git will still be able to obtain the correct date from
+# the malformed string. There are also some types of malformed
+# strings which Git will parse wrong, and yet consider valid.
+# Seriously malformed strings will be rejected.
+# +
+# Unlike the `raw` format above, the time zone/UTC offset information
+# contained in an RFC 2822 date string is used to adjust the date
+# value to UTC prior to storage. Therefore it is important that
+# this information be as accurate as possible.
+# +
+# If the source material uses RFC 2822 style dates,
+# the frontend should let fast-import handle the parsing and conversion
+# (rather than attempting to do it itself) as the Git parser has
+# been well tested in the wild.
+# +
+# Frontends should prefer the `raw` format if the source material
+# already uses UNIX-epoch format, can be coaxed to give dates in that
+# format, or its format is easily convertible to it, as there is no
+# ambiguity in parsing.
+#
+# `now`::
+# Always use the current time and time zone. The literal
+# `now` must always be supplied for `<when>`.
+# +
+# This is a toy format. The current time and time zone of this system
+# is always copied into the identity string at the time it is being
+# created by fast-import. There is no way to specify a different time or
+# time zone.
+# +
+# This particular format is supplied as it's short to implement and
+# may be useful to a process that wants to create a new commit
+# right now, without needing to use a working directory or
+# 'git update-index'.
+# +
+# If separate `author` and `committer` commands are used in a `commit`
+# the timestamps may not match, as the system clock will be polled
+# twice (once for each command). The only way to ensure that both
+# author and committer identity information has the same timestamp
+# is to omit `author` (thus copying from `committer`) or to use a
+# date format other than `now`.
+#
+# Commands
+# ~~~~~~~~
+# fast-import accepts several commands to update the current repository
+# and control the current import process. More detailed discussion
+# (with examples) of each command follows later.
+#
+parse() {
+ while get_line; do
+ case "$line" in
+# `commit`::
+# Creates a new branch or updates an existing branch by
+# creating a new commit and updating the branch to point at
+# the newly created commit.
+ 'commit '*) cmd_commit "${line#commit }";;
+#
+# `tag`::
+# Creates an annotated tag object from an existing commit or
+# branch. Lightweight tags are not supported by this command,
+# as they are not recommended for recording meaningful points
+# in time.
+ 'tag '*) cmd_tag "${line#tag }";;
+#
+# `reset`::
+# Reset an existing branch (or a new branch) to a specific
+# revision. This command must be used to change a branch to
+# a specific revision without making a commit on it.
+ 'reset '*) cmd_reset "${line#reset }";;
+#
+# `blob`::
+# Convert raw file data into a blob, for future use in a
+# `commit` command. This command is optional and is not
+# needed to perform an import.
+ 'blob '*) cmd_blob "${line#blob }";;
+#
+# `checkpoint`::
+# Forces fast-import to close the current packfile, generate its
+# unique SHA-1 checksum and index, and start a new packfile.
+# This command is optional and is not needed to perform
+# an import.
+ 'checkpoint '*) cmd_checkpoint "${line#checkpoint }";;
+#
+# `progress`::
+# Causes fast-import to echo the entire line to its own
+# standard output. This command is optional and is not needed
+# to perform an import.
+ 'progress '*) cmd_progress "${line#progress }";;
+#
+# `done`::
+# Marks the end of the stream. This command is optional
+# unless the `done` feature was requested using the
+# `--done` command-line option or `feature done` command.
+ 'done '*) cmd_done "${line#done }";;
+#
+# `cat-blob`::
+# Causes fast-import to print a blob in 'cat-file --batch'
+# format to the file descriptor set with `--cat-blob-fd` or
+# `stdout` if unspecified.
+ 'cat-blob '*) cmd_cat-blob "${line#cat-blob }";;
+#
+# `ls`::
+# Causes fast-import to print a line describing a directory
+# entry in 'ls-tree' format to the file descriptor set with
+# `--cat-blob-fd` or `stdout` if unspecified.
+ 'ls '*) cmd_ls "${line#ls }";;
+#
+# `feature`::
+# Enable the specified feature. This requires that fast-import
+# supports the specified feature, and aborts if it does not.
+ 'feature '*) cmd_feature "${line#feature }";;
+#
+# `option`::
+# Specify any of the options listed under OPTIONS that do not
+# change stream semantic to suit the frontend's needs. This
+# command is optional and is not needed to perform an import.
+ 'option '*) cmd_option "${line#option }";;
+ *) die 'Unsupported command: %s' "$line";;
+ esac
+ done
+#
+}
+# `commit`
+# ~~~~~~~~
+# Create or update a branch with a new commit, recording one logical
+# change to the project.
+#
+cmd_commit() {
+# ....
+# 'commit' SP <ref> LF
+ local ref=$1
+ get_line
+# mark?
+ get_mark || true
+# ('author' (SP <name>)? SP LT <email> GT SP <when> LF)?
+ if [[ $line = 'author '* ]]; then
+ author="${line#author }"
+ get_line
+ fi
+# 'committer' (SP <name>)? SP LT <email> GT SP <when> LF
+ if [[ $line = 'committer '* ]]; then
+ committer="${line#committer }"
+ get_line
+ else
+ die "Expected committer but didn't get one";
+ fi
+# data
+ get_data
+# ('from' SP <commit-ish> LF)?
+ if [[ $line = 'from '* ]]; then
+ from="${line#from }"
+ get_line
+ fi
+# ('merge' SP <commit-ish> LF)*
+ while [[ $line = 'merge '* ]]; do
+ parents+=("${line#merge }")
+ get_line
+ done
+# (filemodify | filedelete | filecopy | filerename | filedeleteall | notemodify)*
+ while cmd_commit--filemodify ||
+ cmd_commit--filedelete ||
+ cmd_commit--filecopy ||
+ cmd_commit--filerename ||
+ cmd_commit--filedeleteall ||
+ cmd_commit--notemodify
+ do :; done
+# LF?
+ [[ -n $line ]] || get_line
+# ....
+}
+#
+# where `<ref>` is the name of the branch to make the commit on.
+# Typically branch names are prefixed with `refs/heads/` in
+# Git, so importing the CVS branch symbol `RELENG-1_0` would use
+# `refs/heads/RELENG-1_0` for the value of `<ref>`. The value of
+# `<ref>` must be a valid refname in Git. As `LF` is not valid in
+# a Git refname, no quoting or escaping syntax is supported here.
+#
+# A `mark` command may optionally appear, requesting fast-import to save a
+# reference to the newly created commit for future use by the frontend
+# (see below for format). It is very common for frontends to mark
+# every commit they create, thereby allowing future branch creation
+# from any imported commit.
+#
+# The `data` command following `committer` must supply the commit
+# message (see below for `data` command syntax). To import an empty
+# commit message use a 0 length data. Commit messages are free-form
+# and are not interpreted by Git. Currently they must be encoded in
+# UTF-8, as fast-import does not permit other encodings to be specified.
+#
+# Zero or more `filemodify`, `filedelete`, `filecopy`, `filerename`,
+# `filedeleteall` and `notemodify` commands
+# may be included to update the contents of the branch prior to
+# creating the commit. These commands may be supplied in any order.
+# However it is recommended that a `filedeleteall` command precede
+# all `filemodify`, `filecopy`, `filerename` and `notemodify` commands in
+# the same commit, as `filedeleteall` wipes the branch clean (see below).
+#
+# The `LF` after the command is optional (it used to be required).
+#
+# `author`
+# ^^^^^^^^
+# An `author` command may optionally appear, if the author information
+# might differ from the committer information. If `author` is omitted
+# then fast-import will automatically use the committer's information for
+# the author portion of the commit. See below for a description of
+# the fields in `author`, as they are identical to `committer`.
+#
+# `committer`
+# ^^^^^^^^^^^
+# The `committer` command indicates who made this commit, and when
+# they made it.
+#
+# Here `<name>` is the person's display name (for example
+# ``Com M Itter'') and `<email>` is the person's email address
+# (``\cm@example.com''). `LT` and `GT` are the literal less-than (\x3c)
+# and greater-than (\x3e) symbols. These are required to delimit
+# the email address from the other fields in the line. Note that
+# `<name>` and `<email>` are free-form and may contain any sequence
+# of bytes, except `LT`, `GT` and `LF`. `<name>` is typically UTF-8 encoded.
+#
+# The time of the change is specified by `<when>` using the date format
+# that was selected by the --date-format=<fmt> command-line option.
+# See ``Date Formats'' above for the set of supported formats, and
+# their syntax.
+#
+# `from`
+# ^^^^^^
+# The `from` command is used to specify the commit to initialize
+# this branch from. This revision will be the first ancestor of the
+# new commit. The state of the tree built at this commit will begin
+# with the state at the `from` commit, and be altered by the content
+# modifications in this commit.
+#
+# Omitting the `from` command in the first commit of a new branch
+# will cause fast-import to create that commit with no ancestor. This
+# tends to be desired only for the initial commit of a project.
+# If the frontend creates all files from scratch when making a new
+# branch, a `merge` command may be used instead of `from` to start
+# the commit with an empty tree.
+# Omitting the `from` command on existing branches is usually desired,
+# as the current commit on that branch is automatically assumed to
+# be the first ancestor of the new commit.
+#
+# As `LF` is not valid in a Git refname or SHA-1 expression, no
+# quoting or escaping syntax is supported within `<commit-ish>`.
+#
+# Here `<commit-ish>` is any of the following:
+#
+# * The name of an existing branch already in fast-import's internal branch
+# table. If fast-import doesn't know the name, it's treated as a SHA-1
+# expression.
+#
+# * A mark reference, `:<idnum>`, where `<idnum>` is the mark number.
+# +
+# The reason fast-import uses `:` to denote a mark reference is this character
+# is not legal in a Git branch name. The leading `:` makes it easy
+# to distinguish between the mark 42 (`:42`) and the branch 42 (`42`
+# or `refs/heads/42`), or an abbreviated SHA-1 which happened to
+# consist only of base-10 digits.
+# +
+# Marks must be declared (via `mark`) before they can be used.
+#
+# * A complete 40 byte or abbreviated commit SHA-1 in hex.
+#
+# * Any valid Git SHA-1 expression that resolves to a commit. See
+# ``SPECIFYING REVISIONS'' in linkgit:gitrevisions[7] for details.
+#
+# * The special null SHA-1 (40 zeros) specifies that the branch is to be
+# removed.
+#
+# The special case of restarting an incremental import from the
+# current branch value should be written as:
+# ----
+# from refs/heads/branch^0
+# ----
+# The `^0` suffix is necessary as fast-import does not permit a branch to
+# start from itself, and the branch is created in memory before the
+# `from` command is even read from the input. Adding `^0` will force
+# fast-import to resolve the commit through Git's revision parsing library,
+# rather than its internal branch table, thereby loading in the
+# existing value of the branch.
+#
+# `merge`
+# ^^^^^^^
+# Includes one additional ancestor commit. The additional ancestry
+# link does not change the way the tree state is built at this commit.
+# If the `from` command is
+# omitted when creating a new branch, the first `merge` commit will be
+# the first ancestor of the current commit, and the branch will start
+# out with no files. An unlimited number of `merge` commands per
+# commit are permitted by fast-import, thereby establishing an n-way merge.
+#
+# Here `<commit-ish>` is any of the commit specification expressions
+# also accepted by `from` (see above).
+#
+# `filemodify`
+# ^^^^^^^^^^^^
+# Included in a `commit` command to add a new file or change the
+# content of an existing file. This command has two different means
+# of specifying the content of the file.
+#
+cmd_commit--filemodify() {
+# External data format::
+# The data content for the file was already supplied by a prior
+# `blob` command. The frontend just needs to connect it.
+# +
+# ....
+# 'M' SP <mode> SP <dataref> SP <path> LF
+# ....
+# +
+# Here usually `<dataref>` must be either a mark reference (`:<idnum>`)
+# set by a prior `blob` command, or a full 40-byte SHA-1 of an
+# existing Git blob object. If `<mode>` is `040000`` then
+# `<dataref>` must be the full 40-byte SHA-1 of an existing
+# Git tree object or a mark reference set with `--import-marks`.
+ local re='^M ([0-7]+) (\S+) (.+)'
+ if [[ $line =~ $re ]]; then
+ local mode=${BASH_REMATCH[1]}
+ local dataref=${BASH_REMATCH[2]}
+ local ifs=$IFS
+ IFS=$' \t\n'
+ local path=($(parse_path "${BASH_REMATCH[3]}"))
+ IFS=$ifs
+ if [[ -n "${path[1]}" ]]; then
+ error
+ fi
+ get_line
+ else
+ return 1
+ fi
+#
+# Inline data format::
+# The data content for the file has not been supplied yet.
+# The frontend wants to supply it as part of this modify
+# command.
+# +
+# ....
+# 'M' SP <mode> SP 'inline' SP <path> LF
+# data
+# ....
+# +
+# See below for a detailed description of the `data` command.
+ if [[ $dataref = 'inline' ]]; then
+ get_data
+ fi
+#
+# In both formats `<mode>` is the type of file entry, specified
+# in octal. Git only supports the following modes:
+#
+# * `100644` or `644`: A normal (not-executable) file. The majority
+# of files in most projects use this mode. If in doubt, this is
+# what you want.
+# * `100755` or `755`: A normal, but executable, file.
+# * `120000`: A symlink, the content of the file will be the link target.
+# * `160000`: A gitlink, SHA-1 of the object refers to a commit in
+# another repository. Git links can only be specified by SHA or through
+# a commit mark. They are used to implement submodules.
+# * `040000`: A subdirectory. Subdirectories can only be specified by
+# SHA or through a tree mark set with `--import-marks`.
+#
+}
+# In both formats `<path>` is the complete path of the file to be added
+# (if not already existing) or modified (if already existing).
+#
+# A `<path>` string must use UNIX-style directory separators (forward
+# slash `/`), may contain any byte other than `LF`, and must not
+# start with double quote (`"`).
+#
+# A path can use C-style string quoting; this is accepted in all cases
+# and mandatory if the filename starts with double quote or contains
+# `LF`. In C-style quoting, the complete name should be surrounded with
+# double quotes, and any `LF`, backslash, or double quote characters
+# must be escaped by preceding them with a backslash (e.g.,
+# `"path/with\n, \\ and \" in it"`).
+#
+# The value of `<path>` must be in canonical form. That is it must not:
+#
+# * contain an empty directory component (e.g. `foo//bar` is invalid),
+# * end with a directory separator (e.g. `foo/` is invalid),
+# * start with a directory separator (e.g. `/foo` is invalid),
+# * contain the special component `.` or `..` (e.g. `foo/./bar` and
+# `foo/../bar` are invalid).
+#
+# The root of the tree can be represented by an empty string as `<path>`.
+#
+# It is recommended that `<path>` always be encoded using UTF-8.
+unquote_c_style() { # this is based on the function from git:quote.c
+ local in=$1
+ local out=''
+ if [[ "${in:0:1}" != '"' ]]; then
+ return 1
+ fi
+ in=${in:1}
+ while true; do
+ #local add="${in%%['"\']*}"
+ in=${in:${#add}}
+ out+=$add
+ case "${in:0:1}" in
+ '"')
+ in=${in:1}
+ printf '%q %q' "$out" "$in"
+ return 0
+ ;;
+ "\\")
+ in=${in:1};;
+ *)
+ return 1;;
+ esac
+ local ch="${in:0:1}"
+ in=${in:1};
+ case "$ch" in
+ a) ch=$'\a';;
+ b) ch=$'\b';;
+ f) ch=$'\f';;
+ n) ch=$'\n';;
+ r) ch=$'\r';;
+ t) ch=$'\t';;
+ v) ch=$'\v';;
+ ['"\']) :;; # verbatim
+ # octal values with first digit over 4 overflow
+ [0-3])
+ ch+="$ch${in:0:2}"
+ in=${in:2};
+ if [[ $ch != [0-3][0-7][0-7] ]]; then
+ return 1
+ fi
+ ;;
+ esac
+ out+=$ch
+ fi
+}
+parse_path() {
+ local str=$1
+ local split
+ if unquote_c_style "$str"; then
+ :
+ else
+ local path="${str%% *}"
+ local rest="${str#"$path"}"
+ printf '%q %q' "$path" "$rest"
+ fi
+}
+#
+# `filedelete`
+# ^^^^^^^^^^^^
+# Included in a `commit` command to remove a file or recursively
+# delete an entire directory from the branch. If the file or directory
+# removal makes its parent directory empty, the parent directory will
+# be automatically removed too. This cascades up the tree until the
+# first non-empty directory or the root is reached.
+#
+cmd_commit--filedelete() {
+# ....
+# 'D' SP <path> LF
+# ....
+ if [[ $line != 'D '* ]]; then
+ return 1
+ fi
+ local path=${line#D }
+#
+# here `<path>` is the complete path of the file or subdirectory to
+# be removed from the branch.
+# See `filemodify` above for a detailed description of `<path>`.
+#
+}
+# `filecopy`
+# ^^^^^^^^^^
+# Recursively copies an existing file or subdirectory to a different
+# location within the branch. The existing file or directory must
+# exist. If the destination exists it will be completely replaced
+# by the content copied from the source.
+#
+cmd_commit--filecopy() {
+# ....
+# 'C' SP <path> SP <path> LF
+# ....
+#
+# here the first `<path>` is the source location and the second
+# `<path>` is the destination. See `filemodify` above for a detailed
+# description of what `<path>` may look like. To use a source path
+# that contains SP the path must be quoted.
+#
+# A `filecopy` command takes effect immediately. Once the source
+# location has been copied to the destination any future commands
+# applied to the source location will not impact the destination of
+# the copy.
+#
+# `filerename`
+# ^^^^^^^^^^^^
+# Renames an existing file or subdirectory to a different location
+# within the branch. The existing file or directory must exist. If
+# the destination exists it will be replaced by the source directory.
+#
+# ....
+# 'R' SP <path> SP <path> LF
+# ....
+#
+# here the first `<path>` is the source location and the second
+# `<path>` is the destination. See `filemodify` above for a detailed
+# description of what `<path>` may look like. To use a source path
+# that contains SP the path must be quoted.
+#
+# A `filerename` command takes effect immediately. Once the source
+# location has been renamed to the destination any future commands
+# applied to the source location will create new files there and not
+# impact the destination of the rename.
+#
+# Note that a `filerename` is the same as a `filecopy` followed by a
+# `filedelete` of the source location. There is a slight performance
+# advantage to using `filerename`, but the advantage is so small
+# that it is never worth trying to convert a delete/add pair in
+# source material into a rename for fast-import. This `filerename`
+# command is provided just to simplify frontends that already have
+# rename information and don't want bother with decomposing it into a
+# `filecopy` followed by a `filedelete`.
+#
+# `filedeleteall`
+# ^^^^^^^^^^^^^^^
+# Included in a `commit` command to remove all files (and also all
+# directories) from the branch. This command resets the internal
+# branch structure to have no files in it, allowing the frontend
+# to subsequently add all interesting files from scratch.
+#
+# ....
+# 'deleteall' LF
+# ....
+#
+# This command is extremely useful if the frontend does not know
+# (or does not care to know) what files are currently on the branch,
+# and therefore cannot generate the proper `filedelete` commands to
+# update the content.
+#
+# Issuing a `filedeleteall` followed by the needed `filemodify`
+# commands to set the correct content will produce the same results
+# as sending only the needed `filemodify` and `filedelete` commands.
+# The `filedeleteall` approach may however require fast-import to use slightly
+# more memory per active branch (less than 1 MiB for even most large
+# projects); so frontends that can easily obtain only the affected
+# paths for a commit are encouraged to do so.
+#
+# `notemodify`
+# ^^^^^^^^^^^^
+# Included in a `commit` `<notes_ref>` command to add a new note
+# annotating a `<commit-ish>` or change this annotation contents.
+# Internally it is similar to filemodify 100644 on `<commit-ish>`
+# path (maybe split into subdirectories). It's not advised to
+# use any other commands to write to the `<notes_ref>` tree except
+# `filedeleteall` to delete all existing notes in this tree.
+# This command has two different means of specifying the content
+# of the note.
+#
+# External data format::
+# The data content for the note was already supplied by a prior
+# `blob` command. The frontend just needs to connect it to the
+# commit that is to be annotated.
+# +
+# ....
+# 'N' SP <dataref> SP <commit-ish> LF
+# ....
+# +
+# Here `<dataref>` can be either a mark reference (`:<idnum>`)
+# set by a prior `blob` command, or a full 40-byte SHA-1 of an
+# existing Git blob object.
+#
+# Inline data format::
+# The data content for the note has not been supplied yet.
+# The frontend wants to supply it as part of this modify
+# command.
+# +
+# ....
+# 'N' SP 'inline' SP <commit-ish> LF
+# data
+# ....
+# +
+# See below for a detailed description of the `data` command.
+#
+# In both formats `<commit-ish>` is any of the commit specification
+# expressions also accepted by `from` (see above).
+#
+# `mark`
+# ~~~~~~
+# Arranges for fast-import to save a reference to the current object, allowing
+# the frontend to recall this object at a future point in time, without
+# knowing its SHA-1. Here the current object is the object creation
+# command the `mark` command appears within. This can be `commit`,
+# `tag`, and `blob`, but `commit` is the most common usage.
+#
+# ....
+# 'mark' SP ':' <idnum> LF
+# ....
+#
+# where `<idnum>` is the number assigned by the frontend to this mark.
+# The value of `<idnum>` is expressed as an ASCII decimal integer.
+# The value 0 is reserved and cannot be used as
+# a mark. Only values greater than or equal to 1 may be used as marks.
+#
+# New marks are created automatically. Existing marks can be moved
+# to another object simply by reusing the same `<idnum>` in another
+# `mark` command.
+#
+# `tag`
+# ~~~~~
+# Creates an annotated tag referring to a specific commit. To create
+# lightweight (non-annotated) tags see the `reset` command below.
+#
+# ....
+# 'tag' SP <name> LF
+# 'from' SP <commit-ish> LF
+# 'tagger' (SP <name>)? SP LT <email> GT SP <when> LF
+# data
+# ....
+#
+# where `<name>` is the name of the tag to create.
+#
+# Tag names are automatically prefixed with `refs/tags/` when stored
+# in Git, so importing the CVS branch symbol `RELENG-1_0-FINAL` would
+# use just `RELENG-1_0-FINAL` for `<name>`, and fast-import will write the
+# corresponding ref as `refs/tags/RELENG-1_0-FINAL`.
+#
+# The value of `<name>` must be a valid refname in Git and therefore
+# may contain forward slashes. As `LF` is not valid in a Git refname,
+# no quoting or escaping syntax is supported here.
+#
+# The `from` command is the same as in the `commit` command; see
+# above for details.
+#
+# The `tagger` command uses the same format as `committer` within
+# `commit`; again see above for details.
+#
+# The `data` command following `tagger` must supply the annotated tag
+# message (see below for `data` command syntax). To import an empty
+# tag message use a 0 length data. Tag messages are free-form and are
+# not interpreted by Git. Currently they must be encoded in UTF-8,
+# as fast-import does not permit other encodings to be specified.
+#
+# Signing annotated tags during import from within fast-import is not
+# supported. Trying to include your own PGP/GPG signature is not
+# recommended, as the frontend does not (easily) have access to the
+# complete set of bytes which normally goes into such a signature.
+# If signing is required, create lightweight tags from within fast-import with
+# `reset`, then create the annotated versions of those tags offline
+# with the standard 'git tag' process.
+#
+# `reset`
+# ~~~~~~~
+# Creates (or recreates) the named branch, optionally starting from
+# a specific revision. The reset command allows a frontend to issue
+# a new `from` command for an existing branch, or to create a new
+# branch from an existing commit without creating a new commit.
+#
+# ....
+# 'reset' SP <ref> LF
+# ('from' SP <commit-ish> LF)?
+# LF?
+# ....
+#
+# For a detailed description of `<ref>` and `<commit-ish>` see above
+# under `commit` and `from`.
+#
+# The `LF` after the command is optional (it used to be required).
+#
+# The `reset` command can also be used to create lightweight
+# (non-annotated) tags. For example:
+#
+# ====
+# reset refs/tags/938
+# from :938
+# ====
+#
+# would create the lightweight tag `refs/tags/938` referring to
+# whatever commit mark `:938` references.
+#
+# `blob`
+# ~~~~~~
+# Requests writing one file revision to the packfile. The revision
+# is not connected to any commit; this connection must be formed in
+# a subsequent `commit` command by referencing the blob through an
+# assigned mark.
+#
+# ....
+# 'blob' LF
+# mark?
+# data
+# ....
+#
+# The mark command is optional here as some frontends have chosen
+# to generate the Git SHA-1 for the blob on their own, and feed that
+# directly to `commit`. This is typically more work than it's worth
+# however, as marks are inexpensive to store and easy to use.
+#
+# `data`
+# ~~~~~~
+# Supplies raw data (for use as blob/file content, commit messages, or
+# annotated tag messages) to fast-import. Data can be supplied using an exact
+# byte count or delimited with a terminating line. Real frontends
+# intended for production-quality conversions should always use the
+# exact byte count format, as it is more robust and performs better.
+# The delimited format is intended primarily for testing fast-import.
+#
+# Comment lines appearing within the `<raw>` part of `data` commands
+# are always taken to be part of the body of the data and are therefore
+# never ignored by fast-import. This makes it safe to import any
+# file/message content whose lines might start with `#`.
+#
+# Exact byte count format::
+# The frontend must specify the number of bytes of data.
+# +
+# ....
+# 'data' SP <count> LF
+# <raw> LF?
+# ....
+# +
+# where `<count>` is the exact number of bytes appearing within
+# `<raw>`. The value of `<count>` is expressed as an ASCII decimal
+# integer. The `LF` on either side of `<raw>` is not
+# included in `<count>` and will not be included in the imported data.
+# +
+# The `LF` after `<raw>` is optional (it used to be required) but
+# recommended. Always including it makes debugging a fast-import
+# stream easier as the next command always starts in column 0
+# of the next line, even if `<raw>` did not end with an `LF`.
+get_data--exact-byte-count() {
+ declare -i count="${line#data }"
+ blob="$(head -c "${count}" | "$RVS" commit.f -)"
+ get_line
+ [[ -n $line ]] || get_line
+}
+#
+# Delimited format::
+# A delimiter string is used to mark the end of the data.
+# fast-import will compute the length by searching for the delimiter.
+# This format is primarily useful for testing and is not
+# recommended for real data.
+# +
+# ....
+# 'data' SP '<<' <delim> LF
+# <raw> LF
+# <delim> LF
+# LF?
+# ....
+# +
+# where `<delim>` is the chosen delimiter string. The string `<delim>`
+# must not appear on a line by itself within `<raw>`, as otherwise
+# fast-import will think the data ends earlier than it really does. The `LF`
+# immediately trailing `<raw>` is part of `<raw>`. This is one of
+# the limitations of the delimited format, it is impossible to supply
+# a data chunk which does not have an LF as its last byte.
+# +
+# The `LF` after `<delim> LF` is optional (it used to be required).
+get_data--delimited() {
+ local delim="${line#'data <<'}"
+ blob="$(
+ while get_line && [[ $line != "$delim" ]]; do
+ printf '%s\n' "$line"
+ done | "$RVS" commit.f -)"
+ get_line
+ [[ -n $line ]] || get_line
+}
+get_data() {
+ if [[ $line = 'data <<'* ]]; then get_data--delimited
+ elif [[ $line = 'data '+([0-9]) ]]; then get_data--exact-byte-count
+ else false; fi
+}
+#
+# `checkpoint`
+# ~~~~~~~~~~~~
+# Forces fast-import to close the current packfile, start a new one, and to
+# save out all current branch refs, tags and marks.
+#
+# ....
+# 'checkpoint' LF
+# LF?
+# ....
+#
+# Note that fast-import automatically switches packfiles when the current
+# packfile reaches --max-pack-size, or 4 GiB, whichever limit is
+# smaller. During an automatic packfile switch fast-import does not update
+# the branch refs, tags or marks.
+#
+# As a `checkpoint` can require a significant amount of CPU time and
+# disk IO (to compute the overall pack SHA-1 checksum, generate the
+# corresponding index file, and update the refs) it can easily take
+# several minutes for a single `checkpoint` command to complete.
+#
+# Frontends may choose to issue checkpoints during extremely large
+# and long running imports, or when they need to allow another Git
+# process access to a branch. However given that a 30 GiB Subversion
+# repository can be loaded into Git through fast-import in about 3 hours,
+# explicit checkpointing may not be necessary.
+#
+# The `LF` after the command is optional (it used to be required).
+#
+# `progress`
+# ~~~~~~~~~~
+# Causes fast-import to print the entire `progress` line unmodified to
+# its standard output channel (file descriptor 1) when the command is
+# processed from the input stream. The command otherwise has no impact
+# on the current import, or on any of fast-import's internal state.
+#
+# ....
+# 'progress' SP <any> LF
+# LF?
+# ....
+#
+# The `<any>` part of the command may contain any sequence of bytes
+# that does not contain `LF`. The `LF` after the command is optional.
+# Callers may wish to process the output through a tool such as sed to
+# remove the leading part of the line, for example:
+#
+# ====
+# frontend | git fast-import | sed 's/^progress //'
+# ====
+#
+# Placing a `progress` command immediately after a `checkpoint` will
+# inform the reader when the `checkpoint` has been completed and it
+# can safely access the refs that fast-import updated.
+#
+# `cat-blob`
+# ~~~~~~~~~~
+# Causes fast-import to print a blob to a file descriptor previously
+# arranged with the `--cat-blob-fd` argument. The command otherwise
+# has no impact on the current import; its main purpose is to
+# retrieve blobs that may be in fast-import's memory but not
+# accessible from the target repository.
+#
+# ....
+# 'cat-blob' SP <dataref> LF
+# ....
+#
+# The `<dataref>` can be either a mark reference (`:<idnum>`)
+# set previously or a full 40-byte SHA-1 of a Git blob, preexisting or
+# ready to be written.
+#
+# Output uses the same format as `git cat-file --batch`:
+#
+# ====
+# <sha1> SP 'blob' SP <size> LF
+# <contents> LF
+# ====
+#
+# This command can be used anywhere in the stream that comments are
+# accepted. In particular, the `cat-blob` command can be used in the
+# middle of a commit but not in the middle of a `data` command.
+#
+# See ``Responses To Commands'' below for details about how to read
+# this output safely.
+#
+# `ls`
+# ~~~~
+# Prints information about the object at a path to a file descriptor
+# previously arranged with the `--cat-blob-fd` argument. This allows
+# printing a blob from the active commit (with `cat-blob`) or copying a
+# blob or tree from a previous commit for use in the current one (with
+# `filemodify`).
+#
+# The `ls` command can be used anywhere in the stream that comments are
+# accepted, including the middle of a commit.
+#
+# Reading from the active commit::
+# This form can only be used in the middle of a `commit`.
+# The path names a directory entry within fast-import's
+# active commit. The path must be quoted in this case.
+# +
+# ....
+# 'ls' SP <path> LF
+# ....
+#
+# Reading from a named tree::
+# The `<dataref>` can be a mark reference (`:<idnum>`) or the
+# full 40-byte SHA-1 of a Git tag, commit, or tree object,
+# preexisting or waiting to be written.
+# The path is relative to the top level of the tree
+# named by `<dataref>`.
+# +
+# ....
+# 'ls' SP <dataref> SP <path> LF
+# ....
+#
+# See `filemodify` above for a detailed description of `<path>`.
+#
+# Output uses the same format as `git ls-tree <tree> -- <path>`:
+#
+# ====
+# <mode> SP ('blob' | 'tree' | 'commit') SP <dataref> HT <path> LF
+# ====
+#
+# The <dataref> represents the blob, tree, or commit object at <path>
+# and can be used in later 'cat-blob', 'filemodify', or 'ls' commands.
+#
+# If there is no file or subtree at that path, 'git fast-import' will
+# instead report
+#
+# ====
+# missing SP <path> LF
+# ====
+#
+# See ``Responses To Commands'' below for details about how to read
+# this output safely.
+#
+# `feature`
+# ~~~~~~~~~
+# Require that fast-import supports the specified feature, or abort if
+# it does not.
+#
+# ....
+# 'feature' SP <feature> ('=' <argument>)? LF
+# ....
+#
+# The <feature> part of the command may be any one of the following:
+#
+# date-format::
+# export-marks::
+# relative-marks::
+# no-relative-marks::
+# force::
+# Act as though the corresponding command-line option with
+# a leading '--' was passed on the command line
+# (see OPTIONS, above).
+#
+# import-marks::
+# import-marks-if-exists::
+# Like --import-marks except in two respects: first, only one
+# "feature import-marks" or "feature import-marks-if-exists"
+# command is allowed per stream; second, an --import-marks=
+# or --import-marks-if-exists command-line option overrides
+# any of these "feature" commands in the stream; third,
+# "feature import-marks-if-exists" like a corresponding
+# command-line option silently skips a nonexistent file.
+#
+# cat-blob::
+# ls::
+# Require that the backend support the 'cat-blob' or 'ls' command.
+# Versions of fast-import not supporting the specified command
+# will exit with a message indicating so.
+# This lets the import error out early with a clear message,
+# rather than wasting time on the early part of an import
+# before the unsupported command is detected.
+#
+# notes::
+# Require that the backend support the 'notemodify' (N)
+# subcommand to the 'commit' command.
+# Versions of fast-import not supporting notes will exit
+# with a message indicating so.
+#
+# done::
+# Error out if the stream ends without a 'done' command.
+# Without this feature, errors causing the frontend to end
+# abruptly at a convenient point in the stream can go
+# undetected. This may occur, for example, if an import
+# front end dies in mid-operation without emitting SIGTERM
+# or SIGKILL at its subordinate git fast-import instance.
+#
+# `option`
+# ~~~~~~~~
+# Processes the specified option so that git fast-import behaves in a
+# way that suits the frontend's needs.
+# Note that options specified by the frontend are overridden by any
+# options the user may specify to git fast-import itself.
+#
+# ....
+# 'option' SP <option> LF
+# ....
+#
+# The `<option>` part of the command may contain any of the options
+# listed in the OPTIONS section that do not change import semantics,
+# without the leading '--' and is treated in the same way.
+#
+# Option commands must be the first commands on the input (not counting
+# feature commands), to give an option command after any non-option
+# command is an error.
+#
+# The following command-line options change import semantics and may therefore
+# not be passed as option:
+#
+# * date-format
+# * import-marks
+# * export-marks
+# * cat-blob-fd
+# * force
+#
+# `done`
+# ~~~~~~
+# If the `done` feature is not in use, treated as if EOF was read.
+# This can be used to tell fast-import to finish early.
+#
+# If the `--done` command-line option or `feature done` command is
+# in use, the `done` command is mandatory and marks the end of the
+# stream.
diff --git a/modules/module.mk b/modules/module.mk
new file mode 100644
index 0000000..b2dbde8
--- /dev/null
+++ b/modules/module.mk
@@ -0,0 +1,36 @@
+#!/usr/bin/make -f
+# Copyright (C) 2009, 2015 Luke Shumaker
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+include $(dir $(lastword $(MAKEFILE_LIST)))/../../config.mk
+include $(topsrcdir)/automake.head.mk
+
+name := $(lastword $(subst /, ,$(abspath $(srcdir))))
+include $(srcdir)/Makefile.inc.mk
+
+makefiles = Makefile Makefile.inc.mk
+dirs += $(DESTDIR)$(pkglibexecdir)/modules/$(name)
+am_src_files += Module.mk
+am_sys_files += $(pkglibexecdir)/modules/$(name).mk
+am_sys_files += $(addprefix $(pkglibexecdir)/modules/$(name)/,$(am_out_files))
+
+$(DESTDIR)$(pkglibexecdir)/modules/$(name).mk: $(srcdir)/Module.mk | $(DESTDIR)$(pkglibexecdir)/modules
+ $(INSTALL_DATA) $< $@
+$(DESTDIR)$(pkglibexecdir)/modules/$(name)/%: $(srcdir)/% | $(DESTDIR)$(pkglibexecdir)/modules/$(name)
+ $(INSTALL_PROGRAM) $< $@
+$(DESTDIR)$(pkglibexecdir)/modules/$(name)/%: $(outdir)/% | $(DESTDIR)$(pkglibexecdir)/modules/$(name)
+ $(INSTALL_PROGRAM) $< $@
+
+include $(topsrcdir)/automake.tail.mk
diff --git a/modules/tags/Makefile b/modules/tags/Makefile
new file mode 120000
index 0000000..fa7273c
--- /dev/null
+++ b/modules/tags/Makefile
@@ -0,0 +1 @@
+../module.mk \ No newline at end of file
diff --git a/modules/tags/Makefile.inc.mk b/modules/tags/Makefile.inc.mk
new file mode 100644
index 0000000..1ccdada
--- /dev/null
+++ b/modules/tags/Makefile.inc.mk
@@ -0,0 +1,2 @@
+am_src_files += commit.sh get-tag.sh print.sh tag-id.sh tag.sh
+am_out_files += commit get-tag print tag-id tag
diff --git a/modules/tags/Module.mk b/modules/tags/Module.mk
new file mode 100644
index 0000000..2ef7ffb
--- /dev/null
+++ b/modules/tags/Module.mk
@@ -0,0 +1 @@
+commit/tags : commit/blobs commit/tree
diff --git a/modules/tags/commit.sh b/modules/tags/commit.sh
new file mode 100644
index 0000000..d8df1d0
--- /dev/null
+++ b/modules/tags/commit.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+name='rvs @ID@ commit'
+ver=0.1
+# Copyright (C) 2010 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+if [ "$RVS_LEVEL" = '0' ]; then
+ id=`cat "$TMPDIR/commit/files"`
+ "$RVS" tag "$id" wch
+fi
+
diff --git a/modules/tags/get-tag.sh b/modules/tags/get-tag.sh
new file mode 100644
index 0000000..27d04da
--- /dev/null
+++ b/modules/tags/get-tag.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+name='rvs @ID@ get-tag'
+ver=0.1
+# Copyright (C) 2010 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+usage="usage: $RVS get-tag FILENAME TAG"
+name="${1?"$usage"}"
+ tag="${2?"$usage"}"
+
+"$RVS" get "$name" "`"$RVS" tag-id "$tag"`"
+
diff --git a/modules/tags/print.sh b/modules/tags/print.sh
new file mode 100644
index 0000000..f9f7a54
--- /dev/null
+++ b/modules/tags/print.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+name='print'
+ver=0.1
+# Copyright (C) 2010 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+usage="Usage: $RVS $name ID"
+id="${1?"$usage"}"
+
+dir="$REPO/@ID@"
+if [ -d "$dir" ]; then
+ cd "$dir"
+ echo "Tags:"
+ grep -rFxl "$id" ./ | sed 's/^\.\/\(.*\)/ \1/'
+fi
+
+
diff --git a/modules/tags/tag-id.sh b/modules/tags/tag-id.sh
new file mode 100644
index 0000000..050d12e
--- /dev/null
+++ b/modules/tags/tag-id.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+name='tag-id'
+ver=0.1
+# Copyright (C) 2010 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+usage="usage: $RVS $name TAG"
+tag="${1?"$usage"}"
+
+file="$REPO/@ID@/$tag"
+
+if [ -f "$file" ]; then
+ cat "$REPO/@ID@/$tag"
+else
+ echo "$0: cannot find tag \`$tag'" >> /dev/stderr
+ exit 1
+fi
+
+
+
diff --git a/modules/tags/tag.sh b/modules/tags/tag.sh
new file mode 100644
index 0000000..90ff0f1
--- /dev/null
+++ b/modules/tags/tag.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+name='rvs @ID@ tag'
+ver=0.1
+# Copyright (C) 2010 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+# tag ID TAG
+usage="usage: $RVS tag ID TAG"
+ ID="${1?"$usage"}"
+tag="${2?"$usage"}"
+
+file="$REPO/@ID@/$tag"
+mkdir -p "`dirname "$file"`"
+echo "$ID" > "$file"
+
diff --git a/modules/tree/Makefile b/modules/tree/Makefile
new file mode 120000
index 0000000..fa7273c
--- /dev/null
+++ b/modules/tree/Makefile
@@ -0,0 +1 @@
+../module.mk \ No newline at end of file
diff --git a/modules/tree/Makefile.inc.mk b/modules/tree/Makefile.inc.mk
new file mode 100644
index 0000000..c91bef2
--- /dev/null
+++ b/modules/tree/Makefile.inc.mk
@@ -0,0 +1,2 @@
+am_src_files += addparent.d.sh addparent.f.sh addparent.sh commit.sh delparent.f.sh getchildren.sh getparents.sh print.sh
+am_out_files += addparent.d addparent.f addparent commit delparent.f getchildren getparents print
diff --git a/modules/tree/Module.mk b/modules/tree/Module.mk
new file mode 100644
index 0000000..c214a35
--- /dev/null
+++ b/modules/tree/Module.mk
@@ -0,0 +1 @@
+commit/tree : commit/blobs
diff --git a/modules/tree/addparent.d.sh b/modules/tree/addparent.d.sh
new file mode 100644
index 0000000..20c28b4
--- /dev/null
+++ b/modules/tree/addparent.d.sh
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+name='addparent.d'
+ver=0.1
+# Copyright (C) 2010 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+usage="usage: $RVS $name CHILD PARENT"
+ child=${1?"$usage"}
+parent=${2?"$usage"}
+
+tc="`mktemp`"
+tp="`mktemp`"
+
+"$RVS" ls "$child" '%i\t%n' > "$tc"
+"$RVS" ls "$parent" '%i\t%n' > "$tp"
+
+while read line; do
+ name="`echo "$line" | cut -f2-`"
+ nID="`echo "$line" | cut -f1`"
+ oID="`sed -n "s:^\([a-z]\:[0-9a-f]*\)\t${name/:/\\:}$:\1:p" "$tp"`"
+
+ if [ -n "$oID" ]; then
+ nT="`"$RVS" blob-gettype "$nID"`"
+ oT="`"$RVS" blob-gettype "$oID"`"
+ if [ "$nT" = "$oT" ]; then
+ "$RVS" addparent "$nID" "$oID"
+ fi
+ fi
+done < "$tc"
+
+"$RVS" addparent.f "$child" "$parent"
diff --git a/modules/tree/addparent.f.sh b/modules/tree/addparent.f.sh
new file mode 100644
index 0000000..5d913da
--- /dev/null
+++ b/modules/tree/addparent.f.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+name='addparent.f'
+ver=0.1
+# Copyright (C) 2010 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+usage="usage: $RVS $name CHILD PARENT"
+ child=${1?"$usage"}
+parent=${2?"$usage"}
+
+file="$REPO/tree/$child/$parent"
+mkdir -p "`dirname "$file"`"
+echo "$parent" > "$file"
+
diff --git a/modules/tree/addparent.sh b/modules/tree/addparent.sh
new file mode 100644
index 0000000..4f1fd86
--- /dev/null
+++ b/modules/tree/addparent.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+name='addparent'
+ver=0.1
+# Copyright (C) 2010 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+usage="usage: $RVS $name CHILD PARENT"
+ child=${1?"$usage"}
+parent=${2?"$usage"}
+
+if [ ! "$child" = "$parent" ]; then
+ ct="`"$RVS" blob-gettype "$child"`"
+ pt="`"$RVS" blob-gettype "$parent"`"
+
+ if [ "$ct" = "$pt" ]; then
+ "$RVS" "addparent.$ct" "$child" "$parent"
+ else
+ echo "$0: CHILD and PARENT must be the same type">>/dev/stderr
+ exit 1
+ fi
+fi
+
diff --git a/modules/tree/commit.sh b/modules/tree/commit.sh
new file mode 100644
index 0000000..1715f23
--- /dev/null
+++ b/modules/tree/commit.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+name='rvs @ID@ commit'
+ver=0.1
+# Copyright (C) 2010 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+if [ "$RVS_LEVEL" = '0' ]; then
+ id=`cat "$TMPDIR/commit/files"`
+ wch="`"$RVS" tag-id wch 2>/dev/null`"
+ if [ -n "$wch" ]; then
+ "$RVS" addparent "$id" "$wch"
+ fi
+fi
+
diff --git a/modules/tree/delparent.f.sh b/modules/tree/delparent.f.sh
new file mode 100644
index 0000000..422778d
--- /dev/null
+++ b/modules/tree/delparent.f.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+name='delparent.f'
+ver=0.1
+# Copyright (C) 2010 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+usage="usage: $RVS $name CHILD PARENT"
+ child=${1?"$usage"}
+parent=${2?"$usage"}
+
+file="$REPO/tree/$child/$parent"
+rm "$file"
+if [ -z "$(ls "`dirname "$file"`")" ]; then
+ rmdir "`dirname "$file"`"
+fi
+
+ dir="$REPO/tree/$child"
+if [ -z "$(ls "`dirname "$dir"`")" ]; then
+ rmdir "`dirname "$dir"`"
+fi
+
diff --git a/modules/tree/getchildren.sh b/modules/tree/getchildren.sh
new file mode 100644
index 0000000..4ef5a22
--- /dev/null
+++ b/modules/tree/getchildren.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+name='getchildren'
+ver=0.1
+# Copyright (C) 2010 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+usage="Usage: $RVS $name ID"
+id="${1?"$usage"}"
+
+dir="$REPO/@ID@/"
+if [ -d "$dir" ]; then
+ grep -rFxh "$id" "$dir"
+fi
+
+
diff --git a/modules/tree/getparents.sh b/modules/tree/getparents.sh
new file mode 100644
index 0000000..c060605
--- /dev/null
+++ b/modules/tree/getparents.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+name='getparents'
+ver=0.1
+# Copyright (C) 2010 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+usage="Usage: $RVS $name ID"
+id="${1?"$usage"}"
+
+dir="$REPO/@ID@/$id"
+if [ -d "$dir" ]; then
+ cat "$dir"/*
+fi
+
diff --git a/modules/tree/print.sh b/modules/tree/print.sh
new file mode 100644
index 0000000..709d125
--- /dev/null
+++ b/modules/tree/print.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+name='print'
+ver=0.1
+# Copyright (C) 2010 Luke Shumaker
+#
+# 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; see the file COPYING.
+# If not, see <http://www.gnu.org/licenses>.
+
+usage="Usage: $RVS $name ID"
+id="${1?"$usage"}"
+
+echo "Parents:"
+"$RVS" getparents "$id" | sed 's/\(.*\)/ \1/'
+echo "Children:"
+"$RVS" getchildren "$id" | sed 's/\(.*\)/ \1/'
+
diff --git a/wrapper/.gitignore b/wrapper/.gitignore
new file mode 100644
index 0000000..0c3c90a
--- /dev/null
+++ b/wrapper/.gitignore
@@ -0,0 +1,3 @@
+/outer
+/inner
+/inner.sh
diff --git a/wrapper/Makefile b/wrapper/Makefile
new file mode 100644
index 0000000..65a6613
--- /dev/null
+++ b/wrapper/Makefile
@@ -0,0 +1,36 @@
+#!/usr/bin/make -f
+# Copyright (C) 2009, 2015 Luke Shumaker
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+include $(dir $(lastword $(MAKEFILE_LIST)))/../config.mk
+include $(topsrcdir)/automake.head.mk
+
+makefiles = Makefile
+am_src_files += outer.c inner.sh.m4 runcmd.mk
+am_out_files += outer inner
+am_clean_files += inner.sh
+am_sys_files += $(bindir)/$(PACKAGE) $(pkglibexecdir)/$(PACKAGE) $(pkglibexecdir)/runcmd.mk
+
+$(outdir)/outer.o: $(topoutdir)/config.h
+$(outdir)/inner.sh: $(topoutdir)/config.sh
+
+$(DESTDIR)$(bindir)/$(PACKAGE) : $(outdir)/outer | $(DESTDIR)$(bindir)
+ $(INSTALL_PROGRAM) $< $@
+$(DESTDIR)$(pkglibexecdir)/$(PACKAGE) : $(outdir)/inner | $(DESTDIR)$(pkglibexecdir)
+ $(INSTALL_PROGRAM) $< $@
+$(DESTDIR)$(pkglibexecdir)/runcmd.mk : $(srcdir)/runcmd.mk | $(DESTDIR)$(pkglibexecdir)
+ $(INSTALL_PROGRAM) $< $@
+
+include $(topsrcdir)/automake.tail.mk
diff --git a/wrapper/inner.sh.m4 b/wrapper/inner.sh.m4
new file mode 100644
index 0000000..bd7a643
--- /dev/null
+++ b/wrapper/inner.sh.m4
@@ -0,0 +1,156 @@
+#!/usr/bin/env bash
+# rvs inner.sh - The main RVS program
+# Copyright (C) 2009-2010, 2015 Luke Shumaker
+#
+# This file is part of rvs.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+set -u
+
+m4_include(config.sh)
+
+declare -r varname_REPO="${PACKAGE^^}_REPO"
+declare -r varname_EXEC_PATH="${PACKAGE^^}_EXEC_PATH"
+
+declare -r program_name="$1"; shift
+
+
+
+_() {
+ if type gettext &>/dev/null; then
+ TEXTDOMAINDIR=$localedir gettext "$pkgtextdomain" "$1";
+ else
+ echo "$1";
+ fi
+}
+
+sighandler_exit() {
+ local signal=$1; shift
+ echo
+ error 0 "$@"
+ trap -- "$signal"
+ kill -"$signal" "$$"
+}
+
+install_sighandlers() {
+ set -E
+ for signal in TERM HUP QUIT; do
+ trap "signalhandler_exit $signal '%s signal cought. Exiting...'" $signal
+ done
+ trap 'signalhandler_exit INT "Aborted by user. Exiting..."' INT
+ trap 'kill -USR1 "$$"' ERR
+}
+
+# Like GLibC's error(3), but call gettext on the format string
+error() {
+ >&2 printf "%s: $(_ "$2")\n" "$program_name" "${@:3}"
+ [[ $1 -eq 0 ]] || exit $1
+}
+
+errusage() {
+ >&2 printf "$(_ "$2")\n" "$program_name" "${@:3}"
+ [[ $1 -eq 0 ]] || exit $1
+}
+
+_runcmd() {
+ [[ $# -ge 1 ]] || errusage 1 'Usage: %q <command> [<args>]'
+ local cmd=$1; shift
+ local args_str=''
+ [[ $# -eq 0 ]] || printf -v args_str '%q ' "$@"
+
+ local exec_path="${!varname_EXEC_PATH:-$pkglibexecdir}"
+
+ shopt -s nullglob
+ local files=("${exec_path}"/modules/*/"$cmd")
+ if [[ ${#files[@]} -eq 0 ]]; then
+ error 127 '%s: Not a %s command' "$cmd" "$PACKAGE"
+ fi
+ files=("${files[@]#"${exec_path/modules/}"}")
+
+ local tmpdir
+ trap '[ -z "${tmpdir:-}" ] || rm -rf -- "$tmpdir"' EXIT
+ tmpdir="$(mktemp -dt "${PACKAGE}.XXXXXXXXXX")"
+ mkdir -- "$tmpdir/output"
+
+ local repo
+ repo="$(_repo)"
+ export "${varname_REPO}=${repo}"
+
+ local cwd
+ printf -v cwd '%q' "$PWD"
+
+ make -j1 \
+ -f "$exec_path/runcmd.mk" \
+ -C "$tmpdir/output" \
+ CWD="$cwd" \
+ ARGS="$args_str" \
+ EXEC_PATH="$exec_path" \
+ TMPDIR="$tmpdir" \
+ -- "${files[@]}"
+ exit $?
+}
+
+_repo() {
+ [[ $# -ne 0 ]] || errusage 1 'Usage: %q repo'
+ if [ -z "${!varname_REPO:-}" ]; then # we aren't getting a value from then env
+ local repo=".${PACKAGE,,}"
+
+ # [------can ascend-----] && ! [-not found repo--]
+ while [ "$PWD" != "$OLDPWD" ] && ! [ -d "$PWD/$repo" ]; do
+ cd ..
+ done
+
+ if [ -d "$PWD/$repo" ]; then
+ # we found a repository
+ printf '%s\n' "$PWD/$repo"
+ else
+ # we didn't find a repository
+ error 128 "No %s repository found" "$PACKAGE"
+ fi
+ else
+ printf '%s\n' "${!varname_REPO}"
+ fi
+}
+
+_init() {
+ [[ $# -gt 1 ]] || errusage 1 'Usage: %q init [directory]'
+ local dir="${1:-$PWD}"
+ mkdir -p -- "$dir"
+ cd "$dir"
+ repo="$(_repo 2> /dev/null)" || true
+ if [ -n "${repo:-}" ]; then
+ _error 129 "Repository already exists at \`%s'" "$repo"
+ fi
+ export "$varname_REPO=$PWD/.${PACKAGE,,}"
+ mkdir "${!varname_REPO}"
+ _runcmd init "$dir"
+}
+
+main() {
+ install_sighandlers
+ [[ $# -ge 1 ]] || error 'No command specified';;
+ export "${PACKAGE^^}=$program_name"
+
+ local cmd=$1; shift
+ case "$cmd" in
+ repo) _repo "$@";;
+ init) _init "$@";;
+ *) _runcmd "$cmd" "$@";;
+ esac
+}
+
+main "$@"
+
+# Copy/Paste Virus 1.3c Please copy and paste this text anywhere. Track
+# its progress by searching for this MD5#f7eac285ebfe21c4587bfebb9582f90d
diff --git a/wrapper/outer.c b/wrapper/outer.c
new file mode 100644
index 0000000..c465555
--- /dev/null
+++ b/wrapper/outer.c
@@ -0,0 +1,63 @@
+/* RVS outer.c - A wrapper for $(bindir) to call the main RVS program
+ * Copyright (C) 2015 Luke Shumaker
+ *
+ * This file is part of rvs.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <errno.h> /* for errno */
+#include <error.h> /* for error(3) */
+#include <libintl.h> /* for dgettext(3) */
+#include <locale.h> /* for bindtextdomain(3) and textdomain(3) */
+#include <stdio.h> /* for asprintf(3) */
+#include <stdlib.h> /* for getenv(3), calloc(3) */
+#include <string.h> /* for mempcy(3) */
+#include <unistd.h> /* for execv(3) */
+
+#include "config.h"
+#define _ gettext
+
+#define EXIT_FAILURE_OOM 126
+#define EXIT_FAILURE_EXEC 127
+
+int
+main(int argc, char *argv[]) {
+ bindtextdomain(pkgtextdomain, localedir);
+ textdomain(pkgtextdomain);
+
+ unsetenv("ENV");
+ unsetenv("BASH_ENV");
+
+ const char *varname = PACKAGE_UPPER "_EXEC_PATH";
+
+ char *exec_path = getenv(varname);
+ if (!exec_path)
+ exec_path = pkglibexecdir;
+
+ char *exec_file = NULL;
+ if (asprintf(&exec_file, "%s/" PACKAGE, exec_path) < 0)
+ error(EXIT_FAILURE_OOM, errno,
+ _("Could not allocate memory for string"));
+
+ char **args = calloc(argc+2, sizeof(char*));
+ if (!args)
+ error(EXIT_FAILURE_OOM, errno,
+ _("Could not allocate cleared memory"));
+ args[0] = exec_file;
+ memcpy(&args[1], argv, sizeof(char*) * argc);
+
+ execv(exec_file, args);
+ error(EXIT_FAILURE_EXEC, errno, _("Could not execute: %s"), exec_file);
+ return EXIT_FAILURE_EXEC;
+}
diff --git a/wrapper/runcmd.mk b/wrapper/runcmd.mk
new file mode 100644
index 0000000..7340d11
--- /dev/null
+++ b/wrapper/runcmd.mk
@@ -0,0 +1,15 @@
+#!/usr/bin/make -f
+
+# Environment/command line variables:
+# - ARGS
+# - EXEC_DIR
+# - CWD
+
+SHELL = bash -o pipefail
+
+export OUTPUT_DIR := $(realpath .)
+
+% : $(EXEC_PATH)/modules/%
+ cd $(CWD) && '$<' $(ARGS) | tee -- '$@' | sed 's,^,$@:,' >/dev/tty
+
+include $(wildcard $(EXEC_PATH)/modules/*.mk)