@@ -401,6 +401,8 @@ curl_orgs() {
401401
402402explore () {
403403 local node=$1
404+ local is_user=false
405+ local got_orgs=false
404406 [[ " $node " =~ .* \/ .* ]] && local graph=(" stargazers" " watchers" " forks" ) || local graph=(" followers" " following" " people" )
405407 [ -z " $2 " ] || graph=(" $2 " )
406408
@@ -412,12 +414,19 @@ explore() {
412414 if [[ " $node " =~ .* \/ .* ]]; then
413415 nodes=$( curl_users " $node /$edge ?page=$page " ) # repo
414416 else
415- nodes=$( curl_users " orgs/$node /$edge ?page=$page " ) # org
416-
417- if [ -z " $nodes " ]; then
418- nodes=$( curl_users " $node ?tab=$edge &page=$page " ) # user
419- curl_orgs " $1 "
420- fi
417+ if [ " $is_user " = false ]; then
418+ nodes=$( curl_users " orgs/$node /$edge ?page=$page " ) # org
419+ [ -n " $nodes " ] || is_user=true
420+ fi
421+
422+ if [ " $is_user " = true ]; then
423+ nodes=$( curl_users " $node ?tab=$edge &page=$page " ) # user
424+
425+ if [ " $got_orgs " = false ]; then
426+ curl_orgs " $node "
427+ got_orgs=true
428+ fi
429+ fi
421430 fi
422431
423432 grep -v " $( cut -d' /' -f1 <<< " $node" ) " <<< " $nodes"
@@ -444,62 +453,92 @@ ytox() {
444453}
445454
446455ytoxt () {
447- # ytox + trim if the json or xml is over 50MB, remove oldest versions
448- while [ -f " $1 " ] && [[ " $( ytox " $1 " ) " -ge 50000000 || " $( stat -c %s " $1 " ) " -ge 50000000 ]]; do
456+ # ytox + trim: if the json or xml is over 50MB, remove oldest versions
457+ local f=" $1 "
458+ local tmp
459+
460+ [ -f " $f " ] || return 1
461+
462+ tmp=$( mktemp " ${f} .XXXXXX" ) || return 1
463+ trap ' rm -f "$tmp"' RETURN
464+
465+ while [ -f " $f " ]; do
466+ local json_size
467+ local xml_size
468+
469+ json_size=$( stat -c %s " $f " 2> /dev/null || echo -1)
470+
471+ if [ " $json_size " -lt 50000000 ]; then
472+ # Only generate/check XML if JSON is already under limit.
473+ xml_size=$( ytox " $f " 2> /dev/null || echo -1)
474+ [ " $xml_size " -ge 50000000 ] || break
475+ fi
476+
449477 if jq -e '
450- if type == "array" then
451- any(.[]; (.version // []) | length > 0)
452- else
453- ( .version // []) | length > 0
454- end
455- ' " $1 " > /dev/null; then
478+ if type == "array" then
479+ any(.[]; (( .version // []) | type == "array") and ((.version // []) | length > 0) )
480+ else
481+ (( .version // []) | type == "array") and ((.version // []) | length > 0)
482+ end
483+ ' " $f " > /dev/null; then
456484 jq -c '
457- def trim_versions:
458- if (.version // []) | length > 0 then
459- .version |= (
460- sort_by(.id | (if type == "string" and test("^-?[0-9]+$") then tonumber else . end))
461- | del(.[0])
462- )
463- else
464- .
465- end;
466- if type == "array" then
467- (to_entries
468- | (max_by((.value.version // []) | length) // empty) as $max
469- | map(
470- if .key == $max.key and ((.value.version // []) | length > 0)
471- then (.value |= trim_versions)
472- else .
473- end
474- )
475- | map(.value))
476- else
477- trim_versions
478- end
479- ' " $1 " > " $1 " .tmp
480- else
481- jq -c '
482- if type == "array" then
483- (
484- def to_num:
485- if type == "number" then .
486- elif type == "string" then tonumber? // 0
487- else 0 end;
488- to_entries
489- | (min_by([ (.value.raw_downloads // 0 | to_num), (.value.date // "") ]) // null) as $target
490- | if $target == null then
491- map(.value)
492- else
493- [ .[] | select(.key != $target.key) | .value ]
494- end
495- )
496- else
497- .
498- end
499- ' " $1 " > " $1 " .tmp
485+ def id_to_num:
486+ if type == "number" then .
487+ elif type == "string" then tonumber? // 0
488+ else 0 end;
489+ def trim_versions:
490+ if ((.version // []) | type == "array") and ((.version // []) | length > 0) then
491+ ((.version
492+ | to_entries
493+ | min_by(.value.id | id_to_num)
494+ | .key) // empty) as $idx
495+ | if ($idx | tostring) == "" then .
496+ else .version |= del(.[ $idx ])
497+ end
498+ else
499+ .
500+ end;
501+ if type == "array" then
502+ (to_entries
503+ | (max_by((.value.version // []) | length) // empty) as $max
504+ | map(
505+ if .key == $max.key and (((.value.version // []) | type == "array") and ((.value.version // []) | length > 0))
506+ then (.value |= trim_versions)
507+ else .
508+ end
509+ )
510+ | map(.value))
511+ else
512+ trim_versions
513+ end
514+ ' " $f " > " $tmp "
515+ else
516+ jq -c '
517+ if type == "array" then
518+ (
519+ def to_num:
520+ if type == "number" then .
521+ elif type == "string" then tonumber? // 0
522+ else 0 end;
523+ to_entries
524+ | (min_by([ (.value.raw_downloads // 0 | to_num), (.value.date // "") ]) // null) as $target
525+ | if $target == null then
526+ map(.value)
527+ else
528+ [ .[] | select(.key != $target.key) | .value ]
529+ end
530+ )
531+ else
532+ .
533+ end
534+ ' " $f " > " $tmp "
500535 fi
501- mv " $1 " .tmp " $1 "
536+
537+ mv " $tmp " " $f "
502538 done
539+
540+ # Ensure the XML output corresponds to the final JSON.
541+ ytox " $f " > /dev/null 2>&1
503542}
504543
505544ytoy () {
0 commit comments