mach_commands.py (4351B)
1 # This Source Code Form is subject to the terms of the Mozilla Public 2 # License, v. 2.0. If a copy of the MPL was not distributed with this 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 5 import os 6 import subprocess 7 import threading 8 import time 9 from pathlib import Path 10 11 import mozpack.path as mozpath 12 from mach.decorators import Command, CommandArgument, SubCommand 13 14 15 @Command( 16 "storybook", 17 category="misc", 18 description="Start the Storybook server and launch the site in a local build of Firefox. This will install npm dependencies, if necessary.", 19 ) 20 @CommandArgument( 21 "--no-open", 22 action="store_true", 23 help="Start the Storybook server without opening a local Firefox build.", 24 ) 25 def storybook_server(command_context, no_open=False): 26 ensure_env(command_context) 27 if not no_open: 28 start_browser_thread = threading.Thread( 29 target=start_browser, args=(command_context,) 30 ) 31 start_browser_thread.start() 32 return run_npm(command_context, args=["run", "storybook"]) 33 34 35 @SubCommand( 36 "storybook", 37 "build", 38 description="Build the Storybook for export.", 39 ) 40 def storybook_build(command_context): 41 ensure_env(command_context) 42 return run_npm(command_context, args=["run", "build-storybook"]) 43 44 45 @SubCommand( 46 "storybook", 47 "upgrade", 48 description="Upgrade all storybook dependencies to latest of ranges in package.json", 49 ) 50 def storybook_upgrade(command_context): 51 delete_storybook_node_modules() 52 package_lock_path = "browser/components/storybook/package-lock.json" 53 if os.path.exists(package_lock_path): 54 os.unlink(package_lock_path) 55 return run_npm(command_context, args=["install"]) 56 57 58 @SubCommand( 59 "storybook", "launch", description="Launch the Storybook site in your local build." 60 ) 61 def storybook_launch(command_context): 62 return run_mach( 63 command_context, 64 "run", 65 argv=["http://localhost:5703"], 66 setpref=[ 67 "svg.context-properties.content.enabled=true", 68 "layout.forms.input-type-search.enabled=true", 69 "layout.forms.reveal-password-button.enabled=true", 70 ], 71 ) 72 73 74 def delete_path(path): 75 if path.is_file() or path.is_symlink(): 76 path.unlink() 77 return 78 for p in path.iterdir(): 79 delete_path(p) 80 path.rmdir() 81 82 83 def delete_storybook_node_modules(): 84 node_modules_path = Path("browser/components/storybook/node_modules") 85 if node_modules_path.exists(): 86 delete_path(node_modules_path) 87 88 89 def start_browser(command_context): 90 # This delay is used to avoid launching the browser before the Storybook server has started. 91 time.sleep(5) 92 subprocess.run( 93 run_mach(command_context, "storybook", subcommand="launch"), check=True 94 ) 95 96 97 def build_storybook_manifest(command_context): 98 print("Build ChromeMap backend") 99 run_mach(command_context, "build-backend", backend=["ChromeMap"]) 100 config_environment = command_context.config_environment 101 storybook_chrome_map_path = "browser/components/storybook/.storybook/chrome-map.js" 102 chrome_map_path = mozpath.join(config_environment.topobjdir, "chrome-map.json") 103 with open(chrome_map_path) as chrome_map_f: 104 with open(storybook_chrome_map_path, "w") as storybook_chrome_map_f: 105 storybook_chrome_map_f.write("module.exports = ") 106 storybook_chrome_map_f.write(chrome_map_f.read()) 107 storybook_chrome_map_f.write(";") 108 109 110 def run_mach(command_context, cmd, **kwargs): 111 return command_context._mach_context.commands.dispatch( 112 cmd, command_context._mach_context, **kwargs 113 ) 114 115 116 def run_npm(command_context, args): 117 return run_mach( 118 command_context, "npm", args=[*args, "--prefix=browser/components/storybook"] 119 ) 120 121 122 def ensure_env(command_context): 123 ensure_npm_deps(command_context) 124 build_storybook_manifest(command_context) 125 126 127 def ensure_npm_deps(command_context): 128 if not check_npm_deps(command_context): 129 install_npm_deps(command_context) 130 else: 131 print("Dependencies up to date\n") 132 133 134 def check_npm_deps(command_context): 135 print("Checking installed npm dependencies") 136 return not run_npm(command_context, args=["ls"]) 137 138 139 def install_npm_deps(command_context): 140 print("Installing missing npm dependencies") 141 run_npm(command_context, args=["ci"])