SlideShare una empresa de Scribd logo
1 de 205
Dependency Management
      With Pinto
      Jeffrey Thalhammer
       thaljef@cpan.org

           YAPC::NA
         June 15, 2012
CPAN Is Heaven
Tens of thousands of
modules for every
purpose imaginable
Lots of ser vices for
testing, bug tracking,
ratings, forums
Awesome tool chain
for building, testing,
installing
CPAN Is Hell
The CPAN is not
stable
Developers
constantly adding
and removing stuff
Sometimes the code
is broken
Tool chain expects
backward
compatibility
Unintended Consequences

Avoiding
dependencies
Avoiding upgrades
Shared resources &
monolithic systems
Unreproducible
environments
Combating The Problem
“Just stash the site_perl directory in the VCS”


Brittle
Not portable
Can’t smoke it
Hard to evolve
Combating The Problem
 “Just stash the distribution tarballs in the VCS”



Slightly less brittle
Portable
Smokable
Still icky
CPAN::Site & CPAN::Mini


• Snapshots     of the CPAN

• Solves    the stability problem

• Still   clunky
More Shops Are Writing CPAN-
            style Dists
• M::B
     and EU::MM more
 commonplace

• Dist::Zilla
          makes the
 development fun

• cpanmmakes the
 deployment easy

• DarkPANs      proliferate
Lots of DarkPAN Tools Emerge


• CPAN::Mini::Inject

• MyCPAN::App::DPAN

• CPAN::Dark

• OrePAN
Pinto Is Born
Had built 3 private
CPANS
Always required some
hacks
Not happy with the
result
Started form scratch
What is Pinto?

   An extensible tool for managing
dependencies via a CPAN-like repository
Context
You have an app called My-App
The app contains package My::App
The app requires URI (latest is 1.59)
Creating A Repository
Creating A Repository

pinto --root=~/mypan init
Creating A Repository

pinto --root=~/mypan init

   path to the repository
Creating A Repository

pinto --root=~/mypan init

      “init” command
Creating A Repository

pinto --root=~/mypan init
Inspecting The Repository


pinto --root=~/mypan list
Inspecting The Repository


pinto --root=~/mypan list

      “list” command
Inspecting The Repository


pinto --root=~/mypan list

   path to the repository
Inspecting The Repository


pinto --root=~/mypan list
A Shortcut

pinto --root=~/mypan list
A Shortcut

pinto --root=~/mypan list


  pinto -r ~/mypan list
A Shortcut

    pinto --root=~/mypan list


      pinto -r ~/mypan list


export PINTO_REPOSITORY_ROOT=~/mypan
A Shortcut

    pinto --root=~/mypan list


      pinto -r ~/mypan list


export PINTO_REPOSITORY_ROOT=~/mypan


            pinto list
Fetching Dependencies
Fetching Dependencies


pinto pull URI
Fetching Dependencies


pinto pull URI

“pull” command
Fetching Dependencies


pinto pull URI

 package name
Fetching Dependencies


pinto pull URI
What Did We Get?
What Did We Get?


pinto list
What Did We Get?


                   pinto list


rf    URI             1.59   GAAS/URI-1.59.tar.gz
rf    URI::Escape     3.31   GAAS/URI-1.59.tar.gz
rf    URI::Heuristic 4.20    GAAS/URI-1.59.tar.gz
rf    URI::IRI           0   GAAS/URI-1.59.tar.gz
rf    URI::QueryParam    0   GAAS/URI-1.59.tar.gz
rf    URI::Split         0   GAAS/URI-1.59.tar.gz
...
Understanding The Listing


rf URI   1.59      GAAS/URI-1.59.tar.gz
Understanding The Listing


rf URI   1.59      GAAS/URI-1.59.tar.gz


         “r” means release dist
Understanding The Listing


rf URI    1.59     GAAS/URI-1.59.tar.gz


         “f” means a foreign dist
Understanding The Listing


rf URI   1.59      GAAS/URI-1.59.tar.gz


           The package name
Understanding The Listing


rf URI      1.59     GAAS/URI-1.59.tar.gz


         The package version number
Understanding The Listing


rf URI      1.59     GAAS/URI-1.59.tar.gz


         The distribution’s author ID
Understanding The Listing


rf URI    1.59      GAAS/URI-1.59.tar.gz


         The distribution archive
Understanding The Listing


rf URI   1.59      GAAS/URI-1.59.tar.gz
Injecting Your Own Distribution
Injecting Your Own Distribution


pinto add some/dir/My-App-1.0.tar.gz
Injecting Your Own Distribution


pinto add some/dir/My-App-1.0.tar.gz


           “
           add” command
Injecting Your Own Distribution


pinto add some/dir/My-App-1.0.tar.gz


       Path to local dist archive
Injecting Your Own Distribution


pinto add some/dir/My-App-1.0.tar.gz
Injecting Your Own Distribution


pinto add some/dir/My-App-1.0.tar.gz



             pinto list
Injecting Your Own Distribution


  pinto add some/dir/My-App-1.0.tar.gz



                 pinto list


rl My::App          1.0   YOU/My-App-1.0.tar.gz
rf URI             1.59   GAAS/URI-1.59.tar.gz
rf URI::Escape     3.31   GAAS/URI-1.59.tar.gz
...
Installing With cpan


$ cpan
cpan[1]> o conf urllist file://$HOME/mypan
cpan[2]> install My::App
Installing With cpan


$ cpan
cpan[1]> o conf urllist file://$HOME/mypan
cpan[2]> install My::App


        point to your repository
Installing With cpan


$ cpan
cpan[1]> o conf urllist file://$HOME/mypan
cpan[2]> install My::App
Installing With cpanm
Installing With cpanm


cpanm --mirror file://$HOME/mypan 
      --mirror-only My::App
Installing With cpanm


cpanm --mirror file://$HOME/mypan 
      --mirror-only My::App


          point to your repository
Installing With cpanm


cpanm --mirror file://$HOME/mypan 
      --mirror-only My::App


          do not fall back to CPAN
Installing With cpanm


cpanm --mirror file://$HOME/mypan 
      --mirror-only My::App
Installing With pinto
Installing With pinto

pinto install My::App
Installing With pinto

pinto install My::App


   “install” command
Installing With pinto

pinto install My::App
Upgrading Dependencies
Upgrading Dependencies


pinto pull URI~1.60
Upgrading Dependencies


pinto pull URI~1.60


    “pull” command
Upgrading Dependencies


    pinto pull URI~1.60


Package name and minimum version
Upgrading Dependencies


pinto pull GAAS/URI-1.60.tar.gz
Upgrading Dependencies


pinto pull GAAS/URI-1.60.tar.gz


          pinto list
Upgrading Dependencies


      pinto pull GAAS/URI-1.60.tar.gz


                  pinto list

rl    My::App         1.0   YOU/My-App-1.0.tar.gz
rf    URI            1.60   GAAS/URI-1.60.tar.gz
rf    URI::Escape    3.32   GAAS/URI-1.60.tar.gz
rf    URI::Heuristic 4.20   GAAS/URI-1.60.tar.gz
...
Working With Stacks
What Is A Stack?


A named mapping from package
names to distribution archives

Conceptually equivalent to the
02packages.details.txt file

In a CPAN, there is only one
“stack”, and it usually contains
only latest package versions

But a Pinto repository can have
multiple stacks, that contain
arbitrary package versions
The Default Stack




Every Pinto repository has a
built-in stack called “init”

It is the default stack for all
operations

You can change the default
stack
Creating A Stack
Creating A Stack

pinto new upgrades
Creating A Stack

pinto new upgrades


“new” command
Creating A Stack

pinto new upgrades


   stack name
Creating A Stack

   pinto new upgrades




pinto copy init upgrades
Creating A Stack

   pinto new upgrades




pinto copy init upgrades


   “copy” command
Creating A Stack

   pinto new upgrades




pinto copy init upgrades


      from stack
Creating A Stack

   pinto new upgrades




pinto copy init upgrades


       to stack
Creating A Stack

   pinto new upgrades




pinto copy init upgrades
Upgrading On A Stack


pinto pull --stack=upgrades URI~1.62
Upgrading On A Stack


pinto pull --stack=upgrades URI~1.62


          “pull” command
Upgrading On A Stack


pinto pull --stack=upgrades URI~1.62


       specify the stack name
Upgrading On A Stack


pinto pull --stack=upgrades URI~1.62


      package name and version
Upgrading On A Stack


pinto pull --stack=upgrades URI~1.62
Upgrading On A Stack


pinto pull --stack=upgrades URI~1.62



 pinto list --stack=upgrades
Upgrading On A Stack


pinto pull --stack=upgrades URI~1.62



 pinto list --stack=upgrades

       specify the stack name
Upgrading On A Stack


  pinto pull --stack=upgrades URI~1.62



      pinto list --stack=upgrades


rl    My::App         1.0   YOU/My-App-1.0.tar.gz
rf    URI            1.62   GAAS/URI-1.62.tar.gz
rf    URI::Escape    3.32   GAAS/URI-1.62.tar.gz
rf    URI::Heuristic 4.20   GAAS/URI-1.62.tar.gz
...
Looking Across Stacks


pinto list --stack=@ -P=URI
Looking Across Stacks


pinto list --stack=@ -P=URI

       special stack “
                     @”
Looking Across Stacks


pinto list --stack=@ -P=URI

   only packages matching %URI%
Looking Across Stacks


    pinto list --stack=@ -P=URI



rf init     URI     1.60   GAAS/URI-1.60.tar.gz
rf upgrades URI     1.62   GAAS/URI-1.62.tar.gz
...
Installing From A Stack


pinto install --stack=upgrades My::App
Installing From A Stack


pinto install --stack=upgrades My::App


          “install” command
Installing From A Stack


pinto install --stack=upgrades My::App


          specify stack name
Installing From A Stack


pinto install --stack=upgrades My::App


            package name
Installing From A Stack


pinto install --stack=upgrades My::App
Merging Stacks


pinto merge upgrades init
Merging Stacks


pinto merge upgrades init


    “merge” command
Merging Stacks


pinto merge upgrades init


       from stack
Merging Stacks


pinto merge upgrades init


        to stack
Merging Stacks


pinto merge upgrades init
Merging Stacks


       pinto merge upgrades init




rf init     URI       1.62   GAAS/URI-1.62.tar.gz
rf upgrades URI       1.62   GAAS/URI-1.62.tar.gz
...
Why Use Stacks?


• Stacks   for upgrades

• Stacks   for each feature

• Stacks   for dev/qa/prod

• Stacks   for each product

• Stacks   for each perl version

• Stacks   for each customer
Working With Pins
What Is A Pin?




Fixes a particular
package & version to
stack
Cannot be upgraded
or downgraded
Until you unpin it
Pinning A Package

pinto pin URI
Pinning A Package

pinto pin URI

 “pin” command
Pinning A Package

pinto pin URI

 package name
Pinning A Package

pinto pin URI
Pinning A Package

pinto pin URI


  pinto list
Pinning A Package

              pinto pin URI


                pinto list

rf+ URI            1.59   GAAS/URI-1.59.tar.gz
rf+ URI::Escape    3.31   GAAS/URI-1.59.tar.gz
rf+ URI::Heuristic 4.20   GAAS/URI-1.59.tar.gz
Pinning A Package

              pinto pin URI


                pinto list

rf+ URI            1.59   GAAS/URI-1.59.tar.gz
rf+ URI::Escape    3.31   GAAS/URI-1.59.tar.gz
rf+ URI::Heuristic 4.20   GAAS/URI-1.59.tar.gz


              “+” indicates a pin
Pinning A Package

              pinto pin URI


                pinto list

rf+ URI            1.59   GAAS/URI-1.59.tar.gz
rf+ URI::Escape    3.31   GAAS/URI-1.59.tar.gz
rf+ URI::Heuristic 4.20   GAAS/URI-1.59.tar.gz
Pinning A Package
Pinning A Package


Suppose you want to use Catalyst
Pinning A Package


Suppose you want to use Catalyst
And Catalyst requires Plack 0.99
Pinning A Package


Suppose you want to use Catalyst
And Catalyst requires Plack 0.99
And Plack 0.99 requires HTTP::Request 6.03
Pinning A Package


Suppose you want to use Catalyst
And Catalyst requires Plack 0.99
And Plack 0.99 requires HTTP::Request 6.03
And HTTP::Request requires ...
Pinning A Package


Suppose you want to use Catalyst
And Catalyst requires Plack 0.99
And Plack 0.99 requires HTTP::Request 6.03
And HTTP::Request requires ...
...requires URI 1.62
Pinning A Package

pinto -v pull Catalyst
Pinning A Package

        pinto -v pull Catalyst

Pulling Catalyst-Runtime-5.90012.tar.gz
Pinning A Package

        pinto -v pull Catalyst

Pulling Catalyst-Runtime-5.90012.tar.gz
Pulling CGI-Simple-1.113.tar.gz
Pinning A Package

        pinto -v pull Catalyst

Pulling Catalyst-Runtime-5.90012.tar.gz
Pulling CGI-Simple-1.113.tar.gz
...
Pinning A Package

        pinto -v pull Catalyst

Pulling Catalyst-Runtime-5.90012.tar.gz
Pulling CGI-Simple-1.113.tar.gz
...
Pulling Plack-0.9988.tar.gz
Pinning A Package

          pinto -v pull Catalyst

Pulling   Catalyst-Runtime-5.90012.tar.gz
Pulling   CGI-Simple-1.113.tar.gz
...
Pulling   Plack-0.9988.tar.gz
Pulling   Devel-StackTrace-1.27.tar.gz
Pinning A Package

          pinto -v pull Catalyst

Pulling   Catalyst-Runtime-5.90012.tar.gz
Pulling   CGI-Simple-1.113.tar.gz
...
Pulling   Plack-0.9988.tar.gz
Pulling   Devel-StackTrace-1.27.tar.gz
...
Pinning A Package

          pinto -v pull Catalyst

Pulling   Catalyst-Runtime-5.90012.tar.gz
Pulling   CGI-Simple-1.113.tar.gz
...
Pulling   Plack-0.9988.tar.gz
Pulling   Devel-StackTrace-1.27.tar.gz
...
Pulling   HTTP-Message-6.03.tar.gz
Pinning A Package

          pinto -v pull Catalyst

Pulling   Catalyst-Runtime-5.90012.tar.gz
Pulling   CGI-Simple-1.113.tar.gz
...
Pulling   Plack-0.9988.tar.gz
Pulling   Devel-StackTrace-1.27.tar.gz
...
Pulling   HTTP-Message-6.03.tar.gz
Pulling   URI-1.62
Pinning A Package

          pinto -v pull Catalyst

Pulling   Catalyst-Runtime-5.90012.tar.gz
Pulling   CGI-Simple-1.113.tar.gz
...
Pulling   Plack-0.9988.tar.gz
Pulling   Devel-StackTrace-1.27.tar.gz
...
Pulling   HTTP-Message-6.03.tar.gz
Pulling   URI-1.62

Cannot add GAAS/URI-1.62/URI~1.62 to stack init
because URI is pinned to GAAS/URI-1.59/URI~1.59
Why Pin?
Why Pin?




Prevent other
developers from
upgrading directly
Why Pin?




Prevent other
developers from
upgrading directly
Prevent other
dependencies from
upgrading directly
Using Pins And Stacks
       Together
Experiment With Upgrades
Experiment With Upgrades

You have a “prod” stack with DBIx::Class 1.6
Experiment With Upgrades

You have a “prod” stack with DBIx::Class 1.6
Make a copy of the “prod” stack called “test”
Experiment With Upgrades

You have a “prod” stack with DBIx::Class 1.6
Make a copy of the “prod” stack called “test”
Upgrade to DBIx::Class 1.7 on “test” stack
Experiment With Upgrades

You have a “prod” stack with DBIx::Class 1.6
Make a copy of the “prod” stack called “test”
Upgrade to DBIx::Class 1.7 on “test” stack
Build & test application using the “test” stack
Experiment With Upgrades

You have a “prod” stack with DBIx::Class 1.6
Make a copy of the “prod” stack called “test”
Upgrade to DBIx::Class 1.7 on “test” stack
Build & test application using the “test” stack
If the tests fail pin DBIx::Class on the “prod” stack
Making Local Patches
Making Local Patches

You find a bug in Plack-0.98
Making Local Patches

You find a bug in Plack-0.98
You patch and re-package as Plack-0.98_01.tar.gz
Making Local Patches

You find a bug in Plack-0.98
You patch and re-package as Plack-0.98_01.tar.gz
Put Plack-0.98_01.tar.gz in the “prod” stack
Making Local Patches

You find a bug in Plack-0.98
You patch and re-package as Plack-0.98_01.tar.gz
Put Plack-0.98_01.tar.gz in the “prod” stack
Pin Plack on the “prod” stack
Making Local Patches

You find a bug in Plack-0.98
You patch and re-package as Plack-0.98_01.tar.gz
Put Plack-0.98_01.tar.gz in the “prod” stack
Pin Plack on the “prod” stack
Remove pin when the author fixes bug
Making Local Patches

You find a bug in Plack-0.98
You patch and re-package as Plack-0.98_01.tar.gz
Put Plack-0.98_01.tar.gz in the “prod” stack
Pin Plack on the “prod” stack
Remove pin when the author fixes bug
Pull Plack-0.99 into the “prod” stack
Pinto In The Real World
Pinto And Legacy Code
Pinto And Legacy Code
Don’t always know what has been installed.
So use Dist::Sur veyor to discover dependencies.
Stash dependency list in a text file.
Then feed dependencies into a Pinto repository.
Pinto And Legacy Code
  Don’t always know what has been installed.
  So use Dist::Sur veyor to discover dependencies.
  Stash dependency list in a text file.
  Then feed dependencies into a Pinto repository.

pinto pull --norecurse < dependencies.txt
Pinto And Legacy Code
  Don’t always know what has been installed.
  So use Dist::Sur veyor to discover dependencies.
  Stash dependency list in a text file.
  Then feed dependencies into a Pinto repository.

pinto pull --norecurse < dependencies.txt


        do not automatically fetch deps
Pinto And Legacy Code
  Don’t always know what has been installed.
  So use Dist::Sur veyor to discover dependencies.
  Stash dependency list in a text file.
  Then feed dependencies into a Pinto repository.

pinto pull --norecurse < dependencies.txt
Pinto And Dist::Zilla
Pinto And Dist::Zilla


dzil listdeps | pinto pull
Pinto And Dist::Zilla


dzil listdeps | pinto pull

dzil authordeps | pinto pull
Pinto And The Development Cycle
Pinto And The Development Cycle

Usually don’t know dependencies ahead of time.
Pinto And The Development Cycle

Usually don’t know dependencies ahead of time.
Might install several modules before choosing.
Pinto And The Development Cycle

Usually don’t know dependencies ahead of time.
Might install several modules before choosing.
This process might take several days or weeks.
Pinto And The Development Cycle

Usually don’t know dependencies ahead of time.
Might install several modules before choosing.
This process might take several days or weeks.
By the time we decide, CPAN might changed.
Pinto And The Development Cycle

Usually don’t know dependencies ahead of time.
Might install several modules before choosing.
This process might take several days or weeks.
By the time we decide, CPAN might changed.
So there’s a hole in the development process.
Pinto And The Development Cycle

pinto install -L ~/myperl5 --pull Catalyst
Pinto And The Development Cycle

pinto install -L ~/myperl5 --pull Catalyst


            “install” command
Pinto And The Development Cycle

pinto install -L ~/myperl5 --pull Catalyst


           install into local::lib
Pinto And The Development Cycle

pinto install -L ~/myperl5 --pull Catalyst


              package name
Pinto And The Development Cycle

pinto install -L ~/myperl5 --pull Catalyst


           awesome --pull flag
Pinto And The Development Cycle

pinto install -L ~/myperl5 --pull Catalyst
Pinto And The Development Cycle

pinto install -L ~/myperl5 --pull Catalyst




  First, pulls Catalyst and any missing
  dependencies into the repository.
Pinto And The Development Cycle

pinto install -L ~/myperl5 --pull Catalyst




  First, pulls Catalyst and any missing
  dependencies into the repository.
  Dependencies must not violate pin constraints
  or command fails before installing anything.
Pinto And The Development Cycle

pinto install -L ~/myperl5 --pull Catalyst




  First, pulls Catalyst and any missing
  dependencies into the repository.
  Dependencies must not violate pin constraints
  or command fails before installing anything.
  Then, installs Catalyst and dependencies (from
  the repository) into your local::lib directory.
Gotchas
Pinto does not index exactly like PAUSE
May not work for old or oddly packaged code
Pinto does not enforce permissions
Pinto is strict about version numbers
Pinto And Teamwork
     Repository on shared storage area



Easy to setup
Performance may suck on NFS
Usual permission issues
Pinto And Teamwork
  Repository on a remote host via HTTP


pintod on remote host

pinto on local host

Can utilize fast storage

Can use HTTP authentication
Running pintod

  remotehost
Running pintod

          remotehost

pinto --root=/var/ourpan init
Running pintod

          remotehost

pinto --root=/var/ourpan init


  pintod --root=/var/ourpan
Running pintod

          remotehost

pinto --root=/var/ourpan init


  pintod --root=/var/ourpan


           localhost
Running pintod

             remotehost

   pinto --root=/var/ourpan init


     pintod --root=/var/ourpan


              localhost

pinto --root=http://somehost COMMAND
Using pintod For Installation
Using pintod For Installation

$ cpan
cpan[1]> o conf urllist http://remotehost/dev
cpan[2]> install My::App
Using pintod For Installation

$ cpan
cpan[1]> o conf urllist http://remotehost/dev
cpan[2]> install My::App



           append stack name to url
Using pintod For Installation

$ cpan
cpan[1]> o conf urllist http://remotehost/dev
cpan[2]> install My::App



cpanm --mirror http://remotehost/dev 
      --mirror-only My::App
Using pintod For Installation

$ cpan
cpan[1]> o conf urllist http://remotehost/dev
cpan[2]> install My::App



cpanm --mirror http://remotehost/dev 
      --mirror-only My::App


           append stack name to url
Using pintod For Installation

$ cpan
cpan[1]> o conf urllist http://remotehost/dev
cpan[2]> install My::App



cpanm --mirror http://remotehost/dev 
      --mirror-only My::App


pinto --root=http://remotehost install 
      --stack=dev My::App
Using pintod For Installation

$ cpan
cpan[1]> o conf urllist http://remotehost/dev
cpan[2]> install My::App



cpanm --mirror http://remotehost/dev 
      --mirror-only My::App


pinto --root=http://remotehost install 
      --stack=dev My::App

            point to pinto ser ver
Using pintod For Installation

$ cpan
cpan[1]> o conf urllist http://remotehost/dev
cpan[2]> install My::App



cpanm --mirror http://remotehost/dev 
      --mirror-only My::App


pinto --root=http://remotehost install 
      --stack=dev My::App

             specify the stack
Using pintod For Installation

$ cpan
cpan[1]> o conf urllist http://remotehost/dev
cpan[2]> install My::App



cpanm --mirror http://remotehost/dev 
      --mirror-only My::App


pinto --root=http://remotehost install 
      --stack=dev My::App
Pinto Net works
Pinto Net works


CPAN succeeds because it is
centralized
Pinto Net works


CPAN succeeds because it is
centralized

CPAN fails because it is
centralized
Pinto Net works


CPAN succeeds because it is
centralized

CPAN fails because it is
centralized

Pinto can be centralized or
distributed
Pinto Net works

       The CPAN



Team              Team
  1                 3

        Team
          2
Pinto Net works
Pinto Net works


Might not be a good idea
Pinto Net works


Might not be a good idea

No obvious way to resolve
namespace conflicts
Pinto Net works


Might not be a good idea

No obvious way to resolve
namespace conflicts

We’ll have to wait and see
if this pans out
Pinto And OS Packaging
• UsePinto to build up your
 application in some
 directory

• Packagethe directory with
 your favorite OS tools

• Add dependencies on non-
 perl stuff

• Deploy   as usual
Pinto And Other Tools


• Still
     just a pile of directories
 and files with an index

• AnnoCPAN,   MetaCPAN,
 CPAN::Mini::Webser ver, etc.
 should still work
Pinto versus Carton
                Pinto   Carton

Light weight

VCS-Friendly

Local Patches

Stack Support
 Enterprise
  Strength
Some Odds & Ends


• Dist::Zilla::Plugin::Pinto::Add   - release your dist to a
 Pinto repository with dzil

• Dist::Zilla::Chef
                 - use Pinto to manage your project
 dependencies within the dzil workflow
Pinto Architecture

                            Pinto
Configuration



                Pull   Add     Copy Merge




                                                 Logging
                       Repository

                 Database           File Store
Extending Pinto

• Create
       an Action subclass and override the “execute”
 method

• YourAction has access to the configuration, logger, and
 repository objects

• Your    Action can do whatever it wants

• Like   extract POD or ack source code in a distribution

• But    the API is not really stable yet
Future Plans

More VCS-behaviors: revert, diffs
Report upstream impacts of upgrades
Check stack for unsatisfiable dependencies
Visualize dependency graphs
Faster
Get Yours Today


https://metacpan.org/module/Pinto

 https://github.com/thaljef/Pinto
Thanks For Your Time


    Jeffrey Thalhammer
     thaljef@cpan.org

Más contenido relacionado

La actualidad más candente

Tracking large game assets with Git LFS
Tracking large game assets with Git LFSTracking large game assets with Git LFS
Tracking large game assets with Git LFSTim Pettersen
 
SymfonyCon Madrid 2014 - Rock Solid Deployment of Symfony Apps
SymfonyCon Madrid 2014 - Rock Solid Deployment of Symfony AppsSymfonyCon Madrid 2014 - Rock Solid Deployment of Symfony Apps
SymfonyCon Madrid 2014 - Rock Solid Deployment of Symfony AppsPablo Godel
 
Deploying and maintaining your software with RPM/APT
Deploying and maintaining your software with RPM/APTDeploying and maintaining your software with RPM/APT
Deploying and maintaining your software with RPM/APTJoshua Thijssen
 
Symfony Live NYC 2014 - Rock Solid Deployment of Symfony Apps
Symfony Live NYC 2014 -  Rock Solid Deployment of Symfony AppsSymfony Live NYC 2014 -  Rock Solid Deployment of Symfony Apps
Symfony Live NYC 2014 - Rock Solid Deployment of Symfony AppsPablo Godel
 
Frontend Performance: Expert to Crazy Person
Frontend Performance: Expert to Crazy PersonFrontend Performance: Expert to Crazy Person
Frontend Performance: Expert to Crazy PersonPhilip Tellis
 
The Modern Developer Toolbox
The Modern Developer ToolboxThe Modern Developer Toolbox
The Modern Developer ToolboxPablo Godel
 
Console Apps: php artisan forthe:win
Console Apps: php artisan forthe:winConsole Apps: php artisan forthe:win
Console Apps: php artisan forthe:winJoe Ferguson
 
Frontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonFrontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonPhilip Tellis
 
Frontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonFrontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonPhilip Tellis
 
Tracking huge files with Git LFS - LinuxCon 2016
Tracking huge files with Git LFS - LinuxCon 2016Tracking huge files with Git LFS - LinuxCon 2016
Tracking huge files with Git LFS - LinuxCon 2016Tim Pettersen
 
PHP Conference Argentina 2013 - Independizate de tu departamento IT - Habilid...
PHP Conference Argentina 2013 - Independizate de tu departamento IT - Habilid...PHP Conference Argentina 2013 - Independizate de tu departamento IT - Habilid...
PHP Conference Argentina 2013 - Independizate de tu departamento IT - Habilid...Pablo Godel
 
Frontend Performance: De débutant à Expert à Fou Furieux
Frontend Performance: De débutant à Expert à Fou FurieuxFrontend Performance: De débutant à Expert à Fou Furieux
Frontend Performance: De débutant à Expert à Fou FurieuxPhilip Tellis
 
ZLM-Cython Build you first module
ZLM-Cython Build you first moduleZLM-Cython Build you first module
ZLM-Cython Build you first moduleVladimir Ulogov
 
Frontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonFrontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonPhilip Tellis
 
Bootstrapping Puppet and Application Deployment - PuppetConf 2013
Bootstrapping Puppet and Application Deployment - PuppetConf 2013Bootstrapping Puppet and Application Deployment - PuppetConf 2013
Bootstrapping Puppet and Application Deployment - PuppetConf 2013Puppet
 
Testing for Ops: Going Beyond the Manifest - PuppetConf 2013
Testing for Ops: Going Beyond the Manifest - PuppetConf 2013Testing for Ops: Going Beyond the Manifest - PuppetConf 2013
Testing for Ops: Going Beyond the Manifest - PuppetConf 2013Puppet
 
Laravel Code Generators and Packages
Laravel Code Generators and PackagesLaravel Code Generators and Packages
Laravel Code Generators and PackagesPovilas Korop
 

La actualidad más candente (20)

Tracking large game assets with Git LFS
Tracking large game assets with Git LFSTracking large game assets with Git LFS
Tracking large game assets with Git LFS
 
SymfonyCon Madrid 2014 - Rock Solid Deployment of Symfony Apps
SymfonyCon Madrid 2014 - Rock Solid Deployment of Symfony AppsSymfonyCon Madrid 2014 - Rock Solid Deployment of Symfony Apps
SymfonyCon Madrid 2014 - Rock Solid Deployment of Symfony Apps
 
Deploying and maintaining your software with RPM/APT
Deploying and maintaining your software with RPM/APTDeploying and maintaining your software with RPM/APT
Deploying and maintaining your software with RPM/APT
 
2021laravelconftwslides6
2021laravelconftwslides62021laravelconftwslides6
2021laravelconftwslides6
 
Symfony Live NYC 2014 - Rock Solid Deployment of Symfony Apps
Symfony Live NYC 2014 -  Rock Solid Deployment of Symfony AppsSymfony Live NYC 2014 -  Rock Solid Deployment of Symfony Apps
Symfony Live NYC 2014 - Rock Solid Deployment of Symfony Apps
 
Frontend Performance: Expert to Crazy Person
Frontend Performance: Expert to Crazy PersonFrontend Performance: Expert to Crazy Person
Frontend Performance: Expert to Crazy Person
 
The Modern Developer Toolbox
The Modern Developer ToolboxThe Modern Developer Toolbox
The Modern Developer Toolbox
 
Console Apps: php artisan forthe:win
Console Apps: php artisan forthe:winConsole Apps: php artisan forthe:win
Console Apps: php artisan forthe:win
 
CPAN Training
CPAN TrainingCPAN Training
CPAN Training
 
Frontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonFrontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy Person
 
Frontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonFrontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy Person
 
Tracking huge files with Git LFS - LinuxCon 2016
Tracking huge files with Git LFS - LinuxCon 2016Tracking huge files with Git LFS - LinuxCon 2016
Tracking huge files with Git LFS - LinuxCon 2016
 
PHP Conference Argentina 2013 - Independizate de tu departamento IT - Habilid...
PHP Conference Argentina 2013 - Independizate de tu departamento IT - Habilid...PHP Conference Argentina 2013 - Independizate de tu departamento IT - Habilid...
PHP Conference Argentina 2013 - Independizate de tu departamento IT - Habilid...
 
Frontend Performance: De débutant à Expert à Fou Furieux
Frontend Performance: De débutant à Expert à Fou FurieuxFrontend Performance: De débutant à Expert à Fou Furieux
Frontend Performance: De débutant à Expert à Fou Furieux
 
ZLM-Cython Build you first module
ZLM-Cython Build you first moduleZLM-Cython Build you first module
ZLM-Cython Build you first module
 
zlm-cython
zlm-cythonzlm-cython
zlm-cython
 
Frontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonFrontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy Person
 
Bootstrapping Puppet and Application Deployment - PuppetConf 2013
Bootstrapping Puppet and Application Deployment - PuppetConf 2013Bootstrapping Puppet and Application Deployment - PuppetConf 2013
Bootstrapping Puppet and Application Deployment - PuppetConf 2013
 
Testing for Ops: Going Beyond the Manifest - PuppetConf 2013
Testing for Ops: Going Beyond the Manifest - PuppetConf 2013Testing for Ops: Going Beyond the Manifest - PuppetConf 2013
Testing for Ops: Going Beyond the Manifest - PuppetConf 2013
 
Laravel Code Generators and Packages
Laravel Code Generators and PackagesLaravel Code Generators and Packages
Laravel Code Generators and Packages
 

