1
0
mirror of https://github.com/hustcer/deepseek-review.git synced 2026-05-13 05:16:05 +08:00
Files
deepseek-review/nu/common.nu
Justin Ma 0c001b0ee2 refactor: A better from env parser (#194)
* refactor: A better `from env` parser

* refactor: A better `from env` parser
2025-11-29 22:45:55 +08:00

218 lines
7.7 KiB
Plaintext

#!/usr/bin/env nu
# Author: hustcer
# Created: 2025/02/12 19:05:20
# Description: Common helpers for DeepSeek-Review
#
use std-rfc/kv ['kv set', 'kv get']
# Commonly used exit codes
export const ECODE = {
SUCCESS: 0,
OUTDATED: 1,
AUTH_FAILED: 2,
SERVER_ERROR: 3,
MISSING_BINARY: 5,
INVALID_PARAMETER: 6,
MISSING_DEPENDENCY: 7,
CONDITION_NOT_SATISFIED: 8,
}
export const GITHUB_API_BASE = 'https://api.github.com'
# If current host is Windows
export def windows? [] {
# Windows / Darwin
(sys host | get name) == 'Windows'
}
# If current host is macOS
export def mac? [] {
# Windows / Darwin
(sys host | get name) == 'Darwin'
}
# Compare two version number, return `1` if first one is higher than second one,
# Return `0` if they are equal, otherwise return `-1`
# Format: Expects semantic version strings (major.minor.patch)
# - Optional 'v' prefix
# - Pre-release suffixes (-beta, -rc, etc.) are ignored
# - Missing segments default to 0
export def compare-ver [v1: string, v2: string] {
# Parse the version number: remove pre-release and build information,
# only take the main version part, and convert it to a list of numbers
def parse-ver [v: string] {
$v | str downcase | str trim -c v | str trim
| split row - | first | split row . | each { into int }
}
let a = parse-ver $v1
let b = parse-ver $v2
# Compare the major, minor, and patch parts; fill in the missing parts with 0
# If you want to compare more parts use the following code:
# for i in 0..([2 ($a | length) ($b | length)] | math max)
for i in 0..2 {
let x = $a | get -o $i | default 0
let y = $b | get -o $i | default 0
if $x > $y { return 1 }
if $x < $y { return (-1) }
}
0
}
# Check nushell version and notify user to upgrade it if outdated
# Check version once daily and cache the result
export def check-nushell [--debug] {
const _DATE_FMT = '%Y.%m.%d'
const V_KEY = 'NU-VERSION-CHECK@DEEPSEEK-REVIEW'
let version_cached = kv get -u $V_KEY
let today = date now | format date $_DATE_FMT
let check = if ($version_cached | is-empty) or $version_cached.date? != $today {
let $check = try { ({ ...(version check), date: $today }) } catch { ({ current: true }) }
if $debug { print 'Checking for the latest Nushell version...'; $check | print }
kv set -u $V_KEY $check --return value
} else {
$version_cached
}
# If the current version is the latest after user upgrade, return
if $check.current or (compare-ver $check.latest (version).version) == 0 { return }
print $'(char nl) (ansi yr) WARNING: (ansi reset) Your Nushell is (ansi r)OUTDATED(ansi reset)'
print $' ------------> Please upgrade Nushell to the latest version: (ansi g)($check.latest)(ansi reset) <------------'
print -n (char nl)
}
# Converts a .env file into a record
# May be used like this: open .env | load-env
# Works with quoted and unquoted .env files
export def "from env" []: string -> record {
let input = $in
# Process escape sequences in double-quoted values using str replace chain
# Use NUL char as placeholder to avoid replacement conflicts
let process_escapes = {|content: string|
$content
| str replace -a '\\' (char nul) # Placeholder for \\ to avoid conflicts
| str replace -a '\n' (char nl)
| str replace -a '\r' (char cr)
| str replace -a '\t' (char tab)
| str replace -a '\"' '"'
| str replace -a (char nul) '\' # Restore \\ to single \
}
# Parse double-quoted value with escape sequence support
let parse_double_quoted = {|val: string|
let matched = ($val | parse -r '^"(?P<content>(?:[^"\\]|\\.)*)"')
if ($matched | is-empty) { $val | str trim -c '"' } else { do $process_escapes $matched.0.content }
}
# Parse single-quoted value (no escape processing)
let parse_single_quoted = {|val: string|
let matched = ($val | parse -r "^'(?P<content>[^']*)'")
if ($matched | is-empty) { $val | str trim -c "'" } else { $matched.0.content }
}
# Parse unquoted value: handle escaped hash (\#) and strip inline comments
let parse_unquoted = {|val: string|
$val
| str replace -a '\#' (char nul) # Placeholder for \#
| split row '#' # Split by comment delimiter
| first # Take content before first #
| str replace -a (char nul) '#' # Restore \# to #
| str trim
}
# Parse value based on its format
let parse_value = {|val: string|
match $val {
$v if ($v | str starts-with '"') => { do $parse_double_quoted $v }
$v if ($v | str starts-with "'") => { do $parse_single_quoted $v }
_ => { do $parse_unquoted $val }
}
}
let parsed = $input | lines
| str trim
| compact -e
| where {|line| not ($line | str starts-with '#') }
| parse "{key}={value}"
| update key {|row| $row.key | str trim | str replace -r '^export\s+' '' }
| update value {|row| do $parse_value ($row.value | str trim) }
if ($parsed | is-empty) { {} } else { $parsed | transpose -r -d -l }
}
# Compact the record by removing empty columns
export def compact-record []: record -> record {
let record = $in
let empties = $record | columns | where {|it| $record | get $it | is-empty }
$record | reject ...$empties
}
# Check if some command available in current shell
export def is-installed [ app: string ] {
(which $app | length) > 0
}
export def hr-line [
width?: int = 90,
--blank-line(-b),
--with-arrow(-a),
--color(-c): string = 'g',
] {
# Create a line by repeating the unit with specified times
def build-line [
times: int,
unit: string = '-',
] {
0..<$times | reduce -f '' { |i, acc| $unit + $acc }
}
print $'(ansi $color)(build-line $width)(if $with_arrow {'>'})(ansi reset)'
if $blank_line { char nl | print -n }
}
# Check if git was installed and if current directory is a git repo
export def git-check [
dest: string, # The dest dir to check
--check-repo: int, # Check if current directory is a git repo
] {
cd $dest
if not (is-installed git) {
print $'You should (ansi r)INSTALL git(ansi reset) first to run this command, bye...'
exit $ECODE.MISSING_BINARY
}
# If we don't need repo check just quit now
if ($check_repo != 0) {
if not (is-repo) {
print $'Current directory is (ansi r)NOT(ansi reset) a git repo, bye...(char nl)'
exit $ECODE.CONDITION_NOT_SATISFIED
}
}
true
}
# Check if current directory is a git repo
export def is-repo [] {
let checkRepo = try {
do -i { git rev-parse --is-inside-work-tree } | complete
} catch {
({ stdout: 'false' })
}
if ($checkRepo.stdout =~ 'true') { true } else { false }
}
# Check if a git repo has the specified ref: could be a branch or tag, etc.
export def has-ref [
ref: string # The git ref to check
] {
if not (is-repo) { return false }
# Brackets were required here, or error will occur
let parse = (do -i { git rev-parse --verify -q $ref } | complete)
if ($parse.stdout | is-empty) { false } else { true }
}
# Notify the user that the `CHAT_TOKEN` hasn't been configured
export const NO_TOKEN_TIP = (
"**Notice:** It looks like you're using [`hustcer/deepseek-review`](https://github.com/hustcer/deepseek-review), but the `CHAT_TOKEN` hasn't " +
"been configured in your repo's **Variables/Secrets**. Please ensure this token is set for proper functionality. For step-by-step guidance, refer " +
"to the **CHAT_TOKEN Config** section of [README](https://github.com/hustcer/deepseek-review/blob/main/README.md#code-review-with-github-action).")