Address some PR feedback, update README

This commit is contained in:
Peter deHaan 2016-03-11 15:25:47 -08:00
Родитель 1f6a8d9b52
Коммит cfd2a26aee
10 изменённых файлов: 116 добавлений и 140 удалений

Просмотреть файл

@ -1,29 +1,28 @@
# ff-tool
**Summary**
## Summary
ff-tool is a Python CLI tool we've created to facilitate browser testing of
cloud services. It is largely a convenience wrapper we've written around
these amazing tools/libraries (see note below):
ff-tool is a Python CLI tool we've created to facilitate browser testing of
cloud services. It is largely a convenience wrapper we've written around
these amazing tools/libraries (see note below):
* [mozdownload](https://github.com/mozilla/mozdownload)
* [mozprofile](https://github.com/mozilla/mozprofile)
- [mozdownload](https://github.com/mozilla/mozdownload)
- [mozprofile](https://github.com/mozilla/mozprofile)
Our typical use case is launching various Firefox browser versions with a
Our typical use case is launching various Firefox browser versions with a
fresh profile and loading custom preferences. This tool enables us to do this
quickly with a 1-liner from the CLI.
**Features**
## Features
1. DownloadFirefox desktop versions
** (Nightly, Developer Edition, Beta, Release)
2. Manage profiles
3. Load test preferences
1. DownloadFirefox desktop versions (Nightly, Developer Edition, Beta, Release)
2. Manage profiles
3. Load test preferences
**Notes**
## Notes
If you plan on creating a tool of your own, please import the above libs
directly in your script(s). This tool was designed for convenience of our
If you plan on creating a tool of your own, please import the above lib
directly in your script(s). This tool was designed for convenience of our
team for testing Cloud Services and not intended to be used as a library.
Profiles are stored in a temp directory by default which can be overridden.
@ -31,31 +30,32 @@ Use caution if you specify your own profile directory as profile cleanup
functions can wipe out all profiles in your specified directory.
:bangbang: _NOTE: This tool is work in progress... DO NOT USE_ :bangbang:
:bangbang: _**NOTE:** This tool is work in progress... DO NOT USE_ :bangbang:
# Installation
## Installation
## Pre-requisites
* ff-tool requires you have python and virtualenv installed.
### Pre-requisites
## Build
```
**NOTE:** ff-tool requires you have Python and virtualenv installed
### Build
```sh
$ make build
$ source ./venv/bin/activate
```
## Cleanup
```
### Cleanup
```sh
$ deactivate
$ make clean
$ make clean
```
# Run
## Run
_When not specified, ff will use defaults_
## Help
```
## Help
```sh
$ ff -h
```
@ -63,14 +63,14 @@ $ ff -h
* version: Nightly
* profile_name: \<random\>
```
$ ff run
```sh
$ ff
```
* version: Developer Edition (aurora)
* version: Developer Edition (aurora)
* profile_name: \<random\>
```
$ ff run -c aurora
```sh
$ ff -c aurora
```
## Launch browser, clean profile, specify profile name
@ -78,30 +78,38 @@ $ ff run -c aurora
* version: Nightly
* profile_name: my_cool_profile1
NOTE: if profile exists, we use it, if not we create a new one
**NOTE:** If the specified profile exists, we use it, if not we create a new one
with that name.
```
$ ff run -p my_cool_profile1
```sh
$ ff -p my_cool_profile1
```
# Cloud Services (only)
## Launch browser, clean profile, specify services-specific options...
## Launch browser, clean profile, specify services-specific options...
* version: Beta
* version: Beta
* profile_name: my_cool_profile1
* product: loop-server
* environment: stage
* test-type: e2e-test
NOTE: if profile exists, we use it, if not we create a new one
**NOTE:** If the specified profile exists, we use it, if not we create a new one
with that name.
```
$ ff run -c aurora -p my_cool_profile1 -a loop-server -e stage -t e2e-test
```sh
$ ff -c beta -p my_cool_profile1 -a loop-server -e stage -t e2e-test
```
## Download all browsers, but don't create a profile or launch any browsers...
**NOTE:** This is useful for our daily refresh task where we make sure we have
the latest browsers installed.
* version: all
* profile_name: none
```sh
$ ff -c ALL --no-profile --no-launch
```

Просмотреть файл

@ -1,7 +1,6 @@
[DEFAULT]
PATH_FIREFOX_APP = _temp/browsers/%(APP_DEST_FILENAME)s
PATH_FIREFOX_BIN = Contents/MacOS/firefox
PATH_FIREFOX_BIN_ENV = %(PATH_FIREFOX_APP)s/%(PATH_FIREFOX_BIN)s
PATH_FIREFOX_BIN_ENV = %(PATH_FIREFOX_APP)s/Contents/MacOS/firefox
PATH_FIREFOX_PROFILES_ENV = $HOME/Library/Application Support/Firefox/
[nightly]

Просмотреть файл

@ -9,9 +9,10 @@ Module to download OS-specific versions of Firefox:
import os
import time
from firefox_install import install
from firefox_install import install, get_firefox_version
from firefox_env_handler import IniHandler
from mozdownload import FactoryScraper
from outlawg import Outlawg
try:
import configparser # Python 3
@ -21,6 +22,7 @@ except:
BASE_DIR = os.path.join('_temp', 'browsers')
CONFIG_CHANNELS = os.path.join('configs', 'channels.ini')
SCRIPT_START_TIME = time.time()
config = configparser.ConfigParser()
config.read(CONFIG_CHANNELS)
@ -28,7 +30,7 @@ config.read(CONFIG_CHANNELS)
env = IniHandler()
env.load_os_config('configs')
SCRIPT_START_TIME = time.time()
out = Outlawg()
def replace_ext(filename, ext):
@ -62,16 +64,23 @@ def download(channel):
destination=download_path
)
print("Downloading {0} to {1}".format(channel, download_path))
args = {"channel": channel, "download_path": download_path}
print("Downloading {channel} to {download_path}".format(**args))
scraper.download()
is_recent_file = modification_date(download_path) > SCRIPT_START_TIME
firefox_bin = env.get(channel, 'PATH_FIREFOX_BIN_ENV')
if is_recent_file:
print("You should install")
# If the *.dmg file was downloaded recently, or we don't have the *.app
# file installed, install the current Firefox channel.
if is_recent_file or not os.path.exists(firefox_bin):
install(channel)
else:
print("Not recent. skipping install")
firefox_version = get_firefox_version(channel)
args = {"channel": channel, "version": firefox_version}
msg = "You have the latest version of {channel} installed ({version})."
out.header(msg.format(**args))
def download_all():

Просмотреть файл

@ -7,6 +7,10 @@ import shutil
import sys
import configparser
from outlawg import Outlawg
out = Outlawg()
class FirefoxEnvHandler():
LINUX = 'linux'
@ -52,19 +56,6 @@ class FirefoxEnvHandler():
"""
return cls.get_os() == cls.WINDOWS
@staticmethod
def banner(str, length=79, delimiter='='):
"""
Throws up a debug header to make output subjectively "easier" to read
in stdout.
"""
if length <= 0:
length = len(str)
divider = delimiter * length
output = '\n'.join(['', divider, str, divider])
print(output)
@staticmethod
def clean_folder(path, foot_gun=True):
"""
@ -93,7 +84,7 @@ class IniHandler(FirefoxEnvHandler):
"""
Load an INI config based on the specified `ini_path`.
"""
IniHandler.banner('LOADING {0}'.format(ini_path), 79, '-')
out.header('LOADING {0}'.format(ini_path))
# Make sure the specified config file exists, fail hard if missing.
if not os.path.isfile(ini_path):
@ -115,7 +106,7 @@ class IniHandler(FirefoxEnvHandler):
Generate and save the output environment file so we can source it from
something like .bashrc or .bashprofile.
"""
IniHandler.banner('CREATING ENV FILE ({0})'.format(out_file))
out.header('CREATING ENV FILE ({0})'.format(out_file))
env_fmt = "export %s=\"%s\""
env_vars = []

Просмотреть файл

@ -3,18 +3,20 @@
import os
from firefox_env_handler import IniHandler
from fabric.api import local
from outlawg import Outlawg
env = IniHandler()
env.load_os_config('configs')
out = Outlawg()
def install(channel):
if channel == 'ALL':
install_all()
return
filename = env.get(channel, 'DOWNLOAD_FILENAME')
# filename = env.get(channel, 'DOWNLOAD_FILENAME')
install_dir = env.get(channel, 'PATH_FIREFOX_APP')
if IniHandler.is_linux():
@ -40,6 +42,15 @@ def install(channel):
extract_dmg(dmg_dirname, app_src_filename, app_dest_filename, channel)
firefox_version = get_firefox_version(channel)
out.header("Installed {0} ({1})".format(firefox_version, channel))
def get_firefox_version(channel):
path_firefox_bin = env.get(channel, "PATH_FIREFOX_BIN_ENV")
cmd = "{0} --version".format(path_firefox_bin)
return local(cmd, capture=True)
def install_all():
for channel in env.sections():

Просмотреть файл

@ -21,7 +21,7 @@ except:
import ConfigParser as configparser # Python 2
PATH_PROJECT = os.path.abspath('.')
PROFILE_DIR = os.path.join(PATH_PROJECT, '_temp', 'profiles')
BASE_PROFILE_DIR = os.path.join(PATH_PROJECT, '_temp', 'profiles')
FILE_PREFS = 'prefs.ini'
config = configparser.ConfigParser()
@ -41,6 +41,8 @@ def prefs_paths(application, test_type, env='stage'):
# Make sure the specified INI file has the specified section.
if config.has_section(env):
valid_paths.append(path_app + ":" + env)
else:
valid_paths.append(path_app)
if test_type:
path_app_test_type = os.path.join(path_app_dir, test_type, FILE_PREFS)
@ -48,23 +50,22 @@ def prefs_paths(application, test_type, env='stage'):
config.read(path_app_test_type)
if config.has_section(env):
valid_paths.append(path_app_test_type + ":" + env)
else:
valid_paths.append(path_app_test_type)
return valid_paths
def create_mozprofile(profile_dir, application=None, test_type=None, env=None):
if not profile_dir:
print("Create random profile")
full_profile_dir = mkdtemp(dir=PROFILE_DIR, prefix="fftool.", suffix="")
print(full_profile_dir)
else:
print("Using named profile")
full_profile_dir = os.path.join(PROFILE_DIR, profile_dir)
full_profile_dir = mkdtemp(dir=BASE_PROFILE_DIR, prefix="fftool.", suffix="")
# If temp profile already exists, kill it so it doesn't merge unexpectedly.
if os.path.exists(full_profile_dir):
msg = "WARNING: Profile '{0}' already exists. Merging configs."
out.header(msg.format(profile_dir), 'XL', '-')
else:
full_profile_dir = os.path.join(BASE_PROFILE_DIR, profile_dir)
if os.path.exists(full_profile_dir):
msg = "WARNING: Profile '{0}' already exists. Merging configs."
out.header(msg.format(full_profile_dir), 'XL', '-')
prefs = Preferences()
for path in prefs_paths(application, test_type):

Просмотреть файл

@ -2,18 +2,10 @@ import os
from firefox_env_handler import IniHandler
try:
import configparser # Python 3
except:
import ConfigParser as configparser # Python 2
from fabric.api import local # It looks like Fabric may only support Python 2.
PATH_PROJECT = os.path.abspath('.')
PATH_TEMP = os.path.join(PATH_PROJECT, '_temp', 'profiles')
FILE_PREFS = 'prefs.ini'
config = configparser.ConfigParser()
env = IniHandler()
env.load_os_config('configs')
@ -21,16 +13,10 @@ env.load_os_config('configs')
def launch_firefox(profile_path, channel):
"""
this will be an all-encompassing function that may make use of all the
others (with the exception of uninstall
This function will rely on the other functions (download, install, profile)
having successfully done their business.
"""
# we need to invoke each of these here
print("1. download firefox! (if not already)")
print("2. install firefox! (if not already)")
print("3. create profile! (unless we specify an existing)")
print("4. Launch firefox!")
FIREFOX_APP_BIN = env.get(channel, 'PATH_FIREFOX_BIN_ENV')
PROFILE_PATH = os.path.join(PATH_TEMP, profile_path)

Просмотреть файл

@ -1,20 +1,15 @@
"""
NOTE: THIS IS AN OSX SPECIFIC FILE, SPECIFICALLY FOR MOUNTING DMG FILES.
"""
import os
import shutil
from fabric.api import local
cmd_hdiutil = local("which hdiutil", capture=True)
def replace_ext(filename, ext):
"""
Takes a filename, and changes it's extension.
"""
basename = os.path.splitext(filename)[0]
args = {"basename": basename, "ext": ext}
return "{basename}.{ext}".format(**args)
def attach(dmg_path, mountpoint):
args = {
"hdiutil": cmd_hdiutil,
@ -55,17 +50,3 @@ def extract_dmg(dmg_path, app_src_filename, app_dest_filename, channel):
attach(dmg_path, mountpoint=tmp_dirname)
move_app(app_src_path, app_dest_path)
detach(mountpoint=tmp_dirname)
ver = get_firefox_version(app_dest_path)
print("Installed {0} ({1})".format(ver, channel))
def get_firefox_version(app):
bin = os.path.join(app, "Contents", "MacOS", "firefox")
if not os.path.exists(bin):
print("{0} not found. Aborting.".format(bin))
return
cmd = "{0} --version".format(bin)
output = local(cmd, capture=True)
for line in output.splitlines():
return line

Просмотреть файл

@ -26,7 +26,6 @@ def main():
'--channel',
choices=CHANNELS,
default=DEFAULT_CHANNEL,
type=str,
help='A specific Firefox channel.'
)
@ -34,7 +33,7 @@ def main():
parser.add_argument(
'-p',
'--profile',
help='Name of the Firefox to create/use.'
help='Name of the Firefox profile to create/use.'
)
parser.add_argument(
@ -46,7 +45,7 @@ def main():
parser.add_argument(
'-t',
'--test-type',
help="TODO: (ie: e2e-test, stack-check)."
help="Name of the test-type (ie: e2e-test, stack-check)."
)
parser.add_argument(
@ -58,40 +57,33 @@ def main():
parser.add_argument(
'--no-launch',
action='store_true',
help="TODO:"
help="Whether or not to launch a Firefox instance."
)
"""
TODO-this:
parser.add_argument(
'--no-profile',
help="TODO:"
action='store_true',
help="Whether to create a profile. This is used for the daily refresh job."
)
"""
options = parser.parse_args()
# INSTALL
print("Installing...")
# DOWNLOAD/INSTALL
download(options.channel)
# PROFILE
print("Creating profile...")
profile_path = create_mozprofile(options.profile, options.app, options.test_type, options.env)
if not options.no_profile:
profile_path = create_mozprofile(
options.profile,
application=options.app,
test_type=options.test_type,
env=options.env
)
# LAUNCH
if not options.no_launch:
print("Launching!")
launch_firefox(profile_path, channel=options.channel)
"""
if not options.env:
print("Unknown env")
else:
print("Load settings for env: {0}".format(options.env))
"""
if __name__ == '__main__':
main()

Просмотреть файл

@ -1,8 +1,6 @@
Fabric3
configargparse
configparser
mozdownload==1.20.2
mozprofile
mozprofile==0.28
tox==2.3.1
flake8==2.5.4
outlawg