Skip to content

Instantly share code, notes, and snippets.

@123andy
Last active February 3, 2020 18:57
Show Gist options
  • Save 123andy/e05f712e4fce42d9033a0ca9d2bbd41e to your computer and use it in GitHub Desktop.
Save 123andy/e05f712e4fce42d9033a0ca9d2bbd41e to your computer and use it in GitHub Desktop.
A script to update any cloned modules in your local REDCap development server
<?php
/*
* This script is intended to help you keep your many cloned external modules current...
* To run, place this in your redcap root folder and from the command line run
*
* php update_pull.php
*
* Note that nothing will be automatically done unless you pass in a true argument as in
*
* php update_pull.php true
*
*/
// SCAN YOUR REDCAP TO SEE IF THERE ARE UPDATES TO BE HAD FORM GIT
// Find all folders that have a .gitsubrepo folder
$doUpdate = isset($argv[1]) && $argv[1] == "true";
$dirs = scanDir::scan(__DIR__, ".git", true);
// $files = array_slice($files,0,2); // DEBUG TEMP
// echo print_r($dirs);
// Parse out subrepo information
$subrepos = array();
$current = array();
$behind = array();
$other = array();
$errors = array();
$update = array();
foreach ($dirs as $i => $dir) {
$rel_dir = str_replace(__DIR__ . '/', '', $dir);
echo "Checking [" . str_pad($i, 3,' ',STR_PAD_LEFT) . "] " . str_pad($rel_dir,80,".");
$result = syscall("git fetch", $dir);
$result = syscall("git status", $dir);
if (!empty($result['error'])) {
$errors[] = $result;
$status = "errors";
} elseif (strpos($result['output'], "Your branch is up to date with") !== false && strpos($result['output'], "working tree clean") !== false) {
// echo "\n$dir is current";
$current[] = $dir;
$status = "current";
} elseif (strpos($result['output'], "Your branch is behind") !== false) {
$behind[] = $dir;
$update[] = "cd $dir; git pull;";
$status = "behind";
} else {
$other[$dir] = $result['output'];
$status = "see details";
}
echo $status . "\n";
$result = syscall("git remote get-url origin", $dir);
$subrepos[$dir] = $result['output'];
}
if (!empty($errors)) {
echo "\n============= ERRORS =============\n";
echo print_r($errors);
echo "\n";
}
if (!empty($other)) {
$file = sys_get_temp_dir() . "/update_issues.log";
$title = "============= " . count($other) . "OTHER ISSUES =============\n";
echo "\n$title";
echo "Saved to temp file as: $file\n";
file_put_contents($file, $title);
foreach ($other as $dir => $detail) {
// echo json_encode($o) . "\n";
$output = "=================================\n" . $dir .
"\n---------------------------------\n" . $detail . "\n";
// echo $output;
file_put_contents($file, $output, FILE_APPEND);
}
}
if (!empty($current)) {
echo "\n============= CURRENT =============\n";
echo count($current) . " of " . count($dirs) . " are current\n";
}
if (!empty($subrepos)) {
echo "\n============= SUBREPOS =============\n";
foreach ($subrepos as $path => $url) {
echo "$path => $url";
}
}
if (!empty($behind)) {
echo "\n============= BEHIND =============\n";
echo count($behind) . " of " . count($dirs) . " are behind\n";
echo "\t" . implode("\n\t", $behind);
if ($doUpdate) {
echo "Pulling updates...\n";
foreach ($behind as $dir) {
$result = syscall("git pull", $dir);
echo "\n----------------\n" . $dir . "\n" . print_r($result,true) . "\n";
}
echo "\n";
} else {
echo "\n\nExecute the following to update these repos or re-run this script with a 'true' argument (e.g. php " . $argv[0] . " true)\n" . implode("\n", $update) . "\n";
}
}
// var_dump($errors);
// var_dump($current);
// var_dump($behind);
// var_dump($other);
// $this->log($files);
// $this->log($subrepos);
// $this->subrepos = $subrepos;
/**
* Utility function for calling command-line functions as the www user
* @param $cmd string command to call
* @param $cwd string current working directory (defaults to repo)
* @param $useBash boolean Load bash shell
* @return array true/false if command was successful
*/
function syscall ($cmd, $cwd, $useBash = false)
{
if ($useBash === true) {
// We will be passing all input through the www-data user's bash
$bashCmd = $cmd;
$cmd = 'bash';
$descriptorspec = array(
0 => array('pipe', 'r'), // stdin
1 => array('pipe', 'w'), // stdout is a pipe that the child will write to
2 => array('pipe', 'w') // stderr out
);
} else {
$descriptorspec = array(
1 => array('pipe', 'w'), // stdout is a pipe that the child will write to
2 => array('pipe', 'w') // stderr out
);
}
$resource = proc_open($cmd, $descriptorspec, $pipes, $cwd);
if (is_resource($resource)) {
// if ($useBash) {
// fwrite($pipes[0], escapeshellcmd('source ' . $_ENV['APACHE_RUN_HOME'] . DIRECTORY_SEPARATOR . '.bash_profile')."\n");
// fwrite($pipes[0], escapeshellcmd($bashCmd) . "\n");
// fclose($pipes[0]);
// }
$output = stream_get_contents($pipes[1]);
$error = stream_get_contents($pipes[2]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($resource);
} else {
$error = "Unable to open resource";
}
$result = array (
"cmd" => $cmd,
"cwd" => $cwd,
"output" => $output,
"error" => $error);
return $result;
}
class scanDir {
static private $directories, $files, $ext_filter, $recursive, $dir_filter;
// ----------------------------------------------------------------------------------------------
// scan(dirpath::string|array, extensions::string|array, recursive::true|false, skipDirs::array)
static public function scan(){
// Initialize defaults
self::$recursive = true;
self::$directories = array();
self::$files = array();
self::$ext_filter = false;
self::$dir_filter = array();
// Check we have minimum parameters
if(!$args = func_get_args()){
die("Must provide a path string or array of path strings");
}
if(gettype($args[0]) != "string" && gettype($args[0]) != "array"){
die("Must provide a path string or array of path strings");
}
// Check if recursive scan | default action: no sub-directories
if(isset($args[2]) && $args[2] == true){self::$recursive = true;}
// Check if recursive scan | default action: no sub-directories
if(isset($args[3])) {
if(gettype($args[3]) == "array"){
self::$dir_filter = $args[3];
} else if(gettype($args[3]) == "string"){
self::$dir_filter[] = $args[3];
}
}
// Was a filter on file extensions included? | default action: return all file types
if(isset($args[1])){
if(gettype($args[1]) == "array"){self::$ext_filter = array_map('strtolower', $args[1]);}
else
if(gettype($args[1]) == "string"){self::$ext_filter[] = strtolower($args[1]);}
}
// Grab path(s)
self::verifyPaths($args[0]);
// return self::$files;
// Remove Duplicates and Re-index
return array_values(array_unique(self::$files));
}
static private function verifyPaths($paths){
$path_errors = array();
if(gettype($paths) == "string"){$paths = array($paths);}
foreach($paths as $path){
if(is_dir($path)){
self::$directories[] = $path;
$dirContents = self::find_contents($path);
} else {
$path_errors[] = $path;
}
}
}
// This is how we scan directories
static private function find_contents($dir){
// Skip filtered directories
foreach (self::$dir_filter as $filter) {
if (strpos($dir, $filter) !== false) {
// echo "<br>Skipping [$dir]";
return false;
} else {
// echo "<br>Including [$dir]";
}
}
$result = array();
$root = scandir($dir);
// self::$files[] = $result[] = "Scanning $dir";
foreach($root as $value){
// echo "<br>START $value";
if($value === '.' || $value === '..') {continue;}
if(is_link($value)) {continue;}
// SKIPPING NORMAL BEHAVIOR HERE
if(is_file($dir.DIRECTORY_SEPARATOR.$value)){
if(!self::$ext_filter || in_array(strtolower(pathinfo($dir.DIRECTORY_SEPARATOR.$value, PATHINFO_EXTENSION)), self::$ext_filter)){
self::$files[] = $result[] = $dir.DIRECTORY_SEPARATOR.$value;
// echo "<br>Adding $dir / $value";
}
continue;
}
// GET DIR for .GIT
if ($value == ".git") {
self::$files[] = $result[] = $dir;
continue;
}
// // Check for dotfile matches
// if(!self::$ext_filter || ( (substr($value,0,1) === ".") && in_array(substr($value,1), self::$ext_filter))) {
// self::$files[] = $result[] = $dir.DIRECTORY_SEPARATOR.$value;
// echo "<br>Adding $dir / $value";
// continue;
// }
if (self::$recursive) {
foreach(self::find_contents($dir.DIRECTORY_SEPARATOR.$value) as $foo) {
// echo "<br>Adding2 $dir / $value";
self::$files[] = $result[] = $foo;
}
}
}
// Return required for recursive search
return $result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment