def test_no_briefcase_section(): "If the config file doesn't contain a briefcase tool section, raise an error" config_file = StringIO( """ [tool.section] name="value" number=42 """ ) with pytest.raises(BriefcaseConfigError, match="No tool.briefcase section"): parse_config(config_file, platform='macOS', output_format='xcode')
def test_no_apps(): "If the config file doesn't contain at least one briefcase app, raise an error" config_file = StringIO( """ [tool.briefcase] name="value" number=42 """ ) with pytest.raises(BriefcaseConfigError, match="No Briefcase apps defined"): parse_config(config_file, platform='macOS', output_format='xcode')
def test_no_briefcase_section(): """If the config file doesn't contain a briefcase tool section, raise an error.""" config_file = BytesIO(b""" [tool.section] name="value" number=42 """) with pytest.raises(BriefcaseConfigError, match="No tool.briefcase section"): parse_config(config_file, platform="macOS", output_format="xcode")
def parse_config(self, filename): try: with open(filename, "rb") as config_file: # Parse the content of the pyproject.toml file, extracting # any platform and output format configuration for each app, # creating a single set of configuration options. global_config, app_configs = parse_config( config_file, platform=self.platform, output_format=self.output_format, ) self.global_config = create_config( klass=self.GLOBAL_CONFIG_CLASS, config=global_config, msg="Global configuration", ) for app_name, app_config in app_configs.items(): # Construct an AppConfig object with the final set of # configuration options for the app. self.apps[app_name] = create_config( klass=self.APP_CONFIG_CLASS, config=app_config, msg=f"Configuration for '{app_name}'", ) except FileNotFoundError as e: raise BriefcaseConfigError("configuration file not found") from e
def test_single_minimal_app(): "A single app can be defined, but can exist without any app attributes" config_file = StringIO( """ [tool.briefcase] value = 42 [tool.briefcase.app.my_app] """ ) global_options, apps = parse_config(config_file, platform='macOS', output_format='xcode') # There's a single global option assert global_options == { 'value': 42 } # The app gets the name from it's header line. # It inherits the value from the base definition. assert apps == { 'my_app': { "app_name": "my_app", "value": 42 } }
def test_multiple_minimal_apps(): "The configuration can contain multiple apps without an explicit tool header" config_file = StringIO( """ [tool.briefcase.app.first] number=37 [tool.briefcase.app.second] app_name="my_app" number=42 """ ) global_options, apps = parse_config(config_file, platform='macOS', output_format='xcode') # There are no global options assert global_options == {} # The apps gets their name from the header lines. # The second tool overrides it's app name assert apps == { 'first': { "app_name": "first", "number": 37, }, 'second': { "app_name": "my_app", "number": 42, }, }
def test_platform_override(): "An app can define platform settings that override base settings" config_file = StringIO(""" [build-system] requires = ["briefcase"] [tool.briefcase] value = 0 basevalue = "the base" [tool.briefcase.app.my_app] value = 1 appvalue = "the app" [tool.briefcase.app.my_app.macOS] value = 2 platformvalue = "macos platform" [tool.briefcase.app.my_app.linux] value = 3 platformvalue = "linux platform" [tool.briefcase.app.other_app.macOS] value = 4 platformvalue = "other macos platform" """) global_options, apps = parse_config(config_file, platform='macOS', output_format='app') # The global options are exactly as specified assert global_options == { 'value': 0, 'basevalue': 'the base', } # Since a macOS app has been requested, the macOS platform values # take priority. Linux configuration values are dropped. # The second app doesn't provide an explicit app-level config, but # the app exists because the platform exists. # Platforms should be processed in sorted order, which means that linux # will be processed before macos. assert apps == { 'my_app': { "name": "my_app", "value": 2, "basevalue": "the base", "appvalue": "the app", "platformvalue": "macos platform", }, 'other_app': { "name": "other_app", "value": 4, "basevalue": "the base", "platformvalue": "other macos platform", } }
def test_platform_override_ordering(): "The order of platform processing doesn't affect output" config_file = StringIO( """ [tool.briefcase] value = 0 basevalue = "the base" [tool.briefcase.app.my_app] value = 1 appvalue = "the app" [tool.briefcase.app.my_app.macOS] value = 2 platformvalue = "macos platform" [tool.briefcase.app.my_app.windows] value = 3 platformvalue = "windows platform" [tool.briefcase.app.other_app.macOS] value = 4 platformvalue = "other macos platform" """ ) global_options, apps = parse_config(config_file, platform='macOS', output_format='xcode') # The global options are exactly as specified assert global_options == { 'value': 0, 'basevalue': "the base" } # Since a macOS app has been requested, the macOS platform values # take priority. Linux configuration values are dropped. # The second app doesn't provide an explicit app-level config, but # the app exists because the platform exists. # Platforms should be processed in order, which means that windows # will be processed after macos. assert apps == { 'my_app': { "app_name": "my_app", "value": 2, "basevalue": "the base", "appvalue": "the app", "platformvalue": "macos platform", }, 'other_app': { "app_name": "other_app", "value": 4, "basevalue": "the base", "platformvalue": "other macos platform", } }
def test_document_types(): "Document types can be specified" config_file = StringIO(""" [build-system] requires = ["briefcase"] [tool.briefcase] value = 0 [tool.briefcase.app.my_app] [tool.briefcase.app.my_app.macOS] [tool.briefcase.app.my_app.macOS.document_type.document] extension = "doc" description = "A document" [tool.briefcase.app.my_app.macOS.document_type.image] extension = "img" description = "An image" [tool.briefcase.app.other_app] """) # Request a macOS app global_options, apps = parse_config(config_file, platform='macOS', output_format='app') # The macOS my_app app specifies a full inherited chain. # The other_app app doesn't specify any options. assert apps == { 'my_app': { "name": "my_app", "document_type": { 'document': { 'extension': 'doc', 'description': 'A document', }, 'image': { 'extension': 'img', 'description': 'An image', } }, "value": 0, }, 'other_app': { "name": "other_app", "value": 0, } }
def get_executable(): from briefcase.config import parse_config with open(ROOT / "pyproject.toml") as ff: _, appconfig = parse_config(ff, sys.platform, "") version = appconfig[APPNAME]["version"] if platform.system() == "Windows": exe = ["briefcase", "run"] else: exe = [ Path(__file__).parents[1] / "linux" / f"{APPNAME}-{version}-x86_64.AppImage" ] return exe
def cmd_install(*args, **kwargs): runCommand(f"python -m pip install -U pip") # runCommand("pip install https://github.com/jgirardet/briefcase/archive/docker-tty.zip") runCommand(f"pip install -r requirements.txt") try: from briefcase.config import parse_config except ModuleNotFoundError: runCommand("python run.py install") return with open("pyproject.toml") as ff: _, appconfig = parse_config(ff, sys.platform, "") reqs = [f'"{r}"' for r in appconfig["mycartable"]["requires"]] runCommand(f"pip install {' '.join(reqs)}")
def test_document_types(): """Document types can be specified.""" config_file = BytesIO(b""" [tool.briefcase] value = 0 [tool.briefcase.app.my_app] [tool.briefcase.app.my_app.macOS] [tool.briefcase.app.my_app.macOS.document_type.document] extension = "doc" description = "A document" [tool.briefcase.app.my_app.macOS.document_type.image] extension = "img" description = "An image" [tool.briefcase.app.other_app] """) # Request a macOS app global_options, apps = parse_config(config_file, platform="macOS", output_format="xcode") # The macOS my_app app specifies a full inherited chain. # The other_app app doesn't specify any options. assert apps == { "my_app": { "app_name": "my_app", "document_type": { "document": { "extension": "doc", "description": "A document", }, "image": { "extension": "img", "description": "An image", }, }, "value": 0, }, "other_app": { "app_name": "other_app", "value": 0, }, }
def cmd_version(*args, **kwargs): from briefcase.config import parse_config from git import Repo vcs = Repo(".") if vcs.is_dirty(): raise EnvironmentError("Il reste des changements non validés") if vcs.active_branch.name != "master": raise EnvironmentError("Le changement de version doit s'effectuer sur master") with open("pyproject.toml") as ff: _, appconfig = parse_config(ff, sys.platform, "") version = appconfig[PACKAGE_NAME]["version"] vcs.create_tag(version) print(f"tag {version} créé")
def pytest_cmdline_main(config): "Parse the command line, adding the sys.path entries needed to support the app" app_name = config.getoption("app") platform = config.getoption("platform") # Load the platform module and determine the default output format. platforms = get_platforms() platform_module = platforms[platform] # Determine the output format to target try: output_format = config.getoption("output_format") except ValueError: output_format = platform_module.DEFAULT_OUTPUT_FORMAT # Load the application config from the pyproject.toml # in the pytest rootdir _, app_configs = parse_config(config.rootdir / 'pyproject.toml', platform=platform, output_format=output_format) # If no app name has been provided, check to see if there is # a single app in the project. If there is, use it. Otherwise, # raise an error. # If an app name has been provided, load that app config. if app_name == '*': if len(app_configs) == 1: app = AppConfig(**list(app_configs.values())[0]) else: raise BriefcasePytestConfigError( 'More than one app in the porject. Specify an app name with --app' ) else: try: app = AppConfig(**app_configs[app_name]) except KeyError: raise BriefcasePytestConfigError( "'{app_name}' is not an app name in this project".format( app_name=app_name)) # Process the `sources` list for the app, adding to the pythonpath. # This matches the PYTHONPATH configuration done by `briefcase dev` for path in app.PYTHONPATH: sys.path.insert(0, str(config.rootdir / path))
def test_invalid_toml(): "If the config file isn't TOML, raise an error" config_file = StringIO("this is not toml!") with pytest.raises(BriefcaseConfigError, match="Invalid pyproject.toml"): parse_config(config_file, platform='macOS', output_format='xcode')
def test_invalid_toml(): """If the config file isn't TOML, raise an error.""" config_file = BytesIO(b"this is not toml!") with pytest.raises(BriefcaseConfigError, match="Invalid pyproject.toml"): parse_config(config_file, platform="macOS", output_format="xcode")
def test_format_override(): "An app can define format settings that override base and platform settings" config_file = StringIO(""" [build-system] requires = ["briefcase"] [tool.briefcase] value = 0 basevalue = "the base" [tool.briefcase.app.my_app] value = 1 appvalue = "the app" [tool.briefcase.app.my_app.macOS] value = 2 platformvalue = "macos platform" [tool.briefcase.app.my_app.macOS.app] value = 21 formatvalue = "app format" [tool.briefcase.app.my_app.macOS.dmg] value = 22 formatvalue = "dmg format" [tool.briefcase.app.my_app.macOS.homebrew] value = 23 formatvalue = "homebrew format" [tool.briefcase.app.my_app.linux] value = 3 platformvalue = "linux platform" [tool.briefcase.app.my_app.linux.snap] value = 31 formatvalue = "snap format" [tool.briefcase.app.my_app.linux.appimage] value = 32 formatvalue = "appimage format" [tool.briefcase.app.other_app.macOS.app] value = 41 formatvalue = "other macos app format" """) global_options, apps = parse_config(config_file, platform='macOS', output_format='app') # The global options are exactly as specified assert global_options == {'value': 0, 'basevalue': "the base"} # Since a macOS app has been requested, the macOS app format values # take priority. Linux configuration values are dropped. # The second app doesn't provide an explicit app-level config, but # the app exists because the platform exists. # Formats should be processed in order, which means that app # will be processed before dmg and homebrew. assert apps == { 'my_app': { "name": "my_app", "value": 21, "basevalue": "the base", "appvalue": "the app", "platformvalue": "macos platform", "formatvalue": "app format", }, 'other_app': { "name": "other_app", "value": 41, "basevalue": "the base", "formatvalue": "other macos app format", } }
def test_requires(): "Requirements can be specified" config_file = StringIO( """ [tool.briefcase] value = 0 requires = ["base value"] [tool.briefcase.app.my_app] requires = ["my_app value"] [tool.briefcase.app.my_app.macOS] requires = ["macos value"] [tool.briefcase.app.my_app.macOS.xcode] requires = ["xcode value"] [tool.briefcase.app.my_app.macOS.app] requires = ["app value"] [tool.briefcase.app.my_app.linux] requires = ["linux value"] [tool.briefcase.app.my_app.linux.appimage] requires = ["appimage value"] [tool.briefcase.app.other_app] """ ) # Request a macOS app global_options, apps = parse_config(config_file, platform='macOS', output_format='app') # The global options are exactly as specified assert global_options == { 'value': 0, 'requires': ["base value"], } # The macOS my_app app specifies a full inherited chain. # The other_app app doesn't specify any options. assert apps == { 'my_app': { "app_name": "my_app", "requires": [ "base value", "my_app value", "macos value", "app value", ], "value": 0, }, 'other_app': { "app_name": "other_app", "requires": [ "base value", ], "value": 0, } } # Request a macOS xcode project config_file.seek(0) global_options, apps = parse_config(config_file, platform='macOS', output_format='xcode') # The global options are exactly as specified assert global_options == { 'value': 0, 'requires': ["base value"] } # The macOS my_app dmg specifies a full inherited chain. # The other_app dmg doesn't specify any options. assert apps == { 'my_app': { "app_name": "my_app", "requires": [ "base value", "my_app value", "macos value", "xcode value", ], "value": 0, }, 'other_app': { "app_name": "other_app", "requires": [ "base value", ], "value": 0, } } config_file.seek(0) global_options, apps = parse_config(config_file, platform='linux', output_format='appimage') # The global options are exactly as specified assert global_options == { 'value': 0, 'requires': ["base value"] } # The linux my_app appimage overrides the *base* value, but extends for linux. assert apps == { 'my_app': { "app_name": "my_app", "requires": [ "base value", "my_app value", "linux value", "appimage value", ], "value": 0, }, 'other_app': { "app_name": "other_app", "requires": [ "base value", ], "value": 0, } }
def test_format_override_ordering(): "The order of format processing doesn't affect output" config_file = StringIO( """ [tool.briefcase] value = 0 basevalue = "the base" [tool.briefcase.app.my_app] value = 1 appvalue = "the app" [tool.briefcase.app.my_app.macOS] value = 2 platformvalue = "macos platform" [tool.briefcase.app.my_app.macOS.xcode] value = 21 formatvalue = "app format" [tool.briefcase.app.my_app.macOS.app] value = 22 formatvalue = "app format" [tool.briefcase.app.my_app.macOS.homebrew] value = 23 formatvalue = "homebrew format" [tool.briefcase.app.my_app.linux] value = 3 platformvalue = "linux platform" [tool.briefcase.app.my_app.linux.snap] value = 31 formatvalue = "snap format" [tool.briefcase.app.my_app.linux.appimage] value = 32 formatvalue = "appimage format" [tool.briefcase.app.other_app.macOS.xcode] value = 41 formatvalue = "other macos app format" """ ) global_options, apps = parse_config(config_file, platform='macOS', output_format='app') # The global options are exactly as specified assert global_options == { 'value': 0, 'basevalue': "the base" } # Since a macOS dmg has been requested, the macOS dmg format values # take priority. Linux configuration values are dropped. # The second app doesn't provide an explicit app-level config, but # the app exists because the platform exists. # Formats should be processed in order, which means that dmg # will be processed after app, but before homebrew. assert apps == { 'my_app': { "app_name": "my_app", "value": 22, "basevalue": "the base", "appvalue": "the app", "platformvalue": "macos platform", "formatvalue": "app format", }, 'other_app': { "app_name": "other_app", "value": 0, "basevalue": "the base", } }