Beispiel #1
0
def test_build_generics_symlink_dir(tmp_path):
    """Respects a symlinked dir."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    entrypoint = tmp_path / 'crazycharm.py'
    entrypoint.touch()
    somedir = tmp_path / 'somedir'
    somedir.mkdir()
    somefile = somedir / 'sanity check'
    somefile.touch()
    the_symlink = tmp_path / 'thelink'
    the_symlink.symlink_to(somedir)

    builder = Builder({
        'from': tmp_path,
        'entrypoint': entrypoint,
        'requirement': [],
    })
    builder.handle_generic_paths()

    built_symlink = build_dir / 'thelink'
    assert built_symlink.is_symlink()
    assert built_symlink.resolve() == build_dir / 'somedir'
    real_link = os.readlink(str(built_symlink))
    assert real_link == 'somedir'

    # as a sanity check, the file inside the linked dir should exist
    assert (build_dir / 'thelink' / 'sanity check').exists()
Beispiel #2
0
def test_build_generics_symlink_deep(tmp_path):
    """Correctly re-links a symlink across deep dirs."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()
    entrypoint = tmp_path / 'crazycharm.py'
    entrypoint.touch()

    dir1 = tmp_path / 'dir1'
    dir1.mkdir()
    dir2 = tmp_path / 'dir2'
    dir2.mkdir()
    original_target = dir1 / 'file.real'
    original_target.touch()
    the_symlink = dir2 / 'file.link'
    the_symlink.symlink_to(original_target)

    builder = Builder({
        'from': tmp_path,
        'entrypoint': entrypoint,
        'requirement': [],
    })
    builder.handle_generic_paths()

    built_symlink = build_dir / 'dir2' / 'file.link'
    assert built_symlink.is_symlink()
    assert built_symlink.resolve() == build_dir / 'dir1' / 'file.real'
    real_link = os.readlink(str(built_symlink))
    assert real_link == '../dir1/file.real'
Beispiel #3
0
def test_build_generics_ignored_file(tmp_path, caplog, config):
    """Don't include ignored filed."""
    caplog.set_level(logging.DEBUG)
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    # create two files (and the needed entrypoint)
    file1 = tmp_path / "file1.txt"
    file1.touch()
    file2 = tmp_path / "file2.txt"
    file2.touch()
    entrypoint = tmp_path / "crazycharm.py"
    entrypoint.touch()

    builder = Builder(
        {
            "from": tmp_path,
            "entrypoint": entrypoint,
            "requirement": [],
        },
        config,
    )

    # set it up to ignore file 2 and make it work
    builder.ignore_rules.extend_patterns(["file2.*"])
    builder.handle_generic_paths()

    assert (build_dir / "file1.txt").exists()
    assert not (build_dir / "file2.txt").exists()

    expected = "Ignoring file because of rules: 'file2.txt'"
    assert expected in [rec.message for rec in caplog.records]
