summaryrefslogtreecommitdiff
path: root/Master/tlpkg/tlperl.straw/lib/pip.pm
blob: eda1540419c5f9498c1089c69db3fecd52e9b83a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
package pip;

use 5.00503;
use strict;
use File::Spec         ();
use File::Temp         ();
use File::Which        ();
use Getopt::Long       ();
use URI::file          ();
use Module::Plan::Base ();

use vars qw{$VERSION};
BEGIN {
	$VERSION = '1.16';
}





#####################################################################
# Main Function

# Save a copy of @ARGV for error messages
my $install = 0;
Getopt::Long::GetOptions(
	install => \$install,
);

sub main {
	unless ( @ARGV ) {
		error("Did not provide a command");
	}

	# If the first argument is a file, install it
	if ( $ARGV[0] =~ /^https?\:\/\// ) {
		return fetch_any($ARGV[0]);
	}
	if ( -f $ARGV[0] ) {
		return install_any($ARGV[0]);
	}

	error("Unknown or unsupported command '$ARGV[0]'");
}

sub fetch_any {
	my $uri = $_[0];

	# Handle tarballs via a custom Module::Plan::Lite object.
	# Also handle PAR archives
	if ( $uri =~ /\.(?:par|zip|tar\.gz)$/  ) {
		require Module::Plan::Lite;
		my $plan = Module::Plan::Lite->new(
			p5i   => 'default.p5i',
			lines => [ '', $uri ],
		);
		$plan->run;
		return 1;
	}

	# P5I files can have a plan created for the remote URI
	if ( $uri =~ /\.p5i$/ ) {
		require Module::Plan::Lite;
		my $plan = Module::Plan::Lite->new(
			p5i => $uri,
		);
		$plan->run;
		return 1;
	}

	# We don't yet support remote p5z files
	if ( $uri =~ /\.p5z$/ ) {
		error("Remote p5z installation is not yet supported");
	}

	error("Unknown or unsupported uri '$uri'");
}

sub install_any {
	# Load the plan
	my $plan = read_any(@_);

	# Run it
	$plan->run;

	return 1;
}

sub read_any {
	my $param = $_[0];

	# If the first argument is a tar.gz file, hand off to install
	if ( $param =~ /\.(?:zip|tar\.gz)$/ ) {
		return read_archive(@_);
	}

	# If the first argument is a par file, hand off to install
	if ( $param =~ /\.par$/ ) {
		return read_archive(@_);
	}

	# If the first argument is a p5i file, hand off to read
	if ( $param =~ /\.p5i$/ ) {
		return read_p5i(@_);
	}

	# If the first argument is a p5z file, hand off to instal
	if ( $param =~ /\.p5z$/ ) {
		return read_p5z(@_);
	}

	error("Unknown or unsupported file '$param'");
}

# Create the plan object from a file
sub read_p5i {
	my $pip = @_
		? shift
		: File::Spec->curdir;
	if ( -d $pip ) {
		$pip = File::Spec->catfile( $pip, 'default.p5i' );
	}
	$pip = File::Spec->rel2abs( $pip );
	unless ( -f $pip ) {
		error( "The plan file $pip does not exist" );
	}

	# Create the plan object
	my $plan = eval {
		Module::Plan::Base->read( $pip );
	};
	if ( $@ ) {
		unless ( $@ =~ /The sources directory is not owned by the current user/ ) {
			# Rethrow the error
			die $@;
		}

		# Generate an appropriate error
		my @msg = (
			"The current user does not control the default CPAN client",
			);
		if ( File::Which::which('sudo') ) {
			my $cmd = join(' ', 'sudo', '-H', $0, @_);
			push @msg, "You may need to try again with the following command:";
			push @msg, "";
			push @msg, "  $cmd";
		}
		error( @msg );
	}

	return $plan;
}

sub read_archive {
	my $archive = File::Spec->rel2abs(shift);
	unless ( -f $archive ) {
		error("Filed does no exist: $archive");
	}
	require Module::Plan::Lite;
	Module::Plan::Lite->new(
		p5i   => 'default.p5i',
		lines => [ '', URI::file->new($archive)->as_string ],
		);
}

sub read_p5z {
	my $p5z = File::Spec->rel2abs(shift);
	unless ( -f $p5z ) {
		error("File does not exist: $p5z");
	}

	# Create the temp directory
	my $dir   = File::Temp::tempdir( CLEANUP => 1 );
	my $pushd = File::pushd::pushd( $dir );

	# Extract the tarball
	require Archive::Tar;
	my @files = Archive::Tar->extract_archive( $p5z, 1 );
	unless ( @files ) {
		error( "Failed to extract P5Z file: " . Archive::Tar->error );
	}

	# Find the plan
	my $path = File::Spec->catfile( $dir, 'default.p5i' );
	unless ( -f $path ) {
		error("P5Z file did not contain a default.p5i");
	}

	# Load the plan
	return read_p5i( $path );
}





