NAME
App::rs - The package manager for RSLinux and the first reference counting CPAN client
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
DESCRIPTION
(Please see the section "CPAN" and my TPF proposal for my ongoing effort to marry App::rs
and CPAN.)
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 rs, since directory and files, which a package manager deals everyday, recursiveness is in their nature.
rs keeps a database of the metadata of every file/directory that you didn't ask it to ignore, you will typically ask it to ignore something like /tmp
, /proc
, etc., if you're using it to manage system wide packages. With rs you compile and install a package from source as usual, and when the installation process is done, you run rs diff oid
, rs then starts a scan of the root directory into which you just installed your package, and during the scan process, it compares what's actually there with the database, calculate the difference between them as well as updating the database, and when the scan process ends, the difference is then tagged as oid
in the database, serialized and stored as oid.rs
, and the database is saved as well.
This serialized difference is what rs considers as a package, and it could be transferred across machines and installed using rs patch
, it's very much like a tarball, but I could not just use a tarball since I need to maintain all these metadata in the database when patching, instead of parsing a tarball I thought I might just use a trivial binary format that integrates well with rs and suits my need.
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 rs eliminates ninety percent of the inconvenience yet without sacrificing even a tiny bit of the freedom.
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, rs is a perfect choice for this, you could use rs to properly manage packages somewhere inside your home directory while still using your favorite distribution.
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 rs is to avoid all these subjective feelings and views on how a distribution should be made, which init system should be used, what configure switches, compiling flags should be passed, whether stable version should be preferred over bleeding edge version or the other way around, how a filesystem hierarchy should be laid out. Whatever you feel is right, you just go for it, and what rs does is to make this process easier. Since the packaging by diff
method is general, it works with every single package with no exception, you don't need any tweak for an individual package, thus most packages need zero configuration, and all the build instructions I used to build a distribution that I use everyday are only literally one hundred lines long.
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 rs to manage a couple of packages user wide while retain your distribution untouched, once you get your way around it, then maybe consider to jump on the ship, there's nothing to be afraid of.
OPTIONS
--root=<dir>
Specify the directory in which rs will operate, it will scan this directory for newly installed files during a
diff
operation, and will put or remove files under it during apatch
,remove
operation respectively.--db=<file>
Specify the database where all the metadata of the files and directories in
root
is stored. If it doesn't exist yet rs will create an empty one for you. But you should always specifiy it since it's used by all of the commands.--pool=<dir>
The direcory where a generated package will be stored during a
diff
command. It's also occasionally used when youremove
a package, see the "remove" command for more detail.--prefix=<dir>
Definitely the most used compiling option, all packages use it somewhere somehow during the compiling process. Defaults to the directory specified by
--root
.--compile-as=<user>
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, rs will switch to the user specified when compiling.
--compile-in=<dir>
The directory to change into when compiling, if you use it with
--compile-as
make sure the directory is writable by that user.--build=<file>
Building instructions, see "build".
--ign=<file>
This is the file that specifies which directory/file should be ignored when doing a
diff
, see "ignore".--profile=<file>
Since many options are used everytime, it would be really tedious to type them out each time you run rs, a profile allows you to collect these options into a file so that you do not have to do it everytime, and you could easily switch between multiple profiles. See "profile".
Not surprisingly, options in the command line take precedence over the ones in a profile.
--package=<package name>
rs will try to use the build instructions associated with this package name. Normally you don't have to specifiy this, since it's automatically calculated from
oid
, for example, if you useperl-v5.22.3
asoid
, the package name will beperl
. Nontheless sometimes it could come in handy.--subtree=<relative path>
Typically when you install a package using
rs patch
everything inside it will be installed, this option allows you install only some part of it. You could pass this option multiple times.--prepared
If you pass a directory as arugument to
rs compile
, rs will assume that it's a git directory, use this option if it's a prepared source directory instead.--branch=<branch or tag>
Checkout this branch or tag when compiling from a git directory. By default rs will try to use the
oid
you specified as the branch or tag to checkout.--bootstrap
Let rs know that you're bootstrapping the toolchain, additional flags to set include path, library path, and dynamic interpreter will be passed to related compiling process, so that the final toolchain is self-contained.
--jobs=<number>
How many parallel jobs should be used during
make
.--no-rm
By default rs will ask you if you want to remove the temporary build directory if you're compiling from a tarball or a git directory, if you toggle this option it will not try to remove the build directory.
--dry
Tell the
diff
command to only show the difference, neither gernerate package nor update the database.--soft
Used with
remove
, such that no file/directory will be removed, but the entries in the database will be removed as usual, it's used to do arbitrary amending.--refdb=<file>
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.
--latest
This option applies to the
install
command, so that it will check the CPAN module to be installed and all its recursive dependency for updating.--version=<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.
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 --
removed, like pool
to mean the value of the option --pool
.
COMMANDS
- diff
-
The
diff
command takes one argument,oid
, it traverses the root directory and tag the difference between the content there and what's recorded indb
asoid
, and serializes it asoid.rs
inpool
.You can choose anything you want as
oid
, usually you want to use something meaningful like the package name with the package version appended, such asgcc-6.4.0
.If the
oid.rs
already exists inpool
, the new difference will be merged with the old, this way thediff
command could do limited amending, that's most useful when you forgot to install something, like documentation, you could always install it later and merge with the content you installed previously. See "AMEND" for why amending usingdiff
is limited and how to do arbitrary amending.If the option
dry
is given, the difference will only be displayed, that's handy to check if your system is consistent with what's recorded in the database, the difference should be empty if you didn't do a mannual installation, or you can have a preview of what's installed if you did do that. - compile
-
The
compile
command integrates thediff
andtag
commands to make it easier for you to install a package from source, it automatically compiles and installs a package, then does adiff
command followed by atag
command.The compiling instructions are taken from the "build" configuration file with the entry associated with the package name. The package name could be set explicitly by the
--package
option, or more commonly it's derived fromoid
by using the longest prefix of it before the-
character, for example, withman-pages-4.15
as oid the package name will default toman-pages
, and withperl-v5.22.3
it will beperl
.There're three types of compile commands, compile from a tarball, a git directory, or a prepared source tree.
compile <tarball>
rs will extract, compile, then install the tarball in the direcory
compile-in
, or the current directory if it's not specified. The filename of the tarball, with the extension name like.tar.gz
,.tar.xz
, etc. stripped, is used asoid
to thediff
command. For example, if the tarball isman-pages-4.15.tar.xz
, theoid
will be derived asman-pages-4.15
, justmv
the tarball if you want to change theoid
to something different.[--branch=<branch>] compile <git-directory> <oid>
rs will do a
git clone
from the specified git directory, checkout branch or tag specified by the--branch
option oroid
if absent, incompile-in
, and then compile and install the package.--prepared compile <source-directory> <oid>
rs will
chdir
into the prepared source directory and start the compiling process, thus thecompile-in
directory is ignored in this case. It's useful when you need more complex preparations of the source like applying some patches, or initializing git submodules, etc.
The
compile
command really covers ninety percent of the case, but it may not be flexible enough to compile every package in the wild, but that's actually okay, since you could always do a manual installation followed by adiff
command. - patch
-
patch
takes one argument, a compiled package file <path/to/oid.rs>, which is produced by a previousdiff
command, it then installs the package intoroot
and tag it asoid
.Optionally, one or more
--subtree
could be provided so that only part of the package is installed, for example,--subtree=bin/
will instruct rs to only install anything under thebin
directory of the package. It's also particularly handy to let a file be from a specific package, if there're multiple packages that contain it. - remove
-
remove
takes one argument, theoid
of the package to be removed. rs will remove both the content of the package underroot
and its metadata in the database.Sometimes, different packages install files into the same location. rs takes care of that by recording a list of owners associated with a file, along with the timestamps when ther're installed, that's why you are seeing all the
oid
s floating around the manual, it means owner's id. And when you remove a package, a file is removed if and only if this package is the most recent owner of it, and if it's not, nothing will happen, only the entry in the owner recording list will be removed. On the other hand, if you're removing a package that's indeed the most recent owner of a file, but this file has multiple owners, then the file will be restored to the version of the second most recent owner. That's why I said earlier that the--pool
option is used not only when diffing, but also removing sometimes. Suppose the second most recent owner isoid
, then rs will try to parse the compiled packageoid.rs
inpool
, and restore the file according to it. - tag
-
tag
takes one argumentoid
and displays a list of files which are owned by it, followed by the detailed metadata about them in the database as JSON. - which
-
Takes an absolute path or a path that's relative to the
root
, display its entry in the database, useful to find out to which package a file belongs. - list
-
Print a full list of installed packages, sorted from the most recent to the least.
- 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.
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 do
statement and a hash is expected as the return value, with the exception that the "build" configuration could also return a subroutine.
You don't necessarily have to know Perl to write the configuration files, you could just write them in JSON with the :
separator substituted as =>
. That being said knowing a bit of Perl surely will help you use rs to its best potential, and you don't have to be a Perl expert to write it, so don't be afraid.
See also the released VM image to have a look at some sane configuration files and get you started.
- 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>}
- build
-
This file specifies the building instructions, it's only used by the
compile
command, the keys are package names while the values are hashes that detail the instructions on how the build process should be done. In the following text that explains the build process, you'll often see the value of something, or if something exists, it's talking about this hash.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
build
file could also return a subroutine which will be called with a collection of the options, you could then return the building instructions differently, depending on whether you're bootstrapping or not, for an example.The build process is divided into several steps:
- 1. pre-configure
-
If
pre-configure
exists, the value of it should be a string and rs will try to evaluate it withbash
, before running theconfigure
script.Usually something like
autogen.sh
orbootstrap
is run in this step. - 2. configure
-
Unless there's a true value in the
no-configure
slot, rs will try to run the <configure> script, if it doesn't exist rs will runautoreconf
to make one. A--prefix
switch is always passed, using the value of theprefix
option, along with the value ofswitch
slot, which if exists, should be an array of configure options that should be passed to theconfigure
script.rs will pipe the output of
configure
to the pagerless
, sinceconfigure
usually outputs important information about whether a package is properly configured, you should briefly scroll over the outputs, and exit the pager normally using theq
key to startmake
, after theconfigure
script stopped procuding output, you don't want to startmake
beforeconfigure
finishes. If you find something wrong in theconfigure
outputs, you should typeCtrl-C
to abort the compile process. - 3. post-configure
-
Like
pre-configure
,post-configure
should contain a string to be evaluated bybash
, it will be run after theconfigure
script. It's usually coupled withno-configure
to build packages that don't use aconfigure
script. - 4. make
-
Unless
no-make
is true, rs will runmake
to build the package,make-parameter
could be an array of parameters that should be passed to make, the command line optionjobs
tells how many parallel processes to use. - 5. post-make
-
The value of
post-make
should be a string to be evaluated bybash
if exists, it's run aftermake
is finished, most commonly something likemake check
ormake tests
happens here. - 6. make install
-
rs will run
make install
to install the compiled package, the value ofmake-install-parameter
could be an array of parameters to be passed tomake
. - 7. post-make-install
-
The value of
post-make-install
, if exists, should be a string to be evaluated bybash
, it's run aftermake install
, if you want to make some symbolic links, remove some undesired files after installation, that's the place to go.
An example
build
file:{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/]}}
- ignore
-
This is typically used when you're installing into a system-wide location, you certainly would not want to include the content of
/proc
,/sys
into your package during adiff
command, and this file is where to put it.If you want to ignore a file/directory completely, at the top level, add a hash entry with the name as the key and
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
/proc
and/sys
completely,resolv.conf
andhosts
inside/etc
but not the others, you could write:{proc => 1, sys => 1, etc => {'resolv.conf' => 1, hosts => 1}}
ADVANCED
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 amend.
In the description of the diff
command a brief introduction to amending is included, but it's limited and you could only add or overwrite things. So why is that? You may get the impression now that rs acts more like a version control system than a traditional package manager, while that's true, it's also not a version control system, it expects the packages that it manage to be independent to an extent, i.e. during the installation of a package a file/directory of another package will not suddenly be removed, that's really normal for a vcs since a patch in a vcs is always applied to a previous state, but a patch in rs could always be applied to nothing, much like you could always extract a tarball into an empty directory, in the terminology of git
, that is, a patch in rs doesn't have a parent.
In fact, I never encountered any package that removes files during a make install
, it overwrites files at worst, and rs will handle that well.
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 remove
this package completely, then patch
it using a temporary root
and db
, do whatever you want with this temporary root
using shell commands, file mangager, emacs or whatever you want and then do a diff
with the same root
, an empty db
and a temporary pool
, after that you should move the newly generated rs package into your normal pool
and patch
that with your usual configuration. Yeah, that maybe a little bit complicated, but it rarely happens, just know it could be done and refer to this section again when you find yourself in this kind of situation.
Amend by soft remove
In comparison with amending by diff
, where you could only add or overwrite things, this method allows you do arbitrary amending.
First, you do a soft remove
with the package you want to amend, then you delete or overwrite anything of this package or add things to it, after that remove the compiled package in pool
, finally you run diff
to generate the new modified package.
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 patch diff patch
method mentioned previously.
UPGRADE
If a package is not essential to build itself it's really easy to upgrade it, just remove
it and then install it again, so while it's trivial to upgrade wget or curl, you need more consideration to upgrade glibc.
The problem is that usually make install
uses the command install
to do the installation, and the install
command overwrites a file instead of removing it and create a new one with same name. That's actually pretty different, since overwrite a file while there're still other process accessing it will cause undefined results, but remove a file and create a new one with the same name will not influence any other process that's still accessing the removed file in any way since they're two different files.
So, you have to make sure that no other process is accessing a file when when you overwrite it, which is impossible for make
itself, to say the least, and any program make install
launched when you're overwriting it. Or you have to remove it before make install
but you certainly cannot remove make
since you need make
to do make install
. That's the reason not to throw your toolchain away when you are done bootstrapping, the toolchain resides in a different path and you don't have to worry about it getting overwritten, and it provides a complete environment for building so you could safely remove any package even glibc, while using this environment to build a new one.
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 make install
.
INSTALLATION
- 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.
- 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
bash
andcoreutils
could be enough for the swapping task,patch
a few more packages to help you if you feel unsafe. Then you enter this container with the root directory bind mounted somewhere under it, and start moving things around, also pray that electricity won't be cut while you're doing it.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.
- 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
patch
some vital packages into it, so be sure to include something likesocat
orrsync
oropenssh
forscp
depending on your mood or taste, and of course theiproute2
package and necessary kernel modules to bring up the network.
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 bash
and coreutils
I will patch openssh
in the third sanctuary as well, so that's the list of things I want directly. Now the dependencies, well, definitely base
since it setups the directories that a sane person will always want, and needless to say glibc
, since I always compile bash
with curses so ncurses
as well, and openssl
since that's what openssh
is built upon. So the complete list is base glibc ncurses bash coreutils openssl openssh
. Now I'm going to try and see how it works out.
Well, apparently openssh
needs zlib
as well, that's the only thing I forgot, after patch zlib
I successfully entered this sanctuary with the root directory bind mounted somewhere under it and launched sshd
on a different port, confirmed that I could login through it. Then I did the actual swap, moved everything under root to a backup directory, well, except the usually mounted /proc /sys /dev
, since it's meaningless to umount
them and then mount
later, after that I moved all the directories of the already prepared RSLinux into root, then I entered this fresh root, played around a little bit, launched sshd
and ended the session with the sshd
of the sanctuary.
Finally, I did a login through the sshd
of RSLinux I just launched, cleaned up all the applications of the old system and sanctuary that're still running, and mountpoints related to them. After that I did a rm -rf
on the backup directory and the sanctuary to celebrate, the installation is done!
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.
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 fdisk
from util-linux
is absolutely necessary, and needless to say the mount
command from it, and in order to mount
I have to format it first, so e2fsprogs
as well, and I like syslinux
as the bootloader so include that too. The next thing to consider is how to transfer the compiled packages, I never include them in the iso image since I don't want to upload a big iso file again if I made a mistake, instead they're transferred using network, this immediately implies that iproute2
is required, while there may be some circumstances that you don't need a encrypted connection, but I think I'll just stick to scp
of openssh
, for good practice, and the additional benefit to login via ssh
if the installation is complicated, so add openssh
to list. Also, I definitely want to pack things into a tarball, so put tar
on the list so that I could unpack them later. Finally, bash
and coreutils
of course, they're essential for the commandline.
That's everything I need directly, but since it's expected to boot from this environment, a init system, kernel modules, eudev
, kmod
are also required, I always use my one-liner Perl script as the init system so I will patch perl
as well.
Now the dependencies, openssl zlib
are required for openssh
, ncurses
is required for bash
, and glibc
is required by everybody, and base
for a sane person, so the final list is base glibc ncurses bash coreutils util-linux e2fsprogs syslinux openssl zlib openssh iproute2 perl eudev kmod tar
, now I'am going to patch
them into a temporary directory and make a bootable iso out of it and see how things are going.
So I patch
ed all the packages, copied the kernel and its modules, along with relative isolinux
file and configuration, setup the script to boot, and finally generated the iso using mkisofs
. After that I launched to qemu
to test it, well, I forgot that agetty
will launch the login
program which is from shadow-utils
, and the ip
command will link against libmnl
if available, but that's fine, I patch
ed them and regenerated the iso, did extensive testing on it and became pretty confident that it's solid.
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 scp
and extracted it. I rebooted the VPS and saw a login prompt as a indication of success, the installation is done!
PERFORMANCE
rs is actually pretty efficient, all the serializations routines are written in C
, the first diff
operation will probably take some noticeable time if you're not using a SSD since all the metadata is not yet cached, that's just like the first git status
command inside a repository, but the succesives ones take negligible time. Also note that the diff
operation is only needed on the machine that does the actual compilation, which will usually be the most powerful one you can get your hands on, if you only install pre-compiled packages on a machine that's really just like extracting a tarball, performance is not an issue there.
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 rs, try to add a new functionality or fix an existing problem, I'll always be glad to see a new quality pull request.
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 App::rs
and make it better.
VM image
A VM image to be used with qemu
in raw format is released on github as a demostration of RSLinux, it contains all the neccessary packages to build itself, as well as some basic utilities.
You should first decompress the image using 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 sshd
will be running in the guest and you could login through it using ssh -p 2222 user@localhost
, the password for root is rslinux
, there's also a non-privileged user somebody
with the same password in case you do not like wandering around with root. You could also forget about ssh
all together and use the GUI of qemu
if you happen to like it.
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 tty1
to tty12
but it doesn't restart them, so don't be confused if you logged out but a new login prompt is not displayed, just restart the VT mannually using setsid /sbin/agetty ttyX
. Feel free to change the init system to whatever you like, the whole point of RSLinux is to go for it instead of doing meaningless arguing with others.
The rs profile is already properly written under the home of root
, it's highly recommended to login as root
first, and have a look at how all the configuration files are chained together, and play around a little bit to get familiar with rs. There're two source tarballs, one of emacs
and another of vim
, try compile your favorite editor using rs compile tarball
and see how a package is generated using rs. The rs
directory is the git repository of rs, and the pkg directory contains the compiled packages and database for the VM image. Happy hacking, and remember man rs
is your friend.
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 qemu
, by entering I mean all the methods from unshare
to a full fledged container utility and to a plain chroot
, pick the one you like best.
BUILDING
Just follow the usual idiom to build a Perl module:
# perl Makefile.PL
# make
# make install
That will install rs to your system directory and it's recommended since you do not have to mess around with the PATH or PERL5LIB environment. You could also install to a custom directory by using:
# perl Makefile.PL INSTALL_BASE=/path/to/prefix
The executable will reside in the bin
direcory under prefix and the Perl modules will be in lib/perl5
. Adjust your PATH and PERL5LIB accordingly.
Note that since App::rs
is used to bootstrap both RSLinux and CPAN, it's explicitly designed to have no dependency other than the core Perl modules.
CPAN
I recently extended App::rs
to be the first reference counting CPAN client, by adding a reference counting database to connect each package together.
By default, modules will be installed into the CPAN
directory under your home, and .rs
directory will be used to store metadata about those installed modules. Compilation will happen under the current directory, the build directory of individual module will be removed automatically, but the downloaded source tarballs will be preserved since they may be useful for futher reference. You could use App::rs
without any configuration, but of course all these settings could be customized, if you want to do customization reading the full mannual is highly suggested, it will be worth your while.
The only thing you have to do is setting your PERL5LIB
environment to include <HOME>/CPAN/lib/perl5
, assuming you're using the default configuration, you don't have to do this before doing installation using rs since rs will automatically add them and print a helpful reminder if they're missing during the installation process. Here's some quick usage introduction:
# 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.
CPAN COMMANDS
- install
-
install
accepts the name of a CPAN module (A::B::C) as parameter and installs this module and all its recursive dependency. No installation will be done if this module is already installed, but thedirect
flag will always be set in the database. - uninstall
-
uninstall
takes one argument, the name of the module to be uninstalled, it must be directly installed by you, i.e. not only as a dependency pulled in, if it's still being referenced by another module no uninstallation will be done, but thedirect
flag will still be cleared in the database, otherwise this module will be removed along with its dependency, potentially its dependency's dependency, etc. - direct
-
Print a list of modules that're directly installed by you, in comparison to the
list
command where every installed module will be printed. - 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 rs and later uninstalled it, this module and all of its recursive dependency will become orphans, they're removed from the directory into which CPAN modules are installed, but binary packages of them and their entries in the reference counting database are not deleted, since it allows instant restoration if you later decide to re-install this module, or if you are installing a module that shares dependency with this module.
- 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
The not CPAN specific commands "tag" "which" "list" "crowded" are still very useful when using rs as a CPAN client, please see their description for more information.
SEE ALSO
A short video introduction to App::rs as CPAN client.
LICENSE
The package manager rs as well as the RSLinux VM image are released under GPLv3.
AUTHOR
Yang Bo <rslovers@yandex.com>