Exemple #1
0
def desktop(profile: Profile) -> bool:
    exists = profile.exists()
    if exists:
        profiles.create_desktop_file(profile)
    else:
        error(f"profile {profile.name} not found at {profile.root}")
    return exists
Exemple #2
0
def from_session(
    session: str,
    profile_name: Optional[str] = None,
    profile_dir: Optional[Path] = None,
    desktop_file: bool = True,
    overwrite: bool = False,
) -> Optional[Profile]:
    if session.endswith(".yml"):
        session_file = Path(session).expanduser()
        session_name = session_file.stem
    else:
        session_name = session
        session_file = user_data_dir() / "sessions" / (session_name + ".yml")
    if not session_file.is_file():
        error(f"{session_file} is not a file")
        return None

    profile = Profile(profile_name or session_name, profile_dir)
    if not profiles.new_profile(profile, None, desktop_file, overwrite):
        return None

    session_dir = profile.root / "data" / "sessions"
    session_dir.mkdir(parents=True, exist_ok=overwrite)
    shutil.copy(session_file, session_dir / "_autosave.yml")

    return profile
Exemple #3
0
def edit(profile: Profile) -> bool:
    if not profile.exists():
        error(f"profile {profile.name} not found at {profile.root}")
        return False
    editor = os.environ.get("VISUAL") or os.environ.get("EDITOR") or "vim"
    os.execlp(editor, editor, str(profile.root / "config" / "config.py"))
    return True
Exemple #4
0
def menu_command(menu: str, profiles: List[str],
                 args: argparse.Namespace) -> Optional[str]:
    arg_string = " ".join(args.qb_args)
    if menu == "applescript":
        profile_list = '", "'.join(profiles)
        return f"""osascript -e \'set profiles to {{"{profile_list}"}}
set profile to choose from list profiles with prompt "qutebrowser: {arg_string}" default items {{item 1 of profiles}}
item 1 of profile\'"""

    prompt = "-p qutebrowser"
    command = menu
    if len(menu.split(" ")) == 1:
        program = Path(menu).name
        if program == "rofi":
            command = f"{menu} -dmenu -no-custom {prompt} -mesg {arg_string}"
        elif program == "wofi":
            command = f"{menu} --dmenu {prompt}"
        elif program in ["dmenu", "dmenu-wl"]:
            command = f"{menu} {prompt}"
        elif program == "fzf":
            command = f"{menu} --prompt 'qutebrowser '"
    exe = command.split(" ")[0]
    if not shutil.which(exe):
        error(f"command '{exe}' not found")
        return None
    profile_list = "\n".join(profiles)
    return f'echo "{profile_list}" | {command}'
Exemple #5
0
def ensure_profile_exists(profile: Profile, create: bool = True) -> bool:
    if profile.root.exists() and not profile.root.is_dir():
        error(f"{profile.root} is not a directory")
        return False
    if not profile.root.exists() and create:
        return new_profile(profile)
    if not profile.root.exists():
        error(f"{profile.root} does not exist")
        return False
    return True
Exemple #6
0
def create_profile(profile: Profile, overwrite: bool = False) -> bool:
    if not profile.check():
        return False

    if not overwrite and profile.root.exists():
        error(f"{profile.root} already exists")
        return False

    config_dir = profile.root / "config"
    config_dir.mkdir(parents=True, exist_ok=overwrite)
    print(profile.root)
    return True
Exemple #7
0
def choose(args: argparse.Namespace) -> bool:
    menu = args.menu or get_default_menu()
    if not menu:
        error(f"No menu program found, please install one of: {AUTO_MENUS}")
        return False
    if menu == "applescript" and platform != "darwin":
        error(f"Menu applescript cannot be used on a {platform} host")
        return False
    profiles = [profile.name for profile in sorted(args.profile_dir.iterdir())]
    if len(profiles) == 0:
        error("No profiles")
        return False

    command = menu_command(menu, profiles, args)
    if not command:
        return False

    selection_cmd = subprocess.Popen(
        command,
        shell=True,
        stdout=subprocess.PIPE,
        stderr=None,
    )
    out = selection_cmd.stdout
    selection = out and out.read().decode(errors="ignore").rstrip("\n")

    if selection:
        profile = Profile(selection, args.profile_dir)
        launch(profile, True, args.foreground, args.qb_args)
    else:
        error("No profile selected")
        return False
    return True
