Ejemplo n.º 1
0
def manual():
    ''' Run a manual update '''

    if is_running():
        message('Updater is running, please wait.')
        return

    if xbmcgui.Dialog().yesno(__addonname__,
                              "Would you like to do an online update?"):
        new_version, update_url, update_md5 = new_update()
        xbmc.log('BOXiK Manual Service: New update check - %s' % new_version)
        if not new_version:
            dp = xbmcgui.Dialog()
            dp.ok(__addonname__,
                  "Your BOXiK version %s is up to date." % get_local_version())
        else:
            start(new_version, update_url, update_md5)
    else:
        if xbmcgui.Dialog().yesno(__addonname__, \
                        "Do you have the update.zip on USB thumb?", \
                        "Selecting 'Yes' will backup, reboot and start the update."):
            try:
                backup = Backup(which_usb(), get_local_version())
                backup.run()
                reboot()
            except:
                dp.ok(__addonname__, \
                    "Backup could not be completed. Please use a 16GB USB or larger.",
                    " ", \
                    "Update manually from Settings > Update")
Ejemplo n.º 2
0
def createBackup(backups):
	print(backups)
	backup = Backup()
	backup.getUserInput()
	backups['backups'].append(json.loads(backup.returnJson()))
	with open("presets.json", "w") as jsonWriter:
		jsonWriter.write(json.dumps(backups, sort_keys = True, indent = 4))
Ejemplo n.º 3
0
def createBackup(backups):
    print(backups)
    backup = Backup()
    backup.getUserInput()
    backups['backups'].append(json.loads(backup.returnJson()))
    with open("presets.json", "w") as jsonWriter:
        jsonWriter.write(json.dumps(backups, sort_keys=True, indent=4))
Ejemplo n.º 4
0
    def test_invoke(self, mock_send_errors, mock_error, mock_configure,
                    mock_traceback):
        for thrown in [None, BaseException, Exception, IOError]:
            trace = 'trace-%s' % uid()

            def invoke():
                mock_send_errors.assert_not_called()
                if thrown:
                    raise thrown

            def format_exc():
                mock_send_errors.assert_not_called()
                return trace

            with self.subTest(thrown=thrown):
                for m in (mock_send_errors, mock_error, mock_configure,
                          mock_traceback):
                    m.reset_mock()
                subj = Backup()
                method = Mock()
                method.side_effect = invoke
                mock_configure.return_value = method
                mock_traceback.format_exc.side_effect = format_exc

                subj.invoke()

                if thrown:
                    mock_error.assert_called_once_with(subj, "%s", trace)
                else:
                    mock_error.assert_not_called()
                mock_send_errors.assert_called_once_with(subj)
async def main(args):
    datastore = []

    # Build blobs
    with args.file as f:
        while True:
            blob = f.read(args.blob_size)
            if not blob:
                break
            # This loop is used to not break word in half
            while not str.isspace(blob[-1]):
                ch = f.read(1)
                if not ch:
                    break

                blob += ch

            logger.debug('Blob: %s\n\n', blob)
            datastore.append(blob)

    #############################################

    # Create Coordinator
    coordinator = Coordinator(datastore)
    failCounter = 0

    try:  # Its a coordinator!
        loop = asyncio.get_event_loop()
        server = await loop.create_server(lambda: EchoProtocol(coordinator),
                                          "127.0.0.1", args.port)
        logger.info("Coordinator created!")
        await server.serve_forever()

    except:  # Its a backup!
        port = args.port + 1  # Backup port, used to communicate with workers
        while True:
            try:
                backup_coord = Backup("127.0.0.1", args.port, datastore,
                                      "127.0.0.1", port)
                failCounter = 0
                break
            except:
                failCounter += 1
                port += 1
                if failCounter >= 10:
                    break
                pass

        logger.info("Backup created!")
        backup_coord.start_backup()

        # When the coordinator dies, backup becomes the new coordinator by launching a server
        coordinator = Coordinator(datastore, backup_coord.indexDatastore,
                                  backup_coord.maps)

        loop = asyncio.get_event_loop()
        server = await loop.create_server(lambda: EchoProtocol(coordinator),
                                          "127.0.0.1", args.port)
        logger.info("Coordinator created!")
        await server.serve_forever()
Ejemplo n.º 6
0
def manual():
    ''' Run a manual update '''
    
    if is_running():
        message('Updater is running, please wait.')
        return

    if xbmcgui.Dialog().yesno(__addonname__, "Would you like to do an online update?"):
        new_version, update_url, update_md5 = new_update()
        xbmc.log('BOXiK Manual Service: New update check - %s' % new_version)
        if not new_version:
            dp = xbmcgui.Dialog()
            dp.ok(__addonname__, "Your BOXiK version %s is up to date." % get_local_version())
        else:
            start(new_version, update_url, update_md5)
    else:
        if xbmcgui.Dialog().yesno(__addonname__, \
                        "Do you have the update.zip on USB thumb?", \
                        "Selecting 'Yes' will backup, reboot and start the update."):
            try:
                backup = Backup( which_usb() , get_local_version() )
                backup.run()
                reboot()
            except:    
                dp.ok(__addonname__, \
                    "Backup could not be completed. Please use a 16GB USB or larger.", 
                    " ", \
                    "Update manually from Settings > Update")
Ejemplo n.º 7
0
    def test_read_md5_with_times(self, mock_read_dir_md5_with_time,
                                 mock_load_md5_with_times, mock_os):
        subj = Backup()
        directory = 'dir-%s' % uid()
        log_md5_with_time = uid()
        mock_load_md5_with_times.return_value = log_md5_with_time
        walk = [('root-%s' % uid(), 'dirs-%s' % uid(),
                 ['file-%s' % uid() for _ in uid_range()])
                for _ in uid_range()]
        mock_os.walk.return_value = walk
        dir_md5_with_time = [{
            'key-%s' % uid(): 'value-%s' % uid()
            for _ in range(0, 3 + uid(5))
        } for _ in range(0, len(walk))]
        mock_read_dir_md5_with_time.side_effect = dir_md5_with_time
        expected = {}
        for i in dir_md5_with_time:
            expected.update(i)
        expected_calls = [
            call(directory, root, set(files), log_md5_with_time)
            for root, dirs, files in walk
        ]

        self.assertEqual(subj.read_md5_with_times(directory), expected)

        mock_load_md5_with_times.assert_called_once_with(directory + '/.log')
        mock_os.walk.assert_called_once_with(directory)
        mock_read_dir_md5_with_time.assert_has_calls(expected_calls)
Ejemplo n.º 8
0
    def test_configure(self, mock_command, mock_read_config, mock_log,
                       mock_sys):
        for log_level in (None, logging.DEBUG, logging.INFO, logging.ERROR):
            for log_format in (None, str(uid())):
                with self.subTest(log_level=log_level, log_format=log_format):
                    subj = Backup()
                    mock_log.reset_mock()
                    mock_sys.reset_mock()
                    config = {}
                    command = uid()
                    mock_command.return_value = command
                    mock_read_config.return_value = config
                    if log_format is not None:
                        config['log_format'] = log_format
                    if log_level is not None:
                        config['log_level'] = logging.getLevelName(log_level)
                    mock_log.getLevelName.side_effect = logging.getLevelName

                    self.assertEqual(subj.configure(), command)

                    mock_log.basicConfig.assert_called_once_with(
                        level=mock_log.INFO
                        if log_level is None else log_level,
                        stream=mock_sys.stdout,
                        format="%(message)s"
                        if log_format is None else log_format)
                    mock_sys.setrecursionlimit.assert_called_once_with(100)
Ejemplo n.º 9
0
def initializeStorage(trezor, pwMap, settings):
	"""
	Initialize new encrypted password file, ask for master passphrase.
	
	Initialize RSA keypair for backup, encrypt private RSA key using
	backup passphrase and Trezor's cipher-key-value system.
	
	Makes sure a session is created on Trezor so that the passphrase
	will be cached until disconnect.
	
	@param trezor: Trezor client
	@param pwMap: PasswordMap where to put encrypted backupKeys
	@param settings: Settings object to store password database location
	"""
	dialog = InitializeDialog()
	if not dialog.exec_():
		sys.exit(4)
		
	masterPassphrase = q2s(dialog.pw1())
	
	trezor.prefillPassphrase(masterPassphrase)
	backup = Backup(trezor)
	backup.generate()
	pwMap.backupKey = backup
	settings.dbFilename = q2s(dialog.pwFile())
	settings.store()
Ejemplo n.º 10
0
def test_no_params():
    sys.argv = ['backup']
    bck = Backup()
    with pytest.raises(SystemExit) as pytest_wrapped_e:
        bck.main()
    assert pytest_wrapped_e.type == SystemExit
    assert pytest_wrapped_e.value.code == 2
Ejemplo n.º 11
0
    def test_command(self, mock_arg, mock_svn_separator, mock_time_separator,
                     mock_socket):
        subj = Backup()
        for command, method, has_src_dirs, has_dst_dirs in (
            ('full', subj.full, True, True), ('dump', subj.dump, True, True),
            ('clone', subj.clone, False, True), ('git', subj.git, True, False),
            ('checks', subj.checks, False,
             True), ('any', subj.help, False, False), (str(uid()), subj.help,
                                                       False, False)):
            for empty in (False, True):
                with self.subTest(command=command, empty=empty):
                    mock_time_separator.reset_mock()
                    mock_svn_separator.reset_mock()
                    subj.commands = {}
                    src_dirs = ['src%s-%s' % (i, uid()) for i in uid_range()]
                    dest_dirs = ['dst%s-%s' % (i, uid()) for i in uid_range()]
                    num = uid()
                    command_line = [command]
                    if has_src_dirs:
                        command_line.append(','.join(src_dirs))
                    if has_dst_dirs:
                        command_line.append(','.join(dest_dirs))
                    command_line.append(str(num))
                    mock_arg.side_effect = command_line
                    hostname = 'hostname%s' % uid()
                    smtp_host = 'smtp_host%s' % uid()
                    subj.config = {} if empty else {
                        'hostname': hostname,
                        'smtp_host': smtp_host
                    }
                    mock_socket.gethostname.return_value = hostname if empty else None
                    commands = {}
                    if not has_dst_dirs:
                        dest_dirs = []
                    else:
                        for dst in dest_dirs:
                            commands[dst] = []

                    result = subj.command()

                    self.assertEqual(result, method)
                    self.assertEqual(subj.hostname, hostname)
                    self.assertEqual(subj.smtp_host,
                                     None if empty else smtp_host)
                    self.assertTrue(
                        isinstance(subj.time_separator, TimeSeparator))
                    mock_time_separator.assert_called_once_with(
                        num
                        if command == 'full' or command == 'clone' else None)
                    mock_svn_separator.assert_called_once_with()
                    self.assertEqual(subj.separators[0], subj.time_separator)
                    self.assertTrue(
                        isinstance(subj.separators[1], SvnSeparator))
                    self.assertEqual(len(subj.separators), 2)
                    self.assertEqual(subj.src_dirs,
                                     src_dirs if has_src_dirs else [''])
                    self.assertEqual(subj.dest_dirs,
                                     dest_dirs if has_dst_dirs else [])
                    self.assertEqual(subj.commands, commands)
Ejemplo n.º 12
0
    def test_recovery_for_each_dest(self):
        subj = Backup()
        key = 'key-%s'
        # TODO возвращать результат. Перенести конструирование recovery_key_search внутрь recovery_for_each_dest

        subj.recovery_for_each_dest(key)

        self.fail("TODO")
Ejemplo n.º 13
0
def test_multi_dir_backup(tmpdir):
    tmp_dir = os.path.join(str(tmpdir), '2')  # Needed for Python 3.5 and older
    os.mkdir(tmp_dir)
    print('dir {}'.format(tmp_dir))
    source_dir = os.path.join(tmp_dir, 'src')
    target_dir = os.path.join(tmp_dir, 'target')
    config_file = os.path.join(tmp_dir, 'cfg.json')
    os.mkdir(source_dir)
    os.mkdir(target_dir)

    src_dir_1 = os.path.join(source_dir, 'someplace')
    trg_dir_1 = 'some_backup'
    os.mkdir(src_dir_1)
    with open(config_file, 'w') as fh:
        json.dump(
            {
                'pairs': [{
                    "src": src_dir_1,
                    "trg": trg_dir_1,
                }],
                'target': target_dir,
            }, fh)

    # pretend the git repository
    os.mkdir(os.path.join(target_dir, '.git'))
    with open(os.path.join(target_dir, '.git', 'HEAD'), 'w') as fh:
        fh.write('head')

    sys.argv = ['backup', '--config', config_file]

    with open(os.path.join(src_dir_1, 'a.txt'), 'w') as fh:
        fh.write('hello')
    os.mkdir(os.path.join(src_dir_1, 'notes'))
    os.mkdir(os.path.join(src_dir_1, 'notes', 'personal'))
    with open(os.path.join(src_dir_1, 'notes', 'personal', 'diary.txt'),
              'w') as fh:
        fh.write('First entry')
    with open(os.path.join(src_dir_1, 'notes', 'personal', 'todo.txt'),
              'w') as fh:
        fh.write('TODO list')

    os.mkdir(os.path.join(src_dir_1, 'clients'))
    with open(os.path.join(src_dir_1, 'clients', 'contacts.csv'), 'w') as fh:
        fh.write('Name,email,phone')

    bck = Backup()
    bck.main()
    assert set(os.listdir(target_dir)) == set(['.git', 'some_backup'])
    assert set(os.listdir(os.path.join(target_dir, 'some_backup'))) == set(
        ['a.txt', 'notes', 'clients'])
    assert set(os.listdir(os.path.join(target_dir, 'some_backup',
                                       'notes'))) == set(['personal'])
    assert set(
        os.listdir(os.path.join(target_dir, 'some_backup', 'notes',
                                'personal'))) == set(['diary.txt', 'todo.txt'])
    assert set(os.listdir(os.path.join(target_dir, 'some_backup',
                                       'clients'))) == set(['contacts.csv'])
Ejemplo n.º 14
0
    def test_lazy_write_md5_to_md5dirs(self, mock_lazy_write_md5):
        subj = Backup()
        md5dirs = ['dir-%s' % uid() for _ in uid_range()]
        key = 'key-%s' % uid()
        md5files = 'md5files-%s' % uid()
        expected_calls = [call(subj, d, key, md5files) for d in md5dirs]

        subj.lazy_write_md5_to_md5dirs(md5dirs, key, md5files)

        mock_lazy_write_md5.assert_has_calls(expected_calls)
Ejemplo n.º 15
0
    def do_backup(self, host, logger):
        host_backup = Backup(host, logger=logger)

        backup_lock.acquire()
        try:
            host_backup.setup()
        finally:
            backup_lock.release()

        return host_backup.do_backup()
Ejemplo n.º 16
0
    def do_backup(self, host, logger):
        host_backup = Backup(host, logger=logger)

        backup_lock.acquire()
        try:
            host_backup.setup()
        finally:
            backup_lock.release()

        return host_backup.do_backup()
Ejemplo n.º 17
0
    def test_sorted_md5_with_time_by_time(self):
        subj = Backup()
        key1 = 'key1-%s' % uid()
        key2 = 'key2-%s' % uid()
        key3 = 'key3-%s' % uid()
        keys = [key3, key1, key2]
        md5_with_time = {k: (uid(), uid_datetime()) for k in keys}
        keys.reverse()

        self.assertEqual(subj.sorted_md5_with_time_by_time(md5_with_time),
                         keys)
Ejemplo n.º 18
0
    def test_write_md5_with_time():
        subj = Backup()
        fd = Mock(name='fd')
        key = 'key-%s' % uid()
        checksum = 'sum-%s' % uid()
        sum_time = uid_datetime()

        subj.write_md5_with_time(fd, key, checksum, sum_time)

        fd.write.assert_called_once_with(
            bytes(checksum + ' ' + sum_time.isoformat() + ' ' + key + '\n',
                  'UTF-8'))
Ejemplo n.º 19
0
 def test_read_config(self, mock_path):
     subj = Backup()
     path = str(uid())
     mock_path.expanduser.return_value = path
     config = {'a': uid(), 'b': uid()}
     data = json.dumps(config)
     with patch('builtins.open',
                new_callable=mock.mock_open,
                read_data=data) as mock_file:
         self.assertEqual(subj.read_config(), config)
     mock_path.expanduser.assert_called_once_with(
         '~/.config/backup/backup.cfg')
     mock_file.assert_called_once_with(path, encoding='UTF-8')
Ejemplo n.º 20
0
    def test_finds_correct_location_to_store_backup_file(self):
        tmp_path = '/tmp'

        actual = Backup.find_path_to_backup_file(
            '/Users/rob/test/googledrive/sports',
            '/Users/rob/test/googledrive/sports/notes.md', tmp_path)
        self.assertEquals(('/tmp/sports', '/tmp/sports/notes.md'), actual)

        actual = Backup.find_path_to_backup_file(
            '/Users/rob/test/googledrive/technical',
            '/Users/rob/test/googledrive/technical/java/notes.md', tmp_path)
        self.assertEquals(
            ('/tmp/technical/java', '/tmp/technical/java/notes.md'), actual)
Ejemplo n.º 21
0
    def test_slow_check_dir(self, mock_datetime, mock_md5sum, mock_with_open,
                            mock_write_md5_with_time,
                            mock_sorted_md5_with_time_by_time):
        subj = Backup()
        path = 'path-%s' % uid()
        keys = ['key-%s' % uid() for _ in uid_range()]
        mock_sorted_md5_with_time_by_time.return_value = keys
        md5_with_time = {k: (uid(), uid()) for k in keys}
        times = [uid_datetime() for _ in keys]
        mock_datetime.now.side_effect = times
        corrupted_index = uid(len(keys))
        mock_md5sum.side_effect = [
            uid() if i == corrupted_index else md5_with_time[keys[i]][0]
            for i in range(0, len(keys))
        ]
        lines = ['line-%s' % uid() for _ in keys]
        mock_write_md5_with_time.side_effect = lines
        index = 0
        fd = ['fd-%s' % uid() for _ in keys]

        def md5_sum(i):
            return 'corrupted' if i == corrupted_index else md5_with_time[
                keys[i]][0]

        def with_open(file, mode, handler):
            nonlocal index
            mock_write_md5_with_time.assert_has_calls([
                call(fd[i], keys[i], md5_sum(i), times[i])
                for i in range(0, index)
            ])

            self.assertEqual(handler(fd[index]), lines[index])
            index += 1
            mock_write_md5_with_time.assert_has_calls([
                call(fd[i], keys[i], md5_sum(i), times[i])
                for i in range(0, index)
            ])

        mock_with_open.side_effect = with_open

        subj.slow_check_dir(path, md5_with_time)

        mock_sorted_md5_with_time_by_time.assert_called_once_with(
            md5_with_time)
        mock_datetime.now.assert_has_calls([call(timezone.utc) for _ in keys])
        mock_md5sum.assert_has_calls([
            call(path + '/' + k, multiplier=subj.with_sleep_multiplier)
            for k in keys
        ])
        mock_with_open.assert_has_calls(
            [call(path + '/.log', 'ab', mock.ANY) for _ in keys])
Ejemplo n.º 22
0
def actionBackup():
    """
    Backups the latest build.
  """
    Backup.init()
    for target in Settings.targets:
        for platform in Settings.targetPlatforms:
            for cpu in Settings.targetCPUs:
                if System.checkIfCPUIsSupportedForPlatform(cpu, platform):
                    for configuration in Settings.targetConfigurations:
                        if not Summary.checkIfActionFailed(
                                ACTION_BUILD, target, platform, cpu,
                                configuration):
                            Backup.run(target, platform, cpu, configuration)
Ejemplo n.º 23
0
    def test_svn_revision(self, mock_system):
        subj = Backup()
        subj = SvnBackup(subj)
        for src in (str(uid()), "/%s" % uid(), "../%s" % uid()):
            with self.subTest(src=src):
                expected = uid()
                mock_system.reset_mock()
                mock_system.return_value = expected
                url = "file://" + os.path.abspath(src)

                self.assertEqual(subj.svn_revision(src), expected)
                mock_system.assert_called_once_with(("svn", "info", url),
                                                    subj.read_revision)
                self.assertTrue(".." in "../%s" % uid())
                self.assertFalse(".." in url)
Ejemplo n.º 24
0
    def test_recovery_key_search(self, mock_recovery_entry,
                                 mock_recovery_dirs):
        subj = Backup()
        dst = 'dst-%s' % uid()
        key = 'key-%s' % uid()
        name = 'name-%s' % uid()
        md5dirs = ['md5dirs-%s' % uid() for _ in uid_range()]
        file_dict = {'file-%s' % uid(): uid() for _ in uid_range()}
        recovery = ['recovery-%s' % uid() for _ in uid_range()]
        indexes = [uid() for _ in uid_range()]
        lists = {i: ['list-%s' % uid() for _ in uid_range()] for i in indexes}

        subj.recovery_key_search(dst, key, name, md5dirs, file_dict, recovery,
                                 lists)

        self.fail("TODO")
Ejemplo n.º 25
0
    def test_init(self, mock_time):
        now = uid_time()
        mock_time.time.return_value = now
        subj = Backup()

        self.assertEqual(time_to_iso(subj.checked),
                         time_to_iso(now - 2 * 24 * 3600))
Ejemplo n.º 26
0
	def load(self, fname):
		"""
		Load encrypted passwords from disk file, decrypt outer
		layer containing key names. Requires Trezor connected.
		
		@throws IOError: if reading file failed
		"""
		with file(fname) as f:
			header = f.read(len(Magic.headerStr))
			if header != Magic.headerStr:
				raise IOError("Bad header in storage file")
			version = f.read(4)
			if len(version) != 4 or struct.unpack("!I", version)[0] != 1:
				raise IOError("Unknown version of storage file")
			wrappedKey = f.read(KEYSIZE)
			if len(wrappedKey) != KEYSIZE:
				raise IOError("Corrupted disk format - bad wrapped key length")
			
			self.outerKey = self.unwrapKey(wrappedKey)
			
			self.outerIv = f.read(BLOCKSIZE)
			if len(self.outerIv) != BLOCKSIZE:
				raise IOError("Corrupted disk format - bad IV length")
			
			lb = f.read(2)
			if len(lb) != 2:
				raise IOError("Corrupted disk format - bad backup key length")
			lb = struct.unpack("!H", lb)[0]
			
			self.backupKey = Backup(self.trezor)
			serializedBackup = f.read(lb)
			if len(serializedBackup) != lb:
				raise IOError("Corrupted disk format - not enough encrypted backup key bytes")
			self.backupKey.deserialize(serializedBackup)
			
			ls = f.read(4)
			if len(ls) != 4:
				raise IOError("Corrupted disk format - bad data length")
			l = struct.unpack("!I", ls)[0]
			
			encrypted = f.read(l)
			if len(encrypted) != l:
				raise IOError("Corrupted disk format - not enough data bytes")
			
			hmacDigest = f.read(MACSIZE)
			if len(hmacDigest) != MACSIZE:
				raise IOError("Corrupted disk format - HMAC not complete")
			
			#time-invariant HMAC comparison that also works with python 2.6
			newHmacDigest = hmac.new(self.outerKey, encrypted, hashlib.sha256).digest()
			hmacCompare = 0
			for (ch1, ch2) in zip(hmacDigest, newHmacDigest):
				hmacCompare |= int(ch1 != ch2)
			if hmacCompare != 0:
				raise IOError("Corrupted disk format - HMAC does not match or bad passphrase")
				
			serialized = self.decryptOuter(encrypted, self.outerIv)
			self.groups = cPickle.loads(serialized)
Ejemplo n.º 27
0
    def test_write_md5_with_time_dict(self, mock_write_md5_with_time,
                                      mock_sorted_md5_with_time_by_time):
        subj = Backup()
        fd = 'fd-%s' % uid()
        keys = ['key-%s' % uid() for _ in uid_range()]
        mock_sorted_md5_with_time_by_time.return_value = keys
        md5_with_time = {
            k: ('sum-%s' % uid(), 'time-%s' % uid())
            for k in keys
        }

        subj.write_md5_with_time_dict(fd, md5_with_time)

        mock_sorted_md5_with_time_by_time.assert_called_once_with(
            md5_with_time)
        mock_write_md5_with_time.assert_has_calls([
            call(fd, k, md5_with_time[k][0], md5_with_time[k][1]) for k in keys
        ])
