flashdrive-cli 1.0.0__py3-none-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flashdrive_cli/__init__.py +5 -0
- flashdrive_cli/__main__.py +3 -0
- flashdrive_cli/_api.py +3 -0
- flashdrive_cli/_channel.py +6 -0
- flashdrive_cli/_exit_codes.py +17 -0
- flashdrive_cli/_legacy.py +13 -0
- flashdrive_cli/_messages.py +239 -0
- flashdrive_cli/_time_scale.py +29 -0
- flashdrive_cli/_version.py +1 -0
- flashdrive_cli/api.py +522 -0
- flashdrive_cli/assets/VolumeIcon.icns +0 -0
- flashdrive_cli/bin/wd-fs +0 -0
- flashdrive_cli/browser_login.py +331 -0
- flashdrive_cli/config.py +200 -0
- flashdrive_cli/csv_merge.py +159 -0
- flashdrive_cli/error-catalogue.json +1505 -0
- flashdrive_cli/errors.py +113 -0
- flashdrive_cli/file_edits.py +64 -0
- flashdrive_cli/git_broker.py +488 -0
- flashdrive_cli/git_launch.py +383 -0
- flashdrive_cli/git_launch_service.py +288 -0
- flashdrive_cli/git_process.py +123 -0
- flashdrive_cli/git_sessions.py +888 -0
- flashdrive_cli/imports.py +1346 -0
- flashdrive_cli/main.py +2136 -0
- flashdrive_cli/merge3.py +107 -0
- flashdrive_cli/mount.py +4069 -0
- flashdrive_cli/mount_exclusions.py +117 -0
- flashdrive_cli/mount_git.py +1030 -0
- flashdrive_cli/mount_git_guard.py +165 -0
- flashdrive_cli/mount_history.py +117 -0
- flashdrive_cli/mount_lease.py +472 -0
- flashdrive_cli/mount_namespace.py +2947 -0
- flashdrive_cli/mount_status.py +1029 -0
- flashdrive_cli/mount_sync.py +4030 -0
- flashdrive_cli/mount_sync_scope.py +596 -0
- flashdrive_cli/mount_watch.py +164 -0
- flashdrive_cli/multipart.py +230 -0
- flashdrive_cli/notices.py +207 -0
- flashdrive_cli/recovery_names.py +417 -0
- flashdrive_cli/release_policy.py +18 -0
- flashdrive_cli/releases.py +270 -0
- flashdrive_cli/text_files.py +39 -0
- flashdrive_cli/updates.py +529 -0
- flashdrive_cli/uploads.py +1408 -0
- flashdrive_cli/workcopy.py +870 -0
- flashdrive_cli/workcopy_storage.py +893 -0
- flashdrive_cli-1.0.0.dist-info/METADATA +57 -0
- flashdrive_cli-1.0.0.dist-info/RECORD +53 -0
- flashdrive_cli-1.0.0.dist-info/WHEEL +4 -0
- flashdrive_cli-1.0.0.dist-info/entry_points.txt +2 -0
- flashdrive_cli-1.0.0.dist-info/licenses/LICENSE +202 -0
- flashdrive_cli-1.0.0.dist-info/licenses/THIRD_PARTY_NOTICES.txt +12559 -0
flashdrive_cli/_api.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Generated by backend/scripts/errors.mjs from backend/src/error-catalogue.json. Do not edit.
|
|
2
|
+
"""Process exit statuses by error type. 1 is any other failure and 2 a usage error; 130 is an interrupt."""
|
|
3
|
+
|
|
4
|
+
TYPE_EXITS: dict[str, int] = {
|
|
5
|
+
"auth": 3,
|
|
6
|
+
"permission": 4,
|
|
7
|
+
"not_found": 5,
|
|
8
|
+
"invalid": 2,
|
|
9
|
+
"conflict": 6,
|
|
10
|
+
"precondition": 6,
|
|
11
|
+
"rate_limit": 7,
|
|
12
|
+
"payment_required": 8,
|
|
13
|
+
"quota": 9,
|
|
14
|
+
"too_large": 2,
|
|
15
|
+
"unavailable": 10,
|
|
16
|
+
"upgrade": 11,
|
|
17
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Read-only identifiers for retained state from earlier private clients.
|
|
2
|
+
|
|
3
|
+
New state uses FlashDrive identifiers. These sets only admit existing records
|
|
4
|
+
so an upgrade does not discard pending work. They do not enable old commands,
|
|
5
|
+
imports, credential namespaces or default hosts.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
GIT_SCOPE_SCHEMAS = ("flashdrive-mount-git-sync-scope.v1", "baseseat-mount-git-sync-scope.v1")
|
|
9
|
+
# The service validates this issued wire format. Renaming it requires an API
|
|
10
|
+
# migration, independently of the Python package and local recovery filenames.
|
|
11
|
+
GIT_CHECKPOINT_WIRE_SCHEMA = "baseseat.git-checkpoint.v1"
|
|
12
|
+
GIT_CHECKPOINT_SCHEMAS = (GIT_CHECKPOINT_WIRE_SCHEMA,)
|
|
13
|
+
WORKCOPY_METADATA = (".flashdrive", ".baseseat", ".wondersearch")
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"""Local error messages. Backend response messages are preserved verbatim."""
|
|
2
|
+
|
|
3
|
+
MESSAGES = {
|
|
4
|
+
"mount_credential_origin_mismatch": "The mount belongs to a different API origin. Select its original profile or set credentials and their matching API base URL before restarting it.",
|
|
5
|
+
"expected_revision_must_be_a_document_revision": "--expected-revision is required from your original document read (a positive decimal integer through 9223372036854775807)",
|
|
6
|
+
"expected_revision_requires_replace": "--expected-revision requires --replace",
|
|
7
|
+
"file_revision_is_required": "--revision is required from your original file read (a positive decimal integer through 9223372036854775807)",
|
|
8
|
+
"folder_move_needs_a_target": "Give --to PARENT (or --to root for the top level), --name, or both.",
|
|
9
|
+
"folder_deletion_progress": "Deleted {} of {} files...",
|
|
10
|
+
"folder_sync_retired": "FlashDrive uses mounted drives for filesystem access. Folder synchronization commands are unavailable. Existing folders, drafts and recovery data remain intact. Stop old synchronization processes, manually review selected drafts, then copy the selected files into a mounted drive. This command does not read, upload, move or delete those files.",
|
|
11
|
+
"mount_unsupported": "Mounting needs macOS, or Linux with FUSE, and this machine has no /dev/fuse. Read and write single files with flashdrive file cat|get|patch, and flashdrive file link for a URL a program can stream.",
|
|
12
|
+
"mount_needs_fusermount": "Mounting as a user other than root needs fusermount3 (Debian and Ubuntu: apt-get install fuse3). Use a machine with FUSE support, or read and write files through the CLI file commands or SDK.",
|
|
13
|
+
"state_too_new": "{} was written by a newer FlashDrive CLI (state version {}). Update the CLI to use it.",
|
|
14
|
+
"file_edit_pairs": "Give each edit as --old TEXT --new TEXT (old text not empty), or a list with --edits.",
|
|
15
|
+
"file_edit_one_source": "Give the edits either as --old/--new pairs or with --edits, not both.",
|
|
16
|
+
"file_edit_bad_list": "--edits needs a JSON list of objects, each with old and new text.",
|
|
17
|
+
"delete_many_pairs": "Give each file as DOCUMENT_ID:REVISION, with the revision from your original document read (a positive decimal integer through 9223372036854775807), or a list with --documents.",
|
|
18
|
+
"delete_many_one_source": "Give the files either as DOCUMENT_ID:REVISION arguments or with --documents, not both.",
|
|
19
|
+
"delete_many_bad_list": "--documents needs a JSON list of objects, each with id and expected_revision text.",
|
|
20
|
+
"delete_many_count": "Name from 1 through {} files. One request deletes all of them or none; split a larger delete into several.",
|
|
21
|
+
"delete_many_duplicate": "Name each file once.",
|
|
22
|
+
"delete_many_idempotency_key": "Delete idempotency key: {} (pass it with --idempotency-key to retry this same delete)",
|
|
23
|
+
"mount_journal_newer": "This drive was last used with a newer FlashDrive. Update FlashDrive, then mount again; your pending changes are kept.",
|
|
24
|
+
"mount_helper_version": "The mount helper wd-fs (version {}, protocol {}) does not match this CLI. Install the wd-fs that came with it, or update both.",
|
|
25
|
+
"mount_busy": "The drive is in use by {}, so it stays mounted. Close them (or their windows on the drive), then unmount again.",
|
|
26
|
+
"mount_busy_unknown": "The drive is in use, and which programs hold it could not be told, so it stays mounted. Close the programs using it, then unmount again.",
|
|
27
|
+
"mount_helper_override_missing": "FLASHDRIVE_WD_FS is set to {}, which is not an executable file. Point it at the wd-fs mount helper, or unset it to use the one installed with the CLI.",
|
|
28
|
+
"mount_helper_missing": "This install has no mount helper (wd-fs): it came from a package without one. Install the CLI again with the uv, pipx or pip command for macOS or Linux at {}, adding its reinstall option (uv tool install --reinstall, pipx install --force, pip install --force-reinstall); those packages include wd-fs. Or set FLASHDRIVE_WD_FS to the path of a wd-fs you have.",
|
|
29
|
+
"mount_folder_not_empty": "{} is not empty. Mount into an empty folder, or choose one with --at.",
|
|
30
|
+
"mount_already_running": "{} is already mounted. Run flashdrive unmount first.",
|
|
31
|
+
"mount_failed": "The drive could not be mounted: {}",
|
|
32
|
+
"mount_not_found": "No mount found there. flashdrive mounts lists them.",
|
|
33
|
+
"mount_which": "Several drives are mounted. Name the folder: flashdrive unmount <folder>.",
|
|
34
|
+
"workcopy_bad_path": "Refused the path {}: it is not a plain path inside the folder.",
|
|
35
|
+
"workcopy_other_drive": "{} is a working copy of another drive.",
|
|
36
|
+
"workcopy_no_manifest": "{} has no legacy working-copy manifest. Keep existing drafts intact and manually review selected files before copying them into a mounted drive.",
|
|
37
|
+
"conflicts_wait": "{} conflict(s) wait for a merge. Each entry under conflicts lists next_steps: merge the two versions, then save the file in the mounted drive.",
|
|
38
|
+
"workcopy_confirm_deletes": "This legacy operation would delete {0} drive files. Folder synchronization is unavailable. Preserve local files and manually review any intended changes in a mounted drive.",
|
|
39
|
+
"mount_unsaved_read_only": "This folder's last mount left changes the drive does not have yet. Mount it again without --read-only to save them.",
|
|
40
|
+
"unmount_unsaved": "Some changes are not saved to the drive yet, so the folder stays mounted: {} Fix them, or unmount with --force to keep them on this machine only.",
|
|
41
|
+
"unmount_failed": "Could not unmount: {} (leave the folder and close files in it, then try again).",
|
|
42
|
+
"file_range_modes_conflict": "Read by lines (--start-line, --line-count) or by bytes (--offset, --length), not both.",
|
|
43
|
+
"file_option_out_of_range": "{} must be a whole number from {} through {}.",
|
|
44
|
+
"file_download_unexpected_answer": "The service did not answer with the requested byte range. Try the download again.",
|
|
45
|
+
"file_bytes_range_invalid": "--bytes takes A-B (inclusive), A- or -N, in bytes.",
|
|
46
|
+
"file_text_required": "Provide nonempty text of at most {} characters for {}.",
|
|
47
|
+
"file_pages_exceeded": "Stopped after {} pages. Continue with --cursor {}.",
|
|
48
|
+
"upload_metadata_exceeds_batch_limit": "Upload metadata exceeds the drive's {} byte request limit. Reduce the metadata before retrying.",
|
|
49
|
+
"upload_capacity_pending_resume": "Unresolved uploads fill this run's pending window. Resume the saved run to reconcile them before adding more files.",
|
|
50
|
+
"upload_recovery_quarantined": "This saved upload cannot safely submit mutations. Its original recovery record and source paths are unchanged. Keep the source as a draft and reconcile any upload or operation receipt before starting a new edit; do not assign the draft today's revision. Receipt checks here are read-only and do not prove the file is still current.",
|
|
51
|
+
"upload_exceeds_drive_limits": "This upload has {} files and {} bytes, but a drive holds at most {} documents and {} bytes. Split it across drives.",
|
|
52
|
+
"unreadable_file": "Cannot read file or directory.",
|
|
53
|
+
"invalid_signin_callback": "Invalid sign-in callback. Return to your terminal.",
|
|
54
|
+
"api_url_must_be_a_string": "API URL must be a string.",
|
|
55
|
+
"api_url_must_be_an_https_origin_http": "API URL must be an HTTPS origin (HTTP is permitted only on loopback).",
|
|
56
|
+
"configuration_recovery_paths_must_not_contain_symlinks": "Configuration/recovery paths must not contain symlinks.",
|
|
57
|
+
"invalid_profile_name": "Invalid profile name.",
|
|
58
|
+
"configuration_profiles_must_be_an_object": "Configuration profiles must be an object.",
|
|
59
|
+
"profile_settings_must_contain_string_values": "Profile settings must contain string values.",
|
|
60
|
+
"private_configuration_recovery_file_must_have_mode_0600": "Private configuration/recovery file must have mode 0600.",
|
|
61
|
+
"set_only_one_of_flashdrive_api_key_and": "Set only one of FLASHDRIVE_API_KEY and FLASHDRIVE_ACCESS_TOKEN.",
|
|
62
|
+
"invalid_saved_credential_record_log_in_again": "Invalid saved credential record. Log in again.",
|
|
63
|
+
"log_in_or_provide_credentials_for_this_api": "Log in or provide credentials for this API origin.",
|
|
64
|
+
"cannot_read_private_configuration_recovery_file": "Cannot read private configuration/recovery file.",
|
|
65
|
+
"saved_credential_belongs_to_a_different_api_origin": "Saved credential belongs to a different API origin. Log in for this origin first.",
|
|
66
|
+
"unlock_or_configure_your_operating_system_credential_store": "Unlock or configure your operating system credential store, then run flashdrive login again. For automation, use FLASHDRIVE_API_KEY.",
|
|
67
|
+
"the_saved_session_is_invalid_run_flashdrive_login": "The saved session is invalid. Run flashdrive login again.",
|
|
68
|
+
"credential_paths_must_not_contain_symlinks": "Credential paths must not contain symlinks.",
|
|
69
|
+
"the_server_returned_an_invalid_sign_in_address": "The server returned an invalid sign-in address.",
|
|
70
|
+
"sign_in_timed_out_run_flashdrive_login_again": "Sign-in timed out. Run flashdrive login again.",
|
|
71
|
+
"sign_in_cancelled": "Sign-in cancelled.",
|
|
72
|
+
"your_session_has_expired_run_flashdrive_login_to": "Your session has expired. Run flashdrive login to sign in again.",
|
|
73
|
+
"browser_sign_in_is_unavailable_on_this_server": "Browser sign-in is unavailable on this server. Try again shortly, or use flashdrive login --api-key.",
|
|
74
|
+
"could_not_complete_sign_in_check_your_connection": "Could not complete sign-in. Check your connection and try again.",
|
|
75
|
+
"could_not_save_your_session_in_the_operating": "Could not save your session in the operating system credential store.",
|
|
76
|
+
"run_flashdrive_login_to_sign_in": "Run flashdrive login to sign in.",
|
|
77
|
+
"could_not_read_your_saved_session_unlock_your": "Could not read your saved session. Unlock your operating system credential store and try again.",
|
|
78
|
+
"the_session_was_revoked_but_local_cleanup_failed": "The session was revoked, but local cleanup failed. Unlock your credential store and run flashdrive logout again.",
|
|
79
|
+
"this_server_requires_a_different_cli_api_major": "This server requires a different CLI API major.",
|
|
80
|
+
"upgrade_flashdrive_cli_to_at_least_0": "Upgrade flashdrive-cli to at least {0}. Run flashdrive update.",
|
|
81
|
+
"cli_upgrade_available": "flashdrive-cli {} is available. Run flashdrive update to upgrade.",
|
|
82
|
+
"cli_version_deprecated": "flashdrive-cli {} will stop being supported. Run flashdrive update to install {} or later.",
|
|
83
|
+
"api_feature_deprecated": "This request uses a deprecated API feature.",
|
|
84
|
+
"api_feature_sunset": "It stops working on {}.",
|
|
85
|
+
"api_feature_replacement": "Use {} instead.",
|
|
86
|
+
"api_feature_docs": "See {}.",
|
|
87
|
+
"api_version_retired": "This API version or feature has been retired.",
|
|
88
|
+
"client_upgrade_required": "This version of flashdrive-cli is no longer supported.",
|
|
89
|
+
"run_flashdrive_update": "Run flashdrive update.",
|
|
90
|
+
"minimum_cli_version_is": "The minimum supported version is {}.",
|
|
91
|
+
"update_source_install": "This CLI was installed from a local checkout or file. Update it from that source.",
|
|
92
|
+
"update_installer_missing": "This CLI was installed with {}, which is not on PATH. Run its upgrade command yourself.",
|
|
93
|
+
"update_unknown_installer": "Cannot tell how this CLI was installed (installer: {}). Upgrade it with the tool you used to install it.",
|
|
94
|
+
"update_uv_upgrade_yourself": "This CLI is a uv tool installed with its own sources or settings, which an update here would not keep. Run: uv tool upgrade flashdrive-cli",
|
|
95
|
+
"update_no_manifest": "The service did not report a current CLI release. Try again later.",
|
|
96
|
+
"update_busy": "Another updater is using this CLI environment, or its update lock is unavailable. Try again after it finishes.",
|
|
97
|
+
"update_version_conflict": "The installed CLI version could not be verified or is newer than the update target. Restart the CLI and check again.",
|
|
98
|
+
"update_verification_failed": "The upgrade did not produce a working CLI at the exact requested version {}. Inspect the installation before retrying.",
|
|
99
|
+
"update_api_incompatible": "This release targets an incompatible API major. Select the correct API instance before updating.",
|
|
100
|
+
"update_channel_incompatible": "Automatic and in-place updates require a stable release channel and version.",
|
|
101
|
+
"update_origin_incompatible": "This staging build accepts release updates only from its configured staging API.",
|
|
102
|
+
"update_staging_manual": "Manual staging update required. Install {} from {} with the tool that owns this environment. Preserve its settings and staging access credentials.",
|
|
103
|
+
"update_manual_command": "Run: {}",
|
|
104
|
+
"upload_file_exceeds_limit": "Provide a file no larger than {} bytes.",
|
|
105
|
+
"upload_expected_regular_file": "Expected a regular file.",
|
|
106
|
+
"update_major_metadata": "This API instance has not advertised compatibility for a new CLI major. Keep this client until compatible release metadata is available.",
|
|
107
|
+
"update_major_required": "CLI {} is a new major version. Review its migration guide, then run flashdrive update --allow-major.",
|
|
108
|
+
"update_installing": "Updating flashdrive-cli to {}.",
|
|
109
|
+
"update_installing_newest": "Updating flashdrive-cli to its newest release.",
|
|
110
|
+
"update_failed": "The {} upgrade did not finish. Its output is shown above.",
|
|
111
|
+
"update_rerun": "flashdrive-cli was updated. Running the command again.",
|
|
112
|
+
"cli_release_available": "flashdrive-cli {} is available (installed {}). Run: flashdrive update",
|
|
113
|
+
"cli_below_minimum": "flashdrive-cli {1} is the minimum supported version (installed {0}). Run: flashdrive update",
|
|
114
|
+
"cli_moved": "The FlashDrive CLI is now published as {} (command {}). It is not installed automatically.",
|
|
115
|
+
"cli_moved_install": "Install it with: {}.",
|
|
116
|
+
"update_no_workdir": "Cannot prepare the private update directory in the CLI configuration directory.",
|
|
117
|
+
"update_continues": "flashdrive-cli was updated; this command runs on the version that was already running.",
|
|
118
|
+
"update_rerun_failed": "flashdrive-cli was updated, but the command could not be run again. Run it again yourself.",
|
|
119
|
+
"update_unchanged": "The {} upgrade finished, but the installed version did not change. Upgrade with the tool you used to install the CLI.",
|
|
120
|
+
"update_timed_out": "The upgrade did not finish in time. Run it yourself: {}",
|
|
121
|
+
"server_response_is_missing_required_fields_or_has": "Server response is missing required fields or has invalid field types.",
|
|
122
|
+
"operation_timed_out_accepted_server_work_continues": "Operation timed out; accepted server work continues.",
|
|
123
|
+
"expected_a_resource_uuid": "Expected a resource UUID.",
|
|
124
|
+
"complete_account_setup_in_the_console_first": "Complete account setup in the Console first.",
|
|
125
|
+
"sign_in_with_a_user_session_to_run": "Sign in with a user session to run this command. API keys cannot be used here.",
|
|
126
|
+
"api_request_failed": "API request failed.",
|
|
127
|
+
"unsafe_transfer_destination": "Unsafe transfer destination.",
|
|
128
|
+
"invalid_api_path": "Invalid API path.",
|
|
129
|
+
"server_returned_an_invalid_response": "Server returned an invalid response.",
|
|
130
|
+
"server_returned_invalid_pagination_data": "Server returned invalid pagination data.",
|
|
131
|
+
"repeated_pagination_cursor": "Repeated pagination cursor.",
|
|
132
|
+
"resource_is_missing_its_concurrency_etag": "Resource is missing its concurrency ETag.",
|
|
133
|
+
"server_returned_a_non_json_response": "Server returned a non-JSON response.",
|
|
134
|
+
"network_request_failed": "Network request failed.",
|
|
135
|
+
"processing_failed": "Processing failed.",
|
|
136
|
+
"replace_requires_exactly_one_file_and_no_recursive": "--replace requires exactly one file and no --recursive.",
|
|
137
|
+
"directories_require_recursive": "Directories require --recursive.",
|
|
138
|
+
"recovery_record_does_not_match_this_profile_origin": "Recovery record does not match this profile, origin, identity, workspace, and drive.",
|
|
139
|
+
"invalid_upload_recovery_record_restore_the_original_record": "Invalid upload recovery record. Restore the original record before resuming.",
|
|
140
|
+
"expected_a_supported_regular_file_of_1_through": "Expected a regular file of at most 1,000,000,000 bytes.",
|
|
141
|
+
"upload_bytes_are_incomplete_use_upload_resume_with": "Upload bytes are incomplete. Use upload resume with the original run ID.",
|
|
142
|
+
"source_changed_since_reservation_cannot_resume_this_upload": "Source changed since reservation; cannot resume this upload.",
|
|
143
|
+
"ambiguous_destination_folder": "Ambiguous destination folder: ",
|
|
144
|
+
"destination_folder_could_not_be_created_or_resolved": "Destination folder could not be created or resolved.",
|
|
145
|
+
"transfer_headers_must_be_strings": "Transfer headers must be strings.",
|
|
146
|
+
"unknown_transfer_transport": "Unknown transfer transport.",
|
|
147
|
+
"cannot_read_source_file": "Cannot read source file.",
|
|
148
|
+
"unsupported_command": "Unsupported command.",
|
|
149
|
+
"incorrect_number_of_command_arguments_see_help": "Incorrect number of command arguments. See --help.",
|
|
150
|
+
"use_either_a_positional_drive_or_drive_not": "Use either a positional drive or --drive, not both.",
|
|
151
|
+
"use_either_a_positional_workspace_or_workspace_not": "Use either a positional workspace or --workspace, not both.",
|
|
152
|
+
"deletion_revocation_requires_confirmation_use_yes_in_scripts": "Deletion/revocation requires confirmation; use --yes in scripts.",
|
|
153
|
+
"deletion_revocation_was_not_confirmed": "Deletion/revocation was not confirmed.",
|
|
154
|
+
"allowed_config_keys": "Allowed config keys: ",
|
|
155
|
+
"": ", ",
|
|
156
|
+
"provide_a_configuration_value": "Provide a configuration value.",
|
|
157
|
+
"list_limit_must_be_between_1_and_100": "List limit must be between 1 and 100.",
|
|
158
|
+
"missing_command_argument_see_help": "Missing command argument. See --help.",
|
|
159
|
+
"processing_timeout_requires_wait": "--processing-timeout requires --wait.",
|
|
160
|
+
"dry_run_cannot_be_combined_with_wait": "--dry-run cannot be combined with --wait.",
|
|
161
|
+
"0_is_not_supported_for_this_command": "--{0} is not supported for this command.",
|
|
162
|
+
"select_an_organization_with_organization_or_config_set": "Select an organization with --organization or config set organization.",
|
|
163
|
+
"drive_is_not_accessible_in_the_selected_workspace": "Drive is not accessible in the selected workspace.",
|
|
164
|
+
"operation_is_looked_up_in_one_drive": "An operation is looked up in the drive it was made in. This one was looked for in the default drive ({}). If it was made in another drive, name it with --drive.",
|
|
165
|
+
"full_text_must_be_on_or_off": "Full-text search must be on or off.",
|
|
166
|
+
"mode_must_be_drive_or_search": "Mode must be drive or search.",
|
|
167
|
+
"this_token_is_limited_to_another_drive": "This sandbox token is limited to another drive. Omit --drive or mint a token for this drive.",
|
|
168
|
+
"token_not_saved": "The token was created but could not be saved. Revoke it: flashdrive sandbox-token revoke {0} --yes",
|
|
169
|
+
"token_file_exists": "The --out file already exists. Choose a new path; the token is written only to a new private file.",
|
|
170
|
+
"choose_out_or_print": "Choose --out FILE to save the token to a private file, or --print to show it once.",
|
|
171
|
+
"profile_names_must_contain_1_through_120_characters": "Profile names must contain 1 through 120 characters.",
|
|
172
|
+
"unknown_profile_create_it_with_login_profile_name": "Unknown profile. Create it with login --profile NAME or config set KEY VALUE --profile NAME.",
|
|
173
|
+
"waiting_interrupted_drive_0_continues_provisioning_check_it": "Waiting interrupted; drive {0} continues provisioning. Check it with drive get {1}.",
|
|
174
|
+
"idempotency_key_must_be_1_128_visible_ascii": "Idempotency key must be 1-128 visible ASCII characters.",
|
|
175
|
+
"input_ended_before_a_credential_was_provided": "Input ended before a credential was provided.",
|
|
176
|
+
"cannot_read_write_a_local_file_or_parse": "Cannot read/write a local file or parse its contents. Check paths, permissions, and encoding.",
|
|
177
|
+
"timeout_applies_only_to_browser_login": "--timeout applies only to browser login.",
|
|
178
|
+
"timeout_requires_wait": "--timeout requires --wait.",
|
|
179
|
+
"0_name_must_match_exactly_one_accessible_resource": "{0} name must match exactly one accessible resource; use its UUID.",
|
|
180
|
+
"this_api_key_is_scoped_to_a_different": "This API key is scoped to a different workspace.",
|
|
181
|
+
"drive_provisioning_failed": "Drive provisioning failed.",
|
|
182
|
+
"unknown_drive_provisioning_status": "Unknown drive provisioning status.",
|
|
183
|
+
"use_workspace_default_drive_get_or_set_drive": "Use workspace default-drive get or set <drive>.",
|
|
184
|
+
"use_upload_status_upload_id": "Use upload status <upload-id>.",
|
|
185
|
+
"use_upload_resume_run_id_wait": "Use upload resume <run-id> [--wait].",
|
|
186
|
+
"document_text_exceeds_2_000_000_bytes": "Document text exceeds 2,000,000 bytes.",
|
|
187
|
+
"timeouts_must_be_finite_and_positive": "Timeouts must be finite and positive.",
|
|
188
|
+
"select_a_workspace_with_workspace_or_workspace_use": "Select a workspace with --workspace or workspace use.",
|
|
189
|
+
"select_the_profile_for_this_api_origin_before": "Select the profile for this API origin before signing out.",
|
|
190
|
+
"choose_browser_sign_in_or_one_credential_type": "Choose browser sign-in or one credential type. Browser timeout must be at most 300 seconds.",
|
|
191
|
+
"provide_a_nonempty_credential_without_whitespace": "Provide a nonempty credential without whitespace.",
|
|
192
|
+
"import_exceeds_drive_limits": "This import has {} documents and {} bytes, but a drive holds at most {} documents and {} bytes. Split it across drives.",
|
|
193
|
+
"import_exceeds_service_limits": "This import has {} documents, {} bytes and {} chunks, but one import holds at most {} documents, {} bytes and {} chunks. Split it into several imports.",
|
|
194
|
+
"import_has_nothing_to_send": "No importable files found. Imports accept nonempty UTF-8 .txt and .md files.",
|
|
195
|
+
"import_unfinished_exists": "An unfinished import of these paths to this drive exists. Continue it with flashdrive import PATHS --drive DRIVE --resume.",
|
|
196
|
+
"import_no_unfinished_run": "No unfinished import of these paths to this drive was found. Run the command without --resume to start one.",
|
|
197
|
+
"import_record_mismatch": "The saved import does not match this profile, origin, identity, workspace, and drive.",
|
|
198
|
+
"import_record_invalid": "The saved import record is invalid. Restore the original record, or start a new import.",
|
|
199
|
+
"import_option_conflicts_with_saved_run": "--{0} differs from the value saved with this import. Resume without it.",
|
|
200
|
+
"import_source_changed": "Files changed since this import started. Restore them, or start a new import.",
|
|
201
|
+
"import_rejected_content": "The service rejected part of this import. Check that every file is UTF-8 text, then start a new import.",
|
|
202
|
+
"import_conflict": "This import no longer matches its declared files. Start a new import.",
|
|
203
|
+
"import_closed": "This import is closed or has expired. Start a new import for any files that are not yet searchable.",
|
|
204
|
+
"import_not_found": "The import could not be found on this drive. Start a new import.",
|
|
205
|
+
"import_busy": "The import is busy. Run the same command with --resume to continue.",
|
|
206
|
+
"import_failed_documents": "{} documents could not be imported. Their files are listed in the error details; import them again in a new import.",
|
|
207
|
+
"import_failed_operations": "Some documents could not be made searchable. Run the same command with --resume --retry-failed to try them again.",
|
|
208
|
+
"import_interrupted": "Interrupted; the service keeps the accepted work. Run the same command with --resume to continue.",
|
|
209
|
+
"import_timed_out": "Waiting reached its time limit; the service keeps the accepted work. Run the same command with --resume to continue.",
|
|
210
|
+
"import_invalid_combine_bytes": "--combine-bytes must be between 0 and 1,000,000.",
|
|
211
|
+
"import_resume_or_dry_run": "Use --dry-run or --resume, not both.",
|
|
212
|
+
"import_retry_requires_resume": "--retry-failed requires --resume.",
|
|
213
|
+
"import_file_too_large": "This file is larger than one import chunk allows. Use flashdrive upload for it.",
|
|
214
|
+
"import_invalid_text": "Imports accept nonempty UTF-8 text only.",
|
|
215
|
+
"import_operations_not_retryable": "Some documents could not be made searchable and cannot be retried. The import is closed; import the listed files again in a new import.",
|
|
216
|
+
"import_scan_timed_out": "Reading the files reached the time limit; nothing was sent. Run the command again with a longer --timeout.",
|
|
217
|
+
"import_sealed_follow": "The import is sealed; its documents become searchable over time. Follow it with: {}",
|
|
218
|
+
"import_service_unavailable": "The service is temporarily unavailable. Run the same command with --resume to continue.",
|
|
219
|
+
"import_duplicate_paths": "Two files would become the same document ({}). Import paths with the same name separately, or rename one.",
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def local_message(code: str, *values: object) -> str:
|
|
224
|
+
return MESSAGES[code].format(*values)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
# 429s that are capacity or a daily quota, not pacing: their own messages say what to do.
|
|
228
|
+
QUOTA_CODES = {"upload_limit", "agent_quota_exhausted"}
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def throttle_line(retry_after=None, now=None) -> str:
|
|
232
|
+
"""The one line for any rate throttle: the next whole minute after the wait asked for."""
|
|
233
|
+
import math
|
|
234
|
+
import time
|
|
235
|
+
|
|
236
|
+
wait = float(retry_after) if isinstance(retry_after, (int, float)) and math.isfinite(retry_after) else 60.0
|
|
237
|
+
moment = math.ceil(((time.time() if now is None else now) + max(wait, 1.0)) / 60) * 60
|
|
238
|
+
stamp = time.gmtime(moment)
|
|
239
|
+
return f"Too many requests. Try again after {stamp.tm_hour:02d}:{stamp.tm_min:02d} UTC."
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""One factor for the mount's waits, read once when the process starts.
|
|
2
|
+
|
|
3
|
+
Test-only: FLASHDRIVE_TEST_TIME_SCALE (a float from 0.01 to 1) shortens the
|
|
4
|
+
waits that bound how long a queued change takes to end (retry backoff, the
|
|
5
|
+
limit, permission and held waits, the offline probe and the status journal
|
|
6
|
+
grace), so a real-mount test grid runs in minutes. Unset or invalid, SCALE is
|
|
7
|
+
exactly 1.0 and every wait is its production value. Never documented for
|
|
8
|
+
customers. HTTP timeouts and the mount lease are never scaled.
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
import math
|
|
12
|
+
import os
|
|
13
|
+
|
|
14
|
+
VARIABLE = "FLASHDRIVE_TEST_TIME_SCALE"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def read_scale(value: str | None) -> float:
|
|
18
|
+
try:
|
|
19
|
+
scale = float(value) if value is not None else 1.0
|
|
20
|
+
except ValueError:
|
|
21
|
+
return 1.0
|
|
22
|
+
return scale if math.isfinite(scale) and 0.01 <= scale <= 1.0 else 1.0
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
SCALE = read_scale(os.environ.get(VARIABLE))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def scaled(seconds: float) -> float:
|
|
29
|
+
return seconds if SCALE == 1.0 else seconds * SCALE
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '1.0.0'
|