44$ opts = parseOpts ();
55
66$ changes = array ();
7+ $ data_from = load ($ opts ['from ' ], $ opts ['path ' ], $ opts ['vcs ' ], '' );
8+ $ data_to = load ($ opts ['to ' ], $ opts ['path ' ], $ opts ['vcs ' ], 'composer.lock ' );
79
810if (! $ opts ['only-dev ' ]) {
9- $ changes ['changes ' ] = diff ('packages ' , $ opts [ ' from ' ] , $ opts [ ' to ' ], $ opts [ ' path ' ], $ opts [ ' vcs ' ] );
11+ $ changes ['changes ' ] = diff ('packages ' , $ data_from , $ data_to );
1012}
1113
1214if (! $ opts ['only-prod ' ]) {
13- $ changes ['changes-dev ' ] = diff ('packages-dev ' , $ opts [ ' from ' ] , $ opts [ ' to ' ], $ opts [ ' path ' ], $ opts [ ' vcs ' ] );
15+ $ changes ['changes-dev ' ] = diff ('packages-dev ' , $ data_from , $ data_to );
1416}
1517
1618if ($ opts ['json ' ]) {
@@ -31,28 +33,24 @@ if ($opts['md']) {
3133 ));
3234}
3335
34- $ table_titles = [
36+ $ table_titles = array (
3537 'changes ' => 'Production Changes ' ,
3638 'changes-dev ' => 'Dev Changes ' ,
37- ] ;
39+ ) ;
3840
3941foreach ($ changes as $ k => $ diff ) {
4042 print tableize ($ table_titles [$ k ], $ diff , $ table_opts );
4143}
4244
43- function diff ($ key , $ from , $ to , $ base_path , $ vcs ) {
45+ function diff ($ key , $ data_from , $ data_to ) {
4446
4547 $ pkgs = array ();
4648
47- $ data = load ($ from , $ base_path , $ vcs );
48-
49- foreach ($ data ->$ key as $ pkg ) {
49+ foreach ($ data_from ->$ key as $ pkg ) {
5050 $ pkgs [$ pkg ->name ] = array (version ($ pkg ), 'REMOVED ' , '' );
5151 }
5252
53- $ data = load ($ to , $ base_path , $ vcs );
54-
55- foreach ($ data ->$ key as $ pkg ) {
53+ foreach ($ data_to ->$ key as $ pkg ) {
5654 if (! array_key_exists ($ pkg ->name , $ pkgs )) {
5755 $ pkgs [$ pkg ->name ] = array ('NEW ' , version ($ pkg ), '' );
5856 continue ;
@@ -150,68 +148,72 @@ function urlFormatterMd($url, $text) {
150148 return sprintf ('[%s](%s) ' , $ text , $ url );
151149}
152150
153- function load ($ fileish , $ base_path = '' , $ vcs ) {
154- $ orig = $ fileish ;
151+ // $fileish is what the user actually requested.
152+ // $default_fileish is what it should be if $fileish is empty
153+ function load ($ fileish , $ base_path , $ force_vcs , $ default_fileish ) {
154+ $ loaders = ($ force_vcs || (empty ($ fileish ) && empty ($ default_fileish ))) ? array () : array ('loadFile ' );
155155
156- if (empty ($ base_path )) {
157- $ base_path = '. ' . DIRECTORY_SEPARATOR ;
158- } else {
159- $ base_path = rtrim ($ base_path , DIRECTORY_SEPARATOR ) . DIRECTORY_SEPARATOR ;
160- }
156+ $ vcses = $ force_vcs ? array ($ force_vcs ) : getVcses ();
157+ $ errors = array ();
161158
162- if (empty ($ fileish )) {
163- $ fileish = $ base_path . 'composer.lock ' ;
159+ foreach ($ vcses as $ vcs ) {
160+ $ detector = 'vcsDetect ' . ucfirst ($ vcs );
161+ if ($ vcs != $ force_vcs && function_exists ($ detector )) {
162+ list ($ available , $ err ) = call_user_func ($ detector , $ fileish , $ base_path , $ default_fileish );
163+ if ($ err ) {
164+ $ errors [] = $ err ;
165+ continue ;
166+ }
167+ if (!$ available ) continue ;
168+ }
169+ $ loaders [] = 'vcsLoad ' . ucfirst ($ vcs );
164170 }
165171
166- if (strpos ('svn:// ' , $ fileish ) !== 0 && isUrl ($ fileish )) {
167- if (! in_array (parse_url ($ fileish , PHP_URL_SCHEME ), stream_get_wrappers ())) {
168- error_log ("Error: no stream wrapper to open ' $ fileish' " );
169- exit (1 );
172+ if (empty ($ loaders )) {
173+ error_log (implode ("\n" , $ errors ));
174+ if ($ force_vcs ) {
175+ error_log ("Requested vcs ' $ force_vcs' not installed or otherwise unavailable " );
176+ } else {
177+ error_log ("No loaders were found; perhaps your vcs cli tools are not installed, not in PATH, or otherwise unavailable " );
170178 }
171-
172- return mustDecodeJson (file_get_contents ($ fileish ), $ fileish );
179+ exit (1 );
173180 }
174181
175- if (strpos ('svn:// ' , $ fileish ) !== 0 && file_exists ($ fileish )) {
176- return mustDecodeJson (file_get_contents ($ fileish ), $ fileish );
182+ $ errors = array ();
183+ foreach ($ loaders as $ loader ) {
184+ list ($ result , $ err ) = call_user_func_array ($ loader , array ($ fileish , $ base_path , $ default_fileish ));
185+ if (empty ($ err )) {
186+ return $ result ;
187+ }
188+ $ errors [] = "Failed to find ' $ fileish' with ' $ loader'; $ err " ;
177189 }
178190
179- //try to find vcs revision
180- if ($ vcs == 'git ' ){
181- if (strpos ($ orig , ': ' ) === false ) {
182- $ fileish .= ': ' . $ base_path . 'composer.lock ' ;
183- }
191+ foreach ($ errors as $ e ) {
192+ error_log ($ e );
193+ }
184194
185- $ lines = array ( );
186- exec ( ' git show ' . escapeshellarg ( $ fileish ), $ lines , $ exit );
195+ exit ( 1 );
196+ }
187197
188- if ($ exit !== 0 ) {
189- error_log ("Error: cannot open $ orig or find it in git as $ fileish " );
190- exit (1 );
198+ function loadFile ($ fileish , $ base_path , $ default_fileish ) {
199+ if (empty ($ fileish )) {
200+ $ fileish = $ default_fileish ;
201+ if (!empty ($ base_path )) {
202+ $ fileish = joinPath ($ base_path , $ fileish );
191203 }
192-
193- return mustDecodeJson (implode ("\n" , $ lines ), $ fileish );
194204 }
195205
196- elseif ($ vcs == 'svn ' ){
197- # explaination:
198- # http:// https:// svn:// => absolute url of repository (http/https already handled before)
199- # ^ => relative url from current workspace repository
200- # @ => repository url with version
201- if (preg_match ('#^\^|^svn://|@# ' , $ orig ) === 0 ) {
202- $ fileish = $ base_path . 'composer.lock@ ' .$ fileish ;
203- }
204- exec ('svn cat ' . escapeshellarg ($ fileish ), $ lines , $ exit );
206+ // Does it look like a url that we can handle with stream wrappers?
207+ if (isUrl ($ fileish ) && in_array (parse_url ($ fileish , PHP_URL_SCHEME ), stream_get_wrappers ())) {
208+ return array (mustDecodeJson (file_get_contents ($ fileish ), $ fileish ), false );
209+ }
205210
206- if ($ exit !== 0 ) {
207- error_log ("Error: cannot open $ orig or find it in svn as $ fileish " );
208- exit (1 );
209- }
210- return mustDecodeJson (implode ("\n" , $ lines ), $ fileish );
211+ // Is it a file in the local filesystem?
212+ if (file_exists ($ fileish )) {
213+ return array (mustDecodeJson (file_get_contents ($ fileish ), $ fileish ), false );
211214 }
212215
213- error_log ("Error: unhandled VCS $ vcs " );
214- exit (1 );
216+ return array (false , "Candidate ' $ fileish' does not look loadable from the fs or php stream wrappers " );
215217}
216218
217219function isUrl ($ string ) {
@@ -310,7 +312,7 @@ function getVcses() {
310312
311313function vcsDetectGit ($ _fileish ) {
312314 // Is there a git executable?
313- exec ('git --version ' , null , $ exit );
315+ exec ('sh -c " git --version" > /dev/null 2>&1 ' , $ _out , $ exit );
314316 if ($ exit !== 0 ) return array (false , "'git --version' exited with non-zero code ' $ exit' " );
315317
316318 // Does this look like a git repo?
@@ -341,7 +343,7 @@ function vcsLoadGit($fileish, $base_path, $_default_fileish) {
341343
342344function vcsDetectSvn ($ fileish , $ base_path , $ default_fileish ) {
343345 // Is there a git executable?
344- exec ('svn --version ' , null , $ exit );
346+ exec ('sh -c " svn --version" > /dev/null 2>&1 ' , $ _out , $ exit );
345347 if ($ exit !== 0 ) return array (false , "'svn --version' exited with non-zero code ' $ exit' " );
346348
347349 if (strpos ('svn:// ' , $ fileish ) === 0 ) {
@@ -428,13 +430,15 @@ function parseOpts() {
428430 usage ();
429431 }
430432
431- $ path = array_key_exists ('path ' , $ given ) ? $ given ['path ' ] : '' ;
432- $ vcs = array_key_exists ('vcs ' , $ given ) ? strtolower ($ given ['vcs ' ]) : vcsDetect ($ path );
433- $ defaultFrom = $ vcs == 'svn ' ? "BASE " : "HEAD " ;
433+ $ vcs = array_key_exists ('vcs ' , $ given ) ? $ given ['vcs ' ] : '' ;
434+ if ($ vcs && !function_exists ('vcsLoad ' . ucfirst ($ vcs ))) {
435+ error_log ("Unsupported vcs ' $ vcs' \n" );
436+ usage ();
437+ }
434438
435439 return array (
436- 'path ' => $ path ,
437- 'from ' => array_key_exists ('from ' , $ given ) ? $ given ['from ' ] : $ defaultFrom ,
440+ 'path ' => array_key_exists ( ' path ' , $ given ) ? $ given [ ' path ' ] : '' ,
441+ 'from ' => array_key_exists ('from ' , $ given ) ? $ given ['from ' ] : '' ,
438442 'to ' => array_key_exists ('to ' , $ given ) ? $ given ['to ' ] : '' ,
439443 'md ' => array_key_exists ('md ' , $ given ),
440444 'json ' => array_key_exists ('json ' , $ given ),
@@ -446,59 +450,25 @@ function parseOpts() {
446450 );
447451}
448452
449- function dirnameSafe ($ path ) {
450- $ parent = dirname ($ path );
451- return ($ parent != $ path && !empty ($ parent )) ? $ parent : false ;
452- }
453-
454- function joinPath (/* path parts */ ) {
455- return implode (DIRECTORY_SEPARATOR , array_map (function ($ part ) {
456- return trim ($ part , DIRECTORY_SEPARATOR );
457- }, func_get_args ()));
458- }
459-
460- function vcsDetect ($ base_path ) {
461- if (empty ($ base_path )) {
462- $ base_path = '. ' ;
463- }
464-
465- // > Trailing delimiters, such as \ and /, are also removed
466- // > returns false on failure, e.g. if the file does not exist.
467- $ base_path = realpath ($ base_path );
468- if ($ base_path === false ) return 'unknown ' ;
469-
470- $ tries = 10 ;
471- do {
472- if (is_dir (joinPath ($ base_path , '.git ' ))) {
473- return 'git ' ;
474- } elseif (is_dir (joinPath ($ base_path , '.svn ' ))) {
475- return 'svn ' ;
476- }
477-
478- $ base_path = dirnameSafe ($ base_path );
479- } while ($ base_path !== false && --$ tries > 0 );
480-
481- return 'unknown ' ;
482- }
483-
484453function usage () {
454+ $ vcses = implode (', ' , getVcses ());
485455 print <<<EOF
486456Usage: composer-lock-diff [options]
487457
488458Options:
489459 -h --help Print this message
490460 --path, -p Base to with which to prefix paths. Default "./"
491461 E.g. `-p app` would look for HEAD:app/composer.lock and app/composer.lock
492- --from The file, git ref, or git ref with filename to compare from
493- (git : HEAD:composer.lock, svn: composer.lock@BASE)
462+ --from The file, git ref, or git ref with filename to compare from
463+ (git: HEAD:composer.lock, svn: composer.lock@BASE)
494464 --to The file, git ref, or git ref with filename to compare to (composer.lock)
495465 --json Format output as JSON
496466 --pretty Pretty print JSON output (PHP >= 5.4.0)
497467 --md Use markdown instead of plain text
498468 --no-links Don't include Compare links in plain text or any links in markdown
499469 --only-prod Only include changes from `packages`
500470 --only-dev Only include changes from `packages-dev`
501- --vcs Force vcs (git, svn, ... ). Default auto-detect from path
471+ --vcs Force vcs ( $ vcses ). Default: attempt to auto-detect
502472
503473EOF ;
504474
0 commit comments