Skip to content

Commit b1ddb81

Browse files
committed
uplaod to gcs cli
1 parent 88ac01d commit b1ddb81

File tree

2 files changed

+209
-15
lines changed

2 files changed

+209
-15
lines changed

packages/browseros/build/build.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def load_env_file():
5151
from modules.inject import inject_version
5252
from modules.configure import configure
5353
from modules.compile import build
54-
from modules.gcs import upload_package_artifacts, upload_signed_artifacts
54+
from modules.gcs import upload_package_artifacts, upload_signed_artifacts, handle_upload_dist
5555

5656
# Platform-specific imports
5757
if IS_MACOS:
@@ -568,6 +568,17 @@ def build_main(
568568
default=False,
569569
help="Skip uploading artifacts to Google Cloud Storage",
570570
)
571+
@click.option(
572+
"--upload-dist",
573+
type=click.Path(exists=True, path_type=Path),
574+
help="Upload pre-built artifacts from dist/<version> directory to GCS: --upload-dist dist/61",
575+
)
576+
@click.option(
577+
"--platform",
578+
type=click.Choice(["macos", "linux", "win"]),
579+
default=None,
580+
help="Override platform for GCS upload (auto-detected if not specified)",
581+
)
571582
def main(
572583
config,
573584
clean,
@@ -586,6 +597,8 @@ def main(
586597
patch_interactive,
587598
patch_commit,
588599
no_gcs_upload,
600+
upload_dist,
601+
platform,
589602
):
590603
"""Simple build system for Nxtscape Browser"""
591604

@@ -662,6 +675,17 @@ def main(
662675
else:
663676
sys.exit(1)
664677

678+
# Handle upload-dist command
679+
if upload_dist:
680+
# Get root directory
681+
root_dir = Path(__file__).parent.parent
682+
683+
# Call the upload handler from gcs module
684+
if handle_upload_dist(upload_dist, root_dir, platform_override=platform):
685+
sys.exit(0)
686+
else:
687+
sys.exit(1)
688+
665689
# Regular build workflow
666690
build_main(
667691
config_file=config,

packages/browseros/build/modules/gcs.py

Lines changed: 184 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
"""
55

66
import os
7+
import sys
78
from pathlib import Path
8-
from typing import List, Optional
9+
from typing import List, Optional, Tuple
910
from context import BuildContext
1011
from utils import (
1112
log_info,
@@ -14,6 +15,7 @@
1415
log_warning,
1516
IS_WINDOWS,
1617
IS_MACOS,
18+
IS_LINUX,
1719
join_paths,
1820
)
1921

@@ -29,10 +31,38 @@
2931
# Service account file name
3032
SERVICE_ACCOUNT_FILE = "gclient.json"
3133

34+
# GCS bucket configuration
35+
GCS_BUCKET_NAME = "nxtscape"
3236

33-
def upload_to_gcs(ctx: BuildContext, file_paths: List[Path]) -> tuple[bool, List[str]]:
37+
38+
def _get_platform_dir(platform_override: Optional[str] = None) -> str:
39+
"""Get platform directory name for GCS path"""
40+
if platform_override:
41+
return platform_override
42+
43+
if IS_WINDOWS:
44+
return "win"
45+
elif IS_MACOS:
46+
return "macos"
47+
else:
48+
return "linux"
49+
50+
51+
def upload_to_gcs(
52+
ctx: BuildContext,
53+
file_paths: List[Path],
54+
platform_override: Optional[str] = None
55+
) -> Tuple[bool, List[str]]:
3456
"""Upload build artifacts to Google Cloud Storage
35-
Returns: (success, list of GCS URIs)"""
57+
58+
Args:
59+
ctx: BuildContext with root_dir and nxtscape_version
60+
file_paths: List of file paths to upload
61+
platform_override: Optional platform override (macos/linux/win)
62+
63+
Returns:
64+
(success, list of GCS URIs)
65+
"""
3666
if not GCS_AVAILABLE:
3767
log_warning("google-cloud-storage not installed. Skipping GCS upload.")
3868
log_info("Install with: pip install google-cloud-storage")
@@ -43,18 +73,12 @@ def upload_to_gcs(ctx: BuildContext, file_paths: List[Path]) -> tuple[bool, List
4373
return True, []
4474

4575
# Determine platform subdirectory
46-
if IS_WINDOWS:
47-
platform_dir = "win"
48-
elif IS_MACOS:
49-
platform_dir = "macos"
50-
else:
51-
platform_dir = "linux"
76+
platform_dir = _get_platform_dir(platform_override)
5277

5378
# Build GCS path: gs://nxtscape/resources/<version>/<platform>/
54-
bucket_name = "nxtscape"
5579
gcs_prefix = f"resources/{ctx.nxtscape_version}/{platform_dir}"
5680

57-
log_info(f"\n☁️ Uploading artifacts to gs://{bucket_name}/{gcs_prefix}/")
81+
log_info(f"\n☁️ Uploading artifacts to gs://{GCS_BUCKET_NAME}/{gcs_prefix}/")
5882

5983
# Check for service account file
6084
service_account_path = join_paths(ctx.root_dir, SERVICE_ACCOUNT_FILE)
@@ -71,7 +95,7 @@ def upload_to_gcs(ctx: BuildContext, file_paths: List[Path]) -> tuple[bool, List
7195
str(service_account_path)
7296
)
7397
client = storage.Client(credentials=credentials)
74-
bucket = client.bucket(bucket_name)
98+
bucket = client.bucket(GCS_BUCKET_NAME)
7599

76100
uploaded_files = []
77101
gcs_uris = []
@@ -93,8 +117,8 @@ def upload_to_gcs(ctx: BuildContext, file_paths: List[Path]) -> tuple[bool, List
93117
# Note: With uniform bucket-level access, objects inherit bucket's IAM policies
94118
# No need to set individual object ACLs
95119

96-
public_url = f"https://storage.googleapis.com/{bucket_name}/{blob_name}"
97-
gcs_uri = f"gs://{bucket_name}/{blob_name}"
120+
public_url = f"https://storage.googleapis.com/{GCS_BUCKET_NAME}/{blob_name}"
121+
gcs_uri = f"gs://{GCS_BUCKET_NAME}/{blob_name}"
98122
uploaded_files.append(public_url)
99123
gcs_uris.append(gcs_uri)
100124
log_success(f"✓ Uploaded: {public_url}")
@@ -194,3 +218,149 @@ def download_from_gcs(
194218
except Exception as e:
195219
log_error(f"Failed to download from GCS: {e}")
196220
return False
221+
222+
223+
def _detect_artifacts(dist_path: Path, platform_override: Optional[str] = None) -> List[Path]:
224+
"""Detect artifacts in a dist directory based on platform
225+
226+
Args:
227+
dist_path: Path to the dist/<version> directory
228+
platform_override: Optional platform override (macos/linux/win)
229+
230+
Returns:
231+
List of artifact file paths found
232+
"""
233+
artifacts = []
234+
235+
# Determine which file types to look for
236+
if platform_override:
237+
if platform_override == "macos":
238+
patterns = ["*.dmg"]
239+
elif platform_override == "win":
240+
patterns = ["*.exe", "*.zip"]
241+
elif platform_override == "linux":
242+
patterns = ["*.AppImage"]
243+
else:
244+
log_error(f"Invalid platform: {platform_override}. Must be macos/linux/win")
245+
return []
246+
else:
247+
# Auto-detect based on current platform
248+
if IS_MACOS:
249+
patterns = ["*.dmg"]
250+
elif IS_WINDOWS:
251+
patterns = ["*.exe", "*.zip"]
252+
else: # Linux
253+
patterns = ["*.AppImage"]
254+
255+
# Find all matching files
256+
for pattern in patterns:
257+
artifacts.extend(dist_path.glob(pattern))
258+
259+
return sorted(artifacts)
260+
261+
262+
def handle_upload_dist(
263+
dist_path: Path,
264+
root_dir: Path,
265+
platform_override: Optional[str] = None
266+
) -> bool:
267+
"""Upload pre-built artifacts from a dist directory to GCS
268+
269+
This is the main entry point for manual uploads of already-built artifacts.
270+
271+
Args:
272+
dist_path: Path to dist/<version> directory containing artifacts
273+
root_dir: Root directory of the project (for finding gclient.json)
274+
platform_override: Optional platform override (macos/linux/win)
275+
276+
Returns:
277+
True if successful, False otherwise
278+
279+
Example:
280+
handle_upload_dist(Path("dist/61"), Path("."), platform_override="macos")
281+
"""
282+
log_info("=" * 60)
283+
log_info("📤 Manual GCS Upload")
284+
log_info("=" * 60)
285+
286+
# 1. Validate dist_path exists
287+
if not dist_path.exists():
288+
log_error(f"Distribution directory does not exist: {dist_path}")
289+
return False
290+
291+
if not dist_path.is_dir():
292+
log_error(f"Path is not a directory: {dist_path}")
293+
return False
294+
295+
# 2. Extract version from path (assume dist/<version> structure)
296+
version = dist_path.name
297+
log_info(f"📦 Version detected: {version}")
298+
299+
# 3. Determine platform
300+
platform_dir = _get_platform_dir(platform_override)
301+
if platform_override:
302+
log_info(f"🖥️ Platform (override): {platform_dir}")
303+
else:
304+
log_info(f"🖥️ Platform (auto-detected): {platform_dir}")
305+
306+
# 4. Scan for artifacts
307+
log_info(f"\n🔍 Scanning for artifacts in: {dist_path}")
308+
artifacts = _detect_artifacts(dist_path, platform_override)
309+
310+
if not artifacts:
311+
log_warning("No artifacts found to upload")
312+
log_info("\nExpected file types by platform:")
313+
log_info(" - macOS: *.dmg")
314+
log_info(" - Windows: *.exe, *.zip")
315+
log_info(" - Linux: *.AppImage")
316+
return False
317+
318+
# 5. Preview files
319+
log_info(f"\n📋 Found {len(artifacts)} artifact(s):")
320+
total_size = 0
321+
for artifact in artifacts:
322+
size_mb = artifact.stat().st_size / (1024 * 1024)
323+
total_size += size_mb
324+
log_info(f" - {artifact.name} ({size_mb:.2f} MB)")
325+
326+
log_info(f"\nTotal size: {total_size:.2f} MB")
327+
log_info(f"Upload destination: gs://{GCS_BUCKET_NAME}/resources/{version}/{platform_dir}/")
328+
329+
# 6. Create minimal BuildContext for upload
330+
# BuildContext will try to load chromium_src, but we'll provide a dummy one
331+
# since we don't need it for uploads
332+
try:
333+
ctx = BuildContext(
334+
root_dir=root_dir,
335+
chromium_src=Path("/dev/null"), # Dummy path, won't be used
336+
architecture="", # Not needed for upload
337+
build_type="release", # Not needed for upload
338+
)
339+
# Override the version with what we detected
340+
ctx.nxtscape_version = version
341+
except Exception as e:
342+
# If BuildContext fails, we can still upload with minimal info
343+
log_warning(f"Could not create full BuildContext: {e}")
344+
log_info("Creating minimal context for upload...")
345+
346+
# Create a simple object with just what we need
347+
class MinimalContext:
348+
def __init__(self, root_dir: Path, version: str):
349+
self.root_dir = root_dir
350+
self.nxtscape_version = version
351+
352+
ctx = MinimalContext(root_dir, version)
353+
354+
# 7. Upload using existing upload_to_gcs function
355+
success, gcs_uris = upload_to_gcs(ctx, artifacts, platform_override=platform_override)
356+
357+
if success:
358+
log_success("\n✅ Upload completed successfully!")
359+
if gcs_uris:
360+
log_info("\nUploaded URIs:")
361+
for uri in gcs_uris:
362+
log_info(f" {uri}")
363+
return True
364+
else:
365+
log_error("\n❌ Upload failed")
366+
return False

0 commit comments

Comments
 (0)