Ejemplo n.º 1
0
    def test_dirty_stage_reprimes(self):
        self.make_snapcraft_yaml(
            textwrap.dedent("""\
                parts:
                  part1:
                    plugin: nil
                """))

        # Strip it.
        lifecycle.execute('prime', self.project_options)

        # Reset logging since we only care about the following
        self.fake_logger = fixtures.FakeLogger(level=logging.INFO)
        self.useFixture(self.fake_logger)

        def _fake_dirty_report(self, step):
            if step == 'stage':
                return pluginhandler.DirtyReport({'foo'}, {'bar'})
            return None

        # Should automatically clean and re-stage if that step is dirty
        # for the part.
        with mock.patch.object(pluginhandler.PluginHandler, 'get_dirty_report',
                               _fake_dirty_report):
            lifecycle.execute('prime', self.project_options)

        self.assertThat(
            self.fake_logger.output, Equals(
                'Skipping pull part1 (already ran)\n'
                'Skipping build part1 (already ran)\n'
                'Cleaning priming area for part1 (out of date)\n'
                'Cleaning staging area for part1 (out of date)\n'
                'Staging part1 \n'
                'Priming part1 \n'))
Ejemplo n.º 2
0
    def test_core_setup_skipped_if_not_classic(self):
        self.useFixture(fixtures.EnvironmentVariable("SNAPCRAFT_SETUP_CORE", "1"))

        project_config = self.make_snapcraft_project(confinement="strict")
        lifecycle.execute(steps.PULL, project_config)

        self.assertThat(self.witness_path, Not(FileExists()))
Ejemplo n.º 3
0
    def test_dirty_pull_raises(self):
        self.make_snapcraft_yaml("""parts:
  part1:
    plugin: nil
""")

        # Pull it.
        lifecycle.execute('pull', self.project_options)

        # Reset logging since we only care about the following
        self.fake_logger = fixtures.FakeLogger(level=logging.INFO)
        self.useFixture(self.fake_logger)

        def _fake_dirty_report(self, step):
            if step == 'pull':
                return pluginhandler.DirtyReport(set(), {'foo', 'bar'})
            return None

        # Should catch that the part needs to be re-pulled and raise an error.
        with mock.patch.object(pluginhandler.PluginHandler, 'get_dirty_report',
                               _fake_dirty_report):
            raised = self.assertRaises(
                RuntimeError,
                lifecycle.execute,
                'pull', self.project_options)

        self.assertEqual('', self.fake_logger.output)

        self.assertEqual(
            "The 'pull' step of 'part1' is out of date:\n\n"
            "The 'bar' and 'foo' project options appear to have changed.\n\n"
            "In order to continue, please clean that part's 'pull' step "
            "by running: snapcraft clean part1 -s pull\n",
            str(raised))
Ejemplo n.º 4
0
    def test_prime_with_build_info_records_manifest(self):
        self.useFixture(fixtures.EnvironmentVariable(
            'SNAPCRAFT_BUILD_INFO', '1'))
        self.make_snapcraft_yaml(
            textwrap.dedent("""\
                parts:
                  test-part:
                    plugin: nil
                """))
        lifecycle.execute('prime', self.project_options)

        expected = textwrap.dedent("""\
            name: test
            version: 0
            summary: test
            description: test
            confinement: strict
            grade: stable
            parts:
              test-part:
                build-packages: []
                installed-packages: []
                installed-snaps: []
                plugin: nil
                prime: []
                stage: []
                stage-packages: []
                uname: Linux test uname 4.10 x86_64
            architectures: [{}]
            build-packages: []
            build-snaps: []
            """.format(self.project_options.deb_arch))
        self.assertThat(
            os.path.join('prime', 'snap', 'manifest.yaml'),
            FileContains(expected))
Ejemplo n.º 5
0
def run(args, project_options):
    lifecycle_command = _get_lifecycle_command(args)
    argless_command = _get_command_from_arg(args)
    if lifecycle_command:
        lifecycle.execute(
            lifecycle_command, project_options, args['<part>'])
    elif argless_command:
        argless_command()
    elif args['clean']:
        step = args['--step']
        if step == 'strip':
            logger.warning('DEPRECATED: Use `prime` instead of `strip` '
                           'as the step to clean')
            step = 'prime'
        lifecycle.clean(project_options, args['<part>'], step)
    elif args['upload']:
        snapcraft.upload(args['<snap-file>'])
    elif args['cleanbuild']:
        lifecycle.cleanbuild(project_options),
    # disable until the tour command is activated
    # elif args['tour']:
    #    _scaffold_examples(args['<directory>'] or _SNAPCRAFT_TOUR_DIR)
    elif args['help']:
        snapcraft.topic_help(args['<topic>'] or args['<plugin>'],
                             args['--devel'], args['topics'])
    else:  # snap by default:
        lifecycle.snap(project_options, args['<directory>'], args['--output'])

    return project_options
Ejemplo n.º 6
0
    def test_prime_with_build_info_records_snapcraft_yaml(self):
        self.useFixture(fixtures.EnvironmentVariable(
            'SNAPCRAFT_BUILD_INFO', '1'))
        self.make_snapcraft_yaml(
            textwrap.dedent("""\
                parts:
                  test-part:
                    plugin: nil
                """),
            snap_type='type: app')
        lifecycle.execute('prime', self.project_options)

        expected = textwrap.dedent("""\
            name: test
            version: 0
            summary: test
            description: test
            confinement: strict
            grade: stable
            type: app

            parts:
              test-part:
                plugin: nil

            """)

        self.assertThat(
            os.path.join('prime', 'snap', 'snapcraft.yaml'),
            FileContains(expected))
Ejemplo n.º 7
0
    def test_core_setup_if_docker_env(self, dockerenv_fake, download_mock):
        dockerenv_file = os.path.join(self.tempdir, "dockerenv")
        os.makedirs(self.tempdir)
        open(dockerenv_file, "w").close()
        dockerenv_fake.return_value = dockerenv_file

        project_config = self.make_snapcraft_project(confinement="classic")
        core_snap = self.create_core_snap(project_config.project.deb_arch)
        core_snap_hash = calculate_sha3_384(core_snap)
        download_mock.return_value = core_snap_hash
        self.tempdir_mock.side_effect = self._setup_tempdir_side_effect(core_snap)

        lifecycle.execute(steps.PULL, project_config)

        regex = (".*mkdir -p {}\nunsquashfs -d {} .*{}\n").format(
            os.path.dirname(self.core_path), self.core_path, core_snap_hash
        )
        self.assertThat(
            self.witness_path,
            FileContains(matcher=MatchesRegex(regex, flags=re.DOTALL)),
        )

        download_mock.assert_called_once_with(
            "core",
            "stable",
            os.path.join(self.tempdir, "core.snap"),
            project_config.project.deb_arch,
            "",
        )
Ejemplo n.º 8
0
    def test_no_exception_when_dependency_is_required_but_already_staged(self):
        self.make_snapcraft_yaml("""parts:
  part1:
    plugin: nil
  part2:
    plugin: nil
    after:
      - part1
""")

        def _fake_should_step_run(self, step, force=False):
            return self.name != 'part1'

        with mock.patch.object(pluginhandler.PluginHandler,
                               'should_step_run',
                               _fake_should_step_run):
            lifecycle.execute('pull', self.project_options,
                              part_names=['part2'])

        self.assertEqual(
            'Skipping pull part1 (already ran)\n'
            'Skipping build part1 (already ran)\n'
            'Skipping stage part1 (already ran)\n'
            'Skipping prime part1 (already ran)\n'
            'Preparing to pull part2 \n'
            'Pulling part2 \n',
            self.fake_logger.output)