Beispiel #4
0
def test_build_generics_symlink_deep(tmp_path, config):
    """Correctly re-links a symlink across deep dirs."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()
    entrypoint = tmp_path / "crazycharm.py"
    entrypoint.touch()

    dir1 = tmp_path / "dir1"
    dir1.mkdir()
    dir2 = tmp_path / "dir2"
    dir2.mkdir()
    original_target = dir1 / "file.real"
    original_target.touch()
    the_symlink = dir2 / "file.link"
    the_symlink.symlink_to(original_target)

    builder = Builder(
        {
            "from": tmp_path,
            "entrypoint": entrypoint,
            "requirement": [],
        },
        config,
    )
    builder.handle_generic_paths()

    built_symlink = build_dir / "dir2" / "file.link"
    assert built_symlink.is_symlink()
    assert built_symlink.resolve() == build_dir / "dir1" / "file.real"
    real_link = os.readlink(str(built_symlink))
    assert real_link == "../dir1/file.real"
Beispiel #5
0
def test_build_generics_symlink_file_outside(tmp_path, caplog, config):
    """Ignores (with warning) a symlink pointing a file outside projects dir."""
    caplog.set_level(logging.WARNING)

    project_dir = tmp_path / "test-project"
    project_dir.mkdir()

    build_dir = project_dir / BUILD_DIRNAME
    build_dir.mkdir()
    entrypoint = project_dir / "crazycharm.py"
    entrypoint.touch()

    outside_project = tmp_path / "dangerous.txt"
    outside_project.touch()
    the_symlink = project_dir / "external-file"
    the_symlink.symlink_to(outside_project)

    builder = Builder(
        {
            "from": project_dir,
            "entrypoint": entrypoint,
            "requirement": [],
        },
        config,
    )
    builder.handle_generic_paths()

    assert not (build_dir / "external-file").exists()
    expected = "Ignoring symlink because targets outside the project: 'external-file'"
    assert expected in [rec.message for rec in caplog.records]
Beispiel #6
0
def test_build_generics_symlink_dir(tmp_path, config):
    """Respects a symlinked dir."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    entrypoint = tmp_path / "crazycharm.py"
    entrypoint.touch()
    somedir = tmp_path / "somedir"
    somedir.mkdir()
    somefile = somedir / "sanity check"
    somefile.touch()
    the_symlink = tmp_path / "thelink"
    the_symlink.symlink_to(somedir)

    builder = Builder(
        {
            "from": tmp_path,
            "entrypoint": entrypoint,
            "requirement": [],
        },
        config,
    )
    builder.handle_generic_paths()

    built_symlink = build_dir / "thelink"
    assert built_symlink.is_symlink()
    assert built_symlink.resolve() == build_dir / "somedir"
    real_link = os.readlink(str(built_symlink))
    assert real_link == "somedir"

    # as a sanity check, the file inside the linked dir should exist
    assert (build_dir / "thelink" / "sanity check").exists()
Beispiel #7
0
def test_build_generics_symlink_file(tmp_path, config):
    """Respects a symlinked file."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    entrypoint = tmp_path / "crazycharm.py"
    entrypoint.touch()
    the_symlink = tmp_path / "somehook.py"
    the_symlink.symlink_to(entrypoint)

    builder = Builder(
        {
            "from": tmp_path,
            "entrypoint": entrypoint,
            "requirement": [],
        },
        config,
    )
    builder.handle_generic_paths()

    built_symlink = build_dir / "somehook.py"
    assert built_symlink.is_symlink()
    assert built_symlink.resolve() == build_dir / "crazycharm.py"
    real_link = os.readlink(str(built_symlink))
    assert real_link == "crazycharm.py"
Beispiel #8
0
def test_build_generics_symlink_directory_outside(tmp_path, caplog):
    """Ignores (with warning) a symlink pointing a dir outside projects dir."""
    caplog.set_level(logging.WARNING)

    project_dir = tmp_path / 'test-project'
    project_dir.mkdir()

    build_dir = project_dir / BUILD_DIRNAME
    build_dir.mkdir()
    entrypoint = project_dir / 'crazycharm.py'
    entrypoint.touch()

    outside_project = tmp_path / 'dangerous'
    outside_project.mkdir()
    the_symlink = project_dir / 'external-dir'
    the_symlink.symlink_to(outside_project)

    builder = Builder({
        'from': project_dir,
        'entrypoint': entrypoint,
        'requirement': [],
    })
    builder.handle_generic_paths()

    assert not (build_dir / 'external-dir').exists()
    expected = "Ignoring symlink because targets outside the project: 'external-dir'"
    assert expected in [rec.message for rec in caplog.records]
Beispiel #9
0
def test_build_generics_ignored_dir(tmp_path, caplog):
    """Don't include ignored dir."""
    caplog.set_level(logging.DEBUG)
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    # create two files (and the needed entrypoint)
    dir1 = tmp_path / 'dir1'
    dir1.mkdir()
    dir2 = tmp_path / 'dir2'
    dir2.mkdir()
    entrypoint = tmp_path / 'crazycharm.py'
    entrypoint.touch()

    builder = Builder({
        'from': tmp_path,
        'entrypoint': entrypoint,
        'requirement': [],
    })

    # set it up to ignore dir 2 and make it work
    builder.ignore_rules.extend_patterns(['dir2'])
    builder.handle_generic_paths()

    assert (build_dir / 'dir1').exists()
    assert not (build_dir / 'dir2').exists()

    expected = "Ignoring directory because of rules: 'dir2'"
    assert expected in [rec.message for rec in caplog.records]