Similar a Dependency Management With Pinto

Arbeiten mit distribute, pip und virtualenv
Arbeiten mit distribute, pip und virtualenvArbeiten mit distribute, pip und virtualenv
Arbeiten mit distribute, pip und virtualenvMarkus Zapke-Gründemann
 
Python packaging and dependency resolution
Python packaging and dependency resolutionPython packaging and dependency resolution
Python packaging and dependency resolutionTatiana Al-Chueyr
 
Installing softwares in linux
Installing softwares in linuxInstalling softwares in linux
Installing softwares in linuxvedantsharma
 
Isolated development in python
Isolated development in pythonIsolated development in python
Isolated development in pythonAndrés J. Díaz
 
RPM: Speed up your deploy
RPM: Speed up your deployRPM: Speed up your deploy
RPM: Speed up your deployfcrippa
 
Virtualenv
VirtualenvVirtualenv
VirtualenvWEBdeBS
 
Christian Strappazzon - Presentazione Python Milano - Codemotion Milano 2017
Christian Strappazzon - Presentazione Python Milano - Codemotion Milano 2017Christian Strappazzon - Presentazione Python Milano - Codemotion Milano 2017
Christian Strappazzon - Presentazione Python Milano - Codemotion Milano 2017Codemotion
 
Arbeiten mit distribute, pip und virtualenv
Arbeiten mit distribute, pip und virtualenvArbeiten mit distribute, pip und virtualenv
Arbeiten mit distribute, pip und virtualenvMarkus Zapke-Gründemann
 
Instrumentación de entrega continua con Gitlab
Instrumentación de entrega continua con GitlabInstrumentación de entrega continua con Gitlab
Instrumentación de entrega continua con GitlabSoftware Guru
 
21st Century CPAN Testing: CPANci
21st Century CPAN Testing: CPANci21st Century CPAN Testing: CPANci
21st Century CPAN Testing: CPANciMike Friedman
 
OpenStack How To - PyLadies ATX
OpenStack How To - PyLadies ATXOpenStack How To - PyLadies ATX
OpenStack How To - PyLadies ATXAnne Gentle
 
Composer - The missing package manager for PHP
Composer - The missing package manager for PHPComposer - The missing package manager for PHP
Composer - The missing package manager for PHPTareq Hasan
 
Installing OpenCV 4 on Ubuntu 18.x
Installing OpenCV 4 on Ubuntu 18.xInstalling OpenCV 4 on Ubuntu 18.x
Installing OpenCV 4 on Ubuntu 18.xNader Karimi
 
Perl in RPM-Land
Perl in RPM-LandPerl in RPM-Land
Perl in RPM-LandDave Cross
 

Similar a Dependency Management With Pinto (20)

Arbeiten mit distribute, pip und virtualenv
Arbeiten mit distribute, pip und virtualenvArbeiten mit distribute, pip und virtualenv
Arbeiten mit distribute, pip und virtualenv
 
Git::Hooks
Git::HooksGit::Hooks
Git::Hooks
 
Python packaging and dependency resolution
Python packaging and dependency resolutionPython packaging and dependency resolution
Python packaging and dependency resolution
 
Installing softwares in linux
Installing softwares in linuxInstalling softwares in linux
Installing softwares in linux
 
Isolated development in python
Isolated development in pythonIsolated development in python
Isolated development in python
 
RPM: Speed up your deploy
RPM: Speed up your deployRPM: Speed up your deploy
RPM: Speed up your deploy
 
Virtualenv
VirtualenvVirtualenv
Virtualenv
 
Christian Strappazzon - Presentazione Python Milano - Codemotion Milano 2017
Christian Strappazzon - Presentazione Python Milano - Codemotion Milano 2017Christian Strappazzon - Presentazione Python Milano - Codemotion Milano 2017
Christian Strappazzon - Presentazione Python Milano - Codemotion Milano 2017
 
Arbeiten mit distribute, pip und virtualenv
Arbeiten mit distribute, pip und virtualenvArbeiten mit distribute, pip und virtualenv
Arbeiten mit distribute, pip und virtualenv
 
Instrumentación de entrega continua con Gitlab
Instrumentación de entrega continua con GitlabInstrumentación de entrega continua con Gitlab
Instrumentación de entrega continua con Gitlab
 
21st Century CPAN Testing: CPANci
21st Century CPAN Testing: CPANci21st Century CPAN Testing: CPANci
21st Century CPAN Testing: CPANci
 
Os Treat
Os TreatOs Treat
Os Treat
 
OpenStack How To - PyLadies ATX
OpenStack How To - PyLadies ATXOpenStack How To - PyLadies ATX
OpenStack How To - PyLadies ATX
 
Composer - The missing package manager for PHP
Composer - The missing package manager for PHPComposer - The missing package manager for PHP
Composer - The missing package manager for PHP
 
Linux Presentation
Linux PresentationLinux Presentation
Linux Presentation
 
Installing OpenCV 4 on Ubuntu 18.x
Installing OpenCV 4 on Ubuntu 18.xInstalling OpenCV 4 on Ubuntu 18.x
Installing OpenCV 4 on Ubuntu 18.x
 
Perl in RPM-Land
Perl in RPM-LandPerl in RPM-Land
Perl in RPM-Land
 
RPM Packaging 101 (Old)
RPM Packaging 101 (Old)RPM Packaging 101 (Old)
RPM Packaging 101 (Old)
 
Python+gradle
Python+gradlePython+gradle
Python+gradle
 
Composer
ComposerComposer
Composer
 

Último

How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 

Último (20)

How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 

Dependency Management With Pinto

  • 1. Dependency Management With Pinto Jeffrey Thalhammer thaljef@cpan.org YAPC::NA June 15, 2012
  • 2. CPAN Is Heaven Tens of thousands of modules for every purpose imaginable Lots of ser vices for testing, bug tracking, ratings, forums Awesome tool chain for building, testing, installing
  • 3. CPAN Is Hell The CPAN is not stable Developers constantly adding and removing stuff Sometimes the code is broken Tool chain expects backward compatibility
  • 4. Unintended Consequences Avoiding dependencies Avoiding upgrades Shared resources & monolithic systems Unreproducible environments
  • 5. Combating The Problem “Just stash the site_perl directory in the VCS” Brittle Not portable Can’t smoke it Hard to evolve
  • 6. Combating The Problem “Just stash the distribution tarballs in the VCS” Slightly less brittle Portable Smokable Still icky
  • 7. CPAN::Site & CPAN::Mini • Snapshots of the CPAN • Solves the stability problem • Still clunky
  • 8. More Shops Are Writing CPAN- style Dists • M::B and EU::MM more commonplace • Dist::Zilla makes the development fun • cpanmmakes the deployment easy • DarkPANs proliferate
  • 9. Lots of DarkPAN Tools Emerge • CPAN::Mini::Inject • MyCPAN::App::DPAN • CPAN::Dark • OrePAN
  • 10. Pinto Is Born Had built 3 private CPANS Always required some hacks Not happy with the result Started form scratch
  • 11. What is Pinto? An extensible tool for managing dependencies via a CPAN-like repository
  • 12. Context You have an app called My-App The app contains package My::App The app requires URI (latest is 1.59)
  • 14. Creating A Repository pinto --root=~/mypan init
  • 15. Creating A Repository pinto --root=~/mypan init path to the repository
  • 16. Creating A Repository pinto --root=~/mypan init “init” command
  • 17. Creating A Repository pinto --root=~/mypan init
  • 18. Inspecting The Repository pinto --root=~/mypan list
  • 19. Inspecting The Repository pinto --root=~/mypan list “list” command
  • 20. Inspecting The Repository pinto --root=~/mypan list path to the repository
  • 21. Inspecting The Repository pinto --root=~/mypan list
  • 23. A Shortcut pinto --root=~/mypan list pinto -r ~/mypan list
  • 24. A Shortcut pinto --root=~/mypan list pinto -r ~/mypan list export PINTO_REPOSITORY_ROOT=~/mypan
  • 25. A Shortcut pinto --root=~/mypan list pinto -r ~/mypan list export PINTO_REPOSITORY_ROOT=~/mypan pinto list
  • 28. Fetching Dependencies pinto pull URI “pull” command
  • 31. What Did We Get?
  • 32. What Did We Get? pinto list
  • 33. What Did We Get? pinto list rf URI 1.59 GAAS/URI-1.59.tar.gz rf URI::Escape 3.31 GAAS/URI-1.59.tar.gz rf URI::Heuristic 4.20 GAAS/URI-1.59.tar.gz rf URI::IRI 0 GAAS/URI-1.59.tar.gz rf URI::QueryParam 0 GAAS/URI-1.59.tar.gz rf URI::Split 0 GAAS/URI-1.59.tar.gz ...
  • 34. Understanding The Listing rf URI 1.59 GAAS/URI-1.59.tar.gz
  • 35. Understanding The Listing rf URI 1.59 GAAS/URI-1.59.tar.gz “r” means release dist
  • 36. Understanding The Listing rf URI 1.59 GAAS/URI-1.59.tar.gz “f” means a foreign dist
  • 37. Understanding The Listing rf URI 1.59 GAAS/URI-1.59.tar.gz The package name
  • 38. Understanding The Listing rf URI 1.59 GAAS/URI-1.59.tar.gz The package version number
  • 39. Understanding The Listing rf URI 1.59 GAAS/URI-1.59.tar.gz The distribution’s author ID
  • 40. Understanding The Listing rf URI 1.59 GAAS/URI-1.59.tar.gz The distribution archive
  • 41. Understanding The Listing rf URI 1.59 GAAS/URI-1.59.tar.gz
  • 42. Injecting Your Own Distribution
  • 43. Injecting Your Own Distribution pinto add some/dir/My-App-1.0.tar.gz
  • 44. Injecting Your Own Distribution pinto add some/dir/My-App-1.0.tar.gz “ add” command
  • 45. Injecting Your Own Distribution pinto add some/dir/My-App-1.0.tar.gz Path to local dist archive
  • 46. Injecting Your Own Distribution pinto add some/dir/My-App-1.0.tar.gz
  • 47. Injecting Your Own Distribution pinto add some/dir/My-App-1.0.tar.gz pinto list
  • 48. Injecting Your Own Distribution pinto add some/dir/My-App-1.0.tar.gz pinto list rl My::App 1.0 YOU/My-App-1.0.tar.gz rf URI 1.59 GAAS/URI-1.59.tar.gz rf URI::Escape 3.31 GAAS/URI-1.59.tar.gz ...
  • 49. Installing With cpan $ cpan cpan[1]> o conf urllist file://$HOME/mypan cpan[2]> install My::App
  • 50. Installing With cpan $ cpan cpan[1]> o conf urllist file://$HOME/mypan cpan[2]> install My::App point to your repository
  • 51. Installing With cpan $ cpan cpan[1]> o conf urllist file://$HOME/mypan cpan[2]> install My::App
  • 53. Installing With cpanm cpanm --mirror file://$HOME/mypan --mirror-only My::App
  • 54. Installing With cpanm cpanm --mirror file://$HOME/mypan --mirror-only My::App point to your repository
  • 55. Installing With cpanm cpanm --mirror file://$HOME/mypan --mirror-only My::App do not fall back to CPAN
  • 56. Installing With cpanm cpanm --mirror file://$HOME/mypan --mirror-only My::App
  • 58. Installing With pinto pinto install My::App
  • 59. Installing With pinto pinto install My::App “install” command
  • 60. Installing With pinto pinto install My::App
  • 63. Upgrading Dependencies pinto pull URI~1.60 “pull” command
  • 64. Upgrading Dependencies pinto pull URI~1.60 Package name and minimum version
  • 65. Upgrading Dependencies pinto pull GAAS/URI-1.60.tar.gz
  • 66. Upgrading Dependencies pinto pull GAAS/URI-1.60.tar.gz pinto list
  • 67. Upgrading Dependencies pinto pull GAAS/URI-1.60.tar.gz pinto list rl My::App 1.0 YOU/My-App-1.0.tar.gz rf URI 1.60 GAAS/URI-1.60.tar.gz rf URI::Escape 3.32 GAAS/URI-1.60.tar.gz rf URI::Heuristic 4.20 GAAS/URI-1.60.tar.gz ...
  • 69. What Is A Stack? A named mapping from package names to distribution archives Conceptually equivalent to the 02packages.details.txt file In a CPAN, there is only one “stack”, and it usually contains only latest package versions But a Pinto repository can have multiple stacks, that contain arbitrary package versions
  • 70. The Default Stack Every Pinto repository has a built-in stack called “init” It is the default stack for all operations You can change the default stack
  • 72. Creating A Stack pinto new upgrades
  • 73. Creating A Stack pinto new upgrades “new” command
  • 74. Creating A Stack pinto new upgrades stack name
  • 75. Creating A Stack pinto new upgrades pinto copy init upgrades
  • 76. Creating A Stack pinto new upgrades pinto copy init upgrades “copy” command
  • 77. Creating A Stack pinto new upgrades pinto copy init upgrades from stack
  • 78. Creating A Stack pinto new upgrades pinto copy init upgrades to stack
  • 79. Creating A Stack pinto new upgrades pinto copy init upgrades
  • 80. Upgrading On A Stack pinto pull --stack=upgrades URI~1.62
  • 81. Upgrading On A Stack pinto pull --stack=upgrades URI~1.62 “pull” command
  • 82. Upgrading On A Stack pinto pull --stack=upgrades URI~1.62 specify the stack name
  • 83. Upgrading On A Stack pinto pull --stack=upgrades URI~1.62 package name and version
  • 84. Upgrading On A Stack pinto pull --stack=upgrades URI~1.62
  • 85. Upgrading On A Stack pinto pull --stack=upgrades URI~1.62 pinto list --stack=upgrades
  • 86. Upgrading On A Stack pinto pull --stack=upgrades URI~1.62 pinto list --stack=upgrades specify the stack name
  • 87. Upgrading On A Stack pinto pull --stack=upgrades URI~1.62 pinto list --stack=upgrades rl My::App 1.0 YOU/My-App-1.0.tar.gz rf URI 1.62 GAAS/URI-1.62.tar.gz rf URI::Escape 3.32 GAAS/URI-1.62.tar.gz rf URI::Heuristic 4.20 GAAS/URI-1.62.tar.gz ...
  • 88. Looking Across Stacks pinto list --stack=@ -P=URI
  • 89. Looking Across Stacks pinto list --stack=@ -P=URI special stack “ @”
  • 90. Looking Across Stacks pinto list --stack=@ -P=URI only packages matching %URI%
  • 91. Looking Across Stacks pinto list --stack=@ -P=URI rf init URI 1.60 GAAS/URI-1.60.tar.gz rf upgrades URI 1.62 GAAS/URI-1.62.tar.gz ...
  • 92. Installing From A Stack pinto install --stack=upgrades My::App
  • 93. Installing From A Stack pinto install --stack=upgrades My::App “install” command
  • 94. Installing From A Stack pinto install --stack=upgrades My::App specify stack name
  • 95. Installing From A Stack pinto install --stack=upgrades My::App package name
  • 96. Installing From A Stack pinto install --stack=upgrades My::App
  • 97. Merging Stacks pinto merge upgrades init
  • 98. Merging Stacks pinto merge upgrades init “merge” command
  • 99. Merging Stacks pinto merge upgrades init from stack
  • 100. Merging Stacks pinto merge upgrades init to stack
  • 101. Merging Stacks pinto merge upgrades init
  • 102. Merging Stacks pinto merge upgrades init rf init URI 1.62 GAAS/URI-1.62.tar.gz rf upgrades URI 1.62 GAAS/URI-1.62.tar.gz ...
  • 103. Why Use Stacks? • Stacks for upgrades • Stacks for each feature • Stacks for dev/qa/prod • Stacks for each product • Stacks for each perl version • Stacks for each customer
  • 105. What Is A Pin? Fixes a particular package & version to stack Cannot be upgraded or downgraded Until you unpin it
  • 107. Pinning A Package pinto pin URI “pin” command
  • 108. Pinning A Package pinto pin URI package name
  • 110. Pinning A Package pinto pin URI pinto list
  • 111. Pinning A Package pinto pin URI pinto list rf+ URI 1.59 GAAS/URI-1.59.tar.gz rf+ URI::Escape 3.31 GAAS/URI-1.59.tar.gz rf+ URI::Heuristic 4.20 GAAS/URI-1.59.tar.gz
  • 112. Pinning A Package pinto pin URI pinto list rf+ URI 1.59 GAAS/URI-1.59.tar.gz rf+ URI::Escape 3.31 GAAS/URI-1.59.tar.gz rf+ URI::Heuristic 4.20 GAAS/URI-1.59.tar.gz “+” indicates a pin
  • 113. Pinning A Package pinto pin URI pinto list rf+ URI 1.59 GAAS/URI-1.59.tar.gz rf+ URI::Escape 3.31 GAAS/URI-1.59.tar.gz rf+ URI::Heuristic 4.20 GAAS/URI-1.59.tar.gz
  • 115. Pinning A Package Suppose you want to use Catalyst
  • 116. Pinning A Package Suppose you want to use Catalyst And Catalyst requires Plack 0.99
  • 117. Pinning A Package Suppose you want to use Catalyst And Catalyst requires Plack 0.99 And Plack 0.99 requires HTTP::Request 6.03
  • 118. Pinning A Package Suppose you want to use Catalyst And Catalyst requires Plack 0.99 And Plack 0.99 requires HTTP::Request 6.03 And HTTP::Request requires ...
  • 119. Pinning A Package Suppose you want to use Catalyst And Catalyst requires Plack 0.99 And Plack 0.99 requires HTTP::Request 6.03 And HTTP::Request requires ... ...requires URI 1.62
  • 120. Pinning A Package pinto -v pull Catalyst
  • 121. Pinning A Package pinto -v pull Catalyst Pulling Catalyst-Runtime-5.90012.tar.gz
  • 122. Pinning A Package pinto -v pull Catalyst Pulling Catalyst-Runtime-5.90012.tar.gz Pulling CGI-Simple-1.113.tar.gz
  • 123. Pinning A Package pinto -v pull Catalyst Pulling Catalyst-Runtime-5.90012.tar.gz Pulling CGI-Simple-1.113.tar.gz ...
  • 124. Pinning A Package pinto -v pull Catalyst Pulling Catalyst-Runtime-5.90012.tar.gz Pulling CGI-Simple-1.113.tar.gz ... Pulling Plack-0.9988.tar.gz
  • 125. Pinning A Package pinto -v pull Catalyst Pulling Catalyst-Runtime-5.90012.tar.gz Pulling CGI-Simple-1.113.tar.gz ... Pulling Plack-0.9988.tar.gz Pulling Devel-StackTrace-1.27.tar.gz
  • 126. Pinning A Package pinto -v pull Catalyst Pulling Catalyst-Runtime-5.90012.tar.gz Pulling CGI-Simple-1.113.tar.gz ... Pulling Plack-0.9988.tar.gz Pulling Devel-StackTrace-1.27.tar.gz ...
  • 127. Pinning A Package pinto -v pull Catalyst Pulling Catalyst-Runtime-5.90012.tar.gz Pulling CGI-Simple-1.113.tar.gz ... Pulling Plack-0.9988.tar.gz Pulling Devel-StackTrace-1.27.tar.gz ... Pulling HTTP-Message-6.03.tar.gz
  • 128. Pinning A Package pinto -v pull Catalyst Pulling Catalyst-Runtime-5.90012.tar.gz Pulling CGI-Simple-1.113.tar.gz ... Pulling Plack-0.9988.tar.gz Pulling Devel-StackTrace-1.27.tar.gz ... Pulling HTTP-Message-6.03.tar.gz Pulling URI-1.62
  • 129. Pinning A Package pinto -v pull Catalyst Pulling Catalyst-Runtime-5.90012.tar.gz Pulling CGI-Simple-1.113.tar.gz ... Pulling Plack-0.9988.tar.gz Pulling Devel-StackTrace-1.27.tar.gz ... Pulling HTTP-Message-6.03.tar.gz Pulling URI-1.62 Cannot add GAAS/URI-1.62/URI~1.62 to stack init because URI is pinned to GAAS/URI-1.59/URI~1.59
  • 131. Why Pin? Prevent other developers from upgrading directly
  • 132. Why Pin? Prevent other developers from upgrading directly Prevent other dependencies from upgrading directly
  • 133. Using Pins And Stacks Together
  • 135. Experiment With Upgrades You have a “prod” stack with DBIx::Class 1.6
  • 136. Experiment With Upgrades You have a “prod” stack with DBIx::Class 1.6 Make a copy of the “prod” stack called “test”
  • 137. Experiment With Upgrades You have a “prod” stack with DBIx::Class 1.6 Make a copy of the “prod” stack called “test” Upgrade to DBIx::Class 1.7 on “test” stack
  • 138. Experiment With Upgrades You have a “prod” stack with DBIx::Class 1.6 Make a copy of the “prod” stack called “test” Upgrade to DBIx::Class 1.7 on “test” stack Build & test application using the “test” stack
  • 139. Experiment With Upgrades You have a “prod” stack with DBIx::Class 1.6 Make a copy of the “prod” stack called “test” Upgrade to DBIx::Class 1.7 on “test” stack Build & test application using the “test” stack If the tests fail pin DBIx::Class on the “prod” stack
  • 141. Making Local Patches You find a bug in Plack-0.98
  • 142. Making Local Patches You find a bug in Plack-0.98 You patch and re-package as Plack-0.98_01.tar.gz
  • 143. Making Local Patches You find a bug in Plack-0.98 You patch and re-package as Plack-0.98_01.tar.gz Put Plack-0.98_01.tar.gz in the “prod” stack
  • 144. Making Local Patches You find a bug in Plack-0.98 You patch and re-package as Plack-0.98_01.tar.gz Put Plack-0.98_01.tar.gz in the “prod” stack Pin Plack on the “prod” stack
  • 145. Making Local Patches You find a bug in Plack-0.98 You patch and re-package as Plack-0.98_01.tar.gz Put Plack-0.98_01.tar.gz in the “prod” stack Pin Plack on the “prod” stack Remove pin when the author fixes bug
  • 146. Making Local Patches You find a bug in Plack-0.98 You patch and re-package as Plack-0.98_01.tar.gz Put Plack-0.98_01.tar.gz in the “prod” stack Pin Plack on the “prod” stack Remove pin when the author fixes bug Pull Plack-0.99 into the “prod” stack
  • 147. Pinto In The Real World
  • 149. Pinto And Legacy Code Don’t always know what has been installed. So use Dist::Sur veyor to discover dependencies. Stash dependency list in a text file. Then feed dependencies into a Pinto repository.
  • 150. Pinto And Legacy Code Don’t always know what has been installed. So use Dist::Sur veyor to discover dependencies. Stash dependency list in a text file. Then feed dependencies into a Pinto repository. pinto pull --norecurse < dependencies.txt
  • 151. Pinto And Legacy Code Don’t always know what has been installed. So use Dist::Sur veyor to discover dependencies. Stash dependency list in a text file. Then feed dependencies into a Pinto repository. pinto pull --norecurse < dependencies.txt do not automatically fetch deps
  • 152. Pinto And Legacy Code Don’t always know what has been installed. So use Dist::Sur veyor to discover dependencies. Stash dependency list in a text file. Then feed dependencies into a Pinto repository. pinto pull --norecurse < dependencies.txt
  • 154. Pinto And Dist::Zilla dzil listdeps | pinto pull
  • 155. Pinto And Dist::Zilla dzil listdeps | pinto pull dzil authordeps | pinto pull
  • 156. Pinto And The Development Cycle
  • 157. Pinto And The Development Cycle Usually don’t know dependencies ahead of time.
  • 158. Pinto And The Development Cycle Usually don’t know dependencies ahead of time. Might install several modules before choosing.
  • 159. Pinto And The Development Cycle Usually don’t know dependencies ahead of time. Might install several modules before choosing. This process might take several days or weeks.
  • 160. Pinto And The Development Cycle Usually don’t know dependencies ahead of time. Might install several modules before choosing. This process might take several days or weeks. By the time we decide, CPAN might changed.
  • 161. Pinto And The Development Cycle Usually don’t know dependencies ahead of time. Might install several modules before choosing. This process might take several days or weeks. By the time we decide, CPAN might changed. So there’s a hole in the development process.
  • 162. Pinto And The Development Cycle pinto install -L ~/myperl5 --pull Catalyst
  • 163. Pinto And The Development Cycle pinto install -L ~/myperl5 --pull Catalyst “install” command
  • 164. Pinto And The Development Cycle pinto install -L ~/myperl5 --pull Catalyst install into local::lib
  • 165. Pinto And The Development Cycle pinto install -L ~/myperl5 --pull Catalyst package name
  • 166. Pinto And The Development Cycle pinto install -L ~/myperl5 --pull Catalyst awesome --pull flag
  • 167. Pinto And The Development Cycle pinto install -L ~/myperl5 --pull Catalyst
  • 168. Pinto And The Development Cycle pinto install -L ~/myperl5 --pull Catalyst First, pulls Catalyst and any missing dependencies into the repository.
  • 169. Pinto And The Development Cycle pinto install -L ~/myperl5 --pull Catalyst First, pulls Catalyst and any missing dependencies into the repository. Dependencies must not violate pin constraints or command fails before installing anything.
  • 170. Pinto And The Development Cycle pinto install -L ~/myperl5 --pull Catalyst First, pulls Catalyst and any missing dependencies into the repository. Dependencies must not violate pin constraints or command fails before installing anything. Then, installs Catalyst and dependencies (from the repository) into your local::lib directory.
  • 171. Gotchas Pinto does not index exactly like PAUSE May not work for old or oddly packaged code Pinto does not enforce permissions Pinto is strict about version numbers
  • 172. Pinto And Teamwork Repository on shared storage area Easy to setup Performance may suck on NFS Usual permission issues
  • 173. Pinto And Teamwork Repository on a remote host via HTTP pintod on remote host pinto on local host Can utilize fast storage Can use HTTP authentication
  • 174. Running pintod remotehost
  • 175. Running pintod remotehost pinto --root=/var/ourpan init
  • 176. Running pintod remotehost pinto --root=/var/ourpan init pintod --root=/var/ourpan
  • 177. Running pintod remotehost pinto --root=/var/ourpan init pintod --root=/var/ourpan localhost
  • 178. Running pintod remotehost pinto --root=/var/ourpan init pintod --root=/var/ourpan localhost pinto --root=http://somehost COMMAND
  • 179. Using pintod For Installation
  • 180. Using pintod For Installation $ cpan cpan[1]> o conf urllist http://remotehost/dev cpan[2]> install My::App
  • 181. Using pintod For Installation $ cpan cpan[1]> o conf urllist http://remotehost/dev cpan[2]> install My::App append stack name to url
  • 182. Using pintod For Installation $ cpan cpan[1]> o conf urllist http://remotehost/dev cpan[2]> install My::App cpanm --mirror http://remotehost/dev --mirror-only My::App
  • 183. Using pintod For Installation $ cpan cpan[1]> o conf urllist http://remotehost/dev cpan[2]> install My::App cpanm --mirror http://remotehost/dev --mirror-only My::App append stack name to url
  • 184. Using pintod For Installation $ cpan cpan[1]> o conf urllist http://remotehost/dev cpan[2]> install My::App cpanm --mirror http://remotehost/dev --mirror-only My::App pinto --root=http://remotehost install --stack=dev My::App
  • 185. Using pintod For Installation $ cpan cpan[1]> o conf urllist http://remotehost/dev cpan[2]> install My::App cpanm --mirror http://remotehost/dev --mirror-only My::App pinto --root=http://remotehost install --stack=dev My::App point to pinto ser ver
  • 186. Using pintod For Installation $ cpan cpan[1]> o conf urllist http://remotehost/dev cpan[2]> install My::App cpanm --mirror http://remotehost/dev --mirror-only My::App pinto --root=http://remotehost install --stack=dev My::App specify the stack
  • 187. Using pintod For Installation $ cpan cpan[1]> o conf urllist http://remotehost/dev cpan[2]> install My::App cpanm --mirror http://remotehost/dev --mirror-only My::App pinto --root=http://remotehost install --stack=dev My::App
  • 189. Pinto Net works CPAN succeeds because it is centralized
  • 190. Pinto Net works CPAN succeeds because it is centralized CPAN fails because it is centralized
  • 191. Pinto Net works CPAN succeeds because it is centralized CPAN fails because it is centralized Pinto can be centralized or distributed
  • 192. Pinto Net works The CPAN Team Team 1 3 Team 2
  • 194. Pinto Net works Might not be a good idea
  • 195. Pinto Net works Might not be a good idea No obvious way to resolve namespace conflicts
  • 196. Pinto Net works Might not be a good idea No obvious way to resolve namespace conflicts We’ll have to wait and see if this pans out
  • 197. Pinto And OS Packaging • UsePinto to build up your application in some directory • Packagethe directory with your favorite OS tools • Add dependencies on non- perl stuff • Deploy as usual
  • 198. Pinto And Other Tools • Still just a pile of directories and files with an index • AnnoCPAN, MetaCPAN, CPAN::Mini::Webser ver, etc. should still work
  • 199. Pinto versus Carton Pinto Carton Light weight VCS-Friendly Local Patches Stack Support Enterprise Strength
  • 200. Some Odds & Ends • Dist::Zilla::Plugin::Pinto::Add - release your dist to a Pinto repository with dzil • Dist::Zilla::Chef - use Pinto to manage your project dependencies within the dzil workflow
  • 201. Pinto Architecture Pinto Configuration Pull Add Copy Merge Logging Repository Database File Store
  • 202. Extending Pinto • Create an Action subclass and override the “execute” method • YourAction has access to the configuration, logger, and repository objects • Your Action can do whatever it wants • Like extract POD or ack source code in a distribution • But the API is not really stable yet
  • 203. Future Plans More VCS-behaviors: revert, diffs Report upstream impacts of upgrades Check stack for unsatisfiable dependencies Visualize dependency graphs Faster
  • 204. Get Yours Today https://metacpan.org/module/Pinto https://github.com/thaljef/Pinto
  • 205. Thanks For Your Time Jeffrey Thalhammer thaljef@cpan.org