Ejemplo n.º 9
0
def run(args, project_options):  # noqa
    lifecycle_command = _get_lifecycle_command(args)
    argless_command = _get_command_from_arg(args)
    if lifecycle_command:
        lifecycle.execute(
            lifecycle_command, project_options, args['<part>'])
    elif argless_command:
        argless_command()
    elif args['clean']:
        _run_clean(args, project_options)
    elif args['cleanbuild']:
        lifecycle.cleanbuild(project_options),
    elif _is_store_command(args):
        _run_store_command(args)
    elif args['tour']:
        _scaffold_examples(args['<directory>'] or _SNAPCRAFT_TOUR_DIR)
    elif args['help']:
        snapcraft.topic_help(args['<topic>'] or args['<plugin>'],
                             args['--devel'], args['topics'])
    elif args['update']:
        parts.update()
    elif args['define']:
        parts.define(args['<part-name>'])
    elif args['search']:
        parts.search(' '.join(args['<query>']))
    else:  # snap by default:
        lifecycle.snap(project_options, args['<directory>'], args['--output'])

    return project_options
Ejemplo n.º 10
0
    def test_pull_is_dirty_if_target_arch_changes(
            self, mock_install_build_packages, mock_enable_cross_compilation):
        self.make_snapcraft_yaml("""parts:
  part1:
    plugin: nil
""")

        # Pull it with amd64
        lifecycle.execute('pull', snapcraft.ProjectOptions(
            target_deb_arch='amd64'))

        # Reset logging since we only care about the following
        self.fake_logger = fixtures.FakeLogger(level=logging.INFO)
        self.useFixture(self.fake_logger)

        # Pull it again with armhf. Should catch that the part needs to be
        # re-pulled due to the change in target architecture and raise an
        # error.
        raised = self.assertRaises(
            RuntimeError,
            lifecycle.execute,
            'pull', snapcraft.ProjectOptions(
                target_deb_arch='armhf'))

        self.assertEqual("Setting target machine to 'armhf'\n",
                         self.fake_logger.output)

        self.assertEqual(
            "The 'pull' step of 'part1' is out of date:\n\n"
            "The 'deb_arch' project option appears to have changed.\n\n"
            "In order to continue, please clean that part's 'pull' step "
            "by running: snapcraft clean part1 -s pull\n",
            str(raised))
Ejemplo n.º 11
0
    def test_dirty_stage_restrips(self):
        self.make_snapcraft_yaml("""parts:
  part1:
    plugin: nil
""")

        # Strip it.
        lifecycle.execute('strip', self.project_options)

        # Reset logging since we only care about the following
        self.fake_logger = fixtures.FakeLogger(level=logging.INFO)
        self.useFixture(self.fake_logger)

        def _fake_is_dirty(self, step):
            return step == 'stage'

        # Should automatically clean and re-stage if that step is dirty
        # for the part.
        with mock.patch.object(pluginhandler.PluginHandler, 'is_dirty',
                               _fake_is_dirty):
            lifecycle.execute('strip', self.project_options)

        self.assertEqual(
            'Skipping pull part1 (already ran)\n'
            'Skipping build part1 (already ran)\n'
            'Cleaning snapping area for part1 (out of date)\n'
            'Cleaning staging area for part1 (out of date)\n'
            'Staging part1 \n'
            'Stripping part1 \n',
            self.fake_logger.output)
Ejemplo n.º 12
0
    def test_dirty_stage_part_with_unbuilt_dependent(self):
        self.make_snapcraft_yaml("""parts:
  part1:
    plugin: nil
  part2:
    plugin: nil
    after: [part1]
""")

        # Stage dependency (dependent is unbuilt)
        lifecycle.execute('stage', self.project_options, part_names=['part1'])

        # Reset logging since we only care about the following
        self.fake_logger = fixtures.FakeLogger(level=logging.INFO)
        self.useFixture(self.fake_logger)

        def _fake_is_dirty(self, step):
            return step == 'stage'

        # Should automatically clean and re-stage if that step is dirty
        # for the part.
        with mock.patch.object(pluginhandler.PluginHandler, 'is_dirty',
                               _fake_is_dirty):
            lifecycle.execute('stage', self.project_options,
                              part_names=['part1'])

        self.assertEqual(
            'Skipping pull part1 (already ran)\n'
            'Skipping build part1 (already ran)\n'
            'Skipping cleaning priming area for part1 (out of date) '
            '(already clean)\n'
            'Cleaning staging area for part1 (out of date)\n'
            'Staging part1 \n',
            self.fake_logger.output)
Ejemplo n.º 13
0
    def test_dirty_build_raises(self):
        self.make_snapcraft_yaml("""parts:
  part1:
    plugin: nil
""")

        # Build it.
        lifecycle.execute('build', self.project_options)

        # Reset logging since we only care about the following
        self.fake_logger = fixtures.FakeLogger(level=logging.INFO)
        self.useFixture(self.fake_logger)

        def _fake_dirty_report(self, step):
            if step == 'build':
                return pluginhandler.DirtyReport({'foo', 'bar'}, set())
            return None

        # Should catch that the part needs to be rebuilt and raise an error.
        with mock.patch.object(pluginhandler.PluginHandler, 'get_dirty_report',
                               _fake_dirty_report):
            raised = self.assertRaises(
                RuntimeError,
                lifecycle.execute,
                'build', self.project_options)

        self.assertEqual(
            'Skipping pull part1 (already ran)\n',
            self.fake_logger.output)

        self.assertEqual(
            "The 'build' step of 'part1' is out of date:\n\n"
            "The 'bar' and 'foo' part properties appear to have changed.\n\n"
            "Please clean that part's 'build' step in order to continue",
            str(raised))
Ejemplo n.º 14
0
    def test_dirty_pull_raises(self):
        self.make_snapcraft_yaml("""parts:
  part1:
    plugin: nil
""")

        # Pull it.
        lifecycle.execute('pull', self.project_options)

        # Reset logging since we only care about the following
        self.fake_logger = fixtures.FakeLogger(level=logging.INFO)
        self.useFixture(self.fake_logger)

        def _fake_is_dirty(self, step):
            return step == 'pull'

        # Should catch that the part needs to be re-pulled and raise an error.
        with mock.patch.object(pluginhandler.PluginHandler, 'is_dirty',
                               _fake_is_dirty):
            with self.assertRaises(RuntimeError) as raised:
                lifecycle.execute('pull', self.project_options)

        self.assertEqual('', self.fake_logger.output)

        self.assertEqual(
            "The 'pull' step of 'part1' is out of date. Please clean that "
            "part's 'pull' step in order to rebuild", str(raised.exception))
Ejemplo n.º 15
0
    def test_core_setup_with_env_var(self, download_mock):
        self.useFixture(fixtures.EnvironmentVariable("SNAPCRAFT_SETUP_CORE", "1"))

        project_config = self.make_snapcraft_project(confinement="classic")
        core_snap = self.create_core_snap(project_config.project.deb_arch)
        core_snap_hash = calculate_sha3_384(core_snap)
        download_mock.return_value = core_snap_hash
        self.tempdir_mock.side_effect = self._setup_tempdir_side_effect(core_snap)

        lifecycle.execute(steps.PULL, project_config)

        regex = (".*mkdir -p {}\nunsquashfs -d {} .*{}\n").format(
            os.path.dirname(self.core_path), self.core_path, core_snap_hash
        )
        self.assertThat(
            self.witness_path,
            FileContains(matcher=MatchesRegex(regex, flags=re.DOTALL)),
        )

        download_mock.assert_called_once_with(
            "core",
            "stable",
            os.path.join(self.tempdir, "core.snap"),
            project_config.project.deb_arch,
            "",
        )
