fetchware - Fetchware is a package manager for source code distributions.


version 1.016


Manpage synopsis.

    fetchware [-v | --verbose] [-q | --quiet] [-h | -? | --help]
              [-V | --version] <command> [<filenames | paths | Fetchwarfiles>]

Create a new fetchware package.

    fetchware new <name of program>

    ... Read the printed explanations...

    ... And answer the questions fetchware asks you appropriately and then press

Install a new fetchware package.

    fetchware install name-of-program.Fetchwarefile

    # And you can use a .fpkg fetchware package instead of a Fetchwarefile if
    # you have one.
    fetchware install name-of-program.fpkg

Upgrade a specific fetchware package.

    fetchware upgrade <name of already installed program>

    # Use fetchware list to see a list of already installed programs.
    fetchware list

Upgrade all installed fetchware packages.

    fetchware upgrade-all

Uninstall an installed fetchware package.

    # Requires a "uninstall" make target, or customization of its Fetchwarefile
    # to specify what specific C<uninstall_commands> will uninstall this package.
    fetchware uninstall <name of already installed program>

List all installed fetchware packages.

    fetchware list 

    # Pipe to grep if you want to search for something specific.
    fetchware list | grep <something specific>

"Look" inside a fetchware package.

    fetchware look <name-of-program.fpkg> | <name-of-program.Fetchwarefile>

Put this in your /etc/cron.daily to make fetchware check for updates every night

    # Update all already installed fetchware packages.
    fetchware upgrade-all

Or use crontab -e to put this in a user crontab if you don't want to fetchware system wide

    # Check for updates using fetchware every night at 2:30AM.
    # Minute   Hour   Day of Month     Month          Day of Week     Command    
    # (0-59)  (0-23)     (1-31)  (1-12 or Jan-Dec) (0-6 or Sun-Sat)
        30      2          *              *               *           fetchware upgrade-all


While sysadmining I liked to install my own compiled from source versions of popular programs like Apache, MySQL, or Perl without threading. However, doing so means that you have to manually recompile everytime a new security hole comes out, which is annoyingly frequent for Apache. So, fetchware was created to bring the power of package management to source code distributions.


Fetchware is a package manager for source code distributions. It takes advantage of the fact that coincidentially most source code distributions follow the same conventions. Most use FTP and HTTP mirrors. Most use AutoTools or at least just a few commands that you execute in sequence to configure, build, and install the program.

Fetchware harnesses these conventions to create a powerful and flexible package manager for source code distributions. It includes a simple, powerful, and flexible configuration syntax stored in files called Fetchwarefiles. These Fetchwarefiles specify the required mandatory configuration options, program, lookup, mirror, and a method of verifying your program. And they also specify any additional optional configuration options.

To create a new Fetchwarefile to install a source code distribution use the fetchware new command. It will ask you a bunch of questions, and based on your answers and fetchware's assumptions fetchware will automagically create a new Fetchwarefile for you. Then it will ask if you would like fetchware to install it for you.

If your source code distribution exceeds fetchware's new command's capabilities, then see the section "MANUALLY CREATING A App::Fetchware FETCHWAREFILE" in App::Fetchware. It details how to create a Fetchwarefile manually in a text editor of your choice.

Fetchware's commands are described next followed by its options. Following that is the section "HOW FETCHWARE WORKS", which describes in some detail how Fetchware does its magic, and documents how it all fits together.

See App::Fetchware for more information on fetchware's Fetchwarefile syntax:


Each command maps to one operation a package manager can do. install, upgrade, and uninstall. There is also new to create new Fetchwarefiles without bothering with a text editor. And fetchware's way of upgrading all packages with upgrade-all. Fetchware can also list its installed packages with list. And look is similar to Perl's original CPAN client's look command that downloads and unarchives the package, so you can "look" at it. The clean command deletes any unused, leftover temporary files and directories Fetchware has unintentionally left in your system's temporary directory.


    fetchware new <name of program>

new asks you a bunch of questions, and uses the answers you provide in addition to the contents of the directory listing fetchware downloads based on the lookup_url you give fetchware, to create a Fetchwarefile for you with all the mandatory options filled in. It also gives you the opportunity to add any additional options that you may want to use. new also gives you a chance to edit the Fetchwarefile it created for you manually in your editor. Set the EDITOR environment variable to pick which editor to use, or leave it empty, and fetchware will ask you what editor you would like to use.