Ejemplo n.º 28
0
 def backup_processor(self):
     if not self._backup_processor:
         self._backup_processor = TaskQueueProcessor(
             "Backups",
             Backup().type_name,
             "backups",
             self,
             self._max_workers,
             sleep_time=self.sleep_time)
     return self._backup_processor
Ejemplo n.º 29
0
    def test_read_dir_md5_with_time(self, mock_update_dir_md5_with_time):
        for is_same_dir in (False, True):
            with self.subTest(is_same_dir=is_same_dir):
                mock_update_dir_md5_with_time.reset_mock()
                subj = Backup()
                backup_dir = 'backup-%s' % uid()
                prefix = '' if is_same_dir else 'prefix-%s' % uid()
                directory = backup_dir if is_same_dir else backup_dir + '/' + prefix
                if not is_same_dir:
                    prefix += '/'
                targets = [
                    'file-%s.any%s' % (uid(), uid()) for _ in uid_range()
                ]  # целевые файлы
                md5_files = ['file-%s.md5' % uid()
                             for _ in uid_range()]  # файлы .md5
                files = targets + md5_files + [
                    'file-%s.any%s' % (uid(), uid()) for _ in uid_range()
                ]  # + другие файлы
                dir_md5_with_time = {prefix + f: uid()
                                     for f in targets}  # целевой результат
                log_md5_with_time = dir_md5_with_time.copy()
                log_md5_with_time.update({
                    f: uid()
                    for f in [  # файлы в других директориях игнорируются
                        'dir-%s/file-%s' % (uid(), uid()) for _ in uid_range()
                    ]
                })
                log_md5_with_time.update({
                    prefix + 'file-%s.any%s' % (uid(), uid()): uid()
                    for _ in uid_range()
                })  # файлы, которых уже нет, игнорируются
                expected_calls = [
                    call(dir_md5_with_time,
                         len(backup_dir) + 1, directory, i, files)
                    for i in md5_files
                ]

                self.assertEqual(
                    subj.read_dir_md5_with_time(backup_dir, directory, files,
                                                log_md5_with_time),
                    dir_md5_with_time)

                mock_update_dir_md5_with_time.assert_has_calls(expected_calls)
Ejemplo n.º 30
0
def readConfig(cmdargs):

    parser = OptionParser()
    parser.add_option(
        '--dry-run',
        action='store_true',
        dest='dry_run',
        help='show commands, do not execute except collection-status')
    parser.add_option('--cleanup',
                      action='store_true',
                      dest='cleanup',
                      help='cleanup only, implies --dry-run')
    parser.add_option(
        '--remove-older',
        action='store',
        type='int',
        dest='remove_older',
        default=None,
        help=
        'run remove_old only, with the given value. implies --dry-run (set the value in the config to customize for each run and do other operations)'
    )
    parser.add_option('--config',
                      action='store',
                      type='string',
                      dest='configFile',
                      default='config.cfg.example',
                      help='use this config file')
    parser.add_option(
        '--full',
        action='store_true',
        dest='full',
        help=
        'force a full backup. will retry for each backup target if necessary until full backups are done'
    )
    (options, args) = parser.parse_args(cmdargs)

    globals = {}
    locals = {}
    try:
        execfile(options.configFile, globals, locals)
    except:
        print 'exception raised while reading config file %s' % options.configFile
        raise
    if (not locals.has_key('DupiConfig')):
        raise 'DupiConfig dictionary was not defined'
    DupiConfig = locals['DupiConfig']

    # setup default backup class if needed
    if (not DupiConfig.has_key('backup')):
        from backup import Backup
        DupiConfig['backup'] = Backup(DupiConfig)

    DupiConfig['backup'].commandLineOverrides(options)

    return DupiConfig
Ejemplo n.º 31
0
class TestBackup(unittest.TestCase):
    """ call to make unittest of the backup.Backup() class."""

    def __init__( self, methodName = 'runTest' ):
        unittest.TestCase.__init__( self, methodName )
        self.backup = Backup("VIM", config["VIM"], search=False, keep=True )
        self.backup.compression = None

    def test_read_options(self):
        """read_options() should return a dictionary."""
        options = read_options(config["TXT"])
        self.assertEqual(type({}), type(options), "options has to ba a dictionary")
        self.assertEqual(type([]), type(options["dirs"]), "options[\"dirs\"] has to ba a list")
        self.assertEqual(type(""), type(options["archive_path"]), "options[\"archive_path\"] has to be a string")
        self.assertEqual(type(""), type(options["compression"]), "options[\"compression\"] has to be a string")
        self.assertEqual(type([]), type(options["input_files"]), "options[\"input_files\"] has to be a list")

    def test_target(self):
        """ Backup.target should be a string."""
        self.assertEqual(type([]), type(self.backup._target))

    def test_time(self):
        """ Backup.time should be a float number."""
        self.assertEqual(type(float(0)), type(self.backup.time), "backup.time should be a float number")
        # The following test fails if test_make_backup() is run:
        # self.assertAlmostEqual(time.time(), self.backup.time, places=0 )

    def test_log_file(self):
        """ Backup.log_file should be a string ."""
        backup = Backup( "VIM", config["VIM"], search=False, keep=True )
        dir_name = os.path.dirname(backup.log_file)
        self.assertTrue(os.path.isdir(dir_name))

    def test_make_backup(self):
        """ test for Backup.make_backup() """
        self.backup.compression=None
        self.backup.target("/tmp")
        self.backup.find_files()
        self.backup.make_backup()
        self.assertTrue(os.path.isfile(self.backup.path))
        self.assertNotEqual([],self.backup.file_list, "VIM backup should be non empty")
        self.backup.put()
        path = os.path.join(self.backup._target[2],os.path.basename(self.backup.path))
        self.assertTrue(os.path.isfile(path), "Backup.make_backup() should make the backup file: %s" % path)
        with tarfile.open(path, 'r') as tarfile_o:
            has = len(tarfile_o.getnames())
            should = len(tarfile_o.getnames())
            self.assertEqual(has, should, "Backup should contain %d files, but contains %d files" % (has, should))
        # The path is net removed unless both above test are passed. If a test
        # fails, an exception is raised which stopes the execution of the
        # module.
        os.remove(path)
Ejemplo n.º 32
0
    def _test_full(self, mock_log, mock_time):
        now = uid_time()
        mock_time.time.return_value = now
        mock_log.debug = Mock()
        mock_log.info = Mock()
        mock_log.error = Mock()
        subj = Backup()
        self.assertEqual(time_to_iso(subj.checked),
                         time_to_iso(now - 2 * 24 * 3600))

        self.fail("TODO")
Ejemplo n.º 33
0
def initializeStorage(trezor, pwMap, settings):
    """
    Initialize new encrypted password file, ask for master passphrase.
    Initialize RSA keypair for backup, encrypt private RSA key using
    backup passphrase and Trezor's cipher-key-value system. Makes sure
    a session is created on Trezor so that the passphrase will be cached
    until disconnect.

    @param trezor:   Trezor client
    @param pwMap:    PasswordMap where to put encrypted backupKeys
    @param settings: Settings object to store password database location
    """
    dialog = InitializeDialog()
    if not dialog.exec_():
        sys.exit(4)
    masterPassphrase = q2s(dialog.pw1())
    trezor.prefillPassphrase(masterPassphrase)
    backup = Backup(trezor)
    backup.generate()
    pwMap.backupKey = backup
    settings.dbFilename = q2s(dialog.pwFile())
    settings.store()
Ejemplo n.º 34
0
def test_backup_repr(monkeypatch):
    # Pretend path exists and is directory to allow initialisation
    monkeypatch.setattr(Path, 'is_dir', lambda _: True)
    monkeypatch.setattr(Path, 'exists', lambda _: True)
    # Get absolute path from current working directory to allow tests on
    # different platforms
    cwd = Path.cwd()
    given_path = cwd / 'example/string'
    expected_reprs = (f"Backup(path='{cwd}/example/string')",
                      f"Backup(path='{cwd}\\example\\string')")
    # Act, assert
    actual_repr = str(Backup(given_path))
    assert actual_repr in expected_reprs
Ejemplo n.º 35
0
def start(version, update_url, update_md5):
    ''' init update process '''

    set_lock()
    if version and xbmcgui.Dialog().yesno(__addonname__, \
                        "New update ("+ version +") is available.", \
                        "Selecting 'Yes' will backup your data, download the update,", \
                        "reboot your device and start the update process."):
        download_location = which_usb()

        try:
            backup = Backup(download_location, get_local_version())
            backup.run()
        except:
            dp = xbmcgui.Dialog()
            dp.ok(__addonname__, \
                    "Backup could not be completed.",
                    "Please use a 16GB USB or larger.", \
                    "Update manually from Settings > Update")

            remove_lock()
            return

        if download_location:
            xbmc.log("BOXiK Auto Service: %s %s %s %s " % \
                     (remote_path(), download_location, update_url, update_md5))
            if download.firmware(download_location, update_url, update_md5):
                reboot()
            else:
                dp = xbmcgui.Dialog()
                dp.ok(__addonname__, "Download failed", "", "Try again later.")
        else:
            dp = xbmcgui.Dialog()
            dp.ok(__addonname__, \
                  "Please insert a compatible USB into the BOXiK",
                  " ", \
                  "Update manually from Settings > Update")
    remove_lock()
Ejemplo n.º 36
0
def start(version, update_url, update_md5):
    ''' init update process '''

    set_lock()
    if version and xbmcgui.Dialog().yesno(__addonname__, \
                        "New update ("+ version +") is available.", \
                        "Selecting 'Yes' will backup your data, download the update,", \
                        "reboot your device and start the update process."):
        download_location = which_usb()

        try:
            backup = Backup(download_location, get_local_version())
            backup.run()
        except:  
            dp = xbmcgui.Dialog()  
            dp.ok(__addonname__, \
                    "Backup could not be completed.", 
                    "Please use a 16GB USB or larger.", \
                    "Update manually from Settings > Update")
                
            remove_lock()
            return

        if download_location:
            xbmc.log("BOXiK Auto Service: %s %s %s %s " % \
                     (remote_path(), download_location, update_url, update_md5))
            if download.firmware(download_location, update_url, update_md5):
                reboot()
            else: 
                dp = xbmcgui.Dialog()
                dp.ok(__addonname__, "Download failed", "", "Try again later.")
        else:
            dp = xbmcgui.Dialog()
            dp.ok(__addonname__, \
                  "Please insert a compatible USB into the BOXiK", 
                  " ", \
                  "Update manually from Settings > Update")
    remove_lock()
Ejemplo n.º 37
0
    def test_recovery_for_each(self, mock_os):
        for isdir in (False, True):
            with self.subTest(isdir=isdir):
                mock_os.reset_mock()
                subj = Backup()
                dst = 'dst-%s' % uid()
                key = 'key-%s'
                recovery_key_search = Mock()
                mock_os.path.isdir.return_value = isdir
                mock_os.listdir.return_value = listdir = [
                    'name-%s' % uid() for _ in uid_range()
                ]

                subj.recovery_for_each(dst, key, recovery_key_search)

                mock_os.path.isdir.assert_called_once_with(dst + key)
                if isdir:
                    mock_os.listdir.assert_called_once_with(dst + key)
                    recovery_key_search.assert_has_calls(
                        [call(dst, name) for name in listdir])
                else:
                    mock_os.listdir.assert_not_called()
                    recovery_key_search.assert_not_called()
Ejemplo n.º 38
0
    def OnInit(self):

        if mf.err_msg:
            msg = mf.err_msg + u'\n\nもしエラーを自己解決できない場合は、お手数ですがこのエラーメッセージの内容を作者へお知らせください。\nCtrl + C キーを押すとテキストがコピーされます。\n個人情報の部分は、適当な文字に書き換えといてください。'
            wx.MessageBox(msg)
            sys.exit(1)

        self.conf = Config(mf.app_data_dir)

        if os.path.exists(mf.persist_path):
            self._processing_persist = True
        else:
            self._processing_persist = False

        self.wp = WavePlayer()
        self.snd = None
        self.bk = Backup()

        self.InitUI()

        self.binder.parent = self.frame
        self.binder.bindall(self)

        self.SetPersist()

        self.frame.Centre()
        self.frame.Show()

        self.RegisterControls()

        # spl_logの位置を記憶しておくため
        # register_controlsを呼び出したあとにログ画面を閉じる。
        if not self.conf.show_log:
            self.OnLog(None)

        self.UpdateFlist()

        if self._processing_persist:
            # exe化したときにも正しく動くように遅らせて実行
            wx.CallLater(1000, self.OffProcessingPersist)

        return True