Ejemplo n.º 16
0
    def test_prime_with_build_info_records_snapcraft_yaml(self):
        self.useFixture(fixtures.EnvironmentVariable("SNAPCRAFT_BUILD_INFO", "1"))
        project_config = self.make_snapcraft_project(
            textwrap.dedent(
                """\
                parts:
                  test-part:
                    plugin: nil
                """
            ),
            snap_type="type: app",
        )
        lifecycle.execute(steps.PRIME, project_config)

        expected = textwrap.dedent(
            """\
            name: test
            version: 0
            summary: test
            description: test
            confinement: strict
            grade: stable
            type: app

            parts:
              test-part:
                plugin: nil

            """
        )

        self.assertThat(
            os.path.join(steps.PRIME.name, "snap", "snapcraft.yaml"),
            FileContains(expected),
        )
Ejemplo n.º 17
0
    def test_dependency_is_staged_when_required(self):
        project_config = self.make_snapcraft_project(
            textwrap.dedent(
                """\
                parts:
                  part1:
                    plugin: nil
                  part2:
                    plugin: nil
                    after:
                      - part1
                """
            )
        )

        lifecycle.execute(steps.PULL, project_config, part_names=["part2"])

        self.assertThat(
            self.fake_logger.output,
            Equals(
                "'part2' has dependencies that need to be staged: part1\n"
                "Pulling part1 \n"
                "Building part1 \n"
                "Staging part1 \n"
                "Pulling part2 \n"
            ),
        )
Ejemplo n.º 18
0
    def test_prime_with_image_info_records_manifest(self):
        self.useFixture(fixtures.EnvironmentVariable("SNAPCRAFT_BUILD_INFO", "1"))
        test_image_info = (
            '{"architecture": "test-architecture", '
            '"created_at": "test-created-at", '
            '"fingerprint": "test-fingerprint"}'
        )
        self.useFixture(
            fixtures.EnvironmentVariable("SNAPCRAFT_IMAGE_INFO", test_image_info)
        )
        project_config = self.make_snapcraft_project(
            textwrap.dedent(
                """\
                parts:
                  test-part:
                    plugin: nil
                """
            )
        )
        lifecycle.execute(steps.PRIME, project_config)

        expected = textwrap.dedent(
            """\
            snapcraft-version: '3.0'
            snapcraft-os-release-id: ubuntu
            snapcraft-os-release-version-id: '16.04'
            name: test
            version: 0
            summary: test
            description: test
            confinement: strict
            grade: stable
            parts:
              test-part:
                build-packages: []
                installed-packages:
                - patchelf=0.9
                installed-snaps: []
                plugin: nil
                prime: []
                stage: []
                stage-packages: []
                uname: Linux test uname 4.10 x86_64
            architectures:
            - {}
            image-info:
              architecture: test-architecture
              created_at: test-created-at
              fingerprint: test-fingerprint
            build-packages: []
            build-snaps: []
            """.format(
                project_config.project.deb_arch
            )
        )
        self.assertThat(
            os.path.join(steps.PRIME.name, "snap", "manifest.yaml"),
            FileContains(expected),
        )
Ejemplo n.º 19
0
    def test_prime_with_virtual_build_package(self, _):
        self.useFixture(fixtures.EnvironmentVariable("SNAPCRAFT_BUILD_INFO", "1"))
        self.fake_apt_cache.add_package(
            fixture_setup.FakeAptCachePackage(
                "test-provider-package",
                "test-version",
                provides=["test-virtual-package"],
            )
        )

        project_config = self.make_snapcraft_project(
            textwrap.dedent(
                """\
                parts:
                  test-part:
                    plugin: nil
                    build-packages: ['test-virtual-package']
                """
            )
        )

        lifecycle.execute(steps.PRIME, project_config)

        expected = textwrap.dedent(
            """\
            snapcraft-version: '3.0'
            snapcraft-os-release-id: ubuntu
            snapcraft-os-release-version-id: '16.04'
            name: test
            version: 0
            summary: test
            description: test
            confinement: strict
            grade: stable
            parts:
              test-part:
                build-packages:
                - test-virtual-package
                installed-packages:
                - patchelf=0.9
                installed-snaps: []
                plugin: nil
                prime: []
                stage: []
                stage-packages: []
                uname: Linux test uname 4.10 x86_64
            architectures:
            - {}
            build-packages:
            - test-provider-package=test-version
            build-snaps: []
            """.format(
                project_config.project.deb_arch
            )
        )
        self.assertThat(
            os.path.join(steps.PRIME.name, "snap", "manifest.yaml"),
            FileContains(expected),
        )
Ejemplo n.º 20
0
    def test_core_setup_skipped_if_core_exists(self):
        os.makedirs(self.core_path)
        open(os.path.join(self.core_path, 'fake-content'), 'w').close()

        self._create_classic_confined_snapcraft_yaml()
        lifecycle.execute('pull', self.project_options)

        self.assertThat(self.witness_path, Not(FileExists()))
Ejemplo n.º 21
0
def _execute(command, parts, **kwargs):
    project_options = get_project_options(**kwargs)
    container_config = env.get_container_config()
    if container_config.use_container:
        lifecycle.containerbuild(command, project_options,
                                 container_config, parts)
    else:
        lifecycle.execute(command, project_options, parts)
    return project_options
Ejemplo n.º 22
0
 def test_prime_excludes_internal_snapcraft_dir(self):
     self.make_snapcraft_yaml(
         textwrap.dedent("""\
             parts:
               test-part:
                 plugin: nil
             """))
     lifecycle.execute('prime', self.project_options)
     self.assertThat(
         os.path.join('prime', 'snap', '.snapcraft'),
         Not(DirExists()))
Ejemplo n.º 23
0
    def test_prime_with_installed_snaps(self):
        self.useFixture(fixtures.EnvironmentVariable("SNAPCRAFT_BUILD_INFO", "1"))
        self.fake_snapd.snaps_result = [
            {"name": "test-snap-1", "revision": "test-snap-1-revision"},
            {"name": "test-snap-2", "revision": "test-snap-2-revision"},
        ]

        project_config = self.make_snapcraft_project(
            textwrap.dedent(
                """\
                parts:
                  test-part:
                    plugin: nil
                """
            )
        )
        lifecycle.execute(steps.PRIME, project_config)

        expected = textwrap.dedent(
            """\
            snapcraft-version: '3.0'
            snapcraft-os-release-id: ubuntu
            snapcraft-os-release-version-id: '16.04'
            name: test
            version: 0
            summary: test
            description: test
            confinement: strict
            grade: stable
            parts:
              test-part:
                build-packages: []
                installed-packages:
                - patchelf=0.9
                installed-snaps:
                - test-snap-1=test-snap-1-revision
                - test-snap-2=test-snap-2-revision
                plugin: nil
                prime: []
                stage: []
                stage-packages: []
                uname: Linux test uname 4.10 x86_64
            architectures:
            - {}
            build-packages: []
            build-snaps: []
            """.format(
                project_config.project.deb_arch
            )
        )
        self.assertThat(
            os.path.join(steps.PRIME.name, "snap", "manifest.yaml"),
            FileContains(expected),
        )
Ejemplo n.º 24
0
 def test_clean_removes_global_state(self):
     self.make_snapcraft_yaml(
         textwrap.dedent("""\
             parts:
               test-part:
                 plugin: nil
             """))
     lifecycle.execute('pull', self.project_options)
     lifecycle.clean(self.project_options, parts=None)
     self.assertThat(
         os.path.join('snap', '.snapcraft'),
         Not(DirExists()))