new finishes by asking if you would like fetchware to go ahead and install the Fetchwarefile it has just created for you. If you say yes, then fetchware will install it, or if you say no, fetchware will skip installing it for you, and print out the path to the Fetchwarefile it just created for you.

You can install that Fetchwarefile later with:

    fetchware install path/to/your/some-program.Fetchwarefile

For more details about fetchware's configuration files Fetchwarefiles see "CREATING A App::Fetchware FETCHWAREFILE" in App::Fetchware


    fetchware install <path to program.Fetchwarefile>

    fetchware install <path to program.fpkg>

install parses the given Fetchwarefile or uses the embeded Fetchwarefile inside the fetchware package you specify. Then install installs your program as you specified in your Fetchwarefile.

By default executes the commands:

1. ./configure
2. make
3. make install

You can use the Fetchwarefile configuration options make_options and configure_options to customize how your program is build and installed. make_options specifies command line options that are added before make is run each time by Fetchware. And configure_options specifies options to the first AutoTools command, ./configure that customizes how your program is built and installed.

    prefix '/usr/local';
    make_options '-j 4';
    configure_options '--enable-mpm --enable-so';

Or, you can use Fetchwarefile's more generic configuraton options. You cannot use both build_options and any of prefix, make_options, configure_options at the same time. build_commands specifies alternate commands to build the program replacing ./configure and make, and you can also specify the install_commands to replace make install with some other command or commands that install your program.

    # build_commands and install_commands Fetchwarefile example.
    build_commands './Configure', 'make';

    install_commands 'make test', 'make install';


See ""App::Fetchware'S FETCHWAREFILE CONFIGURATION OPTIONS" in App::Fetchware for more details on these configuration options.


    fetchware upgrade <already installed fetchware package>

upgrade only upgrades already installed fetchware packages. You cannot upgrade a Fetchwarefile only an already installed fetchware package. To see a list of already installed fetchware packages run fetchware list, or pipe it through grep(1)

    fetchware list | grep <keyword>


    fetchware upgrade-all

upgrade-all takes no arguments. Instead, it loops over the list of installed programs as shown in fetchware list and runs upgrade on each one to upgrade all currently installed programs.


uninstall removes all components of a currently installed program. Afterwards, that program won't show up in a fetchware list anymore.


uninstall is only capable of uninstalling programs that maintain a uninstall make target. For example, ctags has a make uninstall, while Apache does not; therefore, without a prefix, fetchware can uninstall ctags, but it cannot uninstall Apache.

The easiest way to be able to uninstall a program you install with fetchware that does not have a make uninstall is to use the prefix configuration option to use a separate prefix that everything is installed into this directory. Then you could specify a custom uninstall_commands that would delete everything in that directory:

    # Set prefix so apache can be easily uninstalled.
    prefix '/usr/local/apache';

    # Set uninstall_commands to delete everything in the prefix directory when
    # apache is uninstalled.
    uninstall_commands 'rm -r /usr/local/apache';

Then when you uninstall apache, fetchware deletes its associated files, which may include your Web site's Web files, so back them up before hand if you need to keep them.

The other way around this limitation is to use one of the following programs that use a cool LD_PRELOAD trick to watch what files make install or its equivelent copy, and where they are copied to. Then these files are put into some sort of vendor-specific package such as apt-get or rpm.


Run like checkinstall make install will detect what files are copied where during installation, and will create a slackware, debian, or redhat package based on this information.


Provides very similar functionality to fetchware, but lacks fetchware's lookup and verify mechanisms. Includes its own package management functionality.

As far as fetchware one day supporting some sort of hack like checkinstall or paco use, I'm against it. I'd prefer everyone just adding a make uninstall to their Makefiles. But it is on my todo list, and I may add similar functionality in the future, but I'll make no promises. Until then consider using the prefix and uninstall_commands hack.


    fetchware list

    fetchware list | grep <what are you looking for?>

list just prints out the names of all fetchware packages that have been installed. It takes no arguments, and currently does not support listing only packages that match a certain criteria. However, you can just pipe it to grep(1) to using a regex to limit which packages you're looking for.


    fetchware look <package name>

look looks up the specified program using your lookup_url, downloads it, verifies it, and unarchives it. Then it prints out the location of the unarchived program, so you can take a look at its code, or install it manually if you would like to.


    fetchware clean

