コード例 #1
0
ファイル: test_pak.py プロジェクト: rndtrash/vgio
    def test_empty_pak_file(self):
        with pak.PakFile(self.buff, 'w'):
            pass

        self.buff.seek(0)

        with pak.PakFile(self.buff, 'r') as pak_file:
            self.assertEqual(len(pak_file.namelist()), 0,
                             'Pak file should have not entries')
            self.assertEqual(
                pak_file.end_of_data, 12,
                'Directory should start immediately after header')
コード例 #2
0
ファイル: test_pak.py プロジェクト: rndtrash/vgio
    def test_zero_byte_file(self):
        with pak.PakFile(self.buff, 'w') as pak_file:
            pak_file.writestr('zero.txt', b'')

        self.buff.seek(0)

        with pak.PakFile(self.buff) as pak_file:
            info = pak_file.getinfo('zero.txt')
            self.assertEqual(info.file_offset, 12,
                             'File Info offset of test file should be 12')
            self.assertEqual(info.file_size, 0,
                             'File Info size of test file should be 0')

            data = pak_file.read('zero.txt')
            self.assertEqual(len(data), 0,
                             'Length of bytes read should be zero.')
コード例 #3
0
ファイル: test_pak.py プロジェクト: rndtrash/vgio
    def test_context_manager(self):
        with pak.PakFile('./test_data/test.pak', 'r') as pak_file:
            self.assertFalse(pak_file.fp.closed, 'File should be open')
            self.assertEqual(pak_file.mode, 'r', 'File mode should be \'r\'')
            fp = pak_file.fp
            pak_file._did_modify = False

        self.assertTrue(fp.closed, 'File should be closed')
        self.assertIsNone(pak_file.fp, 'File pointer should be cleaned up')
コード例 #4
0
ファイル: test_pak.py プロジェクト: rndtrash/vgio
    def test_write_string(self):
        p0 = pak.PakFile(self.buff, 'w')
        p0.writestr('test.cfg', b'bind ALT +strafe')
        p0.writestr(pak.PakInfo('docs/readme.txt'), 'test')
        p0.close()

        self.buff.seek(0)

        p1 = pak.PakFile(self.buff, 'r')

        self.assertTrue('test.cfg' in p1.namelist(),
                        'Cfg file should be in Pak file')
        self.assertTrue('docs/readme.txt' in p1.namelist(),
                        'Txt file should be in Pak file')
        self.assertEqual(p1.read('test.cfg'), b'bind ALT +strafe',
                         'Cfg file content should not change')
        self.assertEqual(
            p1.read('docs/readme.txt').decode('ascii'), 'test',
            'Txt file conent should not change')

        p1.close()
        self.buff.close()
コード例 #5
0
ファイル: test_pak.py プロジェクト: rndtrash/vgio
    def test_append(self):
        with open('./test_data/test.pak', 'rb') as f:
            self.buff = io.BytesIO(f.read())

        pak_file = pak.PakFile(self.buff, 'a')
        pak_file.write('./test_data/test.bsp')
        pak_file.close()

        self.buff.seek(0)

        pak_file = pak.PakFile(self.buff, 'r')
        self.assertTrue('./test_data/test.bsp' in pak_file.namelist(),
                        'Appended file should be in Pak file')
        self.assertEqual(len(pak_file.infolist()), 3,
                         'Pak file should contain exactly three entries.')

        fp = pak_file.fp
        pak_file.close()

        self.assertFalse(self.buff.closed,
                         'Pak file should not close passed file-like object')

        self.buff.close()
コード例 #6
0
ファイル: test_pak.py プロジェクト: rndtrash/vgio
    def test_write(self):
        pak_file = pak.PakFile(self.buff, 'w')
        self.assertFalse(pak_file.fp.closed, 'File should be open')

        pak_file.write('./test_data/test.mdl')
        pak_file.write('./test_data/test.bsp', './progs/test.bsp')

        self.assertTrue('./test_data/test.mdl' in pak_file.namelist(),
                        'Mdl file should be in Pak file')
        self.assertTrue('./progs/test.bsp' in pak_file.namelist(),
                        'Bsp file should be in Pak file')

        fp = pak_file.fp
        pak_file.close()
        self.assertFalse(fp.closed, 'File should be open')
        self.assertIsNone(pak_file.fp, 'File pointer should be cleaned up')

        self.buff.close()
コード例 #7
0
ファイル: test_pak.py プロジェクト: rndtrash/vgio
    def test_read(self):
        pak_file = pak.PakFile('./test_data/test.pak', 'r')
        self.assertFalse(pak_file.fp.closed, 'File should be open')
        self.assertEqual(len(pak_file.infolist()), 2,
                         'Pak file should contain exactly two entries.')

        info = pak_file.getinfo('./test_data/test.mdl')
        self.assertIsNotNone(info, 'FileInfo should not be None')
        self.assertEqual(info.filename, './test_data/test.mdl',
                         'FileInfo names should match')
        self.assertEqual(info.file_size, 4724,
                         'FileInfo size of test file should be 4724')
        self.assertEqual(info.file_offset, 12,
                         'FileInfo offset of test file should be 12')

        file = pak_file.open('./test_data/test.mdl')
        self.assertIsNotNone(file, 'File should not be None')
        file.close()

        fp = pak_file.fp
        pak_file.close()
        self.assertTrue(fp.closed, 'File should be closed')
        self.assertIsNone(pak_file.fp, 'File pointer should be cleaned up')
コード例 #8
0
def main():
    parser = Parser(
        prog='pak',
        description='Default action is to add or replace pak files '
                    'entries from list.\nIf list is omitted, pak will '
                    'use stdin.',
        epilog='example: pak tex.pak image.png => adds image.png to tex.pak'
    )

    parser.add_argument(
        'file',
        metavar='file.pak',
        action=ResolvePathAction,
        help='pak file to create'
    )

    parser.add_argument(
        'list',
        nargs='*',
        action=ResolvePathAction,
        default=read_from_stdin()
    )

    parser.add_argument(
        '-q',
        dest='quiet',
        action='store_true',
        help='quiet mode'
    )

    parser.add_argument(
        '-v', '--version',
        dest='version',
        action='version',
        help=argparse.SUPPRESS,
        version='{} version {}'.format(parser.prog, qcli.__version__)
    )

    args = parser.parse_args()

    if not args.list:
        parser.error('the following arguments are required: list')

    dir = os.path.dirname(args.file) or '.'
    if not os.path.exists(dir):
        os.makedirs(dir)

    filemode = 'a'
    if not os.path.isfile(args.file):
        filemode = 'w'

    with pak.PakFile(args.file, filemode) as pak_file:
        if not args.quiet:
            print(f'Archive: {os.path.basename(args.file)}')

        # Process input files
        for file in args.list:
            # Walk directories
            if os.path.isdir(file):
                for root, dirs, files in os.walk(file):
                    for name in [f for f in files if not f.startswith('.')]:
                        fullpath = os.path.join(root, name)
                        relpath = os.path.relpath(fullpath, os.getcwd())

                        if not args.quiet:
                            print(f'  adding: {relpath}')

                        pak_file.write(relpath)

            else:
                relpath = os.path.relpath(file, os.getcwd())

                if not args.quiet:
                    print(f'  adding: {relpath}')

                pak_file.write(relpath)

    sys.exit(0)
コード例 #9
0
ファイル: cli.py プロジェクト: Sickelmo83/quake-cli-tools
def main():
    parser = Parser(
        prog='unpak',
        description='Default action is to extract files to xdir.',
        epilog='example: unpak PAK0.PAK -d ./out => extract all files to ./out'
    )

    parser.add_argument(
        'file',
        metavar='file.pak',
        action=ResolvePathAction
    )

    parser.add_argument(
        '-l', '--list',
        action='store_true',
        help='list files'
    )

    parser.add_argument(
        '-d',
        metavar='xdir',
        dest='dest',
        default=os.getcwd(),
        action=ResolvePathAction,
        help='extract files into xdir'
    )

    parser.add_argument(
        '-q',
        dest='quiet',
        action='store_true',
        help='quiet mode'
    )

    parser.add_argument(
        '-v', '--version',
        dest='version',
        action='version',
        help=argparse.SUPPRESS,
        version=f'{parser.prog} version {qcli.unpak.__version__}'
    )

    args = parser.parse_args()

    if not pak.is_pakfile(args.file):
        print(f'{parser.prog}: cannot find or open {args.file}', file=sys.stderr)
        sys.exit(1)

    if args.list:
        with pak.PakFile(args.file) as pak_file:
            info_list = sorted(pak_file.infolist(), key=lambda i: i.filename)

            headers = ['Length', 'Name']
            table = [[i.file_size, i.filename] for i in info_list]
            length = sum([i.file_size for i in info_list])
            count = len(info_list)
            table.append([length, f'{count} file{"s" if count == 1 else ""}'])

            separator = []
            for i in range(len(headers)):
                t = max(len(str(length)), len(headers[i]) + 2)
                separator.append('-' * t)

            table.insert(-1, separator)

            print(f'Archive: {os.path.basename(args.file)}')
            print(tabulate(table, headers=headers))

            sys.exit(0)

    with pak.PakFile(args.file) as pak_file:
        info_list = pak_file.infolist()
        for item in sorted(info_list, key=lambda i: i.filename):
            filename = item.filename
            fullpath = os.path.join(args.dest, filename)

            if not args.quiet:
                print(f' extracting: {fullpath}')

            try:
                pak_file.extract(filename, args.dest)

            except:
                print(f'{parser.prog}: error: {sys.exc_info()[0]}', file=sys.stderr)

    sys.exit(0)