#####################################################################
# Support Functions

sub error {
	print "\n";
	print map { $_ . "\n" } @_;
	exit(255);
}

1;

=pod

=head1 NAME

pip - The Perl Installation Program, for scripted and third-party
distribution installation.

=head1 DESCRIPTION

The B<pip> ("Perl Installation Program") console application is used to
install Perl distributions in a wide variety of formats, both from CPAN
and from external third-party locations, while supporting module
dependencies that go across the boundary from third-party to CPAN.

Using B<pip> you can install CPAN modules, arbitrary tarballs from both
the local file-system or across the internet from arbitrary URIs.

You can use B<pip> to ensure that specific versions of CPAN modules are
installed I<instead> of the most current version.

And beyond just single installations, you script script a series of
these installations by creating a "P5I" (Perl 5 Installation) file.

A Perl 5 Installation (P5I) file is a small script-like file that
describes a set of distributions to install, and integrates the
installation of these distributions with the CPAN installer.

The primary use of P5I files are for installing proprietary or
non-CPAN software that may still require the installation of a
number of CPAN dependencies in order to function.

P5I files are also extensible, with the first line of the file
specifying the name of the Perl class that implements the plan.

For the moment, the class described at the top of the P5I file
must be installed.

The simple L<Module::Plan::Lite> plan class is bundled with the main
distribution, and additional types can be installed if needed.

=head2 Future Additions

Also on the development schedule for B<pip> is the creation and
installation of distributions via "P5Z" files, which are tarballs
containing a P5I file, as well as all the distribution tarballs
referenced by the P5I file.

It is also anticipated that B<pip> will gain support for L<PAR>
binary packages and potentially also for ActivePerl L<PPM> files.

=head1 USAGE

The primary use of F<pip> is to install from a P5I script, with the
canonical use case as follows:

  pip directory/myplan.p5i

This command will load the plan file F<directory/myplan.p5i>, create
the plan, and then execute it.

If only a directory name is given, F<pip> will look for a F<default.p5i>
plan in the directory. Thus, all of the following are equivalent

  pip directory
  pip directory/
  pip directory/default.p5i

If no target is provided at all, then the current directory will be used.
Thus, the following are equivalent

  pip
  pip .
  pip default.p5i
  pip ./default.p5i

=head2 Syntax of a plan file

Initially, the only plan is available is the L<Module::Plan::Lite>
(MPL) plan.

A typical MPL plan will look like the following

  # myplan.p5i
  Module::Plan::Lite
  
  Process-0.17.tar.gz
  YAML-Tiny-0.10.tar.gz

=head2 Direct installation of a single tarball

With the functionality available in F<pip>, you can find that sometimes
you don't even want to make a file at all, you just want to install a
single tarball.

The C<-i> option lets you pass the name of a single file and it will treat
it as an installer for that single file. Further, if the extention of the
tarball is .tar.gz, the B<-i> option is implied.

For example, the following are equivalent.

  # Installing with the -i|--install option
  > pip Process-0.17.tar.gz
  > pip -i Process-0.17.tar.gz
  > pip --install Process-0.17.tar.gz
  
  # Installing from the file as normal
  > pip ./default.p5i
  
  # myplan.p5i
  Module::Plan::Lite
  
  Process-0.17.tar.gz

The C<-i> option can be used with any single value supported by
L<Module::Plan::Lite> (see above).

This means you can also use B<pip> to install a distribution from any
arbitrary URI, including installing direct from a subversion repository.

  > pip http://svn.ali.as/cpan/release/Process-0.17.tar.gz

=head1 SUPPORT

This module is stored in an Open Repository at the following address.

L<http://svn.ali.as/cpan/trunk/pip>

Write access to the repository is made available automatically to any
published CPAN author, and to most other volunteers on request.

If you are able to submit your bug report in the form of new (failing)
unit tests, or can apply your fix directly instead of submitting a patch,
you are B<strongly> encouraged to do so. The author currently maintains
over 100 modules and it may take some time to deal with non-Critical bug
reports or patches.

This will guarentee that your issue will be addressed in the next
release of the module.

If you cannot provide a direct test or fix, or don't have time to do so,
then regular bug reports are still accepted and appreciated via the CPAN
bug tracker.

L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=pip>

For other issues, for commercial enhancement and support, or to have your
write access enabled for the repository, contact the author at the email
address above.

=head1 AUTHORS

Adam Kennedy E<lt>adamk@cpan.orgE<gt>

=head1 SEE ALSO

L<Module::Plan::Base>, L<Module::Plan::Lite>, L<Module::Plan>

=head1 COPYRIGHT

Copyright 2006 - 2009 Adam Kennedy.

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

The full text of the license can be found in the
LICENSE file included with this module.

=cut