summaryrefslogtreecommitdiff
path: root/morphlib/plugins/list_system_contents_plugin.py
blob: 02565620f49ee7395e9dbb04ab839f5ac5e35e64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# Copyright (C) 2014 Codethink Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import cliapp
import contextlib
import fnmatch
import tarfile
import uuid

import morphlib

import pdb


class ListSystemContentsPlugin(cliapp.Plugin):
    '''Annotate the root file system for a given system.

    Command line arguments:

    * `SYSTEM` is the name of a system

    '''

    def enable(self):
        self.app.add_subcommand(
            'list-system-contents', self.list_system_contents,
            arg_synopsis='SYSTEM')

    def disable(self):
        pass

    def commit_uncommitted_changes(self, system_branch):
        # from morphlib/plugins/build_plugin.py
        build_uuid = uuid.uuid4().hex

        build_ref_prefix = self.app.settings['build-ref-prefix'] or 'build/'

        self.app.status(msg="Creating temporary build branch")

        build_branch = morphlib.buildbranch.BuildBranch(
                system_branch, build_ref_prefix, push_temporary=False)
        with contextlib.closing(build_branch) as build_branch:
            # These functions return impure generators to do their work
            # rather than actually doing what their names suggest.
            list(build_branch.add_uncommitted_changes())

            loader = morphlib.morphloader.MorphologyLoader()
            list(build_branch.inject_build_refs(loader))

            name = morphlib.git.get_user_name(self.app.runcmd)
            email = morphlib.git.get_user_email(self.app.runcmd)
            list(build_branch.update_build_refs(name, email, build_uuid))

        return build_branch

    def list_system_contents(self, args):
        if len(args) != 1:
            raise morphlib.Error("Usage: morph-search-file SYSTEM")

        system_filename = morphlib.util.sanitise_morphology_path(args[0])

        workspace = morphlib.workspace.open('.')
        system_branch = morphlib.sysbranchdir.open_from_within('.')

        build_branch = self.commit_uncommitted_changes(system_branch)

        build_command = morphlib.buildcommand.BuildCommand(self.app)

        source_pool = build_command.create_source_pool(
                build_branch.root_repo_url,
                build_branch.root_ref,
                system_filename)
        root_artifact = build_command.resolve_artifacts(source_pool)

        build_command.build_in_order(root_artifact)

        files = dict()
        for artifact in root_artifact.walk():
            if artifact.source.morphology['kind'] != 'chunk':
                continue
            try:
                artifact_file = build_command.lac.get(artifact)
                contents = morphlib.builder2.get_chunk_files(artifact_file)
                for path in contents:
                    abs_path = '/%s' % path
                    if abs_path in files:
                        print 'WARNING: file %s is in more than one chunk!' % abs_path
                    files[abs_path] = artifact
                files.update('/%s' % p for p in contents)
            except tarfile.ReadError:
                print "Read error for %s" % artifact.name

        def get_stratum_for_chunk(chunk):
            for artifact in chunk.dependents:
                # Currently it's safe to assume that only the containing
                # stratum will be in the chunk artifact's list of dependents.
                if artifact.source.morphology['kind'] == 'stratum':
                    return artifact
            raise ValueError(
                'Chunk %s has no stratum in its dependent list!' % chunk)

        for path in sorted(files.iterkeys()):
            chunk = files[path]
            stratum = get_stratum_for_chunk(chunk)
            chunk_in_system = (stratum in root_artifact.dependencies)
            present_flag = ' ' if chunk_in_system else 'X'
            print '%s  %20s: %s' % (present_flag, chunk.name, path)