Pinto:...utorial(3pm)
π Pinto::Manual::Tutorial β a narrative introduction to Pinto π
okay bestie, buckle UP β this is Pinto::Manual::Tutorial, and it's your cozy lil walkthrough of a Pinto repository. It's a narrative introduction, which is just fancy speak for "we're gonna gossip about the whole thing together."
β¨ VERSION β¨
version 0.14 β that's the vibe. Write it down. π
πΈ INTRODUCTION πΈ
So here's the deal, bestie: this tutorial takes you by the hand through some of the typical use cases for a Pinto repository. Along the way it shows off most of the pinto commands. And like, genuinely β try the commands as you read along. It hits different when you actually run them. π¦
But if you're the type who wants the sparknotes version β a more condensed summary of features and commands β go read Pinto::Manual::QuickStart. And if you need the detailed tea on installing the software, that's Pinto::Manual::Installing. iykyk π
π BASIC OPERATIONS π
π Creating a repository π
Step one, first thing, no skipping: you gotta create a repository. That's the init command, and it looks like this:
pinto --root ~/repo init
This creates a brand new repository in the ~/repo directory. If that directory doesn't exist yet? It gets created for you, bestie, don't even worry. But if it does already exist, then it must be empty. Empty. Like your inbox after a good archive spree. π
The --root option (or -r if you're feeling lazy, which, same) specifies where the repository lives. And heads up: this argument is required for every single pinto command. Every one. But if you get tired of typing it over and over (and you will, let's be real), you can set the PINTO_REPOSITORY_ROOT environment variable to point at your repository instead. Slay.
The repository gets created with a stack called master, and master is also marked as the default stack. We'll gossip about stacks and the default stack later, promise. π
π¦ Inspecting the repository π¦
Now that you've got a repository, let's be nosy and look inside. To see the contents of a repository, you use the list command:
pinto --root ~/repo list
You're gonna use list quite often, fr fr. But right now the listing will be empty, because there is literally nothing in the repository yet. Which is kinda sad. So let's go add something...
π Adding dependencies π
Say we're working on an application called My-App that contains a package called My::App. And say this application also depends on the URI package. Using the pull command, you can bring the URI package into your repository:
pinto --root ~/repo pull URI
You'll get prompted to enter a log message describing why this change is happening. The message template comes with a semi-informative generated message already in there. Feel free to edit it as you see fit β it's your repo, your words. Then save the file and close your editor when you're done. β¨
Now you should have URI in your local repository. So let's look and see what we actually got. Once again: list command, inside the repository:
pinto --root ~/repo list
This time the listing will look something like this:
rf URI 1.60 GAAS/URI-1.60.tar.gz
rf URI::Escape 3.31 GAAS/URI-1.60.tar.gz
rf URI::Heuristic 4.20 GAAS/URI-1.60.tar.gz
...
So you can see the URI package has been added to the repository β plus all the prerequisites for URI, and all of their prerequisites, and so on. It's giving dependency chain. It's giving family reunion. π
π Adding your own distributions π
Now suppose you've finished work on My-App and you're ready to release the first version. Using your preferred build tool (ExtUtils::MakeMaker, Module::Build, Module::Install, etc.) you package a release as My-App-1.0.tar.gz. Now put that distribution into the repository with the add command:
pinto --root ~/repo add path/to/My-App-1.0.tar.gz
When you list the repository contents now, it'll include the My::App package and show you as the author of the distribution:
rl My::App 1.0 JEFF/My-App-1.0.tar.gz
rf URI 1.60 GAAS/URI-1.60.tar.gz
rf URI::Escape 3.31 GAAS/URI-1.60.tar.gz
rf URI::Heuristic 4.20 GAAS/URI-1.60.tar.gz
...
Main character energy, honestly. π«Ά
π Installing packages π
Now the repository contains both your application and all of its prerequisites, so you can install it into your environment using the install command:
pinto --root ~/repo install My::App
When My::App gets installed, it will only use the prerequisites that are in your repository. Even if a newer version of URI gets released to the CPAN in the future, My::App will always be built with the same versions of the same prerequisites that you developed and tested against. This ensures your application builds will be stable and predictable. No surprises. No chaos. Just vibes.
On the surface, a Pinto repository looks like an ordinary CPAN, so you can also install packages from it using cpanm directly. All you gotta do is point them at the URI of your repository. (Under the hood, this is all the install command is really doing anyway.) For example:
cpanm --mirror file:///home/jeff/repo --mirror-only My::App
The --mirror-only flag is important, bestie, don't skip it β it tells cpanm to not use the cpanmetadb to resolve packages. Instead you only want to use the index from your repository. Periodt.
You can do the same thing with cpan and cpanp as well. See their documentation for info on how to set the URI of the repository. π
π₯ Upgrading a dependency π₯
Suppose several weeks have passed since you first released My-App, and now URI version 1.62 is available on the CPAN. It has some critical bug fixes that you'd like to get. Again, we can bring that into the repository using the pull command. But since your repository already contains a version of URI, you must indicate that you want a newer one by specifying the minimum version that you want:
pinto --root ~/repo pull URI~1.62
If you look at the listing again, this time you'll see the newer version of URI (and possibly other packages as well):
rl My::App 1.0 JEFF/My-App-1.0.tar.gz
rf URI 1.62 GAAS/URI-1.62.tar.gz
rf URI::Escape 3.38 GAAS/URI-1.62.tar.gz
rf URI::Heuristic 4.20 GAAS/URI-1.62.tar.gz
...
If the new version of URI requires any new prerequisites, those will be in the repository too. And now when you install My::App, you'll get version 1.62 of URI. Glow up complete. β¨
π WORKING WITH STACKS π
So far in this tutorial we've treated the repository as a singular resource. Which is cute, but. For example, when we upgraded URI in the last section, it impacted every person and every application that might have been using the repository. And that kind of broad impact is... undesirable, bestie. You would prefer to make those kinds of changes in isolation and test them before forcing everyone else to upgrade. This is what stacks are designed for. π
πΈ What is a stack πΈ
All CPAN-like repositories have an index which maps the latest version of each package to the archive that contains it. Usually there's only one such index per repository. But with Pinto? There can be many indexes. Each of these indexes is called a stack. This allows you to create different stacks of dependencies within a single repository. So you could have a development stack and a production stack. Whenever you add a distribution or upgrade a prerequisite, it only affects one stack. Chef's kiss. π©βπ³
β The default stack β
Before getting into the gory details, you first need to know about the default stack. For most operations, the name of the stack is an optional parameter. So if you don't specify a stack explicitly, then the operation gets applied to whichever stack is marked as the default.
In any repository, there is never more than one default stack. When we created this repository, the master stack was marked as the default. You can also change the default stack or change the name of a stack, but we won't go into that here β see the default command to learn more about that. π
Just remember: master is the name of the stack that was created when the repository was first initialized. Write it on your hand. ποΈ
π¦ Creating a stack π¦
Suppose your repository contains version 1.60 of URI, but version 1.62 has been released to the CPAN, just like in the earlier section. You want to try upgrading β but this time you're gonna do it on a separate stack. Fancy.
Thus far, everything you've added or pulled into the repository has gone onto the master stack. You could create an entirely new stack, but master already has the prerequisites for My-App, so we're just gonna make a clone using the copy command:
pinto --root ~/repo copy master uri_upgrade
This creates a new stack called uri_upgrade. If you want to see the contents of that stack, just use the list command with the --stack option:
pinto --root ~/repo list --stack uri_upgrade
The listing should be identical to the master stack:
rl My::App 1.0 JEFF/My-App-1.0.tar.gz
rf URI 1.60 GAAS/URI-1.60.tar.gz
...
Twinning! π
π Upgrading a stack π
Now that you've got a separate stack, you can try upgrading URI. Just as before, you'll use the pull command. But this time you'll tell Pinto that you want the packages pulled onto the uri_upgrade stack:
pinto --root ~/repo pull --stack uri_upgrade URI~1.62
Now let's compare the master and uri_upgrade stacks using the diff command:
pinto --root ~/repo diff master uri_upgrade
+rf URI 1.62 GAAS/URI-1.62.tar.gz
+rf URI::Escape 3.31 GAAS/URI-1.62.tar.gz
+rf URI::Heuristic 4.20 GAAS/URI-1.62.tar.gz
...
-rf URI 1.60 GAAS/URI-1.60.tar.gz
-rf URI::Escape 3.31 GAAS/URI-1.60.tar.gz
-rf URI::Heuristic 4.20 GAAS/URI-1.60.tar.gz
The output is similar to the diff(1) command. Records starting with a + were added, and those starting with a - have been removed. Simple as. π
π Installing from a stack π
With URI upgraded on the uri_upgrade stack, you can now try building and testing our application. All you have to do is run the install command and point to the right stack:
pinto --root ~/repo install --stack uri_upgrade My::App
This will build My::App using only the prerequisites that are on the uri_upgrade stack. If the tests pass, then you can confidently upgrade URI on the dev stack as well. π«Ά
As mentioned earlier, you can also use cpanm to install modules from your repository. But when installing from a stack other than the default, you must append stacks/stack_name to the URI. For example:
cpanm --mirror file:///home/jeff/repo/stacks/uri_upgrade --mirror-only My::App
and that's where we're pausing, bestie β there's more tutorial coming, so don't go anywhere β¨
π USING PINS π
okay so bestie, in the last section we used a stack to experiment with upgrading a dependency. and fortunately, all the tests passed π. but likeβ¦ what if they didn't pass? π
If the problem lies within My-App and you can quickly correct it, you might just modify your code, release version 2.0 of My-App, and then proceed to upgrade URI on the master stack. easy peasy.
But if the issue is a bug in URI, or fixing My-App is gonna take a long time? then you have a real problem. π You do not want someone else to upgrade URI, and you definitely don't want it upgraded inadvertently just to satisfy some other prerequisite that My-App may have. So until the bug is fixed (in either URI or My-App) you need to prevent URI from being upgraded. This is what pins are for. π
π Pinning a package π
When you pin a package, that version of the package is forced to stay in a stack. Any attempt to upgrade it (either directly or via another prerequisite) will fail. no cap. To pin a package, use the pin command like this:
pinto --root ~/repo pin URI
If you look at the listing for the master stack again, you'll see something like this:
...
rl My::App 1.0 JEFF/My-App-1.0.tar.gz
rf! URI 1.60 GAAS/URI-1.60.tar.gz
rf! URI::Escape 3.31 GAAS/URI-1.60.tar.gz
...
The ! near the beginning of the line indicates the package has been pinned. π
And notice β every package in the URI-1.60.tar.gz distribution has been pinned, so it is impossible to partially upgrade a distribution (this situation could happen when a package moves into a different distribution). so iconic, honestly.
ποΈ Unpinning a packages ποΈ
After a while, suppose you fix the problem in My-App, or a new version of URI is released that fixes the bug. When that happens, you can unpin URI from the stack using the unpin command:
pinto --root ~/repo unpin URI
At this point you're free to upgrade URI to the latest version whenever you're ready. π¦ And just as with pinning, when you unpin a package, it unpins every other package in that distribution as well. slay.
β¨ USING PINS AND STACKS TOGETHER β¨
Pins and stacks are used together to help manage change during the development cycle. like, think about it. π§
For example, you could create a stack called prod that contains your known-good dependencies. Likewise, you could create a stack called dev that contains experimental dependencies for your next release. Initially, the dev stack is just a copy of the prod stack.
As development proceeds, you may upgrade or add several packages on the dev stack. If an upgraded package breaks your application, then you'll place a pin in that package on the prod stack to signal that it shouldn't be upgraded. communication, but make it dependency management. π
π©Ή Pins and Patches π©Ή
Sometimes you may find that a new version of a CPAN distribution has a bug but the author is unable or unwilling to fix it (at least not before your next release is due). π In that situation, you may elect to make a local patch of the CPAN distribution.
So suppose that you forked the code for URI and made a local version of the distribution called URI-1.60_PATCHED.tar.gz. You can add it to your repository using the add command:
pinto --root ~/repo add path/to/URI-1.60_PATCHED.tar.gz
In this situation, it is wise to pin the package as well, since you do not want it to be updated until you are sure that the new release includes your patch or the author has fixed the bug by other means.
pinto --root ~/repo pin URI
When the author of URI releases version 1.62 with your patch, you'll want to try it before deciding to unpin from your locally patched version. Just as before, this can be done by cloning the stack with the copy command. Let's call it the trial stack this time:
pinto --root ~/repo copy master trial
But before you can update URI on the trial stack, you'll have to unpin it there:
pinto --root ~/repo unpin --stack trial URI
Now you can proceed to update URI on the stack and try building My::App like this:
pinto --root ~/repo update --stack trial URI
pinto --root ~/repo install --stack trial My::App
If all the tests pass, then you can merge the changes back to the master stack:
pinto --root ~/repo merge trial master
periodt. π β¨
π Reviewing Past Changes π
As you've noticed by now, each command that changes the state of a stack requires a log message to describe it. You can review those messages using the log command:
pinto --root ~/repo log
That should display something like this:
revision 4a62d7ce-245c-45d4-89f8-987080a90112
Date: Mar 15, 2013 1:58:05 PM
User: jeff
Pin GAAS/URI-1.59.tar.gz
Pinning URI because it is not causes our foo.t script to fail
revision 4a62d7ce-245c-45d4-89f8-987080a90112
Date: Mar 15, 2013 1:58:05 PM
User: jeff
Pull GAAS/URI-1.59.tar.gz
URI is required for HTTP support in our application
...
The header for each message shows who made the change and when it happened. It also has a unique identifier similar to Git's SHA-1 digests. You can use these identifiers to see the diffs between different revisions, or to reset the stack back to a prior revision [NB: this feature is not actually implemented yet]. π okay so it's giving aspirational, we love that for it.
π CONCLUSION π
In this tutorial, you've seen the basic pinto commands for pulling dependencies into the repository, and adding your own distributions to the repository. You've also seen how to use stacks and pins to manage your dependencies in the face of some common development obstacles. look at you go, bestie. π
Each command has several options that were not discussed in this tutorial, and there are some commands that were not mentioned here at all. So you are encouraged to explore the manual pages for each command and learn more. go forth, explore, be curious. π₯
π SEE ALSO π
Pinto::Manual::QuickStartPinto::Manual::InstallingPinto(the library)pinto(the application)
βοΈ AUTHOR βοΈ
Jeffrey Ryan Thalhammer <jeff@stratopan.com>
βοΈ COPYRIGHT AND LICENSE βοΈ
This software is copyright (c) 2015 by Jeffrey Ryan Thalhammer.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
and that's a wrap, bestie ππ¦ this was perl v5.40.1, dated 2025-04-21, and it's the Pinto:...utorial(3pm) page. go pin something (responsibly). mwah π
π¦ where this page comes from
- debian trixie: pinto 0.14000-3 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu resolute: pinto 0.14000-3 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms