267 lines
7 KiB
Bash
Executable file
267 lines
7 KiB
Bash
Executable file
#!/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 @- <<EOF
|
|
{
|
|
"data": {
|
|
"type": "nodes",
|
|
"attributes": {
|
|
"title": "$TITLE",
|
|
"description": "$DESCRIPTION",
|
|
"category": "$CATEGORY",
|
|
"public": $PUBLIC
|
|
}
|
|
}
|
|
}
|
|
EOF
|
|
)
|
|
|
|
STATUS="${RESPONSE: -3}"
|
|
if [[ "$STATUS" != "201" ]]; then
|
|
echo "❌ Project creation failed with status $STATUS"
|
|
echo "🧾 Response:"
|
|
cat "$TMP_JSON"
|
|
exit 1
|
|
fi
|
|
|
|
NODE_ID=$(jq -r '.data.id' "$TMP_JSON")
|
|
if [[ "$NODE_ID" == "null" || -z "$NODE_ID" ]]; then
|
|
echo "❌ No valid OSF project ID returned."
|
|
cat "$TMP_JSON"
|
|
exit 1
|
|
fi
|
|
|
|
echo "📡 Project created: $NODE_ID"
|
|
|
|
upload_file() {
|
|
local path="$1"
|
|
local name="$2"
|
|
echo "📁 Uploading $name from $path..."
|
|
UPLOAD_URL="https://files.osf.io/v1/resources/$NODE_ID/providers/osfstorage/?kind=file&name=$(basename "$name")"
|
|
curl -s -X PUT "$UPLOAD_URL" \
|
|
-H "Authorization: Bearer $OSF_TOKEN" \
|
|
-F "file=@$path" > /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 @- <<EOF > /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
|