From 2cac48713cfad224470b2d3bc5713c893830a288 Mon Sep 17 00:00:00 2001
From: Jan-Hendrik Willms <tleilax+github@gmail.com>
Date: Fri, 19 Mar 2021 16:28:20 +0100
Subject: [PATCH] more adjustments, cache current progress and allow stopping
 by pressing q, fixes #2

---
 .gitignore                          |  1 +
 composer.json                       |  2 +-
 convert.php                         |  5 ++
 src/Cache.php                       | 72 +++++++++++++++++++++++++++++
 steps/convert-tickets-to-issues.php | 51 ++++++++++++++------
 5 files changed, 115 insertions(+), 16 deletions(-)
 create mode 100644 src/Cache.php

diff --git a/.gitignore b/.gitignore
index 42c8849..ba24927 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@ includes/config.php
 includes/trac-users.txt
 
 trac-to-gitlab.phar
+cache/*
 vendor/*
 puli.phar
 puli.json
diff --git a/composer.json b/composer.json
index 5c7c683..198a3d3 100644
--- a/composer.json
+++ b/composer.json
@@ -12,7 +12,7 @@
         }
     ],
     "require": {
-    	"php": ">=5.6.0",
+    	"php": ">=7.0",
         "ext-mbstring": "*",
         "ext-json": "*",
         "m4tthumphrey/php-gitlab-api": "9.9.0",
diff --git a/convert.php b/convert.php
index e237099..a2dd842 100755
--- a/convert.php
+++ b/convert.php
@@ -3,6 +3,11 @@
 require_once __DIR__ . '/vendor/autoload.php';
 require_once __DIR__ . '/includes/functions.php';
 
+Trac2GitLab\Cache::setPath(__DIR__ . '/cache');
+if ($_SERVER['argc'] > 1 && $_SERVER['argv'][1] === '--clear-cache') {
+    Trac2GitLab\Cache::getInstance()->clear();
+}
+
 $config = require __DIR__ . '/includes/config.php';
 $config['trac-clean-url'] = preg_replace('/(?<=:\/\/).*?:.*?@|\/login/', '${1}', $config['trac-url']);
 
diff --git a/src/Cache.php b/src/Cache.php
new file mode 100644
index 0000000..3ddbe57
--- /dev/null
+++ b/src/Cache.php
@@ -0,0 +1,72 @@
+<?php
+namespace Trac2GitLab;
+
+final class Cache
+{
+    private static $instance = null;
+    private static $path = null;
+
+    public static function setPath($path)
+    {
+        if (file_exists($path) && !is_dir($path)) {
+            throw new \Exception("Path {$path} exists and is no folder");
+        } elseif (!file_exists($path)) {
+            mkdir($path);
+        }
+
+        if (!is_writable($path)) {
+            throw new \Exception("Path {$path} is not writable");
+        }
+        self::$path = rtrim($path, '/');
+    }
+
+    public static function getInstance()
+    {
+        if (!isset(self::$path)) {
+            throw new \Exception('No path has been defined, use Cache::setPath().');
+        }
+
+        if (self::$instance === null) {
+            self::$instance = new self(self::$path);
+        }
+        return self::$instance;
+    }
+
+    private $cache_path;
+    private $cache;
+
+    private function __construct($path)
+    {
+        $this->cache = [];
+        $this->cache_path = $path;
+    }
+
+    public function clear()
+    {
+        array_map('unlink', glob($this->cache_path . '/*'));
+        $this->cache = [];
+    }
+
+    public function get($key, $default = null)
+    {
+        $this->cache[$key] = $default;
+
+        $filename = $this->getCacheFilenameForKey($key);
+        if (file_exists($filename)) {
+            $this->cache[$key] = json_decode(file_get_contents($filename), true);
+        }
+
+        return $this->cache[$key];
+    }
+
+    public function set($key, $value)
+    {
+        $this->cache[$key] = $value;
+        file_put_contents($this->getCacheFilenameForKey($key), json_encode($value));
+    }
+
+    private function getCacheFilenameForKey($key)
+    {
+        return $this->cache_path . '/' . md5($key) . '.json';
+    }
+}
diff --git a/steps/convert-tickets-to-issues.php b/steps/convert-tickets-to-issues.php
index 47816d3..530c692 100644
--- a/steps/convert-tickets-to-issues.php
+++ b/steps/convert-tickets-to-issues.php
@@ -1,7 +1,13 @@
 <?php
 use Trac2GitLab\Migration;
 
-$issue_mapping = [];
+$cache = Trac2GitLab\Cache::getInstance();
+// Maps svn tickets to gitlab issues
+$issue_mapping = $cache->get('issue-mapping', []);
+// Trac Milestones that have already been created in Gitlab.
+$milestones = $cache->get('milestones', []);
+// Milestones that have already been migrated and closed.
+$closedMilestones = $cache->get('closed-milestones', []);
 
 // Actually migrate
 $migration = new Migration(
@@ -16,14 +22,12 @@ $trac = $migration->trac;
 
 $trac_client = $trac->getClient();
 $gitlab = $migration->gitLab;
-$gitlab_users = $gitlab->listUsers();
+$gitlab_users = []; // $gitlab->listUsers();
 
 $step_size = 50;
 $page = 1;
-// Trac Milestones that have already been created in Gitlab.
-$milestones = [];
-// Milestones that have already been migrated and closed.
-$closedMilestones = [];
+
+stream_set_blocking(STDIN, 0);
 
 do {
     $query = "{$config['trac-query']}&page={$page}&max={$step_size}";
@@ -35,6 +39,16 @@ do {
 
 
     foreach ($ticket_ids as $ticket_id) {
+        while ($c = fgetc(STDIN)) {
+            if ($c === 'q') {
+                echo "! Stopping process\n";
+                exit;
+            }
+        }
+        if (isset($issue_mapping[$ticket_id])) {
+            continue;
+        }
+
         try {
             $ticket = $trac_client->execute('ticket.get', [$ticket_id]);
 
@@ -66,6 +80,7 @@ do {
                         'id' => $g['id'],
                         'closed' => is_array($m['completed'])
                     ];
+                    $cache->set('milestones', $milestones);
                     echo "Created milestone " . $ticket[3]['milestone'] . ".\n";
                 }
             }
@@ -79,9 +94,10 @@ do {
                 $description, $dateCreated, $assigneeId, $creatorId, $labels,
                 $confidential, $milestone);
 
-            echo "Created a GitLab issue #{$issue['iid']} for Trac ticket #{$ticket_id} : {$config['trac-clean-url']}/tickets/{$ticket_id}\n";
+            echo "Created a GitLab issue #{$issue['iid']} for Trac ticket #{$ticket_id} : {$config['trac-clean-url']}/ticket/{$ticket_id}\n";
 
-            $mapping[$ticket_id] = $issue['iid'];
+            $issue_mapping[$ticket_id] = $issue['iid'];
+            $cache->set('issue-mapping', $issue_mapping);
 
             $attachments = $trac->getAttachments($ticket_id);
 
@@ -100,10 +116,11 @@ do {
 
                 file_put_contents($filename, base64_decode($a['content']));
 
-                $gitlab->createIssueAttachment($config['gitlab-project'], $issue['iid'], $filename, $a['author']);
+//                $gitlab->createIssueAttachment($config['gitlab-project'], $issue['iid'], $filename, $a['author']);
+                $gitlab->createIssueAttachment($config['gitlab-project'], $issue['iid'], $filename, null);
                 unlink($filename);
 
-                echo "\tAttached file " . $filename . " to issue " . $issue['iid'] . ".\n";
+                echo "\tAttached file {$filename} to issue {$issue['iid']}\n";
             }
 
             // Close issue if Trac ticket was closed.
@@ -111,7 +128,8 @@ do {
                 if (isset($ticket[4])) {
                     $gitlab->closeIssue(
                         $config['gitlab-project'], $issue['iid'],
-                        $ticket[4][0]['time']['__jsonclass__'][1], $ticket[4][0]['author']
+                        $ticket[4][0]['time']['__jsonclass__'][1]
+//                        $ticket[4][0]['time']['__jsonclass__'][1], $ticket[4][0]['author']
                     );
                 } else {
                     $gitlab->closeIssue($config['gitlab-project'], $issue['iid']);
@@ -124,6 +142,8 @@ do {
             ) {
                 $gitlab->closeMilestone($config['gitlab-project'], $milestones[$ticket[3]['milestone']]['id']);
                 $closedMilestones[] = $milestones[$ticket[3]['milestone']]['id'];
+                $cache->set('closed-milestones', $closedMilestones);
+
 
                 echo "\tClosed milestone " . $ticket[3]['milestone'] . ".\n";
             }
@@ -138,7 +158,8 @@ do {
 
 } while (count($ticket_ids) > 0);
 
-return $migration->migrateQuery(
-    $config['trac-query'],
-    $config['gitlab-project']
-);
+return $issue_mapping;
+//$migration->migrateQuery(
+//    $config['trac-query'],
+//    $config['gitlab-project']
+//);
-- 
GitLab