forked from Chaospott/site
		
	
		
			
				
	
	
		
			727 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			727 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
require_once(dirname(__FILE__) . '/Post.php');
 | 
						|
require_once(dirname(__FILE__) . '/Hook.php');
 | 
						|
 | 
						|
class Updater
 | 
						|
{
 | 
						|
    public static $source_path;
 | 
						|
    public static $dest_path;
 | 
						|
    public static $cache_path;
 | 
						|
    public static $post_extension = '.md';
 | 
						|
    
 | 
						|
    // This option writes each draft preview into (web root)/drafts/whatever-slug
 | 
						|
    // Without it, drafts only reside in the (source)/drafts/_previews folder 
 | 
						|
    //  and are not accessible publicly.
 | 
						|
    public static $write_public_drafts = false;
 | 
						|
 | 
						|
    public static $frontpage_post_limit = 4;
 | 
						|
    public static $frontpage_template = 'front.php';
 | 
						|
    public static $frontpage_tag_filter = '!rss-only';
 | 
						|
    public static $frontpage_type_filter = false;
 | 
						|
    public static $frontpage_paginate = false;
 | 
						|
 | 
						|
    public static $logbuch_post_limit = 20;
 | 
						|
    public static $logbuch_template = 'main.php';
 | 
						|
    public static $logbuch_tag_filter = '!rss-only';
 | 
						|
    public static $logbuch_type_filter = false;
 | 
						|
    public static $logbuch_paginate = false;
 | 
						|
 | 
						|
    public static $rss_post_limit = 20;
 | 
						|
    public static $rss_template = 'rss.php';
 | 
						|
    public static $rss_tag_filter = '!site-only';
 | 
						|
    public static $rss_type_filter = false;
 | 
						|
 | 
						|
    public static $archive_month_template = 'main.php';
 | 
						|
    public static $archive_year_template = 'main.php';
 | 
						|
    public static $archive_tag_filter = '!rss-only';
 | 
						|
    public static $archive_type_filter = '!ad';
 | 
						|
    
 | 
						|
    public static $tag_page_post_limit = 20;
 | 
						|
    
 | 
						|
    public static $permalink_template = 'main.php';
 | 
						|
    public static $tag_page_template  = 'main.php';
 | 
						|
    public static $type_page_template = 'main.php';
 | 
						|
    public static $page_template      = 'main.php';
 | 
						|
    
 | 
						|
    public static $api_blog_id = 1;
 | 
						|
    public static $api_blog_username = '';
 | 
						|
    public static $api_blog_password = '';
 | 
						|
 | 
						|
    public static $changes_were_written = false;
 | 
						|
    
 | 
						|
    private static $index_to_be_updated = false;
 | 
						|
    private static $index_months_to_be_updated = array();
 | 
						|
    private static $tags_to_be_updated = array();
 | 
						|
    private static $types_to_be_updated = array();
 | 
						|
    private static $posts_to_be_updated = array();
 | 
						|
    private static $pages_to_be_updated = array();
 | 
						|
        
 | 
						|
    public static function posts_in_year_month($year, $month, $require_tag = false, $require_type = false)
 | 
						|
    {
 | 
						|
        $month = str_pad($month, 2, '0', STR_PAD_LEFT);
 | 
						|
        $cache_fname = self::$cache_path . "/posts-$year-$month-" . md5($require_tag . ' ' . $require_type);
 | 
						|
        if (file_exists($cache_fname)) {
 | 
						|
            $files = unserialize(file_get_contents($cache_fname));
 | 
						|
        } else {
 | 
						|
            $all_files = self::filelist(self::$source_path . "/posts/$year/$month", true);
 | 
						|
            ksort($all_files);
 | 
						|
            $in_month = false;
 | 
						|
            $files = array();
 | 
						|
            foreach ($all_files as $fname => $info) {
 | 
						|
                if (substr($fname, -(strlen(self::$post_extension))) != self::$post_extension) continue;
 | 
						|
 | 
						|
                // Tag/type filtering
 | 
						|
                list($ignored_hash, $type, $tags) = explode('|', $info, 3);
 | 
						|
                $include = true;
 | 
						|
                if ($require_type) {
 | 
						|
                    if ($require_type[0] == '!' && $type == $require_type) $include = false;
 | 
						|
                    else if ($require_type[0] != '!' && $type != $require_type) $include = false;
 | 
						|
                }
 | 
						|
                if ($require_tag) {
 | 
						|
                    if ($require_tag[0] == '!' && in_array($require_tag, Post::parse_tag_str($tags))) $include = false;
 | 
						|
                    else if ($require_tag[0] != '!' && ! in_array($require_tag, Post::parse_tag_str($tags))) $include = false;
 | 
						|
                }
 | 
						|
                if (! $include) continue;
 | 
						|
 | 
						|
                list($y, $m, $d) = array_map('intval', array_slice(explode('/', $fname), -3, 3));
 | 
						|
                $d = intval(substr($d, 6));
 | 
						|
                if ($year == $y && $month == $m) {
 | 
						|
                    if (isset($files[$d])) $files[$d][] = $fname;
 | 
						|
                    else $files[$d] = array($fname);
 | 
						|
                } else {
 | 
						|
                    if ($in_month) break;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            
 | 
						|
            if (! file_exists(self::$cache_path)) mkdir_as_parent_owner(self::$cache_path, 0755, true);
 | 
						|
            file_put_contents_as_dir_owner($cache_fname, serialize($files));
 | 
						|
        }
 | 
						|
        return $files;
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static function post_filenames_in_year_month($year, $month, $require_tag = false, $require_type = false)
 | 
						|
    {
 | 
						|
        $out = array();
 | 
						|
        foreach (self::posts_in_year_month($year, $month, $require_tag, $require_type) as $day) {
 | 
						|
            foreach ($day as $filename) $out[] = $filename;
 | 
						|
        }
 | 
						|
        return $out;
 | 
						|
    }
 | 
						|
    
 | 
						|
    private static function resequence_post_offsets($year, $month, $day)
 | 
						|
    {
 | 
						|
        $month = str_pad($month, 2, '0', STR_PAD_LEFT);
 | 
						|
        $day = str_pad($day, 2, '0', STR_PAD_LEFT);
 | 
						|
 | 
						|
        error_log("Resequencing post offsets for $year-$month-$day");
 | 
						|
 | 
						|
        $prefix = self::$source_path . "/posts/$year/$month/$year$month$day-";
 | 
						|
        $files = glob($prefix . '*' . self::$post_extension);
 | 
						|
        if (count($files) > 99) {
 | 
						|
            error_log("Cannot resequence offsets for $year-$month-$day: too many posts (" . count($files) . ')');
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        
 | 
						|
        $timestamps = array();
 | 
						|
        foreach ($files as $filename) {
 | 
						|
            $p = new Post($filename, false);
 | 
						|
            if (in_array($p->timestamp, $timestamps)) {
 | 
						|
                // Multiple posts with identical timestamp. No good way to handle this. Abort resequencing.
 | 
						|
                error_log("Cannot resequence offsets for $year-$month-$day: multiple identical timestamps");
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
            $timestamps[$filename] = $p->timestamp;
 | 
						|
        }
 | 
						|
        asort($timestamps);
 | 
						|
        
 | 
						|
        $offset = 0;
 | 
						|
        $slugs = array();
 | 
						|
        $out_files = array();
 | 
						|
        $made_changes = false;
 | 
						|
        foreach ($timestamps as $filename => $timestamp) {
 | 
						|
            $offset++;
 | 
						|
 | 
						|
            $slug = preg_replace('/-p[0-9]{1,2}$/ms', '', substr(basename($filename), 12, -(strlen(self::$post_extension))));
 | 
						|
            if (! isset($slugs[$slug])) $slugs[$slug] = 1;
 | 
						|
            else $slugs[$slug]++;
 | 
						|
 | 
						|
            $correct_filename = 
 | 
						|
                $prefix . 
 | 
						|
                str_pad($offset, 2, '0', STR_PAD_LEFT) . '-' . 
 | 
						|
                $slug . ($slugs[$slug] < 2 ? '' : '-p' .$slugs[$slug]) .
 | 
						|
                self::$post_extension
 | 
						|
            ;
 | 
						|
            if ($filename != $correct_filename) {
 | 
						|
                error_log("file [$filename] should be [$correct_filename]");
 | 
						|
                if (isset($out_files[$correct_filename])) throw new Exception("Target-filename collision for [$correct_filename], this should never happen");
 | 
						|
                $made_changes = true;
 | 
						|
                $out_files[$correct_filename] = array(file_get_contents($filename), $timestamp);
 | 
						|
                safe_unlink($filename);
 | 
						|
            }
 | 
						|
            
 | 
						|
            foreach ($out_files as $correct_filename => $a) {
 | 
						|
                list($contents, $timestamp) = $a;
 | 
						|
                file_put_contents_as_dir_owner($correct_filename, $contents);
 | 
						|
                @touch($correct_filename, $timestamp);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        
 | 
						|
        return $made_changes;
 | 
						|
    }
 | 
						|
    
 | 
						|
    private static function filelist($dir, $parse_info_in_text_files = true, $use_cached_info = array(), &$deleted_files = array())
 | 
						|
    {
 | 
						|
        $out = array();
 | 
						|
        if (is_dir($dir)) {
 | 
						|
            if ($dh = opendir($dir)) {
 | 
						|
                while ( ($file = readdir($dh) ) !== false) {
 | 
						|
                    if ($file[0] == '.') continue;
 | 
						|
                    $fullpath = $dir . '/' . $file;
 | 
						|
                    if (is_dir($fullpath)) {
 | 
						|
                        $out = array_merge($out, self::filelist($fullpath, $parse_info_in_text_files, $use_cached_info, $deleted_files));
 | 
						|
                    } else {
 | 
						|
                        if (isset($deleted_files[$fullpath])) unset($deleted_files[$fullpath]);
 | 
						|
                        
 | 
						|
                        $new_stat_prefix = filemtime($fullpath) . '-' . filesize($fullpath);
 | 
						|
                        
 | 
						|
                        if (isset($use_cached_info[$fullpath])) {
 | 
						|
                            $stat_prefix = substr($use_cached_info[$fullpath], 0, strpos($use_cached_info[$fullpath], '|'));
 | 
						|
                            if ($stat_prefix == $new_stat_prefix) continue;
 | 
						|
                        }
 | 
						|
                        
 | 
						|
                        $tags = '';
 | 
						|
                        $type = '';
 | 
						|
                        if ($parse_info_in_text_files && substr($fullpath, -(strlen(self::$post_extension))) == self::$post_extension) {
 | 
						|
                            $post = new Post($fullpath);
 | 
						|
                            $tags = implode(',', $post->tags);
 | 
						|
                            $type = $post->type;
 | 
						|
                            $expected_fname = $post->expected_source_filename();
 | 
						|
                            if ($expected_fname != $fullpath && ! $post->is_draft) {
 | 
						|
                                rename($fullpath, $expected_fname);
 | 
						|
                                $fullpath = $expected_fname;
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                        
 | 
						|
                        $out[$fullpath] = $new_stat_prefix . '|' . $type . '|' . $tags;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                closedir($dh);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return $out;
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static function changed_files_in_directory($directory)
 | 
						|
    {
 | 
						|
        $cache_fname = self::$cache_path . '/dir-' . md5($directory);
 | 
						|
        $changed = array();
 | 
						|
        if (file_exists($cache_fname)) {
 | 
						|
            $fileinfo = unserialize(file_get_contents($cache_fname));
 | 
						|
            $doesnt_exist_anymore = $fileinfo;
 | 
						|
            foreach (self::filelist($directory, true, $fileinfo, $doesnt_exist_anymore) as $filename => $new_info) {
 | 
						|
                if (! isset($fileinfo[$filename]) || $fileinfo[$filename] != $new_info) {
 | 
						|
                    $changed[$filename] = array(isset($fileinfo[$filename]) ? $fileinfo[$filename] : '||', $new_info);
 | 
						|
                    $fileinfo[$filename] = $new_info;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            
 | 
						|
            foreach ($doesnt_exist_anymore as $deleted_fname => $old_info) {
 | 
						|
                error_log("Deleted file: $deleted_fname");
 | 
						|
                $changed[$deleted_fname] = array($old_info, '||');
 | 
						|
                unset($fileinfo[$deleted_fname]);
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            $fileinfo = self::filelist($directory, true);
 | 
						|
            foreach ($fileinfo as $filename => $new_info) $changed[$filename] = array('||', $new_info);
 | 
						|
            if (! file_exists(self::$cache_path)) mkdir_as_parent_owner(self::$cache_path, 0755, true);
 | 
						|
        }
 | 
						|
        if ($changed) file_put_contents_as_dir_owner($cache_fname, serialize($fileinfo));
 | 
						|
        return $changed;
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static function most_recent_post_filenames($limit = 0, $require_tag = false, $require_type = false)
 | 
						|
    {
 | 
						|
        $cache_fname = self::$cache_path . '/dir-' . md5(self::$source_path . '/posts');
 | 
						|
        if (! file_exists($cache_fname)) throw new Exception('Cache files not found, expected in [' . self::$cache_path . ']');
 | 
						|
        $fileinfo = unserialize(file_get_contents($cache_fname));
 | 
						|
        krsort($fileinfo); // reverse-chrono
 | 
						|
 | 
						|
        $posts = array();
 | 
						|
        foreach ($fileinfo as $filename => $info) {
 | 
						|
            if (substr($filename, -(strlen(self::$post_extension))) != self::$post_extension) continue;
 | 
						|
            list($ignored_hash, $type, $tags) = explode('|', $info, 3);
 | 
						|
            $include = true;
 | 
						|
            if ($require_type) {
 | 
						|
                if ($require_type[0] == '!' && $type == substr($require_type, 1)) $include = false;
 | 
						|
                else if ($require_type[0] != '!' && $type != $require_type) $include = false;
 | 
						|
            }
 | 
						|
            
 | 
						|
            if ($require_tag) {
 | 
						|
                if ($require_tag[0] == '!' && in_array(substr($require_tag, 1), Post::parse_tag_str($tags))) $include = false;
 | 
						|
                else if ($require_tag[0] != '!' && ! in_array($require_tag, Post::parse_tag_str($tags))) $include = false;
 | 
						|
            }
 | 
						|
            
 | 
						|
            if (! $include) continue;
 | 
						|
            $posts[] = $filename;
 | 
						|
            if ($limit && count($posts) >= $limit) break;
 | 
						|
        }
 | 
						|
        return $posts;
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static function set_has_posts_for_month($year, $month, $scope = '')
 | 
						|
    {
 | 
						|
        $cache_fname = self::$cache_path . "/months-with-posts-$scope";
 | 
						|
        if (file_exists($cache_fname)) {
 | 
						|
            $existing = unserialize(file_get_contents($cache_fname));
 | 
						|
        } else {
 | 
						|
            $existing = array();
 | 
						|
        }
 | 
						|
        
 | 
						|
        $changed = false;
 | 
						|
        if (! isset($existing[$year])) {
 | 
						|
            $existing[$year] = array($month => true);
 | 
						|
            $changed = true;
 | 
						|
        } else if (! isset($existing[$year][$month])) {
 | 
						|
            $existing[$year][$month] = true;
 | 
						|
            $changed = true;
 | 
						|
        }
 | 
						|
 | 
						|
        if ($changed) {
 | 
						|
            if (! file_exists(self::$cache_path)) mkdir_as_parent_owner(self::$cache_path, 0755, true);
 | 
						|
            file_put_contents_as_dir_owner($cache_fname, serialize($existing));
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static function months_with_posts($scope = '')
 | 
						|
    {
 | 
						|
        $cache_fname = self::$cache_path . "/months-with-posts-$scope";
 | 
						|
        if (! file_exists($cache_fname)) throw new Exception('Cache files not found, expected ' . $cache_fname);
 | 
						|
        return unserialize(file_get_contents($cache_fname));
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static function archive_array($scope = '')
 | 
						|
    {
 | 
						|
        $out = array();
 | 
						|
        foreach (self::months_with_posts($scope) as $year => $months) {
 | 
						|
            foreach ($months as $month => $x) {
 | 
						|
                $ts = mktime(0, 0, 0, $month, 15, $year);
 | 
						|
                $out[$year . str_pad($month, 2, '0', STR_PAD_LEFT)] = array(
 | 
						|
                    'archives-uri' => "/$year/" . str_pad($month, 2, '0', STR_PAD_LEFT) . '/' . $scope,
 | 
						|
                    'archives-year' => $year,
 | 
						|
                    'archives-month-number' => intval($month),
 | 
						|
                    'archives-month-name' => date('F', $ts),
 | 
						|
                    'archives-month-short-name' => date('M', $ts),
 | 
						|
                );
 | 
						|
            }
 | 
						|
        }
 | 
						|
        arsort($out);
 | 
						|
        return $out;
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static function update_drafts()
 | 
						|
    {
 | 
						|
        foreach (self::changed_files_in_directory(self::$source_path . '/drafts') as $filename => $info) {
 | 
						|
            self::$changes_were_written = true;
 | 
						|
            
 | 
						|
            if (contains($filename, '/_publish-now/') && file_exists($filename)) {
 | 
						|
                $post = new Post($filename, false);
 | 
						|
                $expected_fname = $post->expected_source_filename(true);
 | 
						|
                error_log("Publishing draft $filename");
 | 
						|
                $dir = dirname($expected_fname);
 | 
						|
                if (! file_exists($dir)) mkdir_as_parent_owner($dir, 0755, true);
 | 
						|
                if (file_put_contents_as_dir_owner($expected_fname, $post->normalized_source())) safe_unlink($filename);
 | 
						|
                self::post_hooks($post);
 | 
						|
            }
 | 
						|
 | 
						|
            if (! file_exists($filename)) {
 | 
						|
                if (ends_with($filename, self::$post_extension)) {
 | 
						|
                    error_log("Deleted draft $filename");
 | 
						|
                    $slug = substring_before(basename($filename), '.', true);
 | 
						|
                    $html_preview_filename = self::$source_path . '/drafts/_previews/' . $slug . '.html';
 | 
						|
                    $webroot_preview_filename = self::$dest_path . '/drafts/' . $slug;
 | 
						|
                    if (file_exists($html_preview_filename)) safe_unlink($html_preview_filename);
 | 
						|
                    if (file_exists($webroot_preview_filename)) safe_unlink($webroot_preview_filename);
 | 
						|
                }
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
 | 
						|
            if (substr($filename, -(strlen(self::$post_extension))) == self::$post_extension) {
 | 
						|
                $post = new Post($filename, true);
 | 
						|
                if ($post->publish_now) {
 | 
						|
                    $post = new Post($filename, false);
 | 
						|
                    $expected_fname = $post->expected_source_filename(true);
 | 
						|
                    error_log("Publishing draft $filename");
 | 
						|
                    $dir = dirname($expected_fname);
 | 
						|
                    if (! file_exists($dir)) mkdir_as_parent_owner($dir, 0755, true);
 | 
						|
                    if (file_put_contents_as_dir_owner($expected_fname, $post->normalized_source())) safe_unlink($filename);
 | 
						|
                    self::post_hooks($post);
 | 
						|
                } else {
 | 
						|
                    $post->write_permalink_page(true);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }        
 | 
						|
    }
 | 
						|
 | 
						|
    public static function update_styles()
 | 
						|
    {
 | 
						|
        foreach (self::changed_files_in_directory(self::$source_path . '/templates') as $filename => $info) {
 | 
						|
            $file_info = pathinfo($filename);
 | 
						|
            if ($file_info['extension'] != 'css') continue;
 | 
						|
            
 | 
						|
            error_log("Changed style file: $filename");
 | 
						|
            $uri = substring_after($filename, self::$source_path . '/templates');
 | 
						|
            $dest_filename = self::$dest_path . $uri;
 | 
						|
            $output_path = dirname($dest_filename);
 | 
						|
            if (! file_exists($output_path)) mkdir_as_parent_owner($output_path, 0755, true);
 | 
						|
            copy($filename, $dest_filename);
 | 
						|
            self::$changes_were_written = true;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static function post_hooks($post)
 | 
						|
    {
 | 
						|
        $dir = self::$source_path . '/hooks';
 | 
						|
        if (is_dir($dir)) {
 | 
						|
            if ( ($dh = opendir($dir)) ) {
 | 
						|
                while ( ($file = readdir($dh) ) !== false) {
 | 
						|
                    if ($file[0] == '.') continue;
 | 
						|
                    if (substr($file, 0, 5) == 'post_') {
 | 
						|
                        $fullpath = $dir . '/' . $file;
 | 
						|
                        require_once($fullpath);
 | 
						|
                        $className = ucfirst(substr($file, 5, strlen($file) - 9));
 | 
						|
                        $hook = new $className;
 | 
						|
                        $hook->doHook($post);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                closedir($dh);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static function update_pages()
 | 
						|
    {
 | 
						|
        foreach (self::changed_files_in_directory(self::$source_path . '/pages') as $filename => $info) {
 | 
						|
            self::$changes_were_written = true;
 | 
						|
            
 | 
						|
            if (! file_exists($filename)) {
 | 
						|
                if (ends_with($filename, self::$post_extension)) {
 | 
						|
                    error_log("Deleted page $filename");
 | 
						|
                    $dest_filename = self::$dest_path . '/' . substring_before(basename($filename), '.', true);
 | 
						|
                    if (file_exists($dest_filename)) safe_unlink($dest_filename);
 | 
						|
                }
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
 | 
						|
            if (substr($filename, -(strlen(self::$post_extension))) == self::$post_extension) {
 | 
						|
                $post = new Post($filename, true);
 | 
						|
                $post->slug = basename($filename, self::$post_extension);
 | 
						|
                error_log("Writing page [{$post->slug}]");
 | 
						|
                $post->write_page(true);
 | 
						|
            }
 | 
						|
        }        
 | 
						|
    }
 | 
						|
    
 | 
						|
    const RESEQUENCED_POSTS = -1;
 | 
						|
    public static function update()
 | 
						|
    {
 | 
						|
        if (! file_exists(self::$cache_path)) {
 | 
						|
            // Starting fresh, probably multiple resequences to do.
 | 
						|
            // Let them all happen at once.
 | 
						|
            $status = self::_update(false);
 | 
						|
        }
 | 
						|
        
 | 
						|
        do {
 | 
						|
            $status = self::_update();
 | 
						|
        } while ($status == self::RESEQUENCED_POSTS);
 | 
						|
 | 
						|
        return $status;
 | 
						|
    }
 | 
						|
    
 | 
						|
    private static function _update($restart_if_resequenced = true)
 | 
						|
    {
 | 
						|
        if (! file_exists(self::$dest_path)) mkdir_as_parent_owner(self::$dest_path, 0755, true);
 | 
						|
        if (! file_exists(self::$dest_path . '/.htaccess')) copy(dirname(__FILE__) . '/default.htaccess', self::$dest_path . '/.htaccess');
 | 
						|
 | 
						|
        if (! file_exists(self::$source_path . '/drafts/_publish-now')) mkdir_as_parent_owner(self::$source_path . '/drafts/_publish-now', 0755, true);
 | 
						|
        if (! file_exists(self::$source_path . '/drafts/_previews')) mkdir_as_parent_owner(self::$source_path . '/drafts/_previews', 0755, true);
 | 
						|
        if (! file_exists(self::$source_path . '/pages')) mkdir_as_parent_owner(self::$source_path . '/pages', 0755, true);
 | 
						|
        
 | 
						|
        self::update_pages();
 | 
						|
        self::update_drafts();
 | 
						|
        self::update_styles();
 | 
						|
 | 
						|
        foreach (self::changed_files_in_directory(self::$source_path . '/media') as $filename => $info) {
 | 
						|
            error_log("Changed media file: $filename");
 | 
						|
            $uri = substring_after($filename, self::$source_path);
 | 
						|
            $dest_filename = self::$dest_path . $uri;
 | 
						|
            $output_path = dirname($dest_filename);
 | 
						|
            if (! file_exists($output_path)) mkdir_as_parent_owner($output_path, 0755, true);
 | 
						|
            copy($filename, $dest_filename);
 | 
						|
            self::$changes_were_written = true;
 | 
						|
        }
 | 
						|
 | 
						|
        $resequence_days = array();
 | 
						|
        
 | 
						|
        foreach (self::changed_files_in_directory(self::$source_path . '/posts') as $filename => $info) {
 | 
						|
            self::$posts_to_be_updated[$filename] = true;
 | 
						|
            
 | 
						|
            if (substr($filename, -(strlen(self::$post_extension))) == self::$post_extension) {
 | 
						|
                list($old_info, $new_info) = $info;
 | 
						|
                list($old_hash, $old_type, $old_tags) = explode('|', $old_info, 3);
 | 
						|
                list($new_hash, $new_type, $new_tags) = explode('|', $new_info, 3);
 | 
						|
 | 
						|
                if ($old_type) self::$types_to_be_updated[$old_type] = true;
 | 
						|
                if ($new_type) self::$types_to_be_updated[$new_type] = true;
 | 
						|
 | 
						|
                foreach (Post::parse_tag_str($old_tags) as $tag) self::$tags_to_be_updated[$tag] = true;
 | 
						|
                foreach (Post::parse_tag_str($new_tags) as $tag) self::$tags_to_be_updated[$tag] = true;
 | 
						|
            }
 | 
						|
            
 | 
						|
            $yearpos = strpos($filename, '/posts/') + 7;
 | 
						|
            $year = substr($filename, $yearpos, 4);
 | 
						|
            $month = substr($filename, $yearpos + 5, 2);
 | 
						|
            $day = substr($filename, $yearpos + 14, 2);
 | 
						|
            $resequence_days[$year . $month . $day] = array($year, $month, $day);
 | 
						|
            self::$index_months_to_be_updated[$year . '-' . $month] = true;
 | 
						|
            self::$index_to_be_updated = true;
 | 
						|
        }
 | 
						|
 | 
						|
        foreach (self::$posts_to_be_updated as $filename => $x) { 
 | 
						|
            if (! file_exists($filename)) {
 | 
						|
                // This file was deleted. Delete corresponding output file
 | 
						|
                $filename_datestr = substr(basename($filename), 0, 8);
 | 
						|
                if (is_numeric($filename_datestr)) {
 | 
						|
                    $year = substr($filename_datestr, 0, 4);
 | 
						|
                    $month = substr($filename_datestr, 4, 2);
 | 
						|
                    $day = substr($filename_datestr, 6, 2);
 | 
						|
                    $slug = substr(basename($filename), 12, -(strlen(self::$post_extension)));
 | 
						|
                    $target_filename = self::$dest_path . "/$year/$month/$day/$slug";
 | 
						|
                    if ($year && $month && $day && $slug && file_exists($target_filename)) {
 | 
						|
                        error_log("Deleting abandoned target file: $target_filename");
 | 
						|
                        safe_unlink($target_filename);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            
 | 
						|
            error_log("Updating post: $filename");
 | 
						|
            self::$changes_were_written = true;
 | 
						|
 | 
						|
            if (substr($filename, -(strlen(self::$post_extension))) == self::$post_extension) {
 | 
						|
                $post = new Post($filename);
 | 
						|
                $post->write_permalink_page();
 | 
						|
 | 
						|
                self::set_has_posts_for_month($post->year, $post->month);
 | 
						|
                foreach ($post->tags as $tag) self::set_has_posts_for_month($post->year, $post->month, 'tagged-' . $tag);
 | 
						|
                if ($post->type) self::set_has_posts_for_month($post->year, $post->month, 'type-' . $post->type);
 | 
						|
 | 
						|
            } else {
 | 
						|
                $filename_datestr = substr(basename($filename), 0, 8);
 | 
						|
                if (is_numeric($filename_datestr)) {
 | 
						|
                    $year = intval(substr($filename_datestr, 0, 4));
 | 
						|
                    $month = intval(substr($filename_datestr, 4, 2));
 | 
						|
                    $day = intval(substr($filename_datestr, 6, 2));
 | 
						|
                    if ($year && $month && $day) {
 | 
						|
                        $output_path = self::$dest_path . "/$year/" . str_pad($month, 2, '0', STR_PAD_LEFT) . '/' . str_pad($day, 2, '0', STR_PAD_LEFT);
 | 
						|
                        if (! file_exists($output_path)) mkdir_as_parent_owner($output_path, 0755, true);
 | 
						|
                        $output_filename = $output_path . '/' . basename($filename);
 | 
						|
                        copy($filename, $output_filename);
 | 
						|
                        $resequence_days[$year . $month . $day] = array($year, $month, $day);
 | 
						|
                    } else {
 | 
						|
                        error_log("Can't figure out where to put unrecognized numeric filename [$filename]");
 | 
						|
                    }
 | 
						|
                } else {
 | 
						|
                    error_log("Can't figure out where to put unrecognized filename [$filename]");
 | 
						|
                }
 | 
						|
                
 | 
						|
            }
 | 
						|
        }
 | 
						|
        
 | 
						|
        $sequence_changed = false;
 | 
						|
        foreach ($resequence_days as $a) {
 | 
						|
            list($year, $month, $day) = array_map('intval', $a);
 | 
						|
            if (self::resequence_post_offsets($year, $month, $day)) $sequence_changed = true;
 | 
						|
        }
 | 
						|
        
 | 
						|
        if ($sequence_changed && $restart_if_resequenced) {
 | 
						|
            self::$changes_were_written = true;
 | 
						|
            error_log("Resequencing was performed. Restarting update...");
 | 
						|
            return self::RESEQUENCED_POSTS;
 | 
						|
        }
 | 
						|
        
 | 
						|
        if (! self::$index_to_be_updated) self::$index_to_be_updated = self::$index_months_to_be_updated || self::$tags_to_be_updated || self::$types_to_be_updated || self::$posts_to_be_updated;
 | 
						|
 | 
						|
        if (self::$index_to_be_updated) {
 | 
						|
            error_log("Updating frontpage...");
 | 
						|
            self::$changes_were_written = true;
 | 
						|
 | 
						|
            $seq_count = 0;
 | 
						|
            if (self::$frontpage_paginate) {
 | 
						|
                $seq_count = Post::write_index_sequence(
 | 
						|
                    self::$dest_path . "/index", 
 | 
						|
                    Post::$blog_title, 
 | 
						|
                    'frontpage', 
 | 
						|
                    Post::from_files(self::most_recent_post_filenames(0, self::$frontpage_tag_filter, self::$frontpage_type_filter)),
 | 
						|
                    self::$frontpage_template,
 | 
						|
                    self::archive_array(),
 | 
						|
                    self::$frontpage_post_limit
 | 
						|
                );
 | 
						|
            }
 | 
						|
            
 | 
						|
            Post::write_index(
 | 
						|
                self::$dest_path . "/index.html", 
 | 
						|
                Post::$blog_title, 
 | 
						|
                'frontpage', 
 | 
						|
                Post::from_files(self::most_recent_post_filenames(self::$frontpage_post_limit, self::$frontpage_tag_filter, self::$frontpage_type_filter)),
 | 
						|
                self::$frontpage_template,
 | 
						|
                self::archive_array(),
 | 
						|
                $seq_count
 | 
						|
            );
 | 
						|
            
 | 
						|
            $seq_count = 0;
 | 
						|
            if (self::$logbuch_paginate) {
 | 
						|
                $seq_count = Post::write_index_sequence(
 | 
						|
                    self::$dest_path . "/logbuch", 
 | 
						|
                    Post::$blog_title, 
 | 
						|
                    'frontpage', 
 | 
						|
                    Post::from_files(self::most_recent_post_filenames(0, self::$logbuch_tag_filter, self::$flogbuch_type_filter)),
 | 
						|
                    self::$logbuch_template,
 | 
						|
                    self::archive_array(),
 | 
						|
                    self::$logbuch_post_limit
 | 
						|
                );
 | 
						|
            }
 | 
						|
            
 | 
						|
            Post::write_index(
 | 
						|
                self::$dest_path . "/logbuch.html", 
 | 
						|
                Post::$blog_title, 
 | 
						|
                'frontpage', 
 | 
						|
                Post::from_files(self::most_recent_post_filenames(self::$logbuch_post_limit, self::$logbuch_tag_filter, self::$logbuch_type_filter)),
 | 
						|
                self::$logbuch_template,
 | 
						|
                self::archive_array(),
 | 
						|
                $seq_count
 | 
						|
            );
 | 
						|
 | 
						|
            error_log("Updating RSS...");
 | 
						|
            Post::write_index(
 | 
						|
                self::$dest_path . "/rss.xml", 
 | 
						|
                Post::$blog_title, 
 | 
						|
                'rss', 
 | 
						|
                Post::from_files(self::most_recent_post_filenames(self::$rss_post_limit, self::$rss_tag_filter, self::$rss_type_filter)),
 | 
						|
                self::$rss_template
 | 
						|
            );
 | 
						|
        }
 | 
						|
 | 
						|
        foreach (self::$index_months_to_be_updated as $ym => $x) {
 | 
						|
            error_log("Updating month index: $ym");
 | 
						|
            self::$changes_were_written = true;
 | 
						|
 | 
						|
            list($year, $month) = explode('-', $ym);
 | 
						|
            $posts = Post::from_files(self::post_filenames_in_year_month($year, $month, self::$archive_tag_filter, self::$archive_type_filter));
 | 
						|
            $ts = mktime(0, 0, 0, $month, 15, $year);
 | 
						|
            Post::write_index(
 | 
						|
                self::$dest_path . "/$year/$month/index.html", 
 | 
						|
                date('F Y', $ts), 
 | 
						|
                'archive', 
 | 
						|
                $posts, 
 | 
						|
                self::$archive_month_template,
 | 
						|
                self::archive_array()
 | 
						|
            );
 | 
						|
        }
 | 
						|
        
 | 
						|
        foreach (self::$tags_to_be_updated as $tag => $x) {
 | 
						|
            if (! strlen($tag)) continue;
 | 
						|
            error_log("Updating tag: $tag");
 | 
						|
            self::$changes_were_written = true;
 | 
						|
 | 
						|
            $seq_count = Post::write_index_sequence(
 | 
						|
                self::$dest_path . "/tagged-$tag", 
 | 
						|
                Post::$blog_title, 
 | 
						|
                'tag', 
 | 
						|
                Post::from_files(self::most_recent_post_filenames(0, $tag, self::$archive_tag_filter)),
 | 
						|
                self::$tag_page_template,
 | 
						|
                self::archive_array(),
 | 
						|
                self::$tag_page_post_limit
 | 
						|
            );
 | 
						|
 | 
						|
            Post::write_index(
 | 
						|
                self::$dest_path . "/tagged-$tag.html", 
 | 
						|
                Post::$blog_title, 
 | 
						|
                'tag', 
 | 
						|
                Post::from_files(self::most_recent_post_filenames(self::$frontpage_post_limit, $tag, self::$archive_tag_filter)),
 | 
						|
                self::$tag_page_template,
 | 
						|
                self::archive_array('tagged-' . $tag),
 | 
						|
                $seq_count
 | 
						|
            );
 | 
						|
 | 
						|
            Post::write_index(
 | 
						|
                self::$dest_path . "/tagged-$tag.xml", 
 | 
						|
                Post::$blog_title, 
 | 
						|
                'tag', 
 | 
						|
                Post::from_files(self::most_recent_post_filenames(self::$rss_post_limit, $tag, self::$archive_tag_filter)),
 | 
						|
                self::$rss_template,
 | 
						|
                self::archive_array('tagged-' . $tag)
 | 
						|
            );
 | 
						|
 | 
						|
            $months_with_posts = self::months_with_posts('tagged-' . $tag);
 | 
						|
            foreach (self::$index_months_to_be_updated as $ym => $x) {
 | 
						|
                list($year, $month) = explode('-', $ym);
 | 
						|
                if (! isset($months_with_posts[$year]) || ! isset($months_with_posts[$year][intval($month)])) continue;
 | 
						|
                error_log("Updating month index: $ym for tag: $tag");
 | 
						|
                $posts = Post::from_files(self::post_filenames_in_year_month($year, $month, $tag, self::$archive_type_filter));
 | 
						|
                $ts = mktime(0, 0, 0, $month, 15, $year);
 | 
						|
                Post::write_index(
 | 
						|
                    self::$dest_path . "/$year/$month/tagged-$tag.html",
 | 
						|
                    date('F Y', $ts),
 | 
						|
                    'tag',
 | 
						|
                    $posts,
 | 
						|
                    self::$tag_page_template,
 | 
						|
                    self::archive_array('tagged-' . $tag)
 | 
						|
                );
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        foreach (self::$types_to_be_updated as $type => $x) {
 | 
						|
            if (! strlen($type)) continue;
 | 
						|
            error_log("Updating type: $type");
 | 
						|
            self::$changes_were_written = true;
 | 
						|
 | 
						|
            Post::write_index(
 | 
						|
                self::$dest_path . "/type-$type.html", 
 | 
						|
                Post::$blog_title, 
 | 
						|
                'type', 
 | 
						|
                Post::from_files(self::most_recent_post_filenames(self::$frontpage_post_limit, self::$archive_type_filter, $type)),
 | 
						|
                self::$type_page_template,
 | 
						|
                self::archive_array('type-' . $type)
 | 
						|
            );
 | 
						|
 | 
						|
            Post::write_index(
 | 
						|
                self::$dest_path . "/type-$type.xml", 
 | 
						|
                Post::$blog_title, 
 | 
						|
                'type', 
 | 
						|
                Post::from_files(self::most_recent_post_filenames(self::$rss_post_limit, self::$archive_type_filter, $type)),
 | 
						|
                self::$rss_template,
 | 
						|
                self::archive_array('type-' . $type)
 | 
						|
            );
 | 
						|
 | 
						|
            $months_with_posts = self::months_with_posts('type-' . $type);
 | 
						|
            foreach (self::$index_months_to_be_updated as $ym => $x) {
 | 
						|
                list($year, $month) = explode('-', $ym);
 | 
						|
                if (! isset($months_with_posts[$year]) || ! isset($months_with_posts[$year][intval($month)])) continue;
 | 
						|
                error_log("Updating month index: $ym for type: $type");
 | 
						|
                $posts = Post::from_files(self::post_filenames_in_year_month($year, $month, self::$archive_tag_filter, $type));
 | 
						|
                $ts = mktime(0, 0, 0, $month, 15, $year);
 | 
						|
                Post::write_index(
 | 
						|
                    self::$dest_path . "/$year/$month/type-$type.html",
 | 
						|
                    date('F Y', $ts),
 | 
						|
                    'type',
 | 
						|
                    $posts,
 | 
						|
                    self::$type_page_template,
 | 
						|
                    self::archive_array('type-' . $type)
 | 
						|
                );
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 |