clean deletes all fetchware temporary files and directories to clean up your system temporary directory.

You can also specify one or more arguments to fetchware clean to specify what directories you want fetchware to search for fetchware's left over temp files to clean up.


Prints out a brief screen full of help messages reminding you of fetchware's command-line syntax.


Fetchware's configuration file options are detailed below.

Most of its options are stored in its configuration file. If none of these options suite what you need fetchware to do, consider using its Fetchwarefile to meet your needs. See ""App::Fetchware'S FETCHWAREFILE CONFIGURATION OPTIONS" in App::Fetchware

-v or --verbose

    fetchware -v install <some-program.Fetchwarefile>

Fetchware's -v or --verbose option turns on verbose logging, which prints to STDOUT additional information regarding what fetchware is doing and how fetchware does it.

If you have any problems with your Fetchwarefile, then you could turn on verbose mode to have fetchware log additional messages to STDOUT to aid in debugging your Fetchwarefile.

-q or --quite

    fetchware -q upgrade <some-program>

The -q or --quite option tells fetchware to not log anything at all. Fetchware will even prevent any commands it runs from printing output to your terminal's STDOUT to avoid cluttering up your screen.

Any warnings or error messages are still printed to STDERR.

To determine if fetchware succeeded or failed you can test its exit status:

    fetchware -q upgrade <some-program>

    echo $?

Fetchware exits 0 for success and non-zero for failure.

-V or --version

Prints out a short message and says what version of fetchware is running.

-h or -? or --help

Prints out a brief screen full of help messages reminding you of fetchware's command-line syntax.


Fetchware works by having fetchware, the bin/fetchware file and App::Fetchware Perl package, do all of the "package manager" stuff:

  • Creating fetchware packages (create_fetchware_package())

  • Copying fetchware packages to the fetchware database (copy_fpkg_to_fpkg_database())

  • Creating and managing the fetchware database (determine_fetchware_package_path(), extract_fetchwarefile(), and fetchware_database_path())

  • uninstalling installed packages from the fetchware database (uninstall_fetchware_package_from_database())

Fetchware delegates all of the specifics on how to install, upgrade, and uninstall the fetchware packages that fetchware manages to App::Fetchware or a App::Fetchware extension:

  • Implement Fetchware's new command's Q&A wizard interface (new() and new_install())

  • Checking Fetchwarefile's high-level syntax before execution (check_syntax())

  • Lookup to see if a new version is available (lookup())

  • Downloading the archive (download())

  • Verifying that the downloaded file is the same one the author uploaded (verify())

  • Unarchiving the package (unarchive())

  • Building and installing it (build() and install())

  • Uninstalling any already installed fetchware package (uninstall())

  • Determining if a newer version is available (upgrade())

  • Some before and after hooks (start() and end()).

How fetchware's commands work

Fetchware's commands work by using fetchware's API, described in the section "INTERNAL LIBRARY SUBROUTINES", to manage the package manager stuff. And fetchware delegates the heavy lifting of the steps needed to install, upgrade, and uninstall fetchware packages to App::Fetchware or a App::Fetchware extension.


new just asks the user a bunch of questions, and gives them an opportunity to answer questions. Then it uses your answers to generate a Fetchwarefile for you, so that you don't have to mess with creating one manually in a text editor.


Fetchware's install runs whatever fetchware API subroutines it needs to use, see the section "INTERNAL LIBRARY SUBROUTINES" for more. Then, install() will parse a user provided Fetchwarefile or a Fetchwarefile fetchware finds in a fetchware package. The act of parsing the Fetchwarefile will import the App::Fetchware API subroutines into fetchware's namespace. This gives fetchware access to App::Fetchwares API or whatever extension may have been used. Then, the API subroutines are run providing whatever arguments they need and storing whatever their important return values may be in a variable to probably later be given to a later API subroutine as an argument.


Cleverly reusues the same API subroutines that install uses, but in the middle of all that uses the upgrade() API subroutine to determine if a newer version is available. The upgrade() API subroutine allows Fetchware extensions to modify how Fetcwhare determines if a new version is available to support using git or something else to determine this.


Uninstall parses the Fetcwharefile of the installed pacakges you specified. Then it runs whatever uninstall_commands you specified or the default, make uninstall if you specified none. Then the installed package is deleted from the fetchware database.