Notas del editor

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n
  54. \n
  55. \n
  56. \n
  57. \n
  58. \n
  59. \n
  60. \n
  61. \n
  62. \n
  63. \n
  64. \n
  65. \n
  66. \n
  67. \n
  68. \n
  69. \n
  70. \n
  71. \n
  72. \n
  73. \n
  74. \n
  75. \n
  76. \n
  77. \n
  78. \n
  79. \n
  80. \n
  81. \n
  82. \n
  83. \n
  84. \n
  85. \n
  86. \n
  87. \n
  88. \n
  89. \n
  90. \n
  91. \n
  92. \n
  93. \n
  94. \n
  95. \n
  96. \n
  97. \n
  98. \n
  99. \n
  100. \n
  101. \n
  102. \n
  103. \n
  104. \n
  105. \n
  106. \n
  107. \n
  108. \n
  109. \n
  110. \n
  111. \n
  112. \n
  113. \n
  114. \n
  115. \n
  116. \n
  117. \n
  118. \n
  119. \n
  120. \n
  121. \n
  122. \n
  123. \n
  124. \n
  125. \n
  126. \n
  127. \n
  128. \n
  129. \n
  130. \n
  131. \n
  132. \n
  133. \n
  134. \n
  135. \n
  136. \n
  137. \n
  138. \n
  139. \n
  140. \n
  141. \n
  142. \n
  143. \n
  144. \n
  145. \n
  146. \n
  147. \n
  148. \n
  149. \n
  150. \n
  151. \n
  152. \n
  153. \n
  154. \n
  155. \n
  156. \n
  157. \n
  158. \n
  159. \n
  160. \n
  161. \n
  162. \n
  163. \n
  164. \n
  165. \n
  166. \n
  167. \n
  168. \n
  169. \n
  170. \n
  171. \n
  172. \n
  173. \n
  174. \n
  175. \n
  176. \n
  177. \n
  178. \n
  179. \n
  180. \n
  181. \n
  182. \n
  183. \n
  184. \n
  185. \n
  186. \n
  187. \n
  188. \n
  189. \n
  190. \n
  191. \n
  192. \n
  193. \n
  194. \n
  195. \n
  196. \n
  197. \n
  198. \n
  199. \n
  200. \n
  201. \n
  202. \n
  203. \n
  204. \n
  205. \n
  206. \n
  207. \n
  208. \n
  209. \n
  210. \n
  211. \n