(ref string)
| 121 | } |
| 122 | |
| 123 | func parseURLRef(ref string) (parsed Ref, fragment string, err error) { |
| 124 | // A good way to test how Nix parses a flake reference is to run: |
| 125 | // |
| 126 | // nix eval --json --expr 'builtins.parseFlakeRef "ref"' | jq |
| 127 | refURL, err := url.Parse(ref) |
| 128 | if err != nil { |
| 129 | return Ref{}, "", redact.Errorf("parse flake reference as URL: %v", err) |
| 130 | } |
| 131 | |
| 132 | // ensure that the fragment is excluded from the parsed URL |
| 133 | // since those are not valid in flake references. |
| 134 | fragment = refURL.Fragment |
| 135 | refURL.Fragment = "" |
| 136 | |
| 137 | switch refURL.Scheme { |
| 138 | case "", "flake": |
| 139 | // [flake:]<flake-id>(/<rev-or-ref>(/rev)?)? |
| 140 | |
| 141 | parsed.Type = TypeIndirect |
| 142 | split, err := splitPathOrOpaque(refURL, -1) |
| 143 | if err != nil { |
| 144 | return Ref{}, "", redact.Errorf("parse flake reference URL path: %v", err) |
| 145 | } |
| 146 | parsed.ID = split[0] |
| 147 | if len(split) > 1 { |
| 148 | if isGitHash(split[1]) { |
| 149 | parsed.Rev = split[1] |
| 150 | } else { |
| 151 | parsed.Ref = split[1] |
| 152 | } |
| 153 | } |
| 154 | if len(split) > 2 && parsed.Rev == "" { |
| 155 | parsed.Rev = split[2] |
| 156 | } |
| 157 | case "path": |
| 158 | // [path:]<path>(\?<params)? |
| 159 | |
| 160 | parsed.Type = TypePath |
| 161 | if refURL.Path == "" { |
| 162 | parsed.Path, err = url.PathUnescape(refURL.Opaque) |
| 163 | if err != nil { |
| 164 | return Ref{}, "", err |
| 165 | } |
| 166 | } else { |
| 167 | parsed.Path = refURL.Path |
| 168 | } |
| 169 | |
| 170 | query := refURL.Query() |
| 171 | parsed.NARHash = query.Get("narHash") |
| 172 | parsed.LastModified, err = atoiOmitZero(query.Get("lastModified")) |
| 173 | if err != nil { |
| 174 | return Ref{}, "", redact.Errorf("parse flake reference URL query parameter: lastModified=%s: %v", redact.Safe(parsed.LastModified), redact.Safe(err)) |
| 175 | } |
| 176 | case "http", "https", "file": |
| 177 | if isArchive(refURL.Path) { |
| 178 | parsed.Type = TypeTarball |
| 179 | } else { |
| 180 | parsed.Type = TypeFile |
no test coverage detected