Ejemplo n.º 25
0
    def test_dirty_stage_restages_multiple_parts(self):
        self.make_snapcraft_yaml(
            textwrap.dedent("""\
                parts:
                  part1:
                    plugin: nil
                  part2:
                    plugin: nil
                """))

        # Stage it.
        lifecycle.execute('stage', self.project_options)

        # Reset logging since we only care about the following
        self.fake_logger = fixtures.FakeLogger(level=logging.INFO)
        self.useFixture(self.fake_logger)

        def _fake_dirty_report(self, step):
            if step == 'stage':
                return pluginhandler.DirtyReport({'foo'}, {'bar'})
            return None

        # Should automatically clean and re-stage if that step is dirty
        # for the part.
        with mock.patch.object(pluginhandler.PluginHandler, 'get_dirty_report',
                               _fake_dirty_report):
            lifecycle.execute('stage', self.project_options)

        output = self.fake_logger.output.split('\n')
        part1_output = [line.strip() for line in output if 'part1' in line]
        part2_output = [line.strip() for line in output if 'part2' in line]

        self.assertThat(
            part2_output,
            Equals([
                'Skipping pull part2 (already ran)',
                'Skipping build part2 (already ran)',
                'Skipping cleaning priming area for part2 (out of date) '
                '(already clean)',
                'Cleaning staging area for part2 (out of date)',
                'Staging part2',
            ]))

        self.assertThat(
            part1_output,
            Equals([
                'Skipping pull part1 (already ran)',
                'Skipping build part1 (already ran)',
                'Skipping cleaning priming area for part1 (out of date) '
                '(already clean)',
                'Cleaning staging area for part1 (out of date)',
                'Staging part1',
            ]))
Ejemplo n.º 26
0
 def test_clean_removes_global_state(self):
     project_config = self.make_snapcraft_project(
         textwrap.dedent(
             """\
             parts:
               test-part:
                 plugin: nil
             """
         )
     )
     lifecycle.execute(steps.PULL, project_config)
     lifecycle.clean(project_config.project, parts=None)
     self.assertThat(os.path.join("snap", ".snapcraft"), Not(DirExists()))
Ejemplo n.º 27
0
    def test_dirty_stage_part_with_built_dependent_raises(self):
        self.make_snapcraft_yaml(
            textwrap.dedent("""\
                parts:
                  part1:
                    plugin: nil
                  part2:
                    plugin: nil
                    after: [part1]
                """))

        # Stage dependency
        lifecycle.execute('stage', self.project_options, part_names=['part1'])
        # Build dependent
        lifecycle.execute('build', self.project_options, part_names=['part2'])

        # Reset logging since we only care about the following
        self.fake_logger = fixtures.FakeLogger(level=logging.INFO)
        self.useFixture(self.fake_logger)

        def _fake_dirty_report(self, step):
            if step == 'stage':
                return pluginhandler.DirtyReport({'foo'}, {'bar'})
            return None

        # Should raise a RuntimeError about the fact that stage is dirty but
        # it has dependents that need it.
        with mock.patch.object(pluginhandler.PluginHandler, 'get_dirty_report',
                               _fake_dirty_report):
            raised = self.assertRaises(
                errors.StepOutdatedError,
                lifecycle.execute,
                'stage', self.project_options,
                part_names=['part1'])

        output = self.fake_logger.output.split('\n')
        part1_output = [line.strip() for line in output if 'part1' in line]
        self.assertThat(
            part1_output,
            Equals([
                'Skipping pull part1 (already ran)',
                'Skipping build part1 (already ran)',
            ]))

        self.assertThat(
            str(raised), Equals(
                "The 'stage' step of 'part1' is out of date:\n"
                "The 'stage' step for 'part1' needs to be run again, but "
                "'part2' depends on it.\n"
                "In order to continue, please clean that part's 'stage' step "
                "by running:\nsnapcraft clean part2 -s stage\n"))
Ejemplo n.º 28
0
 def test_prime_excludes_internal_snapcraft_dir(self):
     project_config = self.make_snapcraft_project(
         textwrap.dedent(
             """\
             parts:
               test-part:
                 plugin: nil
             """
         )
     )
     lifecycle.execute(steps.PRIME, project_config)
     self.assertThat(
         os.path.join(steps.PRIME.name, "snap", ".snapcraft"), Not(DirExists())
     )
Ejemplo n.º 29
0
    def test_build_is_dirty_if_scriptlet_changes(
        self, mock_install_build_packages, mock_enable_cross_compilation
    ):
        mock_install_build_packages.return_value = []
        project_config = self.make_snapcraft_project(
            textwrap.dedent(
                """\
                parts:
                  part1:
                    plugin: nil
                    {}: touch scriptlet
                """
            ).format(self.scriptlet)
        )

        # Build it
        lifecycle.execute(steps.BUILD, project_config)

        # Reset logging since we only care about the following
        self.fake_logger = fixtures.FakeLogger(level=logging.INFO)
        self.useFixture(self.fake_logger)

        # Change prepare scriptlet
        project_config = self.make_snapcraft_project(
            textwrap.dedent(
                """\
                parts:
                  part1:
                    plugin: nil
                    {}: touch changed
                """
            ).format(self.scriptlet)
        )

        # Build it again. Should catch that the scriptlet changed and it needs
        # to be rebuilt.
        raised = self.assertRaises(
            errors.StepOutdatedError, lifecycle.execute, steps.BUILD, project_config
        )

        self.assertThat(raised.step, Equals(steps.BUILD))
        self.assertThat(raised.part, Equals("part1"))
        self.assertThat(
            raised.report,
            Equals(
                "The {!r} part property appears to have changed.\n".format(
                    self.scriptlet
                )
            ),
        )
Ejemplo n.º 30
0
    def test_has_step_run(self):
        # No steps should have run, yet
        main_part = self.project_config.parts.get_part("main")
        self.assertFalse(self.cache.has_step_run(main_part, steps.PULL))

        # Now run the pull step
        lifecycle.execute(steps.PULL, self.project_config, part_names=["main"])

        # Should still have cached that no steps have run
        self.assertFalse(self.cache.has_step_run(main_part, steps.PULL))

        # Now clear that step from the cache, and it should be up-to-date
        self.cache.clear_step(main_part, steps.PULL)
        self.assertTrue(self.cache.has_step_run(main_part, steps.PULL))
Ejemplo n.º 31
0
    def test_prime_with_stage_packages(self):
        self.useFixture(fixtures.EnvironmentVariable(
            'SNAPCRAFT_BUILD_INFO', '1'))
        for name, version in [('test-package1', 'test-version1'),
                              ('test-package2', 'test-version2')]:
            self.fake_apt_cache.add_package(
                fixture_setup.FakeAptCachePackage(name, version))

        self.make_snapcraft_yaml(
            textwrap.dedent("""\
                parts:
                  test-part:
                    plugin: nil
                    stage-packages: [test-package1=test-version1, test-package2]
                """))  # NOQA

        lifecycle.execute('prime', self.project_options)

        expected = textwrap.dedent("""\
            name: test
            version: 0
            summary: test
            description: test
            confinement: strict
            grade: stable
            parts:
              test-part:
                build-packages: []
                installed-packages: []
                installed-snaps: []
                plugin: nil
                prime: []
                stage: []
                stage-packages: [test-package1=test-version1, test-package2=test-version2]
                uname: Linux test uname 4.10 x86_64
            architectures: [{}]
            build-packages: []
            build-snaps: []
            """.format(self.project_options.deb_arch))  # NOQA
        self.assertThat(
            os.path.join('prime', 'snap', 'manifest.yaml'),
            FileContains(expected))