Ejemplo n.º 39
0
    def OnInit(self):
        self.conf = Config(mf.app_data_dir)

        if os.path.exists(mf.persist_path):
            self._processing_persist = True
        else:
            self._processing_persist = False

        self.wp = WavePlayer()
        self.snd = None
        self.bk = Backup()

        self.InitUI()

        self.binder.parent = self.frame
        self.binder.bindall(self)

        self.SetPersist()

        self.frame.Centre()
        self.frame.Show()

        self.RegisterControls()

        # spl_logの位置を記憶しておくため
        # register_controlsを呼び出したあとにログ画面を閉じる。
        if not self.conf.show_log:
            self.OnLog(None)

        self.UpdateFlist()

        if self._processing_persist:
            # exe化したときにも正しく動くように遅らせて実行
            wx.CallLater(1000, self.OffProcessingPersist)

        return True
Ejemplo n.º 40
0
 def __init__(self, backup_path, backup_id,
              subprocess_factory=subprocess, db_connection_factory=sqlite3):
     Backup.__init__(self, backup_path, backup_id)
     self.subprocess_factory = subprocess_factory
     self.db_connection_factory = db_connection_factory
from cmd import Cmd
from auothisation import Authorisation
from gdrive import GDrive
from backup import Backup

if __name__ == '__main__':
    cli = Cmd()
    authorisation = Authorisation(cli)
    gdrive = GDrive(authorisation)
    backup = Backup(cli, gdrive)
    backup.backup()
Ejemplo n.º 42
0
    def schedule_backup(self, **kwargs):

        try:
            backup = Backup()
            backup.created_date = date_now()
            backup.strategy = get_validate_arg(kwargs, "strategy",
                                               expected_type=BackupStrategy)
            backup.source = get_validate_arg(kwargs, "source", BackupSource)
            backup.target = get_validate_arg(kwargs, "target", BackupTarget)
            backup.priority = get_validate_arg(kwargs, "priority",
                                               expected_type=(int, long,
                                                              float, complex),
                                               required=False)
            backup.plan_occurrence = \
                get_validate_arg(kwargs, "plan_occurrence",
                                 expected_type=datetime,
                                 required=False)
            backup.plan = get_validate_arg(kwargs, "plan",
                                           expected_type=BackupPlan,
                                           required=False)

            backup.secondary_targets = get_validate_arg(kwargs,
                                                        "secondary_targets",
                                                        expected_type=list,
                                                        required=False)

            backup.change_state(State.SCHEDULED)
            # set tags
            tags = get_validate_arg(kwargs, "tags", expected_type=dict,
                                    required=False)

            backup.tags = tags

            bc = get_mbs().backup_collection
            try:
                # resolve tags

                self._resolve_task_tags(backup)
            except Exception, ex:
                self._task_failed_to_schedule(backup, bc, ex)

            self.set_custom_backup_props(backup)

            backup_doc = backup.to_document()
            get_mbs().backup_collection.save_document(backup_doc)
            # set the backup id from the saved doc

            backup.id = backup_doc["_id"]

            self.info("Saved backup \n%s" % backup)

            if backup.state == State.FAILED:
                trigger_task_finished_event(backup, State.FAILED)

            return backup
Ejemplo n.º 43
0
def backup_rm(id, namespace):
    Backup.remove(id, namespace)
Ejemplo n.º 44
0
def backup_inspect(id, namespace):
    backup = Backup.fetch(id, namespace)
    result = backup.inspect()
    util.print_json_result(result)
Ejemplo n.º 45
0
def backup_list(namespace):
    backup_list = Backup.list(namespace)
    util.print_backup_ps_output(backup_list)
Ejemplo n.º 46
0
    def do_backup(self, host, logger):
        host_backup = Backup(host, logger=logger)
        host_backup.setup()

        return host_backup.do_backup()
