diff --git a/VERSION b/VERSION index 7c1777d22..bdc7d50a4 100644 --- a/VERSION +++ b/VERSION @@ -1,2 +1,2 @@ PRODUCT_ID=Airtime -PRODUCT_RELEASE=2.3.0 +PRODUCT_RELEASE=2.3.1 diff --git a/install_minimal/include/airtime-constants.php b/install_minimal/include/airtime-constants.php index cd5514f6d..10c620da9 100644 --- a/install_minimal/include/airtime-constants.php +++ b/install_minimal/include/airtime-constants.php @@ -1,3 +1,3 @@ &1 | grep -v \"will create implicit index\""); + passthru("export PGPASSWORD=$password && psql -h $host -U $username -q -f $dir/data/upgrade.sql $database 2>&1 | grep -v \"will create implicit index\""); + } +} diff --git a/install_minimal/upgrades/airtime-2.3.1/airtime-upgrade.php b/install_minimal/upgrades/airtime-2.3.1/airtime-upgrade.php new file mode 100644 index 000000000..80108a7ad --- /dev/null +++ b/install_minimal/upgrades/airtime-2.3.1/airtime-upgrade.php @@ -0,0 +1,9 @@ +fetchColumn(); + + date_default_timezone_set($timezone); + } + + public static function connectToDatabase($p_exitOnError = true) + { + try { + $con = Propel::getConnection(); + } catch (Exception $e) { + echo $e->getMessage().PHP_EOL; + echo "Database connection problem.".PHP_EOL; + echo "Check if database exists with corresponding permissions.".PHP_EOL; + if ($p_exitOnError) { + exit(1); + } + return false; + } + return true; + } + + + public static function DbTableExists($p_name) + { + $con = Propel::getConnection(); + try { + $sql = "SELECT * FROM ".$p_name." LIMIT 1"; + $con->query($sql); + } catch (PDOException $e){ + return false; + } + return true; + } + + private static function GetAirtimeSrcDir() + { + return __DIR__."/../../../../airtime_mvc"; + } + + public static function MigrateTablesToVersion($dir, $version) + { + echo "Upgrading database, may take several minutes, please wait".PHP_EOL; + + $appDir = self::GetAirtimeSrcDir(); + $command = "php --php-ini $dir/../../airtime-php.ini ". + "$appDir/library/doctrine/migrations/doctrine-migrations.phar ". + "--configuration=$dir/common/migrations.xml ". + "--db-configuration=$appDir/library/doctrine/migrations/migrations-db.php ". + "--no-interaction migrations:migrate $version"; + system($command); + } + + public static function BypassMigrations($dir, $version) + { + $appDir = self::GetAirtimeSrcDir(); + $command = "php --php-ini $dir/../../airtime-php.ini ". + "$appDir/library/doctrine/migrations/doctrine-migrations.phar ". + "--configuration=$dir/common/migrations.xml ". + "--db-configuration=$appDir/library/doctrine/migrations/migrations-db.php ". + "--no-interaction --add migrations:version $version"; + system($command); + } + + public static function upgradeConfigFiles(){ + + $configFiles = array(UpgradeCommon::CONF_FILE_AIRTIME, + UpgradeCommon::CONF_FILE_PYPO, + //this is not necessary because liquidsoap configs + //are automatically generated + //UpgradeCommon::CONF_FILE_LIQUIDSOAP, + UpgradeCommon::CONF_FILE_MEDIAMONITOR, + UpgradeCommon::CONF_FILE_API_CLIENT); + + // Backup the config files + $suffix = date("Ymdhis")."-".UpgradeCommon::VERSION_NUMBER; + foreach ($configFiles as $conf) { + // do not back up monit cfg -- ok?? not being done anyway + if (file_exists($conf)) { + echo "Backing up $conf to $conf$suffix.bak".PHP_EOL; + //copy($conf, $conf.$suffix.".bak"); + exec("cp -p $conf $conf$suffix.bak"); //use cli version to preserve file attributes + } + } + + self::CreateIniFiles(UpgradeCommon::CONF_BACKUP_SUFFIX); + self::MergeConfigFiles($configFiles, $suffix); + + //HACK: This will fix a last minute bug we discovered with our upgrade scripts. + //Will be fixed properly in 2.3.0 + $old = "list_all_db_files = 'list-all-files/format/json/api_key/%%api_key%%/dir_id/%%dir_id%%'"; + $new = "list_all_db_files = 'list-all-files/format/json/api_key/%%api_key%%/dir_id/%%dir_id%%/all/%%all%%'"; + exec("sed -i \"s#$old#$new#g\" /etc/airtime/api_client.cfg"); + + $old = "update_start_playing_url = 'notify-media-item-start-play/api_key/%%api_key%%/media_id/%%media_id%%/schedule_id/%%schedule_id%%'"; + $new = "update_start_playing_url = 'notify-media-item-start-play/api_key/%%api_key%%/media_id/%%media_id%%/'"; + exec("sed -i \"s#$old#$new#g\" /etc/airtime/api_client.cfg"); + } + + /** + * This function creates the /etc/airtime configuration folder + * and copies the default config files to it. + */ + public static function CreateIniFiles($suffix) + { + if (!file_exists("/etc/airtime/")){ + if (!mkdir("/etc/airtime/", 0755, true)){ + echo "Could not create /etc/airtime/ directory. Exiting."; + exit(1); + } + } + + $config_copy = array( + "../etc/airtime.conf" => self::CONF_FILE_AIRTIME, + "../etc/pypo.cfg" => self::CONF_FILE_PYPO, + "../etc/media-monitor.cfg" => self::CONF_FILE_MEDIAMONITOR, + "../etc/api_client.cfg" => self::CONF_FILE_API_CLIENT + ); + + echo "Copying configs:\n"; + foreach ($config_copy as $path_part => $destination) { + $full_path = OsPath::normpath(OsPath::join(__DIR__, + "$path_part.$suffix")); + echo "'$full_path' --> '$destination'\n"; + if(!copy($full_path, $destination)) { + echo "Failed on the copying operation above\n"; + exit(1); + } + } + } + + private static function MergeConfigFiles(array $configFiles, $suffix) { + foreach ($configFiles as $conf) { + if (file_exists("$conf$suffix.bak")) { + + if($conf === self::CONF_FILE_AIRTIME) { + // Parse with sections + $newSettings = parse_ini_file($conf, true); + $oldSettings = parse_ini_file("$conf$suffix.bak", true); + } + else { + $newSettings = self::ReadPythonConfig($conf); + $oldSettings = self::ReadPythonConfig("$conf$suffix.bak"); + } + + $settings = array_keys($newSettings); + + foreach($settings as $section) { + if(isset($oldSettings[$section])) { + if(is_array($oldSettings[$section])) { + $sectionKeys = array_keys($newSettings[$section]); + foreach($sectionKeys as $sectionKey) { + + if(isset($oldSettings[$section][$sectionKey])) { + self::UpdateIniValue($conf, $sectionKey, + $oldSettings[$section][$sectionKey]); + } + } + } else { + self::UpdateIniValue($conf, $section, + $oldSettings[$section]); + } + } + } + } + } + } + + private static function ReadPythonConfig($p_filename) + { + $values = array(); + + $fh = fopen($p_filename, 'r'); + + while(!feof($fh)){ + $line = fgets($fh); + if(substr(trim($line), 0, 1) == '#' || trim($line) == ""){ + continue; + }else{ + $info = explode('=', $line, 2); + $values[trim($info[0])] = trim($info[1]); + } + } + + return $values; + } + + /** + * This function updates an INI style config file. + * + * A property and the value the property should be changed to are + * supplied. If the property is not found, then no changes are made. + * + * @param string $p_filename + * The path the to the file. + * @param string $p_property + * The property to look for in order to change its value. + * @param string $p_value + * The value the property should be changed to. + * + */ + private static function UpdateIniValue($p_filename, $p_property, $p_value) + { + $lines = file($p_filename); + $n = count($lines); + foreach ($lines as &$line) { + if ($line[0] != "#"){ + $key_value = explode("=", $line); + $key = trim($key_value[0]); + + if ($key == $p_property){ + $line = "$p_property = $p_value".PHP_EOL; + } + } + } + + $fp=fopen($p_filename, 'w'); + for($i=0; $i<$n; $i++){ + fwrite($fp, $lines[$i]); + } + fclose($fp); + } + + public static function queryDb($p_sql){ + $con = Propel::getConnection(); + + try { + $result = $con->query($p_sql); + } catch (Exception $e) { + echo "Error executing $p_sql. Exiting."; + exit(1); + } + + return $result; + } +} + +class OsPath { + // this function is from http://stackoverflow.com/questions/2670299/is-there-a-php-equivalent-function-to-the-python-os-path-normpath + public static function normpath($path) + { + if (empty($path)) + return '.'; + + if (strpos($path, '/') === 0) + $initial_slashes = true; + else + $initial_slashes = false; + if ( + ($initial_slashes) && + (strpos($path, '//') === 0) && + (strpos($path, '///') === false) + ) + $initial_slashes = 2; + $initial_slashes = (int) $initial_slashes; + + $comps = explode('/', $path); + $new_comps = array(); + foreach ($comps as $comp) + { + if (in_array($comp, array('', '.'))) + continue; + if ( + ($comp != '..') || + (!$initial_slashes && !$new_comps) || + ($new_comps && (end($new_comps) == '..')) + ) + array_push($new_comps, $comp); + elseif ($new_comps) + array_pop($new_comps); + } + $comps = $new_comps; + $path = implode('/', $comps); + if ($initial_slashes) + $path = str_repeat('/', $initial_slashes) . $path; + if ($path) + return $path; + else + return '.'; + } + + /* Similar to the os.path.join python method + * http://stackoverflow.com/a/1782990/276949 */ + public static function join() { + $args = func_get_args(); + $paths = array(); + + foreach($args as $arg) { + $paths = array_merge($paths, (array)$arg); + } + + foreach($paths as &$path) { + $path = trim($path, DIRECTORY_SEPARATOR); + } + + if (substr($args[0], 0, 1) == DIRECTORY_SEPARATOR) { + $paths[0] = DIRECTORY_SEPARATOR . $paths[0]; + } + + return join(DIRECTORY_SEPARATOR, $paths); + } +} diff --git a/install_minimal/upgrades/airtime-2.3.1/data/upgrade.sql b/install_minimal/upgrades/airtime-2.3.1/data/upgrade.sql new file mode 100644 index 000000000..6b3bb0a42 --- /dev/null +++ b/install_minimal/upgrades/airtime-2.3.1/data/upgrade.sql @@ -0,0 +1,2 @@ +DELETE FROM cc_pref WHERE keystr = 'system_version'; +INSERT INTO cc_pref (keystr, valstr) VALUES ('system_version', '2.3.1'); diff --git a/python_apps/api_clients/api_client.py b/python_apps/api_clients/api_client.py index 991fd3f7c..a583b4772 100644 --- a/python_apps/api_clients/api_client.py +++ b/python_apps/api_clients/api_client.py @@ -15,7 +15,7 @@ import json import base64 from configobj import ConfigObj -AIRTIME_VERSION = "2.3.0" +AIRTIME_VERSION = "2.3.1" # TODO : Place these functions in some common module. Right now, media