#!/usr/bin/env python
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
"""
Creates
and/
or modifies a Firefox profile.
The profile can be modified by passing
in addons to install
or preferences to set.
If no profile
is specified, a new profile
is created
and the path of the
resulting profile
is printed.
"""
import sys
from optparse
import OptionParser
from .prefs
import Preferences
from .profile
import FirefoxProfile, Profile
__all__ = [
"MozProfileCLI",
"cli",
"KeyValueParseError",
"parse_key_value",
"parse_preferences",
]
class KeyValueParseError(Exception):
"""Error when parsing strings of serialized key-values."""
def __init__(self, msg, errors=()):
self.errors = errors
Exception.__init__(self, msg)
def parse_key_value(strings, separator=
"=", context=
"key, value"):
"""Parse string-serialized key-value pairs in the form of `key = value`.
Args:
strings (list): List of strings to parse.
separator (str): Identifier used to split the strings.
Returns:
list: A list of (<key>, <value>) tuples. Whitespace
is not stripped.
Raises:
KeyValueParseError
"""
# syntax check
missing = [string
for string
in strings
if separator
not in string]
if missing:
raise KeyValueParseError(
"Error: syntax error in %s: %s" % (context,
",".join(missing)),
errors=missing,
)
return [string.split(separator, 1)
for string
in strings]
def parse_preferences(prefs, context=
"--setpref="):
"""Parse preferences specified on the command line.
Args:
prefs (list): A list of strings, usually of the form
"=".
Returns:
dict: A dictionary of the form {<pref>: <value>} where values have been
cast.
"""
try:
prefs = dict(parse_key_value(prefs, context=context))
except KeyValueParseError
as e:
print(str(e))
sys.exit(1)
return {k: Preferences.cast(v)
for k, v
in prefs.items()}
class MozProfileCLI(object):
"""The Command Line Interface for ``mozprofile``."""
module =
"mozprofile"
profile_class = Profile
def __init__(self, args=sys.argv[1:], add_options=
None):
self.parser = OptionParser(description=__doc__)
self.add_options(self.parser)
if add_options:
add_options(self.parser)
(self.options, self.args) = self.parser.parse_args(args)
def add_options(self, parser):
parser.add_option(
"-p",
"--profile",
dest=
"profile",
help=
"The path to the profile to operate on. "
"If none, creates a new profile in temp directory",
)
parser.add_option(
"-a",
"--addon",
dest=
"addons",
action=
"append",
default=[],
help=
"Addon paths to install. Can be a filepath, "
"a directory containing addons, or a url",
)
parser.add_option(
"--pref",
dest=
"prefs",
action=
"append",
default=[],
help=
"A preference to set. " "Must be a key-value pair separated by a ':'",
)
parser.add_option(
"--preferences",
dest=
"prefs_files",
action=
"append",
default=[],
metavar=
"FILE",
help=
"read preferences from a JSON or INI file. "
"For INI, use 'file.ini:section' to specify a particular section.",
)
def profile_args(self):
"""arguments to instantiate the profile class"""
return dict(
profile=self.options.profile,
addons=self.options.addons,
preferences=self.preferences(),
)
def preferences(self):
"""profile preferences"""
# object to hold preferences
prefs = Preferences()
# add preferences files
for prefs_file
in self.options.prefs_files:
prefs.add_file(prefs_file)
# change CLI preferences into 2-tuples
cli_prefs = parse_key_value(self.options.prefs, separator=
":")
# string preferences
prefs.add(cli_prefs, cast=
True)
return prefs()
def profile(self, restore=
False):
"""create the profile"""
kwargs = self.profile_args()
kwargs[
"restore"] = restore
return self.profile_class(**kwargs)
def cli(args=sys.argv[1:]):
"""Handles the command line arguments for ``mozprofile`` via ``sys.argv``"""
# add a view method for this cli method only
def add_options(parser):
parser.add_option(
"--view",
dest=
"view",
action=
"store_true",
default=
False,
help=
"view summary of profile following invocation",
)
parser.add_option(
"--firefox",
dest=
"firefox_profile",
action=
"store_true",
default=
False,
help=
"use FirefoxProfile defaults",
)
# process the command line
cli = MozProfileCLI(args, add_options)
if cli.args:
cli.parser.error(
"Program doesn't support positional arguments.")
if cli.options.firefox_profile:
cli.profile_class = FirefoxProfile
# create the profile
profile = cli.profile()
if cli.options.view:
# view the profile, if specified
print(profile.summary())
return
# if no profile was passed in print the newly created profile
if not cli.options.profile:
print(profile.profile)
if __name__ ==
"__main__":
cli()