Beispiel #10
0
def test_build_generics_different_filetype(tmp_path, caplog, monkeypatch):
    """Ignores whatever is not a regular file, symlink or dir."""
    caplog.set_level(logging.DEBUG)

    # change into the tmp path and do everything locally, because otherwise the socket path
    # will be too long for mac os
    monkeypatch.chdir(tmp_path)

    build_dir = pathlib.Path(BUILD_DIRNAME)
    build_dir.mkdir()
    entrypoint = pathlib.Path('crazycharm.py')
    entrypoint.touch()

    # create a socket
    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    sock.bind('test-socket')

    builder = Builder({
        'from': tmp_path,
        'entrypoint': tmp_path / entrypoint,
        'requirement': [],
    })
    builder.handle_generic_paths()

    assert not (build_dir / 'test-socket').exists()
    expected = "Ignoring file because of type: 'test-socket'"
    assert expected in [rec.message for rec in caplog.records]
Beispiel #11
0
def test_build_generics_simple_files(tmp_path):
    """Check transferred metadata and simple entrypoint, also return proper linked entrypoint."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    metadata = tmp_path / CHARM_METADATA
    metadata.touch()
    entrypoint = tmp_path / 'crazycharm.py'
    entrypoint.touch()

    builder = Builder({
        'from': tmp_path,
        'entrypoint': entrypoint,
        'requirement': [],
    })
    linked_entrypoint = builder.handle_generic_paths()

    # check files are there, are files, and are really hard links (so no
    # check for permissions needed)
    built_metadata = build_dir / CHARM_METADATA
    assert built_metadata.is_file()
    assert built_metadata.stat().st_ino == metadata.stat().st_ino

    built_entrypoint = build_dir / 'crazycharm.py'
    assert built_entrypoint.is_file()
    assert built_entrypoint.stat().st_ino == entrypoint.stat().st_ino

    assert linked_entrypoint == built_entrypoint
Beispiel #12
0
def test_build_generics_simple_dir(tmp_path):
    """Check transferred any directory, with proper permissions."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()
    entrypoint = tmp_path / 'crazycharm.py'
    entrypoint.touch()

    somedir = tmp_path / 'somedir'
    somedir.mkdir(mode=0o700)

    builder = Builder({
        'from': tmp_path,
        'entrypoint': entrypoint,
        'requirement': [],
    })
    builder.handle_generic_paths()

    built_dir = build_dir / 'somedir'
    assert built_dir.is_dir()
    assert built_dir.stat().st_mode & 0xFFF == 0o700
Beispiel #13
0
def test_build_generics_symlink_file(tmp_path):
    """Respects a symlinked file."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    entrypoint = tmp_path / 'crazycharm.py'
    entrypoint.touch()
    the_symlink = tmp_path / 'somehook.py'
    the_symlink.symlink_to(entrypoint)

    builder = Builder({
        'from': tmp_path,
        'entrypoint': entrypoint,
        'requirement': [],
    })
    builder.handle_generic_paths()

    built_symlink = build_dir / 'somehook.py'
    assert built_symlink.is_symlink()
    assert built_symlink.resolve() == build_dir / 'crazycharm.py'
    real_link = os.readlink(str(built_symlink))
    assert real_link == 'crazycharm.py'
Beispiel #14
0
def test_build_generics_simple_dir(tmp_path, config):
    """Check transferred any directory, with proper permissions."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()
    entrypoint = tmp_path / "crazycharm.py"
    entrypoint.touch()

    somedir = tmp_path / "somedir"
    somedir.mkdir(mode=0o700)

    builder = Builder(
        {
            "from": tmp_path,
            "entrypoint": entrypoint,
            "requirement": [],
        },
        config,
    )
    builder.handle_generic_paths()

    built_dir = build_dir / "somedir"
    assert built_dir.is_dir()
    assert built_dir.stat().st_mode & 0xFFF == 0o700
