|
| 1 | +import os |
| 2 | +import sys |
| 3 | +import time |
| 4 | +import platform |
| 5 | +import json |
| 6 | +import shutil |
| 7 | + |
| 8 | +from subprocess import check_call |
| 9 | +from distutils import log |
| 10 | + |
| 11 | +here = os.path.dirname(os.path.abspath(__file__)) |
| 12 | +project_root = os.path.dirname(os.path.dirname(os.path.dirname(here))) |
| 13 | +node_root = os.path.join(project_root, "packages", "python", "plotly", "js") |
| 14 | +is_repo = os.path.exists(os.path.join(project_root, ".git")) |
| 15 | +node_modules = os.path.join(node_root, "node_modules") |
| 16 | +targets = [ |
| 17 | + os.path.join(here, "plotly", "package_data", "widgetbundle.js"), |
| 18 | +] |
| 19 | + |
| 20 | +npm_path = os.pathsep.join( |
| 21 | + [ |
| 22 | + os.path.join(node_root, "node_modules", ".bin"), |
| 23 | + os.environ.get("PATH", os.defpath), |
| 24 | + ] |
| 25 | +) |
| 26 | + |
| 27 | +# Load plotly.js version from js/package.json |
| 28 | +def plotly_js_version(): |
| 29 | + path = os.path.join(here, "js", "package.json") |
| 30 | + with open(path, "rt") as f: |
| 31 | + package_json = json.load(f) |
| 32 | + version = package_json["dependencies"]["plotly.js"] |
| 33 | + version = version.replace("^", "") |
| 34 | + |
| 35 | + return version |
| 36 | + |
| 37 | + |
| 38 | +# install package.json dependencies using npm |
| 39 | +def install_js_deps(local): |
| 40 | + npmName = "npm" |
| 41 | + if platform.system() == "Windows": |
| 42 | + npmName = "npm.cmd" |
| 43 | + |
| 44 | + try: |
| 45 | + check_call([npmName, "--version"]) |
| 46 | + has_npm = True |
| 47 | + except: |
| 48 | + has_npm = False |
| 49 | + |
| 50 | + |
| 51 | + skip_npm = os.environ.get("SKIP_NPM", False) |
| 52 | + if skip_npm: |
| 53 | + log.info("Skipping npm-installation") |
| 54 | + return |
| 55 | + |
| 56 | + if not has_npm: |
| 57 | + log.error( |
| 58 | + "`npm` unavailable. If you're running this command using sudo, make sure `npm` is available to sudo" |
| 59 | + ) |
| 60 | + |
| 61 | + env = os.environ.copy() |
| 62 | + env["PATH"] = npm_path |
| 63 | + |
| 64 | + if has_npm: |
| 65 | + log.info( |
| 66 | + "Installing build dependencies with npm. This may take a while..." |
| 67 | + ) |
| 68 | + check_call( |
| 69 | + [npmName, "install"], |
| 70 | + cwd=node_root, |
| 71 | + stdout=sys.stdout, |
| 72 | + stderr=sys.stderr, |
| 73 | + ) |
| 74 | + if local is not None: |
| 75 | + plotly_archive = os.path.join(local, "plotly.js.tgz") |
| 76 | + check_call( |
| 77 | + [npmName, "install", plotly_archive], |
| 78 | + cwd=node_root, |
| 79 | + stdout=sys.stdout, |
| 80 | + stderr=sys.stderr, |
| 81 | + ) |
| 82 | + check_call( |
| 83 | + [npmName, "run", "build"], |
| 84 | + cwd=node_root, |
| 85 | + stdout=sys.stdout, |
| 86 | + stderr=sys.stderr, |
| 87 | + ) |
| 88 | + os.utime(node_modules, None) |
| 89 | + |
| 90 | + for t in targets: |
| 91 | + if not os.path.exists(t): |
| 92 | + msg = "Missing file: %s" % t |
| 93 | + raise ValueError(msg) |
| 94 | + |
| 95 | +# Generate class hierarchy from Plotly JSON schema |
| 96 | +def run_codegen(): |
| 97 | + if sys.version_info < (3, 8): |
| 98 | + raise ImportError("Code generation must be executed with Python >= 3.8") |
| 99 | + |
| 100 | + from codegen import perform_codegen |
| 101 | + |
| 102 | + perform_codegen() |
| 103 | + |
| 104 | + |
| 105 | +def overwrite_schema_local(uri): |
| 106 | + path = os.path.join(here, "codegen", "resources", "plot-schema.json") |
| 107 | + shutil.copyfile(uri, path) |
| 108 | + |
| 109 | + |
| 110 | +def overwrite_schema(url): |
| 111 | + import requests |
| 112 | + |
| 113 | + req = requests.get(url) |
| 114 | + assert req.status_code == 200 |
| 115 | + path = os.path.join(here, "codegen", "resources", "plot-schema.json") |
| 116 | + with open(path, "wb") as f: |
| 117 | + f.write(req.content) |
| 118 | + |
| 119 | + |
| 120 | +def overwrite_bundle_local(uri): |
| 121 | + path = os.path.join(here, "plotly", "package_data", "plotly.min.js") |
| 122 | + shutil.copyfile(uri, path) |
| 123 | + |
| 124 | + |
| 125 | +def overwrite_bundle(url): |
| 126 | + import requests |
| 127 | + |
| 128 | + req = requests.get(url) |
| 129 | + print('url:', url) |
| 130 | + assert req.status_code == 200 |
| 131 | + path = os.path.join(here, "plotly", "package_data", "plotly.min.js") |
| 132 | + with open(path, "wb") as f: |
| 133 | + f.write(req.content) |
| 134 | + |
| 135 | + |
| 136 | +def overwrite_plotlyjs_version_file(plotlyjs_version): |
| 137 | + path = os.path.join(here, "plotly", "offline", "_plotlyjs_version.py") |
| 138 | + with open(path, "w") as f: |
| 139 | + f.write( |
| 140 | + """\ |
| 141 | +# DO NOT EDIT |
| 142 | +# This file is generated by the updatebundle commands.py command |
| 143 | +__plotlyjs_version__ = "{plotlyjs_version}" |
| 144 | +""".format( |
| 145 | + plotlyjs_version=plotlyjs_version |
| 146 | + ) |
| 147 | + ) |
| 148 | + |
| 149 | +def request_json(url): |
| 150 | + import requests |
| 151 | + |
| 152 | + req = requests.get(url) |
| 153 | + return json.loads(req.content.decode("utf-8")) |
| 154 | + |
| 155 | + |
| 156 | +def get_latest_publish_build_info(repo, branch): |
| 157 | + url = ( |
| 158 | + r"https://circleci.com/api/v1.1/project/github/" |
| 159 | + r"{repo}/tree/{branch}?limit=100&filter=completed" |
| 160 | + ).format(repo=repo, branch=branch) |
| 161 | + |
| 162 | + branch_jobs = request_json(url) |
| 163 | + |
| 164 | + # Get most recent successful publish build for branch |
| 165 | + builds = [ |
| 166 | + j |
| 167 | + for j in branch_jobs |
| 168 | + if j.get("workflows", {}).get("job_name", None) == "publish-dist" |
| 169 | + and j.get("status", None) == "success" |
| 170 | + ] |
| 171 | + build = builds[0] |
| 172 | + |
| 173 | + # Extract build info |
| 174 | + return {p: build[p] for p in ["vcs_revision", "build_num", "committer_date"]} |
| 175 | + |
| 176 | + |
| 177 | +def get_bundle_schema_local(local): |
| 178 | + plotly_archive = os.path.join(local, "plotly.js.tgz") |
| 179 | + plotly_bundle = os.path.join(local, "dist/plotly.min.js") |
| 180 | + plotly_schemas = os.path.join(local, "dist/plot-schema.json") |
| 181 | + return plotly_archive, plotly_bundle, plotly_schemas |
| 182 | + |
| 183 | + |
| 184 | +def get_bundle_schema_urls(build_num): |
| 185 | + url = ( |
| 186 | + "https://circleci.com/api/v1.1/project/github/" |
| 187 | + "plotly/plotly.js/{build_num}/artifacts" |
| 188 | + ).format(build_num=build_num) |
| 189 | + |
| 190 | + artifacts = request_json(url) |
| 191 | + |
| 192 | + # Find archive |
| 193 | + archives = [a for a in artifa
D7AE
cts if a.get("path", None) == "plotly.js.tgz"] |
| 194 | + archive = archives[0] |
| 195 | + |
| 196 | + # Find bundle |
| 197 | + bundles = [a for a in artifacts if a.get("path", None) == "dist/plotly.min.js"] |
| 198 | + bundle = bundles[0] |
| 199 | + |
| 200 | + # Find schema |
| 201 | + schemas = [a for a in artifacts if a.get("path", None) == "dist/plot-schema.json"] |
| 202 | + schema = schemas[0] |
| 203 | + |
| 204 | + return archive["url"], bundle["url"], schema["url"] |
| 205 | + |
| 206 | + |
| 207 | +# Download latest version of the plot-schema JSON file |
| 208 | +def update_schema(plotly_js_version): |
| 209 | + url = ( |
| 210 | + "https://raw.githubusercontent.com/plotly/plotly.js/" |
| 211 | + "v%s/dist/plot-schema.json" % plotly_js_version |
| 212 | + ) |
| 213 | + overwrite_schema(url) |
| 214 | + |
| 215 | +# Download latest version of the plotly.js bundle |
| 216 | +def update_bundle(plotly_js_version): |
| 217 | + url = ( |
| 218 | + "https://raw.githubusercontent.com/plotly/plotly.js/" |
| 219 | + "v%s/dist/plotly.min.js" % plotly_js_version |
| 220 | + ) |
| 221 | + overwrite_bundle(url) |
| 222 | + |
| 223 | + # Write plotly.js version file |
| 224 | + plotlyjs_version = plotly_js_version |
| 225 | + overwrite_plotlyjs_version_file(plotlyjs_version) |
| 226 | + |
| 227 | +# Update project to a new version of plotly.js |
| 228 | +def update_plotlyjs(plotly_js_version): |
| 229 | + update_bundle(plotly_js_version) |
| 230 | + update_schema(plotly_js_version) |
| 231 | + run_codegen() |
| 232 | + |
| 233 | +# Update the plotly.js schema and bundle from master |
| 234 | +def update_schema_bundle_from_master(): |
| 235 | + |
| 236 | + if "--devrepo" in sys.argv: |
| 237 | + devrepo = sys.argv[sys.argv.index("--devrepo") + 1] |
| 238 | + else: |
| 239 | + devrepo =<
F438
/span> "plotly/plotly.js" |
| 240 | + |
| 241 | + if "--devbranch" in sys.argv: |
| 242 | + devbranch = sys.argv[sys.argv.index("--devbranch") + 1] |
| 243 | + else: |
| 244 | + devbranch = "master" |
| 245 | + |
| 246 | + if "--local" in sys.argv: |
| 247 | + local = sys.argv[sys.argv.index("--local") + 1] |
| 248 | + else: |
| 249 | + local = None |
| 250 | + |
| 251 | + if local is None: |
| 252 | + build_info = get_latest_publish_build_info(devrepo, devbranch) |
| 253 | + |
| 254 | + archive_url, bundle_url, schema_url = get_bundle_schema_urls( |
| 255 | + build_info["build_num"] |
| 256 | + ) |
| 257 | + |
| 258 | + # Update bundle in package data |
| 259 | + overwrite_bundle(bundle_url) |
| 260 | + |
| 261 | + # Update schema in package data |
| 262 | + overwrite_schema(schema_url) |
| 263 | + else: |
| 264 | + # this info could be more informative but |
| 265 | + # it doesn't seem as useful in a local context |
| 266 | + # and requires dependencies and programming. |
| 267 | + build_info = {"vcs_revision": "local", "committer_date": str(time.time())} |
| 268 | + devrepo = local |
| 269 | + devbranch = "" |
| 270 | + |
| 271 | + archive_uri, bundle_uri, schema_uri = get_bundle_schema_local(local) |
| 272 | + overwrite_bundle_local(bundle_uri) |
| 273 | + overwrite_schema_local(schema_uri) |
| 274 | + |
| 275 | + # Update plotly.js url in package.json |
| 276 | + package_json_path = os.path.join(node_root, "package.json") |
| 277 | + with open(package_json_path, "r") as f: |
| 278 | + package_json = json.load(f) |
| 279 | + |
| 280 | + # Replace version with bundle url |
| 281 | + package_json["dependencies"]["plotly.js"] = ( |
| 282 | + archive_url if local is None else archive_uri |
| 283 | + ) |
| 284 | + with open(package_json_path, "w") as f: |
| 285 | + json.dump(package_json, f, indent=2) |
| 286 | + |
| 287 | + # update plotly.js version in _plotlyjs_version |
| 288 | + rev = build_info["vcs_revision"] |
| 289 | + date = str(build_info["committer_date"]) |
| 290 | + version = "_".join([devrepo, devbranch, date[:10], rev[:8]]) |
| 291 | + overwrite_plotlyjs_version_file(version) |
| 292 | + install_js_deps(local) |
| 293 | + |
| 294 | +# Update project to a new development version of plotly.js |
| 295 | +def update_plotlyjs_dev(): |
| 296 | + update_schema_bundle_from_master() |
| 297 | + run_codegen() |
| 298 | + |
| 299 | +if "updateplotlyjsdev" in sys.argv: |
| 300 | + update_plotlyjs_dev() |
| 301 | +elif "updateplotlyjs" in sys.argv: |
| 302 | + print(plotly_js_version()) |
| 303 | + update_plotlyjs(plotly_js_version()) |
| 304 | + |
0 commit comments