#!/usr/bin/env bash set -euo pipefail # === Constants and Paths === BASEDIR="$(pwd)" OSF_YAML="$BASEDIR/osf.yaml" GITFIELD_DIR="$BASEDIR/.gitfield" mkdir -p "$GITFIELD_DIR" SCAN_LOG_INIT="$GITFIELD_DIR/scan_log.json" SCAN_LOG_PUSH="$GITFIELD_DIR/push_log.json" TMP_JSON="$GITFIELD_DIR/tmp_project.json" TOKEN_PATH="$HOME/.local/gitfieldlib/osf.token" mkdir -p "$(dirname "$TOKEN_PATH")" # === Dependency Check & Auto-Install === require_yq() { if ! command -v yq &>/dev/null || ! yq --version 2>/dev/null | grep -q 'version 4'; then echo "⚠️ Correct 'yq' (Go version) not found. Installing from GitHub..." YQ_BIN="/usr/local/bin/yq" ARCH=$(uname -m) case $ARCH in x86_64) ARCH=amd64 ;; aarch64) ARCH=arm64 ;; *) echo "❌ Unsupported architecture: $ARCH" && exit 1 ;; esac YQ_VERSION="v4.43.1" curl -Lo yq "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_${ARCH}" \ && chmod +x yq && sudo mv yq "$YQ_BIN" echo "✅ 'yq' installed to $YQ_BIN" fi } require_jq() { if ! command -v jq &>/dev/null; then echo "⚠️ 'jq' not found. Installing..." sudo apt update && sudo apt install -y jq echo "✅ 'jq' installed." fi } require_yq require_jq # === Token Retrieval === if [[ -z "${OSF_TOKEN:-}" ]]; then if [[ -f "$TOKEN_PATH" ]]; then OSF_TOKEN=$(<"$TOKEN_PATH") else echo -n "🔐 Enter your OSF_TOKEN (stored for future use): " read -rs OSF_TOKEN echo echo "$OSF_TOKEN" > "$TOKEN_PATH" chmod 600 "$TOKEN_PATH" echo "📁 Token saved to $TOKEN_PATH" fi fi # === INIT MODE === init_mode() { echo "🔍 Scanning project directory..." mapfile -t ALL_FILES < <(find "$BASEDIR" -type f \( -name '*.md' -o -name '*.pdf' -o -name '*.tex' \) ! -path "*/.git/*" ! -path "*/.gitfield/*") detect_file() { local keywords=("$@") for file in "${ALL_FILES[@]}"; do for kw in "${keywords[@]}"; do if [[ "${file,,}" == *"$kw"* ]]; then echo "$file" return 0 fi done done } WIKI_PATH=$(detect_file "wiki.md" "wiki") README_PATH=$(detect_file "readme.md") PAPER_PATH=$(detect_file "main.pdf" "theory.pdf" "paper.pdf") ESSAYS=() FILES=() for f in "${ALL_FILES[@]}"; do case "$f" in "$WIKI_PATH"|"$README_PATH"|"$PAPER_PATH") continue ;; *essays/*|*notes/*|*docs/*) ESSAYS+=("$f") ;; *) FILES+=("$f") ;; esac done echo "📝 Generating osf.yaml..." { echo "title: \"$(basename "$BASEDIR")\"" echo "description: \"Auto-generated by GitField OSF publisher\"" echo "category: \"project\"" echo "public: false" echo "tags: [gitfield, auto-generated]" [[ -n "$WIKI_PATH" ]] && echo -e "\nwiki:\n path: \"${WIKI_PATH#$BASEDIR/}\"\n overwrite: true" [[ -n "$README_PATH" ]] && echo -e "\nreadme:\n path: \"${README_PATH#$BASEDIR/}\"" [[ -n "$PAPER_PATH" ]] && echo -e "\npaper:\n path: \"${PAPER_PATH#$BASEDIR/}\"\n name: \"$(basename "$PAPER_PATH")\"" if ((${#ESSAYS[@]})); then echo -e "\nessays:" for essay in "${ESSAYS[@]}"; do echo " - path: \"${essay#$BASEDIR/}\"" echo " name: \"$(basename "$essay")\"" done fi if ((${#FILES[@]})); then echo -e "\nfiles:" for file in "${FILES[@]}"; do echo " - path: \"${file#$BASEDIR/}\"" echo " name: \"$(basename "$file")\"" done fi } > "$OSF_YAML" jq -n \ --argjson all "$(printf '%s\n' "${ALL_FILES[@]}" | jq -R . | jq -s .)" \ --arg wiki "$WIKI_PATH" \ --arg readme "$README_PATH" \ --arg paper "$PAPER_PATH" \ --argjson essays "$(printf '%s\n' "${ESSAYS[@]}" | jq -R . | jq -s .)" \ --argjson files "$(printf '%s\n' "${FILES[@]}" | jq -R . | jq -s .)" \ --arg osf_yaml "$OSF_YAML" \ '{ detected_files: $all, classified: { wiki: $wiki, readme: $readme, paper: $paper, essays: $essays, files: $files }, osf_yaml_path: $osf_yaml }' > "$SCAN_LOG_INIT" echo "✅ osf.yaml created at $OSF_YAML" } # === PUSH MODE === push_mode() { TITLE=$(yq e '.title' "$OSF_YAML") DESCRIPTION=$(yq e '.description' "$OSF_YAML") CATEGORY=$(yq e '.category' "$OSF_YAML") PUBLIC=$(yq e '.public' "$OSF_YAML") echo "🚀 Creating OSF project..." RESPONSE=$(curl -s -w "%{http_code}" -o "$TMP_JSON" -X POST "https://api.osf.io/v2/nodes/" \ -H "Authorization: Bearer $OSF_TOKEN" \ -H "Content-Type: application/vnd.api+json" \ -d @- < /dev/null } upload_group() { local section="$1" local count count=$(yq e ".${section} | length" "$OSF_YAML") for ((i = 0; i < count; i++)); do local path path=$(yq e ".${section}[$i].path" "$OSF_YAML") local name name=$(yq e ".${section}[$i].name" "$OSF_YAML") upload_file "$path" "$name" done } [[ $(yq e '.readme.path' "$OSF_YAML") != "null" ]] && { path=$(yq e '.readme.path' "$OSF_YAML") upload_file "$path" "$(basename "$path")" } [[ $(yq e '.paper.path' "$OSF_YAML") != "null" ]] && { path=$(yq e '.paper.path' "$OSF_YAML") name=$(yq e '.paper.name' "$OSF_YAML") upload_file "$path" "$name" } upload_group "files" upload_group "essays" if [[ $(yq e '.wiki.path' "$OSF_YAML") != "null" ]]; then WIKI_PATH=$(yq e '.wiki.path' "$OSF_YAML") echo "📜 Pushing wiki from $WIKI_PATH..." CONTENT=$(jq -Rs . < "$WIKI_PATH") curl -s -X PATCH "https://api.osf.io/v2/nodes/$NODE_ID/wikis/home/" \ -H "Authorization: Bearer $OSF_TOKEN" \ -H "Content-Type: application/vnd.api+json" \ -d @- < /dev/null { "data": { "type": "wikis", "attributes": { "content": $CONTENT } } } EOF fi jq -n \ --arg node_id "$NODE_ID" \ --arg pushed_at "$(date -Iseconds)" \ --arg token_path "$TOKEN_PATH" \ '{ project_id: $node_id, pushed_at: $pushed_at, token_used: $token_path }' > "$SCAN_LOG_PUSH" echo "✅ OSF Push Complete!" echo "🌐 View project: https://osf.io/$NODE_ID/" } # === Dispatcher === case "${1:-}" in --init | init) init_mode ;; --push | push) push_mode ;; *) echo "Usage: $0 [--init | --push]" exit 1 ;; esac