List just globs all files in the fetchware database directory as returned by fetchware_database_path(), and prints them to STDOUT. It does not let you specify a Perl regex, or a keyword or anything yet, because I'm currently unsure about the security ramifications of doing so. This feature may be added in the future.


look just does the first part of install(). It parses whatever Fetchwarefile it gets passed to it, then it does the start(), lookup(), download(), verify(), and unarchive() parts of install(). Then look prints the path of this directory, and exits.


Clean just deletes all fetchware temp files and directories in the system temp_dir. These files and directories all start with fetchware-* or Fetchwarefile-*.


Just prints a simple, short, concise help message.

How fetchware interfaces with App::Fetchware

Fetchware interfaces with App::Fetchware using the parse_fetchwarefile() API subroutine. This subroutine simply eval()'s your Fetchwarefile and traps any errors, and then rethrows that exception adding a helpful message about what happened in addition to passing along the original problem from Perl.

The act of eval()ing your Fetchwarefile causes Perl to parse and execute as it would any other Perl program. Only because its inside an eval any subroutines that are imported are imported in the the caller of eval()'s package. In this case fetchware.

Fetchware takes advantage of this by requiring all Fetchwarefile's to have a use App::Fetchware...; line. This line is what imports the default imports of App::Fetchware into fetchware, which include App::Fetchware's API subroutines.

How fetchware intefaces with a fetchware extension

As explained above parse_fetchwarefile() eval()'s your Fetchwarefile, and this causes Perl to parse and execute it. And any imports are imported into the caller's package, which is fetchware.

That's how fetchware receives App::Fetchware's API subroutines, and it is also how fetchware receives a fetchware extensions API subroutines, the fetchware extension is simply use()d inside your Fetchwarefile instead of the default one of App::Fetchware. Instead of:

    use App::Fetchware;

You would write:

    use App::FetchwareX::HTMLPageSync;

To use the fetchware extension HTMLPageSync.


Below are all of subroutines that implement fetchware's main command line options such as fetchware install or fetchware new and so on. These main subroutines are called based on the options you pass to fetchware from the command line.


    my $installed_fetchware_package_path = cmd_install($filename|@ARGV)

cmd_install() implements fetchware's install command, which installs a package based on the specified Fetchwarefile or fetchware package.


    my $uninstall_package_path = cmd_uninstall($uninstall_package_path|@ARGV);

Uninstalls the given package. Note the given package does not have to be an exact match, but it does have to be unique if you have two versions of the same software installed such as httpd-2.2 and httpd-2.4. In that case you'd have to specify the version number as well.


cmd_uninstall() unlike cmd_install() does not accept Fetchwarefiles as an argument to uninstall a fetchware package! Instead, you must provide the name and perhaps the name and version number of an already installed software package. For a list of such package names just run fetchware list to list all installed fetchware packages.


cmd_uninstall() does not call drop_privs() to drop privileges, because it needs root privileges to copy the installed fetchware package from the system level fetchware package database, and it needs root to actually be able to delete files in system level directories.


    my $fetchware_package_path = cmd_new($program_name);

cmd_new() implements fetchware's new command. See "CREATING A App::Fetchware FETCHWAREFILE" in App::Fetchware for detailed documentation for the specifics of the new command. This chunk of POD is about its implementation. cmd_new() calls the new() and new_install() App::Fetchware API subroutines, which in turn call a bunch of helper subroutines that implement the algorithm fetchware uses to build new Fetchwarefiles automagically for the user. The algorithm is dead stupid:

1. Ask for lookup_url & download it.
2. Analyze the contents of the output from the lookup_url.
3. Build the Fetchwarefile according to the output.
4. Ask other questions as needed.

cmd_new() uses Term::UI, which in turn uses Term::ReadLine to implement the character based question and anwser wizard interface.

cmd_new() also asks the user if they would like fetchware to build and install their new program based on their newly created Fetchwarefile. If they answer yes, it builds and installs it, and if not, cmd_new() returns the path to the created Fetchwarefile for them.


    my $installed_fetchware_package_path = cmd_upgrade($upgrade_name);
    'No upgrade needed.' = cmd_upgrade($upgrade_name);

