Fix a bug introduced in #2996 that single line hash extraction is broken.
When `find_hash_in_textfile()` is called in `get_hash_for_app()`, `$null` is used as `$regex` value for default single line hash extraction and the default value (`'^([a-fA-F0-9]+)$'`) is overriden, which leads a error of "hash not found".
Some JSON file ([example](https://mranapi.azurewebsites.net/api/download)) is surrounded by brackets ("[", "]") and cannot be parsed using `[Newtonsoft.Json.Linq.JObject]::Parse()` in `json_path()`. Instead, they could be parsed by `[Newtonsoft.Json.Linq.JArray]::Parse()` and then be treated as normal, e.g., applies a filter (script) expression.
- Add `[Newtonsoft.Json.Linq.JArray]::Parse()` after `[Newtonsoft.Json.Linq.JObject]::Parse()` failed
- Some JArray are handled by `json_path_legacy()` when `json_path()` throw error before, and the JSONPath is illegal when parsed with `JArray::Parse()`. To keep compatibility, add try-catch in this situation and let `json_path_legacy()` handle them still.
- In the above situation, manifest maintainer should use double dots after `$`, i.e., use `$..NODE` instead of `$.NODE` since it is a JArray contained the JObject.
**Data matters, please review**
This is a rework of #2891#2890 and #2882 . This will also fix#2724 and fix#2900 , close#2779
**Introduction**
I add a function called `unlink_persist_data($dir)`, which recursively unlink all junction/hard link in the given directory. This affects some sub-commands which have interaction with junction/hard link:
- `scoop-install`: the persisting logic has been improved as follow:
1. if there are data in the `persist` folder, also in app(`source`) folder, rename that one located in app folder (e.g. app's default setting files) with a `original` suffix, then create link from `persist` to app
2. if there are data in the `persist` folder, but no in app(`source`) folder, just create link from `persist` to app
3. if there is no data in the `persist` folder (e.g. fresh install), but there are data in app(`source`) folder (e.g. app's default setting files), we will just use that default setting files as the first-time persisting. So move that files from app folder to `persist` folder, then create link from `persist` to app
4. But what if if there is neither data in the `persist` folder (e.g. fresh install), nor in the app(`source`) folder (e.g. setting files will be created after first startup, like `Everthing.db`). We need to create empty persisting target in the `persist` folder. But by default we can't know if a persisting target is a file or a directory (e.g. `conf.d`). So we create a directory by default, and to avoid this, manifest maintainers should use `pre_install` to manually create the source file before persisting.
- `scoop-reset`: `reset` command uses the logic of `install`, but there is a problem: before re-persisting data, there have been `junction/hard link` in the app(`source`) folder. It will throw an exception of file exists #2724 . To fix this, we should unlink all old link before re-persisting, using `unlink_persist_data`.
- `scoop-uninstall`: `Remove-Item` can not remove `NTFS junction`, we need to unlink all persistting data, before uninstalling/deleting an app, but keeping persisting data.
- `scoop-cleanup`: like `uninstall`, `Remove-Item` can not remove `NTFS junction`, we need to unlink all persistting data, before deleting old versions of an app. Before PR #2882 , it use `fsutil.exe` to unlink junction, which is not friendly to restricted users (#2832 and #2881 ).
Beyond the logic improvement, there is a new feature now: it supports sub-folder data persisting, like:
```json
{
"homepage": "https://scoop.sh",
"description": "A dummy manifest for scoop tests.",
"license": "Freeware",
"version": "1.1.0",
"url": "https://get.scoop.sh",
"pre_install": [
"if (!(test-path \"$dir\\dummy.txt\")) { new-item -force \"$dir\\dummy.txt\" -itemtype file | out-null }",
"if (!(test-path \"$dir\\dummydir\")) { new-item \"$dir\\dummydir\" -itemtype directory | out-null }",
"if (!(test-path \"$dir\\subdir\")) { new-item \"$dir\\subdir\" -itemtype directory | out-null }",
"if (!(test-path \"$dir\\subdir\\subdummydir\")) { new-item \"$dir\\subdir\\subdummydir\" -itemtype directory | out-null }",
"if (!(test-path \"$dir\\subdir\\subdummy.txt\")) { new-item -force \"$dir\\subdir\\subdummy.txt\" -itemtype file | out-null }",
],
"persist": [
"dummy.txt",
"dummydir",
"subdir\\subdummydir",
"subdir\\subdummy.txt"
]
}
```
So no need to strip directories of source for target anymore.
To participate in the code review and tests, go visit https://github.com/h404bi/scoop-persist-test for test cases.
- Closes#2531
Actual behaviour is kept and nothing is broken.
If external bucket contains `bucket` folder it's used for finding manifests.
How to test:
1. Create folder `TestBucket` in `$env:SCOOP\buckets`
1. Create manifest `CosiTest.json` with hello manifest # Or some other name which definetely cannot exists❗
1. execute `.\bin\scoop.ps1 install CosiTest` within this branch
1. Installing done
1. `.\bin\scoop.ps1 uninstall CosiTest`
1. Create folder `bucket` in `TestBucket` directory and copy CosiTest.json as `bucket\CosiTestBucket.json`
1. `.\bin\scoop.ps1 install CosiTest`
1. Installation will failed with `Couldn't find manifest for 'CosiTest'.`
1. `.\bin\scoop.ps1 install CosiTestBucket`
1. Installation Done
1. `.\bin\scoop.ps1 uninstall CosiTestBucket`
1. Unnstallation Done
* Workaround Microsofts syntactic PSModulePath
The default user PSModulePath is "$env:USERPROFILE\Documents\WindowsPowerShell\Modules". I the user env variable PSModulePath actually exists the default path is omitted - so we need to explicitly add it.
Fixes#2740.
Adding .exe suffix to cmd is needed in WSL.
Removing MSYS' slash-escaping from //C is needed in WSL, Cygwin, or anywhere outside MSYS (or Git Bash). Doesn't break MSYS after .exe suffix is added.
See also #1949, #1951
Due to my prior PR #2562 which changed the content of .ps1 shims, the code that attempts to warn about shims being overwritten no longer detects app name correctly. This is to correct that.
PowerShell on Windows comes with both 2.0 and 3.0+ installed. This is a feature inherited from .NET -- PowerShell 2.0 is based on .NET 2.0 which is installed side-by-side with .NET 3.0-4.7. It is possible to run PowerShell 2.0 by invoking the command powershell.exe -Version 2.0 -NoProfile.
This is a fairly useful feature for PowerShell scripters, as one can use PowerShell 2.0 to check for the basic compatibility of scripts without having to run a VM. As such, a user can have scoop apps installed via PowerShell 3.0+, and then launch PowerShell 2.0 for casual testing.
Currently the scoop shims are broken in PowerShell 2.0, as they use $PSScriptRoot. In addition, since PowerShell picks up {command}.ps1 before {command}.exe when looking for {command}, this makes using scoop-installed app difficult in PowerShell 2.0.
While Scoop command itself doesn't support PowerShell 2.0, and there is no point in doing so, it is fairly easy to make the shims support PowerShell 2.0, so this is what this patch does.