Ejemplo n.º 47
0
class InsPause(wx.App):

    binder = wx_utils.bind_manager()

    def OnInit(self):
        self.conf = Config(mf.app_data_dir)

        if os.path.exists(mf.persist_path):
            self._processing_persist = True
        else:
            self._processing_persist = False

        self.wp = WavePlayer()
        self.snd = None
        self.bk = Backup()

        self.InitUI()

        self.binder.parent = self.frame
        self.binder.bindall(self)

        self.SetPersist()

        self.frame.Centre()
        self.frame.Show()

        self.RegisterControls()

        # spl_logの位置を記憶しておくため
        # register_controlsを呼び出したあとにログ画面を閉じる。
        if not self.conf.show_log:
            self.OnLog(None)

        self.UpdateFlist()

        if self._processing_persist:
            # exe化したときにも正しく動くように遅らせて実行
            wx.CallLater(1000, self.OffProcessingPersist)

        return True

    def OffProcessingPersist(self):
        self._processing_persist = False

    #--------------------------------------------------------------------------
    # persist (ウィンドウのサイズや最大化の保持)関連

    def SetPersist(self):
        self.pm = PM.PersistenceManager.Get()
        self.pm.SetPersistenceFile(mf.persist_path)
        self.pm.RegisterAndRestore(self.frame)

    def RegisterControls(self):
        self.frame.Freeze()

        # ここに記憶させたいウィジェットを書く
        self.pm.RegisterAndRestore(self.spl_h)
        self.pm.RegisterAndRestore(self.spl_v)
        self.pm.RegisterAndRestore(self.spl_log)
        self.pm.RegisterAndRestore(self.flist)

        self.frame.Thaw()

    #--------------------------------------------------------------------------
    # UI 初期化

    def InitUI(self):
        self.res = xrc.XmlResource(mf.xrc_path)

        self.InitFrame()
        self.InitLog()
        self.InitView()
        self.InitSetting()
        self.InitFileList()
        self.InitMenu()
        self.InitToolbar()
        self.InitStatusbar()

        self.EnableUI()

    def InitFrame(self):
        self.frame = self.res.LoadFrame(None, 'MainFrame')
        self.frame.Title = APP_NAME
        self.wp.add_listener(self.frame)
        SetIcon(self.frame)

        self.spl_h = xrc.XRCCTRL(self.frame, 'HorizontalSplitter')
        self.spl_v = xrc.XRCCTRL(self.frame, 'VerticalSplitter')

        # ドラッグアンドドロップ
        dd = DirDrop(self)
        self.frame.SetDropTarget(dd)

    def InitLog(self):
        self.spl_log = xrc.XRCCTRL(self.frame, 'LogSplitter')
        self.win1 = self.spl_log.GetWindow1()
        self.win2 = self.spl_log.GetWindow2()

        logtext = xrc.XRCCTRL(self.frame, 'LogText')
        sys.stdout = sys.stderr = self.log = Mylog(logtext, mf.log_path)

        self.auto_show_log = xrc.XRCCTRL(self.frame, 'ChkAutoShowLog')
        self.auto_show_log.SetValue(self.conf.auto_show_log)

    def InitView(self):
        self.view = LabelsWindow(parent=self.frame)
        self.view.view_factor = self.conf.view_factor
        self.view.scale = self.conf.scale
        self.res.AttachUnknownControl('WaveView', self.view, self.frame)

    def InitSetting(self):
        # ---- ポーズ音声作成
        self.SetDefaultSaveDir()

        # ---- ポーズ時間
        self.NumCtrl('TextFactor', self.conf.factor, MIN_FACTOR, MAX_FACTOR)
        self.NumCtrl('TextAdd', self.conf.add_s, MIN_ADD_S, MAX_ADD_S)

        # ---- バックアップ(コンボボックス、復元ボタン)
        self.cmb_backup = xrc.XRCCTRL(self.frame, 'CmbBackup')
        for info in self.bk:
            self.AddBackupInfo(info)
        self.btn_restore = xrc.XRCCTRL(self.frame, 'BtnRestore')
        self.btn_delbackup = xrc.XRCCTRL(self.frame, 'BtnDelBackup')

        # ---- ラベル検索(無音認識時間、無音レベル、前余裕、後余裕)
        self.NumCtrl('TextSilDur', self.conf.sil_dur_s, MIN_SIL_DUR_S, MAX_SIL_DUR_S)
        xrc.XRCCTRL(self.frame, 'SilLvSlider').Value = self.conf.sil_lv
        self.NumCtrl('TextBeforeDur', self.conf.before_dur_s, 0.0, 9.99)
        self.NumCtrl('TextAfterDur', self.conf.after_dur_s, 0.0, 9.99)

        # ---- 色
        self.SetViewBgColour(self.conf.bg)
        self.SetViewFgColour(self.conf.fg)
        self.view.SetHandleColour(self.conf.handle)

        # ---- 表示範囲
        self.sld_scale = xrc.XRCCTRL(self.frame, 'SldScale')
        self.sld_scale.SetValue(self.conf.scale)

        # ---- ファイルリストの幅
        self.sld_flist_width = xrc.XRCCTRL(self.frame, 'SldFlistWidth')
        self.sld_flist_width.SetValue(self.conf.flist_width)

        self.SetScroll('ScrMain')
        self.SetScroll('ScrTool')
        self.SetScroll('ScrView')

    def AddBackupInfo(self, info, tail=True):
        name = '(%02d) %s' % (info.num_labels, info.name)
        if tail:
            self.cmb_backup.Append(name, info)
        else:
            self.cmb_backup.Insert(name, 0, info)

    def InitFileList(self):
        self.flist = xrc.XRCCTRL(self.frame, 'FileList')
        self.flist.InsertColumn(0, u'音声')

        icon = wx.ArtProvider.GetIcon(wx.ART_LIST_VIEW, size=(16, 16))

        bmp = wx.EmptyBitmap(16, 16)
        dc = wx.BufferedDC(None, bmp)
        dc.SetBackground(wx.WHITE_BRUSH)
        dc.Clear()
        del dc

        il = wx.ImageList(16, 16, False, 2)
        il.AddIcon(icon)
        il.Add(bmp)
        self.flist.AssignImageList(il, wx.IMAGE_LIST_SMALL)

    def InitMenu(self):
        self.menu = self.res.LoadMenuBar('MenuBar')
        self.frame.SetMenuBar(self.menu)
        self.menu.Check(xrc.XRCID('MenuLog'), self.conf.show_log)

    def InitToolbar(self):
        tools = []
        self.tools = tools

        tools += [{'name': 'ToolHead',       'check': self.view.can_head}]
        tools += [{'name': 'ToolPlay',       'check': self.CanPlay}]
        tools += [{'name': 'ToolPlayPause',  'check': self.CanPlay}]
        tools += [{'name': 'ToolPause',      'check': self.CanPause}]
        tools += [{'name': 'ToolZoomIn',     'check': self.view.can_zoom_in}]
        tools += [{'name': 'ToolZoomOut',    'check': self.view.can_zoom_out}]
        tools += [{'name': 'ToolUndo',       'check': self.view.can_undo}]
        tools += [{'name': 'ToolRedo',       'check': self.view.can_redo}]
        tools += [{'name': 'ToolSaveLabels', 'check': self.view.can_save}]
        tools += [{'name': 'ToolSaveSound',  'check': lambda: True }]

        self.tool_bar = self.res.LoadToolBar(self.frame, 'ToolBar')

        if not self.conf.show_save2:
            self.tool_bar.RemoveTool(xrc.XRCID('ToolSaveSound'))

        self.tool_bar.Realize()

    def CanPlay(self):
        if self.snd and self.wp.can_play():
            return True
        else:
            return False

    def CanPause(self):
        if self.snd and self.wp.can_pause():
            return True
        else:
            return False

    def InitStatusbar(self):
        statusbar = self.frame.CreateStatusBar()
        statusbar.SetFieldsCount(2)
        label = '  00:00.000 / 00:00.000   '
        cw = wx.ClientDC(statusbar).GetTextExtent(label)[0]
        statusbar.SetStatusWidths([-1, cw])
        self.statusbar = statusbar

    def SetFlistIcon(self):
        for i in range(self.flist.GetItemCount()):
            labels_path = mf.get_labels_path(self.snd_dir, i + 1)

            if os.path.exists(labels_path):
                image_no = IMG_HAS_LABELS
            else:
                image_no = IMG_NO_LABELS

            self.flist.SetItemImage(i, image_no, image_no)

    def SetDefaultSaveDir(self):
        path = mf.get_default_pause_dir(self.snd_dir)
        ctrl = xrc.XRCCTRL(self.frame, 'TextSaveDir')
        ctrl.SetValue(path)

    #--------------------------------------------------------------------------
    # UI

    def SetTitleBar(self, snd_path):
        snd_file = os.path.basename(snd_path)
        self.frame.Title = snd_file + ' - ' + APP_NAME

    def NumCtrl(self, name, val, min_val, max_val):
        '''
        小数テキストコントロールの作成
        #.## 形式で、最小値は引数min_val、最大値は引数max_valに制限される。
        '''

        ctrl = NumCtrl(self.frame)
        ctrl.SetAllowNegative(False)
        ctrl.SetIntegerWidth(1)
        ctrl.SetFractionWidth(2)
        ctrl.SetValue(val)
        ctrl.SetMin(min_val)
        ctrl.SetMax(max_val)
        ctrl.SetLimited(True)
        cw, ch = ctrl.GetTextExtent('X0.00X')
        ctrl.SetMinSize((cw, -1))

        self.res.AttachUnknownControl(name, ctrl, self.frame)

        return ctrl

    def SetStatusPosText(self, pos_f):
        '''
        ステータスバーに現在位置(秒)を設定
        @param pos_f 現在位置(フレーム)
        '''

        pos_s = self.view.f_to_s(pos_f)
        pos_str = sec_to_str(pos_s)
        s = '  %s / %s' % (pos_str, self.dur_str)
        self.statusbar.SetStatusText(s, STB_POS)

    def LogIsVisible(self):
        '''
        ログ画面が表示されているか?
        '''

        return self.spl_log.IsSplit()

    def SetScroll(self, name):
        '''
        設定ノートブックの中の領域をスクロールできるようにする
        '''

        ctrl = xrc.XRCCTRL(self.frame, name)
        w, h = ctrl.Size
        su = 20
        ctrl.SetScrollbars(su, su, w, su, h / su)

    def EnableUI(self):
        '''
        ツールバーやコントロールの有効・無効を設定する
        '''

        # ---- メニュー
        self.menu.Enable(xrc.XRCID('MenuSave'), self.view.can_save())

        # ---- ツールバー
        for tool in self.tools:
            self.tool_bar.EnableTool(xrc.XRCID(tool['name']), tool['check']())

        # ---- 設定コントロール
        notebook = xrc.XRCCTRL(self.frame, 'NoteBook')

        if self.wp.is_playing or self.snd is None:
            notebook.Enabled = False
        else:
            notebook.Enabled = True

        self.EnableBackup()

    def EnableBackup(self):
        '''
        バックアップコンボボックス・バックアップボタン・復元ボタン・
        削除ボタンの有効/無効を設定
        '''

        if self.cmb_backup.Count == 0:
            self.cmb_backup.Enabled = False
            self.btn_restore.Enabled = False
            self.btn_delbackup.Enabled = False
        else:
            self.cmb_backup.Enabled = True
            if self.cmb_backup.Value != '':
                self.btn_restore.Enabled = True

                info = self.GetSelectedBkInfo()
                if info.is_sys:
                    self.btn_delbackup.Enabled = False
                else:
                    self.btn_delbackup.Enabled = True
            else:
                self.btn_restore.Enabled = False
                self.btn_delbackup.Enabled = False

    # ---- 色

    def SetViewBgColour(self, colour):
        self.conf.bg = self.GetColour(colour)
        ctrl = xrc.XRCCTRL(self.frame, 'BtnBg')
        ctrl.SetBackgroundColour(colour)
        self.view.SetBackgroundColour(colour)

    def SetViewFgColour(self, colour):
        self.conf.fg = self.GetColour(colour)
        ctrl = xrc.XRCCTRL(self.frame, 'BtnFg')
        ctrl.SetBackgroundColour(colour)
        self.view.SetForegroundColour(colour)

    def GetColour(self, colour):
        if isinstance(colour, basestring):
            name = colour
            colour = wx.Colour()
            colour.SetFromName(name)

        return colour

    def ShowAboutDlg(self):
        msg = '''\
%s version %s
Author: %s
Web Site: %s\
''' % (APP_NAME, __version__, __author__, web_site)
        dlg = wx.MessageDialog(self.frame, msg, 'About %s' % APP_NAME, wx.OK | wx.CENTRE)
        dlg.ShowModal()
        dlg.Destroy()

    #--------------------------------------------------------------------------

    def ConfirmSave(self, cancel=False):
        '''
        保存するかをユーザに確認する

        @param cancel Trueならキャンセルボタンも表示する
        @return 保存の必要がないならNone
                それ以外はユーザの選択によりwx.YES, wx.NO, wx.CANCEL
        '''

        if self.view.can_save():
            flg = wx.YES_NO | wx.ICON_QUESTION
            if cancel:
                flg |= wx.CANCEL

            res = wx.MessageBox(u'変更を保存しますか?', u'確認',  flg)

            if res == wx.YES:
                self.view.save()
                self.EnableUI()
                return wx.YES
            else:
                return res

        return None

    def UpdateFlist(self):
        '''
        音声ファイル一覧画面を更新する
        '''

        self.ConfirmSave()

        self.flist.DeleteAllItems()

        snd_files = mf.get_snd_files(self.snd_dir)

        if not snd_files:
            self.conf.list_index = 0
            self.snd = None
            self.view.SetVolume(None)
            self.view.SetLabels(Labels(), '')
            self.EnableUI()
            return

        snd_files.sort()

        for i, name in enumerate(snd_files):
            labels_path = mf.get_labels_path(self.snd_dir, i + 1)

            if os.path.exists(labels_path):
                image_no = IMG_HAS_LABELS
            else:
                image_no = IMG_NO_LABELS

            self.flist.InsertImageStringItem(i, name, image_no)

        list_index = self.conf.list_index
        list_index = max(0, min(list_index, self.flist.ItemCount - 1))
        self.conf.list_index = list_index

        self.conf.list_index = -1  # OnSelectSndで波形画面を更新するため
        self.flist.Select(list_index)
        self.flist.EnsureVisible(list_index)
        self.flist.SetColumnWidth(0, self.conf.flist_width)

    def SetSound(self, snd_path, labels_path):
        '''
        波形画面に音声を設定する
        '''

        if self.wp.is_playing:
            self.Pause()

        msg = u'音声ファイルを読み込み中'
        dlg = wx.ProgressDialog(u'読込', msg, parent=self.frame)

        try:
            self.snd = pausewave.open(snd_path, 'rb', dlg.Update)
            if self.snd.getnframes() == 0:
                raise Exception('num of frames == 0')
        except Exception as e:
            print str(e)
            msg = u'音声ファイルの読み込みに失敗しました。\n\n' \
                  u'音声ファイル=%s\nラベルファイル=%s' % (snd_path, labels_path)
            wx.MessageBox(msg)

            self.view.SetVolume(None)
            self.view.SetLabels(Labels(), labels_path)
            self.EnableUI()
            return
        finally:
            dlg.Destroy()

        vol = Volume(self.snd)
        self.view.SetVolume(vol)

        labels = self.LoadLabels(labels_path, self.snd)
        self.view.SetLabels(labels, labels_path)

        item = self.flist.GetFirstSelected()
        if item != -1:
            self.flist.SetItemImage(item, IMG_HAS_LABELS, IMG_HAS_LABELS)

        self.SetTitleBar(snd_path)

        nframes = self.snd.getnframes()
        rate = self.snd.getframerate()
        self.dur_str = sec_to_str(float(nframes) / rate)
        self.SetStatusPosText(self.view.pos_f)

        self.EnableUI()

    def LoadLabels(self, f, snd):
        '''
        ラベル情報ファイルを読み込む。なければ作成する
        '''

        if os.path.exists(f):
            labels = Labels(f)
        else:
            sil_lv = self.conf.sil_lv
            sil_dur = self.conf.sil_dur_s
            before_dur = self.conf.before_dur_s
            after_dur = self.conf.after_dur_s

            vol = Volume(snd, FIND_RATE)
            labels = find_sound(vol, sil_lv, sil_dur, before_dur, after_dur)

            labels.write(f)

        if not hasattr(labels, 'dist_s') or labels.dist_s == NO_DISTINCTION:
            labels.dist_s = find_dist_s(snd)
            labels.write(f)

        return labels

    def InsertPause(self):
        '''
        ポーズファイルを作成する
        '''

        if self.ConfirmSave() == wx.NO:
            return

        pause_dir = self.GetPauseDir()
        if not pause_dir:
            return

        if not self.ExistsLabels():
            return

        snd_paths, labels_paths, pause_paths = self.GetFilesList(pause_dir)

        msg = u'ポーズ挿入中 %d / %d'
        max_n = len(snd_paths)
        style = wx.PD_AUTO_HIDE | wx.PD_APP_MODAL | wx.PD_CAN_ABORT | wx.PD_ELAPSED_TIME | wx.PD_REMAINING_TIME
        dlg = wx.ProgressDialog(u'進捗', msg % (1, max_n), maximum=max_n, parent=self.frame, style=style)

        err_num = 0

        for i, (snd_path, labels_path, pause_path) in \
                enumerate(zip(snd_paths, labels_paths, pause_paths)):

            keep_going, skip = dlg.Update(i, msg % (i + 1, max_n))

            if not keep_going:
                break

            try:
                insp.insert_pause(snd_path, pause_path, labels_path,
                        self.conf.factor, self.conf.add_s)
            except Exception:
                try:
                    if not pause_path.endswith('.wav'):
                        base = os.path.splitext(pause_path)[0]
                        pause_path = base + '.wav'
                        insp.insert_pause(snd_path, pause_path, labels_path,
                                self.conf.factor, self.conf.add_s)
                        print u'[Encoder Error] wav形式に自動的に変更しました:', pause_path
                        continue
                except Exception as e:
                    print str(type(e)), str(e)
                    err_num += 1

        dlg.Destroy()

        if err_num > 0:
            msg = u'ポーズ音声の作成中にエラーが発生しました'
            wx.MessageBox(msg, u'エラー', wx.OK | wx.ICON_ERROR)

        # ---- 結果を通知
        if sys.platform == 'win32':
            try:
                import subprocess
                subprocess.Popen('explorer "%s"' % pause_dir.encode('cp932'))
            except:
                wx.MessageBox(u'出力場所 : %s' % pause_dir, u'完了', wx.OK)
        else:
            wx.MessageBox(u'出力場所 : %s' % pause_dir, u'完了', wx.OK)

    def GetPauseDir(self):
        '''
        ポーズ音声出力先ディレクトリの取得
        '''

        pause_dir = xrc.XRCCTRL(self.frame, 'TextSaveDir').GetValue()
        if not os.path.exists(pause_dir):
            parent = os.path.dirname(pause_dir)
            if os.path.exists(parent):
                msg = u'フォルダを新しく作りますか?'
                flg = wx.YES_NO | wx.ICON_QUESTION
                res = wx.MessageBox(msg, u'確認', flg)

                if res == wx.YES:
                    os.mkdir(pause_dir)
                else:
                    return None
            else:
                msg = u'存在しないフォルダです:%s' % pause_dir
                wx.MessageBox(msg)
                return None

        if pause_dir == self.snd_dir:
            msg = u'入力音声ファイルと同じ場所には出力できません'
            wx.MessageBox(msg)
            return None

        return pause_dir

    def ExistsLabels(self):
        '''
        ラベルファイルが存在するか?
        '''

        is_all = xrc.XRCCTRL(self.frame, 'RadAllFiles').GetValue()
        if is_all:  # すべてのファイル
            labels_paths = self.GetFullLabelsPath()
            if not labels_paths:
                return False

        return True

    def GetFilesList(self, pause_dir):
        '''
        入力音声ファイル・ラベルファイル・ポーズ付き音声ファイルの
        それぞれのリストを取得
        '''

        is_all = xrc.XRCCTRL(self.frame, 'RadAllFiles').GetValue()
        if is_all:  # すべてのファイル
            rng = range(self.flist.ItemCount)
        else:  # このファイルのみ
            list_index = self.conf.list_index
            rng = range(list_index, list_index+1)

        snd_paths = []
        labels_paths = []
        pause_paths = []

        for i in rng:
            snd_path, labels_path, pause_path = self.GetFiles(i, pause_dir)
            snd_paths.append(snd_path)
            labels_paths.append(labels_path)
            pause_paths.append(pause_path)

        return snd_paths, labels_paths, pause_paths

    def GetFiles(self, i, pause_dir):
        snd_file = self.flist.GetItem(i, 0).GetText()
        snd_path = os.path.join(self.snd_dir, snd_file)

        labels_path = mf.get_labels_path(self.snd_dir, i + 1)

        pause_path = os.path.join(pause_dir, snd_file)

        return snd_path, labels_path, pause_path

    #--------------------------------------------------------------------------
    # 再生/停止

    def Play(self):
        self.snd.settable(None)
        self.snd.setpos(self.view.pos_f, True)
        self.pos_f_after_eow = self.snd.tell(True)
        self.view.playing = True
        self.wp.play(self.snd, True)
        self.EnableUI()
        self.tool_bar.EnableTool(xrc.XRCID('ToolHead'), True)

    def PausePlay(self):
        factor = self.conf.factor
        add = self.conf.add_s
        rate = self.snd.getframerate()
        nframes = self.snd.getnframes(True)

        labels = self.view.GetLabels()
        tbl = Conv_table(labels, rate, nframes, factor, add)
        self.snd.settable(tbl)

        self.snd.setpos(self.view.pos_f, True)
        self.pos_f_after_eow = self.snd.tell(True)
        self.view.playing = True
        self.wp.play(self.snd, True)
        self.EnableUI()
        self.tool_bar.EnableTool(xrc.XRCID('ToolHead'), True)

    def IfcutPlay(self, pos_s):
        tbl = self.CreateIfcutTable(pos_s)
        self.snd.settable(tbl)

        rate = self.snd.getframerate()
        pos_f = pos_s * rate
        start_f = max(0, int((pos_s - IFCUT_DUR_S) * rate))

        self.snd.setpos(start_f, True)
        self.pos_f_after_eow = pos_f
        self.view.playing = True
        self.wp.play(self.snd, False)
        self.EnableUI()
        self.tool_bar.EnableTool(xrc.XRCID('ToolHead'), True)

    def CreateIfcutTable(self, pos_s):
        '''
        引数で指定された位置にポーズを入れるような変換テーブルを作成
        '''

        pause_lbl = Label(pos_s, pos_s, LBL_PAUSE)
        labels = Labels([str(pause_lbl)])
        rate = self.snd.getframerate()
        end_f = int((pos_s + IFCUT_DUR_S) * rate)
        return Conv_table(labels, rate, end_f, 0, IFCUT_PAUSE_S)

    def Pause(self):
        self.wp.pause()
        self.view.playing = False
        self.EnableUI()

    #--------------------------------------------------------------------------
    # ラベル情報のバックアップ

    # バックアップ
    def Backup(self, prefix=''):
        info = self.bk.backup(self.snd_dir, prefix)
        if info:
            self.AddBackupInfo(info, False)
            self.cmb_backup.SetSelection(0)
            self.EnableBackup()

    # 復元
    def Restore(self):
        self.ConfirmSave()

        info = self.GetSelectedBkInfo()

        if not info:
            return

        # 自動バックアップ
        try:
            self.Backup('auto_')
        except:
            pass

        self.bk.restore(self.snd_dir, info)
        self.view.ReloadLabels()
        self.SetFlistIcon()

    # 削除
    def DelBackup(self):
        info = self.GetSelectedBkInfo()

        if info and not info.is_sys:
            flg = wx.YES_NO | wx.ICON_QUESTION
            res = wx.MessageBox(u'本当に削除しますか?', u'確認',  flg)

            if res != wx.YES:
                self.view.save()
                self.EnableUI()
                return

            if self.bk.delete(info):
                self.DelSelectedBkInfo()
                self.EnableBackup()

    # 自動ずれ調整
    def AutoShift(self):
        if self.ConfirmSave() == wx.NO:
            return

        if not self.ExistsLabels():
            return

        # 自動バックアップ
        try:
            self.Backup('auto_')
        except:
            pass

        snd_paths, labels_paths, pause_paths = self.GetFilesList('.')

        msg = u'自動ずれ調整中 %d / %d'
        max_n = len(snd_paths)
        style = wx.PD_AUTO_HIDE | wx.PD_APP_MODAL | wx.PD_CAN_ABORT | wx.PD_ELAPSED_TIME | wx.PD_REMAINING_TIME
        dlg = wx.ProgressDialog(u'進捗', msg % (1, max_n), maximum=max_n, parent=self.frame, style=style)

        err_num = 0

        for i, (snd_path, labels_path, pause_path) in \
                enumerate(zip(snd_paths, labels_paths, pause_paths)):

            keep_going, skip = dlg.Update(i, msg % (i + 1, max_n))

            if not keep_going:
                break

            try:
                auto_shift(snd_path, labels_path)
            except Exception as e:
                print str(e)
                err_num += 1

        dlg.Destroy()

        if err_num > 0:
            msg = u'エラーが発生しました'
            wx.MessageBox(msg, u'エラー', wx.OK | wx.ICON_ERROR)

    def GetFullLabelsPath(self):
        labels_paths = mf.get_labels_paths(self.snd_dir)
        num_labels = len(labels_paths)
        num_snds = self.flist.ItemCount

        if num_labels < num_snds:
            wx.MessageBox(u'まだポーズがついてない音声があります')
            return None

        # 音声ファイル数以上にあるラベルファイルは無視する
        return labels_paths[:num_snds]

    def GetSelectedBkInfo(self):
        selection = self.cmb_backup.Selection

        if selection == wx.NOT_FOUND:
            return None

        return self.cmb_backup.GetClientData(selection)

    def DelSelectedBkInfo(self):
        selection = self.cmb_backup.Selection

        if selection == wx.NOT_FOUND or self.cmb_backup.Value == '':
            return

        self.cmb_backup.Delete(selection)
        self.cmb_backup.SetSelection(0)

    #--------------------------------------------------------------------------
    # イベント

    @binder(wx.EVT_SIZE, control='MainFrame')
    def OnSize(self, evt):
        if not self._processing_persist:
            w, h = evt.Size
            self.spl_h.SetSashPosition(h / 2)
            self.spl_v.SetSashPosition(w / 2)
            self.spl_log.SetSashPosition(w / 2)

        evt.Skip()

    # ---- ログ

    @binder(wx.EVT_BUTTON, control='BtnClearLog')
    def OnClearLog(self, evt):
        self.log.clear()

    @binder(wx.EVT_CHECKBOX, control='ChkAutoShowLog')
    def OnChangeAutoShowLog(self, evt):
        self.conf.auto_show_log = self.auto_show_log.IsChecked()

    @binder(EVT_LOG_CHANGE)
    def OnLogChange(self, evt):
        if not self.LogIsVisible() and self.conf.auto_show_log:
            self.OnLog(None)

    @binder(wx.EVT_MENU, id='MenuLog')
    @binder(wx.EVT_BUTTON, control='BtnCloseLog')
    def OnLog(self, evt):
        if self.LogIsVisible():
            self.log_sash_pos = self.spl_log.GetSashPosition()
            self.spl_log.Unsplit()
            self.conf.show_log = False
            self.menu.Check(xrc.XRCID('MenuLog'), False)
        else:
            self.spl_log.SplitVertically(self.win1, self.win2, self.log_sash_pos)
            self.conf.show_log = True
            self.menu.Check(xrc.XRCID('MenuLog'), True)

    # ---- マニュアル

    @binder(wx.EVT_MENU, id='MenuManual')
    def OnManual(self, evt):
        webbrowser.open('http://vanya.jp.net/eng/inspause/manual.html')

    # ---- About

    @binder(wx.EVT_MENU, id='MenuAbout')
    def OnAbout(self, evt):
        self.ShowAboutDlg()

    # ----

    # 音声ファイル一覧のクリック
    @binder(wx.EVT_LIST_ITEM_SELECTED, control='FileList')
    def OnSelectSnd(self, evt):
        # 同じファイルは読み直さない
        if self.conf.list_index == evt.m_itemIndex:
            return

        self.ConfirmSave()

        snd_path = os.path.join(self.snd_dir, evt.GetText())
        labels_path = mf.get_labels_path(self.snd_dir, evt.m_itemIndex + 1)
        self.conf.list_index = evt.m_itemIndex

        self.SetSound(snd_path, labels_path)

    # 音声ディレクトリを開く
    @binder(wx.EVT_MENU, id='MenuOpen')
    def OnOpenDir(self, evt=None):
        snd_dir = self.snd_dir

        if not snd_dir:
            snd_dir = mf.get_music_dir()

        if not os.path.exists(snd_dir):
            snd_dir = os.getcwd()

        msg = u'音声フォルダの選択'
        style = wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST

        dlg = wx.DirDialog(self.frame, msg, snd_dir, style)
        if dlg.ShowModal() == wx.ID_OK:
            self.snd_dir = dlg.GetPath()
            self.CheckCanRead()
        dlg.Destroy()

    def CheckCanRead(self):
        '''
        ffmpegがないのにwav以外を読み込もうとした場合に
        メッセージを表示する
        '''

        snd_files = mf.get_snd_files(self.snd_dir)
        if not snd_files and not ffmpeg.has_ffmpeg and \
                mf.exists(self.snd_dir, ffmpeg.EXTENSIONS):
            msg = u'wav形式以外に対応するにはffmpeg.exeを' \
                  u'inspause.exeと同じフォルダに置く必要があります'
            wx.MessageBox(msg, u'wav以外の読み書き')

    # ---- 設定項目

    # FACTOR テキスト変更
    @binder(wx.EVT_TEXT, control='TextFactor')
    def OnFactorChange(self, evt):
        self.conf.factor = float(evt.EventObject.Value)

    # ADD テキスト変更
    @binder(wx.EVT_TEXT, control='TextAdd')
    def OnAddChange(self, evt):
        self.conf.add_s = float(evt.EventObject.Value)

    # -------- ポーズファイル作成

    @binder(wx.EVT_BUTTON, control='BtnSaveDir')
    def OnSaveDir(self, evt):
        msg = u'ポーズ音声の保存先フォルダの選択'
        style = wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST | wx.DD_NEW_DIR_BUTTON
        default_dir = mf.get_default_pause_dir(self.snd_dir)

        dlg = wx.DirDialog(self.frame, msg, default_dir, style)

        if dlg.ShowModal() == wx.ID_OK:
            if dlg.GetPath() == self.snd_dir:
                msg = u'入力音声ファイルと同じ場所には出力できません'
                wx.MessageBox(msg)
                return

            ctrl = xrc.XRCCTRL(self.frame, 'TextSaveDir')
            ctrl.SetValue(dlg.GetPath())

        dlg.Destroy()

    @binder(wx.EVT_BUTTON, control='BtnInsertPause')
    def OnInsertPauseAll(self, evt):
        self.conf.show_save2 = False
        self.InsertPause()

    # -------- ずれ調整

    # ずれ調整スライダーのスクロール
    @binder(wx.EVT_SCROLL, control='ShiftSlider')
    def OnShiftSliderScroll(self, evt):
        lbl_shift = xrc.XRCCTRL(self.frame, 'LblShift')
        lbl_shift.Label = '%.3f%s' % (float(evt.Position) / 1000, u'秒')

        btn_shift = xrc.XRCCTRL(self.frame, 'BtnShift')

        if evt.Position == 0:
            btn_shift.Enabled = False
        else:
            btn_shift.Enabled = True

    @binder(wx.EVT_BUTTON, control='BtnShift')
    def OnShift(self, evt):
        shift_slider = xrc.XRCCTRL(self.frame, 'ShiftSlider')

        val_s = float(shift_slider.Value) / 1000
        self.view.shift(val_s)
        shift_slider.Value = 0

        evt = wx.ScrollEvent()
        evt.Position = shift_slider.Value
        self.OnShiftSliderScroll(evt)

    # -------- バックアップ

    # ポーズ情報コンボボックス
    @binder(wx.EVT_COMBOBOX, control='CmbBackup')
    def OnChangeBackupCmb(self, evt):
        self.EnableBackup()

    # バックアップの作成
    @binder(wx.EVT_BUTTON, control='BtnBackup')
    def OnBackup(self, evt):
        self.Backup()

    # 復元
    @binder(wx.EVT_BUTTON, control='BtnRestore')
    def OnRestore(self, evt):
        self.Restore()

    # 削除
    @binder(wx.EVT_BUTTON, control='BtnDelBackup')
    def OnDelBackup(self, evt):
        self.DelBackup()

    # 自動ずれ調整
    @binder(wx.EVT_BUTTON, control='BtnAutoShift')
    def OnAutoShift(self, evt):
        self.AutoShift()

    # -------- ポーズ再検索

    # 無音認識時間 テキスト変更
    @binder(wx.EVT_TEXT, control='TextSilDur')
    def OnSilDurChange(self, evt):
        self.conf.sil_dur_s = float(evt.EventObject.Value)

    # 無音レベルスライダーのスクロール
    @binder(wx.EVT_SCROLL, control='SilLvSlider')
    def OnSilLvSliderScroll(self, evt):
        pos = max(0, min(evt.Position, 100))
        self.conf.sil_lv = pos

    # 前余裕 テキスト変更
    @binder(wx.EVT_TEXT, control='TextBeforeDur')
    def OnBeforeDurChange(self, evt):
        self.conf.before_dur_s = float(evt.EventObject.Value)

    # 後余裕 テキスト変更
    @binder(wx.EVT_TEXT, control='TextAfterDur')
    def OnAfterDurChange(self, evt):
        self.conf.after_dur_s = float(evt.EventObject.Value)

    @binder(wx.EVT_BUTTON, control='BtnResetSearch')
    def OnResetSearch(self, evt):
        xrc.XRCCTRL(self.frame, 'TextSilDur').Value = str(SIL_DUR_S)
        xrc.XRCCTRL(self.frame, 'SilLvSlider').Value = SIL_LV
        self.conf.sil_lv = SIL_LV
        xrc.XRCCTRL(self.frame, 'TextBeforeDur').Value = str(BEFORE_DUR_S)
        xrc.XRCCTRL(self.frame, 'TextAfterDur').Value = str(AFTER_DUR_S)

    @binder(wx.EVT_BUTTON, control='BtnSearch')
    def OnSearch(self, evt):
        sil_lv = self.conf.sil_lv
        sil_dur = self.conf.sil_dur_s
        before_dur = self.conf.before_dur_s
        after_dur = self.conf.after_dur_s

        self.view.find(sil_lv, sil_dur, before_dur, after_dur)

    # -------- 色

    @binder(wx.EVT_BUTTON, control='BtnBg')
    def OnBgColour(self, evt):
        colour = wx.GetColourFromUser(self.frame, self.conf.bg)
        if colour.IsOk():
            self.SetViewBgColour(colour)
            self.view.UpdateDrawing()

    @binder(wx.EVT_BUTTON, control='BtnFg')
    def OnFgColour(self, evt):
        colour = wx.GetColourFromUser(self.frame, self.conf.fg)
        if colour.IsOk():
            self.SetViewFgColour(colour)
            self.view.UpdateDrawing()

    @binder(wx.EVT_BUTTON, control='BtnResetColour')
    def OnResetColour(self, evt):
        self.SetViewBgColour(BG_COLOUR)
        self.SetViewFgColour(FG_COLOUR)
        self.view.UpdateDrawing()

    # -------- 表示範囲

    @binder(wx.EVT_SLIDER, control='SldScale')
    def OnScaleSlider(self, evt):
        self.conf.scale = self.sld_scale.GetValue()
        self.view.scale = self.conf.scale

    # -------- ファイルリストの幅

    @binder(wx.EVT_SLIDER, control='SldFlistWidth')
    def OnFlistWidth(self, evt):
        self.conf.flist_width = self.sld_flist_width.GetValue()
        self.flist.SetColumnWidth(0, self.conf.flist_width)

    # ---- ツールバー

    # 先頭へ移動
    @binder(wx.EVT_TOOL, id='ToolHead')
    def OnHead(self, evt):
        self.view.head()
        self.EnableUI()

        if self.view.playing:
            self.tool_bar.EnableTool(xrc.XRCID('ToolHead'), True)

        if self.wp.is_playing:
            self.snd.rewind()

    # 再生
    @binder(wx.EVT_TOOL, id='ToolPlay')
    def OnPlay(self, evt):
        self.Play()

    # ポーズモード再生
    @binder(wx.EVT_TOOL, id='ToolPlayPause')
    def OnPausePlay(self, evt):
        self.PausePlay()

    # 一時停止
    @binder(wx.EVT_TOOL, id='ToolPause')
    def OnPause(self, evt):
        self.Pause()

    # 拡大
    @binder(wx.EVT_TOOL, id='ToolZoomIn')
    def OnZoomIn(self, evt):
        self.view.zoom_in()
        self.EnableUI()

    # 縮小
    @binder(wx.EVT_TOOL, id='ToolZoomOut')
    def OnZoomOut(self, evt):
        self.view.zoom_out()
        self.EnableUI()

    # もとに戻す
    @binder(wx.EVT_TOOL, id='ToolUndo')
    def OnUndo(self, evt):
        self.view.undo()
        self.EnableUI()

    # やり直し
    @binder(wx.EVT_TOOL, id='ToolRedo')
    def OnRedo(self, evt):
        self.view.redo()
        self.EnableUI()

    # ポーズ情報保存
    @binder(wx.EVT_MENU, id='MenuSave')
    @binder(wx.EVT_TOOL, id='ToolSaveLabels')
    def OnSaveLabels(self, evt):
        self.view.save()
        self.EnableUI()

    # ポーズ音声出力
    @binder(wx.EVT_TOOL, id='ToolSaveSound')
    def OnSaveSound(self, evt):
        res = wx.MessageBox(u'画面左下「メイン」タブの中の「ポーズ音声作成」ボタンを押してください。', u'メッセージ')


    # ---- メニュー

    # フレームを閉じる
    @binder(wx.EVT_MENU, id='MenuExit')
    @binder(wx.EVT_CLOSE)
    def OnClose(self, evt):
        if self.ConfirmSave(True) == wx.CANCEL:
            evt.Veto()
            return

        self._processing_persist = True

        self.conf.view_factor = self.view.view_factor
        self.conf.scale = self.view.scale
        self.conf.store()
        mf.store_map()

        if not self.spl_log.IsSplit():
            self.frame.Hide()
            # スプリッタの位置を記憶させるために、一時的にスプリッタを表示
            self.spl_log.SplitVertically(self.win1, self.win2, self.log_sash_pos)

        self.pm.SaveAndUnregister()

        self.wp.pause()

        self.frame.Destroy()

    # ---- 自作コントロールイベント

    @binder(EVT_REQ_PLAY)
    def OnReqPlay(self, evt):
        self.Play()
        self.view.UpdateDrawing(2)

    @binder(EVT_REQ_PAUSE_PLAY)
    def OnReqPausePlay(self, evt):
        self.PausePlay()
        self.view.UpdateDrawing(2)

    @binder(EVT_REQ_IFCUT_PLAY)
    def OnReqIfCutPlay(self, evt):
        self.IfcutPlay(evt.GetSec())
        self.view.UpdateDrawing(2)

    @binder(EVT_REQ_PAUSE)
    def OnReqPause(self, evt):
        self.Pause()

    # WavePlayer からの現在位置変更イベント
    @binder(EVT_CUR_POS_CHANGE)
    def OnWPPosChange(self, evt):
        pos_f = self.snd.tell(True)
        self.view.pos_f = pos_f
        self.SetStatusPosText(pos_f)

    # LabelsWindow からの現在位置変更イベント
    @binder(EVT_VW_POS_CHANGE)
    def OnLWPosChange(self, evt):
        self.SetStatusPosText(evt.GetPos())

        if self.wp.is_playing:
            self.snd.setpos(evt.GetPos(), True)

        self.EnableUI()

    @binder(EVT_OPEN_SND)
    def OnOpenSnd(self, evt):
        self.OnOpenDir(None)

    @binder(EVT_STATUS_MSG)
    def OnStatusMsg(self, evt):
        self.statusbar.SetStatusText(evt.GetMsg())

    @binder(EVT_LABEL_CHANGE)
    def OnLabelChange(self, evt):
        self.EnableUI()

    @binder(EVT_SCALE_CHANGE)
    def OnScaleChange(self, evt):
        self.conf.scale = evt.GetPos()
        self.sld_scale.SetValue(self.conf.scale)

    @binder(EVT_EOW)
    def OnEOW(self, evt):
        self.view.playing = False
        self.view.pos_f = self.pos_f_after_eow
        self.EnableUI()

    #--------------------------------------------------------------------------
    # プロパティ

    # ---- 音声ディレクトリ名

    @property
    def snd_dir(self):
        return self.conf.snd_dir

    @snd_dir.setter
    def snd_dir(self, snd_dir):
        if snd_dir != self.snd_dir:
            self.conf.list_index = 0
            self.conf.snd_dir = snd_dir

            self.snd = None
            self.view.SetVolume(None)

            self.frame.Title = APP_NAME
            self.UpdateFlist()
            self.SetDefaultSaveDir()
            self.EnableUI()