Ejemplo n.º 32
0
    def test_prime_with_virtual_build_package(self, _):
        self.useFixture(fixtures.EnvironmentVariable(
            'SNAPCRAFT_BUILD_INFO', '1'))
        self.fake_apt_cache.add_package(
            fixture_setup.FakeAptCachePackage(
                'test-provider-package', 'test-version',
                provides=['test-virtual-package']))

        self.make_snapcraft_yaml(
            textwrap.dedent("""\
                parts:
                  test-part:
                    plugin: nil
                    build-packages: ['test-virtual-package']
                """))

        lifecycle.execute('prime', self.project_options)

        expected = textwrap.dedent("""\
            name: test
            version: 0
            summary: test
            description: test
            confinement: strict
            grade: stable
            parts:
              test-part:
                build-packages: [test-virtual-package]
                installed-packages: []
                installed-snaps: []
                plugin: nil
                prime: []
                stage: []
                stage-packages: []
                uname: Linux test uname 4.10 x86_64
            architectures: [{}]
            build-packages: [test-provider-package=test-version]
            build-snaps: []
            """.format(self.project_options.deb_arch))
        self.assertThat(
            os.path.join('prime', 'snap', 'manifest.yaml'),
            FileContains(expected))
Ejemplo n.º 33
0
    def test_dirty_stage_part_with_unbuilt_dependent(self):
        self.make_snapcraft_yaml(
            textwrap.dedent("""\
                parts:
                  part1:
                    plugin: nil
                  part2:
                    plugin: nil
                    after: [part1]
                """))

        # Stage dependency (dependent is unbuilt)
        lifecycle.execute('stage', self.project_options, part_names=['part1'])

        # Reset logging since we only care about the following
        self.fake_logger = fixtures.FakeLogger(level=logging.INFO)
        self.useFixture(self.fake_logger)

        def _fake_dirty_report(self, step):
            if step == 'stage':
                return pluginhandler.DirtyReport({'foo'}, {'bar'})
            return None

        # Should automatically clean and re-stage if that step is dirty
        # for the part.
        with mock.patch.object(pluginhandler.PluginHandler, 'get_dirty_report',
                               _fake_dirty_report):
            lifecycle.execute('stage', self.project_options,
                              part_names=['part1'])

        self.assertThat(
            self.fake_logger.output, Equals(
                'Skipping pull part1 (already ran)\n'
                'Skipping build part1 (already ran)\n'
                'Skipping cleaning priming area for part1 (out of date) '
                '(already clean)\n'
                'Cleaning staging area for part1 (out of date)\n'
                'Skipping cleaning priming area for part2 (out of date) '
                '(already clean)\n'
                'Skipping cleaning staging area for part2 (out of date) '
                '(already clean)\n'
                'Staging part1 \n'))
Ejemplo n.º 34
0
def run(args, project_options):
    lifecycle_command = _get_lifecycle_command(args)
    argless_command = _get_command_from_arg(args)
    if lifecycle_command:
        lifecycle.execute(lifecycle_command, project_options, args['<part>'])
    elif argless_command:
        argless_command()
    elif args['clean']:
        lifecycle.clean(project_options, args['<part>'], args['--step'])
    elif args['upload']:
        snapcraft.upload(args['<snap-file>'])
    elif args['cleanbuild']:
        lifecycle.cleanbuild(project_options),
    elif args['help']:
        snapcraft.topic_help(args['<topic>'] or args['<plugin>'],
                             args['--devel'], args['topics'])
    else:  # snap by default:
        lifecycle.snap(project_options, args['<directory>'], args['--output'])

    return project_options
Ejemplo n.º 35
0
    def test_part_with_build_snaps_on_docker(self, mock_install_build_snaps,
                                             mock_docker_instance):
        project = self.make_snapcraft_project(
            textwrap.dedent("""\
                parts:
                  part1:
                    plugin: nil
                    build-snaps: [snap1, snap2]
                """))

        lifecycle.execute(steps.PULL, project)

        mock_install_build_snaps.assert_not_called()

        self.assertThat(
            self.fake_logger.output,
            Contains(
                "The following snaps are required but not installed as snapcraft "
                "is running inside docker: "),
        )
Ejemplo n.º 36
0
    def test_get_dirty_report(self):
        # No dirty reports should be available, yet
        dependent_part = self.project_config.parts.get_part("dependent")
        self.assertFalse(
            self.cache.get_dirty_report(dependent_part, steps.PULL))

        # Now run the pull step
        lifecycle.execute(steps.PULL, self.project_config)

        # Re-stage main, which will make dependent dirty
        lifecycle.execute(steps.PULL, self.project_config, part_names=["main"])

        # Should still have cached that it's not dirty, though
        self.assertFalse(
            self.cache.get_dirty_report(dependent_part, steps.PULL))

        # Now clear that step from the cache, and it should be up-to-date
        self.cache.clear_step(dependent_part, steps.PULL)
        self.assertTrue(self.cache.get_dirty_report(dependent_part,
                                                    steps.PULL))
Ejemplo n.º 37
0
    def test_no_exception_when_dependency_is_required_but_already_staged(self):
        project_config = self.make_snapcraft_project(
            textwrap.dedent("""\
                parts:
                  part1:
                    plugin: nil
                  part2:
                    plugin: nil
                    after:
                      - part1
                """))

        def _fake_should_step_run(self, step, force=False):
            return self.name != "part1"

        with mock.patch.object(pluginhandler.PluginHandler, "should_step_run",
                               _fake_should_step_run):
            lifecycle.execute(steps.PULL, project_config, part_names=["part2"])

        self.assertThat(self.fake_logger.output, Equals("Pulling part2 \n"))
Ejemplo n.º 38
0
    def test_prime_with_build_info_records_manifest(self):
        self.useFixture(
            fixtures.EnvironmentVariable("SNAPCRAFT_BUILD_INFO", "1"))
        project_config = self.make_snapcraft_project(
            textwrap.dedent("""\
                parts:
                  test-part:
                    plugin: nil
                """))
        lifecycle.execute(steps.PRIME, project_config)

        expected = textwrap.dedent("""\
            snapcraft-version: '3.0'
            snapcraft-os-release-id: ubuntu
            snapcraft-os-release-version-id: '16.04'
            name: test
            version: 0
            summary: test
            description: test
            confinement: strict
            grade: stable
            parts:
              test-part:
                build-packages: []
                installed-packages:
                - patchelf=0.9
                installed-snaps: []
                plugin: nil
                prime: []
                stage: []
                stage-packages: []
                uname: Linux test uname 4.10 x86_64
            architectures:
            - {}
            build-packages: []
            build-snaps: []
            """.format(project_config.project.deb_arch))
        self.assertThat(
            os.path.join(steps.PRIME.name, "snap", "manifest.yaml"),
            FileContains(expected),
        )
Ejemplo n.º 39
0
    def test_no_exception_when_dependency_is_required_but_already_staged(self):
        self.make_snapcraft_yaml("""parts:
  part1:
    plugin: nil
  part2:
    plugin: nil
    after:
      - part1
""")

        def _fake_should_step_run(self, step, force=False):
            return self.name != 'part1'

        with mock.patch.object(pluginhandler.PluginHandler, 'should_step_run',
                               _fake_should_step_run):
            lifecycle.execute('pull',
                              self.project_options,
                              part_names=['part2'])

        self.assertEqual('Preparing to pull part2 \n'
                         'Pulling part2 \n', self.fake_logger.output)
Ejemplo n.º 40
0
    def test_dependency_is_staged_when_required(self, mock_install_build_snaps):
        project_config = self.make_snapcraft_project(
            textwrap.dedent(
                """\
                parts:
                  part1:
                    plugin: nil
                  part2:
                    plugin: nil
                    after:
                      - part1
                """
            )
        )

        lifecycle.execute(steps.PULL, project_config, part_names=["part2"])

        self.assertThat(
            self.fake_logger.output,
            Contains("'part2' has dependencies that need to be staged: part1"),
        )