Subroutine implementing Fetchware's upgrade command. This subroutine and command upgrade one and only one package that must be specified on the command line as well.


    my @upgraded_packages = cmd_upgrade_all();
    'No upgrade needed.' = cmd_upgrade_all();

Implements the fetchware upgrade-all command, which upgrades all installed packages simply by looping over the fetchware database and running cmd_upgrade() on each one.

Returns a list of the packages that were upgraded or the string 'No upgrade needed.' if no packages were upgraded.


    my $look_path = cmd_look($filename);

Looks up the latest version of the specified Fetchwarefile or fetchware package, and downloads, verifies, and unarchives the specified source code distribution, and then prints out the location of this archive.


cmd_look() unarchive's the desired source code distribution into the same sort of temporary directory that fetchware itself uses during regular installs or upgrades. This cannot be changed, but after fetchware creates this directory it outputs its path, so that you can cd to it, and do whatever you need to it. You could also move it to where you want it to be as well. Remember to delete the fetchware-$PID-randomeletters style directory that it was stored in, or just run fetchware clean when you are finished working with it.



Lists all of the packages fetchware has stored in its fetchware_database_path().


There is no ability to limit this listing with a regex currently, so just pipe it to grep for now. Obviously in the future this ability could be added, but I'm currently unclear about its security ramifications. So for now, I'll hold out until I study what ack does.



cmd_clean() implements fetchware's clean command, which deletes any left over fetchware temporary directories from your system's temorary directory. It cleverly uses locking to ensure that cmd_clean() does not delete a temporary directory that is still being used by a running fetchware process.

cmd_clean() also deletes any temporary files that Fetchware uses that are regular files not directories. These start with either fetchware-* or Fetchwarefile-* for Fetchwarefiles cmd_new() creates for the user.

