diff --git a/LICENSE b/LICENSE index 43ec9c4..384dec9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018 Jelmer van Arnhem +Copyright (c) 2018-2020 Jelmer van Arnhem Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 8449651..0b76931 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ carafe is a tiny management tool for wine ~~bottles~~ carafes. - A tiny command-line script to create bottles/carafes for different programs - Automatically manages different wine prefixes -- Always uses system wine, but never changes the default .wine configuration +- Never changes the default .wine configuration - Configure settings for each carafe separately - Create shortcuts for installed programs and/or easily start them from the carafe CLI - All configuration and carafes are neatly stored in a single folder (and are auto-deleted when all carafes are deleted) @@ -16,7 +16,7 @@ carafe is a tiny management tool for wine ~~bottles~~ carafes. ## Simple usage, get going fast -There are two example provided here, +There are two examples provided here, both of which assume you have the setup stored inside the `~/Downloads` folder. It's recommended to read both examples before starting, to get a good idea of the different ways to configure carafe. @@ -86,6 +86,21 @@ the most important ones are listed here: - Remove the rufus carafe completely with: `./carafe rufus remove` - Copy a carafe to a new location (as a backup for example): `./carafe steam copy steam-backup` +### Dependencies + +carafe is pure python and only uses native imports, some of them are python 3.5+. + +Wine is the only dependency of carafe and it can even do some management tasks without wine installed (such as remove, info and list). +Creating and starting the carafes is done by wine, and won't work without it installed. + +carafe will show a warning when the 'wine' command is not found, +and offer instructions to resolve the problem. +For some installation methods an alias might be needed, +or you can configure the wine location in the config file. +You can manually edit the `~/.carafe/config.json` to change the default wine command location. +It might be needed to create the config file, as it normally will only be stored when links or special arch types are used. +The config file also accepts a 'winetricks' field for setting the winetricks location/path separately. + ## Advanced usage carafe is a single script which can be started from any location. @@ -95,8 +110,7 @@ Most testing was done on Linux, but I'm open to pull requests to broaden OS supp ### Wine versions carafe will need wine as the most important dependency. -Unlike other management tools for wine bottles, carafe does not allow the user to switch between versions. -Instead it uses the system wine for all carafes. +By default, the system wine is used for all carafes. The following advantages are a direct consequence of this decision: - All carafes will automatically use the latest/greatest version of wine @@ -110,6 +124,14 @@ There is one trade-off to all these advantages: The [wine wiki](https://wiki.winehq.org/FAQ#Which_version_of_Wine_should_I_use.3F) recommends to use a recent or even the latest version of wine, which is automatically configured by using carafe. +#### Changing a wine version + +In the rare cases where you want to use a custom wine version, +you can manually update the carafe config. +A toplevel "wine" key can be used as the global wine location, +while a carafe specific "wine" key can be used to override that per carafe. +The value of the configuration should be an absolute path to the wine executable. + ### Manage carafe After running `./carafe` a list of the supported options will shown. @@ -118,7 +140,7 @@ All of them are listed in the output as shown here: ``` usage: carafe {,list} -Welcome to carafe 1.0.0 +Welcome to carafe 1.1.0 carafe is a tiny management tool for wine bottles/carafes. optional arguments: @@ -521,21 +543,6 @@ which is something that the carafe command will handle for you. In short, carafe is aimed to ease the configuration of wine bottles/carafes, without introducing any magic or changing the wine prefix system. -### Dependencies - -carafe is pure python and only uses native imports, some of them are python 3.5+. - -Wine is the only dependency of carafe and it can even do some management tasks without wine installed (such as remove, info and list). -Creating and starting the carafes is done by wine, and won't work without it installed. - -carafe will show a warning when the 'wine' command is not found, -and offer instructions to resolve the problem. -For some installation methods an alias might be needed, -or you can configure the wine location in the config file. -You can manually edit the `~/.carafe/config.json` to change the default wine command location. -It might be needed to create the config file, as it normally will only be stored when links or special arch types are used. -The config file also accepts a 'winetricks' field for setting the winetricks location/path separately. - ### Logging No wine commands executed by carafe will show any output in the terminal. diff --git a/carafe b/carafe index 1eeb674..36c3d48 100755 --- a/carafe +++ b/carafe @@ -6,7 +6,7 @@ __author__ = "Jelmer van Arnhem" # See README.md for more details and usage instructions __license__ = "MIT" # See LICENSE for more details and exact terms -__version__ = "1.0.0" +__version__ = "1.1.0" # See https://github.com/jelmerro/carafe for repo and updates import argparse @@ -23,7 +23,6 @@ CONFIG_FOLDER = os.path.join(os.path.expanduser("~"), ".carafe") # CONFIG FILE LOCATION # It's recommended to leave this path as is and only change the folder location -# Read and write function assume the file is directly inside the config folder CONFIG_FILE = os.path.join(CONFIG_FOLDER, "config.json") @@ -123,6 +122,7 @@ class Carafe: self.prefix = os.path.join(CONFIG_FOLDER, self.name) self.arch = self.read_arch() self.link_location = self.read_link() + self.wine = self.read_wine() # Linked functions directly called from the parser @@ -137,7 +137,7 @@ class Carafe: remove_config(self.name) if self.arch: modify_config(self.name, "arch", self.arch) - self.run_command(f"{WINE} wineboot --init") + self.run_command(f"{self.wine} wineboot --init") def install(self, args): self.exists() @@ -155,9 +155,9 @@ class Carafe: print("The specified executable could not be found") sys.exit(1) if executable.endswith(".msi"): - self.run_command(f"{WINE} msiexec /i \"{executable}\"") + self.run_command(f"{self.wine} msiexec /i \"{executable}\"") else: - self.run_command(f"{WINE} \"{executable}\"") + self.run_command(f"{self.wine} \"{executable}\"") def start(self, args): self.exists() @@ -176,8 +176,13 @@ class Carafe: start = self.link_location self.arch = self.read_arch() path = os.path.join(self.prefix, "drive_c", start) + arg_string = " " + for arg in args.arguments: + arg_string += f"{arg} " if args.keep_log: - self.run_command(f"{WINE} \"{path}\"", os.path.dirname(path)) + self.run_command( + f"{self.wine} \"{path}\" {arg_string}", + os.path.dirname(path)) else: env = os.environ env["WINEPREFIX"] = self.prefix @@ -185,7 +190,7 @@ class Carafe: env["WINEARCH"] = self.arch env["WINEDEBUG"] = "-all" subprocess.run( - f"{WINE} \"{path}\"", shell=True, + f"{self.wine} \"{path}\" {arg_string}", shell=True, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL, cwd=os.path.dirname(path), env=env) @@ -295,11 +300,11 @@ class Carafe: def regedit(self, args): self.exists() - self.run_command(f"{WINE} regedit") + self.run_command(f"{self.wine} regedit") def winecfg(self, args): self.exists() - self.run_command(f"{WINE} winecfg") + self.run_command(f"{self.wine} winecfg") def winetricks(self, args): self.exists() @@ -326,6 +331,13 @@ class Carafe: return config[self.name]["link"] return None + def read_wine(self): + config = read_config() + if self.name in config: + if "wine" in config[self.name]: + return config[self.name]["wine"] + return WINE + def read_arch(self): config = read_config() if self.name in config: @@ -362,7 +374,8 @@ class Carafe: windows = os.path.join(drive_c, "windows") exe_pattern = os.path.join(drive_c, "**", "*.exe") executables = [] - for exe in glob.glob(exe_pattern, recursive=True): + exe_files = sorted(glob.glob(exe_pattern, recursive=True)) + for exe in exe_files: if not exe.startswith(windows): exe = exe.replace(drive_c, "", 1) if exe.startswith("/"): @@ -418,7 +431,7 @@ class Carafe: command = f"env WINEPREFIX=\"{self.prefix}\"" if self.arch: command += " WINEARCH=\"{self.arch}\"" - command += f" {WINE} \"C:/{loc}\"" + command += f" {self.wine} \"C:/{loc}\"" path = os.path.dirname(os.path.join(self.prefix, "drive_c", loc)) return "#!/usr/bin/env xdg-open\n" \ "[Desktop Entry]\n" \ @@ -428,8 +441,7 @@ class Carafe: f"Path={path}\n" -# Main startup steps -if __name__ == "__main__": +def main(): # Prepare the main parser description = f"Welcome to carafe {__version__}\n" \ "carafe is a tiny management tool for wine bottles/carafes.\n" @@ -474,6 +486,9 @@ if __name__ == "__main__": sub_start.add_argument( "-l", "--location", help="Location of the executable inside the carafe to start") + sub_start.add_argument( + "arguments", nargs=argparse.REMAINDER, + help="Any arguments will directly be passed to the started executable") # Rename sub_rename = sub.add_parser( "rename", help="rename an existing carafe", @@ -557,3 +572,8 @@ if __name__ == "__main__": # Call the correct subcommand on the Carafe class carafe = globals()["Carafe"](carafe_name) getattr(carafe, subargs.sub)(subargs) + + +# Main startup steps +if __name__ == "__main__": + main()