Ejemplo n.º 41
0
    def test_core_setup(self, download_mock):
        core_snap = self._create_core_snap()
        core_snap_hash = calculate_sha3_384(core_snap)
        download_mock.return_value = core_snap_hash
        self.tempdir_mock.side_effect = self._setup_tempdir_side_effect(
            core_snap)

        self._create_classic_confined_snapcraft_yaml()
        lifecycle.execute('pull', self.project_options)

        regex = ('mkdir -p {}\n'
                 'unsquashfs -d {} .*{}\n').format(
                     os.path.dirname(self.core_path), self.core_path,
                     core_snap_hash)
        self.assertThat(
            self.witness_path,
            FileContains(matcher=MatchesRegex(regex, flags=re.DOTALL)))

        download_mock.assert_called_once_with(
            'core', 'stable', os.path.join(self.tempdir, 'core.snap'),
            self.project_options.deb_arch, '')
Ejemplo n.º 42
0
    def test_build_is_dirty_if_scriptlet_changes(
            self, mock_install_build_packages, mock_enable_cross_compilation):
        mock_install_build_packages.return_value = []
        self.make_snapcraft_yaml(
            textwrap.dedent("""\
                parts:
                  part1:
                    plugin: nil
                    {}: touch scriptlet
                """).format(self.scriptlet))

        # Build it
        lifecycle.execute('build', snapcraft.ProjectOptions())

        # Reset logging since we only care about the following
        self.fake_logger = fixtures.FakeLogger(level=logging.INFO)
        self.useFixture(self.fake_logger)

        # Change prepare scriptlet
        self.make_snapcraft_yaml(
            textwrap.dedent("""\
                parts:
                  part1:
                    plugin: nil
                    {}: touch changed
                """).format(self.scriptlet))

        # Build it again. Should catch that the scriptlet changed and it needs
        # to be rebuilt.
        raised = self.assertRaises(
            errors.StepOutdatedError,
            lifecycle.execute, 'build', snapcraft.ProjectOptions())

        self.assertThat(
            str(raised), Equals(
                "The 'build' step of 'part1' is out of date:\n"
                "The {!r} part property appears to have changed.\n"
                "In order to continue, please clean that part's 'build' step "
                "by running:\nsnapcraft clean part1 -s build\n".format(
                    self.scriptlet)))
Ejemplo n.º 43
0
    def test_dirty_build_raises(self):
        project_config = self.make_snapcraft_project(
            textwrap.dedent("""\
                parts:
                  part1:
                    plugin: nil
                """))

        # Build it.
        lifecycle.execute(steps.BUILD, project_config)

        # Reset logging since we only care about the following
        self.fake_logger = fixtures.FakeLogger(level=logging.INFO)
        self.useFixture(self.fake_logger)

        def _fake_dirty_report(self, step):
            if step == steps.BUILD:
                return pluginhandler.DirtyReport(
                    dirty_properties={"foo", "bar"})
            return None

        # Should catch that the part needs to be rebuilt and raise an error.
        with mock.patch.object(pluginhandler.PluginHandler, "get_dirty_report",
                               _fake_dirty_report):
            raised = self.assertRaises(errors.StepOutdatedError,
                                       lifecycle.execute, steps.BUILD,
                                       project_config)

        self.assertThat(self.fake_logger.output,
                        Equals("Skipping pull part1 (already ran)\n"))

        self.assertThat(raised.step, Equals(steps.BUILD))
        self.assertThat(raised.part, Equals("part1"))
        self.assertThat(
            raised.report,
            Equals(
                "The 'bar' and 'foo' part properties appear to have changed.\n"
            ),
        )
        self.assertThat(raised.parts_names, Equals("part1"))
Ejemplo n.º 44
0
    def test_build_is_dirty_if_scriptlet_changes(
            self, mock_install_build_packages, mock_enable_cross_compilation):
        mock_install_build_packages.return_value = []
        project_config = self.make_snapcraft_project(
            textwrap.dedent("""\
                parts:
                  part1:
                    plugin: nil
                    {}: touch scriptlet
                """).format(self.scriptlet))

        # Build it
        lifecycle.execute(self.step, project_config)

        # Reset logging since we only care about the following
        self.fake_logger = fixtures.FakeLogger(level=logging.INFO)
        self.useFixture(self.fake_logger)

        # Change prepare scriptlet
        project_config = self.make_snapcraft_project(
            textwrap.dedent("""\
                parts:
                  part1:
                    plugin: nil
                    {}: touch changed
                """).format(self.scriptlet))

        # Build it again. Should catch that the scriptlet changed and it needs
        # to be rebuilt.
        raised = self.assertRaises(errors.StepOutdatedError, lifecycle.execute,
                                   self.step, project_config)

        self.assertThat(raised.step, Equals(self.step))
        self.assertThat(raised.part, Equals("part1"))
        self.assertThat(
            raised.report,
            Equals("The {!r} part property appears to have changed.\n".format(
                self.scriptlet)),
        )
Ejemplo n.º 45
0
    def test_prime_with_source_details(self, _):
        self.useFixture(fixtures.EnvironmentVariable(
            'SNAPCRAFT_BUILD_INFO', '1'))

        self.make_snapcraft_yaml("""parts:
  test-part:
    plugin: nil
    source: test-source
    source-type: git
    source-commit: test-commit
""")

        lifecycle.execute('prime', self.project_options)

        expected = ("""name: test
version: 0
summary: test
description: test
confinement: strict
grade: stable
parts:
  test-part:
    build-packages: []
    plugin: nil
    prime: []
    source: test-source
    source-branch: ''
    source-checksum: ''
    source-commit: test-commit
    source-tag: ''
    source-type: git
    stage: []
    stage-packages: []
architectures: [{}]
build-packages: []
""".format(self.project_options.deb_arch))
        self.assertThat(
            os.path.join('prime', 'snap', 'snapcraft.yaml'),
            FileContains(expected))
Ejemplo n.º 46
0
    def test_dependency_is_staged_when_required(self):
        project_config = self.make_snapcraft_project(
            textwrap.dedent("""\
                parts:
                  part1:
                    plugin: nil
                  part2:
                    plugin: nil
                    after:
                      - part1
                """))

        lifecycle.execute(steps.PULL, project_config, part_names=["part2"])

        self.assertThat(
            self.fake_logger.output,
            Equals("'part2' has dependencies that need to be staged: part1\n"
                   "Pulling part1 \n"
                   "Building part1 \n"
                   "Staging part1 \n"
                   "Pulling part2 \n"),
        )
Ejemplo n.º 47
0
    def test_dirty_build_raises(self):
        self.make_snapcraft_yaml(
            textwrap.dedent("""\
                parts:
                  part1:
                    plugin: nil
                """))

        # Build it.
        lifecycle.execute('build', self.project_options)

        # Reset logging since we only care about the following
        self.fake_logger = fixtures.FakeLogger(level=logging.INFO)
        self.useFixture(self.fake_logger)

        def _fake_dirty_report(self, step):
            if step == 'build':
                return pluginhandler.DirtyReport({'foo', 'bar'}, set())
            return None

        # Should catch that the part needs to be rebuilt and raise an error.
        with mock.patch.object(pluginhandler.PluginHandler, 'get_dirty_report',
                               _fake_dirty_report):
            raised = self.assertRaises(
                errors.StepOutdatedError,
                lifecycle.execute,
                'build', self.project_options)

        self.assertThat(
            self.fake_logger.output,
            Equals('Skipping pull part1 (already ran)\n'))

        self.assertThat(
            str(raised), Equals(
                "The 'build' step of 'part1' is out of date:\n"
                "The 'bar' and 'foo' part properties appear to have changed.\n"
                "In order to continue, please clean that part's 'build' step "
                "by running:\nsnapcraft clean part1 -s build\n"))
