=head1 NAME
App::rs - The package manager for RSLinux and the first reference counting CPAN client
=head1 SYNOPSIS
# compile, install, and generate package.
rs compile <tarball>
rs compile <git-directory> <oid>
rs --prepared compile <source-directory> <oid>
# generate package after manual installation.
rs diff <oid>
# install a previously compiled package.
rs patch <path/to/oid.rs>
# remove a package.
rs remove <oid>
# display the package tagged as oid.
rs tag <oid>
# show relative entry in database
rs which <path>
# print a list of installed packages
rs list
# find places where multiple packages tried to install
rs crowded
# install CPAN module A::B::C recursively (i.e. including dependency)
rs install A::B::C
# uninstall CPAN module A::B::C recursively (i.e. including dependency)
rs uninstall A::B::C
# print a list of installed modules directly from you (i.e. not dependency)
rs direct
# show a list of modules that are orphaned (i.e. not referenced by anybody)
rs orphan
# adopt all the orphans and you will never be able to see them again.
rs adopt
=head1 DESCRIPTION
(Please see the section L and
L<my TPF proposal|https://github.com/057a3dd61f99517a3afea0051a49cb27994f94d/rslinux/blob/rs/TPF-proposal.pod>
for my ongoing effort to marry C
RSLinux was born out of desire for freedom. Back in 2012, I was using ArchLinux, as with many distributions at that time, it's switching to systemd, and I would be forced to switch to it if I chose to update. It frustrated me deeply, as I always seek freedom, from a very young age, and I knew from my own experience that no matter how wonderful a thing is, it will become a demon that haunts me once I'm being forced to do it. I made up my mind to create something of my own so that I have complete freedom to choose how it would be.
At first, I got my hand dirty with LFS, succeeded and got pretty satisfied with it. Later in 2013, I made it again without following the LFS book, I tried a different bootstrapping process with what I thought was right and necessary, and it fits my mind much better. I typically rebuild my system on an annual basis, after I did it in 2014 I gradually realized its problem, without a package manager, thus an easy way to remove installed package, I tended to dislike denpendency, and prefer a minimalist system, which prevented me to explore since I knew I would have no easy way to clean up the mess after I installed a lot of things, experimented with them a bit, and then decided that I don't want them anymore.
I knew it was bad, and something to be dealt with. In the end of 2015, I
was working on something that's recursive, and it inspired me to
write a simple and elegant package manager B
B
This serialized difference is what B
Being someone who came from LFS, I knew this is a game changer, it gave me a
complete new experience, besides the ability to explore without any hesitation,
I could easily upgrade, or switch between multiple versions of package;
I could now compile once on desktop, and then install the compiled package
on laptop, or vps; I could select a few packages, patch them, and then make
a bootable usb disk or cdrom, or a complete environment that's suitable to
put into a container and run web service. I sincerely believe anyone who
likes LFS will like it, and anyone who likes the freedom of LFS but hated
the inconvenience will like it also, since B
RSLinux is a Linux distribution, but not necessarily so, it's a way of doing
things more. You do not need to take a full commitment using it as a
distribution, there're almost always packages that you care about more and
want to follow closely, while other people haven't packaged it for you,
B
Till this day, I still haven't tried systemd once, I don't know one single
objective reason why I don't use it, but it's true enough that it's the
very first motivation that got all these things started. I guess that's just
how the world is, few things are objective while basically everything is
subjective. Nevertheless, the goal of B
Still, RSLinux will never be easier than a classic distribution where other
people do everything for you, but there're still many things to do and
improve, and I do think in the long run the effort will be negligible
and the reword will be immense. If you never tried LFS or something like
it before, I suggest you use B
=head1 OPTIONS
=over 4
=item * --root=
Specify the directory in which B
=item * --db=
Specify the database where all the metadata of the files and directories
in C
=item * --pool=
The direcory where a generated package will be stored during a C
=item * --prefix=
Definitely the most used compiling option, all packages use it somewhere somehow during the compiling process. Defaults to the directory specified by C<--root>.
=item * --compile-as=
Typically you need to run as root if you want to install a package globally
into the system directory, however most packages recommend compiling as
a non-privileged user and few even make it mandatory. If you specify this
option, and you're running as root, B
=item * --compile-in=
The directory to change into when compiling, if you use it with C<--compile-as> make sure the directory is writable by that user.
=item * --build=
Building instructions, see L.
=item * --ign=
This is the file that specifies which directory/file should be ignored when doing
a C
=item * --profile=
Since many options are used everytime, it would be really tedious to type them
out each time you run B
Not surprisingly, options in the command line take precedence over the ones in a profile.
=item * --package=
B
=item * --subtree=
Typically when you install a package using C
=item * --prepared
If you pass a directory as arugument to C
=item * --branch=
Checkout this branch or tag when compiling from a git directory. By default
B
=item * --bootstrap
Let B
=item * --jobs=
How many parallel jobs should be used during C
=item * --no-rm
By default B
=item * --dry
Tell the C
=item * --soft
Used with C
=item * --refdb=
The database that connects all the packages together, it's the core data structure used for managing CPAN modules. Currently it uses JSON as its format.
=item * --latest
This option applies to the C
=item * --version=
Specify the minimum version requirement for the CPAN module to be installed so that it will be updated if it's already installed but failed to satisfy the requirement.
=back
Note that all options should be specified before any command.
In the following text sometimes I refer to the value of an option as
the name of the option with the preceding C<--> removed, like C
=head1 COMMANDS
=over 4
=item diff
The C
You can choose anything you want as C
If the C
If the option C
=item compile
The C
The compiling instructions are taken from the L configuration file
with the entry associated with the package name. The package name could
be set explicitly by the C<--package> option, or more commonly it's derived
from C
There're three types of compile commands, compile from a tarball, a git directory, or a prepared source tree.
=over 4
=item * compile
B
=item * [--branch=
B
=item * --prepared compile
B
=back
The C
=item patch
C
Optionally, one or more C<--subtree> could be provided so that only part of
the package is installed, for example, C<--subtree=bin/> will instruct B
=item remove
C
Sometimes, different packages install files into the same location. B
=item tag
C
=item which
Takes an absolute path or a path that's relative to the C
=item list
Print a full list of installed packages, sorted from the most recent to the least.
=item crowded
Find out the crowded places, where more than one package likes to reside, that's useful if you want a file from a specific package, and also to discover accidental overwrite.
=back
=head1 CONFIGURATION FILES
(Note I intentionally blur the difference between things like a hash and a hash reference in the following text, since it's easier to type, and also to comprehend for non-Perl speakers, Perl speakers should always know what I'm talking about.)
All configuration files are evaluated using Perl's C
You don't necessarily have to know Perl to write the configuration files,
you could just write them in JSON with the C<:> separator substituted
as C<< => >>. That being said knowing a bit of Perl surely will help
you use B
See also the released VM image to have a look at some sane configuration files and get you started.
=over 4
=item profile
This is a configuration file which collects options that you always need to specifiy. The keys of the hash are option names while the values are, well, corresponding values. A typical profile looks like:
{db => '<file>',
build => '<file>',
ign => '<file>',
pool => '<dir>',
'compile-as' => '<user>',
'compile-in' => '<dir>',
root => '<dir>',
jobs => <number>}
=item build
This file specifies the building instructions, it's only used by the
C
For many packages the build instruction is exactly the same, you could alias the build instruction of a package to another one by setting it to the name of the other package.
As previous mentioned, instead of a hash, the C
The build process is divided into several steps:
=over 4
=item 1. pre-configure
If C
Usually something like C
=item 2. configure
Unless there's a true value in the C
B key to start C
=item 3. post-configure
Like C
=item 4. make
Unless C
=item 5. post-make
The value of C
=item 6. make install
B
=item 7. post-make-install
The value of C
=back
An example C
{gmp => {'post-make' => 'make check'},
mpfr => 'gmp',
'man-pages' => {'no-configure' => 1,
'no-make' => 1},
ncurses => {switch => [qw/--with-shared --without-debug/]},
'XML-Parser' => {'no-configure' => 1,
'post-configure' => 'perl Makefile.PL',
'post-make' => 'make test'},
git => {'make-parameter' => [qw/all doc/],
'make-install-parameter' => [qw/install-doc install-html/]}}
=item ignore
This is typically used when you're installing into a system-wide location,
you certainly would not want to include the content of C, C
into your package during a C
If you want to ignore a file/directory completely, at the top level, add a hash entry with the name as the key and C<1> as the value. For a directory, you may want to be more specific, like ignore only part of it while care for the rest, then you should make the value a hash to specify what should be ignored under this directory, and if some of sub-directories should also be partially ignored then you nest a hash inside again. So yeah, it's recursive and like a tree, naturally.
Suppose you want to ignore C and C completely,
C
{proc => 1,
sys => 1,
etc => {'resolv.conf' => 1,
hosts => 1}}
=back
=head1 ADVANCED
=head2 AMEND
You may find that you forgot to install something, or you installed more than
you should from a package, the process of fixing all that up is called I
In the description of the C
In fact, I never encountered any package that removes files during a
C
But there're indeed sometimes you installed more than you should and you
want to remove things you don't want from a package, well, first you should
C
=head3 Amend by soft C
In comparison with amending by C
First, you do a soft C
Since it relies on the filesystem to generate package, if some of its files
are overwritten by others, then they're lost, it may very well be what you
want, or not, you could always do the C
=head2 UPGRADE
If a package is not essential to build itself it's really easy to upgrade
it, just C
The problem is that usually C
So, you have to make sure that no other process is accessing a file when
when you overwrite it, which is impossible for C
In summary, always remove a package before install a new version of it by
compiling from source, usually you don't want to overwrite files unless
you're absolutely sure no one is using them. And use the toolchain to
build the package if the package requires itself to do C
=head2 INSTALLATION
=over 4
=item 1. No installation at all
With the advancing with various namespaces, this kind of installation actually makes perfect sense, you could boot and live with your favorite distribution while entering RSLinux in isolated namespaces for exploration. Since VM images are used for release it's very easy to do so by mounting the image directly.
=item 2. Live replace
You could do installation by simply swap directories under your current root and the ones under your newly prepared system, what you need is a third environment to do the actual swap, so that you are safe since everything under the main system will be unavailable during moving.
The third environment doesn't need to be large, just C
This method is the best option to install RSLinux on a system that's already running Linux, and probably the only option to install it on a OpenVZ based VPS.
=item 3. Bootable media
If a system is not running Linux already, you cannot use the live replace method to install RSLinux, you have to use a bootable media like USB disk or CDROM.
A USB disk is handy to do installation locally while a CDROM image is
suitable to install remotely on a KVM based VPS. For both situations
the most important utilities to include are probably the ones to do
disk partition and filesystem formatting, for remote installation, it's
best to make the CDROM image as small as possible and transfer all the
packages to be installed via network at some later point since it's much easier
to re-upload the image if you forgot to C
=back
=head3 A faithful recording of live replace installation on a OpenVZ based VPS
I now have a complete RSLinux system inside a directory on my VPS, I have already entered it several times and I'm confident that it's good, and the next step is to swap it with the current distribution.
Since it's a VPS I must login remotely, so in addition to C
Well, apparently C
Finally, I did a login through the C
So yeah, the previously mentioned eight packages are guaranteed to do a successful live replacing installation, and I'm sure you can reduce the number even more if you want. It surely is an exicting, adventurous, and fruitful journey for me, and it's not that hard, so don't hesitate to give it a try.
=head3 A faithful recording of CDROM installation on a KVM based VPS
The first step is of course making a list of the packages that I need,
since this is a KVM based VPS I need to do disk partition, so C
That's everything I need directly, but since it's expected to boot from
this environment, a init system, kernel modules, C
Now the dependencies, C
So I C
And with all these preparations done the rest was really easy and smooth, I
uploaded the iso file and booted the VPS, did disk partition first, formatted
the filesystems after that, and then installed the bootloader, finally tranferred
the root filesystem tarball using C
=head1 PERFORMANCE
B
=head1 CONTRIBUTING
Try it! Download the VM image and play around with it, share your thoughts, make suggestions or reporting bugs. Spread the word around if you find it good or useful.
At some later point you may want to have a look at the guts of B
You can also contribute by hiring me or help getting me hired, if you find me appropriate for a job, a stable living for the author is surely inevitable for a healthy project.
Support me during the TPF granting process, it will find me the necessary
time and resource to work on C
=head1 VM image
A VM image to be used with C
You should first decompress the image using C<xz -d>, then launch it via:
# qemu-system-x86_64 -machine accel=kvm -hda vm.img -m 512M -net nic -net user,hostfwd=::2222-:2222
A C
For simplicity, I used a Perl one liner as the init system, it's a poor
man's init but it does the job, it starts twelve virtual consoles from
C
The B
You could also mount the image directly using:
# mount -o offset=$((2048*512)) vm.img mountpoint
And then enter the mountpoint and use it without C
=head1 BUILDING
Just follow the usual idiom to build a Perl module:
# perl Makefile.PL
# make
# make install
That will install B
# perl Makefile.PL INSTALL_BASE=/path/to/prefix
The executable will reside in the C
Note that since C
=head1 CPAN
I recently extended C
By default, modules will be installed into the C
The only thing you have to do is setting your C
# CPAN module A::B::C will be installed along with all its dependency.
$ rs install A::B::C
# CPAN module A::B::C will be uninstalled along with all its dependency,
# so that the rs-cpan directory will be completely empty.
$ rs uninstall A::B::C
# CPAN module A::B::C will be immediately restored from the binary packages
# generated during the first install.
$ rs install A::B::C
Please see my TPF proposal for more information on the current state, plans, caveats, etc., I will merge it back here once the granting process finishes.
=head2 CPAN COMMANDS
=over 4
=item install
C
=item uninstall
C
=item direct
Print a list of modules that're directly installed by you, in comparison to
the C command where every installed module will be printed.
=item orphan
Show which module has become an orphan, i.e. a module that's neither directly
installed by you nor a dependency of another module. For example, if you only
installed one module using B
=item adopt
Adopt all the orphans, binary packages of them and their entries in the reference counting database will all be removed, there will be no sign that they ever existed once this command finishes. A typical pattern would be:
# Module A::B::C looks interesting, install it and have a try.
$ rs install A::B::C
# Don't want it anymore.
$ rs uninstall A::B::C
# There will be absolutely no sign that module A::B::C is ever installed.
$ rs adopt
=back
The not CPAN specific commands L L L L
are still very useful when using B
=head1 SEE ALSO
A short L<video|https://www.youtube.com/watch?v=QtMcbqtivOU> introduction to App::rs as CPAN client.
=head1 LICENSE
The package manager B
=head1 AUTHOR
Yang Bo yb@rslinux.fun
=cut