Net-GitHub-0.55/000755 000765 000024 00000000000 12254516254 014140 5ustar00faylandstaff000000 000000 Net-GitHub-0.55/Changes000644 000765 000024 00000012144 12254515142 015430 0ustar00faylandstaff000000 000000 Revision history for Net-GitHub 0.55 2013-12-19 - remove JSON::XS requirements in Makefile.PL (no code changes) 0.54 2013-09-25 - $user->contributions (mikegrb)(Rev Michael Greb) 0.53 2013.09.01 - listing all public repos (kimmel) 0.52 2013.03.28 - Fix argument handling for pulls (dagolden) 0.51 2013.03.14 - move pod.t to xt and fix POD (RT 83926) 0.50 2012.11.28 - repos merging and statuses - fix gist comments changes - # TODO. Repos Contents, Activity Notifications 0.49 2012.11.28 - remove V2 - add search api 0.48 2012.11.15 - repackage 0.47 2012.11.07 - Documentation to demonstrate enterprise use (nebulous) - Fix @_ vs shift bug for milestones (nebulous) 0.46 2012.05.07 - fix user emails (hdragolov (Hristo Dragolov)) 0.45 2012.05.03 - pagination (ioanrogers (Ioan Rogers)) 0.44 2012.04.12 - bump up version 0.43_02 2012.03.31 - Fixed small typo that breaks is_following, follow and unfollow (worr) - tree functions to Net::GitHub::V3::GitData (worr) 0.43_01 2012.03.30 - NOTE: We will terminate API v1 and API v2 in 1 month on May 1st, 2012 (From https://github.com/blog/1090-github-api-moving-on) - so V3 is default on now - access_token can be created with Net::GitHub::V3::OAuth create_authorization - OAuth API - Events API 0.42 2012.03.23 - Fixed typo in Net::GitHub::V2::NoRepo.pm that crippled App::GitHub (worr) 0.41 2012.03.22 - still let V2 as default to make ppl using token happy - api_throttle work with unauthenticated requests 0.40_04 2011.10.20 - fix Content-Type check by regex (V3) 0.40_03 2011.10.14 - Use utf8 => 1 for JSON::Any by default. (jamesronan (James Ronan)) - if you still want to use V2, pass version => 2 0.40_02 2011.09.29 - Orgs, Git Data and Gists - code cleanup and built on-fly 0.40_01 2011.09.28 - access_token patch on V2 (c9s) - V3 API by default (no backwards with V2, if you still want to stick with V2, pass version => 2) - Note: Missing Orgs, Gists, Git Data (will be added in next version soon) 0.30 2011.08.27 - Default to GET method if we've no data to POST (Lubomir Rintel) - repository update (Lubomir Rintel) - Slow down with requests if we're approaching the rate limit (Lubomir Rintel) - Make it possible to turn API errors into exceptions (Lubomir Rintel) 0.29 2011.05.07 always_Authorization for private respo 0.28 2011.03.06 use official GitHub API request instead of screen-scraping for 'comments' issues by spang (Christine Spang) 0.27 2011.02.17 requires HTTP::Request::Common; (RT 65787 by JQUELIN) 0.26 2011.01.20 fix Makefile.PL 0.25 2011.01.19 partial implementation of Pull Request API (doy) 0.24 2011.01.01 Organizations API (fayland) update Auth to 'Basic Auth' (fayland) 0.23 2010.11.04 Moose has deprected 'excludes', '-excludes' is preferred (datamuc) 0.22 2010.05.26 token and login are really optional (franck cuny) 0.21 2010.05.18 try to load user and token from .gitconfig if not specified in new (franck cuny) 0.20 2010.01.27 add languages support to repositories api (franck cuny) 0.19 2009.09.05 Bugfix: Send delete token to GitHub, not obj hash (spang) 0.18 2009.06.14 Switch to Any::Moose from Moose (Jesse Vincent) Issue comments (sunnavy) 0.17 2009.05.19 use 'https' for user->update, issue->comment etc. 0.16 2009.05.19 fix the role (Chris Nehren) 0.15 2009.05.16 Refactored role support. (Chris Nehren) Copy $repo->list to $user->list where it makes more sense (and doesn't require a repo object). (Chris Nehren) 0.14 2009.05.15 Users pod fix 0.13 2009.05.15 Refactor the role system to be finer-grained based upon whether a class needs repo access or not. (Chris Nehren) 0.12 2009.05.01 Commits.pm sub file default branch as 'master' Strip the leading '/' from paths provided to get_json_to_obj* methods (bingos) make_immutable inline_constructor => 0 0.11 2009.4.21 deal with 404 0.10 2009.4.21 owner/repo/login/token are 'ro' to avoid bug fix user->update 0.09 2009.4.21 issues pod tweak by c9s search issues and comment issues (new API) 0.08 2009.4.19 bug fix 0.07 2009.4.19 make 'owner' and 'repo' is => 'rw' for App::GitHub 0.06 2009.4.18 http://github.com/api/v2/ (API are changed) 0.05 2009.3.11 pod fix 0.04 2009.3.10 use WWW::Mechanize::GZip add N::G::Project::Wiki and Downloads Wiki new_page/edit_page/edit_or_new Downloads downloads 0.03 2009.3.9 add login in Net::GitHub::Role pod updates, bug fixes and API enhancement 0.01 2009.3.8 First version, released on an unsuspecting world. Net-GitHub-0.55/inc/000755 000765 000024 00000000000 12254516254 014711 5ustar00faylandstaff000000 000000 Net-GitHub-0.55/lib/000755 000765 000024 00000000000 12254516254 014706 5ustar00faylandstaff000000 000000 Net-GitHub-0.55/Makefile.PL000644 000765 000024 00000001227 12254515137 016113 0ustar00faylandstaff000000 000000 use inc::Module::Install; name 'Net-GitHub'; all_from 'lib/Net/GitHub.pm'; author 'Fayland Lam '; license 'perl'; repository 'https://github.com/fayland/perl-net-github'; requires 'MIME::Base64'; requires 'URI'; requires 'URI::Escape'; requires 'Any::Moose'; requires 'Crypt::SSLeay'; requires 'WWW::Mechanize::GZip'; requires 'JSON::Any'; # requires 'JSON::XS'; # avoid "Couldn't find a JSON package. Need XS, JSON, or DWIW" requires 'HTML::TreeBuilder'; requires 'HTTP::Request::Common'; build_requires 'Test::More'; test_requires 'Test::MockModule'; test_requires 'File::Slurp'; tests('t/*.t t/*/*.t'); auto_install; WriteAll; Net-GitHub-0.55/MANIFEST000644 000765 000024 00000001631 12254516235 015271 0ustar00faylandstaff000000 000000 Changes inc/Module/AutoInstall.pm inc/Module/Install.pm inc/Module/Install/AutoInstall.pm inc/Module/Install/Base.pm inc/Module/Install/Can.pm inc/Module/Install/Fetch.pm inc/Module/Install/Include.pm inc/Module/Install/Makefile.pm inc/Module/Install/Metadata.pm inc/Module/Install/Win32.pm inc/Module/Install/WriteAll.pm lib/Net/GitHub.pm lib/Net/GitHub/V3.pm lib/Net/GitHub/V3/Events.pm lib/Net/GitHub/V3/Gists.pm lib/Net/GitHub/V3/GitData.pm lib/Net/GitHub/V3/Issues.pm lib/Net/GitHub/V3/OAuth.pm lib/Net/GitHub/V3/Orgs.pm lib/Net/GitHub/V3/PullRequests.pm lib/Net/GitHub/V3/Query.pm lib/Net/GitHub/V3/Repos.pm lib/Net/GitHub/V3/Search.pm lib/Net/GitHub/V3/Users.pm Makefile.PL MANIFEST This list of files META.yml README t/00-load.t xt/pod.t xt/v3/01-access-token.t xt/v3/02-user-pass.t xt/v3/100-users.t xt/v3/200-repos.t xt/v3/500-org.t xt/v3/600-git_data.t xt/v3/700-gists.t xt/v3/800-oauth.t xt/v3/900-search.t Net-GitHub-0.55/META.yml000644 000765 000024 00000001522 12254516227 015411 0ustar00faylandstaff000000 000000 --- abstract: 'Perl Interface for github.com' author: - 'Fayland Lam, C<< >>' - 'Fayland Lam ' build_requires: ExtUtils::MakeMaker: 6.36 File::Slurp: 0 Test::MockModule: 0 Test::More: 0 configure_requires: ExtUtils::MakeMaker: 6.36 distribution_type: module dynamic_config: 1 generated_by: 'Module::Install version 1.06' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Net-GitHub no_index: directory: - inc - t - xt requires: Any::Moose: 0 Crypt::SSLeay: 0 HTML::TreeBuilder: 0 HTTP::Request::Common: 0 JSON::Any: 0 MIME::Base64: 0 URI: 0 URI::Escape: 0 WWW::Mechanize::GZip: 0 resources: license: http://dev.perl.org/licenses/ repository: https://github.com/fayland/perl-net-github version: 0.55 Net-GitHub-0.55/README000644 000765 000024 00000004533 12254514652 015025 0ustar00faylandstaff000000 000000 NAME Net::GitHub - Perl Interface for github.com SYNOPSIS use Net::GitHub; my $github = Net::GitHub->new( # Net::GitHub::V3 login => 'fayland', pass => 'secret' ); # Pass api_url for GitHub Enterprise installations my $github = Net::GitHub->new( # Net::GitHub::V3 login => 'fayland', pass => 'secret', api_url => 'https://gits.aresweet.com/api/v3' ); # suggested # use OAuth to create token with user/pass my $github = Net::GitHub->new( # Net::GitHub::V3 access_token => $token ); # L my $user = $github->user->show('nothingmuch'); $github->user->update( bio => 'Just Another Perl Programmer' ); # L my @repos = $github->repos->list; my $rp = $github->repos->create( { "name" => "Hello-World", "description" => "This is your first repo", "homepage" => "https://github.com" } ); DESCRIPTION is a popular git host. This distribution provides easy methods to access GitHub via their APIs. Check for more details of the GitHub APIs. Read Net::GitHub::V3 for API usage. If you prefer object oriented way, Pithub is 'There is more than one way to do it'. FAQ * create access_token for Non-Web Application my $gh = Net::GitHub::V3->new( login => 'fayland', pass => 'secret' ); my $oauth = $gh->oauth; my $o = $oauth->create_authorization( { scopes => ['user', 'public_repo', 'repo', 'gist'], # just ['public_repo'] note => 'test purpose', } ); print $o->{token}; after create the token, you can use it without your password publicly written my $github = Net::GitHub->new( access_token => $token, # from above ); Git SEE ALSO Any::Moose, Pithub AUTHOR Fayland Lam, "" Everyone who is listed in Changes. COPYRIGHT & LICENSE Copyright 2009-2012 Fayland Lam all rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Net-GitHub-0.55/t/000755 000765 000024 00000000000 12254516254 014403 5ustar00faylandstaff000000 000000 Net-GitHub-0.55/xt/000755 000765 000024 00000000000 12254516254 014573 5ustar00faylandstaff000000 000000 Net-GitHub-0.55/xt/pod.t000644 000765 000024 00000000350 12254514652 015540 0ustar00faylandstaff000000 000000 #!perl -T use strict; use warnings; use Test::More; # Ensure a recent version of Test::Pod my $min_tp = 1.22; eval "use Test::Pod $min_tp"; plan skip_all => "Test::Pod $min_tp required for testing POD" if $@; all_pod_files_ok(); Net-GitHub-0.55/xt/v3/000755 000765 000024 00000000000 12254516254 015123 5ustar00faylandstaff000000 000000 Net-GitHub-0.55/xt/v3/01-access-token.t000644 000765 000024 00000000743 12254514652 020111 0ustar00faylandstaff000000 000000 #!/usr/bin/env perl use Test::More; use Net::GitHub; plan skip_all => 'Please export environment variable GITHUB_ACCESS_TOKEN' unless $ENV{GITHUB_ACCESS_TOKEN}; my $gh = Net::GitHub->new( access_token => $ENV{GITHUB_ACCESS_TOKEN}); diag( 'Using access_token = ' . $ENV{GITHUB_ACCESS_TOKEN} ); ok( $gh ); my $data = $gh->user->show(); ok( $data ); ok( $data->{id} ); ok( $data->{gravatar_id} ); ok( $data->{email} ); ok( $data->{login} ); ok( $data->{name} ); done_testing; 1;Net-GitHub-0.55/xt/v3/02-user-pass.t000644 000765 000024 00000000776 12254514652 017463 0ustar00faylandstaff000000 000000 #!/usr/bin/env perl use Test::More; use Net::GitHub::V3; plan skip_all => 'Please export environment variable GITHUB_USER/GITHUB_PASS' unless $ENV{GITHUB_USER} and $ENV{GITHUB_PASS}; my $gh = Net::GitHub::V3->new( login => $ENV{GITHUB_USER}, pass => $ENV{GITHUB_PASS}); diag( 'Using user = ' . $ENV{GITHUB_USER} ); ok( $gh ); my $data = $gh->user->show(); ok( $data ); ok( $data->{id} ); ok( $data->{gravatar_id} ); ok( $data->{email} ); ok( $data->{login} ); ok( $data->{name} ); done_testing; 1;Net-GitHub-0.55/xt/v3/100-users.t000644 000765 000024 00000002262 12254514652 016751 0ustar00faylandstaff000000 000000 #!/usr/bin/env perl use strict; use warnings; use Test::More; use Net::GitHub::V3; plan skip_all => 'Please export environment variable GITHUB_USER/GITHUB_PASS' unless $ENV{GITHUB_USER} and $ENV{GITHUB_PASS}; my $gh = Net::GitHub::V3->new( login => $ENV{GITHUB_USER}, pass => $ENV{GITHUB_PASS}); my $user = $gh->user; diag( 'Using user = ' . $ENV{GITHUB_USER} ); ok( $gh ); ok( $user ); diag( 'Updating ..' ); my $bio = 'another Perl programmer and Father'; my $uu = $user->update( bio => $bio ); is($uu->{bio}, $bio); sleep 1; my $u = $user->show(); is($u->{bio}, $bio); is_deeply($u, $uu); =pod diag("Testing follow/unfollow"); my $f = 'c9s'; my $is_following = $user->is_following($f); if ($is_following) { diag("unfollow then follow"); my $ok = $user->unfollow($f); ok($ok); $ok = $user->follow($f); ok($ok); my $following = $user->following; ok( (grep { $_->{login} eq $f } @$following ) ); } else { diag("follow then unfollow"); my $ok = $user->follow($f); ok($ok); my $following = $user->following; ok( (grep { $_->{login} eq $f } @$following ) ); $ok = $user->unfollow($f); ok($ok); } =cut done_testing; 1;Net-GitHub-0.55/xt/v3/200-repos.t000644 000765 000024 00000001475 12254514652 016746 0ustar00faylandstaff000000 000000 #!/usr/bin/env perl use strict; use warnings; use Test::More; use Net::GitHub::V3; plan skip_all => 'Please export environment variable GITHUB_USER/GITHUB_PASS' unless $ENV{GITHUB_USER} and $ENV{GITHUB_PASS}; my $gh = Net::GitHub::V3->new( login => $ENV{GITHUB_USER}, pass => $ENV{GITHUB_PASS}); my $repos = $gh->repos; diag( 'Using user = ' . $ENV{GITHUB_USER} ); ok( $gh ); ok( $repos ); my @p = $repos->list; ok(@p > 3, 'more than 3 repos'); =pod $repos->set_default_user_repo('fayland', 'perl-net-github'); my $hook = $repos->create_hook( { "name" => "web", "active" => 'true', "config" => { "url" => "http://something.com/webhook" } } ); use Data::Dumper; diag(Dumper(\$hook)); my @hooks = $repos->hooks; is(@hooks, 1); my $st = $repos->delete_hook($hook->{id}); is($st, 1); =cut done_testing; 1;Net-GitHub-0.55/xt/v3/500-org.t000644 000765 000024 00000001423 12254514652 016401 0ustar00faylandstaff000000 000000 #!/usr/bin/env perl use strict; use warnings; use Test::More; use Net::GitHub::V3; plan skip_all => 'Please export environment variable GITHUB_USER/GITHUB_PASS' unless $ENV{GITHUB_USER} and $ENV{GITHUB_PASS}; my $gh = Net::GitHub::V3->new( login => $ENV{GITHUB_USER}, pass => $ENV{GITHUB_PASS}); my $org = $gh->org; diag( 'Using user = ' . $ENV{GITHUB_USER} ); ok( $gh ); ok( $org ); =pod my $o = $org->org('perlchina'); # PerlChina ok($o); is($o->{'billing_email'}, 'perlchina@googlegroups.com'); $o = $org->update_org('perlchina', { name => 'PerlChina' }); ok($o); is($o->{name}, 'PerlChina'); =cut my $is_member = $org->is_member('perlchina', 'fayland'); is($is_member, 1); $is_member = $org->is_member('perlchina', 'nothingmuch'); is($is_member, 0); done_testing; 1;Net-GitHub-0.55/xt/v3/600-git_data.t000644 000765 000024 00000001231 12254514652 017364 0ustar00faylandstaff000000 000000 #!/usr/bin/env perl use strict; use warnings; use Test::More; use Net::GitHub::V3; plan skip_all => 'Please export environment variable GITHUB_USER/GITHUB_PASS' unless $ENV{GITHUB_USER} and $ENV{GITHUB_PASS}; my $gh = Net::GitHub::V3->new( login => $ENV{GITHUB_USER}, pass => $ENV{GITHUB_PASS}); my $git_data = $gh->git_data; diag( 'Using user = ' . $ENV{GITHUB_USER} ); ok( $gh ); ok( $git_data ); $git_data->set_default_user_repo('fayland', 'perl-net-github'); my $blob = $git_data->blob('5a1faac3ad54da26be60970ddbbdfbf6b08fdc57'); ok($blob); my $commit = $git_data->commit('5a1faac3ad54da26be60970ddbbdfbf6b08fdc57'); ok($commit); done_testing; 1;Net-GitHub-0.55/xt/v3/700-gists.t000644 000765 000024 00000001245 12254514652 016747 0ustar00faylandstaff000000 000000 #!/usr/bin/env perl use strict; use warnings; use Test::More; use Net::GitHub::V3; plan skip_all => 'Please export environment variable GITHUB_USER/GITHUB_PASS' unless $ENV{GITHUB_USER} and $ENV{GITHUB_PASS}; my $gh = Net::GitHub::V3->new( login => $ENV{GITHUB_USER}, pass => $ENV{GITHUB_PASS}); my $gist = $gh->gist; diag( 'Using user = ' . $ENV{GITHUB_USER} ); ok($gist); my $g = $gist->create( { "description" => "the description for this gist", "public" => 'true', "files" => { "file1.txt" => { "content" => "String file contents" } } } ); ok($g); use Data::Dumper; diag(Dumper(\$g)); done_testing; 1;Net-GitHub-0.55/xt/v3/800-oauth.t000755 000765 000024 00000001106 12254514652 016736 0ustar00faylandstaff000000 000000 #!/usr/bin/env perl use strict; use warnings; use Test::More; use Net::GitHub::V3; plan skip_all => 'Please export environment variable GITHUB_USER/GITHUB_PASS' unless $ENV{GITHUB_USER} and $ENV{GITHUB_PASS}; my $gh = Net::GitHub::V3->new( login => $ENV{GITHUB_USER}, pass => $ENV{GITHUB_PASS}); my $oauth = $gh->oauth; diag( 'Using user = ' . $ENV{GITHUB_USER} ); ok($oauth); my $o = $oauth->create_authorization( { scopes => ['user', 'public_repo', 'repo', 'gist'], note => 'test purpose', } ); ok($o); use Data::Dumper; diag(Dumper(\$o)); done_testing; 1;Net-GitHub-0.55/xt/v3/900-search.t000644 000765 000024 00000001032 12254514652 017057 0ustar00faylandstaff000000 000000 #!/usr/bin/env perl use strict; use warnings; use Test::More; use Net::GitHub::V3; use Data::Dumper; my $gh = Net::GitHub::V3->new(); my $search = $gh->search; ok( $gh ); ok( $search ); my %data = $search->issues('fayland', 'perl-net-github', 'closed', 'milestone'); diag Dumper(\$data{issues}); #%data = $search->repos('perl-net-github'); #diag Dumper(\$data{repositories}); #%data = $search->user('fayland'); #diag Dumper(\$data{users}); %data = $search->email('fayland@gmail.com'); diag Dumper(\$data{user}); done_testing; 1;Net-GitHub-0.55/t/00-load.t000644 000765 000024 00000000222 12254514652 015720 0ustar00faylandstaff000000 000000 #!perl -T use Test::More tests => 1; BEGIN { use_ok( 'Net::GitHub' ); } diag( "Testing Net::GitHub $Net::GitHub::VERSION, Perl $], $^X" ); Net-GitHub-0.55/lib/Net/000755 000765 000024 00000000000 12254516254 015434 5ustar00faylandstaff000000 000000 Net-GitHub-0.55/lib/Net/GitHub/000755 000765 000024 00000000000 12254516254 016616 5ustar00faylandstaff000000 000000 Net-GitHub-0.55/lib/Net/GitHub.pm000644 000765 000024 00000005116 12254515061 017152 0ustar00faylandstaff000000 000000 package Net::GitHub; use Any::Moose; use Net::GitHub::V3; our $VERSION = '0.55'; our $AUTHORITY = 'cpan:FAYLAND'; sub new { my $class = shift; my $params = $class->BUILDARGS(@_); return Net::GitHub::V3->new($params); #return $class->meta->new_object( __INSTANCE__ => $obj, @_,); } no Any::Moose; __PACKAGE__->meta->make_immutable(inline_constructor => 0); 1; __END__ =head1 NAME Net::GitHub - Perl Interface for github.com =head1 SYNOPSIS use Net::GitHub; my $github = Net::GitHub->new( # Net::GitHub::V3 login => 'fayland', pass => 'secret' ); # Pass api_url for GitHub Enterprise installations my $github = Net::GitHub->new( # Net::GitHub::V3 login => 'fayland', pass => 'secret', api_url => 'https://gits.aresweet.com/api/v3' ); # suggested # use OAuth to create token with user/pass my $github = Net::GitHub->new( # Net::GitHub::V3 access_token => $token ); # L my $user = $github->user->show('nothingmuch'); $github->user->update( bio => 'Just Another Perl Programmer' ); # L my @repos = $github->repos->list; my $rp = $github->repos->create( { "name" => "Hello-World", "description" => "This is your first repo", "homepage" => "https://github.com" } ); =head1 DESCRIPTION L is a popular git host. This distribution provides easy methods to access GitHub via their APIs. Check L for more details of the GitHub APIs. Read L for API usage. If you prefer object oriented way, L is 'There is more than one way to do it'. =head2 FAQ =over 4 =item * create access_token for Non-Web Application my $gh = Net::GitHub::V3->new( login => 'fayland', pass => 'secret' ); my $oauth = $gh->oauth; my $o = $oauth->create_authorization( { scopes => ['user', 'public_repo', 'repo', 'gist'], # just ['public_repo'] note => 'test purpose', } ); print $o->{token}; after create the token, you can use it without your password publicly written my $github = Net::GitHub->new( access_token => $token, # from above ); =back =head1 Git L =head1 SEE ALSO L, L =head1 AUTHOR Fayland Lam, C<< >> Everyone who is listed in B. =head1 COPYRIGHT & LICENSE Copyright 2009-2012 Fayland Lam all rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Net-GitHub-0.55/lib/Net/GitHub/V3/000755 000765 000024 00000000000 12254516254 017106 5ustar00faylandstaff000000 000000 Net-GitHub-0.55/lib/Net/GitHub/V3.pm000644 000765 000024 00000016023 12254514652 017446 0ustar00faylandstaff000000 000000 package Net::GitHub::V3; use Any::Moose; our $VERSION = '0.49'; our $AUTHORITY = 'cpan:FAYLAND'; with 'Net::GitHub::V3::Query'; use Net::GitHub::V3::Users; use Net::GitHub::V3::Repos; use Net::GitHub::V3::Issues; use Net::GitHub::V3::PullRequests; use Net::GitHub::V3::Orgs; use Net::GitHub::V3::GitData; use Net::GitHub::V3::Gists; use Net::GitHub::V3::OAuth; use Net::GitHub::V3::Events; use Net::GitHub::V3::Search; has '+is_main_module' => (default => 1); has 'user' => ( is => 'rw', isa => 'Net::GitHub::V3::Users', lazy => 1, default => sub { my $self = shift; return Net::GitHub::V3::Users->new( $self->args_to_pass ); }, ); has 'org' => ( is => 'rw', isa => 'Net::GitHub::V3::Orgs', lazy => 1, default => sub { my $self = shift; return Net::GitHub::V3::Orgs->new( $self->args_to_pass ); }, ); has 'gist' => ( is => 'rw', isa => 'Net::GitHub::V3::Gists', lazy => 1, default => sub { my $self = shift; return Net::GitHub::V3::Gists->new( $self->args_to_pass ); }, ); has 'repos' => ( is => 'rw', isa => 'Net::GitHub::V3::Repos', lazy => 1, predicate => 'is_repos_init', default => sub { my $self = shift; return Net::GitHub::V3::Repos->new( $self->args_to_pass ); }, ); has 'issue' => ( is => 'rw', isa => 'Net::GitHub::V3::Issues', lazy => 1, predicate => 'is_issue_init', default => sub { my $self = shift; return Net::GitHub::V3::Issues->new( $self->args_to_pass ); }, ); has 'pull_request' => ( is => 'rw', isa => 'Net::GitHub::V3::PullRequests', lazy => 1, predicate => 'is_pull_request_init', default => sub { my $self = shift; return Net::GitHub::V3::PullRequests->new( $self->args_to_pass ); }, ); has 'git_data' => ( is => 'rw', isa => 'Net::GitHub::V3::GitData', lazy => 1, predicate => 'is_git_data_init', default => sub { my $self = shift; return Net::GitHub::V3::GitData->new( $self->args_to_pass ); }, ); has 'oauth' => ( is => 'rw', isa => 'Net::GitHub::V3::OAuth', lazy => 1, default => sub { my $self = shift; return Net::GitHub::V3::OAuth->new( $self->args_to_pass ); }, ); has 'event' => ( is => 'rw', isa => 'Net::GitHub::V3::Events', lazy => 1, default => sub { my $self = shift; return Net::GitHub::V3::Events->new( $self->args_to_pass ); }, ); has 'search' => ( is => 'rw', isa => 'Net::GitHub::V3::Search', lazy => 1, default => sub { my $self = shift; return Net::GitHub::V3::Search->new( $self->args_to_pass ); }, ); no Any::Moose; __PACKAGE__->meta->make_immutable; 1; __END__ =head1 NAME Net::GitHub::V3 - Github API v3 =head1 SYNOPSIS Prefer: use Net::GitHub; my $gh = Net::GitHub->new( version => 3, login => 'fayland', pass => 'mypass', # or # access_token => $oauth_token ); Or: use Net::GitHub::V3; my $gh = Net::GitHub::V3->new( login => 'fayland', pass => 'mypass', # or # access_token => $oauth_token ); =head1 DESCRIPTION L =head2 ATTRIBUTES =head3 Authentication There are two ways to authenticate through GitHub API v3: =over 4 =item login/pass my $gh = Net::GitHub::V3->new( login => $ENV{GITHUB_USER}, pass => $ENV{GITHUB_PASS} ); =item access_token my $gh = Net::GitHub->new( access_token => $ENV{GITHUB_ACCESS_TOKEN} ); =back =head3 raw_response my $gh = Net::GitHub->new( # login/pass or access_token raw_response => 1 ); return raw L object =head3 raw_string my $gh = Net::GitHub->new( # login/pass or access_token raw_string => 1 ); return L response content as string =head3 api_throttle my $gh = Net::GitHub->new( # login/pass or access_token api_throttle => 0 ); To disable call rate limiting (e.g. if your account is whitelisted), set B to 0. =head3 RaiseError By default, error responses are propagated to the user as they are received from the API. By switching B on you can make the be turned into exceptions instead, so that you don't have to check for error response after every call. =head3 next_url, last_url, prev_url, first_url Any methods which return multiple results I be paginated. After performing a query you should check to see if there are more results. These attributes will be reset for each query. The predicates to check these attributes are C, C, C and C. See Github's documentation: L The C parameter mentioned in their docs is B supported by this module. my @issues = $gh->issue->repos_issues; while ($gh->issue->has_next_page) { push @issues, $gh->issue->query($gh->issue->next_url); ## OR ## push @issues, $gh->issue->next_page); } =head2 METHODS =head3 query($method, $url, $data) my $data = $gh->query('/user'); $gh->query('PATCH', '/user', $data); $gh->query('DELETE', '/user/emails', [ 'myemail@somewhere.com' ]); query API directly =head3 next_page When the results have been paginated, C is sugar for the common case of iterating through all the pages in order. It simply calls C with the C. =head3 set_default_user_repo $gh->set_default_user_repo('fayland', 'perl-net-github'); # take effects for all $gh-> $gh->repos->set_default_user_repo('fayland', 'perl-net-github'); # take effects on $gh->repos B 1. SET user/repos before call methods below $gh->set_default_user_repo('fayland', 'perl-net-github'); my @contributors = $gh->repos->contributors; 2. If it is just for once, we can pass :user, :repo before any arguments my @contributors = $repos->contributors($user, $repo); =head2 MODULES =head3 user my $user = $gh->user->show('nothingmuch'); $gh->user->update( bio => 'Just Another Perl Programmer' ); L =head3 repos my @repos = $gh->repos->list; my $rp = $gh->repos->create( { "name" => "Hello-World", "description" => "This is your first repo", "homepage" => "https://github.com" } ); L =head3 issue my @issues = $gh->issue->issues(); my $issue = $gh->issue->issue($issue_id); L =head3 pull_request my @pulls = $gh->pull_request->pulls(); L =head3 org my @orgs = $gh->org->orgs; L =head3 git_data L =head3 gist L =head3 oauth L =head3 event L =head3 search L =head1 SEE ALSO L, L =head1 AUTHOR & COPYRIGHT & LICENSE Refer L Net-GitHub-0.55/lib/Net/GitHub/V3/Events.pm000644 000765 000024 00000003766 12254514652 020724 0ustar00faylandstaff000000 000000 package Net::GitHub::V3::Events; use Any::Moose; our $VERSION = '0.40'; our $AUTHORITY = 'cpan:FAYLAND'; use URI::Escape; with 'Net::GitHub::V3::Query'; ## build methods on fly my %__methods = ( events => { url => '/events' }, repos_events => { url => "/repos/%s/%s/events" }, issues_events => { url => "/repos/%s/%s/issues/events" }, networks_events => { url => "/networks/%s/%s/events" }, orgs_events => { url => "/orgs/%s/events" }, user_received_events => { url => "/users/%s/received_events" }, user_public_received_events => { url => "/users/%s/received_events/public" }, user_events => { url => "/users/%s/events" }, user_public_events => { url => "/users/%s/events/public" }, user_orgs_events => { url => "/users/%s/events/orgs/%s" }, ); __build_methods(__PACKAGE__, %__methods); no Any::Moose; __PACKAGE__->meta->make_immutable; 1; __END__ =head1 NAME Net::GitHub::V3::Events - GitHub Events API =head1 SYNOPSIS use Net::GitHub::V3; my $gh = Net::GitHub::V3->new; # read L to set right authentication info my $event = $gh->event; =head1 DESCRIPTION =head2 METHODS =head3 Events L =over 4 =item events my @events = $event->events(); =item repos_events =item issues_events =item networks_events my @events = $event->repos_events($user, $repo); my @events = $event->issues_events($user, $repo); my @events = $event->networks_events($user, $repo); =item orgs_events my @events = $event->orgs_events($org); =item user_received_events =item user_public_received_events =item user_events =item user_public_events my @events = $event->user_received_events($user); my @events = $event->user_public_received_events($user); my @events = $event->user_events($user); my @events = $event->user_public_events($user); =item user_orgs_events my @events = $event->user_orgs_events($user, $org); =back =head1 AUTHOR & COPYRIGHT & LICENSE Refer L Net-GitHub-0.55/lib/Net/GitHub/V3/Gists.pm000644 000765 000024 00000006403 12254514652 020540 0ustar00faylandstaff000000 000000 package Net::GitHub::V3::Gists; use Any::Moose; our $VERSION = '0.40'; our $AUTHORITY = 'cpan:FAYLAND'; use URI::Escape; with 'Net::GitHub::V3::Query'; sub gists { my ( $self, $user ) = @_; my $u = $user ? "/users/" . uri_escape($user) . '/gists' : '/gists'; return $self->query($u); } ## build methods on fly my %__methods = ( public_gists => { url => "/gists/public" }, starred_gists => { url => "/gists/starred" }, gist => { url => "/gists/%s" }, create => { url => "/gists", method => "POST", args => 1 }, update => { url => "/gists/%s", method => "PATCH", args => 1 }, star => { url => "/gists/%s/star", method => "PUT", check_status => 204 }, unstar => { url => "/gists/%s/star", method => "DELETE", check_status => 204 }, is_starred => { url => "/gists/%s/star", method => "GET", check_status => 204 }, fork => { url => "/gists/%s/fork", method => "POST" }, delete => { url => "/gists/%s", method => "DELETE", check_status => 204 }, # http://developer.github.com/v3/gists/comments/ comments => { url => "/gists/%s/comments" }, comment => { url => "/gists/%s/comments/%s" }, create_comment => { url => "/gists/%s/comments", method => 'POST', args => 1 }, update_comment => { url => "/gists/%s/comments/%s", method => 'PATCH', args => 1 }, delete_comment => { url => "/gists/%s/comments/%s", method => 'DELETE', check_status => 204 }, ); __build_methods(__PACKAGE__, %__methods); no Any::Moose; __PACKAGE__->meta->make_immutable; 1; __END__ =head1 NAME Net::GitHub::V3::Gists - GitHub Gists API =head1 SYNOPSIS use Net::GitHub::V3; my $gh = Net::GitHub::V3->new; # read L to set right authentication info my $gist = $gh->gist; =head1 DESCRIPTION =head2 METHODS =head3 Git Data L =over 4 =item gists my @gists = $gist->gists; my @gists = $gist->gists('nothingmuch'); =item public_gists =item starred_gists my @gists = $gist->public_gists; my @gists = $gist->starred_gists; =item gist my $gist = $gist->gist($gist_id); =item create my $gist = $gist->create( { "description" => "the description for this gist", "public" => 'true', "files" => { "file1.txt" => { "content" => "String file contents" } } } ); =item update my $g = $gist->update( $gist_id, { description => "edited desc" } ); =item star =item unstar =item is_starred my $st = $gist->star($gist_id); my $st = $gist->unstar($gist_id); my $st = $gist->is_starred($gist_id); =item fork =item delete my $g = $gist->fork($gist_id); my $st = $gist->delete($gist_id); =back =head3 Gist Comments API L =over 4 =item comments =item comment =item create_comment =item update_comment =item delete_comment my @comments = $gist->comments(); my $comment = $gist->comment($comment_id); my $comment = $gist->create_comment($gist_id, { "body" => "a new comment" }); my $comment = $gist->update_comment($gist_id, $comment_id, { "body" => "Nice change" }); my $st = $gist->delete_comment($gist_id, $comment_id); =back =head1 AUTHOR & COPYRIGHT & LICENSE Refer LNet-GitHub-0.55/lib/Net/GitHub/V3/GitData.pm000644 000765 000024 00000006340 12254514652 020764 0ustar00faylandstaff000000 000000 package Net::GitHub::V3::GitData; use Any::Moose; our $VERSION = '0.40'; our $AUTHORITY = 'cpan:FAYLAND'; use URI::Escape; with 'Net::GitHub::V3::Query'; ## build methods on fly my %__methods = ( blob => { url => "/repos/%s/%s/git/blobs/%s" }, create_blob => { url => "/repos/%s/%s/git/blobs", method => 'POST', args => 1 }, commit => { url => "/repos/%s/%s/git/commits/%s" }, create_commit => { url => "/repos/%s/%s/git/commits", method => 'POST', args => 1 }, tree => { url => "/repos/%s/%s/git/trees/%s" }, trees => { url => "/repos/%s/%s/git/trees/%s?recursive=1" }, create_tree => { url => "/repos/%s/%s/git/trees", method => 'POST', args => 1 }, refs => { url => "/repos/%s/%s/git/refs" }, ref => { url => "/repos/%s/%s/git/refs/%s" }, create_ref => { url => "/repos/%s/%s/git/refs", method => 'POST', args => 1 }, update_ref => { url => "repos/%s/%s/git/refs/%s", method => 'PATCH', args => 1 }, tag => { url => "/repos/%s/%s/git/tags/%s" }, create_tag => { url => "/repos/%s/%s/git/tags", method => 'POST', args => 1 }, ); __build_methods(__PACKAGE__, %__methods); no Any::Moose; __PACKAGE__->meta->make_immutable; 1; __END__ =head1 NAME Net::GitHub::V3::GitData - GitHub Git DB API =head1 SYNOPSIS use Net::GitHub::V3; my $gh = Net::GitHub::V3->new; # read L to set right authentication info my $git_data = $gh->git_data; =head1 DESCRIPTION B 1. SET user/repos before call methods below $gh->set_default_user_repo('fayland', 'perl-net-github'); # take effects for all $gh-> $git_data->set_default_user_repo('fayland', 'perl-net-github'); # only take effect to $gh->pull_request my $blob = $git_data->blob($sha); 2. If it is just for once, we can pass :user, :repo before any arguments my $blob = $git_data->blob($user, $repo, $sha); =head2 METHODS =head3 Git Data L =head3 Blob =over 4 =item blob my $blob = $git_data->blob('5a1faac3ad54da26be60970ddbbdfbf6b08fdc57'); =item create_blob my $result = $git_data->create_blob( { content => $content, encoding => 'utf-8', } ); =back =head3 Commits L =over 4 =item commit my $commit = $git_data->commit('5a1faac3ad54da26be60970ddbbdfbf6b08fdc57'); =item create_commit =back =head3 Refs L =over 4 =item refs =item ref =item create_ref =item update_ref my @refs = $git_data->refs; my $ref = $git_data->ref($ref_id); my $ref = $git_data->create_ref($ref_data); my $ref = $git_data->update_ref($ref_id, $ref_data); =back =head3 Tags L =over 4 =item tag =item create_tag my $tag = $git_data->tag($sha); my $tag = $git_data->create_tag($tag_data); =back =head3 L =over 4 =item tree =item trees =item create_tree my $tree = $git_data->tree($sha); my $trees = $git_data->trees($sha); my $tree = $git_data->create_tree($tree_data); =back =head1 AUTHOR & COPYRIGHT & LICENSE Refer L Net-GitHub-0.55/lib/Net/GitHub/V3/Issues.pm000644 000765 000024 00000017715 12254514652 020732 0ustar00faylandstaff000000 000000 package Net::GitHub::V3::Issues; use Any::Moose; our $VERSION = '0.47'; our $AUTHORITY = 'cpan:FAYLAND'; use URI::Escape; with 'Net::GitHub::V3::Query'; sub issues { my $self = shift; my $args = @_ % 2 ? shift : { @_ }; my @p; foreach my $p (qw/filter state labels sort direction since/) { push @p, "$p=" . $args->{$p} if exists $args->{$p}; } my $u = '/issues'; $u .= '?' . join('&', @p) if @p; return $self->query($u); } sub repos_issues { my $self = shift; if (@_ < 2) { unshift @_, $self->repo; unshift @_, $self->u; } my ($user, $repos, $args) = @_; my @p; foreach my $p (qw/milestone state assignee mentioned labels sort direction since/) { push @p, "$p=" . $args->{$p} if exists $args->{$p}; } my $u = "/repos/" . uri_escape($user) . "/" . uri_escape($repos) . '/issues'; $u .= '?' . join('&', @p) if @p; return $self->query($u); } ## build methods on fly my %__methods = ( issue => { url => "/repos/%s/%s/issues/%s" }, create_issue => { url => "/repos/%s/%s/issues", method => 'POST', args => 1 }, update_issue => { url => "/repos/%s/%s/issues/%s", method => 'PATCH', args => 1 }, ## http://developer.github.com/v3/issues/comments/ comments => { url => "/repos/%s/%s/issues/%s/comments" }, comment => { url => "/repos/%s/%s/issues/comments/%s" }, create_comment => { url => "/repos/%s/%s/issues/%s/comments", method => 'POST', args => 1 }, update_comment => { url => "/repos/%s/%s/issues/comments/%s", method => 'PATCH', args => 1 }, delete_comment => { url => "/repos/%s/%s/issues/comments/%s", method => 'DELETE', check_status => 204 }, # http://developer.github.com/v3/issues/events/ events => { url => "/repos/%s/%s/issues/%s/events" }, repos_events => { url => "/repos/%s/%s/issues/events" }, event => { url => "/repos/%s/%s/issues/events/%s" }, # http://developer.github.com/v3/issues/labels/ labels => { url => "/repos/%s/%s/labels" }, label => { url => "/repos/%s/%s/labels/%s" }, create_label => { url => "/repos/%s/%s/labels", method => 'POST', args => 1 }, update_label => { url => "/repos/%s/%s/labels/%s", method => 'PATCH', args => 1 }, delete_label => { url => "/repos/%s/%s/labels/%s", method => 'DELETE', check_status => 204 }, issue_labels => { url => "/repos/%s/%s/issues/%s/labels" }, create_issue_label => { url => "/repos/%s/%s/issues/%s/labels", method => 'POST', args => 1 }, delete_issue_label => { url => "/repos/%s/%s/issues/%s/labels/%s", method => 'DELETE', check_status => 204 }, replace_issue_label => { url => "/repos/%s/%s/issues/%s/labels", method => 'PUT', args => 1 }, delete_issue_labels => { url => "/repos/%s/%s/issues/%s/labels", method => 'DELETE', check_status => 204 }, milestone_labels => { url => "/repos/%s/%s/milestones/%s/labels" }, # http://developer.github.com/v3/issues/milestones/ milestone => { url => "/repos/%s/%s/milestones/%s" }, create_milestone => { url => "/repos/%s/%s/milestones", method => 'POST', args => 1 }, update_milestone => { url => "/repos/%s/%s/milestones/%s", method => 'PATCH', args => 1 }, delete_milestone => { url => "/repos/%s/%s/milestones/%s", method => 'DELETE', check_status => 204 }, ); __build_methods(__PACKAGE__, %__methods); ## http://developer.github.com/v3/issues/milestones/ sub milestones { my $self = shift; if (@_ < 3) { unshift @_, $self->repo; unshift @_, $self->u; } my ($user, $repos, $args) = @_; my @p; foreach my $p (qw/state sort direction/) { push @p, "$p=" . $args->{$p} if exists $args->{$p}; } my $u = "/repos/" . uri_escape($user) . "/" . uri_escape($repos) . '/milestones'; $u .= '?' . join('&', @p) if @p; return $self->query($u); } no Any::Moose; __PACKAGE__->meta->make_immutable; 1; __END__ =head1 NAME Net::GitHub::V3::Issues - GitHub Issues API =head1 SYNOPSIS use Net::GitHub::V3; my $gh = Net::GitHub::V3->new; # read L to set right authentication info my $issue = $gh->issue; =head1 DESCRIPTION =head2 METHODS =head3 Issues L =over 4 =item issues my @issues = $issue->issues(); my @issues = $issue->issues(filter => 'assigned', state => 'open'); =back B 1. SET user/repo before call methods below $gh->set_default_user_repo('fayland', 'perl-net-github'); # take effects for all $gh-> $issue->set_default_user_repo('fayland', 'perl-net-github'); # only take effect to $gh->issue my @issues = $repos->issues; 2. If it is just for once, we can pass :user, :repo before any arguments my @issues = $issue->repos_issues($user, $repo); =over 4 =item repos_issues my @issues = $issue->repos_issues; my @issues = $issue->repos_issues($user, $repos); my @issues = $issue->repos_issues( { state => 'open' } ); my @issues = $issue->repos_issues($user, $repos, { state => 'open' } ); =item issue my $issue = $issue->issue($issue_id); =item create_issue my $isu = $issue->create_issue( { "title" => "Found a bug", "body" => "I'm having a problem with this.", "assignee" => "octocat", "milestone" => 1, "labels" => [ "Label1", "Label2" ] } ); =item update_issue my $isu = $issue->update_issue( $issue_id, { state => 'closed' } ); =back =head3 Issue Comments API L =over 4 =item comments =item comment =item create_comment =item update_comment =item delete_comment my @comments = $issue->comments($issue_id); my $comment = $issue->comment($comment_id); my $comment = $issue->create_comment($issue_id, { "body" => "a new comment" }); my $comment = $issue->update_comment($comment_id, { "body" => "Nice change" }); my $st = $issue->delete_comment($comment_id); =back =head3 Issue Event API L =over 4 =item events =item repos_events my @events = $issue->events($issue_id); my @events = $issue->repos_events; my $event = $issue->event($event_id); =back =head3 Issue Labels API L =over 4 =item labels =item label =item create_label =item update_label =item delete_label my @labels = $issue->labels; my $label = $issue->label($label_id); my $label = $issue->create_label( { "name" => "API", "color" => "FFFFFF" } ); my $label = $issue->update_label( $label_id, { "name" => "bugs", "color" => "000000" } ); my $st = $issue->delete_label($label_id); =item issue_labels =item create_issue_label =item delete_issue_label =item replace_issue_label =item delete_issue_labels =item milestone_labels my @labels = $issue->issue_label($issue_id); my @labels = $issue->create_issue_label($issue_id, ['New Label']); my $st = $issue->delete_issue_label($issue_id, $label_id); my @labels = $issue->replace_issue_label($issue_id, ['New Label']); my $st = $issue->delete_issue_labels($issue_id); my @lbales = $issue->milestone_labels($milestone_id); =back =head3 Issue Milestones API L =over 4 =item milestones =item milestone =item create_milestone =item update_milestone =item delete_milestone my @milestones = $issue->milestones; my @milestones = $issue->milestones( { state => 'open' } ); my $milestone = $issue->milestone($milestone_id); my $milestone = $issue->create_milestone( { "title" => "String", "state" => "open", "description" => "String", } ); my $milestone = $issue->update_milestone( $milestone_id, { title => 'New Title' } ); my $st = $issue->delete_milestone($milestone_id); =back =head1 AUTHOR & COPYRIGHT & LICENSE Refer L Net-GitHub-0.55/lib/Net/GitHub/V3/OAuth.pm000644 000765 000024 00000003373 12254514652 020472 0ustar00faylandstaff000000 000000 package Net::GitHub::V3::OAuth; use Any::Moose; our $VERSION = '0.43'; our $AUTHORITY = 'cpan:FAYLAND'; use URI::Escape; with 'Net::GitHub::V3::Query'; ## build methods on fly my %__methods = ( authorizations => { url => "/authorizations" }, get_authorization => { url => "/authorizations/%s" }, authorization => { url => "/authorizations/%s" }, create_authorization => { url => "/authorizations", method => "POST", args => 1 }, update_authorization => { url => "/authorizations/%s", method => "PATCH", args => 1 }, delete_authorization => { url => "/authorizations/%s", method => "DELETE", check_status => 204 }, ); __build_methods(__PACKAGE__, %__methods); no Any::Moose; __PACKAGE__->meta->make_immutable; 1; __END__ =head1 NAME Net::GitHub::V3::OAuth - GitHub OAuth API =head1 SYNOPSIS use Net::GitHub::V3; my $gh = Net::GitHub::V3->new; # read L to set right authentication info my $oauth = $gh->oauth; =head2 DESCRIPTION For Web Application Flow, we suggest to use L. For Non-Web Application Flow, read the L FAQ. =head2 METHODS =head3 OAuth L =over 4 =item authorizations my @authorizations = $oauth->authorizations(); =item authorization my $authorization = $oauth->authorization($authorization_id); =item create_authorization =item update_authorization my $oauth = $oauth->create_authorization( { scopes => ['public_repo'], note => 'admin script', } ); my $oauth = $oauth->update_authorization( $authorization_id, $new_authorization_data ); =item delete my $is_deleted = $oauth->delete_authorization($authorization_id); =back =head1 AUTHOR & COPYRIGHT & LICENSE Refer L Net-GitHub-0.55/lib/Net/GitHub/V3/Orgs.pm000644 000765 000024 00000010651 12254514652 020361 0ustar00faylandstaff000000 000000 package Net::GitHub::V3::Orgs; use Any::Moose; our $VERSION = '0.40'; our $AUTHORITY = 'cpan:FAYLAND'; use URI::Escape; with 'Net::GitHub::V3::Query'; sub orgs { my ( $self, $user ) = @_; my $u = $user ? "/users/" . uri_escape($user) . '/orgs' : '/user/orgs'; return $self->query($u); } ## build methods on fly my %__methods = ( org => { url => "/orgs/%s" }, update_org => { url => "/orgs/%s", method => 'PATCH', args => 1 }, # Members members => { url => "/orgs/%s/members" }, is_member => { url => "/orgs/%s/members/%s", check_status => 204 }, delete_member => { url => "/orgs/%s/members/%s", method => 'DELETE', check_status => 204 }, public_members => { url => "/orgs/%s/public_members" }, is_public_member => { url => "/orgs/%s/public_members/%s", check_status => 204 }, publicize_member => { url => "/orgs/%s/public_members/%s", method => 'PUT', check_status => 204 }, conceal_member => { url => "/orgs/%s/public_members/%s", method => 'DELETE', check_status => 204 }, # Org Teams API teams => { url => "/orgs/%s/teams" }, team => { url => "/teams/%s" }, create_team => { url => "/orgs/%s/teams", method => 'POST', args => 1 }, update_team => { url => "/teams/%s", method => 'PATCH', args => 1 }, delete_team => { url => "/teams/%s", method => 'DELETE', check_status => 204 }, team_members => { url => "/teams/%s/members" }, is_team_member => { url => "/teams/%s/members/%s", check_status => 204 }, add_team_member => { url => "/teams/%s/members/%s", method => 'PUT', check_status => 204 }, delete_team_member => { url => "/teams/%s/members/%s", method => 'DELETE', check_status => 204 }, team_repos => { url => "/teams/%s/repos" }, is_team_repos => { url => "/teams/%s/repos/%s", check_status => 204 }, add_team_repos => { url => "/teams/%s/repos/%s", method => 'PUT', check_status => 204 }, delete_team_repos => { url => "/teams/%s/repos/%s", method => 'DELETE', check_status => 204 }, ); __build_methods(__PACKAGE__, %__methods); no Any::Moose; __PACKAGE__->meta->make_immutable; 1; __END__ =head1 NAME Net::GitHub::V3::Orgs - GitHub Orgs API =head1 SYNOPSIS use Net::GitHub::V3; my $gh = Net::GitHub::V3->new; # read L to set right authentication info my $org = $gh->org; =head1 DESCRIPTION =head2 METHODS =head3 Orgs L =over 4 =item orgs my @orgs = $org->orgs(); # /user/org my @orgs = $org->orgs( 'nothingmuch' ); # /users/:user/org =item org my $org = $org->org('perlchina'); =item update_org my $org = $org->update_org($org_name, { name => 'new org name' }); =back =head3 Members L =over 4 =item members =item is_member =item delete_member my @members = $org->members('perlchina'); my $is_member = $org->is_member('perlchina', 'fayland'); my $st = $org->delete_member('perlchina', 'fayland'); =item public_members =item is_public_member =item publicize_member =item conceal_member my @members = $org->public_members('perlchina'); my $is_public_member = $org->is_public_member('perlchina', 'fayland'); my $st = $org->publicize_member('perlchina', 'fayland'); my $st = $org->conceal_member('perlchina', 'fayland'); =back =head3 Org Teams API L =over 4 =item teams =item team =item create_team =item update_team =item delete_team my @teams = $org->teams('perlchina'); my $team = $org->team($team_id); my $team = $org->create_team('perlchina', { "name" => "new team" }); my $team = $org->update_team($team_id, { name => "new team name" }); my $st = $org->delete_team($team_id); =item team_members =item is_team_member =item add_team_member =item delete_team_member my @members = $org->team_members($team_id); my $is_team_member = $org->is_team_member($team_id, 'fayland'); my $st = $org->add_team_member($team_id, 'fayland'); my $st = $org->delete_team_member($team_id, 'fayland'); =item team_repos =item is_team_repos =item add_team_repos =item delete_item_repos my @repos = $org->team_repos($team_id); my $is_team_repos = $org->is_team_repos($team_id, 'Hello-World'); my $st = $org->add_team_repos($team_id, 'Hello-World'); my $st = $org->delete_team_repos($team_id, 'Hello-World'); =back =head1 AUTHOR & COPYRIGHT & LICENSE Refer LNet-GitHub-0.55/lib/Net/GitHub/V3/PullRequests.pm000644 000765 000024 00000007637 12254514652 022131 0ustar00faylandstaff000000 000000 package Net::GitHub::V3::PullRequests; use Any::Moose; our $VERSION = '0.40'; our $AUTHORITY = 'cpan:FAYLAND'; use URI::Escape; with 'Net::GitHub::V3::Query'; sub pulls { my ($self, $user, $repos, $args) = @_; $user = $self->u unless defined $user; $repos = $self->repo unless defined $repos; $args = $self unless defined $args; my @p; foreach my $p (qw/state/) { push @p, "$p=" . $args->{$p} if exists $args->{$p}; } my $u = "/repos/" . uri_escape($user) . "/" . uri_escape($repos) . '/pulls'; $u .= '?' . join('&', @p) if @p; return $self->query($u); } ## build methods on fly my %__methods = ( pull => { url => "/repos/%s/%s/pulls/%s" }, create_pull => { url => "/repos/%s/%s/pulls", method => "POST", args => 1 }, update_pull => { url => "/repos/%s/%s/pulls/%s", method => "PATCH", args => 1 }, commits => { url => "/repos/%s/%s/pulls/%s/commits" }, files => { url => "/repos/%s/%s/pulls/%s/files" }, is_merged => { url => "/repos/%s/%s/pulls/%s/merge", check_status => 204 }, merge => { url => "/repos/%s/%s/pulls/%s/merge", method => "PUT" }, # http://developer.github.com/v3/pulls/comments/ comments => { url => "/repos/%s/%s/pulls/%s/comments" }, comment => { url => "/repos/%s/%s/pulls/comments/%s" }, create_comment => { url => "/repos/%s/%s/pulls/%s/comments", method => 'POST', args => 1 }, update_comment => { url => "/repos/%s/%s/pulls/comments/%s", method => 'PATCH', args => 1 }, delete_comment => { url => "/repos/%s/%s/pulls/comments/%s", method => 'DELETE', check_status => 204 }, ); __build_methods(__PACKAGE__, %__methods); no Any::Moose; __PACKAGE__->meta->make_immutable; 1; __END__ =head1 NAME Net::GitHub::V3::PullRequests - GitHub Pull Requests API =head1 SYNOPSIS use Net::GitHub::V3; my $gh = Net::GitHub::V3->new; # read L to set right authentication info my $pull_request = $gh->pull_request; =head1 DESCRIPTION B 1. SET user/repos before call methods below $gh->set_default_user_repo('fayland', 'perl-net-github'); # take effects for all $gh-> $pull_request->set_default_user_repo('fayland', 'perl-net-github'); # only take effect to $gh->pull_request my @pulls = $pull_request->pulls(); 2. If it is just for once, we can pass :user, :repo before any arguments my @pulls = $pull_request->pulls($user, $repo); =head2 METHODS =head3 Pull Requets L =over 4 =item pulls my @pulls = $pull_request->pulls(); my @pulls = $pull_request->pulls( { state => 'open' } ); =item pull my $pull = $pull_request->pull($pull_id); =item create_pull =item update_pull my $pull = $pull_request->create_pull( { "title" => "Amazing new feature", "body" => "Please pull this in!", "head" => "octocat:new-feature", "base" => "master" } ); my $pull = $pull_request->update_pull( $pull_id, $new_pull_data ); =item commits =item files my @commits = $pull_request->commits($pull_id); my @files = $pull_request->files($pull_id); =item is_merged =item merge my $is_merged = $pull_request->is_merged($pull_id); my $result = $pull_request->merge($pull_id); =back =head3 Pull Request Comments API L =over 4 =item comments =item comment =item create_comment =item update_comment =item delete_comment my @comments = $pull_request->comments($pull_id); my $comment = $pull_request->comment($comment_id); my $comment = $pull_request->create_comment($pull_id, { "body" => "a new comment" }); my $comment = $pull_request->update_comment($comment_id, { "body" => "Nice change" }); my $st = $pull_request->delete_comment($comment_id); =back =head1 AUTHOR & COPYRIGHT & LICENSE Refer L Net-GitHub-0.55/lib/Net/GitHub/V3/Query.pm000644 000765 000024 00000020525 12254514652 020555 0ustar00faylandstaff000000 000000 package Net::GitHub::V3::Query; use Any::Moose 'Role'; our $VERSION = '0.40'; our $AUTHORITY = 'cpan:FAYLAND'; use URI; use JSON::Any; use WWW::Mechanize::GZip; use MIME::Base64; use HTTP::Request; use Carp qw/croak/; use URI::Escape; # configurable args # Authentication has 'login' => ( is => 'rw', isa => 'Str', predicate => 'has_login' ); has 'pass' => ( is => 'rw', isa => 'Str', predicate => 'has_pass' ); has 'access_token' => ( is => 'rw', isa => 'Str', predicate => 'has_access_token' ); # return raw unparsed JSON has 'raw_string' => (is => 'rw', isa => 'Bool', default => 0); has 'raw_response' => (is => 'rw', isa => 'Bool', default => 0); has 'api_url' => (is => 'ro', default => 'https://api.github.com'); has 'api_throttle' => ( is => 'rw', isa => 'Bool', default => 1 ); # pagination has 'next_url' => ( is => 'rw', isa => 'Str', predicate => 'has_next_page', clearer => 'clear_next_url' ); has 'last_url' => ( is => 'rw', isa => 'Str', predicate => 'has_last_page', clearer => 'clear_last_url' ); has 'first_url' => ( is => 'rw', isa => 'Str', predicate => 'has_first_page', clearer => 'clear_first_url' ); has 'prev_url' => ( is => 'rw', isa => 'Str', predicate => 'has_prev_page', clearer => 'clear_prev_url' ); # Error handle has 'RaiseError' => ( is => 'rw', isa => 'Bool', default => 1 ); # optional has 'u' => (is => 'rw', isa => 'Str'); has 'repo' => (is => 'rw', isa => 'Str'); has 'is_main_module' => (is => 'ro', isa => 'Bool', default => 0); sub set_default_user_repo { my ($self, $user, $repo) = @_; $self->u($user); $self->repo($repo); # need apply to all sub modules if ($self->is_main_module) { if ($self->is_repos_init) { $self->repos->u($user); $self->repos->repo($repo); } if ($self->is_issue_init) { $self->issue->u($user); $self->issue->repo($repo); } if ($self->is_pull_request_init) { $self->pull_request->u($user); $self->pull_request->repo($repo); } if ($self->is_git_data_init) { $self->git_data->u($user); $self->git_data->repo($repo); } } return $self; } sub args_to_pass { my $self = shift; my $ret; foreach my $col ('login', 'pass', 'access_token', 'raw_string', 'raw_response', 'api_url', 'api_throttle', 'u', 'repo') { my $v = $self->$col; $ret->{$col} = $v if defined $v; } return $ret; } has 'ua' => ( isa => 'WWW::Mechanize::GZip', is => 'ro', lazy => 1, default => sub { my $self = shift; return WWW::Mechanize::GZip->new( agent => "perl-net-github $VERSION", cookie_jar => {}, stack_depth => 1, autocheck => 0, keep_alive => 4, timeout => 60, ); }, ); has 'json' => ( is => 'ro', isa => 'JSON::Any', lazy => 1, default => sub { return JSON::Any->new( utf8 => 1 ); } ); sub query { my $self = shift; # fix ARGV, not sure if it's the good idea my @args = @_; if (@args == 1) { unshift @args, 'GET'; # method by default } elsif (@args > 1 and not (grep { $args[0] eq $_ } ('GET', 'POST', 'PUT', 'PATCH', 'HEAD', 'DELETE')) ) { unshift @args, 'POST'; # if POST content } my $request_method = shift @args; my $url = shift @args; my $data = shift @args; my $ua = $self->ua; ## always go with login:pass or access_token (for private repos) if ($self->has_access_token) { $ua->default_header('Authorization', "token " . $self->access_token); } elsif ($self->has_login and $self->has_pass) { my $auth_basic = $self->login . ':' . $self->pass; $ua->default_header('Authorization', 'Basic ' . encode_base64($auth_basic)); } $url = $self->api_url . $url unless $url =~ /^https\:/; my $req = HTTP::Request->new( $request_method, $url ); if ($data) { my $json = $self->json->objToJson($data); $req->content($json); } $req->header( 'Content-Length' => length $req->content ); my $res = $ua->request($req); # Slow down if we're approaching the rate limit # By the way GitHub mistakes days for minutes in their documentation -- # the rate limit is per minute, not per day. if ( $self->api_throttle ) { sleep 2 if (($res->header('x-ratelimit-remaining') || 0) < ($res->header('x-ratelimit-limit') || 60) / 2); } return $ua->res if $self->raw_response; return $ua->content if $self->raw_string; if ($res->header('Content-Type') and $res->header('Content-Type') =~ 'application/json') { my $json = $ua->content; $data = eval { $self->json->jsonToObj($json) }; unless ($data) { # We tolerate bad JSON for errors, # otherwise we just rethrow the JSON parsing problem. die unless $res->is_error; $data = { message => $res->message }; } } else { $data = { message => $res->message }; } if ( $self->RaiseError ) { croak $data->{message} if not $ua->success and ref $data eq 'HASH' and exists $data->{message}; # for 'Client Errors' } $self->_clear_pagination; if ($res->header('link')) { my @rel_strs = split ',', $res->header('link'); $self->_extract_link_url(\@rel_strs); } ## be smarter if (wantarray) { return @$data if ref $data eq 'ARRAY'; return %$data if ref $data eq 'HASH'; } return $data; } sub next_page { my $self = shift; return $self->query($self->next_url); } sub _clear_pagination { my $self = shift; foreach my $page (qw/first last prev next/) { my $clearer = 'clear_' . $page . '_url'; $self->$clearer; } return 1; } sub _extract_link_url { my ($self, $raw_strs) = @_; foreach my $str (@$raw_strs) { my ($link_url, $rel) = split ';', $str; $link_url =~ s/^\s*//; $link_url =~ s/^$//; $rel =~ m/rel="(next|last|first|prev)"/; $rel = $1; my $url_attr = $rel . "_url"; $self->$url_attr($link_url); } return 1; } ## build methods on fly sub __build_methods { my $package = shift; my %methods = @_; foreach my $m (keys %methods) { my $v = $methods{$m}; my $url = $v->{url}; my $method = $v->{method} || 'GET'; my $args = $v->{args} || 0; # args for ->query my $check_status = $v->{check_status}; my $is_u_repo = $v->{is_u_repo}; # need auto shift u/repo $package->meta->add_method( $m => sub { my $self = shift; # count how much %s inside u my $n = 0; while ($url =~ /\%s/g) { $n++ } ## if is_u_repo, both ($user, $repo, @args) or (@args) should be supported if ( ($is_u_repo or index($url, '/repos/%s/%s') > -1) and @_ < $n + $args) { unshift @_, ($self->u, $self->repo); } # make url, replace %s with real args my @uargs = splice(@_, 0, $n); my $u = sprintf($url, @uargs); # args for json data POST my @qargs = $args ? splice(@_, 0, $args) : (); if ($check_status) { # need check Response Status my $old_raw_response = $self->raw_response; $self->raw_response(1); # need check header my $res = $self->query($method, $u, @qargs); $self->raw_response($old_raw_response); return index($res->header('Status'), $check_status) > -1 ? 1 : 0; } else { return $self->query($method, $u, @qargs); } } ); } } no Any::Moose; 1; __END__ =head1 NAME Net::GitHub::V3::Query - Base Query role for Net::GitHub::V3 =head1 SYNOPSIS package Net::GitHub::V3::XXX; use Any::Moose; with 'Net::GitHub::V3::Query'; =head1 DESCRIPTION set Authentication and call API =head2 ATTRIBUTES =over 4 =item login =item pass =item access_token either set access_token from OAuth or login:pass for Basic Authentication L =item raw_string =item raw_response =item api_throttle =item RaiseError =back =head2 METHODS =over 4 =item query Refer L =item next_page Calls C with C. See L =back =head1 AUTHOR & COPYRIGHT & LICENSE Refer LNet-GitHub-0.55/lib/Net/GitHub/V3/Repos.pm000644 000765 000024 00000033366 12254514652 020547 0ustar00faylandstaff000000 000000 package Net::GitHub::V3::Repos; use Any::Moose; our $VERSION = '0.53'; our $AUTHORITY = 'cpan:FAYLAND'; use URI::Escape; use HTTP::Request::Common qw(POST); with 'Net::GitHub::V3::Query'; sub list { my ( $self, $type ) = @_; $type ||= 'all'; my $u = '/user/repos'; $u .= '?type=' . $type if $type ne 'all'; return $self->query($u); } sub list_all { my ( $self, $since ) = @_; $since ||= 'first'; my $u = '/repositories'; $u .= '?since=' . $since if $since ne 'first'; return $self->query($u); } sub list_user { my ($self, $user, $type) = @_; $user ||= $self->u; $type ||= 'all'; my $u = "/users/" . uri_escape($user) . "/repos"; $u .= '?type=' . $type if $type ne 'all'; return $self->query($u); } sub list_org { my ($self, $org, $type) = @_; $type ||= 'all'; my $u = "/orgs/" . uri_escape($org) . "/repos"; $u .= '?type=' . $type if $type ne 'all'; return $self->query($u); } sub create { my ( $self, $data ) = @_; my $u = '/user/repos'; if (exists $data->{org}) { my $o = delete $data->{org}; $u = "/orgs/" . uri_escape($o) . "/repos"; } return $self->query('POST', $u, $data); } ## build methods on fly my %__methods = ( get => { url => "/repos/%s/%s" }, update => { url => "/repos/%s/%s", method => 'PATCH', args => 1 }, contributors => { url => "/repos/%s/%s/contributors" }, languages => { url => "/repos/%s/%s/languages" }, teams => { url => "/repos/%s/%s/teams" }, tags => { url => "/repos/%s/%s/tags" }, branches => { url => "/repos/%s/%s/branches" }, # http://developer.github.com/v3/repos/collaborators/ collaborators => { url => "/repos/%s/%s/collaborators" }, is_collaborator => { url => "/repos/%s/%s/collaborators/%s", check_status => 204 }, add_collaborator => { url => "/repos/%s/%s/collaborators/%s", method => 'PUT', check_status => 204 }, delete_collaborator => { url => "/repos/%s/%s/collaborators/%s", method => 'DELETE', check_status => 204 }, # http://developer.github.com/v3/repos/commits/ commits => { url => "/repos/%s/%s/commits" }, commit => { url => "/repos/%s/%s/commits/%s" }, comments => { url => "/repos/%s/%s/comments" }, comment => { url => "/repos/%s/%s/comments/%s" }, commit_comments => { url => "/repos/%s/%s/commits/%s/comments" }, create_comment => { url => "/repos/%s/%s/commits/%s/comments", method => 'POST', args => 1 }, update_comment => { url => "/repos/%s/%s/comments/%s", method => 'PATCH', args => 1 }, delete_comment => { url => "/repos/%s/%s/comments/%s", method => 'DELETE', check_status => 204 }, compare_commits => { url => "/repos/%s/%s/compare/%s...%s" }, # http://developer.github.com/v3/repos/contents/ readme => { url => "/repos/%s/%s/readme" }, get_content => { url => "/repos/%s/%s/contents/%s" }, # http://developer.github.com/v3/repos/downloads/ downloads => { url => "/repos/%s/%s/downloads" }, download => { url => "/repos/%s/%s/downloads/%s" }, delete_download => { url => "/repos/%s/%s/downloads/%s", method => 'DELETE', check_status => 204 }, forks => { url => "/repos/%s/%s/forks" }, # http://developer.github.com/v3/repos/keys/ keys => { url => "/repos/%s/%s/keys" }, key => { url => "/repos/%s/%s/keys/%s" }, create_key => { url => "/repos/%s/%s/keys", method => 'POST', args => 1 }, update_key => { url => "/repos/%s/%s/keys/%s", method => 'PATCH', check_status => 204, args => 1 }, delete_key => { url => "/repos/%s/%s/keys/%s", method => 'DELETE', check_status => 204 }, # http://developer.github.com/v3/repos/watching/ watchers => { url => "/repos/%s/%s/watchers" }, is_watching => { url => "/user/watched/%s/%s", is_u_repo => 1, check_status => 204 }, watch => { url => "/user/watched/%s/%s", is_u_repo => 1, method => 'PUT', check_status => 204 }, unwatch => { url => "/user/watched/%s/%s", is_u_repo => 1, method => 'DELETE', check_status => 204 }, # http://developer.github.com/v3/repos/hooks/ hooks => { url => "/repos/%s/%s/hooks" }, hook => { url => "/repos/%s/%s/hooks/%s" }, delete_hook => { url => "/repos/%s/%s/hooks/%s", method => 'DELETE', check_status => 204 }, test_hook => { url => "/repos/%s/%s/hooks/%s/test", method => 'POST', check_status => 204 }, create_hook => { url => "/repos/%s/%s/hooks", method => 'POST', args => 1 }, update_hook => { url => "/repos/%s/%s/hooks/%s", method => 'PATCH', args => 1 }, # http://developer.github.com/v3/repos/merging/ merges => { url => "/repos/%s/%s/merges", method => 'POST', args => 1 }, # http://developer.github.com/v3/repos/statuses/ list_statuses => { url => "/repos/%s/%s/statuses/%s" }, create_status => { url => "/repos/%s/%s/statuses/%s", method => 'POST', args => 1 }, ); __build_methods(__PACKAGE__, %__methods); sub create_download { my $self = shift; if (@_ == 1) { unshift @_, $self->repo; unshift @_, $self->u; } my ($user, $repos, $download) = @_; my $file = delete $download->{file}; my $u = "/repos/" . uri_escape($user) . "/" . uri_escape($repos) . '/downloads'; my $d = $self->query('POST', $u, $download); if (defined $file) { return $self->upload_download($d, $file); } else { return $d; } } sub upload_download { my $self = shift; if (@_ < 3) { unshift @_, $self->repo; unshift @_, $self->u; } my ($user, $repos, $download, $file) = @_; # must successful on create_download return 0 unless exists $download->{s3_url}; ## POST form-data my %data = ( Content_Type => 'form-data', Content => [ 'key' => $download->{path}, 'acl' => $download->{acl}, 'success_action_status' => 201, 'Filename' => $download->{name}, 'AWSAccessKeyId' => $download->{accesskeyid}, 'Policy' => $download->{policy}, 'Signature' => $download->{signature}, 'Content-Type' => $download->{mime_type}, 'file' => [ $file ], ], ); my $request = POST $download->{s3_url}, %data; my $res = $self->ua->request($request); return $res->code == 201 ? 1 : 0; } ## http://developer.github.com/v3/repos/forks/ sub create_fork { my $self = shift; if (@_ < 2) { unshift @_, $self->repo; unshift @_, $self->u; } my ($user, $repos, $org) = @_; my $u = "/repos/" . uri_escape($user) . "/" . uri_escape($repos) . '/forks'; $u .= '?org=' . $org if defined $org; return $self->query('POST', $u); } ## http://developer.github.com/v3/repos/watching/ sub watched { my ($self, $user) = @_; my $u = $user ? '/users/' . uri_escape($user). '/watched' : '/user/watched'; return $self->query($u); } no Any::Moose; __PACKAGE__->meta->make_immutable; 1; __END__ =head1 NAME Net::GitHub::V3::Repos - GitHub Repos API =head1 SYNOPSIS use Net::GitHub::V3; my $gh = Net::GitHub::V3->new; # read L to set right authentication info my $repos = $gh->repos; # set :user/:repo for simple calls $repos->set_default_user_repo('fayland', 'perl-net-github'); my @contributors = $repos->contributors; # don't need pass user and repos =head1 DESCRIPTION =head2 METHODS =head3 Repos L =over 4 =item list =item list_all # All public repositories on Github my @rp = $repos->list_all; # starting at id 500 my @rp = $repos->list_all(500); =item list_user =item list_org my @rp = $repos->list; # or my $rp = $repos->list; my @rp = $repos->list('private'); my @rp = $repos->list_user('c9s'); my @rp = $repos->list_user('c9s', 'member'); my @rp = $repos->list_org('perlchina'); my @rp = $repos->list_org('perlchina', 'public'); =item create # create for yourself my $rp = $repos->create( { "name" => "Hello-World", "description" => "This is your first repo", "homepage" => "https://github.com" } ); # create for organization my $rp = $repos->create( { "org" => "perlchina", ## the organization "name" => "Hello-World", "description" => "This is your first repo", "homepage" => "https://github.com" } ); =item get my $rp = $repos->get('fayland', 'perl-net-github'); =back B 1. SET user/repos before call methods below $gh->set_default_user_repo('fayland', 'perl-net-github'); # take effects for all $gh-> $repos->set_default_user_repo('fayland', 'perl-net-github'); # only take effect to $gh->repos my @contributors = $repos->contributors; 2. If it is just for once, we can pass :user, :repo before any arguments my @contributors = $repos->contributors($user, $repo); =over 4 =item update $repos->update({ homepage => 'https://metacpan.org/module/Net::GitHub' }); =item contributors =item languages =item teams =item tags =item contributors my @contributors = $repos->contributors; my @languages = $repos->languages; my @teams = $repos->teams; my @tags = $repos->tags; my @branches = $repos->branches; =back =head3 Repo Collaborators API L =over 4 =item collaborators =item is_collaborator =item add_collaborator =item delete_collaborator my @collaborators = $repos->collaborators; my $is = $repos->is_collaborator('fayland'); $repos->add_collaborator('fayland'); $repos->delete_collaborator('fayland'); =back =head3 Commits API L =over 4 =item commits =item commit my @commits = $repos->commits; my $commit = $repos->commit($sha); =item comments =item commit_comments =item create_comment =item comment =item update_comment =item delete_comment my @comments = $repos->comments; my @comments = $repos->commit_comments($sha); my $comment = $repos->create_comment($sha, { "body" => "Nice change", "commit_id" => "6dcb09b5b57875f334f61aebed695e2e4193db5e", "line" => 1, "path" => "file1.txt", "position" => 4 }); my $comment = $repos->comment($comment_id); my $comment = $repos->update_comment($comment_id, { "body" => "Nice change" }); my $st = $repos->delete_comment($comment_id); =item compare_commits my $diffs = $repos->compare_commits($base, $head); =back =head3 Downloads L =over 4 =item downloads =item download =item delete_download my @downloads = $repos->downloads; my $download = $repos->download($download_id); my $st = $repos->delete_download($download_id); =item create_download =item upload_download my $download = $repos->create_download( { "name" => "new_file.jpg", "size" => 114034, "description" => "Latest release", "content_type" => "text/plain" } ); my $st = $repos->upload_download($download, "/path/to/new_file.jpg"); # or batch it my $st = $repos->create_download( { "name" => "new_file.jpg", "size" => 114034, "description" => "Latest release", "content_type" => "text/plain", file => '/path/to/new_file.jpg', } ); =back =head3 Forks API L =over 4 =item forks =item create_fork my @forks = $repos->forks; my $fork = $repos->create_fork; my $fork = $repos->create_fork($org); =back =head3 Repos Deploy Keys API L =over 4 =item keys =item key =item create_key =item update_key =item delete_key my @keys = $repos->keys; my $key = $repos->key($key_id); # get key $repos->create_key( { title => 'title', key => $key } ); $repos->update_key($key_id, { title => $title, key => $key }); $repos->delete_key($key_id); =back =head3 Repo Watching API L =over 4 =item watchers my @watchers = $repos->watchers; =item watched my @repos = $repos->watched; # what I watched my @repos = $repos->watched('c9s'); =item is_watching my $is_watching = $repos->is_watching; my $is_watching = $repos->is_watching('fayland', 'perl-net-github'); =item watch =item unwatch my $st = $repos->watch(); my $st = $repos->watch('fayland', 'perl-net-github'); my $st = $repos->unwatch(); my $st = $repos->unwatch('fayland', 'perl-net-github'); =back =head3 Hooks API L =over 4 =item hooks =item hook =item create_hook =item update_hook =item test_hook =item delete_hook my @hooks = $repos->hooks; my $hook = $repos->hook($hook_id); my $hook = $repos->create_hook($hook_hash); my $hook = $repos->update_hook($hook_id, $new_hook_hash); my $st = $repos->test_hook($hook_id); my $st = $repos->delete_hook($hook_id); =back =head3 Repo Merging API L =over 4 =item merges my $status = $repos->merges( { "base" => "master", "head" => "cool_feature", "commit_message" => "Shipped cool_feature!" } ); =back =head3 Repo Statuses API L =over 4 =item list_statuses my @statuses = $repos->list_statuses($sha1); =item create_status my $status = $repos->create_status( { "state" => "success", "target_url" => "https://example.com/build/status", "description" => "The build succeeded!" } ); =back =head1 AUTHOR & COPYRIGHT & LICENSE Refer LNet-GitHub-0.55/lib/Net/GitHub/V3/Search.pm000644 000765 000024 00000002517 12254514652 020656 0ustar00faylandstaff000000 000000 package Net::GitHub::V3::Search; use Any::Moose; our $VERSION = '0.49'; our $AUTHORITY = 'cpan:FAYLAND'; use URI::Escape; with 'Net::GitHub::V3::Query'; ## build methods on fly my %__methods = ( issues => { url => '/legacy/issues/search/%s/%s/%s/%s', is_u_repo => 1 }, repos => { url => '/legacy/repos/search/%s' }, user => { url => '/legacy/user/search/%s' }, email => { url => '/legacy/user/email/%s' }, ); __build_methods(__PACKAGE__, %__methods); no Any::Moose; __PACKAGE__->meta->make_immutable; 1; __END__ =head1 NAME Net::GitHub::V3::Search - GitHub Search API =head1 SYNOPSIS use Net::GitHub::V3; my $gh = Net::GitHub::V3->new; # read L to set right authentication info my $search = $gh->search; =head1 DESCRIPTION =head2 METHODS =head3 Search L =over 4 =item issues my %data = $search->issues('fayland', 'perl-net-github', 'closed', 'milestone'); print Dumper(\$data{issues}); =item repos my %data = $search->repos('perl-net-github'); print Dumper(\$data{repositories}); =item user my %data = $search->user('fayland'); print Dumper(\$data{users}); =item email my %data = $search->email('fayland@gmail.com'); print Dumper(\$data{user}); =back =head1 AUTHOR & COPYRIGHT & LICENSE Refer L Net-GitHub-0.55/lib/Net/GitHub/V3/Users.pm000644 000765 000024 00000010270 12254514652 020545 0ustar00faylandstaff000000 000000 package Net::GitHub::V3::Users; use Any::Moose; our $VERSION = '0.54'; our $AUTHORITY = 'cpan:FAYLAND'; use URI::Escape; with 'Net::GitHub::V3::Query'; sub show { my ( $self, $user ) = @_; my $u = $user ? "/users/" . uri_escape($user) : '/user'; return $self->query($u); } sub update { my $self = shift; my $data = @_ % 2 ? shift @_ : { @_ }; return $self->query('PATCH', '/user', $data); } sub add_email { (shift)->query( 'POST', '/user/emails', [ @_ ] ); } sub remove_email { (shift)->query( 'DELETE', '/user/emails', [ @_ ] ); } sub followers { my ($self, $user) = @_; my $u = $user ? "/users/" . uri_escape($user) . '/followers' : '/user/followers'; return $self->query($u); } sub following { my ($self, $user) = @_; my $u = $user ? "/users/" . uri_escape($user) . '/following' : '/user/following'; return $self->query($u); } sub contributions { my ( $self, $user ) = @_; my $path = "/users/" . uri_escape($user) . "/contributions_calendar_data"; my $domain = $self->api_url eq 'https://api.github.com' ? 'https://github.com' : $self->api_url; return $self->query( $domain . $path ); } ## build methods on fly my %__methods = ( emails => { url => "/user/emails" }, is_following => { url => "/user/following/%s", check_status => 204 }, follow => { url => "/user/following/%s", method => 'PUT', check_status => 204 }, unfollow => { url => "/user/following/%s", method => 'DELETE', check_status => 204 }, keys => { url => "/user/keys" }, key => { url => "/user/keys/%s" }, create_key => { url => "/user/keys", method => 'POST', args => 1 }, update_key => { url => "/user/keys/%s", method => 'PATCH', args => 1 }, delete_key => { url => "/user/keys/%s", method => 'DELETE', check_status => 204 }, ); __build_methods(__PACKAGE__, %__methods); no Any::Moose; __PACKAGE__->meta->make_immutable; 1; __END__ =head1 NAME Net::GitHub::V3::Users - GitHub Users API =head1 SYNOPSIS use Net::GitHub::V3; my $gh = Net::GitHub::V3->new; # read L to set right authentication info my $user = $gh->user; =head1 DESCRIPTION =head2 METHODS =head3 Users L =over 4 =item show my $uinfo = $user->show(); # /user my $uinfo = $user->show( 'nothingmuch' ); # /users/:user =item update $user->update( bio => 'another Perl programmer and Father', ); =back =head3 Emails L =over 4 =item emails =item add_email =item remove_email $user->add_email( 'another@email.com' ); $user->add_email( 'batch1@email.com', 'batch2@email.com' ); my $emails = $user->emails; $user->remove_email( 'another@email.com' ); $user->remove_email( 'batch1@email.com', 'batch2@email.com' ); =back =head3 Followers L =over 4 =item followers =item following my $followers = $user->followers; my $followers = $user->followers($user); my $following = $user->following; my $following = $user->following($user); =item is_following my $is_following = $user->is_following($user); =item follow =item unfollow $user->follow( 'nothingmuch' ); $user->unfollow( 'nothingmuch' ); =back =head3 Keys L =over 4 =item keys =item key =item create_key =item update_key =item delete_key my $keys = $user->keys; my $key = $user->key($key_id); # get key $user->create_key({ title => 'title', key => $key }); $user->update_key($key_id, { title => $title, key => $key }); $user->delete_key($key_id); =item contributions my $contributions = $user->contributions($username); # $contributions = ( ..., ['2013/09/22', 3], [ '2013/09/23', 2 ] ) Unpublished GitHub API used to build the 'Public contributions' graph on a users' profile page. The data structure is a list of 365 arrayrefs, one per day. Each array has two elements, the date in YYYY/MM/DD format is the first element, the second is the number of contrubtions for that day.stree . =back =head1 AUTHOR & COPYRIGHT & LICENSE Refer L Net-GitHub-0.55/inc/Module/000755 000765 000024 00000000000 12254516254 016136 5ustar00faylandstaff000000 000000 Net-GitHub-0.55/inc/Module/AutoInstall.pm000644 000765 000024 00000062162 12254516226 020741 0ustar00faylandstaff000000 000000 #line 1 package Module::AutoInstall; use strict; use Cwd (); use File::Spec (); use ExtUtils::MakeMaker (); use vars qw{$VERSION}; BEGIN { $VERSION = '1.06'; } # special map on pre-defined feature sets my %FeatureMap = ( '' => 'Core Features', # XXX: deprecated '-core' => 'Core Features', ); # various lexical flags my ( @Missing, @Existing, %DisabledTests, $UnderCPAN, $InstallDepsTarget, $HasCPANPLUS ); my ( $Config, $CheckOnly, $SkipInstall, $AcceptDefault, $TestOnly, $AllDeps, $UpgradeDeps ); my ( $PostambleActions, $PostambleActionsNoTest, $PostambleActionsUpgradeDeps, $PostambleActionsUpgradeDepsNoTest, $PostambleActionsListDeps, $PostambleActionsListAllDeps, $PostambleUsed, $NoTest); # See if it's a testing or non-interactive session _accept_default( $ENV{AUTOMATED_TESTING} or ! -t STDIN ); _init(); sub _accept_default { $AcceptDefault = shift; } sub _installdeps_target { $InstallDepsTarget = shift; } sub missing_modules { return @Missing; } sub do_install { __PACKAGE__->install( [ $Config ? ( UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) : () ], @Missing, ); } # initialize various flags, and/or perform install sub _init { foreach my $arg ( @ARGV, split( /[\s\t]+/, $ENV{PERL_AUTOINSTALL} || $ENV{PERL_EXTUTILS_AUTOINSTALL} || '' ) ) { if ( $arg =~ /^--config=(.*)$/ ) { $Config = [ split( ',', $1 ) ]; } elsif ( $arg =~ /^--installdeps=(.*)$/ ) { __PACKAGE__->install( $Config, @Missing = split( /,/, $1 ) ); exit 0; } elsif ( $arg =~ /^--upgradedeps=(.*)$/ ) { $UpgradeDeps = 1; __PACKAGE__->install( $Config, @Missing = split( /,/, $1 ) ); exit 0; } elsif ( $arg =~ /^--default(?:deps)?$/ ) { $AcceptDefault = 1; } elsif ( $arg =~ /^--check(?:deps)?$/ ) { $CheckOnly = 1; } elsif ( $arg =~ /^--skip(?:deps)?$/ ) { $SkipInstall = 1; } elsif ( $arg =~ /^--test(?:only)?$/ ) { $TestOnly = 1; } elsif ( $arg =~ /^--all(?:deps)?$/ ) { $AllDeps = 1; } } } # overrides MakeMaker's prompt() to automatically accept the default choice sub _prompt { goto &ExtUtils::MakeMaker::prompt unless $AcceptDefault; my ( $prompt, $default ) = @_; my $y = ( $default =~ /^[Yy]/ ); print $prompt, ' [', ( $y ? 'Y' : 'y' ), '/', ( $y ? 'n' : 'N' ), '] '; print "$default\n"; return $default; } # the workhorse sub import { my $class = shift; my @args = @_ or return; my $core_all; print "*** $class version " . $class->VERSION . "\n"; print "*** Checking for Perl dependencies...\n"; my $cwd = Cwd::cwd(); $Config = []; my $maxlen = length( ( sort { length($b) <=> length($a) } grep { /^[^\-]/ } map { ref($_) ? ( ( ref($_) eq 'HASH' ) ? keys(%$_) : @{$_} ) : '' } map { +{@args}->{$_} } grep { /^[^\-]/ or /^-core$/i } keys %{ +{@args} } )[0] ); # We want to know if we're under CPAN early to avoid prompting, but # if we aren't going to try and install anything anyway then skip the # check entirely since we don't want to have to load (and configure) # an old CPAN just for a cosmetic message $UnderCPAN = _check_lock(1) unless $SkipInstall || $InstallDepsTarget; while ( my ( $feature, $modules ) = splice( @args, 0, 2 ) ) { my ( @required, @tests, @skiptests ); my $default = 1; my $conflict = 0; if ( $feature =~ m/^-(\w+)$/ ) { my $option = lc($1); # check for a newer version of myself _update_to( $modules, @_ ) and return if $option eq 'version'; # sets CPAN configuration options $Config = $modules if $option eq 'config'; # promote every features to core status $core_all = ( $modules =~ /^all$/i ) and next if $option eq 'core'; next unless $option eq 'core'; } print "[" . ( $FeatureMap{ lc($feature) } || $feature ) . "]\n"; $modules = [ %{$modules} ] if UNIVERSAL::isa( $modules, 'HASH' ); unshift @$modules, -default => &{ shift(@$modules) } if ( ref( $modules->[0] ) eq 'CODE' ); # XXX: bugward combatability while ( my ( $mod, $arg ) = splice( @$modules, 0, 2 ) ) { if ( $mod =~ m/^-(\w+)$/ ) { my $option = lc($1); $default = $arg if ( $option eq 'default' ); $conflict = $arg if ( $option eq 'conflict' ); @tests = @{$arg} if ( $option eq 'tests' ); @skiptests = @{$arg} if ( $option eq 'skiptests' ); next; } printf( "- %-${maxlen}s ...", $mod ); if ( $arg and $arg =~ /^\D/ ) { unshift @$modules, $arg; $arg = 0; } # XXX: check for conflicts and uninstalls(!) them. my $cur = _version_of($mod); if (_version_cmp ($cur, $arg) >= 0) { print "loaded. ($cur" . ( $arg ? " >= $arg" : '' ) . ")\n"; push @Existing, $mod => $arg; $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; } else { if (not defined $cur) # indeed missing { print "missing." . ( $arg ? " (would need $arg)" : '' ) . "\n"; } else { # no need to check $arg as _version_cmp ($cur, undef) would satisfy >= above print "too old. ($cur < $arg)\n"; } push @required, $mod => $arg; } } next unless @required; my $mandatory = ( $feature eq '-core' or $core_all ); if ( !$SkipInstall and ( $CheckOnly or ($mandatory and $UnderCPAN) or $AllDeps or $InstallDepsTarget or _prompt( qq{==> Auto-install the } . ( @required / 2 ) . ( $mandatory ? ' mandatory' : ' optional' ) . qq{ module(s) from CPAN?}, $default ? 'y' : 'n', ) =~ /^[Yy]/ ) ) { push( @Missing, @required ); $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; } elsif ( !$SkipInstall and $default and $mandatory and _prompt( qq{==> The module(s) are mandatory! Really skip?}, 'n', ) =~ /^[Nn]/ ) { push( @Missing, @required ); $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; } else { $DisabledTests{$_} = 1 for map { glob($_) } @tests; } } if ( @Missing and not( $CheckOnly or $UnderCPAN) ) { require Config; my $make = $Config::Config{make}; if ($InstallDepsTarget) { print "*** To install dependencies type '$make installdeps' or '$make installdeps_notest'.\n"; } else { print "*** Dependencies will be installed the next time you type '$make'.\n"; } # make an educated guess of whether we'll need root permission. print " (You may need to do that as the 'root' user.)\n" if eval '$>'; } print "*** $class configuration finished.\n"; chdir $cwd; # import to main:: no strict 'refs'; *{'main::WriteMakefile'} = \&Write if caller(0) eq 'main'; return (@Existing, @Missing); } sub _running_under { my $thing = shift; print <<"END_MESSAGE"; *** Since we're running under ${thing}, I'll just let it take care of the dependency's installation later. END_MESSAGE return 1; } # Check to see if we are currently running under CPAN.pm and/or CPANPLUS; # if we are, then we simply let it taking care of our dependencies sub _check_lock { return unless @Missing or @_; if ($ENV{PERL5_CPANM_IS_RUNNING}) { return _running_under('cpanminus'); } my $cpan_env = $ENV{PERL5_CPAN_IS_RUNNING}; if ($ENV{PERL5_CPANPLUS_IS_RUNNING}) { return _running_under($cpan_env ? 'CPAN' : 'CPANPLUS'); } require CPAN; if ($CPAN::VERSION > '1.89') { if ($cpan_env) { return _running_under('CPAN'); } return; # CPAN.pm new enough, don't need to check further } # last ditch attempt, this -will- configure CPAN, very sorry _load_cpan(1); # force initialize even though it's already loaded # Find the CPAN lock-file my $lock = MM->catfile( $CPAN::Config->{cpan_home}, ".lock" ); return unless -f $lock; # Check the lock local *LOCK; return unless open(LOCK, $lock); if ( ( $^O eq 'MSWin32' ? _under_cpan() : == getppid() ) and ( $CPAN::Config->{prerequisites_policy} || '' ) ne 'ignore' ) { print <<'END_MESSAGE'; *** Since we're running under CPAN, I'll just let it take care of the dependency's installation later. END_MESSAGE return 1; } close LOCK; return; } sub install { my $class = shift; my $i; # used below to strip leading '-' from config keys my @config = ( map { s/^-// if ++$i; $_ } @{ +shift } ); my ( @modules, @installed ); while ( my ( $pkg, $ver ) = splice( @_, 0, 2 ) ) { # grep out those already installed if ( _version_cmp( _version_of($pkg), $ver ) >= 0 ) { push @installed, $pkg; } else { push @modules, $pkg, $ver; } } if ($UpgradeDeps) { push @modules, @installed; @installed = (); } return @installed unless @modules; # nothing to do return @installed if _check_lock(); # defer to the CPAN shell print "*** Installing dependencies...\n"; return unless _connected_to('cpan.org'); my %args = @config; my %failed; local *FAILED; if ( $args{do_once} and open( FAILED, '.#autoinstall.failed' ) ) { while () { chomp; $failed{$_}++ } close FAILED; my @newmod; while ( my ( $k, $v ) = splice( @modules, 0, 2 ) ) { push @newmod, ( $k => $v ) unless $failed{$k}; } @modules = @newmod; } if ( _has_cpanplus() and not $ENV{PERL_AUTOINSTALL_PREFER_CPAN} ) { _install_cpanplus( \@modules, \@config ); } else { _install_cpan( \@modules, \@config ); } print "*** $class installation finished.\n"; # see if we have successfully installed them while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { if ( _version_cmp( _version_of($pkg), $ver ) >= 0 ) { push @installed, $pkg; } elsif ( $args{do_once} and open( FAILED, '>> .#autoinstall.failed' ) ) { print FAILED "$pkg\n"; } } close FAILED if $args{do_once}; return @installed; } sub _install_cpanplus { my @modules = @{ +shift }; my @config = _cpanplus_config( @{ +shift } ); my $installed = 0; require CPANPLUS::Backend; my $cp = CPANPLUS::Backend->new; my $conf = $cp->configure_object; return unless $conf->can('conf') # 0.05x+ with "sudo" support or _can_write($conf->_get_build('base')); # 0.04x # if we're root, set UNINST=1 to avoid trouble unless user asked for it. my $makeflags = $conf->get_conf('makeflags') || ''; if ( UNIVERSAL::isa( $makeflags, 'HASH' ) ) { # 0.03+ uses a hashref here $makeflags->{UNINST} = 1 unless exists $makeflags->{UNINST}; } else { # 0.02 and below uses a scalar $makeflags = join( ' ', split( ' ', $makeflags ), 'UNINST=1' ) if ( $makeflags !~ /\bUNINST\b/ and eval qq{ $> eq '0' } ); } $conf->set_conf( makeflags => $makeflags ); $conf->set_conf( prereqs => 1 ); while ( my ( $key, $val ) = splice( @config, 0, 2 ) ) { $conf->set_conf( $key, $val ); } my $modtree = $cp->module_tree; while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { print "*** Installing $pkg...\n"; MY::preinstall( $pkg, $ver ) or next if defined &MY::preinstall; my $success; my $obj = $modtree->{$pkg}; if ( $obj and _version_cmp( $obj->{version}, $ver ) >= 0 ) { my $pathname = $pkg; $pathname =~ s/::/\\W/; foreach my $inc ( grep { m/$pathname.pm/i } keys(%INC) ) { delete $INC{$inc}; } my $rv = $cp->install( modules => [ $obj->{module} ] ); if ( $rv and ( $rv->{ $obj->{module} } or $rv->{ok} ) ) { print "*** $pkg successfully installed.\n"; $success = 1; } else { print "*** $pkg installation cancelled.\n"; $success = 0; } $installed += $success; } else { print << "."; *** Could not find a version $ver or above for $pkg; skipping. . } MY::postinstall( $pkg, $ver, $success ) if defined &MY::postinstall; } return $installed; } sub _cpanplus_config { my @config = (); while ( @_ ) { my ($key, $value) = (shift(), shift()); if ( $key eq 'prerequisites_policy' ) { if ( $value eq 'follow' ) { $value = CPANPLUS::Internals::Constants::PREREQ_INSTALL(); } elsif ( $value eq 'ask' ) { $value = CPANPLUS::Internals::Constants::PREREQ_ASK(); } elsif ( $value eq 'ignore' ) { $value = CPANPLUS::Internals::Constants::PREREQ_IGNORE(); } else { die "*** Cannot convert option $key = '$value' to CPANPLUS version.\n"; } push @config, 'prereqs', $value; } elsif ( $key eq 'force' ) { push @config, $key, $value; } elsif ( $key eq 'notest' ) { push @config, 'skiptest', $value; } else { die "*** Cannot convert option $key to CPANPLUS version.\n"; } } return @config; } sub _install_cpan { my @modules = @{ +shift }; my @config = @{ +shift }; my $installed = 0; my %args; _load_cpan(); require Config; if (CPAN->VERSION < 1.80) { # no "sudo" support, probe for writableness return unless _can_write( MM->catfile( $CPAN::Config->{cpan_home}, 'sources' ) ) and _can_write( $Config::Config{sitelib} ); } # if we're root, set UNINST=1 to avoid trouble unless user asked for it. my $makeflags = $CPAN::Config->{make_install_arg} || ''; $CPAN::Config->{make_install_arg} = join( ' ', split( ' ', $makeflags ), 'UNINST=1' ) if ( $makeflags !~ /\bUNINST\b/ and eval qq{ $> eq '0' } ); # don't show start-up info $CPAN::Config->{inhibit_startup_message} = 1; # set additional options while ( my ( $opt, $arg ) = splice( @config, 0, 2 ) ) { ( $args{$opt} = $arg, next ) if $opt =~ /^(?:force|notest)$/; # pseudo-option $CPAN::Config->{$opt} = $arg; } if ($args{notest} && (not CPAN::Shell->can('notest'))) { die "Your version of CPAN is too old to support the 'notest' pragma"; } local $CPAN::Config->{prerequisites_policy} = 'follow'; while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { MY::preinstall( $pkg, $ver ) or next if defined &MY::preinstall; print "*** Installing $pkg...\n"; my $obj = CPAN::Shell->expand( Module => $pkg ); my $success = 0; if ( $obj and _version_cmp( $obj->cpan_version, $ver ) >= 0 ) { my $pathname = $pkg; $pathname =~ s/::/\\W/; foreach my $inc ( grep { m/$pathname.pm/i } keys(%INC) ) { delete $INC{$inc}; } my $rv = do { if ($args{force}) { CPAN::Shell->force( install => $pkg ) } elsif ($args{notest}) { CPAN::Shell->notest( install => $pkg ) } else { CPAN::Shell->install($pkg) } }; $rv ||= eval { $CPAN::META->instance( 'CPAN::Distribution', $obj->cpan_file, ) ->{install} if $CPAN::META; }; if ( $rv eq 'YES' ) { print "*** $pkg successfully installed.\n"; $success = 1; } else { print "*** $pkg installation failed.\n"; $success = 0; } $installed += $success; } else { print << "."; *** Could not find a version $ver or above for $pkg; skipping. . } MY::postinstall( $pkg, $ver, $success ) if defined &MY::postinstall; } return $installed; } sub _has_cpanplus { return ( $HasCPANPLUS = ( $INC{'CPANPLUS/Config.pm'} or _load('CPANPLUS::Shell::Default') ) ); } # make guesses on whether we're under the CPAN installation directory sub _under_cpan { require Cwd; require File::Spec; my $cwd = File::Spec->canonpath( Cwd::cwd() ); my $cpan = File::Spec->canonpath( $CPAN::Config->{cpan_home} ); return ( index( $cwd, $cpan ) > -1 ); } sub _update_to { my $class = __PACKAGE__; my $ver = shift; return if _version_cmp( _version_of($class), $ver ) >= 0; # no need to upgrade if ( _prompt( "==> A newer version of $class ($ver) is required. Install?", 'y' ) =~ /^[Nn]/ ) { die "*** Please install $class $ver manually.\n"; } print << "."; *** Trying to fetch it from CPAN... . # install ourselves _load($class) and return $class->import(@_) if $class->install( [], $class, $ver ); print << '.'; exit 1; *** Cannot bootstrap myself. :-( Installation terminated. . } # check if we're connected to some host, using inet_aton sub _connected_to { my $site = shift; return ( ( _load('Socket') and Socket::inet_aton($site) ) or _prompt( qq( *** Your host cannot resolve the domain name '$site', which probably means the Internet connections are unavailable. ==> Should we try to install the required module(s) anyway?), 'n' ) =~ /^[Yy]/ ); } # check if a directory is writable; may create it on demand sub _can_write { my $path = shift; mkdir( $path, 0755 ) unless -e $path; return 1 if -w $path; print << "."; *** You are not allowed to write to the directory '$path'; the installation may fail due to insufficient permissions. . if ( eval '$>' and lc(`sudo -V`) =~ /version/ and _prompt( qq( ==> Should we try to re-execute the autoinstall process with 'sudo'?), ((-t STDIN) ? 'y' : 'n') ) =~ /^[Yy]/ ) { # try to bootstrap ourselves from sudo print << "."; *** Trying to re-execute the autoinstall process with 'sudo'... . my $missing = join( ',', @Missing ); my $config = join( ',', UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) if $Config; return unless system( 'sudo', $^X, $0, "--config=$config", "--installdeps=$missing" ); print << "."; *** The 'sudo' command exited with error! Resuming... . } return _prompt( qq( ==> Should we try to install the required module(s) anyway?), 'n' ) =~ /^[Yy]/; } # load a module and return the version it reports sub _load { my $mod = pop; # method/function doesn't matter my $file = $mod; $file =~ s|::|/|g; $file .= '.pm'; local $@; return eval { require $file; $mod->VERSION } || ( $@ ? undef: 0 ); } # report version without loading a module sub _version_of { my $mod = pop; # method/function doesn't matter my $file = $mod; $file =~ s|::|/|g; $file .= '.pm'; foreach my $dir ( @INC ) { next if ref $dir; my $path = File::Spec->catfile($dir, $file); next unless -e $path; require ExtUtils::MM_Unix; return ExtUtils::MM_Unix->parse_version($path); } return undef; } # Load CPAN.pm and it's configuration sub _load_cpan { return if $CPAN::VERSION and $CPAN::Config and not @_; require CPAN; # CPAN-1.82+ adds CPAN::Config::AUTOLOAD to redirect to # CPAN::HandleConfig->load. CPAN reports that the redirection # is deprecated in a warning printed at the user. # CPAN-1.81 expects CPAN::HandleConfig->load, does not have # $CPAN::HandleConfig::VERSION but cannot handle # CPAN::Config->load # Which "versions expect CPAN::Config->load? if ( $CPAN::HandleConfig::VERSION || CPAN::HandleConfig->can('load') ) { # Newer versions of CPAN have a HandleConfig module CPAN::HandleConfig->load; } else { # Older versions had the load method in Config directly CPAN::Config->load; } } # compare two versions, either use Sort::Versions or plain comparison # return values same as <=> sub _version_cmp { my ( $cur, $min ) = @_; return -1 unless defined $cur; # if 0 keep comparing return 1 unless $min; $cur =~ s/\s+$//; # check for version numbers that are not in decimal format if ( ref($cur) or ref($min) or $cur =~ /v|\..*\./ or $min =~ /v|\..*\./ ) { if ( ( $version::VERSION or defined( _load('version') )) and version->can('new') ) { # use version.pm if it is installed. return version->new($cur) <=> version->new($min); } elsif ( $Sort::Versions::VERSION or defined( _load('Sort::Versions') ) ) { # use Sort::Versions as the sorting algorithm for a.b.c versions return Sort::Versions::versioncmp( $cur, $min ); } warn "Cannot reliably compare non-decimal formatted versions.\n" . "Please install version.pm or Sort::Versions.\n"; } # plain comparison local $^W = 0; # shuts off 'not numeric' bugs return $cur <=> $min; } # nothing; this usage is deprecated. sub main::PREREQ_PM { return {}; } sub _make_args { my %args = @_; $args{PREREQ_PM} = { %{ $args{PREREQ_PM} || {} }, @Existing, @Missing } if $UnderCPAN or $TestOnly; if ( $args{EXE_FILES} and -e 'MANIFEST' ) { require ExtUtils::Manifest; my $manifest = ExtUtils::Manifest::maniread('MANIFEST'); $args{EXE_FILES} = [ grep { exists $manifest->{$_} } @{ $args{EXE_FILES} } ]; } $args{test}{TESTS} ||= 't/*.t'; $args{test}{TESTS} = join( ' ', grep { !exists( $DisabledTests{$_} ) } map { glob($_) } split( /\s+/, $args{test}{TESTS} ) ); my $missing = join( ',', @Missing ); my $config = join( ',', UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) if $Config; $PostambleActions = ( ($missing and not $UnderCPAN) ? "\$(PERL) $0 --config=$config --installdeps=$missing" : "\$(NOECHO) \$(NOOP)" ); my $deps_list = join( ',', @Missing, @Existing ); $PostambleActionsUpgradeDeps = "\$(PERL) $0 --config=$config --upgradedeps=$deps_list"; my $config_notest = join( ',', (UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config}), 'notest', 1 ) if $Config; $PostambleActionsNoTest = ( ($missing and not $UnderCPAN) ? "\$(PERL) $0 --config=$config_notest --installdeps=$missing" : "\$(NOECHO) \$(NOOP)" ); $PostambleActionsUpgradeDepsNoTest = "\$(PERL) $0 --config=$config_notest --upgradedeps=$deps_list"; $PostambleActionsListDeps = '@$(PERL) -le "print for @ARGV" ' . join(' ', map $Missing[$_], grep $_ % 2 == 0, 0..$#Missing); my @all = (@Missing, @Existing); $PostambleActionsListAllDeps = '@$(PERL) -le "print for @ARGV" ' . join(' ', map $all[$_], grep $_ % 2 == 0, 0..$#all); return %args; } # a wrapper to ExtUtils::MakeMaker::WriteMakefile sub Write { require Carp; Carp::croak "WriteMakefile: Need even number of args" if @_ % 2; if ($CheckOnly) { print << "."; *** Makefile not written in check-only mode. . return; } my %args = _make_args(@_); no strict 'refs'; $PostambleUsed = 0; local *MY::postamble = \&postamble unless defined &MY::postamble; ExtUtils::MakeMaker::WriteMakefile(%args); print << "." unless $PostambleUsed; *** WARNING: Makefile written with customized MY::postamble() without including contents from Module::AutoInstall::postamble() -- auto installation features disabled. Please contact the author. . return 1; } sub postamble { $PostambleUsed = 1; my $fragment; $fragment .= <<"AUTO_INSTALL" if !$InstallDepsTarget; config :: installdeps \t\$(NOECHO) \$(NOOP) AUTO_INSTALL $fragment .= <<"END_MAKE"; checkdeps :: \t\$(PERL) $0 --checkdeps installdeps :: \t$PostambleActions installdeps_notest :: \t$PostambleActionsNoTest upgradedeps :: \t$PostambleActionsUpgradeDeps upgradedeps_notest :: \t$PostambleActionsUpgradeDepsNoTest listdeps :: \t$PostambleActionsListDeps listalldeps :: \t$PostambleActionsListAllDeps END_MAKE return $fragment; } 1; __END__ #line 1193 Net-GitHub-0.55/inc/Module/Install/000755 000765 000024 00000000000 12254516254 017544 5ustar00faylandstaff000000 000000 Net-GitHub-0.55/inc/Module/Install.pm000644 000765 000024 00000030135 12254516226 020103 0ustar00faylandstaff000000 000000 #line 1 package Module::Install; # For any maintainers: # The load order for Module::Install is a bit magic. # It goes something like this... # # IF ( host has Module::Install installed, creating author mode ) { # 1. Makefile.PL calls "use inc::Module::Install" # 2. $INC{inc/Module/Install.pm} set to installed version of inc::Module::Install # 3. The installed version of inc::Module::Install loads # 4. inc::Module::Install calls "require Module::Install" # 5. The ./inc/ version of Module::Install loads # } ELSE { # 1. Makefile.PL calls "use inc::Module::Install" # 2. $INC{inc/Module/Install.pm} set to ./inc/ version of Module::Install # 3. The ./inc/ version of Module::Install loads # } use 5.005; use strict 'vars'; use Cwd (); use File::Find (); use File::Path (); use vars qw{$VERSION $MAIN}; BEGIN { # All Module::Install core packages now require synchronised versions. # This will be used to ensure we don't accidentally load old or # different versions of modules. # This is not enforced yet, but will be some time in the next few # releases once we can make sure it won't clash with custom # Module::Install extensions. $VERSION = '1.06'; # Storage for the pseudo-singleton $MAIN = undef; *inc::Module::Install::VERSION = *VERSION; @inc::Module::Install::ISA = __PACKAGE__; } sub import { my $class = shift; my $self = $class->new(@_); my $who = $self->_caller; #------------------------------------------------------------- # all of the following checks should be included in import(), # to allow "eval 'require Module::Install; 1' to test # installation of Module::Install. (RT #51267) #------------------------------------------------------------- # Whether or not inc::Module::Install is actually loaded, the # $INC{inc/Module/Install.pm} is what will still get set as long as # the caller loaded module this in the documented manner. # If not set, the caller may NOT have loaded the bundled version, and thus # they may not have a MI version that works with the Makefile.PL. This would # result in false errors or unexpected behaviour. And we don't want that. my $file = join( '/', 'inc', split /::/, __PACKAGE__ ) . '.pm'; unless ( $INC{$file} ) { die <<"END_DIE" } Please invoke ${\__PACKAGE__} with: use inc::${\__PACKAGE__}; not: use ${\__PACKAGE__}; END_DIE # This reportedly fixes a rare Win32 UTC file time issue, but # as this is a non-cross-platform XS module not in the core, # we shouldn't really depend on it. See RT #24194 for detail. # (Also, this module only supports Perl 5.6 and above). eval "use Win32::UTCFileTime" if $^O eq 'MSWin32' && $] >= 5.006; # If the script that is loading Module::Install is from the future, # then make will detect this and cause it to re-run over and over # again. This is bad. Rather than taking action to touch it (which # is unreliable on some platforms and requires write permissions) # for now we should catch this and refuse to run. if ( -f $0 ) { my $s = (stat($0))[9]; # If the modification time is only slightly in the future, # sleep briefly to remove the problem. my $a = $s - time; if ( $a > 0 and $a < 5 ) { sleep 5 } # Too far in the future, throw an error. my $t = time; if ( $s > $t ) { die <<"END_DIE" } Your installer $0 has a modification time in the future ($s > $t). This is known to create infinite loops in make. Please correct this, then run $0 again. END_DIE } # Build.PL was formerly supported, but no longer is due to excessive # difficulty in implementing every single feature twice. if ( $0 =~ /Build.PL$/i ) { die <<"END_DIE" } Module::Install no longer supports Build.PL. It was impossible to maintain duel backends, and has been deprecated. Please remove all Build.PL files and only use the Makefile.PL installer. END_DIE #------------------------------------------------------------- # To save some more typing in Module::Install installers, every... # use inc::Module::Install # ...also acts as an implicit use strict. $^H |= strict::bits(qw(refs subs vars)); #------------------------------------------------------------- unless ( -f $self->{file} ) { foreach my $key (keys %INC) { delete $INC{$key} if $key =~ /Module\/Install/; } local $^W; require "$self->{path}/$self->{dispatch}.pm"; File::Path::mkpath("$self->{prefix}/$self->{author}"); $self->{admin} = "$self->{name}::$self->{dispatch}"->new( _top => $self ); $self->{admin}->init; @_ = ($class, _self => $self); goto &{"$self->{name}::import"}; } local $^W; *{"${who}::AUTOLOAD"} = $self->autoload; $self->preload; # Unregister loader and worker packages so subdirs can use them again delete $INC{'inc/Module/Install.pm'}; delete $INC{'Module/Install.pm'}; # Save to the singleton $MAIN = $self; return 1; } sub autoload { my $self = shift; my $who = $self->_caller; my $cwd = Cwd::cwd(); my $sym = "${who}::AUTOLOAD"; $sym->{$cwd} = sub { my $pwd = Cwd::cwd(); if ( my $code = $sym->{$pwd} ) { # Delegate back to parent dirs goto &$code unless $cwd eq $pwd; } unless ($$sym =~ s/([^:]+)$//) { # XXX: it looks like we can't retrieve the missing function # via $$sym (usually $main::AUTOLOAD) in this case. # I'm still wondering if we should slurp Makefile.PL to # get some context or not ... my ($package, $file, $line) = caller; die <<"EOT"; Unknown function is found at $file line $line. Execution of $file aborted due to runtime errors. If you're a contributor to a project, you may need to install some Module::Install extensions from CPAN (or other repository). If you're a user of a module, please contact the author. EOT } my $method = $1; if ( uc($method) eq $method ) { # Do nothing return; } elsif ( $method =~ /^_/ and $self->can($method) ) { # Dispatch to the root M:I class return $self->$method(@_); } # Dispatch to the appropriate plugin unshift @_, ( $self, $1 ); goto &{$self->can('call')}; }; } sub preload { my $self = shift; unless ( $self->{extensions} ) { $self->load_extensions( "$self->{prefix}/$self->{path}", $self ); } my @exts = @{$self->{extensions}}; unless ( @exts ) { @exts = $self->{admin}->load_all_extensions; } my %seen; foreach my $obj ( @exts ) { while (my ($method, $glob) = each %{ref($obj) . '::'}) { next unless $obj->can($method); next if $method =~ /^_/; next if $method eq uc($method); $seen{$method}++; } } my $who = $self->_caller; foreach my $name ( sort keys %seen ) { local $^W; *{"${who}::$name"} = sub { ${"${who}::AUTOLOAD"} = "${who}::$name"; goto &{"${who}::AUTOLOAD"}; }; } } sub new { my ($class, %args) = @_; delete $INC{'FindBin.pm'}; { # to suppress the redefine warning local $SIG{__WARN__} = sub {}; require FindBin; } # ignore the prefix on extension modules built from top level. my $base_path = Cwd::abs_path($FindBin::Bin); unless ( Cwd::abs_path(Cwd::cwd()) eq $base_path ) { delete $args{prefix}; } return $args{_self} if $args{_self}; $args{dispatch} ||= 'Admin'; $args{prefix} ||= 'inc'; $args{author} ||= ($^O eq 'VMS' ? '_author' : '.author'); $args{bundle} ||= 'inc/BUNDLES'; $args{base} ||= $base_path; $class =~ s/^\Q$args{prefix}\E:://; $args{name} ||= $class; $args{version} ||= $class->VERSION; unless ( $args{path} ) { $args{path} = $args{name}; $args{path} =~ s!::!/!g; } $args{file} ||= "$args{base}/$args{prefix}/$args{path}.pm"; $args{wrote} = 0; bless( \%args, $class ); } sub call { my ($self, $method) = @_; my $obj = $self->load($method) or return; splice(@_, 0, 2, $obj); goto &{$obj->can($method)}; } sub load { my ($self, $method) = @_; $self->load_extensions( "$self->{prefix}/$self->{path}", $self ) unless $self->{extensions}; foreach my $obj (@{$self->{extensions}}) { return $obj if $obj->can($method); } my $admin = $self->{admin} or die <<"END_DIE"; The '$method' method does not exist in the '$self->{prefix}' path! Please remove the '$self->{prefix}' directory and run $0 again to load it. END_DIE my $obj = $admin->load($method, 1); push @{$self->{extensions}}, $obj; $obj; } sub load_extensions { my ($self, $path, $top) = @_; my $should_reload = 0; unless ( grep { ! ref $_ and lc $_ eq lc $self->{prefix} } @INC ) { unshift @INC, $self->{prefix}; $should_reload = 1; } foreach my $rv ( $self->find_extensions($path) ) { my ($file, $pkg) = @{$rv}; next if $self->{pathnames}{$pkg}; local $@; my $new = eval { local $^W; require $file; $pkg->can('new') }; unless ( $new ) { warn $@ if $@; next; } $self->{pathnames}{$pkg} = $should_reload ? delete $INC{$file} : $INC{$file}; push @{$self->{extensions}}, &{$new}($pkg, _top => $top ); } $self->{extensions} ||= []; } sub find_extensions { my ($self, $path) = @_; my @found; File::Find::find( sub { my $file = $File::Find::name; return unless $file =~ m!^\Q$path\E/(.+)\.pm\Z!is; my $subpath = $1; return if lc($subpath) eq lc($self->{dispatch}); $file = "$self->{path}/$subpath.pm"; my $pkg = "$self->{name}::$subpath"; $pkg =~ s!/!::!g; # If we have a mixed-case package name, assume case has been preserved # correctly. Otherwise, root through the file to locate the case-preserved # version of the package name. if ( $subpath eq lc($subpath) || $subpath eq uc($subpath) ) { my $content = Module::Install::_read($subpath . '.pm'); my $in_pod = 0; foreach ( split //, $content ) { $in_pod = 1 if /^=\w/; $in_pod = 0 if /^=cut/; next if ($in_pod || /^=cut/); # skip pod text next if /^\s*#/; # and comments if ( m/^\s*package\s+($pkg)\s*;/i ) { $pkg = $1; last; } } } push @found, [ $file, $pkg ]; }, $path ) if -d $path; @found; } ##################################################################### # Common Utility Functions sub _caller { my $depth = 0; my $call = caller($depth); while ( $call eq __PACKAGE__ ) { $depth++; $call = caller($depth); } return $call; } # Done in evals to avoid confusing Perl::MinimumVersion eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@; sub _read { local *FH; open( FH, '<', $_[0] ) or die "open($_[0]): $!"; my $string = do { local $/; }; close FH or die "close($_[0]): $!"; return $string; } END_NEW sub _read { local *FH; open( FH, "< $_[0]" ) or die "open($_[0]): $!"; my $string = do { local $/; }; close FH or die "close($_[0]): $!"; return $string; } END_OLD sub _readperl { my $string = Module::Install::_read($_[0]); $string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg; $string =~ s/(\n)\n*__(?:DATA|END)__\b.*\z/$1/s; $string =~ s/\n\n=\w+.+?\n\n=cut\b.+?\n+/\n\n/sg; return $string; } sub _readpod { my $string = Module::Install::_read($_[0]); $string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg; return $string if $_[0] =~ /\.pod\z/; $string =~ s/(^|\n=cut\b.+?\n+)[^=\s].+?\n(\n=\w+|\z)/$1$2/sg; $string =~ s/\n*=pod\b[^\n]*\n+/\n\n/sg; $string =~ s/\n*=cut\b[^\n]*\n+/\n\n/sg; $string =~ s/^\n+//s; return $string; } # Done in evals to avoid confusing Perl::MinimumVersion eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@; sub _write { local *FH; open( FH, '>', $_[0] ) or die "open($_[0]): $!"; foreach ( 1 .. $#_ ) { print FH $_[$_] or die "print($_[0]): $!"; } close FH or die "close($_[0]): $!"; } END_NEW sub _write { local *FH; open( FH, "> $_[0]" ) or die "open($_[0]): $!"; foreach ( 1 .. $#_ ) { print FH $_[$_] or die "print($_[0]): $!"; } close FH or die "close($_[0]): $!"; } END_OLD # _version is for processing module versions (eg, 1.03_05) not # Perl versions (eg, 5.8.1). sub _version ($) { my $s = shift || 0; my $d =()= $s =~ /(\.)/g; if ( $d >= 2 ) { # Normalise multipart versions $s =~ s/(\.)(\d{1,3})/sprintf("$1%03d",$2)/eg; } $s =~ s/^(\d+)\.?//; my $l = $1 || 0; my @v = map { $_ . '0' x (3 - length $_) } $s =~ /(\d{1,3})\D?/g; $l = $l . '.' . join '', @v if @v; return $l + 0; } sub _cmp ($$) { _version($_[1]) <=> _version($_[2]); } # Cloned from Params::Util::_CLASS sub _CLASS ($) { ( defined $_[0] and ! ref $_[0] and $_[0] =~ m/^[^\W\d]\w*(?:::\w+)*\z/s ) ? $_[0] : undef; } 1; # Copyright 2008 - 2012 Adam Kennedy. Net-GitHub-0.55/inc/Module/Install/AutoInstall.pm000644 000765 000024 00000004162 12254516226 022343 0ustar00faylandstaff000000 000000 #line 1 package Module::Install::AutoInstall; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.06'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub AutoInstall { $_[0] } sub run { my $self = shift; $self->auto_install_now(@_); } sub write { my $self = shift; $self->auto_install(@_); } sub auto_install { my $self = shift; return if $self->{done}++; # Flatten array of arrays into a single array my @core = map @$_, map @$_, grep ref, $self->build_requires, $self->requires; my @config = @_; # We'll need Module::AutoInstall $self->include('Module::AutoInstall'); require Module::AutoInstall; my @features_require = Module::AutoInstall->import( (@config ? (-config => \@config) : ()), (@core ? (-core => \@core) : ()), $self->features, ); my %seen; my @requires = map @$_, map @$_, grep ref, $self->requires; while (my ($mod, $ver) = splice(@requires, 0, 2)) { $seen{$mod}{$ver}++; } my @build_requires = map @$_, map @$_, grep ref, $self->build_requires; while (my ($mod, $ver) = splice(@build_requires, 0, 2)) { $seen{$mod}{$ver}++; } my @configure_requires = map @$_, map @$_, grep ref, $self->configure_requires; while (my ($mod, $ver) = splice(@configure_requires, 0, 2)) { $seen{$mod}{$ver}++; } my @deduped; while (my ($mod, $ver) = splice(@features_require, 0, 2)) { push @deduped, $mod => $ver unless $seen{$mod}{$ver}++; } $self->requires(@deduped); $self->makemaker_args( Module::AutoInstall::_make_args() ); my $class = ref($self); $self->postamble( "# --- $class section:\n" . Module::AutoInstall::postamble() ); } sub installdeps_target { my ($self, @args) = @_; $self->include('Module::AutoInstall'); require Module::AutoInstall; Module::AutoInstall::_installdeps_target(1); $self->auto_install(@args); } sub auto_install_now { my $self = shift; $self->auto_install(@_); Module::AutoInstall::do_install(); } 1; Net-GitHub-0.55/inc/Module/Install/Base.pm000644 000765 000024 00000002147 12254516226 020757 0ustar00faylandstaff000000 000000 #line 1 package Module::Install::Base; use strict 'vars'; use vars qw{$VERSION}; BEGIN { $VERSION = '1.06'; } # Suspend handler for "redefined" warnings BEGIN { my $w = $SIG{__WARN__}; $SIG{__WARN__} = sub { $w }; } #line 42 sub new { my $class = shift; unless ( defined &{"${class}::call"} ) { *{"${class}::call"} = sub { shift->_top->call(@_) }; } unless ( defined &{"${class}::load"} ) { *{"${class}::load"} = sub { shift->_top->load(@_) }; } bless { @_ }, $class; } #line 61 sub AUTOLOAD { local $@; my $func = eval { shift->_top->autoload } or return; goto &$func; } #line 75 sub _top { $_[0]->{_top}; } #line 90 sub admin { $_[0]->_top->{admin} or Module::Install::Base::FakeAdmin->new; } #line 106 sub is_admin { ! $_[0]->admin->isa('Module::Install::Base::FakeAdmin'); } sub DESTROY {} package Module::Install::Base::FakeAdmin; use vars qw{$VERSION}; BEGIN { $VERSION = $Module::Install::Base::VERSION; } my $fake; sub new { $fake ||= bless(\@_, $_[0]); } sub AUTOLOAD {} sub DESTROY {} # Restore warning handler BEGIN { $SIG{__WARN__} = $SIG{__WARN__}->(); } 1; #line 159 Net-GitHub-0.55/inc/Module/Install/Can.pm000644 000765 000024 00000006157 12254516226 020613 0ustar00faylandstaff000000 000000 #line 1 package Module::Install::Can; use strict; use Config (); use ExtUtils::MakeMaker (); use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.06'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } # check if we can load some module ### Upgrade this to not have to load the module if possible sub can_use { my ($self, $mod, $ver) = @_; $mod =~ s{::|\\}{/}g; $mod .= '.pm' unless $mod =~ /\.pm$/i; my $pkg = $mod; $pkg =~ s{/}{::}g; $pkg =~ s{\.pm$}{}i; local $@; eval { require $mod; $pkg->VERSION($ver || 0); 1 }; } # Check if we can run some command sub can_run { my ($self, $cmd) = @_; my $_cmd = $cmd; return $_cmd if (-x $_cmd or $_cmd = MM->maybe_command($_cmd)); for my $dir ((split /$Config::Config{path_sep}/, $ENV{PATH}), '.') { next if $dir eq ''; require File::Spec; my $abs = File::Spec->catfile($dir, $cmd); return $abs if (-x $abs or $abs = MM->maybe_command($abs)); } return; } # Can our C compiler environment build XS files sub can_xs { my $self = shift; # Ensure we have the CBuilder module $self->configure_requires( 'ExtUtils::CBuilder' => 0.27 ); # Do we have the configure_requires checker? local $@; eval "require ExtUtils::CBuilder;"; if ( $@ ) { # They don't obey configure_requires, so it is # someone old and delicate. Try to avoid hurting # them by falling back to an older simpler test. return $self->can_cc(); } # Do we have a working C compiler my $builder = ExtUtils::CBuilder->new( quiet => 1, ); unless ( $builder->have_compiler ) { # No working C compiler return 0; } # Write a C file representative of what XS becomes require File::Temp; my ( $FH, $tmpfile ) = File::Temp::tempfile( "compilexs-XXXXX", SUFFIX => '.c', ); binmode $FH; print $FH <<'END_C'; #include "EXTERN.h" #include "perl.h" #include "XSUB.h" int main(int argc, char **argv) { return 0; } int boot_sanexs() { return 1; } END_C close $FH; # Can the C compiler access the same headers XS does my @libs = (); my $object = undef; eval { local $^W = 0; $object = $builder->compile( source => $tmpfile, ); @libs = $builder->link( objects => $object, module_name => 'sanexs', ); }; my $result = $@ ? 0 : 1; # Clean up all the build files foreach ( $tmpfile, $object, @libs ) { next unless defined $_; 1 while unlink; } return $result; } # Can we locate a (the) C compiler sub can_cc { my $self = shift; my @chunks = split(/ /, $Config::Config{cc}) or return; # $Config{cc} may contain args; try to find out the program part while (@chunks) { return $self->can_run("@chunks") || (pop(@chunks), next); } return; } # Fix Cygwin bug on maybe_command(); if ( $^O eq 'cygwin' ) { require ExtUtils::MM_Cygwin; require ExtUtils::MM_Win32; if ( ! defined(&ExtUtils::MM_Cygwin::maybe_command) ) { *ExtUtils::MM_Cygwin::maybe_command = sub { my ($self, $file) = @_; if ($file =~ m{^/cygdrive/}i and ExtUtils::MM_Win32->can('maybe_command')) { ExtUtils::MM_Win32->maybe_command($file); } else { ExtUtils::MM_Unix->maybe_command($file); } } } } 1; __END__ #line 236 Net-GitHub-0.55/inc/Module/Install/Fetch.pm000644 000765 000024 00000004627 12254516226 021143 0ustar00faylandstaff000000 000000 #line 1 package Module::Install::Fetch; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.06'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub get_file { my ($self, %args) = @_; my ($scheme, $host, $path, $file) = $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; if ( $scheme eq 'http' and ! eval { require LWP::Simple; 1 } ) { $args{url} = $args{ftp_url} or (warn("LWP support unavailable!\n"), return); ($scheme, $host, $path, $file) = $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; } $|++; print "Fetching '$file' from $host... "; unless (eval { require Socket; Socket::inet_aton($host) }) { warn "'$host' resolve failed!\n"; return; } return unless $scheme eq 'ftp' or $scheme eq 'http'; require Cwd; my $dir = Cwd::getcwd(); chdir $args{local_dir} or return if exists $args{local_dir}; if (eval { require LWP::Simple; 1 }) { LWP::Simple::mirror($args{url}, $file); } elsif (eval { require Net::FTP; 1 }) { eval { # use Net::FTP to get past firewall my $ftp = Net::FTP->new($host, Passive => 1, Timeout => 600); $ftp->login("anonymous", 'anonymous@example.com'); $ftp->cwd($path); $ftp->binary; $ftp->get($file) or (warn("$!\n"), return); $ftp->quit; } } elsif (my $ftp = $self->can_run('ftp')) { eval { # no Net::FTP, fallback to ftp.exe require FileHandle; my $fh = FileHandle->new; local $SIG{CHLD} = 'IGNORE'; unless ($fh->open("|$ftp -n")) { warn "Couldn't open ftp: $!\n"; chdir $dir; return; } my @dialog = split(/\n/, <<"END_FTP"); open $host user anonymous anonymous\@example.com cd $path binary get $file $file quit END_FTP foreach (@dialog) { $fh->print("$_\n") } $fh->close; } } else { warn "No working 'ftp' program available!\n"; chdir $dir; return; } unless (-f $file) { warn "Fetching failed: $@\n"; chdir $dir; return; } return if exists $args{size} and -s $file != $args{size}; system($args{run}) if exists $args{run}; unlink($file) if $args{remove}; print(((!exists $args{check_for} or -e $args{check_for}) ? "done!" : "failed! ($!)"), "\n"); chdir $dir; return !$?; } 1; Net-GitHub-0.55/inc/Module/Install/Include.pm000644 000765 000024 00000001015 12254516226 021461 0ustar00faylandstaff000000 000000 #line 1 package Module::Install::Include; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.06'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub include { shift()->admin->include(@_); } sub include_deps { shift()->admin->include_deps(@_); } sub auto_include { shift()->admin->auto_include(@_); } sub auto_include_deps { shift()->admin->auto_include_deps(@_); } sub auto_include_dependent_dists { shift()->admin->auto_include_dependent_dists(@_); } 1; Net-GitHub-0.55/inc/Module/Install/Makefile.pm000644 000765 000024 00000027437 12254516226 021633 0ustar00faylandstaff000000 000000 #line 1 package Module::Install::Makefile; use strict 'vars'; use ExtUtils::MakeMaker (); use Module::Install::Base (); use Fcntl qw/:flock :seek/; use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.06'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub Makefile { $_[0] } my %seen = (); sub prompt { shift; # Infinite loop protection my @c = caller(); if ( ++$seen{"$c[1]|$c[2]|$_[0]"} > 3 ) { die "Caught an potential prompt infinite loop ($c[1]|$c[2]|$_[0])"; } # In automated testing or non-interactive session, always use defaults if ( ($ENV{AUTOMATED_TESTING} or -! -t STDIN) and ! $ENV{PERL_MM_USE_DEFAULT} ) { local $ENV{PERL_MM_USE_DEFAULT} = 1; goto &ExtUtils::MakeMaker::prompt; } else { goto &ExtUtils::MakeMaker::prompt; } } # Store a cleaned up version of the MakeMaker version, # since we need to behave differently in a variety of # ways based on the MM version. my $makemaker = eval $ExtUtils::MakeMaker::VERSION; # If we are passed a param, do a "newer than" comparison. # Otherwise, just return the MakeMaker version. sub makemaker { ( @_ < 2 or $makemaker >= eval($_[1]) ) ? $makemaker : 0 } # Ripped from ExtUtils::MakeMaker 6.56, and slightly modified # as we only need to know here whether the attribute is an array # or a hash or something else (which may or may not be appendable). my %makemaker_argtype = ( C => 'ARRAY', CONFIG => 'ARRAY', # CONFIGURE => 'CODE', # ignore DIR => 'ARRAY', DL_FUNCS => 'HASH', DL_VARS => 'ARRAY', EXCLUDE_EXT => 'ARRAY', EXE_FILES => 'ARRAY', FUNCLIST => 'ARRAY', H => 'ARRAY', IMPORTS => 'HASH', INCLUDE_EXT => 'ARRAY', LIBS => 'ARRAY', # ignore '' MAN1PODS => 'HASH', MAN3PODS => 'HASH', META_ADD => 'HASH', META_MERGE => 'HASH', PL_FILES => 'HASH', PM => 'HASH', PMLIBDIRS => 'ARRAY', PMLIBPARENTDIRS => 'ARRAY', PREREQ_PM => 'HASH', CONFIGURE_REQUIRES => 'HASH', SKIP => 'ARRAY', TYPEMAPS => 'ARRAY', XS => 'HASH', # VERSION => ['version',''], # ignore # _KEEP_AFTER_FLUSH => '', clean => 'HASH', depend => 'HASH', dist => 'HASH', dynamic_lib=> 'HASH', linkext => 'HASH', macro => 'HASH', postamble => 'HASH', realclean => 'HASH', test => 'HASH', tool_autosplit => 'HASH', # special cases where you can use makemaker_append CCFLAGS => 'APPENDABLE', DEFINE => 'APPENDABLE', INC => 'APPENDABLE', LDDLFLAGS => 'APPENDABLE', LDFROM => 'APPENDABLE', ); sub makemaker_args { my ($self, %new_args) = @_; my $args = ( $self->{makemaker_args} ||= {} ); foreach my $key (keys %new_args) { if ($makemaker_argtype{$key}) { if ($makemaker_argtype{$key} eq 'ARRAY') { $args->{$key} = [] unless defined $args->{$key}; unless (ref $args->{$key} eq 'ARRAY') { $args->{$key} = [$args->{$key}] } push @{$args->{$key}}, ref $new_args{$key} eq 'ARRAY' ? @{$new_args{$key}} : $new_args{$key}; } elsif ($makemaker_argtype{$key} eq 'HASH') { $args->{$key} = {} unless defined $args->{$key}; foreach my $skey (keys %{ $new_args{$key} }) { $args->{$key}{$skey} = $new_args{$key}{$skey}; } } elsif ($makemaker_argtype{$key} eq 'APPENDABLE') { $self->makemaker_append($key => $new_args{$key}); } } else { if (defined $args->{$key}) { warn qq{MakeMaker attribute "$key" is overriden; use "makemaker_append" to append values\n}; } $args->{$key} = $new_args{$key}; } } return $args; } # For mm args that take multiple space-seperated args, # append an argument to the current list. sub makemaker_append { my $self = shift; my $name = shift; my $args = $self->makemaker_args; $args->{$name} = defined $args->{$name} ? join( ' ', $args->{$name}, @_ ) : join( ' ', @_ ); } sub build_subdirs { my $self = shift; my $subdirs = $self->makemaker_args->{DIR} ||= []; for my $subdir (@_) { push @$subdirs, $subdir; } } sub clean_files { my $self = shift; my $clean = $self->makemaker_args->{clean} ||= {}; %$clean = ( %$clean, FILES => join ' ', grep { length $_ } ($clean->{FILES} || (), @_), ); } sub realclean_files { my $self = shift; my $realclean = $self->makemaker_args->{realclean} ||= {}; %$realclean = ( %$realclean, FILES => join ' ', grep { length $_ } ($realclean->{FILES} || (), @_), ); } sub libs { my $self = shift; my $libs = ref $_[0] ? shift : [ shift ]; $self->makemaker_args( LIBS => $libs ); } sub inc { my $self = shift; $self->makemaker_args( INC => shift ); } sub _wanted_t { } sub tests_recursive { my $self = shift; my $dir = shift || 't'; unless ( -d $dir ) { die "tests_recursive dir '$dir' does not exist"; } my %tests = map { $_ => 1 } split / /, ($self->tests || ''); require File::Find; File::Find::find( sub { /\.t$/ and -f $_ and $tests{"$File::Find::dir/*.t"} = 1 }, $dir ); $self->tests( join ' ', sort keys %tests ); } sub write { my $self = shift; die "&Makefile->write() takes no arguments\n" if @_; # Check the current Perl version my $perl_version = $self->perl_version; if ( $perl_version ) { eval "use $perl_version; 1" or die "ERROR: perl: Version $] is installed, " . "but we need version >= $perl_version"; } # Make sure we have a new enough MakeMaker require ExtUtils::MakeMaker; if ( $perl_version and $self->_cmp($perl_version, '5.006') >= 0 ) { # This previous attempted to inherit the version of # ExtUtils::MakeMaker in use by the module author, but this # was found to be untenable as some authors build releases # using future dev versions of EU:MM that nobody else has. # Instead, #toolchain suggests we use 6.59 which is the most # stable version on CPAN at time of writing and is, to quote # ribasushi, "not terminally fucked, > and tested enough". # TODO: We will now need to maintain this over time to push # the version up as new versions are released. $self->build_requires( 'ExtUtils::MakeMaker' => 6.59 ); $self->configure_requires( 'ExtUtils::MakeMaker' => 6.59 ); } else { # Allow legacy-compatibility with 5.005 by depending on the # most recent EU:MM that supported 5.005. $self->build_requires( 'ExtUtils::MakeMaker' => 6.36 ); $self->configure_requires( 'ExtUtils::MakeMaker' => 6.36 ); } # Generate the MakeMaker params my $args = $self->makemaker_args; $args->{DISTNAME} = $self->name; $args->{NAME} = $self->module_name || $self->name; $args->{NAME} =~ s/-/::/g; $args->{VERSION} = $self->version or die <<'EOT'; ERROR: Can't determine distribution version. Please specify it explicitly via 'version' in Makefile.PL, or set a valid $VERSION in a module, and provide its file path via 'version_from' (or 'all_from' if you prefer) in Makefile.PL. EOT if ( $self->tests ) { my @tests = split ' ', $self->tests; my %seen; $args->{test} = { TESTS => (join ' ', grep {!$seen{$_}++} @tests), }; } elsif ( $Module::Install::ExtraTests::use_extratests ) { # Module::Install::ExtraTests doesn't set $self->tests and does its own tests via harness. # So, just ignore our xt tests here. } elsif ( -d 'xt' and ($Module::Install::AUTHOR or $ENV{RELEASE_TESTING}) ) { $args->{test} = { TESTS => join( ' ', map { "$_/*.t" } grep { -d $_ } qw{ t xt } ), }; } if ( $] >= 5.005 ) { $args->{ABSTRACT} = $self->abstract; $args->{AUTHOR} = join ', ', @{$self->author || []}; } if ( $self->makemaker(6.10) ) { $args->{NO_META} = 1; #$args->{NO_MYMETA} = 1; } if ( $self->makemaker(6.17) and $self->sign ) { $args->{SIGN} = 1; } unless ( $self->is_admin ) { delete $args->{SIGN}; } if ( $self->makemaker(6.31) and $self->license ) { $args->{LICENSE} = $self->license; } my $prereq = ($args->{PREREQ_PM} ||= {}); %$prereq = ( %$prereq, map { @$_ } # flatten [module => version] map { @$_ } grep $_, ($self->requires) ); # Remove any reference to perl, PREREQ_PM doesn't support it delete $args->{PREREQ_PM}->{perl}; # Merge both kinds of requires into BUILD_REQUIRES my $build_prereq = ($args->{BUILD_REQUIRES} ||= {}); %$build_prereq = ( %$build_prereq, map { @$_ } # flatten [module => version] map { @$_ } grep $_, ($self->configure_requires, $self->build_requires) ); # Remove any reference to perl, BUILD_REQUIRES doesn't support it delete $args->{BUILD_REQUIRES}->{perl}; # Delete bundled dists from prereq_pm, add it to Makefile DIR my $subdirs = ($args->{DIR} || []); if ($self->bundles) { my %processed; foreach my $bundle (@{ $self->bundles }) { my ($mod_name, $dist_dir) = @$bundle; delete $prereq->{$mod_name}; $dist_dir = File::Basename::basename($dist_dir); # dir for building this module if (not exists $processed{$dist_dir}) { if (-d $dist_dir) { # List as sub-directory to be processed by make push @$subdirs, $dist_dir; } # Else do nothing: the module is already present on the system $processed{$dist_dir} = undef; } } } unless ( $self->makemaker('6.55_03') ) { %$prereq = (%$prereq,%$build_prereq); delete $args->{BUILD_REQUIRES}; } if ( my $perl_version = $self->perl_version ) { eval "use $perl_version; 1" or die "ERROR: perl: Version $] is installed, " . "but we need version >= $perl_version"; if ( $self->makemaker(6.48) ) { $args->{MIN_PERL_VERSION} = $perl_version; } } if ($self->installdirs) { warn qq{old INSTALLDIRS (probably set by makemaker_args) is overriden by installdirs\n} if $args->{INSTALLDIRS}; $args->{INSTALLDIRS} = $self->installdirs; } my %args = map { ( $_ => $args->{$_} ) } grep {defined($args->{$_} ) } keys %$args; my $user_preop = delete $args{dist}->{PREOP}; if ( my $preop = $self->admin->preop($user_preop) ) { foreach my $key ( keys %$preop ) { $args{dist}->{$key} = $preop->{$key}; } } my $mm = ExtUtils::MakeMaker::WriteMakefile(%args); $self->fix_up_makefile($mm->{FIRST_MAKEFILE} || 'Makefile'); } sub fix_up_makefile { my $self = shift; my $makefile_name = shift; my $top_class = ref($self->_top) || ''; my $top_version = $self->_top->VERSION || ''; my $preamble = $self->preamble ? "# Preamble by $top_class $top_version\n" . $self->preamble : ''; my $postamble = "# Postamble by $top_class $top_version\n" . ($self->postamble || ''); local *MAKEFILE; open MAKEFILE, "+< $makefile_name" or die "fix_up_makefile: Couldn't open $makefile_name: $!"; eval { flock MAKEFILE, LOCK_EX }; my $makefile = do { local $/; }; $makefile =~ s/\b(test_harness\(\$\(TEST_VERBOSE\), )/$1'inc', /; $makefile =~ s/( -I\$\(INST_ARCHLIB\))/ -Iinc$1/g; $makefile =~ s/( "-I\$\(INST_LIB\)")/ "-Iinc"$1/g; $makefile =~ s/^(FULLPERL = .*)/$1 "-Iinc"/m; $makefile =~ s/^(PERL = .*)/$1 "-Iinc"/m; # Module::Install will never be used to build the Core Perl # Sometimes PERL_LIB and PERL_ARCHLIB get written anyway, which breaks # PREFIX/PERL5LIB, and thus, install_share. Blank them if they exist $makefile =~ s/^PERL_LIB = .+/PERL_LIB =/m; #$makefile =~ s/^PERL_ARCHLIB = .+/PERL_ARCHLIB =/m; # Perl 5.005 mentions PERL_LIB explicitly, so we have to remove that as well. $makefile =~ s/(\"?)-I\$\(PERL_LIB\)\1//g; # XXX - This is currently unused; not sure if it breaks other MM-users # $makefile =~ s/^pm_to_blib\s+:\s+/pm_to_blib :: /mg; seek MAKEFILE, 0, SEEK_SET; truncate MAKEFILE, 0; print MAKEFILE "$preamble$makefile$postamble" or die $!; close MAKEFILE or die $!; 1; } sub preamble { my ($self, $text) = @_; $self->{preamble} = $text . $self->{preamble} if defined $text; $self->{preamble}; } sub postamble { my ($self, $text) = @_; $self->{postamble} ||= $self->admin->postamble; $self->{postamble} .= $text if defined $text; $self->{postamble} } 1; __END__ #line 544 Net-GitHub-0.55/inc/Module/Install/Metadata.pm000644 000765 000024 00000043277 12254516226 021636 0ustar00faylandstaff000000 000000 #line 1 package Module::Install::Metadata; use strict 'vars'; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.06'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } my @boolean_keys = qw{ sign }; my @scalar_keys = qw{ name module_name abstract version distribution_type tests installdirs }; my @tuple_keys = qw{ configure_requires build_requires requires recommends bundles resources }; my @resource_keys = qw{ homepage bugtracker repository }; my @array_keys = qw{ keywords author }; *authors = \&author; sub Meta { shift } sub Meta_BooleanKeys { @boolean_keys } sub Meta_ScalarKeys { @scalar_keys } sub Meta_TupleKeys { @tuple_keys } sub Meta_ResourceKeys { @resource_keys } sub Meta_ArrayKeys { @array_keys } foreach my $key ( @boolean_keys ) { *$key = sub { my $self = shift; if ( defined wantarray and not @_ ) { return $self->{values}->{$key}; } $self->{values}->{$key} = ( @_ ? $_[0] : 1 ); return $self; }; } foreach my $key ( @scalar_keys ) { *$key = sub { my $self = shift; return $self->{values}->{$key} if defined wantarray and !@_; $self->{values}->{$key} = shift; return $self; }; } foreach my $key ( @array_keys ) { *$key = sub { my $self = shift; return $self->{values}->{$key} if defined wantarray and !@_; $self->{values}->{$key} ||= []; push @{$self->{values}->{$key}}, @_; return $self; }; } foreach my $key ( @resource_keys ) { *$key = sub { my $self = shift; unless ( @_ ) { return () unless $self->{values}->{resources}; return map { $_->[1] } grep { $_->[0] eq $key } @{ $self->{values}->{resources} }; } return $self->{values}->{resources}->{$key} unless @_; my $uri = shift or die( "Did not provide a value to $key()" ); $self->resources( $key => $uri ); return 1; }; } foreach my $key ( grep { $_ ne "resources" } @tuple_keys) { *$key = sub { my $self = shift; return $self->{values}->{$key} unless @_; my @added; while ( @_ ) { my $module = shift or last; my $version = shift || 0; push @added, [ $module, $version ]; } push @{ $self->{values}->{$key} }, @added; return map {@$_} @added; }; } # Resource handling my %lc_resource = map { $_ => 1 } qw{ homepage license bugtracker repository }; sub resources { my $self = shift; while ( @_ ) { my $name = shift or last; my $value = shift or next; if ( $name eq lc $name and ! $lc_resource{$name} ) { die("Unsupported reserved lowercase resource '$name'"); } $self->{values}->{resources} ||= []; push @{ $self->{values}->{resources} }, [ $name, $value ]; } $self->{values}->{resources}; } # Aliases for build_requires that will have alternative # meanings in some future version of META.yml. sub test_requires { shift->build_requires(@_) } sub install_requires { shift->build_requires(@_) } # Aliases for installdirs options sub install_as_core { $_[0]->installdirs('perl') } sub install_as_cpan { $_[0]->installdirs('site') } sub install_as_site { $_[0]->installdirs('site') } sub install_as_vendor { $_[0]->installdirs('vendor') } sub dynamic_config { my $self = shift; my $value = @_ ? shift : 1; if ( $self->{values}->{dynamic_config} ) { # Once dynamic we never change to static, for safety return 0; } $self->{values}->{dynamic_config} = $value ? 1 : 0; return 1; } # Convenience command sub static_config { shift->dynamic_config(0); } sub perl_version { my $self = shift; return $self->{values}->{perl_version} unless @_; my $version = shift or die( "Did not provide a value to perl_version()" ); # Normalize the version $version = $self->_perl_version($version); # We don't support the really old versions unless ( $version >= 5.005 ) { die "Module::Install only supports 5.005 or newer (use ExtUtils::MakeMaker)\n"; } $self->{values}->{perl_version} = $version; } sub all_from { my ( $self, $file ) = @_; unless ( defined($file) ) { my $name = $self->name or die( "all_from called with no args without setting name() first" ); $file = join('/', 'lib', split(/-/, $name)) . '.pm'; $file =~ s{.*/}{} unless -e $file; unless ( -e $file ) { die("all_from cannot find $file from $name"); } } unless ( -f $file ) { die("The path '$file' does not exist, or is not a file"); } $self->{values}{all_from} = $file; # Some methods pull from POD instead of code. # If there is a matching .pod, use that instead my $pod = $file; $pod =~ s/\.pm$/.pod/i; $pod = $file unless -e $pod; # Pull the different values $self->name_from($file) unless $self->name; $self->version_from($file) unless $self->version; $self->perl_version_from($file) unless $self->perl_version; $self->author_from($pod) unless @{$self->author || []}; $self->license_from($pod) unless $self->license; $self->abstract_from($pod) unless $self->abstract; return 1; } sub provides { my $self = shift; my $provides = ( $self->{values}->{provides} ||= {} ); %$provides = (%$provides, @_) if @_; return $provides; } sub auto_provides { my $self = shift; return $self unless $self->is_admin; unless (-e 'MANIFEST') { warn "Cannot deduce auto_provides without a MANIFEST, skipping\n"; return $self; } # Avoid spurious warnings as we are not checking manifest here. local $SIG{__WARN__} = sub {1}; require ExtUtils::Manifest; local *ExtUtils::Manifest::manicheck = sub { return }; require Module::Build; my $build = Module::Build->new( dist_name => $self->name, dist_version => $self->version, license => $self->license, ); $self->provides( %{ $build->find_dist_packages || {} } ); } sub feature { my $self = shift; my $name = shift; my $features = ( $self->{values}->{features} ||= [] ); my $mods; if ( @_ == 1 and ref( $_[0] ) ) { # The user used ->feature like ->features by passing in the second # argument as a reference. Accomodate for that. $mods = $_[0]; } else { $mods = \@_; } my $count = 0; push @$features, ( $name => [ map { ref($_) ? ( ref($_) eq 'HASH' ) ? %$_ : @$_ : $_ } @$mods ] ); return @$features; } sub features { my $self = shift; while ( my ( $name, $mods ) = splice( @_, 0, 2 ) ) { $self->feature( $name, @$mods ); } return $self->{values}->{features} ? @{ $self->{values}->{features} } : (); } sub no_index { my $self = shift; my $type = shift; push @{ $self->{values}->{no_index}->{$type} }, @_ if $type; return $self->{values}->{no_index}; } sub read { my $self = shift; $self->include_deps( 'YAML::Tiny', 0 ); require YAML::Tiny; my $data = YAML::Tiny::LoadFile('META.yml'); # Call methods explicitly in case user has already set some values. while ( my ( $key, $value ) = each %$data ) { next unless $self->can($key); if ( ref $value eq 'HASH' ) { while ( my ( $module, $version ) = each %$value ) { $self->can($key)->($self, $module => $version ); } } else { $self->can($key)->($self, $value); } } return $self; } sub write { my $self = shift; return $self unless $self->is_admin; $self->admin->write_meta; return $self; } sub version_from { require ExtUtils::MM_Unix; my ( $self, $file ) = @_; $self->version( ExtUtils::MM_Unix->parse_version($file) ); # for version integrity check $self->makemaker_args( VERSION_FROM => $file ); } sub abstract_from { require ExtUtils::MM_Unix; my ( $self, $file ) = @_; $self->abstract( bless( { DISTNAME => $self->name }, 'ExtUtils::MM_Unix' )->parse_abstract($file) ); } # Add both distribution and module name sub name_from { my ($self, $file) = @_; if ( Module::Install::_read($file) =~ m/ ^ \s* package \s* ([\w:]+) \s* ; /ixms ) { my ($name, $module_name) = ($1, $1); $name =~ s{::}{-}g; $self->name($name); unless ( $self->module_name ) { $self->module_name($module_name); } } else { die("Cannot determine name from $file\n"); } } sub _extract_perl_version { if ( $_[0] =~ m/ ^\s* (?:use|require) \s* v? ([\d_\.]+) \s* ; /ixms ) { my $perl_version = $1; $perl_version =~ s{_}{}g; return $perl_version; } else { return; } } sub perl_version_from { my $self = shift; my $perl_version=_extract_perl_version(Module::Install::_read($_[0])); if ($perl_version) { $self->perl_version($perl_version); } else { warn "Cannot determine perl version info from $_[0]\n"; return; } } sub author_from { my $self = shift; my $content = Module::Install::_read($_[0]); if ($content =~ m/ =head \d \s+ (?:authors?)\b \s* ([^\n]*) | =head \d \s+ (?:licen[cs]e|licensing|copyright|legal)\b \s* .*? copyright .*? \d\d\d[\d.]+ \s* (?:\bby\b)? \s* ([^\n]*) /ixms) { my $author = $1 || $2; # XXX: ugly but should work anyway... if (eval "require Pod::Escapes; 1") { # Pod::Escapes has a mapping table. # It's in core of perl >= 5.9.3, and should be installed # as one of the Pod::Simple's prereqs, which is a prereq # of Pod::Text 3.x (see also below). $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } { defined $2 ? chr($2) : defined $Pod::Escapes::Name2character_number{$1} ? chr($Pod::Escapes::Name2character_number{$1}) : do { warn "Unknown escape: E<$1>"; "E<$1>"; }; }gex; } elsif (eval "require Pod::Text; 1" && $Pod::Text::VERSION < 3) { # Pod::Text < 3.0 has yet another mapping table, # though the table name of 2.x and 1.x are different. # (1.x is in core of Perl < 5.6, 2.x is in core of # Perl < 5.9.3) my $mapping = ($Pod::Text::VERSION < 2) ? \%Pod::Text::HTML_Escapes : \%Pod::Text::ESCAPES; $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } { defined $2 ? chr($2) : defined $mapping->{$1} ? $mapping->{$1} : do { warn "Unknown escape: E<$1>"; "E<$1>"; }; }gex; } else { $author =~ s{E}{<}g; $author =~ s{E}{>}g; } $self->author($author); } else { warn "Cannot determine author info from $_[0]\n"; } } #Stolen from M::B my %license_urls = ( perl => 'http://dev.perl.org/licenses/', apache => 'http://apache.org/licenses/LICENSE-2.0', apache_1_1 => 'http://apache.org/licenses/LICENSE-1.1', artistic => 'http://opensource.org/licenses/artistic-license.php', artistic_2 => 'http://opensource.org/licenses/artistic-license-2.0.php', lgpl => 'http://opensource.org/licenses/lgpl-license.php', lgpl2 => 'http://opensource.org/licenses/lgpl-2.1.php', lgpl3 => 'http://opensource.org/licenses/lgpl-3.0.html', bsd => 'http://opensource.org/licenses/bsd-license.php', gpl => 'http://opensource.org/licenses/gpl-license.php', gpl2 => 'http://opensource.org/licenses/gpl-2.0.php', gpl3 => 'http://opensource.org/licenses/gpl-3.0.html', mit => 'http://opensource.org/licenses/mit-license.php', mozilla => 'http://opensource.org/licenses/mozilla1.1.php', open_source => undef, unrestricted => undef, restrictive => undef, unknown => undef, ); sub license { my $self = shift; return $self->{values}->{license} unless @_; my $license = shift or die( 'Did not provide a value to license()' ); $license = __extract_license($license) || lc $license; $self->{values}->{license} = $license; # Automatically fill in license URLs if ( $license_urls{$license} ) { $self->resources( license => $license_urls{$license} ); } return 1; } sub _extract_license { my $pod = shift; my $matched; return __extract_license( ($matched) = $pod =~ m/ (=head \d \s+ L(?i:ICEN[CS]E|ICENSING)\b.*?) (=head \d.*|=cut.*|)\z /xms ) || __extract_license( ($matched) = $pod =~ m/ (=head \d \s+ (?:C(?i:OPYRIGHTS?)|L(?i:EGAL))\b.*?) (=head \d.*|=cut.*|)\z /xms ); } sub __extract_license { my $license_text = shift or return; my @phrases = ( '(?:under )?the same (?:terms|license) as (?:perl|the perl (?:\d )?programming language)' => 'perl', 1, '(?:under )?the terms of (?:perl|the perl programming language) itself' => 'perl', 1, 'Artistic and GPL' => 'perl', 1, 'GNU general public license' => 'gpl', 1, 'GNU public license' => 'gpl', 1, 'GNU lesser general public license' => 'lgpl', 1, 'GNU lesser public license' => 'lgpl', 1, 'GNU library general public license' => 'lgpl', 1, 'GNU library public license' => 'lgpl', 1, 'GNU Free Documentation license' => 'unrestricted', 1, 'GNU Affero General Public License' => 'open_source', 1, '(?:Free)?BSD license' => 'bsd', 1, 'Artistic license 2\.0' => 'artistic_2', 1, 'Artistic license' => 'artistic', 1, 'Apache (?:Software )?license' => 'apache', 1, 'GPL' => 'gpl', 1, 'LGPL' => 'lgpl', 1, 'BSD' => 'bsd', 1, 'Artistic' => 'artistic', 1, 'MIT' => 'mit', 1, 'Mozilla Public License' => 'mozilla', 1, 'Q Public License' => 'open_source', 1, 'OpenSSL License' => 'unrestricted', 1, 'SSLeay License' => 'unrestricted', 1, 'zlib License' => 'open_source', 1, 'proprietary' => 'proprietary', 0, ); while ( my ($pattern, $license, $osi) = splice(@phrases, 0, 3) ) { $pattern =~ s#\s+#\\s+#gs; if ( $license_text =~ /\b$pattern\b/i ) { return $license; } } return ''; } sub license_from { my $self = shift; if (my $license=_extract_license(Module::Install::_read($_[0]))) { $self->license($license); } else { warn "Cannot determine license info from $_[0]\n"; return 'unknown'; } } sub _extract_bugtracker { my @links = $_[0] =~ m#L<( https?\Q://rt.cpan.org/\E[^>]+| https?\Q://github.com/\E[\w_]+/[\w_]+/issues| https?\Q://code.google.com/p/\E[\w_\-]+/issues/list )>#gx; my %links; @links{@links}=(); @links=keys %links; return @links; } sub bugtracker_from { my $self = shift; my $content = Module::Install::_read($_[0]); my @links = _extract_bugtracker($content); unless ( @links ) { warn "Cannot determine bugtracker info from $_[0]\n"; return 0; } if ( @links > 1 ) { warn "Found more than one bugtracker link in $_[0]\n"; return 0; } # Set the bugtracker bugtracker( $links[0] ); return 1; } sub requires_from { my $self = shift; my $content = Module::Install::_readperl($_[0]); my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+(v?[\d\.]+)/mg; while ( @requires ) { my $module = shift @requires; my $version = shift @requires; $self->requires( $module => $version ); } } sub test_requires_from { my $self = shift; my $content = Module::Install::_readperl($_[0]); my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+([\d\.]+)/mg; while ( @requires ) { my $module = shift @requires; my $version = shift @requires; $self->test_requires( $module => $version ); } } # Convert triple-part versions (eg, 5.6.1 or 5.8.9) to # numbers (eg, 5.006001 or 5.008009). # Also, convert double-part versions (eg, 5.8) sub _perl_version { my $v = $_[-1]; $v =~ s/^([1-9])\.([1-9]\d?\d?)$/sprintf("%d.%03d",$1,$2)/e; $v =~ s/^([1-9])\.([1-9]\d?\d?)\.(0|[1-9]\d?\d?)$/sprintf("%d.%03d%03d",$1,$2,$3 || 0)/e; $v =~ s/(\.\d\d\d)000$/$1/; $v =~ s/_.+$//; if ( ref($v) ) { # Numify $v = $v + 0; } return $v; } sub add_metadata { my $self = shift; my %hash = @_; for my $key (keys %hash) { warn "add_metadata: $key is not prefixed with 'x_'.\n" . "Use appopriate function to add non-private metadata.\n" unless $key =~ /^x_/; $self->{values}->{$key} = $hash{$key}; } } ###################################################################### # MYMETA Support sub WriteMyMeta { die "WriteMyMeta has been deprecated"; } sub write_mymeta_yaml { my $self = shift; # We need YAML::Tiny to write the MYMETA.yml file unless ( eval { require YAML::Tiny; 1; } ) { return 1; } # Generate the data my $meta = $self->_write_mymeta_data or return 1; # Save as the MYMETA.yml file print "Writing MYMETA.yml\n"; YAML::Tiny::DumpFile('MYMETA.yml', $meta); } sub write_mymeta_json { my $self = shift; # We need JSON to write the MYMETA.json file unless ( eval { require JSON; 1; } ) { return 1; } # Generate the data my $meta = $self->_write_mymeta_data or return 1; # Save as the MYMETA.yml file print "Writing MYMETA.json\n"; Module::Install::_write( 'MYMETA.json', JSON->new->pretty(1)->canonical->encode($meta), ); } sub _write_mymeta_data { my $self = shift; # If there's no existing META.yml there is nothing we can do return undef unless -f 'META.yml'; # We need Parse::CPAN::Meta to load the file unless ( eval { require Parse::CPAN::Meta; 1; } ) { return undef; } # Merge the perl version into the dependencies my $val = $self->Meta->{values}; my $perl = delete $val->{perl_version}; if ( $perl ) { $val->{requires} ||= []; my $requires = $val->{requires}; # Canonize to three-dot version after Perl 5.6 if ( $perl >= 5.006 ) { $perl =~ s{^(\d+)\.(\d\d\d)(\d*)}{join('.', $1, int($2||0), int($3||0))}e } unshift @$requires, [ perl => $perl ]; } # Load the advisory META.yml file my @yaml = Parse::CPAN::Meta::LoadFile('META.yml'); my $meta = $yaml[0]; # Overwrite the non-configure dependency hashs delete $meta->{requires}; delete $meta->{build_requires}; delete $meta->{recommends}; if ( exists $val->{requires} ) { $meta->{requires} = { map { @$_ } @{ $val->{requires} } }; } if ( exists $val->{build_requires} ) { $meta->{build_requires} = { map { @$_ } @{ $val->{build_requires} } }; } return $meta; } 1; Net-GitHub-0.55/inc/Module/Install/Win32.pm000644 000765 000024 00000003403 12254516226 021003 0ustar00faylandstaff000000 000000 #line 1 package Module::Install::Win32; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.06'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } # determine if the user needs nmake, and download it if needed sub check_nmake { my $self = shift; $self->load('can_run'); $self->load('get_file'); require Config; return unless ( $^O eq 'MSWin32' and $Config::Config{make} and $Config::Config{make} =~ /^nmake\b/i and ! $self->can_run('nmake') ); print "The required 'nmake' executable not found, fetching it...\n"; require File::Basename; my $rv = $self->get_file( url => 'http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe', ftp_url => 'ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe', local_dir => File::Basename::dirname($^X), size => 51928, run => 'Nmake15.exe /o > nul', check_for => 'Nmake.exe', remove => 1, ); die <<'END_MESSAGE' unless $rv; ------------------------------------------------------------------------------- Since you are using Microsoft Windows, you will need the 'nmake' utility before installation. It's available at: http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe or ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe Please download the file manually, save it to a directory in %PATH% (e.g. C:\WINDOWS\COMMAND\), then launch the MS-DOS command line shell, "cd" to that directory, and run "Nmake15.exe" from there; that will create the 'nmake.exe' file needed by this module. You may then resume the installation process described in README. ------------------------------------------------------------------------------- END_MESSAGE } 1; Net-GitHub-0.55/inc/Module/Install/WriteAll.pm000644 000765 000024 00000002376 12254516226 021634 0ustar00faylandstaff000000 000000 #line 1 package Module::Install::WriteAll; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.06'; @ISA = qw{Module::Install::Base}; $ISCORE = 1; } sub WriteAll { my $self = shift; my %args = ( meta => 1, sign => 0, inline => 0, check_nmake => 1, @_, ); $self->sign(1) if $args{sign}; $self->admin->WriteAll(%args) if $self->is_admin; $self->check_nmake if $args{check_nmake}; unless ( $self->makemaker_args->{PL_FILES} ) { # XXX: This still may be a bit over-defensive... unless ($self->makemaker(6.25)) { $self->makemaker_args( PL_FILES => {} ) if -f 'Build.PL'; } } # Until ExtUtils::MakeMaker support MYMETA.yml, make sure # we clean it up properly ourself. $self->realclean_files('MYMETA.yml'); if ( $args{inline} ) { $self->Inline->write; } else { $self->Makefile->write; } # The Makefile write process adds a couple of dependencies, # so write the META.yml files after the Makefile. if ( $args{meta} ) { $self->Meta->write; } # Experimental support for MYMETA if ( $ENV{X_MYMETA} ) { if ( $ENV{X_MYMETA} eq 'JSON' ) { $self->Meta->write_mymeta_json; } else { $self->Meta->write_mymeta_yaml; } } return 1; } 1;