Ejemplo n.º 48
0
    def test_prime_with_plugin_manifest(self, fake_plugin_manifest):
        fake_plugin_manifest.return_value = {
            'test-plugin-manifest': 'test-value'
        }
        self.useFixture(
            fixtures.EnvironmentVariable('SNAPCRAFT_BUILD_INFO', '1'))
        self.make_snapcraft_yaml(
            textwrap.dedent("""\
                parts:
                  test-part:
                    plugin: nil
                """))
        lifecycle.execute('prime', self.project_options)

        expected = textwrap.dedent("""\
            name: test
            version: 0
            summary: test
            description: test
            confinement: strict
            grade: stable
            parts:
              test-part:
                build-packages: []
                installed-packages: []
                installed-snaps: []
                plugin: nil
                prime: []
                stage: []
                stage-packages: []
                test-plugin-manifest: test-value
                uname: Linux test uname 4.10 x86_64
            architectures: [{}]
            build-packages: []
            build-snaps: []
            """.format(self.project_options.deb_arch))
        self.assertThat(os.path.join('prime', 'snap', 'manifest.yaml'),
                        FileContains(expected))
Ejemplo n.º 49
0
    def test_prime_with_virtual_build_package(self, _):
        self.useFixture(fixtures.EnvironmentVariable(
            'SNAPCRAFT_BUILD_INFO', '1'))
        fake_apt_cache = fixture_setup.FakeAptCache()
        self.useFixture(fake_apt_cache)
        fake_apt_cache.cache['test-provider-package'] = (
            fixture_setup.FakeAptCachePackage(
                fake_apt_cache.path,
                'test-provider-package', 'test-version',
                provides=['test-virtual-package']))

        self.make_snapcraft_yaml("""parts:
  test-part:
    plugin: nil
    build-packages: ['test-virtual-package']
""")

        lifecycle.execute('prime', self.project_options)

        expected = ("""name: test
version: 0
summary: test
description: test
confinement: strict
grade: stable
parts:
  test-part:
    build-packages: [test-provider-package=test-version]
    plugin: nil
    prime: []
    stage: []
    stage-packages: []
architectures: [{}]
build-packages: []
""".format(self.project_options.deb_arch))
        self.assertThat(
            os.path.join('prime', 'snap', 'snapcraft.yaml'),
            FileContains(expected))
Ejemplo n.º 50
0
    def test_get_outdated_report(self):
        # No outdated reports should be available, yet
        main_part = self.project_config.parts.get_part("main")
        self.assertFalse(self.cache.get_outdated_report(main_part, steps.PULL))

        # Now run the pull step for main
        lifecycle.execute(steps.PULL, self.project_config, part_names=["main"])

        # Change the source on disk, which will make the pull step of main
        # outdated (to ensure this is the case, manually set the timestamp)
        open("new-file", "w").close()
        pull_state_file = states.get_step_state_file(main_part.plugin.statedir,
                                                     steps.PULL)
        access_time = os.stat(pull_state_file).st_atime
        modified_time = os.stat(pull_state_file).st_atime
        os.utime("new-file", (access_time, modified_time + 1))

        # Should still have cached that it's not outdated, though
        self.assertFalse(self.cache.get_outdated_report(main_part, steps.PULL))

        # Now clear that step from the cache, and it should be up-to-date
        self.cache.clear_step(main_part, steps.PULL)
        self.assertTrue(self.cache.get_outdated_report(main_part, steps.PULL))
Ejemplo n.º 51
0
    def test_pull_is_dirty_if_target_arch_changes(
            self, mock_install_build_packages, mock_enable_cross_compilation):
        mock_install_build_packages.return_value = []
        self.make_snapcraft_yaml(
            textwrap.dedent("""\
                parts:
                  part1:
                    plugin: nil
                """))

        # Pull it with amd64
        lifecycle.execute('pull', snapcraft.ProjectOptions(
            target_deb_arch='amd64'))

        # Reset logging since we only care about the following
        self.fake_logger = fixtures.FakeLogger(level=logging.INFO)
        self.useFixture(self.fake_logger)

        # Pull it again with armhf. Should catch that the part needs to be
        # re-pulled due to the change in target architecture and raise an
        # error.
        raised = self.assertRaises(
            errors.StepOutdatedError,
            lifecycle.execute,
            'pull', snapcraft.ProjectOptions(
                target_deb_arch='armhf'))

        self.assertThat(
            self.fake_logger.output,
            Equals("Setting target machine to 'armhf'\n"))

        self.assertThat(
            str(raised), Equals(
                "The 'pull' step of 'part1' is out of date:\n"
                "The 'deb_arch' project option appears to have changed.\n"
                "In order to continue, please clean that part's 'pull' step "
                "by running:\nsnapcraft clean part1 -s pull\n"))
Ejemplo n.º 52
0
    def test_prime_with_build_info_records_snapcraft_yaml(self):
        self.useFixture(fixtures.EnvironmentVariable("SNAPCRAFT_BUILD_INFO", "1"))
        project_config = self.make_snapcraft_project(
            textwrap.dedent(
                """\
                parts:
                  test-part:
                    plugin: nil
                """
            ),
            snap_type="type: app",
        )
        lifecycle.execute(steps.PRIME, project_config)

        expected = textwrap.dedent(
            """\
            name: test
            base: core18
            version: "1.0"
            summary: test
            description: test
            confinement: strict
            grade: stable
            type: app

            parts:
              test-part:
                plugin: nil

            """
        )

        self.assertThat(
            os.path.join(steps.PRIME.name, "snap", "snapcraft.yaml"),
            FileContains(expected),
        )
Ejemplo n.º 53
0
def run(args, project_options):  # noqa
    lifecycle_command = _get_lifecycle_command(args)
    argless_command = _get_command_from_arg(args)
    if lifecycle_command:
        lifecycle.execute(lifecycle_command, project_options, args['<part>'])
    elif argless_command:
        argless_command()
    elif args['clean']:
        _run_clean(args, project_options)
    elif args['cleanbuild']:
        lifecycle.cleanbuild(project_options, remote=args['--remote']),
    elif _is_store_command(args):
        _run_store_command(args)
    elif args['tour']:
        _scaffold_examples(args['<directory>'] or _SNAPCRAFT_TOUR_DIR)
    elif args['help']:
        snapcraft.topic_help(args['<topic>'] or args['<plugin>'],
                             args['--devel'], args['topics'])
    elif args['enable-ci']:
        enable_ci(args['<ci-system>'], args['--refresh'])
    elif args['update']:
        parts.update()
    elif args['define']:
        parts.define(args['<part-name>'])
    elif args['search']:
        parts.search(' '.join(args['<query>']))
    elif os.environ.get('SNAPCRAFT_CONTAINER_BUILDS'):
        lifecycle.containerbuild(project_options, args['--output'],
                                 args['--remote'])
    else:  # snap by default:
        if args['--remote']:
            raise RuntimeError(
                '--remote can only be used with SNAPCRAFT_CONTAINER_BUILDS')
        lifecycle.snap(project_options, args['<directory>'], args['--output'])

    return project_options
