From e3270172b83afcb28b6527f4c8aa58c067f7143f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=BD=C3=A1dn=C3=ADk?= Date: Sun, 28 Jan 2024 14:36:13 +0200 Subject: [PATCH] Add `nupm search` for searching packages --- nupm/install.nu | 146 ++++++++++++----------------------------- nupm/mod.nu | 1 + nupm/search.nu | 12 ++++ nupm/utils/registry.nu | 79 ++++++++++++++++++++++ 4 files changed, 133 insertions(+), 105 deletions(-) create mode 100644 nupm/search.nu create mode 100644 nupm/utils/registry.nu diff --git a/nupm/install.nu b/nupm/install.nu index e1774f4..e6a3925 100644 --- a/nupm/install.nu +++ b/nupm/install.nu @@ -4,6 +4,7 @@ use utils/completions.nu complete-registries use utils/dirs.nu [ nupm-home-prompt cache-dir module-dir script-dir tmp-dir ] use utils/log.nu throw-error use utils/misc.nu check-cols +use utils/registry.nu search-package use utils/version.nu filter-by-version def open-package-file [dir: path] { @@ -149,110 +150,6 @@ def install-path [ } } -def fetch-package [ - package: string # Name of the package - --registry: string # Which registry to use - --version: any # Package version to install (string or null) -] { - let registries = if (not ($registry | is-empty)) and ($registry in $env.NUPM_REGISTRIES) { - # If $registry is a valid column in $env.NUPM_REGISTRIES, use that - { $registry : ($env.NUPM_REGISTRIES | get $registry) } - } else if (not ($registry | is-empty)) and ($registry | path exists) { - # If $registry is a path, use that - let reg_name = $registry | path parse | get stem - { $reg_name: $registry } - } else { - # Otherwise use $env.NUPM_REGISTRIES - $env.NUPM_REGISTRIES - } - - # Collect all registries matching the package and all matching packages - let regs = $registries - | items {|name, path| - print $path - - # Open registry (online or offline) - let registry = if ($path | path type) == file { - open $path - } else { - try { - let reg = http get $path - - if local in $reg { - throw-error ("Can't have local packages in online registry" - + $" '($path)'.") - } - - $reg - } catch { - throw-error $"Cannot open '($path)' as a file or URL." - } - } - - $registry | check-cols --missing-ok "registry" [ git local ] | ignore - - # Find all packages matching $package in the registry - let pkgs_local = $registry.local? - | default [] - | check-cols "local packages" [ name version path ] - | where name == $package - - let pkgs_git = $registry.git? - | default [] - | check-cols "git packages" [ name version url revision path ] - | where name == $package - - # Detect duplicate versions - let all_versions = $pkgs_local.version? - | default [] - | append ($pkgs_git.version? | default []) - - if ($all_versions | uniq | length) != ($all_versions | length) { - throw-error ($'Duplicate versions of package ($package) detected' - + $' in registry ($name).') - } - - let pkgs = $pkgs_local - | insert type local - | insert url null - | insert revision null - | append ($pkgs_git | insert type git) - - { - name: $name - path: $path - pkgs: $pkgs - } - } - | compact - - if ($regs | is-empty) { - throw-error 'No registries found' - } else if ($regs | length) > 1 { - # TODO: Here could be interactive prompt - throw-error 'Multiple registries contain the same package' - } - - # Now, only one registry contains the package - let reg = $regs | first - let pkgs = $reg.pkgs | filter-by-version $version - - let pkg = try { - $pkgs | last - } catch { - throw-error $'No package matching version `($version)`' - } - - print $pkg - - if $pkg.type == 'git' { - download-pkg $pkg - } else { - # local package path is relative to the registry file (absolute paths - # are discouraged but work) - $reg.path | path dirname | path join $pkg.path - } -} # Downloads a package and returns its downloaded path def download-pkg [ @@ -310,6 +207,45 @@ def download-pkg [ $pkg_dir } +# Fetch a package from a registry +def fetch-package [ + package: string # Name of the package + --registry: string # Which registry to use + --version: string # Package version to install (string or null) +]: nothing -> path { + let regs = (search-package $package + --registry $registry + --version $version + --exact-match) + + if ($regs | is-empty) { + throw-error 'No registries found' + } else if ($regs | length) > 1 { + # TODO: Here could be interactive prompt + throw-error 'Multiple registries contain the same package' + } + + # Now, only one registry contains the package + let reg = $regs | first + let pkgs = $reg.pkgs | filter-by-version $version + + let pkg = try { + $pkgs | last + } catch { + throw-error $'No package matching version `($version)`' + } + + print $pkg + + if $pkg.type == 'git' { + download-pkg $pkg + } else { + # local package path is relative to the registry file (absolute paths + # are discouraged but work) + $reg.path | path dirname | path join $pkg.path + } +} + # Install a nupm package # # Installation consists of two parts: @@ -328,7 +264,7 @@ export def main [ return } - let pkg = if not $path { + let pkg: path = if not $path { fetch-package $package --registry $registry --version $pkg_version } else { if $pkg_version != null { diff --git a/nupm/mod.nu b/nupm/mod.nu index accc715..26cbf48 100644 --- a/nupm/mod.nu +++ b/nupm/mod.nu @@ -4,6 +4,7 @@ use utils/dirs.nu [ export module install.nu export module test.nu +export module search.nu export-env { # Ensure that $env.NUPM_HOME is always set when running nupm. Any missing diff --git a/nupm/search.nu b/nupm/search.nu new file mode 100644 index 0000000..4695826 --- /dev/null +++ b/nupm/search.nu @@ -0,0 +1,12 @@ +use utils/completions.nu complete-registries +use utils/registry.nu search-package + +# Search for a package +export def main [ + package # Name, path, or link to the package + --registry: string@complete-registries # Which registry to use (either a name + # in $env.NUPM_REGISTRIES or a path) + --pkg-version(-v): string # Package version to install +]: nothing -> table { + search-package $package --registry $registry --version $pkg_version +} diff --git a/nupm/utils/registry.nu b/nupm/utils/registry.nu new file mode 100644 index 0000000..15a95ee --- /dev/null +++ b/nupm/utils/registry.nu @@ -0,0 +1,79 @@ +# Utilities related to nupm registries + +# Search for a package in a registry +export def search-package [ + package: string # Name of the package + --registry: string # Which registry to use + --version: any # Package version to install (string or null) + --exact-match # Searched package name must match exactly +] -> table { + let registries = if (not ($registry | is-empty)) and ($registry in $env.NUPM_REGISTRIES) { + # If $registry is a valid column in $env.NUPM_REGISTRIES, use that + { $registry : ($env.NUPM_REGISTRIES | get $registry) } + } else if (not ($registry | is-empty)) and ($registry | path exists) { + # If $registry is a path, use that + let reg_name = $registry | path parse | get stem + { $reg_name: $registry } + } else { + # Otherwise use $env.NUPM_REGISTRIES + $env.NUPM_REGISTRIES + } + + let name_matcher: closure = if $exact_match { + {|row| $row.name == $package } + } else { + {|row| $package in $row.name } + } + + # Collect all registries matching the package and all matching packages + let regs = $registries + | items {|name, path| + print $path + + # Open registry (online or offline) + let registry = if ($path | path type) == file { + open $path + } else { + try { + let reg = http get $path + + if local in $reg { + throw-error ("Can't have local packages in online registry" + + $" '($path)'.") + } + + $reg + } catch { + throw-error $"Cannot open '($path)' as a file or URL." + } + } + + $registry | check-cols --missing-ok "registry" [ git local ] | ignore + + # Find all packages matching $package in the registry + let pkgs_local = $registry.local? + | default [] + | check-cols "local packages" [ name version path ] + | filter $name_matcher + + let pkgs_git = $registry.git? + | default [] + | check-cols "git packages" [ name version url revision path ] + | filter $name_matcher + + let pkgs = $pkgs_local + | insert type local + | insert url null + | insert revision null + | append ($pkgs_git | insert type git) + + { + name: $name + path: $path + pkgs: $pkgs + } + } + | compact + + $regs | where not ($it.pkgs | is-empty) +}