├── .github └── workflows │ └── test.yml ├── .gitignore ├── Changes ├── LICENSE ├── META.json ├── README.md ├── cpm.yml ├── dist.ini ├── lib └── App │ └── FatPacker │ ├── Simple.pm │ └── Simple │ └── Tutorial.pm ├── script └── fatpack-simple ├── t └── 00_compile.t └── xt ├── 01_basic.t ├── 02_basic.t └── lib └── Util.pm /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | tags-ignore: 8 | - '*' 9 | pull_request: 10 | 11 | jobs: 12 | linux: 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | perl-version: 17 | - '5.16-buster' 18 | - 'latest' 19 | container: 20 | image: perl:${{ matrix.perl-version }} 21 | steps: 22 | - uses: actions/checkout@v3 23 | - run: perl -V 24 | - name: Install Dependencies 25 | run: curl -fsSL --compressed https://raw.githubusercontent.com/skaji/cpm/main/cpm | perl - install -g --with-develop --with-recommends --show-build-log-on-failure 26 | - run: prove -l t xt 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /*.bs 2 | /*.c 3 | /*.o 4 | /*.old 5 | /App-FatPacker-Simple-* 6 | /MYMETA.* 7 | /Makefile 8 | /blib 9 | /pm_to_blib 10 | /MANIFEST 11 | /local 12 | /cpanfile.snapshot 13 | /Build 14 | /_build 15 | /.build 16 | 17 | -------------------------------------------------------------------------------- /Changes: -------------------------------------------------------------------------------- 1 | Revision history for App::FatPacker::Simple 2 | 3 | {{$NEXT}} 4 | 5 | 0.20 2023-05-05 09:04:08 JST 6 | 7 | - Require perl v5.16 8 | 9 | 0.09 2019-04-14 17:24:21 JST 10 | 11 | - Add --cache option for perl-strip 12 | 13 | 0.08 2017-05-10 18:22:15 CEST 14 | 15 | - Allow *.pl files to be fatpacked (#8 ccakes) 16 | 17 | 0.07 2016-02-27 20:23:06 JST 18 | 19 | - Introduce --exclude-strip option (#5, #7 by glensc) 20 | 21 | 0.06 2015-10-04 00:50:34 JST 22 | 23 | - rename bin/ to script/ in order to install fatpack-simple script 24 | 25 | 0.05 2015-10-04 00:37:51 JST 26 | 27 | - Update mentioned module App::fatten (has been renamed to App::depak) (#6 by perlancar) 28 | 29 | 0.04 2015-04-28T12:38:04Z 30 | 31 | - introduce --shebang SHEBANG option 32 | 33 | 0.03 2015-04-19T07:13:27Z 34 | 35 | - handle lib/ directories more correctly 36 | - recognize multi-line shebang, 37 | as described in `perldoc perlrun` (#3 by kazuho) 38 | 39 | 0.02 2015-02-23T16:13:47Z 40 | 41 | - document that this module is an alternative 42 | for ONLY fatpack file command 43 | - stop localizing PERL5LIB and PERL5OPT in test 44 | 45 | 0.01 2015-02-22T08:18:14Z 46 | 47 | - initial version 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This software is copyright (c) 2015 by Shoichi Kaji . 2 | 3 | This is free software; you can redistribute it and/or modify it under 4 | the same terms as the Perl 5 programming language system itself. 5 | 6 | Terms of the Perl programming language system itself 7 | 8 | a) the GNU General Public License as published by the Free 9 | Software Foundation; either version 1, or (at your option) any 10 | later version, or 11 | b) the "Artistic License" 12 | 13 | --- The GNU General Public License, Version 1, February 1989 --- 14 | 15 | This software is Copyright (c) 2015 by Shoichi Kaji . 16 | 17 | This is free software, licensed under: 18 | 19 | The GNU General Public License, Version 1, February 1989 20 | 21 | GNU GENERAL PUBLIC LICENSE 22 | Version 1, February 1989 23 | 24 | Copyright (C) 1989 Free Software Foundation, Inc. 25 | 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 26 | 27 | Everyone is permitted to copy and distribute verbatim copies 28 | of this license document, but changing it is not allowed. 29 | 30 | Preamble 31 | 32 | The license agreements of most software companies try to keep users 33 | at the mercy of those companies. By contrast, our General Public 34 | License is intended to guarantee your freedom to share and change free 35 | software--to make sure the software is free for all its users. The 36 | General Public License applies to the Free Software Foundation's 37 | software and to any other program whose authors commit to using it. 38 | You can use it for your programs, too. 39 | 40 | When we speak of free software, we are referring to freedom, not 41 | price. Specifically, the General Public License is designed to make 42 | sure that you have the freedom to give away or sell copies of free 43 | software, that you receive source code or can get it if you want it, 44 | that you can change the software or use pieces of it in new free 45 | programs; and that you know you can do these things. 46 | 47 | To protect your rights, we need to make restrictions that forbid 48 | anyone to deny you these rights or to ask you to surrender the rights. 49 | These restrictions translate to certain responsibilities for you if you 50 | distribute copies of the software, or if you modify it. 51 | 52 | For example, if you distribute copies of a such a program, whether 53 | gratis or for a fee, you must give the recipients all the rights that 54 | you have. You must make sure that they, too, receive or can get the 55 | source code. And you must tell them their rights. 56 | 57 | We protect your rights with two steps: (1) copyright the software, and 58 | (2) offer you this license which gives you legal permission to copy, 59 | distribute and/or modify the software. 60 | 61 | Also, for each author's protection and ours, we want to make certain 62 | that everyone understands that there is no warranty for this free 63 | software. If the software is modified by someone else and passed on, we 64 | want its recipients to know that what they have is not the original, so 65 | that any problems introduced by others will not reflect on the original 66 | authors' reputations. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | GNU GENERAL PUBLIC LICENSE 72 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 73 | 74 | 0. This License Agreement applies to any program or other work which 75 | contains a notice placed by the copyright holder saying it may be 76 | distributed under the terms of this General Public License. The 77 | "Program", below, refers to any such program or work, and a "work based 78 | on the Program" means either the Program or any work containing the 79 | Program or a portion of it, either verbatim or with modifications. Each 80 | licensee is addressed as "you". 81 | 82 | 1. You may copy and distribute verbatim copies of the Program's source 83 | code as you receive it, in any medium, provided that you conspicuously and 84 | appropriately publish on each copy an appropriate copyright notice and 85 | disclaimer of warranty; keep intact all the notices that refer to this 86 | General Public License and to the absence of any warranty; and give any 87 | other recipients of the Program a copy of this General Public License 88 | along with the Program. You may charge a fee for the physical act of 89 | transferring a copy. 90 | 91 | 2. You may modify your copy or copies of the Program or any portion of 92 | it, and copy and distribute such modifications under the terms of Paragraph 93 | 1 above, provided that you also do the following: 94 | 95 | a) cause the modified files to carry prominent notices stating that 96 | you changed the files and the date of any change; and 97 | 98 | b) cause the whole of any work that you distribute or publish, that 99 | in whole or in part contains the Program or any part thereof, either 100 | with or without modifications, to be licensed at no charge to all 101 | third parties under the terms of this General Public License (except 102 | that you may choose to grant warranty protection to some or all 103 | third parties, at your option). 104 | 105 | c) If the modified program normally reads commands interactively when 106 | run, you must cause it, when started running for such interactive use 107 | in the simplest and most usual way, to print or display an 108 | announcement including an appropriate copyright notice and a notice 109 | that there is no warranty (or else, saying that you provide a 110 | warranty) and that users may redistribute the program under these 111 | conditions, and telling the user how to view a copy of this General 112 | Public License. 113 | 114 | d) You may charge a fee for the physical act of transferring a 115 | copy, and you may at your option offer warranty protection in 116 | exchange for a fee. 117 | 118 | Mere aggregation of another independent work with the Program (or its 119 | derivative) on a volume of a storage or distribution medium does not bring 120 | the other work under the scope of these terms. 121 | 122 | 3. You may copy and distribute the Program (or a portion or derivative of 123 | it, under Paragraph 2) in object code or executable form under the terms of 124 | Paragraphs 1 and 2 above provided that you also do one of the following: 125 | 126 | a) accompany it with the complete corresponding machine-readable 127 | source code, which must be distributed under the terms of 128 | Paragraphs 1 and 2 above; or, 129 | 130 | b) accompany it with a written offer, valid for at least three 131 | years, to give any third party free (except for a nominal charge 132 | for the cost of distribution) a complete machine-readable copy of the 133 | corresponding source code, to be distributed under the terms of 134 | Paragraphs 1 and 2 above; or, 135 | 136 | c) accompany it with the information you received as to where the 137 | corresponding source code may be obtained. (This alternative is 138 | allowed only for noncommercial distribution and only if you 139 | received the program in object code or executable form alone.) 140 | 141 | Source code for a work means the preferred form of the work for making 142 | modifications to it. For an executable file, complete source code means 143 | all the source code for all modules it contains; but, as a special 144 | exception, it need not include source code for modules which are standard 145 | libraries that accompany the operating system on which the executable 146 | file runs, or for standard header files or definitions files that 147 | accompany that operating system. 148 | 149 | 4. You may not copy, modify, sublicense, distribute or transfer the 150 | Program except as expressly provided under this General Public License. 151 | Any attempt otherwise to copy, modify, sublicense, distribute or transfer 152 | the Program is void, and will automatically terminate your rights to use 153 | the Program under this License. However, parties who have received 154 | copies, or rights to use copies, from you under this General Public 155 | License will not have their licenses terminated so long as such parties 156 | remain in full compliance. 157 | 158 | 5. By copying, distributing or modifying the Program (or any work based 159 | on the Program) you indicate your acceptance of this license to do so, 160 | and all its terms and conditions. 161 | 162 | 6. Each time you redistribute the Program (or any work based on the 163 | Program), the recipient automatically receives a license from the original 164 | licensor to copy, distribute or modify the Program subject to these 165 | terms and conditions. You may not impose any further restrictions on the 166 | recipients' exercise of the rights granted herein. 167 | 168 | 7. The Free Software Foundation may publish revised and/or new versions 169 | of the General Public License from time to time. Such new versions will 170 | be similar in spirit to the present version, but may differ in detail to 171 | address new problems or concerns. 172 | 173 | Each version is given a distinguishing version number. If the Program 174 | specifies a version number of the license which applies to it and "any 175 | later version", you have the option of following the terms and conditions 176 | either of that version or of any later version published by the Free 177 | Software Foundation. If the Program does not specify a version number of 178 | the license, you may choose any version ever published by the Free Software 179 | Foundation. 180 | 181 | 8. If you wish to incorporate parts of the Program into other free 182 | programs whose distribution conditions are different, write to the author 183 | to ask for permission. For software which is copyrighted by the Free 184 | Software Foundation, write to the Free Software Foundation; we sometimes 185 | make exceptions for this. Our decision will be guided by the two goals 186 | of preserving the free status of all derivatives of our free software and 187 | of promoting the sharing and reuse of software generally. 188 | 189 | NO WARRANTY 190 | 191 | 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 192 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 193 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 194 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 195 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 196 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 197 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 198 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 199 | REPAIR OR CORRECTION. 200 | 201 | 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 202 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 203 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 204 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 205 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 206 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 207 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 208 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 209 | POSSIBILITY OF SUCH DAMAGES. 210 | 211 | END OF TERMS AND CONDITIONS 212 | 213 | Appendix: How to Apply These Terms to Your New Programs 214 | 215 | If you develop a new program, and you want it to be of the greatest 216 | possible use to humanity, the best way to achieve this is to make it 217 | free software which everyone can redistribute and change under these 218 | terms. 219 | 220 | To do so, attach the following notices to the program. It is safest to 221 | attach them to the start of each source file to most effectively convey 222 | the exclusion of warranty; and each file should have at least the 223 | "copyright" line and a pointer to where the full notice is found. 224 | 225 | 226 | Copyright (C) 19yy 227 | 228 | This program is free software; you can redistribute it and/or modify 229 | it under the terms of the GNU General Public License as published by 230 | the Free Software Foundation; either version 1, or (at your option) 231 | any later version. 232 | 233 | This program is distributed in the hope that it will be useful, 234 | but WITHOUT ANY WARRANTY; without even the implied warranty of 235 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 236 | GNU General Public License for more details. 237 | 238 | You should have received a copy of the GNU General Public License 239 | along with this program; if not, write to the Free Software 240 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA 241 | 242 | 243 | Also add information on how to contact you by electronic and paper mail. 244 | 245 | If the program is interactive, make it output a short notice like this 246 | when it starts in an interactive mode: 247 | 248 | Gnomovision version 69, Copyright (C) 19xx name of author 249 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 250 | This is free software, and you are welcome to redistribute it 251 | under certain conditions; type `show c' for details. 252 | 253 | The hypothetical commands `show w' and `show c' should show the 254 | appropriate parts of the General Public License. Of course, the 255 | commands you use may be called something other than `show w' and `show 256 | c'; they could even be mouse-clicks or menu items--whatever suits your 257 | program. 258 | 259 | You should also get your employer (if you work as a programmer) or your 260 | school, if any, to sign a "copyright disclaimer" for the program, if 261 | necessary. Here a sample; alter the names: 262 | 263 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 264 | program `Gnomovision' (a program to direct compilers to make passes 265 | at assemblers) written by James Hacker. 266 | 267 | , 1 April 1989 268 | Ty Coon, President of Vice 269 | 270 | That's all there is to it! 271 | 272 | 273 | --- The Artistic License 1.0 --- 274 | 275 | This software is Copyright (c) 2015 by Shoichi Kaji . 276 | 277 | This is free software, licensed under: 278 | 279 | The Artistic License 1.0 280 | 281 | The Artistic License 282 | 283 | Preamble 284 | 285 | The intent of this document is to state the conditions under which a Package 286 | may be copied, such that the Copyright Holder maintains some semblance of 287 | artistic control over the development of the package, while giving the users of 288 | the package the right to use and distribute the Package in a more-or-less 289 | customary fashion, plus the right to make reasonable modifications. 290 | 291 | Definitions: 292 | 293 | - "Package" refers to the collection of files distributed by the Copyright 294 | Holder, and derivatives of that collection of files created through 295 | textual modification. 296 | - "Standard Version" refers to such a Package if it has not been modified, 297 | or has been modified in accordance with the wishes of the Copyright 298 | Holder. 299 | - "Copyright Holder" is whoever is named in the copyright or copyrights for 300 | the package. 301 | - "You" is you, if you're thinking about copying or distributing this Package. 302 | - "Reasonable copying fee" is whatever you can justify on the basis of media 303 | cost, duplication charges, time of people involved, and so on. (You will 304 | not be required to justify it to the Copyright Holder, but only to the 305 | computing community at large as a market that must bear the fee.) 306 | - "Freely Available" means that no fee is charged for the item itself, though 307 | there may be fees involved in handling the item. It also means that 308 | recipients of the item may redistribute it under the same conditions they 309 | received it. 310 | 311 | 1. You may make and give away verbatim copies of the source form of the 312 | Standard Version of this Package without restriction, provided that you 313 | duplicate all of the original copyright notices and associated disclaimers. 314 | 315 | 2. You may apply bug fixes, portability fixes and other modifications derived 316 | from the Public Domain or from the Copyright Holder. A Package modified in such 317 | a way shall still be considered the Standard Version. 318 | 319 | 3. You may otherwise modify your copy of this Package in any way, provided that 320 | you insert a prominent notice in each changed file stating how and when you 321 | changed that file, and provided that you do at least ONE of the following: 322 | 323 | a) place your modifications in the Public Domain or otherwise make them 324 | Freely Available, such as by posting said modifications to Usenet or an 325 | equivalent medium, or placing the modifications on a major archive site 326 | such as ftp.uu.net, or by allowing the Copyright Holder to include your 327 | modifications in the Standard Version of the Package. 328 | 329 | b) use the modified Package only within your corporation or organization. 330 | 331 | c) rename any non-standard executables so the names do not conflict with 332 | standard executables, which must also be provided, and provide a separate 333 | manual page for each non-standard executable that clearly documents how it 334 | differs from the Standard Version. 335 | 336 | d) make other distribution arrangements with the Copyright Holder. 337 | 338 | 4. You may distribute the programs of this Package in object code or executable 339 | form, provided that you do at least ONE of the following: 340 | 341 | a) distribute a Standard Version of the executables and library files, 342 | together with instructions (in the manual page or equivalent) on where to 343 | get the Standard Version. 344 | 345 | b) accompany the distribution with the machine-readable source of the Package 346 | with your modifications. 347 | 348 | c) accompany any non-standard executables with their corresponding Standard 349 | Version executables, giving the non-standard executables non-standard 350 | names, and clearly documenting the differences in manual pages (or 351 | equivalent), together with instructions on where to get the Standard 352 | Version. 353 | 354 | d) make other distribution arrangements with the Copyright Holder. 355 | 356 | 5. You may charge a reasonable copying fee for any distribution of this 357 | Package. You may charge any fee you choose for support of this Package. You 358 | may not charge a fee for this Package itself. However, you may distribute this 359 | Package in aggregate with other (possibly commercial) programs as part of a 360 | larger (possibly commercial) software distribution provided that you do not 361 | advertise this Package as a product of your own. 362 | 363 | 6. The scripts and library files supplied as input to or produced as output 364 | from the programs of this Package do not automatically fall under the copyright 365 | of this Package, but belong to whomever generated them, and may be sold 366 | commercially, and may be aggregated with this Package. 367 | 368 | 7. C or perl subroutines supplied by you and linked into this Package shall not 369 | be considered part of this Package. 370 | 371 | 8. The name of the Copyright Holder may not be used to endorse or promote 372 | products derived from this software without specific prior written permission. 373 | 374 | 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED 375 | WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 376 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 377 | 378 | The End 379 | 380 | -------------------------------------------------------------------------------- /META.json: -------------------------------------------------------------------------------- 1 | { 2 | "abstract" : "only fatpack a script", 3 | "author" : [ 4 | "Shoichi Kaji " 5 | ], 6 | "dynamic_config" : 0, 7 | "generated_by" : "Dist::Zilla version 6.030, CPAN::Meta::Converter version 2.150010", 8 | "license" : [ 9 | "perl_5" 10 | ], 11 | "meta-spec" : { 12 | "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", 13 | "version" : 2 14 | }, 15 | "name" : "App-FatPacker-Simple", 16 | "prereqs" : { 17 | "configure" : { 18 | "requires" : { 19 | "Module::Build::Tiny" : "0.034" 20 | } 21 | }, 22 | "develop" : { 23 | "requires" : { 24 | "Capture::Tiny" : "0", 25 | "File::pushd" : "0" 26 | } 27 | }, 28 | "runtime" : { 29 | "requires" : { 30 | "App::FatPacker" : "0", 31 | "Distribution::Metadata" : "0.05", 32 | "Getopt::Long" : "2.39", 33 | "Perl::Strip" : "0", 34 | "perl" : "v5.16.0" 35 | } 36 | } 37 | }, 38 | "provides" : { 39 | "App::FatPacker::Simple" : { 40 | "file" : "lib/App/FatPacker/Simple.pm", 41 | "version" : "0.20" 42 | }, 43 | "App::FatPacker::Simple::Tutorial" : { 44 | "file" : "lib/App/FatPacker/Simple/Tutorial.pm" 45 | } 46 | }, 47 | "release_status" : "stable", 48 | "resources" : { 49 | "bugtracker" : { 50 | "web" : "https://github.com/skaji/App-FatPacker-Simple/issues" 51 | }, 52 | "homepage" : "https://github.com/skaji/App-FatPacker-Simple", 53 | "repository" : { 54 | "type" : "git", 55 | "url" : "https://github.com/skaji/App-FatPacker-Simple.git", 56 | "web" : "https://github.com/skaji/App-FatPacker-Simple" 57 | } 58 | }, 59 | "version" : "0.20", 60 | "x_contributors" : [ 61 | "Kazuho Oku ", 62 | "perlancar ", 63 | "Shoichi Kaji " 64 | ], 65 | "x_generated_by_perl" : "v5.36.1", 66 | "x_serialization_backend" : "Cpanel::JSON::XS version 4.36", 67 | "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later", 68 | "x_static_install" : 1 69 | } 70 | 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Actions Status](https://github.com/skaji/App-FatPacker-Simple/actions/workflows/test.yml/badge.svg)](https://github.com/skaji/App-FatPacker-Simple/actions) 2 | 3 | # NAME 4 | 5 | App::FatPacker::Simple - only fatpack a script 6 | 7 | # SYNOPSIS 8 | 9 | $ fatpack-simple script.pl 10 | 11 | # DESCRIPTION 12 | 13 | App::FatPacker::Simple or its frontend `fatpack-simple` helps you 14 | fatpack a script when **YOU** understand the whole dependencies of it. 15 | 16 | For tutorial, please look at [App::FatPacker::Simple::Tutorial](https://metacpan.org/pod/App%3A%3AFatPacker%3A%3ASimple%3A%3ATutorial). 17 | 18 | # MOTIVATION 19 | 20 | App::FatPacker::Simple is an alternative for [App::FatPacker](https://metacpan.org/pod/App%3A%3AFatPacker)'s 21 | `fatpack file` command. 22 | Let me explain why I wrote this module. 23 | 24 | [App::FatPacker](https://metacpan.org/pod/App%3A%3AFatPacker) brings more portability to Perl, that is totally awesome. 25 | 26 | As far as I understand, App::FatPacker does 3 things: 27 | 28 | - (a) trace dependencies for a script 29 | - (b) collects dependencies to `fatlib` directory 30 | - (c) fatpack the script with modules in `fatlib` 31 | 32 | As for (a), I have often encountered problems. For example, 33 | modules that I don't want to trace trace, 34 | conversely, modules that I DO want to trace do not trace. 35 | Moreover a core module has changed interfaces or has been bug-fixed recently, 36 | so we have to fatpack that module with new version, etc. 37 | So I think if you author intend to fatpack a script, 38 | **YOU** need to understand the whole dependencies of it. 39 | 40 | As for (b), to locate modules in a directory, why don't you use 41 | `carton` or `cpanm`? 42 | 43 | So the rest is (c) to fatpack a script with modules in directories, 44 | on which App::FatPacker::Simple concentrates. 45 | 46 | That is, App::FatPacker::Simple only fatpacks a script with features: 47 | 48 | - automatically perl-strip modules 49 | - has option to exclude some modules 50 | 51 | # SEE ALSO 52 | 53 | [App::FatPacker](https://metacpan.org/pod/App%3A%3AFatPacker) 54 | 55 | [App::depak](https://metacpan.org/pod/App%3A%3Adepak) 56 | 57 | [Perl::Strip](https://metacpan.org/pod/Perl%3A%3AStrip) 58 | 59 | # COPYRIGHT AND LICENSE 60 | 61 | Copyright 2015 Shoichi Kaji 62 | 63 | This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. 64 | -------------------------------------------------------------------------------- /cpm.yml: -------------------------------------------------------------------------------- 1 | prereqs: 2 | runtime: 3 | requires: 4 | App::FatPacker: 5 | Distribution::Metadata: { version: '0.05' } 6 | Getopt::Long: { version: '2.39' } 7 | Perl::Strip: 8 | perl: { version: 'v5.16' } 9 | develop: 10 | requires: 11 | File::pushd: 12 | Capture::Tiny: 13 | -------------------------------------------------------------------------------- /dist.ini: -------------------------------------------------------------------------------- 1 | name = App-FatPacker-Simple 2 | 3 | [Git::GatherDir] 4 | exclude_filename = META.json 5 | exclude_filename = LICENSE 6 | [CopyFilesFromBuild] 7 | copy = META.json 8 | copy = LICENSE 9 | [VersionFromMainModule] 10 | [LicenseFromModule] 11 | override_author = 1 12 | [ReversionOnRelease] 13 | prompt = 1 14 | [NextRelease] 15 | format = %v %{yyyy-MM-dd HH:mm:ss VVV}d%{ (TRIAL RELEASE)}T 16 | [Git::Check] 17 | allow_dirty = Changes 18 | allow_dirty = META.json 19 | [GithubMeta] 20 | issues = 1 21 | [ReadmeAnyFromPod] 22 | type = markdown 23 | filename = README.md 24 | location = root 25 | [MetaProvides::Package] 26 | inherit_version = 0 27 | inherit_missing = 0 28 | [PruneFiles] 29 | filename = dist.ini 30 | filename = cpm.yml 31 | filename = README.md 32 | match = ^(xt|author|maint|example|eg)/ 33 | [GitHubREADME::Badge] 34 | badges = github_actions/test.yml 35 | [Prereqs::From::cpmfile] 36 | [ModuleBuildTiny] 37 | [MetaJSON] 38 | [StaticInstall] 39 | [Git::Contributors] 40 | [License] 41 | 42 | [CheckChangesHasContent] 43 | [TestRelease] 44 | [ConfirmRelease] 45 | [UploadToCPAN] 46 | [CopyFilesFromRelease] 47 | match = \.pm$ 48 | [Git::Commit] 49 | commit_msg = %v 50 | allow_dirty = Changes 51 | allow_dirty = META.json 52 | allow_dirty_match = \.pm$ 53 | [Git::Tag] 54 | tag_format = %v 55 | tag_message = 56 | [Git::Push] 57 | -------------------------------------------------------------------------------- /lib/App/FatPacker/Simple.pm: -------------------------------------------------------------------------------- 1 | package App::FatPacker::Simple 0.20; 2 | use v5.16; 3 | use warnings; 4 | 5 | use App::FatPacker; 6 | use Config; 7 | use Cwd (); 8 | use Distribution::Metadata; 9 | use File::Basename (); 10 | use File::Find (); 11 | use File::Spec; 12 | use File::Spec::Unix; 13 | use Getopt::Long (); 14 | use Perl::Strip; 15 | use Pod::Usage (); 16 | 17 | our $IGNORE_FILE = [ 18 | qr/\.pod$/, 19 | qr/\.packlist$/, 20 | qr/MYMETA\.json$/, 21 | qr/install\.json$/, 22 | ]; 23 | 24 | sub new { 25 | my ($class, @argv) = @_; 26 | bless { @argv }, $class; 27 | } 28 | 29 | sub parse_options { 30 | my ($self, @argv) = @_; 31 | my $parser = Getopt::Long::Parser->new( 32 | config => [qw(no_auto_abbrev no_ignore_case)], 33 | ); 34 | $parser->getoptionsfromarray( 35 | \@argv, 36 | "d|dir=s" => \(my $dir = 'lib,fatlib,local,extlib'), 37 | "e|exclude=s" => \(my $exclude), 38 | "h|help" => sub { $self->show_help; exit 1 }, 39 | "o|output=s" => \(my $output), 40 | "q|quiet" => \(my $quiet), 41 | "s|strict" => \(my $strict), 42 | "v|version" => sub { printf "%s %s\n", __PACKAGE__, __PACKAGE__->VERSION; exit }, 43 | "color!" => \(my $color = 1), 44 | "shebang=s" => \(my $custom_shebang), 45 | "exclude-strip=s@" => \(my $exclude_strip), 46 | "no-strip|no-perl-strip" => \(my $no_perl_strip), 47 | "cache=s" => \(my $cache), 48 | ) or exit 1; 49 | $self->{script} = shift @argv or do { warn "Missing script.\n"; $self->show_help; exit 1 }; 50 | $self->{dir} = $self->build_dir($dir); 51 | $self->{output} = $output; 52 | $self->{quiet} = $quiet; 53 | $self->{strict} = $strict; 54 | $self->{color} = $color; 55 | $self->{custom_shebang} = $custom_shebang; 56 | $self->{exclude_strip} = [map { qr/$_/ } @{$exclude_strip || []}]; 57 | $self->{exclude} = []; 58 | if (!$no_perl_strip) { 59 | $self->{perl_strip} = Perl::Strip->new($cache ? (cache => $cache) : ()); 60 | } 61 | if ($exclude) { 62 | for my $e (split /,/, $exclude) { 63 | my $dist = Distribution::Metadata->new_from_module( 64 | $e, inc => $self->{dir}, 65 | ); 66 | if (my $files = $dist->files) { 67 | push @{$self->{exclude}}, @$files; 68 | } else { 69 | $self->warning("Missing $e in $dir"); 70 | } 71 | } 72 | } 73 | $self; 74 | } 75 | 76 | sub show_help { 77 | open my $fh, '>', \my $out; 78 | Pod::Usage::pod2usage 79 | exitval => 'noexit', 80 | input => $0, 81 | output => $fh, 82 | sections => 'SYNOPSIS|COMMANDS|OPTIONS|EXAMPLES', 83 | verbose => 99, 84 | ; 85 | $out =~ s/^[ ]{4,6}/ /mg; 86 | $out =~ s/\n$//; 87 | print $out; 88 | } 89 | 90 | sub warning { 91 | my ($self, $msg) = @_; 92 | chomp $msg; 93 | my $color = $self->{color} 94 | ? sub { "\e[31m$_[0]\e[m", "\n" } 95 | : sub { "$_[0]\n" }; 96 | if ($self->{strict}) { 97 | die $color->("=> ERROR $msg"); 98 | } elsif (!$self->{quiet}) { 99 | warn $color->("=> WARN $msg"); 100 | } 101 | } 102 | 103 | sub debug { 104 | my ($self, $msg) = @_; 105 | chomp $msg; 106 | if (!$self->{quiet}) { 107 | warn "-> $msg\n"; 108 | } 109 | } 110 | 111 | sub output_filename { 112 | my $self = shift; 113 | return $self->{output} if $self->{output}; 114 | 115 | my $script = File::Basename::basename $self->{script}; 116 | my ($suffix, @other) = reverse split /\./, $script; 117 | if (!@other) { 118 | "$script.fatpack"; 119 | } else { 120 | unshift @other, "fatpack"; 121 | join ".", reverse(@other), $suffix; 122 | } 123 | } 124 | 125 | sub run { 126 | my $self = shift; 127 | my $fatpacked = $self->fatpack_file($self->{script}); 128 | my $output_filename = $self->output_filename; 129 | open my $fh, ">", $output_filename 130 | or die "Cannot open '$output_filename': $!\n"; 131 | print {$fh} $fatpacked; 132 | close $fh; 133 | my $mode = (stat $self->{script})[2]; 134 | chmod $mode, $output_filename; 135 | $self->debug("Successfully created $output_filename"); 136 | } 137 | 138 | # In order not to depend on App::FatPacker internals, 139 | # we use only App::FatPacker::fatpack_code method. 140 | sub fatpack_file { 141 | my ($self, $file) = @_; 142 | my ($shebang, $script) = $self->load_main_script($file); 143 | $shebang = $self->{custom_shebang} if $self->{custom_shebang}; 144 | my %files; 145 | $self->collect_files($_, \%files) for @{ $self->{dir} }; 146 | my $fatpacker = App::FatPacker->new; 147 | return join "\n", $shebang, $fatpacker->fatpack_code(\%files), $script; 148 | } 149 | 150 | # almost copy from App::FatPacker::load_main_script 151 | sub load_main_script { 152 | my ($self, $file) = @_; 153 | open my $fh, "<", $file or die "Cannot open '$file': $!\n"; 154 | my @lines = <$fh>; 155 | my @shebang; 156 | if (@lines && index($lines[0], '#!') == 0) { 157 | while (1) { 158 | push @shebang, shift @lines; 159 | last if $shebang[-1] =~ m{^\#\!.*perl}; 160 | } 161 | } 162 | ((join "", @shebang), (join "", @lines)); 163 | } 164 | 165 | sub load_file { 166 | my ($self, $absolute, $relative, $original) = @_; 167 | 168 | my $content = do { 169 | open my $fh, "<", $absolute or die "Cannot open '$absolute': $!\n"; 170 | local $/; <$fh>; 171 | }; 172 | 173 | if ($self->{perl_strip} and !grep { $original =~ $_ } @{$self->{exclude_strip}}) { 174 | $self->debug("fatpack $relative (with perl-strip)"); 175 | return $self->{perl_strip}->strip($content); 176 | } else { 177 | $self->debug("fatpack $relative (without perl-strip)"); 178 | return $content; 179 | } 180 | } 181 | 182 | sub collect_files { 183 | my ($self, $dir, $files) = @_; 184 | 185 | my $absolute_dir = Cwd::abs_path($dir); 186 | # When $dir is not an archlib, 187 | # and we are about to search $dir/archlib, skip it! 188 | # because $dir/archlib itself will be searched another time. 189 | my $skip_dir = File::Spec->catdir($absolute_dir, $Config{archname}); 190 | $skip_dir = qr/\Q$skip_dir\E/; 191 | 192 | my $find = sub { 193 | return unless -f $_; 194 | for my $ignore (@$IGNORE_FILE) { 195 | $_ =~ $ignore and return; 196 | } 197 | my $original = $_; 198 | my $absolute = Cwd::abs_path($original); 199 | return if $absolute =~ $skip_dir; 200 | my $relative = File::Spec::Unix->abs2rel($absolute, $absolute_dir); 201 | for my $exclude (@{$self->{exclude}}) { 202 | if ($absolute eq $exclude) { 203 | $self->debug("exclude $relative"); 204 | return; 205 | } 206 | } 207 | if (!/\.(?:pm|ix|al|pl)$/) { 208 | $self->warning("skip non perl module file $relative"); 209 | return; 210 | } 211 | $files->{$relative} = $self->load_file($absolute, $relative, $original); 212 | }; 213 | File::Find::find({wanted => $find, no_chdir => 1}, $dir); 214 | } 215 | 216 | sub build_dir { 217 | my ($self, $dir_string) = @_; 218 | my @dir; 219 | for my $d (grep -d, split /,/, $dir_string) { 220 | my $try = File::Spec->catdir($d, "lib/perl5"); 221 | if (-d $try) { 222 | push @dir, $try, File::Spec->catdir($try, $Config{archname}); 223 | } else { 224 | push @dir, $d, File::Spec->catdir($d, $Config{archname}); 225 | } 226 | } 227 | return [ grep -d, @dir ]; 228 | } 229 | 230 | 1; 231 | __END__ 232 | 233 | =for stopwords fatpack fatpacks fatpacked deps 234 | 235 | =encoding utf-8 236 | 237 | =head1 NAME 238 | 239 | App::FatPacker::Simple - only fatpack a script 240 | 241 | =head1 SYNOPSIS 242 | 243 | $ fatpack-simple script.pl 244 | 245 | =head1 DESCRIPTION 246 | 247 | App::FatPacker::Simple or its frontend C helps you 248 | fatpack a script when B understand the whole dependencies of it. 249 | 250 | For tutorial, please look at L. 251 | 252 | =head1 MOTIVATION 253 | 254 | App::FatPacker::Simple is an alternative for L's 255 | C command. 256 | Let me explain why I wrote this module. 257 | 258 | L brings more portability to Perl, that is totally awesome. 259 | 260 | As far as I understand, App::FatPacker does 3 things: 261 | 262 | =over 4 263 | 264 | =item (a) trace dependencies for a script 265 | 266 | =item (b) collects dependencies to C directory 267 | 268 | =item (c) fatpack the script with modules in C 269 | 270 | =back 271 | 272 | As for (a), I have often encountered problems. For example, 273 | modules that I don't want to trace trace, 274 | conversely, modules that I DO want to trace do not trace. 275 | Moreover a core module has changed interfaces or has been bug-fixed recently, 276 | so we have to fatpack that module with new version, etc. 277 | So I think if you author intend to fatpack a script, 278 | B need to understand the whole dependencies of it. 279 | 280 | As for (b), to locate modules in a directory, why don't you use 281 | C or C? 282 | 283 | So the rest is (c) to fatpack a script with modules in directories, 284 | on which App::FatPacker::Simple concentrates. 285 | 286 | That is, App::FatPacker::Simple only fatpacks a script with features: 287 | 288 | =over 4 289 | 290 | =item * automatically perl-strip modules 291 | 292 | =item * has option to exclude some modules 293 | 294 | =back 295 | 296 | =head1 SEE ALSO 297 | 298 | L 299 | 300 | L 301 | 302 | L 303 | 304 | =head1 COPYRIGHT AND LICENSE 305 | 306 | Copyright 2015 Shoichi Kaji Eskaji@cpan.orgE 307 | 308 | This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. 309 | 310 | =cut 311 | -------------------------------------------------------------------------------- /lib/App/FatPacker/Simple/Tutorial.pm: -------------------------------------------------------------------------------- 1 | package App::FatPacker::Simple::Tutorial; 2 | use v5.16; 3 | use warnings; 4 | 5 | 1; 6 | __END__ 7 | 8 | =for stopwords fatpack fatpacks fatpacked deps 9 | 10 | =head1 NAME 11 | 12 | App::FatPacker::Simple::Tutorial - tutorial! 13 | 14 | =head1 SUMMARY 15 | 16 | If you execute C, 17 | then you will get C 18 | that is the fatpacked C with all modules in 19 | C directories. 20 | Also note that the all modules are automatically perl-stripped. 21 | 22 | =head1 TUTORIAL 23 | 24 | Let's say you have C and want to fatpack it. 25 | And assume 26 | 27 | =over 4 28 | 29 | =item * C uses your modules in C directory: C, C 30 | 31 | =item * external cpan module dependencies are declared in C 32 | 33 | =back 34 | 35 | so that you have: 36 | 37 | $ find . -type f 38 | ./cpanfile 39 | ./hello.pl 40 | ./lib/Hello/CLI.pm 41 | ./lib/Hello.pm 42 | 43 | $ cat cpanfile 44 | requires 'Sub::Retry'; 45 | requires 'HTTP::Tiny'; 46 | 47 | Well, C just fatpacks a script with all modules in 48 | C, 49 | so let's install dependencies to C directory first: 50 | 51 | # if you have carton, then: 52 | $ carton install 53 | 54 | # or just: 55 | $ cpanm -Llocal -nq --installdeps . 56 | 57 | # Oh, HTTP::Tiny is not core module for old perls, so we have to fatpack it too! 58 | $ cpanm --reinstall -Llocal -nq HTTP::Tiny 59 | 60 | # Oh, Sub::Retry depends on 'parent' module, so we have to fatpack it too! 61 | $ cpanm --reinstall -Llocal -nq parent 62 | 63 | Now the whole dependencies are in C and C directories, 64 | it's time to execute C. 65 | However if you use perl 5.20+, 66 | then cpanm installed configure deps Module::Build, CPAN::Meta, right? 67 | They are not necessary for runtime, so execute C with 68 | C<--exclude> option: 69 | 70 | $ fatpack-simple --exclude Module::Build,CPAN::Meta hello.pl 71 | -> perl strip Hello.pm 72 | -> perl strip Hello/CLI.pm 73 | -> perl strip parent.pm 74 | -> exclude CPAN/Meta.pm 75 | ... 76 | -> perl strip HTTP/Tiny.pm 77 | -> exclude Module/Build.pm 78 | ... 79 | -> perl strip Sub/Retry.pm 80 | -> Successfully created hello.fatpack.pl 81 | 82 | Finally you get C! 83 | 84 | =cut 85 | -------------------------------------------------------------------------------- /script/fatpack-simple: -------------------------------------------------------------------------------- 1 | #!perl 2 | use v5.16; 3 | use warnings; 4 | use App::FatPacker::Simple; 5 | 6 | App::FatPacker::Simple->new->parse_options(@ARGV)->run; 7 | 8 | __END__ 9 | 10 | =for stopwords fatpack fatpacks fatpacked deps 11 | 12 | =head1 NAME 13 | 14 | fatpack-simple - only fatpack a script 15 | 16 | =head1 SYNOPSIS 17 | 18 | $ fatpack-simple [OPTIONS] SCRIPT 19 | 20 | =head1 OPTIONS 21 | 22 | -d, --dir DIRECTORIES where pm files to be fatpacked are. 23 | default: lib,fatlib,local,extlib 24 | -o, --output OUTPUT output filename 25 | -e, --exclude MODULES modules not to be fatpacked 26 | -s, --strict turn on strict mode 27 | -q, --quiet be quiet 28 | --color color output, default: on 29 | --no-strip do not perform perl-strip 30 | --cache DIRECTORY cache directory for perl-strip 31 | --shebang SHEBANG use custom shebang 32 | --exclude-strip REGEXP do not perform perl-strip on files which match REGEXP 33 | -h, --help show this help 34 | -v, --version show version 35 | 36 | =head1 EXAMPLES 37 | 38 | $ fatpack-simple script.pl 39 | $ fatpack-simple --dir deps,my-ext --output artifact.pl script.pl 40 | $ fatpack-simple --exclude Module::Build,List::MoreUtils --strict script.pl 41 | $ fatpack-simple --shebang '#!/usr/bin/env perl' script.pl 42 | $ fatpack-simple --exclude-strip 'MyApp.*\.pm' script.pl 43 | 44 | =head1 DESCRIPTION 45 | 46 | C helps you fatpack a script when B understand the whole 47 | dependencies of it. 48 | 49 | If you execute C, 50 | then you will get C 51 | that is the fatpacked C with all modules in 52 | C directories. 53 | Also note that the all modules are automatically perl-stripped. 54 | 55 | For tutorial, please look at L. 56 | 57 | =head1 LICENSE 58 | 59 | Copyright (C) Shoichi Kaji. 60 | 61 | This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. 62 | 63 | =head1 AUTHOR 64 | 65 | Shoichi Kaji Eskaji@cpan.orgE 66 | 67 | =cut 68 | 69 | -------------------------------------------------------------------------------- /t/00_compile.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use Test::More tests => 1; 3 | use App::FatPacker::Simple; 4 | pass "happy hacking!"; 5 | -------------------------------------------------------------------------------- /xt/01_basic.t: -------------------------------------------------------------------------------- 1 | use v5.16; 2 | use warnings; 3 | 4 | use Test::More; 5 | use Config; 6 | use Capture::Tiny 'capture'; 7 | 8 | use lib "xt/lib"; 9 | use Util; 10 | 11 | subtest basic => sub { 12 | my $guard = tempd; 13 | spew 1 => "hello.pl"; 14 | chmod 0755, "hello.pl"; 15 | run "hello.pl"; 16 | ok -f "hello.fatpack.pl"; 17 | my $exit; capture { $exit = system $^X, "-c", "hello.fatpack.pl" }; 18 | is $exit, 0; 19 | ok -x "hello.fatpack.pl"; 20 | 21 | run "hello.pl", "--output", "foo.pl"; 22 | ok -f "foo.pl"; 23 | 24 | spew "1" => "output-test"; 25 | run "output-test"; 26 | ok -f "output-test.fatpack"; 27 | }; 28 | 29 | subtest dir => sub { 30 | my $guard = tempd; 31 | spew 1 => "hello.pl"; 32 | spew_pm "Hoge1", "lib"; 33 | spew_pm "Hoge2", "extlib"; 34 | spew_pm "Hoge3", "local"; 35 | spew_pm "Hoge4", "fatlib"; 36 | run "hello.pl"; 37 | ok -f "hello.fatpack.pl"; 38 | for my $i (1..4) { 39 | ok contains("hello.fatpack.pl", "Hoge$i"); 40 | } 41 | 42 | spew_pm "Hoge5", "other"; 43 | run "hello.pl", "--dir", "other"; 44 | for my $i (1..4) { 45 | ok !contains("hello.fatpack.pl", "Hoge$i"); 46 | } 47 | ok contains("hello.fatpack.pl", "Hoge5"); 48 | }; 49 | 50 | subtest local_lib => sub { 51 | my $guard = tempd; 52 | spew 1 => "hello.pl"; 53 | spew_pm "Hoge1", "lib"; 54 | spew_pm "Hoge2", "extlib/lib/perl5"; 55 | spew_pm "Hoge3", "local/lib/perl5"; 56 | run "hello.pl"; 57 | ok -f "hello.fatpack.pl"; 58 | for my $i (1..3) { 59 | ok contains("hello.fatpack.pl", "Hoge$i"); 60 | } 61 | }; 62 | 63 | subtest non_pm => sub { 64 | my $guard = tempd; 65 | spew 1 => "hello.pl"; 66 | spew 1 => "lib/foo.so"; 67 | my $r = run "hello.pl"; 68 | ok $r->success; 69 | like $r->err, qr/WARN/; 70 | 71 | $r = run "hello.pl", "--strict", "--output", "foo.pl"; 72 | ok !$r->success; 73 | like $r->err, qr/ERROR/; 74 | ok !-f "foo.pl"; 75 | }; 76 | 77 | subtest handle_relative_and_abs_path => sub { 78 | my $guard = tempd; 79 | spew 1 => "hello.pl"; 80 | spew_pm "Hoge1", "lib"; 81 | spew_pm "Hoge2", "extlib/lib/perl5"; 82 | spew_pm "Hoge3", "extlib/lib/perl5/$Config{archname}"; 83 | { 84 | mkdir "test1"; 85 | my $guard1 = pushd "test1"; 86 | run "--dir", "../lib,../extlib", "../hello.pl"; 87 | ok contains("hello.fatpack.pl", "Hoge1"); 88 | ok contains("hello.fatpack.pl", "Hoge2"); 89 | ok contains("hello.fatpack.pl", "Hoge3"); 90 | } 91 | { 92 | mkdir "test2"; 93 | my $guard2 = pushd "test2"; 94 | run "--dir", "$guard/lib,$guard/extlib", "$guard/hello.pl"; 95 | ok contains("hello.fatpack.pl", "Hoge1"); 96 | ok contains("hello.fatpack.pl", "Hoge2"); 97 | ok contains("hello.fatpack.pl", "Hoge3"); 98 | } 99 | }; 100 | 101 | subtest no_strip => sub { 102 | my $guard = tempd; 103 | spew 1 => "hello.pl"; 104 | spew_pm "Hoge1", "lib"; 105 | spew_pm "Hoge2", "extlib/lib/perl5"; 106 | spew_pm "Hoge3", "local/lib/perl5"; 107 | run "--no-strip", "hello.pl"; 108 | ok -f "hello.fatpack.pl"; 109 | for my $i (1..3) { 110 | ok contains("hello.fatpack.pl", "Hoge$i"); 111 | } 112 | my $content = slurp("hello.fatpack.pl"); 113 | like $content, qr/\Quse Hoge1; 1; # this is comment/; 114 | like $content, qr/\Quse Hoge2; 1; # this is comment/; 115 | like $content, qr/\Quse Hoge3; 1; # this is comment/; 116 | }; 117 | 118 | subtest exclude_strip => sub { 119 | my $guard = tempd; 120 | spew 1 => "hello.pl"; 121 | spew_pm "Hoge1", "lib"; 122 | spew_pm "Hoge2", "extlib/lib/perl5"; 123 | spew_pm "Hoge3", "local/lib/perl5"; 124 | { 125 | run "--exclude-strip", "Hoge1", "hello.pl"; 126 | ok -f "hello.fatpack.pl"; 127 | for my $i (1..3) { 128 | ok contains("hello.fatpack.pl", "Hoge$i"); 129 | } 130 | my $content = slurp("hello.fatpack.pl"); 131 | like $content, qr/\Quse Hoge1; 1; # this is comment/; 132 | like $content, qr/\Quse Hoge2;1;/; 133 | like $content, qr/\Quse Hoge3;1;/; 134 | } 135 | { 136 | run "--exclude-strip", "^(?:local|extlib)", "hello.pl"; 137 | ok -f "hello.fatpack.pl"; 138 | for my $i (1..3) { 139 | ok contains("hello.fatpack.pl", "Hoge$i"); 140 | } 141 | my $content = slurp("hello.fatpack.pl"); 142 | like $content, qr/\Quse Hoge1;1;/; 143 | like $content, qr/\Quse Hoge2; 1; # this is comment/; 144 | like $content, qr/\Quse Hoge3; 1; # this is comment/; 145 | } 146 | }; 147 | 148 | done_testing; 149 | -------------------------------------------------------------------------------- /xt/02_basic.t: -------------------------------------------------------------------------------- 1 | use v5.16; 2 | use warnings; 3 | 4 | use Test::More; 5 | use lib "xt/lib"; 6 | use Util; 7 | 8 | subtest exclude => sub { 9 | my $guard = tempd; 10 | spew "use Hoge1; use File::pushd;" => "hello.pl"; 11 | spew_pm "Hoge1", "lib"; 12 | system("cpanm", "-nq", "--reinstall", "-Llocal", "File::pushd") == 0 or die; 13 | system("cpanm", "-nq", "--reinstall", "-Llocal", "Capture::Tiny") == 0 or die; 14 | 15 | subtest basic => sub { 16 | run "hello.pl", "--exclude", "Capture::Tiny"; 17 | ok -f "hello.fatpack.pl"; 18 | ok contains("hello.fatpack.pl", "Hoge1"); 19 | ok contains("hello.fatpack.pl", "File::pushd"); 20 | ok !contains("hello.fatpack.pl", "Capture::Tiny"); 21 | }; 22 | 23 | subtest abs_path => sub { 24 | my $r = run "hello.pl", 25 | "-d", "$guard/local", 26 | "-e", "Capture::Tiny", 27 | "-o", "abs_out"; 28 | unlike $r->err, qr/WARN/; 29 | ok !contains("abs_out", "Capture::Tiny"); 30 | }; 31 | 32 | subtest relative_path => sub { 33 | mkdir "test"; 34 | my $guard = pushd "test"; 35 | my $r = run "../hello.pl", 36 | "-d", "../local", 37 | "-e", "Capture::Tiny", 38 | "-o", "relative_out"; 39 | unlike $r->err, qr/WARN/; 40 | ok !contains("relative_out", "Capture::Tiny"); 41 | }; 42 | }; 43 | 44 | subtest shebang => sub { 45 | my $guard = tempd; 46 | spew <<'...' => 'no_shebang'; 47 | 1; 48 | ... 49 | spew <<'...' => 'shebang'; 50 | #!/usr/bin/perl 51 | 1; 52 | ... 53 | spew <<'...' => 'multi_shebang'; 54 | #!/bin/sh 55 | exec perl -x $0 "$@" 56 | #!perl 57 | 1; 58 | ... 59 | run "no_shebang"; 60 | run "shebang"; 61 | run "multi_shebang"; 62 | 63 | my $fatpack_line = '# This chunk of stuff was generated by App::FatPacker. To find the original'; 64 | 65 | my @lines; 66 | @lines = split /\n/, slurp "no_shebang.fatpack"; 67 | is $lines[0], ''; # make sense? 68 | is $lines[1], $fatpack_line; 69 | 70 | @lines = split /\n/, slurp 'shebang.fatpack'; 71 | is $lines[0], '#!/usr/bin/perl'; 72 | is $lines[1], ''; 73 | is $lines[2], $fatpack_line; 74 | 75 | @lines = split /\n/, slurp 'multi_shebang.fatpack'; 76 | is $lines[0], '#!/bin/sh'; 77 | is $lines[1], 'exec perl -x $0 "$@"'; 78 | is $lines[2], '#!perl'; 79 | is $lines[3], ''; 80 | is $lines[4], $fatpack_line; 81 | }; 82 | 83 | subtest custom_shebang => sub { 84 | my $guard = tempd; 85 | spew <<'...' => 'no_shebang'; 86 | 1; 87 | ... 88 | spew <<'...' => 'shebang'; 89 | #!/usr/bin/perl 90 | 1; 91 | ... 92 | spew <<'...' => 'multi_shebang'; 93 | #!/bin/sh 94 | exec perl -x $0 "$@" 95 | #!perl 96 | 1; 97 | ... 98 | my $custom_shebang = <<'...'; 99 | #!/bin/sh 100 | exec perl -x $0 "$@" 101 | #!perl 102 | ... 103 | run '--shebang', $custom_shebang, "no_shebang"; 104 | run '--shebang', $custom_shebang, "shebang"; 105 | run '--shebang', '#!/usr/bin/env perl', "multi_shebang"; 106 | 107 | my $fatpack_line = '# This chunk of stuff was generated by App::FatPacker. To find the original'; 108 | 109 | my @lines; 110 | @lines = split /\n/, slurp "no_shebang.fatpack"; 111 | is $lines[0], '#!/bin/sh'; 112 | is $lines[1], 'exec perl -x $0 "$@"'; 113 | is $lines[2], '#!perl'; 114 | is $lines[3], ''; 115 | is $lines[4], $fatpack_line; 116 | 117 | @lines = split /\n/, slurp 'shebang.fatpack'; 118 | is $lines[0], '#!/bin/sh'; 119 | is $lines[1], 'exec perl -x $0 "$@"'; 120 | is $lines[2], '#!perl'; 121 | is $lines[3], ''; 122 | is $lines[4], $fatpack_line; 123 | 124 | @lines = split /\n/, slurp 'multi_shebang.fatpack'; 125 | is $lines[0], '#!/usr/bin/env perl'; 126 | is $lines[1], $fatpack_line; 127 | }; 128 | 129 | done_testing; 130 | -------------------------------------------------------------------------------- /xt/lib/Util.pm: -------------------------------------------------------------------------------- 1 | package Util; 2 | use v5.16; 3 | use warnings; 4 | 5 | use Capture::Tiny qw(capture); 6 | use Cwd 'abs_path'; 7 | use Exporter 'import'; 8 | use File::Basename 'dirname'; 9 | use File::Path 'mkpath'; 10 | use File::Spec; 11 | use File::pushd qw(pushd tempd); 12 | 13 | our @EXPORT = qw(run spew spew_pm slurp contains pushd tempd); 14 | 15 | my $base = abs_path( File::Spec->catdir( dirname(__FILE__), "..", "..") ); 16 | 17 | package Result { 18 | sub new { 19 | my ($class, $out, $err, $exit) = @_; 20 | bless { exit => $exit, out => $out, err => $err }, $class; 21 | } 22 | sub success { 23 | shift->{exit} == 0; 24 | } 25 | sub out { 26 | my $out = shift->{out}; 27 | wantarray ? ( split /\n/, $out ) : $out; 28 | } 29 | sub err { 30 | my $err = shift->{err}; 31 | wantarray ? ( split /\n/, $err ) : $err; 32 | } 33 | } 34 | 35 | sub run { 36 | my @argv = @_; 37 | my ($out, $err, $exit) = capture { 38 | # your responsibility :-) 39 | # local $ENV{PERL5LIB}; 40 | # local $ENV{PERL5OPT}; 41 | system $^X, "-I$base/lib", "$base/script/fatpack-simple", @argv; 42 | }; 43 | Result->new($out, $err, $exit); 44 | } 45 | 46 | sub spew { 47 | my ($content, $file) = @_; 48 | my $dir = dirname($file); 49 | mkpath $dir unless -d $dir; 50 | open my $fh, ">", $file or die "open $file: $!"; 51 | print {$fh} $content; 52 | } 53 | 54 | sub slurp { 55 | my $file = shift; 56 | open my $fh, "<", $file or die "open $file: $!"; 57 | local $/; <$fh>; 58 | } 59 | 60 | sub spew_pm { 61 | my ($package, $dir) = @_; 62 | my $pm = $package; 63 | $pm =~ s{::}{/}; $pm .= ".pm"; 64 | spew "use $package; 1; # this is comment" => "$dir/$pm"; 65 | } 66 | 67 | sub contains { 68 | my ($file, $package) = @_; 69 | my $content = slurp $file; 70 | my $pm = $package; 71 | $pm =~ s{::}{/}; $pm .= ".pm"; 72 | index( $content, qq(\$fatpacked{"$pm"}) ) != -1; 73 | } 74 | 75 | 1; 76 | --------------------------------------------------------------------------------