163 lines
4.8 KiB
Python
163 lines
4.8 KiB
Python
|
import sys
|
||
|
import subprocess
|
||
|
import shlex
|
||
|
import os
|
||
|
import argparse
|
||
|
import shutil
|
||
|
import logging
|
||
|
import coloredlogs
|
||
|
|
||
|
|
||
|
class _CombinedFormatter(
|
||
|
argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter
|
||
|
):
|
||
|
pass
|
||
|
|
||
|
|
||
|
logger = logging.getLogger(__name__)
|
||
|
coloredlogs.install(
|
||
|
fmt="%(asctime)s,%(msecs)03d %(levelname)s - %(message)s", datefmt="%H:%M:%S"
|
||
|
)
|
||
|
|
||
|
|
||
|
def bootstrap_components(components_source, concurrency, install_type):
|
||
|
|
||
|
is_windows = sys.platform == "win32"
|
||
|
|
||
|
source_glob = (
|
||
|
components_source
|
||
|
if components_source != "all"
|
||
|
else "dash-core-components|dash-html-components|dash-table"
|
||
|
)
|
||
|
|
||
|
cmdstr = f"npx lerna exec --concurrency {concurrency} --scope *@({source_glob})* -- npm {install_type}"
|
||
|
cmd = shlex.split(cmdstr, posix=not is_windows)
|
||
|
print(cmdstr)
|
||
|
|
||
|
with subprocess.Popen(
|
||
|
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=is_windows
|
||
|
) as proc:
|
||
|
out, err = proc.communicate()
|
||
|
status = proc.poll()
|
||
|
|
||
|
if err:
|
||
|
print(("🛑 " if status else "") + err.decode(), file=sys.stderr)
|
||
|
|
||
|
if status or not out:
|
||
|
print(
|
||
|
f"🚨 Failed installing npm dependencies for component packages: {source_glob} (status={status}) 🚨",
|
||
|
file=sys.stderr,
|
||
|
)
|
||
|
sys.exit(1)
|
||
|
else:
|
||
|
print(
|
||
|
f"🟢 Finished installing npm dependencies for component packages: {source_glob} 🟢",
|
||
|
file=sys.stderr,
|
||
|
)
|
||
|
|
||
|
|
||
|
def build_components(components_source, concurrency):
|
||
|
|
||
|
is_windows = sys.platform == "win32"
|
||
|
|
||
|
source_glob = (
|
||
|
components_source
|
||
|
if components_source != "all"
|
||
|
else "dash-core-components|dash-html-components|dash-table"
|
||
|
)
|
||
|
|
||
|
cmdstr = f"npx lerna exec --concurrency {concurrency} --scope *@({source_glob})* -- npm run build"
|
||
|
cmd = shlex.split(cmdstr, posix=not is_windows)
|
||
|
print(cmdstr)
|
||
|
|
||
|
with subprocess.Popen(
|
||
|
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=is_windows
|
||
|
) as proc:
|
||
|
out, err = proc.communicate()
|
||
|
status = proc.poll()
|
||
|
|
||
|
if err:
|
||
|
print(("🛑 " if status else "") + err.decode(), file=sys.stderr)
|
||
|
|
||
|
if status or not out:
|
||
|
print(
|
||
|
f"🚨 Finished updating component packages: {source_glob} (status={status}) 🚨",
|
||
|
file=sys.stderr,
|
||
|
)
|
||
|
sys.exit(1)
|
||
|
|
||
|
for package in source_glob.split("|"):
|
||
|
build_directory = os.path.join(
|
||
|
"components", package, package.replace("-", "_").rstrip("/\\")
|
||
|
)
|
||
|
|
||
|
dest_dir = (
|
||
|
"dcc"
|
||
|
if package == "dash-core-components"
|
||
|
else "html"
|
||
|
if package == "dash-html-components"
|
||
|
else "dash_table"
|
||
|
)
|
||
|
|
||
|
dest_path = os.path.join("dash", dest_dir)
|
||
|
|
||
|
if not os.path.exists(dest_path):
|
||
|
try:
|
||
|
os.makedirs(dest_path)
|
||
|
except OSError:
|
||
|
logger.exception("🚨 Having issues manipulating %s", dest_path)
|
||
|
sys.exit(1)
|
||
|
|
||
|
if not os.path.exists(build_directory):
|
||
|
print(
|
||
|
"🚨 Could not locate build artifacts."
|
||
|
+ " Check that the npm build process completed"
|
||
|
+ f" successfully for package: {package} 🚨"
|
||
|
)
|
||
|
sys.exit(1)
|
||
|
else:
|
||
|
print(f"🚚 Moving build artifacts from {build_directory} to Dash 🚚")
|
||
|
shutil.rmtree(dest_path)
|
||
|
shutil.copytree(build_directory, dest_path)
|
||
|
with open(os.path.join(dest_path, ".gitkeep"), "w", encoding="utf-8"):
|
||
|
pass
|
||
|
print(f"🟢 Finished moving build artifacts from {build_directory} to Dash 🟢")
|
||
|
|
||
|
|
||
|
def cli():
|
||
|
parser = argparse.ArgumentParser(
|
||
|
prog="dash-update-components",
|
||
|
formatter_class=_CombinedFormatter,
|
||
|
description="Update the specified subcomponent libraries within Dash"
|
||
|
" by copying over build artifacts, dependencies, and dependency metadata.",
|
||
|
)
|
||
|
parser.add_argument(
|
||
|
"components_source",
|
||
|
help="A glob string that matches the Dash component libraries to be updated"
|
||
|
" (eg.'dash-table' // 'dash-core-components|dash-html-components' // 'all')."
|
||
|
" The default argument is 'all'.",
|
||
|
default="all",
|
||
|
)
|
||
|
parser.add_argument(
|
||
|
"--concurrency",
|
||
|
type=int,
|
||
|
default=3,
|
||
|
help="Maximum concurrent steps, up to 3 (ie all components in parallel)",
|
||
|
)
|
||
|
parser.add_argument(
|
||
|
"--ci",
|
||
|
help="For clean-install use '--ci True'",
|
||
|
default="False",
|
||
|
)
|
||
|
|
||
|
args = parser.parse_args()
|
||
|
|
||
|
bootstrap_components(
|
||
|
args.components_source, args.concurrency, "ci" if args.ci == "True" else "i"
|
||
|
)
|
||
|
build_components(args.components_source, args.concurrency)
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
cli()
|