Ejemplo n.º 54
0
    def test_dirty_stage_part_with_built_dependent_raises(self):
        # Set the option to error on dirty/outdated steps
        with snapcraft.config.CLIConfig() as cli_config:
            cli_config.set_outdated_step_action(
                snapcraft.config.OutdatedStepAction.ERROR
            )

        project_config = self.make_snapcraft_project(
            textwrap.dedent(
                """\
                parts:
                  part1:
                    plugin: nil
                  part2:
                    plugin: nil
                    after: [part1]
                """
            )
        )

        # Stage dependency
        lifecycle.execute(steps.STAGE, project_config, part_names=["part1"])
        # Build dependent
        lifecycle.execute(steps.BUILD, project_config, part_names=["part2"])

        def _fake_dirty_report(self, step):
            if step == steps.STAGE:
                return pluginhandler.DirtyReport(
                    dirty_properties={"foo"}, dirty_project_options={"bar"}
                )
            return None

        # Should stage no problem
        with mock.patch.object(
            pluginhandler.PluginHandler, "get_dirty_report", _fake_dirty_report
        ):
            lifecycle.execute(steps.STAGE, project_config, part_names=["part1"])

        # Reset logging since we only care about the following
        self.fake_logger = fixtures.FakeLogger(level=logging.INFO)
        self.useFixture(self.fake_logger)

        # Should raise an error since part2 is now dirty
        raised = self.assertRaises(
            errors.StepOutdatedError, lifecycle.execute, steps.BUILD, project_config
        )

        output = self.fake_logger.output.split("\n")
        part1_output = [line.strip() for line in output if "part1" in line]
        self.assertThat(part1_output, Equals(["Skipping pull part1 (already ran)"]))

        self.assertThat(raised.step, Equals(steps.PULL))
        self.assertThat(raised.part, Equals("part2"))
        self.assertThat(raised.report, Equals("A dependency has changed: 'part1'\n"))
Ejemplo n.º 55
0
    def test_dependency_recursed_correctly(self):
        self.make_snapcraft_yaml(
            textwrap.dedent("""\
                parts:
                  part1:
                    plugin: nil
                  part2:
                    plugin: nil
                    after:
                      - part1
                  part3:
                    plugin: nil
                    after:
                      - part2
                """))

        snap_info = lifecycle.execute('pull', self.project_options)

        expected_snap_info = {
            'name': 'test',
            'version': 0,
            'arch': [self.project_options.deb_arch],
            'type': ''
        }
        self.assertThat(snap_info, Equals(expected_snap_info))

        self.assertThat(
            self.fake_logger.output,
            Equals(
                'Preparing to pull part1 \n'
                'Pulling part1 \n'
                '\'part2\' has prerequisites that need to be staged: part1\n'
                'Preparing to build part1 \n'
                'Building part1 \n'
                'Staging part1 \n'
                'Preparing to pull part2 \n'
                'Pulling part2 \n'
                '\'part3\' has prerequisites that need to be staged: part2\n'
                'Preparing to build part2 \n'
                'Building part2 \n'
                'Staging part2 \n'
                'Preparing to pull part3 \n'
                'Pulling part3 \n', ))
Ejemplo n.º 56
0
    def test_os_type_returned_by_lifecycle(self):
        self.make_snapcraft_yaml("""parts:
  part1:
    plugin: nil
  part2:
    plugin: nil
    after:
      - part1
""", 'type: os')

        snap_info = lifecycle.execute('pull', self.project_options)

        expected_snap_info = {
            'name': 'test',
            'version': 0,
            'arch': [self.project_options.deb_arch],
            'type': 'os'
        }
        self.assertEqual(snap_info, expected_snap_info)
Ejemplo n.º 57
0
    def test_os_type_returned_by_lifecycle(self):
        project_config = self.make_snapcraft_project(
            textwrap.dedent("""\
                parts:
                  part1:
                    plugin: nil
                  part2:
                    plugin: nil
                    after:
                      - part1
                """),
            "type: os",
        )

        snap_info = lifecycle.execute(steps.PULL, project_config)

        expected_snap_info = {
            "name": "test",
            "version": "1.0",
            "arch": [project_config.project.deb_arch],
            "type": "os",
        }
        self.assertThat(snap_info, Equals(expected_snap_info))
    def test_dirty_stage_part_with_built_dependent_raises(self):
        self.make_snapcraft_yaml("""parts:
  part1:
    plugin: nil
  part2:
    plugin: nil
    after: [part1]
""")

        # Stage dependency
        lifecycle.execute('stage', self.project_options, part_names=['part1'])
        # Build dependent
        lifecycle.execute('build', self.project_options, part_names=['part2'])

        # Reset logging since we only care about the following
        self.fake_logger = fixtures.FakeLogger(level=logging.INFO)
        self.useFixture(self.fake_logger)

        def _fake_is_dirty(self, step):
            return step == 'stage'

        # Should raise a RuntimeError about the fact that stage is dirty but
        # it has dependents that need it.
        with mock.patch.object(pluginhandler.PluginHandler, 'is_dirty',
                               _fake_is_dirty):
            with self.assertRaises(RuntimeError) as raised:
                lifecycle.execute('stage', self.project_options,
                                  part_names=['part1'])

        output = self.fake_logger.output.split('\n')
        part1_output = [line.strip() for line in output if 'part1' in line]
        self.assertEqual(
            [
                'Skipping pull part1 (already ran)',
                'Skipping build part1 (already ran)',
            ],
            part1_output)

        self.assertEqual(
            "The 'stage' step for 'part1' needs to be run again, but 'part2' "
            "depends upon it. Please clean the build step of 'part2' first.",
            str(raised.exception))
Ejemplo n.º 59
0
    def test_core_setup_skipped_if_not_classic(self):
        lifecycle.init()
        lifecycle.execute('pull', self.project_options)

        self.assertThat(self.witness_path, Not(FileExists()))
Ejemplo n.º 60
0
def _execute(  # noqa: C901
        step: steps.Step,
        parts: str,
        pack_project: bool = False,
        output: str = None,
        shell: bool = False,
        shell_after: bool = False,
        destructive_mode: bool = False,
        **kwargs) -> "Project":
    _clean_provider_error()
    provider = "host" if destructive_mode else None
    build_environment = env.BuilderEnvironmentConfig(force_provider=provider)
    project = get_project(is_managed_host=build_environment.is_managed_host,
                          **kwargs)

    echo.wrapped("Using {!r}: Project assets will be "
                 "searched for from the {!r} directory.".format(
                     project.info.snapcraft_yaml_file_path,
                     os.path.relpath(project._get_snapcraft_assets_dir(),
                                     project._project_dir),
                 ))

    conduct_project_sanity_check(project)

    if build_environment.is_managed_host or build_environment.is_host:
        project_config = project_loader.load_config(project)
        lifecycle.execute(step, project_config, parts)
        if pack_project:
            _pack(project.prime_dir, output=output)
    else:
        build_provider_class = build_providers.get_provider_for(
            build_environment.provider)
        try:
            build_provider_class.ensure_provider()
        except build_providers.errors.ProviderNotFound as provider_error:
            if provider_error.prompt_installable:
                click.echo(str(provider_error))
                if click.confirm("Would you like to install it now?"):
                    build_provider_class.setup_provider(echoer=echo)
                else:
                    raise provider_error
            else:
                raise provider_error

        echo.info("Launching a VM.")
        with build_provider_class(project=project, echoer=echo) as instance:
            instance.mount_project()
            try:
                if shell:
                    # shell means we want to do everything right up to the previous
                    # step and then go into a shell instead of the requested step.
                    # the "snap" target is a special snowflake that has not made its
                    # way to be a proper step.
                    previous_step = None
                    if pack_project:
                        previous_step = steps.PRIME
                    elif step > steps.PULL:
                        previous_step = step.previous_step()
                    # steps.PULL is the first step, so we would directly shell into it.
                    if previous_step:
                        instance.execute_step(previous_step)
                elif pack_project:
                    instance.pack_project(output=output)
                else:
                    instance.execute_step(step)
            except Exception:
                _retrieve_provider_error(instance)
                if project.debug:
                    instance.shell()
                else:
                    echo.warning(
                        "Run the same command again with --debug to shell into the environment "
                        "if you wish to introspect this failure.")
                    raise
            else:
                if shell or shell_after:
                    instance.shell()
    return project