{"action":"created","comment":{"url":"https://api.github.com/repos/rhinstaller/anaconda/pulls/comments/91783106","pull_request_review_id":12295640,"id":91783106,"diff_hunk":"@@ -0,0 +1,400 @@\n+# installation_tasks.py\n+# Container classes for running of installation tasks.\n+#\n+# Copyright (C) 2016  Red Hat, Inc.\n+#\n+# This copyrighted material is made available to anyone wishing to use,\n+# modify, copy, or redistribute it subject to the terms and conditions of\n+# the GNU General Public License v.2, or (at your option) any later version.\n+# This program is distributed in the hope that it will be useful, but WITHOUT\n+# ANY WARRANTY expressed or implied, including the implied warranties of\n+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General\n+# Public License for more details.  You should have received a copy of the\n+# GNU General Public License along with this program; if not, write to the\n+# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\n+# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the\n+# source code or documentation are not subject to the GNU General Public\n+# License and may only be used or replicated with the express permission of\n+# Red Hat, Inc.\n+#\n+from threading import RLock\n+from pyanaconda.isignal import Signal\n+import time\n+import logging\n+log = logging.getLogger(\"anaconda\")\n+\n+\n+class TaskQueue(list):\n+    \"\"\"TaskQueue represents a queue of TaskQueues or Tasks.\n+\n+    TaskQueues and Tasks can be mixed in a single TaskQueue.\n+    \"\"\"\n+\n+    def __init__(self, name, status_message=None):\n+        super(TaskQueue, self).__init__()\n+        self._name = name\n+        self._status_message = status_message\n+        self._lock = RLock()\n+        self._current_task_number = None\n+        self._current_queue_number = None\n+        self._running = False\n+        self._done = False\n+        self._parent = None\n+        # triggered when this TaskQueue is started/completed\n+        self.started = Signal()\n+        self.completed = Signal()\n+        # triggered if a TaskQueue contained in this one was started/completed\n+        self.queue_started = Signal()\n+        self.queue_completed = Signal()\n+        # triggered when a task is started\n+        self.task_started = Signal()\n+        self.task_completed = Signal()\n+\n+        # connect to the task & queue started signals for\n+        # progress reporting purposes\n+        self.queue_started.connect(self._queue_started_cb)\n+        self.task_started.connect(self._task_started_cb)\n+\n+    def _queue_started_cb(self, *args):\n+        with self._lock:\n+            self._current_queue_number += 1\n+\n+    def _task_started_cb(self, *args):\n+        with self._lock:\n+            self._current_task_number += 1\n+\n+    def __hash__(self):\n+        \"\"\"List are normally not hashable but our list subclass is.\n+\n+        Unlike with a plain list we care more about a queue instance than about it's content.\n+        \"\"\"\n+        return id(self)\n+\n+    @property\n+    def name(self):\n+        \"\"\"Task queue name.\n+\n+        :returns: task queue name\n+        :rtype: str\n+        \"\"\"\n+        return self._name\n+\n+    @property\n+    def status_message(self):\n+        return self._status_message\n+\n+    @property\n+    def running(self):\n+        \"\"\"Reports if the task queue processing is currently running.\n+\n+        :returns: if the task queue is currently running\n+        :rtype: bool\n+        \"\"\"\n+        with self._lock:\n+            return self._running\n+\n+    @property\n+    def done(self):\n+        \"\"\"Reports if the task queue has finished processing.\n+\n+        :reports: if the task queue is done\n+        :rtype: bool\n+        \"\"\"\n+        with self._lock:\n+            return self._done\n+\n+    @property\n+    def queue_count(self):\n+        \"\"\"Returns number of TaskQueues contained in this and all nested TaskQueues.\n+\n+        :returns: number of queues\n+        :rtype: int\n+        \"\"\"\n+        with self._lock:\n+            queue_count = 0\n+            for item in self:\n+                # count only queues\n+                if isinstance(item, TaskQueue):\n+                    # count the queue itself\n+                    queue_count += 1\n+                    # and its contents\n+                    queue_count += item.queue_count\n+            return queue_count\n+\n+    @property\n+    def task_count(self):\n+        \"\"\"Returns number of tasks contained in this and all nested TaskQueues.\n+\n+        :returns: number of tasks\n+        :rtype: int\n+        \"\"\"\n+        with self._lock:\n+            task_count = 0\n+            for item in self:\n+                if isinstance(item, Task):\n+                    # count tasks\n+                    task_count += 1\n+                elif isinstance(item, TaskQueue):\n+                    # count tasks in nested queues\n+                    task_count += item.task_count\n+            return task_count\n+\n+    @property\n+    def current_task_number(self):\n+        with self._lock:\n+            return self._current_task_number\n+\n+    @property\n+    def current_queue_number(self):\n+        with self._lock:\n+            return self._current_queue_number\n+\n+    @property\n+    def progress(self):\n+        \"\"\"Task queue processing progress.\n+\n+        The progress is reported as a floating point number from 0.0 to 1.0.\n+        :returns: task queue processing progress\n+        :rtype: float\n+        \"\"\"\n+        with self._lock:\n+            if self.current_task_number:\n+                return self.task_count / self.current_task_number\n+            else:\n+                return 0.0\n+\n+    @property\n+    def summary(self):\n+        \"\"\"Return a multi-line summary of the contents of the task queue.\n+\n+        :returns: summary of task queue contents\n+        :rtype: str\n+        \"\"\"\n+        if self.parent is None:\n+            message = \"Top-level task queue: %s\\n\" % self.name\n+            # this is the top-level queue, so add some \"global\" stats\n+            message += \"Number of task queues: %d\\n\" % self.queue_count\n+            message += \"Number of tasks: %d\\n\" % self.task_count\n+            message += \"Task & task group listing:\\n\"\n+        else:\n+            message = \"Task queue: %s\\n\" % self.name\n+        for item in self:\n+            for line in item.summary.splitlines():\n+                message += \" %s\\n\" % line\n+        # remove trailing newlines from the top level message\n+        if self.parent is None and message[-1] == \"\\n\":\n+            message = message[0: -1]","path":"pyanaconda/install_tasks.py","position":196,"original_position":186,"commit_id":"b144bdb1e7a5a9434c0042d1f3da4bb414889d18","original_commit_id":"f0d88f1afc37a8dc73d8d0c1c846b8c61b201310","user":{"login":"M4rtinK","id":829558,"avatar_url":"https://avatars.githubusercontent.com/u/829558?v=3","gravatar_id":"","url":"https://api.github.com/users/M4rtinK","html_url":"https://github.com/M4rtinK","followers_url":"https://api.github.com/users/M4rtinK/followers","following_url":"https://api.github.com/users/M4rtinK/following{/other_user}","gists_url":"https://api.github.com/users/M4rtinK/gists{/gist_id}","starred_url":"https://api.github.com/users/M4rtinK/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/M4rtinK/subscriptions","organizations_url":"https://api.github.com/users/M4rtinK/orgs","repos_url":"https://api.github.com/users/M4rtinK/repos","events_url":"https://api.github.com/users/M4rtinK/events{/privacy}","received_events_url":"https://api.github.com/users/M4rtinK/received_events","type":"User","site_admin":false},"body":"Good point. :)","created_at":"2016-12-09T19:50:41Z","updated_at":"2016-12-09T19:50:41Z","html_url":"https://github.com/rhinstaller/anaconda/pull/898#discussion_r91783106","pull_request_url":"https://api.github.com/repos/rhinstaller/anaconda/pulls/898","_links":{"self":{"href":"https://api.github.com/repos/rhinstaller/anaconda/pulls/comments/91783106"},"html":{"href":"https://github.com/rhinstaller/anaconda/pull/898#discussion_r91783106"},"pull_request":{"href":"https://api.github.com/repos/rhinstaller/anaconda/pulls/898"}}},"pull_request":{"url":"https://api.github.com/repos/rhinstaller/anaconda/pulls/898","id":96719508,"html_url":"https://github.com/rhinstaller/anaconda/pull/898","diff_url":"https://github.com/rhinstaller/anaconda/pull/898.diff","patch_url":"https://github.com/rhinstaller/anaconda/pull/898.patch","issue_url":"https://api.github.com/repos/rhinstaller/anaconda/issues/898","number":898,"state":"open","locked":false,"title":"Structured installation tasks","user":{"login":"M4rtinK","id":829558,"avatar_url":"https://avatars.githubusercontent.com/u/829558?v=3","gravatar_id":"","url":"https://api.github.com/users/M4rtinK","html_url":"https://github.com/M4rtinK","followers_url":"https://api.github.com/users/M4rtinK/followers","following_url":"https://api.github.com/users/M4rtinK/following{/other_user}","gists_url":"https://api.github.com/users/M4rtinK/gists{/gist_id}","starred_url":"https://api.github.com/users/M4rtinK/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/M4rtinK/subscriptions","organizations_url":"https://api.github.com/users/M4rtinK/orgs","repos_url":"https://api.github.com/users/M4rtinK/repos","events_url":"https://api.github.com/users/M4rtinK/events{/privacy}","received_events_url":"https://api.github.com/users/M4rtinK/received_events","type":"User","site_admin":false},"body":"The first two commits add structured installation task classes and the Signal class they use.\r\nThe third commit the installation phase to use the structured installation task classes.","created_at":"2016-12-06T13:00:30Z","updated_at":"2016-12-09T19:50:41Z","closed_at":null,"merged_at":null,"merge_commit_sha":"8cdda801fb6f9604729cb05b367acc652a9ab3e0","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/rhinstaller/anaconda/pulls/898/commits","review_comments_url":"https://api.github.com/repos/rhinstaller/anaconda/pulls/898/comments","review_comment_url":"https://api.github.com/repos/rhinstaller/anaconda/pulls/comments{/number}","comments_url":"https://api.github.com/repos/rhinstaller/anaconda/issues/898/comments","statuses_url":"https://api.github.com/repos/rhinstaller/anaconda/statuses/b144bdb1e7a5a9434c0042d1f3da4bb414889d18","head":{"label":"M4rtinK:master-structured_installation_tasks","ref":"master-structured_installation_tasks","sha":"b144bdb1e7a5a9434c0042d1f3da4bb414889d18","user":{"login":"M4rtinK","id":829558,"avatar_url":"https://avatars.githubusercontent.com/u/829558?v=3","gravatar_id":"","url":"https://api.github.com/users/M4rtinK","html_url":"https://github.com/M4rtinK","followers_url":"https://api.github.com/users/M4rtinK/followers","following_url":"https://api.github.com/users/M4rtinK/following{/other_user}","gists_url":"https://api.github.com/users/M4rtinK/gists{/gist_id}","starred_url":"https://api.github.com/users/M4rtinK/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/M4rtinK/subscriptions","organizations_url":"https://api.github.com/users/M4rtinK/orgs","repos_url":"https://api.github.com/users/M4rtinK/repos","events_url":"https://api.github.com/users/M4rtinK/events{/privacy}","received_events_url":"https://api.github.com/users/M4rtinK/received_events","type":"User","site_admin":false},"repo":{"id":30928257,"name":"anaconda","full_name":"M4rtinK/anaconda","owner":{"login":"M4rtinK","id":829558,"avatar_url":"https://avatars.githubusercontent.com/u/829558?v=3","gravatar_id":"","url":"https://api.github.com/users/M4rtinK","html_url":"https://github.com/M4rtinK","followers_url":"https://api.github.com/users/M4rtinK/followers","following_url":"https://api.github.com/users/M4rtinK/following{/other_user}","gists_url":"https://api.github.com/users/M4rtinK/gists{/gist_id}","starred_url":"https://api.github.com/users/M4rtinK/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/M4rtinK/subscriptions","organizations_url":"https://api.github.com/users/M4rtinK/orgs","repos_url":"https://api.github.com/users/M4rtinK/repos","events_url":"https://api.github.com/users/M4rtinK/events{/privacy}","received_events_url":"https://api.github.com/users/M4rtinK/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/M4rtinK/anaconda","description":"Graphical system installer","fork":true,"url":"https://api.github.com/repos/M4rtinK/anaconda","forks_url":"https://api.github.com/repos/M4rtinK/anaconda/forks","keys_url":"https://api.github.com/repos/M4rtinK/anaconda/keys{/key_id}","collaborators_url":"https://api.github.com/repos/M4rtinK/anaconda/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/M4rtinK/anaconda/teams","hooks_url":"https://api.github.com/repos/M4rtinK/anaconda/hooks","issue_events_url":"https://api.github.com/repos/M4rtinK/anaconda/issues/events{/number}","events_url":"https://api.github.com/repos/M4rtinK/anaconda/events","assignees_url":"https://api.github.com/repos/M4rtinK/anaconda/assignees{/user}","branches_url":"https://api.github.com/repos/M4rtinK/anaconda/branches{/branch}","tags_url":"https://api.github.com/repos/M4rtinK/anaconda/tags","blobs_url":"https://api.github.com/repos/M4rtinK/anaconda/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/M4rtinK/anaconda/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/M4rtinK/anaconda/git/refs{/sha}","trees_url":"https://api.github.com/repos/M4rtinK/anaconda/git/trees{/sha}","statuses_url":"https://api.github.com/repos/M4rtinK/anaconda/statuses/{sha}","languages_url":"https://api.github.com/repos/M4rtinK/anaconda/languages","stargazers_url":"https://api.github.com/repos/M4rtinK/anaconda/stargazers","contributors_url":"https://api.github.com/repos/M4rtinK/anaconda/contributors","subscribers_url":"https://api.github.com/repos/M4rtinK/anaconda/subscribers","subscription_url":"https://api.github.com/repos/M4rtinK/anaconda/subscription","commits_url":"https://api.github.com/repos/M4rtinK/anaconda/commits{/sha}","git_commits_url":"https://api.github.com/repos/M4rtinK/anaconda/git/commits{/sha}","comments_url":"https://api.github.com/repos/M4rtinK/anaconda/comments{/number}","issue_comment_url":"https://api.github.com/repos/M4rtinK/anaconda/issues/comments{/number}","contents_url":"https://api.github.com/repos/M4rtinK/anaconda/contents/{+path}","compare_url":"https://api.github.com/repos/M4rtinK/anaconda/compare/{base}...{head}","merges_url":"https://api.github.com/repos/M4rtinK/anaconda/merges","archive_url":"https://api.github.com/repos/M4rtinK/anaconda/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/M4rtinK/anaconda/downloads","issues_url":"https://api.github.com/repos/M4rtinK/anaconda/issues{/number}","pulls_url":"https://api.github.com/repos/M4rtinK/anaconda/pulls{/number}","milestones_url":"https://api.github.com/repos/M4rtinK/anaconda/milestones{/number}","notifications_url":"https://api.github.com/repos/M4rtinK/anaconda/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/M4rtinK/anaconda/labels{/name}","releases_url":"https://api.github.com/repos/M4rtinK/anaconda/releases{/id}","deployments_url":"https://api.github.com/repos/M4rtinK/anaconda/deployments","created_at":"2015-02-17T17:27:17Z","updated_at":"2015-02-17T17:27:20Z","pushed_at":"2016-12-09T19:48:28Z","git_url":"git://github.com/M4rtinK/anaconda.git","ssh_url":"git@github.com:M4rtinK/anaconda.git","clone_url":"https://github.com/M4rtinK/anaconda.git","svn_url":"https://github.com/M4rtinK/anaconda","homepage":null,"size":134885,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"rhinstaller:master","ref":"master","sha":"2a1224cce9b9f3e87cea41b004348683d7806acb","user":{"login":"rhinstaller","id":10549274,"avatar_url":"https://avatars.githubusercontent.com/u/10549274?v=3","gravatar_id":"","url":"https://api.github.com/users/rhinstaller","html_url":"https://github.com/rhinstaller","followers_url":"https://api.github.com/users/rhinstaller/followers","following_url":"https://api.github.com/users/rhinstaller/following{/other_user}","gists_url":"https://api.github.com/users/rhinstaller/gists{/gist_id}","starred_url":"https://api.github.com/users/rhinstaller/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rhinstaller/subscriptions","organizations_url":"https://api.github.com/users/rhinstaller/orgs","repos_url":"https://api.github.com/users/rhinstaller/repos","events_url":"https://api.github.com/users/rhinstaller/events{/privacy}","received_events_url":"https://api.github.com/users/rhinstaller/received_events","type":"Organization","site_admin":false},"repo":{"id":30210846,"name":"anaconda","full_name":"rhinstaller/anaconda","owner":{"login":"rhinstaller","id":10549274,"avatar_url":"https://avatars.githubusercontent.com/u/10549274?v=3","gravatar_id":"","url":"https://api.github.com/users/rhinstaller","html_url":"https://github.com/rhinstaller","followers_url":"https://api.github.com/users/rhinstaller/followers","following_url":"https://api.github.com/users/rhinstaller/following{/other_user}","gists_url":"https://api.github.com/users/rhinstaller/gists{/gist_id}","starred_url":"https://api.github.com/users/rhinstaller/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rhinstaller/subscriptions","organizations_url":"https://api.github.com/users/rhinstaller/orgs","repos_url":"https://api.github.com/users/rhinstaller/repos","events_url":"https://api.github.com/users/rhinstaller/events{/privacy}","received_events_url":"https://api.github.com/users/rhinstaller/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/rhinstaller/anaconda","description":"Graphical system installer","fork":false,"url":"https://api.github.com/repos/rhinstaller/anaconda","forks_url":"https://api.github.com/repos/rhinstaller/anaconda/forks","keys_url":"https://api.github.com/repos/rhinstaller/anaconda/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rhinstaller/anaconda/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rhinstaller/anaconda/teams","hooks_url":"https://api.github.com/repos/rhinstaller/anaconda/hooks","issue_events_url":"https://api.github.com/repos/rhinstaller/anaconda/issues/events{/number}","events_url":"https://api.github.com/repos/rhinstaller/anaconda/events","assignees_url":"https://api.github.com/repos/rhinstaller/anaconda/assignees{/user}","branches_url":"https://api.github.com/repos/rhinstaller/anaconda/branches{/branch}","tags_url":"https://api.github.com/repos/rhinstaller/anaconda/tags","blobs_url":"https://api.github.com/repos/rhinstaller/anaconda/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rhinstaller/anaconda/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rhinstaller/anaconda/git/refs{/sha}","trees_url":"https://api.github.com/repos/rhinstaller/anaconda/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rhinstaller/anaconda/statuses/{sha}","languages_url":"https://api.github.com/repos/rhinstaller/anaconda/languages","stargazers_url":"https://api.github.com/repos/rhinstaller/anaconda/stargazers","contributors_url":"https://api.github.com/repos/rhinstaller/anaconda/contributors","subscribers_url":"https://api.github.com/repos/rhinstaller/anaconda/subscribers","subscription_url":"https://api.github.com/repos/rhinstaller/anaconda/subscription","commits_url":"https://api.github.com/repos/rhinstaller/anaconda/commits{/sha}","git_commits_url":"https://api.github.com/repos/rhinstaller/anaconda/git/commits{/sha}","comments_url":"https://api.github.com/repos/rhinstaller/anaconda/comments{/number}","issue_comment_url":"https://api.github.com/repos/rhinstaller/anaconda/issues/comments{/number}","contents_url":"https://api.github.com/repos/rhinstaller/anaconda/contents/{+path}","compare_url":"https://api.github.com/repos/rhinstaller/anaconda/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rhinstaller/anaconda/merges","archive_url":"https://api.github.com/repos/rhinstaller/anaconda/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rhinstaller/anaconda/downloads","issues_url":"https://api.github.com/repos/rhinstaller/anaconda/issues{/number}","pulls_url":"https://api.github.com/repos/rhinstaller/anaconda/pulls{/number}","milestones_url":"https://api.github.com/repos/rhinstaller/anaconda/milestones{/number}","notifications_url":"https://api.github.com/repos/rhinstaller/anaconda/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rhinstaller/anaconda/labels{/name}","releases_url":"https://api.github.com/repos/rhinstaller/anaconda/releases{/id}","deployments_url":"https://api.github.com/repos/rhinstaller/anaconda/deployments","created_at":"2015-02-02T21:56:45Z","updated_at":"2016-12-04T23:24:53Z","pushed_at":"2016-12-09T19:48:29Z","git_url":"git://github.com/rhinstaller/anaconda.git","ssh_url":"git@github.com:rhinstaller/anaconda.git","clone_url":"https://github.com/rhinstaller/anaconda.git","svn_url":"https://github.com/rhinstaller/anaconda","homepage":null,"size":178799,"stargazers_count":69,"watchers_count":69,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":86,"mirror_url":null,"open_issues_count":31,"forks":86,"open_issues":31,"watchers":69,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/rhinstaller/anaconda/pulls/898"},"html":{"href":"https://github.com/rhinstaller/anaconda/pull/898"},"issue":{"href":"https://api.github.com/repos/rhinstaller/anaconda/issues/898"},"comments":{"href":"https://api.github.com/repos/rhinstaller/anaconda/issues/898/comments"},"review_comments":{"href":"https://api.github.com/repos/rhinstaller/anaconda/pulls/898/comments"},"review_comment":{"href":"https://api.github.com/repos/rhinstaller/anaconda/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/rhinstaller/anaconda/pulls/898/commits"},"statuses":{"href":"https://api.github.com/repos/rhinstaller/anaconda/statuses/b144bdb1e7a5a9434c0042d1f3da4bb414889d18"}}}}
{"actor":{"display_login":"M4rtinK"}}