From e0a915144a40619b8f1ebb83baebbfbec6c7ca58 Mon Sep 17 00:00:00 2001 From: Michal Date: Tue, 19 Jul 2022 22:12:33 +0100 Subject: [PATCH 001/116] Fixed strange .gitignore --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index c3ab214..442db94 100755 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ /target .idea -/pkg -*tar* \ No newline at end of file +.direnv \ No newline at end of file From 345deb09d8f3d20f5ba65ff8d75a1acf3cb8ef83 Mon Sep 17 00:00:00 2001 From: Michal Date: Tue, 19 Jul 2022 22:14:18 +0100 Subject: [PATCH 002/116] Ver bump in PKGBUILD --- .envrc | 1 + PKGBUILD | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 .envrc diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/PKGBUILD b/PKGBUILD index 62d6701..bcfce0f 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -1,7 +1,7 @@ # Maintainer: Matt C pkgname=malachite -pkgver=1.3.0 +pkgver=1.4.0 pkgrel=1 pkgdesc="Tool for packaging and maintaining pacman repositories" license=('GPL3') From 6996a693d0b6d8e9d323f0fcd0b19dc0ad425fc1 Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Jul 2022 00:02:50 +0100 Subject: [PATCH 003/116] Macro-ized info and crash, AppExitCode Struct, libc crate call --- Cargo.lock | 35 +- Cargo.toml | 10 +- License | 674 ------------------------------------- src/internal/exit_codes.rs | 9 + src/internal/mod.rs | 5 +- src/internal/strings.rs | 31 +- src/main.rs | 21 +- src/operations/build.rs | 17 +- src/operations/init.rs | 11 +- src/operations/prune.rs | 7 +- src/operations/pull.rs | 2 +- src/repository/config.rs | 6 +- src/repository/package.rs | 3 +- src/workspace/read.rs | 3 +- 14 files changed, 99 insertions(+), 735 deletions(-) delete mode 100644 License create mode 100644 src/internal/exit_codes.rs diff --git a/Cargo.lock b/Cargo.lock index 86dc152..27f6b08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,6 +7,8 @@ name = "Malachite" version = "1.3.0" dependencies = [ "clap", + "colored", + "libc", "mimalloc", "serde", "serde_derive", @@ -44,9 +46,9 @@ checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" [[package]] name = "clap" -version = "3.2.3" +version = "3.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df386a2d0f35bdefc0642fd8bcb2cd28243959f028abfd22fbade6f7d30980e" +checksum = "ac2bd7a1eb07da9ac757c923f69373deb7bc2ba5efc951b873bcb5e693992dca" dependencies = [ "atty", "bitflags", @@ -61,9 +63,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "3.2.3" +version = "3.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b740354ad9fcf20e27b46d921be4bb3712f5b3c2c7a89ba68a72a8e51d3a47f" +checksum = "759bf187376e1afa7b85b959e6a664a3e7a95203415dba952ad19139e798f902" dependencies = [ "heck", "proc-macro-error", @@ -81,6 +83,17 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + [[package]] name = "hashbrown" version = "0.11.2" @@ -112,6 +125,12 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.126" @@ -192,15 +211,15 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.137" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" [[package]] name = "serde_derive" -version = "1.0.137" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 61789d1..c997b52 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "1.3.0" authors = [ "michal " ] edition = "2021" description = "Packaging tool for pacman repositories" -license-file = "LICENSE.md" +license-file = "LICENSE" [[bin]] name = "mlc" @@ -18,7 +18,9 @@ codegen-units = 1 [dependencies] mimalloc = { version = "0.1.29" } -clap = { version = "3.2.1", features = ["derive", "suggestions"] } +clap = { version = "3.2.8", features = ["derive", "suggestions"] } toml = { version = "0.5.9", default-features = false } -serde = { version = "1.0.137", default-features = false } -serde_derive = { version = "1.0.137", default-features = false } +serde = { version = "1.0.139", default-features = false } +serde_derive = { version = "1.0.139", default-features = false } +libc = { version = "0.2.126", default-features = false } +colored = { version = "2.0.0", default-features = false } \ No newline at end of file diff --git a/License b/License deleted file mode 100644 index f288702..0000000 --- a/License +++ /dev/null @@ -1,674 +0,0 @@ - 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/src/internal/exit_codes.rs b/src/internal/exit_codes.rs new file mode 100644 index 0000000..b916295 --- /dev/null +++ b/src/internal/exit_codes.rs @@ -0,0 +1,9 @@ +pub enum AppExitCode { + RunAsRoot = 1, + BuildInWorkspace = 2, + PkgNotFound = 3, + InvalidMode = 4, + DirNotEmpty = 5, + DirNotGit = 6, + ConfigNotFound = 7, +} \ No newline at end of file diff --git a/src/internal/mod.rs b/src/internal/mod.rs index fbf1f31..58cbc53 100755 --- a/src/internal/mod.rs +++ b/src/internal/mod.rs @@ -1,4 +1,5 @@ -mod strings; +mod exit_codes; pub mod structs; +pub mod strings; -pub use strings::*; +pub use exit_codes::*; \ No newline at end of file diff --git a/src/internal/strings.rs b/src/internal/strings.rs index 3ce7f52..0833858 100755 --- a/src/internal/strings.rs +++ b/src/internal/strings.rs @@ -1,10 +1,31 @@ use std::process::exit; +use crate::internal::AppExitCode; +use colored::*; -pub fn info(a: String) { - println!("\x1b[2;22;30mμ\x1b[0m \x1b[1;37m{}\x1b[0m", a); +const LOGO_SYMBOL: &str = "μ"; +const ERR_SYMBOL: &str = "❌"; + +#[macro_export] +macro_rules! info { + ($($arg:tt)+) => { + $crate::internal::strings::info_fn(format!($($arg)+)) + } +} + +#[macro_export] +macro_rules! crash { + ($exit_code:expr, $($arg:tt)+) => { + $crate::internal::strings::crash_fn(format!($($arg)+), $exit_code) + } +} + +pub fn info_fn(msg: S) { + let msg = msg.to_string(); + println!("{} {}", LOGO_SYMBOL.black(), msg.bold()) } -pub fn crash(a: String, b: i32) { - println!("\x1b[2;22;31m❌:\x1b[0m \x1b[1;91m{}\x1b[0m", a); - exit(b); +pub fn crash_fn(msg: S, exit_code: AppExitCode) { + let msg = msg.to_string(); + println!("{} {}", ERR_SYMBOL.red(), msg.bold()); + exit(exit_code as i32); } diff --git a/src/main.rs b/src/main.rs index 2249831..564c505 100755 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,7 @@ use std::path::Path; use std::process::Command; use crate::args::{Args, Operation}; -use crate::internal::{crash, info}; +use crate::internal::AppExitCode; use crate::repository::create_config; use clap::Parser; @@ -19,21 +19,14 @@ mod repository; mod workspace; fn main() { - extern "C" { - fn geteuid() -> u32; - } - - if unsafe { geteuid() } == 0 { - crash("Running malachite as root is disallowed as it can lead to system breakage. Instead, malachite will prompt you when it needs superuser permissions".to_string(), 1); + if unsafe { libc::geteuid() } == 0 { + crash!(AppExitCode::RunAsRoot, "Running malachite as root is disallowed as it can lead to system breakage. Instead, malachite will prompt you when it needs superuser permissions"); } let args: Args = Args::parse(); if Path::exists("mlc.toml".as_ref()) && Path::exists(".git".as_ref()) { - info( - "In a git repository, pulling latest mlc.toml. It is advised you run mlc pull/update" - .to_string(), - ); + info!("In a git repository, pulling latest mlc.toml. It is advised you run mlc pull/update"); Command::new("git") .arg("pull") .spawn() @@ -43,7 +36,7 @@ fn main() { } if Path::exists("../.git".as_ref()) { - info("Parent directory is a git directory, pulling latest mlc.toml. It is advised you run mlc pull/update in all malachite directories".to_string()); + info!("Parent directory is a git directory, pulling latest mlc.toml. It is advised you run mlc pull/update in all malachite directories"); let dir = env::current_dir().unwrap(); env::set_current_dir("../").unwrap(); Command::new("git") @@ -69,9 +62,9 @@ fn main() { Operation::RepoGen => { let config = read_cfg(); if config.mode != "repository" { - panic!("Cannot build packages in workspace mode") + crash!(AppExitCode::BuildInWorkspace, "Cannot build packages in workspace mode") } - info(format!("Generating repository: {}", config.name.unwrap())); + info!("Generating repository: {}", config.name.unwrap()); repository::generate(); } Operation::Prune => operations::prune(), diff --git a/src/operations/build.rs b/src/operations/build.rs index 18c4bda..3ab7c65 100644 --- a/src/operations/build.rs +++ b/src/operations/build.rs @@ -1,19 +1,12 @@ use crate::repository::generate; use crate::{crash, info, repository, workspace}; +use crate::internal::AppExitCode; -pub fn build(mut packages: Vec, exclude: Vec, no_regen: bool) { +pub fn build(packages: Vec, exclude: Vec, no_regen: bool) { let all = packages.is_empty(); let config = workspace::read_cfg(); - for pkg in &exclude { - packages.retain(|x| x != pkg); - } - - if config.mode != "repository" { - crash("Cannot build packages in workspace mode".to_string(), 2); - } - let mut repos: Vec = vec![]; for r in config.repo { let split = r.split('/').collect::>(); @@ -31,7 +24,7 @@ pub fn build(mut packages: Vec, exclude: Vec, no_regen: bool) { for pkg in packages { if !repos.contains(&pkg) { - crash(format!("Package {} not found in repos in mlc.toml", pkg), 3); + crash!(AppExitCode::PkgNotFound, "Package {} not found in repos in mlc.toml", pkg); } else { let code = repository::build(&pkg); if code != 0 { @@ -55,9 +48,9 @@ pub fn build(mut packages: Vec, exclude: Vec, no_regen: bool) { } if !errored.is_empty() { - info(format!( + info!( "The following packages build jobs returned a non-zero exit code: {}", errored.join(" ") - )) + ) } } diff --git a/src/operations/init.rs b/src/operations/init.rs index 496d316..0d1c2ec 100644 --- a/src/operations/init.rs +++ b/src/operations/init.rs @@ -1,4 +1,5 @@ use crate::{crash, info, workspace}; +use crate::internal::AppExitCode; use std::process::Command; pub fn init() { @@ -33,15 +34,15 @@ pub fn init() { } if diff.is_empty() { - info("All repos are already cloned".to_string()); + info!("All repos are already cloned"); } else { - info(format!("New/missing repos to clone: {}", diff.join(", "))); + info!("New/missing repos to clone: {}", diff.join(", ")); for r in diff_matches { - info(format!( + info!( "Cloning ({} mode): {}", config.mode, r.split('/').last().unwrap() - )); + ); Command::new("git") .args(&["clone", r]) .spawn() @@ -51,6 +52,6 @@ pub fn init() { } } } else { - crash("Invalid mode in mlc.toml".to_string(), 1); + crash!(AppExitCode::InvalidMode, "Invalid mode in mlc.toml"); } } diff --git a/src/operations/prune.rs b/src/operations/prune.rs index b6ca627..287b838 100644 --- a/src/operations/prune.rs +++ b/src/operations/prune.rs @@ -4,9 +4,6 @@ use std::process::Command; pub fn prune() { let config = read_cfg(); - if &config.mode != "repository" { - panic!("Cannot build packages in workspace mode") - } let mut packages = vec![]; for untrimmed_repo in &config.repo { pub fn trim_repo(a: String) -> String { @@ -48,10 +45,10 @@ pub fn prune() { } if !packages_to_del.is_empty() { - info(format!( + info!( "Pruning duplicates: {}", packages_to_del.join(", ") - )); + ); } for pkg in packages_to_del { diff --git a/src/operations/pull.rs b/src/operations/pull.rs index 0cf9387..737f9c4 100644 --- a/src/operations/pull.rs +++ b/src/operations/pull.rs @@ -5,7 +5,7 @@ use std::process::Command; fn do_the_pulling(packages: Vec) { for dir in packages { let current_dir = env::current_dir().unwrap(); - info(format!("Entering working directory: {}", dir)); + info!("Entering working directory: {}", dir); env::set_current_dir(dir).unwrap(); Command::new("git") .arg("pull") diff --git a/src/repository/config.rs b/src/repository/config.rs index c5740c5..8276bf8 100644 --- a/src/repository/config.rs +++ b/src/repository/config.rs @@ -3,6 +3,7 @@ use std::env; use std::fs::File; use std::io::Write; use std::path::Path; +use crate::internal::AppExitCode; const DEFAULT_CONFIG: &str = r#"# either "repository" or "workspace" mode = "" @@ -30,10 +31,9 @@ pub fn create_config() { .next() .is_some() { - crash( + crash!( + AppExitCode::DirNotEmpty, "Directory is not empty, please only create a repository in an empty directory" - .to_string(), - 6, ); } if !Path::exists("mlc.toml".as_ref()) { diff --git a/src/repository/package.rs b/src/repository/package.rs index ef5721a..aa045ab 100755 --- a/src/repository/package.rs +++ b/src/repository/package.rs @@ -2,6 +2,7 @@ use crate::crash; use std::path::Path; use std::process::Command; use std::{env, fs}; +use crate::internal::AppExitCode; pub fn build(pkg: &str) -> i32 { let dir = env::current_dir().unwrap(); @@ -9,7 +10,7 @@ pub fn build(pkg: &str) -> i32 { fs::create_dir_all("out").unwrap(); } if !Path::exists(pkg.as_ref()) { - crash(format!("Git directory for {} not found, aborting", pkg), 4); + crash!(AppExitCode::DirNotGit, "Git directory for {} not found, aborting", pkg); } env::set_current_dir(pkg).unwrap(); diff --git a/src/workspace/read.rs b/src/workspace/read.rs index c1f08e0..7d43c3d 100755 --- a/src/workspace/read.rs +++ b/src/workspace/read.rs @@ -1,12 +1,13 @@ use crate::crash; use std::fs; use std::path::Path; +use crate::internal::AppExitCode; use crate::internal::structs::{Config, SplitRepo, UnexpandedConfig}; pub fn read_cfg() -> Config { if !Path::exists("mlc.toml".as_ref()) { - crash("Config file not found (mlc.toml)".to_string(), 5) + crash!(AppExitCode::ConfigNotFound, "Config file not found (mlc.toml)") } let file = fs::read_to_string("mlc.toml").unwrap(); From 8e66b07fd14733e861ff438016fc7d13ac526ab0 Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Jul 2022 00:03:21 +0100 Subject: [PATCH 004/116] LICENSE + Fmt --- LICENSE | 674 +++++++++++++++++++++++++++++++++++++ src/internal/exit_codes.rs | 2 +- src/internal/mod.rs | 4 +- src/internal/strings.rs | 2 +- src/main.rs | 9 +- src/operations/build.rs | 8 +- src/operations/init.rs | 2 +- src/operations/prune.rs | 5 +- src/repository/config.rs | 2 +- src/repository/package.rs | 8 +- src/workspace/read.rs | 7 +- 11 files changed, 705 insertions(+), 18 deletions(-) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -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/src/internal/exit_codes.rs b/src/internal/exit_codes.rs index b916295..e2b54e3 100644 --- a/src/internal/exit_codes.rs +++ b/src/internal/exit_codes.rs @@ -6,4 +6,4 @@ pub enum AppExitCode { DirNotEmpty = 5, DirNotGit = 6, ConfigNotFound = 7, -} \ No newline at end of file +} diff --git a/src/internal/mod.rs b/src/internal/mod.rs index 58cbc53..c68dd1d 100755 --- a/src/internal/mod.rs +++ b/src/internal/mod.rs @@ -1,5 +1,5 @@ mod exit_codes; -pub mod structs; pub mod strings; +pub mod structs; -pub use exit_codes::*; \ No newline at end of file +pub use exit_codes::*; diff --git a/src/internal/strings.rs b/src/internal/strings.rs index 0833858..15028c6 100755 --- a/src/internal/strings.rs +++ b/src/internal/strings.rs @@ -1,6 +1,6 @@ -use std::process::exit; use crate::internal::AppExitCode; use colored::*; +use std::process::exit; const LOGO_SYMBOL: &str = "μ"; const ERR_SYMBOL: &str = "❌"; diff --git a/src/main.rs b/src/main.rs index 564c505..2ecd9ac 100755 --- a/src/main.rs +++ b/src/main.rs @@ -26,7 +26,9 @@ fn main() { let args: Args = Args::parse(); if Path::exists("mlc.toml".as_ref()) && Path::exists(".git".as_ref()) { - info!("In a git repository, pulling latest mlc.toml. It is advised you run mlc pull/update"); + info!( + "In a git repository, pulling latest mlc.toml. It is advised you run mlc pull/update" + ); Command::new("git") .arg("pull") .spawn() @@ -62,7 +64,10 @@ fn main() { Operation::RepoGen => { let config = read_cfg(); if config.mode != "repository" { - crash!(AppExitCode::BuildInWorkspace, "Cannot build packages in workspace mode") + crash!( + AppExitCode::BuildInWorkspace, + "Cannot build packages in workspace mode" + ) } info!("Generating repository: {}", config.name.unwrap()); repository::generate(); diff --git a/src/operations/build.rs b/src/operations/build.rs index 3ab7c65..30f2894 100644 --- a/src/operations/build.rs +++ b/src/operations/build.rs @@ -1,6 +1,6 @@ +use crate::internal::AppExitCode; use crate::repository::generate; use crate::{crash, info, repository, workspace}; -use crate::internal::AppExitCode; pub fn build(packages: Vec, exclude: Vec, no_regen: bool) { let all = packages.is_empty(); @@ -24,7 +24,11 @@ pub fn build(packages: Vec, exclude: Vec, no_regen: bool) { for pkg in packages { if !repos.contains(&pkg) { - crash!(AppExitCode::PkgNotFound, "Package {} not found in repos in mlc.toml", pkg); + crash!( + AppExitCode::PkgNotFound, + "Package {} not found in repos in mlc.toml", + pkg + ); } else { let code = repository::build(&pkg); if code != 0 { diff --git a/src/operations/init.rs b/src/operations/init.rs index 0d1c2ec..6cd638b 100644 --- a/src/operations/init.rs +++ b/src/operations/init.rs @@ -1,5 +1,5 @@ -use crate::{crash, info, workspace}; use crate::internal::AppExitCode; +use crate::{crash, info, workspace}; use std::process::Command; pub fn init() { diff --git a/src/operations/prune.rs b/src/operations/prune.rs index 287b838..52ac06b 100644 --- a/src/operations/prune.rs +++ b/src/operations/prune.rs @@ -45,10 +45,7 @@ pub fn prune() { } if !packages_to_del.is_empty() { - info!( - "Pruning duplicates: {}", - packages_to_del.join(", ") - ); + info!("Pruning duplicates: {}", packages_to_del.join(", ")); } for pkg in packages_to_del { diff --git a/src/repository/config.rs b/src/repository/config.rs index 8276bf8..12a616a 100644 --- a/src/repository/config.rs +++ b/src/repository/config.rs @@ -1,9 +1,9 @@ use crate::crash; +use crate::internal::AppExitCode; use std::env; use std::fs::File; use std::io::Write; use std::path::Path; -use crate::internal::AppExitCode; const DEFAULT_CONFIG: &str = r#"# either "repository" or "workspace" mode = "" diff --git a/src/repository/package.rs b/src/repository/package.rs index aa045ab..2e1de55 100755 --- a/src/repository/package.rs +++ b/src/repository/package.rs @@ -1,8 +1,8 @@ use crate::crash; +use crate::internal::AppExitCode; use std::path::Path; use std::process::Command; use std::{env, fs}; -use crate::internal::AppExitCode; pub fn build(pkg: &str) -> i32 { let dir = env::current_dir().unwrap(); @@ -10,7 +10,11 @@ pub fn build(pkg: &str) -> i32 { fs::create_dir_all("out").unwrap(); } if !Path::exists(pkg.as_ref()) { - crash!(AppExitCode::DirNotGit, "Git directory for {} not found, aborting", pkg); + crash!( + AppExitCode::DirNotGit, + "Git directory for {} not found, aborting", + pkg + ); } env::set_current_dir(pkg).unwrap(); diff --git a/src/workspace/read.rs b/src/workspace/read.rs index 7d43c3d..4ad3649 100755 --- a/src/workspace/read.rs +++ b/src/workspace/read.rs @@ -1,13 +1,16 @@ use crate::crash; +use crate::internal::AppExitCode; use std::fs; use std::path::Path; -use crate::internal::AppExitCode; use crate::internal::structs::{Config, SplitRepo, UnexpandedConfig}; pub fn read_cfg() -> Config { if !Path::exists("mlc.toml".as_ref()) { - crash!(AppExitCode::ConfigNotFound, "Config file not found (mlc.toml)") + crash!( + AppExitCode::ConfigNotFound, + "Config file not found (mlc.toml)" + ) } let file = fs::read_to_string("mlc.toml").unwrap(); From 9fc6931583d641626de11fd7121e2866a0fa8efa Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Jul 2022 00:04:25 +0100 Subject: [PATCH 005/116] Ver bump in Cargo.toml --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c997b52..4093d04 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "Malachite" -version = "1.3.0" +version = "1.4.0" authors = [ "michal " ] edition = "2021" description = "Packaging tool for pacman repositories" From a68d201bbaf01433fd30c3e8f6d4cb7033868ca9 Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Jul 2022 00:13:28 +0100 Subject: [PATCH 006/116] Code optimise --- src/args.rs | 32 ++++++++++++++++---------------- src/internal/mod.rs | 4 ++-- src/internal/strings.rs | 3 ++- src/main.rs | 3 +-- src/operations/config.rs | 3 ++- src/operations/init.rs | 3 ++- src/operations/mod.rs | 12 ++++++------ src/operations/prune.rs | 3 ++- src/operations/pull.rs | 3 ++- src/repository/config.rs | 5 +++-- src/repository/mod.rs | 8 ++++---- src/repository/package.rs | 5 +++-- src/workspace/mod.rs | 4 ++-- src/workspace/read.rs | 4 ++-- 14 files changed, 49 insertions(+), 43 deletions(-) diff --git a/src/args.rs b/src/args.rs index fecad99..f2e73ec 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1,71 +1,71 @@ use clap::{ArgAction, Parser, Subcommand}; #[derive(Debug, Clone, Parser)] -#[clap(name="Malachite", version=env!("CARGO_PKG_VERSION"), about=env!("CARGO_PKG_DESCRIPTION"))] +#[clap(name = "Malachite", version = env ! ("CARGO_PKG_VERSION"), about = env ! ("CARGO_PKG_DESCRIPTION"))] pub struct Args { #[clap(subcommand)] pub subcommand: Option, /// Sets the level of verbosity - #[clap(long, short, global(true), action=ArgAction::Count)] + #[clap(long, short, global(true), action = ArgAction::Count)] pub verbose: u8, /// Complete operations without prompting user - #[clap(long="noconfirm", global(true), action=ArgAction::SetTrue)] + #[clap(long = "noconfirm", global(true), action = ArgAction::SetTrue)] pub no_confirm: bool, } #[derive(Debug, Clone, Subcommand)] pub enum Operation { /// Builds the given packages - #[clap(name="build", aliases=&["b"])] + #[clap(name = "build", aliases = & ["b"])] Build { /// The packages to operate on - #[clap(name="package(s)", action=ArgAction::Append, index=1)] + #[clap(name = "package(s)", action = ArgAction::Append, index = 1)] packages: Vec, /// Builds all packages in mlc.toml (except if -x is specified) - #[clap(long="all", takes_value=false, action=ArgAction::SetTrue, conflicts_with="package(s)")] + #[clap(long = "all", takes_value = false, action = ArgAction::SetTrue, conflicts_with = "package(s)")] all: bool, /// Excludes packages from given operation - #[clap(short='x', long="exclude", action=ArgAction::Append, takes_value=true)] + #[clap(short = 'x', long = "exclude", action = ArgAction::Append, takes_value = true)] exclude: Vec, /// Does not regenerate repository after building given package(s) - #[clap(short='n', long="no-regen", action=ArgAction::SetTrue)] + #[clap(short = 'n', long = "no-regen", action = ArgAction::SetTrue)] no_regen: bool, }, /// Generates repository from built packages - #[clap(name="repo-gen", aliases=&["r"])] + #[clap(name = "repo-gen", aliases = & ["r"])] RepoGen, /// Prunes duplicate packages from the repository - #[clap(name="prune", aliases=&["p"])] + #[clap(name = "prune", aliases = & ["p"])] Prune, /// Clones all git repositories from mlc.toml branching from current directory - #[clap(name="init", aliases=&["i"])] + #[clap(name = "init", aliases = & ["i"])] Init, /// Pulls in git repositories from mlc.toml branching from current directory - #[clap(name="pull", aliases=&["u"])] + #[clap(name = "pull", aliases = & ["u"])] Pull { /// The packages to operate on - #[clap(name="package(s)", help="The packages to operate on", action=ArgAction::Append, index=1)] + #[clap(name = "package(s)", help = "The packages to operate on", action = ArgAction::Append, index = 1)] packages: Vec, /// Pulls from all git repositories from mlc.toml branching from current directory - #[clap(long="all", action=ArgAction::SetTrue, conflicts_with="package(s)")] + #[clap(long = "all", action = ArgAction::SetTrue, conflicts_with = "package(s)")] all: bool, /// Excludes packages from given operation - #[clap(short='x', long="exclude", action=ArgAction::Append, takes_value=true)] + #[clap(short = 'x', long = "exclude", action = ArgAction::Append, takes_value = true)] exclude: Vec, }, /// Create and/or open local config file - #[clap(name="config", aliases=&["c"])] + #[clap(name = "config", aliases = & ["c"])] Config, } diff --git a/src/internal/mod.rs b/src/internal/mod.rs index c68dd1d..b9a7664 100755 --- a/src/internal/mod.rs +++ b/src/internal/mod.rs @@ -1,5 +1,5 @@ +pub use exit_codes::*; + mod exit_codes; pub mod strings; pub mod structs; - -pub use exit_codes::*; diff --git a/src/internal/strings.rs b/src/internal/strings.rs index 15028c6..903f9e4 100755 --- a/src/internal/strings.rs +++ b/src/internal/strings.rs @@ -1,7 +1,8 @@ -use crate::internal::AppExitCode; use colored::*; use std::process::exit; +use crate::internal::AppExitCode; + const LOGO_SYMBOL: &str = "μ"; const ERR_SYMBOL: &str = "❌"; diff --git a/src/main.rs b/src/main.rs index 2ecd9ac..d101fb7 100755 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +use clap::Parser; use std::env; use std::path::Path; use std::process::Command; @@ -5,8 +6,6 @@ use std::process::Command; use crate::args::{Args, Operation}; use crate::internal::AppExitCode; use crate::repository::create_config; -use clap::Parser; - use crate::workspace::read_cfg; #[global_allocator] diff --git a/src/operations/config.rs b/src/operations/config.rs index 4e102cf..2d02f1b 100644 --- a/src/operations/config.rs +++ b/src/operations/config.rs @@ -1,8 +1,9 @@ -use crate::create_config; use std::env; use std::path::Path; use std::process::Command; +use crate::create_config; + pub fn config() { if !Path::exists("mlc.toml".as_ref()) { create_config(); diff --git a/src/operations/init.rs b/src/operations/init.rs index 6cd638b..32c2f84 100644 --- a/src/operations/init.rs +++ b/src/operations/init.rs @@ -1,6 +1,7 @@ +use std::process::Command; + use crate::internal::AppExitCode; use crate::{crash, info, workspace}; -use std::process::Command; pub fn init() { let config = workspace::read_cfg(); diff --git a/src/operations/mod.rs b/src/operations/mod.rs index f3e1f81..514bbc2 100644 --- a/src/operations/mod.rs +++ b/src/operations/mod.rs @@ -1,11 +1,11 @@ -mod build; -mod config; -mod init; -mod prune; -mod pull; - pub use build::*; pub use config::*; pub use init::*; pub use prune::*; pub use pull::*; + +mod build; +mod config; +mod init; +mod prune; +mod pull; diff --git a/src/operations/prune.rs b/src/operations/prune.rs index 52ac06b..2bb15a2 100644 --- a/src/operations/prune.rs +++ b/src/operations/prune.rs @@ -1,7 +1,8 @@ -use crate::{info, read_cfg}; use std::fs; use std::process::Command; +use crate::{info, read_cfg}; + pub fn prune() { let config = read_cfg(); let mut packages = vec![]; diff --git a/src/operations/pull.rs b/src/operations/pull.rs index 737f9c4..088baa3 100644 --- a/src/operations/pull.rs +++ b/src/operations/pull.rs @@ -1,7 +1,8 @@ -use crate::info; use std::env; use std::process::Command; +use crate::info; + fn do_the_pulling(packages: Vec) { for dir in packages { let current_dir = env::current_dir().unwrap(); diff --git a/src/repository/config.rs b/src/repository/config.rs index 12a616a..c2274fe 100644 --- a/src/repository/config.rs +++ b/src/repository/config.rs @@ -1,10 +1,11 @@ -use crate::crash; -use crate::internal::AppExitCode; use std::env; use std::fs::File; use std::io::Write; use std::path::Path; +use crate::crash; +use crate::internal::AppExitCode; + const DEFAULT_CONFIG: &str = r#"# either "repository" or "workspace" mode = "" diff --git a/src/repository/mod.rs b/src/repository/mod.rs index 0d2ce29..59534d6 100755 --- a/src/repository/mod.rs +++ b/src/repository/mod.rs @@ -1,7 +1,7 @@ -mod config; -mod package; -mod repo; - pub use config::*; pub use package::*; pub use repo::*; + +mod config; +mod package; +mod repo; diff --git a/src/repository/package.rs b/src/repository/package.rs index 2e1de55..602298e 100755 --- a/src/repository/package.rs +++ b/src/repository/package.rs @@ -1,9 +1,10 @@ -use crate::crash; -use crate::internal::AppExitCode; use std::path::Path; use std::process::Command; use std::{env, fs}; +use crate::crash; +use crate::internal::AppExitCode; + pub fn build(pkg: &str) -> i32 { let dir = env::current_dir().unwrap(); if !Path::exists("out".as_ref()) { diff --git a/src/workspace/mod.rs b/src/workspace/mod.rs index cd2e912..aa2213b 100755 --- a/src/workspace/mod.rs +++ b/src/workspace/mod.rs @@ -1,3 +1,3 @@ -mod read; - pub use read::*; + +mod read; diff --git a/src/workspace/read.rs b/src/workspace/read.rs index 4ad3649..ac167e5 100755 --- a/src/workspace/read.rs +++ b/src/workspace/read.rs @@ -1,9 +1,9 @@ -use crate::crash; -use crate::internal::AppExitCode; use std::fs; use std::path::Path; +use crate::crash; use crate::internal::structs::{Config, SplitRepo, UnexpandedConfig}; +use crate::internal::AppExitCode; pub fn read_cfg() -> Config { if !Path::exists("mlc.toml".as_ref()) { From 06e906d2efbf4a8aa201059123692aa4a8ff1b9d Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Jul 2022 14:05:51 +0100 Subject: [PATCH 007/116] Massive malachite internal rework --- Cargo.lock | 2 +- example-mlc.toml | 2 +- src/args.rs | 38 ++++++++------------- src/internal/exit_codes.rs | 3 +- src/internal/structs.rs | 17 +++++++++- src/main.rs | 18 ++++------ src/operations/build.rs | 68 ++++++++++++++++++++++---------------- src/operations/clone.rs | 49 +++++++++++++++++++++++++++ src/operations/config.rs | 3 ++ src/operations/init.rs | 58 -------------------------------- src/operations/mod.rs | 6 ++-- src/operations/prune.rs | 56 ------------------------------- src/operations/pull.rs | 53 +++++++++++++++++++---------- src/repository/config.rs | 16 ++++++--- src/repository/package.rs | 19 ++++++++--- src/repository/repo.rs | 20 ++++++----- src/workspace/read.rs | 45 +++++++++++++++++-------- 17 files changed, 238 insertions(+), 235 deletions(-) create mode 100644 src/operations/clone.rs delete mode 100644 src/operations/init.rs delete mode 100644 src/operations/prune.rs diff --git a/Cargo.lock b/Cargo.lock index 27f6b08..05547c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "Malachite" -version = "1.3.0" +version = "1.4.0" dependencies = [ "clap", "colored", diff --git a/example-mlc.toml b/example-mlc.toml index 2daee34..09d8e5a 100644 --- a/example-mlc.toml +++ b/example-mlc.toml @@ -4,7 +4,7 @@ name = "test" repo = [ "1::amethyst", "1::jade", - "2::notop-git", + "2::notop-git!", "3::slippy-rb" ] diff --git a/src/args.rs b/src/args.rs index f2e73ec..e87394c 100644 --- a/src/args.rs +++ b/src/args.rs @@ -13,6 +13,14 @@ pub struct Args { /// Complete operations without prompting user #[clap(long = "noconfirm", global(true), action = ArgAction::SetTrue)] pub no_confirm: bool, + + /// Excludes packages from given operation, if applicable + #[clap(short = 'x', long = "exclude", action = ArgAction::Append, takes_value = true)] + pub exclude: Vec, + + /// Operates on all packages in the workspace, if applicable + #[clap(long = "all", action = ArgAction::SetTrue, conflicts_with = "package(s)")] + pub all: bool, } #[derive(Debug, Clone, Subcommand)] @@ -24,30 +32,18 @@ pub enum Operation { #[clap(name = "package(s)", action = ArgAction::Append, index = 1)] packages: Vec, - /// Builds all packages in mlc.toml (except if -x is specified) - #[clap(long = "all", takes_value = false, action = ArgAction::SetTrue, conflicts_with = "package(s)")] - all: bool, - - /// Excludes packages from given operation - #[clap(short = 'x', long = "exclude", action = ArgAction::Append, takes_value = true)] - exclude: Vec, - /// Does not regenerate repository after building given package(s) #[clap(short = 'n', long = "no-regen", action = ArgAction::SetTrue)] no_regen: bool, }, - /// Generates repository from built packages - #[clap(name = "repo-gen", aliases = & ["r"])] + /// Generates Pacman repository from built packages + #[clap(name = "repo-gen", aliases = & ["repo", "r"])] RepoGen, - /// Prunes duplicate packages from the repository - #[clap(name = "prune", aliases = & ["p"])] - Prune, - /// Clones all git repositories from mlc.toml branching from current directory - #[clap(name = "init", aliases = & ["i"])] - Init, + #[clap(name = "clone", aliases = & ["c"])] + Clone, /// Pulls in git repositories from mlc.toml branching from current directory #[clap(name = "pull", aliases = & ["u"])] @@ -55,17 +51,9 @@ pub enum Operation { /// The packages to operate on #[clap(name = "package(s)", help = "The packages to operate on", action = ArgAction::Append, index = 1)] packages: Vec, - - /// Pulls from all git repositories from mlc.toml branching from current directory - #[clap(long = "all", action = ArgAction::SetTrue, conflicts_with = "package(s)")] - all: bool, - - /// Excludes packages from given operation - #[clap(short = 'x', long = "exclude", action = ArgAction::Append, takes_value = true)] - exclude: Vec, }, /// Create and/or open local config file - #[clap(name = "config", aliases = & ["c"])] + #[clap(name = "config", aliases = & ["conf"])] Config, } diff --git a/src/internal/exit_codes.rs b/src/internal/exit_codes.rs index e2b54e3..4d28575 100644 --- a/src/internal/exit_codes.rs +++ b/src/internal/exit_codes.rs @@ -4,6 +4,7 @@ pub enum AppExitCode { PkgNotFound = 3, InvalidMode = 4, DirNotEmpty = 5, - DirNotGit = 6, + RepoNotFound = 6, ConfigNotFound = 7, + NoPkgs = 8, } diff --git a/src/internal/structs.rs b/src/internal/structs.rs index 0bedb11..2e73406 100755 --- a/src/internal/structs.rs +++ b/src/internal/structs.rs @@ -3,13 +3,22 @@ use serde_derive::Deserialize; #[derive(Debug, Deserialize)] pub struct Config { pub mode: String, + pub sign: bool, pub name: Option, - pub repo: Vec, + pub repo: Vec, +} + +#[derive(Debug, Deserialize)] +pub struct Repo { + pub name: String, + pub url: String, + pub priority: usize, } #[derive(Debug, Deserialize)] pub struct UnexpandedConfig { pub mode: String, + pub sign: bool, pub name: Option, pub repo: Vec, pub urls: Vec, @@ -20,3 +29,9 @@ pub struct SplitRepo { pub indx: usize, pub name: String, } + +#[derive(Debug)] +pub struct ErroredPackage { + pub name: String, + pub code: i32, +} diff --git a/src/main.rs b/src/main.rs index d101fb7..c3c0583 100755 --- a/src/main.rs +++ b/src/main.rs @@ -36,6 +36,8 @@ fn main() { .unwrap(); } + let exclude = &args.exclude; + if Path::exists("../.git".as_ref()) { info!("Parent directory is a git directory, pulling latest mlc.toml. It is advised you run mlc pull/update in all malachite directories"); let dir = env::current_dir().unwrap(); @@ -49,17 +51,12 @@ fn main() { env::set_current_dir(dir).unwrap(); } - match args.subcommand.unwrap_or(Operation::Init) { - Operation::Init => operations::init(), + match args.subcommand.unwrap_or(Operation::Clone) { + Operation::Clone => operations::clone(), Operation::Build { - packages, - exclude, - no_regen, - .. - } => operations::build(packages, exclude, no_regen), - Operation::Pull { - packages, exclude, .. - } => operations::pull(packages, exclude), + packages, no_regen, .. + } => operations::build(packages, exclude.to_vec(), no_regen), + Operation::Pull { packages, .. } => operations::pull(packages, exclude.to_vec()), Operation::RepoGen => { let config = read_cfg(); if config.mode != "repository" { @@ -71,7 +68,6 @@ fn main() { info!("Generating repository: {}", config.name.unwrap()); repository::generate(); } - Operation::Prune => operations::prune(), Operation::Config => operations::config(), } } diff --git a/src/operations/build.rs b/src/operations/build.rs index 30f2894..d9ad7d2 100644 --- a/src/operations/build.rs +++ b/src/operations/build.rs @@ -1,60 +1,72 @@ +use crate::internal::structs::ErroredPackage; use crate::internal::AppExitCode; -use crate::repository::generate; use crate::{crash, info, repository, workspace}; pub fn build(packages: Vec, exclude: Vec, no_regen: bool) { - let all = packages.is_empty(); - + // Read config struct from mlc.toml let config = workspace::read_cfg(); + let all = packages.is_empty(); - let mut repos: Vec = vec![]; - for r in config.repo { - let split = r.split('/').collect::>(); - let a = split.last().unwrap(); - repos.push(a.parse().unwrap()); - } - - if exclude.is_empty() { + // Get list of repos and subtract exclude + let mut repos: Vec = config.repo.iter().map(|x| x.name.clone()).collect(); + if !exclude.is_empty() { for ex in exclude { repos.retain(|x| *x != ex); } } - let mut errored: Vec = vec![]; - - for pkg in packages { - if !repos.contains(&pkg) { - crash!( - AppExitCode::PkgNotFound, - "Package {} not found in repos in mlc.toml", - pkg - ); - } else { - let code = repository::build(&pkg); - if code != 0 { - errored.push(pkg); + // If packages is not empty and all isn't specified, build specifed packages + let mut errored: Vec = vec![]; + if !packages.is_empty() && !all { + for pkg in &packages { + if !repos.contains(pkg) { + crash!( + AppExitCode::PkgNotFound, + "Package repo {} not found in in mlc.toml", + pkg + ); + } else { + let code = repository::build(pkg, config.sign); + if code != 0 { + let error = ErroredPackage { name: pkg.to_string(), code }; + errored.push(error); + } } } } + // If all is specified, attempt to build a package from all repos if all { for pkg in repos { - let code = repository::build(&pkg); + let code = repository::build(&pkg, config.sign); if code != 0 { - errored.push(pkg); + let error = ErroredPackage { name: pkg, code }; + errored.push(error); } } - generate(); } + // If all is not specified, but packages is empty, crash + if !all && packages.is_empty() { + crash!(AppExitCode::NoPkgs, "No packages specified"); + } + + // If no_regen is passed, do not generate a repository if !no_regen { repository::generate(); } + // Map errored packages to a string for display + let error_strings: Vec = errored + .iter() + .map(|x| format!("{}: Returned {}", x.name, x.code)) + .collect(); + + // If errored is not empty, let the user know which packages failed if !errored.is_empty() { info!( "The following packages build jobs returned a non-zero exit code: {}", - errored.join(" ") + error_strings.join("\n") ) } } diff --git a/src/operations/clone.rs b/src/operations/clone.rs new file mode 100644 index 0000000..365a592 --- /dev/null +++ b/src/operations/clone.rs @@ -0,0 +1,49 @@ +use crate::{info, workspace}; +use std::process::Command; + +pub fn clone() { + // Read config struct from mlc.toml + let config = workspace::read_cfg(); + let repos = &config.repo; + + // Get a vector of all files/dirs in the current directory, excluding config file + let dir_paths = std::fs::read_dir("./").unwrap(); + let mut dirs = dir_paths + .map(|x| x.unwrap().path().display().to_string()) + .collect::>(); + dirs.retain(|x| *x != "./mlc.toml"); + + // Creates a vector of the difference between cloned repos and repos defined in config + let mut repo_diff = vec![]; + for repo in repos { + let name = &repo.name; + if !dirs.contains(name) { + repo_diff.push(repo); + } + } + + // Diff logic + if repo_diff.is_empty() { + // No diff, do nothing + info!("All repos are already cloned"); + } else { + // This is just for pretty display purposes + let display = repo_diff + .iter() + .map(|x| x.name.to_string()) + .collect::>() + .join(" "); + info!("New/missing repos to clone: {}", display); + + // Clone all diff repos + for r in repo_diff { + info!("Cloning ({} mode): {}", config.mode, r.name); + Command::new("git") + .args(&["clone", &r.url, &r.name]) + .spawn() + .unwrap() + .wait() + .unwrap(); + } + } +} diff --git a/src/operations/config.rs b/src/operations/config.rs index 2d02f1b..a880549 100644 --- a/src/operations/config.rs +++ b/src/operations/config.rs @@ -5,9 +5,12 @@ use std::process::Command; use crate::create_config; pub fn config() { + // Generate new config file if not already present if !Path::exists("mlc.toml".as_ref()) { create_config(); } + + // Open config file in user's editor of choice let editor = env::var("EDITOR").unwrap_or_else(|_| "nano".to_string()); Command::new(editor) .arg("mlc.toml") diff --git a/src/operations/init.rs b/src/operations/init.rs deleted file mode 100644 index 32c2f84..0000000 --- a/src/operations/init.rs +++ /dev/null @@ -1,58 +0,0 @@ -use std::process::Command; - -use crate::internal::AppExitCode; -use crate::{crash, info, workspace}; - -pub fn init() { - let config = workspace::read_cfg(); - if config.mode == "workspace" || config.mode == "repository" { - let dirs_raw = Command::new("ls").arg("-1").output().unwrap().stdout; - let dirs_string = String::from_utf8_lossy(&dirs_raw); - let mut dirs = dirs_string.lines().collect::>(); - - dirs.retain(|x| *x != "mlc.toml"); - dirs.sort_unstable(); - - let repos = &config.repo; - let mut repos = repos - .iter() - .map(|x| x.split('/').last().unwrap()) - .collect::>(); - - repos.sort_unstable(); - - let mut diff = repos.clone(); - diff.retain(|x| !dirs.contains(x)); - - let mut diff_matches = vec![]; - - for &x in &diff { - for y in config.repo.iter() { - if x == y.split('/').last().unwrap() { - diff_matches.push(y); - } - } - } - - if diff.is_empty() { - info!("All repos are already cloned"); - } else { - info!("New/missing repos to clone: {}", diff.join(", ")); - for r in diff_matches { - info!( - "Cloning ({} mode): {}", - config.mode, - r.split('/').last().unwrap() - ); - Command::new("git") - .args(&["clone", r]) - .spawn() - .unwrap() - .wait() - .unwrap(); - } - } - } else { - crash!(AppExitCode::InvalidMode, "Invalid mode in mlc.toml"); - } -} diff --git a/src/operations/mod.rs b/src/operations/mod.rs index 514bbc2..686ef4d 100644 --- a/src/operations/mod.rs +++ b/src/operations/mod.rs @@ -1,11 +1,9 @@ pub use build::*; +pub use clone::*; pub use config::*; -pub use init::*; -pub use prune::*; pub use pull::*; mod build; +mod clone; mod config; -mod init; -mod prune; mod pull; diff --git a/src/operations/prune.rs b/src/operations/prune.rs deleted file mode 100644 index 2bb15a2..0000000 --- a/src/operations/prune.rs +++ /dev/null @@ -1,56 +0,0 @@ -use std::fs; -use std::process::Command; - -use crate::{info, read_cfg}; - -pub fn prune() { - let config = read_cfg(); - let mut packages = vec![]; - for untrimmed_repo in &config.repo { - pub fn trim_repo(a: String) -> String { - (a.split('/') - .map(|s| s.to_string()) - .collect::>() - .last() - .unwrap()) - .to_string() - } - packages.push(trim_repo(untrimmed_repo.to_string())); - } - - let mut packages_to_del = vec![]; - - for pkg in packages { - let dups = Command::new("bash") - .args(&[ - "-c", - &format!( - "ls out/{}*.tar.* -w 1 | grep .sig | sed 's/.sig//g' | sort -r", - pkg - ), - ]) - .output() - .unwrap() - .stdout - .to_ascii_lowercase(); - - let duplicates = String::from_utf8_lossy(&dups); - let duplicates_lines = duplicates.lines().collect::>(); - let variable_hell = duplicates_lines.iter().skip(1).collect::>(); - - if !variable_hell.is_empty() { - for var in variable_hell { - packages_to_del.push(var.to_string()); - } - } - } - - if !packages_to_del.is_empty() { - info!("Pruning duplicates: {}", packages_to_del.join(", ")); - } - - for pkg in packages_to_del { - fs::remove_file(&pkg).unwrap(); - fs::remove_file(format!("{}.sig", &pkg)).unwrap(); - } -} diff --git a/src/operations/pull.rs b/src/operations/pull.rs index 088baa3..ccb25ed 100644 --- a/src/operations/pull.rs +++ b/src/operations/pull.rs @@ -1,40 +1,57 @@ +use crate::{internal::AppExitCode, crash}; use std::env; use std::process::Command; use crate::info; -fn do_the_pulling(packages: Vec) { - for dir in packages { - let current_dir = env::current_dir().unwrap(); - info!("Entering working directory: {}", dir); - env::set_current_dir(dir).unwrap(); +fn do_the_pulling(repos: Vec) { + for repo in repos { + // Set root dir to return after each git pull + let root_dir = env::current_dir().unwrap(); + info!("Entering working directory: {}", &repo); + env::set_current_dir(repo).unwrap(); Command::new("git") .arg("pull") .spawn() .unwrap() .wait() .unwrap(); - env::set_current_dir(current_dir).unwrap(); + + // Return to root dir + env::set_current_dir(root_dir).unwrap(); } } pub fn pull(packages: Vec, exclude: Vec) { + // If no packages are specified, imply all let all = packages.is_empty(); - if all { - let stdout = Command::new("ls").arg("-1").output().unwrap().stdout; - let dirs_string = String::from_utf8_lossy(&stdout); - let mut dirs = dirs_string.lines().collect::>(); + // Read repos from config file + let repos = crate::workspace::read_cfg() + .repo + .iter() + .map(|x| x.name.clone()) + .collect::>(); - dirs.retain(|x| *x != "mlc.toml"); - for x in exclude { - dirs.retain(|y| *y != x); - } + // Set repos_applicable for next function + let mut repos_applicable = if all { + repos + } else { + packages + }; - let dirs_mapped = dirs.iter().map(|x| x.to_string()).collect(); + // Subtract exclude from repos_applicable + if !exclude.is_empty() { + for ex in exclude { + repos_applicable.retain(|x| *x != ex); + } + } - do_the_pulling(dirs_mapped); - } else { - do_the_pulling(packages); + // If all is not specified and packages is empty, crash + if repos_applicable.is_empty() { + crash!(AppExitCode::NoPkgs, "No packages specified"); } + + // Pull! + do_the_pulling(repos_applicable); } diff --git a/src/repository/config.rs b/src/repository/config.rs index c2274fe..22c2506 100644 --- a/src/repository/config.rs +++ b/src/repository/config.rs @@ -6,25 +6,31 @@ use std::path::Path; use crate::crash; use crate::internal::AppExitCode; -const DEFAULT_CONFIG: &str = r#"# either "repository" or "workspace" +const DEFAULT_CONFIG: &str = r#" +# Either "repository" or "workspace" mode = "" -# only required when in repository mode, decides what to call the repository and relevant files +# Only required when in repository mode, decides what to call the repository and relevant files name = "" +# Only required when in repository mode, decides whether to PGP sign built packages +sign = true -# an array of git repos to clone from, formatted url_index::repo_name, e.g. if you had urls = [ "https://example.com/%repo%" ], 1::package would expand to https://example.com/package +# An array of Git repositories to clone from, formatted url_index::repo_name(!) +# e.g. if you had URLs = [ "https://example.com/%repo%.git" ], 1::package would expand to https://example.com/package.git +# Repository mode only: Depending on the number of "!"s appended to the name, the priority of the package will be determined. More "!"s = higher priority = built first. repo = [ "", "" ] -# an array of urls to clone from, in the format https://example.com/%repo% (the %repo% is NOT optional) +# An array of URLs to clone from, in the format https://example.com/%repo% (the %repo% is NOT optional and will be replaced with the name of the repository) urls = [ "", "" ]"#; pub fn create_config() { + // Ensure current directory is empty if env::current_dir() .unwrap() .read_dir() @@ -37,6 +43,8 @@ pub fn create_config() { "Directory is not empty, please only create a repository in an empty directory" ); } + + // If config file exists, create it if !Path::exists("mlc.toml".as_ref()) { let mut file = File::create("mlc.toml").unwrap(); file.write_all(DEFAULT_CONFIG.as_ref()).unwrap(); diff --git a/src/repository/package.rs b/src/repository/package.rs index 602298e..3600172 100755 --- a/src/repository/package.rs +++ b/src/repository/package.rs @@ -5,28 +5,37 @@ use std::{env, fs}; use crate::crash; use crate::internal::AppExitCode; -pub fn build(pkg: &str) -> i32 { +pub fn build(pkg: &str, sign: bool) -> i32 { + // Set root dir to return after build + let dir = env::current_dir().unwrap(); + + // Create out dir if not already present if !Path::exists("out".as_ref()) { fs::create_dir_all("out").unwrap(); } + + // If directory is not found, crash if !Path::exists(pkg.as_ref()) { crash!( - AppExitCode::DirNotGit, - "Git directory for {} not found, aborting", + AppExitCode::RepoNotFound, + "Repo for {} not found, aborting", pkg ); } + // Enter build directory env::set_current_dir(pkg).unwrap(); + // Build each package let a = Command::new("makepkg") - .args(&["-sf", "--skippgpcheck", "--sign", "--noconfirm"]) + .args(&["-sf", "--skippgpcheck", if sign { "--sign" } else {"--nosign"}, "--noconfirm"]) .spawn() .unwrap() .wait() .unwrap(); + // Copy built package to out dir Command::new("bash") .args(&["-c", "cp *.pkg.tar* ../out/"]) .spawn() @@ -34,7 +43,9 @@ pub fn build(pkg: &str) -> i32 { .wait() .unwrap(); + // Return to root dir env::set_current_dir(dir).unwrap(); + // Return exit code a.code().unwrap() } diff --git a/src/repository/repo.rs b/src/repository/repo.rs index 5dd750e..ee8bb3a 100644 --- a/src/repository/repo.rs +++ b/src/repository/repo.rs @@ -5,15 +5,21 @@ use std::{env, fs}; use crate::workspace::read_cfg; pub fn generate() { + // Read config struct from mlc.toml let config = read_cfg(); + + // Get repository name from config let name = config.name.unwrap(); + // If repository exists, delete it if Path::exists(name.as_ref()) { fs::remove_dir_all(&name).unwrap(); } + // Create or recreate repository directory fs::create_dir_all(&name).unwrap(); + // Copy out packages to repository directory Command::new("bash") .args(&["-c", &format!("cp -v out/* {}/", &name)]) .spawn() @@ -21,17 +27,19 @@ pub fn generate() { .wait() .unwrap(); + // Enter repository directory env::set_current_dir(&name).unwrap(); let db = format!("{}.db", &name); let files = format!("{}.files", &name); + // Create repo.db and repo.files using repo-add Command::new("bash") .args(&[ "-c", &format!( - "repo-add {}.tar.gz *.pkg.tar.zst; repo-add {}.tar.gz *.pkg.tar.xz", - db, db + "GLOBIGNORE=\"*.sig\" repo-add {}.tar.gz *.pkg.tar.*", + db ), ]) .spawn() @@ -39,13 +47,7 @@ pub fn generate() { .wait() .unwrap(); - Command::new("bash") - .args(&["-c", &format!("rm {}.{{db,files}}", &name)]) - .spawn() - .unwrap() - .wait() - .unwrap(); - + // Replace repo.{db,files}.tar.gz with just repo.{db,files} Command::new("bash") .args(&[ "-c", diff --git a/src/workspace/read.rs b/src/workspace/read.rs index ac167e5..8902ba4 100755 --- a/src/workspace/read.rs +++ b/src/workspace/read.rs @@ -2,10 +2,11 @@ use std::fs; use std::path::Path; use crate::crash; -use crate::internal::structs::{Config, SplitRepo, UnexpandedConfig}; +use crate::internal::structs::{Config, Repo, SplitRepo, UnexpandedConfig}; use crate::internal::AppExitCode; pub fn read_cfg() -> Config { + // Crash if mlc.toml doesn't exist if !Path::exists("mlc.toml".as_ref()) { crash!( AppExitCode::ConfigNotFound, @@ -13,32 +14,48 @@ pub fn read_cfg() -> Config { ) } + // Reading the config file to an UnexpandedConfig struct let file = fs::read_to_string("mlc.toml").unwrap(); let config: UnexpandedConfig = toml::from_str(&file).unwrap(); - let mut trimmed_urls: Vec = vec![]; - let mut expanded_repos: Vec = vec![]; - - for url in config.urls { - let a = url.split("%repo%").collect::>()[0]; - let mut b = vec![a.to_string()]; - trimmed_urls.append(&mut b); + // Crash if incorrect mode is set + if config.mode != "workspace" && config.mode != "repository" { + crash!( + AppExitCode::InvalidMode, + "Invalid mode in mlc.toml, must be either \"repository\" or \"workspace\"" + ); } - let config_repos = config.repo; - for x in config_repos { + let mut expanded_repos: Vec = vec![]; + + // Parsing repos from the config file + for x in config.repo { + // Splits the repo name and index inta a SplitRepo struct let split: Vec<&str> = x.split("::").collect(); - let sr_struct = SplitRepo { + let split_struct = SplitRepo { indx: split[0].parse().unwrap(), name: split[1].parse().unwrap(), }; - let index = sr_struct.indx; - let expanded = format!("{}{}", trimmed_urls[index - 1], sr_struct.name); - expanded_repos.push(expanded); + + // Parses all necessary values for expanding the repo to a Repo struct + let index = split_struct.indx; + let name = split_struct.name.replace('!', ""); + let url = config.urls[index - 1].replace("%repo%", &split_struct.name); + let priority = &split_struct.name.matches('!').count(); + + // Creates and pushes Repo struct to expanded_repos + let repo = Repo { + name, + url, + priority: *priority, + }; + expanded_repos.push(repo); } + // Returns parsed config file Config { mode: config.mode, + sign: config.sign, name: config.name, repo: expanded_repos, } From c2dc3189f1b2f27d722586876098f95fce70c374 Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Jul 2022 14:06:20 +0100 Subject: [PATCH 008/116] Type --- src/operations/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operations/build.rs b/src/operations/build.rs index d9ad7d2..1d7876d 100644 --- a/src/operations/build.rs +++ b/src/operations/build.rs @@ -15,7 +15,7 @@ pub fn build(packages: Vec, exclude: Vec, no_regen: bool) { } } - // If packages is not empty and all isn't specified, build specifed packages + // If packages is not empty and all isn't specified, build specified packages let mut errored: Vec = vec![]; if !packages.is_empty() && !all { for pkg in &packages { From 085b460739e01f668df3b5fe29b8392cfdf11c67 Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Jul 2022 14:16:53 +0100 Subject: [PATCH 009/116] Implemented package priorities --- src/operations/build.rs | 24 +++++++++++++++++------- src/operations/pull.rs | 8 ++------ src/repository/package.rs | 7 ++++++- src/repository/repo.rs | 5 +---- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/operations/build.rs b/src/operations/build.rs index 1d7876d..abd6d82 100644 --- a/src/operations/build.rs +++ b/src/operations/build.rs @@ -1,4 +1,4 @@ -use crate::internal::structs::ErroredPackage; +use crate::internal::structs::{ErroredPackage, Repo}; use crate::internal::AppExitCode; use crate::{crash, info, repository, workspace}; @@ -8,10 +8,10 @@ pub fn build(packages: Vec, exclude: Vec, no_regen: bool) { let all = packages.is_empty(); // Get list of repos and subtract exclude - let mut repos: Vec = config.repo.iter().map(|x| x.name.clone()).collect(); + let mut repos: Vec = config.repo; if !exclude.is_empty() { for ex in exclude { - repos.retain(|x| *x != ex); + repos.retain(|x| *x.name != ex); } } @@ -19,16 +19,21 @@ pub fn build(packages: Vec, exclude: Vec, no_regen: bool) { let mut errored: Vec = vec![]; if !packages.is_empty() && !all { for pkg in &packages { - if !repos.contains(pkg) { + // If repo is not in config, crash + if !repos.iter().map(|x| x.name.clone()).any(|x| x == *pkg) { crash!( AppExitCode::PkgNotFound, "Package repo {} not found in in mlc.toml", pkg ); } else { + // Otherwise, build let code = repository::build(pkg, config.sign); if code != 0 { - let error = ErroredPackage { name: pkg.to_string(), code }; + let error = ErroredPackage { + name: pkg.to_string(), + code, + }; errored.push(error); } } @@ -37,10 +42,15 @@ pub fn build(packages: Vec, exclude: Vec, no_regen: bool) { // If all is specified, attempt to build a package from all repos if all { + // Sort by package priority + repos.sort_by(|a, b| b.priority.cmp(&a.priority)); for pkg in repos { - let code = repository::build(&pkg, config.sign); + let code = repository::build(&pkg.name, config.sign); if code != 0 { - let error = ErroredPackage { name: pkg, code }; + let error = ErroredPackage { + name: pkg.name, + code, + }; errored.push(error); } } diff --git a/src/operations/pull.rs b/src/operations/pull.rs index ccb25ed..c550206 100644 --- a/src/operations/pull.rs +++ b/src/operations/pull.rs @@ -1,4 +1,4 @@ -use crate::{internal::AppExitCode, crash}; +use crate::{crash, internal::AppExitCode}; use std::env; use std::process::Command; @@ -34,11 +34,7 @@ pub fn pull(packages: Vec, exclude: Vec) { .collect::>(); // Set repos_applicable for next function - let mut repos_applicable = if all { - repos - } else { - packages - }; + let mut repos_applicable = if all { repos } else { packages }; // Subtract exclude from repos_applicable if !exclude.is_empty() { diff --git a/src/repository/package.rs b/src/repository/package.rs index 3600172..c8645db 100755 --- a/src/repository/package.rs +++ b/src/repository/package.rs @@ -29,7 +29,12 @@ pub fn build(pkg: &str, sign: bool) -> i32 { // Build each package let a = Command::new("makepkg") - .args(&["-sf", "--skippgpcheck", if sign { "--sign" } else {"--nosign"}, "--noconfirm"]) + .args(&[ + "-sf", + "--skippgpcheck", + if sign { "--sign" } else { "--nosign" }, + "--noconfirm", + ]) .spawn() .unwrap() .wait() diff --git a/src/repository/repo.rs b/src/repository/repo.rs index ee8bb3a..65fdc0c 100644 --- a/src/repository/repo.rs +++ b/src/repository/repo.rs @@ -37,10 +37,7 @@ pub fn generate() { Command::new("bash") .args(&[ "-c", - &format!( - "GLOBIGNORE=\"*.sig\" repo-add {}.tar.gz *.pkg.tar.*", - db - ), + &format!("GLOBIGNORE=\"*.sig\" repo-add {}.tar.gz *.pkg.tar.*", db), ]) .spawn() .unwrap() From eace7d727e7e00de63c394aafbf77af0b73569b5 Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Jul 2022 14:20:31 +0100 Subject: [PATCH 010/116] Reworked example --- example-mlc.toml | 26 -------------------------- example/mlc.toml | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 26 deletions(-) delete mode 100644 example-mlc.toml create mode 100644 example/mlc.toml diff --git a/example-mlc.toml b/example-mlc.toml deleted file mode 100644 index 09d8e5a..0000000 --- a/example-mlc.toml +++ /dev/null @@ -1,26 +0,0 @@ -mode = "repository" -name = "test" - -repo = [ - "1::amethyst", - "1::jade", - "2::notop-git!", - "3::slippy-rb" -] - -urls = [ - "https://github.com/crystal-linux/%repo%", - "https://aur.archlinux.org/%repo%", - "https://github.com/jnats/%repo%" -] - -# in this example, mlc will create a repository called "test", with 4 packages -# these packages will be expanded based on the index number they have (index_number::package) -# to demonstrate, the ones in this config will expand to the following: -# -# https://github.com/crystal-linux/ame -# https://github.com/crystal-linux/jade -# https://aur.archlinux.org/notop-git -# https://github.com/jnats/slippy-rb -# -# when in repository mode, malachite only pulls the PKGBUILD file from the repository (all we need to build the packages from src) \ No newline at end of file diff --git a/example/mlc.toml b/example/mlc.toml new file mode 100644 index 0000000..215276d --- /dev/null +++ b/example/mlc.toml @@ -0,0 +1,32 @@ +mode = "repository" +name = "test" +sign = false + +repo = [ + "1::amethyst", + "1::jade!", + "2::notop-git", + "3::slippy-rb" +] + +urls = [ + "https://github.com/crystal-linux/%repo%", + "https://aur.archlinux.org/%repo%", + "https://github.com/jnats/%repo%" +] + +# In this example, Malachite will create a repository called "test", with 4 packages +# These packages will be expanded based on the index number they have (index_number::package) +# To demonstrate, the ones in this config will expand to the following: +# +# https://github.com/crystal-linux/ame +# https://github.com/crystal-linux/jade +# https://aur.archlinux.org/notop-git +# https://github.com/jnats/slippy-rb +# +# The "name" option specifies the name of the pacman repository. +# The "sign" option specifies whether the built packages should be signed, which is recommended for all pacman repositories. +# When in repository mode, malachite only pulls the PKGBUILD file from the git repository (all we need to build the packages from src) +# +# Additionally, packages are built in the order of priority, so packages with a higher priority (denoted by "!"s appended to the name) will be built first. +# In this case, jade has a higher priority than amethyst, so it will be built first. \ No newline at end of file From 711a39fdd5cd31e020f889b8195816952aef4f8e Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Jul 2022 14:22:50 +0100 Subject: [PATCH 011/116] Fixed ! retaining in URLs to clone --- src/args.rs | 5 +---- src/workspace/read.rs | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/args.rs b/src/args.rs index e87394c..7fc7cbb 100644 --- a/src/args.rs +++ b/src/args.rs @@ -18,9 +18,6 @@ pub struct Args { #[clap(short = 'x', long = "exclude", action = ArgAction::Append, takes_value = true)] pub exclude: Vec, - /// Operates on all packages in the workspace, if applicable - #[clap(long = "all", action = ArgAction::SetTrue, conflicts_with = "package(s)")] - pub all: bool, } #[derive(Debug, Clone, Subcommand)] @@ -42,7 +39,7 @@ pub enum Operation { RepoGen, /// Clones all git repositories from mlc.toml branching from current directory - #[clap(name = "clone", aliases = & ["c"])] + #[clap(name = "clone", aliases = & ["init", "i", "c"])] Clone, /// Pulls in git repositories from mlc.toml branching from current directory diff --git a/src/workspace/read.rs b/src/workspace/read.rs index 8902ba4..0a144f2 100755 --- a/src/workspace/read.rs +++ b/src/workspace/read.rs @@ -40,7 +40,7 @@ pub fn read_cfg() -> Config { // Parses all necessary values for expanding the repo to a Repo struct let index = split_struct.indx; let name = split_struct.name.replace('!', ""); - let url = config.urls[index - 1].replace("%repo%", &split_struct.name); + let url = config.urls[index - 1].replace("%repo%", &name); let priority = &split_struct.name.matches('!').count(); // Creates and pushes Repo struct to expanded_repos From 6cce99162c0daa4779e85660174648312108db62 Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Jul 2022 14:23:46 +0100 Subject: [PATCH 012/116] .gitignore --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 442db94..cf9e1e2 100755 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ /target .idea -.direnv \ No newline at end of file +.direnv +test/* + +!test/mlc.toml \ No newline at end of file From cbd598a0840355e62b9c24df81e97d3248ab4b1f Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Jul 2022 14:24:34 +0100 Subject: [PATCH 013/116] .gitignore --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index cf9e1e2..c0fcff6 100755 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ /target .idea .direnv -test/* -!test/mlc.toml \ No newline at end of file +example/* +!example/mlc.toml \ No newline at end of file From 0c154966b2b75aa1250bcf32bfd0b9d0ab4864cf Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Jul 2022 14:30:52 +0100 Subject: [PATCH 014/116] Implemented new Clean operation --- src/args.rs | 4 ++++ src/main.rs | 1 + src/operations/clean.rs | 16 ++++++++++++++++ src/operations/mod.rs | 2 ++ 4 files changed, 23 insertions(+) create mode 100644 src/operations/clean.rs diff --git a/src/args.rs b/src/args.rs index 7fc7cbb..4eb3eb4 100644 --- a/src/args.rs +++ b/src/args.rs @@ -42,6 +42,10 @@ pub enum Operation { #[clap(name = "clone", aliases = & ["init", "i", "c"])] Clone, + /// Removes everything in directory except for mlc.toml + #[clap(name = "clean", aliases = & ["clean", "cl", "reset"])] + Clean, + /// Pulls in git repositories from mlc.toml branching from current directory #[clap(name = "pull", aliases = & ["u"])] Pull { diff --git a/src/main.rs b/src/main.rs index c3c0583..47e8879 100755 --- a/src/main.rs +++ b/src/main.rs @@ -69,5 +69,6 @@ fn main() { repository::generate(); } Operation::Config => operations::config(), + Operation::Clean => operations::clean(), } } diff --git a/src/operations/clean.rs b/src/operations/clean.rs new file mode 100644 index 0000000..68f21e7 --- /dev/null +++ b/src/operations/clean.rs @@ -0,0 +1,16 @@ +use crate::info; + +pub fn clean() { + info!("Resetting mlc repo, deleting all directories"); + // Get a vec of all files/dirs in the current directory + let dir_paths = std::fs::read_dir("./").unwrap(); + let mut dirs = dir_paths + .map(|x| x.unwrap().path().display().to_string()) + .collect::>(); + + // Remove all files/dirs in the current directory, excluding ./mlc.toml + dirs.retain(|x| *x != "./mlc.toml"); + for dir in dirs { + std::fs::remove_dir_all(dir).unwrap(); + } +} \ No newline at end of file diff --git a/src/operations/mod.rs b/src/operations/mod.rs index 686ef4d..bbba783 100644 --- a/src/operations/mod.rs +++ b/src/operations/mod.rs @@ -2,8 +2,10 @@ pub use build::*; pub use clone::*; pub use config::*; pub use pull::*; +pub use clean::*; mod build; mod clone; mod config; mod pull; +mod clean; From 703eb74e2526a2244e0289621e88a946b72b8ec4 Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Jul 2022 14:33:44 +0100 Subject: [PATCH 015/116] Big FMT job --- flake.nix | 62 ++++++++++++++++++++++------------------- src/args.rs | 1 - src/operations/clean.rs | 2 +- src/operations/clone.rs | 3 +- src/operations/mod.rs | 4 +-- src/operations/pull.rs | 2 +- 6 files changed, 39 insertions(+), 35 deletions(-) diff --git a/flake.nix b/flake.nix index f72710c..17be9ac 100644 --- a/flake.nix +++ b/flake.nix @@ -5,36 +5,40 @@ naersk.url = "github:nix-community/naersk"; }; - outputs = { self, nixpkgs, utils, naersk }: - utils.lib.eachDefaultSystem (system: - let - pkgs = nixpkgs.legacyPackages."${system}"; - naersk-lib = naersk.lib."${system}"; - in rec - { - packages.malachite = naersk-lib.buildPackage { - pname = "mlc"; - root = ./.; - }; - - packages.default = packages.malachite; + outputs = { + self, + nixpkgs, + utils, + naersk, + }: + utils.lib.eachDefaultSystem (system: let + pkgs = nixpkgs.legacyPackages."${system}"; + naersk-lib = naersk.lib."${system}"; + in rec + { + packages.malachite = naersk-lib.buildPackage { + pname = "mlc"; + root = ./.; + }; - apps.malachite = utils.lib.mkApp { - drv = packages.malachite; - }; - - apps.default = apps.malachite; + packages.default = packages.malachite; - devShells.default = pkgs.mkShell { - nativeBuildInputs = with pkgs; [ - rustc - cargo - rustfmt - cargo-audit - clippy - ]; - }; + apps.malachite = utils.lib.mkApp { + drv = packages.malachite; + }; - formatter = pkgs.alejandra; - }); + apps.default = apps.malachite; + + devShells.default = pkgs.mkShell { + nativeBuildInputs = with pkgs; [ + rustc + cargo + rustfmt + cargo-audit + clippy + ]; + }; + + formatter = pkgs.alejandra; + }); } diff --git a/src/args.rs b/src/args.rs index 4eb3eb4..081ff16 100644 --- a/src/args.rs +++ b/src/args.rs @@ -17,7 +17,6 @@ pub struct Args { /// Excludes packages from given operation, if applicable #[clap(short = 'x', long = "exclude", action = ArgAction::Append, takes_value = true)] pub exclude: Vec, - } #[derive(Debug, Clone, Subcommand)] diff --git a/src/operations/clean.rs b/src/operations/clean.rs index 68f21e7..e39cea5 100644 --- a/src/operations/clean.rs +++ b/src/operations/clean.rs @@ -13,4 +13,4 @@ pub fn clean() { for dir in dirs { std::fs::remove_dir_all(dir).unwrap(); } -} \ No newline at end of file +} diff --git a/src/operations/clone.rs b/src/operations/clone.rs index 365a592..0d5c1ab 100644 --- a/src/operations/clone.rs +++ b/src/operations/clone.rs @@ -1,6 +1,7 @@ -use crate::{info, workspace}; use std::process::Command; +use crate::{info, workspace}; + pub fn clone() { // Read config struct from mlc.toml let config = workspace::read_cfg(); diff --git a/src/operations/mod.rs b/src/operations/mod.rs index bbba783..1a251dd 100644 --- a/src/operations/mod.rs +++ b/src/operations/mod.rs @@ -1,11 +1,11 @@ pub use build::*; +pub use clean::*; pub use clone::*; pub use config::*; pub use pull::*; -pub use clean::*; mod build; +mod clean; mod clone; mod config; mod pull; -mod clean; diff --git a/src/operations/pull.rs b/src/operations/pull.rs index c550206..50c829d 100644 --- a/src/operations/pull.rs +++ b/src/operations/pull.rs @@ -1,8 +1,8 @@ -use crate::{crash, internal::AppExitCode}; use std::env; use std::process::Command; use crate::info; +use crate::{crash, internal::AppExitCode}; fn do_the_pulling(repos: Vec) { for repo in repos { From efa953c43af5790b72ad9126b32060d82f127715 Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Jul 2022 15:04:05 +0100 Subject: [PATCH 016/116] Base implementation of verbose logging --- src/internal/strings.rs | 14 ++++++++++++++ src/operations/build.rs | 21 ++++++++++++++++++++- src/operations/clean.rs | 4 +++- src/operations/clone.rs | 8 +++++++- src/operations/config.rs | 4 +++- src/operations/pull.rs | 16 +++++++++++++--- src/repository/config.rs | 4 +++- src/repository/package.rs | 13 ++++++++++--- src/repository/repo.rs | 10 +++++++++- 9 files changed, 82 insertions(+), 12 deletions(-) diff --git a/src/internal/strings.rs b/src/internal/strings.rs index 903f9e4..737678d 100755 --- a/src/internal/strings.rs +++ b/src/internal/strings.rs @@ -1,5 +1,6 @@ use colored::*; use std::process::exit; +use std::time::UNIX_EPOCH; use crate::internal::AppExitCode; @@ -13,6 +14,13 @@ macro_rules! info { } } +#[macro_export] +macro_rules! log { + ($($arg:tt)+) => { + $crate::internal::strings::log_fn(format!($($arg)+)) + } +} + #[macro_export] macro_rules! crash { ($exit_code:expr, $($arg:tt)+) => { @@ -20,11 +28,17 @@ macro_rules! crash { } } + pub fn info_fn(msg: S) { let msg = msg.to_string(); println!("{} {}", LOGO_SYMBOL.black(), msg.bold()) } +pub fn log_fn(msg: S) { + let msg = msg.to_string(); + eprintln!("{} {}", std::time::SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(), msg) +} + pub fn crash_fn(msg: S, exit_code: AppExitCode) { let msg = msg.to_string(); println!("{} {}", ERR_SYMBOL.red(), msg.bold()); diff --git a/src/operations/build.rs b/src/operations/build.rs index abd6d82..b16e68b 100644 --- a/src/operations/build.rs +++ b/src/operations/build.rs @@ -1,23 +1,31 @@ use crate::internal::structs::{ErroredPackage, Repo}; use crate::internal::AppExitCode; -use crate::{crash, info, repository, workspace}; +use crate::{crash, info, log, repository, workspace}; pub fn build(packages: Vec, exclude: Vec, no_regen: bool) { // Read config struct from mlc.toml let config = workspace::read_cfg(); + log!("Config: {:?}", config); let all = packages.is_empty(); + log!("All: {:?}", all); + log!("Signing: {:?}", config.sign); // Get list of repos and subtract exclude let mut repos: Vec = config.repo; + log!("{} Repos: {:?}", repos.len(), repos ); if !exclude.is_empty() { + log!("Exclude not empty: {:?}", exclude); for ex in exclude { repos.retain(|x| *x.name != ex); } } + log!("Exclusions parsed. Now {} Repos: {:?}", repos.len(), repos); + // If packages is not empty and all isn't specified, build specified packages let mut errored: Vec = vec![]; if !packages.is_empty() && !all { + log!("Packages not empty: {:?}", packages); for pkg in &packages { // If repo is not in config, crash if !repos.iter().map(|x| x.name.clone()).any(|x| x == *pkg) { @@ -28,7 +36,9 @@ pub fn build(packages: Vec, exclude: Vec, no_regen: bool) { ); } else { // Otherwise, build + log!("Building {}", pkg); let code = repository::build(pkg, config.sign); + log!("Package {} finished with exit code: {:?}", pkg, code); if code != 0 { let error = ErroredPackage { name: pkg.to_string(), @@ -42,10 +52,16 @@ pub fn build(packages: Vec, exclude: Vec, no_regen: bool) { // If all is specified, attempt to build a package from all repos if all { + log!("Proceeding to build all"); + // Sort by package priority + log!("Sorting by priority: {:?}", repos); repos.sort_by(|a, b| b.priority.cmp(&a.priority)); + log!("Sorted: {:?}", repos); for pkg in repos { + log!("Building {}", pkg.name); let code = repository::build(&pkg.name, config.sign); + log!("Package {} finished with exit code: {:?}", pkg.name, code); if code != 0 { let error = ErroredPackage { name: pkg.name, @@ -58,11 +74,13 @@ pub fn build(packages: Vec, exclude: Vec, no_regen: bool) { // If all is not specified, but packages is empty, crash if !all && packages.is_empty() { + log!("Packages empty. Crashing"); crash!(AppExitCode::NoPkgs, "No packages specified"); } // If no_regen is passed, do not generate a repository if !no_regen { + log!("Generating repository"); repository::generate(); } @@ -74,6 +92,7 @@ pub fn build(packages: Vec, exclude: Vec, no_regen: bool) { // If errored is not empty, let the user know which packages failed if !errored.is_empty() { + log!("Errored packages: \n{:?}", error_strings); info!( "The following packages build jobs returned a non-zero exit code: {}", error_strings.join("\n") diff --git a/src/operations/clean.rs b/src/operations/clean.rs index e39cea5..a2d4c9f 100644 --- a/src/operations/clean.rs +++ b/src/operations/clean.rs @@ -1,15 +1,17 @@ -use crate::info; +use crate::{info, log}; pub fn clean() { info!("Resetting mlc repo, deleting all directories"); // Get a vec of all files/dirs in the current directory let dir_paths = std::fs::read_dir("./").unwrap(); + log!("Paths: {:?}", dir_paths); let mut dirs = dir_paths .map(|x| x.unwrap().path().display().to_string()) .collect::>(); // Remove all files/dirs in the current directory, excluding ./mlc.toml dirs.retain(|x| *x != "./mlc.toml"); + log!("Paths with mlc.toml excluded: {:?}", dirs); for dir in dirs { std::fs::remove_dir_all(dir).unwrap(); } diff --git a/src/operations/clone.rs b/src/operations/clone.rs index 0d5c1ab..12bc803 100644 --- a/src/operations/clone.rs +++ b/src/operations/clone.rs @@ -1,11 +1,13 @@ use std::process::Command; -use crate::{info, workspace}; +use crate::{info, workspace, log}; pub fn clone() { // Read config struct from mlc.toml let config = workspace::read_cfg(); + log!("Config: {:?}", config); let repos = &config.repo; + log!("Repos: {:?}", repos); // Get a vector of all files/dirs in the current directory, excluding config file let dir_paths = std::fs::read_dir("./").unwrap(); @@ -13,6 +15,7 @@ pub fn clone() { .map(|x| x.unwrap().path().display().to_string()) .collect::>(); dirs.retain(|x| *x != "./mlc.toml"); + log!("Paths with mlc.toml excluded: {:?}", dirs); // Creates a vector of the difference between cloned repos and repos defined in config let mut repo_diff = vec![]; @@ -26,8 +29,10 @@ pub fn clone() { // Diff logic if repo_diff.is_empty() { // No diff, do nothing + log!("No diff"); info!("All repos are already cloned"); } else { + log!("Diff: {:?}", repo_diff); // This is just for pretty display purposes let display = repo_diff .iter() @@ -38,6 +43,7 @@ pub fn clone() { // Clone all diff repos for r in repo_diff { + log!("Cloning {}", r.name); info!("Cloning ({} mode): {}", config.mode, r.name); Command::new("git") .args(&["clone", &r.url, &r.name]) diff --git a/src/operations/config.rs b/src/operations/config.rs index a880549..e06b9de 100644 --- a/src/operations/config.rs +++ b/src/operations/config.rs @@ -2,16 +2,18 @@ use std::env; use std::path::Path; use std::process::Command; -use crate::create_config; +use crate::{create_config, log}; pub fn config() { // Generate new config file if not already present if !Path::exists("mlc.toml".as_ref()) { + log!("Creating mlc.toml"); create_config(); } // Open config file in user's editor of choice let editor = env::var("EDITOR").unwrap_or_else(|_| "nano".to_string()); + log!("Opening mlc.toml in {}", editor); Command::new(editor) .arg("mlc.toml") .spawn() diff --git a/src/operations/pull.rs b/src/operations/pull.rs index 50c829d..004313c 100644 --- a/src/operations/pull.rs +++ b/src/operations/pull.rs @@ -2,14 +2,17 @@ use std::env; use std::process::Command; use crate::info; -use crate::{crash, internal::AppExitCode}; +use crate::{crash, internal::AppExitCode, log}; fn do_the_pulling(repos: Vec) { for repo in repos { // Set root dir to return after each git pull let root_dir = env::current_dir().unwrap(); + log!("Root dir: {:?}", root_dir); info!("Entering working directory: {}", &repo); env::set_current_dir(repo).unwrap(); + log!("Current dir: {:?}", env::current_dir().unwrap()); + log!("Pulling"); Command::new("git") .arg("pull") .spawn() @@ -19,12 +22,14 @@ fn do_the_pulling(repos: Vec) { // Return to root dir env::set_current_dir(root_dir).unwrap(); + log!("Returned to root dir: {:?}", env::current_dir().unwrap()); } } pub fn pull(packages: Vec, exclude: Vec) { // If no packages are specified, imply all let all = packages.is_empty(); + log!("All: {}", all); // Read repos from config file let repos = crate::workspace::read_cfg() @@ -32,16 +37,20 @@ pub fn pull(packages: Vec, exclude: Vec) { .iter() .map(|x| x.name.clone()) .collect::>(); + log!("Repos: {:?}", repos); // Set repos_applicable for next function let mut repos_applicable = if all { repos } else { packages }; + log!("Repos applicable: {:?}", repos_applicable); // Subtract exclude from repos_applicable if !exclude.is_empty() { - for ex in exclude { - repos_applicable.retain(|x| *x != ex); + for ex in &exclude { + repos_applicable.retain(|x| *x != *ex); } } + log!("Exclude: {:?}", exclude); + log!("Repos applicable excluded: {:?}", repos_applicable); // If all is not specified and packages is empty, crash if repos_applicable.is_empty() { @@ -49,5 +58,6 @@ pub fn pull(packages: Vec, exclude: Vec) { } // Pull! + log!("Pulling {:?}", repos_applicable); do_the_pulling(repos_applicable); } diff --git a/src/repository/config.rs b/src/repository/config.rs index 22c2506..7ac3b2a 100644 --- a/src/repository/config.rs +++ b/src/repository/config.rs @@ -3,7 +3,7 @@ use std::fs::File; use std::io::Write; use std::path::Path; -use crate::crash; +use crate::{crash, log}; use crate::internal::AppExitCode; const DEFAULT_CONFIG: &str = r#" @@ -43,10 +43,12 @@ pub fn create_config() { "Directory is not empty, please only create a repository in an empty directory" ); } + log!("Creating config file"); // If config file exists, create it if !Path::exists("mlc.toml".as_ref()) { let mut file = File::create("mlc.toml").unwrap(); file.write_all(DEFAULT_CONFIG.as_ref()).unwrap(); } + log!("Config file created"); } diff --git a/src/repository/package.rs b/src/repository/package.rs index c8645db..1ae02df 100755 --- a/src/repository/package.rs +++ b/src/repository/package.rs @@ -2,20 +2,23 @@ use std::path::Path; use std::process::Command; use std::{env, fs}; -use crate::crash; +use crate::{crash, log}; use crate::internal::AppExitCode; pub fn build(pkg: &str, sign: bool) -> i32 { + log!("Building {}", pkg); + log!("Signing: {}", sign); // Set root dir to return after build - let dir = env::current_dir().unwrap(); + log!("Root dir: {:?}", dir); // Create out dir if not already present if !Path::exists("out".as_ref()) { + log!("Creating out dir"); fs::create_dir_all("out").unwrap(); } - // If directory is not found, crash + // If package directory is not found, crash if !Path::exists(pkg.as_ref()) { crash!( AppExitCode::RepoNotFound, @@ -26,6 +29,7 @@ pub fn build(pkg: &str, sign: bool) -> i32 { // Enter build directory env::set_current_dir(pkg).unwrap(); + log!("Current dir: {:?}", env::current_dir().unwrap()); // Build each package let a = Command::new("makepkg") @@ -39,6 +43,7 @@ pub fn build(pkg: &str, sign: bool) -> i32 { .unwrap() .wait() .unwrap(); + log!("{} Build job returned: {:?}", pkg, a); // Copy built package to out dir Command::new("bash") @@ -47,9 +52,11 @@ pub fn build(pkg: &str, sign: bool) -> i32 { .unwrap() .wait() .unwrap(); + log!("Copied built package to out dir"); // Return to root dir env::set_current_dir(dir).unwrap(); + log!("Returned to root dir: {:?}", env::current_dir().unwrap()); // Return exit code a.code().unwrap() diff --git a/src/repository/repo.rs b/src/repository/repo.rs index 65fdc0c..9fcb254 100644 --- a/src/repository/repo.rs +++ b/src/repository/repo.rs @@ -2,22 +2,26 @@ use std::path::Path; use std::process::Command; use std::{env, fs}; -use crate::workspace::read_cfg; +use crate::{workspace::read_cfg, log}; pub fn generate() { // Read config struct from mlc.toml let config = read_cfg(); + log!("Config: {:?}", config); // Get repository name from config let name = config.name.unwrap(); + log!("Name: {}", name); // If repository exists, delete it if Path::exists(name.as_ref()) { + log!("Deleting {}", name); fs::remove_dir_all(&name).unwrap(); } // Create or recreate repository directory fs::create_dir_all(&name).unwrap(); + log!("Created {}", name); // Copy out packages to repository directory Command::new("bash") @@ -26,9 +30,11 @@ pub fn generate() { .unwrap() .wait() .unwrap(); + log!("Copied out packages to {}", name); // Enter repository directory env::set_current_dir(&name).unwrap(); + log!("Current dir: {:?}", env::current_dir().unwrap()); let db = format!("{}.db", &name); let files = format!("{}.files", &name); @@ -43,6 +49,7 @@ pub fn generate() { .unwrap() .wait() .unwrap(); + log!("Created {} and {}", db, files); // Replace repo.{db,files}.tar.gz with just repo.{db,files} Command::new("bash") @@ -54,4 +61,5 @@ pub fn generate() { .unwrap() .wait() .unwrap(); + log!("Renamed {}.tar.gz to {} and {}.tar.gz to {}", db, db, files, files); } From 229aa83e5384d84b528fa8fe2161947c7e9997fb Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Jul 2022 15:35:40 +0100 Subject: [PATCH 017/116] Implement debug logging, they said. It'll be fun, they said. --- src/args.rs | 4 +-- src/internal/strings.rs | 20 ++++++++---- src/main.rs | 15 ++++----- src/operations/build.rs | 65 ++++++++++++++++++++++++--------------- src/operations/clean.rs | 6 ++-- src/operations/clone.rs | 18 +++++------ src/operations/config.rs | 8 ++--- src/operations/pull.rs | 34 +++++++++++--------- src/repository/config.rs | 6 ++-- src/repository/package.rs | 24 +++++++++------ src/repository/repo.rs | 31 +++++++++++-------- src/workspace/read.rs | 16 +++++++--- 12 files changed, 146 insertions(+), 101 deletions(-) diff --git a/src/args.rs b/src/args.rs index 081ff16..42b6ed9 100644 --- a/src/args.rs +++ b/src/args.rs @@ -7,8 +7,8 @@ pub struct Args { pub subcommand: Option, /// Sets the level of verbosity - #[clap(long, short, global(true), action = ArgAction::Count)] - pub verbose: u8, + #[clap(long, short, global(true), action = ArgAction::SetTrue)] + pub verbose: bool, /// Complete operations without prompting user #[clap(long = "noconfirm", global(true), action = ArgAction::SetTrue)] diff --git a/src/internal/strings.rs b/src/internal/strings.rs index 737678d..287f027 100755 --- a/src/internal/strings.rs +++ b/src/internal/strings.rs @@ -10,14 +10,14 @@ const ERR_SYMBOL: &str = "❌"; #[macro_export] macro_rules! info { ($($arg:tt)+) => { - $crate::internal::strings::info_fn(format!($($arg)+)) + $crate::internal::strings::info_fn(format!($($arg)+)); } } #[macro_export] macro_rules! log { - ($($arg:tt)+) => { - $crate::internal::strings::log_fn(format!($($arg)+)) + ($verbose:expr, $($arg:tt)+) => { + $crate::internal::strings::log_fn(format!($($arg)+), $verbose); } } @@ -28,15 +28,23 @@ macro_rules! crash { } } - pub fn info_fn(msg: S) { let msg = msg.to_string(); println!("{} {}", LOGO_SYMBOL.black(), msg.bold()) } -pub fn log_fn(msg: S) { +pub fn log_fn(msg: S, verbose: bool) { let msg = msg.to_string(); - eprintln!("{} {}", std::time::SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(), msg) + if verbose { + eprintln!( + "{} {}", + std::time::SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(), + msg + ); + } } pub fn crash_fn(msg: S, exit_code: AppExitCode) { diff --git a/src/main.rs b/src/main.rs index 47e8879..97e1297 100755 --- a/src/main.rs +++ b/src/main.rs @@ -37,6 +37,7 @@ fn main() { } let exclude = &args.exclude; + let verbose = args.verbose; if Path::exists("../.git".as_ref()) { info!("Parent directory is a git directory, pulling latest mlc.toml. It is advised you run mlc pull/update in all malachite directories"); @@ -52,13 +53,13 @@ fn main() { } match args.subcommand.unwrap_or(Operation::Clone) { - Operation::Clone => operations::clone(), + Operation::Clone => operations::clone(verbose), Operation::Build { packages, no_regen, .. - } => operations::build(packages, exclude.to_vec(), no_regen), - Operation::Pull { packages, .. } => operations::pull(packages, exclude.to_vec()), + } => operations::build(packages, exclude.to_vec(), no_regen, verbose), + Operation::Pull { packages, .. } => operations::pull(packages, exclude.to_vec(), verbose), Operation::RepoGen => { - let config = read_cfg(); + let config = read_cfg(verbose); if config.mode != "repository" { crash!( AppExitCode::BuildInWorkspace, @@ -66,9 +67,9 @@ fn main() { ) } info!("Generating repository: {}", config.name.unwrap()); - repository::generate(); + repository::generate(verbose); } - Operation::Config => operations::config(), - Operation::Clean => operations::clean(), + Operation::Config => operations::config(verbose), + Operation::Clean => operations::clean(verbose), } } diff --git a/src/operations/build.rs b/src/operations/build.rs index b16e68b..d7a5015 100644 --- a/src/operations/build.rs +++ b/src/operations/build.rs @@ -1,31 +1,36 @@ -use crate::internal::structs::{ErroredPackage, Repo}; -use crate::internal::AppExitCode; use crate::{crash, info, log, repository, workspace}; +use crate::internal::AppExitCode; +use crate::internal::structs::{ErroredPackage, Repo}; -pub fn build(packages: Vec, exclude: Vec, no_regen: bool) { +pub fn build(packages: Vec, exclude: Vec, no_regen: bool, verbose: bool) { // Read config struct from mlc.toml - let config = workspace::read_cfg(); - log!("Config: {:?}", config); + let config = workspace::read_cfg(verbose); + log!(verbose, "Config: {:?}", config); let all = packages.is_empty(); - log!("All: {:?}", all); - log!("Signing: {:?}", config.sign); + log!(verbose, "All: {:?}", all); + log!(verbose, "Signing: {:?}", config.sign); // Get list of repos and subtract exclude let mut repos: Vec = config.repo; - log!("{} Repos: {:?}", repos.len(), repos ); + log!(verbose, "{} Repos: {:?}", repos.len(), repos); if !exclude.is_empty() { - log!("Exclude not empty: {:?}", exclude); + log!(verbose, "Exclude not empty: {:?}", exclude); for ex in exclude { repos.retain(|x| *x.name != ex); } } - log!("Exclusions parsed. Now {} Repos: {:?}", repos.len(), repos); + log!( + verbose, + "Exclusions parsed. Now {} Repos: {:?}", + repos.len(), + repos + ); // If packages is not empty and all isn't specified, build specified packages let mut errored: Vec = vec![]; if !packages.is_empty() && !all { - log!("Packages not empty: {:?}", packages); + log!(verbose, "Packages not empty: {:?}", packages); for pkg in &packages { // If repo is not in config, crash if !repos.iter().map(|x| x.name.clone()).any(|x| x == *pkg) { @@ -36,9 +41,14 @@ pub fn build(packages: Vec, exclude: Vec, no_regen: bool) { ); } else { // Otherwise, build - log!("Building {}", pkg); - let code = repository::build(pkg, config.sign); - log!("Package {} finished with exit code: {:?}", pkg, code); + log!(verbose, "Building {}", pkg); + let code = repository::build(pkg, config.sign, verbose); + log!( + verbose, + "Package {} finished with exit code: {:?}", + pkg, + code + ); if code != 0 { let error = ErroredPackage { name: pkg.to_string(), @@ -52,16 +62,21 @@ pub fn build(packages: Vec, exclude: Vec, no_regen: bool) { // If all is specified, attempt to build a package from all repos if all { - log!("Proceeding to build all"); + log!(verbose, "Proceeding to build all"); // Sort by package priority - log!("Sorting by priority: {:?}", repos); + log!(verbose, "Sorting by priority: {:?}", repos); repos.sort_by(|a, b| b.priority.cmp(&a.priority)); - log!("Sorted: {:?}", repos); + log!(verbose, "Sorted: {:?}", repos); for pkg in repos { - log!("Building {}", pkg.name); - let code = repository::build(&pkg.name, config.sign); - log!("Package {} finished with exit code: {:?}", pkg.name, code); + log!(verbose, "Building {}", pkg.name); + let code = repository::build(&pkg.name, config.sign, verbose); + log!( + verbose, + "Package {} finished with exit code: {:?}", + pkg.name, + code + ); if code != 0 { let error = ErroredPackage { name: pkg.name, @@ -74,14 +89,14 @@ pub fn build(packages: Vec, exclude: Vec, no_regen: bool) { // If all is not specified, but packages is empty, crash if !all && packages.is_empty() { - log!("Packages empty. Crashing"); + log!(verbose, "Packages empty. Crashing"); crash!(AppExitCode::NoPkgs, "No packages specified"); } // If no_regen is passed, do not generate a repository if !no_regen { - log!("Generating repository"); - repository::generate(); + log!(verbose, "Generating repository"); + repository::generate(verbose); } // Map errored packages to a string for display @@ -92,10 +107,10 @@ pub fn build(packages: Vec, exclude: Vec, no_regen: bool) { // If errored is not empty, let the user know which packages failed if !errored.is_empty() { - log!("Errored packages: \n{:?}", error_strings); + log!(verbose, "Errored packages: \n{:?}", error_strings); info!( "The following packages build jobs returned a non-zero exit code: {}", error_strings.join("\n") - ) + ); } } diff --git a/src/operations/clean.rs b/src/operations/clean.rs index a2d4c9f..f454ada 100644 --- a/src/operations/clean.rs +++ b/src/operations/clean.rs @@ -1,17 +1,17 @@ use crate::{info, log}; -pub fn clean() { +pub fn clean(verbose: bool) { info!("Resetting mlc repo, deleting all directories"); // Get a vec of all files/dirs in the current directory let dir_paths = std::fs::read_dir("./").unwrap(); - log!("Paths: {:?}", dir_paths); + log!(verbose, "Paths: {:?}", dir_paths); let mut dirs = dir_paths .map(|x| x.unwrap().path().display().to_string()) .collect::>(); // Remove all files/dirs in the current directory, excluding ./mlc.toml dirs.retain(|x| *x != "./mlc.toml"); - log!("Paths with mlc.toml excluded: {:?}", dirs); + log!(verbose, "Paths with mlc.toml excluded: {:?}", dirs); for dir in dirs { std::fs::remove_dir_all(dir).unwrap(); } diff --git a/src/operations/clone.rs b/src/operations/clone.rs index 12bc803..837909e 100644 --- a/src/operations/clone.rs +++ b/src/operations/clone.rs @@ -1,13 +1,13 @@ use std::process::Command; -use crate::{info, workspace, log}; +use crate::{info, log, workspace}; -pub fn clone() { +pub fn clone(verbose: bool) { // Read config struct from mlc.toml - let config = workspace::read_cfg(); - log!("Config: {:?}", config); + let config = workspace::read_cfg(verbose); + log!(verbose, "Config: {:?}", config); let repos = &config.repo; - log!("Repos: {:?}", repos); + log!(verbose, "Repos: {:?}", repos); // Get a vector of all files/dirs in the current directory, excluding config file let dir_paths = std::fs::read_dir("./").unwrap(); @@ -15,7 +15,7 @@ pub fn clone() { .map(|x| x.unwrap().path().display().to_string()) .collect::>(); dirs.retain(|x| *x != "./mlc.toml"); - log!("Paths with mlc.toml excluded: {:?}", dirs); + log!(verbose, "Paths with mlc.toml excluded: {:?}", dirs); // Creates a vector of the difference between cloned repos and repos defined in config let mut repo_diff = vec![]; @@ -29,10 +29,10 @@ pub fn clone() { // Diff logic if repo_diff.is_empty() { // No diff, do nothing - log!("No diff"); + log!(verbose, "No diff"); info!("All repos are already cloned"); } else { - log!("Diff: {:?}", repo_diff); + log!(verbose, "Diff: {:?}", repo_diff); // This is just for pretty display purposes let display = repo_diff .iter() @@ -43,7 +43,7 @@ pub fn clone() { // Clone all diff repos for r in repo_diff { - log!("Cloning {}", r.name); + log!(verbose, "Cloning {}", r.name); info!("Cloning ({} mode): {}", config.mode, r.name); Command::new("git") .args(&["clone", &r.url, &r.name]) diff --git a/src/operations/config.rs b/src/operations/config.rs index e06b9de..ea8f701 100644 --- a/src/operations/config.rs +++ b/src/operations/config.rs @@ -4,16 +4,16 @@ use std::process::Command; use crate::{create_config, log}; -pub fn config() { +pub fn config(verbose: bool) { // Generate new config file if not already present if !Path::exists("mlc.toml".as_ref()) { - log!("Creating mlc.toml"); - create_config(); + log!(verbose, "Creating mlc.toml"); + create_config(verbose); } // Open config file in user's editor of choice let editor = env::var("EDITOR").unwrap_or_else(|_| "nano".to_string()); - log!("Opening mlc.toml in {}", editor); + log!(verbose, "Opening mlc.toml in {}", editor); Command::new(editor) .arg("mlc.toml") .spawn() diff --git a/src/operations/pull.rs b/src/operations/pull.rs index 004313c..cdab0fa 100644 --- a/src/operations/pull.rs +++ b/src/operations/pull.rs @@ -1,18 +1,18 @@ use std::env; use std::process::Command; -use crate::info; use crate::{crash, internal::AppExitCode, log}; +use crate::info; -fn do_the_pulling(repos: Vec) { +fn do_the_pulling(repos: Vec, verbose: bool) { for repo in repos { // Set root dir to return after each git pull let root_dir = env::current_dir().unwrap(); - log!("Root dir: {:?}", root_dir); + log!(verbose, "Root dir: {:?}", root_dir); info!("Entering working directory: {}", &repo); env::set_current_dir(repo).unwrap(); - log!("Current dir: {:?}", env::current_dir().unwrap()); - log!("Pulling"); + log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); + log!(verbose, "Pulling"); Command::new("git") .arg("pull") .spawn() @@ -22,26 +22,30 @@ fn do_the_pulling(repos: Vec) { // Return to root dir env::set_current_dir(root_dir).unwrap(); - log!("Returned to root dir: {:?}", env::current_dir().unwrap()); + log!( + verbose, + "Returned to root dir: {:?}", + env::current_dir().unwrap() + ); } } -pub fn pull(packages: Vec, exclude: Vec) { +pub fn pull(packages: Vec, exclude: Vec, verbose: bool) { // If no packages are specified, imply all let all = packages.is_empty(); - log!("All: {}", all); + log!(verbose, "All: {}", all); // Read repos from config file - let repos = crate::workspace::read_cfg() + let repos = crate::workspace::read_cfg(verbose) .repo .iter() .map(|x| x.name.clone()) .collect::>(); - log!("Repos: {:?}", repos); + log!(verbose, "Repos: {:?}", repos); // Set repos_applicable for next function let mut repos_applicable = if all { repos } else { packages }; - log!("Repos applicable: {:?}", repos_applicable); + log!(verbose, "Repos applicable: {:?}", repos_applicable); // Subtract exclude from repos_applicable if !exclude.is_empty() { @@ -49,8 +53,8 @@ pub fn pull(packages: Vec, exclude: Vec) { repos_applicable.retain(|x| *x != *ex); } } - log!("Exclude: {:?}", exclude); - log!("Repos applicable excluded: {:?}", repos_applicable); + log!(verbose, "Exclude: {:?}", exclude); + log!(verbose, "Repos applicable excluded: {:?}", repos_applicable); // If all is not specified and packages is empty, crash if repos_applicable.is_empty() { @@ -58,6 +62,6 @@ pub fn pull(packages: Vec, exclude: Vec) { } // Pull! - log!("Pulling {:?}", repos_applicable); - do_the_pulling(repos_applicable); + log!(verbose, "Pulling {:?}", repos_applicable); + do_the_pulling(repos_applicable, verbose); } diff --git a/src/repository/config.rs b/src/repository/config.rs index 7ac3b2a..29a1c3a 100644 --- a/src/repository/config.rs +++ b/src/repository/config.rs @@ -29,7 +29,7 @@ urls = [ "" ]"#; -pub fn create_config() { +pub fn create_config(verbose: bool) { // Ensure current directory is empty if env::current_dir() .unwrap() @@ -43,12 +43,12 @@ pub fn create_config() { "Directory is not empty, please only create a repository in an empty directory" ); } - log!("Creating config file"); + log!(verbose, "Creating config file"); // If config file exists, create it if !Path::exists("mlc.toml".as_ref()) { let mut file = File::create("mlc.toml").unwrap(); file.write_all(DEFAULT_CONFIG.as_ref()).unwrap(); } - log!("Config file created"); + log!(verbose, "Config file created"); } diff --git a/src/repository/package.rs b/src/repository/package.rs index 1ae02df..73d8c9e 100755 --- a/src/repository/package.rs +++ b/src/repository/package.rs @@ -1,20 +1,20 @@ +use std::{env, fs}; use std::path::Path; use std::process::Command; -use std::{env, fs}; use crate::{crash, log}; use crate::internal::AppExitCode; -pub fn build(pkg: &str, sign: bool) -> i32 { - log!("Building {}", pkg); - log!("Signing: {}", sign); +pub fn build(pkg: &str, sign: bool, verbose: bool) -> i32 { + log!(verbose, "Building {}", pkg); + log!(verbose, "Signing: {}", sign); // Set root dir to return after build let dir = env::current_dir().unwrap(); - log!("Root dir: {:?}", dir); + log!(verbose, "Root dir: {:?}", dir); // Create out dir if not already present if !Path::exists("out".as_ref()) { - log!("Creating out dir"); + log!(verbose, "Creating out dir"); fs::create_dir_all("out").unwrap(); } @@ -29,7 +29,7 @@ pub fn build(pkg: &str, sign: bool) -> i32 { // Enter build directory env::set_current_dir(pkg).unwrap(); - log!("Current dir: {:?}", env::current_dir().unwrap()); + log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); // Build each package let a = Command::new("makepkg") @@ -43,7 +43,7 @@ pub fn build(pkg: &str, sign: bool) -> i32 { .unwrap() .wait() .unwrap(); - log!("{} Build job returned: {:?}", pkg, a); + log!(verbose, "{} Build job returned: {:?}", pkg, a); // Copy built package to out dir Command::new("bash") @@ -52,11 +52,15 @@ pub fn build(pkg: &str, sign: bool) -> i32 { .unwrap() .wait() .unwrap(); - log!("Copied built package to out dir"); + log!(verbose, "Copied built package to out dir"); // Return to root dir env::set_current_dir(dir).unwrap(); - log!("Returned to root dir: {:?}", env::current_dir().unwrap()); + log!( + verbose, + "Returned to root dir: {:?}", + env::current_dir().unwrap() + ); // Return exit code a.code().unwrap() diff --git a/src/repository/repo.rs b/src/repository/repo.rs index 9fcb254..fe5b629 100644 --- a/src/repository/repo.rs +++ b/src/repository/repo.rs @@ -1,27 +1,27 @@ +use std::{env, fs}; use std::path::Path; use std::process::Command; -use std::{env, fs}; -use crate::{workspace::read_cfg, log}; +use crate::{log, workspace::read_cfg}; -pub fn generate() { +pub fn generate(verbose: bool) { // Read config struct from mlc.toml - let config = read_cfg(); - log!("Config: {:?}", config); + let config = read_cfg(verbose); + log!(verbose, "Config: {:?}", config); // Get repository name from config let name = config.name.unwrap(); - log!("Name: {}", name); + log!(verbose, "Name: {}", name); // If repository exists, delete it if Path::exists(name.as_ref()) { - log!("Deleting {}", name); + log!(verbose, "Deleting {}", name); fs::remove_dir_all(&name).unwrap(); } // Create or recreate repository directory fs::create_dir_all(&name).unwrap(); - log!("Created {}", name); + log!(verbose, "Created {}", name); // Copy out packages to repository directory Command::new("bash") @@ -30,11 +30,11 @@ pub fn generate() { .unwrap() .wait() .unwrap(); - log!("Copied out packages to {}", name); + log!(verbose, "Copied out packages to {}", name); // Enter repository directory env::set_current_dir(&name).unwrap(); - log!("Current dir: {:?}", env::current_dir().unwrap()); + log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); let db = format!("{}.db", &name); let files = format!("{}.files", &name); @@ -49,7 +49,7 @@ pub fn generate() { .unwrap() .wait() .unwrap(); - log!("Created {} and {}", db, files); + log!(verbose, "Created {} and {}", db, files); // Replace repo.{db,files}.tar.gz with just repo.{db,files} Command::new("bash") @@ -61,5 +61,12 @@ pub fn generate() { .unwrap() .wait() .unwrap(); - log!("Renamed {}.tar.gz to {} and {}.tar.gz to {}", db, db, files, files); + log!( + verbose, + "Renamed {}.tar.gz to {} and {}.tar.gz to {}", + db, + db, + files, + files + ); } diff --git a/src/workspace/read.rs b/src/workspace/read.rs index 0a144f2..681aeb9 100755 --- a/src/workspace/read.rs +++ b/src/workspace/read.rs @@ -1,11 +1,11 @@ use std::fs; use std::path::Path; -use crate::crash; -use crate::internal::structs::{Config, Repo, SplitRepo, UnexpandedConfig}; +use crate::{crash, log}; use crate::internal::AppExitCode; +use crate::internal::structs::{Config, Repo, SplitRepo, UnexpandedConfig}; -pub fn read_cfg() -> Config { +pub fn read_cfg(verbose: bool) -> Config { // Crash if mlc.toml doesn't exist if !Path::exists("mlc.toml".as_ref()) { crash!( @@ -17,6 +17,7 @@ pub fn read_cfg() -> Config { // Reading the config file to an UnexpandedConfig struct let file = fs::read_to_string("mlc.toml").unwrap(); let config: UnexpandedConfig = toml::from_str(&file).unwrap(); + log!(verbose, "Config file read: {:?}", config); // Crash if incorrect mode is set if config.mode != "workspace" && config.mode != "repository" { @@ -30,12 +31,14 @@ pub fn read_cfg() -> Config { // Parsing repos from the config file for x in config.repo { + log!(verbose, "Parsing repo: {:?}", x); // Splits the repo name and index inta a SplitRepo struct let split: Vec<&str> = x.split("::").collect(); let split_struct = SplitRepo { indx: split[0].parse().unwrap(), name: split[1].parse().unwrap(), }; + log!(verbose, "Split repo: {:?}", split_struct); // Parses all necessary values for expanding the repo to a Repo struct let index = split_struct.indx; @@ -49,14 +52,17 @@ pub fn read_cfg() -> Config { url, priority: *priority, }; + log!(verbose, "Expanded repo: {:?}", repo); expanded_repos.push(repo); } // Returns parsed config file - Config { + let conf = Config { mode: config.mode, sign: config.sign, name: config.name, repo: expanded_repos, - } + }; + log!(verbose, "Config: {:?}", conf); + conf } From f135f0edcf5a74ec9ee8240d4b62c6541e70f194 Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Jul 2022 15:38:09 +0100 Subject: [PATCH 018/116] README.md updatde --- README.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 19f1999..4988b75 100644 --- a/README.md +++ b/README.md @@ -22,14 +22,13 @@ ## Basic usage -| Action | Command | -|--------------------------------------------------------|--------------| +| Action | Command | +|--------------------------------------------------------|-----------------------| | Build a package | mlc build \ | -| Generate local repository | mlc repo-gen | -| Update local repos/PKGBUILDs | mlc pull/update | -| Create and/or open config file | mlc conf | -| Initialises repo/workspace based on config in mlc.toml | mlc init | -| Prunes old duplicate packages from repository | mlc prune | +| Generate local repository | mlc repo-gen | +| Update local repos/PKGBUILDs | mlc pull/update | +| Create and/or open config file | mlc conf | +| Initialises repo/workspace based on config in mlc.toml | mlc clone/init | ### Pacman Repository Creation From 8daede1533cfc4df77814c43cb2f2958ad6276e6 Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Jul 2022 15:40:10 +0100 Subject: [PATCH 019/116] {Cargo,flake}.lock update --- Cargo.lock | 40 ++++++++++++++++++++-------------------- flake.lock | 12 ++++++------ 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 05547c9..0783c1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -46,9 +46,9 @@ checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" [[package]] name = "clap" -version = "3.2.13" +version = "3.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac2bd7a1eb07da9ac757c923f69373deb7bc2ba5efc951b873bcb5e693992dca" +checksum = "54635806b078b7925d6e36810b1755f2a4b5b4d57560432c1ecf60bcbe10602b" dependencies = [ "atty", "bitflags", @@ -76,9 +76,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5538cd660450ebeb4234cfecf8f2284b844ffc4c50531e66d584ad5b91293613" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" dependencies = [ "os_str_bytes", ] @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heck" @@ -117,9 +117,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.2" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", "hashbrown", @@ -157,15 +157,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" [[package]] name = "os_str_bytes" -version = "6.1.0" +version = "6.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" +checksum = "648001efe5d5c0102d8cea768e348da85d90af8ba91f0bea908f157951493cd4" [[package]] name = "proc-macro-error" @@ -193,18 +193,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ "proc-macro2", ] @@ -234,9 +234,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.96" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", @@ -269,9 +269,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" +checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" [[package]] name = "version_check" diff --git a/flake.lock b/flake.lock index e3e611a..6c9d2c1 100644 --- a/flake.lock +++ b/flake.lock @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1658150454, - "narHash": "sha256-dhyOQvRT8oYWN0SwsNyujohBsJqwF5W7fnhEcfgBk7E=", + "lastModified": 1658371388, + "narHash": "sha256-ACjtJNUAqjAdR+o5EDcOGgK3aseB+IF1TSBNPVftdLg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "3110964916469ad6ed9fea72a0a3119a0959a14e", + "rev": "af7d2aaa0d7fae44cdef463538833d536e3def1f", "type": "github" }, "original": { @@ -34,11 +34,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1658260742, - "narHash": "sha256-wpamr67wf4xKa2KFg+H/kN0vRGnQ76obLu+NAw5h9Jw=", + "lastModified": 1658411452, + "narHash": "sha256-eaGBS2czRjZW/lChi9cWOQjusF/UHuHGJeYzk6QWKUw=", "owner": "nixos", "repo": "nixpkgs", - "rev": "7ecd637ffa005222a4efb7771b3e8ad69460dcb9", + "rev": "e3a3abe560a143dde4b77176575d02ff32ffebcb", "type": "github" }, "original": { From bcb070fe5b8fdff4f37d9242d00b33d68d81f323 Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Jul 2022 16:31:26 +0100 Subject: [PATCH 020/116] Beginning prune implementation --- src/args.rs | 4 ++ src/main.rs | 1 + src/operations/mod.rs | 2 + src/operations/prune.rs | 116 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 123 insertions(+) create mode 100644 src/operations/prune.rs diff --git a/src/args.rs b/src/args.rs index 42b6ed9..f0e6228 100644 --- a/src/args.rs +++ b/src/args.rs @@ -45,6 +45,10 @@ pub enum Operation { #[clap(name = "clean", aliases = & ["clean", "cl", "reset"])] Clean, + /// Removes all but the latest 3 versions of each package in a repository + #[clap(name = "prune", aliases = & ["prune", "p"])] + Prune, + /// Pulls in git repositories from mlc.toml branching from current directory #[clap(name = "pull", aliases = & ["u"])] Pull { diff --git a/src/main.rs b/src/main.rs index 97e1297..26aa8fc 100755 --- a/src/main.rs +++ b/src/main.rs @@ -70,6 +70,7 @@ fn main() { repository::generate(verbose); } Operation::Config => operations::config(verbose), + Operation::Prune => operations::prune(verbose), Operation::Clean => operations::clean(verbose), } } diff --git a/src/operations/mod.rs b/src/operations/mod.rs index 1a251dd..e2afbff 100644 --- a/src/operations/mod.rs +++ b/src/operations/mod.rs @@ -3,9 +3,11 @@ pub use clean::*; pub use clone::*; pub use config::*; pub use pull::*; +pub use prune::*; mod build; mod clean; mod clone; mod config; mod pull; +mod prune; \ No newline at end of file diff --git a/src/operations/prune.rs b/src/operations/prune.rs new file mode 100644 index 0000000..9ce0f73 --- /dev/null +++ b/src/operations/prune.rs @@ -0,0 +1,116 @@ +use std::env; +use std::path::PathBuf; +use std::fs; +use crate::info; +use crate::log; +use crate::read_cfg; + +#[derive(Debug, Clone)] +struct PackageFile { + name: String, + ver: String, + ext: String, +} + +pub fn prune(verbose: bool) { + // Read config struct from mlc.toml + let config = read_cfg(verbose); + log!(verbose, "Config: {:?}", config); + + // Read current directory + let current_dir = env::current_dir().unwrap(); + log!(verbose, "Current dir: {:?}", current_dir); + + // Enter out directory + env::set_current_dir("out").unwrap(); + log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); + + // Read all files from ./ into a Vec, except for .sig files + let mut files: Vec = vec![]; + for entry in fs::read_dir("./").unwrap() { + let entry = entry.unwrap(); + let path = entry.path(); + if path.extension().unwrap() != "sig" { + files.push(path); + } + } + log!(verbose, "Files: {:?}", files); + + // Split files into Vec, turning name-1.0.0-1-x86_64.tar.gz into PackageFile { name: "name", ver: "1.0.0-1", ext: "x86_64.tar.gz" } + let mut packages: Vec = vec![]; + for file in files { + let file = file.to_str().unwrap(); + let mut parts = file.split('-'); + let name = parts.next().unwrap(); + let ver = parts.next().unwrap(); + let rel = parts.next().unwrap(); + let ext = parts.next().unwrap(); + let package = PackageFile { + name: name.to_string(), + ver: ver.to_string() + "-" + &rel.to_string(), + ext: ext.to_string(), + }; + log!(verbose, "Package: {:?}", package); + packages.push(package); + } + + // Split packages into a Vector of Vectors by unique name + let mut packages_by_name: Vec> = vec![]; + for package in &packages { + log!(verbose, "Sorting Package: {:?}", package); + let name = &package.name; + let mut found = false; + for p in packages_by_name.iter_mut() { + if &p[0].name == name { + log!(verbose, "Found {}", name); + found = true; + p.push(package); + } + } + if !found { + log!(verbose, "Creating {}", name); + packages_by_name.push(vec![package]); + } + } + + // Sort each Vector of Vectors by version + for p in packages_by_name.iter_mut() { + log!(verbose, "Sorting {:?}", p); + p.sort_by(|a, b| b.ver.cmp(&a.ver)); + } + + // Pushes all but the 4 most recent versions of each package into a new Vector of PackageFiles + let mut packages_to_delete: Vec = vec![]; + for p in packages_by_name.iter() { + let mut to_delete = vec![]; + for i in 0..p.len() { + if i >= 4 { + log!(verbose, "Deleting {:?}", p[i]); + to_delete.push(p[i].clone()); + } + } + packages_to_delete.extend(to_delete); + } + log!(verbose, "Packages to delete: {:?}", packages_to_delete); + + // Delete all packages in packages_to_delete + for p in packages_to_delete.iter() { + let path = format!("{}-{}-{}", p.name, p.ver, p.ext); + log!(verbose, "Deleting {}", path); + std::process::Command::new("bash").args(&["-c", + &format!("rm -rf ./{} ./{}.sig", path, path) + ]) + .output() + .unwrap(); + } + + // Return to current directory + env::set_current_dir(current_dir).unwrap(); + log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); + + // Print which packages were deleted + info!("Deleted the following packages:"); + for p in packages_to_delete.iter_mut() { + info!("{}-{}-{}", p.name, p.ver, p.ext); + } +} \ No newline at end of file From 44627c25fc383ba680dff8a4908ad527786f9b32 Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Jul 2022 16:35:34 +0100 Subject: [PATCH 021/116] Prune implemented PROPERLY and in a way that WORKS --- src/operations/prune.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/operations/prune.rs b/src/operations/prune.rs index 9ce0f73..b412064 100644 --- a/src/operations/prune.rs +++ b/src/operations/prune.rs @@ -47,7 +47,7 @@ pub fn prune(verbose: bool) { let ext = parts.next().unwrap(); let package = PackageFile { name: name.to_string(), - ver: ver.to_string() + "-" + &rel.to_string(), + ver: ver.to_string() + "-" + rel, ext: ext.to_string(), }; log!(verbose, "Package: {:?}", package); @@ -83,8 +83,8 @@ pub fn prune(verbose: bool) { let mut packages_to_delete: Vec = vec![]; for p in packages_by_name.iter() { let mut to_delete = vec![]; - for i in 0..p.len() { - if i >= 4 { + for (i, _) in p.iter().enumerate() { + if i >= 3 { log!(verbose, "Deleting {:?}", p[i]); to_delete.push(p[i].clone()); } From 6694c50c4d2ec528b3ca6a54f72688bbace9ce4e Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Jul 2022 16:36:57 +0100 Subject: [PATCH 022/116] Fmt and whatnot --- src/operations/build.rs | 4 ++-- src/operations/mod.rs | 4 ++-- src/operations/prune.rs | 13 ++++++------- src/operations/pull.rs | 2 +- src/repository/config.rs | 2 +- src/repository/package.rs | 4 ++-- src/repository/repo.rs | 2 +- src/workspace/read.rs | 4 ++-- 8 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/operations/build.rs b/src/operations/build.rs index d7a5015..f22fdef 100644 --- a/src/operations/build.rs +++ b/src/operations/build.rs @@ -1,6 +1,6 @@ -use crate::{crash, info, log, repository, workspace}; -use crate::internal::AppExitCode; use crate::internal::structs::{ErroredPackage, Repo}; +use crate::internal::AppExitCode; +use crate::{crash, info, log, repository, workspace}; pub fn build(packages: Vec, exclude: Vec, no_regen: bool, verbose: bool) { // Read config struct from mlc.toml diff --git a/src/operations/mod.rs b/src/operations/mod.rs index e2afbff..6588e22 100644 --- a/src/operations/mod.rs +++ b/src/operations/mod.rs @@ -2,12 +2,12 @@ pub use build::*; pub use clean::*; pub use clone::*; pub use config::*; -pub use pull::*; pub use prune::*; +pub use pull::*; mod build; mod clean; mod clone; mod config; +mod prune; mod pull; -mod prune; \ No newline at end of file diff --git a/src/operations/prune.rs b/src/operations/prune.rs index b412064..e8372b6 100644 --- a/src/operations/prune.rs +++ b/src/operations/prune.rs @@ -1,9 +1,9 @@ -use std::env; -use std::path::PathBuf; -use std::fs; use crate::info; use crate::log; use crate::read_cfg; +use std::env; +use std::fs; +use std::path::PathBuf; #[derive(Debug, Clone)] struct PackageFile { @@ -97,9 +97,8 @@ pub fn prune(verbose: bool) { for p in packages_to_delete.iter() { let path = format!("{}-{}-{}", p.name, p.ver, p.ext); log!(verbose, "Deleting {}", path); - std::process::Command::new("bash").args(&["-c", - &format!("rm -rf ./{} ./{}.sig", path, path) - ]) + std::process::Command::new("bash") + .args(&["-c", &format!("rm -rf ./{} ./{}.sig", path, path)]) .output() .unwrap(); } @@ -113,4 +112,4 @@ pub fn prune(verbose: bool) { for p in packages_to_delete.iter_mut() { info!("{}-{}-{}", p.name, p.ver, p.ext); } -} \ No newline at end of file +} diff --git a/src/operations/pull.rs b/src/operations/pull.rs index cdab0fa..daf31e3 100644 --- a/src/operations/pull.rs +++ b/src/operations/pull.rs @@ -1,8 +1,8 @@ use std::env; use std::process::Command; -use crate::{crash, internal::AppExitCode, log}; use crate::info; +use crate::{crash, internal::AppExitCode, log}; fn do_the_pulling(repos: Vec, verbose: bool) { for repo in repos { diff --git a/src/repository/config.rs b/src/repository/config.rs index 29a1c3a..4ac4c3a 100644 --- a/src/repository/config.rs +++ b/src/repository/config.rs @@ -3,8 +3,8 @@ use std::fs::File; use std::io::Write; use std::path::Path; -use crate::{crash, log}; use crate::internal::AppExitCode; +use crate::{crash, log}; const DEFAULT_CONFIG: &str = r#" # Either "repository" or "workspace" diff --git a/src/repository/package.rs b/src/repository/package.rs index 73d8c9e..e8ac524 100755 --- a/src/repository/package.rs +++ b/src/repository/package.rs @@ -1,9 +1,9 @@ -use std::{env, fs}; use std::path::Path; use std::process::Command; +use std::{env, fs}; -use crate::{crash, log}; use crate::internal::AppExitCode; +use crate::{crash, log}; pub fn build(pkg: &str, sign: bool, verbose: bool) -> i32 { log!(verbose, "Building {}", pkg); diff --git a/src/repository/repo.rs b/src/repository/repo.rs index fe5b629..9dab54a 100644 --- a/src/repository/repo.rs +++ b/src/repository/repo.rs @@ -1,6 +1,6 @@ -use std::{env, fs}; use std::path::Path; use std::process::Command; +use std::{env, fs}; use crate::{log, workspace::read_cfg}; diff --git a/src/workspace/read.rs b/src/workspace/read.rs index 681aeb9..85781fb 100755 --- a/src/workspace/read.rs +++ b/src/workspace/read.rs @@ -1,9 +1,9 @@ use std::fs; use std::path::Path; -use crate::{crash, log}; -use crate::internal::AppExitCode; use crate::internal::structs::{Config, Repo, SplitRepo, UnexpandedConfig}; +use crate::internal::AppExitCode; +use crate::{crash, log}; pub fn read_cfg(verbose: bool) -> Config { // Crash if mlc.toml doesn't exist From eb838e818535914e6e9c0b1935cbb379dab96634 Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 21 Jul 2022 16:43:19 +0100 Subject: [PATCH 023/116] Prune formatting --- src/operations/prune.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operations/prune.rs b/src/operations/prune.rs index e8372b6..732346e 100644 --- a/src/operations/prune.rs +++ b/src/operations/prune.rs @@ -110,6 +110,6 @@ pub fn prune(verbose: bool) { // Print which packages were deleted info!("Deleted the following packages:"); for p in packages_to_delete.iter_mut() { - info!("{}-{}-{}", p.name, p.ver, p.ext); + info!("{}-{}", p.name.replace("./", ""), p.ver); } } From 340f121f983e4d6b81b9761a1d662d0cc6927bda Mon Sep 17 00:00:00 2001 From: Michal Date: Fri, 22 Jul 2022 16:50:54 +0100 Subject: [PATCH 024/116] Added new smart_pull option --- example/mlc.toml | 1 + src/internal/structs.rs | 6 +++-- src/operations/pull.rs | 54 +++++++++++++++++++++++++++++++---------- src/workspace/read.rs | 1 + 4 files changed, 47 insertions(+), 15 deletions(-) diff --git a/example/mlc.toml b/example/mlc.toml index 215276d..f1cc194 100644 --- a/example/mlc.toml +++ b/example/mlc.toml @@ -1,6 +1,7 @@ mode = "repository" name = "test" sign = false +smart_pull = true repo = [ "1::amethyst", diff --git a/src/internal/structs.rs b/src/internal/structs.rs index 2e73406..ff8b575 100755 --- a/src/internal/structs.rs +++ b/src/internal/structs.rs @@ -3,8 +3,9 @@ use serde_derive::Deserialize; #[derive(Debug, Deserialize)] pub struct Config { pub mode: String, - pub sign: bool, pub name: Option, + pub sign: bool, + pub smart_pull: bool, pub repo: Vec, } @@ -18,8 +19,9 @@ pub struct Repo { #[derive(Debug, Deserialize)] pub struct UnexpandedConfig { pub mode: String, - pub sign: bool, pub name: Option, + pub sign: bool, + pub smart_pull: bool, pub repo: Vec, pub urls: Vec, } diff --git a/src/operations/pull.rs b/src/operations/pull.rs index daf31e3..671b125 100644 --- a/src/operations/pull.rs +++ b/src/operations/pull.rs @@ -2,24 +2,48 @@ use std::env; use std::process::Command; use crate::info; -use crate::{crash, internal::AppExitCode, log}; +use crate::{crash, internal::AppExitCode, workspace::read_cfg, log}; -fn do_the_pulling(repos: Vec, verbose: bool) { +fn do_the_pulling(repos: Vec, verbose: bool, smart_pull: bool) { for repo in repos { // Set root dir to return after each git pull let root_dir = env::current_dir().unwrap(); log!(verbose, "Root dir: {:?}", root_dir); + info!("Entering working directory: {}", &repo); env::set_current_dir(repo).unwrap(); log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); - log!(verbose, "Pulling"); - Command::new("git") - .arg("pull") - .spawn() - .unwrap() - .wait() - .unwrap(); + log!(verbose, "Pulling"); + if smart_pull { + Command::new("git") + .args(&["remote", "update"]) + .spawn() + .unwrap() + .wait() + .unwrap(); + let output = Command::new("git") + .arg("status") + .output() + .unwrap(); + if String::from_utf8(output.stdout).unwrap().to_string().contains("Your branch is behind") { + Command::new("git") + .arg("pull") + .spawn() + .unwrap() + .wait() + .unwrap(); + } else { + info!("No changes to pull"); + } + } else { + Command::new("git") + .arg("pull") + .spawn() + .unwrap() + .wait() + .unwrap(); + } // Return to root dir env::set_current_dir(root_dir).unwrap(); log!( @@ -31,13 +55,17 @@ fn do_the_pulling(repos: Vec, verbose: bool) { } pub fn pull(packages: Vec, exclude: Vec, verbose: bool) { + let config = read_cfg(verbose); + log!(verbose, "Config: {:?}", config); // If no packages are specified, imply all let all = packages.is_empty(); log!(verbose, "All: {}", all); + // Read smart_pull from config + let smart_pull = config.smart_pull; + log!(verbose, "Smart pull: {}", smart_pull); - // Read repos from config file - let repos = crate::workspace::read_cfg(verbose) - .repo + // Read repos from config + let repos = config.repo .iter() .map(|x| x.name.clone()) .collect::>(); @@ -63,5 +91,5 @@ pub fn pull(packages: Vec, exclude: Vec, verbose: bool) { // Pull! log!(verbose, "Pulling {:?}", repos_applicable); - do_the_pulling(repos_applicable, verbose); + do_the_pulling(repos_applicable, verbose, smart_pull); } diff --git a/src/workspace/read.rs b/src/workspace/read.rs index 85781fb..9ae9e35 100755 --- a/src/workspace/read.rs +++ b/src/workspace/read.rs @@ -61,6 +61,7 @@ pub fn read_cfg(verbose: bool) -> Config { mode: config.mode, sign: config.sign, name: config.name, + smart_pull: config.smart_pull, repo: expanded_repos, }; log!(verbose, "Config: {:?}", conf); From 15ed191fb7f5469ee61a416ccd5e34d74a32f01a Mon Sep 17 00:00:00 2001 From: Michal Date: Fri, 22 Jul 2022 16:57:48 +0100 Subject: [PATCH 025/116] Added new comments --- src/operations/pull.rs | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/operations/pull.rs b/src/operations/pull.rs index 671b125..849a80d 100644 --- a/src/operations/pull.rs +++ b/src/operations/pull.rs @@ -2,7 +2,7 @@ use std::env; use std::process::Command; use crate::info; -use crate::{crash, internal::AppExitCode, workspace::read_cfg, log}; +use crate::{crash, internal::AppExitCode, log, workspace::read_cfg}; fn do_the_pulling(repos: Vec, verbose: bool, smart_pull: bool) { for repo in repos { @@ -10,23 +10,32 @@ fn do_the_pulling(repos: Vec, verbose: bool, smart_pull: bool) { let root_dir = env::current_dir().unwrap(); log!(verbose, "Root dir: {:?}", root_dir); + // Enter repo dir info!("Entering working directory: {}", &repo); env::set_current_dir(repo).unwrap(); log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); + // Pull log!(verbose, "Pulling"); if smart_pull { + // Just update the remote + log!(verbose, "Smart pull"); Command::new("git") .args(&["remote", "update"]) .spawn() .unwrap() .wait() .unwrap(); - let output = Command::new("git") - .arg("status") - .output() - .unwrap(); - if String::from_utf8(output.stdout).unwrap().to_string().contains("Your branch is behind") { + + // Check the repository status + let output = Command::new("git").arg("status").output().unwrap(); + + // If there are changes, pull normally + if String::from_utf8(output.stdout) + .unwrap() + .to_string() + .contains("Your branch is behind") + { Command::new("git") .arg("pull") .spawn() @@ -34,9 +43,12 @@ fn do_the_pulling(repos: Vec, verbose: bool, smart_pull: bool) { .wait() .unwrap(); } else { + // If there are no changes, alert the user info!("No changes to pull"); } } else { + // Pull normally + log!(verbose, "Normal pull"); Command::new("git") .arg("pull") .spawn() @@ -55,6 +67,7 @@ fn do_the_pulling(repos: Vec, verbose: bool, smart_pull: bool) { } pub fn pull(packages: Vec, exclude: Vec, verbose: bool) { + // Read config file let config = read_cfg(verbose); log!(verbose, "Config: {:?}", config); // If no packages are specified, imply all @@ -65,7 +78,8 @@ pub fn pull(packages: Vec, exclude: Vec, verbose: bool) { log!(verbose, "Smart pull: {}", smart_pull); // Read repos from config - let repos = config.repo + let repos = config + .repo .iter() .map(|x| x.name.clone()) .collect::>(); From bd4f864060a08661e7ad668daa64a80f9d4a4786 Mon Sep 17 00:00:00 2001 From: Michal Date: Fri, 22 Jul 2022 17:38:55 +0100 Subject: [PATCH 026/116] Implemented new config format and smart pull --- example/mlc.toml | 12 ++++++-- src/internal/exit_codes.rs | 1 + src/internal/structs.rs | 47 ++++++++++++++++++++++++++------ src/main.rs | 56 ++++++++++++++++++++++++-------------- src/operations/pull.rs | 12 ++++++-- src/repository/repo.rs | 2 +- src/workspace/read.rs | 26 ++++++++++++------ 7 files changed, 113 insertions(+), 43 deletions(-) diff --git a/example/mlc.toml b/example/mlc.toml index f1cc194..b1e407f 100644 --- a/example/mlc.toml +++ b/example/mlc.toml @@ -1,15 +1,21 @@ +[base] mode = "repository" +smart_pull = true + +[mode.repository] name = "test" sign = false -smart_pull = true +build_on_update = true -repo = [ +[mode.workspace] + +[repositories] +name = [ "1::amethyst", "1::jade!", "2::notop-git", "3::slippy-rb" ] - urls = [ "https://github.com/crystal-linux/%repo%", "https://aur.archlinux.org/%repo%", diff --git a/src/internal/exit_codes.rs b/src/internal/exit_codes.rs index 4d28575..a464d08 100644 --- a/src/internal/exit_codes.rs +++ b/src/internal/exit_codes.rs @@ -7,4 +7,5 @@ pub enum AppExitCode { RepoNotFound = 6, ConfigNotFound = 7, NoPkgs = 8, + ConfigParseError = 9, } diff --git a/src/internal/structs.rs b/src/internal/structs.rs index ff8b575..978eda0 100755 --- a/src/internal/structs.rs +++ b/src/internal/structs.rs @@ -1,37 +1,66 @@ use serde_derive::Deserialize; +//// Config structs #[derive(Debug, Deserialize)] pub struct Config { pub mode: String, - pub name: Option, + pub name: String, pub sign: bool, pub smart_pull: bool, + pub build_on_update: bool, pub repo: Vec, } #[derive(Debug, Deserialize)] -pub struct Repo { - pub name: String, - pub url: String, - pub priority: usize, +pub struct UnexpandedConfig { + pub base: ConfigBase, + pub mode: ConfigMode, + pub repositories: ConfigRepositories, } #[derive(Debug, Deserialize)] -pub struct UnexpandedConfig { +pub struct ConfigBase { pub mode: String, - pub name: Option, - pub sign: bool, pub smart_pull: bool, - pub repo: Vec, +} + +#[derive(Debug, Deserialize)] +pub struct ConfigMode { + pub repository: ConfigModeRepository, + pub workspace: ConfigModeWorkspace, +} + +#[derive(Debug, Deserialize)] +pub struct ConfigModeRepository { + pub name: String, + pub sign: bool, + pub build_on_update: bool, +} + +#[derive(Debug, Deserialize)] +pub struct ConfigModeWorkspace {} + +#[derive(Debug, Deserialize)] +pub struct ConfigRepositories { + pub name: Vec, pub urls: Vec, } +//// Repository structs +#[derive(Debug, Deserialize)] +pub struct Repo { + pub name: String, + pub url: String, + pub priority: usize, +} + #[derive(Debug)] pub struct SplitRepo { pub indx: usize, pub name: String, } +//// Build operation structs #[derive(Debug)] pub struct ErroredPackage { pub name: String, diff --git a/src/main.rs b/src/main.rs index 26aa8fc..5117a23 100755 --- a/src/main.rs +++ b/src/main.rs @@ -24,32 +24,48 @@ fn main() { let args: Args = Args::parse(); - if Path::exists("mlc.toml".as_ref()) && Path::exists(".git".as_ref()) { - info!( - "In a git repository, pulling latest mlc.toml. It is advised you run mlc pull/update" - ); - Command::new("git") - .arg("pull") - .spawn() - .unwrap() - .wait() - .unwrap(); - } - let exclude = &args.exclude; let verbose = args.verbose; if Path::exists("../.git".as_ref()) { info!("Parent directory is a git directory, pulling latest mlc.toml. It is advised you run mlc pull/update in all malachite directories"); + let dir = env::current_dir().unwrap(); env::set_current_dir("../").unwrap(); - Command::new("git") - .arg("pull") - .spawn() - .unwrap() - .wait() - .unwrap(); - env::set_current_dir(dir).unwrap(); + log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); + + if read_cfg(args.verbose).smart_pull { + log!(verbose, "Smart pull"); + Command::new("git") + .args(&["remote", "update"]) + .spawn() + .unwrap() + .wait() + .unwrap(); + let output = Command::new("git").arg("status").output().unwrap(); + if String::from_utf8(output.stdout) + .unwrap() + .contains("Your branch is behind") + { + Command::new("git") + .arg("pull") + .spawn() + .unwrap() + .wait() + .unwrap(); + } else { + info!("No changes to pull"); + } + } else { + log!(verbose, "Normal pull"); + Command::new("git") + .arg("pull") + .spawn() + .unwrap() + .wait() + .unwrap(); + env::set_current_dir(dir).unwrap(); + } } match args.subcommand.unwrap_or(Operation::Clone) { @@ -66,7 +82,7 @@ fn main() { "Cannot build packages in workspace mode" ) } - info!("Generating repository: {}", config.name.unwrap()); + info!("Generating repository: {}", config.name); repository::generate(verbose); } Operation::Config => operations::config(verbose), diff --git a/src/operations/pull.rs b/src/operations/pull.rs index 849a80d..d704b94 100644 --- a/src/operations/pull.rs +++ b/src/operations/pull.rs @@ -4,7 +4,7 @@ use std::process::Command; use crate::info; use crate::{crash, internal::AppExitCode, log, workspace::read_cfg}; -fn do_the_pulling(repos: Vec, verbose: bool, smart_pull: bool) { +fn do_the_pulling(repos: Vec, verbose: bool, smart_pull: bool, build_on_update: bool) { for repo in repos { // Set root dir to return after each git pull let root_dir = env::current_dir().unwrap(); @@ -42,6 +42,11 @@ fn do_the_pulling(repos: Vec, verbose: bool, smart_pull: bool) { .unwrap() .wait() .unwrap(); + + // If build_on_update is set, rebuild package + if build_on_update { + unimplemented!() + } } else { // If there are no changes, alert the user info!("No changes to pull"); @@ -76,6 +81,9 @@ pub fn pull(packages: Vec, exclude: Vec, verbose: bool) { // Read smart_pull from config let smart_pull = config.smart_pull; log!(verbose, "Smart pull: {}", smart_pull); + // Read build_on_update from config + let build_on_update = config.build_on_update; + log!(verbose, "Build on update: {}", build_on_update); // Read repos from config let repos = config @@ -105,5 +113,5 @@ pub fn pull(packages: Vec, exclude: Vec, verbose: bool) { // Pull! log!(verbose, "Pulling {:?}", repos_applicable); - do_the_pulling(repos_applicable, verbose, smart_pull); + do_the_pulling(repos_applicable, verbose, smart_pull, build_on_update); } diff --git a/src/repository/repo.rs b/src/repository/repo.rs index 9dab54a..2896a13 100644 --- a/src/repository/repo.rs +++ b/src/repository/repo.rs @@ -10,7 +10,7 @@ pub fn generate(verbose: bool) { log!(verbose, "Config: {:?}", config); // Get repository name from config - let name = config.name.unwrap(); + let name = config.name; log!(verbose, "Name: {}", name); // If repository exists, delete it diff --git a/src/workspace/read.rs b/src/workspace/read.rs index 9ae9e35..7df1cb0 100755 --- a/src/workspace/read.rs +++ b/src/workspace/read.rs @@ -16,11 +16,20 @@ pub fn read_cfg(verbose: bool) -> Config { // Reading the config file to an UnexpandedConfig struct let file = fs::read_to_string("mlc.toml").unwrap(); - let config: UnexpandedConfig = toml::from_str(&file).unwrap(); + let config: UnexpandedConfig = toml::from_str(&file).unwrap_or_else(|e| { + crash!( + AppExitCode::ConfigParseError, + "Error parsing config file: {}", + e + ); + // This is unreachable, but rustc complains about it otherwise + std::process::exit(1); + }); + log!(verbose, "Config file read: {:?}", config); // Crash if incorrect mode is set - if config.mode != "workspace" && config.mode != "repository" { + if config.base.mode != "workspace" && config.base.mode != "repository" { crash!( AppExitCode::InvalidMode, "Invalid mode in mlc.toml, must be either \"repository\" or \"workspace\"" @@ -30,7 +39,7 @@ pub fn read_cfg(verbose: bool) -> Config { let mut expanded_repos: Vec = vec![]; // Parsing repos from the config file - for x in config.repo { + for x in config.repositories.name { log!(verbose, "Parsing repo: {:?}", x); // Splits the repo name and index inta a SplitRepo struct let split: Vec<&str> = x.split("::").collect(); @@ -43,7 +52,7 @@ pub fn read_cfg(verbose: bool) -> Config { // Parses all necessary values for expanding the repo to a Repo struct let index = split_struct.indx; let name = split_struct.name.replace('!', ""); - let url = config.urls[index - 1].replace("%repo%", &name); + let url = config.repositories.urls[index - 1].replace("%repo%", &name); let priority = &split_struct.name.matches('!').count(); // Creates and pushes Repo struct to expanded_repos @@ -58,10 +67,11 @@ pub fn read_cfg(verbose: bool) -> Config { // Returns parsed config file let conf = Config { - mode: config.mode, - sign: config.sign, - name: config.name, - smart_pull: config.smart_pull, + mode: config.base.mode, + smart_pull: config.base.smart_pull, + sign: config.mode.repository.sign, + name: config.mode.repository.name, + build_on_update: config.mode.repository.build_on_update, repo: expanded_repos, }; log!(verbose, "Config: {:?}", conf); From 86ef1f4932bc6d16683efda299a9e2d331957ede Mon Sep 17 00:00:00 2001 From: Michal Date: Fri, 22 Jul 2022 17:41:34 +0100 Subject: [PATCH 027/116] Added new config to function --- src/repository/config.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/repository/config.rs b/src/repository/config.rs index 4ac4c3a..a442c01 100644 --- a/src/repository/config.rs +++ b/src/repository/config.rs @@ -7,18 +7,28 @@ use crate::internal::AppExitCode; use crate::{crash, log}; const DEFAULT_CONFIG: &str = r#" +[base] # Either "repository" or "workspace" mode = "" +# Better left as true, but can be set to false if it causes issues with branches +smart_pull = true +[mode.repository] # Only required when in repository mode, decides what to call the repository and relevant files name = "" # Only required when in repository mode, decides whether to PGP sign built packages sign = true +# Only required when in repository mode, decides whether to build packages if pull is successful +build_on_update = false +[mode.workspace] +# There are currently no options for workspace mode + +[repositories] # An array of Git repositories to clone from, formatted url_index::repo_name(!) # e.g. if you had URLs = [ "https://example.com/%repo%.git" ], 1::package would expand to https://example.com/package.git # Repository mode only: Depending on the number of "!"s appended to the name, the priority of the package will be determined. More "!"s = higher priority = built first. -repo = [ +name = [ "", "" ] From 2b4ace250b582de5be98921658e583814902cd56 Mon Sep 17 00:00:00 2001 From: Michal Date: Fri, 22 Jul 2022 17:42:46 +0100 Subject: [PATCH 028/116] Updated ver + pkgbuild --- Cargo.toml | 2 +- PKGBUILD | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4093d04..2c09f98 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "Malachite" -version = "1.4.0" +version = "2.0.0" authors = [ "michal " ] edition = "2021" description = "Packaging tool for pacman repositories" diff --git a/PKGBUILD b/PKGBUILD index bcfce0f..a188e56 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -1,15 +1,15 @@ # Maintainer: Matt C pkgname=malachite -pkgver=1.4.0 +pkgver=2.0.0 pkgrel=1 pkgdesc="Tool for packaging and maintaining pacman repositories" license=('GPL3') arch=('any') -url="https://git.tar.black/crystal/programs/malachite" -source=("git+https://git.tar.black/crystal/programs/malachite") +url="https://github.com/crystal-linux/malachite" +source=("git+$url") sha256sums=('SKIP') -depends=('git') +depends=('git' 'pacman-contrib') makedepends=('cargo') build() { From 1ad8b76e51fb6d2010f0d7a5118f716fdca2a1c2 Mon Sep 17 00:00:00 2001 From: Michal Date: Fri, 22 Jul 2022 17:48:38 +0100 Subject: [PATCH 029/116] Added smart pull to parent git checker --- Cargo.lock | 2 +- src/main.rs | 8 ++++++-- src/operations/pull.rs | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0783c1b..de96b8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "Malachite" -version = "1.4.0" +version = "2.0.0" dependencies = [ "clap", "colored", diff --git a/src/main.rs b/src/main.rs index 5117a23..358b96f 100755 --- a/src/main.rs +++ b/src/main.rs @@ -30,11 +30,13 @@ fn main() { if Path::exists("../.git".as_ref()) { info!("Parent directory is a git directory, pulling latest mlc.toml. It is advised you run mlc pull/update in all malachite directories"); + let config = read_cfg(verbose); + let dir = env::current_dir().unwrap(); env::set_current_dir("../").unwrap(); log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); - if read_cfg(args.verbose).smart_pull { + if config.smart_pull { log!(verbose, "Smart pull"); Command::new("git") .args(&["remote", "update"]) @@ -47,6 +49,7 @@ fn main() { .unwrap() .contains("Your branch is behind") { + info!("Branch out of date, pulling changes"); Command::new("git") .arg("pull") .spawn() @@ -64,8 +67,9 @@ fn main() { .unwrap() .wait() .unwrap(); - env::set_current_dir(dir).unwrap(); } + env::set_current_dir(dir).unwrap(); + log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); } match args.subcommand.unwrap_or(Operation::Clone) { diff --git a/src/operations/pull.rs b/src/operations/pull.rs index d704b94..c9d3bab 100644 --- a/src/operations/pull.rs +++ b/src/operations/pull.rs @@ -36,6 +36,7 @@ fn do_the_pulling(repos: Vec, verbose: bool, smart_pull: bool, build_on_ .to_string() .contains("Your branch is behind") { + info!("Branch out of date, pulling changes"); Command::new("git") .arg("pull") .spawn() From 68c2751b3d3ffa3a163842c02a827a558075a508 Mon Sep 17 00:00:00 2001 From: Michal Date: Fri, 22 Jul 2022 23:48:47 +0100 Subject: [PATCH 030/116] Fully reworked config struct + began work on signing on repo gen --- example/mlc.toml | 6 +++++- src/internal/structs.rs | 23 ++++++++++++++++------- src/main.rs | 6 +++--- src/operations/build.rs | 13 +++++++++---- src/operations/clone.rs | 4 ++-- src/operations/pull.rs | 8 ++++---- src/repository/repo.rs | 30 +++++++++++++++++++++++++++++- src/workspace/read.rs | 9 +++------ 8 files changed, 71 insertions(+), 28 deletions(-) diff --git a/example/mlc.toml b/example/mlc.toml index b1e407f..9a56512 100644 --- a/example/mlc.toml +++ b/example/mlc.toml @@ -4,9 +4,13 @@ smart_pull = true [mode.repository] name = "test" -sign = false build_on_update = true +[mode.repository.signing] +enabled = true +key = "" +on_gen = true + [mode.workspace] [repositories] diff --git a/src/internal/structs.rs b/src/internal/structs.rs index 978eda0..a44a0d6 100755 --- a/src/internal/structs.rs +++ b/src/internal/structs.rs @@ -3,12 +3,9 @@ use serde_derive::Deserialize; //// Config structs #[derive(Debug, Deserialize)] pub struct Config { - pub mode: String, - pub name: String, - pub sign: bool, - pub smart_pull: bool, - pub build_on_update: bool, - pub repo: Vec, + pub base: ConfigBase, + pub mode: ConfigMode, + pub repositories: Vec, } #[derive(Debug, Deserialize)] @@ -33,8 +30,15 @@ pub struct ConfigMode { #[derive(Debug, Deserialize)] pub struct ConfigModeRepository { pub name: String, - pub sign: bool, pub build_on_update: bool, + pub signing: ConfigModeRepositorySigning, +} + +#[derive(Debug, Deserialize)] +pub struct ConfigModeRepositorySigning { + pub enabled: bool, + pub key: String, + pub on_gen: bool, } #[derive(Debug, Deserialize)] @@ -46,6 +50,11 @@ pub struct ConfigRepositories { pub urls: Vec, } +#[derive(Debug, Deserialize)] +pub struct ConfigRepositoriesExpanded { + pub repos: Vec, +} + //// Repository structs #[derive(Debug, Deserialize)] pub struct Repo { diff --git a/src/main.rs b/src/main.rs index 358b96f..5583bea 100755 --- a/src/main.rs +++ b/src/main.rs @@ -36,7 +36,7 @@ fn main() { env::set_current_dir("../").unwrap(); log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); - if config.smart_pull { + if config.base.smart_pull { log!(verbose, "Smart pull"); Command::new("git") .args(&["remote", "update"]) @@ -80,13 +80,13 @@ fn main() { Operation::Pull { packages, .. } => operations::pull(packages, exclude.to_vec(), verbose), Operation::RepoGen => { let config = read_cfg(verbose); - if config.mode != "repository" { + if config.base.mode != "repository" { crash!( AppExitCode::BuildInWorkspace, "Cannot build packages in workspace mode" ) } - info!("Generating repository: {}", config.name); + info!("Generating repository: {}", config.mode.repository.name); repository::generate(verbose); } Operation::Config => operations::config(verbose), diff --git a/src/operations/build.rs b/src/operations/build.rs index f22fdef..302e99f 100644 --- a/src/operations/build.rs +++ b/src/operations/build.rs @@ -8,10 +8,15 @@ pub fn build(packages: Vec, exclude: Vec, no_regen: bool, verbos log!(verbose, "Config: {:?}", config); let all = packages.is_empty(); log!(verbose, "All: {:?}", all); - log!(verbose, "Signing: {:?}", config.sign); + let sign = if config.mode.repository.signing.enabled && config.mode.repository.signing.on_gen { + false + } else { + config.mode.repository.signing.enabled + }; + log!(verbose, "Signing: {:?}", config.mode.repository.signing); // Get list of repos and subtract exclude - let mut repos: Vec = config.repo; + let mut repos: Vec = config.repositories; log!(verbose, "{} Repos: {:?}", repos.len(), repos); if !exclude.is_empty() { log!(verbose, "Exclude not empty: {:?}", exclude); @@ -42,7 +47,7 @@ pub fn build(packages: Vec, exclude: Vec, no_regen: bool, verbos } else { // Otherwise, build log!(verbose, "Building {}", pkg); - let code = repository::build(pkg, config.sign, verbose); + let code = repository::build(pkg, sign, verbose); log!( verbose, "Package {} finished with exit code: {:?}", @@ -70,7 +75,7 @@ pub fn build(packages: Vec, exclude: Vec, no_regen: bool, verbos log!(verbose, "Sorted: {:?}", repos); for pkg in repos { log!(verbose, "Building {}", pkg.name); - let code = repository::build(&pkg.name, config.sign, verbose); + let code = repository::build(&pkg.name, sign, verbose); log!( verbose, "Package {} finished with exit code: {:?}", diff --git a/src/operations/clone.rs b/src/operations/clone.rs index 837909e..3d78741 100644 --- a/src/operations/clone.rs +++ b/src/operations/clone.rs @@ -6,7 +6,7 @@ pub fn clone(verbose: bool) { // Read config struct from mlc.toml let config = workspace::read_cfg(verbose); log!(verbose, "Config: {:?}", config); - let repos = &config.repo; + let repos = &config.repositories; log!(verbose, "Repos: {:?}", repos); // Get a vector of all files/dirs in the current directory, excluding config file @@ -44,7 +44,7 @@ pub fn clone(verbose: bool) { // Clone all diff repos for r in repo_diff { log!(verbose, "Cloning {}", r.name); - info!("Cloning ({} mode): {}", config.mode, r.name); + info!("Cloning ({} mode): {}", config.base.mode, r.name); Command::new("git") .args(&["clone", &r.url, &r.name]) .spawn() diff --git a/src/operations/pull.rs b/src/operations/pull.rs index c9d3bab..b6b0b7f 100644 --- a/src/operations/pull.rs +++ b/src/operations/pull.rs @@ -46,7 +46,7 @@ fn do_the_pulling(repos: Vec, verbose: bool, smart_pull: bool, build_on_ // If build_on_update is set, rebuild package if build_on_update { - unimplemented!() + unimplemented!() // TODO: Implement build_on_update } } else { // If there are no changes, alert the user @@ -80,15 +80,15 @@ pub fn pull(packages: Vec, exclude: Vec, verbose: bool) { let all = packages.is_empty(); log!(verbose, "All: {}", all); // Read smart_pull from config - let smart_pull = config.smart_pull; + let smart_pull = config.base.smart_pull; log!(verbose, "Smart pull: {}", smart_pull); // Read build_on_update from config - let build_on_update = config.build_on_update; + let build_on_update = config.mode.repository.build_on_update; log!(verbose, "Build on update: {}", build_on_update); // Read repos from config let repos = config - .repo + .repositories .iter() .map(|x| x.name.clone()) .collect::>(); diff --git a/src/repository/repo.rs b/src/repository/repo.rs index 2896a13..a283536 100644 --- a/src/repository/repo.rs +++ b/src/repository/repo.rs @@ -10,7 +10,7 @@ pub fn generate(verbose: bool) { log!(verbose, "Config: {:?}", config); // Get repository name from config - let name = config.name; + let name = config.mode.repository.name; log!(verbose, "Name: {}", name); // If repository exists, delete it @@ -32,6 +32,34 @@ pub fn generate(verbose: bool) { .unwrap(); log!(verbose, "Copied out packages to {}", name); + // Sign all package files in repository if signing and on_gen are true + if config.mode.repository.signing.enabled && config.mode.repository.signing.on_gen { + // Directory stuff + let dir = env::current_dir().unwrap(); + log!(verbose, "Current dir: {:?}", dir); + env::set_current_dir(&name).unwrap(); + log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); + // Get a list of all .tar.* files in repository + let files = fs::read_dir("./").unwrap(); + for file in files { + let file = file.unwrap(); + let path = file.path(); + if path.extension().unwrap() == "zst" || path.extension().unwrap() == "xz" { + log!(verbose, "Signing {}", path.display()); + Command::new("bash") + .args(&["-c", &format!("gpg --default-key {} --detach-sign {}", config.mode.repository.signing.key, file.file_name().to_str().unwrap())]) + .spawn() + .unwrap() + .wait() + .unwrap(); + } + } + // Return to root dir + env::set_current_dir(dir).unwrap(); + log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); + log!(verbose, "Signed repository"); + } + // Enter repository directory env::set_current_dir(&name).unwrap(); log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); diff --git a/src/workspace/read.rs b/src/workspace/read.rs index 7df1cb0..1c4e439 100755 --- a/src/workspace/read.rs +++ b/src/workspace/read.rs @@ -67,12 +67,9 @@ pub fn read_cfg(verbose: bool) -> Config { // Returns parsed config file let conf = Config { - mode: config.base.mode, - smart_pull: config.base.smart_pull, - sign: config.mode.repository.sign, - name: config.mode.repository.name, - build_on_update: config.mode.repository.build_on_update, - repo: expanded_repos, + base: config.base, + mode: config.mode, + repositories: expanded_repos, }; log!(verbose, "Config: {:?}", conf); conf From e6c10bfd4203e677dd6ae3b4648e51d8975d0f96 Mon Sep 17 00:00:00 2001 From: Michal Date: Fri, 22 Jul 2022 23:49:11 +0100 Subject: [PATCH 031/116] fmt --- src/repository/repo.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/repository/repo.rs b/src/repository/repo.rs index a283536..fcf20d6 100644 --- a/src/repository/repo.rs +++ b/src/repository/repo.rs @@ -47,7 +47,14 @@ pub fn generate(verbose: bool) { if path.extension().unwrap() == "zst" || path.extension().unwrap() == "xz" { log!(verbose, "Signing {}", path.display()); Command::new("bash") - .args(&["-c", &format!("gpg --default-key {} --detach-sign {}", config.mode.repository.signing.key, file.file_name().to_str().unwrap())]) + .args(&[ + "-c", + &format!( + "gpg --default-key {} --detach-sign {}", + config.mode.repository.signing.key, + file.file_name().to_str().unwrap() + ), + ]) .spawn() .unwrap() .wait() From fe0552a7123d1fb9ed389eb944675833d432b25c Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 00:26:38 +0100 Subject: [PATCH 032/116] Fully implemented signing after --- src/internal/exit_codes.rs | 1 + src/repository/repo.rs | 50 +++++++++++++++++++++++++++----------- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/internal/exit_codes.rs b/src/internal/exit_codes.rs index a464d08..9ff032c 100644 --- a/src/internal/exit_codes.rs +++ b/src/internal/exit_codes.rs @@ -8,4 +8,5 @@ pub enum AppExitCode { ConfigNotFound = 7, NoPkgs = 8, ConfigParseError = 9, + NoPackagesFound = 10, } diff --git a/src/repository/repo.rs b/src/repository/repo.rs index fcf20d6..01d0018 100644 --- a/src/repository/repo.rs +++ b/src/repository/repo.rs @@ -2,7 +2,7 @@ use std::path::Path; use std::process::Command; use std::{env, fs}; -use crate::{log, workspace::read_cfg}; +use crate::{log, crash, workspace::read_cfg, internal::AppExitCode}; pub fn generate(verbose: bool) { // Read config struct from mlc.toml @@ -32,13 +32,13 @@ pub fn generate(verbose: bool) { .unwrap(); log!(verbose, "Copied out packages to {}", name); + + // Enter repository directory + env::set_current_dir(&name).unwrap(); + log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); + // Sign all package files in repository if signing and on_gen are true if config.mode.repository.signing.enabled && config.mode.repository.signing.on_gen { - // Directory stuff - let dir = env::current_dir().unwrap(); - log!(verbose, "Current dir: {:?}", dir); - env::set_current_dir(&name).unwrap(); - log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); // Get a list of all .tar.* files in repository let files = fs::read_dir("./").unwrap(); for file in files { @@ -61,24 +61,46 @@ pub fn generate(verbose: bool) { .unwrap(); } } - // Return to root dir - env::set_current_dir(dir).unwrap(); - log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); log!(verbose, "Signed repository"); } - // Enter repository directory - env::set_current_dir(&name).unwrap(); - log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); - let db = format!("{}.db", &name); let files = format!("{}.files", &name); + // Check if package files end with .tar.zst or .tar.xz + let zst = Command::new("bash") + .args(&["-c", "ls *.tar.zst"]) + .spawn() + .unwrap() + .wait() + .unwrap(); + let xz = Command::new("bash") + .args(&["-c", "ls *.tar.xz"]) + .spawn() + .unwrap() + .wait() + .unwrap(); + + // Ensuring aarch64/ALARM support for the future + let aarch64_mode = if zst.success() { + false + } else if xz.success() { + true + } else { + crash!( + AppExitCode::NoPackagesFound, + "No .zst or .xz packages found in repository" + ); + // This should theoretically never be reached, but let's just give the compiler what it wants + false + }; + let suffix = if aarch64_mode { "xz" } else { "zst" }; + // Create repo.db and repo.files using repo-add Command::new("bash") .args(&[ "-c", - &format!("GLOBIGNORE=\"*.sig\" repo-add {}.tar.gz *.pkg.tar.*", db), + &format!("GLOBIGNORE=\"*.sig\" repo-add {}.tar.gz *.pkg.tar.{}", db, suffix), ]) .spawn() .unwrap() From b97a8855e46456e1068f3e5bf068521e8311ad85 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 00:28:51 +0100 Subject: [PATCH 033/116] Added gnupg dep to PKGBUILD --- PKGBUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PKGBUILD b/PKGBUILD index a188e56..c4860ce 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -9,7 +9,7 @@ arch=('any') url="https://github.com/crystal-linux/malachite" source=("git+$url") sha256sums=('SKIP') -depends=('git' 'pacman-contrib') +depends=('git' 'pacman-contrib' 'gnupg') makedepends=('cargo') build() { From a576848703cd442be7835170d76c19a86b475221 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 00:29:15 +0100 Subject: [PATCH 034/116] .gitignore update --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index c0fcff6..a810b72 100755 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,5 @@ .idea .direnv -example/* -!example/mlc.toml \ No newline at end of file +example*/* +!example*/mlc.toml \ No newline at end of file From 6074f6cab854bbbf3ff01354368b782d0941bbd2 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 00:40:38 +0100 Subject: [PATCH 035/116] reworked examples --- .gitignore | 6 ++++-- examples/repository/mlc.toml | 24 ++++++++++++++++++++++++ {example => examples/workspace}/mlc.toml | 0 src/internal/exit_codes.rs | 1 + src/repository/repo.rs | 8 ++++++++ 5 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 examples/repository/mlc.toml rename {example => examples/workspace}/mlc.toml (100%) diff --git a/.gitignore b/.gitignore index a810b72..6d5293e 100755 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,7 @@ .idea .direnv -example*/* -!example*/mlc.toml \ No newline at end of file +examples/workspace/* +examples/repository/* +!examples/workspace/mlc.toml +!examples/repository/mlc.toml \ No newline at end of file diff --git a/examples/repository/mlc.toml b/examples/repository/mlc.toml new file mode 100644 index 0000000..3e995b2 --- /dev/null +++ b/examples/repository/mlc.toml @@ -0,0 +1,24 @@ +[base] +mode = "repository" +smart_pull = true + +[mode.repository] +name = "repository-test" +build_on_update = true + +[mode.repository.signing] +enabled = true +key = "michal@tar.black" +on_gen = true + +[mode.workspace] + +[repositories] +name = [ + "1::crystal-keyring", + "2::pfetch!", +] +urls = [ + "https://github.com/crystal-linux/%repo%", + "https://github.com/crystal-linux/pkgbuild.%repo%", +] \ No newline at end of file diff --git a/example/mlc.toml b/examples/workspace/mlc.toml similarity index 100% rename from example/mlc.toml rename to examples/workspace/mlc.toml diff --git a/src/internal/exit_codes.rs b/src/internal/exit_codes.rs index 9ff032c..7ed8aff 100644 --- a/src/internal/exit_codes.rs +++ b/src/internal/exit_codes.rs @@ -9,4 +9,5 @@ pub enum AppExitCode { NoPkgs = 8, ConfigParseError = 9, NoPackagesFound = 10, + InvalidRepo = 11, } diff --git a/src/repository/repo.rs b/src/repository/repo.rs index 01d0018..6ff7530 100644 --- a/src/repository/repo.rs +++ b/src/repository/repo.rs @@ -81,6 +81,14 @@ pub fn generate(verbose: bool) { .wait() .unwrap(); + // This should never happen, crash and burn if it does + if zst.success() && xz.success() { + crash!( + AppExitCode::InvalidRepo, + "Both .tar.zst and .tar.xz files found in repository. You've done something wrong. Aborting" + ); + } + // Ensuring aarch64/ALARM support for the future let aarch64_mode = if zst.success() { false From 8970931ff17af180c3af6ae8de4986486eda63a1 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 00:47:14 +0100 Subject: [PATCH 036/116] fmt --- src/repository/repo.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/repository/repo.rs b/src/repository/repo.rs index 6ff7530..9b74303 100644 --- a/src/repository/repo.rs +++ b/src/repository/repo.rs @@ -2,7 +2,7 @@ use std::path::Path; use std::process::Command; use std::{env, fs}; -use crate::{log, crash, workspace::read_cfg, internal::AppExitCode}; +use crate::{crash, internal::AppExitCode, log, workspace::read_cfg}; pub fn generate(verbose: bool) { // Read config struct from mlc.toml @@ -32,7 +32,6 @@ pub fn generate(verbose: bool) { .unwrap(); log!(verbose, "Copied out packages to {}", name); - // Enter repository directory env::set_current_dir(&name).unwrap(); log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); @@ -92,7 +91,7 @@ pub fn generate(verbose: bool) { // Ensuring aarch64/ALARM support for the future let aarch64_mode = if zst.success() { false - } else if xz.success() { + } else if xz.success() { true } else { crash!( @@ -108,7 +107,10 @@ pub fn generate(verbose: bool) { Command::new("bash") .args(&[ "-c", - &format!("GLOBIGNORE=\"*.sig\" repo-add {}.tar.gz *.pkg.tar.{}", db, suffix), + &format!( + "GLOBIGNORE=\"*.sig\" repo-add {}.tar.gz *.pkg.tar.{}", + db, suffix + ), ]) .spawn() .unwrap() From 5b8786692221c053f2c29c3ad5c125dafc2a2ecb Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 00:59:20 +0100 Subject: [PATCH 037/116] Improved workspace/repository checks --- examples/workspace/mlc.toml | 32 ++++++++------------------------ src/main.rs | 27 ++++++++++++++++++++------- src/repository/repo.rs | 4 +++- 3 files changed, 31 insertions(+), 32 deletions(-) diff --git a/examples/workspace/mlc.toml b/examples/workspace/mlc.toml index 9a56512..77b0e6a 100644 --- a/examples/workspace/mlc.toml +++ b/examples/workspace/mlc.toml @@ -1,15 +1,15 @@ [base] -mode = "repository" +mode = "workspace" smart_pull = true [mode.repository] -name = "test" -build_on_update = true +name = "" +build_on_update = false [mode.repository.signing] -enabled = true +enabled = false key = "" -on_gen = true +on_gen = false [mode.workspace] @@ -18,26 +18,10 @@ name = [ "1::amethyst", "1::jade!", "2::notop-git", - "3::slippy-rb" + "3::appendage", ] urls = [ "https://github.com/crystal-linux/%repo%", "https://aur.archlinux.org/%repo%", - "https://github.com/jnats/%repo%" -] - -# In this example, Malachite will create a repository called "test", with 4 packages -# These packages will be expanded based on the index number they have (index_number::package) -# To demonstrate, the ones in this config will expand to the following: -# -# https://github.com/crystal-linux/ame -# https://github.com/crystal-linux/jade -# https://aur.archlinux.org/notop-git -# https://github.com/jnats/slippy-rb -# -# The "name" option specifies the name of the pacman repository. -# The "sign" option specifies whether the built packages should be signed, which is recommended for all pacman repositories. -# When in repository mode, malachite only pulls the PKGBUILD file from the git repository (all we need to build the packages from src) -# -# Additionally, packages are built in the order of priority, so packages with a higher priority (denoted by "!"s appended to the name) will be built first. -# In this case, jade has a higher priority than amethyst, so it will be built first. \ No newline at end of file + "https://github.com/not-my-segfault/%repo%" +] \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 5583bea..bce418e 100755 --- a/src/main.rs +++ b/src/main.rs @@ -23,15 +23,19 @@ fn main() { } let args: Args = Args::parse(); - let exclude = &args.exclude; let verbose = args.verbose; + log!(verbose, "Args: {:?}", args); + log!(verbose, "Exclude: {:?}", exclude); + log!(verbose, "Verbose: You guess. :)"); + + let config = read_cfg(verbose); + log!(verbose, "Config: {:?}", config); if Path::exists("../.git".as_ref()) { + log!(verbose, "Detected parent git repository"); info!("Parent directory is a git directory, pulling latest mlc.toml. It is advised you run mlc pull/update in all malachite directories"); - let config = read_cfg(verbose); - let dir = env::current_dir().unwrap(); env::set_current_dir("../").unwrap(); log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); @@ -72,21 +76,30 @@ fn main() { log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); } + let repository = config.base.mode == "repository"; + log!(verbose, "Repository Mode: {:?}", repository); + match args.subcommand.unwrap_or(Operation::Clone) { Operation::Clone => operations::clone(verbose), Operation::Build { packages, no_regen, .. - } => operations::build(packages, exclude.to_vec(), no_regen, verbose), + } => { + if !repository { + crash!( + AppExitCode::BuildInWorkspace, + "Cannot build packages in workspace mode" + ) + } + operations::build(packages, exclude.to_vec(), no_regen, verbose) + } Operation::Pull { packages, .. } => operations::pull(packages, exclude.to_vec(), verbose), Operation::RepoGen => { - let config = read_cfg(verbose); - if config.base.mode != "repository" { + if !repository { crash!( AppExitCode::BuildInWorkspace, "Cannot build packages in workspace mode" ) } - info!("Generating repository: {}", config.mode.repository.name); repository::generate(verbose); } Operation::Config => operations::config(verbose), diff --git a/src/repository/repo.rs b/src/repository/repo.rs index 9b74303..fe4177c 100644 --- a/src/repository/repo.rs +++ b/src/repository/repo.rs @@ -2,7 +2,7 @@ use std::path::Path; use std::process::Command; use std::{env, fs}; -use crate::{crash, internal::AppExitCode, log, workspace::read_cfg}; +use crate::{crash, info, internal::AppExitCode, log, workspace::read_cfg}; pub fn generate(verbose: bool) { // Read config struct from mlc.toml @@ -13,6 +13,8 @@ pub fn generate(verbose: bool) { let name = config.mode.repository.name; log!(verbose, "Name: {}", name); + info!("Generating repository: {}", name); + // If repository exists, delete it if Path::exists(name.as_ref()) { log!(verbose, "Deleting {}", name); From 33689c85df34c6d85af8802b1894c389486dbf28 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 01:11:44 +0100 Subject: [PATCH 038/116] Initial build_on_update implementation --- src/args.rs | 4 ++++ src/main.rs | 4 +++- src/operations/pull.rs | 33 ++++++++++++++++++++++++++++----- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/args.rs b/src/args.rs index f0e6228..0f9f9e2 100644 --- a/src/args.rs +++ b/src/args.rs @@ -55,6 +55,10 @@ pub enum Operation { /// The packages to operate on #[clap(name = "package(s)", help = "The packages to operate on", action = ArgAction::Append, index = 1)] packages: Vec, + + /// Does not regenerate repository after pulling given package(s). This only applies if build_on_update is set to true in repository config + #[clap(short = 'n', long = "no-regen", action = ArgAction::SetTrue)] + no_regen: bool, }, /// Create and/or open local config file diff --git a/src/main.rs b/src/main.rs index bce418e..fd56704 100755 --- a/src/main.rs +++ b/src/main.rs @@ -92,7 +92,9 @@ fn main() { } operations::build(packages, exclude.to_vec(), no_regen, verbose) } - Operation::Pull { packages, .. } => operations::pull(packages, exclude.to_vec(), verbose), + Operation::Pull { + packages, no_regen, .. + } => operations::pull(packages, exclude.to_vec(), verbose, no_regen), Operation::RepoGen => { if !repository { crash!( diff --git a/src/operations/pull.rs b/src/operations/pull.rs index b6b0b7f..c8161e6 100644 --- a/src/operations/pull.rs +++ b/src/operations/pull.rs @@ -4,7 +4,13 @@ use std::process::Command; use crate::info; use crate::{crash, internal::AppExitCode, log, workspace::read_cfg}; -fn do_the_pulling(repos: Vec, verbose: bool, smart_pull: bool, build_on_update: bool) { +fn do_the_pulling( + repos: Vec, + verbose: bool, + smart_pull: bool, + build_on_update: bool, + no_regen: bool, +) { for repo in repos { // Set root dir to return after each git pull let root_dir = env::current_dir().unwrap(); @@ -12,9 +18,11 @@ fn do_the_pulling(repos: Vec, verbose: bool, smart_pull: bool, build_on_ // Enter repo dir info!("Entering working directory: {}", &repo); - env::set_current_dir(repo).unwrap(); + env::set_current_dir(&repo).unwrap(); log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); + let mut packages_to_rebuild: Vec = vec![]; + // Pull log!(verbose, "Pulling"); if smart_pull { @@ -46,7 +54,9 @@ fn do_the_pulling(repos: Vec, verbose: bool, smart_pull: bool, build_on_ // If build_on_update is set, rebuild package if build_on_update { - unimplemented!() // TODO: Implement build_on_update + info!("Package {} updated, staging for rebuild", &repo); + log!(verbose, "Pushing package {} to be rebuilt", &repo); + packages_to_rebuild.push(repo); } } else { // If there are no changes, alert the user @@ -69,10 +79,17 @@ fn do_the_pulling(repos: Vec, verbose: bool, smart_pull: bool, build_on_ "Returned to root dir: {:?}", env::current_dir().unwrap() ); + + if !packages_to_rebuild.is_empty() && build_on_update { + info!("Rebuilding packages: {}", &packages_to_rebuild.join(", ")); + log!(verbose, "Rebuilding packages: {:?}", &packages_to_rebuild); + + crate::operations::build(packages_to_rebuild, vec![], no_regen, verbose); + } } } -pub fn pull(packages: Vec, exclude: Vec, verbose: bool) { +pub fn pull(packages: Vec, exclude: Vec, verbose: bool, no_regen: bool) { // Read config file let config = read_cfg(verbose); log!(verbose, "Config: {:?}", config); @@ -114,5 +131,11 @@ pub fn pull(packages: Vec, exclude: Vec, verbose: bool) { // Pull! log!(verbose, "Pulling {:?}", repos_applicable); - do_the_pulling(repos_applicable, verbose, smart_pull, build_on_update); + do_the_pulling( + repos_applicable, + verbose, + smart_pull, + build_on_update, + no_regen, + ); } From 6488cce299ee849d282adc4283776f2c9ad0cd26 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 01:16:38 +0100 Subject: [PATCH 039/116] No more devcontainer, sorry --- .devcontainer/Dockerfile | 20 -------------------- .devcontainer/devcontainer.json | 20 -------------------- .devcontainer/setup.sh | 10 ---------- 3 files changed, 50 deletions(-) delete mode 100644 .devcontainer/Dockerfile delete mode 100644 .devcontainer/devcontainer.json delete mode 100644 .devcontainer/setup.sh diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index c99ee3e..0000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -FROM crystallinux/crystal:crystal - -WORKDIR /home/ -COPY . . - -RUN bash ./setup.sh - -RUN useradd -m -G wheel vscode - -USER vscode -RUN rustup install nightly - -RUN sudo pacman --noconfirm -S pfetch - -RUN echo "[[ \$- != *i* ]] && return" > /home/vscode/.bashrc -RUN echo "alias ls=\"ls --color=auto\"" >> /home/vscode/.bashrc -RUN echo "alias clear=\"clear; pfetch\"" >> /home/vscode/.bashrc -RUN echo "pfetch" >> /home/vscode/.bashrc - -RUN echo "PS1=\"\[\033[38;5;8m\]\T\[$(tput sgr0)\] \[$(tput sgr0)\]\[\033[38;5;13m\]\W\[$(tput sgr0)\] \$(git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/') \[$(tput sgr0)\]\[\033[38;5;7m\][\$?]\[$(tput sgr0)\]\n\[$(tput sgr0)\]\[\033[38;5;5m\]\\$\[$(tput sgr0)\] \[$(tput sgr0)\]\"" >> /home/vscode/.bashrc diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index 4a768f6..0000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "Rust on Crystal", - "build": { - "dockerfile": "Dockerfile" - }, - "settings": { - "lldb.executable": "/usr/bin/lldb", - "files.watcherExclude": { - "**/target/**": true - } - }, - "extensions": [ - "rust-lang.rust-analyzer", - "bungcip.better-toml", - "vadimcn.vscode-lldb", - "mutantndino.resourcemonitor" - ], - "forwardPorts": [], - "remoteUser": "vscode" -} diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh deleted file mode 100644 index 7cb947f..0000000 --- a/.devcontainer/setup.sh +++ /dev/null @@ -1,10 +0,0 @@ -pacman -Syu --noconfirm - -pacman -S --noconfirm \ - curl \ - git \ - base-devel \ - lldb \ - rustup - -echo "%wheel ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers \ No newline at end of file From e6599fdf7bbe34cb0f86f60e6c2defa1cdb8568b Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 01:22:00 +0100 Subject: [PATCH 040/116] Fixed up PKGBUILD --- PKGBUILD | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/PKGBUILD b/PKGBUILD index c4860ce..723b626 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -1,24 +1,36 @@ -# Maintainer: Matt C +# Maintainer: Matt C +# Maintainer: Michal S +# Developer: Michal S pkgname=malachite pkgver=2.0.0 pkgrel=1 pkgdesc="Tool for packaging and maintaining pacman repositories" -license=('GPL3') -arch=('any') +arch=('x86_64') url="https://github.com/crystal-linux/malachite" +license=('GPL3') source=("git+$url") sha256sums=('SKIP') depends=('git' 'pacman-contrib' 'gnupg') makedepends=('cargo') +prepare() { + cd "$srcdir/$pkgname" + cargo fetch --locked --target "$CARCH-unknown-linux-gnu" +} + build() { - cd ${srcdir}/malachite - cargo build --release + cd "$srcdir/$pkgname" + export RUSTUP_TOOLCHAIN=stable + export CARGO_TARGET_DIR=target + cargo build --frozen --release --all-features } package() { - mkdir -p $pkgdir/usr/bin - chmod +x ${srcdir}/malachite/target/release/mlc - cp ${srcdir}/malachite/target/release/mlc $pkgdir/usr/bin/. -} + cd "$srcdir/$pkgname" + find target/release \ + -maxdepth 1 \ + -executable \ + -type f \ + -exec install -Dm0755 -t "${pkgdir}/usr/bin" {} + +} \ No newline at end of file From ce23d12a9962e1fa9f3c7f0eea77c876964d2d2c Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 01:25:08 +0100 Subject: [PATCH 041/116] Removed useless files --- .gitlab-ci.yml | 27 --------------------------- CONTRIBUTING.md | 28 ---------------------------- 2 files changed, 55 deletions(-) delete mode 100644 .gitlab-ci.yml delete mode 100644 CONTRIBUTING.md diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 39a6a8c..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,27 +0,0 @@ -image: "rust:latest" - -default: - before_script: - - rustc --version - - cargo --version - -stages: - - test - -lint-code: - stage: test - script: - - rustup component add clippy - - cargo clippy -- -D warnings - -format-code: - stage: test - script: - - rustup component add rustfmt - - cargo fmt -- --check - -audit-code: - stage: test - script: - - cargo install cargo-audit - - cargo audit diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 161f3a0..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,28 +0,0 @@ -# Crystal Linux Contributing Guidelines - -#### !! Always make sure to `git pull` before doing any work to avoid commit hell !! - -### Pre-Commit Checks - -- Make sure to `cargo fmt` your code before every commit push -- Unless in specific edge cases, don't push code that doesn't pass `cargo check` -- Try to correct any code with `cargo clippy` before you push - -### Formatting - -- UNIX line endings (LF instead of CRLF) -- 4 spaces per TAB - -### Good Practices - -- Try to use .unwrap() as little as possible -- Try to never use panic!() in production code, always try to have a possible way to resolve errors, even if it's just - unwrap_or/_else() -- Never use println!() or eprintln!() in finalised code. Using string functions (e.g. info() in Amethyst v3.0.0) is - preferred -- Compartmentalise as much as you can, avoid writing the exact same line of code 50 times if you can turn it into a - function - -### Examples of these guidelines in practice - -- https://git.getcryst.al/crystal/ame/src/branch/rewrite \ No newline at end of file From 1978c268f660cc8881296d84eb34f375b451122b Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 02:19:28 +0100 Subject: [PATCH 042/116] Documentation time! --- docs/COMMON_FEATURES.md | 123 ++++++++++++++++++++++++++++++++++++++++ docs/GETTING_STARTED.md | 47 +++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 docs/COMMON_FEATURES.md create mode 100644 docs/GETTING_STARTED.md diff --git a/docs/COMMON_FEATURES.md b/docs/COMMON_FEATURES.md new file mode 100644 index 0000000..0e1365c --- /dev/null +++ b/docs/COMMON_FEATURES.md @@ -0,0 +1,123 @@ +# Common Features Between Modes +As[mode]us, shared of between uh... repositories... or something. + +### What you need to know +Malachite is fairly fleshed out in Repository mode, and not so much in Workspace mode. + +This isn't of course because I'm lazy and hate Workspace mode or anything, there's just not +a whole lot *to* add. + +Without further ado, let's take a look at this example config file. + +```toml +# mlc.toml + +[base] +mode = "workspace" +smart_pull = true + +[mode.repository] +name = "" +build_on_update = false + +[mode.repository.signing] +enabled = false +key = "" +on_gen = false + +[mode.workspace] + +[repositories] +name = [ + "1::foo", + "1::bar" + "2::baz", + "2::qux", +] +urls = [ + "https://example.org/%repo%.git", + "https://example.org/other/%repo%.git", +] +``` + +Now this is going to look really confusing at first, but bear with me. + +In this document we'll cover only what is required to know for **both** modes. +More specialised tutorials will be linked for each mode at the bottom of this page. + +Let's start with the base(ics). + + +### Base Config +The base config defines a few common parameters between all the Malachite modes. + +```toml +[base] +mode = "workspace" +smart_pull = true +``` + +In this snippet, we define `mode` to be `"workspace"`. + +`base.mode` in Malachite can only ever be one of `"workspace"` or `"repository"`, and defines, drumroll... +The mode in which it operates. + +If it is set to anything but those 2 modes, it crashes. + +Also defined in this snippet is `smart_pull`, which controls whether or not to pull... smartly. + +What that actually means is that instead of just performing a simple `git pull` in each repository, Malachite +will: + +- First run `git remote update` to fetch new remotes from origin +- Then run `git status` and parse the output to see if the current branch is behind +- If the current branch is behind, it runs a regular `git pull`, which will take advantage of the remotes + already being updated. + +Theoretically, this only actually speeds things up by a minute amount (think milliseconds, really). Where this feature shines however is in repository mode, +where it enables helpful automation features such as `build_on_update`. + +Either way, it's recommended to keep this enabled for the slight speedup, and only disable it if it causes issues. +I've never personally had issues with it in the past, but who knows what could happen. This is Git we're talking about. + + +### Repositories Config + +The repositories config is realistically what makes Malachite churn repo butter internally. It's the whole +purpose of what it does, and because of that we've tried to come up with a neat little system so as to help +facilitate many packages without having to type each url out a million times. + +```toml +[repositories] +name = [ + "1::foo", + "1::bar" + "2::baz", + "2::qux", +] +urls = [ + "https://example.org/%repo%.git", + "https://example.org/other/%repo%.git", +] +``` + +The way this works is simple. + +We have 2 urls in the `repositories.urls` key. + +Each `name` in the `repositories.name` key is prefixed with an index. + +If the number is `1`, it'll insert the name into the `1`st URL. + +Specifically, in the repo's URL, it'll insert the defined `name` in place of the `%repo%` substring. + +That's literally it! + + +### Mode-Specific Config + +For mode-specific config, avert your eyes to the following links! + +- [Workspace Mode](WORKSPACE_MODE.md) +- [Repository Mode](REPOSITORY_MODE.md) + diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md new file mode 100644 index 0000000..1cc8627 --- /dev/null +++ b/docs/GETTING_STARTED.md @@ -0,0 +1,47 @@ +# Getting Started With Malachite +Baby's first Malachite repository! + +### What you need to know + +Malachite is: +- A pacman repository manager +- A workspace manager +- ~~Awesome~~ + +Malachite isn't: +- The end-all solution for all pacman repositories +- Perfect + + +### With that out of the way + +Hi! My name is Michal, I wrote this tool pretty much on my own for [Crystal Linux](https://getcryst.al), +but it is not at all exclusive to Crystal. This tool should and will work on and for any pacman-based +distribution (so long as it packages all of Malachite's dependencies, of course). + +Throughout this tutorial I'll explain each little feature of Malachite in what I hope to be bite-sized and +programmatic chunks. + +Without further ado, let's begin with the first most important question + + +### Modes + +What mode are you using malachite in? + +Currently malachite supports 2 modes: + +#### Repository Mode +- Allows the user to configure and manage a remote (or local) pacman-based package repository +- Allows for customisability in repository name, signing preferences, signing key etc. +- Allows for basic levels of automation, by using features such as build_on_update + +#### Workspace Mode +- The most basic functionality of Malachite +- Just clones git directories into a "Workspace" directory for easier management +- Allows for basic pulling operations to keep your repositories up-to-date + +These modes essentially dictate everything about how Malachite functions, so much so that I now need to +split this page off before it gets too long! + +For more info, get started with the [Common Features](COMMON_FEATURES.md) page! \ No newline at end of file From f6d97a3f030ffe3ed4dc7e10004ff59db34c8d06 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 02:29:33 +0100 Subject: [PATCH 043/116] Docs + README update --- README.md | 29 ++++++++++++++++------------- docs/COMMON_FEATURES.md | 20 +++++++------------- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 4988b75..3222526 100644 --- a/README.md +++ b/README.md @@ -20,33 +20,36 @@

Malachite is a simple yet useful workspace and local repository management tool, made for packagers of Arch Linux based distributions.

-## Basic usage +### Usage Guide -| Action | Command | -|--------------------------------------------------------|-----------------------| -| Build a package | mlc build \ | -| Generate local repository | mlc repo-gen | -| Update local repos/PKGBUILDs | mlc pull/update | -| Create and/or open config file | mlc conf | -| Initialises repo/workspace based on config in mlc.toml | mlc clone/init | +| Action | Command | +|--------------------------------------------------------|-------------------------------------------| +| Build a package | mlc build \ [all if left empty] | +| Generate local repository | mlc repo-gen | +| Update local repos/PKGBUILDs | mlc pull/update [all if left empty] | +| Create and/or open config file | mlc conf | +| Initialises repo/workspace based on config in mlc.toml | mlc clone/init | ### Pacman Repository Creation - `mlc config` to create the config (and also populate it) - `mlc init` to build repository base from config file -- `mlc build /--all` to either build individual packages or all packages in mlc.toml +- `mlc build ` to either build individual packages, or don't specify package names to build all packages in mlc.toml + - `build` typically automatically updates the repository unless `--no-regen` is passed, if so: - `mlc repo-gen` to generate functional pacman repository at \/\.db from built packages + +## \>> [Detailed Usage Guide](docs/GETTING_STARTED.md) << + + ## How to build: Tested on latest Cargo (1.60.0-nightly) -
- -#### Debug/development builds +### Debug/development builds - `cargo build` -#### Optimised/release builds +### Optimised/release builds - `cargo build --release` diff --git a/docs/COMMON_FEATURES.md b/docs/COMMON_FEATURES.md index 0e1365c..f1de5b4 100644 --- a/docs/COMMON_FEATURES.md +++ b/docs/COMMON_FEATURES.md @@ -60,9 +60,7 @@ smart_pull = true In this snippet, we define `mode` to be `"workspace"`. `base.mode` in Malachite can only ever be one of `"workspace"` or `"repository"`, and defines, drumroll... -The mode in which it operates. - -If it is set to anything but those 2 modes, it crashes. +The mode in which it operates. If it is set to anything but those 2 modes, it crashes. Also defined in this snippet is `smart_pull`, which controls whether or not to pull... smartly. @@ -77,7 +75,7 @@ will: Theoretically, this only actually speeds things up by a minute amount (think milliseconds, really). Where this feature shines however is in repository mode, where it enables helpful automation features such as `build_on_update`. -Either way, it's recommended to keep this enabled for the slight speedup, and only disable it if it causes issues. +Regardless, it's recommended to keep this enabled for the slight speedup, and only disable it if it causes issues. I've never personally had issues with it in the past, but who knows what could happen. This is Git we're talking about. @@ -101,15 +99,11 @@ urls = [ ] ``` -The way this works is simple. - -We have 2 urls in the `repositories.urls` key. - -Each `name` in the `repositories.name` key is prefixed with an index. - -If the number is `1`, it'll insert the name into the `1`st URL. - -Specifically, in the repo's URL, it'll insert the defined `name` in place of the `%repo%` substring. +The way this works is simple: +- We have 2 urls in the `repositories.urls` key. +- Each `name` in the `repositories.name` key is prefixed with an index. +- If the number is `N`, it'll insert the name into the `N`th URL. + - Specifically, in the repo's URL, it'll insert the defined `name` in place of the `%repo%` substring. That's literally it! From a08b80c06439ff8576a62e10dd79cfde21f654ce Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 02:50:44 +0100 Subject: [PATCH 044/116] More documentation. Yippee --- README.md | 2 +- docs/COMMON_FEATURES.md | 1 + docs/USAGE.md | 37 +++++++++++++++++++++++++++++++++++++ src/args.rs | 4 ---- src/internal/exit_codes.rs | 10 ++++------ src/repository/package.rs | 4 ++-- 6 files changed, 45 insertions(+), 13 deletions(-) create mode 100644 docs/USAGE.md diff --git a/README.md b/README.md index 3222526..ee71539 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@

Malachite is a simple yet useful workspace and local repository management tool, made for packagers of Arch Linux based distributions.

-### Usage Guide +### Basic Usage Guide | Action | Command | |--------------------------------------------------------|-------------------------------------------| diff --git a/docs/COMMON_FEATURES.md b/docs/COMMON_FEATURES.md index f1de5b4..94f72b5 100644 --- a/docs/COMMON_FEATURES.md +++ b/docs/COMMON_FEATURES.md @@ -115,3 +115,4 @@ For mode-specific config, avert your eyes to the following links! - [Workspace Mode](WORKSPACE_MODE.md) - [Repository Mode](REPOSITORY_MODE.md) +Alternatively, you can look at more [Detailed Usage](USAGE.md) diff --git a/docs/USAGE.md b/docs/USAGE.md new file mode 100644 index 0000000..0a11bcf --- /dev/null +++ b/docs/USAGE.md @@ -0,0 +1,37 @@ +# Detailed Usage +Work it harder, make it better! + +### Global Flags + +| Flag | Description | +|-------------------|----------------------------------------------------------------------------------------------------------------------------------------| +| `--verbose`, `-v` | Prints lots of debug information to `stderr`. If something doesn't go right, sending us the output with this enabled will help greatly | +| `--exclude`, `-x` | Excludes the supplied package from the current operation. Can be used multiple times. | + +### Basic Commands + +| Action | Command | Extra Flags | +|--------------------------------------------------------|-------------------------------------------|------------------------------------------------------------------------------------------------------------------| +| Build a package/packages. | `mlc build ` [all if left empty] | `--no-regen`: Doesn't regenerate repository after build | +| Generate pacman repository | `mlc repo-gen` | | +| Update local repos/PKGBUILDs | `mlc pull/update` [all if left empty] | `--no-regen`: If `mode.repository.build_on_update` is `true`, Do not regenerate repository after package rebuild | +| Create and/or open config file | `mlc conf` | | +| Initialises repo/workspace based on config in mlc.toml | `mlc clone/init` | | + +### Exit Codes + +| AppExitCode (named Enum) | Exit code (i32) | Error Description | +|--------------------------|-----------------|--------------------------------------------------------------------------------------------------------| +| `RunAsRoot` | `1` | Malachite was ran as root. This is highly discouraged. So highly, in fact, that it will refuse to run. | +| `BuildInWorkspace` | `2` | Malachite was ran in Workspace mode, but a Repository-mode-specific operation was supplied | +| `PkgNotFound` | `3` | A build was attempted for a package that does not exist | +| `InvalidMode` | `4` | Malachite was launched in a mode other than `workspace` or `repository` | +| `DirNotEmpty` | `5` | The creation of a Malachite repository was attempted in a non-empty directory | +| `ConfigNotFound` | `6` | The default config file (`./mlc.toml`) was not found | +| `NoPkgs` | `7` | Somehow, no packages were supplied to/found in the relevant operation | +| `ConfigParseError` | `8` | The config file could not be parsed | +| `InvalidRepo` | `9` | The generated repository somehow contains no packages | + + + + diff --git a/src/args.rs b/src/args.rs index 0f9f9e2..14f7394 100644 --- a/src/args.rs +++ b/src/args.rs @@ -10,10 +10,6 @@ pub struct Args { #[clap(long, short, global(true), action = ArgAction::SetTrue)] pub verbose: bool, - /// Complete operations without prompting user - #[clap(long = "noconfirm", global(true), action = ArgAction::SetTrue)] - pub no_confirm: bool, - /// Excludes packages from given operation, if applicable #[clap(short = 'x', long = "exclude", action = ArgAction::Append, takes_value = true)] pub exclude: Vec, diff --git a/src/internal/exit_codes.rs b/src/internal/exit_codes.rs index 7ed8aff..f50199f 100644 --- a/src/internal/exit_codes.rs +++ b/src/internal/exit_codes.rs @@ -4,10 +4,8 @@ pub enum AppExitCode { PkgNotFound = 3, InvalidMode = 4, DirNotEmpty = 5, - RepoNotFound = 6, - ConfigNotFound = 7, - NoPkgs = 8, - ConfigParseError = 9, - NoPackagesFound = 10, - InvalidRepo = 11, + ConfigNotFound = 6, + NoPkgs = 7, + ConfigParseError = 8, + InvalidRepo = 9, } diff --git a/src/repository/package.rs b/src/repository/package.rs index e8ac524..c363a71 100755 --- a/src/repository/package.rs +++ b/src/repository/package.rs @@ -21,8 +21,8 @@ pub fn build(pkg: &str, sign: bool, verbose: bool) -> i32 { // If package directory is not found, crash if !Path::exists(pkg.as_ref()) { crash!( - AppExitCode::RepoNotFound, - "Repo for {} not found, aborting", + AppExitCode::PkgNotFound, + "Repo for package {} not found, aborting", pkg ); } From 03ba34525a1448fffbebc493275d4c0855eff531 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 03:02:23 +0100 Subject: [PATCH 045/116] This might be enough documentation for tonight --- docs/COMMON_FEATURES.md | 2 +- docs/REPOSITORY_MODE.md | 38 ++++++++++++++++++++++++++++++++++++++ docs/WORKSPACE_MODE.md | 15 +++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 docs/REPOSITORY_MODE.md create mode 100644 docs/WORKSPACE_MODE.md diff --git a/docs/COMMON_FEATURES.md b/docs/COMMON_FEATURES.md index 94f72b5..0486cd5 100644 --- a/docs/COMMON_FEATURES.md +++ b/docs/COMMON_FEATURES.md @@ -115,4 +115,4 @@ For mode-specific config, avert your eyes to the following links! - [Workspace Mode](WORKSPACE_MODE.md) - [Repository Mode](REPOSITORY_MODE.md) -Alternatively, you can look at more [Detailed Usage](USAGE.md) +Alternatively, you can look at the [Usage](USAGE.md) guide! diff --git a/docs/REPOSITORY_MODE.md b/docs/REPOSITORY_MODE.md new file mode 100644 index 0000000..edcae1b --- /dev/null +++ b/docs/REPOSITORY_MODE.md @@ -0,0 +1,38 @@ +# Repository Mode +PacManage your repositories in style! + +### Repository Config + +As opposed to the rather barren Workspace mode, the Repository mode config is rather fleshed out, +and we have a few options to choose from. + +Let's take an example config, + +```toml +[mode.repository] +name = "example" +build_on_update = true + +[mode.repository.signing] +enabled = true +key = "you@example.org" +on_gen = true +``` + +### Basic Repository Config + +To start with, there are 2 main config keys to Repository mode: +- `name`: Defines what pacman calls your repository. +- `build_on_update`: In conjunction with `smart_pull`, defines whether to rebuild packages automatically when an update is detected. + +### Signing + +Malachite also supports, and encourages the signing of packages. +GPG Signing packages ensures that the user receives exactly what you packaged, without any chance of tampering. + +Calling back to the example above, we can see 3 config keys: + +- `enabled`: Defines whether to sign packages (heavily encouraged). +- `key`: Defines the GPG key ID to use for signing. +- `on_gen`: Defines whether to sign packages when they are built, or all at once on repository generation (this is also recommended). + diff --git a/docs/WORKSPACE_MODE.md b/docs/WORKSPACE_MODE.md new file mode 100644 index 0000000..125bd02 --- /dev/null +++ b/docs/WORKSPACE_MODE.md @@ -0,0 +1,15 @@ +# Workspace Mode +You'll never have to work(space) another day in your life! + +### Workspace Config + +```toml +[mode.workspace] + +``` + +Oh, this is awkward. It seems like there *is no* workspace-specific config yet. I'm open to suggestions though! + +### For Now... + +You can return to [Getting Started](GETTING_STARTED.md), or head directly into [Repository Mode](REPOSITORY_MODE.md) to see where Malachite really shines! \ No newline at end of file From d4f73c3cb9c91bfbab4c150194d5ab0775fc5e03 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 03:03:32 +0100 Subject: [PATCH 046/116] Syntax error in TOML in Docs --- docs/COMMON_FEATURES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/COMMON_FEATURES.md b/docs/COMMON_FEATURES.md index 0486cd5..92c7ad6 100644 --- a/docs/COMMON_FEATURES.md +++ b/docs/COMMON_FEATURES.md @@ -30,7 +30,7 @@ on_gen = false [repositories] name = [ "1::foo", - "1::bar" + "1::bar", "2::baz", "2::qux", ] From 5a27b02029a35d96e25043926adffb493e0da54c Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 03:04:00 +0100 Subject: [PATCH 047/116] Syntax error in TOML in Docs --- docs/COMMON_FEATURES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/COMMON_FEATURES.md b/docs/COMMON_FEATURES.md index 92c7ad6..8bf99cf 100644 --- a/docs/COMMON_FEATURES.md +++ b/docs/COMMON_FEATURES.md @@ -89,7 +89,7 @@ facilitate many packages without having to type each url out a million times. [repositories] name = [ "1::foo", - "1::bar" + "1::bar", "2::baz", "2::qux", ] From 45cf3189ef08ddd61f117f1956b0e55d84ca1ecc Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 03:07:06 +0100 Subject: [PATCH 048/116] Fixed AppExitCode missing --- src/repository/repo.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/repository/repo.rs b/src/repository/repo.rs index fe4177c..b4f1e9e 100644 --- a/src/repository/repo.rs +++ b/src/repository/repo.rs @@ -97,7 +97,7 @@ pub fn generate(verbose: bool) { true } else { crash!( - AppExitCode::NoPackagesFound, + AppExitCode::NoPkgs, "No .zst or .xz packages found in repository" ); // This should theoretically never be reached, but let's just give the compiler what it wants From b455b6747b6f61f074c7b22268bc9a99f304178e Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 03:26:30 +0100 Subject: [PATCH 049/116] Implemented cloning specific branches --- examples/workspace/mlc.toml | 2 +- src/internal/structs.rs | 1 + src/operations/clone.rs | 5 +++++ src/workspace/read.rs | 19 ++++++++++++++++++- 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/examples/workspace/mlc.toml b/examples/workspace/mlc.toml index 77b0e6a..fa6d8b0 100644 --- a/examples/workspace/mlc.toml +++ b/examples/workspace/mlc.toml @@ -16,7 +16,7 @@ on_gen = false [repositories] name = [ "1::amethyst", - "1::jade!", + "1::malachite@development!", "2::notop-git", "3::appendage", ] diff --git a/src/internal/structs.rs b/src/internal/structs.rs index a44a0d6..ce9f916 100755 --- a/src/internal/structs.rs +++ b/src/internal/structs.rs @@ -60,6 +60,7 @@ pub struct ConfigRepositoriesExpanded { pub struct Repo { pub name: String, pub url: String, + pub branch: Option, pub priority: usize, } diff --git a/src/operations/clone.rs b/src/operations/clone.rs index 3d78741..74e442f 100644 --- a/src/operations/clone.rs +++ b/src/operations/clone.rs @@ -47,6 +47,11 @@ pub fn clone(verbose: bool) { info!("Cloning ({} mode): {}", config.base.mode, r.name); Command::new("git") .args(&["clone", &r.url, &r.name]) + .args(if r.branch.is_some() { + vec!["-b", r.branch.as_ref().unwrap()] + } else { + vec![] + }) .spawn() .unwrap() .wait() diff --git a/src/workspace/read.rs b/src/workspace/read.rs index 1c4e439..e3059e9 100755 --- a/src/workspace/read.rs +++ b/src/workspace/read.rs @@ -51,7 +51,23 @@ pub fn read_cfg(verbose: bool) -> Config { // Parses all necessary values for expanding the repo to a Repo struct let index = split_struct.indx; - let name = split_struct.name.replace('!', ""); + + let branch = if split_struct.name.contains('@') { + Some( + split_struct.name.split('@').collect::>()[1] + .to_string() + .replace('!', ""), + ) + } else { + None + }; + + let name = if split_struct.name.contains('@') { + split_struct.name.split('@').collect::>()[0].to_string() + } else { + split_struct.name.to_string().replace('!', "") + }; + let url = config.repositories.urls[index - 1].replace("%repo%", &name); let priority = &split_struct.name.matches('!').count(); @@ -59,6 +75,7 @@ pub fn read_cfg(verbose: bool) -> Config { let repo = Repo { name, url, + branch, priority: *priority, }; log!(verbose, "Expanded repo: {:?}", repo); From 21b80478bbdbacd9f17af594f360306c3b1c7eeb Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 03:27:22 +0100 Subject: [PATCH 050/116] Cleanup --- src/operations/prune.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/operations/prune.rs b/src/operations/prune.rs index 732346e..c86a2bc 100644 --- a/src/operations/prune.rs +++ b/src/operations/prune.rs @@ -1,10 +1,11 @@ -use crate::info; -use crate::log; -use crate::read_cfg; use std::env; use std::fs; use std::path::PathBuf; +use crate::info; +use crate::log; +use crate::read_cfg; + #[derive(Debug, Clone)] struct PackageFile { name: String, From 98a4bf55cf76519e7f54b207f3a7919305ea4815 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 03:30:40 +0100 Subject: [PATCH 051/116] Cleanup --- src/operations/clone.rs | 1 + src/workspace/read.rs | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/src/operations/clone.rs b/src/operations/clone.rs index 74e442f..d45a20d 100644 --- a/src/operations/clone.rs +++ b/src/operations/clone.rs @@ -47,6 +47,7 @@ pub fn clone(verbose: bool) { info!("Cloning ({} mode): {}", config.base.mode, r.name); Command::new("git") .args(&["clone", &r.url, &r.name]) + // If a branch is specified, clone that specific branch .args(if r.branch.is_some() { vec!["-b", r.branch.as_ref().unwrap()] } else { diff --git a/src/workspace/read.rs b/src/workspace/read.rs index e3059e9..aac2a2c 100755 --- a/src/workspace/read.rs +++ b/src/workspace/read.rs @@ -52,23 +52,30 @@ pub fn read_cfg(verbose: bool) -> Config { // Parses all necessary values for expanding the repo to a Repo struct let index = split_struct.indx; + // If a branch is defined, parse it let branch = if split_struct.name.contains('@') { + log!(verbose, "Branch defined: {}", split_struct.name); Some( split_struct.name.split('@').collect::>()[1] .to_string() .replace('!', ""), ) } else { + log!(verbose, "No branch defined"); None }; + // Strip branch and priority info from the name, if present let name = if split_struct.name.contains('@') { split_struct.name.split('@').collect::>()[0].to_string() } else { split_struct.name.to_string().replace('!', "") }; + // Substitutes the name into the url let url = config.repositories.urls[index - 1].replace("%repo%", &name); + + // Counts instances of ! in the name, and totals a priority accordingly let priority = &split_struct.name.matches('!').count(); // Creates and pushes Repo struct to expanded_repos From 2f70e06e859f46f650aa9a09310d7831b459a499 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 04:03:10 +0100 Subject: [PATCH 052/116] New format oop --- examples/repository/mlc.toml | 14 +++++++------- src/internal/structs.rs | 5 +++-- src/workspace/read.rs | 24 ++++++++++++++++-------- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/examples/repository/mlc.toml b/examples/repository/mlc.toml index 3e995b2..2a921f3 100644 --- a/examples/repository/mlc.toml +++ b/examples/repository/mlc.toml @@ -14,11 +14,11 @@ on_gen = true [mode.workspace] [repositories] -name = [ - "1::crystal-keyring", - "2::pfetch!", +repos = [ + "crs:malachite/development", + "pkg:pfetch!", ] -urls = [ - "https://github.com/crystal-linux/%repo%", - "https://github.com/crystal-linux/pkgbuild.%repo%", -] \ No newline at end of file + +[repositories.urls] +crs = "https://github.com/crystal-linux/%repo%" +pkg = "https://github.com/crystal-linux/pkgbuild.%repo%" diff --git a/src/internal/structs.rs b/src/internal/structs.rs index ce9f916..1dad2b4 100755 --- a/src/internal/structs.rs +++ b/src/internal/structs.rs @@ -1,4 +1,5 @@ use serde_derive::Deserialize; +use std::collections::HashMap; //// Config structs #[derive(Debug, Deserialize)] @@ -47,7 +48,7 @@ pub struct ConfigModeWorkspace {} #[derive(Debug, Deserialize)] pub struct ConfigRepositories { pub name: Vec, - pub urls: Vec, + pub urls: HashMap, } #[derive(Debug, Deserialize)] @@ -66,7 +67,7 @@ pub struct Repo { #[derive(Debug)] pub struct SplitRepo { - pub indx: usize, + pub id: String, pub name: String, } diff --git a/src/workspace/read.rs b/src/workspace/read.rs index aac2a2c..4ffaed5 100755 --- a/src/workspace/read.rs +++ b/src/workspace/read.rs @@ -42,21 +42,21 @@ pub fn read_cfg(verbose: bool) -> Config { for x in config.repositories.name { log!(verbose, "Parsing repo: {:?}", x); // Splits the repo name and index inta a SplitRepo struct - let split: Vec<&str> = x.split("::").collect(); + let split: Vec<&str> = x.split(':').collect(); let split_struct = SplitRepo { - indx: split[0].parse().unwrap(), + id: split[0].parse().unwrap(), name: split[1].parse().unwrap(), }; log!(verbose, "Split repo: {:?}", split_struct); // Parses all necessary values for expanding the repo to a Repo struct - let index = split_struct.indx; + let id = split_struct.id; // If a branch is defined, parse it - let branch = if split_struct.name.contains('@') { + let branch = if split_struct.name.contains('/') { log!(verbose, "Branch defined: {}", split_struct.name); Some( - split_struct.name.split('@').collect::>()[1] + split_struct.name.split('/').collect::>()[1] .to_string() .replace('!', ""), ) @@ -66,14 +66,22 @@ pub fn read_cfg(verbose: bool) -> Config { }; // Strip branch and priority info from the name, if present - let name = if split_struct.name.contains('@') { - split_struct.name.split('@').collect::>()[0].to_string() + let name = if split_struct.name.contains('/') { + split_struct.name.split('/').collect::>()[0].to_string() } else { split_struct.name.to_string().replace('!', "") }; // Substitutes the name into the url - let url = config.repositories.urls[index - 1].replace("%repo%", &name); + let urls = &config.repositories.urls; + let mut urls_vec = vec![]; + for (i, url) in urls { + if i == &id { + log!(verbose, "Substituting url: {:?}", url); + urls_vec.push(url); + } + } + let url = urls_vec[0].replace("%repo%", &name); // Counts instances of ! in the name, and totals a priority accordingly let priority = &split_struct.name.matches('!').count(); From 447aab6a0438f795383a43a4aa53804e194d8b1c Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 04:06:17 +0100 Subject: [PATCH 053/116] Changed to a more readable name --- src/internal/structs.rs | 2 +- src/workspace/read.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/internal/structs.rs b/src/internal/structs.rs index 1dad2b4..5d83b84 100755 --- a/src/internal/structs.rs +++ b/src/internal/structs.rs @@ -47,7 +47,7 @@ pub struct ConfigModeWorkspace {} #[derive(Debug, Deserialize)] pub struct ConfigRepositories { - pub name: Vec, + pub repos: Vec, pub urls: HashMap, } diff --git a/src/workspace/read.rs b/src/workspace/read.rs index 4ffaed5..03412ad 100755 --- a/src/workspace/read.rs +++ b/src/workspace/read.rs @@ -39,7 +39,7 @@ pub fn read_cfg(verbose: bool) -> Config { let mut expanded_repos: Vec = vec![]; // Parsing repos from the config file - for x in config.repositories.name { + for x in config.repositories.repos { log!(verbose, "Parsing repo: {:?}", x); // Splits the repo name and index inta a SplitRepo struct let split: Vec<&str> = x.split(':').collect(); From 45a5f5700dab06a5aac52899c3192ef32800136c Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 04:14:43 +0100 Subject: [PATCH 054/116] Updated examples to reflect new format --- examples/workspace/mlc.toml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/workspace/mlc.toml b/examples/workspace/mlc.toml index fa6d8b0..3a2559d 100644 --- a/examples/workspace/mlc.toml +++ b/examples/workspace/mlc.toml @@ -15,13 +15,13 @@ on_gen = false [repositories] name = [ - "1::amethyst", - "1::malachite@development!", - "2::notop-git", - "3::appendage", + "crs:amethyst", + "crs:malachite/development!", + "aur::notop-git", + "nms::appendage", ] -urls = [ - "https://github.com/crystal-linux/%repo%", - "https://aur.archlinux.org/%repo%", - "https://github.com/not-my-segfault/%repo%" -] \ No newline at end of file + +[repositories.urls] +crs = "https://github.com/crystal-linux/%repo%" +aur = "https://aur.archlinux.org/%repo%" +nms = "https://github.com/not-my-segfault/%repo%" From 8623fb20c34f576eaf9a3b98a79d6395bdc7bc71 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 04:25:17 +0100 Subject: [PATCH 055/116] Updated COMMON_FEATURES.md to reflect new format --- docs/COMMON_FEATURES.md | 46 +++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/docs/COMMON_FEATURES.md b/docs/COMMON_FEATURES.md index 8bf99cf..9f509bc 100644 --- a/docs/COMMON_FEATURES.md +++ b/docs/COMMON_FEATURES.md @@ -29,15 +29,15 @@ on_gen = false [repositories] name = [ - "1::foo", - "1::bar", - "2::baz", - "2::qux", -] -urls = [ - "https://example.org/%repo%.git", - "https://example.org/other/%repo%.git", + "foo:repo1", + "foo::repo2/testing", + "bar::baz!", + "bar::qux/testing!", ] + +[repositories.urls] +foo = "https://example.org/%repo%.git" +bar = "https://example.org/other/%repo%.git" ``` Now this is going to look really confusing at first, but bear with me. @@ -87,23 +87,29 @@ facilitate many packages without having to type each url out a million times. ```toml [repositories] -name = [ - "1::foo", - "1::bar", - "2::baz", - "2::qux", -] -urls = [ - "https://example.org/%repo%.git", - "https://example.org/other/%repo%.git", +repos = [ + "foo:repo1", + "foo:repo2/testing", + "bar:baz!", + "bar:qux/testing!", ] + +[repositories.urls] +foo = "https://example.org/%repo%.git" +bar = "https://example.org/other/%repo%.git" ``` The way this works is simple: - We have 2 urls in the `repositories.urls` key. -- Each `name` in the `repositories.name` key is prefixed with an index. -- If the number is `N`, it'll insert the name into the `N`th URL. - - Specifically, in the repo's URL, it'll insert the defined `name` in place of the `%repo%` substring. +- Each `repo` in the `repositories.repos` key is prefixed with an identifier. +- If the number is `foo`, it'll insert the url with the id `foo`. + - Specifically, in the URL, it'll insert the defined `repo`'s name in place of the `%repo%` substring. + +#### Hang on, what are the special symbols???? + +I'm glad you asked! +- If you want to clone a specific branch, simply use the `/` delimiter. To clone repository `foo` on branch `bar`, use `id:foo/bar`. +- If you want a specific package to build first, use instances of `!` to set priority. This is explained later in the [Repository Mode](REPOSITORY_MODE.md) page That's literally it! From 8201f2e2eedd483a15219f87c069bd9425fdd41e Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 04:28:32 +0100 Subject: [PATCH 056/116] write down thta idea before i pass out --- docs/USAGE.md | 1 + src/args.rs | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/docs/USAGE.md b/docs/USAGE.md index 0a11bcf..66a9f03 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -17,6 +17,7 @@ Work it harder, make it better! | Update local repos/PKGBUILDs | `mlc pull/update` [all if left empty] | `--no-regen`: If `mode.repository.build_on_update` is `true`, Do not regenerate repository after package rebuild | | Create and/or open config file | `mlc conf` | | | Initialises repo/workspace based on config in mlc.toml | `mlc clone/init` | | +| Displays an info panel/overview of the current repo | `mlc info/status` | | ### Exit Codes diff --git a/src/args.rs b/src/args.rs index 14f7394..e6955b0 100644 --- a/src/args.rs +++ b/src/args.rs @@ -45,6 +45,10 @@ pub enum Operation { #[clap(name = "prune", aliases = & ["prune", "p"])] Prune, + /// Shows an info panel/overview about the current repository + #[clap(name = "info", aliases = & ["status", "s", "i"])] + Info, // TODO: Implement this + /// Pulls in git repositories from mlc.toml branching from current directory #[clap(name = "pull", aliases = & ["u"])] Pull { From 7505b79a817381ed9e61b6b7ab6fdcab9f049ce1 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 04:31:56 +0100 Subject: [PATCH 057/116] Alright I'm stopping myself here --- src/args.rs | 2 +- src/main.rs | 1 + src/operations/info.rs | 6 ++++++ src/operations/mod.rs | 2 ++ 4 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 src/operations/info.rs diff --git a/src/args.rs b/src/args.rs index e6955b0..3601042 100644 --- a/src/args.rs +++ b/src/args.rs @@ -47,7 +47,7 @@ pub enum Operation { /// Shows an info panel/overview about the current repository #[clap(name = "info", aliases = & ["status", "s", "i"])] - Info, // TODO: Implement this + Info, /// Pulls in git repositories from mlc.toml branching from current directory #[clap(name = "pull", aliases = & ["u"])] diff --git a/src/main.rs b/src/main.rs index fd56704..0e812b8 100755 --- a/src/main.rs +++ b/src/main.rs @@ -107,5 +107,6 @@ fn main() { Operation::Config => operations::config(verbose), Operation::Prune => operations::prune(verbose), Operation::Clean => operations::clean(verbose), + Operation::Info => operations::info(verbose), } } diff --git a/src/operations/info.rs b/src/operations/info.rs new file mode 100644 index 0000000..e700e0f --- /dev/null +++ b/src/operations/info.rs @@ -0,0 +1,6 @@ +use crate::log; + +pub fn info(verbose: bool) { + log!(verbose, "Showing Info"); + unimplemented!(); +} \ No newline at end of file diff --git a/src/operations/mod.rs b/src/operations/mod.rs index 6588e22..775ed89 100644 --- a/src/operations/mod.rs +++ b/src/operations/mod.rs @@ -4,6 +4,7 @@ pub use clone::*; pub use config::*; pub use prune::*; pub use pull::*; +pub use info::*; mod build; mod clean; @@ -11,3 +12,4 @@ mod clone; mod config; mod prune; mod pull; +mod info; From aae7a78e579266b524f508635ba29b210e47bb5e Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 04:32:30 +0100 Subject: [PATCH 058/116] an fmt for the night --- src/operations/info.rs | 2 +- src/operations/mod.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/operations/info.rs b/src/operations/info.rs index e700e0f..a4080e2 100644 --- a/src/operations/info.rs +++ b/src/operations/info.rs @@ -3,4 +3,4 @@ use crate::log; pub fn info(verbose: bool) { log!(verbose, "Showing Info"); unimplemented!(); -} \ No newline at end of file +} diff --git a/src/operations/mod.rs b/src/operations/mod.rs index 775ed89..82a8a46 100644 --- a/src/operations/mod.rs +++ b/src/operations/mod.rs @@ -2,14 +2,14 @@ pub use build::*; pub use clean::*; pub use clone::*; pub use config::*; +pub use info::*; pub use prune::*; pub use pull::*; -pub use info::*; mod build; mod clean; mod clone; mod config; +mod info; mod prune; mod pull; -mod info; From 5df1907fb499a95f8189dc3c87cd05f5cad6798f Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 15:54:51 +0100 Subject: [PATCH 059/116] Implemented info properly --- Cargo.lock | 91 +++++++++++++++++++++++++++++++++++++ Cargo.toml | 4 +- examples/workspace/mlc.toml | 6 +-- src/internal/strings.rs | 2 +- src/operations/info.rs | 84 +++++++++++++++++++++++++++++++++- 5 files changed, 180 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index de96b8a..b260f19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,6 +12,8 @@ dependencies = [ "mimalloc", "serde", "serde_derive", + "tabled", + "termion", "toml", ] @@ -38,6 +40,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bytecount" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c" + [[package]] name = "cc" version = "1.0.73" @@ -94,6 +102,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "hashbrown" version = "0.12.3" @@ -155,6 +169,12 @@ dependencies = [ "libmimalloc-sys", ] +[[package]] +name = "numtoa" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" + [[package]] name = "once_cell" version = "1.13.0" @@ -167,6 +187,17 @@ version = "6.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "648001efe5d5c0102d8cea768e348da85d90af8ba91f0bea908f157951493cd4" +[[package]] +name = "papergrid" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453cf71f2a37af495a1a124bf30d4d7469cfbea58e9f2479be9d222396a518a2" +dependencies = [ + "bytecount", + "fnv", + "unicode-width", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -209,6 +240,24 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "redox_syscall" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534cfe58d6a18cc17120fbf4635d53d14691c1fe4d951064df9bd326178d7d5a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_termios" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f" +dependencies = [ + "redox_syscall", +] + [[package]] name = "serde" version = "1.0.140" @@ -243,6 +292,30 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tabled" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5b2f8c37d26d87d2252187b0a45ea3cbf42baca10377c7e7eaaa2800fa9bf97" +dependencies = [ + "papergrid", + "tabled_derive", + "unicode-width", +] + +[[package]] +name = "tabled_derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9ee618502f497abf593e1c5c9577f34775b111480009ffccd7ad70d23fcaba8" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "termcolor" version = "1.1.3" @@ -252,6 +325,18 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "termion" +version = "1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e" +dependencies = [ + "libc", + "numtoa", + "redox_syscall", + "redox_termios", +] + [[package]] name = "textwrap" version = "0.15.0" @@ -273,6 +358,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + [[package]] name = "version_check" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index 2c09f98..b593ea1 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,4 +23,6 @@ toml = { version = "0.5.9", default-features = false } serde = { version = "1.0.139", default-features = false } serde_derive = { version = "1.0.139", default-features = false } libc = { version = "0.2.126", default-features = false } -colored = { version = "2.0.0", default-features = false } \ No newline at end of file +colored = { version = "2.0.0", default-features = false } +tabled = { version = "0.8.0", default-features = false, features = ["derive"] } +termion = { version = "1.5.6", default-features = false } \ No newline at end of file diff --git a/examples/workspace/mlc.toml b/examples/workspace/mlc.toml index 3a2559d..f29b013 100644 --- a/examples/workspace/mlc.toml +++ b/examples/workspace/mlc.toml @@ -14,11 +14,11 @@ on_gen = false [mode.workspace] [repositories] -name = [ +repos = [ "crs:amethyst", "crs:malachite/development!", - "aur::notop-git", - "nms::appendage", + "aur:notop-git", + "nms:appendage", ] [repositories.urls] diff --git a/src/internal/strings.rs b/src/internal/strings.rs index 287f027..db71f8a 100755 --- a/src/internal/strings.rs +++ b/src/internal/strings.rs @@ -17,7 +17,7 @@ macro_rules! info { #[macro_export] macro_rules! log { ($verbose:expr, $($arg:tt)+) => { - $crate::internal::strings::log_fn(format!($($arg)+), $verbose); + $crate::internal::strings::log_fn(format!("{}:{} {}", file!(), line!(), format!($($arg)+)), $verbose); } } diff --git a/src/operations/info.rs b/src/operations/info.rs index a4080e2..5b76506 100644 --- a/src/operations/info.rs +++ b/src/operations/info.rs @@ -1,6 +1,86 @@ -use crate::log; +use crate::{info, log}; +use colored::Colorize; +use std::env; +use tabled::Tabled; + +// For displaying the table of contents +#[derive(Clone, tabled::Tabled, Debug)] +struct RepoDisplay { + #[tabled(rename = "Name")] + name: String, + #[tabled(rename = "URL")] + url: String, + #[tabled(rename = "Priority")] + priority: usize, +} pub fn info(verbose: bool) { log!(verbose, "Showing Info"); - unimplemented!(); + let config = crate::workspace::read_cfg(verbose); + log!(verbose, "Config: {:?}", config); + + // Add the branch to the name if it's not the default branch for said repository + let repos_unparsed = config.repositories; + let mut repos = vec![]; + for repo in repos_unparsed { + let name = if repo.branch.is_some() { + format!("{}/{}", repo.name, repo.branch.unwrap()) + } else { + repo.name.clone() + }; + repos.push(RepoDisplay { + name, + url: repo.url, + priority: repo.priority, + }); + } + log!(verbose, "Repos: {:?}", repos); + // Sort by priority + repos.sort_by(|a, b| b.priority.cmp(&a.priority)); + log!(verbose, "Repos Sorted: {:?}", repos); + + // Displaying basic info about the Malachite Repository + let internal_name = if !config.mode.repository.name.is_empty() { + config.mode.repository.name + } else { + env::current_dir() + .unwrap() + .file_name() + .unwrap() + .to_str() + .unwrap() + .to_string() + }; + let name = format!( + "{} \"{}\":", + if config.base.mode == "repository" { + "Repository".to_string() + } else if config.base.mode == "workspace" { + "Workspace".to_string() + } else { + "".to_string() + }, + internal_name + ); + + // Get terminal width + let width = match termion::terminal_size() { + Ok((w, _)) => w, + Err(_) => 80, + }; + + // Create table for displaying info + let table = tabled::Table::new(&repos) + .with(tabled::Style::modern()) + .with(tabled::Width::wrap(width as usize)) + .with(tabled::Width::increase(width as usize)) + .to_string(); + + // Print all of the info + info!("{}", name); + info!( + "Local Repositories: {}", + repos.len().to_string().green().bold() + ); + println!("{}", table.bold()); } From 68e12aa9594debbc0322eedd4b9c245ed56b267d Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 16:15:34 +0100 Subject: [PATCH 060/116] Fixed formatting on table --- src/operations/info.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/operations/info.rs b/src/operations/info.rs index 5b76506..3eb7e27 100644 --- a/src/operations/info.rs +++ b/src/operations/info.rs @@ -73,7 +73,6 @@ pub fn info(verbose: bool) { let table = tabled::Table::new(&repos) .with(tabled::Style::modern()) .with(tabled::Width::wrap(width as usize)) - .with(tabled::Width::increase(width as usize)) .to_string(); // Print all of the info From 0cf709bc901cd18fbf7c358873364117ced80a01 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 16:22:42 +0100 Subject: [PATCH 061/116] Added check to prune --- src/operations/prune.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/operations/prune.rs b/src/operations/prune.rs index c86a2bc..1749e51 100644 --- a/src/operations/prune.rs +++ b/src/operations/prune.rs @@ -109,8 +109,12 @@ pub fn prune(verbose: bool) { log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); // Print which packages were deleted - info!("Deleted the following packages:"); - for p in packages_to_delete.iter_mut() { - info!("{}-{}", p.name.replace("./", ""), p.ver); + if !packages_to_delete.is_empty() { + info!("Deleted the following packages:"); + for p in packages_to_delete.iter_mut() { + info!("{}-{}", p.name.replace("./", ""), p.ver); + } + } else { + info!("No packages were deleted."); } } From c1a6460f97346ab91892cf960aa837fa1781071e Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 16:57:34 +0100 Subject: [PATCH 062/116] Fixed sorting issue on prune command --- Cargo.lock | 16 ++++++++++++++++ Cargo.toml | 3 ++- src/operations/prune.rs | 24 ++++++++++++------------ 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b260f19..4a6fe4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,6 +10,7 @@ dependencies = [ "colored", "libc", "mimalloc", + "regex", "serde", "serde_derive", "tabled", @@ -258,6 +259,21 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "regex" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" + [[package]] name = "serde" version = "1.0.140" diff --git a/Cargo.toml b/Cargo.toml index b593ea1..68a509c 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,4 +25,5 @@ serde_derive = { version = "1.0.139", default-features = false } libc = { version = "0.2.126", default-features = false } colored = { version = "2.0.0", default-features = false } tabled = { version = "0.8.0", default-features = false, features = ["derive"] } -termion = { version = "1.5.6", default-features = false } \ No newline at end of file +termion = { version = "1.5.6", default-features = false } +regex = { version = "1.6.0", default-features = false, features = ["std"] } diff --git a/src/operations/prune.rs b/src/operations/prune.rs index 1749e51..59e5fe9 100644 --- a/src/operations/prune.rs +++ b/src/operations/prune.rs @@ -40,19 +40,19 @@ pub fn prune(verbose: bool) { // Split files into Vec, turning name-1.0.0-1-x86_64.tar.gz into PackageFile { name: "name", ver: "1.0.0-1", ext: "x86_64.tar.gz" } let mut packages: Vec = vec![]; for file in files { + // Regex fuckery. Please don't mess with this. + let re = regex::Regex::new(r"^(.+)(-.+-.+)(-.+\..+\..+\.+..+)$").unwrap(); let file = file.to_str().unwrap(); - let mut parts = file.split('-'); - let name = parts.next().unwrap(); - let ver = parts.next().unwrap(); - let rel = parts.next().unwrap(); - let ext = parts.next().unwrap(); - let package = PackageFile { - name: name.to_string(), - ver: ver.to_string() + "-" + rel, - ext: ext.to_string(), - }; - log!(verbose, "Package: {:?}", package); - packages.push(package); + for cap in re.captures_iter(file) { + let name = cap[1].to_string(); + let mut ver = cap[2].to_string(); + ver.remove(0).to_string(); + let mut ext = cap[3].to_string(); + ext.remove(0).to_string(); + let package = PackageFile { name, ver, ext }; + log!(verbose, "Package: {:?}", package); + packages.push(package); + } } // Split packages into a Vector of Vectors by unique name From f6f7656caa62694df9e576c7dad4bf7701169449 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 17:44:35 +0100 Subject: [PATCH 063/116] Super pedantic clippy, for fun --- Cargo.toml | 2 ++ src/internal/mod.rs | 2 ++ src/{workspace => internal}/read.rs | 4 ++-- src/internal/strings.rs | 4 ++-- src/main.rs | 19 ++++++++++++------- src/operations/build.rs | 8 ++++---- src/operations/clone.rs | 4 ++-- src/operations/info.rs | 2 +- src/operations/prune.rs | 15 ++++++++------- src/operations/pull.rs | 10 +++++----- src/repository/repo.rs | 4 ++-- src/workspace/mod.rs | 3 --- 12 files changed, 42 insertions(+), 35 deletions(-) rename src/{workspace => internal}/read.rs (98%) mode change 100755 => 100644 delete mode 100755 src/workspace/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 68a509c..3b9abbc 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,8 @@ authors = [ "michal " ] edition = "2021" description = "Packaging tool for pacman repositories" license-file = "LICENSE" +keywords = [ "pacman", "repository", "packaging" ] +categories = [ "filesystem", "development-tools" ] [[bin]] name = "mlc" diff --git a/src/internal/mod.rs b/src/internal/mod.rs index b9a7664..799267c 100755 --- a/src/internal/mod.rs +++ b/src/internal/mod.rs @@ -1,5 +1,7 @@ pub use exit_codes::*; +pub use read::*; mod exit_codes; +mod read; pub mod strings; pub mod structs; diff --git a/src/workspace/read.rs b/src/internal/read.rs old mode 100755 new mode 100644 similarity index 98% rename from src/workspace/read.rs rename to src/internal/read.rs index 03412ad..4110d57 --- a/src/workspace/read.rs +++ b/src/internal/read.rs @@ -5,13 +5,13 @@ use crate::internal::structs::{Config, Repo, SplitRepo, UnexpandedConfig}; use crate::internal::AppExitCode; use crate::{crash, log}; -pub fn read_cfg(verbose: bool) -> Config { +pub fn parse_cfg(verbose: bool) -> Config { // Crash if mlc.toml doesn't exist if !Path::exists("mlc.toml".as_ref()) { crash!( AppExitCode::ConfigNotFound, "Config file not found (mlc.toml)" - ) + ); } // Reading the config file to an UnexpandedConfig struct diff --git a/src/internal/strings.rs b/src/internal/strings.rs index db71f8a..2d5feda 100755 --- a/src/internal/strings.rs +++ b/src/internal/strings.rs @@ -1,4 +1,4 @@ -use colored::*; +use colored::Colorize; use std::process::exit; use std::time::UNIX_EPOCH; @@ -30,7 +30,7 @@ macro_rules! crash { pub fn info_fn(msg: S) { let msg = msg.to_string(); - println!("{} {}", LOGO_SYMBOL.black(), msg.bold()) + println!("{} {}", LOGO_SYMBOL.black(), msg.bold()); } pub fn log_fn(msg: S, verbose: bool) { diff --git a/src/main.rs b/src/main.rs index 0e812b8..dec2ad9 100755 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,9 @@ +#![warn( + clippy::all, + clippy::pedantic, + clippy::nursery, +)] + use clap::Parser; use std::env; use std::path::Path; @@ -6,7 +12,7 @@ use std::process::Command; use crate::args::{Args, Operation}; use crate::internal::AppExitCode; use crate::repository::create_config; -use crate::workspace::read_cfg; +use crate::internal::parse_cfg; #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; @@ -15,7 +21,6 @@ mod args; mod internal; mod operations; mod repository; -mod workspace; fn main() { if unsafe { libc::geteuid() } == 0 { @@ -29,7 +34,7 @@ fn main() { log!(verbose, "Exclude: {:?}", exclude); log!(verbose, "Verbose: You guess. :)"); - let config = read_cfg(verbose); + let config = parse_cfg(verbose); log!(verbose, "Config: {:?}", config); if Path::exists("../.git".as_ref()) { @@ -88,19 +93,19 @@ fn main() { crash!( AppExitCode::BuildInWorkspace, "Cannot build packages in workspace mode" - ) + ); } - operations::build(packages, exclude.to_vec(), no_regen, verbose) + operations::build(&packages, exclude.clone(), no_regen, verbose); } Operation::Pull { packages, no_regen, .. - } => operations::pull(packages, exclude.to_vec(), verbose, no_regen), + } => operations::pull(packages, exclude, verbose, no_regen), Operation::RepoGen => { if !repository { crash!( AppExitCode::BuildInWorkspace, "Cannot build packages in workspace mode" - ) + ); } repository::generate(verbose); } diff --git a/src/operations/build.rs b/src/operations/build.rs index 302e99f..79679f5 100644 --- a/src/operations/build.rs +++ b/src/operations/build.rs @@ -1,10 +1,10 @@ use crate::internal::structs::{ErroredPackage, Repo}; use crate::internal::AppExitCode; -use crate::{crash, info, log, repository, workspace}; +use crate::{crash, info, log, repository, internal}; -pub fn build(packages: Vec, exclude: Vec, no_regen: bool, verbose: bool) { +pub fn build(packages: &[String], exclude: Vec, no_regen: bool, verbose: bool) { // Read config struct from mlc.toml - let config = workspace::read_cfg(verbose); + let config = internal::parse_cfg(verbose); log!(verbose, "Config: {:?}", config); let all = packages.is_empty(); log!(verbose, "All: {:?}", all); @@ -36,7 +36,7 @@ pub fn build(packages: Vec, exclude: Vec, no_regen: bool, verbos let mut errored: Vec = vec![]; if !packages.is_empty() && !all { log!(verbose, "Packages not empty: {:?}", packages); - for pkg in &packages { + for pkg in packages.iter() { // If repo is not in config, crash if !repos.iter().map(|x| x.name.clone()).any(|x| x == *pkg) { crash!( diff --git a/src/operations/clone.rs b/src/operations/clone.rs index d45a20d..1fb89bf 100644 --- a/src/operations/clone.rs +++ b/src/operations/clone.rs @@ -1,10 +1,10 @@ use std::process::Command; -use crate::{info, log, workspace}; +use crate::{info, log}; pub fn clone(verbose: bool) { // Read config struct from mlc.toml - let config = workspace::read_cfg(verbose); + let config = crate::internal::parse_cfg(verbose); log!(verbose, "Config: {:?}", config); let repos = &config.repositories; log!(verbose, "Repos: {:?}", repos); diff --git a/src/operations/info.rs b/src/operations/info.rs index 3eb7e27..dadd004 100644 --- a/src/operations/info.rs +++ b/src/operations/info.rs @@ -16,7 +16,7 @@ struct RepoDisplay { pub fn info(verbose: bool) { log!(verbose, "Showing Info"); - let config = crate::workspace::read_cfg(verbose); + let config = crate::internal::parse_cfg(verbose); log!(verbose, "Config: {:?}", config); // Add the branch to the name if it's not the default branch for said repository diff --git a/src/operations/prune.rs b/src/operations/prune.rs index 59e5fe9..bca8a97 100644 --- a/src/operations/prune.rs +++ b/src/operations/prune.rs @@ -4,7 +4,7 @@ use std::path::PathBuf; use crate::info; use crate::log; -use crate::read_cfg; +use crate::parse_cfg; #[derive(Debug, Clone)] struct PackageFile { @@ -15,7 +15,7 @@ struct PackageFile { pub fn prune(verbose: bool) { // Read config struct from mlc.toml - let config = read_cfg(verbose); + let config = parse_cfg(verbose); log!(verbose, "Config: {:?}", config); // Read current directory @@ -46,6 +46,7 @@ pub fn prune(verbose: bool) { for cap in re.captures_iter(file) { let name = cap[1].to_string(); let mut ver = cap[2].to_string(); + // Remove the leading "-" from the version and ext strings ver.remove(0).to_string(); let mut ext = cap[3].to_string(); ext.remove(0).to_string(); @@ -61,7 +62,7 @@ pub fn prune(verbose: bool) { log!(verbose, "Sorting Package: {:?}", package); let name = &package.name; let mut found = false; - for p in packages_by_name.iter_mut() { + for p in &mut packages_by_name { if &p[0].name == name { log!(verbose, "Found {}", name); found = true; @@ -75,14 +76,14 @@ pub fn prune(verbose: bool) { } // Sort each Vector of Vectors by version - for p in packages_by_name.iter_mut() { + for p in &mut packages_by_name { log!(verbose, "Sorting {:?}", p); p.sort_by(|a, b| b.ver.cmp(&a.ver)); } // Pushes all but the 4 most recent versions of each package into a new Vector of PackageFiles let mut packages_to_delete: Vec = vec![]; - for p in packages_by_name.iter() { + for p in &packages_by_name { let mut to_delete = vec![]; for (i, _) in p.iter().enumerate() { if i >= 3 { @@ -95,7 +96,7 @@ pub fn prune(verbose: bool) { log!(verbose, "Packages to delete: {:?}", packages_to_delete); // Delete all packages in packages_to_delete - for p in packages_to_delete.iter() { + for p in &packages_to_delete { let path = format!("{}-{}-{}", p.name, p.ver, p.ext); log!(verbose, "Deleting {}", path); std::process::Command::new("bash") @@ -111,7 +112,7 @@ pub fn prune(verbose: bool) { // Print which packages were deleted if !packages_to_delete.is_empty() { info!("Deleted the following packages:"); - for p in packages_to_delete.iter_mut() { + for p in &mut packages_to_delete { info!("{}-{}", p.name.replace("./", ""), p.ver); } } else { diff --git a/src/operations/pull.rs b/src/operations/pull.rs index c8161e6..3ebdfd6 100644 --- a/src/operations/pull.rs +++ b/src/operations/pull.rs @@ -2,7 +2,7 @@ use std::env; use std::process::Command; use crate::info; -use crate::{crash, internal::AppExitCode, log, workspace::read_cfg}; +use crate::{crash, internal::AppExitCode, log}; fn do_the_pulling( repos: Vec, @@ -84,14 +84,14 @@ fn do_the_pulling( info!("Rebuilding packages: {}", &packages_to_rebuild.join(", ")); log!(verbose, "Rebuilding packages: {:?}", &packages_to_rebuild); - crate::operations::build(packages_to_rebuild, vec![], no_regen, verbose); + crate::operations::build(&packages_to_rebuild, vec![], no_regen, verbose); } } } -pub fn pull(packages: Vec, exclude: Vec, verbose: bool, no_regen: bool) { +pub fn pull(packages: Vec, exclude: &[String], verbose: bool, no_regen: bool) { // Read config file - let config = read_cfg(verbose); + let config = crate::parse_cfg(verbose); log!(verbose, "Config: {:?}", config); // If no packages are specified, imply all let all = packages.is_empty(); @@ -117,7 +117,7 @@ pub fn pull(packages: Vec, exclude: Vec, verbose: bool, no_regen // Subtract exclude from repos_applicable if !exclude.is_empty() { - for ex in &exclude { + for ex in exclude.iter() { repos_applicable.retain(|x| *x != *ex); } } diff --git a/src/repository/repo.rs b/src/repository/repo.rs index b4f1e9e..0c1ab83 100644 --- a/src/repository/repo.rs +++ b/src/repository/repo.rs @@ -2,11 +2,11 @@ use std::path::Path; use std::process::Command; use std::{env, fs}; -use crate::{crash, info, internal::AppExitCode, log, workspace::read_cfg}; +use crate::{crash, info, internal::AppExitCode, log, internal::parse_cfg}; pub fn generate(verbose: bool) { // Read config struct from mlc.toml - let config = read_cfg(verbose); + let config = parse_cfg(verbose); log!(verbose, "Config: {:?}", config); // Get repository name from config diff --git a/src/workspace/mod.rs b/src/workspace/mod.rs deleted file mode 100755 index aa2213b..0000000 --- a/src/workspace/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub use read::*; - -mod read; From 8d93464d87a222905f881fe15819c3fe3ffbfa38 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 18:03:12 +0100 Subject: [PATCH 064/116] Buncha clippy stuff --- src/main.rs | 1 - src/operations/build.rs | 16 ++++++++-------- src/operations/config.rs | 4 ++-- src/operations/info.rs | 6 +++--- src/operations/prune.rs | 6 +++--- src/repository/config.rs | 2 +- 6 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/main.rs b/src/main.rs index dec2ad9..1779884 100755 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,6 @@ use std::process::Command; use crate::args::{Args, Operation}; use crate::internal::AppExitCode; -use crate::repository::create_config; use crate::internal::parse_cfg; #[global_allocator] diff --git a/src/operations/build.rs b/src/operations/build.rs index 79679f5..b7bf40d 100644 --- a/src/operations/build.rs +++ b/src/operations/build.rs @@ -37,14 +37,8 @@ pub fn build(packages: &[String], exclude: Vec, no_regen: bool, verbose: if !packages.is_empty() && !all { log!(verbose, "Packages not empty: {:?}", packages); for pkg in packages.iter() { - // If repo is not in config, crash - if !repos.iter().map(|x| x.name.clone()).any(|x| x == *pkg) { - crash!( - AppExitCode::PkgNotFound, - "Package repo {} not found in in mlc.toml", - pkg - ); - } else { + // If repo is not in config, crash, otherwise, build + if repos.iter().map(|x| x.name.clone()).any(|x| x == *pkg) { // Otherwise, build log!(verbose, "Building {}", pkg); let code = repository::build(pkg, sign, verbose); @@ -61,6 +55,12 @@ pub fn build(packages: &[String], exclude: Vec, no_regen: bool, verbose: }; errored.push(error); } + } else { + crash!( + AppExitCode::PkgNotFound, + "Package repo {} not found in in mlc.toml", + pkg + ); } } } diff --git a/src/operations/config.rs b/src/operations/config.rs index ea8f701..3b6a49f 100644 --- a/src/operations/config.rs +++ b/src/operations/config.rs @@ -2,13 +2,13 @@ use std::env; use std::path::Path; use std::process::Command; -use crate::{create_config, log}; +use crate::{repository::create, log}; pub fn config(verbose: bool) { // Generate new config file if not already present if !Path::exists("mlc.toml".as_ref()) { log!(verbose, "Creating mlc.toml"); - create_config(verbose); + create(verbose); } // Open config file in user's editor of choice diff --git a/src/operations/info.rs b/src/operations/info.rs index dadd004..3ad7631 100644 --- a/src/operations/info.rs +++ b/src/operations/info.rs @@ -40,9 +40,7 @@ pub fn info(verbose: bool) { log!(verbose, "Repos Sorted: {:?}", repos); // Displaying basic info about the Malachite Repository - let internal_name = if !config.mode.repository.name.is_empty() { - config.mode.repository.name - } else { + let internal_name = if config.mode.repository.name.is_empty() { env::current_dir() .unwrap() .file_name() @@ -50,6 +48,8 @@ pub fn info(verbose: bool) { .to_str() .unwrap() .to_string() + } else { + config.mode.repository.name }; let name = format!( "{} \"{}\":", diff --git a/src/operations/prune.rs b/src/operations/prune.rs index bca8a97..7c83f75 100644 --- a/src/operations/prune.rs +++ b/src/operations/prune.rs @@ -110,12 +110,12 @@ pub fn prune(verbose: bool) { log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); // Print which packages were deleted - if !packages_to_delete.is_empty() { + if packages_to_delete.is_empty() { + info!("No packages were deleted."); + } else { info!("Deleted the following packages:"); for p in &mut packages_to_delete { info!("{}-{}", p.name.replace("./", ""), p.ver); } - } else { - info!("No packages were deleted."); } } diff --git a/src/repository/config.rs b/src/repository/config.rs index a442c01..863d837 100644 --- a/src/repository/config.rs +++ b/src/repository/config.rs @@ -39,7 +39,7 @@ urls = [ "" ]"#; -pub fn create_config(verbose: bool) { +pub fn create(verbose: bool) { // Ensure current directory is empty if env::current_dir() .unwrap() From 989e01649f368248a67d688228f5e2bdb60f548b Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 18:03:49 +0100 Subject: [PATCH 065/116] FMT --- src/main.rs | 8 ++------ src/operations/build.rs | 2 +- src/operations/config.rs | 2 +- src/repository/repo.rs | 2 +- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/main.rs b/src/main.rs index 1779884..5a1fdc7 100755 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,4 @@ -#![warn( - clippy::all, - clippy::pedantic, - clippy::nursery, -)] +#![warn(clippy::all, clippy::pedantic, clippy::nursery)] use clap::Parser; use std::env; @@ -10,8 +6,8 @@ use std::path::Path; use std::process::Command; use crate::args::{Args, Operation}; -use crate::internal::AppExitCode; use crate::internal::parse_cfg; +use crate::internal::AppExitCode; #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; diff --git a/src/operations/build.rs b/src/operations/build.rs index b7bf40d..8b6d3dc 100644 --- a/src/operations/build.rs +++ b/src/operations/build.rs @@ -1,6 +1,6 @@ use crate::internal::structs::{ErroredPackage, Repo}; use crate::internal::AppExitCode; -use crate::{crash, info, log, repository, internal}; +use crate::{crash, info, internal, log, repository}; pub fn build(packages: &[String], exclude: Vec, no_regen: bool, verbose: bool) { // Read config struct from mlc.toml diff --git a/src/operations/config.rs b/src/operations/config.rs index 3b6a49f..503fe25 100644 --- a/src/operations/config.rs +++ b/src/operations/config.rs @@ -2,7 +2,7 @@ use std::env; use std::path::Path; use std::process::Command; -use crate::{repository::create, log}; +use crate::{log, repository::create}; pub fn config(verbose: bool) { // Generate new config file if not already present diff --git a/src/repository/repo.rs b/src/repository/repo.rs index 0c1ab83..0d0b391 100644 --- a/src/repository/repo.rs +++ b/src/repository/repo.rs @@ -2,7 +2,7 @@ use std::path::Path; use std::process::Command; use std::{env, fs}; -use crate::{crash, info, internal::AppExitCode, log, internal::parse_cfg}; +use crate::{crash, info, internal::parse_cfg, internal::AppExitCode, log}; pub fn generate(verbose: bool) { // Read config struct from mlc.toml From 5e4487733c5763650d31972615a6b6abe95fa13d Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 18:07:52 +0100 Subject: [PATCH 066/116] Pull params --- src/operations/pull.rs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/operations/pull.rs b/src/operations/pull.rs index 3ebdfd6..238cdcb 100644 --- a/src/operations/pull.rs +++ b/src/operations/pull.rs @@ -4,12 +4,16 @@ use std::process::Command; use crate::info; use crate::{crash, internal::AppExitCode, log}; -fn do_the_pulling( - repos: Vec, - verbose: bool, +struct PullParams { smart_pull: bool, build_on_update: bool, no_regen: bool, +} + +fn do_the_pulling( + repos: Vec, + verbose: bool, + params: &PullParams, ) { for repo in repos { // Set root dir to return after each git pull @@ -25,7 +29,7 @@ fn do_the_pulling( // Pull log!(verbose, "Pulling"); - if smart_pull { + if params.smart_pull { // Just update the remote log!(verbose, "Smart pull"); Command::new("git") @@ -53,7 +57,7 @@ fn do_the_pulling( .unwrap(); // If build_on_update is set, rebuild package - if build_on_update { + if params.build_on_update { info!("Package {} updated, staging for rebuild", &repo); log!(verbose, "Pushing package {} to be rebuilt", &repo); packages_to_rebuild.push(repo); @@ -80,11 +84,11 @@ fn do_the_pulling( env::current_dir().unwrap() ); - if !packages_to_rebuild.is_empty() && build_on_update { + if !packages_to_rebuild.is_empty() && params.build_on_update { info!("Rebuilding packages: {}", &packages_to_rebuild.join(", ")); log!(verbose, "Rebuilding packages: {:?}", &packages_to_rebuild); - crate::operations::build(&packages_to_rebuild, vec![], no_regen, verbose); + crate::operations::build(&packages_to_rebuild, vec![], params.no_regen, verbose); } } } @@ -134,8 +138,10 @@ pub fn pull(packages: Vec, exclude: &[String], verbose: bool, no_regen: do_the_pulling( repos_applicable, verbose, - smart_pull, - build_on_update, - no_regen, + &PullParams { + smart_pull, + build_on_update, + no_regen, + } ); } From 2d651b75e528898064136da64d4e171dbb66b96e Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 18:15:12 +0100 Subject: [PATCH 067/116] Pedantic clippy moment --- Cargo.toml | 1 + src/internal/strings.rs | 15 ++++++--------- src/main.rs | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3b9abbc..9923a3f 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ version = "2.0.0" authors = [ "michal " ] edition = "2021" description = "Packaging tool for pacman repositories" +repository = "https://github.com/crystal-linux/malachite" license-file = "LICENSE" keywords = [ "pacman", "repository", "packaging" ] categories = [ "filesystem", "development-tools" ] diff --git a/src/internal/strings.rs b/src/internal/strings.rs index 2d5feda..b5b314b 100755 --- a/src/internal/strings.rs +++ b/src/internal/strings.rs @@ -10,31 +10,29 @@ const ERR_SYMBOL: &str = "❌"; #[macro_export] macro_rules! info { ($($arg:tt)+) => { - $crate::internal::strings::info_fn(format!($($arg)+)); + $crate::internal::strings::info_fn(&format!($($arg)+)); } } #[macro_export] macro_rules! log { ($verbose:expr, $($arg:tt)+) => { - $crate::internal::strings::log_fn(format!("{}:{} {}", file!(), line!(), format!($($arg)+)), $verbose); + $crate::internal::strings::log_fn(&format!("{}:{} {}", file!(), line!(), format!($($arg)+)), $verbose); } } #[macro_export] macro_rules! crash { ($exit_code:expr, $($arg:tt)+) => { - $crate::internal::strings::crash_fn(format!($($arg)+), $exit_code) + $crate::internal::strings::crash_fn(&format!($($arg)+), $exit_code) } } -pub fn info_fn(msg: S) { - let msg = msg.to_string(); +pub fn info_fn(msg: &str) { println!("{} {}", LOGO_SYMBOL.black(), msg.bold()); } -pub fn log_fn(msg: S, verbose: bool) { - let msg = msg.to_string(); +pub fn log_fn(msg: &str, verbose: bool) { if verbose { eprintln!( "{} {}", @@ -47,8 +45,7 @@ pub fn log_fn(msg: S, verbose: bool) { } } -pub fn crash_fn(msg: S, exit_code: AppExitCode) { - let msg = msg.to_string(); +pub fn crash_fn(msg: &str, exit_code: AppExitCode) { println!("{} {}", ERR_SYMBOL.red(), msg.bold()); exit(exit_code as i32); } diff --git a/src/main.rs b/src/main.rs index 5a1fdc7..558b1ae 100755 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -#![warn(clippy::all, clippy::pedantic, clippy::nursery)] +#![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)] use clap::Parser; use std::env; From e4d2a81da7d01371a43a3a2af2b85a7b2f413b44 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 18:16:39 +0100 Subject: [PATCH 068/116] Added line numbers and file idents to crashes --- src/internal/strings.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/strings.rs b/src/internal/strings.rs index b5b314b..5e54c24 100755 --- a/src/internal/strings.rs +++ b/src/internal/strings.rs @@ -24,7 +24,7 @@ macro_rules! log { #[macro_export] macro_rules! crash { ($exit_code:expr, $($arg:tt)+) => { - $crate::internal::strings::crash_fn(&format!($($arg)+), $exit_code) + $crate::internal::strings::crash_fn(&format!("{}:{} {}", file!(), line!(), format!($($arg)+)), $exit_code) } } From 7e66bce41870f729b809c9dfdc1e8d164cdaf831 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 18:18:47 +0100 Subject: [PATCH 069/116] README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ee71539..bf92358 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,9 @@

Malachite is a simple yet useful workspace and local repository management tool, made for packagers of Arch Linux based distributions.

+# \>> [Detailed Usage Guide](docs/GETTING_STARTED.md) << + + ### Basic Usage Guide | Action | Command | @@ -39,9 +42,6 @@ - `mlc repo-gen` to generate functional pacman repository at \/\.db from built packages -## \>> [Detailed Usage Guide](docs/GETTING_STARTED.md) << - - ## How to build: Tested on latest Cargo (1.60.0-nightly) From 04d0c96c8e93fb7012e778a584fd386400c56f35 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 18:20:29 +0100 Subject: [PATCH 070/116] README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bf92358..49f5f45 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@

Malachite is a simple yet useful workspace and local repository management tool, made for packagers of Arch Linux based distributions.

-# \>> [Detailed Usage Guide](docs/GETTING_STARTED.md) << + Detailed Usage Guide ### Basic Usage Guide From 9e7daf8aa2b6af7e2789b75f08d86fab00d0a122 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 18:22:26 +0100 Subject: [PATCH 071/116] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 49f5f45..a65340a 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,11 @@ -

Malachite is a simple yet useful workspace and local repository management tool, made for packagers of Arch Linux based distributions.

+

+Malachite is a simple yet useful workspace and local repository management tool, made for packagers of Arch Linux based distributions. +

--> Detailed Usage Guide <--

+

- Detailed Usage Guide ### Basic Usage Guide From a2bafebcfbec7c96e97c81b8134f5d512703b8b1 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 21:23:51 +0100 Subject: [PATCH 072/116] New config represented in `config` command, replaced %repo% with {} --- examples/repository/mlc.toml | 4 ++-- examples/workspace/mlc.toml | 6 +++--- src/internal/read.rs | 2 +- src/repository/config.rs | 31 +++++++++++++++---------------- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/examples/repository/mlc.toml b/examples/repository/mlc.toml index 2a921f3..d2d37a4 100644 --- a/examples/repository/mlc.toml +++ b/examples/repository/mlc.toml @@ -20,5 +20,5 @@ repos = [ ] [repositories.urls] -crs = "https://github.com/crystal-linux/%repo%" -pkg = "https://github.com/crystal-linux/pkgbuild.%repo%" +crs = "https://github.com/crystal-linux/{}" +pkg = "https://github.com/crystal-linux/pkgbuild.{}" diff --git a/examples/workspace/mlc.toml b/examples/workspace/mlc.toml index f29b013..7c1a7d6 100644 --- a/examples/workspace/mlc.toml +++ b/examples/workspace/mlc.toml @@ -22,6 +22,6 @@ repos = [ ] [repositories.urls] -crs = "https://github.com/crystal-linux/%repo%" -aur = "https://aur.archlinux.org/%repo%" -nms = "https://github.com/not-my-segfault/%repo%" +crs = "https://github.com/crystal-linux/{}" +aur = "https://aur.archlinux.org/{}" +nms = "https://github.com/not-my-segfault/{}" diff --git a/src/internal/read.rs b/src/internal/read.rs index 4110d57..9a33bca 100644 --- a/src/internal/read.rs +++ b/src/internal/read.rs @@ -81,7 +81,7 @@ pub fn parse_cfg(verbose: bool) -> Config { urls_vec.push(url); } } - let url = urls_vec[0].replace("%repo%", &name); + let url = urls_vec[0].replace("{}", &name); // Counts instances of ! in the name, and totals a priority accordingly let priority = &split_struct.name.matches('!').count(); diff --git a/src/repository/config.rs b/src/repository/config.rs index 863d837..08b7150 100644 --- a/src/repository/config.rs +++ b/src/repository/config.rs @@ -14,31 +14,30 @@ mode = "" smart_pull = true [mode.repository] -# Only required when in repository mode, decides what to call the repository and relevant files +# Decides what to call the repository and relevant files name = "" -# Only required when in repository mode, decides whether to PGP sign built packages -sign = true -# Only required when in repository mode, decides whether to build packages if pull is successful +# Decides whether to build packages if package repo is updated on pull build_on_update = false +[mode.repository.signing] +# Decides whether or not to sign packages +enabled = true + [mode.workspace] # There are currently no options for workspace mode [repositories] -# An array of Git repositories to clone from, formatted url_index::repo_name(!) -# e.g. if you had URLs = [ "https://example.com/%repo%.git" ], 1::package would expand to https://example.com/package.git -# Repository mode only: Depending on the number of "!"s appended to the name, the priority of the package will be determined. More "!"s = higher priority = built first. -name = [ - "", - "" +# List of repositories formatted as id:name (priority is decided by the ! suffix, and decides package build order) +repos = [ + "aur:hello!", + "crs:malachite" ] -# An array of URLs to clone from, in the format https://example.com/%repo% (the %repo% is NOT optional and will be replaced with the name of the repository) -urls = [ - "", - "" -]"#; - +[repositories.urls] +# URL keys for repositories, with {} where the repository name would go +crs = "https://github.com/crystal-linux/{}" +aur = "https://aur.archlinux.org/{}" +"#; pub fn create(verbose: bool) { // Ensure current directory is empty if env::current_dir() From b165da91125a15eecb75205e61c72b52667226d9 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 21:49:10 +0100 Subject: [PATCH 073/116] Changed formatting for crash!() and log!() file:line formatting --- src/internal/strings.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/internal/strings.rs b/src/internal/strings.rs index 5e54c24..c409863 100755 --- a/src/internal/strings.rs +++ b/src/internal/strings.rs @@ -17,14 +17,14 @@ macro_rules! info { #[macro_export] macro_rules! log { ($verbose:expr, $($arg:tt)+) => { - $crate::internal::strings::log_fn(&format!("{}:{} {}", file!(), line!(), format!($($arg)+)), $verbose); + $crate::internal::strings::log_fn(&format!("[{}:{}] {}", file!(), line!(), format!($($arg)+)), $verbose); } } #[macro_export] macro_rules! crash { ($exit_code:expr, $($arg:tt)+) => { - $crate::internal::strings::crash_fn(&format!("{}:{} {}", file!(), line!(), format!($($arg)+)), $exit_code) + $crate::internal::strings::crash_fn(&format!("[{}:{}] {}", file!(), line!(), format!($($arg)+)), $exit_code) } } From 28387456316b5de9cf83b4d30980854bec5667b2 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 21:56:35 +0100 Subject: [PATCH 074/116] Documentation formatting issue --- docs/COMMON_FEATURES.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/COMMON_FEATURES.md b/docs/COMMON_FEATURES.md index 9f509bc..5ff985a 100644 --- a/docs/COMMON_FEATURES.md +++ b/docs/COMMON_FEATURES.md @@ -28,11 +28,11 @@ on_gen = false [mode.workspace] [repositories] -name = [ +repos = [ "foo:repo1", - "foo::repo2/testing", - "bar::baz!", - "bar::qux/testing!", + "foo:repo2/testing", + "bar:baz!", + "bar:qux/testing!", ] [repositories.urls] From 62f9ad527e72b53ac5b315c85336be49273d2ddf Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 22:27:42 +0100 Subject: [PATCH 075/116] it's green now --- src/internal/strings.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/strings.rs b/src/internal/strings.rs index c409863..6136042 100755 --- a/src/internal/strings.rs +++ b/src/internal/strings.rs @@ -29,7 +29,7 @@ macro_rules! crash { } pub fn info_fn(msg: &str) { - println!("{} {}", LOGO_SYMBOL.black(), msg.bold()); + println!("{} {}", LOGO_SYMBOL.green(), msg.bold()); } pub fn log_fn(msg: &str, verbose: bool) { From c2b963556b41c33c81dba6287b71964136d2d813 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 23 Jul 2022 23:40:17 +0100 Subject: [PATCH 076/116] Fixed clone diff issue --- src/operations/clone.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/operations/clone.rs b/src/operations/clone.rs index 1fb89bf..62e6078 100644 --- a/src/operations/clone.rs +++ b/src/operations/clone.rs @@ -15,13 +15,15 @@ pub fn clone(verbose: bool) { .map(|x| x.unwrap().path().display().to_string()) .collect::>(); dirs.retain(|x| *x != "./mlc.toml"); + dirs.retain(|x| *x != "./out"); + dirs.retain(|x| *x != format!("./{}", config.mode.repository.name)); log!(verbose, "Paths with mlc.toml excluded: {:?}", dirs); // Creates a vector of the difference between cloned repos and repos defined in config let mut repo_diff = vec![]; for repo in repos { let name = &repo.name; - if !dirs.contains(name) { + if !dirs.contains(&format!("./{}", name)) { repo_diff.push(repo); } } From 59f3c69f72690a03388b8760ce6d8c1d04a189e5 Mon Sep 17 00:00:00 2001 From: Michal Date: Sun, 24 Jul 2022 16:07:32 +0100 Subject: [PATCH 077/116] Initial git_info and colorblind implementation --- Cargo.lock | 85 +++++++++++++++ Cargo.toml | 2 +- docs/WORKSPACE_MODE.md | 18 +++- examples/repository/mlc.toml | 2 - examples/workspace/mlc.toml | 11 +- src/internal/exit_codes.rs | 1 + src/internal/structs.rs | 12 ++- src/main.rs | 1 + src/operations/build.rs | 12 ++- src/operations/clean.rs | 3 +- src/operations/clone.rs | 4 +- src/operations/info.rs | 196 ++++++++++++++++++++++++++++++----- src/operations/pull.rs | 14 +-- src/repository/repo.rs | 8 +- 14 files changed, 311 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4a6fe4f..98f9458 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,6 +18,30 @@ dependencies = [ "toml", ] +[[package]] +name = "ansi-str" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e50acdf02a3ac61856d5c8d576a8b5fb452a6549f667ca29fefaa18c2cd05135" +dependencies = [ + "ansitok", +] + +[[package]] +name = "ansitok" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2c6eb31f539d8fc1df948eb26452d6c781be4c9883663e7acb258644b71d5b1" +dependencies = [ + "nom", +] + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + [[package]] name = "atty" version = "0.2.14" @@ -161,6 +185,12 @@ dependencies = [ "cc", ] +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + [[package]] name = "mimalloc" version = "0.1.29" @@ -170,6 +200,22 @@ dependencies = [ "libmimalloc-sys", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "numtoa" version = "0.1.0" @@ -194,8 +240,10 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "453cf71f2a37af495a1a124bf30d4d7469cfbea58e9f2479be9d222396a518a2" dependencies = [ + "ansi-str", "bytecount", "fnv", + "strip-ansi-escapes", "unicode-width", ] @@ -291,6 +339,15 @@ dependencies = [ "syn", ] +[[package]] +name = "strip-ansi-escapes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8" +dependencies = [ + "vte", +] + [[package]] name = "strsim" version = "0.10.0" @@ -314,6 +371,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5b2f8c37d26d87d2252187b0a45ea3cbf42baca10377c7e7eaaa2800fa9bf97" dependencies = [ + "ansi-str", "papergrid", "tabled_derive", "unicode-width", @@ -380,12 +438,39 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +[[package]] +name = "utf8parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" + [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "vte" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983" +dependencies = [ + "arrayvec", + "utf8parse", + "vte_generate_state_changes", +] + +[[package]] +name = "vte_generate_state_changes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 9923a3f..e03621f 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,6 @@ serde = { version = "1.0.139", default-features = false } serde_derive = { version = "1.0.139", default-features = false } libc = { version = "0.2.126", default-features = false } colored = { version = "2.0.0", default-features = false } -tabled = { version = "0.8.0", default-features = false, features = ["derive"] } +tabled = { version = "0.8.0", default-features = false, features = ["derive", "color"] } termion = { version = "1.5.6", default-features = false } regex = { version = "1.6.0", default-features = false, features = ["std"] } diff --git a/docs/WORKSPACE_MODE.md b/docs/WORKSPACE_MODE.md index 125bd02..5bfd573 100644 --- a/docs/WORKSPACE_MODE.md +++ b/docs/WORKSPACE_MODE.md @@ -5,10 +5,24 @@ You'll never have to work(space) another day in your life! ```toml [mode.workspace] - +git_info = true +colorblind = true ``` -Oh, this is awkward. It seems like there *is no* workspace-specific config yet. I'm open to suggestions though! +Currently, Workspace mode only has 2 options, both pertaining to the display of information. (`mlc info`) + +The first key is `git_info`, which is a boolean value. If it is true, the git information will be displayed alongside repository information. + +This information will be formatted as so: `D Pl Ps ` + +The key for the values is as follows: +- D: Whether the repository is dirty or not (unstaged changes) +- Pl: Whether there are unpulled changes at the remote +- Ps: Whether there are unpushed changes in your local repository + +These will be typically displayed in either Green (Clean) or Red (Dirty) + +However, if colorblind is set to true, the colors will instead be set to Blue (Clean) or Dark Red (Dirty), to be more discernible to colorblind users ### For Now... diff --git a/examples/repository/mlc.toml b/examples/repository/mlc.toml index d2d37a4..99387b0 100644 --- a/examples/repository/mlc.toml +++ b/examples/repository/mlc.toml @@ -11,8 +11,6 @@ enabled = true key = "michal@tar.black" on_gen = true -[mode.workspace] - [repositories] repos = [ "crs:malachite/development", diff --git a/examples/workspace/mlc.toml b/examples/workspace/mlc.toml index 7c1a7d6..db0466f 100644 --- a/examples/workspace/mlc.toml +++ b/examples/workspace/mlc.toml @@ -2,16 +2,9 @@ mode = "workspace" smart_pull = true -[mode.repository] -name = "" -build_on_update = false - -[mode.repository.signing] -enabled = false -key = "" -on_gen = false - [mode.workspace] +git_info = true +colorblind = true [repositories] repos = [ diff --git a/src/internal/exit_codes.rs b/src/internal/exit_codes.rs index f50199f..9e7ddb3 100644 --- a/src/internal/exit_codes.rs +++ b/src/internal/exit_codes.rs @@ -8,4 +8,5 @@ pub enum AppExitCode { NoPkgs = 7, ConfigParseError = 8, InvalidRepo = 9, + NotInit = 10, } diff --git a/src/internal/structs.rs b/src/internal/structs.rs index 5d83b84..0be443c 100755 --- a/src/internal/structs.rs +++ b/src/internal/structs.rs @@ -24,8 +24,8 @@ pub struct ConfigBase { #[derive(Debug, Deserialize)] pub struct ConfigMode { - pub repository: ConfigModeRepository, - pub workspace: ConfigModeWorkspace, + pub repository: Option, + pub workspace: Option, } #[derive(Debug, Deserialize)] @@ -43,7 +43,13 @@ pub struct ConfigModeRepositorySigning { } #[derive(Debug, Deserialize)] -pub struct ConfigModeWorkspace {} +pub struct ConfigModeWorkspace { + pub git_info: bool, + pub colorblind: bool, + /* pub backup: bool, + pub backup_dir: Option, TODO: Implement backup + */ +} #[derive(Debug, Deserialize)] pub struct ConfigRepositories { diff --git a/src/main.rs b/src/main.rs index 558b1ae..622d63f 100755 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ #![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)] +#![allow(clippy::too_many_lines)] use clap::Parser; use std::env; diff --git a/src/operations/build.rs b/src/operations/build.rs index 8b6d3dc..a42d3b9 100644 --- a/src/operations/build.rs +++ b/src/operations/build.rs @@ -8,12 +8,18 @@ pub fn build(packages: &[String], exclude: Vec, no_regen: bool, verbose: log!(verbose, "Config: {:?}", config); let all = packages.is_empty(); log!(verbose, "All: {:?}", all); - let sign = if config.mode.repository.signing.enabled && config.mode.repository.signing.on_gen { + let sign = if config.mode.repository.as_ref().unwrap().signing.enabled + && config.mode.repository.as_ref().unwrap().signing.on_gen + { false } else { - config.mode.repository.signing.enabled + config.mode.repository.as_ref().unwrap().signing.enabled }; - log!(verbose, "Signing: {:?}", config.mode.repository.signing); + log!( + verbose, + "Signing: {:?}", + config.mode.repository.unwrap().signing + ); // Get list of repos and subtract exclude let mut repos: Vec = config.repositories; diff --git a/src/operations/clean.rs b/src/operations/clean.rs index f454ada..1c9a65d 100644 --- a/src/operations/clean.rs +++ b/src/operations/clean.rs @@ -9,8 +9,9 @@ pub fn clean(verbose: bool) { .map(|x| x.unwrap().path().display().to_string()) .collect::>(); - // Remove all files/dirs in the current directory, excluding ./mlc.toml + // Remove all files/dirs in the current directory, excluding ./mlc.toml and .git dirs.retain(|x| *x != "./mlc.toml"); + dirs.retain(|x| *x != "./.git"); log!(verbose, "Paths with mlc.toml excluded: {:?}", dirs); for dir in dirs { std::fs::remove_dir_all(dir).unwrap(); diff --git a/src/operations/clone.rs b/src/operations/clone.rs index 62e6078..2872cec 100644 --- a/src/operations/clone.rs +++ b/src/operations/clone.rs @@ -16,7 +16,9 @@ pub fn clone(verbose: bool) { .collect::>(); dirs.retain(|x| *x != "./mlc.toml"); dirs.retain(|x| *x != "./out"); - dirs.retain(|x| *x != format!("./{}", config.mode.repository.name)); + if config.mode.repository.is_some() { + dirs.retain(|x| *x != format!("./{}", config.mode.repository.as_ref().unwrap().name)); + } log!(verbose, "Paths with mlc.toml excluded: {:?}", dirs); // Creates a vector of the difference between cloned repos and repos defined in config diff --git a/src/operations/info.rs b/src/operations/info.rs index 3ad7631..ecc7acf 100644 --- a/src/operations/info.rs +++ b/src/operations/info.rs @@ -1,46 +1,168 @@ -use crate::{info, log}; +use crate::{crash, info, internal::AppExitCode, log}; use colored::Colorize; use std::env; +use std::process::Command; use tabled::Tabled; // For displaying the table of contents +#[derive(Clone, tabled::Tabled, Debug)] +struct RepoDisplayGit { + #[tabled(rename = "Name")] + name: String, + #[tabled(rename = "URL")] + url: String, + #[tabled(skip)] + priority: usize, + #[tabled(rename = "Git Info")] + git_info: String, +} + #[derive(Clone, tabled::Tabled, Debug)] struct RepoDisplay { #[tabled(rename = "Name")] name: String, #[tabled(rename = "URL")] url: String, - #[tabled(rename = "Priority")] + #[tabled(skip)] priority: usize, } +pub fn git_status(verbose: bool, repo: &str, colorblind: bool) -> String { + let dir = env::current_dir().unwrap(); + log!( + verbose, + "Current directory: {}", + env::current_dir().unwrap().display() + ); + env::set_current_dir(&repo).unwrap_or_else(|e| { + crash!( + AppExitCode::NotInit, + "Failed to enter directory {} for Git info: {}", + repo, + e.to_string() + ); + }); + log!(verbose, "Current directory: {}", repo); + + Command::new("git") + .args(&["remote", "update"]) + .output() + .unwrap(); + + let output = Command::new("git").arg("status").output().unwrap(); + let output = String::from_utf8(output.stdout).unwrap(); + log!(verbose, "Git status: {}", output); + + let unstaged = output.contains("Changes not staged for commit"); + let untracked = output.contains("Untracked files"); + let dirty = unstaged || untracked; + + let pull = output.contains("Your branch is behind"); + let push = output.contains("Your branch is ahead"); + + let latest_commit = Command::new("git") + .args(&["log", "--pretty=%h", "-1"]) + .output() + .unwrap(); + let mut latest_commit = String::from_utf8(latest_commit.stdout).unwrap(); + latest_commit.retain(|c| !c.is_whitespace()); + + let output = if colorblind { + format!( + "{} {} {} {}", + if dirty { "D".red() } else { "D".bright_blue() }, + if pull { "Pl".red() } else { "Pl".bright_blue() }, + if push { "Ps".red() } else { "Ps".bright_blue() }, + latest_commit + ) + } else { + format!( + "{} {} {} {}", + if dirty { "D".red() } else { "D".green() }, + if pull { "Pl".red() } else { "Pl".green() }, + if push { "Ps".red() } else { "Ps".green() }, + latest_commit + ) + }; + env::set_current_dir(&dir).unwrap(); + log!(verbose, "Current directory: {}", dir.display()); + output +} + pub fn info(verbose: bool) { log!(verbose, "Showing Info"); let config = crate::internal::parse_cfg(verbose); log!(verbose, "Config: {:?}", config); + let git_info = if config.mode.workspace.is_some() { + config.mode.workspace.as_ref().unwrap().git_info + } else { + false + }; + log!(verbose, "Git info: {}", git_info); + + let colorblind = if config.mode.workspace.is_some() { + config.mode.workspace.as_ref().unwrap().colorblind + } else { + false + }; + log!(verbose, "Colorblind: {}", colorblind); + // Add the branch to the name if it's not the default branch for said repository let repos_unparsed = config.repositories; let mut repos = vec![]; + let mut repos_git = vec![]; for repo in repos_unparsed { + // Get name with branch, '/' serving as the delimiter let name = if repo.branch.is_some() { format!("{}/{}", repo.name, repo.branch.unwrap()) } else { repo.name.clone() }; - repos.push(RepoDisplay { - name, - url: repo.url, - priority: repo.priority, - }); + + // Get git info, if applicable + let git_info_string = if git_info { + Some(git_status( + verbose, + &repo.name, + config.mode.workspace.as_ref().unwrap().colorblind, + )) + } else { + None + }; + + // Push to the correct vector, we're using a separate vector for git info because + // the struct we're displaying is different + if git_info { + repos_git.push(RepoDisplayGit { + name, + url: repo.url.clone(), + priority: repo.priority, + git_info: git_info_string.unwrap(), + }); + } else { + repos.push(RepoDisplay { + name, + url: repo.url.clone(), + priority: repo.priority, + }); + } } log!(verbose, "Repos: {:?}", repos); + // Sort by priority repos.sort_by(|a, b| b.priority.cmp(&a.priority)); - log!(verbose, "Repos Sorted: {:?}", repos); + repos_git.sort_by(|a, b| b.priority.cmp(&a.priority)); + if git_info { + log!(verbose, "Repos Sorted: {:?}", repos_git); + } else { + log!(verbose, "Repos Sorted: {:?}", repos); + } // Displaying basic info about the Malachite Repository - let internal_name = if config.mode.repository.name.is_empty() { + let internal_name = if config.mode.repository.is_none() + || config.mode.repository.as_ref().unwrap().name.is_empty() + { env::current_dir() .unwrap() .file_name() @@ -49,17 +171,13 @@ pub fn info(verbose: bool) { .unwrap() .to_string() } else { - config.mode.repository.name + config.mode.repository.unwrap().name }; let name = format!( "{} \"{}\":", - if config.base.mode == "repository" { - "Repository".to_string() - } else if config.base.mode == "workspace" { - "Workspace".to_string() - } else { - "".to_string() - }, + // Sidenote: It should NOT be this convoluted to capitalise the first character of a string in rust. What the fuck. + String::from_utf8_lossy(&[config.base.mode.as_bytes()[0].to_ascii_uppercase()]) + + &config.base.mode[1..], internal_name ); @@ -70,16 +188,42 @@ pub fn info(verbose: bool) { }; // Create table for displaying info - let table = tabled::Table::new(&repos) - .with(tabled::Style::modern()) - .with(tabled::Width::wrap(width as usize)) - .to_string(); + let table = if git_info { + tabled::Table::new(&repos_git) + .with(tabled::Style::modern()) + .with(tabled::Width::wrap(width as usize)) + .to_string() + } else { + tabled::Table::new(&repos) + .with(tabled::Style::modern()) + .with(tabled::Width::wrap(width as usize)) + .to_string() + }; + + // Get length of Vec for displaying in the table + let len = if git_info { + repos_git.len() + } else { + repos.len() + }; // Print all of the info info!("{}", name); - info!( - "Local Repositories: {}", - repos.len().to_string().green().bold() - ); - println!("{}", table.bold()); + info!("Local Repositories: {}", len); + println!("{}", table); + if config.mode.workspace.is_some() && config.mode.workspace.as_ref().unwrap().git_info { + info!( + "Key: \n \ + D: Dirty - Unstaged Changes \n \ + Pl: Pull - Changes at Remote \n \ + Ps: Push - Unpushed Changes \n \ + {}: Applies, {}: Does Not Apply", + " ".on_red(), + if config.mode.workspace.unwrap().colorblind { + " ".on_bright_blue() + } else { + " ".on_green() + } + ); + } } diff --git a/src/operations/pull.rs b/src/operations/pull.rs index 238cdcb..e74c97a 100644 --- a/src/operations/pull.rs +++ b/src/operations/pull.rs @@ -10,11 +10,7 @@ struct PullParams { no_regen: bool, } -fn do_the_pulling( - repos: Vec, - verbose: bool, - params: &PullParams, -) { +fn do_the_pulling(repos: Vec, verbose: bool, params: &PullParams) { for repo in repos { // Set root dir to return after each git pull let root_dir = env::current_dir().unwrap(); @@ -104,7 +100,11 @@ pub fn pull(packages: Vec, exclude: &[String], verbose: bool, no_regen: let smart_pull = config.base.smart_pull; log!(verbose, "Smart pull: {}", smart_pull); // Read build_on_update from config - let build_on_update = config.mode.repository.build_on_update; + let build_on_update = if config.mode.repository.is_some() { + config.mode.repository.unwrap().build_on_update + } else { + false + }; log!(verbose, "Build on update: {}", build_on_update); // Read repos from config @@ -142,6 +142,6 @@ pub fn pull(packages: Vec, exclude: &[String], verbose: bool, no_regen: smart_pull, build_on_update, no_regen, - } + }, ); } diff --git a/src/repository/repo.rs b/src/repository/repo.rs index 0d0b391..8fab7c8 100644 --- a/src/repository/repo.rs +++ b/src/repository/repo.rs @@ -10,7 +10,7 @@ pub fn generate(verbose: bool) { log!(verbose, "Config: {:?}", config); // Get repository name from config - let name = config.mode.repository.name; + let name = &config.mode.repository.as_ref().unwrap().name; log!(verbose, "Name: {}", name); info!("Generating repository: {}", name); @@ -39,7 +39,9 @@ pub fn generate(verbose: bool) { log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); // Sign all package files in repository if signing and on_gen are true - if config.mode.repository.signing.enabled && config.mode.repository.signing.on_gen { + if config.mode.repository.as_ref().unwrap().signing.enabled + && config.mode.repository.as_ref().unwrap().signing.on_gen + { // Get a list of all .tar.* files in repository let files = fs::read_dir("./").unwrap(); for file in files { @@ -52,7 +54,7 @@ pub fn generate(verbose: bool) { "-c", &format!( "gpg --default-key {} --detach-sign {}", - config.mode.repository.signing.key, + config.mode.repository.as_ref().unwrap().signing.key, file.file_name().to_str().unwrap() ), ]) From 8850997b5de3ea15ebfa53599cc2d05520a11210 Mon Sep 17 00:00:00 2001 From: Michal Date: Sun, 24 Jul 2022 16:10:30 +0100 Subject: [PATCH 078/116] Removed intrusive auto pulling of parent git repo --- src/main.rs | 51 ++++----------------------------------------------- 1 file changed, 4 insertions(+), 47 deletions(-) diff --git a/src/main.rs b/src/main.rs index 622d63f..d9771f5 100755 --- a/src/main.rs +++ b/src/main.rs @@ -2,9 +2,6 @@ #![allow(clippy::too_many_lines)] use clap::Parser; -use std::env; -use std::path::Path; -use std::process::Command; use crate::args::{Args, Operation}; use crate::internal::parse_cfg; @@ -23,6 +20,7 @@ fn main() { crash!(AppExitCode::RunAsRoot, "Running malachite as root is disallowed as it can lead to system breakage. Instead, malachite will prompt you when it needs superuser permissions"); } + // Get required variables let args: Args = Args::parse(); let exclude = &args.exclude; let verbose = args.verbose; @@ -30,56 +28,15 @@ fn main() { log!(verbose, "Exclude: {:?}", exclude); log!(verbose, "Verbose: You guess. :)"); + // Parse config let config = parse_cfg(verbose); log!(verbose, "Config: {:?}", config); - if Path::exists("../.git".as_ref()) { - log!(verbose, "Detected parent git repository"); - info!("Parent directory is a git directory, pulling latest mlc.toml. It is advised you run mlc pull/update in all malachite directories"); - - let dir = env::current_dir().unwrap(); - env::set_current_dir("../").unwrap(); - log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); - - if config.base.smart_pull { - log!(verbose, "Smart pull"); - Command::new("git") - .args(&["remote", "update"]) - .spawn() - .unwrap() - .wait() - .unwrap(); - let output = Command::new("git").arg("status").output().unwrap(); - if String::from_utf8(output.stdout) - .unwrap() - .contains("Your branch is behind") - { - info!("Branch out of date, pulling changes"); - Command::new("git") - .arg("pull") - .spawn() - .unwrap() - .wait() - .unwrap(); - } else { - info!("No changes to pull"); - } - } else { - log!(verbose, "Normal pull"); - Command::new("git") - .arg("pull") - .spawn() - .unwrap() - .wait() - .unwrap(); - } - env::set_current_dir(dir).unwrap(); - log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); - } - + // Get repository mode status let repository = config.base.mode == "repository"; log!(verbose, "Repository Mode: {:?}", repository); + // Arg matching match args.subcommand.unwrap_or(Operation::Clone) { Operation::Clone => operations::clone(verbose), Operation::Build { From 2f56563746aaa35a1c45f1ffc4cb9d192f5b5b9f Mon Sep 17 00:00:00 2001 From: Michal Date: Sun, 24 Jul 2022 16:12:12 +0100 Subject: [PATCH 079/116] Added crash for prune in workspace mode --- src/main.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index d9771f5..f4eb576 100755 --- a/src/main.rs +++ b/src/main.rs @@ -57,13 +57,21 @@ fn main() { if !repository { crash!( AppExitCode::BuildInWorkspace, - "Cannot build packages in workspace mode" + "Cannot generate repository in workspace mode" ); } repository::generate(verbose); } Operation::Config => operations::config(verbose), - Operation::Prune => operations::prune(verbose), + Operation::Prune => { + if !repository { + crash!( + AppExitCode::BuildInWorkspace, + "Cannot prune packages in workspace mode" + ); + } + operations::prune(verbose) + }, Operation::Clean => operations::clean(verbose), Operation::Info => operations::info(verbose), } From 78634aa28ed45958d415354a1a102b43d2583c29 Mon Sep 17 00:00:00 2001 From: Michal Date: Sun, 24 Jul 2022 16:15:55 +0100 Subject: [PATCH 080/116] Added checking for uncomitted added changes for dirty check --- src/operations/info.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operations/info.rs b/src/operations/info.rs index ecc7acf..a8e39f9 100644 --- a/src/operations/info.rs +++ b/src/operations/info.rs @@ -53,7 +53,7 @@ pub fn git_status(verbose: bool, repo: &str, colorblind: bool) -> String { let output = String::from_utf8(output.stdout).unwrap(); log!(verbose, "Git status: {}", output); - let unstaged = output.contains("Changes not staged for commit"); + let unstaged = output.contains("Changes not staged for commit") || output.contains("Changes to be committed"); let untracked = output.contains("Untracked files"); let dirty = unstaged || untracked; From 8dc969032528ae0c1127235de2be3a8b49a1f6ec Mon Sep 17 00:00:00 2001 From: Michal Date: Sun, 24 Jul 2022 16:21:01 +0100 Subject: [PATCH 081/116] Better warn message --- src/operations/info.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operations/info.rs b/src/operations/info.rs index a8e39f9..91aeac9 100644 --- a/src/operations/info.rs +++ b/src/operations/info.rs @@ -37,7 +37,7 @@ pub fn git_status(verbose: bool, repo: &str, colorblind: bool) -> String { env::set_current_dir(&repo).unwrap_or_else(|e| { crash!( AppExitCode::NotInit, - "Failed to enter directory {} for Git info: {}", + "Failed to enter directory {} for Git info: {}, Have you initialized the repo?", repo, e.to_string() ); From 60cdf55d6ad4693cd8399e920ff9fa8204925843 Mon Sep 17 00:00:00 2001 From: Michal Date: Sun, 24 Jul 2022 16:21:47 +0100 Subject: [PATCH 082/116] FMT + consistent formatting --- src/main.rs | 4 ++-- src/operations/info.rs | 6 ++++-- src/repository/config.rs | 1 + 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index f4eb576..193fd4d 100755 --- a/src/main.rs +++ b/src/main.rs @@ -70,8 +70,8 @@ fn main() { "Cannot prune packages in workspace mode" ); } - operations::prune(verbose) - }, + operations::prune(verbose); + } Operation::Clean => operations::clean(verbose), Operation::Info => operations::info(verbose), } diff --git a/src/operations/info.rs b/src/operations/info.rs index 91aeac9..eebac49 100644 --- a/src/operations/info.rs +++ b/src/operations/info.rs @@ -1,9 +1,10 @@ -use crate::{crash, info, internal::AppExitCode, log}; use colored::Colorize; use std::env; use std::process::Command; use tabled::Tabled; +use crate::{crash, info, internal::AppExitCode, log}; + // For displaying the table of contents #[derive(Clone, tabled::Tabled, Debug)] struct RepoDisplayGit { @@ -53,7 +54,8 @@ pub fn git_status(verbose: bool, repo: &str, colorblind: bool) -> String { let output = String::from_utf8(output.stdout).unwrap(); log!(verbose, "Git status: {}", output); - let unstaged = output.contains("Changes not staged for commit") || output.contains("Changes to be committed"); + let unstaged = output.contains("Changes not staged for commit") + || output.contains("Changes to be committed"); let untracked = output.contains("Untracked files"); let dirty = unstaged || untracked; diff --git a/src/repository/config.rs b/src/repository/config.rs index 08b7150..c432dd5 100644 --- a/src/repository/config.rs +++ b/src/repository/config.rs @@ -38,6 +38,7 @@ repos = [ crs = "https://github.com/crystal-linux/{}" aur = "https://aur.archlinux.org/{}" "#; + pub fn create(verbose: bool) { // Ensure current directory is empty if env::current_dir() From d7a858c546998c79238354c2dfb1f73309390372 Mon Sep 17 00:00:00 2001 From: Michal Date: Sun, 24 Jul 2022 16:26:47 +0100 Subject: [PATCH 083/116] Documentation slight changes --- docs/COMMON_FEATURES.md | 2 -- docs/REPOSITORY_MODE.md | 5 ++++- docs/WORKSPACE_MODE.md | 8 +++++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/COMMON_FEATURES.md b/docs/COMMON_FEATURES.md index 5ff985a..3a5c8a7 100644 --- a/docs/COMMON_FEATURES.md +++ b/docs/COMMON_FEATURES.md @@ -25,8 +25,6 @@ enabled = false key = "" on_gen = false -[mode.workspace] - [repositories] repos = [ "foo:repo1", diff --git a/docs/REPOSITORY_MODE.md b/docs/REPOSITORY_MODE.md index edcae1b..3242a8a 100644 --- a/docs/REPOSITORY_MODE.md +++ b/docs/REPOSITORY_MODE.md @@ -6,7 +6,7 @@ PacManage your repositories in style! As opposed to the rather barren Workspace mode, the Repository mode config is rather fleshed out, and we have a few options to choose from. -Let's take an example config, +Let's take an example section from a Repository mode config, ```toml [mode.repository] @@ -36,3 +36,6 @@ Calling back to the example above, we can see 3 config keys: - `key`: Defines the GPG key ID to use for signing. - `on_gen`: Defines whether to sign packages when they are built, or all at once on repository generation (this is also recommended). +--- + +You can return to [Getting Started](GETTING_STARTED.md) page here! diff --git a/docs/WORKSPACE_MODE.md b/docs/WORKSPACE_MODE.md index 5bfd573..3167365 100644 --- a/docs/WORKSPACE_MODE.md +++ b/docs/WORKSPACE_MODE.md @@ -3,6 +3,8 @@ You'll never have to work(space) another day in your life! ### Workspace Config +Taking an example section from the Workspace mode config, + ```toml [mode.workspace] git_info = true @@ -22,8 +24,8 @@ The key for the values is as follows: These will be typically displayed in either Green (Clean) or Red (Dirty) -However, if colorblind is set to true, the colors will instead be set to Blue (Clean) or Dark Red (Dirty), to be more discernible to colorblind users +However, if `colorblind` is set to true, the colors will instead be set to Blue (Clean) or Dark Red (Dirty), to be more discernible to colorblind users -### For Now... +--- -You can return to [Getting Started](GETTING_STARTED.md), or head directly into [Repository Mode](REPOSITORY_MODE.md) to see where Malachite really shines! \ No newline at end of file +You can return to [Getting Started](GETTING_STARTED.md) page here! \ No newline at end of file From aa4bb2fecbe82f50ea890233633036439693afd0 Mon Sep 17 00:00:00 2001 From: Michal Date: Sun, 24 Jul 2022 16:28:04 +0100 Subject: [PATCH 084/116] Documentation slight changes --- docs/COMMON_FEATURES.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/COMMON_FEATURES.md b/docs/COMMON_FEATURES.md index 3a5c8a7..315fb88 100644 --- a/docs/COMMON_FEATURES.md +++ b/docs/COMMON_FEATURES.md @@ -119,4 +119,10 @@ For mode-specific config, avert your eyes to the following links! - [Workspace Mode](WORKSPACE_MODE.md) - [Repository Mode](REPOSITORY_MODE.md) +### Examples + +Functioning config examples for both modes are available in the [examples](../examples) directory! + +### Usage + Alternatively, you can look at the [Usage](USAGE.md) guide! From 09e7e544dc30e3b449064826861f7623eddc3399 Mon Sep 17 00:00:00 2001 From: Michal Date: Sun, 24 Jul 2022 16:32:13 +0100 Subject: [PATCH 085/116] Fixed word wrap formatting in info function --- src/operations/info.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/operations/info.rs b/src/operations/info.rs index eebac49..5bb93b9 100644 --- a/src/operations/info.rs +++ b/src/operations/info.rs @@ -193,12 +193,12 @@ pub fn info(verbose: bool) { let table = if git_info { tabled::Table::new(&repos_git) .with(tabled::Style::modern()) - .with(tabled::Width::wrap(width as usize)) + .with(tabled::Width::wrap(width as usize).keep_words()) .to_string() } else { tabled::Table::new(&repos) .with(tabled::Style::modern()) - .with(tabled::Width::wrap(width as usize)) + .with(tabled::Width::wrap(width as usize).keep_words()) .to_string() }; @@ -215,8 +215,7 @@ pub fn info(verbose: bool) { println!("{}", table); if config.mode.workspace.is_some() && config.mode.workspace.as_ref().unwrap().git_info { info!( - "Key: \n \ - D: Dirty - Unstaged Changes \n \ + "D: Dirty - Unstaged Changes \n \ Pl: Pull - Changes at Remote \n \ Ps: Push - Unpushed Changes \n \ {}: Applies, {}: Does Not Apply", From f6c878d061b8a1b25024666dba2082f77c76a22d Mon Sep 17 00:00:00 2001 From: Michal Date: Sun, 24 Jul 2022 17:16:24 +0100 Subject: [PATCH 086/116] Consistent formatting for lists --- src/operations/clean.rs | 10 +++++++++- src/operations/prune.rs | 14 ++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/operations/clean.rs b/src/operations/clean.rs index 1c9a65d..5a463dc 100644 --- a/src/operations/clean.rs +++ b/src/operations/clean.rs @@ -13,7 +13,15 @@ pub fn clean(verbose: bool) { dirs.retain(|x| *x != "./mlc.toml"); dirs.retain(|x| *x != "./.git"); log!(verbose, "Paths with mlc.toml excluded: {:?}", dirs); - for dir in dirs { + for dir in &dirs { std::fs::remove_dir_all(dir).unwrap(); } + info!( + "Reset complete, dirs removed: \n \ + {}", + dirs.iter() + .map(|x| x.replace("./", "")) + .collect::>() + .join("\n ") + ); } diff --git a/src/operations/prune.rs b/src/operations/prune.rs index 7c83f75..cc17e04 100644 --- a/src/operations/prune.rs +++ b/src/operations/prune.rs @@ -6,6 +6,8 @@ use crate::info; use crate::log; use crate::parse_cfg; +use colored::Colorize; + #[derive(Debug, Clone)] struct PackageFile { name: String, @@ -37,18 +39,19 @@ pub fn prune(verbose: bool) { } log!(verbose, "Files: {:?}", files); - // Split files into Vec, turning name-1.0.0-1-x86_64.tar.gz into PackageFile { name: "name", ver: "1.0.0-1", ext: "x86_64.tar.gz" } + // Split files into Vec, turning package-name-1.0.0-1-x86_64.tar.gz into PackageFile { name: "package-name", ver: "1.0.0-1", ext: "x86_64.tar.gz" } let mut packages: Vec = vec![]; for file in files { // Regex fuckery. Please don't mess with this. let re = regex::Regex::new(r"^(.+)(-.+-.+)(-.+\..+\..+\.+..+)$").unwrap(); let file = file.to_str().unwrap(); for cap in re.captures_iter(file) { + // Collect regex captures let name = cap[1].to_string(); let mut ver = cap[2].to_string(); - // Remove the leading "-" from the version and ext strings - ver.remove(0).to_string(); let mut ext = cap[3].to_string(); + // Strip leading - from ver and ext + ver.remove(0).to_string(); ext.remove(0).to_string(); let package = PackageFile { name, ver, ext }; log!(verbose, "Package: {:?}", package); @@ -115,7 +118,10 @@ pub fn prune(verbose: bool) { } else { info!("Deleted the following packages:"); for p in &mut packages_to_delete { - info!("{}-{}", p.name.replace("./", ""), p.ver); + println!( + "{}", + format!(" {}-{}", p.name.replace("./", ""), p.ver).bold() + ); } } } From 80635576dba7a701c105fddd57bdcbaddae5b49b Mon Sep 17 00:00:00 2001 From: Michal Date: Sun, 24 Jul 2022 17:28:04 +0100 Subject: [PATCH 087/116] Formatting for tables --- src/operations/info.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/operations/info.rs b/src/operations/info.rs index 5bb93b9..635ecce 100644 --- a/src/operations/info.rs +++ b/src/operations/info.rs @@ -211,14 +211,14 @@ pub fn info(verbose: bool) { // Print all of the info info!("{}", name); - info!("Local Repositories: {}", len); + info!("Total Repositories: {}", len.to_string().green()); println!("{}", table); if config.mode.workspace.is_some() && config.mode.workspace.as_ref().unwrap().git_info { info!( "D: Dirty - Unstaged Changes \n \ Pl: Pull - Changes at Remote \n \ Ps: Push - Unpushed Changes \n \ - {}: Applies, {}: Does Not Apply", + {}: Dirty, {}: Clean", " ".on_red(), if config.mode.workspace.unwrap().colorblind { " ".on_bright_blue() From 236c16d824a15c3e8bd81612d7006943ecf96c44 Mon Sep 17 00:00:00 2001 From: Michal Date: Sun, 24 Jul 2022 17:58:38 +0100 Subject: [PATCH 088/116] Added dirty checking to `mlc clean` and `--force` arg to counteract it --- docs/USAGE.md | 17 ++++++++-------- examples/workspace/mlc.toml | 2 +- src/args.rs | 6 +++++- src/internal/exit_codes.rs | 1 + src/main.rs | 2 +- src/operations/clean.rs | 39 ++++++++++++++++++++++++++++++++++--- 6 files changed, 53 insertions(+), 14 deletions(-) diff --git a/docs/USAGE.md b/docs/USAGE.md index 66a9f03..4a714e8 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -10,14 +10,15 @@ Work it harder, make it better! ### Basic Commands -| Action | Command | Extra Flags | -|--------------------------------------------------------|-------------------------------------------|------------------------------------------------------------------------------------------------------------------| -| Build a package/packages. | `mlc build ` [all if left empty] | `--no-regen`: Doesn't regenerate repository after build | -| Generate pacman repository | `mlc repo-gen` | | -| Update local repos/PKGBUILDs | `mlc pull/update` [all if left empty] | `--no-regen`: If `mode.repository.build_on_update` is `true`, Do not regenerate repository after package rebuild | -| Create and/or open config file | `mlc conf` | | -| Initialises repo/workspace based on config in mlc.toml | `mlc clone/init` | | -| Displays an info panel/overview of the current repo | `mlc info/status` | | +| Action | Command | Extra Flags | +|-----------------------------------------------------------------------------------------|-------------------------------------------|------------------------------------------------------------------------------------------------------------------| +| Build a package/packages. | `mlc build ` [all if left empty] | `--no-regen`: Doesn't regenerate repository after build | +| Generate pacman repository | `mlc repo-gen` | | +| Update local repos/PKGBUILDs | `mlc pull/update` [all if left empty] | `--no-regen`: If `mode.repository.build_on_update` is `true`, Do not regenerate repository after package rebuild | +| Create and/or open config file | `mlc conf` | | +| Initialises repo/workspace based on config in mlc.toml | `mlc clone/init` | | +| Displays an info panel/overview of the current repo | `mlc info/status` | | +| Resets Malachite repository by deleting all directories, omitting `mlc.toml` and `.git` | `mlc clean/reset` | `--force`: Remove dirty directories (unstaged, untracked, etc) | ### Exit Codes diff --git a/examples/workspace/mlc.toml b/examples/workspace/mlc.toml index db0466f..6ddb633 100644 --- a/examples/workspace/mlc.toml +++ b/examples/workspace/mlc.toml @@ -4,7 +4,7 @@ smart_pull = true [mode.workspace] git_info = true -colorblind = true +colorblind = false [repositories] repos = [ diff --git a/src/args.rs b/src/args.rs index 3601042..170f297 100644 --- a/src/args.rs +++ b/src/args.rs @@ -39,7 +39,11 @@ pub enum Operation { /// Removes everything in directory except for mlc.toml #[clap(name = "clean", aliases = & ["clean", "cl", "reset"])] - Clean, + Clean { + /// Force removes everything, even if git directory is dirty or has unpushed changes or changes at remote + #[clap(short = 'f', long = "force", action = ArgAction::SetTrue)] + force: bool, + }, /// Removes all but the latest 3 versions of each package in a repository #[clap(name = "prune", aliases = & ["prune", "p"])] diff --git a/src/internal/exit_codes.rs b/src/internal/exit_codes.rs index 9e7ddb3..ba53a67 100644 --- a/src/internal/exit_codes.rs +++ b/src/internal/exit_codes.rs @@ -9,4 +9,5 @@ pub enum AppExitCode { ConfigParseError = 8, InvalidRepo = 9, NotInit = 10, + NotClean = 11, } diff --git a/src/main.rs b/src/main.rs index 193fd4d..445f459 100755 --- a/src/main.rs +++ b/src/main.rs @@ -72,7 +72,7 @@ fn main() { } operations::prune(verbose); } - Operation::Clean => operations::clean(verbose), + Operation::Clean { force, .. } => operations::clean(verbose, force), Operation::Info => operations::info(verbose), } } diff --git a/src/operations/clean.rs b/src/operations/clean.rs index 5a463dc..acb667c 100644 --- a/src/operations/clean.rs +++ b/src/operations/clean.rs @@ -1,6 +1,6 @@ -use crate::{info, log}; +use crate::{info, log, crash, internal::AppExitCode}; -pub fn clean(verbose: bool) { +pub fn clean(verbose: bool, force: bool) { info!("Resetting mlc repo, deleting all directories"); // Get a vec of all files/dirs in the current directory let dir_paths = std::fs::read_dir("./").unwrap(); @@ -9,9 +9,42 @@ pub fn clean(verbose: bool) { .map(|x| x.unwrap().path().display().to_string()) .collect::>(); - // Remove all files/dirs in the current directory, excluding ./mlc.toml and .git + // Remove mlc.toml and .git from output dirs.retain(|x| *x != "./mlc.toml"); dirs.retain(|x| *x != "./.git"); + + // Enter each directory and check git status + + let mut unclean_dirs = vec![]; + + for dir in &dirs { + let root_dir = std::env::current_dir().unwrap(); + log!(verbose, "Entering directory: {}", dir); + std::env::set_current_dir(dir).unwrap(); + let status = std::process::Command::new("git") + .arg("status") + .output() + .unwrap(); + let output = std::string::String::from_utf8(status.stdout).unwrap(); + log!(verbose, "Git status: {}", output); + if output.contains("Your branch is up to date with") && !output.contains("Untracked files") && !output.contains("Changes not staged for commit") { + log!(verbose, "Directory {} is clean", dir); + } else { + unclean_dirs.push(dir); + } + std::env::set_current_dir(&root_dir).unwrap(); + log!(verbose, "Current directory: {}", root_dir.display()); + } + + if unclean_dirs.len() > 0 && !force{ + crash!( + AppExitCode::NotClean, + "The following directories are not clean: \n {}\n\ + If you are sure no important changes are staged, run `mlc clean` with the `--force` flag to delete them.", + unclean_dirs.iter().map(|x| x.to_string().replace("./", "")).collect::>().join(", ") + ); + } + log!(verbose, "Paths with mlc.toml excluded: {:?}", dirs); for dir in &dirs { std::fs::remove_dir_all(dir).unwrap(); From bfee01218aeb9035fc84bd118abda9f6b88ac2d4 Mon Sep 17 00:00:00 2001 From: Michal Date: Sun, 24 Jul 2022 17:59:50 +0100 Subject: [PATCH 089/116] Clippy + Fmt --- src/operations/clean.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/operations/clean.rs b/src/operations/clean.rs index acb667c..1d4ef86 100644 --- a/src/operations/clean.rs +++ b/src/operations/clean.rs @@ -1,4 +1,4 @@ -use crate::{info, log, crash, internal::AppExitCode}; +use crate::{crash, info, internal::AppExitCode, log}; pub fn clean(verbose: bool, force: bool) { info!("Resetting mlc repo, deleting all directories"); @@ -27,7 +27,10 @@ pub fn clean(verbose: bool, force: bool) { .unwrap(); let output = std::string::String::from_utf8(status.stdout).unwrap(); log!(verbose, "Git status: {}", output); - if output.contains("Your branch is up to date with") && !output.contains("Untracked files") && !output.contains("Changes not staged for commit") { + if output.contains("Your branch is up to date with") + && !output.contains("Untracked files") + && !output.contains("Changes not staged for commit") + { log!(verbose, "Directory {} is clean", dir); } else { unclean_dirs.push(dir); @@ -36,12 +39,12 @@ pub fn clean(verbose: bool, force: bool) { log!(verbose, "Current directory: {}", root_dir.display()); } - if unclean_dirs.len() > 0 && !force{ + if !unclean_dirs.is_empty() && !force { crash!( AppExitCode::NotClean, "The following directories are not clean: \n {}\n\ If you are sure no important changes are staged, run `mlc clean` with the `--force` flag to delete them.", - unclean_dirs.iter().map(|x| x.to_string().replace("./", "")).collect::>().join(", ") + unclean_dirs.iter().map(|x| (*x).to_string().replace("./", "")).collect::>().join(", ") ); } From a6bde352687a5f19b1d12697c2eaad366282bb36 Mon Sep 17 00:00:00 2001 From: Michal Date: Sun, 24 Jul 2022 19:32:49 +0100 Subject: [PATCH 090/116] Added spinner for long Git info operations --- Cargo.lock | 53 ++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/operations/info.rs | 17 ++++++++++++-- 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 98f9458..63fdfe8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,6 +13,7 @@ dependencies = [ "regex", "serde", "serde_derive", + "spinoff", "tabled", "termion", "toml", @@ -185,6 +186,12 @@ dependencies = [ "cc", ] +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + [[package]] name = "memchr" version = "2.5.0" @@ -322,6 +329,12 @@ version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" +[[package]] +name = "rustversion" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24c8ad4f0c00e1eb5bc7614d236a7f1300e3dbd76b68cac8e06fb00b015ad8d8" + [[package]] name = "serde" version = "1.0.140" @@ -339,6 +352,18 @@ dependencies = [ "syn", ] +[[package]] +name = "spinoff" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d3f754b5a185a81fa60acbd32f095411e276743d27307a531d34eae5d49c991" +dependencies = [ + "maplit", + "once_cell", + "strum", + "yansi", +] + [[package]] name = "strip-ansi-escapes" version = "0.1.1" @@ -354,6 +379,28 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4faebde00e8ff94316c01800f9054fd2ba77d30d9e922541913051d1d978918b" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "syn" version = "1.0.98" @@ -501,3 +548,9 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" diff --git a/Cargo.toml b/Cargo.toml index e03621f..79bcf9d 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,3 +30,4 @@ colored = { version = "2.0.0", default-features = false } tabled = { version = "0.8.0", default-features = false, features = ["derive", "color"] } termion = { version = "1.5.6", default-features = false } regex = { version = "1.6.0", default-features = false, features = ["std"] } +spinoff = { version = "0.4.0", default-features = false } diff --git a/src/operations/info.rs b/src/operations/info.rs index 635ecce..5363d95 100644 --- a/src/operations/info.rs +++ b/src/operations/info.rs @@ -2,6 +2,7 @@ use colored::Colorize; use std::env; use std::process::Command; use tabled::Tabled; +use spinoff::{Spinner, Spinners, Color}; use crate::{crash, info, internal::AppExitCode, log}; @@ -114,6 +115,8 @@ pub fn info(verbose: bool) { let repos_unparsed = config.repositories; let mut repos = vec![]; let mut repos_git = vec![]; + + let sp = Spinner::new(Spinners::Dots, format!("{}", "Parsing Git Info...".bold()), Color::Green); for repo in repos_unparsed { // Get name with branch, '/' serving as the delimiter let name = if repo.branch.is_some() { @@ -124,11 +127,12 @@ pub fn info(verbose: bool) { // Get git info, if applicable let git_info_string = if git_info { - Some(git_status( + let info = Some(git_status( verbose, &repo.name, config.mode.workspace.as_ref().unwrap().colorblind, - )) + )); + info } else { None }; @@ -150,6 +154,15 @@ pub fn info(verbose: bool) { }); } } + + // Thanks memory management + let symbol = Box::new(format!("{}", "✔".bold().green())); + let done = Box::new(format!("{}", "Done!".bold())); + + let symbol: &'static str = Box::leak(symbol); + let done: &'static str = Box::leak(done); + + sp.stop_and_persist(symbol, done); log!(verbose, "Repos: {:?}", repos); // Sort by priority From 360c669025a6733347d5c0c9a4aeadb85583072f Mon Sep 17 00:00:00 2001 From: Michal Date: Sun, 24 Jul 2022 20:17:27 +0100 Subject: [PATCH 091/116] Fmt --- src/operations/info.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/operations/info.rs b/src/operations/info.rs index 5363d95..4350276 100644 --- a/src/operations/info.rs +++ b/src/operations/info.rs @@ -1,8 +1,8 @@ use colored::Colorize; +use spinoff::{Color, Spinner, Spinners}; use std::env; use std::process::Command; use tabled::Tabled; -use spinoff::{Spinner, Spinners, Color}; use crate::{crash, info, internal::AppExitCode, log}; @@ -116,7 +116,11 @@ pub fn info(verbose: bool) { let mut repos = vec![]; let mut repos_git = vec![]; - let sp = Spinner::new(Spinners::Dots, format!("{}", "Parsing Git Info...".bold()), Color::Green); + let sp = Spinner::new( + Spinners::Dots, + format!("{}", "Parsing Git Info...".bold()), + Color::Green, + ); for repo in repos_unparsed { // Get name with branch, '/' serving as the delimiter let name = if repo.branch.is_some() { From f10e67c334f907e1b558b7680c1355a97091f072 Mon Sep 17 00:00:00 2001 From: Michal Date: Sun, 24 Jul 2022 22:00:05 +0100 Subject: [PATCH 092/116] Added optional 2nd : delimiter for specifying clone depth --- docs/COMMON_FEATURES.md | 9 +++++---- examples/workspace/mlc.toml | 2 ++ src/internal/read.rs | 24 +++++++++++++++++++++--- src/internal/structs.rs | 2 ++ src/operations/clone.rs | 22 +++++++++++++++++++++- src/operations/info.rs | 2 +- 6 files changed, 52 insertions(+), 9 deletions(-) diff --git a/docs/COMMON_FEATURES.md b/docs/COMMON_FEATURES.md index 315fb88..48a3776 100644 --- a/docs/COMMON_FEATURES.md +++ b/docs/COMMON_FEATURES.md @@ -27,10 +27,10 @@ on_gen = false [repositories] repos = [ - "foo:repo1", + "foo:repo1:2", "foo:repo2/testing", "bar:baz!", - "bar:qux/testing!", + "bar:qux/testing!:1", ] [repositories.urls] @@ -86,10 +86,10 @@ facilitate many packages without having to type each url out a million times. ```toml [repositories] repos = [ - "foo:repo1", + "foo:repo1:2", "foo:repo2/testing", "bar:baz!", - "bar:qux/testing!", + "bar:qux/testing!:1", ] [repositories.urls] @@ -108,6 +108,7 @@ The way this works is simple: I'm glad you asked! - If you want to clone a specific branch, simply use the `/` delimiter. To clone repository `foo` on branch `bar`, use `id:foo/bar`. - If you want a specific package to build first, use instances of `!` to set priority. This is explained later in the [Repository Mode](REPOSITORY_MODE.md) page +- If you want to clone the repository with a specific depth, for example, in the case of a large git repository like `nixpkgs`, you can add a 2nd `:` delimiter and the integer after that will be used as the depth That's literally it! diff --git a/examples/workspace/mlc.toml b/examples/workspace/mlc.toml index 6ddb633..7023d69 100644 --- a/examples/workspace/mlc.toml +++ b/examples/workspace/mlc.toml @@ -12,9 +12,11 @@ repos = [ "crs:malachite/development!", "aur:notop-git", "nms:appendage", + "nix:nixpkgs/nixos-unstable:ass", ] [repositories.urls] crs = "https://github.com/crystal-linux/{}" aur = "https://aur.archlinux.org/{}" nms = "https://github.com/not-my-segfault/{}" +nix = "https://github.com/nixos/{}" diff --git a/src/internal/read.rs b/src/internal/read.rs index 9a33bca..9147655 100644 --- a/src/internal/read.rs +++ b/src/internal/read.rs @@ -43,9 +43,26 @@ pub fn parse_cfg(verbose: bool) -> Config { log!(verbose, "Parsing repo: {:?}", x); // Splits the repo name and index inta a SplitRepo struct let split: Vec<&str> = x.split(':').collect(); - let split_struct = SplitRepo { - id: split[0].parse().unwrap(), - name: split[1].parse().unwrap(), + let split_struct = if split.len() > 2 { + SplitRepo { + id: split[0].parse().unwrap(), + name: split[1].parse().unwrap(), + depth: Some(split[2].parse().unwrap_or_else(|e| { + crash!( + AppExitCode::ConfigParseError, + "Depth must be an integer: {}", + e + ); + // This is unreachable, but rustc complains about it otherwise + std::process::exit(1); + })), + } + } else { + SplitRepo { + id: split[0].parse().unwrap(), + name: split[1].parse().unwrap(), + depth: None, + } }; log!(verbose, "Split repo: {:?}", split_struct); @@ -91,6 +108,7 @@ pub fn parse_cfg(verbose: bool) -> Config { name, url, branch, + depth: split_struct.depth, priority: *priority, }; log!(verbose, "Expanded repo: {:?}", repo); diff --git a/src/internal/structs.rs b/src/internal/structs.rs index 0be443c..9e18d32 100755 --- a/src/internal/structs.rs +++ b/src/internal/structs.rs @@ -68,6 +68,7 @@ pub struct Repo { pub name: String, pub url: String, pub branch: Option, + pub depth: Option, pub priority: usize, } @@ -75,6 +76,7 @@ pub struct Repo { pub struct SplitRepo { pub id: String, pub name: String, + pub depth: Option, } //// Build operation structs diff --git a/src/operations/clone.rs b/src/operations/clone.rs index 2872cec..3a48a52 100644 --- a/src/operations/clone.rs +++ b/src/operations/clone.rs @@ -47,8 +47,23 @@ pub fn clone(verbose: bool) { // Clone all diff repos for r in repo_diff { + let depth = if r.depth.is_some() { + format!("{}", r.depth.as_ref().unwrap()) + } else { + "".to_string() + }; + log!(verbose, "Depth: {:?}", r.depth); log!(verbose, "Cloning {}", r.name); - info!("Cloning ({} mode): {}", config.base.mode, r.name); + if r.depth.is_some() { + info!( + "Cloning ({} mode): {} - Depth: {}", + config.base.mode, + r.name, + r.depth.unwrap() + ); + } else { + info!("Cloning ({} mode): {}", config.base.mode, r.name); + } Command::new("git") .args(&["clone", &r.url, &r.name]) // If a branch is specified, clone that specific branch @@ -57,6 +72,11 @@ pub fn clone(verbose: bool) { } else { vec![] }) + .args(if depth.is_empty() { + vec![] + } else { + vec!["--depth", &depth] + }) .spawn() .unwrap() .wait() diff --git a/src/operations/info.rs b/src/operations/info.rs index 4350276..932c2e0 100644 --- a/src/operations/info.rs +++ b/src/operations/info.rs @@ -159,7 +159,7 @@ pub fn info(verbose: bool) { } } - // Thanks memory management + // Because spinoff requires &'static str, we need to Box these in the heap and then leak them to be able to format the spinner let symbol = Box::new(format!("{}", "✔".bold().green())); let done = Box::new(format!("{}", "Done!".bold())); From d570a4d5bef005cbc3e71ec94f9e8312969e9f6f Mon Sep 17 00:00:00 2001 From: Michal Date: Sun, 24 Jul 2022 22:54:55 +0100 Subject: [PATCH 093/116] Implemented second delimiter as rev spec in repo mode --- docs/COMMON_FEATURES.md | 20 +++---- examples/repository/mlc.toml | 4 +- examples/workspace/mlc.toml | 4 +- src/internal/read.rs | 14 +---- src/internal/structs.rs | 4 +- src/operations/clone.rs | 111 +++++++++++++++++++++++++++-------- 6 files changed, 104 insertions(+), 53 deletions(-) diff --git a/docs/COMMON_FEATURES.md b/docs/COMMON_FEATURES.md index 48a3776..cc97717 100644 --- a/docs/COMMON_FEATURES.md +++ b/docs/COMMON_FEATURES.md @@ -16,14 +16,9 @@ Without further ado, let's take a look at this example config file. mode = "workspace" smart_pull = true -[mode.repository] -name = "" -build_on_update = false - -[mode.repository.signing] -enabled = false -key = "" -on_gen = false +[mode.workspace] +git_info = true +colorblind = true [repositories] repos = [ @@ -93,8 +88,8 @@ repos = [ ] [repositories.urls] -foo = "https://example.org/%repo%.git" -bar = "https://example.org/other/%repo%.git" +foo = "https://example.org/{}.git" +bar = "https://example.org/other/{}.git" ``` The way this works is simple: @@ -108,7 +103,10 @@ The way this works is simple: I'm glad you asked! - If you want to clone a specific branch, simply use the `/` delimiter. To clone repository `foo` on branch `bar`, use `id:foo/bar`. - If you want a specific package to build first, use instances of `!` to set priority. This is explained later in the [Repository Mode](REPOSITORY_MODE.md) page -- If you want to clone the repository with a specific depth, for example, in the case of a large git repository like `nixpkgs`, you can add a 2nd `:` delimiter and the integer after that will be used as the depth + +The last `:` delimiter is entirely optional, and behaves differently depending on the mode: +- In Repository mode, it defines the desired commit hash/rev/tag to checkout on repository clone +- In Workspace mode, it defines the desired depth to clone the repository, useful with large git repositories, such as `nixpkgs`. That's literally it! diff --git a/examples/repository/mlc.toml b/examples/repository/mlc.toml index 99387b0..3b9a0f4 100644 --- a/examples/repository/mlc.toml +++ b/examples/repository/mlc.toml @@ -13,10 +13,12 @@ on_gen = true [repositories] repos = [ - "crs:malachite/development", + "crs:malachite/development:0a5bdc9", + "mic:apod:v.1.1.2", "pkg:pfetch!", ] [repositories.urls] crs = "https://github.com/crystal-linux/{}" pkg = "https://github.com/crystal-linux/pkgbuild.{}" +mic = "https://git.tar.black/michal/{}" diff --git a/examples/workspace/mlc.toml b/examples/workspace/mlc.toml index 7023d69..27d2bed 100644 --- a/examples/workspace/mlc.toml +++ b/examples/workspace/mlc.toml @@ -11,12 +11,10 @@ repos = [ "crs:amethyst", "crs:malachite/development!", "aur:notop-git", - "nms:appendage", - "nix:nixpkgs/nixos-unstable:ass", + "nix:nixpkgs/nixos-unstable:1", ] [repositories.urls] crs = "https://github.com/crystal-linux/{}" aur = "https://aur.archlinux.org/{}" -nms = "https://github.com/not-my-segfault/{}" nix = "https://github.com/nixos/{}" diff --git a/src/internal/read.rs b/src/internal/read.rs index 9147655..749c81e 100644 --- a/src/internal/read.rs +++ b/src/internal/read.rs @@ -47,21 +47,13 @@ pub fn parse_cfg(verbose: bool) -> Config { SplitRepo { id: split[0].parse().unwrap(), name: split[1].parse().unwrap(), - depth: Some(split[2].parse().unwrap_or_else(|e| { - crash!( - AppExitCode::ConfigParseError, - "Depth must be an integer: {}", - e - ); - // This is unreachable, but rustc complains about it otherwise - std::process::exit(1); - })), + extra: Some(split[2].parse().unwrap()), } } else { SplitRepo { id: split[0].parse().unwrap(), name: split[1].parse().unwrap(), - depth: None, + extra: None, } }; log!(verbose, "Split repo: {:?}", split_struct); @@ -108,7 +100,7 @@ pub fn parse_cfg(verbose: bool) -> Config { name, url, branch, - depth: split_struct.depth, + extra: split_struct.extra, priority: *priority, }; log!(verbose, "Expanded repo: {:?}", repo); diff --git a/src/internal/structs.rs b/src/internal/structs.rs index 9e18d32..59cb8b3 100755 --- a/src/internal/structs.rs +++ b/src/internal/structs.rs @@ -68,7 +68,7 @@ pub struct Repo { pub name: String, pub url: String, pub branch: Option, - pub depth: Option, + pub extra: Option, pub priority: usize, } @@ -76,7 +76,7 @@ pub struct Repo { pub struct SplitRepo { pub id: String, pub name: String, - pub depth: Option, + pub extra: Option, } //// Build operation structs diff --git a/src/operations/clone.rs b/src/operations/clone.rs index 3a48a52..75db48b 100644 --- a/src/operations/clone.rs +++ b/src/operations/clone.rs @@ -1,3 +1,4 @@ +use std::env; use std::process::Command; use crate::{info, log}; @@ -47,40 +48,100 @@ pub fn clone(verbose: bool) { // Clone all diff repos for r in repo_diff { - let depth = if r.depth.is_some() { - format!("{}", r.depth.as_ref().unwrap()) - } else { - "".to_string() - }; - log!(verbose, "Depth: {:?}", r.depth); + log!(verbose, "Depth: {:?}", r.extra); log!(verbose, "Cloning {}", r.name); - if r.depth.is_some() { + if r.extra.is_some() && config.base.mode == "workspace" { info!( - "Cloning ({} mode): {} - Depth: {}", + "Cloning ({} mode): {} at depth: {}", config.base.mode, r.name, - r.depth.unwrap() + r.extra.as_ref().unwrap() + ); + } else if r.extra.is_some() && config.base.mode == "repository" { + info!( + "Cloning ({} mode): {} at {}", + config.base.mode, + r.name, + r.extra.as_ref().unwrap() ); } else { info!("Cloning ({} mode): {}", config.base.mode, r.name); } - Command::new("git") - .args(&["clone", &r.url, &r.name]) - // If a branch is specified, clone that specific branch - .args(if r.branch.is_some() { - vec!["-b", r.branch.as_ref().unwrap()] - } else { - vec![] - }) - .args(if depth.is_empty() { - vec![] + + if r.extra.is_some() && config.base.mode == "workspace" { + // Clone with specified extra depth + Command::new("git") + .args(&["clone", &r.url, &r.name]) + // If a branch is specified, clone that specific branch + .args(if r.branch.is_some() { + vec!["-b", r.branch.as_ref().unwrap()] + } else { + vec![] + }) + .args(if r.extra.is_some() { + vec!["--depth", r.extra.as_ref().unwrap()] + } else { + vec![] + }) + .spawn() + .unwrap() + .wait() + .unwrap(); + } else if config.base.mode == "repository" { + // Clone and checkout specified hash + // Create an empty directory with repo.name and enter it + let root_dir = env::current_dir().unwrap(); + + // Git clone the repo with the `-n` flag to not immediately checkout the files + Command::new("git") + .args(&["clone", &r.url, &r.name, "-n"]) + .args(if r.branch.is_some() { + vec!["-b", r.branch.as_ref().unwrap()] + } else { + vec![] + }) + .spawn() + .unwrap() + .wait() + .unwrap(); + + std::env::set_current_dir(&r.name).unwrap(); + log!(verbose, "Entered directory: {}", r.name); + + // Git checkout the PKGBUILD from the hash + if r.extra.is_some() { + Command::new("git") + .args(&["checkout", r.extra.as_ref().unwrap(), "PKGBUILD"]) + .spawn() + .unwrap() + .wait() + .unwrap(); } else { - vec!["--depth", &depth] - }) - .spawn() - .unwrap() - .wait() - .unwrap(); + Command::new("git") + .args(&["checkout", "HEAD", "PKGBUILD"]) + .spawn() + .unwrap() + .wait() + .unwrap(); + } + + // Return to the root directory + std::env::set_current_dir(root_dir).unwrap(); + log!(verbose, "Returned to root directory"); + } else { + // Clone normally + Command::new("git") + .args(&["clone", &r.url, &r.name]) + .args(if r.branch.is_some() { + vec!["-b", r.branch.as_ref().unwrap()] + } else { + vec![] + }) + .spawn() + .unwrap() + .wait() + .unwrap(); + } } } } From 965efda97ab4661c4f3645af3ca269f0073c9685 Mon Sep 17 00:00:00 2001 From: Michal Date: Sun, 24 Jul 2022 23:05:24 +0100 Subject: [PATCH 094/116] Changed spinner --- src/operations/info.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operations/info.rs b/src/operations/info.rs index 932c2e0..2880b6b 100644 --- a/src/operations/info.rs +++ b/src/operations/info.rs @@ -117,7 +117,7 @@ pub fn info(verbose: bool) { let mut repos_git = vec![]; let sp = Spinner::new( - Spinners::Dots, + Spinners::Line, format!("{}", "Parsing Git Info...".bold()), Color::Green, ); From 997027e49ba354165583b20e7c58cab794c10e22 Mon Sep 17 00:00:00 2001 From: Michal Date: Sun, 24 Jul 2022 23:42:26 +0100 Subject: [PATCH 095/116] Update COMMON_FEATURES.md --- docs/COMMON_FEATURES.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/docs/COMMON_FEATURES.md b/docs/COMMON_FEATURES.md index cc97717..1cd9031 100644 --- a/docs/COMMON_FEATURES.md +++ b/docs/COMMON_FEATURES.md @@ -1,11 +1,11 @@ # Common Features Between Modes -As[mode]us, shared of between uh... repositories... or something. +As[mode]us, shared of between uh… repositories… or something. ### What you need to know Malachite is fairly fleshed out in Repository mode, and not so much in Workspace mode. This isn't of course because I'm lazy and hate Workspace mode or anything, there's just not -a whole lot *to* add. +a lot *to* add. Without further ado, let's take a look at this example config file. @@ -33,10 +33,10 @@ foo = "https://example.org/%repo%.git" bar = "https://example.org/other/%repo%.git" ``` -Now this is going to look really confusing at first, but bear with me. +Now, this is going to look really confusing at first, but bear with me. -In this document we'll cover only what is required to know for **both** modes. -More specialised tutorials will be linked for each mode at the bottom of this page. +In this document, we'll cover only what is required to know for **both** modes. +More specialized tutorials will be linked for each mode at the bottom of this page. Let's start with the base(ics). @@ -52,10 +52,10 @@ smart_pull = true In this snippet, we define `mode` to be `"workspace"`. -`base.mode` in Malachite can only ever be one of `"workspace"` or `"repository"`, and defines, drumroll... +`base.mode` in Malachite can only ever be one of `"workspace"` or `"repository"`, and defines, drumroll… The mode in which it operates. If it is set to anything but those 2 modes, it crashes. -Also defined in this snippet is `smart_pull`, which controls whether or not to pull... smartly. +Also defined in this snippet is `smart_pull`, which controls whether to pull… smartly. What that actually means is that instead of just performing a simple `git pull` in each repository, Malachite will: @@ -68,15 +68,15 @@ will: Theoretically, this only actually speeds things up by a minute amount (think milliseconds, really). Where this feature shines however is in repository mode, where it enables helpful automation features such as `build_on_update`. -Regardless, it's recommended to keep this enabled for the slight speedup, and only disable it if it causes issues. +Regardless, it's recommended to keep this enabled for the slight speed-up, and only disable it if it causes issues. I've never personally had issues with it in the past, but who knows what could happen. This is Git we're talking about. ### Repositories Config The repositories config is realistically what makes Malachite churn repo butter internally. It's the whole -purpose of what it does, and because of that we've tried to come up with a neat little system so as to help -facilitate many packages without having to type each url out a million times. +purpose of what it does, and because of that we've tried to come up with a neat little system to help +facilitate many packages without having to type each URL out a million times. ```toml [repositories] @@ -93,9 +93,9 @@ bar = "https://example.org/other/{}.git" ``` The way this works is simple: -- We have 2 urls in the `repositories.urls` key. +- We have 2 URLs in the `repositories.urls` key. - Each `repo` in the `repositories.repos` key is prefixed with an identifier. -- If the number is `foo`, it'll insert the url with the id `foo`. +- If the number is `foo`, it'll insert the URL with the id `foo`. - Specifically, in the URL, it'll insert the defined `repo`'s name in place of the `%repo%` substring. #### Hang on, what are the special symbols???? @@ -125,3 +125,4 @@ Functioning config examples for both modes are available in the [examples](../ex ### Usage Alternatively, you can look at the [Usage](USAGE.md) guide! + From b2b2fff81d2d782fd9c11d116a50b8a527bd546b Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 25 Jul 2022 00:43:38 +0100 Subject: [PATCH 096/116] Added windows test flake support + termion -> crossterm --- Cargo.lock | 205 +++++++++++++++++++++++++++++++++++------ Cargo.toml | 2 +- flake.lock | 66 +++++++++---- flake.nix | 53 +++++++++-- src/operations/info.rs | 2 +- 5 files changed, 273 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 63fdfe8..dd575cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,7 @@ version = "2.0.0" dependencies = [ "clap", "colored", + "crossterm", "libc", "mimalloc", "regex", @@ -15,7 +16,6 @@ dependencies = [ "serde_derive", "spinoff", "tabled", - "termion", "toml", ] @@ -78,6 +78,12 @@ version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "clap" version = "3.2.14" @@ -128,6 +134,31 @@ dependencies = [ "winapi", ] +[[package]] +name = "crossterm" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab9f7409c70a38a56216480fba371ee460207dd8926ccf5b4160591759559170" +dependencies = [ + "bitflags", + "crossterm_winapi", + "libc", + "mio", + "parking_lot", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c" +dependencies = [ + "winapi", +] + [[package]] name = "fnv" version = "1.0.7" @@ -186,6 +217,25 @@ dependencies = [ "cc", ] +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + [[package]] name = "maplit" version = "1.0.2" @@ -213,6 +263,18 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "mio" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys", +] + [[package]] name = "nom" version = "7.1.1" @@ -223,12 +285,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "numtoa" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" - [[package]] name = "once_cell" version = "1.13.0" @@ -254,6 +310,29 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -305,15 +384,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "redox_termios" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f" -dependencies = [ - "redox_syscall", -] - [[package]] name = "regex" version = "1.6.0" @@ -335,6 +405,12 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24c8ad4f0c00e1eb5bc7614d236a7f1300e3dbd76b68cac8e06fb00b015ad8d8" +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "serde" version = "1.0.140" @@ -352,6 +428,42 @@ dependencies = [ "syn", ] +[[package]] +name = "signal-hook" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "smallvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" + [[package]] name = "spinoff" version = "0.4.0" @@ -446,18 +558,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "termion" -version = "1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e" -dependencies = [ - "libc", - "numtoa", - "redox_syscall", - "redox_termios", -] - [[package]] name = "textwrap" version = "0.15.0" @@ -518,6 +618,12 @@ dependencies = [ "quote", ] +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "winapi" version = "0.3.9" @@ -549,6 +655,49 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + [[package]] name = "yansi" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index 79bcf9d..5ce3990 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,6 @@ serde_derive = { version = "1.0.139", default-features = false } libc = { version = "0.2.126", default-features = false } colored = { version = "2.0.0", default-features = false } tabled = { version = "0.8.0", default-features = false, features = ["derive", "color"] } -termion = { version = "1.5.6", default-features = false } +crossterm = { version = "0.24.0", default-features = false } regex = { version = "1.6.0", default-features = false, features = ["std"] } spinoff = { version = "0.4.0", default-features = false } diff --git a/flake.lock b/flake.lock index 6c9d2c1..8376166 100644 --- a/flake.lock +++ b/flake.lock @@ -1,8 +1,31 @@ { "nodes": { + "fenix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "rust-analyzer-src": "rust-analyzer-src" + }, + "locked": { + "lastModified": 1658644019, + "narHash": "sha256-P4ZEkrJSvtiBVnXZUagg6QtiVRc6k9XgTbWLZ7Q73Ow=", + "owner": "nix-community", + "repo": "fenix", + "rev": "a844a251dcd8aac45d47a81adae6117ff4f57b8d", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "fenix", + "type": "github" + } + }, "naersk": { "inputs": { - "nixpkgs": "nixpkgs" + "nixpkgs": [ + "nixpkgs" + ] }, "locked": { "lastModified": 1655042882, @@ -20,40 +43,45 @@ }, "nixpkgs": { "locked": { - "lastModified": 1658371388, - "narHash": "sha256-ACjtJNUAqjAdR+o5EDcOGgK3aseB+IF1TSBNPVftdLg=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "af7d2aaa0d7fae44cdef463538833d536e3def1f", - "type": "github" - }, - "original": { - "id": "nixpkgs", - "type": "indirect" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1658411452, - "narHash": "sha256-eaGBS2czRjZW/lChi9cWOQjusF/UHuHGJeYzk6QWKUw=", + "lastModified": 1658644204, + "narHash": "sha256-MWyfCH9K3eVTXJUxBi67OQSAh9jJAnvWklM6qm4j8w8=", "owner": "nixos", "repo": "nixpkgs", - "rev": "e3a3abe560a143dde4b77176575d02ff32ffebcb", + "rev": "2f0c3be57c348f4cfd8820f2d189e29a685d9c41", "type": "github" }, "original": { "owner": "nixos", + "ref": "nixpkgs-unstable", "repo": "nixpkgs", "type": "github" } }, "root": { "inputs": { + "fenix": "fenix", "naersk": "naersk", - "nixpkgs": "nixpkgs_2", + "nixpkgs": "nixpkgs", "utils": "utils" } }, + "rust-analyzer-src": { + "flake": false, + "locked": { + "lastModified": 1658612252, + "narHash": "sha256-mO2M5pgrkxjSURWILT91w+ChkQ3mU+oOpdxF+yFaBEc=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "977e12a0bdc3e329af179ef3a9d466af9eb613bb", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", + "type": "github" + } + }, "utils": { "locked": { "lastModified": 1656928814, diff --git a/flake.nix b/flake.nix index 17be9ac..4c7d731 100644 --- a/flake.nix +++ b/flake.nix @@ -1,8 +1,15 @@ { inputs = { - nixpkgs.url = "github:nixos/nixpkgs"; + nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; utils.url = "github:numtide/flake-utils"; - naersk.url = "github:nix-community/naersk"; + naersk = { + url = "github:nix-community/naersk"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + fenix = { + url = "github:nix-community/fenix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = { @@ -10,20 +17,54 @@ nixpkgs, utils, naersk, + fenix, }: utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages."${system}"; - naersk-lib = naersk.lib."${system}"; + toolchain = with fenix.packages."${system}"; + combine [ + minimal.rustc + minimal.cargo + targets.x86_64-pc-windows-gnu.latest.rust-std + targets.x86_64-unknown-linux-gnu.latest.rust-std + ]; + naersk-lib = naersk.lib."${system}".override { + cargo = toolchain; + rustc = toolchain; + }; in rec { packages.malachite = naersk-lib.buildPackage { - pname = "mlc"; + pname = "Malachite"; + root = ./.; + }; + + packages.malachite-win = naersk-lib.buildPackage { + pname = "Malachite"; root = ./.; + strictDeps = true; + depsBuildBuild = with pkgs; [ + pkgsCross.mingwW64.stdenv.cc + pkgsCross.mingwW64.windows.pthreads + ]; + nativeBuildInputs = with pkgs; [ + ( + if system == "x86_64-linux" + then wineWowPackages.stable + else hello + ) + ]; + CARGO_BUILD_TARGET = "x86_64-pc-windows-gnu"; + CARGO_TARGET_X86_64_PC_WINDOWS_GNU_RUNNER = pkgs.writeScript "wine-wrapper" '' + export WINEPREFIX="$(mktemp -d)" + exec wine64 $@ + ''; + doCheck = true; }; packages.default = packages.malachite; - apps.malachite = utils.lib.mkApp { + apps.apod = utils.lib.mkApp { drv = packages.malachite; }; @@ -33,8 +74,8 @@ nativeBuildInputs = with pkgs; [ rustc cargo - rustfmt cargo-audit + rustfmt clippy ]; }; diff --git a/src/operations/info.rs b/src/operations/info.rs index 2880b6b..b08e1f9 100644 --- a/src/operations/info.rs +++ b/src/operations/info.rs @@ -201,7 +201,7 @@ pub fn info(verbose: bool) { ); // Get terminal width - let width = match termion::terminal_size() { + let width = match crossterm::terminal::size() { Ok((w, _)) => w, Err(_) => 80, }; From de87bbf773538d744d033dfc4120e4c76e58eaba Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 25 Jul 2022 00:45:38 +0100 Subject: [PATCH 097/116] Made geteuid test windows only --- src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.rs b/src/main.rs index 445f459..8bc5eb7 100755 --- a/src/main.rs +++ b/src/main.rs @@ -16,6 +16,7 @@ mod operations; mod repository; fn main() { + #[cfg(target_os = "linux")] if unsafe { libc::geteuid() } == 0 { crash!(AppExitCode::RunAsRoot, "Running malachite as root is disallowed as it can lead to system breakage. Instead, malachite will prompt you when it needs superuser permissions"); } From 365e39c657716211e0aafe3c32e6b86e78ff2e3a Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 25 Jul 2022 00:58:56 +0100 Subject: [PATCH 098/116] Made things vaguely non-linux-centric for potential msys2 support --- Cargo.toml | 4 +++- src/internal/exit_codes.rs | 1 + src/main.rs | 1 + src/operations/clean.rs | 10 +++++----- src/operations/clone.rs | 10 +++++----- src/operations/prune.rs | 6 +++--- src/repository/repo.rs | 2 +- 7 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5ce3990..14e4281 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,6 @@ lto = "fat" codegen-units = 1 [dependencies] -mimalloc = { version = "0.1.29" } clap = { version = "3.2.8", features = ["derive", "suggestions"] } toml = { version = "0.5.9", default-features = false } serde = { version = "1.0.139", default-features = false } @@ -31,3 +30,6 @@ tabled = { version = "0.8.0", default-features = false, features = ["derive", "c crossterm = { version = "0.24.0", default-features = false } regex = { version = "1.6.0", default-features = false, features = ["std"] } spinoff = { version = "0.4.0", default-features = false } + +[target.'cfg(target_os = "linux")'.dependencies] +mimalloc = { version = "0.1.29" } diff --git a/src/internal/exit_codes.rs b/src/internal/exit_codes.rs index ba53a67..5b04209 100644 --- a/src/internal/exit_codes.rs +++ b/src/internal/exit_codes.rs @@ -1,4 +1,5 @@ pub enum AppExitCode { + #[cfg(target_os = "linux")] RunAsRoot = 1, BuildInWorkspace = 2, PkgNotFound = 3, diff --git a/src/main.rs b/src/main.rs index 8bc5eb7..55143fc 100755 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ use crate::args::{Args, Operation}; use crate::internal::parse_cfg; use crate::internal::AppExitCode; +#[cfg(target_os = "linux")] #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; diff --git a/src/operations/clean.rs b/src/operations/clean.rs index 1d4ef86..c92c984 100644 --- a/src/operations/clean.rs +++ b/src/operations/clean.rs @@ -3,15 +3,15 @@ use crate::{crash, info, internal::AppExitCode, log}; pub fn clean(verbose: bool, force: bool) { info!("Resetting mlc repo, deleting all directories"); // Get a vec of all files/dirs in the current directory - let dir_paths = std::fs::read_dir("./").unwrap(); + let dir_paths = std::fs::read_dir(".").unwrap(); log!(verbose, "Paths: {:?}", dir_paths); let mut dirs = dir_paths .map(|x| x.unwrap().path().display().to_string()) .collect::>(); // Remove mlc.toml and .git from output - dirs.retain(|x| *x != "./mlc.toml"); - dirs.retain(|x| *x != "./.git"); + dirs.retain(|x| *x != "./mlc.toml" && *x != ".\\mlc.toml"); + dirs.retain(|x| *x != "./.git" && *x != ".\\.git"); // Enter each directory and check git status @@ -44,7 +44,7 @@ pub fn clean(verbose: bool, force: bool) { AppExitCode::NotClean, "The following directories are not clean: \n {}\n\ If you are sure no important changes are staged, run `mlc clean` with the `--force` flag to delete them.", - unclean_dirs.iter().map(|x| (*x).to_string().replace("./", "")).collect::>().join(", ") + unclean_dirs.iter().map(|x| (*x).to_string().replace("./", "").replace(".\\", "")).collect::>().join(", ") ); } @@ -56,7 +56,7 @@ pub fn clean(verbose: bool, force: bool) { "Reset complete, dirs removed: \n \ {}", dirs.iter() - .map(|x| x.replace("./", "")) + .map(|x| x.replace("./", "").replace(".\\", "")) .collect::>() .join("\n ") ); diff --git a/src/operations/clone.rs b/src/operations/clone.rs index 75db48b..097b38b 100644 --- a/src/operations/clone.rs +++ b/src/operations/clone.rs @@ -11,14 +11,14 @@ pub fn clone(verbose: bool) { log!(verbose, "Repos: {:?}", repos); // Get a vector of all files/dirs in the current directory, excluding config file - let dir_paths = std::fs::read_dir("./").unwrap(); + let dir_paths = std::fs::read_dir(".").unwrap(); let mut dirs = dir_paths .map(|x| x.unwrap().path().display().to_string()) .collect::>(); - dirs.retain(|x| *x != "./mlc.toml"); - dirs.retain(|x| *x != "./out"); + dirs.retain(|x| *x != "./mlc.toml" && *x != ".\\mlc.toml"); + dirs.retain(|x| *x != "./out" && *x != ".\\out"); if config.mode.repository.is_some() { - dirs.retain(|x| *x != format!("./{}", config.mode.repository.as_ref().unwrap().name)); + dirs.retain(|x| *x != format!("./{}", config.mode.repository.as_ref().unwrap().name) && *x != format!(".\\{}", config.mode.repository.as_ref().unwrap().name)); } log!(verbose, "Paths with mlc.toml excluded: {:?}", dirs); @@ -26,7 +26,7 @@ pub fn clone(verbose: bool) { let mut repo_diff = vec![]; for repo in repos { let name = &repo.name; - if !dirs.contains(&format!("./{}", name)) { + if !dirs.contains(&format!("./{}", name)) || !dirs.contains(&format!(".\\{}", name)) { repo_diff.push(repo); } } diff --git a/src/operations/prune.rs b/src/operations/prune.rs index cc17e04..fe38a68 100644 --- a/src/operations/prune.rs +++ b/src/operations/prune.rs @@ -28,9 +28,9 @@ pub fn prune(verbose: bool) { env::set_current_dir("out").unwrap(); log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); - // Read all files from ./ into a Vec, except for .sig files + // Read all files from . into a Vec, except for .sig files let mut files: Vec = vec![]; - for entry in fs::read_dir("./").unwrap() { + for entry in fs::read_dir(".").unwrap() { let entry = entry.unwrap(); let path = entry.path(); if path.extension().unwrap() != "sig" { @@ -120,7 +120,7 @@ pub fn prune(verbose: bool) { for p in &mut packages_to_delete { println!( "{}", - format!(" {}-{}", p.name.replace("./", ""), p.ver).bold() + format!(" {}-{}", p.name.replace("./", "").replace(".\\", ""), p.ver).bold() ); } } diff --git a/src/repository/repo.rs b/src/repository/repo.rs index 8fab7c8..d410edc 100644 --- a/src/repository/repo.rs +++ b/src/repository/repo.rs @@ -43,7 +43,7 @@ pub fn generate(verbose: bool) { && config.mode.repository.as_ref().unwrap().signing.on_gen { // Get a list of all .tar.* files in repository - let files = fs::read_dir("./").unwrap(); + let files = fs::read_dir(".").unwrap(); for file in files { let file = file.unwrap(); let path = file.path(); From 05631220d57e5650b57fe7f48b2fd63116f98879 Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 25 Jul 2022 01:12:59 +0100 Subject: [PATCH 099/116] Fixed issue with removing dirs (hngh fakeroot) --- Cargo.lock | 32 ++++++++++++++++++++++++++++++++ Cargo.toml | 1 + examples/repository/mlc.toml | 4 ++-- src/operations/build.rs | 4 ++-- src/operations/clean.rs | 5 +++-- 5 files changed, 40 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dd575cc..a71351b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,6 +12,7 @@ dependencies = [ "libc", "mimalloc", "regex", + "rm_rf", "serde", "serde_derive", "spinoff", @@ -366,6 +367,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "psm" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f446d0a6efba22928558c4fb4ce0b3fd6c89b0061343e390bf01a703742b8125" +dependencies = [ + "cc", +] + [[package]] name = "quote" version = "1.0.20" @@ -399,6 +409,15 @@ version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" +[[package]] +name = "rm_rf" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3443b7a35aa12ed2e99edfc0ecbefe6a53b4848305cc83e29981dfa1aea1f71e" +dependencies = [ + "stacker", +] + [[package]] name = "rustversion" version = "1.0.8" @@ -476,6 +495,19 @@ dependencies = [ "yansi", ] +[[package]] +name = "stacker" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "winapi", +] + [[package]] name = "strip-ansi-escapes" version = "0.1.1" diff --git a/Cargo.toml b/Cargo.toml index 14e4281..8582322 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ tabled = { version = "0.8.0", default-features = false, features = ["derive", "c crossterm = { version = "0.24.0", default-features = false } regex = { version = "1.6.0", default-features = false, features = ["std"] } spinoff = { version = "0.4.0", default-features = false } +rm_rf = { version = "0.6.2", default-features = false } [target.'cfg(target_os = "linux")'.dependencies] mimalloc = { version = "0.1.29" } diff --git a/examples/repository/mlc.toml b/examples/repository/mlc.toml index 3b9a0f4..bf7510e 100644 --- a/examples/repository/mlc.toml +++ b/examples/repository/mlc.toml @@ -13,8 +13,8 @@ on_gen = true [repositories] repos = [ - "crs:malachite/development:0a5bdc9", - "mic:apod:v.1.1.2", + "crs:malachite/development:0a5bdc9", # Note, in this example, these two + "mic:apod:v.1.1.2", # will fail to build. "pkg:pfetch!", ] diff --git a/src/operations/build.rs b/src/operations/build.rs index a42d3b9..bdf00ce 100644 --- a/src/operations/build.rs +++ b/src/operations/build.rs @@ -120,8 +120,8 @@ pub fn build(packages: &[String], exclude: Vec, no_regen: bool, verbose: if !errored.is_empty() { log!(verbose, "Errored packages: \n{:?}", error_strings); info!( - "The following packages build jobs returned a non-zero exit code: {}", - error_strings.join("\n") + "The following packages build jobs returned a non-zero exit code: \n {}", + error_strings.join("\n ") ); } } diff --git a/src/operations/clean.rs b/src/operations/clean.rs index c92c984..3a6433c 100644 --- a/src/operations/clean.rs +++ b/src/operations/clean.rs @@ -39,7 +39,7 @@ pub fn clean(verbose: bool, force: bool) { log!(verbose, "Current directory: {}", root_dir.display()); } - if !unclean_dirs.is_empty() && !force { + if !unclean_dirs.is_empty() && !force && crate::parse_cfg(verbose).base.mode == "workspace" { crash!( AppExitCode::NotClean, "The following directories are not clean: \n {}\n\ @@ -50,7 +50,8 @@ pub fn clean(verbose: bool, force: bool) { log!(verbose, "Paths with mlc.toml excluded: {:?}", dirs); for dir in &dirs { - std::fs::remove_dir_all(dir).unwrap(); + log!(verbose, "Deleting directory: {}", dir); + rm_rf::remove(dir).unwrap(); } info!( "Reset complete, dirs removed: \n \ From 2e8f49f32884892ced2f82f3d84e1558adf2aaa4 Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 25 Jul 2022 01:13:16 +0100 Subject: [PATCH 100/116] fmt --- src/operations/clone.rs | 5 ++++- src/operations/prune.rs | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/operations/clone.rs b/src/operations/clone.rs index 097b38b..3aa1477 100644 --- a/src/operations/clone.rs +++ b/src/operations/clone.rs @@ -18,7 +18,10 @@ pub fn clone(verbose: bool) { dirs.retain(|x| *x != "./mlc.toml" && *x != ".\\mlc.toml"); dirs.retain(|x| *x != "./out" && *x != ".\\out"); if config.mode.repository.is_some() { - dirs.retain(|x| *x != format!("./{}", config.mode.repository.as_ref().unwrap().name) && *x != format!(".\\{}", config.mode.repository.as_ref().unwrap().name)); + dirs.retain(|x| { + *x != format!("./{}", config.mode.repository.as_ref().unwrap().name) + && *x != format!(".\\{}", config.mode.repository.as_ref().unwrap().name) + }); } log!(verbose, "Paths with mlc.toml excluded: {:?}", dirs); diff --git a/src/operations/prune.rs b/src/operations/prune.rs index fe38a68..20ffc10 100644 --- a/src/operations/prune.rs +++ b/src/operations/prune.rs @@ -120,7 +120,12 @@ pub fn prune(verbose: bool) { for p in &mut packages_to_delete { println!( "{}", - format!(" {}-{}", p.name.replace("./", "").replace(".\\", ""), p.ver).bold() + format!( + " {}-{}", + p.name.replace("./", "").replace(".\\", ""), + p.ver + ) + .bold() ); } } From 6398a391ceea47d0e13f79a2e1405c235af60810 Mon Sep 17 00:00:00 2001 From: UsernameSwift Date: Sun, 24 Jul 2022 20:37:56 -0400 Subject: [PATCH 101/116] Minor changes to grammar in docs --- docs/COMMON_FEATURES.md | 2 +- docs/GETTING_STARTED.md | 10 +++++----- docs/REPOSITORY_MODE.md | 4 ++-- docs/USAGE.md | 4 ++-- docs/WORKSPACE_MODE.md | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/COMMON_FEATURES.md b/docs/COMMON_FEATURES.md index 1cd9031..b939316 100644 --- a/docs/COMMON_FEATURES.md +++ b/docs/COMMON_FEATURES.md @@ -5,7 +5,7 @@ As[mode]us, shared of between uh… repositories… or something. Malachite is fairly fleshed out in Repository mode, and not so much in Workspace mode. This isn't of course because I'm lazy and hate Workspace mode or anything, there's just not -a lot *to* add. +a lot *to add*. Without further ado, let's take a look at this example config file. diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index 1cc8627..6bd3462 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -15,21 +15,21 @@ Malachite isn't: ### With that out of the way -Hi! My name is Michal, I wrote this tool pretty much on my own for [Crystal Linux](https://getcryst.al), +Hi! My name is Michal, and I wrote this tool pretty much on my own for [Crystal Linux](https://getcryst.al); but it is not at all exclusive to Crystal. This tool should and will work on and for any pacman-based distribution (so long as it packages all of Malachite's dependencies, of course). -Throughout this tutorial I'll explain each little feature of Malachite in what I hope to be bite-sized and +Throughout this tutorial, I'll explain each little feature of Malachite in what I hope to be bite-sized and programmatic chunks. -Without further ado, let's begin with the first most important question +Without further ado, let's begin with the first, most important question: ### Modes What mode are you using malachite in? -Currently malachite supports 2 modes: +Currently, malachite supports 2 modes: #### Repository Mode - Allows the user to configure and manage a remote (or local) pacman-based package repository @@ -44,4 +44,4 @@ Currently malachite supports 2 modes: These modes essentially dictate everything about how Malachite functions, so much so that I now need to split this page off before it gets too long! -For more info, get started with the [Common Features](COMMON_FEATURES.md) page! \ No newline at end of file +For more info, get started with the [Common Features](COMMON_FEATURES.md) page! diff --git a/docs/REPOSITORY_MODE.md b/docs/REPOSITORY_MODE.md index 3242a8a..60a580c 100644 --- a/docs/REPOSITORY_MODE.md +++ b/docs/REPOSITORY_MODE.md @@ -3,7 +3,7 @@ PacManage your repositories in style! ### Repository Config -As opposed to the rather barren Workspace mode, the Repository mode config is rather fleshed out, +As opposed to the rather barren Workspace mode, the Repository mode config is rather fleshed out; and we have a few options to choose from. Let's take an example section from a Repository mode config, @@ -27,7 +27,7 @@ To start with, there are 2 main config keys to Repository mode: ### Signing -Malachite also supports, and encourages the signing of packages. +Malachite also supports, and encourages, the signing of packages. GPG Signing packages ensures that the user receives exactly what you packaged, without any chance of tampering. Calling back to the example above, we can see 3 config keys: diff --git a/docs/USAGE.md b/docs/USAGE.md index 4a714e8..975f82c 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -24,8 +24,8 @@ Work it harder, make it better! | AppExitCode (named Enum) | Exit code (i32) | Error Description | |--------------------------|-----------------|--------------------------------------------------------------------------------------------------------| -| `RunAsRoot` | `1` | Malachite was ran as root. This is highly discouraged. So highly, in fact, that it will refuse to run. | -| `BuildInWorkspace` | `2` | Malachite was ran in Workspace mode, but a Repository-mode-specific operation was supplied | +| `RunAsRoot` | `1` | Malachite was run as root. This is highly discouraged. So highly, in fact, that it will refuse to run. | +| `BuildInWorkspace` | `2` | Malachite was run in Workspace mode, but a Repository-mode-specific operation was supplied | | `PkgNotFound` | `3` | A build was attempted for a package that does not exist | | `InvalidMode` | `4` | Malachite was launched in a mode other than `workspace` or `repository` | | `DirNotEmpty` | `5` | The creation of a Malachite repository was attempted in a non-empty directory | diff --git a/docs/WORKSPACE_MODE.md b/docs/WORKSPACE_MODE.md index 3167365..14efb54 100644 --- a/docs/WORKSPACE_MODE.md +++ b/docs/WORKSPACE_MODE.md @@ -24,8 +24,8 @@ The key for the values is as follows: These will be typically displayed in either Green (Clean) or Red (Dirty) -However, if `colorblind` is set to true, the colors will instead be set to Blue (Clean) or Dark Red (Dirty), to be more discernible to colorblind users +However, if `colorblind` is set to true, the colors will instead be set to Blue (Clean) or Dark Red (Dirty), to be more discernible to colorblind users. --- -You can return to [Getting Started](GETTING_STARTED.md) page here! \ No newline at end of file +You can return to [Getting Started](GETTING_STARTED.md) page here! From 075781f54f23b27a9594293ec3ccaa538285ed0c Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 25 Jul 2022 10:57:27 +0100 Subject: [PATCH 102/116] fixed diff issue --- src/operations/clone.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operations/clone.rs b/src/operations/clone.rs index 3aa1477..78f8c72 100644 --- a/src/operations/clone.rs +++ b/src/operations/clone.rs @@ -29,7 +29,7 @@ pub fn clone(verbose: bool) { let mut repo_diff = vec![]; for repo in repos { let name = &repo.name; - if !dirs.contains(&format!("./{}", name)) || !dirs.contains(&format!(".\\{}", name)) { + if !dirs.contains(&format!("./{}", name)) && !dirs.contains(&format!(".\\{}", name)) { repo_diff.push(repo); } } From 67b3e57fcd3d2e6d4f7ff8490e6a471518b1302d Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 25 Jul 2022 11:53:15 +0100 Subject: [PATCH 103/116] Fixed issue w/ config creation requiring existing config --- src/main.rs | 28 +++++++++++++++++++++------- src/repository/config.rs | 5 ++++- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/main.rs b/src/main.rs index 55143fc..ba89d9b 100755 --- a/src/main.rs +++ b/src/main.rs @@ -30,13 +30,6 @@ fn main() { log!(verbose, "Exclude: {:?}", exclude); log!(verbose, "Verbose: You guess. :)"); - // Parse config - let config = parse_cfg(verbose); - log!(verbose, "Config: {:?}", config); - - // Get repository mode status - let repository = config.base.mode == "repository"; - log!(verbose, "Repository Mode: {:?}", repository); // Arg matching match args.subcommand.unwrap_or(Operation::Clone) { @@ -44,6 +37,13 @@ fn main() { Operation::Build { packages, no_regen, .. } => { + // Parse config + let config = parse_cfg(verbose); + log!(verbose, "Config: {:?}", config); + + // Get repository mode status + let repository = config.base.mode == "repository"; + log!(verbose, "Repository Mode: {:?}", repository); if !repository { crash!( AppExitCode::BuildInWorkspace, @@ -56,6 +56,13 @@ fn main() { packages, no_regen, .. } => operations::pull(packages, exclude, verbose, no_regen), Operation::RepoGen => { + // Parse config + let config = parse_cfg(verbose); + log!(verbose, "Config: {:?}", config); + + // Get repository mode status + let repository = config.base.mode == "repository"; + log!(verbose, "Repository Mode: {:?}", repository); if !repository { crash!( AppExitCode::BuildInWorkspace, @@ -66,6 +73,13 @@ fn main() { } Operation::Config => operations::config(verbose), Operation::Prune => { + // Parse config + let config = parse_cfg(verbose); + log!(verbose, "Config: {:?}", config); + + // Get repository mode status + let repository = config.base.mode == "repository"; + log!(verbose, "Repository Mode: {:?}", repository); if !repository { crash!( AppExitCode::BuildInWorkspace, diff --git a/src/repository/config.rs b/src/repository/config.rs index c432dd5..2e182c1 100644 --- a/src/repository/config.rs +++ b/src/repository/config.rs @@ -24,7 +24,10 @@ build_on_update = false enabled = true [mode.workspace] -# There are currently no options for workspace mode +# Whether to show rich git info for repositories +git_info = true +# Colorblind mode toggle +colorblind = false [repositories] # List of repositories formatted as id:name (priority is decided by the ! suffix, and decides package build order) From 0b0e35a5af2252bbb15539b2cfda69c4229851eb Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 25 Jul 2022 11:55:17 +0100 Subject: [PATCH 104/116] Compartmentalised a bit --- src/main.rs | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/src/main.rs b/src/main.rs index ba89d9b..2a1d15f 100755 --- a/src/main.rs +++ b/src/main.rs @@ -16,6 +16,19 @@ mod internal; mod operations; mod repository; +fn repository(verbose: bool) -> bool { + // Parse config + let config = parse_cfg(verbose); + log!(verbose, "Config: {:?}", config); + + // Get repository mode status + let repository = config.base.mode == "repository"; + log!(verbose, "Repository Mode: {:?}", repository); + + // Return repository mode status + repository +} + fn main() { #[cfg(target_os = "linux")] if unsafe { libc::geteuid() } == 0 { @@ -37,14 +50,7 @@ fn main() { Operation::Build { packages, no_regen, .. } => { - // Parse config - let config = parse_cfg(verbose); - log!(verbose, "Config: {:?}", config); - - // Get repository mode status - let repository = config.base.mode == "repository"; - log!(verbose, "Repository Mode: {:?}", repository); - if !repository { + if !repository(verbose) { crash!( AppExitCode::BuildInWorkspace, "Cannot build packages in workspace mode" @@ -56,14 +62,7 @@ fn main() { packages, no_regen, .. } => operations::pull(packages, exclude, verbose, no_regen), Operation::RepoGen => { - // Parse config - let config = parse_cfg(verbose); - log!(verbose, "Config: {:?}", config); - - // Get repository mode status - let repository = config.base.mode == "repository"; - log!(verbose, "Repository Mode: {:?}", repository); - if !repository { + if !repository(verbose) { crash!( AppExitCode::BuildInWorkspace, "Cannot generate repository in workspace mode" @@ -73,14 +72,7 @@ fn main() { } Operation::Config => operations::config(verbose), Operation::Prune => { - // Parse config - let config = parse_cfg(verbose); - log!(verbose, "Config: {:?}", config); - - // Get repository mode status - let repository = config.base.mode == "repository"; - log!(verbose, "Repository Mode: {:?}", repository); - if !repository { + if !repository(verbose) { crash!( AppExitCode::BuildInWorkspace, "Cannot prune packages in workspace mode" From abed0b12fb06a77294af27c1244ead58c3774885 Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 25 Jul 2022 12:13:39 +0100 Subject: [PATCH 105/116] Read through code, ensured it actually makes sense lol --- src/internal/read.rs | 3 ++- src/main.rs | 1 - src/operations/build.rs | 11 +++++++++-- src/operations/clean.rs | 8 ++++++-- src/operations/clone.rs | 10 +++++++++- src/operations/info.rs | 8 +++++++- src/operations/prune.rs | 12 ++++++++++-- src/operations/pull.rs | 9 +++++++-- src/repository/package.rs | 1 + src/repository/repo.rs | 2 ++ 10 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/internal/read.rs b/src/internal/read.rs index 749c81e..7cd9bd7 100644 --- a/src/internal/read.rs +++ b/src/internal/read.rs @@ -41,7 +41,7 @@ pub fn parse_cfg(verbose: bool) -> Config { // Parsing repos from the config file for x in config.repositories.repos { log!(verbose, "Parsing repo: {:?}", x); - // Splits the repo name and index inta a SplitRepo struct + // Splits the repo name and index into a SplitRepo struct let split: Vec<&str> = x.split(':').collect(); let split_struct = if split.len() > 2 { SplitRepo { @@ -114,5 +114,6 @@ pub fn parse_cfg(verbose: bool) -> Config { repositories: expanded_repos, }; log!(verbose, "Config: {:?}", conf); + conf } diff --git a/src/main.rs b/src/main.rs index 2a1d15f..cbddd02 100755 --- a/src/main.rs +++ b/src/main.rs @@ -43,7 +43,6 @@ fn main() { log!(verbose, "Exclude: {:?}", exclude); log!(verbose, "Verbose: You guess. :)"); - // Arg matching match args.subcommand.unwrap_or(Operation::Clone) { Operation::Clone => operations::clone(verbose), diff --git a/src/operations/build.rs b/src/operations/build.rs index bdf00ce..1de926e 100644 --- a/src/operations/build.rs +++ b/src/operations/build.rs @@ -1,13 +1,16 @@ use crate::internal::structs::{ErroredPackage, Repo}; use crate::internal::AppExitCode; -use crate::{crash, info, internal, log, repository}; +use crate::{crash, info, log, repository}; pub fn build(packages: &[String], exclude: Vec, no_regen: bool, verbose: bool) { // Read config struct from mlc.toml - let config = internal::parse_cfg(verbose); + let config = crate::internal::parse_cfg(verbose); log!(verbose, "Config: {:?}", config); + // Check if any packages were passed, if not, imply all let all = packages.is_empty(); log!(verbose, "All: {:?}", all); + + // Parse whether to sign on build or not let sign = if config.mode.repository.as_ref().unwrap().signing.enabled && config.mode.repository.as_ref().unwrap().signing.on_gen { @@ -47,6 +50,7 @@ pub fn build(packages: &[String], exclude: Vec, no_regen: bool, verbose: if repos.iter().map(|x| x.name.clone()).any(|x| x == *pkg) { // Otherwise, build log!(verbose, "Building {}", pkg); + let code = repository::build(pkg, sign, verbose); log!( verbose, @@ -54,6 +58,7 @@ pub fn build(packages: &[String], exclude: Vec, no_regen: bool, verbose: pkg, code ); + if code != 0 { let error = ErroredPackage { name: pkg.to_string(), @@ -81,6 +86,7 @@ pub fn build(packages: &[String], exclude: Vec, no_regen: bool, verbose: log!(verbose, "Sorted: {:?}", repos); for pkg in repos { log!(verbose, "Building {}", pkg.name); + let code = repository::build(&pkg.name, sign, verbose); log!( verbose, @@ -88,6 +94,7 @@ pub fn build(packages: &[String], exclude: Vec, no_regen: bool, verbose: pkg.name, code ); + if code != 0 { let error = ErroredPackage { name: pkg.name, diff --git a/src/operations/clean.rs b/src/operations/clean.rs index 3a6433c..cf52050 100644 --- a/src/operations/clean.rs +++ b/src/operations/clean.rs @@ -13,20 +13,23 @@ pub fn clean(verbose: bool, force: bool) { dirs.retain(|x| *x != "./mlc.toml" && *x != ".\\mlc.toml"); dirs.retain(|x| *x != "./.git" && *x != ".\\.git"); - // Enter each directory and check git status - let mut unclean_dirs = vec![]; + // Enter each directory and check git status for dir in &dirs { let root_dir = std::env::current_dir().unwrap(); + log!(verbose, "Entering directory: {}", dir); std::env::set_current_dir(dir).unwrap(); + let status = std::process::Command::new("git") .arg("status") .output() .unwrap(); + let output = std::string::String::from_utf8(status.stdout).unwrap(); log!(verbose, "Git status: {}", output); + if output.contains("Your branch is up to date with") && !output.contains("Untracked files") && !output.contains("Changes not staged for commit") @@ -35,6 +38,7 @@ pub fn clean(verbose: bool, force: bool) { } else { unclean_dirs.push(dir); } + std::env::set_current_dir(&root_dir).unwrap(); log!(verbose, "Current directory: {}", root_dir.display()); } diff --git a/src/operations/clone.rs b/src/operations/clone.rs index 78f8c72..9425e12 100644 --- a/src/operations/clone.rs +++ b/src/operations/clone.rs @@ -7,6 +7,7 @@ pub fn clone(verbose: bool) { // Read config struct from mlc.toml let config = crate::internal::parse_cfg(verbose); log!(verbose, "Config: {:?}", config); + // Parse repositories from config let repos = &config.repositories; log!(verbose, "Repos: {:?}", repos); @@ -15,13 +16,18 @@ pub fn clone(verbose: bool) { let mut dirs = dir_paths .map(|x| x.unwrap().path().display().to_string()) .collect::>(); + + // Remove mlc.toml and .git from output dirs.retain(|x| *x != "./mlc.toml" && *x != ".\\mlc.toml"); - dirs.retain(|x| *x != "./out" && *x != ".\\out"); + dirs.retain(|x| *x != "./.git" && *x != ".\\.git"); + + // If mode is repository, also exclude repository mode directories if config.mode.repository.is_some() { dirs.retain(|x| { *x != format!("./{}", config.mode.repository.as_ref().unwrap().name) && *x != format!(".\\{}", config.mode.repository.as_ref().unwrap().name) }); + dirs.retain(|x| *x != "./out" && *x != ".\\out"); } log!(verbose, "Paths with mlc.toml excluded: {:?}", dirs); @@ -29,6 +35,7 @@ pub fn clone(verbose: bool) { let mut repo_diff = vec![]; for repo in repos { let name = &repo.name; + if !dirs.contains(&format!("./{}", name)) && !dirs.contains(&format!(".\\{}", name)) { repo_diff.push(repo); } @@ -53,6 +60,7 @@ pub fn clone(verbose: bool) { for r in repo_diff { log!(verbose, "Depth: {:?}", r.extra); log!(verbose, "Cloning {}", r.name); + if r.extra.is_some() && config.base.mode == "workspace" { info!( "Cloning ({} mode): {} at depth: {}", diff --git a/src/operations/info.rs b/src/operations/info.rs index b08e1f9..d43a174 100644 --- a/src/operations/info.rs +++ b/src/operations/info.rs @@ -94,9 +94,11 @@ pub fn git_status(verbose: bool, repo: &str, colorblind: bool) -> String { pub fn info(verbose: bool) { log!(verbose, "Showing Info"); + // Parse config from mlc.toml let config = crate::internal::parse_cfg(verbose); log!(verbose, "Config: {:?}", config); + // Check for git_info let git_info = if config.mode.workspace.is_some() { config.mode.workspace.as_ref().unwrap().git_info } else { @@ -104,6 +106,7 @@ pub fn info(verbose: bool) { }; log!(verbose, "Git info: {}", git_info); + // Check for colorblind mode let colorblind = if config.mode.workspace.is_some() { config.mode.workspace.as_ref().unwrap().colorblind } else { @@ -116,11 +119,14 @@ pub fn info(verbose: bool) { let mut repos = vec![]; let mut repos_git = vec![]; + // Start the spinner let sp = Spinner::new( Spinners::Line, format!("{}", "Parsing Git Info...".bold()), Color::Green, ); + + // Iterate over all repositories for repo in repos_unparsed { // Get name with branch, '/' serving as the delimiter let name = if repo.branch.is_some() { @@ -200,7 +206,7 @@ pub fn info(verbose: bool) { internal_name ); - // Get terminal width + // Get terminal width for table formatting let width = match crossterm::terminal::size() { Ok((w, _)) => w, Err(_) => 80, diff --git a/src/operations/prune.rs b/src/operations/prune.rs index 20ffc10..7869936 100644 --- a/src/operations/prune.rs +++ b/src/operations/prune.rs @@ -42,17 +42,23 @@ pub fn prune(verbose: bool) { // Split files into Vec, turning package-name-1.0.0-1-x86_64.tar.gz into PackageFile { name: "package-name", ver: "1.0.0-1", ext: "x86_64.tar.gz" } let mut packages: Vec = vec![]; for file in files { - // Regex fuckery. Please don't mess with this. + // Regex, splits package-name-1.0.0-1-x86_64.tar.gz into 3 groups: package-name, -1.0.0-1, -x86_64.tar.gz let re = regex::Regex::new(r"^(.+)(-.+-.+)(-.+\..+\..+\.+..+)$").unwrap(); + + // Get file name to string let file = file.to_str().unwrap(); + + // Match file name against regex for cap in re.captures_iter(file) { // Collect regex captures let name = cap[1].to_string(); let mut ver = cap[2].to_string(); let mut ext = cap[3].to_string(); + // Strip leading - from ver and ext ver.remove(0).to_string(); ext.remove(0).to_string(); + let package = PackageFile { name, ver, ext }; log!(verbose, "Package: {:?}", package); packages.push(package); @@ -65,6 +71,7 @@ pub fn prune(verbose: bool) { log!(verbose, "Sorting Package: {:?}", package); let name = &package.name; let mut found = false; + // Check if name is already present in packages_by_name for p in &mut packages_by_name { if &p[0].name == name { log!(verbose, "Found {}", name); @@ -72,6 +79,7 @@ pub fn prune(verbose: bool) { p.push(package); } } + // If not, create a new vector and push to it if !found { log!(verbose, "Creating {}", name); packages_by_name.push(vec![package]); @@ -84,7 +92,7 @@ pub fn prune(verbose: bool) { p.sort_by(|a, b| b.ver.cmp(&a.ver)); } - // Pushes all but the 4 most recent versions of each package into a new Vector of PackageFiles + // Pushes all but the 3 most recent versions of each package into a new Vector of PackageFiles let mut packages_to_delete: Vec = vec![]; for p in &packages_by_name { let mut to_delete = vec![]; diff --git a/src/operations/pull.rs b/src/operations/pull.rs index e74c97a..0622498 100644 --- a/src/operations/pull.rs +++ b/src/operations/pull.rs @@ -23,10 +23,10 @@ fn do_the_pulling(repos: Vec, verbose: bool, params: &PullParams) { let mut packages_to_rebuild: Vec = vec![]; - // Pull + // Pull logic log!(verbose, "Pulling"); if params.smart_pull { - // Just update the remote + // Update the remote log!(verbose, "Smart pull"); Command::new("git") .args(&["remote", "update"]) @@ -80,10 +80,12 @@ fn do_the_pulling(repos: Vec, verbose: bool, params: &PullParams) { env::current_dir().unwrap() ); + // Rebuild packages if necessary if !packages_to_rebuild.is_empty() && params.build_on_update { info!("Rebuilding packages: {}", &packages_to_rebuild.join(", ")); log!(verbose, "Rebuilding packages: {:?}", &packages_to_rebuild); + // Push to build crate::operations::build(&packages_to_rebuild, vec![], params.no_regen, verbose); } } @@ -93,12 +95,15 @@ pub fn pull(packages: Vec, exclude: &[String], verbose: bool, no_regen: // Read config file let config = crate::parse_cfg(verbose); log!(verbose, "Config: {:?}", config); + // If no packages are specified, imply all let all = packages.is_empty(); log!(verbose, "All: {}", all); + // Read smart_pull from config let smart_pull = config.base.smart_pull; log!(verbose, "Smart pull: {}", smart_pull); + // Read build_on_update from config let build_on_update = if config.mode.repository.is_some() { config.mode.repository.unwrap().build_on_update diff --git a/src/repository/package.rs b/src/repository/package.rs index c363a71..6a56aef 100755 --- a/src/repository/package.rs +++ b/src/repository/package.rs @@ -8,6 +8,7 @@ use crate::{crash, log}; pub fn build(pkg: &str, sign: bool, verbose: bool) -> i32 { log!(verbose, "Building {}", pkg); log!(verbose, "Signing: {}", sign); + // Set root dir to return after build let dir = env::current_dir().unwrap(); log!(verbose, "Root dir: {:?}", dir); diff --git a/src/repository/repo.rs b/src/repository/repo.rs index d410edc..e2f3313 100644 --- a/src/repository/repo.rs +++ b/src/repository/repo.rs @@ -45,8 +45,10 @@ pub fn generate(verbose: bool) { // Get a list of all .tar.* files in repository let files = fs::read_dir(".").unwrap(); for file in files { + // Get file name let file = file.unwrap(); let path = file.path(); + // If extension is either .zst or .xz, sign it if path.extension().unwrap() == "zst" || path.extension().unwrap() == "xz" { log!(verbose, "Signing {}", path.display()); Command::new("bash") From 29de35fef52ec09b9ed54eef4ff8e9e4273ed173 Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 25 Jul 2022 12:16:15 +0100 Subject: [PATCH 106/116] sorted imports --- src/operations/prune.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/operations/prune.rs b/src/operations/prune.rs index 7869936..7af2204 100644 --- a/src/operations/prune.rs +++ b/src/operations/prune.rs @@ -1,3 +1,4 @@ +use colored::Colorize; use std::env; use std::fs; use std::path::PathBuf; @@ -6,8 +7,6 @@ use crate::info; use crate::log; use crate::parse_cfg; -use colored::Colorize; - #[derive(Debug, Clone)] struct PackageFile { name: String, From 01b886ca9221a6177f321d4793f45bf14c61610b Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 25 Jul 2022 12:18:16 +0100 Subject: [PATCH 107/116] Update COMMON_FEATURES.md --- docs/COMMON_FEATURES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/COMMON_FEATURES.md b/docs/COMMON_FEATURES.md index 1cd9031..a5692ba 100644 --- a/docs/COMMON_FEATURES.md +++ b/docs/COMMON_FEATURES.md @@ -29,8 +29,8 @@ repos = [ ] [repositories.urls] -foo = "https://example.org/%repo%.git" -bar = "https://example.org/other/%repo%.git" +foo = "https://example.org/{}.git" +bar = "https://example.org/other/{}.git" ``` Now, this is going to look really confusing at first, but bear with me. From a6c89ca4ca426fbc37fc5718248db0cf22cdc0a4 Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 25 Jul 2022 12:22:50 +0100 Subject: [PATCH 108/116] Fixed repository mode not pulling patches etc --- src/operations/clone.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/operations/clone.rs b/src/operations/clone.rs index 9425e12..09e2536 100644 --- a/src/operations/clone.rs +++ b/src/operations/clone.rs @@ -103,9 +103,9 @@ pub fn clone(verbose: bool) { // Create an empty directory with repo.name and enter it let root_dir = env::current_dir().unwrap(); - // Git clone the repo with the `-n` flag to not immediately checkout the files + // Git clone the repo Command::new("git") - .args(&["clone", &r.url, &r.name, "-n"]) + .args(&["clone", &r.url, &r.name]) .args(if r.branch.is_some() { vec!["-b", r.branch.as_ref().unwrap()] } else { @@ -122,14 +122,7 @@ pub fn clone(verbose: bool) { // Git checkout the PKGBUILD from the hash if r.extra.is_some() { Command::new("git") - .args(&["checkout", r.extra.as_ref().unwrap(), "PKGBUILD"]) - .spawn() - .unwrap() - .wait() - .unwrap(); - } else { - Command::new("git") - .args(&["checkout", "HEAD", "PKGBUILD"]) + .args(&["checkout", r.extra.as_ref().unwrap()]) .spawn() .unwrap() .wait() From 202508dcb9f0564320df26ec0f84fb5585289a41 Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 25 Jul 2022 14:23:44 +0100 Subject: [PATCH 109/116] Fixed issues presented in @axtloss 's testing --- examples/repository/mlc.toml | 2 ++ src/internal/structs.rs | 4 +-- src/operations/build.rs | 24 +++++++++----- src/operations/pull.rs | 32 +++++++++++++++++- src/repository/package.rs | 7 ++++ src/repository/repo.rs | 64 +++++++++++++++++++++++++++++++----- 6 files changed, 112 insertions(+), 21 deletions(-) diff --git a/examples/repository/mlc.toml b/examples/repository/mlc.toml index bf7510e..a8aa808 100644 --- a/examples/repository/mlc.toml +++ b/examples/repository/mlc.toml @@ -16,9 +16,11 @@ repos = [ "crs:malachite/development:0a5bdc9", # Note, in this example, these two "mic:apod:v.1.1.2", # will fail to build. "pkg:pfetch!", + "nms:rpass" # This too ] [repositories.urls] crs = "https://github.com/crystal-linux/{}" pkg = "https://github.com/crystal-linux/pkgbuild.{}" mic = "https://git.tar.black/michal/{}" +nms = "https://github.com/not-my-segfault/{}" diff --git a/src/internal/structs.rs b/src/internal/structs.rs index 59cb8b3..c023b12 100755 --- a/src/internal/structs.rs +++ b/src/internal/structs.rs @@ -38,8 +38,8 @@ pub struct ConfigModeRepository { #[derive(Debug, Deserialize)] pub struct ConfigModeRepositorySigning { pub enabled: bool, - pub key: String, - pub on_gen: bool, + pub key: Option, + pub on_gen: Option, } #[derive(Debug, Deserialize)] diff --git a/src/operations/build.rs b/src/operations/build.rs index 1de926e..49c3db3 100644 --- a/src/operations/build.rs +++ b/src/operations/build.rs @@ -10,19 +10,19 @@ pub fn build(packages: &[String], exclude: Vec, no_regen: bool, verbose: let all = packages.is_empty(); log!(verbose, "All: {:?}", all); + // Read signing + let signing = config.mode.repository.as_ref().unwrap().signing.enabled; + + // Read on_gen + let on_gen = config.mode.repository.as_ref().unwrap().signing.on_gen; + // Parse whether to sign on build or not - let sign = if config.mode.repository.as_ref().unwrap().signing.enabled - && config.mode.repository.as_ref().unwrap().signing.on_gen - { + let sign = if signing && on_gen.is_some() && on_gen.unwrap() { false } else { - config.mode.repository.as_ref().unwrap().signing.enabled + signing }; - log!( - verbose, - "Signing: {:?}", - config.mode.repository.unwrap().signing - ); + log!(verbose, "Signing: {:?}", sign); // Get list of repos and subtract exclude let mut repos: Vec = config.repositories; @@ -130,5 +130,11 @@ pub fn build(packages: &[String], exclude: Vec, no_regen: bool, verbose: "The following packages build jobs returned a non-zero exit code: \n {}", error_strings.join("\n ") ); + info!("Please check `man 8 makepkg` for more information"); + // Check if code 63 appeared at all + if errored.iter().any(|x| x.code == 63) { + log!(verbose, "Code 63 found"); + info!("Note: Code 63 is an internal Malachite exit code, and specifies that no PKGBUILD was found."); + } } } diff --git a/src/operations/pull.rs b/src/operations/pull.rs index 0622498..7f179bb 100644 --- a/src/operations/pull.rs +++ b/src/operations/pull.rs @@ -138,8 +138,38 @@ pub fn pull(packages: Vec, exclude: &[String], verbose: bool, no_regen: crash!(AppExitCode::NoPkgs, "No packages specified"); } - // Pull! + // Sort repos_applicable by priority + repos_applicable.sort_by(|a, b| { + config + .repositories + .iter() + .find(|x| x.name == *a) + .unwrap() + .priority + .cmp( + &config + .repositories + .iter() + .find(|x| x.name == *b) + .unwrap() + .priority, + ) + }); + log!(verbose, "Pulling {:?}", repos_applicable); + + // If the directories specified in repos_applicable do not exist, crash + for repo in &repos_applicable { + if !std::path::Path::new(repo).exists() { + crash!( + AppExitCode::NoPkgs, + "Package {} does not exist, have you run `mlc clone/init`?", + repo + ); + } + } + + // Pull! do_the_pulling( repos_applicable, verbose, diff --git a/src/repository/package.rs b/src/repository/package.rs index 6a56aef..bf7e41f 100755 --- a/src/repository/package.rs +++ b/src/repository/package.rs @@ -32,6 +32,13 @@ pub fn build(pkg: &str, sign: bool, verbose: bool) -> i32 { env::set_current_dir(pkg).unwrap(); log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); + // If PKGBUILD is not found, return 63 and break + if !Path::exists("PKGBUILD".as_ref()) { + env::set_current_dir(&dir).unwrap(); + log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); + return 63; + } + // Build each package let a = Command::new("makepkg") .args(&[ diff --git a/src/repository/repo.rs b/src/repository/repo.rs index e2f3313..e7211ac 100644 --- a/src/repository/repo.rs +++ b/src/repository/repo.rs @@ -40,7 +40,22 @@ pub fn generate(verbose: bool) { // Sign all package files in repository if signing and on_gen are true if config.mode.repository.as_ref().unwrap().signing.enabled - && config.mode.repository.as_ref().unwrap().signing.on_gen + && config + .mode + .repository + .as_ref() + .unwrap() + .signing + .on_gen + .is_some() + && config + .mode + .repository + .as_ref() + .unwrap() + .signing + .on_gen + .unwrap() { // Get a list of all .tar.* files in repository let files = fs::read_dir(".").unwrap(); @@ -48,18 +63,49 @@ pub fn generate(verbose: bool) { // Get file name let file = file.unwrap(); let path = file.path(); + + let sign_command = if config + .mode + .repository + .as_ref() + .unwrap() + .signing + .key + .is_some() + && !config + .mode + .repository + .as_ref() + .unwrap() + .signing + .key + .as_ref() + .unwrap() + .is_empty() + { + format!( + "gpg --default-key {} --detach-sign {}", + config + .mode + .repository + .as_ref() + .unwrap() + .signing + .key + .as_ref() + .unwrap(), + path.to_str().unwrap() + ) + } else { + format!("gpg --detach-sign {}", path.to_str().unwrap()) + }; + // If extension is either .zst or .xz, sign it if path.extension().unwrap() == "zst" || path.extension().unwrap() == "xz" { log!(verbose, "Signing {}", path.display()); Command::new("bash") - .args(&[ - "-c", - &format!( - "gpg --default-key {} --detach-sign {}", - config.mode.repository.as_ref().unwrap().signing.key, - file.file_name().to_str().unwrap() - ), - ]) + .arg("-c") + .args(&[&sign_command]) .spawn() .unwrap() .wait() From 5e0d50e995b78a9c8bafc8fc8c6461cd04d6ed3c Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 25 Jul 2022 19:44:17 +0100 Subject: [PATCH 110/116] Compartmentalised AppExitCodes --- src/internal/exit_codes.rs | 15 +++------ src/internal/read.rs | 4 +-- src/main.rs | 6 ++-- src/operations/build.rs | 4 +-- src/operations/clean.rs | 2 +- src/operations/clone.rs | 2 +- src/operations/info.rs | 2 +- src/operations/pull.rs | 11 ++++--- src/repository/package.rs | 2 +- src/repository/repo.rs | 66 +++++++++++--------------------------- 10 files changed, 40 insertions(+), 74 deletions(-) diff --git a/src/internal/exit_codes.rs b/src/internal/exit_codes.rs index 5b04209..b850e1d 100644 --- a/src/internal/exit_codes.rs +++ b/src/internal/exit_codes.rs @@ -1,14 +1,9 @@ pub enum AppExitCode { #[cfg(target_os = "linux")] RunAsRoot = 1, - BuildInWorkspace = 2, - PkgNotFound = 3, - InvalidMode = 4, - DirNotEmpty = 5, - ConfigNotFound = 6, - NoPkgs = 7, - ConfigParseError = 8, - InvalidRepo = 9, - NotInit = 10, - NotClean = 11, + PkgsNotFound = 2, + DirNotEmpty = 3, + ConfigParseError = 4, + RepoParseError = 5, + RepoNotClean = 6, } diff --git a/src/internal/read.rs b/src/internal/read.rs index 7cd9bd7..e960060 100644 --- a/src/internal/read.rs +++ b/src/internal/read.rs @@ -9,7 +9,7 @@ pub fn parse_cfg(verbose: bool) -> Config { // Crash if mlc.toml doesn't exist if !Path::exists("mlc.toml".as_ref()) { crash!( - AppExitCode::ConfigNotFound, + AppExitCode::ConfigParseError, "Config file not found (mlc.toml)" ); } @@ -31,7 +31,7 @@ pub fn parse_cfg(verbose: bool) -> Config { // Crash if incorrect mode is set if config.base.mode != "workspace" && config.base.mode != "repository" { crash!( - AppExitCode::InvalidMode, + AppExitCode::ConfigParseError, "Invalid mode in mlc.toml, must be either \"repository\" or \"workspace\"" ); } diff --git a/src/main.rs b/src/main.rs index cbddd02..9cfc99a 100755 --- a/src/main.rs +++ b/src/main.rs @@ -51,7 +51,7 @@ fn main() { } => { if !repository(verbose) { crash!( - AppExitCode::BuildInWorkspace, + AppExitCode::ConfigParseError, "Cannot build packages in workspace mode" ); } @@ -63,7 +63,7 @@ fn main() { Operation::RepoGen => { if !repository(verbose) { crash!( - AppExitCode::BuildInWorkspace, + AppExitCode::ConfigParseError, "Cannot generate repository in workspace mode" ); } @@ -73,7 +73,7 @@ fn main() { Operation::Prune => { if !repository(verbose) { crash!( - AppExitCode::BuildInWorkspace, + AppExitCode::ConfigParseError, "Cannot prune packages in workspace mode" ); } diff --git a/src/operations/build.rs b/src/operations/build.rs index 49c3db3..8a26888 100644 --- a/src/operations/build.rs +++ b/src/operations/build.rs @@ -68,7 +68,7 @@ pub fn build(packages: &[String], exclude: Vec, no_regen: bool, verbose: } } else { crash!( - AppExitCode::PkgNotFound, + AppExitCode::PkgsNotFound, "Package repo {} not found in in mlc.toml", pkg ); @@ -108,7 +108,7 @@ pub fn build(packages: &[String], exclude: Vec, no_regen: bool, verbose: // If all is not specified, but packages is empty, crash if !all && packages.is_empty() { log!(verbose, "Packages empty. Crashing"); - crash!(AppExitCode::NoPkgs, "No packages specified"); + crash!(AppExitCode::PkgsNotFound, "No packages specified"); } // If no_regen is passed, do not generate a repository diff --git a/src/operations/clean.rs b/src/operations/clean.rs index cf52050..b4761f6 100644 --- a/src/operations/clean.rs +++ b/src/operations/clean.rs @@ -45,7 +45,7 @@ pub fn clean(verbose: bool, force: bool) { if !unclean_dirs.is_empty() && !force && crate::parse_cfg(verbose).base.mode == "workspace" { crash!( - AppExitCode::NotClean, + AppExitCode::RepoNotClean, "The following directories are not clean: \n {}\n\ If you are sure no important changes are staged, run `mlc clean` with the `--force` flag to delete them.", unclean_dirs.iter().map(|x| (*x).to_string().replace("./", "").replace(".\\", "")).collect::>().join(", ") diff --git a/src/operations/clone.rs b/src/operations/clone.rs index 09e2536..f7ab993 100644 --- a/src/operations/clone.rs +++ b/src/operations/clone.rs @@ -63,7 +63,7 @@ pub fn clone(verbose: bool) { if r.extra.is_some() && config.base.mode == "workspace" { info!( - "Cloning ({} mode): {} at depth: {}", + "Cloning ({} mode): {} with `--depth {}`", config.base.mode, r.name, r.extra.as_ref().unwrap() diff --git a/src/operations/info.rs b/src/operations/info.rs index d43a174..6baa58f 100644 --- a/src/operations/info.rs +++ b/src/operations/info.rs @@ -38,7 +38,7 @@ pub fn git_status(verbose: bool, repo: &str, colorblind: bool) -> String { ); env::set_current_dir(&repo).unwrap_or_else(|e| { crash!( - AppExitCode::NotInit, + AppExitCode::RepoParseError, "Failed to enter directory {} for Git info: {}, Have you initialized the repo?", repo, e.to_string() diff --git a/src/operations/pull.rs b/src/operations/pull.rs index 7f179bb..184697b 100644 --- a/src/operations/pull.rs +++ b/src/operations/pull.rs @@ -135,7 +135,7 @@ pub fn pull(packages: Vec, exclude: &[String], verbose: bool, no_regen: // If all is not specified and packages is empty, crash if repos_applicable.is_empty() { - crash!(AppExitCode::NoPkgs, "No packages specified"); + crash!(AppExitCode::PkgsNotFound, "No packages specified"); } // Sort repos_applicable by priority @@ -158,14 +158,15 @@ pub fn pull(packages: Vec, exclude: &[String], verbose: bool, no_regen: log!(verbose, "Pulling {:?}", repos_applicable); - // If the directories specified in repos_applicable do not exist, crash + // If any repos are not in the config, run a clone for repo in &repos_applicable { if !std::path::Path::new(repo).exists() { - crash!( - AppExitCode::NoPkgs, - "Package {} does not exist, have you run `mlc clone/init`?", + info!( + "Repo {} does not exist, ensuring all repos are cloned", repo ); + crate::operations::clone(verbose); + break; } } diff --git a/src/repository/package.rs b/src/repository/package.rs index bf7e41f..544c4ed 100755 --- a/src/repository/package.rs +++ b/src/repository/package.rs @@ -22,7 +22,7 @@ pub fn build(pkg: &str, sign: bool, verbose: bool) -> i32 { // If package directory is not found, crash if !Path::exists(pkg.as_ref()) { crash!( - AppExitCode::PkgNotFound, + AppExitCode::PkgsNotFound, "Repo for package {} not found, aborting", pkg ); diff --git a/src/repository/repo.rs b/src/repository/repo.rs index e7211ac..2447fda 100644 --- a/src/repository/repo.rs +++ b/src/repository/repo.rs @@ -9,10 +9,22 @@ pub fn generate(verbose: bool) { let config = parse_cfg(verbose); log!(verbose, "Config: {:?}", config); + // Get signing from config + let signing = &config.mode.repository.as_ref().unwrap().signing.enabled; + log!(verbose, "Signing: {:?}", signing); + // Get repository name from config let name = &config.mode.repository.as_ref().unwrap().name; log!(verbose, "Name: {}", name); + // Read on_gen from config + let on_gen = &config.mode.repository.as_ref().unwrap().signing.on_gen; + log!(verbose, "On gen: {:?}", on_gen); + + // Read key from config + let key = &config.mode.repository.as_ref().unwrap().signing.key; + log!(verbose, "Key: {:?}", key); + info!("Generating repository: {}", name); // If repository exists, delete it @@ -39,61 +51,19 @@ pub fn generate(verbose: bool) { log!(verbose, "Current dir: {:?}", env::current_dir().unwrap()); // Sign all package files in repository if signing and on_gen are true - if config.mode.repository.as_ref().unwrap().signing.enabled - && config - .mode - .repository - .as_ref() - .unwrap() - .signing - .on_gen - .is_some() - && config - .mode - .repository - .as_ref() - .unwrap() - .signing - .on_gen - .unwrap() - { + if *signing && on_gen.is_some() && on_gen.unwrap() { // Get a list of all .tar.* files in repository let files = fs::read_dir(".").unwrap(); + for file in files { // Get file name let file = file.unwrap(); let path = file.path(); - let sign_command = if config - .mode - .repository - .as_ref() - .unwrap() - .signing - .key - .is_some() - && !config - .mode - .repository - .as_ref() - .unwrap() - .signing - .key - .as_ref() - .unwrap() - .is_empty() - { + let sign_command = if key.is_some() && !key.as_ref().unwrap().is_empty() { format!( "gpg --default-key {} --detach-sign {}", - config - .mode - .repository - .as_ref() - .unwrap() - .signing - .key - .as_ref() - .unwrap(), + key.as_ref().unwrap(), path.to_str().unwrap() ) } else { @@ -135,7 +105,7 @@ pub fn generate(verbose: bool) { // This should never happen, crash and burn if it does if zst.success() && xz.success() { crash!( - AppExitCode::InvalidRepo, + AppExitCode::RepoParseError, "Both .tar.zst and .tar.xz files found in repository. You've done something wrong. Aborting" ); } @@ -147,7 +117,7 @@ pub fn generate(verbose: bool) { true } else { crash!( - AppExitCode::NoPkgs, + AppExitCode::PkgsNotFound, "No .zst or .xz packages found in repository" ); // This should theoretically never be reached, but let's just give the compiler what it wants From c7063ca640efd261b65d44e9ffd7cef2c4df0d6f Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 25 Jul 2022 19:46:49 +0100 Subject: [PATCH 111/116] Fixed docs for compartmentalised exitcodes --- docs/USAGE.md | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/docs/USAGE.md b/docs/USAGE.md index 975f82c..549e6a5 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -25,15 +25,8 @@ Work it harder, make it better! | AppExitCode (named Enum) | Exit code (i32) | Error Description | |--------------------------|-----------------|--------------------------------------------------------------------------------------------------------| | `RunAsRoot` | `1` | Malachite was run as root. This is highly discouraged. So highly, in fact, that it will refuse to run. | -| `BuildInWorkspace` | `2` | Malachite was run in Workspace mode, but a Repository-mode-specific operation was supplied | -| `PkgNotFound` | `3` | A build was attempted for a package that does not exist | -| `InvalidMode` | `4` | Malachite was launched in a mode other than `workspace` or `repository` | -| `DirNotEmpty` | `5` | The creation of a Malachite repository was attempted in a non-empty directory | -| `ConfigNotFound` | `6` | The default config file (`./mlc.toml`) was not found | -| `NoPkgs` | `7` | Somehow, no packages were supplied to/found in the relevant operation | -| `ConfigParseError` | `8` | The config file could not be parsed | -| `InvalidRepo` | `9` | The generated repository somehow contains no packages | - - - - +| `PkgsNotFound` | `2` | No packages were specified/found for the desired operation | +| `DirNotEmpty` | `3` | The creation of a Malachite repository was attempted in a non-empty directory | +| `ConfigParseError` | `4` | The config file could not be parsed | +| `RepoParseError` | `5` | The repository info could not be parsed | +| `RepoNotClean` | `6` | The git repository is not clean and cannot be removed without `--force` | From a6821723b1cf06754ba2b3ab09a570c131c11234 Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 25 Jul 2022 19:53:29 +0100 Subject: [PATCH 112/116] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a65340a..99614f6 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ Malachite is a simple yet useful workspace and local repository management tool, | Update local repos/PKGBUILDs | mlc pull/update [all if left empty] | | Create and/or open config file | mlc conf | | Initialises repo/workspace based on config in mlc.toml | mlc clone/init | +| Displays information about a Malachite repository | mlc info/status | ### Pacman Repository Creation From c2428be80c94e43609824608b8ef148be8b9da56 Mon Sep 17 00:00:00 2001 From: Michal Date: Tue, 26 Jul 2022 20:00:42 +0100 Subject: [PATCH 113/116] HUGE `mlc info` speedup when pulling through ssh --- src/operations/info.rs | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/operations/info.rs b/src/operations/info.rs index 6baa58f..4ff94e9 100644 --- a/src/operations/info.rs +++ b/src/operations/info.rs @@ -1,6 +1,7 @@ use colored::Colorize; use spinoff::{Color, Spinner, Spinners}; use std::env; +use std::fmt::Write; use std::process::Command; use tabled::Tabled; @@ -46,11 +47,6 @@ pub fn git_status(verbose: bool, repo: &str, colorblind: bool) -> String { }); log!(verbose, "Current directory: {}", repo); - Command::new("git") - .args(&["remote", "update"]) - .output() - .unwrap(); - let output = Command::new("git").arg("status").output().unwrap(); let output = String::from_utf8(output.stdout).unwrap(); log!(verbose, "Git status: {}", output); @@ -126,6 +122,26 @@ pub fn info(verbose: bool) { Color::Green, ); + // Construct bash script to run git remote upgrade on all repos asynchronously + // This helps speed up the operation when, for example, you have a lot of repositories and you store your SSH key as a subkey of your GPG key on a yubikey + // This took my `mlc info` time down from 17s to 8s (i have the above described setup) + let mut bash_script = String::new(); + bash_script.push_str("\n\ + #!/usr/bin/env bash\n\ + \n\ + # This script will run `git remote update` in all repositories\n\ + pull() { cd $1; git remote update; cd -; }\n\ + \n"); + for repo in &repos_unparsed { + writeln!(bash_script, "pull {} &", repo.name).unwrap(); + } + bash_script.push_str("wait\n"); + + log!(verbose, "Bash script: {}", bash_script); + + // Run the bash script + Command::new("bash").arg("-c").arg(bash_script).output().unwrap(); + // Iterate over all repositories for repo in repos_unparsed { // Get name with branch, '/' serving as the delimiter From 02eee9e8f6bbb2ee15800a3243824289393799a5 Mon Sep 17 00:00:00 2001 From: Michal Date: Tue, 26 Jul 2022 20:03:39 +0100 Subject: [PATCH 114/116] cargo fmt --- src/operations/info.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/operations/info.rs b/src/operations/info.rs index 4ff94e9..833c501 100644 --- a/src/operations/info.rs +++ b/src/operations/info.rs @@ -126,12 +126,14 @@ pub fn info(verbose: bool) { // This helps speed up the operation when, for example, you have a lot of repositories and you store your SSH key as a subkey of your GPG key on a yubikey // This took my `mlc info` time down from 17s to 8s (i have the above described setup) let mut bash_script = String::new(); - bash_script.push_str("\n\ - #!/usr/bin/env bash\n\ - \n\ - # This script will run `git remote update` in all repositories\n\ - pull() { cd $1; git remote update; cd -; }\n\ - \n"); + bash_script.push_str( + "\n\ + #!/usr/bin/env bash\n\ + \n\ + # This script will run `git remote update` in all repositories\n\ + pull() { cd $1; git remote update; cd -; }\n\ + \n", + ); for repo in &repos_unparsed { writeln!(bash_script, "pull {} &", repo.name).unwrap(); } @@ -140,7 +142,11 @@ pub fn info(verbose: bool) { log!(verbose, "Bash script: {}", bash_script); // Run the bash script - Command::new("bash").arg("-c").arg(bash_script).output().unwrap(); + Command::new("bash") + .arg("-c") + .arg(bash_script) + .output() + .unwrap(); // Iterate over all repositories for repo in repos_unparsed { From 08483adbf9d494db0c8f14e2522f0bb59590655e Mon Sep 17 00:00:00 2001 From: Matt C Date: Wed, 27 Jul 2022 12:52:37 -0400 Subject: [PATCH 115/116] Update COMMON_FEATURES.md --- docs/COMMON_FEATURES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/COMMON_FEATURES.md b/docs/COMMON_FEATURES.md index bff6f6a..2bf3d53 100644 --- a/docs/COMMON_FEATURES.md +++ b/docs/COMMON_FEATURES.md @@ -1,5 +1,5 @@ # Common Features Between Modes -As[mode]us, shared of between uh… repositories… or something. +As [mode]us, shared of between uh… repositories… or something. ### What you need to know Malachite is fairly fleshed out in Repository mode, and not so much in Workspace mode. From 57f160b26d5d5eef1483fda6bba50c6634266e34 Mon Sep 17 00:00:00 2001 From: Michal Date: Wed, 27 Jul 2022 19:40:39 +0100 Subject: [PATCH 116/116] Fixed Malachite parsing git info even if git_info = false --- src/operations/info.rs | 72 ++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/src/operations/info.rs b/src/operations/info.rs index 833c501..1b61269 100644 --- a/src/operations/info.rs +++ b/src/operations/info.rs @@ -115,38 +115,50 @@ pub fn info(verbose: bool) { let mut repos = vec![]; let mut repos_git = vec![]; - // Start the spinner - let sp = Spinner::new( - Spinners::Line, - format!("{}", "Parsing Git Info...".bold()), - Color::Green, - ); + if git_info { + // Start the spinner + let sp = Spinner::new( + Spinners::Line, + format!("{}", "Parsing Git Info...".bold()), + Color::Green, + ); - // Construct bash script to run git remote upgrade on all repos asynchronously - // This helps speed up the operation when, for example, you have a lot of repositories and you store your SSH key as a subkey of your GPG key on a yubikey - // This took my `mlc info` time down from 17s to 8s (i have the above described setup) - let mut bash_script = String::new(); - bash_script.push_str( - "\n\ + // Construct bash script to run git remote upgrade on all repos asynchronously + // This helps speed up the operation when, for example, you have a lot of repositories and you store your SSH key as a subkey of your GPG key on a yubikey + // This took my `mlc info` time down from 17s to 8s (i have the above described setup) + let mut bash_script = String::new(); + bash_script.push_str( + "\n\ #!/usr/bin/env bash\n\ \n\ # This script will run `git remote update` in all repositories\n\ pull() { cd $1; git remote update; cd -; }\n\ - \n", - ); - for repo in &repos_unparsed { - writeln!(bash_script, "pull {} &", repo.name).unwrap(); - } - bash_script.push_str("wait\n"); + \n" + ); + for repo in &repos_unparsed { + writeln!(bash_script, "pull {} &", repo.name).unwrap(); + } + bash_script.push_str("wait\n"); - log!(verbose, "Bash script: {}", bash_script); + log!(verbose, "Bash script: {}", bash_script); - // Run the bash script - Command::new("bash") - .arg("-c") - .arg(bash_script) - .output() - .unwrap(); + // Run the bash script + Command::new("bash") + .arg("-c") + .arg(bash_script) + .output() + .unwrap(); + + // Because spinoff requires &'static str, we need to Box these in the heap and then leak them to be able to format the spinner + let symbol = Box::new(format!("{}", "✔".bold().green())); + let done = Box::new(format!("{}", "Done!".bold())); + + let symbol: &'static str = Box::leak(symbol); + let done: &'static str = Box::leak(done); + + sp.stop_and_persist(symbol, done); + log!(verbose, "Repos: {:?}", repos); + } // Iterate over all repositories for repo in repos_unparsed { @@ -187,16 +199,6 @@ pub fn info(verbose: bool) { } } - // Because spinoff requires &'static str, we need to Box these in the heap and then leak them to be able to format the spinner - let symbol = Box::new(format!("{}", "✔".bold().green())); - let done = Box::new(format!("{}", "Done!".bold())); - - let symbol: &'static str = Box::leak(symbol); - let done: &'static str = Box::leak(done); - - sp.stop_and_persist(symbol, done); - log!(verbose, "Repos: {:?}", repos); - // Sort by priority repos.sort_by(|a, b| b.priority.cmp(&a.priority)); repos_git.sort_by(|a, b| b.priority.cmp(&a.priority));