2014-06-07 19:53:13 +02:00
< ? php
class ExtendedGitGraph {
2014-06-08 15:32:00 +02:00
const FILE_RAW_DATA = 'protected/data/ext_git_graph_apidata.dat' ;
const FILE_FINISHED_DATA = 'protected/data/gitgraph.dat' ;
const API_AUTHORIZE = 'https://github.com/login/oauth/authorize?client_id=%s' ;
const API_TOKEN = 'https://github.com/login/oauth/access_token?client_id=%s&client_secret=%s&code=%s' ;
2014-06-07 19:53:13 +02:00
const API_RATELIMIT = 'https://api.github.com/rate_limit' ;
const API_REPOSITORIESLIST = 'https://api.github.com/users/%s/repos?page=%d&per_page=100' ;
private $username ;
private $token ;
private $tokenHeader ;
2014-06-08 15:32:00 +02:00
private $repositories ;
private $commits ;
private $commitmap = array ();
private $startdate = null ;
private $enddate = null ;
2014-06-07 19:53:13 +02:00
public function __construct ( $usr_name ) {
$this -> username = $usr_name ;
set_time_limit ( 300 ); // 5min
}
2014-06-08 15:32:00 +02:00
public function authenticate ( $auth_key , $client_id , $client_secret ) {
$url = sprintf ( self :: API_TOKEN , $client_id , $client_secret , $auth_key );
2014-06-07 19:53:13 +02:00
$result = file_get_contents ( $url );
$result = str_replace ( 'access_token=' , '' , $result );
$result = str_replace ( '&scope=&token_type=bearer' , '' , $result );
setToken ( $result );
}
public function setToken ( $token ) {
$this -> token = $token ;
$this -> tokenHeader = 'access_token=' . $token . '&token_type=bearer' ;
}
public function collect () {
ob_implicit_flush ( true );
ob_end_flush ();
//--------------------------------
$this -> listRepositories ();
$this -> listAllCommits ();
$this -> save ();
//--------------------------------
$this -> output_flushed ( $this -> getRemainingRequests () . ' Requests remaining' );
}
private function listRepositories () {
$page = 1 ;
$url = sprintf ( self :: API_REPOSITORIESLIST . '&' . $this -> tokenHeader , $this -> username , $page );
$result = $this -> getJSON ( $url );
$repo_list = array ();
while ( ! empty ( $result )) {
foreach ( $result as $result_repo ) {
$repo_list [] = $this -> parseRepoJSON ( $result_repo );
$this -> output_flushed ( " Found Repo: " . $result_repo -> { 'full_name' });
}
//##########
$url = sprintf ( self :: API_REPOSITORIESLIST . '&' . $this -> tokenHeader , $this -> username , ++ $page );
$result = $this -> getJSON ( $url );
}
$this -> repositories = $repo_list ;
}
private function getJSON ( $url ) {
$options = array ( 'http' => array ( 'user_agent' => $_SERVER [ 'HTTP_USER_AGENT' ]));
// $options = array('http' => array('user_agent'=> 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1944.0 Safari/537.36'));
$context = stream_context_create ( $options );
$response = file_get_contents ( $url , false , $context );
return json_decode ( $response );
}
private function getRemainingRequests () {
$json = $this -> getJSON ( self :: API_RATELIMIT . '?' . $this -> tokenHeader );
return $json -> { 'resources' } -> { 'core' } -> { 'remaining' };
}
private function listAllCommits () {
$this -> commits = array ();
foreach ( $this -> repositories as $repo ) {
$this -> listCommits ( $repo );
}
}
private function listCommits ( $repo ) {
$page = 1 ;
$url = $repo [ 'commits_url' ] . '?per_page=100&page=' . $page . '&author=' . $this -> username . '&' . $this -> tokenHeader ;
$result = $this -> getJSON ( $url );
$commit_list = array ();
while ( ! empty ( $result )) {
foreach ( $result as $result_commit ) {
$commit_list [] = $this -> parseCommitJSON ( $repo , $result_commit );
}
$this -> output_flushed ( " Found 100 Commits from " . $repo [ 'full_name' ]);
//##########
$url = $repo [ 'commits_url' ] . '?per_page=100&page=' . ++ $page . '&author=' . $this -> username . '&' . $this -> tokenHeader ;
$result = $this -> getJSON ( $url );
}
$this -> commits = array_merge ( $this -> commits , $commit_list );
}
private function parseRepoJSON ( $json ) {
return
[
'id' => $json -> { 'id' },
'name' => $json -> { 'name' },
'full_name' => $json -> { 'full_name' },
'owner' => $json -> { 'owner' } -> { 'login' },
'owner_id' => $json -> { 'owner' } -> { 'id' },
'owner_avatar-url' => $json -> { 'owner' } -> { 'avatar_url' },
'owner_gravatar-id' => $json -> { 'owner' } -> { 'gravatar_id' },
'url' => $json -> { 'html_url' },
'language' => $json -> { 'language' },
'url' => $json -> { 'html_url' },
'creation' => DateTime :: createFromFormat ( DateTime :: ISO8601 , $json -> { 'created_at' }),
'size' => $json -> { 'size' },
'default_branch' => $json -> { 'default_branch' },
'commits_url' => str_replace ( '{/sha}' , '' , $json -> { 'commits_url' }),
];
}
private function parseCommitJSON ( $repo , $json ) {
return
[
'sha' => $json -> { 'sha' },
'author_name' => $json -> { 'commit' } -> { 'author' } -> { 'name' },
'author_mail' => $json -> { 'commit' } -> { 'author' } -> { 'email' },
'author_login' => $json -> { 'author' } -> { 'login' },
'author_id' => $json -> { 'author' } -> { 'id' },
'sha' => $json -> { 'sha' },
'message' => $json -> { 'commit' } -> { 'message' },
'repository' => $repo ,
'date' => DateTime :: createFromFormat ( DateTime :: ISO8601 , $json -> { 'commit' } -> { 'author' } -> { 'date' }),
];
}
private function save () {
$this -> output_flushed ( " Start saving data " );
$save = serialize (
[
'repositories' => $this -> repositories ,
'commits' => $this -> commits ,
]);
2014-06-08 15:32:00 +02:00
file_put_contents ( self :: FILE_RAW_DATA , $save );
2014-06-07 19:53:13 +02:00
$this -> output_flushed ( 'Finished saving data' );
}
public function output_flushed ( $txt )
{
echo '[' . date ( 'H:i.s' ) . '] ' . $txt . " <br> " ;
}
public function loadData () {
2014-06-08 15:32:00 +02:00
$data = unserialize ( file_get_contents ( self :: FILE_RAW_DATA ));
2014-06-07 19:53:13 +02:00
$this -> repositories = $data [ 'repositories' ];
$this -> commits = $data [ 'commits' ];
}
public function generate ( $year ) {
$ymap = $this -> generateYearMap ( $year ); // unused on purpose (template.php needs it)
$ymapmax = $this -> getMaxCommitCount (); // unused on purpose (template.php needs it)
ob_start ();
include ( 'template.php' );
$returned = ob_get_contents ();
ob_end_clean ();
return $returned ;
}
public function generateAndSave () {
$result = '' ;
foreach ( $this -> getYears () as $year ) {
$result .= $this -> generate ( $year );
$result .= '<br />' ;
}
2014-06-08 15:32:00 +02:00
$this -> generateCommitMap ();
file_put_contents ( self :: FILE_FINISHED_DATA ,
2014-06-07 19:53:13 +02:00
serialize (
[
'creation' => new DateTime (),
2014-06-08 15:32:00 +02:00
'total' => count ( $this -> commits ),
'repos' => count ( $this -> repositories ),
'streak' => $this -> getLongestStreak (),
'streak_start' => $this -> getLongestStreakStart (),
'streak_end' => $this -> getLongestStreakEnd (),
'max_commits' => $this -> getMaxCommits (),
'max_commits_date' => $this -> getMaxCommitsDate (),
'avg_commits' => $this -> getAvgCommits (),
'start' => $this -> startdate ,
'end' => $this -> enddate ,
2014-06-07 19:53:13 +02:00
'content' => $result ,
]));
return $result ;
}
2014-06-08 15:32:00 +02:00
private function generateCommitMap () {
$this -> commitmap = array ();
$this -> startdate = $this -> getStartDate ();
$this -> enddate = $this -> getEndDate ();
$date = clone $this -> startdate ;
while ( $date < $this -> enddate ) {
$this -> commitmap [ $date -> format ( 'Y-m-d' )] = 0 ;
$date = $date -> modify ( " +1 day " );
}
foreach ( $this -> commits as $commit ) {
if ( array_key_exists ( $commit [ 'date' ] -> format ( 'Y-m-d' ), $this -> commitmap ))
$this -> commitmap [ $commit [ 'date' ] -> format ( 'Y-m-d' )] ++ ;
}
}
private function getStartDate () {
$date = $this -> commits [ 0 ][ 'date' ];
foreach ( $this -> commits as $commit ) {
if ( $commit [ 'date' ] < $date ) {
$date = clone $commit [ 'date' ];
}
}
return new DateTime ( $date -> format ( 'Y-m-d' ));
}
private function getEndDate () {
$date = $this -> commits [ 0 ][ 'date' ];
foreach ( $this -> commits as $commit ) {
if ( $commit [ 'date' ] > $date ) {
$date = clone $commit [ 'date' ];
}
}
return new DateTime ( $date -> format ( 'Y-m-d' ));
}
private function getCommitsForDate ( $d ) {
$v = $d -> format ( 'Y-m-d' );
if ( array_key_exists ( $v , $this -> commitmap ))
return $this -> commitmap [ $d -> format ( 'Y-m-d' )];
else
return 0 ;
}
private function getLongestStreak () {
/* @var $curr DateTime */
/* @var $end DateTime */
$curr = clone $this -> startdate ;
$end = clone $this -> enddate ;
$streak_curr = 0 ;
$streak_max = 0 ;
while ( $curr <= $end ) {
if ( $this -> getCommitsForDate ( $curr ) > 0 ) {
$streak_curr ++ ;
} else {
$streak_max = max ( $streak_max , $streak_curr );
$streak_curr = 0 ;
}
$curr = $curr -> modify ( '+1 day' );
}
$streak_max = max ( $streak_max , $streak_curr );
return $streak_max ;
}
private function getLongestStreakStart () {
/* @var $curr DateTime */
/* @var $end DateTime */
$curr = clone $this -> startdate ;
$end = clone $this -> enddate ;
$streak_curr_start = clone $curr ;
$streak_max_start = null ;
$streak_curr = 0 ;
$streak_max = 0 ;
while ( $curr <= $end ) {
if ( $this -> getCommitsForDate ( $curr ) > 0 ) {
$streak_curr ++ ;
} else {
if ( $streak_curr > $streak_max ) {
$streak_max = $streak_curr ;
$streak_max_start = clone $streak_curr_start ;
}
$streak_curr = 0 ;
$streak_curr_start = clone $curr ;
}
$curr = $curr -> modify ( '+1 day' );
}
if ( $streak_curr > $streak_max ) {
$streak_max_start = clone $streak_curr_start ;
}
return $streak_max_start ;
}
private function getLongestStreakEnd () {
/* @var $curr DateTime */
/* @var $end DateTime */
$curr = clone $this -> startdate ;
$end = clone $this -> enddate ;
$streak_max_end = null ;
$streak_curr = 0 ;
$streak_max = 0 ;
while ( $curr <= $end ) {
if ( $this -> getCommitsForDate ( $curr ) > 0 ) {
$streak_curr ++ ;
} else {
if ( $streak_curr > $streak_max ) {
$streak_max = $streak_curr ;
$streak_max_end = clone $curr ;
}
$streak_curr = 0 ;
}
$curr = $curr -> modify ( '+1 day' );
}
if ( $streak_curr > $streak_max ) {
$streak_max_end = clone $curr ;
}
return $streak_max_end ;
}
private function getMaxCommits () {
/* @var $curr DateTime */
/* @var $end DateTime */
$curr = clone $this -> startdate ;
$end = clone $this -> enddate ;
$max = 0 ;
while ( $curr <= $end ) {
$max = max ( $max , $this -> getCommitsForDate ( $curr ));
$curr = $curr -> modify ( '+1 day' );
}
return $max ;
}
private function getMaxCommitsDate () {
/* @var $curr DateTime */
/* @var $end DateTime */
$curr = clone $this -> startdate ;
$end = clone $this -> enddate ;
$max = 0 ;
$max_date = null ;
while ( $curr <= $end ) {
$c = $this -> getCommitsForDate ( $curr );
if ( $c >= $max ) {
$max = $c ;
$max_date = clone $curr ;
}
$max = max ( $max , $this -> getCommitsForDate ( $curr ));
$curr = $curr -> modify ( '+1 day' );
}
return $max_date ;
}
private function getAvgCommits () {
/* @var $curr DateTime */
/* @var $end DateTime */
$curr = clone $this -> startdate ;
$end = clone $this -> enddate ;
$max = array ();
while ( $curr <= $end ) {
$max [] = $this -> getCommitsForDate ( $curr );
$curr = $curr -> modify ( '+1 day' );
}
$sum = array_sum ( $max );
$count = count ( $max );
return $sum / $count ;
}
public function loadFinishedContent () {
$data = unserialize ( file_get_contents ( self :: FILE_FINISHED_DATA ));
2014-06-07 19:53:13 +02:00
return $data [ 'content' ];
}
2014-06-08 15:32:00 +02:00
public function loadFinishedData () {
$data = unserialize ( file_get_contents ( self :: FILE_FINISHED_DATA ));
return $data ;
2014-06-07 19:53:13 +02:00
}
private function getMaxCommitCount () {
$max = 0 ;
foreach ( $this -> getYears () as $year ) {
$max = max ( $max , max ( $this -> generateYearMap ( $year )));
}
return $max ;
}
private function generateYearMap ( $year ) {
$ymap = array ();
$date = new DateTime ( $year . '-01-01' );
while ( $date -> format ( 'Y' ) == $year ) {
$ymap [ $date -> format ( 'Y-m-d' )] = 0 ;
$date = $date -> modify ( " +1 day " );
}
foreach ( $this -> commits as $commit ) {
if ( array_key_exists ( $commit [ 'date' ] -> format ( 'Y-m-d' ), $ymap ))
$ymap [ $commit [ 'date' ] -> format ( 'Y-m-d' )] ++ ;
}
return $ymap ;
}
public function getYears () {
$years = array ();
foreach ( $this -> commits as $commit ) {
if ( ! in_array ( $commit [ 'date' ] -> format ( 'Y' ), $years ))
$years [] = $commit [ 'date' ] -> format ( 'Y' );
}
asort ( $years );
return $years ;
}
}