コード例 #10
0
ファイル: cli.py プロジェクト: Sickelmo83/quake-cli-tools
def main():
    # Fix for frozen packages
    def handleSIGINT(signum, frame):
        raise KeyboardInterrupt

    signal.signal(signal.SIGINT, handleSIGINT)

    parser = Parser(
        prog='qmount',
        description=
        'Default action is to mount the given pak file as a logical volume.',
        epilog=
        'example: qmount TEST.PAK => mounts TEST.PAK as a logical volume.')

    parser.add_argument('file',
                        metavar='file.pak',
                        action=ResolvePathAction,
                        help='pak file to mount')

    parser.add_argument('-f',
                        '--file-browser',
                        dest='open_file_browser',
                        action='store_true',
                        help='opens a file browser once mounted')

    parser.add_argument('--verbose',
                        dest='verbose',
                        action='store_true',
                        help='verbose mode')

    parser.add_argument(
        '-v',
        '--version',
        dest='version',
        action='version',
        help=argparse.SUPPRESS,
        version=f'{parser.prog} version {qcli.qmount.__version__}')

    args = parser.parse_args()

    dir = os.path.dirname(args.file) or '.'
    if not os.path.exists(dir):
        os.makedirs(dir)

    archive_name = os.path.basename(args.file)
    context = {'dirty': False}
    files = {}

    # If the pak file exists put the contents into the file dictionary
    if os.path.exists(args.file):
        with pak.PakFile(args.file) as pak_file:
            for info in pak_file.infolist():
                name = info.filename
                files[name] = pak_file.read(name)

    else:
        context['dirty'] = True

    temp_directory = platforms.temp_volume(archive_name)

    # Copy pak file contents into the temporary directory
    for filename in files:
        abs_path = os.path.join(temp_directory, filename)
        dir = os.path.dirname(abs_path)

        if not os.path.exists(dir):
            os.makedirs(dir)

        with open(abs_path, 'wb') as out_file:
            out_file.write(files[filename])

    # Open a native file browser
    if args.open_file_browser:
        platforms.open_file_browser(temp_directory)

    # Start file watching
    observer = Observer()
    handler = TempPakFileHandler(
        context,
        temp_directory,
        files,
        args.verbose,
        ignore_patterns=['*/.DS_Store', '*/Thumbs.db'],
        ignore_directories=True)
    observer.schedule(handler, path=temp_directory, recursive=True)

    print('Press Ctrl+C to save and quit')

    observer.start()

    # Wait for user to terminate
    try:
        while True:
            time.sleep(1)

            # Detect the deletion of the watched directory.
            if not os.path.exists(temp_directory):
                raise KeyboardInterrupt

    except KeyboardInterrupt:
        print()
        try:
            observer.stop()

        except:
            """This is a temporary workaround. Watchdog will raise an exception
            if the watched media is ejected."""

    observer.join()

    # Write out updated files
    if context['dirty']:
        print(f'Updating changes to {archive_name}')

        with pak.PakFile(args.file, 'w') as pak_file:
            for filename in files:
                pak_file.writestr(filename, files[filename])

    else:
        print(f'No changes detected to {archive_name}')

    # Clean up temp directory
    platforms.unmount_temp_volume(temp_directory)

    sys.exit(0)