mirror of
https://github.com/unisonweb/unison.git
synced 2024-09-11 02:25:39 +03:00
⅄ trunk → topic/merge4
This commit is contained in:
commit
e18bbd40f9
3
.github/CODEOWNERS
vendored
Normal file
3
.github/CODEOWNERS
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# Require approval from ucm team when editing repository workflows
|
||||
# This helps prevent users from sneaking in malicious changes to CI workflows.
|
||||
/.github/ @unisonweb/ucm
|
20
.github/workflows/check-contributor.yaml
vendored
Normal file
20
.github/workflows/check-contributor.yaml
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
name: Contributor signed CONTRIBUTORS.markdown
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
check-contributor:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: CONTRIBUTORS.markdown
|
||||
- name: Look for @${{github.event.pull_request.user.login}} in CONTRIBUTORS.markdown
|
||||
shell: bash
|
||||
run: |
|
||||
echo "If this step fails, make sure you've added yourself to CONTRIBUTORS.markdown"
|
||||
echo "to acknowledge Unison's MIT license."
|
||||
|
||||
egrep '\* .* \(@${{github.event.pull_request.user.login}}\)' \
|
||||
CONTRIBUTORS.markdown
|
20
.github/workflows/ci-build-jit-binary.yaml
vendored
20
.github/workflows/ci-build-jit-binary.yaml
vendored
@ -54,13 +54,13 @@ jobs:
|
||||
with:
|
||||
name: jit-source
|
||||
path: ${{ env.jit_src }}
|
||||
|
||||
|
||||
- name: cache/restore jit binaries
|
||||
id: cache-jit-binaries
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: ${{ env.jit_dist }}
|
||||
key: jit-dist_${{matrix.os}}.racket_${{env.racket_version}}.jit-src_${{hashFiles(format('{0}/**.rkt',env.jit_src),format('{0}/**.ss',env.jit_src))}}.yaml_${{hashFiles('**/ci-build-jit-binary.yaml')}}
|
||||
key: jit-dist_${{matrix.os}}.racket_${{env.racket_version}}.jit-src_${{hashFiles(format('{0}/**/*.rkt',env.jit_src),format('{0}/**/*.ss',env.jit_src))}}.yaml_${{hashFiles('**/ci-build-jit-binary.yaml')}}
|
||||
|
||||
- name: cache racket dependencies
|
||||
if: steps.cache-jit-binaries.outputs.cache-hit != 'true'
|
||||
@ -81,8 +81,18 @@ jobs:
|
||||
if: runner.os == 'macOS' && steps.cache-jit-binaries.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
brew install libb2
|
||||
racket_lib_dir="$(dirname "$(readlink -f "$(which raco)")")/../lib"
|
||||
ln -s "$(brew --prefix)"/lib/libb2.*.dylib "$racket_lib_dir/"
|
||||
brew_lib_dir=$(brew --prefix)/lib
|
||||
racket_lib_dir=$(dirname $(dirname $(readlink -f $(which raco))))/lib
|
||||
|
||||
# link libb2 if not already present/cached
|
||||
for dll in $brew_lib_dir/libb2.*.dylib; do
|
||||
file=$(basename "$dll")
|
||||
if [ ! -e "$racket_lib_dir/$file" ]; then
|
||||
ln -s "$brew_lib_dir/$file" "$racket_lib_dir/$file"
|
||||
else
|
||||
echo "$racket_lib_dir/$file" already exists.
|
||||
fi
|
||||
done
|
||||
|
||||
- name: build jit binary
|
||||
if: steps.cache-jit-binaries.outputs.cache-hit != 'true'
|
||||
@ -104,7 +114,7 @@ jobs:
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: ${{ env.jit_dist }}
|
||||
key: jit-dist_${{matrix.os}}.racket_${{env.racket_version}}.jit-src_${{hashFiles(format('{0}/**.rkt',env.jit_src),format('{0}/**.ss',env.jit_src))}}.yaml_${{hashFiles('**/ci-build-jit-binary.yaml')}}
|
||||
key: jit-dist_${{matrix.os}}.racket_${{env.racket_version}}.jit-src_${{hashFiles(format('{0}/**/*.rkt',env.jit_src),format('{0}/**/*.ss',env.jit_src))}}.yaml_${{hashFiles('**/ci-build-jit-binary.yaml')}}
|
||||
|
||||
- name: save jit binary
|
||||
uses: actions/upload-artifact@v4
|
||||
|
2
.github/workflows/ci.md
vendored
2
.github/workflows/ci.md
vendored
@ -9,7 +9,7 @@ At a high level, the CI process is:
|
||||
Some version numbers that are used during CI:
|
||||
- `ormolu_version: "0.5.0.1"`
|
||||
- `racket_version: "8.7"`
|
||||
- `jit_version: "@unison/internal/releases/0.0.15"`
|
||||
- `jit_version: "@unison/internal/releases/0.0.16"`
|
||||
|
||||
Some cached directories:
|
||||
- `ucm_local_bin` a temp path for caching a built `ucm`
|
||||
|
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@ -20,7 +20,7 @@ on:
|
||||
env:
|
||||
ormolu_version: 0.5.2.0
|
||||
ucm_local_bin: ucm-local-bin
|
||||
jit_version: "@unison/internal/releases/0.0.15"
|
||||
jit_version: "@unison/internal/releases/0.0.16"
|
||||
jit_src_scheme: unison-jit-src/scheme-libs/racket
|
||||
jit_dist: unison-jit-dist
|
||||
jit_generator_os: ubuntu-20.04
|
||||
|
@ -82,3 +82,7 @@ The format for this list: name, GitHub handle
|
||||
* Kyle Goetz (@kylegoetz)
|
||||
* Ethan Morgan (@sixfourtwelve)
|
||||
* Johan Winther (@JohanWinther)
|
||||
* Greg Pfeil (@sellout)
|
||||
* Upendra Upadhyay (@upendra1997)
|
||||
* Dan Doel (@dolio)
|
||||
* Eric Torreborre (@etorreborre)
|
||||
|
@ -15,7 +15,7 @@ be listed here, please [file a ticket](https://github.com/unisonweb/unison/issue
|
||||
|
||||
This file was generated using [unisonweb/credits-generator](http://github.com/unisonweb/credits-generator).
|
||||
|
||||
### Listing
|
||||
### Listing
|
||||
These are listed in alphabetical order.
|
||||
|
||||
| Package name | License |
|
||||
@ -109,6 +109,7 @@ These are listed in alphabetical order.
|
||||
| [network-bsd-2.8.1.0](https://hackage.haskell.org/package/network-bsd-2.8.1.0) | [BSD3](https://hackage.haskell.org/package/network-bsd-2.8.1.0/src/LICENSE) |
|
||||
| [network-info-0.2.0.10](https://hackage.haskell.org/package/network-info-0.2.0.10) | [BSD3](https://hackage.haskell.org/package/network-info-0.2.0.10/src/LICENSE) |
|
||||
| [network-simple-0.4.5](https://hackage.haskell.org/package/network-simple-0.4.5) | [BSD3](https://hackage.haskell.org/package/network-simple-0.4.5/src/LICENSE) |
|
||||
| [network-udp-0.0.0](https://hackage.haskell.org/package/network-udp-0.0.0) | [BSD3](https://hackage.haskell.org/package/network-udp-0.0.0/src/LICENSE) |
|
||||
| [nonempty-containers-0.3.3.0](https://hackage.haskell.org/package/nonempty-containers-0.3.3.0) | [BSD3](https://hackage.haskell.org/package/nonempty-containers-0.3.3.0/src/LICENSE) |
|
||||
| [nonempty-vector-0.2.0.2](https://hackage.haskell.org/package/nonempty-vector-0.2.0.2) | [BSD3](https://hackage.haskell.org/package/nonempty-vector-0.2.0.2/src/LICENSE) |
|
||||
| [parallel-3.2.2.0](https://hackage.haskell.org/package/parallel-3.2.2.0) | [BSD3](https://hackage.haskell.org/package/parallel-3.2.2.0/src/LICENSE) |
|
||||
|
@ -42,7 +42,7 @@ Some tests are executables instead:
|
||||
|
||||
* `stack exec transcripts` runs the transcripts-related integration tests, found in `unison-src/transcripts`. You can add more tests to this directory.
|
||||
* `stack exec transcripts -- prefix-of-filename` runs only transcript tests with a matching filename prefix.
|
||||
* `stack exec integration-tests` runs the additional integration tests for cli. These tests are not triggered by `tests` or `trancscripts`.
|
||||
* `stack exec integration-tests` runs the additional integration tests for cli. These tests are not triggered by `tests` or `transcripts`.
|
||||
* `stack exec unison -- transcript unison-src/transcripts-round-trip/main.md` runs the pretty-printing round trip tests
|
||||
* `stack exec unison -- transcript unison-src/transcripts-manual/benchmarks.md` runs the benchmark suite. Output goes in unison-src/transcripts-manual/benchmarks/output.txt.
|
||||
|
||||
|
@ -4,9 +4,12 @@
|
||||
|
||||
* [Overview](#overview)
|
||||
* [Installation and setup](#installation-and-setup)
|
||||
* [Settings](#settings)
|
||||
* [NeoVim](#neovim)
|
||||
* [VSCode](#vscode)
|
||||
* [Helix Editor](#helix-editor)
|
||||
* [Emacs](#emacs)
|
||||
* [other editors](#other-editors)
|
||||
* [Configuration](#configuration)
|
||||
|
||||
## Overview
|
||||
|
||||
@ -31,7 +34,7 @@ Note for Windows users: Due to an outstanding issue with GHC's IO manager on Win
|
||||
Enabling the LSP on windows can cause UCM to hang on exit and may require the process to be killed by the operating system or via Ctrl-C.
|
||||
Note that this doesn't pose any risk of codebase corruption or cause any known issues, it's simply an annoyance.
|
||||
|
||||
If you accept this annoyance, you can enable the LSP server on Windows by exporting the `UNISON_LSP_ENABLED=true` environment variable.
|
||||
If you accept this annoyance, you can enable the LSP server on Windows by exporting the `UNISON_LSP_ENABLED=true` environment variable.
|
||||
|
||||
You can set this persistently in powershell using:
|
||||
|
||||
@ -41,17 +44,6 @@ You can set this persistently in powershell using:
|
||||
|
||||
See [this issue](https://github.com/unisonweb/unison/issues/3487) for more details.
|
||||
|
||||
### Settings
|
||||
|
||||
Supported settings and their defaults. See information for your language server client about where to provide these.
|
||||
|
||||
```json
|
||||
{
|
||||
// A suggestion for the formatter about how wide (in columns) to print definitions.
|
||||
"formattingWidth": 80
|
||||
}
|
||||
```
|
||||
|
||||
### NeoVim
|
||||
|
||||
Before configuring the LSP, install the Vim plugin for filetype detection and syntax highlighting.
|
||||
@ -193,6 +185,18 @@ language-servers = [ "ucm" ]
|
||||
|
||||
or follow the instructions for Unison in "[How to install the default language servers](https://github.com/helix-editor/helix/wiki/How-to-install-the-default-language-servers#unison)" wiki page.
|
||||
|
||||
### Emacs
|
||||
|
||||
In Emacs 29 (or earlier, if you install the [Eglot](https://elpa.gnu.org/packages/eglot.html) package), add the following to your init file:
|
||||
|
||||
```elisp
|
||||
(push '((unison-ts-mode unisonlang-mode) "127.0.0.1" 5757)
|
||||
eglot-server-programs)
|
||||
```
|
||||
|
||||
This requires having either [unison-ts-mode](https://github.com/fmguerreiro/unison-ts-mode) or [unisonlang-mode](https://melpa.org/#/unisonlang-mode) installed. unison-ts-mode is newer, supported, and more complete, but isn’t in [MELPA](https://melpa.org/) yet and requires a couple commands to set up [tree-sitter-unison](https://github.com/kylegoetz/tree-sitter-unison).
|
||||
|
||||
You can then use `M-x eglot` in a Unison scratch file buffer. You can also [configure Eglot to start automatically](https://www.gnu.org/software/emacs/manual/html_node/eglot/Starting-Eglot.html).
|
||||
|
||||
### Other Editors
|
||||
|
||||
@ -205,11 +209,14 @@ Note that some editors require passing the command and arguments as separate par
|
||||
|
||||
Supported settings and their defaults. See information for your language server client about where to provide these.
|
||||
|
||||
* `formattingWidth`: A suggestion for the formatter about how wide (in columns) to print definitions.
|
||||
* `maxCompletions`: The number of completions the server should collect and send based on a single query. Increasing this limit will provide more completion results, but at the cost of being slower to respond.
|
||||
|
||||
If explicitly set to `null` the server will return ALL completions available.
|
||||
|
||||
```json
|
||||
{
|
||||
// The number of completions the server should collect and send based on a single query.
|
||||
// Increasing this limit will provide more completion results, but at the cost of being slower to respond.
|
||||
// If explicitly set to `null` the server will return ALL completions available.
|
||||
"formattingWidth": 80,
|
||||
"maxCompletions": 100
|
||||
}
|
||||
```
|
||||
|
@ -173,7 +173,7 @@ defaultColors :: ST.Element r -> Maybe Color
|
||||
defaultColors = \case
|
||||
ST.NumericLiteral -> Nothing
|
||||
ST.TextLiteral -> Nothing
|
||||
ST.BytesLiteral -> Just HiBlack
|
||||
ST.BytesLiteral -> Just HiPurple
|
||||
ST.CharLiteral -> Nothing
|
||||
ST.BooleanLiteral -> Nothing
|
||||
ST.Blank -> Nothing
|
||||
@ -182,21 +182,21 @@ defaultColors = \case
|
||||
ST.TermReference _ -> Nothing
|
||||
ST.Op _ -> Nothing
|
||||
ST.Unit -> Nothing
|
||||
ST.AbilityBraces -> Just HiBlack
|
||||
ST.ControlKeyword -> Just Bold
|
||||
ST.LinkKeyword -> Just HiBlack
|
||||
ST.TypeOperator -> Just HiBlack
|
||||
ST.AbilityBraces -> Just HiPurple
|
||||
ST.ControlKeyword -> Just HiCyan
|
||||
ST.LinkKeyword -> Just HiPurple
|
||||
ST.TypeOperator -> Just HiPurple
|
||||
ST.BindingEquals -> Nothing
|
||||
ST.TypeAscriptionColon -> Just Blue
|
||||
ST.DataTypeKeyword -> Nothing
|
||||
ST.DataTypeParams -> Nothing
|
||||
ST.DataTypeModifier -> Nothing
|
||||
ST.UseKeyword -> Just HiBlack
|
||||
ST.UsePrefix -> Just HiBlack
|
||||
ST.UseSuffix -> Just HiBlack
|
||||
ST.HashQualifier _ -> Just HiBlack
|
||||
ST.UseKeyword -> Just HiPurple
|
||||
ST.UsePrefix -> Just HiPurple
|
||||
ST.UseSuffix -> Just HiPurple
|
||||
ST.HashQualifier _ -> Just HiPurple
|
||||
ST.DelayForceChar -> Just Yellow
|
||||
ST.DelimiterChar -> Nothing
|
||||
ST.Parenthesis -> Nothing
|
||||
ST.DocDelimiter -> Just Green
|
||||
ST.DocKeyword -> Just Bold
|
||||
ST.DocKeyword -> Just HiCyan
|
||||
|
@ -23,6 +23,8 @@ dependencies:
|
||||
- NanoID
|
||||
- aeson
|
||||
- ansi-terminal
|
||||
- asn1-encoding
|
||||
- asn1-types
|
||||
- async
|
||||
- atomic-primops
|
||||
- base
|
||||
@ -60,6 +62,7 @@ dependencies:
|
||||
- http-media
|
||||
- http-types
|
||||
- IntervalMap
|
||||
- iproute
|
||||
- lens
|
||||
- lucid
|
||||
- megaparsec
|
||||
@ -73,6 +76,7 @@ dependencies:
|
||||
- natural-transformation
|
||||
- network
|
||||
- network-simple
|
||||
- network-udp
|
||||
- network-uri
|
||||
- nonempty-containers
|
||||
- open-browser
|
||||
@ -158,6 +162,7 @@ tests:
|
||||
- easytest
|
||||
- filemanip
|
||||
- split
|
||||
- hex-text
|
||||
- unison-parser-typechecker
|
||||
when:
|
||||
- condition: false
|
||||
|
@ -246,7 +246,10 @@ builtinTypesSrc =
|
||||
B' "MutableArray" CT.Data,
|
||||
B' "ImmutableByteArray" CT.Data,
|
||||
B' "MutableByteArray" CT.Data,
|
||||
B' "Char.Class" CT.Data
|
||||
B' "Char.Class" CT.Data,
|
||||
B' "UDPSocket" CT.Data,
|
||||
B' "ListenSocket" CT.Data,
|
||||
B' "ClientSockAddr" CT.Data
|
||||
]
|
||||
|
||||
-- rename these to "builtin" later, when builtin means intrinsic as opposed to
|
||||
@ -772,6 +775,10 @@ cryptoBuiltins =
|
||||
[ B "crypto.Ed25519.sign.impl" $
|
||||
bytes --> bytes --> bytes --> eithert failure bytes,
|
||||
B "crypto.Ed25519.verify.impl" $
|
||||
bytes --> bytes --> bytes --> eithert failure boolean,
|
||||
B "crypto.Rsa.sign.impl" $
|
||||
bytes --> bytes --> eithert failure bytes,
|
||||
B "crypto.Rsa.verify.impl" $
|
||||
bytes --> bytes --> bytes --> eithert failure boolean
|
||||
]
|
||||
|
||||
@ -815,6 +822,17 @@ ioBuiltins =
|
||||
("IO.serverSocket.impl.v3", optionalt text --> text --> iof socket),
|
||||
("IO.listen.impl.v3", socket --> iof unit),
|
||||
("IO.clientSocket.impl.v3", text --> text --> iof socket),
|
||||
("IO.UDP.clientSocket.impl.v1", text --> text --> iof udpSocket),
|
||||
("IO.UDP.ClientSockAddr.toText.v1", udpClientSockAddr --> text),
|
||||
("IO.UDP.UDPSocket.toText.impl.v1", udpSocket --> text),
|
||||
("IO.UDP.UDPSocket.close.impl.v1", udpSocket --> iof unit),
|
||||
("IO.UDP.serverSocket.impl.v1", text --> text --> iof udpListenSocket),
|
||||
("IO.UDP.ListenSocket.recvFrom.impl.v1", udpListenSocket --> iof (tuple [bytes, udpClientSockAddr])),
|
||||
("IO.UDP.ListenSocket.sendTo.impl.v1", udpListenSocket --> bytes --> udpClientSockAddr --> iof unit),
|
||||
("IO.UDP.ListenSocket.toText.impl.v1", udpListenSocket --> text),
|
||||
("IO.UDP.ListenSocket.close.impl.v1", udpListenSocket --> iof unit),
|
||||
("IO.UDP.UDPSocket.recv.impl.v1", udpSocket --> iof bytes),
|
||||
("IO.UDP.UDPSocket.send.impl.v1", udpSocket --> bytes --> iof unit),
|
||||
("IO.closeSocket.impl.v3", socket --> iof unit),
|
||||
("IO.socketPort.impl.v3", socket --> iof nat),
|
||||
("IO.socketAccept.impl.v3", socket --> iof socket),
|
||||
@ -1055,6 +1073,12 @@ handle = Type.fileHandle ()
|
||||
phandle = Type.processHandle ()
|
||||
unit = DD.unitType ()
|
||||
|
||||
|
||||
udpSocket, udpListenSocket, udpClientSockAddr :: Type
|
||||
udpSocket = Type.udpSocket ()
|
||||
udpListenSocket = Type.udpListenSocket ()
|
||||
udpClientSockAddr = Type.udpClientSockAddr ()
|
||||
|
||||
tls, tlsClientConfig, tlsServerConfig, tlsSignedCert, tlsPrivateKey, tlsVersion, tlsCipher :: Type
|
||||
tls = Type.ref () Type.tlsRef
|
||||
tlsClientConfig = Type.ref () Type.tlsClientConfigRef
|
||||
|
@ -356,6 +356,9 @@ builtinConstraintTree =
|
||||
flip Type.ref Type.filePathRef,
|
||||
Type.threadId,
|
||||
Type.socket,
|
||||
Type.udpSocket,
|
||||
Type.udpListenSocket,
|
||||
Type.udpClientSockAddr,
|
||||
Type.processHandle,
|
||||
Type.ibytearrayType,
|
||||
flip Type.ref Type.charClassRef,
|
||||
|
@ -39,6 +39,7 @@ import Crypto.Error (CryptoError (..), CryptoFailable (..))
|
||||
import Crypto.Hash qualified as Hash
|
||||
import Crypto.MAC.HMAC qualified as HMAC
|
||||
import Crypto.PubKey.Ed25519 qualified as Ed25519
|
||||
import Crypto.PubKey.RSA.PKCS15 qualified as RSA
|
||||
import Crypto.Random (getRandomBytes)
|
||||
import Data.Bits (shiftL, shiftR, (.|.))
|
||||
import Data.ByteArray qualified as BA
|
||||
@ -52,6 +53,7 @@ import Data.IORef as SYS
|
||||
readIORef,
|
||||
writeIORef,
|
||||
)
|
||||
import Data.IP (IP)
|
||||
import Data.Map qualified as Map
|
||||
import Data.PEM (PEM, pemContent, pemParseLBS)
|
||||
import Data.Set (insert)
|
||||
@ -81,9 +83,23 @@ import Network.Simple.TCP as SYS
|
||||
import Network.Socket as SYS
|
||||
( Socket,
|
||||
accept,
|
||||
socketPort,
|
||||
socketPort, PortNumber,
|
||||
)
|
||||
import Network.TLS as TLS
|
||||
import Network.UDP as UDP
|
||||
( UDPSocket (..),
|
||||
ClientSockAddr,
|
||||
ListenSocket,
|
||||
clientSocket,
|
||||
close,
|
||||
recv,
|
||||
recvFrom,
|
||||
send,
|
||||
sendTo,
|
||||
serverSocket,
|
||||
stop,
|
||||
)
|
||||
|
||||
import Network.TLS.Extra.Cipher as Cipher
|
||||
import System.Clock (Clock (..), getTime, nsec, sec)
|
||||
import System.Directory as SYS
|
||||
@ -138,6 +154,7 @@ import System.Process as SYS
|
||||
)
|
||||
import System.X509 qualified as X
|
||||
import Unison.ABT.Normalized hiding (TTm)
|
||||
import Unison.Runtime.Crypto.Rsa as Rsa
|
||||
import Unison.Builtin qualified as Ty (builtinTypes)
|
||||
import Unison.Builtin.Decls qualified as Ty
|
||||
import Unison.Prelude hiding (Text, some)
|
||||
@ -1544,6 +1561,22 @@ outIoFailBool stack1 stack2 stack3 extra fail result =
|
||||
)
|
||||
]
|
||||
|
||||
outIoFailTup :: forall v . (Var v) => v -> v -> v -> v -> v -> v -> v -> v -> ANormal v
|
||||
outIoFailTup stack1 stack2 stack3 stack4 stack5 extra fail result =
|
||||
TMatch result . MatchSum $
|
||||
mapFromList
|
||||
[ failureCase stack1 stack2 stack3 extra fail,
|
||||
( 1,
|
||||
([BX, BX],
|
||||
TAbss [stack1, stack2]
|
||||
. TLetD stack3 BX (TCon Ty.unitRef 0 [])
|
||||
. TLetD stack4 BX (TCon Ty.pairRef 0 [stack2, stack3])
|
||||
. TLetD stack5 BX (TCon Ty.pairRef 0 [stack1, stack4])
|
||||
$ right stack5
|
||||
)
|
||||
)
|
||||
]
|
||||
|
||||
outIoFailG ::
|
||||
(Var v) =>
|
||||
v ->
|
||||
@ -1767,6 +1800,14 @@ boxToEFBox =
|
||||
where
|
||||
(arg, result, stack1, stack2, stack3, any, fail) = fresh
|
||||
|
||||
-- a -> Either Failure (b, c)
|
||||
boxToEFTup :: ForeignOp
|
||||
boxToEFTup =
|
||||
inBx arg result $
|
||||
outIoFailTup stack1 stack2 stack3 stack4 stack5 extra fail result
|
||||
where
|
||||
(arg, result, stack1, stack2, stack3, stack4, stack5, extra, fail) = fresh
|
||||
|
||||
-- a -> Either Failure (Maybe b)
|
||||
boxToEFMBox :: ForeignOp
|
||||
boxToEFMBox =
|
||||
@ -1858,6 +1899,14 @@ boxBoxToEF0 =
|
||||
where
|
||||
(arg1, arg2, result, stack1, stack2, stack3, fail, unit) = fresh
|
||||
|
||||
-- a -> b -> c -> Either Failure ()
|
||||
boxBoxBoxToEF0 :: ForeignOp
|
||||
boxBoxBoxToEF0 =
|
||||
inBxBxBx arg1 arg2 arg3 result $
|
||||
outIoFailUnit stack1 stack2 stack3 fail unit result
|
||||
where
|
||||
(arg1, arg2, arg3, result, stack1, stack2, stack3, fail, unit) = fresh
|
||||
|
||||
-- a -> Either Failure Nat
|
||||
boxToEFNat :: ForeignOp
|
||||
boxToEFNat =
|
||||
@ -2290,8 +2339,64 @@ mkForeignTlsE f = mkForeign $ \a -> fmap flatten (tryIO2 (tryIO1 (f a)))
|
||||
flatten (Right (Right (Left e))) = Left e
|
||||
flatten (Right (Right (Right a))) = Right a
|
||||
|
||||
declareUdpForeigns :: FDecl Symbol ()
|
||||
declareUdpForeigns = do
|
||||
declareForeign Tracked "IO.UDP.clientSocket.impl.v1" boxBoxToEFBox
|
||||
. mkForeignIOF
|
||||
$ \(host :: Util.Text.Text, port :: Util.Text.Text) ->
|
||||
let hostStr = Util.Text.toString host
|
||||
portStr = Util.Text.toString port
|
||||
in UDP.clientSocket hostStr portStr True
|
||||
|
||||
declareForeign Tracked "IO.UDP.UDPSocket.recv.impl.v1" boxToEFBox
|
||||
. mkForeignIOF
|
||||
$ \(sock :: UDPSocket) -> Bytes.fromArray <$> UDP.recv sock
|
||||
|
||||
declareForeign Tracked "IO.UDP.UDPSocket.send.impl.v1" boxBoxToEF0
|
||||
. mkForeignIOF
|
||||
$ \(sock :: UDPSocket, bytes :: Bytes.Bytes) ->
|
||||
UDP.send sock (Bytes.toArray bytes)
|
||||
|
||||
declareForeign Tracked "IO.UDP.UDPSocket.close.impl.v1" boxToEF0
|
||||
. mkForeignIOF
|
||||
$ \(sock :: UDPSocket) -> UDP.close sock
|
||||
|
||||
declareForeign Tracked "IO.UDP.ListenSocket.close.impl.v1" boxToEF0
|
||||
. mkForeignIOF
|
||||
$ \(sock :: ListenSocket) -> UDP.stop sock
|
||||
|
||||
declareForeign Tracked "IO.UDP.UDPSocket.toText.impl.v1" boxDirect
|
||||
. mkForeign
|
||||
$ \(sock :: UDPSocket) -> pure $ show sock
|
||||
|
||||
declareForeign Tracked "IO.UDP.serverSocket.impl.v1" boxBoxToEFBox
|
||||
. mkForeignIOF
|
||||
$ \(ip :: Util.Text.Text, port :: Util.Text.Text) ->
|
||||
let maybeIp = readMaybe $ Util.Text.toString ip :: Maybe IP
|
||||
maybePort = readMaybe $ Util.Text.toString port :: Maybe PortNumber
|
||||
in case (maybeIp, maybePort) of
|
||||
(Nothing, _) -> fail "Invalid IP Address"
|
||||
(_, Nothing) -> fail "Invalid Port Number"
|
||||
(Just ip, Just pt) -> UDP.serverSocket (ip, pt)
|
||||
|
||||
declareForeign Tracked "IO.UDP.ListenSocket.toText.impl.v1" boxDirect
|
||||
. mkForeign
|
||||
$ \(sock :: ListenSocket) -> pure $ show sock
|
||||
|
||||
declareForeign Tracked "IO.UDP.ListenSocket.recvFrom.impl.v1" boxToEFTup .
|
||||
mkForeignIOF $ fmap (first Bytes.fromArray) <$> UDP.recvFrom
|
||||
|
||||
declareForeign Tracked "IO.UDP.ClientSockAddr.toText.v1" boxDirect
|
||||
. mkForeign
|
||||
$ \(sock :: ClientSockAddr) -> pure $ show sock
|
||||
|
||||
declareForeign Tracked "IO.UDP.ListenSocket.sendTo.impl.v1" boxBoxBoxToEF0 .
|
||||
mkForeignIOF $ \(socket :: ListenSocket, bytes :: Bytes.Bytes, addr :: ClientSockAddr) ->
|
||||
UDP.sendTo socket (Bytes.toArray bytes) addr
|
||||
|
||||
declareForeigns :: FDecl Symbol ()
|
||||
declareForeigns = do
|
||||
declareUdpForeigns
|
||||
declareForeign Tracked "IO.openFile.impl.v3" boxIomrToEFBox $
|
||||
mkForeignIOF $ \(fnameText :: Util.Text.Text, n :: Int) ->
|
||||
let fname = Util.Text.toString fnameText
|
||||
@ -2830,6 +2935,14 @@ declareForeigns = do
|
||||
. mkForeign
|
||||
$ pure . verifyEd25519Wrapper
|
||||
|
||||
declareForeign Untracked "crypto.Rsa.sign.impl" boxBoxToEFBox
|
||||
. mkForeign
|
||||
$ pure . signRsaWrapper
|
||||
|
||||
declareForeign Untracked "crypto.Rsa.verify.impl" boxBoxBoxToEFBool
|
||||
. mkForeign
|
||||
$ pure . verifyRsaWrapper
|
||||
|
||||
let catchAll :: (MonadCatch m, MonadIO m, NFData a) => m a -> m (Either Util.Text.Text a)
|
||||
catchAll e = do
|
||||
e <- Exception.tryAnyDeep e
|
||||
@ -3471,6 +3584,31 @@ verifyEd25519Wrapper (public0, msg0, sig0) = case validated of
|
||||
"ed25519: Secret key structure invalid"
|
||||
errMsg _ = "ed25519: unexpected error"
|
||||
|
||||
signRsaWrapper ::
|
||||
(Bytes.Bytes, Bytes.Bytes) -> Either Failure Bytes.Bytes
|
||||
signRsaWrapper (secret0, msg0) = case validated of
|
||||
Left err ->
|
||||
Left (Failure Ty.cryptoFailureRef err unitValue)
|
||||
Right secret ->
|
||||
case RSA.sign Nothing (Just Hash.SHA256) secret msg of
|
||||
Left err -> Left (Failure Ty.cryptoFailureRef (Rsa.rsaErrorToText err) unitValue)
|
||||
Right signature -> Right $ Bytes.fromByteString signature
|
||||
where
|
||||
msg = Bytes.toArray msg0 :: ByteString
|
||||
validated = Rsa.parseRsaPrivateKey (Bytes.toArray secret0 :: ByteString)
|
||||
|
||||
verifyRsaWrapper ::
|
||||
(Bytes.Bytes, Bytes.Bytes, Bytes.Bytes) -> Either Failure Bool
|
||||
verifyRsaWrapper (public0, msg0, sig0) = case validated of
|
||||
Left err ->
|
||||
Left $ Failure Ty.cryptoFailureRef err unitValue
|
||||
Right public ->
|
||||
Right $ RSA.verify (Just Hash.SHA256) public msg sig
|
||||
where
|
||||
msg = Bytes.toArray msg0 :: ByteString
|
||||
sig = Bytes.toArray sig0 :: ByteString
|
||||
validated = Rsa.parseRsaPublicKey (Bytes.toArray public0 :: ByteString)
|
||||
|
||||
typeReferences :: [(Reference, Word64)]
|
||||
typeReferences = zip rs [1 ..]
|
||||
where
|
||||
|
127
parser-typechecker/src/Unison/Runtime/Crypto/Rsa.hs
Normal file
127
parser-typechecker/src/Unison/Runtime/Crypto/Rsa.hs
Normal file
@ -0,0 +1,127 @@
|
||||
module Unison.Runtime.Crypto.Rsa (
|
||||
parseRsaPublicKey,
|
||||
parseRsaPrivateKey,
|
||||
rsaErrorToText,
|
||||
) where
|
||||
|
||||
import Crypto.Number.Basic qualified as Crypto
|
||||
import Crypto.PubKey.RSA qualified as RSA
|
||||
import Data.ASN1.BinaryEncoding qualified as ASN1
|
||||
import Data.ASN1.BitArray qualified as ASN1
|
||||
import Data.ASN1.Encoding qualified as ASN1
|
||||
import Data.ASN1.Error qualified as ASN1
|
||||
import Data.ASN1.Types qualified as ASN1
|
||||
import Data.ByteString qualified as BS
|
||||
import Data.ByteString.Lazy qualified as BSL
|
||||
import Unison.Util.Text (Text)
|
||||
import Unison.Util.Text qualified as Util.Text
|
||||
|
||||
-- | Parse a RSA public key from a ByteString
|
||||
-- The input bytestring is a hex-encoded string of the DER file for the public key.
|
||||
-- It can be generated with those commands:
|
||||
-- # generate a RSA key of a given size
|
||||
-- openssl genrsa -out private_key.pem <size>
|
||||
-- # output the DER format as a hex string
|
||||
-- openssl rsa -in private_key.pem -outform DER -pubout | xxd -p
|
||||
parseRsaPublicKey :: BS.ByteString -> Either Text RSA.PublicKey
|
||||
parseRsaPublicKey bs = case ASN1.decodeASN1 ASN1.DER (BSL.fromStrict bs) of
|
||||
Left err -> Left $ "rsa: cannot decode as an ASN.1 structure. " <> asn1ErrorToText err
|
||||
Right asn1 ->
|
||||
case asn1 of
|
||||
[ ASN1.Start ASN1.Sequence,
|
||||
ASN1.Start ASN1.Sequence,
|
||||
ASN1.OID _,
|
||||
ASN1.Null,
|
||||
ASN1.End ASN1.Sequence,
|
||||
ASN1.BitString (ASN1.BitArray _ bits),
|
||||
ASN1.End ASN1.Sequence
|
||||
] -> case ASN1.decodeASN1 ASN1.DER (BSL.fromStrict bits) of
|
||||
Left err -> Left $ "rsa: cannot decode as an ASN.1 inner structure. " <> asn1ErrorToText err
|
||||
Right asn1 -> case asn1 of
|
||||
[ASN1.Start ASN1.Sequence, ASN1.IntVal n, ASN1.IntVal e, ASN1.End ASN1.Sequence] ->
|
||||
Right
|
||||
RSA.PublicKey
|
||||
{ public_size = Crypto.numBytes n,
|
||||
public_n = n,
|
||||
public_e = e
|
||||
}
|
||||
other -> Left ("rsa: unexpected ASN.1 inner structure for a RSA public key" <> Util.Text.pack (show other))
|
||||
other -> Left ("rsa: unexpected ASN.1 outer structure for a RSA public key" <> Util.Text.pack (show other))
|
||||
|
||||
-- | Parse a RSA private key from a ByteString
|
||||
-- The input bytestring is a hex-encoded string of the DER file for the private key.
|
||||
-- It can be generated with those commands:
|
||||
-- # generate a RSA key of a given size
|
||||
-- openssl genrsa -out private_key.pem <size>
|
||||
-- # output the DER format as a hex string
|
||||
-- openssl rsa -in private_key.pem -outform DER | xxd -p
|
||||
parseRsaPrivateKey :: BS.ByteString -> Either Text RSA.PrivateKey
|
||||
parseRsaPrivateKey bs = case ASN1.decodeASN1 ASN1.DER (BSL.fromStrict bs) of
|
||||
Left err -> Left $ "Error decoding ASN.1: " <> asn1ErrorToText err
|
||||
Right asn1 ->
|
||||
case asn1 of
|
||||
[ ASN1.Start ASN1.Sequence,
|
||||
ASN1.IntVal 0,
|
||||
ASN1.Start ASN1.Sequence,
|
||||
ASN1.OID _,
|
||||
ASN1.Null,
|
||||
ASN1.End ASN1.Sequence,
|
||||
ASN1.OctetString bits,
|
||||
ASN1.End ASN1.Sequence
|
||||
] ->
|
||||
case ASN1.decodeASN1 ASN1.DER (BSL.fromStrict bits) of
|
||||
Left err -> Left $ "Error decoding inner ASN.1: " <> asn1ErrorToText err
|
||||
Right asn1 ->
|
||||
case asn1 of
|
||||
[ ASN1.Start ASN1.Sequence,
|
||||
ASN1.IntVal _,
|
||||
ASN1.IntVal n,
|
||||
ASN1.IntVal e,
|
||||
ASN1.IntVal d,
|
||||
ASN1.IntVal p,
|
||||
ASN1.IntVal q,
|
||||
ASN1.IntVal dP,
|
||||
ASN1.IntVal dQ,
|
||||
ASN1.IntVal qinv,
|
||||
ASN1.End ASN1.Sequence
|
||||
] ->
|
||||
Right
|
||||
RSA.PrivateKey
|
||||
{ private_pub = RSA.PublicKey {public_size = Crypto.numBytes n, public_n = n, public_e = e},
|
||||
private_d = d,
|
||||
private_p = p,
|
||||
private_q = q,
|
||||
private_dP = dP,
|
||||
private_dQ = dQ,
|
||||
private_qinv = qinv
|
||||
}
|
||||
other -> Left ("rsa: unexpected inner ASN.1 structure for a RSA private key" <> Util.Text.pack (show other))
|
||||
other -> Left ("rsa: unexpected outer ASN.1 structure for a RSA private key" <> Util.Text.pack (show other))
|
||||
|
||||
-- | Display an ASN1 Error
|
||||
asn1ErrorToText :: ASN1.ASN1Error -> Text
|
||||
asn1ErrorToText = \case
|
||||
ASN1.StreamUnexpectedEOC -> "Unexpected EOC in the stream"
|
||||
ASN1.StreamInfinitePrimitive -> "Invalid primitive with infinite length in a stream"
|
||||
ASN1.StreamConstructionWrongSize -> "A construction goes over the size specified in the header"
|
||||
ASN1.StreamUnexpectedSituation s -> "An unexpected situation has come up parsing an ASN1 event stream: " <> Util.Text.pack s
|
||||
ASN1.ParsingHeaderFail s -> "Parsing an invalid header: " <> Util.Text.pack s
|
||||
ASN1.ParsingPartial -> "Parsing is not finished, the key is not complete"
|
||||
ASN1.TypeNotImplemented s -> "Decoding of a type that is not implemented: " <> Util.Text.pack s
|
||||
ASN1.TypeDecodingFailed s -> "Decoding of a known type failed: " <> Util.Text.pack s
|
||||
ASN1.TypePrimitiveInvalid s -> "Invalid primitive type: " <> Util.Text.pack s
|
||||
ASN1.PolicyFailed s1 s2 -> "Policy failed. Policy name: " <> Util.Text.pack s1 <> ", reason:" <> Util.Text.pack s2
|
||||
|
||||
-- | Display a RSA Error
|
||||
rsaErrorToText :: RSA.Error -> Text
|
||||
rsaErrorToText = \case
|
||||
RSA.MessageSizeIncorrect ->
|
||||
"rsa: The message to decrypt is not of the correct size (need to be == private_size)"
|
||||
RSA.MessageTooLong ->
|
||||
"rsa: The message to encrypt is too long"
|
||||
RSA.MessageNotRecognized ->
|
||||
"rsa: The message decrypted doesn't have a PKCS15 structure (0 2 .. 0 msg)"
|
||||
RSA.SignatureTooLong ->
|
||||
"rsa: The message's digest is too long"
|
||||
RSA.InvalidParameters ->
|
||||
"rsa: Some parameters lead to breaking assumptions"
|
@ -27,6 +27,7 @@ import Data.Primitive (ByteArray, MutableArray, MutableByteArray)
|
||||
import Data.Tagged (Tagged (..))
|
||||
import Data.X509 qualified as X509
|
||||
import Network.Socket (Socket)
|
||||
import Network.UDP (ListenSocket, UDPSocket, ClientSockAddr)
|
||||
import Network.TLS qualified as TLS (ClientParams, Context, ServerParams)
|
||||
import System.Clock (TimeSpec)
|
||||
import System.IO (Handle)
|
||||
@ -81,6 +82,10 @@ socketEq :: Socket -> Socket -> Bool
|
||||
socketEq l r = l == r
|
||||
{-# NOINLINE socketEq #-}
|
||||
|
||||
udpSocketEq :: UDPSocket -> UDPSocket -> Bool
|
||||
udpSocketEq l r = l == r
|
||||
{-# NOINLINE udpSocketEq #-}
|
||||
|
||||
refEq :: IORef () -> IORef () -> Bool
|
||||
refEq l r = l == r
|
||||
{-# NOINLINE refEq #-}
|
||||
@ -157,6 +162,7 @@ ref2eq r
|
||||
-- Ditto
|
||||
| r == Ty.tvarRef = Just $ promote tvarEq
|
||||
| r == Ty.socketRef = Just $ promote socketEq
|
||||
| r == Ty.udpSocketRef = Just $ promote udpSocketEq
|
||||
| r == Ty.refRef = Just $ promote refEq
|
||||
| r == Ty.threadIdRef = Just $ promote tidEq
|
||||
| r == Ty.marrayRef = Just $ promote marrEq
|
||||
@ -230,6 +236,12 @@ instance BuiltinForeign Referent where foreignRef = Tagged Ty.termLinkRef
|
||||
|
||||
instance BuiltinForeign Socket where foreignRef = Tagged Ty.socketRef
|
||||
|
||||
instance BuiltinForeign ListenSocket where foreignRef = Tagged Ty.udpListenSocketRef
|
||||
|
||||
instance BuiltinForeign ClientSockAddr where foreignRef = Tagged Ty.udpClientSockAddrRef
|
||||
|
||||
instance BuiltinForeign UDPSocket where foreignRef = Tagged Ty.udpSocketRef
|
||||
|
||||
instance BuiltinForeign ThreadId where foreignRef = Tagged Ty.threadIdRef
|
||||
|
||||
instance BuiltinForeign TLS.ClientParams where foreignRef = Tagged Ty.tlsClientConfigRef
|
||||
|
@ -26,6 +26,7 @@ import Data.Time.Clock.POSIX (POSIXTime)
|
||||
import Data.Word (Word16, Word32, Word64, Word8)
|
||||
import GHC.IO.Exception (IOErrorType (..), IOException (..))
|
||||
import Network.Socket (Socket)
|
||||
import Network.UDP (UDPSocket)
|
||||
import System.IO (BufferMode (..), Handle, IOMode, SeekMode)
|
||||
import Unison.Builtin.Decls qualified as Ty
|
||||
import Unison.Reference (Reference)
|
||||
@ -139,6 +140,10 @@ instance ForeignConvention Socket where
|
||||
readForeign = readForeignBuiltin
|
||||
writeForeign = writeForeignBuiltin
|
||||
|
||||
instance ForeignConvention UDPSocket where
|
||||
readForeign = readForeignBuiltin
|
||||
writeForeign = writeForeignBuiltin
|
||||
|
||||
instance ForeignConvention ThreadId where
|
||||
readForeign = readForeignBuiltin
|
||||
writeForeign = writeForeignBuiltin
|
||||
|
@ -55,6 +55,7 @@ import System.Directory
|
||||
createDirectoryIfMissing,
|
||||
getXdgDirectory,
|
||||
)
|
||||
import System.Environment (getArgs)
|
||||
import System.Exit (ExitCode (..))
|
||||
import System.FilePath ((<.>), (</>))
|
||||
import System.Process
|
||||
@ -869,6 +870,8 @@ nativeEvalInContext executable ppe ctx serv port codes base = do
|
||||
ensureRuntimeExists executable
|
||||
let cc = ccache ctx
|
||||
crs <- readTVarIO $ combRefs cc
|
||||
-- Seems a bit weird, but apparently this is how we do it
|
||||
args <- getArgs
|
||||
let bytes = serializeValue . compileValue base $ codes
|
||||
|
||||
decodeResult (Error msg) = pure . Left $ text msg
|
||||
@ -884,8 +887,14 @@ nativeEvalInContext executable ppe ctx serv port codes base = do
|
||||
(errs, dv) -> pure $ Right (listErrors errs, dv)
|
||||
|
||||
comm mv (sock, _) = do
|
||||
send sock . runPutS . putWord32be . fromIntegral $ BS.length bytes
|
||||
let encodeNum = runPutS . putWord32be . fromIntegral
|
||||
send sock . encodeNum $ BS.length bytes
|
||||
send sock bytes
|
||||
send sock . encodeNum $ length args
|
||||
for_ args $ \arg -> do
|
||||
let bs = encodeUtf8 $ pack arg
|
||||
send sock . encodeNum $ BS.length bs
|
||||
send sock bs
|
||||
UnliftIO.putMVar mv =<< receiveAll sock
|
||||
|
||||
callout _ _ _ ph = do
|
||||
|
@ -1950,8 +1950,10 @@ reserveIds :: Word64 -> TVar Word64 -> IO Word64
|
||||
reserveIds n free = atomically . stateTVar free $ \i -> (i, i + n)
|
||||
|
||||
updateMap :: (Semigroup s) => s -> TVar s -> STM s
|
||||
updateMap new r = stateTVar r $ \old ->
|
||||
let total = new <> old in (total, total)
|
||||
updateMap new0 r = do
|
||||
new <- evaluateSTM new0
|
||||
stateTVar r $ \old ->
|
||||
let total = new <> old in (total, total)
|
||||
|
||||
refLookup :: String -> M.Map Reference Word64 -> Reference -> Word64
|
||||
refLookup s m r
|
||||
@ -2080,6 +2082,11 @@ checkValueSandboxing cc allowed0 v = do
|
||||
where
|
||||
allowed = S.fromList allowed0
|
||||
|
||||
-- Just evaluating to force exceptions. Shouldn't actually be that
|
||||
-- unsafe.
|
||||
evaluateSTM :: a -> STM a
|
||||
evaluateSTM x = unsafeIOToSTM (evaluate x)
|
||||
|
||||
cacheAdd0 ::
|
||||
S.Set Reference ->
|
||||
[(Reference, SuperGroup Symbol)] ->
|
||||
|
48
parser-typechecker/tests/Unison/Test/Runtime/Crypto/Rsa.hs
Normal file
48
parser-typechecker/tests/Unison/Test/Runtime/Crypto/Rsa.hs
Normal file
@ -0,0 +1,48 @@
|
||||
module Unison.Test.Runtime.Crypto.Rsa where
|
||||
|
||||
import Crypto.PubKey.RSA qualified as RSA
|
||||
import Data.Maybe (fromJust)
|
||||
import EasyTest
|
||||
import Text.Hex
|
||||
import Unison.Runtime.Crypto.Rsa
|
||||
|
||||
test :: Test ()
|
||||
test =
|
||||
scope "parsing" $
|
||||
tests
|
||||
[ scope "parseRsaPublicKey" parseRsaPublicKeyTest,
|
||||
scope "parseRsaPrivateKey" parseRsaPrivateKeyTest
|
||||
]
|
||||
|
||||
parseRsaPublicKeyTest :: Test ()
|
||||
parseRsaPublicKeyTest = do
|
||||
let publicKey = fromJust $ decodeHex "30819f300d06092a864886f70d010101050003818d0030818902818100a7104b2f20725896076e629ccedbcd6907b16694c6e3d8768b5e0e685670b49616e796c588e5aafb92ef986c1a42c021fed0bdc99212c969cdab98087a0ee4c2f4acd4b6049a87a96afc45668329a3cf21a86fb13b488bbe9fefa1cd5a459014f0d0101378e9661e11b73acf54c8a91141ac90309e7fb6ed69b4e63230ab29150203010001"
|
||||
let actual = parseRsaPublicKey publicKey
|
||||
let expected =
|
||||
RSA.PublicKey
|
||||
{ public_size = 128,
|
||||
public_n = 117316082691067466889305872575557202673362950667744445659499028356561021937142613205104589546643406309814005581397307365793352915031830083408196867291689544964758311244905648512755140288413724266536406258908443053617981341387254220659107167969619543916073994027510270571746462643891169516098953507692950006037,
|
||||
public_e = 65537
|
||||
}
|
||||
expectEqual actual (Right expected)
|
||||
|
||||
parseRsaPrivateKeyTest :: Test ()
|
||||
parseRsaPrivateKeyTest = do
|
||||
let privateKey = fromJust $ decodeHex "30820276020100300d06092a864886f70d0101010500048202603082025c02010002818100a7104b2f20725896076e629ccedbcd6907b16694c6e3d8768b5e0e685670b49616e796c588e5aafb92ef986c1a42c021fed0bdc99212c969cdab98087a0ee4c2f4acd4b6049a87a96afc45668329a3cf21a86fb13b488bbe9fefa1cd5a459014f0d0101378e9661e11b73acf54c8a91141ac90309e7fb6ed69b4e63230ab291502030100010281807cdc23a4fc3619d93f8293b728af848d0c0fdd603269d5bd7b99f760a9c22065d08693dbdcddf1f5863306133d694819e04d789aef4e95343b601507b8d9eac4492e6d7031b035c5d84eceaa9686b292712632d33b3303af84314d7920bc3d45f90d7818fc2587b129196d378ee4ed3e6b8d9010d504bb6470ff53e7c5fb17a1024100d67cbcf113d24325fcef12a778dc47c7060055290b68287649ef092558daccb61c4e7bc290740b75a29d4356dcbd66d18b0860dbff394cc8ff3d94d57617adbd024100c765d8261dd3d8e0d3caf11ab7b212eed181354215687ca6387283e4f0be16e79c8f298be0a70c7734dea78ea65128517d693cabfa4c0ff5328f2abb85d2023902403ca41dc347285e65c22251b2d9bfe5e7463217e1b7e0e5f7b3a58a7f6da4c6d60220ca6ad2ee8c42e10bf77afa83ee2af6551315800e52404db1ba7fb398b43d02410084877d85c0177933ddb12a554eb8edfa8b872c85d2c2d2ee8be019280696e19469ab81bab5c371f69d4e4be1f54b45d7fbda017870f1333e0eafb78051ee8689024061f694c12e934c44b7734f62d1b2a3d3624a4980e1b8e066d78dbabd2436654fbb9d9701425900daaafa1e031310e8a580520bb9e1c1288c669fce252bad1e65"
|
||||
let actual = parseRsaPrivateKey privateKey
|
||||
let expected =
|
||||
RSA.PrivateKey
|
||||
{ private_pub =
|
||||
RSA.PublicKey
|
||||
{ public_size = 128,
|
||||
public_n = 117316082691067466889305872575557202673362950667744445659499028356561021937142613205104589546643406309814005581397307365793352915031830083408196867291689544964758311244905648512755140288413724266536406258908443053617981341387254220659107167969619543916073994027510270571746462643891169516098953507692950006037,
|
||||
public_e = 65537
|
||||
},
|
||||
private_d = 87679616801061623139678211462583995973938243841750319557622746050821908471598979773246073219465960975647341309221073776399960619667883322633274192544886774496262613234964971623744931197514942326521327825606791139576216469817618072158660015124292686556025876602526093941289386692302798356532230087066424907681,
|
||||
private_p = 11233609214744923027767175501352593646202568021007351512424743595719525825944483790453654486119375677127184086533073126720964060366977171672432803562630589,
|
||||
private_q = 10443311712951670023099443962737058583295522901049380734330015511797675780053495867511334370071427510893202629294375157939437054042246322949533759718949433,
|
||||
private_dP = 3176031022781156885141187342486873181111240716865972140527001145690023864823311109042460960576558461960260523664057127500690343997127119244373520564139069,
|
||||
private_dQ = 6941120510619372179626602981107825119089517097926514417911731475020140673258620725588998791918173107511741662411060736754565186643059761376912904765212297,
|
||||
private_qinv = 5130749483925715543854508655089227892147425255568362503702389513480166321367311031864242660308321705497233758877799126086240198385610964125158868020698725
|
||||
}
|
||||
expectEqual actual (Right expected)
|
@ -142,6 +142,7 @@ library
|
||||
Unison.Runtime.ANF.Serialize
|
||||
Unison.Runtime.Array
|
||||
Unison.Runtime.Builtin
|
||||
Unison.Runtime.Crypto.Rsa
|
||||
Unison.Runtime.Debug
|
||||
Unison.Runtime.Decompile
|
||||
Unison.Runtime.Exception
|
||||
@ -232,6 +233,8 @@ library
|
||||
, NanoID
|
||||
, aeson
|
||||
, ansi-terminal
|
||||
, asn1-encoding
|
||||
, asn1-types
|
||||
, async
|
||||
, atomic-primops
|
||||
, base
|
||||
@ -268,6 +271,7 @@ library
|
||||
, http-client
|
||||
, http-media
|
||||
, http-types
|
||||
, iproute
|
||||
, lens
|
||||
, lucid
|
||||
, megaparsec
|
||||
@ -281,6 +285,7 @@ library
|
||||
, natural-transformation
|
||||
, network
|
||||
, network-simple
|
||||
, network-udp
|
||||
, network-uri
|
||||
, nonempty-containers
|
||||
, open-browser
|
||||
@ -370,6 +375,7 @@ test-suite parser-typechecker-tests
|
||||
Unison.Test.DataDeclaration
|
||||
Unison.Test.MCode
|
||||
Unison.Test.Referent
|
||||
Unison.Test.Runtime.Crypto.Rsa
|
||||
Unison.Test.Syntax.FileParser
|
||||
Unison.Test.Syntax.TermParser
|
||||
Unison.Test.Syntax.TypePrinter
|
||||
@ -424,6 +430,8 @@ test-suite parser-typechecker-tests
|
||||
, NanoID
|
||||
, aeson
|
||||
, ansi-terminal
|
||||
, asn1-encoding
|
||||
, asn1-types
|
||||
, async
|
||||
, atomic-primops
|
||||
, base
|
||||
@ -460,9 +468,11 @@ test-suite parser-typechecker-tests
|
||||
, hashable
|
||||
, hashtables
|
||||
, haskeline
|
||||
, hex-text
|
||||
, http-client
|
||||
, http-media
|
||||
, http-types
|
||||
, iproute
|
||||
, lens
|
||||
, lucid
|
||||
, megaparsec
|
||||
@ -476,6 +486,7 @@ test-suite parser-typechecker-tests
|
||||
, natural-transformation
|
||||
, network
|
||||
, network-simple
|
||||
, network-udp
|
||||
, network-uri
|
||||
, nonempty-containers
|
||||
, open-browser
|
||||
|
@ -30,18 +30,32 @@
|
||||
unison/data-info
|
||||
unison/chunked-seq
|
||||
unison/primops
|
||||
unison/builtin
|
||||
unison/primops-generated
|
||||
unison/builtin-generated)
|
||||
|
||||
(define (grab-num port)
|
||||
(integer-bytes->integer (read-bytes 4 port) #f #t 0 4))
|
||||
|
||||
; Gets bytes using the expected input format. The format is simple:
|
||||
;
|
||||
; - 4 bytes indicating how many bytes follow
|
||||
; - the actual payload, with size matching the above
|
||||
(define (grab-bytes port)
|
||||
(let* ([size-bytes (read-bytes 4 port)]
|
||||
[size (integer-bytes->integer size-bytes #f #t 0 4)])
|
||||
(let ([size (grab-num port)])
|
||||
(read-bytes size port)))
|
||||
|
||||
; Gets args sent after the code payload. Format is:
|
||||
;
|
||||
; - 4 bytes indicating how many arguments
|
||||
; - for each argument
|
||||
; - 4 bytes indicating length of argument
|
||||
; - utf-8 bytes of that length
|
||||
(define (grab-args port)
|
||||
(let ([n (grab-num port)])
|
||||
(for/list ([i (range n)])
|
||||
(bytes->string/utf-8 (grab-bytes port)))))
|
||||
|
||||
; Reads and decodes the input. First uses `grab-bytes` to read the
|
||||
; payload, then uses unison functions to deserialize the `Value` that
|
||||
; is expected.
|
||||
@ -113,13 +127,15 @@
|
||||
; input. Then uses the dynamic loading machinery to add the code to
|
||||
; the runtime. Finally executes a specified main reference.
|
||||
(define (do-evaluate in out)
|
||||
(let-values ([(code main-ref) (decode-input in)])
|
||||
(let-values ([(code main-ref) (decode-input in)]
|
||||
[(args) (list->vector (grab-args in))])
|
||||
(add-runtime-code 'unison-main code)
|
||||
(with-handlers
|
||||
([exn:bug? (lambda (e) (encode-error e out))])
|
||||
|
||||
(handle [ref-exception:typelink] (eval-exn-handler out)
|
||||
((termlink->proc main-ref))))))
|
||||
(parameterize ([current-command-line-arguments args])
|
||||
(handle [ref-exception:typelink] (eval-exn-handler out)
|
||||
((termlink->proc main-ref)))))))
|
||||
|
||||
; Uses racket pretty printing machinery to instead generate a file
|
||||
; containing the given code, and which executes the main definition on
|
||||
|
@ -47,6 +47,10 @@
|
||||
builtin-tls.signedcert:typelink
|
||||
builtin-tls.version:typelink
|
||||
|
||||
builtin-udpsocket:typelink
|
||||
builtin-listensocket:typelink
|
||||
builtin-clientsockaddr:typelink
|
||||
|
||||
bytevector
|
||||
bytes
|
||||
control
|
||||
@ -607,5 +611,5 @@
|
||||
(define (exn:bug->exception b)
|
||||
(raise-unison-exception
|
||||
ref-runtimefailure:typelink
|
||||
(exn:bug-msg b)
|
||||
(string->chunked-string (exn:bug-msg b))
|
||||
(exn:bug-val b)))
|
||||
|
4
scheme-libs/racket/unison/builtin.rkt
Normal file
4
scheme-libs/racket/unison/builtin.rkt
Normal file
@ -0,0 +1,4 @@
|
||||
#lang racket/base
|
||||
(require unison/udp)
|
||||
|
||||
(provide (all-from-out))
|
@ -37,7 +37,6 @@
|
||||
bytevector
|
||||
bytevector-append
|
||||
|
||||
directory-contents
|
||||
current-microseconds
|
||||
|
||||
decode-value
|
||||
@ -227,10 +226,6 @@
|
||||
(define (current-microseconds)
|
||||
(fl->fx (* 1000 (current-inexact-milliseconds))))
|
||||
|
||||
(define (directory-contents path-str)
|
||||
(define (extract path) (string->chunked-string (path->string path)))
|
||||
(map extract (directory-list (chunked-string->string path-str))))
|
||||
|
||||
(define (list-head l n)
|
||||
(let rec ([c l] [m n])
|
||||
(cond
|
||||
@ -476,19 +471,17 @@
|
||||
(next (fx1- i)))))))
|
||||
|
||||
(define (write-exn:bug ex port mode)
|
||||
(when mode
|
||||
(write-string "<exn:bug " port))
|
||||
(when mode (write-string "<exn:bug " port))
|
||||
|
||||
(let ([recur (case mode
|
||||
[(#t) write]
|
||||
[(#f) display]
|
||||
[else (lambda (v port) (print v port mode))])])
|
||||
(recur (chunked-string->string (exn:bug-msg ex)) port)
|
||||
(recur (exn:bug-msg ex) port)
|
||||
(if mode (write-string " " port) (newline port))
|
||||
(write-string (describe-value (exn:bug-val ex)) port))
|
||||
|
||||
(when mode
|
||||
(write-string ">")))
|
||||
(when mode (write-string ">" port)))
|
||||
|
||||
(struct exn:bug (msg val)
|
||||
#:constructor-name make-exn:bug
|
||||
|
@ -80,6 +80,9 @@
|
||||
builtin-timespec:typelink
|
||||
builtin-threadid:typelink
|
||||
builtin-value:typelink
|
||||
builtin-udpsocket:typelink
|
||||
builtin-listensocket:typelink
|
||||
builtin-clientsockaddr:typelink
|
||||
|
||||
builtin-crypto.hashalgorithm:typelink
|
||||
builtin-char.class:typelink
|
||||
@ -440,6 +443,9 @@
|
||||
(define builtin-timespec:typelink (unison-typelink-builtin "TimeSpec"))
|
||||
(define builtin-threadid:typelink (unison-typelink-builtin "ThreadId"))
|
||||
(define builtin-value:typelink (unison-typelink-builtin "Value"))
|
||||
(define builtin-udpsocket:typelink (unison-typelink-builtin "UDPSocket"))
|
||||
(define builtin-listensocket:typelink (unison-typelink-builtin "ListenSocket"))
|
||||
(define builtin-clientsockaddr:typelink (unison-typelink-builtin "ClientSockAddr"))
|
||||
|
||||
(define builtin-crypto.hashalgorithm:typelink
|
||||
(unison-typelink-builtin "crypto.HashAlgorithm"))
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
(provide
|
||||
unison-FOp-IO.stdHandle
|
||||
unison-FOp-IO.openFile.impl.v3
|
||||
(prefix-out
|
||||
builtin-IO.
|
||||
(combine-out
|
||||
@ -100,13 +101,23 @@
|
||||
ref-unit-unit)
|
||||
(ref-either-right char))))
|
||||
|
||||
(define-unison (getSomeBytes.impl.v1 handle bytes)
|
||||
(let* ([buffer (make-bytes bytes)]
|
||||
(define-unison (getSomeBytes.impl.v1 handle nbytes)
|
||||
(let* ([buffer (make-bytes nbytes)]
|
||||
[line (read-bytes-avail! buffer handle)])
|
||||
(if (eof-object? line)
|
||||
(ref-either-right (bytes->chunked-bytes #""))
|
||||
(ref-either-right (bytes->chunked-bytes buffer))
|
||||
)))
|
||||
(cond
|
||||
[(eof-object? line)
|
||||
(ref-either-right (bytes->chunked-bytes #""))]
|
||||
[(procedure? line)
|
||||
(Exception
|
||||
ref-iofailure:typelink
|
||||
"getSomeBytes.impl: special value returned"
|
||||
ref-unit-unit)]
|
||||
[else
|
||||
(ref-either-right
|
||||
(bytes->chunked-bytes
|
||||
(if (< line nbytes)
|
||||
(subbytes buffer 0 line)
|
||||
buffer)))])))
|
||||
|
||||
(define-unison (getBuffering.impl.v3 handle)
|
||||
(case (file-stream-buffer-mode handle)
|
||||
@ -194,6 +205,15 @@
|
||||
(ref-either-right
|
||||
(string->chunked-string (bytes->string/utf-8 value))))))
|
||||
|
||||
(define (unison-FOp-IO.openFile.impl.v3 fn0 mode)
|
||||
(define fn (chunked-string->string fn0))
|
||||
|
||||
(right (case mode
|
||||
[(0) (open-input-file fn)]
|
||||
[(1) (open-output-file fn #:exists 'truncate)]
|
||||
[(2) (open-output-file fn #:exists 'append)]
|
||||
[else (open-input-output-file fn #:exists 'can-update)])))
|
||||
|
||||
;; From https://github.com/sorawee/shlex/blob/5de06500e8c831cfc8dffb99d57a76decc02c569/main.rkt (MIT License)
|
||||
;; with is a port of https://github.com/python/cpython/blob/bf2f76ec0976c09de79c8827764f30e3b6fba776/Lib/shlex.py#L325
|
||||
(define unsafe-pattern #rx"[^a-zA-Z0-9_@%+=:,./-]")
|
||||
|
@ -5,6 +5,10 @@
|
||||
unison/data-info
|
||||
racket/file
|
||||
racket/flonum
|
||||
(only-in racket
|
||||
date-dst?
|
||||
date-time-zone-offset
|
||||
date*-time-zone-name)
|
||||
(only-in unison/boot data-case define-unison)
|
||||
(only-in
|
||||
rnrs/arithmetic/flonums-6
|
||||
@ -12,6 +16,7 @@
|
||||
(require racket/file)
|
||||
|
||||
(provide
|
||||
builtin-Clock.internals.systemTimeZone.v1
|
||||
(prefix-out
|
||||
unison-FOp-Clock.internals.
|
||||
(combine-out
|
||||
@ -35,6 +40,7 @@
|
||||
renameFile.impl.v3
|
||||
createDirectory.impl.v3
|
||||
removeDirectory.impl.v3
|
||||
directoryContents.impl.v3
|
||||
setCurrentDirectory.impl.v3
|
||||
renameDirectory.impl.v3
|
||||
isDirectory.impl.v3
|
||||
@ -42,6 +48,13 @@
|
||||
systemTimeMicroseconds.impl.v3
|
||||
createTempDirectory.impl.v3)))
|
||||
|
||||
(define (failure-result ty msg vl)
|
||||
(ref-either-left
|
||||
(ref-failure-failure
|
||||
ty
|
||||
(string->chunked-string msg)
|
||||
(unison-any-any vl))))
|
||||
|
||||
(define (getFileSize.impl.v3 path)
|
||||
(with-handlers
|
||||
[[exn:fail:filesystem?
|
||||
@ -81,6 +94,24 @@
|
||||
(current-directory (chunked-string->string path))
|
||||
(ref-either-right none))
|
||||
|
||||
(define-unison (directoryContents.impl.v3 path)
|
||||
(with-handlers
|
||||
[[exn:fail:filesystem?
|
||||
(lambda (e)
|
||||
(failure-result
|
||||
ref-iofailure:typelink
|
||||
(exception->string e)
|
||||
ref-unit-unit))]]
|
||||
(let* ([dirps (directory-list (chunked-string->string path))]
|
||||
[dirss (map path->string dirps)])
|
||||
(ref-either-right
|
||||
(vector->chunked-list
|
||||
(list->vector
|
||||
(map
|
||||
string->chunked-string
|
||||
(list* "." ".." dirss))))))))
|
||||
|
||||
|
||||
(define-unison (createTempDirectory.impl.v3 prefix)
|
||||
(ref-either-right
|
||||
(string->chunked-string
|
||||
@ -117,6 +148,14 @@
|
||||
(define-unison (systemTimeMicroseconds.impl.v3 unit)
|
||||
(ref-either-right (inexact->exact (* 1000 (current-inexact-milliseconds)))))
|
||||
|
||||
(define-unison (builtin-Clock.internals.systemTimeZone.v1 secs)
|
||||
(let* ([d (seconds->date secs)])
|
||||
(list->unison-tuple
|
||||
(list
|
||||
(date-time-zone-offset d)
|
||||
(if (date-dst? d) 1 0)
|
||||
(date*-time-zone-name d)))))
|
||||
|
||||
(define (threadCPUTime.v1)
|
||||
(right
|
||||
(integer->time
|
||||
|
31
scheme-libs/racket/unison/network-utils.rkt
Normal file
31
scheme-libs/racket/unison/network-utils.rkt
Normal file
@ -0,0 +1,31 @@
|
||||
#lang racket/base
|
||||
(require racket/exn
|
||||
unison/data ; exception
|
||||
unison/data-info ; ref-*
|
||||
unison/chunked-seq
|
||||
unison/core) ; exception->string, chunked-string
|
||||
|
||||
(provide handle-errors)
|
||||
|
||||
(define (handle-errors fn)
|
||||
(with-handlers
|
||||
[[exn:fail:network?
|
||||
(lambda (e)
|
||||
(exception
|
||||
ref-iofailure:typelink
|
||||
(exception->string e)
|
||||
ref-unit-unit))]
|
||||
[exn:fail:contract?
|
||||
(lambda (e)
|
||||
(exception
|
||||
ref-miscfailure:typelink
|
||||
(exception->string e)
|
||||
ref-unit-unit))]
|
||||
[(lambda _ #t)
|
||||
(lambda (e)
|
||||
(exception
|
||||
ref-miscfailure:typelink
|
||||
(string->chunked-string
|
||||
(format "Unknown exception ~a" (exn->string e)))
|
||||
ref-unit-unit))]]
|
||||
(fn)))
|
@ -221,10 +221,11 @@
|
||||
[(unison-termlink-builtin name)
|
||||
(string-append "builtin-" name)]
|
||||
[(unison-termlink-derived bs i)
|
||||
(let ([hs (bytevector->base32-string bs #:alphabet 'hex)]
|
||||
[po (if (= i 0) "" (string-append "." (number->string i)))])
|
||||
(let* ([hs (bytevector->base32-string bs #:alphabet 'hex)]
|
||||
[tm (string-trim hs "=" #:repeat? #t)]
|
||||
[po (if (= i 0) "" (string-append "." (number->string i)))])
|
||||
(string->symbol
|
||||
(string-append "ref-" (substring hs 0 8) po)))]))
|
||||
(string-append "ref-" tm po)))]))
|
||||
|
||||
(define (ref-bytes r)
|
||||
(sum-case (decode-ref r)
|
||||
@ -304,8 +305,24 @@
|
||||
(match v
|
||||
[(unison-data _ t (list rf rt bs0))
|
||||
#:when (= t ref-value-data:tag)
|
||||
(let ([bs (map reify-value (chunked-list->list bs0))])
|
||||
(make-data (reference->typelink rf) rt bs))]
|
||||
(let ([bs (map reify-value (chunked-list->list bs0))]
|
||||
[tl (reference->typelink rf)])
|
||||
(cond
|
||||
[(eqv? tl builtin-boolean:typelink)
|
||||
(cond
|
||||
[(not (null? bs))
|
||||
(raise
|
||||
(make-exn:bug
|
||||
"reify-value: boolean with arguments"
|
||||
bs0))]
|
||||
[(= rt 0) #f]
|
||||
[(= rt 1) #t]
|
||||
[else
|
||||
(raise
|
||||
(make-exn:bug
|
||||
"reify-value: unknown boolean tag"
|
||||
rt))])]
|
||||
[else (make-data tl rt bs)]))]
|
||||
[(unison-data _ t (list gr bs0))
|
||||
#:when (= t ref-value-partial:tag)
|
||||
(let ([bs (map reify-value (chunked-list->list bs0))]
|
||||
@ -316,11 +333,18 @@
|
||||
(reify-vlit vl)]
|
||||
[(unison-data _ t (list bs0 k))
|
||||
#:when (= t ref-value-cont:tag)
|
||||
(raise "reify-value: unimplemented cont case")]
|
||||
(raise
|
||||
(make-exn:bug
|
||||
"reify-value: unimplemented cont case"
|
||||
ref-unit-unit))]
|
||||
[(unison-data r t fs)
|
||||
(raise "reify-value: unimplemented data case")]
|
||||
(raise
|
||||
(make-exn:bug
|
||||
"reify-value: unrecognized tag"
|
||||
ref-unit-unit))]
|
||||
[else
|
||||
(raise (format "reify-value: unknown tag"))]))
|
||||
(raise
|
||||
(make-exn:bug "reify-value: unrecognized value" v))]))
|
||||
|
||||
(define (reflect-typelink tl)
|
||||
(match tl
|
||||
@ -354,6 +378,11 @@
|
||||
|
||||
(define (reflect-value v)
|
||||
(match v
|
||||
[(? boolean?)
|
||||
(ref-value-data
|
||||
(reflect-typelink builtin-boolean:typelink)
|
||||
(if v 1 0) ; boolean pseudo-data tags
|
||||
empty-chunked-list)]
|
||||
[(? exact-nonnegative-integer?)
|
||||
(ref-value-vlit (ref-vlit-pos v))]
|
||||
[(? exact-integer?)
|
||||
|
@ -186,6 +186,29 @@
|
||||
builtin-TypeLink.toReference
|
||||
builtin-TypeLink.toReference:termlink
|
||||
|
||||
builtin-IO.UDP.clientSocket.impl.v1
|
||||
builtin-IO.UDP.clientSocket.impl.v1:termlink
|
||||
builtin-IO.UDP.UDPSocket.recv.impl.v1
|
||||
builtin-IO.UDP.UDPSocket.recv.impl.v1:termlink
|
||||
builtin-IO.UDP.UDPSocket.send.impl.v1
|
||||
builtin-IO.UDP.UDPSocket.send.impl.v1:termlink
|
||||
builtin-IO.UDP.UDPSocket.close.impl.v1
|
||||
builtin-IO.UDP.UDPSocket.close.impl.v1:termlink
|
||||
builtin-IO.UDP.ListenSocket.close.impl.v1
|
||||
builtin-IO.UDP.ListenSocket.close.impl.v1:termlink
|
||||
builtin-IO.UDP.UDPSocket.toText.impl.v1
|
||||
builtin-IO.UDP.UDPSocket.toText.impl.v1:termlink
|
||||
builtin-IO.UDP.serverSocket.impl.v1
|
||||
builtin-IO.UDP.serverSocket.impl.v1:termlink
|
||||
builtin-IO.UDP.ListenSocket.toText.impl.v1
|
||||
builtin-IO.UDP.ListenSocket.toText.impl.v1:termlink
|
||||
builtin-IO.UDP.ListenSocket.recvFrom.impl.v1
|
||||
builtin-IO.UDP.ListenSocket.recvFrom.impl.v1:termlink
|
||||
builtin-IO.UDP.ClientSockAddr.toText.v1
|
||||
builtin-IO.UDP.ClientSockAddr.toText.v1:termlink
|
||||
builtin-IO.UDP.ListenSocket.sendTo.impl.v1
|
||||
builtin-IO.UDP.ListenSocket.sendTo.impl.v1:termlink
|
||||
|
||||
unison-FOp-internal.dataTag
|
||||
unison-FOp-Char.toText
|
||||
; unison-FOp-Code.dependencies
|
||||
@ -314,13 +337,16 @@
|
||||
unison-FOp-Clock.internals.processCPUTime.v1
|
||||
unison-FOp-Clock.internals.realtime.v1
|
||||
unison-FOp-Clock.internals.monotonic.v1
|
||||
builtin-Clock.internals.systemTimeZone.v1
|
||||
builtin-Clock.internals.systemTimeZone.v1:termlink
|
||||
|
||||
|
||||
; unison-FOp-Value.serialize
|
||||
unison-FOp-IO.stdHandle
|
||||
unison-FOp-IO.getArgs.impl.v1
|
||||
|
||||
unison-FOp-IO.directoryContents.impl.v3
|
||||
builtin-IO.directoryContents.impl.v3
|
||||
builtin-IO.directoryContents.impl.v3:termlink
|
||||
unison-FOp-IO.systemTimeMicroseconds.v1
|
||||
|
||||
unison-FOp-ImmutableArray.copyTo!
|
||||
@ -645,6 +671,7 @@
|
||||
(unison murmurhash)
|
||||
(unison tls)
|
||||
(unison tcp)
|
||||
(unison udp)
|
||||
(unison gzip)
|
||||
(unison zlib)
|
||||
(unison concurrent)
|
||||
@ -732,6 +759,7 @@
|
||||
(define-builtin-link IO.getEnv.impl.v1)
|
||||
(define-builtin-link IO.getChar.impl.v1)
|
||||
(define-builtin-link IO.getCurrentDirectory.impl.v3)
|
||||
(define-builtin-link IO.directoryContents.impl.v3)
|
||||
(define-builtin-link IO.removeDirectory.impl.v3)
|
||||
(define-builtin-link IO.renameFile.impl.v3)
|
||||
(define-builtin-link IO.createTempDirectory.impl.v3)
|
||||
@ -758,6 +786,7 @@
|
||||
(define-builtin-link Char.Class.is)
|
||||
(define-builtin-link Scope.bytearrayOf)
|
||||
(define-builtin-link unsafe.coerceAbilities)
|
||||
(define-builtin-link Clock.internals.systemTimeZone.v1)
|
||||
|
||||
(begin-encourage-inline
|
||||
(define-unison (builtin-Value.toBuiltin v) (unison-quote v))
|
||||
@ -902,11 +931,13 @@
|
||||
(define (unison-POp-LEQT s t) (bool (chunked-string<? s t)))
|
||||
(define (unison-POp-EQLU x y) (bool (universal=? x y)))
|
||||
(define (unison-POp-EROR fnm x)
|
||||
(let-values ([(p g) (open-string-output-port)])
|
||||
(put-string p (chunked-string->string fnm))
|
||||
(let-values
|
||||
([(p g) (open-string-output-port)]
|
||||
[(snm) (chunked-string->string fnm)])
|
||||
(put-string p snm)
|
||||
(put-string p ": ")
|
||||
(display (describe-value x) p)
|
||||
(raise (make-exn:bug fnm x))))
|
||||
(raise (make-exn:bug snm x))))
|
||||
(define (unison-POp-FTOT f)
|
||||
(define base (number->string f))
|
||||
(define dotted
|
||||
@ -1095,11 +1126,6 @@
|
||||
(define (unison-FOp-IO.getArgs.impl.v1)
|
||||
(sum 1 (cdr (command-line))))
|
||||
|
||||
(define (unison-FOp-IO.directoryContents.impl.v3 path)
|
||||
(reify-exn
|
||||
(lambda ()
|
||||
(sum 1 (directory-contents path)))))
|
||||
|
||||
(define unison-FOp-IO.systemTimeMicroseconds.v1 current-microseconds)
|
||||
|
||||
;; TODO should we convert Bytes -> Text directly without the intermediate conversions?
|
||||
@ -1129,13 +1155,6 @@
|
||||
(close-output-port h))
|
||||
(right none))
|
||||
|
||||
(define (unison-FOp-IO.openFile.impl.v3 fn mode)
|
||||
(right (case mode
|
||||
[(0) (open-file-input-port (chunked-string->string fn))]
|
||||
[(1) (open-file-output-port (chunked-string->string fn))]
|
||||
[(2) (open-file-output-port (chunked-string->string fn) 'no-truncate)]
|
||||
[else (open-file-input/output-port (chunked-string->string fn))])))
|
||||
|
||||
(define (unison-FOp-Text.repeat n t)
|
||||
(let loop ([cnt 0]
|
||||
[acc empty-chunked-string])
|
||||
@ -1470,6 +1489,7 @@
|
||||
(declare-builtin-link builtin-IO.getArgs.impl.v1)
|
||||
(declare-builtin-link builtin-IO.getEnv.impl.v1)
|
||||
(declare-builtin-link builtin-IO.getChar.impl.v1)
|
||||
(declare-builtin-link builtin-IO.directoryContents.impl.v3)
|
||||
(declare-builtin-link builtin-IO.getCurrentDirectory.impl.v3)
|
||||
(declare-builtin-link builtin-IO.removeDirectory.impl.v3)
|
||||
(declare-builtin-link builtin-IO.renameFile.impl.v3)
|
||||
@ -1495,4 +1515,5 @@
|
||||
(declare-builtin-link builtin-Char.Class.is)
|
||||
(declare-builtin-link builtin-Pattern.many.corrected)
|
||||
(declare-builtin-link builtin-unsafe.coerceAbilities)
|
||||
(declare-builtin-link builtin-Clock.internals.systemTimeZone.v1)
|
||||
)
|
||||
|
@ -103,6 +103,17 @@
|
||||
(sandbox-builtin "IO.getFileSize.impl.v3")
|
||||
(sandbox-builtin "IO.serverSocket.impl.v3")
|
||||
(sandbox-builtin "Socket.toText")
|
||||
(sandbox-builtin "UDP.clientSocket.impl.v1")
|
||||
(sandbox-builtin "UDP.serverSocket.impl.v1")
|
||||
(sandbox-builtin "UDP.UDPSocket.close.impl.v1")
|
||||
(sandbox-builtin "UDP.UDPSocket.recv.impl.v1")
|
||||
(sandbox-builtin "UDP.UDPSocket.send.impl.v1")
|
||||
(sandbox-builtin "UDP.ListenSocket.close.impl.v1")
|
||||
(sandbox-builtin "UDP.UDPSocket.toText.impl.v1")
|
||||
(sandbox-builtin "UDP.ListenSocket.toText.impl.v1")
|
||||
(sandbox-builtin "UDP.ListenSocket.recvFrom.impl.v1")
|
||||
(sandbox-builtin "UDP.ClientSockAddr.toText.v1")
|
||||
(sandbox-builtin "UDP.ListenSocket.sendTo.impl.v1")
|
||||
(sandbox-builtin "Handle.toText")
|
||||
(sandbox-builtin "ThreadId.toText")
|
||||
(sandbox-builtin "IO.socketPort.impl.v3")
|
||||
|
@ -6,6 +6,7 @@
|
||||
unison/data
|
||||
unison/data-info
|
||||
unison/chunked-seq
|
||||
unison/network-utils
|
||||
unison/core)
|
||||
|
||||
(provide
|
||||
@ -25,29 +26,6 @@
|
||||
|
||||
(struct socket-pair (input output))
|
||||
|
||||
(define (handle-errors fn)
|
||||
(with-handlers
|
||||
[[exn:fail:network?
|
||||
(lambda (e)
|
||||
(exception
|
||||
ref-iofailure:typelink
|
||||
(exception->string e)
|
||||
ref-unit-unit))]
|
||||
[exn:fail:contract?
|
||||
(lambda (e)
|
||||
(exception
|
||||
ref-miscfailure:typelink
|
||||
(exception->string e)
|
||||
ref-unit-unit))]
|
||||
[(lambda _ #t)
|
||||
(lambda (e)
|
||||
(exception
|
||||
ref-miscfailure:typelink
|
||||
(chunked-string->string
|
||||
(format "Unknown exception ~a" (exn->string e)))
|
||||
ref-unit-unit))]]
|
||||
(fn)))
|
||||
|
||||
(define (closeSocket.impl.v3 socket)
|
||||
(handle-errors
|
||||
(lambda ()
|
||||
|
179
scheme-libs/racket/unison/udp.rkt
Normal file
179
scheme-libs/racket/unison/udp.rkt
Normal file
@ -0,0 +1,179 @@
|
||||
; UDP primitives!
|
||||
#lang racket/base
|
||||
(require racket/udp
|
||||
racket/format
|
||||
(only-in unison/boot define-unison)
|
||||
unison/data
|
||||
unison/data-info
|
||||
unison/chunked-seq
|
||||
(only-in unison/boot sum-case)
|
||||
unison/network-utils
|
||||
unison/core)
|
||||
|
||||
(provide
|
||||
(prefix-out
|
||||
builtin-IO.UDP.
|
||||
(combine-out
|
||||
clientSocket.impl.v1
|
||||
clientSocket.impl.v1:termlink
|
||||
UDPSocket.recv.impl.v1
|
||||
UDPSocket.recv.impl.v1:termlink
|
||||
UDPSocket.send.impl.v1
|
||||
UDPSocket.send.impl.v1:termlink
|
||||
UDPSocket.close.impl.v1
|
||||
UDPSocket.close.impl.v1:termlink
|
||||
ListenSocket.close.impl.v1
|
||||
ListenSocket.close.impl.v1:termlink
|
||||
UDPSocket.toText.impl.v1
|
||||
UDPSocket.toText.impl.v1:termlink
|
||||
serverSocket.impl.v1
|
||||
serverSocket.impl.v1:termlink
|
||||
ListenSocket.toText.impl.v1
|
||||
ListenSocket.toText.impl.v1:termlink
|
||||
ListenSocket.recvFrom.impl.v1
|
||||
ListenSocket.recvFrom.impl.v1:termlink
|
||||
ClientSockAddr.toText.v1
|
||||
ClientSockAddr.toText.v1:termlink
|
||||
ListenSocket.sendTo.impl.v1
|
||||
ListenSocket.sendTo.impl.v1:termlink)))
|
||||
|
||||
|
||||
(struct client-sock-addr (host port))
|
||||
|
||||
; Haskell's Network.UDP choice of buffer size is 2048, so mirror that here
|
||||
(define buffer-size 2048)
|
||||
|
||||
(define ; a -> Either Failure a
|
||||
(wrap-in-either a)
|
||||
(sum-case a
|
||||
(0 (type msg meta)
|
||||
(ref-either-left (ref-failure-failure type msg (unison-any-any meta))))
|
||||
(1 (data)
|
||||
(ref-either-right data))))
|
||||
|
||||
(define
|
||||
(format-socket socket)
|
||||
(let*-values ([(local-hn local-port remote-hn remote-port) (udp-addresses socket #t)]
|
||||
[(rv) (~a "<socket local=" local-hn ":" local-port " remote=" remote-hn ":" remote-port ">")])
|
||||
(string->chunked-string rv)))
|
||||
|
||||
(define (close-socket socket)
|
||||
(let ([rv (handle-errors (lambda() (begin
|
||||
(udp-close socket)
|
||||
(right ref-unit-unit))))])
|
||||
(wrap-in-either rv)))
|
||||
|
||||
;; define termlink builtins
|
||||
(define clientSocket.impl.v1:termlink
|
||||
(unison-termlink-builtin "IO.UDP.clientSocket.impl.v1"))
|
||||
(define UDPSocket.recv.impl.v1:termlink
|
||||
(unison-termlink-builtin "IO.UDP.UDPSocket.recv.impl.v1"))
|
||||
(define UDPSocket.send.impl.v1:termlink
|
||||
(unison-termlink-builtin "IO.UDP.UDPSocket.send.impl.v1"))
|
||||
(define UDPSocket.close.impl.v1:termlink
|
||||
(unison-termlink-builtin "IO.UDP.UDPSocket.close.impl.v1"))
|
||||
(define ListenSocket.close.impl.v1:termlink
|
||||
(unison-termlink-builtin "IO.UDP.ListenSocket.close.impl.v1"))
|
||||
(define UDPSocket.toText.impl.v1:termlink
|
||||
(unison-termlink-builtin "IO.UDP.UDPSocket.toText.impl.v1"))
|
||||
(define serverSocket.impl.v1:termlink
|
||||
(unison-termlink-builtin "IO.UDP.serverSocket.impl.v1"))
|
||||
(define ListenSocket.toText.impl.v1:termlink
|
||||
(unison-termlink-builtin "IO.UDP.ListenSocket.toText.impl.v1"))
|
||||
(define ListenSocket.recvFrom.impl.v1:termlink
|
||||
(unison-termlink-builtin "IO.UDP.ListenSocket.recvFrom.impl.v1"))
|
||||
(define ClientSockAddr.toText.v1:termlink
|
||||
(unison-termlink-builtin "IO.UDP.ClientSockAddr.toText.v1"))
|
||||
(define ListenSocket.sendTo.impl.v1:termlink
|
||||
(unison-termlink-builtin "IO.UDP.ListenSocket.sendTo.impl.v1"))
|
||||
|
||||
;; define builtins
|
||||
|
||||
(define-unison
|
||||
(UDPSocket.recv.impl.v1 socket) ; socket -> Either Failure Bytes
|
||||
(let
|
||||
([rv (handle-errors (lambda()
|
||||
(let*-values
|
||||
([(buffer) (make-bytes buffer-size)]
|
||||
[(len a b) (udp-receive! socket buffer)])
|
||||
(right (bytes->chunked-bytes (subbytes buffer 0 len))))))])
|
||||
(wrap-in-either rv)))
|
||||
|
||||
(define-unison
|
||||
(ListenSocket.close.impl.v1 socket) ; socket -> Either Failure ()
|
||||
(close-socket socket))
|
||||
|
||||
(define-unison
|
||||
(serverSocket.impl.v1 ip port) ; string string -> Either Failure socket
|
||||
(let
|
||||
([result (handle-errors (lambda()
|
||||
(let* ([iip (chunked-string->string ip)]
|
||||
[pport (string->number (chunked-string->string port))]
|
||||
[sock (udp-open-socket iip pport)])
|
||||
(begin
|
||||
(udp-bind! sock iip pport)
|
||||
(right sock)))))])
|
||||
(wrap-in-either result)))
|
||||
|
||||
(define-unison
|
||||
(ListenSocket.recvFrom.impl.v1 socket) ; socket -> Either Failure (Bytes, ClientSockAddr)
|
||||
(let ([result (handle-errors (lambda()
|
||||
(if (not (udp? socket))
|
||||
(raise-argument-error 'socket "a UDP socket" socket)
|
||||
(let*-values
|
||||
([(buffer) (make-bytes buffer-size)]
|
||||
[(len host port) (udp-receive! socket buffer)]
|
||||
[(csa) (client-sock-addr host port)]
|
||||
[(bs) (subbytes buffer 0 len)]
|
||||
[(chunked) (bytes->chunked-bytes bs)])
|
||||
(right (ref-tuple-pair chunked (ref-tuple-pair csa ref-unit-unit)))))))])
|
||||
(wrap-in-either result)))
|
||||
|
||||
(define-unison
|
||||
(UDPSocket.send.impl.v1 socket data) ; socket -> Bytes -> Either Failure ()
|
||||
(let
|
||||
([result (handle-errors (lambda () (begin
|
||||
(udp-send socket (chunked-bytes->bytes data))
|
||||
(right ref-unit-unit))))])
|
||||
(wrap-in-either result)))
|
||||
|
||||
(define-unison
|
||||
(ListenSocket.sendTo.impl.v1 sock bytes addr) ; socket -> Bytes -> ClientSockAddr -> Either Failure ()
|
||||
(let
|
||||
([result (handle-errors (lambda()
|
||||
(let* ([host (client-sock-addr-host addr)]
|
||||
[port (client-sock-addr-port addr)]
|
||||
[bytes (chunked-bytes->bytes bytes)])
|
||||
(begin
|
||||
(udp-send-to sock host port bytes)
|
||||
(right ref-unit-unit)))))])
|
||||
(wrap-in-either result)))
|
||||
|
||||
(define-unison
|
||||
(UDPSocket.toText.impl.v1 socket) ; socket -> string
|
||||
(format-socket socket))
|
||||
|
||||
(define-unison
|
||||
(ClientSockAddr.toText.v1 addr) ; ClientSocketAddr -> string
|
||||
(string->chunked-string (format "<client-sock-addr ~a ~a>" (client-sock-addr-host addr) (client-sock-addr-port addr))))
|
||||
|
||||
(define-unison
|
||||
(ListenSocket.toText.impl.v1 socket) ; socket -> string
|
||||
(format-socket socket))
|
||||
|
||||
(define-unison
|
||||
(UDPSocket.close.impl.v1 socket) ; socket -> Either Failure ()
|
||||
(let
|
||||
([rv (handle-errors (lambda() (begin
|
||||
(udp-close socket)
|
||||
(right ref-unit-unit))))])
|
||||
(wrap-in-either rv)))
|
||||
|
||||
(define-unison
|
||||
(clientSocket.impl.v1 host port) ; string string -> Either Failure socket
|
||||
(let ([rv (handle-errors (lambda() (let* ([pport (string->number (chunked-string->string port))]
|
||||
[hhost (chunked-string->string host)]
|
||||
[sock (udp-open-socket hhost pport)]
|
||||
[_ (udp-bind! sock #f 0)]
|
||||
[res (udp-connect! sock hhost pport)]) (right sock))))])
|
||||
(wrap-in-either rv)))
|
@ -22,7 +22,7 @@ getHash() {
|
||||
if [[ -z "$name" ]]; then
|
||||
name="${parts[i]}"
|
||||
else
|
||||
name="$name/${parts[i]}"
|
||||
name="$name%2F${parts[i]}"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
@ -66,6 +66,7 @@ extra-deps:
|
||||
- lsp-2.2.0.0@sha256:82fbf4b69d94d8d22543be71f89986b3e90050032d671fb3de3f8253ea1e5b6f,3550
|
||||
- lsp-types-2.0.2.0@sha256:a9a51c3cea0726d91fe63fa0670935ee720f7b31bc3f3b33b2483fc538152677,29421
|
||||
- row-types-1.0.1.2@sha256:4d4c7cb95d06a32b28ba977852d52a26b4c1f695ef083a6fd874ab6d79933b64,3071
|
||||
- network-udp-0.0.0
|
||||
|
||||
ghc-options:
|
||||
# All packages
|
||||
|
@ -82,6 +82,13 @@ packages:
|
||||
size: 1060
|
||||
original:
|
||||
hackage: row-types-1.0.1.2@sha256:4d4c7cb95d06a32b28ba977852d52a26b4c1f695ef083a6fd874ab6d79933b64,3071
|
||||
- completed:
|
||||
hackage: network-udp-0.0.0@sha256:408d2d4fa1a25e49e95752ee124cca641993404bb133ae10fb81daef22d876ae,1075
|
||||
pantry-tree:
|
||||
sha256: ee19a66c9d420861c5cc1dfad3210e2a53cdc6088ff3dd90b44f7961f5caebee
|
||||
size: 284
|
||||
original:
|
||||
hackage: network-udp-0.0.0
|
||||
snapshots:
|
||||
- completed:
|
||||
sha256: 5a59b2a405b3aba3c00188453be172b85893cab8ebc352b1ef58b0eae5d248a2
|
||||
|
@ -51,6 +51,7 @@ dependencies:
|
||||
- mtl
|
||||
- network
|
||||
- network-simple
|
||||
- network-udp
|
||||
- network-uri
|
||||
- nonempty-containers
|
||||
- open-browser
|
||||
|
@ -13,7 +13,9 @@ import Data.IORef
|
||||
import Data.Text qualified as Text
|
||||
import Data.Text.IO qualified as Text
|
||||
import Ki qualified
|
||||
import System.Console.Haskeline (Settings (autoAddHistory))
|
||||
import System.Console.Haskeline qualified as Line
|
||||
import System.Console.Haskeline.History qualified as Line
|
||||
import System.IO (hGetEcho, hPutStrLn, hSetEcho, stderr, stdin)
|
||||
import System.IO.Error (isDoesNotExistError)
|
||||
import U.Codebase.HashTags (CausalHash)
|
||||
@ -102,17 +104,27 @@ getUserInput codebase authHTTPClient currentPath numberedArgs =
|
||||
ws -> do
|
||||
liftIO (parseInput codebase currentPath numberedArgs IP.patternMap ws) >>= \case
|
||||
Left msg -> do
|
||||
-- We still add history that failed to parse so the user can easily reload
|
||||
-- the input and fix it.
|
||||
Line.modifyHistory $ Line.addHistoryUnlessConsecutiveDupe $ l
|
||||
liftIO $ putPrettyLn msg
|
||||
go
|
||||
Right Nothing -> do
|
||||
-- Ctrl-c or some input cancel, re-run the prompt
|
||||
go
|
||||
Right (Just (expandedArgs, i)) -> do
|
||||
let expandedArgsStr = unwords expandedArgs
|
||||
when (expandedArgs /= ws) $ do
|
||||
liftIO . putStrLn $ fullPrompt <> unwords expandedArgs
|
||||
liftIO . putStrLn $ fullPrompt <> expandedArgsStr
|
||||
Line.modifyHistory $ Line.addHistoryUnlessConsecutiveDupe $ unwords expandedArgs
|
||||
pure i
|
||||
settings :: Line.Settings IO
|
||||
settings = Line.Settings tabComplete (Just ".unisonHistory") True
|
||||
settings =
|
||||
Line.Settings
|
||||
{ complete = tabComplete,
|
||||
historyFile = Just ".unisonHistory",
|
||||
autoAddHistory = False
|
||||
}
|
||||
tabComplete = haskelineTabComplete IP.patternMap codebase authHTTPClient currentPath
|
||||
|
||||
main ::
|
||||
|
@ -217,6 +217,7 @@ library
|
||||
, mtl
|
||||
, network
|
||||
, network-simple
|
||||
, network-udp
|
||||
, network-uri
|
||||
, nonempty-containers
|
||||
, open-browser
|
||||
@ -358,6 +359,7 @@ executable transcripts
|
||||
, mtl
|
||||
, network
|
||||
, network-simple
|
||||
, network-udp
|
||||
, network-uri
|
||||
, nonempty-containers
|
||||
, open-browser
|
||||
@ -507,6 +509,7 @@ test-suite cli-tests
|
||||
, mtl
|
||||
, network
|
||||
, network-simple
|
||||
, network-udp
|
||||
, network-uri
|
||||
, nonempty-containers
|
||||
, open-browser
|
||||
|
@ -15,6 +15,19 @@ import Unison.LabeledDependency qualified as LD
|
||||
import Unison.Name qualified as Name
|
||||
import Unison.Names.ResolutionResult qualified as Names
|
||||
import Unison.Prelude
|
||||
( Const (Const, getConst),
|
||||
Generic,
|
||||
Generic1,
|
||||
Identity (runIdentity),
|
||||
Map,
|
||||
Set,
|
||||
Text,
|
||||
foldl',
|
||||
join,
|
||||
sortOn,
|
||||
($>),
|
||||
(<&>),
|
||||
)
|
||||
import Unison.Reference (TypeReference)
|
||||
import Unison.Reference qualified as Reference
|
||||
import Unison.Settings qualified as Settings
|
||||
@ -269,6 +282,11 @@ filePathRef = Reference.Builtin "FilePath"
|
||||
threadIdRef = Reference.Builtin "ThreadId"
|
||||
socketRef = Reference.Builtin "Socket"
|
||||
|
||||
udpSocketRef, udpListenSocketRef, udpClientSockAddrRef :: TypeReference
|
||||
udpSocketRef = Reference.Builtin "UDPSocket"
|
||||
udpListenSocketRef = Reference.Builtin "ListenSocket"
|
||||
udpClientSockAddrRef = Reference.Builtin "ClientSockAddr"
|
||||
|
||||
processHandleRef :: TypeReference
|
||||
processHandleRef = Reference.Builtin "ProcessHandle"
|
||||
|
||||
@ -388,6 +406,15 @@ mbytearrayType a = ref a mbytearrayRef
|
||||
socket :: (Ord v) => a -> Type v a
|
||||
socket a = ref a socketRef
|
||||
|
||||
udpSocket :: (Ord v) => a -> Type v a
|
||||
udpSocket a = ref a udpSocketRef
|
||||
|
||||
udpListenSocket :: (Ord v) => a -> Type v a
|
||||
udpListenSocket a = ref a udpListenSocketRef
|
||||
|
||||
udpClientSockAddr :: (Ord v) => a -> Type v a
|
||||
udpClientSockAddr a = ref a udpClientSockAddrRef
|
||||
|
||||
list :: (Ord v) => a -> Type v a
|
||||
list a = ref a listRef
|
||||
|
||||
|
@ -9,6 +9,7 @@ import Control.Monad.Writer.Class qualified as Writer
|
||||
import Control.Monad.Writer.Lazy (runWriterT)
|
||||
import Data.Char qualified as Char
|
||||
import Data.Foldable
|
||||
import Data.List (intersperse)
|
||||
import Data.Map (Map)
|
||||
import Data.Map qualified as Map
|
||||
import Data.Maybe
|
||||
@ -357,7 +358,8 @@ toHtml docNamesByRef document =
|
||||
[d] ->
|
||||
currentSectionLevelToHtml d
|
||||
ds ->
|
||||
span_ [class_ "span"] <$> renderSequence currentSectionLevelToHtml (mergeWords " " ds)
|
||||
span_ [class_ "span"]
|
||||
<$> (renderSequence currentSectionLevelToHtml (intersperse (Word " ") (mergeWords " " ds)))
|
||||
BulletedList items ->
|
||||
let itemToHtml i =
|
||||
li_ [] <$> currentSectionLevelToHtml i
|
||||
|
@ -49,3 +49,18 @@ foo = do
|
||||
()
|
||||
|
||||
```
|
||||
This can also only be tested by separately running this test, because
|
||||
it is exercising the protocol that ucm uses to talk to the jit during
|
||||
an exception.
|
||||
|
||||
```ucm
|
||||
runtime-tests/selected> run.native testBug
|
||||
|
||||
💔💥
|
||||
|
||||
I've encountered a call to builtin.bug with the following
|
||||
value:
|
||||
|
||||
"testing"
|
||||
|
||||
```
|
||||
|
@ -34,3 +34,11 @@ foo = do
|
||||
.> run.native foo
|
||||
.> run.native foo
|
||||
```
|
||||
|
||||
This can also only be tested by separately running this test, because
|
||||
it is exercising the protocol that ucm uses to talk to the jit during
|
||||
an exception.
|
||||
|
||||
```ucm:error
|
||||
runtime-tests/selected> run.native testBug
|
||||
```
|
||||
|
66
unison-src/builtin-tests/udp-tests.u
Normal file
66
unison-src/builtin-tests/udp-tests.u
Normal file
@ -0,0 +1,66 @@
|
||||
UDP.client' h p = Either.toException (##IO.UDP.clientSocket.impl.v1 h p)
|
||||
UDP.server' i p = Either.toException (##IO.UDP.serverSocket.impl.v1 i p)
|
||||
closeClient' = ##IO.UDP.UDPSocket.close.impl.v1 >> Either.toException
|
||||
send' s b = Either.toException (##IO.UDP.UDPSocket.send.impl.v1 s b)
|
||||
closeServer' = ##IO.UDP.ListenSocket.close.impl.v1 >> Either.toException
|
||||
sendTo' s b a = Either.toException (##IO.UDP.ListenSocket.sendTo.impl.v1 s b a)
|
||||
recvFrom' = ##IO.UDP.ListenSocket.recvFrom.impl.v1 >> Either.toException
|
||||
recv' = ##IO.UDP.UDPSocket.recv.impl.v1 >> Either.toException
|
||||
|
||||
badPort = "what"
|
||||
badIp = "what"
|
||||
goodPort = "8000"
|
||||
goodIp = "127.0.0.1"
|
||||
|
||||
shouldFail fn =
|
||||
result = catchAll fn
|
||||
isLeft result
|
||||
|
||||
udp.tests = do
|
||||
check "client rejects invalid port" do shouldFail do UDP.client' goodIp badPort
|
||||
check "server rejects invalid port" do shouldFail do UDP.server' goodIp badPort
|
||||
check "server rejects invalid IP address" do shouldFail do UDP.server' badIp goodPort
|
||||
check "client: no send after close" do shouldFail do
|
||||
socket = UDP.client' goodIp goodPort
|
||||
closeClient' socket
|
||||
send' socket (toUtf8 "hello") -- should fail here
|
||||
check "server no send after close" do shouldFail do
|
||||
ssocket = UDP.server' goodIp goodPort
|
||||
csocket = UDP.client' goodIp goodPort
|
||||
send' csocket (toUtf8 "hello")
|
||||
(_, clientSockAddr) = recvFrom' ssocket
|
||||
closeServer' ssocket
|
||||
sendTo' ssocket (toUtf8 "hello") clientSockAddr -- should fail here
|
||||
check "no receive after close" do shouldFail do
|
||||
socket = UDP.client' goodIp goodPort
|
||||
closeClient' socket
|
||||
recv' socket
|
||||
!testServerAndClient
|
||||
|
||||
testServerAndClient = do
|
||||
fromServerMsg = "from server"
|
||||
fromClientMsg = "from client"
|
||||
setup = catchAll do
|
||||
UDP.server' goodIp goodPort
|
||||
match setup with
|
||||
Left e ->
|
||||
Tests.fail "Unable to open a socket for UDP server" (Debug.evalToText e)
|
||||
Right ssocket ->
|
||||
serve = do
|
||||
(data, sockAddr) = recvFrom' ssocket
|
||||
sendTo' ssocket (toUtf8 fromServerMsg) sockAddr
|
||||
closeServer' ssocket
|
||||
fromUtf8 data
|
||||
|
||||
serveResult = !Promise.new
|
||||
_ = fork do Promise.write serveResult (catchAll serve)
|
||||
|
||||
data = catchAll do
|
||||
csocket = UDP.client' goodIp goodPort
|
||||
send' csocket (toUtf8 fromClientMsg)
|
||||
d = recv' csocket
|
||||
closeClient' csocket
|
||||
fromUtf8 d
|
||||
|
||||
checkEqual "Server received data" (Promise.read serveResult) (Right fromClientMsg)
|
||||
checkEqual "Client received data" data (Right fromServerMsg)
|
@ -5,7 +5,7 @@ Next, we'll download the jit project and generate a few Racket files from it.
|
||||
|
||||
```ucm
|
||||
.> project.create-empty jit-setup
|
||||
jit-setup/main> pull @unison/internal/releases/0.0.15 lib.jit
|
||||
jit-setup/main> pull @unison/internal/releases/0.0.16 lib.jit
|
||||
```
|
||||
|
||||
```unison
|
||||
|
@ -20,9 +20,9 @@ Next, we'll download the jit project and generate a few Racket files from it.
|
||||
|
||||
🎉 🥳 Happy coding!
|
||||
|
||||
jit-setup/main> pull @unison/internal/releases/0.0.15 lib.jit
|
||||
jit-setup/main> pull @unison/internal/releases/0.0.16 lib.jit
|
||||
|
||||
Downloaded 15060 entities.
|
||||
Downloaded 15091 entities.
|
||||
|
||||
✅
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -178,21 +178,21 @@ Stream.collect s =
|
||||
handle !s with Stream.collect.handler
|
||||
|
||||
|
||||
-- An ability that facilitates creating temoporary directories that can be
|
||||
-- An ability that facilitates creating temoporary directories that can be
|
||||
-- automatically cleaned up
|
||||
structural ability TempDirs where
|
||||
newTempDir: Text -> Text
|
||||
removeDir: Text -> ()
|
||||
|
||||
-- A handler for TempDirs which cleans up temporary directories
|
||||
-- This will be useful for IO tests which need to interact with
|
||||
-- This will be useful for IO tests which need to interact with
|
||||
-- the filesystem
|
||||
|
||||
autoCleaned.handler: '{io2.IO} (Request {TempDirs} r -> r)
|
||||
autoCleaned.handler _ =
|
||||
remover : [Text] -> {io2.IO} ()
|
||||
remover = cases
|
||||
a +: as -> match removeDirectory.impl a with
|
||||
a +: as -> match removeDirectory.impl a with
|
||||
Left (Failure _ e _) -> watch e ()
|
||||
_ -> ()
|
||||
remover as
|
||||
@ -277,12 +277,12 @@ putBytes = compose2 reraise putBytes.impl
|
||||
getLine = compose reraise getLine.impl
|
||||
systemTime = compose reraise systemTime.impl
|
||||
decodeCert = compose reraise decodeCert.impl
|
||||
serverSocket = compose2 reraise serverSocket.impl
|
||||
serverSocket = compose2 reraise IO.serverSocket.impl
|
||||
listen = compose reraise listen.impl
|
||||
handshake = compose reraise handshake.impl
|
||||
send = compose2 reraise send.impl
|
||||
handshake = compose reraise handshake.impl
|
||||
send = compose2 reraise Tls.send.impl
|
||||
closeSocket = compose reraise closeSocket.impl
|
||||
clientSocket = compose2 reraise clientSocket.impl
|
||||
clientSocket = compose2 reraise IO.clientSocket.impl
|
||||
receive = compose reraise receive.impl
|
||||
terminate = compose reraise terminate.impl
|
||||
newServer = compose2 reraise newServer.impl
|
||||
@ -451,4 +451,3 @@ saveTestCase name ver f i =
|
||||
saveSelfContained (f, i) sfile
|
||||
writeFile ofile (toUtf8 output)
|
||||
writeFile hfile (Bytes.toBase32 (crypto.hash Sha3_512 (f, i)))
|
||||
|
||||
|
@ -145,6 +145,11 @@ And here's the full API:
|
||||
15. hashBytes : HashAlgorithm -> Bytes -> Bytes
|
||||
16. hmac : HashAlgorithm -> Bytes -> a -> Bytes
|
||||
17. hmacBytes : HashAlgorithm -> Bytes -> Bytes -> Bytes
|
||||
18. Rsa.sign.impl : Bytes -> Bytes -> Either Failure Bytes
|
||||
19. Rsa.verify.impl : Bytes
|
||||
-> Bytes
|
||||
-> Bytes
|
||||
-> Either Failure Boolean
|
||||
|
||||
|
||||
```
|
||||
|
@ -1,9 +1,9 @@
|
||||
```unison:hide
|
||||
serverSocket = compose2 reraise serverSocket.impl
|
||||
serverSocket = compose2 reraise IO.serverSocket.impl
|
||||
socketPort = compose reraise socketPort.impl
|
||||
listen = compose reraise listen.impl
|
||||
closeSocket = compose reraise closeSocket.impl
|
||||
clientSocket = compose2 reraise clientSocket.impl
|
||||
clientSocket = compose2 reraise IO.clientSocket.impl
|
||||
socketSend = compose2 reraise socketSend.impl
|
||||
socketReceive = compose2 reraise socketReceive.impl
|
||||
socketAccept = compose reraise socketAccept.impl
|
||||
@ -36,11 +36,11 @@ stored in `/etc/services` and queried with the `getent` tool:
|
||||
# map number to name
|
||||
$ getent services 22
|
||||
ssh 22/tcp
|
||||
|
||||
|
||||
# map name to number
|
||||
$ getent services finger
|
||||
finger 79/tcp
|
||||
|
||||
|
||||
# get a list of all known names
|
||||
$ getent services | head
|
||||
tcpmux 1/tcp
|
||||
@ -58,35 +58,35 @@ Below shows different examples of how we might specify the server coordinates.
|
||||
|
||||
``` unison
|
||||
testExplicitHost : '{io2.IO} [Result]
|
||||
testExplicitHost _ =
|
||||
testExplicitHost _ =
|
||||
test = 'let
|
||||
sock = serverSocket (Some "127.0.0.1") "1028"
|
||||
emit (Ok "successfully created socket")
|
||||
port = socketPort sock
|
||||
putBytes (stdHandle StdOut) (toUtf8 (toText port))
|
||||
expectU "should have bound to port 1028" 1028 port
|
||||
expectU "should have bound to port 1028" 1028 port
|
||||
|
||||
runTest test
|
||||
|
||||
testDefaultHost : '{io2.IO} [Result]
|
||||
testDefaultHost _ =
|
||||
testDefaultHost _ =
|
||||
test = 'let
|
||||
sock = serverSocket None "1028"
|
||||
emit (Ok "successfully created socket")
|
||||
port = socketPort sock
|
||||
putBytes (stdHandle StdOut) (toUtf8 (toText port))
|
||||
expectU "should have bound to port 1028" 1028 port
|
||||
expectU "should have bound to port 1028" 1028 port
|
||||
|
||||
runTest test
|
||||
|
||||
testDefaultPort : '{io2.IO} [Result]
|
||||
testDefaultPort _ =
|
||||
testDefaultPort _ =
|
||||
test = 'let
|
||||
sock = serverSocket None "0"
|
||||
emit (Ok "successfully created socket")
|
||||
port = socketPort sock
|
||||
putBytes (stdHandle StdOut) (toUtf8 (toText port))
|
||||
|
||||
|
||||
check "port should be > 1024" (1024 < port)
|
||||
check "port should be < 65536" (65536 > port)
|
||||
|
||||
@ -113,7 +113,7 @@ serverThread portVar toSend = 'let
|
||||
socketSend sock' (toUtf8 toSend)
|
||||
closeSocket sock'
|
||||
|
||||
match (toEither go) with
|
||||
match (toEither go) with
|
||||
Left (Failure _ t _) -> watch t ()
|
||||
_ -> ()
|
||||
|
||||
@ -130,24 +130,24 @@ clientThread portVar resultVar = 'let
|
||||
_ -> ()
|
||||
|
||||
testTcpConnect : '{io2.IO}[Result]
|
||||
testTcpConnect = 'let
|
||||
testTcpConnect = 'let
|
||||
test = 'let
|
||||
portVar = !MVar.newEmpty
|
||||
resultVar = !MVar.newEmpty
|
||||
|
||||
|
||||
toSend = "12345"
|
||||
|
||||
void (forkComp (serverThread portVar toSend))
|
||||
void (forkComp (clientThread portVar resultVar))
|
||||
|
||||
|
||||
received = take resultVar
|
||||
|
||||
expectU "should have reaped what we've sown" toSend received
|
||||
|
||||
|
||||
runTest test
|
||||
|
||||
|
||||
```
|
||||
```ucm
|
||||
```ucm
|
||||
|
||||
.> add
|
||||
.> io.test testTcpConnect
|
||||
|
@ -1,9 +1,9 @@
|
||||
```unison
|
||||
serverSocket = compose2 reraise serverSocket.impl
|
||||
serverSocket = compose2 reraise IO.serverSocket.impl
|
||||
socketPort = compose reraise socketPort.impl
|
||||
listen = compose reraise listen.impl
|
||||
closeSocket = compose reraise closeSocket.impl
|
||||
clientSocket = compose2 reraise clientSocket.impl
|
||||
clientSocket = compose2 reraise IO.clientSocket.impl
|
||||
socketSend = compose2 reraise socketSend.impl
|
||||
socketReceive = compose2 reraise socketReceive.impl
|
||||
socketAccept = compose reraise socketAccept.impl
|
||||
@ -34,11 +34,11 @@ stored in `/etc/services` and queried with the `getent` tool:
|
||||
# map number to name
|
||||
$ getent services 22
|
||||
ssh 22/tcp
|
||||
|
||||
|
||||
# map name to number
|
||||
$ getent services finger
|
||||
finger 79/tcp
|
||||
|
||||
|
||||
# get a list of all known names
|
||||
$ getent services | head
|
||||
tcpmux 1/tcp
|
||||
@ -56,35 +56,35 @@ Below shows different examples of how we might specify the server coordinates.
|
||||
|
||||
```unison
|
||||
testExplicitHost : '{io2.IO} [Result]
|
||||
testExplicitHost _ =
|
||||
testExplicitHost _ =
|
||||
test = 'let
|
||||
sock = serverSocket (Some "127.0.0.1") "1028"
|
||||
emit (Ok "successfully created socket")
|
||||
port = socketPort sock
|
||||
putBytes (stdHandle StdOut) (toUtf8 (toText port))
|
||||
expectU "should have bound to port 1028" 1028 port
|
||||
expectU "should have bound to port 1028" 1028 port
|
||||
|
||||
runTest test
|
||||
|
||||
testDefaultHost : '{io2.IO} [Result]
|
||||
testDefaultHost _ =
|
||||
testDefaultHost _ =
|
||||
test = 'let
|
||||
sock = serverSocket None "1028"
|
||||
emit (Ok "successfully created socket")
|
||||
port = socketPort sock
|
||||
putBytes (stdHandle StdOut) (toUtf8 (toText port))
|
||||
expectU "should have bound to port 1028" 1028 port
|
||||
expectU "should have bound to port 1028" 1028 port
|
||||
|
||||
runTest test
|
||||
|
||||
testDefaultPort : '{io2.IO} [Result]
|
||||
testDefaultPort _ =
|
||||
testDefaultPort _ =
|
||||
test = 'let
|
||||
sock = serverSocket None "0"
|
||||
emit (Ok "successfully created socket")
|
||||
port = socketPort sock
|
||||
putBytes (stdHandle StdOut) (toUtf8 (toText port))
|
||||
|
||||
|
||||
check "port should be > 1024" (1024 < port)
|
||||
check "port should be < 65536" (65536 > port)
|
||||
|
||||
@ -143,7 +143,7 @@ serverThread portVar toSend = 'let
|
||||
socketSend sock' (toUtf8 toSend)
|
||||
closeSocket sock'
|
||||
|
||||
match (toEither go) with
|
||||
match (toEither go) with
|
||||
Left (Failure _ t _) -> watch t ()
|
||||
_ -> ()
|
||||
|
||||
@ -160,22 +160,22 @@ clientThread portVar resultVar = 'let
|
||||
_ -> ()
|
||||
|
||||
testTcpConnect : '{io2.IO}[Result]
|
||||
testTcpConnect = 'let
|
||||
testTcpConnect = 'let
|
||||
test = 'let
|
||||
portVar = !MVar.newEmpty
|
||||
resultVar = !MVar.newEmpty
|
||||
|
||||
|
||||
toSend = "12345"
|
||||
|
||||
void (forkComp (serverThread portVar toSend))
|
||||
void (forkComp (clientThread portVar resultVar))
|
||||
|
||||
|
||||
received = take resultVar
|
||||
|
||||
expectU "should have reaped what we've sown" toSend received
|
||||
|
||||
|
||||
runTest test
|
||||
|
||||
|
||||
```
|
||||
|
||||
```ucm
|
||||
|
@ -17,74 +17,77 @@ The `builtins.merge` command adds the known builtins to a `builtin` subnamespace
|
||||
6. Bytes/ (34 terms)
|
||||
7. Char (builtin type)
|
||||
8. Char/ (22 terms, 1 type)
|
||||
9. Code (builtin type)
|
||||
10. Code/ (9 terms)
|
||||
11. Debug/ (3 terms)
|
||||
12. Doc (type)
|
||||
13. Doc/ (6 terms)
|
||||
14. Either (type)
|
||||
15. Either/ (2 terms)
|
||||
16. Exception (type)
|
||||
17. Exception/ (1 term)
|
||||
18. Float (builtin type)
|
||||
19. Float/ (38 terms)
|
||||
20. Handle/ (1 term)
|
||||
21. ImmutableArray (builtin type)
|
||||
22. ImmutableArray/ (3 terms)
|
||||
23. ImmutableByteArray (builtin type)
|
||||
24. ImmutableByteArray/ (8 terms)
|
||||
25. Int (builtin type)
|
||||
26. Int/ (31 terms)
|
||||
27. IsPropagated (type)
|
||||
28. IsPropagated/ (1 term)
|
||||
29. IsTest (type)
|
||||
30. IsTest/ (1 term)
|
||||
31. Link (type)
|
||||
32. Link/ (3 terms, 2 types)
|
||||
33. List (builtin type)
|
||||
34. List/ (10 terms)
|
||||
35. MutableArray (builtin type)
|
||||
36. MutableArray/ (6 terms)
|
||||
37. MutableByteArray (builtin type)
|
||||
38. MutableByteArray/ (14 terms)
|
||||
39. Nat (builtin type)
|
||||
40. Nat/ (28 terms)
|
||||
41. Optional (type)
|
||||
42. Optional/ (2 terms)
|
||||
43. Pattern (builtin type)
|
||||
44. Pattern/ (9 terms)
|
||||
45. Ref (builtin type)
|
||||
46. Ref/ (2 terms)
|
||||
47. Request (builtin type)
|
||||
48. RewriteCase (type)
|
||||
49. RewriteCase/ (1 term)
|
||||
50. RewriteSignature (type)
|
||||
51. RewriteSignature/ (1 term)
|
||||
52. RewriteTerm (type)
|
||||
53. RewriteTerm/ (1 term)
|
||||
54. Rewrites (type)
|
||||
55. Rewrites/ (1 term)
|
||||
56. Scope (builtin type)
|
||||
57. Scope/ (6 terms)
|
||||
58. SeqView (type)
|
||||
59. SeqView/ (2 terms)
|
||||
60. Socket/ (1 term)
|
||||
61. Test/ (2 terms, 1 type)
|
||||
62. Text (builtin type)
|
||||
63. Text/ (34 terms)
|
||||
64. ThreadId/ (1 term)
|
||||
65. Tuple (type)
|
||||
66. Tuple/ (1 term)
|
||||
67. Unit (type)
|
||||
68. Unit/ (1 term)
|
||||
69. Universal/ (7 terms)
|
||||
70. Value (builtin type)
|
||||
71. Value/ (5 terms)
|
||||
72. bug (a -> b)
|
||||
73. crypto/ (15 terms, 2 types)
|
||||
74. io2/ (135 terms, 32 types)
|
||||
75. metadata/ (2 terms)
|
||||
76. todo (a -> b)
|
||||
77. unsafe/ (1 term)
|
||||
9. ClientSockAddr (builtin type)
|
||||
10. Code (builtin type)
|
||||
11. Code/ (9 terms)
|
||||
12. Debug/ (3 terms)
|
||||
13. Doc (type)
|
||||
14. Doc/ (6 terms)
|
||||
15. Either (type)
|
||||
16. Either/ (2 terms)
|
||||
17. Exception (type)
|
||||
18. Exception/ (1 term)
|
||||
19. Float (builtin type)
|
||||
20. Float/ (38 terms)
|
||||
21. Handle/ (1 term)
|
||||
22. ImmutableArray (builtin type)
|
||||
23. ImmutableArray/ (3 terms)
|
||||
24. ImmutableByteArray (builtin type)
|
||||
25. ImmutableByteArray/ (8 terms)
|
||||
26. Int (builtin type)
|
||||
27. Int/ (31 terms)
|
||||
28. IsPropagated (type)
|
||||
29. IsPropagated/ (1 term)
|
||||
30. IsTest (type)
|
||||
31. IsTest/ (1 term)
|
||||
32. Link (type)
|
||||
33. Link/ (3 terms, 2 types)
|
||||
34. List (builtin type)
|
||||
35. List/ (10 terms)
|
||||
36. ListenSocket (builtin type)
|
||||
37. MutableArray (builtin type)
|
||||
38. MutableArray/ (6 terms)
|
||||
39. MutableByteArray (builtin type)
|
||||
40. MutableByteArray/ (14 terms)
|
||||
41. Nat (builtin type)
|
||||
42. Nat/ (28 terms)
|
||||
43. Optional (type)
|
||||
44. Optional/ (2 terms)
|
||||
45. Pattern (builtin type)
|
||||
46. Pattern/ (9 terms)
|
||||
47. Ref (builtin type)
|
||||
48. Ref/ (2 terms)
|
||||
49. Request (builtin type)
|
||||
50. RewriteCase (type)
|
||||
51. RewriteCase/ (1 term)
|
||||
52. RewriteSignature (type)
|
||||
53. RewriteSignature/ (1 term)
|
||||
54. RewriteTerm (type)
|
||||
55. RewriteTerm/ (1 term)
|
||||
56. Rewrites (type)
|
||||
57. Rewrites/ (1 term)
|
||||
58. Scope (builtin type)
|
||||
59. Scope/ (6 terms)
|
||||
60. SeqView (type)
|
||||
61. SeqView/ (2 terms)
|
||||
62. Socket/ (1 term)
|
||||
63. Test/ (2 terms, 1 type)
|
||||
64. Text (builtin type)
|
||||
65. Text/ (34 terms)
|
||||
66. ThreadId/ (1 term)
|
||||
67. Tuple (type)
|
||||
68. Tuple/ (1 term)
|
||||
69. UDPSocket (builtin type)
|
||||
70. Unit (type)
|
||||
71. Unit/ (1 term)
|
||||
72. Universal/ (7 terms)
|
||||
73. Value (builtin type)
|
||||
74. Value/ (5 terms)
|
||||
75. bug (a -> b)
|
||||
76. crypto/ (17 terms, 2 types)
|
||||
77. io2/ (146 terms, 32 types)
|
||||
78. metadata/ (2 terms)
|
||||
79. todo (a -> b)
|
||||
80. unsafe/ (1 term)
|
||||
|
||||
```
|
||||
|
@ -23,7 +23,7 @@ Technically, the definitions all exist, but they have no names. `builtins.merge`
|
||||
|
||||
.foo> ls
|
||||
|
||||
1. builtin/ (456 terms, 71 types)
|
||||
1. builtin/ (469 terms, 74 types)
|
||||
|
||||
```
|
||||
And for a limited time, you can get even more builtin goodies:
|
||||
@ -35,7 +35,7 @@ And for a limited time, you can get even more builtin goodies:
|
||||
|
||||
.foo> ls
|
||||
|
||||
1. builtin/ (630 terms, 89 types)
|
||||
1. builtin/ (643 terms, 92 types)
|
||||
|
||||
```
|
||||
More typically, you'd start out by pulling `base.
|
||||
|
@ -37,7 +37,7 @@ Exception.unsafeRun! e _ =
|
||||
|
||||
socketSend s bytes = reraise (socketSend.impl s bytes)
|
||||
closeSocket s = reraise (closeSocket.impl s)
|
||||
serverSocket host port = reraise (serverSocket.impl host port)
|
||||
serverSocket host port = reraise (IO.serverSocket.impl host port)
|
||||
|
||||
hello : Text -> Text -> {IO, Exception} ()
|
||||
hello host port =
|
||||
|
@ -33,7 +33,7 @@ Exception.unsafeRun! e _ =
|
||||
|
||||
socketSend s bytes = reraise (socketSend.impl s bytes)
|
||||
closeSocket s = reraise (closeSocket.impl s)
|
||||
serverSocket host port = reraise (serverSocket.impl host port)
|
||||
serverSocket host port = reraise (IO.serverSocket.impl host port)
|
||||
|
||||
hello : Text -> Text -> {IO, Exception} ()
|
||||
hello host port =
|
||||
|
@ -119,13 +119,13 @@ it's still in the `history` of the parent namespace and can be resurrected at an
|
||||
Note: The most recent namespace hash is immediately below this
|
||||
message.
|
||||
|
||||
⊙ 1. #mqis95ft23
|
||||
⊙ 1. #6j9omad7mv
|
||||
|
||||
- Deletes:
|
||||
|
||||
feature1.y
|
||||
|
||||
⊙ 2. #5ro9c9692q
|
||||
⊙ 2. #59u4sdgodu
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
@ -136,26 +136,26 @@ it's still in the `history` of the parent namespace and can be resurrected at an
|
||||
Original name New name(s)
|
||||
feature1.y master.y
|
||||
|
||||
⊙ 3. #da33td9rni
|
||||
⊙ 3. #0je96at36h
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
feature1.y
|
||||
|
||||
⊙ 4. #ks6rftepdv
|
||||
⊙ 4. #cnv4gjntbl
|
||||
|
||||
> Moves:
|
||||
|
||||
Original name New name
|
||||
x master.x
|
||||
|
||||
⊙ 5. #dgcqc7jftr
|
||||
⊙ 5. #tp0bn8ulih
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
x
|
||||
|
||||
□ 6. #ms344fdodl (start of history)
|
||||
□ 6. #cujaete914 (start of history)
|
||||
|
||||
```
|
||||
To resurrect an old version of a namespace, you can learn its hash via the `history` command, then use `fork #namespacehash .newname`.
|
||||
|
@ -80,7 +80,7 @@ Should be able to move the term, type, and namespace, including its types, terms
|
||||
1. Bar (Nat)
|
||||
2. Bar (type)
|
||||
3. Bar/ (4 terms, 1 type)
|
||||
4. builtin/ (456 terms, 71 types)
|
||||
4. builtin/ (469 terms, 74 types)
|
||||
|
||||
.> ls Bar
|
||||
|
||||
@ -145,7 +145,7 @@ bonk = 5
|
||||
|
||||
.z> ls
|
||||
|
||||
1. builtin/ (456 terms, 71 types)
|
||||
1. builtin/ (469 terms, 74 types)
|
||||
2. zonk (Nat)
|
||||
|
||||
```
|
||||
@ -188,7 +188,7 @@ bonk.zonk = 5
|
||||
|
||||
.a> ls
|
||||
|
||||
1. builtin/ (456 terms, 71 types)
|
||||
1. builtin/ (469 terms, 74 types)
|
||||
2. zonk/ (1 term)
|
||||
|
||||
.a> view zonk.zonk
|
||||
|
@ -277,7 +277,7 @@ I should be able to move the root into a sub-namespace
|
||||
|
||||
.> ls
|
||||
|
||||
1. root/ (1373 terms, 214 types)
|
||||
1. root/ (1412 terms, 223 types)
|
||||
|
||||
.> history
|
||||
|
||||
@ -286,22 +286,22 @@ I should be able to move the root into a sub-namespace
|
||||
|
||||
|
||||
|
||||
□ 1. #vrn80pdffk (start of history)
|
||||
□ 1. #o7cku9c0t9 (start of history)
|
||||
|
||||
```
|
||||
```ucm
|
||||
.> ls .root.at.path
|
||||
|
||||
1. existing/ (457 terms, 71 types)
|
||||
2. happy/ (459 terms, 72 types)
|
||||
3. history/ (457 terms, 71 types)
|
||||
1. existing/ (470 terms, 74 types)
|
||||
2. happy/ (472 terms, 75 types)
|
||||
3. history/ (470 terms, 74 types)
|
||||
|
||||
.> history .root.at.path
|
||||
|
||||
Note: The most recent namespace hash is immediately below this
|
||||
message.
|
||||
|
||||
⊙ 1. #g3ri07hi09
|
||||
⊙ 1. #fv72cqfto4
|
||||
|
||||
- Deletes:
|
||||
|
||||
@ -312,7 +312,7 @@ I should be able to move the root into a sub-namespace
|
||||
Original name New name
|
||||
existing.a.termInA existing.b.termInA
|
||||
|
||||
⊙ 2. #ifjg1bj57v
|
||||
⊙ 2. #12iqsb3l9g
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
@ -324,26 +324,26 @@ I should be able to move the root into a sub-namespace
|
||||
happy.b.termInA existing.a.termInA
|
||||
history.b.termInA existing.a.termInA
|
||||
|
||||
⊙ 3. #bdn8f7vhg1
|
||||
⊙ 3. #r9jmgtco5u
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
existing.a.termInA existing.b.termInB
|
||||
|
||||
⊙ 4. #5dqmgnr0lt
|
||||
⊙ 4. #1k6kae1vn4
|
||||
|
||||
> Moves:
|
||||
|
||||
Original name New name
|
||||
history.a.termInA history.b.termInA
|
||||
|
||||
⊙ 5. #vd3d37rn3c
|
||||
⊙ 5. #ua9re7leg7
|
||||
|
||||
- Deletes:
|
||||
|
||||
history.b.termInB
|
||||
|
||||
⊙ 6. #gi32sh566a
|
||||
⊙ 6. #3k8ouql6cc
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
@ -354,13 +354,13 @@ I should be able to move the root into a sub-namespace
|
||||
Original name New name(s)
|
||||
happy.b.termInA history.a.termInA
|
||||
|
||||
⊙ 7. #u2bs53f2hl
|
||||
⊙ 7. #fp2331i1ek
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
history.a.termInA history.b.termInB
|
||||
|
||||
⊙ 8. #48hsm89mgl
|
||||
⊙ 8. #5sj5jefgcu
|
||||
|
||||
> Moves:
|
||||
|
||||
@ -370,7 +370,7 @@ I should be able to move the root into a sub-namespace
|
||||
happy.a.T.T2 happy.b.T.T2
|
||||
happy.a.termInA happy.b.termInA
|
||||
|
||||
⊙ 9. #pqd79g3q7l
|
||||
⊙ 9. #ell48pttus
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
@ -380,7 +380,7 @@ I should be able to move the root into a sub-namespace
|
||||
|
||||
happy.a.T.T
|
||||
|
||||
⊙ 10. #allrjqq7ga
|
||||
⊙ 10. #al8eguoh70
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
@ -392,7 +392,7 @@ I should be able to move the root into a sub-namespace
|
||||
|
||||
⠇
|
||||
|
||||
⊙ 11. #ohd0a9rim1
|
||||
⊙ 11. #okceqk39nf
|
||||
|
||||
|
||||
```
|
||||
@ -414,26 +414,26 @@ I should be able to move a sub namespace _over_ the root.
|
||||
.> ls
|
||||
|
||||
1. b/ (3 terms, 1 type)
|
||||
2. builtin/ (456 terms, 71 types)
|
||||
2. builtin/ (469 terms, 74 types)
|
||||
|
||||
.> history
|
||||
|
||||
Note: The most recent namespace hash is immediately below this
|
||||
message.
|
||||
|
||||
⊙ 1. #lf3m1s2e7i
|
||||
⊙ 1. #0rvi5q5une
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
b.T b.T.T1 b.T.T2 b.termInA
|
||||
|
||||
⊙ 2. #b1cg22v7s1
|
||||
⊙ 2. #oaa8ltdusf
|
||||
|
||||
- Deletes:
|
||||
|
||||
a.T a.T.T1 a.T.T2 a.termInA
|
||||
|
||||
⊙ 3. #r83v608ifd
|
||||
⊙ 3. #t1c91ou7ri
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
@ -443,13 +443,13 @@ I should be able to move a sub namespace _over_ the root.
|
||||
|
||||
a.T.T
|
||||
|
||||
⊙ 4. #pmm6a0f6fj
|
||||
⊙ 4. #hovh08jep4
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
a.T a.T.T a.termInA
|
||||
|
||||
□ 5. #nmcjvlnbk1 (start of history)
|
||||
□ 5. #4bigcpnl7t (start of history)
|
||||
|
||||
```
|
||||
```ucm
|
||||
|
@ -63,17 +63,17 @@ y = 2
|
||||
most recent, along with the command that got us there. Try:
|
||||
|
||||
`fork 2 .old`
|
||||
`fork #mq4oqhiuuq .old` to make an old namespace
|
||||
`fork #p611n6o5ve .old` to make an old namespace
|
||||
accessible again,
|
||||
|
||||
`reset-root #mq4oqhiuuq` to reset the root namespace and
|
||||
`reset-root #p611n6o5ve` to reset the root namespace and
|
||||
its history to that of the
|
||||
specified namespace.
|
||||
|
||||
When Root Hash Action
|
||||
1. now #1n5tjujeu7 add
|
||||
2. now #mq4oqhiuuq add
|
||||
3. now #nmcjvlnbk1 builtins.merge
|
||||
1. now #rmu2vgm86a add
|
||||
2. now #p611n6o5ve add
|
||||
3. now #4bigcpnl7t builtins.merge
|
||||
4. #sg60bvjo91 history starts here
|
||||
|
||||
Tip: Use `diff.namespace 1 7` to compare namespaces between
|
||||
|
@ -28,13 +28,13 @@ a = 5
|
||||
Note: The most recent namespace hash is immediately below this
|
||||
message.
|
||||
|
||||
⊙ 1. #0nv4t3770d
|
||||
⊙ 1. #d079vet1oj
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
a
|
||||
|
||||
□ 2. #nmcjvlnbk1 (start of history)
|
||||
□ 2. #4bigcpnl7t (start of history)
|
||||
|
||||
.> reset 2
|
||||
|
||||
@ -47,7 +47,7 @@ a = 5
|
||||
|
||||
|
||||
|
||||
□ 1. #nmcjvlnbk1 (start of history)
|
||||
□ 1. #4bigcpnl7t (start of history)
|
||||
|
||||
```
|
||||
```unison
|
||||
@ -83,13 +83,13 @@ foo.a = 5
|
||||
Note: The most recent namespace hash is immediately below this
|
||||
message.
|
||||
|
||||
⊙ 1. #3s91aop8k9
|
||||
⊙ 1. #tfg7r9359n
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
foo.a
|
||||
|
||||
□ 2. #nmcjvlnbk1 (start of history)
|
||||
□ 2. #4bigcpnl7t (start of history)
|
||||
|
||||
.> reset 1 foo
|
||||
|
||||
|
37
unison-src/transcripts/rsa.md
Normal file
37
unison-src/transcripts/rsa.md
Normal file
@ -0,0 +1,37 @@
|
||||
|
||||
```ucm:hide
|
||||
.> builtins.merge
|
||||
```
|
||||
|
||||
```unison
|
||||
|
||||
up = 0xs0123456789abcdef
|
||||
down = 0xsfedcba9876543210
|
||||
|
||||
-- | Generated with:
|
||||
-- openssl genrsa -out private_key.pem 1024
|
||||
-- openssl rsa -in private_key.pem -outform DER | xxd -p
|
||||
secret = 0xs30820276020100300d06092a864886f70d0101010500048202603082025c02010002818100a7104b2f20725896076e629ccedbcd6907b16694c6e3d8768b5e0e685670b49616e796c588e5aafb92ef986c1a42c021fed0bdc99212c969cdab98087a0ee4c2f4acd4b6049a87a96afc45668329a3cf21a86fb13b488bbe9fefa1cd5a459014f0d0101378e9661e11b73acf54c8a91141ac90309e7fb6ed69b4e63230ab291502030100010281807cdc23a4fc3619d93f8293b728af848d0c0fdd603269d5bd7b99f760a9c22065d08693dbdcddf1f5863306133d694819e04d789aef4e95343b601507b8d9eac4492e6d7031b035c5d84eceaa9686b292712632d33b3303af84314d7920bc3d45f90d7818fc2587b129196d378ee4ed3e6b8d9010d504bb6470ff53e7c5fb17a1024100d67cbcf113d24325fcef12a778dc47c7060055290b68287649ef092558daccb61c4e7bc290740b75a29d4356dcbd66d18b0860dbff394cc8ff3d94d57617adbd024100c765d8261dd3d8e0d3caf11ab7b212eed181354215687ca6387283e4f0be16e79c8f298be0a70c7734dea78ea65128517d693cabfa4c0ff5328f2abb85d2023902403ca41dc347285e65c22251b2d9bfe5e7463217e1b7e0e5f7b3a58a7f6da4c6d60220ca6ad2ee8c42e10bf77afa83ee2af6551315800e52404db1ba7fb398b43d02410084877d85c0177933ddb12a554eb8edfa8b872c85d2c2d2ee8be019280696e19469ab81bab5c371f69d4e4be1f54b45d7fbda017870f1333e0eafb78051ee8689024061f694c12e934c44b7734f62d1b2a3d3624a4980e1b8e066d78dbabd2436654fbb9d9701425900daaafa1e031310e8a580520bb9e1c1288c669fce252bad1e65
|
||||
|
||||
-- | Generated with:
|
||||
-- openssl rsa -in private_key.pem -outform DER -pubout | xxd -p
|
||||
publicKey = 0xs30819f300d06092a864886f70d010101050003818d0030818902818100a7104b2f20725896076e629ccedbcd6907b16694c6e3d8768b5e0e685670b49616e796c588e5aafb92ef986c1a42c021fed0bdc99212c969cdab98087a0ee4c2f4acd4b6049a87a96afc45668329a3cf21a86fb13b488bbe9fefa1cd5a459014f0d0101378e9661e11b73acf54c8a91141ac90309e7fb6ed69b4e63230ab29150203010001
|
||||
|
||||
incorrectPublicKey = 0xs30819f300d06092a864886f70d010101050003818d0030818902818100a7104b2f20725896076e629ccedbcd6907b16694c6e3d8768b5e0e685670b49616e796c588e5aafb92ef986c1a42c021fed0bdc99212c969cdab98087a0ee4c2f4acd4b6049a87a96afc45668329a3cf21a86fb13b488bbe9fefa1cd5a459014f0d0101378e9661e11b73acf54c8a91141ac90309e7fb6ed69b4e63230ab29150203010002
|
||||
|
||||
message = up ++ down ++ up ++ down ++ down ++ up ++ down ++ up
|
||||
|
||||
signature = crypto.Rsa.sign.impl secret message
|
||||
|
||||
sigOkay = match signature with
|
||||
Left err -> Left err
|
||||
Right sg -> crypto.Rsa.verify.impl publicKey message sg
|
||||
|
||||
sigKo = match signature with
|
||||
Left err -> Left err
|
||||
Right sg -> crypto.Rsa.verify.impl incorrectPublicKey message sg
|
||||
|
||||
> signature
|
||||
> sigOkay
|
||||
> sigKo
|
||||
```
|
70
unison-src/transcripts/rsa.output.md
Normal file
70
unison-src/transcripts/rsa.output.md
Normal file
@ -0,0 +1,70 @@
|
||||
|
||||
```unison
|
||||
up = 0xs0123456789abcdef
|
||||
down = 0xsfedcba9876543210
|
||||
|
||||
-- | Generated with:
|
||||
-- openssl genrsa -out private_key.pem 1024
|
||||
-- openssl rsa -in private_key.pem -outform DER | xxd -p
|
||||
secret = 0xs30820276020100300d06092a864886f70d0101010500048202603082025c02010002818100a7104b2f20725896076e629ccedbcd6907b16694c6e3d8768b5e0e685670b49616e796c588e5aafb92ef986c1a42c021fed0bdc99212c969cdab98087a0ee4c2f4acd4b6049a87a96afc45668329a3cf21a86fb13b488bbe9fefa1cd5a459014f0d0101378e9661e11b73acf54c8a91141ac90309e7fb6ed69b4e63230ab291502030100010281807cdc23a4fc3619d93f8293b728af848d0c0fdd603269d5bd7b99f760a9c22065d08693dbdcddf1f5863306133d694819e04d789aef4e95343b601507b8d9eac4492e6d7031b035c5d84eceaa9686b292712632d33b3303af84314d7920bc3d45f90d7818fc2587b129196d378ee4ed3e6b8d9010d504bb6470ff53e7c5fb17a1024100d67cbcf113d24325fcef12a778dc47c7060055290b68287649ef092558daccb61c4e7bc290740b75a29d4356dcbd66d18b0860dbff394cc8ff3d94d57617adbd024100c765d8261dd3d8e0d3caf11ab7b212eed181354215687ca6387283e4f0be16e79c8f298be0a70c7734dea78ea65128517d693cabfa4c0ff5328f2abb85d2023902403ca41dc347285e65c22251b2d9bfe5e7463217e1b7e0e5f7b3a58a7f6da4c6d60220ca6ad2ee8c42e10bf77afa83ee2af6551315800e52404db1ba7fb398b43d02410084877d85c0177933ddb12a554eb8edfa8b872c85d2c2d2ee8be019280696e19469ab81bab5c371f69d4e4be1f54b45d7fbda017870f1333e0eafb78051ee8689024061f694c12e934c44b7734f62d1b2a3d3624a4980e1b8e066d78dbabd2436654fbb9d9701425900daaafa1e031310e8a580520bb9e1c1288c669fce252bad1e65
|
||||
|
||||
-- | Generated with:
|
||||
-- openssl rsa -in private_key.pem -outform DER -pubout | xxd -p
|
||||
publicKey = 0xs30819f300d06092a864886f70d010101050003818d0030818902818100a7104b2f20725896076e629ccedbcd6907b16694c6e3d8768b5e0e685670b49616e796c588e5aafb92ef986c1a42c021fed0bdc99212c969cdab98087a0ee4c2f4acd4b6049a87a96afc45668329a3cf21a86fb13b488bbe9fefa1cd5a459014f0d0101378e9661e11b73acf54c8a91141ac90309e7fb6ed69b4e63230ab29150203010001
|
||||
|
||||
incorrectPublicKey = 0xs30819f300d06092a864886f70d010101050003818d0030818902818100a7104b2f20725896076e629ccedbcd6907b16694c6e3d8768b5e0e685670b49616e796c588e5aafb92ef986c1a42c021fed0bdc99212c969cdab98087a0ee4c2f4acd4b6049a87a96afc45668329a3cf21a86fb13b488bbe9fefa1cd5a459014f0d0101378e9661e11b73acf54c8a91141ac90309e7fb6ed69b4e63230ab29150203010002
|
||||
|
||||
message = up ++ down ++ up ++ down ++ down ++ up ++ down ++ up
|
||||
|
||||
signature = crypto.Rsa.sign.impl secret message
|
||||
|
||||
sigOkay = match signature with
|
||||
Left err -> Left err
|
||||
Right sg -> crypto.Rsa.verify.impl publicKey message sg
|
||||
|
||||
sigKo = match signature with
|
||||
Left err -> Left err
|
||||
Right sg -> crypto.Rsa.verify.impl incorrectPublicKey message sg
|
||||
|
||||
> signature
|
||||
> sigOkay
|
||||
> sigKo
|
||||
```
|
||||
|
||||
```ucm
|
||||
|
||||
Loading changes detected in scratch.u.
|
||||
|
||||
I found and typechecked these definitions in scratch.u. If you
|
||||
do an `add` or `update`, here's how your codebase would
|
||||
change:
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
down : Bytes
|
||||
incorrectPublicKey : Bytes
|
||||
message : Bytes
|
||||
publicKey : Bytes
|
||||
secret : Bytes
|
||||
sigKo : Either Failure Boolean
|
||||
sigOkay : Either Failure Boolean
|
||||
signature : Either Failure Bytes
|
||||
up : Bytes
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
|
||||
27 | > signature
|
||||
⧩
|
||||
Right
|
||||
0xs84b02b6bb0e1196b65378cb12b727f7b4b38e5979f0632e8a51cfab088827f6d3da4221788029f75a0a5f4d740372cfa590462888a1189bbd9de9b084f26116640e611af5a1a17229beec7fb2570887181bbdced8f0ebfec6cad6bdd318a616ba4f01c90e1436efe44b18417d18ce712a0763be834f8c76e0c39b2119b061373
|
||||
|
||||
28 | > sigOkay
|
||||
⧩
|
||||
Right true
|
||||
|
||||
29 | > sigKo
|
||||
⧩
|
||||
Right false
|
||||
|
||||
```
|
@ -13,7 +13,7 @@ Let's look at some examples. We'll start with a namespace with just the builtins
|
||||
|
||||
|
||||
|
||||
□ 1. #3pq2vvggng (start of history)
|
||||
□ 1. #i3vp9o9btm (start of history)
|
||||
|
||||
.> fork builtin builtin2
|
||||
|
||||
@ -42,21 +42,21 @@ Now suppose we `fork` a copy of builtin, then rename `Nat.+` to `frobnicate`, th
|
||||
Note: The most recent namespace hash is immediately below this
|
||||
message.
|
||||
|
||||
⊙ 1. #4g884gq7lc
|
||||
⊙ 1. #tpkjb488ei
|
||||
|
||||
> Moves:
|
||||
|
||||
Original name New name
|
||||
Nat.frobnicate Nat.+
|
||||
|
||||
⊙ 2. #hnah4l7s0j
|
||||
⊙ 2. #334ak3epqt
|
||||
|
||||
> Moves:
|
||||
|
||||
Original name New name
|
||||
Nat.+ Nat.frobnicate
|
||||
|
||||
□ 3. #3pq2vvggng (start of history)
|
||||
□ 3. #i3vp9o9btm (start of history)
|
||||
|
||||
```
|
||||
If we merge that back into `builtin`, we get that same chain of history:
|
||||
@ -73,21 +73,21 @@ If we merge that back into `builtin`, we get that same chain of history:
|
||||
Note: The most recent namespace hash is immediately below this
|
||||
message.
|
||||
|
||||
⊙ 1. #4g884gq7lc
|
||||
⊙ 1. #tpkjb488ei
|
||||
|
||||
> Moves:
|
||||
|
||||
Original name New name
|
||||
Nat.frobnicate Nat.+
|
||||
|
||||
⊙ 2. #hnah4l7s0j
|
||||
⊙ 2. #334ak3epqt
|
||||
|
||||
> Moves:
|
||||
|
||||
Original name New name
|
||||
Nat.+ Nat.frobnicate
|
||||
|
||||
□ 3. #3pq2vvggng (start of history)
|
||||
□ 3. #i3vp9o9btm (start of history)
|
||||
|
||||
```
|
||||
Let's try again, but using a `merge.squash` (or just `squash`) instead. The history will be unchanged:
|
||||
@ -108,7 +108,7 @@ Let's try again, but using a `merge.squash` (or just `squash`) instead. The hist
|
||||
|
||||
|
||||
|
||||
□ 1. #3pq2vvggng (start of history)
|
||||
□ 1. #i3vp9o9btm (start of history)
|
||||
|
||||
```
|
||||
The churn that happened in `mybuiltin` namespace ended up back in the same spot, so the squash merge of that namespace with our original namespace had no effect.
|
||||
@ -493,13 +493,13 @@ This checks to see that squashing correctly preserves deletions:
|
||||
Note: The most recent namespace hash is immediately below this
|
||||
message.
|
||||
|
||||
⊙ 1. #jdptkosbfp
|
||||
⊙ 1. #dv00hf6vmg
|
||||
|
||||
- Deletes:
|
||||
|
||||
Nat.* Nat.+
|
||||
|
||||
□ 2. #3pq2vvggng (start of history)
|
||||
□ 2. #i3vp9o9btm (start of history)
|
||||
|
||||
```
|
||||
Notice that `Nat.+` and `Nat.*` are deleted by the squash, and we see them deleted in one atomic step in the history.
|
||||
|
@ -57,7 +57,7 @@ proj/main> upgrade old new
|
||||
|
||||
proj/main> ls lib
|
||||
|
||||
1. builtin/ (456 terms, 71 types)
|
||||
1. builtin/ (469 terms, 74 types)
|
||||
2. new/ (1 term)
|
||||
|
||||
proj/main> view thingy
|
||||
|
Loading…
Reference in New Issue
Block a user