Ejemplo n.º 48
0
			ret = op.mount_backup(options.drive, options.backup_dir)
			logger.info(ret)
		if 1:
			logger.info("* Creating Subvolume")
			ret = op.create_subvol(latest_dir)
			logger.info(ret)

		sys.exit(0)

	if options.subcommand == 'backup':
		from disks import Disks
		disks = Disks()
		di = disks.create_disk_info( options.drive )
	
		from backup import Backup
		backup = Backup(di, options.source_dir)
		backup.do_backup()

		sys.exit(0)

	if options.subcommand == 'delete':
		from disks import Disks
		disks = Disks()
		di = disks.create_disk_info( options.drive )
		
		from backup import Backup
		backup = Backup(di)
		backup.delete_backup(options.date)

		sys.exit(0)
Ejemplo n.º 49
0
def cron_backup(title):
    """
    Make backup, send it to the user@server:directory and update the stamp
    file.

    The backup is made if STAMP[title] is greater than backup.get_stamp()
    """
    global STAMPS
    backup = Backup(title, config[title], search=False, keep=True)
    stamp = backup.get_stamp()
    STAMP = STAMPS.get(title, 0)
    if options.verbose:
        print("state=%s" % backup.state)
        print("[%s] stamp=%f (%s)"
              % (title, stamp,
                 time.strftime("%x %X %Z", time.localtime(stamp))))
        STAMPS_dict = dict(
            map(lambda item: (item[0],
                              time.strftime("%x %X %Z",
                                            time.localtime(item[1]))),
                STAMPS.iteritems()))
        print("[%s] STAMP=%f (%s)" % (title,
                                      STAMP,
                                      STAMPS_dict.get(title, 0)))
        print("STAMP > stamp: %s" % (STAMP > stamp))
    if STAMP > stamp:
        if options.verbose:
            print("[%s] FIND_FILES" % title)
        backup.find_files()
        backup.time = STAMP
        if options.verbose:
            print("[%s] MAKE_BACKUP" % title)
        backup.make_backup()
        backup.log('fsize')
        if options.verbose:
            print("[%s] PUT" % title)
        backup.put()
        msg = "INFO: [%s] backuped to: \"%s\"" % (title, str(backup))
        log(msg)
        if options.verbose:
            print(msg)