flock() is used along with LOCK_{EX,NB} from Fcntl. LOCK_EX gets an exclusive lock (only current process who got lock can access the file, and LOCK_NB, which does a non-blocking attempt to get a lock returning success at getting the lock or not getting the lock immediately. flock() is used on a semaphore file called fetchware.sem it is a useless empty file, that is only used for locking each fetchware temporary directory.

flock() is used, because if the fetchware process using the lock closes the file or the process dies, exits itself, or is killed even sith SIGKILL, the lock is released automatically by the OS and/or system libraries.

cmd_clean() simply attempts to get a lock, and if it does it deletes that particular fetchware temporary directory. If it fails to get the exclusive lock, then it probably means that that fetchware temporary directory is still being used by another fetchware process, so that directory is skipped.

create_tempdir() and cleanup_tempdir() create and lock the fetchware semaphore lock file, and close and unlock it as they are executed by start() and end().

cmd_clean() via @ARGV, which run() calls it with, takes the arguments it receives as paths to whatever temporary directories it should clean.



Prints a help message to STDOUT listing usage, all command options, and examples.

And then exit()s with an exit status of 0 indicating success.


Below are the helper subroutines used by install(), uninstall(), new(), and so on.


    'Evaled config file successfully' = parse_fetchwarefile(\$fetchwarefile);

Eval's the \$fetchwarefile to effectively "parse" it.

The only checking for the $fetchwarefile it does is that it is a scalar ref, and that it has at least one line beginning with use App::Fetchware.

It also checks to see that the eval of the provided $fetchwarefile actually winds up importing all of fetchware's API subroutines into fetchware's namespace.

Then it runs check_syntax() to check the $fetchwarefile's syntax. Typically this only involves running config() a bunch of times to check that configuration options that don't belong together arn't used together.

Returns true on success and dies with an error message if it fails.


    # Most uses should just use this.
    my $fetchware_package_full_path
        create_fetchware_package($fetchwarefile, $unarchived_package_path);

    # But some uses in test suites thanks to safe_open() need to be able to
    # specify where they should write the new fetchware package's path to.
    my $fetchware_package_full_path

Creates a fetchware package, ending in .fpkg, using $unarchived_package_path, as the directory to archive. Also, adds the Fetchwarefile stored in the scalar $fetchwarefile argument to the fethware package that is created.

You can specify an optional $path_to_new_fpkg, which will be a directory where create_fetchware_package() will write the new fetchware package to.

Returns the full pathname to the fetchware package that was created.


    my $fetchware_database_path = fetchware_database_path();

Returns the correct path for the fetchware package database based on operating system and if super user or not.

Also, supports user customizable fetchware database paths via the FETCHWARE_DATABASE_PATH environment variable, and the fetchware_database_path Fetchwarefile configuration file. If both are specified fetchware_database_path is prefered over FETCHWARE_DATABASE_PATH.


    my $fetchware_package_filename = determine_fetchware_package_path($fetchware_package);

Looks up the $fetchware_package in fetchware_database_path(), and returns the full path to that given $fetchware_package.


    my $fetchwarefile = extract_fetchwarefile($fetchware_package_path);

Extracts out the Fetchwarefile of the provided fetchware package as specified by $fetchware_package_path, and returns the content of the Fetchwarefile as a scalar reference. Throws an exception if it it fails.


    my $fetchware_package_path = copy_fpkg_to_fpkg_database($fetchwarefile_path);

Installs (just copies) the specified fetchware package to the fetchware database, which is /var/log/fetchware on UNIX, C:\FETCHWARE on Windows with root or Administrator. All others are whatever File::HomeDir says. For Unix or Unix-like systems such as linux, File::HomeDir will put your own user fetchware database independent of the system-wide one in /var/log/fetchware in ~/.local/share/Perl/dist/fetchware/. This correctly follows some sort of standard. XDG or FreeDesktop perhaps?

Creates the directory the fetchware database is stored in if it does not already exist.

Returns the full path of the copied fetchware package.



Deletes the specified $uninstall_package_name from the fetchware package database. Throws an exception on error.


Like other package managers, fetchware has its own package format:

  • It ends with a .fpkg file extension.

  • The package path, the location of the unarchived downloaded program, is simply archived again using Archive::Tar, and compressed with gzip.

  • But before the package path is archived the currently used Fetchwarefile is copied into the current directory, so that it is included with your fetchware package:


This simple package format was chosen instead of using a native package format such as a Microsoft .msi package, Slackware format, rpm format, .deb format, and so on. Thanks to distros like Gentoo and Arch, there are even more formats now. Also, each version of BSD has its own package format, and each version of commerical UNIX has its own package format too. ...It was easier to create a new format, then deal with all of the existing ones.

This custom package format is unique, bare bones, and retains all of the power that installing the software from source manaully gives you.

  • Simple, and retains backward compatibility with manual installation.

  • The package format includes the source code, so it can be recompiled if you move the fetchware package to an architecture different than the one it was compiled on.

  • You can specify whatever configure and build options you want, so you're not stuck with whatever your distro's package maintainer has chosen.


How does fetchware's database work?

The design of fetchware's database was copied after Slackware's package database design. In Slackware each package is a file in /var/log/packages, an example: /var/log/packages/coreutils-8.14-x86_64_slack13.37. And inside that file is a list of files, whoose names are the locations of all of the files that this Slackware package installed. This format is really simple and flexible.

Fetchware's database is simply the directory /var/log/fetchware (on Unix when run as root), or whatever File::HomeDir recommends. When packages are installed the final version of that package that ends with .fpkg is copied to your fetchware database path. So after you install apache your fetchware database will look like:

    ls /var/log/fetchware

It's not a real database or anything cool like that. It is simply a directory containting a list of fetchware packages that have been installed. However, this directory is managed by fetchware, and should not be messed with unless you are sure of what you are doing.

What exactly is a fetchware package?

A fetchware package is a gziped tar archive with its file extension changed to .fpkg. This archive consists of the package that was downloaded in addition to your Fetchwarefile. For example.

    tar tvf httpd-2.4.3.fpkg

See the section "THE FETCHWARE PACKAGE" to see all of the cool things you can do with them.


As with the rest of Fetchware, fetchware does not return any error codes; instead, all errors are die()'d if it's fetchware's error, or croak()'d if its the caller's fault.



Fetchware was written on Linux and tested by its author only on Linux. However, it should work on popular Unixes without any changes. But it has not been ported or tested on Windows yet, so it may work, or parts of it may work, but some might not. However, I have used File::Spec and Path::Class to support path and file manipulation accross all Perl-supported platorms, so that code should work on Windows. I intend to add Windows support, and add tests for Windows in the future, but for now it is unsupported, but may work. This is likely to improve in the future.


pkgsrc, paco, porg, slackbuilds, sbopkg, fpm, checkinstall


David Yingling <>


This software is copyright (c) 2016 by David Yingling.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.