Exemple #8
0
def launch(profile: Profile, strict: bool, foreground: bool,
           qb_args: List[str]) -> bool:
    if not profiles.ensure_profile_exists(profile, not strict):
        return False

    args = profile.cmdline() + qb_args
    if not shutil.which(args[0]):
        error("qutebrowser is not installed")
        return False

    if foreground:
        return subprocess.run(args).returncode == 0
    else:
        p = subprocess.Popen(args,
                             stdout=subprocess.DEVNULL,
                             stderr=subprocess.PIPE)
        try:
            # give qb a chance to validate input before returning to shell
            stdout, stderr = p.communicate(timeout=0.1)
            print(stderr.decode(errors="ignore"), end="")
        except subprocess.TimeoutExpired:
            pass

    return True
Exemple #9
0
def main(mock_args: Optional[list[str]] = None) -> None:
    parser = argparse.ArgumentParser(description="qutebrowser profile manager")
    parser.set_defaults(operation=lambda args: parser.print_help(),
                        passthrough=False)
    parser.add_argument(
        "-P",
        "--profile-dir",
        metavar="directory",
        type=Path,
        help="directory in which profiles are stored",
    )
    parser.add_argument(
        "--version",
        action="version",
        version=__version__,
    )

    subparsers = parser.add_subparsers()
    new = subparsers.add_parser("new", help="create a new profile")
    new.add_argument("profile_name",
                     metavar="profile",
                     help="name of the new profile")
    new.add_argument("home_page",
                     metavar="url",
                     nargs="?",
                     help="profile's home page")
    new.set_defaults(operation=build_op(profiles.new_profile))
    creator_args(new)

    session = subparsers.add_parser(
        "from-session", help="create a new profile from a qutebrowser session")
    session.add_argument(
        "session",
        help="path to session file or name of session. "
        "e.g. ~/.local/share/qutebrowser/sessions/example.yml or example",
    )
    session.add_argument(
        "profile_name",
        metavar="profile",
        nargs="?",
        help="name of the new profile. if unset the session name will be used",
    )
    session.set_defaults(operation=build_op(operations.from_session))
    creator_args(session)

    desktop = subparsers.add_parser(
        "desktop", help="create a desktop file for an existing profile")
    desktop.add_argument("profile_name",
                         metavar="profile",
                         help="profile to create a desktop file for")
    desktop.set_defaults(operation=build_op(operations.desktop))

    launch = subparsers.add_parser(
        "launch", help="launch qutebrowser with the given profile")
    launch.add_argument(
        "profile_name",
        metavar="profile",
        help=
        "profile to launch. it will be created if it does not exist, unless -s is set",
    )
    launch.add_argument(
        "-n",
        "--new",
        action="store_false",
        dest="strict",
        help="create the profile if it doesn't exist",
    )
    launch.add_argument(
        "-f",
        "--foreground",
        action="store_true",
        help=
        "launch qutebrowser in the foreground and print its stdout and stderr to the console",
    )
    launch.set_defaults(operation=build_op(operations.launch),
                        passthrough=True)

    list_ = subparsers.add_parser("list", help="list existing profiles")
    list_.set_defaults(operation=operations.list_)

    choose = subparsers.add_parser(
        "choose",
        help="interactively choose a profile to launch",
    )
    menus = sorted(SUPPORTED_MENUS)
    choose.add_argument(
        "-m",
        "--menu",
        help=
        f'menu application to use. this may be any dmenu-compatible command (e.g. "dmenu -i -p qbpm" or "/path/to/rofi -d") or one of the following menus with built-in support: {menus}',
    )
    choose.add_argument(
        "-f",
        "--foreground",
        action="store_true",
        help=
        "launch qutebrowser in the foreground and print its stdout and stderr to the console",
    )
    choose.set_defaults(operation=operations.choose, passthrough=True)

    edit = subparsers.add_parser("edit", help="edit a profile's config.py")
    edit.add_argument("profile_name",
                      metavar="profile",
                      help="profile to edit")
    edit.set_defaults(operation=build_op(operations.edit))

    raw_args = parser.parse_known_args(mock_args)
    args = raw_args[0]
    if args.passthrough:
        args.qb_args = raw_args[1]
    elif len(raw_args[1]) > 0:
        error(f"unrecognized arguments: {' '.join(raw_args[1])}")
        exit(1)

    if not args.profile_dir:
        args.profile_dir = Path(
            environ.get("QBPM_PROFILE_DIR") or DEFAULT_PROFILE_DIR)
    if not args.operation(args):
        exit(1)
Exemple #10
0
 def check(self) -> Optional["Profile"]:
     if "/" in self.name:
         error("profile name cannot contain slashes")
         return None
     return self