Beispiel #15
0
def _test_build_generics_tree(tmp_path, caplog, config, *, expect_hardlinks):
    caplog.set_level(logging.DEBUG)

    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    # create this structure:
    # ├─ crazycharm.py  (entrypoint)
    # ├─ file1.txt
    # ├─ dir1
    # │  └─ dir3  (ignored!)
    # └─ dir2
    #    ├─ file2.txt
    #    ├─ file3.txt  (ignored!)
    #    ├─ dir4  (ignored!)
    #    │   └─ file4.txt
    #    └─ dir5
    entrypoint = tmp_path / "crazycharm.py"
    entrypoint.touch()
    file1 = tmp_path / "file1.txt"
    file1.touch()
    dir1 = tmp_path / "dir1"
    dir1.mkdir()
    dir3 = dir1 / "dir3"
    dir3.mkdir()
    dir2 = tmp_path / "dir2"
    dir2.mkdir()
    file2 = dir2 / "file2.txt"
    file2.touch()
    file3 = dir2 / "file3.txt"
    file3.touch()
    dir4 = dir2 / "dir4"
    dir4.mkdir()
    file4 = dir4 / "file4.txt"
    file4.touch()
    dir5 = dir2 / "dir5"
    dir5.mkdir()

    builder = Builder(
        {
            "from": tmp_path,
            "entrypoint": entrypoint,
            "requirement": [],
        },
        config,
    )

    # set it up to ignore some stuff and make it work
    builder.ignore_rules.extend_patterns([
        "dir1/dir3",
        "dir2/file3.txt",
        "dir2/dir4",
    ])
    builder.handle_generic_paths()

    assert (build_dir / "crazycharm.py").exists()
    assert (build_dir / "file1.txt").exists()
    assert (build_dir / "dir1").exists()
    assert not (build_dir / "dir1" / "dir3").exists()
    assert (build_dir / "dir2").exists()
    assert (build_dir / "dir2" / "file2.txt").exists()
    assert not (build_dir / "dir2" / "file3.txt").exists()
    assert not (build_dir / "dir2" / "dir4").exists()
    assert (build_dir / "dir2" / "dir5").exists()

    for (p1, p2) in [
        (build_dir / "crazycharm.py", entrypoint),
        (build_dir / "file1.txt", file1),
        (build_dir / "dir2" / "file2.txt", file2),
    ]:
        if expect_hardlinks:
            # they're hard links
            assert p1.samefile(p2)
        else:
            # they're *not* hard links
            assert not p1.samefile(p2)
            # but they're essentially the same
            assert filecmp.cmp(str(p1), str(p2), shallow=False)
            assert p1.stat().st_mode == p2.stat().st_mode
            assert p1.stat().st_size == p2.stat().st_size
            assert p1.stat().st_atime == pytest.approx(p2.stat().st_atime)
            assert p1.stat().st_mtime == pytest.approx(p2.stat().st_mtime)
Beispiel #16
0
def _test_build_generics_tree(tmp_path, caplog, *, expect_hardlinks):
    caplog.set_level(logging.DEBUG)

    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    # create this structure:
    # ├─ crazycharm.py  (entrypoint)
    # ├─ file1.txt
    # ├─ dir1
    # │  └─ dir3  (ignored!)
    # └─ dir2
    #    ├─ file2.txt
    #    ├─ file3.txt  (ignored!)
    #    ├─ dir4  (ignored!)
    #    │   └─ file4.txt
    #    └─ dir5
    entrypoint = tmp_path / 'crazycharm.py'
    entrypoint.touch()
    file1 = tmp_path / 'file1.txt'
    file1.touch()
    dir1 = tmp_path / 'dir1'
    dir1.mkdir()
    dir3 = dir1 / 'dir3'
    dir3.mkdir()
    dir2 = tmp_path / 'dir2'
    dir2.mkdir()
    file2 = dir2 / 'file2.txt'
    file2.touch()
    file3 = dir2 / 'file3.txt'
    file3.touch()
    dir4 = dir2 / 'dir4'
    dir4.mkdir()
    file4 = dir4 / 'file4.txt'
    file4.touch()
    dir5 = dir2 / 'dir5'
    dir5.mkdir()

    builder = Builder({
        'from': tmp_path,
        'entrypoint': entrypoint,
        'requirement': [],
    })

    # set it up to ignore some stuff and make it work
    builder.ignore_rules.extend_patterns([
        'dir1/dir3',
        'dir2/file3.txt',
        'dir2/dir4',
    ])
    builder.handle_generic_paths()

    assert (build_dir / 'crazycharm.py').exists()
    assert (build_dir / 'file1.txt').exists()
    assert (build_dir / 'dir1').exists()
    assert not (build_dir / 'dir1' / 'dir3').exists()
    assert (build_dir / 'dir2').exists()
    assert (build_dir / 'dir2' / 'file2.txt').exists()
    assert not (build_dir / 'dir2' / 'file3.txt').exists()
    assert not (build_dir / 'dir2' / 'dir4').exists()
    assert (build_dir / 'dir2' / 'dir5').exists()

    for (p1, p2) in [
        (build_dir / 'crazycharm.py', entrypoint),
        (build_dir / 'file1.txt', file1),
        (build_dir / 'dir2' / 'file2.txt', file2),
    ]:
        if expect_hardlinks:
            # they're hard links
            assert p1.samefile(p2)
        else:
            # they're *not* hard links
            assert not p1.samefile(p2)
            # but they're essentially the same
            assert filecmp.cmp(str(p1), str(p2), shallow=False)
            assert p1.stat().st_mode == p2.stat().st_mode
            assert p1.stat().st_size == p2.stat().st_size
            assert p1.stat().st_atime == pytest.approx(p2.stat().st_atime)
            assert p1.stat().st_mtime == pytest.approx(p2.stat().st_mtime)
Beispiel #17
0
def test_build_generics_tree(tmp_path, caplog):
    """Manages ok a deep tree, including internal ignores."""
    caplog.set_level(logging.DEBUG)

    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    # create this structure:
    # ├─ crazycharm.py  (entrypoint)
    # ├─ file1.txt
    # ├─ dir1
    # │  └─ dir3  (ignored!)
    # └─ dir2
    #    ├─ file2.txt
    #    ├─ file3.txt  (ignored!)
    #    ├─ dir4  (ignored!)
    #    │   └─ file4.txt
    #    └─ dir5
    entrypoint = tmp_path / 'crazycharm.py'
    entrypoint.touch()
    file1 = tmp_path / 'file1.txt'
    file1.touch()
    dir1 = tmp_path / 'dir1'
    dir1.mkdir()
    dir3 = dir1 / 'dir3'
    dir3.mkdir()
    dir2 = tmp_path / 'dir2'
    dir2.mkdir()
    file2 = dir2 / 'file2.txt'
    file2.touch()
    file3 = dir2 / 'file3.txt'
    file3.touch()
    dir4 = dir2 / 'dir4'
    dir4.mkdir()
    file4 = dir4 / 'file4.txt'
    file4.touch()
    dir5 = dir2 / 'dir5'
    dir5.mkdir()

    builder = Builder({
        'from': tmp_path,
        'entrypoint': entrypoint,
        'requirement': [],
    })

    # set it up to ignore some stuff and make it work
    builder.ignore_rules.extend_patterns([
        'dir1/dir3',
        'dir2/file3.txt',
        'dir2/dir4',
    ])
    builder.handle_generic_paths()

    assert (build_dir / 'crazycharm.py').exists()
    assert (build_dir / 'file1.txt').exists()
    assert (build_dir / 'dir1').exists()
    assert not (build_dir / 'dir1' / 'dir3').exists()
    assert (build_dir / 'dir2').exists()
    assert (build_dir / 'dir2' / 'file2.txt').exists()
    assert not (build_dir / 'dir2' / 'file3.txt').exists()
    assert not (build_dir / 'dir2' / 'dir4').exists()
    assert (build_dir / 'dir2' / 'dir5').exists()