5.4 KB191 lines
Blame
1#!/usr/bin/env bash
2# Grove - Import a Git repository into Mononoke
3# Uses the gitimport tool (inside the mononoke container) to import a Git repo
4# into Mononoke's blobstore.
5#
6# Usage: ./import-repo.sh <git-repo-path-or-url> <repo-name> [commit-sha]
7#
8# If commit-sha is provided, does incremental import (missing-for-commit).
9# Otherwise, does a full-repo import (first time only).
10#
11# Examples:
12# ./import-repo.sh /path/to/local/repo grove
13# ./import-repo.sh https://github.com/user/repo.git myrepo
14# ./import-repo.sh /path/to/local/repo grove abc123 # incremental
15
16set -euo pipefail
17
18SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
19GROVE_DIR="$SCRIPT_DIR/.."
20HUB_DIR="$GROVE_DIR/hub"
21DATA_DIR="${GROVE_DATA_DIR:-/data/grove}"
22CONFIG_DIR="$DATA_DIR/mononoke-config"
23
24GIT_SOURCE="${1:?Usage: ./import-repo.sh <git-repo-path-or-url> <repo-name> [commit-sha]}"
25REPO_NAME="${2:?Usage: ./import-repo.sh <git-repo-path-or-url> <repo-name> [commit-sha]}"
26COMMIT_SHA="${3:-}"
27
28echo "=== Grove: Importing Git repo into Mononoke ==="
29echo "Source: $GIT_SOURCE"
30echo "Repo name: $REPO_NAME"
31if [[ -n "$COMMIT_SHA" ]]; then
32 echo "Mode: incremental (missing-for-commit $COMMIT_SHA)"
33else
34 echo "Mode: full-repo"
35fi
36echo ""
37
38# Step 1: Clone/prepare bare repo for import
39BARE_REPO="$DATA_DIR/$REPO_NAME-bare.git"
40
41echo "Step 1: Preparing bare clone at $BARE_REPO..."
42if [[ -d "$BARE_REPO" ]]; then
43 echo " Bare repo already exists, updating..."
44 if [[ -d "$GIT_SOURCE" ]]; then
45 (cd "$GIT_SOURCE" && git push "$BARE_REPO" --all --force)
46 elif [[ "$GIT_SOURCE" == http* ]] || [[ "$GIT_SOURCE" == git@* ]]; then
47 git clone --bare "$GIT_SOURCE" "${BARE_REPO}.tmp"
48 rm -rf "$BARE_REPO"
49 mv "${BARE_REPO}.tmp" "$BARE_REPO"
50 fi
51else
52 if [[ -d "$GIT_SOURCE" ]]; then
53 git clone --bare "$GIT_SOURCE" "$BARE_REPO"
54 elif [[ "$GIT_SOURCE" == http* ]] || [[ "$GIT_SOURCE" == git@* ]]; then
55 git clone --bare "$GIT_SOURCE" "$BARE_REPO"
56 else
57 echo "Error: $GIT_SOURCE is not a valid git repo path or URL"
58 exit 1
59 fi
60fi
61echo " Bare clone ready at $BARE_REPO"
62
63# Step 2: Create repo config if it doesn't exist
64REPO_DEF_DIR="$CONFIG_DIR/repo_definitions/$REPO_NAME"
65REPO_CFG_DIR="$CONFIG_DIR/repos/$REPO_NAME"
66
67if [[ ! -d "$REPO_DEF_DIR" ]]; then
68 echo ""
69 echo "Step 2: Creating Mononoke config for '$REPO_NAME'..."
70
71 # Find next available repo_id
72 MAX_ID=0
73 for f in "$CONFIG_DIR"/repo_definitions/*/server.toml; do
74 if [[ -f "$f" ]]; then
75 ID=$(grep -oP 'repo_id\s*=\s*\K[0-9]+' "$f" 2>/dev/null || echo 0)
76 if (( ID > MAX_ID )); then
77 MAX_ID=$ID
78 fi
79 fi
80 done
81 NEXT_ID=$((MAX_ID + 1))
82
83 mkdir -p "$REPO_DEF_DIR" "$REPO_CFG_DIR"
84
85 cat > "$REPO_DEF_DIR/server.toml" <<EOF
86repo_id = $NEXT_ID
87repo_name = "$REPO_NAME"
88repo_config = "$REPO_NAME"
89enabled = true
90hipster_acl = "default"
91EOF
92
93 cat > "$REPO_CFG_DIR/server.toml" <<EOF
94storage_config = "default"
95
96[hook_manager_params]
97disable_acl_checker = true
98
99[push]
100pure_push_allowed = true
101
102[pushrebase]
103rewritedates = false
104
105[source_control_service]
106permit_writes = true
107permit_service_writes = true
108
109[git_configs.git_bundle_uri_config.uri_generator_type.local_fs]
110
111[infinitepush]
112allow_writes = true
113
114[commit_cloud_config]
115
116[derived_data_config]
117enabled_config_name = "default"
118
119[derived_data_config.available_configs.default]
120types = [
121 "blame",
122 "changeset_info",
123 "fastlog",
124 "filenodes",
125 "fsnodes",
126 "git_commits",
127 "git_delta_manifests_v2",
128 "unodes",
129 "hgchangesets",
130 "skeleton_manifests",
131 "skeleton_manifests_v2",
132 "ccsm",
133]
134
135[derived_data_config.available_configs.default.git_delta_manifest_v2_config]
136max_inlined_object_size = 2000
137max_inlined_delta_size = 2000
138delta_chunk_size = 1000000
139EOF
140
141 echo " Config created with repo_id=$NEXT_ID"
142 echo ""
143 echo " NOTE: Mononoke must be restarted to pick up the new repo config."
144 echo " Run: cd $HUB_DIR && docker compose restart mononoke-slapi grove-bridge mononoke-git"
145 echo ""
146 read -p " Restart Mononoke now? [y/N] " -n 1 -r
147 echo
148 if [[ $REPLY =~ ^[Yy]$ ]]; then
149 echo " Restarting Mononoke services..."
150 (cd "$HUB_DIR" && docker compose restart mononoke-slapi grove-bridge mononoke-git)
151 echo " Waiting 5s for services to start..."
152 sleep 5
153 fi
154else
155 echo ""
156 echo "Step 2: Config for '$REPO_NAME' already exists, skipping."
157fi
158
159# Step 3: Run gitimport via docker compose
160echo ""
161echo "Step 3: Importing into Mononoke via gitimport..."
162echo " This may take a while for large repos."
163
164IMPORT_MODE="full-repo"
165IMPORT_ARGS=()
166if [[ -n "$COMMIT_SHA" ]]; then
167 IMPORT_MODE="missing-for-commit"
168 IMPORT_ARGS=("$COMMIT_SHA")
169fi
170
171(cd "$HUB_DIR" && docker compose run --rm --entrypoint gitimport grove-bridge \
172 --repo-name "$REPO_NAME" \
173 --config-path "$CONFIG_DIR" \
174 --local-configerator-path "$DATA_DIR/configerator" \
175 --cache-mode disabled \
176 --just-knobs-config-path "$DATA_DIR/justknobs.json" \
177 --generate-bookmarks \
178 --derive-hg \
179 --git-command-path /usr/bin/git \
180 --concurrency 5 \
181 "$BARE_REPO" \
182 "$IMPORT_MODE" \
183 "${IMPORT_ARGS[@]+"${IMPORT_ARGS[@]}"}")
184
185echo ""
186echo "=== Import complete ==="
187echo "Repo '$REPO_NAME' is now available in Mononoke."
188echo ""
189echo "Clone via git: git clone https://grove.host/repos/$REPO_NAME"
190echo "Clone via grove: grove clone $REPO_NAME"
191