Ejemplo n.º 50
0
def main(args=None):
    """ Main: parse arguments and run. """

    parser = ArgumentParser(
        description=DESCRIPTION,
        epilog=EPILOG,
        formatter_class=argparse.RawDescriptionHelpFormatter
    )
    parser.add_argument(
        'path', action='store',
        type=dir_argument,
        help='path to wordpress instance'
    )
    parser.add_argument(
        '-v', '--verbose', action='store_const',
        dest='loglevel', const=logging.INFO, default=logging.WARN,
        help='enable log messages'
    )
    parser.add_argument(
        '-d', '--debug', action='store_const',
        dest='loglevel', const=logging.DEBUG, default=logging.WARN,
        help='enable debug messages'
    )
    parser.add_argument(
        '-q', '--quiet', action='store_true',
        help='do not print status messages'
    )
    parser.add_argument(
        '--dry', action='store_true',
        help='perform dry run: do not store or delete any archives'
    )
    parser.add_argument(
        '--database', action='store_true',
        help='backup wordpress database'
    )
    parser.add_argument(
        '--filesystem', action='store_true',
        help='backup wordpress filesystem'
    )
    parser.add_argument(
        '--thinning', action='store', metavar='STRATEGY',
        type=functools.partial(value_argument, callee=ThinningStrategy.fromArgument),
        help='thin out backups at targets (except local target) using the specified strategy'
    )

    group_db = parser.add_argument_group(
        'database backup options', ''
    )
    group_db.add_argument(
        '--db', action='store', metavar='NAME',
        help='name for wordpress db'
    )
    group_db.add_argument(
        '--dbhost', action='store', metavar='HOST',
        help='hostname for wordpress db'
    )
    group_db.add_argument(
        '--dbport', action='store', metavar='PORT',
        type=int,
        help='portnumber for wordpress db'
    )
    group_db.add_argument(
        '--dbuser', action='store', metavar='USER',
        help='username for wordpress db'
    )
    group_db.add_argument(
        '--dbpass', action='store', metavar='PASS',
        help='password for wordpress db'
    )
    group_db.add_argument(
        '--dbprefix', action='store', metavar='PREFIX',
        help='prefix for table names in wordpress db'
    )

    group_local = parser.add_argument_group(
        'local target',
        'options for storing the backup archive on local filesystem'
    )
    group_local.add_argument(
        '--attic', action='store', metavar='DIR',
        nargs='?', const='.', default=None,
        type=dir_argument,
        help='local directory to store backup archive'
    )

    group_s3 = parser.add_argument_group(
        's3 target',
        'options for copying the backup archive to a s3 service'
    )
    group_s3.add_argument(
        '--s3', action='store', metavar='HOST',
        help='host for s3 server'
    )
    group_s3.add_argument(
        '--s3accesskey', action='store', metavar='KEY',
        help='access key for s3 server'
    )
    group_s3.add_argument(
        '--s3secretkey', action='store', metavar='KEY',
        help='secret key for s3 server'
    )
    group_s3.add_argument(
        '--s3bucket', action='store', metavar='BUCKET',
        help='bucket at s3 server'
    )

    group_report = parser.add_argument_group(
        'report options', ''
    )
    group_report.add_argument(
        '--mail-from', action='store', metavar='MAIL',
        help='sender address for report mails'
    )
    group_report.add_argument(
        '--mail-to-admin', action='store_true',
        help='send report to wordpress administrator'
    )
    group_report.add_argument(
        '--mail-to', action='store', metavar='MAIL',
        help='recipient address for report mails'
    )

    arguments = parser.parse_args() if args is None else parser.parse_args(args)

    # logging
    import coloredlogs
    coloredlogs.install(
        level=arguments.loglevel,
        format='%(asctime)s - %(filename)s:%(funcName)s - %(levelname)s - %(message)s',
        isatty=True
    )

    # initialize source

    try:
        source = SourceFactory(arguments.path).create(
            dbname=arguments.db,
            dbhost=arguments.dbhost,
            dbport=arguments.dbport,
            dbuser=arguments.dbuser,
            dbpass=arguments.dbpass,
            dbprefix=arguments.dbprefix
        )
    except SourceErrors as exception:
        logging.error("Site-Backup: {}".format(exception))
        sys.exit(1)
    else:
        logging.info("Site-Backup: Source is %s" % (source))

    # initialize targets

    targets = []

    if arguments.s3:
        # transfer backup to s3 service
        s3target = S3(
            arguments.s3,
            arguments.s3accesskey,
            arguments.s3secretkey,
            arguments.s3bucket if arguments.s3bucket else source.slug
        )
        targets.append(s3target)

    for target in targets:
        logging.info("Site-Backup: Target is %s" % (target))

    # initialize options

    mailer = Mailer() if arguments.mail_from else None
    if mailer:
        if arguments.mail_to_admin:
            mailer.addRecipient(Recipient(source.email))
        if arguments.mail_to:
            mailer.addRecipient(Recipient(arguments.mail_to))
        mailer.setSender(Sender(arguments.mail_from))

    # initialize and execute backup

    backup = Backup(source, mailer=mailer, quiet=arguments.quiet)
    backup.execute(
        targets=targets,
        database=arguments.database,
        filesystem=arguments.filesystem,
        thinning=arguments.thinning,
        attic=arguments.attic,
        dry=arguments.dry
    )


    if backup.error:
        logging.error("Site-Backup: {}".format(backup.error))
        sys.exit(1)
