From 42280f662d3ce4affb00eb68a22a081dfb951395 Mon Sep 17 00:00:00 2001 From: Francois Marier Date: Mon, 23 Jun 2008 23:47:09 +1200 Subject: Imported Upstream version 0.2.1 --- .cil | 0 .gitignore | 2 + COPYING | 674 ++++++++++++++++++++++++++++++++++++++++++++++++ INSTALLATION | 74 ++++++ README | 75 ++++++ bin/cil | 667 +++++++++++++++++++++++++++++++++++++++++++++++ debian-etch/.gitignore | 3 + debian-etch/changelog | 17 ++ debian-etch/compat | 1 + debian-etch/control | 18 ++ debian-etch/copyright | 25 ++ debian-etch/docs | 1 + debian-etch/install | 2 + debian-etch/manpages | 1 + debian-etch/rules | 53 ++++ debian-lenny/.gitignore | 3 + debian-lenny/changelog | 17 ++ debian-lenny/compat | 1 + debian-lenny/control | 18 ++ debian-lenny/copyright | 25 ++ debian-lenny/docs | 1 + debian-lenny/install | 2 + debian-lenny/manpages | 1 + debian-lenny/rules | 53 ++++ issues/c_2b92ef13.cil | 6 + issues/c_792a4acf.cil | 6 + issues/c_feb65ae7.cil | 9 + issues/i_02ee35bd.cil | 16 ++ issues/i_5c88cb30.cil | 31 +++ issues/i_6baa8555.cil | 15 ++ issues/i_cbb43db9.cil | 14 + issues/i_fb79b2e8.cil | 16 ++ lib/CIL.pm | 114 ++++++++ lib/CIL/Attachment.pm | 98 +++++++ lib/CIL/Base.pm | 189 ++++++++++++++ lib/CIL/Comment.pm | 80 ++++++ lib/CIL/Issue.pm | 144 +++++++++++ lib/CIL/Utils.pm | 184 +++++++++++++ t/00_files.t | 33 +++ t/i_cafebabe.cil | 13 + 40 files changed, 2702 insertions(+) create mode 100644 .cil create mode 100644 .gitignore create mode 100644 COPYING create mode 100644 INSTALLATION create mode 100644 README create mode 100755 bin/cil create mode 100644 debian-etch/.gitignore create mode 100644 debian-etch/changelog create mode 100644 debian-etch/compat create mode 100644 debian-etch/control create mode 100644 debian-etch/copyright create mode 100644 debian-etch/docs create mode 100644 debian-etch/install create mode 100644 debian-etch/manpages create mode 100755 debian-etch/rules create mode 100644 debian-lenny/.gitignore create mode 100644 debian-lenny/changelog create mode 100644 debian-lenny/compat create mode 100644 debian-lenny/control create mode 100644 debian-lenny/copyright create mode 100644 debian-lenny/docs create mode 100644 debian-lenny/install create mode 100644 debian-lenny/manpages create mode 100755 debian-lenny/rules create mode 100644 issues/c_2b92ef13.cil create mode 100644 issues/c_792a4acf.cil create mode 100644 issues/c_feb65ae7.cil create mode 100644 issues/i_02ee35bd.cil create mode 100644 issues/i_5c88cb30.cil create mode 100644 issues/i_6baa8555.cil create mode 100644 issues/i_cbb43db9.cil create mode 100644 issues/i_fb79b2e8.cil create mode 100644 lib/CIL.pm create mode 100644 lib/CIL/Attachment.pm create mode 100644 lib/CIL/Base.pm create mode 100644 lib/CIL/Comment.pm create mode 100644 lib/CIL/Issue.pm create mode 100644 lib/CIL/Utils.pm create mode 100644 t/00_files.t create mode 100644 t/i_cafebabe.cil diff --git a/.cil b/.cil new file mode 100644 index 0000000..e69de29 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..140fe6f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*-stamp +cil.1 diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is 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. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +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. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + 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 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. Use with the GNU Affero General Public License. + + 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 Affero 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 special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 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 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 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. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + 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 GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/INSTALLATION b/INSTALLATION new file mode 100644 index 0000000..0da7be5 --- /dev/null +++ b/INSTALLATION @@ -0,0 +1,74 @@ +=============================================================================== + +Dependencies +------------ + +Perl Modules: + + * Term::CallEditor + * File::Touch + * File::Glob + * File::Basename + * MIME::Base64 + +Some of these are distributed with perl itself but is left as an excercise to +the reader to figure out what you need in your distribution (for Debian Etch, +see below). + +=============================================================================== + +Debian Packaging +---------------- + +For Debian Etch, the following packages will need to be installed: + +* perl +* libgetopt-mixed-perl +* libdigest-perl +* libfile-touch-perl +* libfile-slurp-perl +* libclass-accessor-perl +* libdatetime-perl + +Out of the box, cil provides two debian directories depending on which version +of Debian you wish to use. Currently, there isn't much difference but choose +which distro you want and link that to 'debian/'. e.g. for Etch, run: + + $ ln -s debian-etch debian + +Then inside the main cil directory, you can type the following to create a +Debian paackage: + + $ dpkg-buildpackage -tc -us -uc -rfakeroot + +which can then be installed with: + + $ sudo dpkg -i ../cil_0.2.1_all.deb + +or added to a repository you are using for easier installation with apt-get or +aptitude. + +Then, you can just run 'cil' from the command line. + +=============================================================================== + +Running 'cil' without installing +-------------------------------- + +The quickest way to start is to 'cd' into the directory you untarred or cloned +the repo into. + + $ cd /path/to/cil/lib + $ export PERL5LIB=`pwd` + +Then you can either run by: + +* /path/to/cil/bin/cil init +* export PATH=/path/to/cil/bin:$PATH +* cd ~/bin && ln -s /path/to/cil/bin/cil + +=============================================================================== + +See http://kapiti.geek.nz/software/cil.html for further information. + +=============================================================================== diff --git a/README b/README new file mode 100644 index 0000000..607b470 --- /dev/null +++ b/README @@ -0,0 +1,75 @@ +=============================================================================== + +Overview +-------- + +'cil' allows easy command-line creation of an issue tracker. It saves each +issue locally and in plain text. Commands are given such that these issues can +be added, edited and listed easily. + +=============================================================================== + +Quick Start +----------- + +Once installed, you should be able to run 'cil': + + $ cil --help + +Now change directory to your current development project. To save the issues, +'cil' requires setting up, so issue the 'init' command: + + $ cil init + +This creates a '.cil' file and an 'issues/' directory. + +Then add an issue. An editor will pop-up and you fill in the details: + + $ cil add + +After you've added it, you can see a representation of the issue. Now you can +list all the issues by using the 'list' command: + + $ cil list + +You can see what the issue name is by looking at the 'Issue' title. Imagine it +is 'cafebabe' (which by default is the time from epoch). To see your issue +again, use the 'show' command: + + $ cil show cafebabe + +Another reporting command is 'summary': + + $ cil summary + +The columns show 'Name', 'Status', 'CreatedBy' and 'Summary'. + +Shucks, we've noticed we got something wrong in the issue. Let's edit it: + + $ cil edit cafebabe + +Save your changes and exit your editor. The issue is now saved. Try showing it +again to make sure your changed are correct. + +We have just found out more about the issue so let's add a comment to it: + + $ cil comment cafebabe + +When you show the issue again, you'll see the comment has been added and is now +displayed. + +Adding an attachment is easy: + + $ cil attach cafebabe core + ... added attachment 'decaf7ea' ... + $ cil show cafebabe + +If someone else added the attachment and you wish to view it, you can extract +it from the issue: + + $ cil extract decaf7ea --filename=mycore + +That's it for now. As you can see, if you've played with any kind of bug/issue +tracker before, 'cil' is straightforward. + +=============================================================================== diff --git a/bin/cil b/bin/cil new file mode 100755 index 0000000..d5a0af1 --- /dev/null +++ b/bin/cil @@ -0,0 +1,667 @@ +#!/usr/bin/perl +## ---------------------------------------------------------------------------- +# cil is a Command line Issue List +# Copyright (C) 2008 Andrew Chilton +# +# 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 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +## ---------------------------------------------------------------------------- + +use strict; +use warnings; + +use Data::Dumper; + +use Getopt::Mixed "nextOption"; +use Digest::MD5 qw(md5_hex); +use File::Touch; +use File::Glob ':glob'; +use File::Basename; +use File::Slurp qw(read_file write_file); +use CIL; +use CIL::Issue; +use CIL::Comment; +use CIL::Attachment; + +## ---------------------------------------------------------------------------- +# constants + +use constant VERSION => '0.2.1'; + +my @IN_OPTS = ( + 'p=s', # p = path + 'path>p', # for 'add' + 'f=s', # f = filename + 'filename=f', # for 'extract' + + 'help', + 'version', +); + +my %BOOLEAN_ARGS = ( + help => 1, + version => 1, +); + +my $gan = $ENV{GIT_AUTHOR_NAME} || 'Your Name'; +my $gae = $ENV{GIT_AUTHOR_EMAIL} || 'you@example.org'; + +my $new_issue_text = <<"EOF"; +Summary : +Status : New +CreatedBy : $gan <$gae> +AssignedTo : $gan <$gae> +Label : + +Description... +EOF + +my $add_comment_text = <<"EOF"; +CreatedBy : $gan <$gae> + +Description... +EOF + +## ---------------------------------------------------------------------------- +# main program + +{ + my $args = get_options(\@IN_OPTS, \%BOOLEAN_ARGS); + + # do the version and help + if ( exists $args->{version} ) { + print "cil version ".VERSION."\n"; + exit; + } + + if ( exists $args->{help} ) { + usage(); + exit; + } + + # make sure that the command given is valid + Getopt::Mixed::abortMsg('specify a command') + if @ARGV == 0; + + my $command = shift @ARGV; + no strict 'refs'; + if ( not defined &{"cmd_$command"} ) { + Getopt::Mixed::abortMsg("'$command' is not a valid cil command."); + } + + my $cil = CIL->new(); + + &{"cmd_$command"}($cil, $args, @ARGV); +} + +## ---------------------------------------------------------------------------- +# commands + +sub cmd_init { + my ($cil, $args) = @_; + + my $path = $args->{p} || '.'; # default path is right here + + # error if $path doesn't exist + unless ( -d $path ) { + fatal("path '$path' doesn't exist"); + } + + # error if issues/ already exists + my $issues_dir = "$path/issues"; + if ( -d $issues_dir ) { + fatal("issues directory '$issues_dir' already exists, not initialising issues"); + } + + # error if .cil already exists + my $config = "$path/.cil"; + if ( -f $config ) { + fatal("config file '$config' already exists, not initialising issues"); + } + + # try to create the issues/ dir + unless ( mkdir $issues_dir ) { + fatal("Couldn't create '$issues_dir' directory: $!"); + } + + # create a .cil file here also + unless ( touch $config ) { + rmdir $issues_dir; + fatal("couldn't create a '$config' file"); + } + + # add a README.txt so people know what this is about + unless ( -f "$issues_dir/README.txt" ) { + write_file("issues_dir/README.txt", <get_issues(); + if ( @$issues ) { + foreach my $issue ( sort { $a->Inserted cmp $b->Inserted } @$issues ) { + separator(); + display_issue_headers($cil, $issue); + } + separator(); + } + else { + msg('no issues found'); + } +} + +sub cmd_summary { + my ($cil) = @_; + + check_paths($cil); + + # find all the issues + my $issues = $cil->get_issues(); + if ( @$issues ) { + separator(); + foreach my $issue ( @$issues ) { + display_issue_summary($cil, $issue); + } + separator(); + } + else { + msg('no issues found'); + } +} + +sub cmd_show { + my ($cil, undef, $issue_name) = @_; + + # firstly, read the issue in + my $issue = CIL::Issue->new_from_name($cil, $issue_name); + unless ( defined $issue ) { + fatal("Couldn't load issue '$issue_name'"); + } + display_issue_full($cil, $issue); +} + +sub cmd_status { + my ($cil, undef, $issue_name, $status) = @_; + + unless ( defined $status ) { + fatal("provide a status to set this issue to"); + } + + # firstly, read the issue in + my $issue = CIL::Issue->new_from_name($cil, $issue_name); + unless ( defined $issue ) { + fatal("Couldn't load issue '$issue_name'"); + } + + # set the status for this issue + $issue->Status( $status ); + $issue->save($cil); + + display_issue($cil, $issue); +} + +sub cmd_add { + my ($cil, undef, $issue_name) = @_; + + # read in the new issue text + CIL::Utils->ensure_interactive(); + my $fh = CIL::Utils->solicit( $new_issue_text ); + + my $issue = CIL::Issue->new_from_fh( 'tmp', $fh ); + + # we've got the issue, so let's name it + my $unique_str = $issue->Inserted . $issue->Summary . $issue->Description; + $issue->set_name( substr(md5_hex($unique_str), 0, 8) ); + $issue->save($cil); + display_issue($cil, $issue); +} + +sub cmd_edit { + my ($cil, undef, $issue_name) = @_; + + my $issue = CIL::Issue->new_from_name($cil, $issue_name); + unless ( defined $issue ) { + fatal("Couldn't load issue '$issue_name'"); + } + + # create the ini file, then edit it + my $edit_issue_text = $issue->as_output; + + # read in the new issue text + CIL::Utils->ensure_interactive(); + my $fh = CIL::Utils->solicit( join('', @$edit_issue_text) ); + + my $issue_edited = CIL::Issue->new_from_fh( $issue->name, $fh ); + unless ( defined $issue_edited ) { + fatal("couldn't create issue (program error)"); + } + + $issue_edited->save($cil); + display_issue($cil, $issue_edited); +} + +sub cmd_comment { + my ($cil, undef, $issue_name) = @_; + + my $issue = CIL::Issue->new_from_name($cil, $issue_name); + unless ( defined $issue ) { + fatal("couldn't load issue '$issue_name'"); + } + + # read in the new issue text + CIL::Utils->ensure_interactive(); + my $fh = CIL::Utils->solicit( $add_comment_text ); + + my $comment = CIL::Comment->new_from_fh( 'tmp', $fh ); + unless ( defined $comment ) { + fatal("could not create new comment"); + } + + # we've got the comment, so let's name it + my $unique_str = $comment->Inserted . $issue->Description; + $comment->set_name( substr(md5_hex($unique_str), 0, 8) ); + + # finally, tell it who it's parent is and then save + $comment->Issue( $issue->name ); + $comment->save($cil); + + # add the comment to the issue, update it's timestamp and save it out + $issue->add_comment( $comment ); + $issue->save($cil); + display_issue_full($cil, $issue); +} + +sub cmd_attach { + my ($cil, undef, $issue_name, $filename) = @_; + + my $issue = CIL::Issue->new_from_name($cil, $issue_name); + unless ( defined $issue ) { + fatal("couldn't load issue '$issue_name'"); + } + + # check to see if the file exists + unless ( -r $filename ) { + fatal("couldn't read file '$filename'"); + } + + my $basename = basename( $filename ); + + my $add_attachment_text = <<"EOF"; +Filename : $basename +CreatedBy : $gan <$gae> + +File goes here ... this will be overwritten. +EOF + + # read in the new issue text + CIL::Utils->ensure_interactive(); + my $fh = CIL::Utils->solicit( $add_attachment_text ); + + my $attachment = CIL::Attachment->new_from_fh( 'tmp', $fh ); + unless ( defined $attachment ) { + fatal("could not create new attachment"); + } + + # now add the file itself + my $contents = read_file( $filename ); + $attachment->set_file_contents( $contents ); + + # set the size + my ($size) = (stat($filename))[7]; + $attachment->Size( $size ); + + # we've got the attachment, so let's name it + my $unique_str = $attachment->Inserted . $attachment->File; + $attachment->set_name( substr(md5_hex($unique_str), 0, 8) ); + + # finally, tell it who it's parent is and then save + $attachment->Issue( $issue->name ); + $attachment->save($cil); + + # add the comment to the issue, update it's timestamp and save it out + $issue->add_attachment( $attachment ); + $issue->save($cil); + display_issue_full($cil, $issue); +} + +sub cmd_extract { + my ($cil, undef, $attachment_name, $args) = @_; + + my $attachment = CIL::Attachment->new_from_name($cil, $attachment_name); + unless ( defined $attachment ) { + fatal("Couldn't load attachment '$attachment_name'"); + } + + my $filename = $args->{f} || $attachment->Filename(); + write_file( $filename, $attachment->as_binary ); +} + +## ---------------------------------------------------------------------------- + +sub check_paths { + my ($cil) = @_; + + # make sure an issue directory is available + unless ( -d $cil->issue_dir ) { + fatal("couldn't find '" . $cil->issue_dir . "' directory"); + } +} + +## ---------------------------------------------------------------------------- +# input/output + +sub display_issue_summary { + my ($cil, $issue) = @_; + + my $msg = $issue->name(); + $msg .= "\t"; + $msg .= $issue->Status(); + $msg .= "\t"; + $msg .= $issue->Summary(); + + msg($msg); +} + +sub display_issue_headers { + my ($cil, $issue) = @_; + + title( 'Issue ' . $issue->name() ); + field( 'Summary', $issue->Summary() ); + field( 'CreatedBy', $issue->CreatedBy() ); + field( 'AssignedTo', $issue->AssignedTo() ); + field( 'Inserted', $issue->Inserted() ); + field( 'Status', $issue->Status() ); + field( 'Labels', join(' ', @{$issue->Label()}) ); +} + +sub display_issue { + my ($cil, $issue) = @_; + + separator(); + title( 'Issue ' . $issue->name() ); + field( 'Summary', $issue->Summary() ); + field( 'Status', $issue->Status() ); + field( 'CreatedBy', $issue->CreatedBy() ); + field( 'AssignedTo', $issue->AssignedTo() ); + field( 'Label', $_ ) + foreach sort @{$issue->Label()}; + field( 'Comment', $_ ) + foreach sort @{$issue->Comment()}; + field( 'Attachment', $_ ) + foreach sort @{$issue->Attachment()}; + field( 'Inserted', $issue->Inserted() ); + field( 'Updated', $issue->Inserted() ); + text('Description', $issue->Description()); + separator(); +} + +sub display_issue_full { + my ($cil, $issue) = @_; + + separator(); + title( 'Issue ' . $issue->name() ); + field( 'Summary', $issue->Summary() ); + field( 'Status', $issue->Status() ); + field( 'CreatedBy', $issue->CreatedBy() ); + field( 'AssignedTo', $issue->AssignedTo() ); + field( 'Label', $_ ) + foreach sort @{$issue->Label()}; + field( 'Inserted', $issue->Inserted() ); + field( 'Updated', $issue->Inserted() ); + text('Description', $issue->Description()); + + my $comments = $cil->get_comments_for( $issue ); + foreach my $comment ( @$comments ) { + title( 'Comment ' . $comment->name() ); + field( 'CreatedBy', $comment->CreatedBy() ); + field( 'Inserted', $comment->Inserted() ); + field( 'Updated', $comment->Inserted() ); + text('Description', $comment->Description()); + } + + my $attachments = $cil->get_attachments_for( $issue ); + foreach my $attachment ( @$attachments ) { + title( 'Attachment ' . $attachment->name() ); + field( 'Filename', $attachment->Filename() ); + field( 'CreatedBy', $attachment->CreatedBy() ); + field( 'Inserted', $attachment->Inserted() ); + field( 'Updated', $attachment->Inserted() ); + msg(); + } + + separator(); +} + +## ---------------------------------------------------------------------------- +# helper functions for this command line tool + +sub get_options { + my ($in_opts, $booleans) = @_; + + my $args = {}; + Getopt::Mixed::init( @$in_opts ); + while( my($opt, $val) = nextOption() ) { + # if boolean, keep a count of how many there is only + if ( exists $booleans->{$opt} ) { + $args->{$opt}++; + next; + } + # normal 'string' value + if ( defined $args->{$opt} ) { + unless ( ref $args->{$opt} eq 'ARRAY' ) { + $args->{$opt} = [ $args->{$opt} ]; + } + push @{$args->{$opt}}, $val; + } + else { + $args->{$opt} = $val; + } + } + Getopt::Mixed::cleanup(); + return $args; +} + +sub msg { + print ( defined $_[0] ? $_[0] : '' ); + print "\n"; +} + +sub separator { + msg('=' x 79); +} + +sub title { + my ($title) = @_; + my $msg = "--- $title "; + $msg .= '-' x (74 - length($title)); + msg($msg); +} + +sub field { + my ($field, $value) = @_; + my $msg = "$field"; + $msg .= " " x (12 - length($field)); + msg("$msg: " . (defined $value ? $value : '') ); +} + +sub text { + my ($field, $value) = @_; + msg ""; + msg($value); + msg ""; +} + +sub err { + print STDERR ( defined $_[0] ? $_[0] : '' ); + print STDERR "\n"; +} + +sub fatal { + my ($msg) = @_; + chomp $msg; + print STDERR $msg, "\n"; + exit 2; +} + +## ---------------------------------------------------------------------------- +# program info + +sub usage { + print <<"END_USAGE"; +Usage: $0 COMMAND [options] + +Commands: + init [--path=PATH] + add + summary + list + show ISSUE + status ISSUE NEW_STATUS + edit ISSUE + comment ISSUE + attach ISSUE FILENAME + extract ATTACHMENT [--filename=FILENAME] + +See for further information. +Report bugs to . +END_USAGE +} + +## ---------------------------------------------------------------------------- + +=head1 NAME + +cil - the command-line issue list + +=head1 SYNOPSIS + + $ cil init + $ cil summary + $ cil list + + $ cil add + ... added issue 'cafebabe' ... + $ cil show cafebabe + $ cil edit cafebabe + $ cil status cafebabe InProgress + + $ cil comment cafebabe + ... added comment 'deadbeef' ... + + $ cil attach cafebabe filename.txt + ... added attachment 'decaf7ea' ... + + $ cil extract decaf7ea + $ cil extract decaf7ea --filename=other_filename.txt + +=head1 DESCRIPTION + +Cil is a small but useful command-line issue list. It saves issues, comments +and attachments as local files which you can check in to your repository. + +=over + +=item init [--path=PATH] + +Creates a local '.cil' file and an 'issues' directory. If PATH is specified, +the config file and directory will be created in the destination directory. + +=item summary + +Displays a one line summary for each issue. + +=item list + +Shows each issue with more information. + +=item add + +Adds an issues after you have edited the input. + +=item show ISSUE + +Shows the issue name with more detail. + +=item status ISSUE NEW_STATUS + +Shortcut so that you can set a new status on an issue without having to edit +it. + +=item edit ISSUE + +Edits the issue. If it changes, set the updates time to now. + +=item comment ISSUE + +Adds a comment to an issues after you have edited the input. + +=item attach ISSUE FILENAME + +Adds that particular filename to an existing issue. + +=item extract ATTACHMENT [--filename=FILENAME] + +Extracts the file from the attachment number. If filename if given uses that, +otherwise it will use the original one saved along with the attachment. + +=back + +=head1 BUGS + +Probably. Let me know :-) + +=head1 TODO + +There is a number of things to do. High on the list are: + +* the ability to set Statuses from the command line + +* set where you want your issues (from a .cil file) + +* simple search first, proper search and indexing second + +=head1 AUTHOR + +Andrew Chilton + +=head1 COPYRIGHT + +Copyright (C) 2008 by Andrew Chilton + +Cil 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 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 General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see or write to the Free +Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. + +=cut +## ---------------------------------------------------------------------------- diff --git a/debian-etch/.gitignore b/debian-etch/.gitignore new file mode 100644 index 0000000..5aeeab2 --- /dev/null +++ b/debian-etch/.gitignore @@ -0,0 +1,3 @@ +/files +/cil +*.substvars diff --git a/debian-etch/changelog b/debian-etch/changelog new file mode 100644 index 0000000..f42576f --- /dev/null +++ b/debian-etch/changelog @@ -0,0 +1,17 @@ +cil (0.2.1) unstable; urgency=low + + * Ready for 0.2.1 release + + -- Andrew Chilton Mon, 23 Jun 2008 22:32:18 +1200 + +cil (0.2.0) unstable; urgency=low + + * Ready for 0.2 release + + -- Andrew Chilton Sun, 22 Jun 2008 16:17:18 +1200 + +cil (0.1.0) unstable; urgency=low + + * Ready for 0.1 release + + -- Andrew Chilton Sun, 04 May 2008 16:17:17 +1200 diff --git a/debian-etch/compat b/debian-etch/compat new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/debian-etch/compat @@ -0,0 +1 @@ +5 diff --git a/debian-etch/control b/debian-etch/control new file mode 100644 index 0000000..ebac134 --- /dev/null +++ b/debian-etch/control @@ -0,0 +1,18 @@ +Source: cil +Section: perl +Priority: optional +Maintainer: Andrew Chilton +Uploaders: Andrew Chilton +Standards-Version: 3.6.1 +Build-Depends: debhelper (>= 5) +Build-Depends-Indep: perl + +Package: cil +Section: perl +Priority: optional +Architecture: all +Depends: ${perl:Depends}, libgetopt-mixed-perl, libfile-touch-perl, libfile-slurp-perl, libclass-accessor-perl, libdatetime-perl +Description: command line issue tracker + 'cil' allows easy command-line creation of an issue tracker. It saves each + issue locally and in plain text. Commands are given such that these issues can + be added, edited and listed easily. diff --git a/debian-etch/copyright b/debian-etch/copyright new file mode 100644 index 0000000..57ddd5f --- /dev/null +++ b/debian-etch/copyright @@ -0,0 +1,25 @@ +This package was debianized by Andrew Chilton on +Sun, 22 Jun 2008 17:48:00 +1200 + +Upstream Author: Andrew Chilton + +Copyright: (C) 2008 Andrew Chilton + +License: + + cil 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 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 General Public License for + more details. + + You should have received a copy of the GNU General Public License along + with this program. If not, see . + +You are free to distribute this software under the terms of the GNU General +Public License. On Debian systems, the complete text of the GNU General Public +License can be found in /usr/share/common-licenses/GPL file. diff --git a/debian-etch/docs b/debian-etch/docs new file mode 100644 index 0000000..e845566 --- /dev/null +++ b/debian-etch/docs @@ -0,0 +1 @@ +README diff --git a/debian-etch/install b/debian-etch/install new file mode 100644 index 0000000..6d9e803 --- /dev/null +++ b/debian-etch/install @@ -0,0 +1,2 @@ +lib/* usr/share/perl5 +bin/cil usr/bin diff --git a/debian-etch/manpages b/debian-etch/manpages new file mode 100644 index 0000000..866347b --- /dev/null +++ b/debian-etch/manpages @@ -0,0 +1 @@ +cil.1 diff --git a/debian-etch/rules b/debian-etch/rules new file mode 100755 index 0000000..b9873e2 --- /dev/null +++ b/debian-etch/rules @@ -0,0 +1,53 @@ +#!/usr/bin/make -f +## ---------------------------------------------------------------------------- + +## ---------------------------------------------------------------------------- +## uncomment this to turn on verbose mode + +# export DH_VERBOSE=1 + +## ---------------------------------------------------------------------------- + +clean: + dh_testdir + dh_testroot + rm -f build-stamp install-stamp + [ ! -f Makefile ] || $(MAKE) clean + rm -f $(CURDIR)/cil.1 + dh_clean + +build: build-stamp +build-stamp: + dh_testdir + [ ! -f Makefile ] || $(MAKE) + echo Doing MAN... + pod2man $(CURDIR)/bin/cil > $(CURDIR)/cil.1 + touch build-stamp + +binary: + dh_testdir + dh_testroot + + dh_install + dh_installdirs + dh_installdocs + dh_installdebconf + dh_installman + dh_installchangelogs + dh_compress + dh_fixperms + dh_installdeb + + dh_perl + + dh_gencontrol + dh_md5sums + dh_builddeb + +binary-arch: + +binary: binary-indep binary-arch + +.PHONY: clean install binary-indep binary-arch binary + +## ---------------------------------------------------------------------------- diff --git a/debian-lenny/.gitignore b/debian-lenny/.gitignore new file mode 100644 index 0000000..5aeeab2 --- /dev/null +++ b/debian-lenny/.gitignore @@ -0,0 +1,3 @@ +/files +/cil +*.substvars diff --git a/debian-lenny/changelog b/debian-lenny/changelog new file mode 100644 index 0000000..f42576f --- /dev/null +++ b/debian-lenny/changelog @@ -0,0 +1,17 @@ +cil (0.2.1) unstable; urgency=low + + * Ready for 0.2.1 release + + -- Andrew Chilton Mon, 23 Jun 2008 22:32:18 +1200 + +cil (0.2.0) unstable; urgency=low + + * Ready for 0.2 release + + -- Andrew Chilton Sun, 22 Jun 2008 16:17:18 +1200 + +cil (0.1.0) unstable; urgency=low + + * Ready for 0.1 release + + -- Andrew Chilton Sun, 04 May 2008 16:17:17 +1200 diff --git a/debian-lenny/compat b/debian-lenny/compat new file mode 100644 index 0000000..7f8f011 --- /dev/null +++ b/debian-lenny/compat @@ -0,0 +1 @@ +7 diff --git a/debian-lenny/control b/debian-lenny/control new file mode 100644 index 0000000..ebac134 --- /dev/null +++ b/debian-lenny/control @@ -0,0 +1,18 @@ +Source: cil +Section: perl +Priority: optional +Maintainer: Andrew Chilton +Uploaders: Andrew Chilton +Standards-Version: 3.6.1 +Build-Depends: debhelper (>= 5) +Build-Depends-Indep: perl + +Package: cil +Section: perl +Priority: optional +Architecture: all +Depends: ${perl:Depends}, libgetopt-mixed-perl, libfile-touch-perl, libfile-slurp-perl, libclass-accessor-perl, libdatetime-perl +Description: command line issue tracker + 'cil' allows easy command-line creation of an issue tracker. It saves each + issue locally and in plain text. Commands are given such that these issues can + be added, edited and listed easily. diff --git a/debian-lenny/copyright b/debian-lenny/copyright new file mode 100644 index 0000000..57ddd5f --- /dev/null +++ b/debian-lenny/copyright @@ -0,0 +1,25 @@ +This package was debianized by Andrew Chilton on +Sun, 22 Jun 2008 17:48:00 +1200 + +Upstream Author: Andrew Chilton + +Copyright: (C) 2008 Andrew Chilton + +License: + + cil 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 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 General Public License for + more details. + + You should have received a copy of the GNU General Public License along + with this program. If not, see . + +You are free to distribute this software under the terms of the GNU General +Public License. On Debian systems, the complete text of the GNU General Public +License can be found in /usr/share/common-licenses/GPL file. diff --git a/debian-lenny/docs b/debian-lenny/docs new file mode 100644 index 0000000..e845566 --- /dev/null +++ b/debian-lenny/docs @@ -0,0 +1 @@ +README diff --git a/debian-lenny/install b/debian-lenny/install new file mode 100644 index 0000000..6d9e803 --- /dev/null +++ b/debian-lenny/install @@ -0,0 +1,2 @@ +lib/* usr/share/perl5 +bin/cil usr/bin diff --git a/debian-lenny/manpages b/debian-lenny/manpages new file mode 100644 index 0000000..866347b --- /dev/null +++ b/debian-lenny/manpages @@ -0,0 +1 @@ +cil.1 diff --git a/debian-lenny/rules b/debian-lenny/rules new file mode 100755 index 0000000..b9873e2 --- /dev/null +++ b/debian-lenny/rules @@ -0,0 +1,53 @@ +#!/usr/bin/make -f +## ---------------------------------------------------------------------------- + +## ---------------------------------------------------------------------------- +## uncomment this to turn on verbose mode + +# export DH_VERBOSE=1 + +## ---------------------------------------------------------------------------- + +clean: + dh_testdir + dh_testroot + rm -f build-stamp install-stamp + [ ! -f Makefile ] || $(MAKE) clean + rm -f $(CURDIR)/cil.1 + dh_clean + +build: build-stamp +build-stamp: + dh_testdir + [ ! -f Makefile ] || $(MAKE) + echo Doing MAN... + pod2man $(CURDIR)/bin/cil > $(CURDIR)/cil.1 + touch build-stamp + +binary: + dh_testdir + dh_testroot + + dh_install + dh_installdirs + dh_installdocs + dh_installdebconf + dh_installman + dh_installchangelogs + dh_compress + dh_fixperms + dh_installdeb + + dh_perl + + dh_gencontrol + dh_md5sums + dh_builddeb + +binary-arch: + +binary: binary-indep binary-arch + +.PHONY: clean install binary-indep binary-arch binary + +## ---------------------------------------------------------------------------- diff --git a/issues/c_2b92ef13.cil b/issues/c_2b92ef13.cil new file mode 100644 index 0000000..ba1f86d --- /dev/null +++ b/issues/c_2b92ef13.cil @@ -0,0 +1,6 @@ +Issue: cbb43db9 +CreatedBy: Andrew Chilton +Inserted: 2008-06-22T03:54:13 +Updated: 2008-06-22T03:54:13 + +This has been now been completed and will be released in cil v0.2. diff --git a/issues/c_792a4acf.cil b/issues/c_792a4acf.cil new file mode 100644 index 0000000..c22f3f4 --- /dev/null +++ b/issues/c_792a4acf.cil @@ -0,0 +1,6 @@ +Issue: fb79b2e8 +CreatedBy: Andrew Chilton +Inserted: 2008-06-22T04:02:46 +Updated: 2008-06-22T04:02:46 + +This has been completed. diff --git a/issues/c_feb65ae7.cil b/issues/c_feb65ae7.cil new file mode 100644 index 0000000..d4e89f3 --- /dev/null +++ b/issues/c_feb65ae7.cil @@ -0,0 +1,9 @@ +Issue: 5c88cb30 +CreatedBy: Andrew Chilton +Inserted: 2008-06-21T10:57:47 +Updated: 2008-06-21T10:57:47 + +Currently I'm adding the ability for each issue name, comment etc to start with +the first 8 hex chars of an MD5 string from the data itself. Therefore, the +main problem with having the epoch and possible duplication goes away. This +issue can then be given a low priority. diff --git a/issues/i_02ee35bd.cil b/issues/i_02ee35bd.cil new file mode 100644 index 0000000..21546ec --- /dev/null +++ b/issues/i_02ee35bd.cil @@ -0,0 +1,16 @@ +Summary: Labels should be allowed to have a 'required' set +Status: New +CreatedBy: Andrew Chilton +AssignedTo: Andrew Chilton +Label: Release-v0.1 +Label: Priority-Medium +Label: Type-Enhancement +Inserted: 2008-05-05T12:53:38 +Updated: 2008-06-21T10:50:05 + +In the .cil config file, there should a field which determines a +'required' set of labels. + +e.g. + +required_labels=against type priority diff --git a/issues/i_5c88cb30.cil b/issues/i_5c88cb30.cil new file mode 100644 index 0000000..003dfdc --- /dev/null +++ b/issues/i_5c88cb30.cil @@ -0,0 +1,31 @@ +Summary: Options for issues names needs to be added +Status: New +CreatedBy: Andrew Chilton +AssignedTo: Andrew Chilton +Label: Milestone-v0.2 +Label: Priority-Low +Label: Release-v0.1 +Label: Type-Enhancement +Comment: feb65ae7 +Inserted: 2008-05-05T12:33:19 +Updated: 2008-06-21T10:57:47 + +When issues are created, they are given the epoch as it's name. +Instead of just using the epoch, the user should be able to configure +the .cil file to use the format of their choice. + +e.g. issue_name_format=[ epoch | inc | iso-8601 ] + +Possible name formats include: + +* an incrementing number + * but if cil goes distributed (which was originally planned), will + this work? + +* ISO 8601 - YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00) + * do we need to have TZD on the end (though obviously this wouldn't + then be ISO 8601) + +* GUID/UUID like 9e28b50a-cba1-4b20-9276-d30ee727b14a + +(and maybe others) diff --git a/issues/i_6baa8555.cil b/issues/i_6baa8555.cil new file mode 100644 index 0000000..5352e93 --- /dev/null +++ b/issues/i_6baa8555.cil @@ -0,0 +1,15 @@ +Summary: Do checking on input fields after adding or editing issue +Status: New +CreatedBy: Andrew Chilton +AssignedTo: Andrew Chilton +Label: Priority-Medium +Label: Release-v0.1 +Label: Type-Enhancement +Inserted: 2008-05-05T12:46:58 +Updated: 2008-06-21T10:59:52 + +For example, if there is a config item in .cil called +'allowed_statuses', all input values in the 'Status' field should be +checked against it. + +This could also be done for Labels too. diff --git a/issues/i_cbb43db9.cil b/issues/i_cbb43db9.cil new file mode 100644 index 0000000..3490199 --- /dev/null +++ b/issues/i_cbb43db9.cil @@ -0,0 +1,14 @@ +Summary: Addition of a 'attach' command +Status: Finished +CreatedBy: Andrew Chilton +AssignedTo: Andrew Chilton +Label: Priority-Medium +Label: Release-v0.1 +Label: Type-Enhancement +Comment: 2b92ef13 +Inserted: 2008-05-05T12:20:28 +Updated: 2008-06-22T03:54:13 + +'cil' currently has no way of adding attachments to issues. + +This should be added so that the actual data cil stores is complete. diff --git a/issues/i_fb79b2e8.cil b/issues/i_fb79b2e8.cil new file mode 100644 index 0000000..b218517 --- /dev/null +++ b/issues/i_fb79b2e8.cil @@ -0,0 +1,16 @@ +Summary: Ability to set Issue Status' from the command line +Status: Finished +CreatedBy: Andrew Chilton +AssignedTo: Andrew Chilton +Label: Mileston-v0.2 +Label: Release-v0.1 +Label: Type-Enhancement +Comment: 792a4acf +Inserted: 2008-06-22T04:00:20 +Updated: 2008-06-22T04:02:46 + +The ability to do something like the following would be good. + + $ cil status cafebabe Finished + +would be rather cool. diff --git a/lib/CIL.pm b/lib/CIL.pm new file mode 100644 index 0000000..b85f2fb --- /dev/null +++ b/lib/CIL.pm @@ -0,0 +1,114 @@ +## ---------------------------------------------------------------------------- +# cil is a Command line Issue List +# Copyright (C) 2008 Andrew Chilton +# +# This file is part of 'cil'. +# +# cil 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 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 General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . +# +## ---------------------------------------------------------------------------- + +package CIL; + +use strict; +use warnings; +use File::Glob qw(:glob); + +use base qw(Class::Accessor); +__PACKAGE__->mk_accessors(qw(issue_dir)); + +my $defaults = { + issue_dir => 'issues', +}; + +## ---------------------------------------------------------------------------- + +sub new { + my ($proto, $cfg) = @_; + + $cfg ||= {}; + + my $class = ref $proto || $proto; + my $self = bless {}, $class; + + # save the settings for various bits of info + foreach my $key ( keys %$defaults ) { + # if we have been passed it in, use it, else use the default + $self->$key( $cfg->{$key} || $defaults->{$key} ); + } + return $self; +} + +sub list_issues { + my ($self) = @_; + + my $globpath = $self->issue_dir . "/i_*.cil"; + my @filenames = bsd_glob($globpath); + + my @issues; + foreach my $filename ( sort @filenames ) { + my ($name) = $filename =~ m{/i_(.*)\.cil$}xms; + push @issues, { + name => $name, + filename => $filename, + }; + } + return \@issues; +} + +sub get_issues { + my ($self) = @_; + + my $issue_list = $self->list_issues(); + + my @issues; + foreach my $issue ( @$issue_list ) { + push @issues, CIL::Issue->new_from_name( $self, $issue->{name} ); + } + return \@issues; +} + +sub get_comments_for { + my ($self, $issue) = @_; + + my @comments; + foreach my $comment_name ( @{$issue->Comments} ) { + my $comment = CIL::Comment->new_from_name( $self, $comment_name ); + push @comments, $comment; + } + + # sort them in cronological order + @comments = sort { $a->Inserted cmp $b->Inserted } @comments; + + return \@comments; +} + +sub get_attachments_for { + my ($self, $issue) = @_; + + my @attachments; + foreach my $attachment_name ( @{$issue->Attachments} ) { + my $attachment = CIL::Attachment->new_from_name( $self, $attachment_name ); + push @attachments, $attachment; + } + + # sort them in cronological order + @attachments = sort { $a->Inserted cmp $b->Inserted } @attachments; + + return \@attachments; +} + +## ---------------------------------------------------------------------------- +1; +## ---------------------------------------------------------------------------- diff --git a/lib/CIL/Attachment.pm b/lib/CIL/Attachment.pm new file mode 100644 index 0000000..337ed1a --- /dev/null +++ b/lib/CIL/Attachment.pm @@ -0,0 +1,98 @@ +## ---------------------------------------------------------------------------- +# cil is a Command line Issue List +# Copyright (C) 2008 Andrew Chilton +# +# This file is part of 'cil'. +# +# cil 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 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 General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . +# +## ---------------------------------------------------------------------------- + +package CIL::Attachment; + +use strict; +use warnings; +use Carp; + +use MIME::Base64; + +use base qw(CIL::Base); + +# fields specific to Attachment +__PACKAGE__->mk_accessors(qw(Issue Filename Size File)); + +# all fields +my @FIELDS = ( qw(Issue Filename Size CreatedBy Inserted Updated File) ); + +## ---------------------------------------------------------------------------- + +sub new { + my ($proto, $name) = @_; + + croak 'please provide an attachment name' + unless defined $name; + + my $class = ref $proto || $proto; + my $self = {}; + bless $self, $class; + + $self->set_name( $name ); + $self->{data} = { + Issue => '', + Filename => '', + Size => '', + CreatedBy => '', + Inserted => '', + Updated => '', + File => '', + }; + $self->{Changed} = 0; + + $self->set_inserted_now; + + return $self; +} + +sub set_file_contents { + my ($self, $contents) = @_; + + # $contents will be binary + $self->{data}{File} = encode_base64( $contents ); +} + +sub as_binary { + my ($self) = @_; + + return decode_base64( $self->{data}{File} ); +} + +sub prefix { + return 'a'; +} + +sub fields { + return \@FIELDS; +} + +sub array_fields { + return {}; +} + +sub last_field { + return 'File'; +} + +## ---------------------------------------------------------------------------- +1; +## ---------------------------------------------------------------------------- diff --git a/lib/CIL/Base.pm b/lib/CIL/Base.pm new file mode 100644 index 0000000..ed5c3a8 --- /dev/null +++ b/lib/CIL/Base.pm @@ -0,0 +1,189 @@ +## ---------------------------------------------------------------------------- +# cil is a Command line Issue List +# Copyright (C) 2008 Andrew Chilton +# +# This file is part of 'cil'. +# +# cil 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 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 General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . +# +## ---------------------------------------------------------------------------- + +package CIL::Base; + +use strict; +use warnings; +use Carp; +use DateTime; + +use base qw(Class::Accessor); +__PACKAGE__->mk_accessors(qw(CreatedBy Inserted Updated)); + +## ---------------------------------------------------------------------------- + +sub new_from_name { + my ($class, $cil, $name) = @_; + + croak 'provide a name' + unless defined $name; + + my $filename = $class->create_filename($cil, $name); + croak "filename '$filename' does no exist" + unless -f $filename; + + my $data = CIL::Utils->parse_cil_file($filename, $class->last_field); + my $issue = $class->new_from_data( $name, $data ); + return $issue; +} + +sub new_from_data { + my ($class, $name, $data) = @_; + + croak 'please provide an issue name' + unless defined $name; + + # ToDo: check we have all the other correct fields + + # create the issue + my $self = $class->new( $name ); + + my $fields = $class->fields(); + my $array_fields = $class->array_fields(); + + # save each field + foreach my $field ( @$fields ) { + next unless defined $data->{$field}; + + # make it an array if it should be one + if ( exists $array_fields->{$field} and ref $data->{$field} ne 'ARRAY' ) { + $data->{$field} = [ $data->{$field} ]; + } + + # modify the data directly, otherwise Updated will kick in + $self->set_no_update($field, $data->{$field}); + } + $self->set_no_update('Changed', 0); + + return $self; +} + +sub new_from_fh { + my ($class, $name, $fh) = @_; + + croak 'please provide name' + unless defined $name; + + my $data = CIL::Utils->parse_from_fh( $fh, $class->last_field ); + return $class->new_from_data( $name, $data ); +} + +sub save { + my ($self, $cil) = @_; + + my $filename = $self->create_filename($cil, $self->name); + + my $fields = $self->fields(); + CIL::Utils->write_cil_file( $filename, $self->{data}, @$fields ); +} + +sub create_filename { + my ($class, $cil, $name) = @_; + + # create the filename from it's parts + my $prefix = $class->prefix(); + my $issue_dir = $cil->issue_dir; + my $filename = "${issue_dir}/${prefix}_${name}.cil"; + + return $filename; +} + +# override Class::Accessor's get +sub get { + my ($self, $field) = @_; + croak "provide a field name" + unless defined $field; + $self->{data}{$field}; +} + +# override Class::Accessor's set +sub set { + my ($self, $field, $value) = @_; + croak "provide a field name" + unless defined $field; + + my $orig = $self->get($field); + + # finish if both are defined and they're the same + if ( defined $orig and defined $value ) { + return if eval { $orig eq $value }; + } + + # finish if neither are defined + return unless ( defined $orig or defined $value ); + + # since we're actually changing the field, say we updated something + $self->{data}{$field} = $value; + $self->set_updated_now; +} + +# so that we can update fields without 'Updated' being changed +sub set_no_update { + my ($self, $field, $value) = @_; + + my $saved_update_time = $self->Updated; + $self->set( $field, $value ); + $self->Updated( $saved_update_time ); +} + +sub set_inserted_now { + my ($self) = @_; + my $time = DateTime->now; + $self->{data}{Inserted} = $time; + $self->{data}{Updated} = $time; + $self->{Changed} = 1; +} + +sub set_updated_now { + my ($self) = @_; + my $time = DateTime->now; + $self->{data}{Updated} = $time; + $self->{Changed} = 1; +} + +sub flag_as_updated { + my ($self) = @_; + $self->{Changed} = 1; +} + +sub changed { + my ($self) = @_; + return $self->{Changed}; +} + +sub set_name { + my ($self, $name) = @_; + + croak 'provide a name' + unless defined $name; + + $self->{name} = $name; +} + +sub name { + my ($self) = @_; + return $self->{name}; +} + +## ---------------------------------------------------------------------------- +1; +## ---------------------------------------------------------------------------- diff --git a/lib/CIL/Comment.pm b/lib/CIL/Comment.pm new file mode 100644 index 0000000..9d0398c --- /dev/null +++ b/lib/CIL/Comment.pm @@ -0,0 +1,80 @@ +## ---------------------------------------------------------------------------- +# cil is a Command line Issue List +# Copyright (C) 2008 Andrew Chilton +# +# This file is part of 'cil'. +# +# cil 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 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 General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . +# +## ---------------------------------------------------------------------------- + +package CIL::Comment; + +use strict; +use warnings; +use Carp; + +use base qw(CIL::Base); + +# fields specific to Comment +__PACKAGE__->mk_accessors(qw(Issue Description)); + +my @FIELDS = ( qw(Issue CreatedBy Inserted Updated Description) ); + +## ---------------------------------------------------------------------------- + +sub new { + my ($proto, $name) = @_; + + croak 'please provide a comment name' + unless defined $name; + + my $class = ref $proto || $proto; + my $self = {}; + bless $self, $class; + + $self->set_name( $name ); + $self->{data} = { + Issue => '', + CreatedBy => '', + Inserted => '', + Updated => '', + Description => '', + }; + $self->{Changed} = 0; + + $self->set_inserted_now; + + return $self; +} + +sub prefix { + return 'c'; +} + +sub fields { + return \@FIELDS; +} + +sub array_fields { + return {}; +} + +sub last_field { + return 'Description'; +} + +## ---------------------------------------------------------------------------- +1; +## ---------------------------------------------------------------------------- diff --git a/lib/CIL/Issue.pm b/lib/CIL/Issue.pm new file mode 100644 index 0000000..0dfaf53 --- /dev/null +++ b/lib/CIL/Issue.pm @@ -0,0 +1,144 @@ +## ---------------------------------------------------------------------------- +# cil is a Command line Issue List +# Copyright (C) 2008 Andrew Chilton +# +# This file is part of 'cil'. +# +# cil 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 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 General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . +# +## ---------------------------------------------------------------------------- + +package CIL::Issue; + +use strict; +use warnings; +use Carp; + +use CIL; +use CIL::Utils; + +use base qw(CIL::Base); + +# fields specific to Issue +__PACKAGE__->mk_accessors(qw(Summary Status AssignedTo Label Comment Attachment Description)); + +my @FIELDS = ( qw(Summary Status CreatedBy AssignedTo Label Comment Attachment Inserted Updated Description) ); +my $cfg = { + array => { + Label => 1, + Comment => 1, + Attachment => 1, + }, +}; + +## ---------------------------------------------------------------------------- + +sub new { + my ($proto, $name) = @_; + + croak 'please provide an issue name' + unless defined $name; + + my $class = ref $proto || $proto; + my $self = {}; + bless $self, $class; + + $self->set_name( $name ); + $self->{data} = { + Summary => '', + Status => '', + CreatedBy => '', + AssignedTo => '', + Inserted => '', + Updated => '', + Label => [], + Comment => [], + Attachment => [], + Description => '', + }; + $self->{Changed} = 0; + + $self->set_inserted_now; + + return $self; +} + +sub prefix { + return 'i'; +} + +sub fields { + return \@FIELDS; +} + +sub array_fields { + return $cfg->{array}; +} + +sub last_field { + return 'Description'; +} + +sub add_label { + my ($self, $label) = @_; + + croak 'provide a label when adding one' + unless defined $label; + + push @{$self->{data}{Label}}, $label; + $self->flag_as_updated(); +} + +sub add_comment { + my ($self, $comment) = @_; + + croak "can only add comments of type CIL::Comment" + unless $comment->isa( 'CIL::Comment' ); + + # add the comment name and set this issue's updated time + push @{$self->{data}{Comment}}, $comment->name; + $self->Updated( $comment->Updated ); + $self->flag_as_updated(); +} + +sub add_attachment { + my ($self, $attachment) = @_; + + croak "can only add attachments of type CIL::Attachment" + unless $attachment->isa( 'CIL::Attachment' ); + + # add the attachment name and set this issue's updated time + push @{$self->{data}{Attachment}}, $attachment->name; + $self->Updated( $attachment->Updated ); + $self->flag_as_updated(); +} + +sub as_output { + my ($self) = @_; + return CIL::Utils->format_data_as_output( $self->{data}, @FIELDS ); +} + +sub Comments { + my ($self) = @_; + return $self->{data}{Comment}; +} + +sub Attachments { + my ($self) = @_; + return $self->{data}{Attachment}; +} + +## ---------------------------------------------------------------------------- +1; +## ---------------------------------------------------------------------------- diff --git a/lib/CIL/Utils.pm b/lib/CIL/Utils.pm new file mode 100644 index 0000000..a0e165c --- /dev/null +++ b/lib/CIL/Utils.pm @@ -0,0 +1,184 @@ +## ---------------------------------------------------------------------------- +# cil is a Command line Issue List +# Copyright (C) 2008 Andrew Chilton +# +# This file is part of 'cil'. +# +# cil 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 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 General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . +# +## ---------------------------------------------------------------------------- + +package CIL::Utils; + +use strict; +use warnings; +use Carp; +use File::Slurp; +use File::Temp qw(tempfile); +use POSIX qw(getpgrp tcgetpgrp); +use Fcntl qw(:DEFAULT :flock); + +## ---------------------------------------------------------------------------- +# setup some globals + +my $editor = $ENV{EDITOR} || 'vi'; + +## ---------------------------------------------------------------------------- + +sub parse_cil_file { + my ($class, $filename, $last_field) = @_; + + my @lines = read_file($filename); + return unless @lines; + + return $class->parse_from_lines( $last_field, @lines ); +} + +sub parse_from_fh { + my ($class, $fh, $last_field) = @_; + + my @lines = <$fh>; + return unless @lines; + + return $class->parse_from_lines( $last_field, @lines ); +} + +sub parse_from_lines { + my ($class, $last_field, @lines) = @_; + return unless @lines; + chomp @lines; + + my $data = {}; + + # read all the initial fields + while ( my $line = shift @lines ) { + my ($key, $value) = split(/\s*:\s*/, $line, 2); + + if ( defined $data->{$key} ) { + unless ( ref $data->{$key} eq 'ARRAY' ) { + $data->{$key} = [ $data->{$key} ]; + }; + push @{$data->{$key}}, $value; + } + else { + $data->{$key} = $value; + } + } + + # now read everything that's left into the $last_field field + $data->{$last_field} = join("\n", @lines); + + return $data; +} + +sub format_data_as_output { + my ($class, $data, @fields) = @_; + + # we format the last field differently, so pop it off now + my $last_field = pop @fields; + + my @lines; + foreach my $field ( @fields ) { + next if $field eq $last_field; + + if ( ref $data->{$field} eq 'ARRAY' ) { + # don't output this field if there is nothing in it + next unless @{$data->{$field}}; + + foreach ( sort @{$data->{$field}} ) { + push @lines, "$field: $_\n"; + } + } + else { + push @lines, "$field: $data->{$field}\n"; + } + } + + # finally, output the last field on it's own + push @lines, "\n"; + push @lines, $data->{$last_field}, "\n"; + + return \@lines; +} + +sub write_cil_file { + my ($class, $filename, $data, @fields) = @_; + + # get the output format + my $lines = $class->format_data_as_output($data, @fields); + + # ... and save + write_file($filename, $lines); +} + +# this method based on Term::CallEditor(v0.11)'s solicit method +# original: Copyright 2004 by Jeremy Mates +# copied under the terms of the GPL +sub solicit { + my ($class, $message) = @_; + + # when calling this, assume we're already interactive + + File::Temp->safe_level(File::Temp::HIGH); + my ( $fh, $filename ) = tempfile( UNLINK => 1 ); + + # since File::Temp returns both, check both + unless ( $fh and $filename ) { + croak "couldn't create temporary file"; + } + + select( ( select($fh), $|++ )[0] ); + print $fh $message; + + # need to unlock for external editor + flock $fh, LOCK_UN; + + # run the editor + my $status = system($editor, $filename); + + # check its return value + if ( $status != 0 ) { + croak $status != -1 + ? "external editor ($editor) failed: $?" + : "could not launch ($editor) program: $!"; + } + + unless ( seek $fh, 0, 0 ) { + croak "could not seek on temp file: errno=$!"; + } + + return $fh; +} + +# this method based on Recipe 15.2 +sub ensure_interactive { + my $tty; + open($tty, "/dev/tty") + or croak "program not running interactively (can't open /dev/tty): $!"; + + my $tpgrp = tcgetpgrp( fileno($tty) ); + my $pgrp = getpgrp(); + close $tty; + + unless ( $tpgrp == $pgrp ) { + croak "can't get exclusive control of tty: tpgrp=$tpgrp, pgrp=$pgrp"; + } + + # if we are here, then we have ensured what we wanted + return; +} + +## ---------------------------------------------------------------------------- +1; +## ---------------------------------------------------------------------------- diff --git a/t/00_files.t b/t/00_files.t new file mode 100644 index 0000000..b000c56 --- /dev/null +++ b/t/00_files.t @@ -0,0 +1,33 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Test::More qw(no_plan); +use Data::Dumper; +use CIL::Utils; + +my $parsed_fields = CIL::Utils->parse_cil_file( 't/i_cafebabe.cil', 'Description' ); + +my $correct_fields = { + 'Summary' => 'Addition of a \'attach\' command', + 'Status' => 'New', + 'CreatedBy' => 'A N Other ', + 'AssignedTo' => 'A Name ', + 'Label' => [ + 'against-v0.1', + 'priority-medium', + 'type-enhancement', + ], + 'Inserted' => '2008-06-15 18:22:01', + 'Updated' => '2008-06-15 23:15:27', + 'Description' => '\'cil\' currently has no way of adding attachments to issues. + +This should be added so that the actual data cil stores is complete.' +}; + +is_deeply($parsed_fields, $correct_fields, 'Check parsing of file'); + +CIL::Utils->write_cil_file( '/tmp/i_deadbeef.cil', $correct_fields, qw(Summary Status CreatedBy AssignedTo Label Inserted Updated Description) ); +CIL::Utils->write_cil_file( '/tmp/i_decaf7ea.cil', $parsed_fields, qw(Summary Status CreatedBy AssignedTo Label Inserted Updated Description) ); + +# is($parsed_fields, $correct_fields, 'Check parsing of file'); diff --git a/t/i_cafebabe.cil b/t/i_cafebabe.cil new file mode 100644 index 0000000..04aeb0c --- /dev/null +++ b/t/i_cafebabe.cil @@ -0,0 +1,13 @@ +Summary: Addition of a 'attach' command +Status: New +CreatedBy: A N Other +AssignedTo: A Name +Label: against-v0.1 +Label: priority-medium +Label: type-enhancement +Inserted: 2008-06-15 18:22:01 +Updated: 2008-06-15 23:15:27 + +'cil' currently has no way of adding attachments to issues. + +This should be added so that the actual data cil stores is complete. -- cgit v1.2.3