diff --git a/beetsplug/permissions.py b/beetsplug/permissions.py index 256f09e52..afff3ce38 100644 --- a/beetsplug/permissions.py +++ b/beetsplug/permissions.py @@ -6,10 +6,13 @@ like the following in your config.yaml to configure: permissions: file: 644 + dir: 755 """ import os +from collections import OrderedDict from beets import config, util from beets.plugins import BeetsPlugin +from beets.util import displayable_path def convert_perm(perm): @@ -28,13 +31,43 @@ def check_permissions(path, permission): return oct(os.stat(path).st_mode & 0o777) == oct(permission) +def get_music_directories(music_directory, imported_item): + """Creates a list of directories the imported item is in. + """ + # Checks for the directory in config and if it has a tilde in it. + # If its that way it will be expanded to the full path. + if '~' in music_directory: + music_directory = os.path.expanduser(music_directory) + + # Getting the absolute path of the directory. + music_directory = os.path.abspath(music_directory) + + # Creates a differential path list of the directory config path and + # the path of the imported item. + differential_path_list = os.path.split( + displayable_path(imported_item).split( + music_directory)[1])[0].split('/')[1:] + + # Creating a list with full paths of all directories in the music library + # we need to look at for chaning permissions. + directory_list = [] + for path in differential_path_list: + if len(directory_list) > 0: + directory_list.append(os.path.join(directory_list[-1], path)) + else: + directory_list.append(os.path.join(music_directory, path)) + + return directory_list + + class Permissions(BeetsPlugin): def __init__(self): super(Permissions, self).__init__() # Adding defaults. self.config.add({ - u'file': 644 + u'file': 644, + u'dir': 755 }) @@ -45,21 +78,25 @@ def permissions(lib, item=None, album=None): """ # Getting the config. file_perm = config['permissions']['file'].get() + dir_perm = config['permissions']['dir'].get() - # Converts file permissions to oct. + # Converts permissions to oct. file_perm = convert_perm(file_perm) + dir_perm = convert_perm(dir_perm) # Create chmod_queue. - chmod_queue = [] + file_chmod_queue = [] if item: - chmod_queue.append(item.path) + file_chmod_queue.append(item.path) elif album: for album_item in album.items(): - chmod_queue.append(album_item.path) + file_chmod_queue.append(album_item.path) - # Setting permissions for every path in the queue. - for path in chmod_queue: - # Changing permissions on the destination path. + # A list of directories to set permissions for. + dir_chmod_queue = [] + + for path in file_chmod_queue: + # Changing permissions on the destination file. os.chmod(util.bytestring_path(path), file_perm) # Checks if the destination path has the permissions configured. @@ -67,3 +104,26 @@ def permissions(lib, item=None, album=None): message = 'There was a problem setting permission on {}'.format( path) print(message) + + # Adding directories to the chmod queue. + dir_chmod_queue.append( + get_music_directories(config['directory'].get(), path)) + + # Unpack sublists. + dir_chmod_queue = [directory + for dir_list in dir_chmod_queue + for directory in dir_list] + + # Get rid of the duplicates. + dir_chmod_queue = list(OrderedDict.fromkeys(dir_chmod_queue)) + + # Change permissions for the directories. + for path in dir_chmod_queue: + # Chaning permissions on the destination directory. + os.chmod(util.bytestring_path(path), dir_perm) + # Checks if the destination path has the permissions configured. + + if not check_permissions(util.bytestring_path(path), dir_perm): + message = 'There was a problem setting permission on {}'.format( + path) + print(message) diff --git a/test/test_permissions.py b/test/test_permissions.py index 1e16a1c34..9f24820d6 100644 --- a/test/test_permissions.py +++ b/test/test_permissions.py @@ -5,7 +5,9 @@ from __future__ import (division, absolute_import, print_function, from test._common import unittest from test.helper import TestHelper -from beetsplug.permissions import check_permissions, convert_perm +from beetsplug.permissions import (check_permissions, + convert_perm, + get_music_directories) class PermissionsPluginTest(unittest.TestCase, TestHelper): @@ -14,7 +16,8 @@ class PermissionsPluginTest(unittest.TestCase, TestHelper): self.load_plugins('permissions') self.config['permissions'] = { - 'file': 777} + 'file': 777, + 'dir': 777} def tearDown(self): self.teardown_beets() @@ -24,23 +27,45 @@ class PermissionsPluginTest(unittest.TestCase, TestHelper): self.importer = self.create_importer() self.importer.run() item = self.lib.items().get() - config_perm = self.config['permissions']['file'].get() - config_perm = convert_perm(config_perm) - self.assertTrue(check_permissions(item.path, config_perm)) + file_perm = self.config['permissions']['file'].get() + file_perm = convert_perm(file_perm) + + dir_perm = self.config['permissions']['dir'].get() + dir_perm = convert_perm(dir_perm) + + music_dirs = get_music_directories(self.config['directory'].get(), + item.path) + + self.assertTrue(check_permissions(item.path, file_perm)) self.assertFalse(check_permissions(item.path, convert_perm(644))) + for path in music_dirs: + self.assertTrue(check_permissions(path, dir_perm)) + self.assertFalse(check_permissions(path, convert_perm(644))) + def test_permissions_on_item_imported(self): self.config['import']['singletons'] = True self.importer = self.create_importer() self.importer.run() item = self.lib.items().get() - config_perm = self.config['permissions']['file'].get() - config_perm = convert_perm(config_perm) - self.assertTrue(check_permissions(item.path, config_perm)) + file_perm = self.config['permissions']['file'].get() + file_perm = convert_perm(file_perm) + + dir_perm = self.config['permissions']['dir'].get() + dir_perm = convert_perm(dir_perm) + + music_dirs = get_music_directories(self.config['directory'].get(), + item.path) + + self.assertTrue(check_permissions(item.path, file_perm)) self.assertFalse(check_permissions(item.path, convert_perm(644))) + for path in music_dirs: + self.assertTrue(check_permissions(path, dir_perm)) + self.assertFalse(check_permissions(path, convert_perm(644))) + def suite(): return unittest.TestLoader().loadTestsFromName(__name__)