mirror of
https://github.com/browseros-ai/BrowserOS.git
synced 2026-05-13 23:53:25 +00:00
cli improvements (#222)
* feat: support annotate * feat: extract supports --feature * feat: support classify in dev cli
This commit is contained in:
@@ -170,6 +170,9 @@ def extract_commit(
|
||||
base: Optional[str] = Option(
|
||||
None, "--base", help="Extract full diff from base commit for files in COMMIT"
|
||||
),
|
||||
feature: bool = Option(
|
||||
False, "--feature", help="Add extracted files to a feature in features.yaml"
|
||||
),
|
||||
):
|
||||
"""Extract patches from a single commit"""
|
||||
ctx = create_build_context(state.chromium_src)
|
||||
@@ -190,6 +193,7 @@ def extract_commit(
|
||||
force=force,
|
||||
include_binary=include_binary,
|
||||
base=base,
|
||||
feature=feature,
|
||||
)
|
||||
except Exception as e:
|
||||
log_error(f"Failed to extract commit: {e}")
|
||||
@@ -201,6 +205,9 @@ def extract_patch_cmd(
|
||||
chromium_path: str = Argument(..., help="Chromium file path (e.g., chrome/common/foo.h)"),
|
||||
base: str = Option(..., "--base", "-b", help="Base commit to diff against"),
|
||||
force: bool = Option(False, "--force", "-f", help="Overwrite existing patch without prompting"),
|
||||
feature: bool = Option(
|
||||
False, "--feature", help="Add extracted file to a feature in features.yaml"
|
||||
),
|
||||
):
|
||||
"""Extract patch for a specific file"""
|
||||
ctx = create_build_context(state.chromium_src)
|
||||
@@ -215,6 +222,17 @@ def extract_patch_cmd(
|
||||
raise typer.Exit(1)
|
||||
log_success(f"Successfully extracted patch for: {chromium_path}")
|
||||
|
||||
# Handle --feature flag
|
||||
if feature:
|
||||
from ..modules.feature import prompt_feature_selection, add_files_to_feature
|
||||
|
||||
result = prompt_feature_selection(ctx, base[:12], None)
|
||||
if result is None:
|
||||
log_warning("Skipped adding file to feature")
|
||||
else:
|
||||
feature_name, description = result
|
||||
add_files_to_feature(ctx, feature_name, description, [chromium_path])
|
||||
|
||||
|
||||
@extract_app.command(name="range")
|
||||
def extract_range(
|
||||
@@ -232,6 +250,9 @@ def extract_range(
|
||||
"--base",
|
||||
help="Use different base for diff (full diff from base for files in range)",
|
||||
),
|
||||
feature: bool = Option(
|
||||
False, "--feature", help="Add extracted files to a feature in features.yaml"
|
||||
),
|
||||
):
|
||||
"""Extract patches from a range of commits"""
|
||||
ctx = create_build_context(state.chromium_src)
|
||||
@@ -254,6 +275,7 @@ def extract_range(
|
||||
include_binary=include_binary,
|
||||
squash=squash,
|
||||
base=base,
|
||||
feature=feature,
|
||||
)
|
||||
except Exception as e:
|
||||
log_error(f"Failed to extract range: {e}")
|
||||
@@ -266,10 +288,12 @@ def apply_all(
|
||||
interactive: bool = Option(
|
||||
True, "--interactive/--no-interactive", "-i/-n", help="Interactive mode"
|
||||
),
|
||||
commit: bool = Option(False, "--commit", "-c", help="Commit after each patch"),
|
||||
reset_to: Optional[str] = Option(
|
||||
None, "--reset-to", "-r", help="Reset files to this commit before applying patches"
|
||||
),
|
||||
annotate: bool = Option(
|
||||
False, "--annotate", "-a", help="Create git commits per feature after applying"
|
||||
),
|
||||
):
|
||||
"""Apply all patches from chromium_patches/"""
|
||||
ctx = create_build_context(state.chromium_src)
|
||||
@@ -281,7 +305,7 @@ def apply_all(
|
||||
module = ApplyAllModule()
|
||||
try:
|
||||
module.validate(ctx)
|
||||
module.execute(ctx, interactive=interactive, commit=commit, reset_to=reset_to)
|
||||
module.execute(ctx, interactive=interactive, reset_to=reset_to, annotate=annotate)
|
||||
except Exception as e:
|
||||
log_error(f"Failed to apply patches: {e}")
|
||||
raise typer.Exit(1)
|
||||
@@ -293,10 +317,12 @@ def apply_feature(
|
||||
interactive: bool = Option(
|
||||
True, "--interactive/--no-interactive", "-i/-n", help="Interactive mode"
|
||||
),
|
||||
commit: bool = Option(False, "--commit", "-c", help="Commit after applying"),
|
||||
reset_to: Optional[str] = Option(
|
||||
None, "--reset-to", "-r", help="Reset files to this commit before applying patches"
|
||||
),
|
||||
annotate: bool = Option(
|
||||
False, "--annotate", "-a", help="Create git commit for this feature after applying"
|
||||
),
|
||||
):
|
||||
"""Apply patches for a specific feature"""
|
||||
ctx = create_build_context(state.chromium_src)
|
||||
@@ -309,7 +335,7 @@ def apply_feature(
|
||||
try:
|
||||
module.validate(ctx)
|
||||
module.execute(
|
||||
ctx, feature_name=feature_name, interactive=interactive, commit=commit, reset_to=reset_to
|
||||
ctx, feature_name=feature_name, interactive=interactive, reset_to=reset_to, annotate=annotate
|
||||
)
|
||||
except Exception as e:
|
||||
log_error(f"Failed to apply feature: {e}")
|
||||
@@ -403,5 +429,61 @@ def feature_add(
|
||||
raise typer.Exit(1)
|
||||
|
||||
|
||||
@feature_app.command(name="classify")
|
||||
def feature_classify():
|
||||
"""Classify unclassified patch files into features
|
||||
|
||||
Lists all patches in chromium_patches/ that are not in any feature,
|
||||
then prompts one-by-one to assign each to a feature.
|
||||
|
||||
Examples:
|
||||
browseros dev feature classify
|
||||
"""
|
||||
ctx = create_build_context(state.chromium_src)
|
||||
if not ctx:
|
||||
raise typer.Exit(1)
|
||||
|
||||
from ..modules.feature import ClassifyFeaturesModule
|
||||
|
||||
module = ClassifyFeaturesModule()
|
||||
try:
|
||||
module.validate(ctx)
|
||||
module.execute(ctx)
|
||||
except Exception as e:
|
||||
log_error(f"Failed to classify features: {e}")
|
||||
raise typer.Exit(1)
|
||||
|
||||
|
||||
# Annotate command
|
||||
@app.command(name="annotate")
|
||||
def annotate_cmd(
|
||||
feature_name: Optional[str] = Argument(
|
||||
None, help="Optional: specific feature to annotate (default: all features)"
|
||||
),
|
||||
):
|
||||
"""Create git commits organized by features from features.yaml
|
||||
|
||||
For each feature with modified files, creates a commit with the format:
|
||||
"{feature_name}: {description}"
|
||||
|
||||
Examples:
|
||||
browseros dev annotate -S /path/to/chromium
|
||||
browseros dev annotate llm-chat -S /path/to/chromium
|
||||
"""
|
||||
ctx = create_build_context(state.chromium_src)
|
||||
if not ctx:
|
||||
raise typer.Exit(1)
|
||||
|
||||
from ..modules.annotate import AnnotateModule
|
||||
|
||||
module = AnnotateModule()
|
||||
try:
|
||||
module.validate(ctx)
|
||||
module.execute(ctx, feature_name=feature_name)
|
||||
except Exception as e:
|
||||
log_error(f"Failed to annotate: {e}")
|
||||
raise typer.Exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app()
|
||||
|
||||
@@ -1,358 +1,370 @@
|
||||
version: "1.0"
|
||||
version: '1.0'
|
||||
features:
|
||||
add-sparkle-info-plist-keys:
|
||||
description: "patch: app-info.plist changes"
|
||||
description: 'patch: app-info.plist changes'
|
||||
files:
|
||||
- chrome/app/app-Info.plist
|
||||
- chrome/app/app-Info.plist
|
||||
adding-new-vector-icons:
|
||||
description: "patch: adding-new-vector-icons"
|
||||
description: 'patch: adding-new-vector-icons'
|
||||
files:
|
||||
- components/vector_icons/BUILD.gn
|
||||
- components/vector_icons/chat_orange.icon
|
||||
- components/vector_icons/clash_of_gpts.icon
|
||||
- components/vector_icons/BUILD.gn
|
||||
- components/vector_icons/chat_orange.icon
|
||||
- components/vector_icons/clash_of_gpts.icon
|
||||
branding-file-updates:
|
||||
description: browseros branding for file paths
|
||||
files:
|
||||
- chrome/common/chrome_constants.cc
|
||||
- chrome/common/chrome_paths_linux.cc
|
||||
- chrome/install_static/chromium_install_modes.cc
|
||||
- chrome/install_static/chromium_install_modes.h
|
||||
- components/os_crypt/sync/keychain_password_mac.mm
|
||||
- chrome/common/chrome_constants.cc
|
||||
- chrome/common/chrome_paths_linux.cc
|
||||
- chrome/install_static/chromium_install_modes.cc
|
||||
- chrome/install_static/chromium_install_modes.h
|
||||
- components/os_crypt/sync/keychain_password_mac.mm
|
||||
branding-resources:
|
||||
description: browseros branding resources and assets
|
||||
files:
|
||||
- chrome/app/chromium_strings.grd
|
||||
- chrome/app/settings_chromium_strings.grdp
|
||||
- chrome/app/theme/chromium/BRANDING
|
||||
- chrome/app/theme/chromium/chromeos/
|
||||
- chrome/app/theme/chromium/chromium.ai
|
||||
- chrome/app/theme/chromium/linux/
|
||||
- chrome/app/theme/chromium/mac/
|
||||
- chrome/app/theme/chromium/product_logo.ai
|
||||
- chrome/app/theme/chromium/product_logo.svg
|
||||
- chrome/app/theme/chromium/product_logo.png
|
||||
- chrome/app/theme/chromium/product_logo_16.png
|
||||
- chrome/app/theme/chromium/product_logo_22.png
|
||||
- chrome/app/theme/chromium/product_logo_22_mono.png
|
||||
- chrome/app/theme/chromium/product_logo_24.png
|
||||
- chrome/app/theme/chromium/product_logo_32.png
|
||||
- chrome/app/theme/chromium/product_logo_48.png
|
||||
- chrome/app/theme/chromium/product_logo_64.png
|
||||
- chrome/app/theme/chromium/product_logo_128.png
|
||||
- chrome/app/theme/chromium/product_logo_192.png
|
||||
- chrome/app/theme/chromium/product_logo_256.png
|
||||
- chrome/app/theme/chromium/product_logo_animation.svg
|
||||
- chrome/app/theme/chromium/product_logo_name_22.png
|
||||
- chrome/app/theme/chromium/product_logo_name_22_2x.png
|
||||
- chrome/app/theme/chromium/product_logo_name_22_white.png
|
||||
- chrome/app/theme/chromium/product_logo_name_22_white_2x.png
|
||||
- chrome/app/theme/chromium/win/
|
||||
- chrome/app/theme/default_100_percent/chromium/
|
||||
- chrome/app/theme/default_200_percent/chromium/
|
||||
- chrome/enterprise_companion/branding.gni
|
||||
- chrome/app/chromium_strings.grd
|
||||
- chrome/app/settings_chromium_strings.grdp
|
||||
- chrome/app/theme/
|
||||
- chrome/enterprise_companion/branding.gni
|
||||
ai-settings-page:
|
||||
description: llm settings page
|
||||
files:
|
||||
- chrome/browser/extensions/api/settings_private/prefs_util.cc
|
||||
- chrome/browser/prefs/browser_prefs.cc
|
||||
- chrome/browser/prefs/browser_prefs.h
|
||||
- chrome/browser/resources/settings/BUILD.gn
|
||||
- chrome/browser/resources/settings/nxtscape_page/nxtscape_page.html
|
||||
- chrome/browser/resources/settings/nxtscape_page/nxtscape_page.ts
|
||||
- chrome/browser/resources/settings/route.ts
|
||||
- chrome/browser/resources/settings/router.ts
|
||||
- chrome/browser/resources/settings/settings.ts
|
||||
- chrome/browser/resources/settings/settings_main/settings_main.html
|
||||
- chrome/browser/resources/settings/settings_main/settings_main.ts
|
||||
- chrome/browser/resources/settings/settings_menu/settings_menu.html
|
||||
- chrome/common/pref_names.h
|
||||
- chrome/browser/extensions/api/settings_private/prefs_util.cc
|
||||
- chrome/browser/prefs/browser_prefs.cc
|
||||
- chrome/browser/prefs/browser_prefs.h
|
||||
- chrome/browser/resources/settings/BUILD.gn
|
||||
- chrome/browser/resources/settings/nxtscape_page/nxtscape_page.html
|
||||
- chrome/browser/resources/settings/nxtscape_page/nxtscape_page.ts
|
||||
- chrome/browser/resources/settings/route.ts
|
||||
- chrome/browser/resources/settings/router.ts
|
||||
- chrome/browser/resources/settings/settings.ts
|
||||
- chrome/browser/resources/settings/settings_main/settings_main.html
|
||||
- chrome/browser/resources/settings/settings_main/settings_main.ts
|
||||
- chrome/browser/resources/settings/settings_menu/settings_menu.html
|
||||
- chrome/common/pref_names.h
|
||||
api:
|
||||
description: browseros API
|
||||
files:
|
||||
- chrome/browser/extensions/BUILD.gn
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_api.cc
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_api.h
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_api_helpers.cc
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_api_helpers.h
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_api_utils.cc
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_api_utils.h
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_change_detector.cc
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_change_detector.h
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_content_processor.cc
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_content_processor.h
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_snapshot_processor.cc
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_snapshot_processor.h
|
||||
- chrome/browser/extensions/chrome_extensions_browser_api_provider.cc
|
||||
- chrome/browser/media/extension_media_access_handler.cc
|
||||
- chrome/common/extensions/api/_api_features.json
|
||||
- chrome/common/extensions/api/_permission_features.json
|
||||
- chrome/common/extensions/api/api_sources.gni
|
||||
- chrome/common/extensions/api/browser_os.idl
|
||||
- chrome/common/extensions/permissions/chrome_api_permissions.cc
|
||||
- extensions/browser/extension_function_histogram_value.h
|
||||
- extensions/common/mojom/api_permission_id.mojom
|
||||
- tools/metrics/histograms/metadata/extensions/enums.xml
|
||||
- chrome/browser/extensions/BUILD.gn
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_api.cc
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_api.h
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_api_helpers.cc
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_api_helpers.h
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_api_utils.cc
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_api_utils.h
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_change_detector.cc
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_change_detector.h
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_content_processor.cc
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_content_processor.h
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_snapshot_processor.cc
|
||||
- chrome/browser/extensions/api/browser_os/browser_os_snapshot_processor.h
|
||||
- chrome/browser/extensions/api/side_panel/side_panel_api.h
|
||||
- chrome/browser/extensions/api/side_panel/side_panel_service.cc
|
||||
- chrome/browser/extensions/api/side_panel/side_panel_service.h
|
||||
- chrome/browser/extensions/chrome_extensions_browser_api_provider.cc
|
||||
- chrome/browser/media/extension_media_access_handler.cc
|
||||
- chrome/browser/ui/extensions/extension_side_panel_utils.h
|
||||
- chrome/browser/ui/views/side_panel/extensions/extension_side_panel_utils.cc
|
||||
- chrome/common/extensions/api/_api_features.json
|
||||
- chrome/common/extensions/api/_permission_features.json
|
||||
- chrome/common/extensions/api/api_sources.gni
|
||||
- chrome/common/extensions/api/browser_os.idl
|
||||
- chrome/common/extensions/api/side_panel.idl
|
||||
- chrome/common/extensions/permissions/chrome_api_permissions.cc
|
||||
- extensions/browser/extension_function_histogram_value.h
|
||||
- extensions/common/mojom/api_permission_id.mojom
|
||||
- tools/metrics/histograms/metadata/extensions/enums.xml
|
||||
server:
|
||||
description: browseros server
|
||||
files:
|
||||
- chrome/browser/browseros_server/
|
||||
- base/threading/thread_restrictions.h
|
||||
- base/threading/thread_restrictions.h
|
||||
- chrome/browser/browseros_server/
|
||||
- chrome/browser/browseros_server/BUILD.gn
|
||||
- chrome/browser/browseros_server/browseros_server_manager.cc
|
||||
- chrome/browser/browseros_server/browseros_server_manager.h
|
||||
- chrome/browser/browseros_server/browseros_server_prefs.cc
|
||||
- chrome/browser/browseros_server/browseros_server_prefs.h
|
||||
- chrome/browser/browseros_server/validate_resources.py
|
||||
metrics:
|
||||
description: browseros metrics
|
||||
files:
|
||||
- chrome/browser/metrics/chrome_metrics_service_client.cc
|
||||
- chrome/browser/prefs/browser_prefs.cc
|
||||
- chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
|
||||
- chrome/browser/ui/BUILD.gn
|
||||
- chrome/browser/ui/webui/settings/browseros_metrics_handler.cc
|
||||
- chrome/browser/ui/webui/settings/browseros_metrics_handler.h
|
||||
- chrome/browser/ui/webui/settings/settings_ui.cc
|
||||
- chrome/common/pref_names.h
|
||||
- components/metrics/browseros_metrics/BUILD.gn
|
||||
- components/metrics/browseros_metrics/DEPS
|
||||
- components/metrics/browseros_metrics/browseros_metrics.cc
|
||||
- components/metrics/browseros_metrics/browseros_metrics.h
|
||||
- components/metrics/browseros_metrics/browseros_metrics_prefs.cc
|
||||
- components/metrics/browseros_metrics/browseros_metrics_prefs.h
|
||||
- components/metrics/browseros_metrics/browseros_metrics_service.cc
|
||||
- components/metrics/browseros_metrics/browseros_metrics_service.h
|
||||
- components/metrics/browseros_metrics/browseros_metrics_service_factory.cc
|
||||
- components/metrics/browseros_metrics/browseros_metrics_service_factory.h
|
||||
- chrome/browser/metrics/chrome_metrics_service_client.cc
|
||||
- chrome/browser/prefs/browser_prefs.cc
|
||||
- chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
|
||||
- chrome/browser/ui/BUILD.gn
|
||||
- chrome/browser/ui/webui/settings/browseros_metrics_handler.cc
|
||||
- chrome/browser/ui/webui/settings/browseros_metrics_handler.h
|
||||
- chrome/browser/ui/webui/settings/settings_ui.cc
|
||||
- chrome/common/pref_names.h
|
||||
- components/metrics/browseros_metrics/BUILD.gn
|
||||
- components/metrics/browseros_metrics/DEPS
|
||||
- components/metrics/browseros_metrics/browseros_metrics.cc
|
||||
- components/metrics/browseros_metrics/browseros_metrics.h
|
||||
- components/metrics/browseros_metrics/browseros_metrics_prefs.cc
|
||||
- components/metrics/browseros_metrics/browseros_metrics_prefs.h
|
||||
- components/metrics/browseros_metrics/browseros_metrics_service.cc
|
||||
- components/metrics/browseros_metrics/browseros_metrics_service.h
|
||||
- components/metrics/browseros_metrics/browseros_metrics_service_factory.cc
|
||||
- components/metrics/browseros_metrics/browseros_metrics_service_factory.h
|
||||
ota-updater:
|
||||
description: extensions ota updater
|
||||
files:
|
||||
- chrome/browser/extensions/BUILD.gn
|
||||
- chrome/browser/extensions/api/developer_private/extension_info_generator_shared.cc
|
||||
- chrome/browser/extensions/browseros_extension_constants.h
|
||||
- chrome/browser/extensions/browseros_external_loader.cc
|
||||
- chrome/browser/extensions/browseros_external_loader.h
|
||||
- chrome/browser/extensions/chrome_extension_registrar_delegate.cc
|
||||
- chrome/browser/extensions/extension_web_ui_override_registrar.cc
|
||||
- chrome/browser/extensions/external_provider_impl.cc
|
||||
- chrome/browser/ui/extensions/settings_overridden_params_providers.cc
|
||||
- chrome/browser/extensions/BUILD.gn
|
||||
- chrome/browser/extensions/api/developer_private/extension_info_generator_shared.cc
|
||||
- chrome/browser/extensions/browseros_extension_constants.h
|
||||
- chrome/browser/extensions/browseros_external_loader.cc
|
||||
- chrome/browser/extensions/browseros_external_loader.h
|
||||
- chrome/browser/extensions/chrome_extension_registrar_delegate.cc
|
||||
- chrome/browser/extensions/extension_web_ui_override_registrar.cc
|
||||
- chrome/browser/extensions/external_provider_impl.cc
|
||||
- chrome/browser/ui/extensions/settings_overridden_params_providers.cc
|
||||
chrome-importer:
|
||||
description: chrome importer
|
||||
files:
|
||||
- chrome/app/generated_resources.grd
|
||||
- chrome/app/settings_strings.grdp
|
||||
- chrome/browser/extensions/api/settings_private/prefs_util.cc
|
||||
- chrome/browser/importer/external_process_importer_client.cc
|
||||
- chrome/browser/importer/external_process_importer_client.h
|
||||
- chrome/browser/importer/importer_list.cc
|
||||
- chrome/browser/importer/importer_uma.cc
|
||||
- chrome/browser/importer/in_process_importer_bridge.cc
|
||||
- chrome/browser/importer/in_process_importer_bridge.h
|
||||
- chrome/browser/importer/profile_writer.cc
|
||||
- chrome/browser/importer/profile_writer.h
|
||||
- chrome/browser/resources/settings/people_page/import_data_browser_proxy.ts
|
||||
- chrome/browser/resources/settings/people_page/import_data_dialog.html
|
||||
- chrome/browser/ui/webui/settings/import_data_handler.cc
|
||||
- chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
|
||||
- chrome/browser/ui/webui/settings/settings_ui.cc
|
||||
- chrome/common/importer/importer_bridge.h
|
||||
- chrome/common/importer/importer_data_types.h
|
||||
- chrome/common/importer/importer_type.h
|
||||
- chrome/common/importer/profile_import.mojom
|
||||
- chrome/common/importer/profile_import_process_param_traits_macros.h
|
||||
- chrome/common/pref_names.h
|
||||
- chrome/utility/BUILD.gn
|
||||
- chrome/utility/importer/chrome_importer.cc
|
||||
- chrome/utility/importer/chrome_importer.h
|
||||
- chrome/utility/importer/external_process_importer_bridge.cc
|
||||
- chrome/utility/importer/external_process_importer_bridge.h
|
||||
- chrome/utility/importer/importer_creator.cc
|
||||
- tools/metrics/histograms/metadata/sql/histograms.xml
|
||||
- chrome/app/generated_resources.grd
|
||||
- chrome/app/settings_strings.grdp
|
||||
- chrome/browser/extensions/api/settings_private/prefs_util.cc
|
||||
- chrome/browser/importer/external_process_importer_client.cc
|
||||
- chrome/browser/importer/external_process_importer_client.h
|
||||
- chrome/browser/importer/importer_list.cc
|
||||
- chrome/browser/importer/importer_uma.cc
|
||||
- chrome/browser/importer/in_process_importer_bridge.cc
|
||||
- chrome/browser/importer/in_process_importer_bridge.h
|
||||
- chrome/browser/importer/profile_writer.cc
|
||||
- chrome/browser/importer/profile_writer.h
|
||||
- chrome/browser/resources/settings/people_page/import_data_browser_proxy.ts
|
||||
- chrome/browser/resources/settings/people_page/import_data_dialog.html
|
||||
- chrome/browser/ui/webui/settings/import_data_handler.cc
|
||||
- chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
|
||||
- chrome/browser/ui/webui/settings/settings_ui.cc
|
||||
- chrome/common/importer/importer_bridge.h
|
||||
- chrome/common/importer/importer_data_types.h
|
||||
- chrome/common/importer/importer_type.h
|
||||
- chrome/common/importer/profile_import.mojom
|
||||
- chrome/common/importer/profile_import_process_param_traits_macros.h
|
||||
- chrome/common/pref_names.h
|
||||
- chrome/utility/BUILD.gn
|
||||
- chrome/utility/importer/chrome_importer.cc
|
||||
- chrome/utility/importer/chrome_importer.h
|
||||
- chrome/utility/importer/external_process_importer_bridge.cc
|
||||
- chrome/utility/importer/external_process_importer_bridge.h
|
||||
- chrome/utility/importer/importer_creator.cc
|
||||
- components/user_data_importer/common/importer_data_types.h
|
||||
- components/user_data_importer/common/importer_type.h
|
||||
- tools/metrics/histograms/metadata/sql/histograms.xml
|
||||
chrome-version-updater:
|
||||
description: "patch: chrome version update"
|
||||
description: 'patch: chrome version update'
|
||||
files:
|
||||
- chrome/VERSION
|
||||
- chrome/VERSION
|
||||
default-light-mode:
|
||||
description: enable light mode as default theme
|
||||
files:
|
||||
- chrome/browser/themes/theme_service_factory.cc
|
||||
- chrome/browser/themes/theme_service_factory.cc
|
||||
disable-chrome-labs-pinning:
|
||||
description: "patch: disable-chrome-labs-pinning"
|
||||
description: 'patch: disable-chrome-labs-pinning'
|
||||
files:
|
||||
- chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.cc
|
||||
- chrome/browser/ui/toolbar/toolbar_pref_names.cc
|
||||
- chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.cc
|
||||
- chrome/browser/ui/toolbar/toolbar_pref_names.cc
|
||||
disable-google-key-info-bar:
|
||||
description: "patch: disable-google-key-info-bar"
|
||||
description: 'patch: disable-google-key-info-bar'
|
||||
files:
|
||||
- chrome/browser/ui/startup/google_api_keys_infobar_delegate.cc
|
||||
- chrome/browser/ui/startup/google_api_keys_infobar_delegate.cc
|
||||
disable-info-bar-in-cdp:
|
||||
description: "patch: disable-info-bar-in-cdp"
|
||||
description: 'patch: disable-info-bar-in-cdp'
|
||||
files:
|
||||
- chrome/browser/extensions/api/debugger/debugger_api.cc
|
||||
- chrome/browser/extensions/api/debugger/debugger_api.cc
|
||||
disable-sidepanel-animation:
|
||||
description: disable sidepanel animation
|
||||
files:
|
||||
- chrome/browser/ui/views/side_panel/side_panel.cc
|
||||
- chrome/browser/ui/views/side_panel/side_panel.h
|
||||
- chrome/browser/ui/views/side_panel/side_panel.cc
|
||||
- chrome/browser/ui/views/side_panel/side_panel.h
|
||||
disable-user-gesture-restriction-on-sidepanel:
|
||||
description: "patch: disable-user-gesture-restriction-on-sidepanel"
|
||||
description: 'patch: disable-user-gesture-restriction-on-sidepanel'
|
||||
files:
|
||||
- chrome/browser/extensions/api/side_panel/side_panel_api.cc
|
||||
- chrome/browser/extensions/api/side_panel/side_panel_api.cc
|
||||
first-run:
|
||||
description: first run
|
||||
files:
|
||||
- chrome/browser/chrome_browser_main.cc
|
||||
- chrome/browser/ui/webui/chrome_web_ui_configs.cc
|
||||
- chrome/browser/ui/webui/nxtscape_first_run.h
|
||||
- chrome/common/webui_url_constants.cc
|
||||
- chrome/browser/chrome_browser_main.cc
|
||||
- chrome/browser/ui/webui/chrome_web_ui_configs.cc
|
||||
- chrome/browser/ui/webui/nxtscape_first_run.h
|
||||
- chrome/common/webui_url_constants.cc
|
||||
llm-chat:
|
||||
description: llm chat and updates
|
||||
files:
|
||||
- chrome/app/chrome_command_ids.h
|
||||
- chrome/app/generated_resources.grd
|
||||
- chrome/browser/global_keyboard_shortcuts_mac.mm
|
||||
- chrome/browser/ui/actions/chrome_action_id.h
|
||||
- chrome/browser/ui/browser_actions.cc
|
||||
- chrome/browser/ui/browser_command_controller.cc
|
||||
- chrome/browser/ui/toolbar/toolbar_pref_names.cc
|
||||
- chrome/browser/ui/ui_features.cc
|
||||
- chrome/browser/ui/ui_features.h
|
||||
- chrome/browser/ui/views/accelerator_table.cc
|
||||
- chrome/browser/ui/views/side_panel/BUILD.gn
|
||||
- chrome/browser/ui/views/side_panel/browseros_simple_page_extractor.cc
|
||||
- chrome/browser/ui/views/side_panel/browseros_simple_page_extractor.h
|
||||
- chrome/browser/ui/views/side_panel/clash_of_gpts/clash_of_gpts_coordinator.cc
|
||||
- chrome/browser/ui/views/side_panel/side_panel_entry_id.h
|
||||
- chrome/browser/ui/views/side_panel/side_panel_prefs.cc
|
||||
- chrome/browser/ui/views/side_panel/side_panel_util.cc
|
||||
- chrome/browser/ui/views/side_panel/third_party_llm/third_party_llm_panel_coordinator.cc
|
||||
- chrome/browser/ui/views/side_panel/third_party_llm/third_party_llm_panel_coordinator.h
|
||||
- chrome/browser/ui/views/side_panel/third_party_llm/third_party_llm_view.cc
|
||||
- chrome/browser/ui/views/side_panel/third_party_llm/third_party_llm_view.h
|
||||
- chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar.mojom
|
||||
- chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler.cc
|
||||
- chrome/app/chrome_command_ids.h
|
||||
- chrome/app/generated_resources.grd
|
||||
- chrome/browser/global_keyboard_shortcuts_mac.mm
|
||||
- chrome/browser/ui/actions/chrome_action_id.h
|
||||
- chrome/browser/ui/browser_actions.cc
|
||||
- chrome/browser/ui/browser_command_controller.cc
|
||||
- chrome/browser/ui/toolbar/toolbar_pref_names.cc
|
||||
- chrome/browser/ui/ui_features.cc
|
||||
- chrome/browser/ui/ui_features.h
|
||||
- chrome/browser/ui/views/accelerator_table.cc
|
||||
- chrome/browser/ui/views/side_panel/BUILD.gn
|
||||
- chrome/browser/ui/views/side_panel/browseros_simple_page_extractor.cc
|
||||
- chrome/browser/ui/views/side_panel/browseros_simple_page_extractor.h
|
||||
- chrome/browser/ui/views/side_panel/clash_of_gpts/clash_of_gpts_coordinator.cc
|
||||
- chrome/browser/ui/views/side_panel/side_panel_entry_id.h
|
||||
- chrome/browser/ui/views/side_panel/side_panel_prefs.cc
|
||||
- chrome/browser/ui/views/side_panel/side_panel_util.cc
|
||||
- chrome/browser/ui/views/side_panel/third_party_llm/third_party_llm_panel_coordinator.cc
|
||||
- chrome/browser/ui/views/side_panel/third_party_llm/third_party_llm_panel_coordinator.h
|
||||
- chrome/browser/ui/views/side_panel/third_party_llm/third_party_llm_view.cc
|
||||
- chrome/browser/ui/views/side_panel/third_party_llm/third_party_llm_view.h
|
||||
- chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar.mojom
|
||||
- chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler.cc
|
||||
llm-hub:
|
||||
description: llm-hub
|
||||
files:
|
||||
- chrome/app/chrome_command_ids.h
|
||||
- chrome/app/generated_resources.grd
|
||||
- chrome/browser/global_keyboard_shortcuts_mac.mm
|
||||
- chrome/browser/ui/actions/chrome_action_id.h
|
||||
- chrome/browser/ui/browser_actions.cc
|
||||
- chrome/browser/ui/browser_command_controller.cc
|
||||
- chrome/browser/ui/toolbar/toolbar_pref_names.cc
|
||||
- chrome/browser/ui/ui_features.cc
|
||||
- chrome/browser/ui/ui_features.h
|
||||
- chrome/browser/ui/views/accelerator_table.cc
|
||||
- chrome/browser/ui/views/side_panel/BUILD.gn
|
||||
- chrome/browser/ui/views/side_panel/clash_of_gpts/clash_of_gpts_coordinator.cc
|
||||
- chrome/browser/ui/views/side_panel/clash_of_gpts/clash_of_gpts_coordinator.h
|
||||
- chrome/browser/ui/views/side_panel/clash_of_gpts/clash_of_gpts_view.cc
|
||||
- chrome/browser/ui/views/side_panel/clash_of_gpts/clash_of_gpts_view.h
|
||||
- chrome/browser/ui/views/side_panel/clash_of_gpts/clash_of_gpts_window.cc
|
||||
- chrome/browser/ui/views/side_panel/clash_of_gpts/clash_of_gpts_window.h
|
||||
- chrome/browser/ui/views/side_panel/side_panel_entry_id.h
|
||||
- chrome/browser/ui/views/side_panel/side_panel_prefs.cc
|
||||
- chrome/browser/ui/views/side_panel/side_panel_util.cc
|
||||
- chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.cc
|
||||
- chrome/browser/ui/webui/BUILD.gn
|
||||
- chrome/browser/ui/webui/chrome_web_ui_configs.cc
|
||||
- chrome/browser/ui/webui/clash_of_gpts/clash_of_gpts_ui.cc
|
||||
- chrome/browser/ui/webui/clash_of_gpts/clash_of_gpts_ui.h
|
||||
- chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar.mojom
|
||||
- chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler.cc
|
||||
- chrome/common/webui_url_constants.h
|
||||
- chrome/app/chrome_command_ids.h
|
||||
- chrome/app/generated_resources.grd
|
||||
- chrome/browser/global_keyboard_shortcuts_mac.mm
|
||||
- chrome/browser/ui/actions/chrome_action_id.h
|
||||
- chrome/browser/ui/browser_actions.cc
|
||||
- chrome/browser/ui/browser_command_controller.cc
|
||||
- chrome/browser/ui/toolbar/toolbar_pref_names.cc
|
||||
- chrome/browser/ui/ui_features.cc
|
||||
- chrome/browser/ui/ui_features.h
|
||||
- chrome/browser/ui/views/accelerator_table.cc
|
||||
- chrome/browser/ui/views/side_panel/BUILD.gn
|
||||
- chrome/browser/ui/views/side_panel/clash_of_gpts/clash_of_gpts_coordinator.cc
|
||||
- chrome/browser/ui/views/side_panel/clash_of_gpts/clash_of_gpts_coordinator.h
|
||||
- chrome/browser/ui/views/side_panel/clash_of_gpts/clash_of_gpts_view.cc
|
||||
- chrome/browser/ui/views/side_panel/clash_of_gpts/clash_of_gpts_view.h
|
||||
- chrome/browser/ui/views/side_panel/clash_of_gpts/clash_of_gpts_window.cc
|
||||
- chrome/browser/ui/views/side_panel/clash_of_gpts/clash_of_gpts_window.h
|
||||
- chrome/browser/ui/views/side_panel/side_panel_entry_id.h
|
||||
- chrome/browser/ui/views/side_panel/side_panel_prefs.cc
|
||||
- chrome/browser/ui/views/side_panel/side_panel_util.cc
|
||||
- chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.cc
|
||||
- chrome/browser/ui/webui/BUILD.gn
|
||||
- chrome/browser/ui/webui/chrome_web_ui_configs.cc
|
||||
- chrome/browser/ui/webui/clash_of_gpts/clash_of_gpts_ui.cc
|
||||
- chrome/browser/ui/webui/clash_of_gpts/clash_of_gpts_ui.h
|
||||
- chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar.mojom
|
||||
- chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler.cc
|
||||
- chrome/common/webui_url_constants.h
|
||||
llm-settings-page-updates:
|
||||
description: "llm settings page: updates"
|
||||
description: 'llm settings page: updates'
|
||||
files:
|
||||
- chrome/browser/resources/settings/BUILD.gn
|
||||
- chrome/browser/resources/settings/nxtscape_page/models_data.html
|
||||
- chrome/browser/resources/settings/nxtscape_page/models_data.ts
|
||||
- chrome/browser/resources/settings/nxtscape_page/nxtscape_page.html
|
||||
- chrome/browser/resources/settings/nxtscape_page/nxtscape_page.ts
|
||||
- chrome/browser/resources/settings/BUILD.gn
|
||||
- chrome/browser/resources/settings/nxtscape_page/models_data.html
|
||||
- chrome/browser/resources/settings/nxtscape_page/models_data.ts
|
||||
- chrome/browser/resources/settings/nxtscape_page/nxtscape_page.html
|
||||
- chrome/browser/resources/settings/nxtscape_page/nxtscape_page.ts
|
||||
mac-sparkle-updater:
|
||||
description: "patch: nxtscape-updater-sparkle"
|
||||
description: 'patch: nxtscape-updater-sparkle'
|
||||
files:
|
||||
- chrome/BUILD.gn
|
||||
- chrome/browser/BUILD.gn
|
||||
- chrome/browser/mac/chrome_browser_main_extra_parts_mac.h
|
||||
- chrome/browser/mac/chrome_browser_main_extra_parts_mac.mm
|
||||
- chrome/browser/mac/sparkle_glue.h
|
||||
- chrome/browser/mac/sparkle_glue.mm
|
||||
- chrome/browser/mac/su_updater.h
|
||||
- chrome/browser/sparkle_buildflags.gni
|
||||
- chrome/browser/ui/BUILD.gn
|
||||
- chrome/browser/ui/webui/help/sparkle_version_updater_mac.h
|
||||
- chrome/browser/ui/webui/help/sparkle_version_updater_mac.mm
|
||||
- chrome/browser/ui/webui/help/version_updater_mac.mm
|
||||
- third_party/sparkle/
|
||||
- chrome/BUILD.gn
|
||||
- chrome/browser/BUILD.gn
|
||||
- chrome/browser/mac/chrome_browser_main_extra_parts_mac.h
|
||||
- chrome/browser/mac/chrome_browser_main_extra_parts_mac.mm
|
||||
- chrome/browser/mac/sparkle_glue.h
|
||||
- chrome/browser/mac/sparkle_glue.mm
|
||||
- chrome/browser/mac/su_updater.h
|
||||
- chrome/browser/sparkle_buildflags.gni
|
||||
- chrome/browser/ui/BUILD.gn
|
||||
- chrome/browser/ui/webui/help/sparkle_version_updater_mac.h
|
||||
- chrome/browser/ui/webui/help/sparkle_version_updater_mac.mm
|
||||
- chrome/browser/ui/webui/help/version_updater_mac.mm
|
||||
- third_party/sparkle/
|
||||
pin-chat-and-hub:
|
||||
description: pin browseros native panels
|
||||
files:
|
||||
- chrome/browser/extensions/browseros_extension_constants.h
|
||||
- chrome/browser/sync/prefs/chrome_syncable_prefs_database.cc
|
||||
- chrome/browser/ui/actions/browseros_actions_config.h
|
||||
- chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.cc
|
||||
- chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.h
|
||||
- chrome/browser/ui/toolbar/toolbar_pref_names.cc
|
||||
- chrome/browser/ui/toolbar/toolbar_pref_names.h
|
||||
- chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.cc
|
||||
- chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.cc
|
||||
- chrome/browser/extensions/browseros_extension_constants.h
|
||||
- chrome/browser/sync/prefs/chrome_syncable_prefs_database.cc
|
||||
- chrome/browser/ui/actions/browseros_actions_config.h
|
||||
- chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.cc
|
||||
- chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.h
|
||||
- chrome/browser/ui/toolbar/toolbar_pref_names.cc
|
||||
- chrome/browser/ui/toolbar/toolbar_pref_names.h
|
||||
- chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.cc
|
||||
- chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.cc
|
||||
pin-extensions-toolbar:
|
||||
description: pin browseros extensions to extension toolbar
|
||||
files:
|
||||
- chrome/browser/extensions/browseros_extension_constants.h
|
||||
- chrome/browser/extensions/extension_context_menu_model.cc
|
||||
- chrome/browser/extensions/extension_management.cc
|
||||
- chrome/browser/ui/actions/browseros_actions_config.h
|
||||
- chrome/browser/ui/toolbar/toolbar_actions_model.cc
|
||||
- chrome/browser/ui/views/side_panel/extensions/extension_side_panel_manager.cc
|
||||
- chrome/browser/extensions/browseros_extension_constants.h
|
||||
- chrome/browser/extensions/extension_context_menu_model.cc
|
||||
- chrome/browser/extensions/extension_management.cc
|
||||
- chrome/browser/ui/actions/browseros_actions_config.h
|
||||
- chrome/browser/ui/toolbar/toolbar_actions_model.cc
|
||||
- chrome/browser/ui/views/side_panel/extensions/extension_side_panel_manager.cc
|
||||
- chrome/browser/ui/views/side_panel/side_panel_action_callback.cc
|
||||
- chrome/browser/ui/views/side_panel/side_panel_action_callback.h
|
||||
preferences-settings-page:
|
||||
description: "patch: settings prefs page"
|
||||
description: 'patch: settings prefs page'
|
||||
files:
|
||||
- chrome/browser/extensions/api/settings_private/prefs_util.cc
|
||||
- chrome/browser/prefs/browser_prefs.cc
|
||||
- chrome/browser/resources/settings/BUILD.gn
|
||||
- chrome/browser/resources/settings/browseros_prefs_page/browseros_prefs_page.html
|
||||
- chrome/browser/resources/settings/browseros_prefs_page/browseros_prefs_page.ts
|
||||
- chrome/browser/resources/settings/route.ts
|
||||
- chrome/browser/resources/settings/router.ts
|
||||
- chrome/browser/resources/settings/settings.ts
|
||||
- chrome/browser/resources/settings/settings_main/settings_main.html
|
||||
- chrome/browser/resources/settings/settings_main/settings_main.ts
|
||||
- chrome/browser/resources/settings/settings_menu/settings_menu.html
|
||||
- chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.cc
|
||||
- chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.h
|
||||
- chrome/common/pref_names.h
|
||||
- chrome/browser/extensions/api/settings_private/prefs_util.cc
|
||||
- chrome/browser/prefs/browser_prefs.cc
|
||||
- chrome/browser/resources/settings/BUILD.gn
|
||||
- chrome/browser/resources/settings/browseros_prefs_page/browseros_prefs_page.html
|
||||
- chrome/browser/resources/settings/browseros_prefs_page/browseros_prefs_page.ts
|
||||
- chrome/browser/resources/settings/route.ts
|
||||
- chrome/browser/resources/settings/router.ts
|
||||
- chrome/browser/resources/settings/settings.ts
|
||||
- chrome/browser/resources/settings/settings_main/settings_main.html
|
||||
- chrome/browser/resources/settings/settings_main/settings_main.ts
|
||||
- chrome/browser/resources/settings/settings_menu/settings_menu.html
|
||||
- chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.cc
|
||||
- chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.h
|
||||
- chrome/common/pref_names.h
|
||||
ui-fixes:
|
||||
description: "patch: chromium ui fixes"
|
||||
description: 'patch: chromium ui fixes'
|
||||
files:
|
||||
- chrome/browser/chrome_content_browser_client.cc
|
||||
- chrome/browser/net/profile_network_context_service.cc
|
||||
- chrome/browser/resources/settings/about_page/about_page.html
|
||||
- chrome/browser/resources/settings/about_page/about_page.ts
|
||||
- chrome/browser/resources/settings/reset_page/reset_profile_dialog.html
|
||||
- chrome/browser/ui/browser_ui_prefs.cc
|
||||
- chrome/browser/ui/views/chrome_layout_provider.cc
|
||||
- chrome/browser/ui/views/infobars/infobar_container_view.cc
|
||||
- chrome/browser/ui/views/new_tab_footer/
|
||||
- chrome/browser/ui/webui/new_tab_footer/
|
||||
- components/bookmarks/browser/bookmark_utils.cc
|
||||
- components/content_settings/core/browser/cookie_settings.cc
|
||||
- components/payments/core/payment_prefs.cc
|
||||
- components/performance_manager/user_tuning/prefs.cc
|
||||
- components/search/ntp_features.cc
|
||||
- chrome/browser/about_flags.cc
|
||||
- chrome/browser/browser_features.cc
|
||||
- chrome/browser/browser_features.h
|
||||
- chrome/browser/chrome_content_browser_client.cc
|
||||
- chrome/browser/net/profile_network_context_service.cc
|
||||
- chrome/browser/resources/settings/about_page/about_page.html
|
||||
- chrome/browser/resources/settings/about_page/about_page.ts
|
||||
- chrome/browser/resources/settings/reset_page/reset_profile_dialog.html
|
||||
- chrome/browser/ui/browser_ui_prefs.cc
|
||||
- chrome/browser/ui/views/chrome_layout_provider.cc
|
||||
- chrome/browser/ui/views/infobars/infobar_container_view.cc
|
||||
- chrome/browser/ui/views/new_tab_footer/
|
||||
- chrome/browser/ui/views/new_tab_footer/footer_controller.cc
|
||||
- chrome/browser/ui/webui/new_tab_footer/
|
||||
- chrome/browser/ui/webui/new_tab_footer/new_tab_footer_ui.cc
|
||||
- components/bookmarks/browser/bookmark_utils.cc
|
||||
- components/content_settings/core/browser/cookie_settings.cc
|
||||
- components/payments/core/payment_prefs.cc
|
||||
- components/performance_manager/user_tuning/prefs.cc
|
||||
- components/search/ntp_features.cc
|
||||
browseros-version:
|
||||
description: "patch: browseros version"
|
||||
description: 'patch: browseros version'
|
||||
files:
|
||||
- base/version_info/BUILD.gn
|
||||
- base/version_info/version_info.h
|
||||
- base/version_info/version_info_values.h.version
|
||||
- chrome/BROWSEROS_VERSION
|
||||
- chrome/browser/resources/settings/about_page/about_page.html
|
||||
- chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
|
||||
- base/version_info/BUILD.gn
|
||||
- base/version_info/version_info.h
|
||||
- base/version_info/version_info_values.h.version
|
||||
- chrome/BROWSEROS_VERSION
|
||||
- chrome/browser/resources/settings/about_page/about_page.html
|
||||
- chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
|
||||
misc:
|
||||
description: miscellaneous patches
|
||||
files:
|
||||
- chrome/browser/ui/omnibox/chrome_omnibox_client.cc
|
||||
- chrome/browser/ui/profiles/profile_error_dialog.cc
|
||||
- chrome/browser/ui/startup/infobar_utils.cc
|
||||
- chrome/installer/mini_installer/chrome.release
|
||||
- chrome/updater/branding.gni
|
||||
- extensions/browser/process_manager.cc
|
||||
- extensions/browser/process_manager.h
|
||||
- third_party/blink/renderer/core/frame/navigator.cc
|
||||
- chrome/browser/browseros_server/.gitignore
|
||||
- chrome/browser/ui/omnibox/chrome_omnibox_client.cc
|
||||
- chrome/browser/ui/profiles/profile_error_dialog.cc
|
||||
- chrome/browser/ui/startup/infobar_utils.cc
|
||||
- chrome/installer/mini_installer/chrome.release
|
||||
- chrome/updater/branding.gni
|
||||
- extensions/browser/process_manager.cc
|
||||
- extensions/browser/process_manager.h
|
||||
- third_party/blink/renderer/core/frame/navigator.cc
|
||||
flags:
|
||||
description: adding new flags or udpating existing
|
||||
files:
|
||||
- chrome/browser/flag_descriptions.cc
|
||||
- chrome/browser/flag_descriptions.h
|
||||
- chrome/browser/ui/browser_window/internal/browser_window_features.cc
|
||||
- chrome/browser/ui/browser_window/public/browser_window_features.h
|
||||
keyboard-shorcuts:
|
||||
description: keyboard shortcuts
|
||||
files:
|
||||
- chrome/browser/ui/accelerator_table.cc
|
||||
mac-sparkle:
|
||||
description: mac sparkle updater
|
||||
files:
|
||||
- third_party/sparkle/BUILD.gn
|
||||
|
||||
15
packages/browseros/build/modules/annotate/__init__.py
Normal file
15
packages/browseros/build/modules/annotate/__init__.py
Normal file
@@ -0,0 +1,15 @@
|
||||
"""
|
||||
Annotate module - Create git commits organized by features.
|
||||
|
||||
Provides commands for creating feature-based commits:
|
||||
- annotate_features: Create commits for all features with modified files
|
||||
- annotate_single_feature: Create a commit for a specific feature
|
||||
"""
|
||||
|
||||
from .annotate import annotate_features, annotate_single_feature, AnnotateModule
|
||||
|
||||
__all__ = [
|
||||
"annotate_features",
|
||||
"annotate_single_feature",
|
||||
"AnnotateModule",
|
||||
]
|
||||
239
packages/browseros/build/modules/annotate/annotate.py
Normal file
239
packages/browseros/build/modules/annotate/annotate.py
Normal file
@@ -0,0 +1,239 @@
|
||||
"""
|
||||
Annotate - Create git commits organized by features from features.yaml
|
||||
|
||||
For each feature, checks which files have modifications and creates a commit
|
||||
with the feature name and description.
|
||||
"""
|
||||
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
from typing import List, Tuple, Optional, Dict
|
||||
|
||||
from ..apply.utils import run_git_command
|
||||
from ...common.context import Context
|
||||
from ...common.module import CommandModule, ValidationError
|
||||
from ...common.utils import log_info, log_error, log_success, log_warning
|
||||
|
||||
|
||||
def load_features(features_file: Path) -> Dict:
|
||||
"""Load features from YAML file."""
|
||||
try:
|
||||
with open(features_file, "r") as f:
|
||||
data = yaml.safe_load(f)
|
||||
return data.get("features", {})
|
||||
except Exception as e:
|
||||
log_error(f"Failed to load features file: {e}")
|
||||
return {}
|
||||
|
||||
|
||||
def get_modified_files(chromium_src: Path, files: List[str]) -> List[str]:
|
||||
"""Get list of files that have modifications or are untracked.
|
||||
|
||||
Args:
|
||||
chromium_src: Chromium source directory
|
||||
files: List of file paths to check
|
||||
|
||||
Returns:
|
||||
List of file paths that have modifications
|
||||
"""
|
||||
modified = []
|
||||
|
||||
for file_path in files:
|
||||
full_path = chromium_src / file_path
|
||||
|
||||
if not full_path.exists():
|
||||
continue
|
||||
|
||||
result = run_git_command(
|
||||
["git", "status", "--porcelain", str(file_path)],
|
||||
cwd=chromium_src,
|
||||
)
|
||||
|
||||
if result.returncode == 0 and result.stdout.strip():
|
||||
modified.append(file_path)
|
||||
|
||||
return modified
|
||||
|
||||
|
||||
def git_add_and_commit(
|
||||
chromium_src: Path, files: List[str], commit_message: str
|
||||
) -> bool:
|
||||
"""Add files and create commit.
|
||||
|
||||
Args:
|
||||
chromium_src: Chromium source directory
|
||||
files: List of file paths to add
|
||||
commit_message: Commit message
|
||||
|
||||
Returns:
|
||||
True if commit was created successfully
|
||||
"""
|
||||
# Add all specified files
|
||||
for file_path in files:
|
||||
result = run_git_command(
|
||||
["git", "add", str(file_path)],
|
||||
cwd=chromium_src,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
log_error(f"Failed to add file: {file_path}")
|
||||
return False
|
||||
|
||||
# Create commit
|
||||
result = run_git_command(
|
||||
["git", "commit", "-m", commit_message],
|
||||
cwd=chromium_src,
|
||||
)
|
||||
|
||||
if result.returncode != 0:
|
||||
stderr = result.stderr or ""
|
||||
if "nothing to commit" in stderr or "nothing added to commit" in stderr:
|
||||
return False
|
||||
log_error(f"Failed to commit: {stderr}")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def annotate_features(
|
||||
ctx: Context,
|
||||
feature_filter: Optional[str] = None,
|
||||
) -> Tuple[int, int]:
|
||||
"""Create commits for features with modified files.
|
||||
|
||||
Iterates through features.yaml and creates a commit for each feature
|
||||
that has modified files in the working tree.
|
||||
|
||||
Args:
|
||||
ctx: Build context
|
||||
feature_filter: If specified, only process this feature
|
||||
|
||||
Returns:
|
||||
Tuple of (commits_created, features_skipped)
|
||||
"""
|
||||
features_file = ctx.get_features_yaml_path()
|
||||
|
||||
if not features_file.exists():
|
||||
log_error(f"Features file not found: {features_file}")
|
||||
return 0, 0
|
||||
|
||||
features = load_features(features_file)
|
||||
if not features:
|
||||
log_error("No features found in features.yaml")
|
||||
return 0, 0
|
||||
|
||||
# Filter to specific feature if requested
|
||||
if feature_filter:
|
||||
if feature_filter not in features:
|
||||
log_error(f"Feature '{feature_filter}' not found in features.yaml")
|
||||
return 0, 0
|
||||
features = {feature_filter: features[feature_filter]}
|
||||
|
||||
log_info(f"📋 Processing {len(features)} feature(s)")
|
||||
log_info("=" * 60)
|
||||
|
||||
commits_created = 0
|
||||
features_skipped = 0
|
||||
|
||||
for feature_name, feature_data in features.items():
|
||||
description = feature_data.get("description", feature_name)
|
||||
files = feature_data.get("files", [])
|
||||
|
||||
log_info(f"\n🔧 {feature_name}")
|
||||
log_info(f" {description}")
|
||||
|
||||
if not files:
|
||||
log_warning(" No files specified, skipping")
|
||||
features_skipped += 1
|
||||
continue
|
||||
|
||||
# Find files with modifications
|
||||
modified_files = get_modified_files(ctx.chromium_src, files)
|
||||
|
||||
if not modified_files:
|
||||
log_warning(f" No modified files ({len(files)} files checked)")
|
||||
features_skipped += 1
|
||||
continue
|
||||
|
||||
log_info(f" Found {len(modified_files)} modified file(s)")
|
||||
|
||||
# Create commit
|
||||
commit_message = f"{feature_name}: {description}"
|
||||
|
||||
if git_add_and_commit(ctx.chromium_src, modified_files, commit_message):
|
||||
log_success(f" ✓ Committed {len(modified_files)} file(s)")
|
||||
commits_created += 1
|
||||
else:
|
||||
log_warning(" No changes staged, skipping commit")
|
||||
features_skipped += 1
|
||||
|
||||
return commits_created, features_skipped
|
||||
|
||||
|
||||
def annotate_single_feature(
|
||||
ctx: Context,
|
||||
feature_name: str,
|
||||
) -> bool:
|
||||
"""Create a commit for a single feature.
|
||||
|
||||
Args:
|
||||
ctx: Build context
|
||||
feature_name: Name of the feature to commit
|
||||
|
||||
Returns:
|
||||
True if commit was created successfully
|
||||
"""
|
||||
commits, _ = annotate_features(ctx, feature_filter=feature_name)
|
||||
return commits > 0
|
||||
|
||||
|
||||
class AnnotateModule(CommandModule):
|
||||
"""Create git commits organized by features from features.yaml"""
|
||||
|
||||
produces = []
|
||||
requires = []
|
||||
description = "Create git commits organized by features"
|
||||
|
||||
def validate(self, ctx: Context) -> None:
|
||||
"""Validate git is available and chromium_src exists."""
|
||||
import shutil
|
||||
|
||||
if not shutil.which("git"):
|
||||
raise ValidationError("Git is not available in PATH")
|
||||
if not ctx.chromium_src.exists():
|
||||
raise ValidationError(f"Chromium source not found: {ctx.chromium_src}")
|
||||
|
||||
# Check if it's a git repository
|
||||
git_dir = ctx.chromium_src / ".git"
|
||||
if not git_dir.exists():
|
||||
raise ValidationError(f"Not a git repository: {ctx.chromium_src}")
|
||||
|
||||
def execute(
|
||||
self,
|
||||
ctx: Context,
|
||||
feature_name: Optional[str] = None,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""Execute annotate.
|
||||
|
||||
Args:
|
||||
ctx: Build context
|
||||
feature_name: If specified, only annotate this feature
|
||||
"""
|
||||
log_info("🏗️ Annotate Features")
|
||||
log_info("=" * 60)
|
||||
log_info(f"📁 Chromium source: {ctx.chromium_src}")
|
||||
log_info(f"📄 Features file: {ctx.get_features_yaml_path()}")
|
||||
|
||||
commits_created, features_skipped = annotate_features(
|
||||
ctx, feature_filter=feature_name
|
||||
)
|
||||
|
||||
log_info("\n" + "=" * 60)
|
||||
if commits_created > 0:
|
||||
log_success(f"✓ Created {commits_created} commit(s)")
|
||||
else:
|
||||
log_info("No commits created (no modified files found)")
|
||||
|
||||
if features_skipped > 0:
|
||||
log_info(f" Skipped {features_skipped} feature(s) with no changes")
|
||||
log_info("=" * 60)
|
||||
@@ -6,13 +6,12 @@ from typing import List, Tuple, Optional
|
||||
|
||||
from ...common.context import Context
|
||||
from ...common.module import CommandModule, ValidationError
|
||||
from ...common.utils import log_info, log_error, log_warning
|
||||
from ...common.utils import log_info, log_error, log_warning, log_success
|
||||
from .common import find_patch_files, process_patch_list
|
||||
|
||||
|
||||
def apply_all_patches(
|
||||
build_ctx: Context,
|
||||
commit_each: bool = False,
|
||||
dry_run: bool = False,
|
||||
interactive: bool = False,
|
||||
reset_to: Optional[str] = None,
|
||||
@@ -21,7 +20,6 @@ def apply_all_patches(
|
||||
|
||||
Args:
|
||||
build_ctx: Build context
|
||||
commit_each: Create a commit after each patch
|
||||
dry_run: Only check if patches would apply
|
||||
interactive: Ask for confirmation before each patch
|
||||
reset_to: Commit to reset files to before applying (optional)
|
||||
@@ -55,7 +53,6 @@ def apply_all_patches(
|
||||
patch_list,
|
||||
build_ctx.chromium_src,
|
||||
patches_dir,
|
||||
commit_each,
|
||||
dry_run,
|
||||
interactive,
|
||||
reset_to=reset_to,
|
||||
@@ -92,23 +89,34 @@ class ApplyAllModule(CommandModule):
|
||||
self,
|
||||
ctx: Context,
|
||||
interactive: bool = True,
|
||||
commit: bool = False,
|
||||
reset_to: Optional[str] = None,
|
||||
annotate: bool = False,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""Execute apply all patches
|
||||
|
||||
Args:
|
||||
interactive: Interactive mode (ask before each patch)
|
||||
commit: Create git commit after each patch
|
||||
reset_to: Commit to reset files to before applying (optional)
|
||||
annotate: Create git commits per feature after applying
|
||||
"""
|
||||
applied, failed = apply_all_patches(
|
||||
ctx,
|
||||
commit_each=commit,
|
||||
dry_run=False,
|
||||
interactive=interactive,
|
||||
reset_to=reset_to,
|
||||
)
|
||||
if failed:
|
||||
raise RuntimeError(f"Failed to apply {len(failed)} patches")
|
||||
|
||||
# Run annotate if requested
|
||||
if annotate:
|
||||
from ..annotate import annotate_features
|
||||
|
||||
log_info("\n" + "=" * 60)
|
||||
log_info("🏗️ Creating feature-based commits...")
|
||||
commits, skipped = annotate_features(ctx)
|
||||
if commits > 0:
|
||||
log_success(f"✓ Created {commits} commit(s)")
|
||||
else:
|
||||
log_info("No commits created (no modified files found)")
|
||||
|
||||
@@ -7,14 +7,13 @@ from typing import List, Tuple, Optional
|
||||
|
||||
from ...common.context import Context
|
||||
from ...common.module import CommandModule, ValidationError
|
||||
from ...common.utils import log_info, log_error, log_warning
|
||||
from ...common.utils import log_info, log_error, log_warning, log_success
|
||||
from .common import process_patch_list
|
||||
|
||||
|
||||
def apply_feature_patches(
|
||||
build_ctx: Context,
|
||||
feature_name: str,
|
||||
commit_each: bool = False,
|
||||
dry_run: bool = False,
|
||||
reset_to: Optional[str] = None,
|
||||
) -> Tuple[int, List[str]]:
|
||||
@@ -23,7 +22,6 @@ def apply_feature_patches(
|
||||
Args:
|
||||
build_ctx: Build context
|
||||
feature_name: Name of the feature
|
||||
commit_each: Create a commit after each patch
|
||||
dry_run: Only check if patches would apply
|
||||
reset_to: Commit to reset files to before applying (optional)
|
||||
|
||||
@@ -71,10 +69,8 @@ def apply_feature_patches(
|
||||
patch_list,
|
||||
build_ctx.chromium_src,
|
||||
patches_dir,
|
||||
commit_each,
|
||||
dry_run,
|
||||
interactive=False, # Feature patches don't support interactive mode
|
||||
feature_name=feature_name,
|
||||
reset_to=reset_to,
|
||||
)
|
||||
|
||||
@@ -110,8 +106,8 @@ class ApplyFeatureModule(CommandModule):
|
||||
ctx: Context,
|
||||
feature_name: str,
|
||||
interactive: bool = True,
|
||||
commit: bool = False,
|
||||
reset_to: Optional[str] = None,
|
||||
annotate: bool = False,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""Execute apply feature patches
|
||||
@@ -119,13 +115,12 @@ class ApplyFeatureModule(CommandModule):
|
||||
Args:
|
||||
feature_name: Name of the feature to apply
|
||||
interactive: Interactive mode (ask before each patch)
|
||||
commit: Create git commit after applying
|
||||
reset_to: Commit to reset files to before applying (optional)
|
||||
annotate: Create git commit for this feature after applying
|
||||
"""
|
||||
applied, failed = apply_feature_patches(
|
||||
ctx,
|
||||
feature_name,
|
||||
commit_each=commit,
|
||||
dry_run=False,
|
||||
reset_to=reset_to,
|
||||
)
|
||||
@@ -133,3 +128,14 @@ class ApplyFeatureModule(CommandModule):
|
||||
raise RuntimeError(
|
||||
f"Failed to apply {len(failed)} patches for feature '{feature_name}'"
|
||||
)
|
||||
|
||||
# Run annotate for this specific feature if requested
|
||||
if annotate:
|
||||
from ..annotate import annotate_single_feature
|
||||
|
||||
log_info("\n" + "=" * 60)
|
||||
log_info(f"🏗️ Creating commit for feature '{feature_name}'...")
|
||||
if annotate_single_feature(ctx, feature_name):
|
||||
log_success(f"✓ Created commit for '{feature_name}'")
|
||||
else:
|
||||
log_info("No commit created (no modified files found)")
|
||||
|
||||
@@ -153,10 +153,8 @@ def process_patch_list(
|
||||
patch_list: List[Tuple[Path, str]],
|
||||
chromium_src: Path,
|
||||
patches_dir: Path,
|
||||
commit_each: bool = False,
|
||||
dry_run: bool = False,
|
||||
interactive: bool = False,
|
||||
feature_name: Optional[str] = None,
|
||||
reset_to: Optional[str] = None,
|
||||
) -> Tuple[int, List[str]]:
|
||||
"""Process a list of patches.
|
||||
@@ -165,10 +163,8 @@ def process_patch_list(
|
||||
patch_list: List of (patch_path, display_name) tuples
|
||||
chromium_src: Chromium source directory
|
||||
patches_dir: Base directory for relative path display
|
||||
commit_each: Create a commit after each patch
|
||||
dry_run: Only check if patches would apply
|
||||
interactive: Ask for confirmation before each patch
|
||||
feature_name: Optional feature name for commit messages
|
||||
reset_to: Commit to reset files to before applying (optional)
|
||||
|
||||
Returns:
|
||||
@@ -218,8 +214,6 @@ def process_patch_list(
|
||||
|
||||
if success:
|
||||
applied += 1
|
||||
if commit_each and not dry_run:
|
||||
create_patch_commit(display_name, chromium_src, feature_name)
|
||||
else:
|
||||
failed.append(display_name)
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Contains core extraction logic used by extract_commit and extract_range.
|
||||
|
||||
import click
|
||||
from pathlib import Path
|
||||
from typing import Dict, Optional
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
from ...common.context import Context
|
||||
from ...common.utils import log_info, log_error, log_warning
|
||||
@@ -50,11 +50,16 @@ def write_patches(
|
||||
file_patches: Dict[str, FilePatch],
|
||||
verbose: bool,
|
||||
include_binary: bool,
|
||||
) -> int:
|
||||
"""Write patches to disk"""
|
||||
) -> Tuple[int, List[str]]:
|
||||
"""Write patches to disk.
|
||||
|
||||
Returns:
|
||||
Tuple of (success_count, list of successfully extracted file paths)
|
||||
"""
|
||||
success_count = 0
|
||||
fail_count = 0
|
||||
skip_count = 0
|
||||
extracted_files: List[str] = []
|
||||
|
||||
for file_path, patch in file_patches.items():
|
||||
if verbose:
|
||||
@@ -66,6 +71,7 @@ def write_patches(
|
||||
# Create deletion marker
|
||||
if create_deletion_marker(ctx, file_path):
|
||||
success_count += 1
|
||||
extracted_files.append(file_path)
|
||||
else:
|
||||
fail_count += 1
|
||||
|
||||
@@ -74,6 +80,7 @@ def write_patches(
|
||||
# Create binary marker
|
||||
if create_binary_marker(ctx, file_path, patch.operation):
|
||||
success_count += 1
|
||||
extracted_files.append(file_path)
|
||||
else:
|
||||
fail_count += 1
|
||||
else:
|
||||
@@ -86,6 +93,7 @@ def write_patches(
|
||||
# If there are changes beyond the rename
|
||||
if write_patch_file(ctx, file_path, patch.patch_content):
|
||||
success_count += 1
|
||||
extracted_files.append(file_path)
|
||||
else:
|
||||
fail_count += 1
|
||||
else:
|
||||
@@ -98,6 +106,7 @@ def write_patches(
|
||||
marker_path.write_text(marker_content)
|
||||
log_info(f" Rename marked: {file_path}")
|
||||
success_count += 1
|
||||
extracted_files.append(file_path)
|
||||
except Exception as e:
|
||||
log_error(f" Failed to mark rename: {e}")
|
||||
fail_count += 1
|
||||
@@ -107,6 +116,7 @@ def write_patches(
|
||||
if patch.patch_content:
|
||||
if write_patch_file(ctx, file_path, patch.patch_content):
|
||||
success_count += 1
|
||||
extracted_files.append(file_path)
|
||||
else:
|
||||
fail_count += 1
|
||||
else:
|
||||
@@ -121,7 +131,7 @@ def write_patches(
|
||||
if skip_count > 0:
|
||||
log_info(f"Skipped {skip_count} files")
|
||||
|
||||
return success_count
|
||||
return success_count, extracted_files
|
||||
|
||||
|
||||
def extract_normal(
|
||||
@@ -130,8 +140,12 @@ def extract_normal(
|
||||
verbose: bool,
|
||||
force: bool,
|
||||
include_binary: bool,
|
||||
) -> int:
|
||||
"""Extract patches normally (diff against parent)"""
|
||||
) -> Tuple[int, List[str]]:
|
||||
"""Extract patches normally (diff against parent).
|
||||
|
||||
Returns:
|
||||
Tuple of (count, list of extracted file paths)
|
||||
"""
|
||||
from .utils import GitError
|
||||
|
||||
# Get diff against parent
|
||||
@@ -149,11 +163,11 @@ def extract_normal(
|
||||
|
||||
if not file_patches:
|
||||
log_warning("No changes found in commit")
|
||||
return 0
|
||||
return 0, []
|
||||
|
||||
# Check for existing patches
|
||||
if not force and not check_overwrite(ctx, file_patches, verbose):
|
||||
return 0
|
||||
return 0, []
|
||||
|
||||
# Write patches
|
||||
return write_patches(ctx, file_patches, verbose, include_binary)
|
||||
@@ -166,15 +180,19 @@ def extract_with_base(
|
||||
verbose: bool,
|
||||
force: bool,
|
||||
include_binary: bool,
|
||||
) -> int:
|
||||
"""Extract patches with custom base (full diff from base for files in commit)"""
|
||||
) -> Tuple[int, List[str]]:
|
||||
"""Extract patches with custom base (full diff from base for files in commit).
|
||||
|
||||
Returns:
|
||||
Tuple of (count, list of extracted file paths)
|
||||
"""
|
||||
|
||||
# Step 1: Get list of files changed in the commit
|
||||
changed_files = get_commit_changed_files(commit_hash, ctx.chromium_src)
|
||||
|
||||
if not changed_files:
|
||||
log_warning(f"No files changed in commit {commit_hash}")
|
||||
return 0
|
||||
return 0, []
|
||||
|
||||
if verbose:
|
||||
log_info(f"Files changed in {commit_hash}: {len(changed_files)}")
|
||||
@@ -243,13 +261,13 @@ def extract_with_base(
|
||||
|
||||
if not file_patches:
|
||||
log_warning("No patches to extract")
|
||||
return 0
|
||||
return 0, []
|
||||
|
||||
log_info(f"Extracting {len(file_patches)} patches with base {base}")
|
||||
|
||||
# Check for existing patches
|
||||
if not force and not check_overwrite(ctx, file_patches, verbose):
|
||||
return 0
|
||||
return 0, []
|
||||
|
||||
# Write patches
|
||||
return write_patches(ctx, file_patches, verbose, include_binary)
|
||||
|
||||
@@ -3,7 +3,7 @@ Extract Commit - Extract patches from a single git commit.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
from ...common.context import Context
|
||||
from ...common.module import CommandModule, ValidationError
|
||||
@@ -24,7 +24,7 @@ def extract_single_commit(
|
||||
force: bool = False,
|
||||
include_binary: bool = False,
|
||||
base: Optional[str] = None,
|
||||
) -> int:
|
||||
) -> Tuple[int, List[str]]:
|
||||
"""Extract patches from a single commit
|
||||
|
||||
Args:
|
||||
@@ -36,7 +36,7 @@ def extract_single_commit(
|
||||
base: If provided, extract full diff from base for files in commit
|
||||
|
||||
Returns:
|
||||
Number of patches successfully extracted
|
||||
Tuple of (count, list of extracted file paths)
|
||||
"""
|
||||
# Step 1: Validate commit
|
||||
if not validate_commit_exists(commit_hash, ctx.chromium_src):
|
||||
@@ -82,6 +82,7 @@ class ExtractCommitModule(CommandModule):
|
||||
force: bool = False,
|
||||
include_binary: bool = False,
|
||||
base: Optional[str] = None,
|
||||
feature: bool = False,
|
||||
) -> None:
|
||||
"""Execute extract commit
|
||||
|
||||
@@ -93,9 +94,10 @@ class ExtractCommitModule(CommandModule):
|
||||
force: Overwrite existing patches
|
||||
include_binary: Include binary files
|
||||
base: Extract full diff from base commit for files in COMMIT
|
||||
feature: Prompt to add extracted files to a feature in features.yaml
|
||||
"""
|
||||
try:
|
||||
count = extract_single_commit(
|
||||
count, extracted_files = extract_single_commit(
|
||||
ctx,
|
||||
commit_hash=commit,
|
||||
verbose=verbose,
|
||||
@@ -107,5 +109,28 @@ class ExtractCommitModule(CommandModule):
|
||||
log_warning(f"No patches extracted from {commit}")
|
||||
else:
|
||||
log_success(f"Successfully extracted {count} patches from {commit}")
|
||||
|
||||
# Handle --feature flag
|
||||
if feature and extracted_files:
|
||||
self._add_to_feature(ctx, commit, extracted_files)
|
||||
|
||||
except GitError as e:
|
||||
raise RuntimeError(f"Git error: {e}")
|
||||
|
||||
def _add_to_feature(self, ctx: Context, commit: str, files: List[str]) -> None:
|
||||
"""Prompt user to add extracted files to a feature."""
|
||||
from ..feature import prompt_feature_selection, add_files_to_feature
|
||||
from .utils import get_commit_info
|
||||
|
||||
# Get commit info for context
|
||||
commit_info = get_commit_info(commit, ctx.chromium_src)
|
||||
commit_message = commit_info.get("subject") if commit_info else None
|
||||
|
||||
# Prompt for feature selection
|
||||
result = prompt_feature_selection(ctx, commit[:12], commit_message)
|
||||
if result is None:
|
||||
log_warning("Skipped adding files to feature")
|
||||
return
|
||||
|
||||
feature_name, description = result
|
||||
add_files_to_feature(ctx, feature_name, description, files)
|
||||
|
||||
@@ -4,7 +4,7 @@ Extract Range - Extract patches from a range of git commits.
|
||||
|
||||
import click
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
from ...common.context import Context
|
||||
from ...common.module import CommandModule, ValidationError
|
||||
@@ -33,11 +33,11 @@ def extract_commit_range(
|
||||
force: bool = False,
|
||||
include_binary: bool = False,
|
||||
custom_base: Optional[str] = None,
|
||||
) -> int:
|
||||
) -> Tuple[int, List[str]]:
|
||||
"""Extract patches from a commit range as a single cumulative diff
|
||||
|
||||
Returns:
|
||||
Number of patches successfully extracted
|
||||
Tuple of (count, list of extracted file paths)
|
||||
"""
|
||||
# Step 1: Validate commits
|
||||
if not validate_commit_exists(base_commit, ctx.chromium_src):
|
||||
@@ -56,7 +56,7 @@ def extract_commit_range(
|
||||
|
||||
if commit_count == 0:
|
||||
log_warning(f"No commits between {base_commit} and {head_commit}")
|
||||
return 0
|
||||
return 0, []
|
||||
|
||||
log_info(f"Processing {commit_count} commits")
|
||||
|
||||
@@ -80,7 +80,7 @@ def extract_commit_range(
|
||||
|
||||
if not changed_files:
|
||||
log_warning("No files changed in range")
|
||||
return 0
|
||||
return 0, []
|
||||
|
||||
log_info(f"Found {len(changed_files)} files changed in range")
|
||||
|
||||
@@ -107,15 +107,16 @@ def extract_commit_range(
|
||||
|
||||
if not file_patches:
|
||||
log_warning("No changes found in commit range")
|
||||
return 0
|
||||
return 0, []
|
||||
|
||||
# Check for existing patches
|
||||
if not force and not check_overwrite(ctx, file_patches, verbose):
|
||||
return 0
|
||||
return 0, []
|
||||
|
||||
success_count = 0
|
||||
fail_count = 0
|
||||
skip_count = 0
|
||||
extracted_files: List[str] = []
|
||||
|
||||
# Process with progress indicator
|
||||
with click.progressbar(
|
||||
@@ -129,6 +130,7 @@ def extract_commit_range(
|
||||
if patch.operation == FileOperation.DELETE:
|
||||
if create_deletion_marker(ctx, file_path):
|
||||
success_count += 1
|
||||
extracted_files.append(file_path)
|
||||
else:
|
||||
fail_count += 1
|
||||
|
||||
@@ -136,6 +138,7 @@ def extract_commit_range(
|
||||
if include_binary:
|
||||
if create_binary_marker(ctx, file_path, patch.operation):
|
||||
success_count += 1
|
||||
extracted_files.append(file_path)
|
||||
else:
|
||||
fail_count += 1
|
||||
else:
|
||||
@@ -144,6 +147,7 @@ def extract_commit_range(
|
||||
elif patch.patch_content:
|
||||
if write_patch_file(ctx, file_path, patch.patch_content):
|
||||
success_count += 1
|
||||
extracted_files.append(file_path)
|
||||
else:
|
||||
fail_count += 1
|
||||
else:
|
||||
@@ -157,7 +161,7 @@ def extract_commit_range(
|
||||
if skip_count > 0:
|
||||
log_info(f"Skipped {skip_count} files")
|
||||
|
||||
return success_count
|
||||
return success_count, extracted_files
|
||||
|
||||
|
||||
def extract_commits_individually(
|
||||
@@ -168,13 +172,13 @@ def extract_commits_individually(
|
||||
force: bool = False,
|
||||
include_binary: bool = False,
|
||||
custom_base: Optional[str] = None,
|
||||
) -> int:
|
||||
) -> Tuple[int, List[str]]:
|
||||
"""Extract patches from each commit in a range individually
|
||||
|
||||
This preserves commit boundaries and can help with conflict resolution.
|
||||
|
||||
Returns:
|
||||
Total number of patches successfully extracted
|
||||
Tuple of (count, list of extracted file paths)
|
||||
"""
|
||||
# Validate custom base if provided
|
||||
if custom_base and not validate_commit_exists(custom_base, ctx.chromium_src):
|
||||
@@ -193,13 +197,14 @@ def extract_commits_individually(
|
||||
|
||||
if not commits:
|
||||
log_warning(f"No commits between {base_commit} and {head_commit}")
|
||||
return 0
|
||||
return 0, []
|
||||
|
||||
log_info(f"Extracting patches from {len(commits)} commits individually")
|
||||
if custom_base:
|
||||
log_info(f"Using custom base: {custom_base}")
|
||||
|
||||
total_extracted = 0
|
||||
all_extracted_files: List[str] = []
|
||||
failed_commits = []
|
||||
|
||||
with click.progressbar(
|
||||
@@ -209,7 +214,7 @@ def extract_commits_individually(
|
||||
try:
|
||||
if custom_base:
|
||||
# Use extract_with_base for full diff from custom base
|
||||
extracted = extract_with_base(
|
||||
extracted, files = extract_with_base(
|
||||
ctx,
|
||||
commit,
|
||||
custom_base,
|
||||
@@ -219,7 +224,7 @@ def extract_commits_individually(
|
||||
)
|
||||
else:
|
||||
# Normal extraction from parent
|
||||
extracted = extract_single_commit(
|
||||
extracted, files = extract_single_commit(
|
||||
ctx,
|
||||
commit,
|
||||
verbose=False,
|
||||
@@ -227,6 +232,7 @@ def extract_commits_individually(
|
||||
include_binary=include_binary,
|
||||
)
|
||||
total_extracted += extracted
|
||||
all_extracted_files.extend(files)
|
||||
except GitError as e:
|
||||
failed_commits.append((commit, str(e)))
|
||||
if verbose:
|
||||
@@ -239,7 +245,9 @@ def extract_commits_individually(
|
||||
if len(failed_commits) > 5:
|
||||
log_warning(f" ... and {len(failed_commits) - 5} more")
|
||||
|
||||
return total_extracted
|
||||
# Deduplicate files (same file may appear in multiple commits)
|
||||
unique_files = list(dict.fromkeys(all_extracted_files))
|
||||
return total_extracted, unique_files
|
||||
|
||||
|
||||
class ExtractRangeModule(CommandModule):
|
||||
@@ -268,6 +276,7 @@ class ExtractRangeModule(CommandModule):
|
||||
include_binary: bool = False,
|
||||
squash: bool = False,
|
||||
base: Optional[str] = None,
|
||||
feature: bool = False,
|
||||
) -> None:
|
||||
"""Execute extract range
|
||||
|
||||
@@ -281,10 +290,11 @@ class ExtractRangeModule(CommandModule):
|
||||
include_binary: Include binary files
|
||||
squash: Squash all commits into single patches
|
||||
base: Use different base for diff (full diff from base for files in range)
|
||||
feature: Prompt to add extracted files to a feature in features.yaml
|
||||
"""
|
||||
try:
|
||||
if squash:
|
||||
count = extract_commit_range(
|
||||
count, extracted_files = extract_commit_range(
|
||||
ctx,
|
||||
base_commit=start,
|
||||
head_commit=end,
|
||||
@@ -294,7 +304,7 @@ class ExtractRangeModule(CommandModule):
|
||||
custom_base=base,
|
||||
)
|
||||
else:
|
||||
count = extract_commits_individually(
|
||||
count, extracted_files = extract_commits_individually(
|
||||
ctx,
|
||||
base_commit=start,
|
||||
head_commit=end,
|
||||
@@ -307,5 +317,28 @@ class ExtractRangeModule(CommandModule):
|
||||
log_warning(f"No patches extracted from range {start}..{end}")
|
||||
else:
|
||||
log_success(f"Successfully extracted {count} patches from {start}..{end}")
|
||||
|
||||
# Handle --feature flag
|
||||
if feature and extracted_files:
|
||||
self._add_to_feature(ctx, end, extracted_files)
|
||||
|
||||
except GitError as e:
|
||||
raise RuntimeError(f"Git error: {e}")
|
||||
|
||||
def _add_to_feature(self, ctx: Context, commit: str, files: List[str]) -> None:
|
||||
"""Prompt user to add extracted files to a feature."""
|
||||
from ..feature import prompt_feature_selection, add_files_to_feature
|
||||
from .utils import get_commit_info
|
||||
|
||||
# Get commit info for context (use the end commit)
|
||||
commit_info = get_commit_info(commit, ctx.chromium_src)
|
||||
commit_message = commit_info.get("subject") if commit_info else None
|
||||
|
||||
# Prompt for feature selection
|
||||
result = prompt_feature_selection(ctx, commit[:12], commit_message)
|
||||
if result is None:
|
||||
log_warning("Skipped adding files to feature")
|
||||
return
|
||||
|
||||
feature_name, description = result
|
||||
add_files_to_feature(ctx, feature_name, description, files)
|
||||
|
||||
@@ -5,6 +5,9 @@ Provides commands for managing features:
|
||||
- add_feature: Add files from a commit to a feature
|
||||
- list_features: List all defined features
|
||||
- show_feature: Show details of a specific feature
|
||||
- prompt_feature_selection: Interactive feature selection for extract commands
|
||||
- add_files_to_feature: Add files to a feature (with duplicate handling)
|
||||
- classify_files: Classify unclassified patch files into features
|
||||
"""
|
||||
|
||||
from .feature import (
|
||||
@@ -14,6 +17,13 @@ from .feature import (
|
||||
ListFeaturesModule,
|
||||
show_feature,
|
||||
ShowFeatureModule,
|
||||
ClassifyFeaturesModule,
|
||||
)
|
||||
from .select import (
|
||||
prompt_feature_selection,
|
||||
add_files_to_feature,
|
||||
classify_files,
|
||||
get_unclassified_files,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
@@ -23,4 +33,9 @@ __all__ = [
|
||||
"ListFeaturesModule",
|
||||
"show_feature",
|
||||
"ShowFeatureModule",
|
||||
"ClassifyFeaturesModule",
|
||||
"prompt_feature_selection",
|
||||
"add_files_to_feature",
|
||||
"classify_files",
|
||||
"get_unclassified_files",
|
||||
]
|
||||
|
||||
@@ -151,4 +151,32 @@ class AddFeatureModule(CommandModule):
|
||||
def execute(self, ctx: Context, feature_name: str, commit: str, description: Optional[str] = None, **kwargs) -> None:
|
||||
success = add_feature(ctx, feature_name, commit, description)
|
||||
if not success:
|
||||
raise RuntimeError(f"Failed to add feature '{feature_name}'")
|
||||
raise RuntimeError(f"Failed to add feature '{feature_name}'")
|
||||
|
||||
|
||||
class ClassifyFeaturesModule(CommandModule):
|
||||
"""Classify unclassified patch files into features"""
|
||||
produces = []
|
||||
requires = []
|
||||
description = "Classify unclassified patch files into features"
|
||||
|
||||
def validate(self, ctx: Context) -> None:
|
||||
"""Validate patches directory exists"""
|
||||
patches_dir = ctx.get_patches_dir()
|
||||
if not patches_dir.exists():
|
||||
raise ValidationError(f"Patches directory not found: {patches_dir}")
|
||||
|
||||
def execute(self, ctx: Context, **kwargs) -> None:
|
||||
from .select import classify_files, get_unclassified_files
|
||||
|
||||
# Show summary first
|
||||
unclassified = get_unclassified_files(ctx)
|
||||
if not unclassified:
|
||||
log_success("All patch files are already classified!")
|
||||
return
|
||||
|
||||
log_info(f"Found {len(unclassified)} unclassified patch file(s)")
|
||||
log_info("")
|
||||
|
||||
# Run classification
|
||||
classified, skipped = classify_files(ctx)
|
||||
396
packages/browseros/build/modules/feature/select.py
Normal file
396
packages/browseros/build/modules/feature/select.py
Normal file
@@ -0,0 +1,396 @@
|
||||
"""
|
||||
Feature selection utilities for interactive feature assignment.
|
||||
|
||||
Provides functions to prompt users to select or create features
|
||||
and add files to them.
|
||||
"""
|
||||
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
from typing import List, Optional, Dict, Tuple, Set
|
||||
|
||||
from ...common.context import Context
|
||||
from ...common.utils import log_info, log_success, log_warning, log_error
|
||||
|
||||
|
||||
def load_features_yaml(features_file: Path) -> Dict:
|
||||
"""Load features from YAML file."""
|
||||
if not features_file.exists():
|
||||
return {"version": "1.0", "features": {}}
|
||||
|
||||
with open(features_file, "r") as f:
|
||||
content = yaml.safe_load(f)
|
||||
if not content:
|
||||
return {"version": "1.0", "features": {}}
|
||||
return content
|
||||
|
||||
|
||||
def save_features_yaml(features_file: Path, data: Dict) -> None:
|
||||
"""Save features to YAML file."""
|
||||
with open(features_file, "w") as f:
|
||||
yaml.safe_dump(data, f, sort_keys=False, default_flow_style=False)
|
||||
|
||||
|
||||
def prompt_feature_selection(
|
||||
ctx: Context,
|
||||
commit_hash: Optional[str] = None,
|
||||
commit_message: Optional[str] = None,
|
||||
) -> Optional[Tuple[str, str]]:
|
||||
"""Prompt user to select an existing feature or create a new one.
|
||||
|
||||
Args:
|
||||
ctx: Build context
|
||||
commit_hash: Optional commit hash for display
|
||||
commit_message: Optional commit message for display/defaults
|
||||
|
||||
Returns:
|
||||
Tuple of (feature_name, description) or None if cancelled
|
||||
"""
|
||||
features_file = ctx.get_features_yaml_path()
|
||||
data = load_features_yaml(features_file)
|
||||
features = data.get("features", {})
|
||||
|
||||
# Display commit info if available
|
||||
if commit_hash or commit_message:
|
||||
log_info("")
|
||||
log_info("=" * 60)
|
||||
if commit_hash:
|
||||
log_info(f"Commit: {commit_hash[:12]}")
|
||||
if commit_message:
|
||||
log_info(f"Message: {commit_message}")
|
||||
log_info("=" * 60)
|
||||
|
||||
# Display numbered list of features
|
||||
log_info("")
|
||||
log_info("Select a feature to add files to:")
|
||||
log_info("-" * 40)
|
||||
|
||||
feature_list = list(features.keys())
|
||||
for i, name in enumerate(feature_list, 1):
|
||||
desc = features[name].get("description", name)
|
||||
file_count = len(features[name].get("files", []))
|
||||
log_info(f" {i}) {desc} ({file_count} files)")
|
||||
|
||||
# Add "new feature" option
|
||||
new_option = len(feature_list) + 1
|
||||
log_info(f" {new_option}) [Add new feature]")
|
||||
log_info("")
|
||||
|
||||
# Get user selection
|
||||
while True:
|
||||
try:
|
||||
choice = input(f"Enter choice (1-{new_option}): ").strip()
|
||||
if not choice:
|
||||
log_warning("Cancelled")
|
||||
return None
|
||||
|
||||
choice_num = int(choice)
|
||||
if choice_num < 1 or choice_num > new_option:
|
||||
log_warning(f"Please enter a number between 1 and {new_option}")
|
||||
continue
|
||||
|
||||
break
|
||||
except ValueError:
|
||||
log_warning("Please enter a valid number")
|
||||
continue
|
||||
except (KeyboardInterrupt, EOFError):
|
||||
log_warning("\nCancelled")
|
||||
return None
|
||||
|
||||
# Handle selection
|
||||
if choice_num == new_option:
|
||||
# Create new feature
|
||||
return prompt_new_feature(commit_message)
|
||||
else:
|
||||
# Selected existing feature
|
||||
feature_name = feature_list[choice_num - 1]
|
||||
description = features[feature_name].get("description", "")
|
||||
return (feature_name, description)
|
||||
|
||||
|
||||
def prompt_new_feature(default_description: Optional[str] = None) -> Optional[Tuple[str, str]]:
|
||||
"""Prompt user to create a new feature.
|
||||
|
||||
Args:
|
||||
default_description: Optional default description (e.g., from commit message)
|
||||
|
||||
Returns:
|
||||
Tuple of (feature_name, description) or None if cancelled
|
||||
"""
|
||||
log_info("")
|
||||
log_info("Creating new feature:")
|
||||
log_info("-" * 40)
|
||||
|
||||
try:
|
||||
# Get feature name
|
||||
feature_name = input("Feature name: ").strip()
|
||||
if not feature_name:
|
||||
log_warning("Cancelled - no feature name provided")
|
||||
return None
|
||||
|
||||
# Sanitize feature name (lowercase, hyphens instead of spaces)
|
||||
feature_name = feature_name.lower().replace(" ", "-")
|
||||
|
||||
# Get description
|
||||
if default_description:
|
||||
desc_prompt = f"Description [{default_description}]: "
|
||||
else:
|
||||
desc_prompt = "Description: "
|
||||
|
||||
description = input(desc_prompt).strip()
|
||||
if not description and default_description:
|
||||
description = default_description
|
||||
|
||||
if not description:
|
||||
description = f"Feature: {feature_name}"
|
||||
|
||||
return (feature_name, description)
|
||||
|
||||
except (KeyboardInterrupt, EOFError):
|
||||
log_warning("\nCancelled")
|
||||
return None
|
||||
|
||||
|
||||
def add_files_to_feature(
|
||||
ctx: Context,
|
||||
feature_name: str,
|
||||
description: str,
|
||||
files: List[str],
|
||||
) -> int:
|
||||
"""Add files to a feature in features.yaml, avoiding duplicates.
|
||||
|
||||
Args:
|
||||
ctx: Build context
|
||||
feature_name: Name of the feature
|
||||
description: Feature description
|
||||
files: List of file paths to add
|
||||
|
||||
Returns:
|
||||
Number of new files added (excludes duplicates)
|
||||
"""
|
||||
features_file = ctx.get_features_yaml_path()
|
||||
data = load_features_yaml(features_file)
|
||||
|
||||
if "features" not in data:
|
||||
data["features"] = {}
|
||||
|
||||
features = data["features"]
|
||||
|
||||
# Get or create feature entry
|
||||
if feature_name in features:
|
||||
existing_files = set(features[feature_name].get("files", []))
|
||||
# Keep existing description if present
|
||||
if not features[feature_name].get("description"):
|
||||
features[feature_name]["description"] = description
|
||||
else:
|
||||
existing_files = set()
|
||||
features[feature_name] = {
|
||||
"description": description,
|
||||
"files": [],
|
||||
}
|
||||
|
||||
# Add new files, avoiding duplicates
|
||||
new_files = []
|
||||
duplicate_files = []
|
||||
|
||||
for file_path in files:
|
||||
if file_path in existing_files:
|
||||
duplicate_files.append(file_path)
|
||||
else:
|
||||
new_files.append(file_path)
|
||||
existing_files.add(file_path)
|
||||
|
||||
# Update feature with merged file list
|
||||
features[feature_name]["files"] = sorted(existing_files)
|
||||
|
||||
# Save to file
|
||||
save_features_yaml(features_file, data)
|
||||
|
||||
# Log results
|
||||
if new_files:
|
||||
log_success(f"Added {len(new_files)} file(s) to feature '{feature_name}'")
|
||||
for f in new_files[:5]:
|
||||
log_info(f" + {f}")
|
||||
if len(new_files) > 5:
|
||||
log_info(f" ... and {len(new_files) - 5} more")
|
||||
|
||||
if duplicate_files:
|
||||
log_warning(f"Skipped {len(duplicate_files)} duplicate file(s)")
|
||||
for f in duplicate_files[:3]:
|
||||
log_info(f" ~ {f}")
|
||||
if len(duplicate_files) > 3:
|
||||
log_info(f" ... and {len(duplicate_files) - 3} more")
|
||||
|
||||
return len(new_files)
|
||||
|
||||
|
||||
def get_all_patch_files(ctx: Context) -> List[str]:
|
||||
"""Get all patch files from chromium_patches/ directory.
|
||||
|
||||
Returns:
|
||||
List of file paths (relative to chromium_patches/)
|
||||
"""
|
||||
patches_dir = ctx.get_patches_dir()
|
||||
if not patches_dir.exists():
|
||||
return []
|
||||
|
||||
patch_files = []
|
||||
for patch_path in patches_dir.rglob("*"):
|
||||
if patch_path.is_file():
|
||||
# Get relative path from patches_dir
|
||||
rel_path = str(patch_path.relative_to(patches_dir))
|
||||
patch_files.append(rel_path)
|
||||
|
||||
return sorted(patch_files)
|
||||
|
||||
|
||||
def get_all_classified_files(ctx: Context) -> Set[str]:
|
||||
"""Get all files that are already classified in features.yaml.
|
||||
|
||||
Returns:
|
||||
Set of file paths
|
||||
"""
|
||||
features_file = ctx.get_features_yaml_path()
|
||||
data = load_features_yaml(features_file)
|
||||
features = data.get("features", {})
|
||||
|
||||
classified = set()
|
||||
for feature_data in features.values():
|
||||
files = feature_data.get("files", [])
|
||||
classified.update(files)
|
||||
|
||||
return classified
|
||||
|
||||
|
||||
def get_unclassified_files(ctx: Context) -> List[str]:
|
||||
"""Get list of patch files not in any feature.
|
||||
|
||||
Returns:
|
||||
List of unclassified file paths
|
||||
"""
|
||||
all_patches = set(get_all_patch_files(ctx))
|
||||
classified = get_all_classified_files(ctx)
|
||||
unclassified = all_patches - classified
|
||||
return sorted(unclassified)
|
||||
|
||||
|
||||
def classify_files(ctx: Context) -> Tuple[int, int]:
|
||||
"""Interactively classify unclassified patch files into features.
|
||||
|
||||
Goes through each unclassified file one-by-one and prompts user
|
||||
to select a feature or create a new one.
|
||||
|
||||
Returns:
|
||||
Tuple of (files_classified, files_skipped)
|
||||
"""
|
||||
unclassified = get_unclassified_files(ctx)
|
||||
|
||||
if not unclassified:
|
||||
log_success("All patch files are already classified!")
|
||||
return 0, 0
|
||||
|
||||
log_info(f"Found {len(unclassified)} unclassified file(s)")
|
||||
log_info("=" * 60)
|
||||
log_info("Press Ctrl+C to stop at any time")
|
||||
log_info("")
|
||||
|
||||
classified_count = 0
|
||||
skipped_count = 0
|
||||
|
||||
for i, file_path in enumerate(unclassified, 1):
|
||||
log_info(f"\n[{i}/{len(unclassified)}] {file_path}")
|
||||
log_info("-" * 40)
|
||||
|
||||
try:
|
||||
# Prompt for feature selection (no commit context for classify)
|
||||
result = prompt_feature_selection_for_file(ctx, file_path)
|
||||
|
||||
if result is None:
|
||||
log_warning("Skipped")
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
feature_name, description = result
|
||||
add_files_to_feature(ctx, feature_name, description, [file_path])
|
||||
classified_count += 1
|
||||
|
||||
except KeyboardInterrupt:
|
||||
log_info("\n\nStopped by user")
|
||||
break
|
||||
|
||||
log_info("")
|
||||
log_info("=" * 60)
|
||||
log_success(f"Classified {classified_count} file(s)")
|
||||
if skipped_count > 0:
|
||||
log_info(f"Skipped {skipped_count} file(s)")
|
||||
remaining = len(unclassified) - classified_count - skipped_count
|
||||
if remaining > 0:
|
||||
log_info(f"Remaining: {remaining} file(s)")
|
||||
|
||||
return classified_count, skipped_count
|
||||
|
||||
|
||||
def prompt_feature_selection_for_file(
|
||||
ctx: Context,
|
||||
file_path: str,
|
||||
) -> Optional[Tuple[str, str]]:
|
||||
"""Prompt user to select a feature for a single file.
|
||||
|
||||
Simplified version of prompt_feature_selection for classify workflow.
|
||||
|
||||
Args:
|
||||
ctx: Build context
|
||||
file_path: The file being classified
|
||||
|
||||
Returns:
|
||||
Tuple of (feature_name, description) or None if skipped
|
||||
"""
|
||||
features_file = ctx.get_features_yaml_path()
|
||||
data = load_features_yaml(features_file)
|
||||
features = data.get("features", {})
|
||||
|
||||
if not features:
|
||||
log_info("No features defined yet. Create a new one:")
|
||||
return prompt_new_feature()
|
||||
|
||||
# Display numbered list of features
|
||||
feature_list = list(features.keys())
|
||||
for i, name in enumerate(feature_list, 1):
|
||||
desc = features[name].get("description", name)
|
||||
file_count = len(features[name].get("files", []))
|
||||
log_info(f" {i}) {desc} ({file_count} files)")
|
||||
|
||||
# Add options
|
||||
new_option = len(feature_list) + 1
|
||||
skip_option = len(feature_list) + 2
|
||||
log_info(f" {new_option}) [Add new feature]")
|
||||
log_info(f" {skip_option}) [Skip this file]")
|
||||
|
||||
# Get user selection
|
||||
while True:
|
||||
try:
|
||||
choice = input(f"Choice (1-{skip_option}): ").strip()
|
||||
if not choice:
|
||||
return None
|
||||
|
||||
choice_num = int(choice)
|
||||
if choice_num < 1 or choice_num > skip_option:
|
||||
log_warning(f"Please enter 1-{skip_option}")
|
||||
continue
|
||||
|
||||
break
|
||||
except ValueError:
|
||||
log_warning("Enter a valid number")
|
||||
continue
|
||||
except (KeyboardInterrupt, EOFError):
|
||||
raise KeyboardInterrupt
|
||||
|
||||
# Handle selection
|
||||
if choice_num == skip_option:
|
||||
return None
|
||||
elif choice_num == new_option:
|
||||
return prompt_new_feature()
|
||||
else:
|
||||
feature_name = feature_list[choice_num - 1]
|
||||
description = features[feature_name].get("description", "")
|
||||
return (feature_name, description)
|
||||
@@ -24,13 +24,11 @@ class PatchesModule(CommandModule):
|
||||
|
||||
def execute(self, ctx: Context) -> None:
|
||||
log_info("\n🩹 Applying patches...")
|
||||
if not apply_patches_impl(ctx, interactive=False, commit_each=False):
|
||||
if not apply_patches_impl(ctx, interactive=False):
|
||||
raise RuntimeError("Failed to apply patches")
|
||||
|
||||
|
||||
def apply_patches_impl(
|
||||
ctx: Context, interactive: bool = False, commit_each: bool = False
|
||||
) -> bool:
|
||||
def apply_patches_impl(ctx: Context, interactive: bool = False) -> bool:
|
||||
"""Apply patches using the dev CLI patch system
|
||||
|
||||
Returns:
|
||||
@@ -53,7 +51,6 @@ def apply_patches_impl(
|
||||
# Call the dev CLI function directly
|
||||
_, failed = apply_all_patches(
|
||||
build_ctx=ctx,
|
||||
commit_each=commit_each,
|
||||
dry_run=False,
|
||||
interactive=interactive,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user