Ejemplo n.º 51
0
 def __init__( self, methodName = 'runTest' ):
     unittest.TestCase.__init__( self, methodName )
     self.backup = Backup("VIM", config["VIM"], search=False, keep=True )
     self.backup.compression = None
Ejemplo n.º 52
0
def backup_create(name, service_name, mounted_dir, namespace):
    service = Service.fetch(service_name, namespace)
    backup = Backup(service=service, name=name, mounted_dir=mounted_dir)
    backup.create()
Ejemplo n.º 53
0
class PasswordMap(object):
	"""Storage of groups of passwords in memory"""
	
	def __init__(self, trezor):
		assert trezor is not None
		self.groups = {}
		self.trezor = trezor
		self.outerKey = None # outer AES-CBC key
		self.outerIv = None  # IV for data blob encrypted with outerKey
		self.backupKey = None
	
	def addGroup(self, groupName):
		"""
		Add group by name as utf-8 encoded string
		"""
		groupName = groupName
		if groupName in self.groups:
			raise KeyError("Password group already exists")
		
		self.groups[groupName] = PasswordGroup()

	def load(self, fname):
		"""
		Load encrypted passwords from disk file, decrypt outer
		layer containing key names. Requires Trezor connected.
		
		@throws IOError: if reading file failed
		"""
		with file(fname) as f:
			header = f.read(len(Magic.headerStr))
			if header != Magic.headerStr:
				raise IOError("Bad header in storage file")
			version = f.read(4)
			if len(version) != 4 or struct.unpack("!I", version)[0] != 1:
				raise IOError("Unknown version of storage file")
			wrappedKey = f.read(KEYSIZE)
			if len(wrappedKey) != KEYSIZE:
				raise IOError("Corrupted disk format - bad wrapped key length")
			
			self.outerKey = self.unwrapKey(wrappedKey)
			
			self.outerIv = f.read(BLOCKSIZE)
			if len(self.outerIv) != BLOCKSIZE:
				raise IOError("Corrupted disk format - bad IV length")
			
			lb = f.read(2)
			if len(lb) != 2:
				raise IOError("Corrupted disk format - bad backup key length")
			lb = struct.unpack("!H", lb)[0]
			
			self.backupKey = Backup(self.trezor)
			serializedBackup = f.read(lb)
			if len(serializedBackup) != lb:
				raise IOError("Corrupted disk format - not enough encrypted backup key bytes")
			self.backupKey.deserialize(serializedBackup)
			
			ls = f.read(4)
			if len(ls) != 4:
				raise IOError("Corrupted disk format - bad data length")
			l = struct.unpack("!I", ls)[0]
			
			encrypted = f.read(l)
			if len(encrypted) != l:
				raise IOError("Corrupted disk format - not enough data bytes")
			
			hmacDigest = f.read(MACSIZE)
			if len(hmacDigest) != MACSIZE:
				raise IOError("Corrupted disk format - HMAC not complete")
			
			#time-invariant HMAC comparison that also works with python 2.6
			newHmacDigest = hmac.new(self.outerKey, encrypted, hashlib.sha256).digest()
			hmacCompare = 0
			for (ch1, ch2) in zip(hmacDigest, newHmacDigest):
				hmacCompare |= int(ch1 != ch2)
			if hmacCompare != 0:
				raise IOError("Corrupted disk format - HMAC does not match or bad passphrase")
				
			serialized = self.decryptOuter(encrypted, self.outerIv)
			self.groups = cPickle.loads(serialized)
	
	def save(self, fname):
		"""
		Write password database to disk, encrypt it. Requires Trezor
		connected.
		
		@throws IOError: if writing file failed
		"""
		assert len(self.outerKey) == KEYSIZE
		rnd = Random.new()
		self.outerIv = rnd.read(BLOCKSIZE)
		wrappedKey = self.wrapKey(self.outerKey)
		
		with file(fname, "wb") as f:
			version = 1
			f.write(Magic.headerStr)
			f.write(struct.pack("!I", version))
			f.write(wrappedKey)
			f.write(self.outerIv)
			serialized = cPickle.dumps(self.groups, cPickle.HIGHEST_PROTOCOL)
			encrypted = self.encryptOuter(serialized, self.outerIv)
			
			hmacDigest = hmac.new(self.outerKey, encrypted, hashlib.sha256).digest()
			serializedBackup = self.backupKey.serialize()
			lb = struct.pack("!H", len(serializedBackup))
			f.write(lb)
			f.write(serializedBackup)
			l = struct.pack("!I", len(encrypted))
			f.write(l)
			f.write(encrypted)
			f.write(hmacDigest)
			
			f.flush()
			f.close()
			
	def encryptOuter(self, plaintext, iv):
		"""
		Pad and encrypt with self.outerKey
		"""
		return self.encrypt(plaintext, iv, self.outerKey)
	
	def encrypt(self, plaintext, iv, key):
		"""
		Pad plaintext with PKCS#5 and encrypt it.
		"""
		cipher = AES.new(key, AES.MODE_CBC, iv)
		padded = Padding(BLOCKSIZE).pad(plaintext)
		return cipher.encrypt(padded)
	
	def decryptOuter(self, ciphertext, iv):
		"""
		Decrypt with self.outerKey and unpad
		"""
		return self.decrypt(ciphertext, iv, self.outerKey)
		
	def decrypt(self, ciphertext, iv, key):
		"""
		Decrypt ciphertext, unpad it and return
		"""
		cipher = AES.new(key, AES.MODE_CBC, iv)
		plaintext = cipher.decrypt(ciphertext)
		unpadded = Padding(BLOCKSIZE).unpad(plaintext)
		return unpadded
	
	def unwrapKey(self, wrappedOuterKey):
		"""
		Decrypt wrapped outer key using Trezor.
		"""
		ret = self.trezor.decrypt_keyvalue(Magic.unlockNode, Magic.unlockKey, wrappedOuterKey, ask_on_encrypt=False, ask_on_decrypt=True)
		return ret
		
	def wrapKey(self, keyToWrap):
		"""
		Encrypt/wrap a key. Its size must be multiple of 16.
		"""
		ret = self.trezor.encrypt_keyvalue(Magic.unlockNode, Magic.unlockKey, keyToWrap, ask_on_encrypt=False, ask_on_decrypt=True)
		return ret
		
	def encryptPassword(self, password, groupName):
		"""
		Encrypt a password. Does PKCS#5 padding before encryption.
		Store IV as first block.
		
		@param groupName key that will be shown to user on Trezor and
			used to encrypt the password. A string in utf-8
		"""
		rnd = Random.new()
		rndBlock = rnd.read(BLOCKSIZE)
		padded = Padding(BLOCKSIZE).pad(password)
		ugroup = groupName.decode("utf-8")
		ret = rndBlock + self.trezor.encrypt_keyvalue(Magic.groupNode, ugroup, padded, ask_on_encrypt=False, ask_on_decrypt=True, iv=rndBlock)
		return ret
		
	def decryptPassword(self, encryptedPassword, groupName):
		"""
		Decrypt a password. First block is IV. After decryption strips PKCS#5 padding.
		
		@param groupName key that will be shown to user on Trezor and
			was used to encrypt the password. A string in utf-8.
		"""
		ugroup = groupName.decode("utf-8")
		iv, encryptedPassword = encryptedPassword[:BLOCKSIZE], encryptedPassword[BLOCKSIZE:]
		plain = self.trezor.decrypt_keyvalue(Magic.groupNode, ugroup, encryptedPassword, ask_on_encrypt=False, ask_on_decrypt=True, iv=iv)
		password = Padding(BLOCKSIZE).unpad(plain)
		return password