feat: initial import

This commit is contained in:
Brian McGee 2023-12-23 12:50:47 +00:00
commit 6904097171
Signed by: brianmcgee
GPG Key ID: D49016E76AD1E8C0
55 changed files with 2480 additions and 0 deletions

1
.envrc Normal file
View File

@ -0,0 +1 @@
use flake

12
.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
# editors
.idea
# nix
result*
repl-result-*
# direnv
/.direnv
# devshell
/.data

21
LICENSE.md Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Nits Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

187
flake.lock Normal file
View File

@ -0,0 +1,187 @@
{
"nodes": {
"devshell": {
"inputs": {
"nixpkgs": ["nixpkgs"],
"systems": "systems"
},
"locked": {
"lastModified": 1700815693,
"narHash": "sha256-JtKZEQUzosrCwDsLgm+g6aqbP1aseUl1334OShEAS3s=",
"owner": "numtide",
"repo": "devshell",
"rev": "7ad1c417c87e98e56dcef7ecd0e0a2f2e5669d51",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "devshell",
"type": "github"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
"lastModified": 1698882062,
"narHash": "sha256-HkhafUayIqxXyHH1X8d9RDl1M2CkFgZLjKD3MzabiEo=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "8c9fa2545007b49a5db5f650ae91f227672c3877",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-root": {
"locked": {
"lastModified": 1692742795,
"narHash": "sha256-f+Y0YhVCIJ06LemO+3Xx00lIcqQxSKJHXT/yk1RTKxw=",
"owner": "srid",
"repo": "flake-root",
"rev": "d9a70d9c7a5fd7f3258ccf48da9335e9b47c3937",
"type": "github"
},
"original": {
"owner": "srid",
"repo": "flake-root",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1694529238,
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"gomod2nix": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": ["nixpkgs"]
},
"locked": {
"lastModified": 1699950847,
"narHash": "sha256-xN/yVtqHb7kimHA/WvQFrEG5WS38t0K+A/W+j/WhQWM=",
"owner": "nix-community",
"repo": "gomod2nix",
"rev": "05c993c9a5bd55a629cd45ed49951557b7e9c61a",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "gomod2nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1702312524,
"narHash": "sha256-gkZJRDBUCpTPBvQk25G0B7vfbpEYM5s5OZqghkjZsnE=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "a9bf124c46ef298113270b1f84a164865987a91c",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-lib": {
"locked": {
"dir": "lib",
"lastModified": 1698611440,
"narHash": "sha256-jPjHjrerhYDy3q9+s5EAsuhyhuknNfowY6yt6pjn9pc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "0cbe9f69c234a7700596e943bfae7ef27a31b735",
"type": "github"
},
"original": {
"dir": "lib",
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"devshell": "devshell",
"flake-parts": "flake-parts",
"flake-root": "flake-root",
"gomod2nix": "gomod2nix",
"nixpkgs": "nixpkgs",
"treefmt-nix": "treefmt-nix"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"treefmt-nix": {
"inputs": {
"nixpkgs": ["nixpkgs"]
},
"locked": {
"lastModified": 1699786194,
"narHash": "sha256-3h3EH1FXQkIeAuzaWB+nK0XK54uSD46pp+dMD3gAcB4=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "e82f32aa7f06bbbd56d7b12186d555223dc399d1",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "treefmt-nix",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

39
flake.nix Normal file
View File

@ -0,0 +1,39 @@
{
description = "Treefmt";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-parts.url = "github:hercules-ci/flake-parts";
flake-root.url = "github:srid/flake-root";
treefmt-nix = {
url = "github:numtide/treefmt-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
devshell = {
url = "github:numtide/devshell";
inputs.nixpkgs.follows = "nixpkgs";
};
gomod2nix = {
url = "github:nix-community/gomod2nix";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = inputs @ {flake-parts, ...}:
flake-parts.lib.mkFlake
{
inherit inputs;
}
{
imports = [
./nix
];
systems = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
};
}

35
go.mod Normal file
View File

@ -0,0 +1,35 @@
module github.com/numtide/treefmt
go 1.21
require (
github.com/BurntSushi/toml v1.3.2
github.com/adrg/xdg v0.4.0
github.com/alecthomas/kong v0.8.1
github.com/charmbracelet/log v0.3.1
github.com/gobwas/glob v0.2.3
github.com/juju/errors v1.0.0
github.com/stretchr/testify v1.8.4
github.com/vmihailenco/msgpack/v5 v5.4.1
github.com/ztrue/shutdown v0.1.1
go.etcd.io/bbolt v1.3.8
golang.org/x/sync v0.5.0
)
require (
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/charmbracelet/lipgloss v0.9.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.18 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/sys v0.13.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

73
go.sum Normal file
View File

@ -0,0 +1,73 @@
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
github.com/alecthomas/assert/v2 v2.1.0 h1:tbredtNcQnoSd3QBhQWI7QZ3XHOVkw1Moklp2ojoH/0=
github.com/alecthomas/assert/v2 v2.1.0/go.mod h1:b/+1DI2Q6NckYi+3mXyH3wFb8qG37K/DuK80n7WefXA=
github.com/alecthomas/kong v0.8.1 h1:acZdn3m4lLRobeh3Zi2S2EpnXTd1mOL6U7xVml+vfkY=
github.com/alecthomas/kong v0.8.1/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U=
github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE=
github.com/alecthomas/repr v0.1.0/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg=
github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I=
github.com/charmbracelet/log v0.3.1 h1:TjuY4OBNbxmHWSwO3tosgqs5I3biyY8sQPny/eCMTYw=
github.com/charmbracelet/log v0.3.1/go.mod h1:OR4E1hutLsax3ZKpXbgUqPtTjQfrh1pG3zwHGWuuq8g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/juju/errors v1.0.0 h1:yiq7kjCLll1BiaRuNY53MGI0+EQ3rF6GB+wvboZDefM=
github.com/juju/errors v1.0.0/go.mod h1:B5x9thDqx0wIMH3+aLIMP9HjItInYWObRovoCFM5Qe8=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
github.com/ztrue/shutdown v0.1.1 h1:GKR2ye2OSQlq1GNVE/s2NbrIMsFdmL+NdR6z6t1k+Tg=
github.com/ztrue/shutdown v0.1.1/go.mod h1:hcMWcM2SwIsQk7Wb49aYme4tX66x6iLzs07w1OYAQLw=
go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA=
go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

81
gomod2nix.toml Normal file
View File

@ -0,0 +1,81 @@
schema = 3
[mod]
[mod."github.com/BurntSushi/toml"]
version = "v1.3.2"
hash = "sha256-FIwyH67KryRWI9Bk4R8s1zFP0IgKR4L66wNQJYQZLeg="
[mod."github.com/adrg/xdg"]
version = "v0.4.0"
hash = "sha256-zGjkdUQmrVqD6rMO9oDY+TeJCpuqnHyvkPCaXDlac/U="
[mod."github.com/alecthomas/kong"]
version = "v0.8.1"
hash = "sha256-170mjSrLNC+0W1KhXltaa+YWYgt5gJQEcfssepcyh4E="
[mod."github.com/aymanbagabas/go-osc52/v2"]
version = "v2.0.1"
hash = "sha256-6Bp0jBZ6npvsYcKZGHHIUSVSTAMEyieweAX2YAKDjjg="
[mod."github.com/charmbracelet/lipgloss"]
version = "v0.9.1"
hash = "sha256-AHbabOymgDRIXsMBgJHS25/GgBWT54oGbd15EBWKeZc="
[mod."github.com/charmbracelet/log"]
version = "v0.3.1"
hash = "sha256-Er60POPID2eNrRZnBHxoI4yHn0mIKnXYftGKSslbXx0="
[mod."github.com/davecgh/go-spew"]
version = "v1.1.1"
hash = "sha256-nhzSUrE1fCkN0+RL04N4h8jWmRFPPPWbCuDc7Ss0akI="
[mod."github.com/go-logfmt/logfmt"]
version = "v0.6.0"
hash = "sha256-RtIG2qARd5sT10WQ7F3LR8YJhS8exs+KiuUiVf75bWg="
[mod."github.com/gobwas/glob"]
version = "v0.2.3"
hash = "sha256-hYHMUdwxVkMOjSKjR7UWO0D0juHdI4wL8JEy5plu/Jc="
[mod."github.com/juju/errors"]
version = "v1.0.0"
hash = "sha256-9uZ0wNf44ilzLsvXqOsmFUpNOBFAVadj6+ZH8+QMDMk="
[mod."github.com/lucasb-eyer/go-colorful"]
version = "v1.2.0"
hash = "sha256-Gg9dDJFCTaHrKHRR1SrJgZ8fWieJkybljybkI9x0gyE="
[mod."github.com/mattn/go-isatty"]
version = "v0.0.18"
hash = "sha256-QpIn0DSggtBn2ocyj0RlXDKLK5F5KZG1/ogzrqBCjF8="
[mod."github.com/mattn/go-runewidth"]
version = "v0.0.15"
hash = "sha256-WP39EU2UrQbByYfnwrkBDoKN7xzXsBssDq3pNryBGm0="
[mod."github.com/muesli/reflow"]
version = "v0.3.0"
hash = "sha256-Pou2ybE9SFSZG6YfZLVV1Eyfm+X4FuVpDPLxhpn47Cc="
[mod."github.com/muesli/termenv"]
version = "v0.15.2"
hash = "sha256-Eum/SpyytcNIchANPkG4bYGBgcezLgej7j/+6IhqoMU="
[mod."github.com/pmezard/go-difflib"]
version = "v1.0.0"
hash = "sha256-/FtmHnaGjdvEIKAJtrUfEhV7EVo5A/eYrtdnUkuxLDA="
[mod."github.com/rivo/uniseg"]
version = "v0.2.0"
hash = "sha256-GLj0jiGrT03Ept4V6FXCN1yeZ/b6PpS3MEXK6rYQ8Eg="
[mod."github.com/stretchr/testify"]
version = "v1.8.4"
hash = "sha256-MoOmRzbz9QgiJ+OOBo5h5/LbilhJfRUryvzHJmXAWjo="
[mod."github.com/vmihailenco/msgpack/v5"]
version = "v5.4.1"
hash = "sha256-pDplX6xU6UpNLcFbO1pRREW5vCnSPvSU+ojAwFDv3Hk="
[mod."github.com/vmihailenco/tagparser/v2"]
version = "v2.0.0"
hash = "sha256-M9QyaKhSmmYwsJk7gkjtqu9PuiqZHSmTkous8VWkWY0="
[mod."github.com/ztrue/shutdown"]
version = "v0.1.1"
hash = "sha256-+ygx5THHu9g+vBAn6b63tV35bvQGdRyto4pLhkontJI="
[mod."go.etcd.io/bbolt"]
version = "v1.3.8"
hash = "sha256-ekKy8198B2GfPldHLYZnvNjID6x07dUPYKgFx84TgVs="
[mod."golang.org/x/exp"]
version = "v0.0.0-20231006140011-7918f672742d"
hash = "sha256-2SO1etTQ6UCUhADR5sgvDEDLHcj77pJKCIa/8mGDbAo="
[mod."golang.org/x/sync"]
version = "v0.5.0"
hash = "sha256-EAKeODSsct5HhXPmpWJfulKSCkuUu6kkDttnjyZMNcI="
[mod."golang.org/x/sys"]
version = "v0.13.0"
hash = "sha256-/+RDZ0a0oEfJ0k304VqpJpdrl2ZXa3yFlOxy4mjW7w0="
[mod."gopkg.in/yaml.v3"]
version = "v3.0.1"
hash = "sha256-FqL9TKYJ0XkNwJFnq9j0VvJ5ZUU1RvH/52h/f5bkYAU="

144
internal/cache/cache.go vendored Normal file
View File

@ -0,0 +1,144 @@
package cache
import (
"context"
"crypto/sha1"
"encoding/base32"
"fmt"
"io/fs"
"os"
"path/filepath"
"github.com/adrg/xdg"
"github.com/juju/errors"
"github.com/vmihailenco/msgpack/v5"
bolt "go.etcd.io/bbolt"
)
const (
modifiedBucket = "modified"
)
var db *bolt.DB
func Open(treeRoot string, clean bool) (err error) {
// determine a unique and consistent db name for the tree root
h := sha1.New()
h.Write([]byte(treeRoot))
digest := h.Sum(nil)
name := base32.StdEncoding.EncodeToString(digest)
path, err := xdg.CacheFile(fmt.Sprintf("treefmt/eval-cache/%v.db", name))
// bust the cache if specified
if clean {
err := os.Remove(path)
if errors.Is(err, os.ErrNotExist) {
err = nil
} else if err != nil {
return errors.Annotate(err, "failed to clear cache")
}
}
if err != nil {
return errors.Annotate(err, "could not resolve local path for the cache")
}
db, err = bolt.Open(path, 0o600, nil)
if err != nil {
return errors.Annotate(err, "failed to open cache")
}
err = db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucket([]byte(modifiedBucket))
if errors.Is(err, bolt.ErrBucketExists) {
return nil
}
return err
})
return
}
func Close() error {
return db.Close()
}
func ChangeSet(ctx context.Context, root string, pathsCh chan<- string) error {
return db.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(modifiedBucket))
return filepath.Walk(root, func(path string, info fs.FileInfo, err error) error {
if err != nil {
return errors.Annotate(err, "failed to walk path")
} else if ctx.Err() != nil {
return ctx.Err()
} else if info.IsDir() {
// todo what about symlinks?
return nil
}
if info.Mode()&os.ModeSymlink == os.ModeSymlink {
// skip symlinks
return nil
}
b := bucket.Get([]byte(path))
var cached FileInfo
if b != nil {
if err = msgpack.Unmarshal(b, &cached); err != nil {
return errors.Annotatef(err, "failed to unmarshal cache info for path '%v'", path)
}
}
changedOrNew := !(cached.Modified == info.ModTime() && cached.Size == info.Size())
if !changedOrNew {
// no change
return nil
}
// pass on the path
pathsCh <- path
return nil
})
})
}
func WriteModTime(paths []string) error {
if len(paths) == 0 {
return nil
}
return db.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(modifiedBucket))
for _, path := range paths {
if path == "" {
continue
}
pathInfo, err := os.Stat(path)
if err != nil {
return err
}
cacheInfo := FileInfo{
Size: pathInfo.Size(),
Modified: pathInfo.ModTime(),
}
bytes, err := msgpack.Marshal(cacheInfo)
if err != nil {
return errors.Annotate(err, "failed to marshal mod time")
}
if err = bucket.Put([]byte(path), bytes); err != nil {
return errors.Annotate(err, "failed to put mode time")
}
}
return nil
})
}

8
internal/cache/types.go vendored Normal file
View File

@ -0,0 +1,8 @@
package cache
import "time"
type FileInfo struct {
Size int64
Modified time.Time
}

29
internal/cli/cli.go Normal file
View File

@ -0,0 +1,29 @@
package cli
import "github.com/charmbracelet/log"
var Cli struct {
Log LogOptions `embed:""`
ConfigFile string `type:"existingfile" default:"./treefmt.toml"`
TreeRoot string `type:"existingdir" default:"."`
ClearCache bool `short:"c" help:"Reset the evaluation cache. Use in case the cache is not precise enough"`
Format Format `cmd:"" default:"."`
}
type LogOptions struct {
Verbosity int `name:"verbose" short:"v" type:"counter" default:"0" env:"LOG_LEVEL" help:"Set the verbosity of logs e.g. -vv"`
}
func (lo *LogOptions) ConfigureLogger() {
log.SetReportTimestamp(false)
if lo.Verbosity == 0 {
log.SetLevel(log.WarnLevel)
} else if lo.Verbosity == 1 {
log.SetLevel(log.InfoLevel)
} else if lo.Verbosity >= 2 {
log.SetLevel(log.DebugLevel)
}
}

155
internal/cli/format.go Normal file
View File

@ -0,0 +1,155 @@
package cli
import (
"context"
"fmt"
"time"
"github.com/numtide/treefmt/internal/cache"
"github.com/numtide/treefmt/internal/format"
"github.com/charmbracelet/log"
"github.com/juju/errors"
"github.com/ztrue/shutdown"
"golang.org/x/sync/errgroup"
)
type Format struct{}
func (f *Format) Run() error {
start := time.Now()
Cli.Log.ConfigureLogger()
l := log.WithPrefix("format")
defer func() {
if err := cache.Close(); err != nil {
l.Errorf("failed to close cache: %v", err)
}
}()
// create an overall context
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// register shutdown hook
shutdown.Add(cancel)
// read config
cfg, err := format.ReadConfigFile(Cli.ConfigFile)
if err != nil {
return errors.Annotate(err, "failed to read config file")
}
// init formatters
for name, formatter := range cfg.Formatters {
if err = formatter.Init(name); err != nil {
return errors.Annotatef(err, "failed to initialise formatter: %v", name)
}
}
ctx = format.RegisterFormatters(ctx, cfg.Formatters)
if err = cache.Open(Cli.TreeRoot, Cli.ClearCache); err != nil {
return err
}
//
pendingCh := make(chan string, 1024)
completedCh := make(chan string, 1024)
ctx = format.SetCompletedChannel(ctx, completedCh)
//
eg, ctx := errgroup.WithContext(ctx)
// start the formatters
for name := range cfg.Formatters {
formatter := cfg.Formatters[name]
eg.Go(func() error {
return formatter.Run(ctx)
})
}
// determine paths to be formatted
pathsCh := make(chan string, 1024)
// update cache as paths are completed
eg.Go(func() error {
batchSize := 1024
batch := make([]string, batchSize)
var pending, completed int
LOOP:
for {
select {
case _, ok := <-pendingCh:
if ok {
pending += 1
} else if pending == completed {
break LOOP
}
case path, ok := <-completedCh:
if !ok {
break LOOP
}
batch = append(batch, path)
if len(batch) == batchSize {
if err := cache.WriteModTime(batch); err != nil {
return err
}
batch = batch[:0]
}
completed += 1
if completed == pending {
close(completedCh)
}
}
}
// final flush
if err := cache.WriteModTime(batch); err != nil {
return err
}
println(fmt.Sprintf("%v files changed in %v", completed, time.Now().Sub(start)))
return nil
})
eg.Go(func() error {
count := 0
for path := range pathsCh {
// todo cycle detection in Befores
for _, formatter := range cfg.Formatters {
if formatter.Wants(path) {
pendingCh <- path
count += 1
formatter.Put(path)
}
}
}
for _, formatter := range cfg.Formatters {
formatter.Close()
}
if count == 0 {
close(completedCh)
}
return nil
})
eg.Go(func() error {
defer close(pathsCh)
return cache.ChangeSet(ctx, Cli.TreeRoot, pathsCh)
})
return eg.Wait()
}

12
internal/format/config.go Normal file
View File

@ -0,0 +1,12 @@
package format
import "github.com/BurntSushi/toml"
type Config struct {
Formatters map[string]*Formatter `toml:"formatter"`
}
func ReadConfigFile(path string) (cfg *Config, err error) {
_, err = toml.DecodeFile(path, &cfg)
return
}

View File

@ -0,0 +1,122 @@
package format
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestConfig(t *testing.T) {
as := require.New(t)
cfg, err := ReadConfigFile("../../test/treefmt.toml")
as.NoError(err, "failed to read config file")
as.NotNil(cfg)
// python
python, ok := cfg.Formatters["python"]
as.True(ok, "python formatter not found")
as.Equal("black", python.Command)
as.Nil(python.Options)
as.Equal([]string{"*.py"}, python.Includes)
as.Nil(python.Excludes)
// elm
elm, ok := cfg.Formatters["elm"]
as.True(ok, "elm formatter not found")
as.Equal("elm-format", elm.Command)
as.Equal([]string{"--yes"}, elm.Options)
as.Equal([]string{"*.elm"}, elm.Includes)
as.Nil(elm.Excludes)
// go
golang, ok := cfg.Formatters["go"]
as.True(ok, "go formatter not found")
as.Equal("gofmt", golang.Command)
as.Equal([]string{"-w"}, golang.Options)
as.Equal([]string{"*.go"}, golang.Includes)
as.Nil(golang.Excludes)
// haskell
haskell, ok := cfg.Formatters["haskell"]
as.True(ok, "haskell formatter not found")
as.Equal("ormolu", haskell.Command)
as.Equal([]string{
"--ghc-opt", "-XBangPatterns",
"--ghc-opt", "-XPatternSynonyms",
"--ghc-opt", "-XTypeApplications",
"--mode", "inplace",
"--check-idempotence",
}, haskell.Options)
as.Equal([]string{"*.hs"}, haskell.Includes)
as.Equal([]string{"examples/haskell/"}, haskell.Excludes)
// nix
nix, ok := cfg.Formatters["nix"]
as.True(ok, "nix formatter not found")
as.Equal("nixpkgs-fmt", nix.Command)
as.Nil(nix.Options)
as.Equal([]string{"*.nix"}, nix.Includes)
as.Equal([]string{"examples/nix/sources.nix"}, nix.Excludes)
// ruby
ruby, ok := cfg.Formatters["ruby"]
as.True(ok, "ruby formatter not found")
as.Equal("rufo", ruby.Command)
as.Equal([]string{"-x"}, ruby.Options)
as.Equal([]string{"*.rb"}, ruby.Includes)
as.Nil(ruby.Excludes)
// prettier
prettier, ok := cfg.Formatters["prettier"]
as.True(ok, "prettier formatter not found")
as.Equal("prettier", prettier.Command)
as.Equal([]string{"--write"}, prettier.Options)
as.Equal([]string{
"*.css",
"*.html",
"*.js",
"*.json",
"*.jsx",
"*.md",
"*.mdx",
"*.scss",
"*.ts",
"*.yaml",
}, prettier.Includes)
as.Equal([]string{"CHANGELOG.md"}, prettier.Excludes)
// rust
// rust, ok := cfg.Formatters["rust"]
// as.True(ok, "rust formatter not found")
// as.Equal("rustfmt", rust.Command)
// as.Equal([]string{"--edition", "2018"}, rust.Options)
// as.Equal([]string{"*.rs"}, rust.Includes)
// as.Nil(rust.Excludes)
// shell
shell, ok := cfg.Formatters["shell"]
as.True(ok, "shell formatter not found")
as.Equal("/bin/sh", shell.Command)
as.Equal([]string{
"-euc",
`# First lint all the scripts
shellcheck "$@"
# Then format them
shfmt -i 2 -s -w "$@"
`,
"--",
}, shell.Options)
as.Equal([]string{"*.sh"}, shell.Includes)
as.Nil(shell.Excludes)
// terraform
terraform, ok := cfg.Formatters["terraform"]
as.True(ok, "terraform formatter not found")
as.Equal("terraform", terraform.Command)
as.Equal([]string{"fmt"}, terraform.Options)
as.Equal([]string{"*.tf"}, terraform.Includes)
as.Nil(terraform.Excludes)
}

View File

@ -0,0 +1,36 @@
package format
import (
"context"
)
const (
formattersKey = "formatters"
completedChKey = "completedCh"
)
func RegisterFormatters(ctx context.Context, formatters map[string]*Formatter) context.Context {
return context.WithValue(ctx, formattersKey, formatters)
}
func GetFormatters(ctx context.Context) map[string]*Formatter {
return ctx.Value(formattersKey).(map[string]*Formatter)
}
func SetCompletedChannel(ctx context.Context, completedCh chan string) context.Context {
return context.WithValue(ctx, completedChKey, completedCh)
}
func MarkFormatComplete(ctx context.Context, path string) {
ctx.Value(completedChKey).(chan string) <- path
}
func ForwardPath(ctx context.Context, path string, names []string) {
if len(names) == 0 {
return
}
formatters := GetFormatters(ctx)
for _, name := range names {
formatters[name].Put(path)
}
}

161
internal/format/format.go Normal file
View File

@ -0,0 +1,161 @@
package format
import (
"context"
"os/exec"
"strings"
"time"
"github.com/charmbracelet/log"
"github.com/gobwas/glob"
"github.com/juju/errors"
)
type Formatter struct {
Name string
Command string
Options []string
Includes []string
Excludes []string
Before []string
log *log.Logger
// globs for matching against paths
includes []glob.Glob
excludes []glob.Glob
inbox chan string
batch []string
batchSize int
}
func (f *Formatter) Init(name string) error {
f.Name = name
f.log = log.WithPrefix("format | " + name)
f.inbox = make(chan string, 1024)
f.batchSize = 1024
f.batch = make([]string, f.batchSize)
f.batch = f.batch[:0]
// todo refactor common code below
if len(f.Includes) > 0 {
for _, pattern := range f.Includes {
if !strings.Contains(pattern, "/") {
pattern = "**/" + pattern
}
g, err := glob.Compile(pattern)
if err != nil {
return errors.Annotatef(err, "failed to compile include pattern '%v' for formatter '%v'", pattern, f.Name)
}
f.includes = append(f.includes, g)
}
}
if len(f.Excludes) > 0 {
for _, pattern := range f.Excludes {
if !strings.Contains(pattern, "/") {
pattern = "**/" + pattern
}
g, err := glob.Compile(pattern)
if err != nil {
return errors.Annotatef(err, "failed to compile exclude pattern '%v' for formatter '%v'", pattern, f.Name)
}
f.excludes = append(f.excludes, g)
}
}
return nil
}
func (f *Formatter) Wants(path string) bool {
if PathMatches(path, f.excludes) {
return false
}
return PathMatches(path, f.includes)
}
func (f *Formatter) Put(path string) {
f.inbox <- path
}
func (f *Formatter) Run(ctx context.Context) (err error) {
LOOP:
for {
select {
case <-ctx.Done():
err = ctx.Err()
break LOOP
case path, ok := <-f.inbox:
if !ok {
break LOOP
}
// add to the current batch
f.batch = append(f.batch, path)
if len(f.batch) == f.batchSize {
// drain immediately
if err := f.apply(ctx); err != nil {
break LOOP
}
}
}
}
if err != nil {
return
}
// final flush
return f.apply(ctx)
}
func (f *Formatter) apply(ctx context.Context) error {
// empty check
if len(f.batch) == 0 {
return nil
}
// construct args, starting with config
args := f.Options
// append each file path
for _, path := range f.batch {
args = append(args, path)
}
start := time.Now()
cmd := exec.CommandContext(ctx, f.Command, args...)
if _, err := cmd.CombinedOutput(); err != nil {
// todo log output
return err
}
f.log.Infof("%v files processed in %v", len(f.batch), time.Now().Sub(start))
// mark completed or forward on
if len(f.Before) == 0 {
for _, path := range f.batch {
MarkFormatComplete(ctx, path)
}
} else {
for _, path := range f.batch {
ForwardPath(ctx, path, f.Before)
}
}
// reset batch
f.batch = f.batch[:0]
return nil
}
func (f *Formatter) Close() {
close(f.inbox)
}

15
internal/format/glob.go Normal file
View File

@ -0,0 +1,15 @@
package format
import (
"github.com/gobwas/glob"
)
func PathMatches(path string, globs []glob.Glob) bool {
for idx := range globs {
if globs[idx].Match(path) {
return true
}
}
return false
}

21
internal/log/writer.go Normal file
View File

@ -0,0 +1,21 @@
package log
import (
"bufio"
"bytes"
"github.com/charmbracelet/log"
)
type Writer struct {
Log *log.Logger
}
func (l *Writer) Write(p []byte) (n int, err error) {
scanner := bufio.NewScanner(bytes.NewReader(p))
for scanner.Scan() {
line := scanner.Text()
l.Log.Debug(line)
}
return len(p), nil
}

11
main.go Normal file
View File

@ -0,0 +1,11 @@
package main
import (
"github.com/alecthomas/kong"
"github.com/numtide/treefmt/internal/cli"
)
func main() {
ctx := kong.Parse(&cli.Cli)
ctx.FatalIfErrorf(ctx.Run())
}

5
nix/checks.nix Normal file
View File

@ -0,0 +1,5 @@
{lib, ...}: {
perSystem = {self', ...}: {
checks = with lib; mapAttrs' (n: nameValuePair "package-${n}") self'.packages;
};
}

10
nix/default.nix Normal file
View File

@ -0,0 +1,10 @@
{inputs, ...}: {
imports = [
inputs.flake-root.flakeModule
./checks.nix
./devshell.nix
./nixpkgs.nix
./packages.nix
./treefmt.nix
];
}

58
nix/devshell.nix Normal file
View File

@ -0,0 +1,58 @@
{inputs, ...}: {
imports = [
inputs.devshell.flakeModule
];
config.perSystem = {
pkgs,
config,
...
}: {
config.devshells.default = {
env = [
{
name = "GOROOT";
value = pkgs.go + "/share/go";
}
{
name = "LD_LIBRARY_PATH";
value = "$DEVSHELL_DIR/lib";
}
];
packages = with pkgs; [
# golang
go
go-tools
delve
golangci-lint
# formatters for testing
elmPackages.elm-format
haskellPackages.cabal-fmt
haskellPackages.ormolu
mdsh
nixpkgs-fmt
nodePackages.prettier
python3.pkgs.black
rufo
rustfmt
shellcheck
shfmt
terraform
];
commands = [
{
category = "development";
package = pkgs.gomod2nix;
}
{
category = "development";
package = pkgs.enumer;
}
];
};
};
}

16
nix/nixpkgs.nix Normal file
View File

@ -0,0 +1,16 @@
{inputs, ...}: {
perSystem = {system, ...}: {
# customise nixpkgs instance
_module.args.pkgs = import inputs.nixpkgs {
inherit system;
overlays = [
inputs.gomod2nix.overlays.default
];
config = {
# for terraform
# todo make this more specific
allowUnfree = true;
};
};
};
}

42
nix/packages.nix Normal file
View File

@ -0,0 +1,42 @@
{inputs, ...}: {
imports = [
inputs.flake-parts.flakeModules.easyOverlay
];
perSystem = {
self',
inputs',
lib,
pkgs,
...
}: {
packages = rec {
treefmt = inputs'.gomod2nix.legacyPackages.buildGoApplication rec {
pname = "treefmt";
version = "0.0.1+dev";
# ensure we are using the same version of go to build with
inherit (pkgs) go;
src = ../.;
modules = ../gomod2nix.toml;
ldflags = [
"-X 'build.Name=${pname}'"
"-X 'build.Version=${version}'"
];
meta = with lib; {
description = "treefmt: one CLI to format your repo";
homepage = "https://github.com/numtide/treefmt";
license = licenses.mit;
mainProgram = "treefmt";
};
};
default = treefmt;
};
overlayAttrs = self'.packages;
};
}

32
nix/treefmt.nix Normal file
View File

@ -0,0 +1,32 @@
{inputs, ...}: {
imports = [
inputs.treefmt-nix.flakeModule
];
perSystem = {config, ...}: {
treefmt.config = {
inherit (config.flake-root) projectRootFile;
flakeCheck = true;
flakeFormatter = true;
programs = {
alejandra.enable = true;
deadnix.enable = true;
gofumpt.enable = true;
prettier.enable = true;
statix.enable = true;
};
settings.formatter.prettier.options = ["--tab-width" "4"];
};
devshells.default = {
commands = [
{
category = "formatting";
name = "fmt";
help = "format the repo";
command = "nix fmt";
}
];
};
};
}

3
test/echo.toml Normal file
View File

@ -0,0 +1,3 @@
[formatter.echo]
command = "echo"
includes = [ "*.*" ]

View File

@ -0,0 +1,22 @@
{
"type": "application",
"source-directories": ["src"],
"elm-version": "0.19.1",
"dependencies": {
"direct": {
"elm/browser": "1.0.2",
"elm/core": "1.0.5",
"elm/html": "1.0.0"
},
"indirect": {
"elm/json": "1.1.3",
"elm/time": "1.0.0",
"elm/url": "1.0.0",
"elm/virtual-dom": "1.0.2"
}
},
"test-dependencies": {
"direct": {},
"indirect": {}
}
}

View File

@ -0,0 +1,31 @@
module Main exposing (Msg(..), main, update, view)
import Browser
import Html exposing (Html, button, div, text)
import Html.Events exposing (onClick)
main =
Browser.sandbox { init = 0, update = update, view = view }
type Msg
= Increment
| Decrement
update msg model =
case msg of
Increment ->
model + 1
Decrement ->
model - 1
view model =
div []
[ button [ onClick Decrement ] [ text "-" ]
, div [] [ text (String.fromInt model) ]
, button [ onClick Increment ] [ text "+" ]
]

3
test/examples/go/go.mod Normal file
View File

@ -0,0 +1,3 @@
module hello
go 1.15

7
test/examples/go/main.go Normal file
View File

@ -0,0 +1,7 @@
package main
import "fmt"
func main() {
fmt.Println("hello world")
}

View File

@ -0,0 +1,5 @@
# Revision history for haskell
## 0.1.0.0 -- YYYY-mm-dd
- First version. Released on an unsuspecting world.

View File

@ -0,0 +1,4 @@
module Main where
main :: IO ()
main = putStrLn "Hello, Haskell!"

View File

@ -0,0 +1,3 @@
import Distribution.Simple
main = defaultMain

View File

@ -0,0 +1,25 @@
cabal-version: >=1.10
-- Initial package description 'haskell.cabal' generated by 'cabal init'.
-- For further documentation, see http://haskell.org/cabal/users-guide/
name: haskell-frontend
version: 0.1.0.0
-- synopsis:
-- description:
-- bug-reports:
-- license:
license-file: LICENSE
author: Andika Demas Riyandi
maintainer: andika.riyan@gmail.com
-- copyright:
-- category:
build-type: Simple
extra-source-files: CHANGELOG.md
executable haskell-frontend
main-is: Main.hs
-- other-modules:
-- other-extensions:
build-depends: base >=4.14 && <4.15
-- hs-source-dirs:
default-language: Haskell2010

View File

@ -0,0 +1,5 @@
# Revision history for haskell
## 0.1.0.0 -- YYYY-mm-dd
- First version. Released on an unsuspecting world.

View File

@ -0,0 +1,4 @@
module Foo where
foo :: IO ()
foo = putStrLn "Hello, Riyan!"

View File

@ -0,0 +1,4 @@
module Main where
main :: IO ()
main = putStrLn "Hello, Riyan!"

View File

@ -0,0 +1,4 @@
module Nested.Foo where
foo :: IO ()
foo = putStrLn "Hello, Riyan!"

View File

@ -0,0 +1,3 @@
import Distribution.Simple
main = defaultMain

View File

@ -0,0 +1,25 @@
cabal-version: >=1.10
-- Initial package description 'haskell.cabal' generated by 'cabal init'.
-- For further documentation, see http://haskell.org/cabal/users-guide/
name: haskell
version: 0.1.0.0
-- synopsis:
-- description:
-- bug-reports:
-- license:
license-file: LICENSE
author: Andika Demas Riyandi
maintainer: andika.riyan@gmail.com
-- copyright:
-- category:
build-type: Simple
extra-source-files: CHANGELOG.md
executable haskell
main-is: Main.hs
-- other-modules:
-- other-extensions:
build-depends: base >=4.14 && <4.15
-- hs-source-dirs:
default-language: Haskell2010

View File

@ -0,0 +1,10 @@
[formatter.haskell]
command = "ormolu"
options = [
"--ghc-opt", "-XBangPatterns",
"--ghc-opt", "-XPatternSynonyms",
"--ghc-opt", "-XTypeApplications",
"--mode", "inplace",
"--check-idempotence",
]
includes = ["Foo.hs"]

View File

@ -0,0 +1,10 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Title</title>
</head>
<body>
<h1>Hi!</h1>
</body>
</html>

View File

View File

@ -0,0 +1,65 @@
const helloFactory = function ({ React }) {
const { string, func } = React.PropTypes;
return function Hello(props) {
// React wants propTypes & defaultProps
// to be static.
Hello.propTypes = {
word: string,
mode: string,
actions: React.PropTypes.shape({
setWord: func.isRequired,
setMode: func.isRequired,
}),
};
return {
props, // set props
componentDidUpdate() {
this.refs.wordInput.getDOMNode().focus();
},
render() {
const { word, mode } = this.props;
const { setMode, setWord } = this.props.actions;
const styles = {
displayMode: {
display: mode === "display" ? "inline" : "none",
},
editMode: {
display: mode === "edit" ? "inline" : "none",
},
};
const onKeyUp = function (e) {
if (e.key !== "Enter") return;
setWord(e.target.value);
setMode("display");
};
return (
<p>
Hello,&nbsp;
<span style={styles.displayMode} onClick={() => setMode("edit")}>
{word}!
</span>
<input
ref="wordInput"
style={styles.editMode}
placeholder={word}
onKeyUp={onKeyUp}
/>
</p>
);
},
};
};
};
export default helloFactory;

View File

@ -0,0 +1,242 @@
# This file has been generated by Niv.
let
#
# The fetchers. fetch_<type> fetches specs of type <type>.
#
fetch_file = pkgs: name: spec:
let
name' = sanitizeName name + "-src";
in
if spec.builtin or true
then
builtins_fetchurl
{
inherit (spec) url sha256;
name = name';
}
else
pkgs.fetchurl {
inherit (spec) url sha256;
name = name';
};
fetch_tarball = pkgs: name: spec:
let
name' = sanitizeName name + "-src";
in
if spec.builtin or true
then
builtins_fetchTarball
{
name = name';
inherit (spec) url sha256;
}
else
pkgs.fetchzip {
name = name';
inherit (spec) url sha256;
};
fetch_git = name: spec:
let
ref =
spec.ref
or (
if spec ? branch
then "refs/heads/${spec.branch}"
else if spec ? tag
then "refs/tags/${spec.tag}"
else abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!"
);
in
builtins.fetchGit {
url = spec.repo;
inherit (spec) rev;
inherit ref;
};
fetch_local = spec: spec.path;
fetch_builtin-tarball = name:
throw
'' [${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`.
$ niv modify ${name} -a type=tarball -a builtin=true'';
fetch_builtin-url = name:
throw
'' [${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`.
$ niv modify ${name} -a type=file -a builtin=true'';
#
# Various helpers
#
# https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695
sanitizeName = name: (
concatMapStrings
(s:
if builtins.isList s
then "-"
else s)
(
builtins.split "[^[:alnum:]+._?=-]+"
((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name)
)
);
# The set of packages used when specs are fetched using non-builtins.
mkPkgs = sources: system:
let
sourcesNixpkgs =
import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; };
hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath;
hasThisAsNixpkgsPath = <nixpkgs> == ./.;
in
if builtins.hasAttr "nixpkgs" sources
then sourcesNixpkgs
else if hasNixpkgsPath && ! hasThisAsNixpkgsPath
then import <nixpkgs> { }
else
abort
''
Please specify either <nixpkgs> (through -I or NIX_PATH=nixpkgs=...) or
add a package called "nixpkgs" to your sources.json.
'';
# The actual fetching function.
fetch = pkgs: name: spec:
if ! builtins.hasAttr "type" spec
then abort "ERROR: niv spec ${name} does not have a 'type' attribute"
else if spec.type == "file"
then fetch_file pkgs name spec
else if spec.type == "tarball"
then fetch_tarball pkgs name spec
else if spec.type == "git"
then fetch_git name spec
else if spec.type == "local"
then fetch_local spec
else if spec.type == "builtin-tarball"
then fetch_builtin-tarball name
else if spec.type == "builtin-url"
then fetch_builtin-url name
else abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";
# If the environment variable NIV_OVERRIDE_${name} is set, then use
# the path directly as opposed to the fetched source.
replace = name: drv:
let
saneName =
stringAsChars
(c:
if ((builtins.match "[a-zA-Z0-9]" c) == null)
then "_"
else c)
name;
ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}";
in
if ersatz == ""
then drv
else
# this turns the string into an actual Nix path (for both absolute and
# relative paths)
if builtins.substring 0 1 ersatz == "/"
then /. + ersatz
else /. + builtins.getEnv "PWD" + "/${ersatz}";
# Ports of functions for older nix versions
# a Nix version of mapAttrs if the built-in doesn't exist
mapAttrs =
builtins.mapAttrs
or (
f: set:
with builtins;
listToAttrs (map
(attr: {
name = attr;
value = f attr set.${attr};
})
(attrNames set))
);
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
range = first: last:
if first > last
then [ ]
else builtins.genList (n: first + n) (last - first + 1);
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
concatMapStrings = f: list: concatStrings (map f list);
concatStrings = builtins.concatStringsSep "";
# https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331
optionalAttrs = cond: as:
if cond
then as
else { };
# fetchTarball version that is compatible between all the versions of Nix
builtins_fetchTarball =
{ url
, name ? null
, sha256
,
} @ attrs:
let
inherit (builtins) lessThan nixVersion fetchTarball;
in
if lessThan nixVersion "1.12"
then fetchTarball ({ inherit url; } // (optionalAttrs (name != null) { inherit name; }))
else fetchTarball attrs;
# fetchurl version that is compatible between all the versions of Nix
builtins_fetchurl =
{ url
, name ? null
, sha256
,
} @ attrs:
let
inherit (builtins) lessThan nixVersion fetchurl;
in
if lessThan nixVersion "1.12"
then fetchurl ({ inherit url; } // (optionalAttrs (name != null) { inherit name; }))
else fetchurl attrs;
# Create the final "sources" from the config
mkSources = config:
mapAttrs
(
name: spec:
if builtins.hasAttr "outPath" spec
then
abort
"The values in sources.json should not have an 'outPath' attribute"
else spec // { outPath = replace name (fetch config.pkgs name spec); }
)
config.sources;
# The "config" used by the fetchers
mkConfig =
{ sourcesFile ? if builtins.pathExists ./sources.json
then ./sources.json
else null
, sources ? if (sourcesFile == null)
then { }
else builtins.fromJSON (builtins.readFile sourcesFile)
, system ? builtins.currentSystem
, pkgs ? mkPkgs sources system
,
}: rec {
# The sources, i.e. the attribute set of spec name to spec
inherit sources;
# The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
inherit pkgs;
};
in
mkSources (mkConfig { }) // { __functor = _: settings: mkSources (mkConfig settings); }

View File

@ -0,0 +1,12 @@
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
return "Hello world"
if __name__ == "__main__":
app.run()

View File

@ -0,0 +1 @@
Flask==0.12.1

View File

@ -0,0 +1,104 @@
import datetime
import os
import sys
import traceback
if sys.version_info[0] == 3:
def to_str(value):
return value.decode(sys.getfilesystemencoding())
def execfile(path, global_dict):
"""Execute a file"""
with open(path, "r") as f:
code = f.read()
code = code.replace("\r\n", "\n") + "\n"
exec(code, global_dict)
else:
def to_str(value):
return value.encode(sys.getfilesystemencoding())
def log(txt):
"""Logs fatal errors to a log file if WSGI_LOG env var is defined"""
log_file = os.environ.get("WSGI_LOG")
if log_file:
f = open(log_file, "a+")
try:
f.write("%s: %s" % (datetime.datetime.now(), txt))
finally:
f.close()
def get_wsgi_handler(handler_name):
if not handler_name:
raise Exception("WSGI_ALT_VIRTUALENV_HANDLER env var must be set")
if not isinstance(handler_name, str):
handler_name = to_str(handler_name)
module_name, _, callable_name = handler_name.rpartition(".")
should_call = callable_name.endswith("()")
callable_name = callable_name[:-2] if should_call else callable_name
name_list = [(callable_name, should_call)]
handler = None
last_tb = ""
while module_name:
try:
handler = __import__(module_name, fromlist=[name_list[0][0]])
last_tb = ""
for name, should_call in name_list:
handler = getattr(handler, name)
if should_call:
handler = handler()
break
except ImportError:
module_name, _, callable_name = module_name.rpartition(".")
should_call = callable_name.endswith("()")
callable_name = callable_name[:-2] if should_call else callable_name
name_list.insert(0, (callable_name, should_call))
handler = None
last_tb = ": " + traceback.format_exc()
if handler is None:
raise ValueError('"%s" could not be imported%s' % (handler_name, last_tb))
return handler
activate_this = os.getenv("WSGI_ALT_VIRTUALENV_ACTIVATE_THIS")
if not activate_this:
raise Exception("WSGI_ALT_VIRTUALENV_ACTIVATE_THIS is not set")
def get_virtualenv_handler():
log("Activating virtualenv with %s\n" % activate_this)
execfile(activate_this, dict(__file__=activate_this))
log("Getting handler %s\n" % os.getenv("WSGI_ALT_VIRTUALENV_HANDLER"))
handler = get_wsgi_handler(os.getenv("WSGI_ALT_VIRTUALENV_HANDLER"))
log("Got handler: %r\n" % handler)
return handler
def get_venv_handler():
log("Activating venv with executable at %s\n" % activate_this)
import site
sys.executable = activate_this
old_sys_path, sys.path = sys.path, []
site.main()
sys.path.insert(0, "")
for item in old_sys_path:
if item not in sys.path:
sys.path.append(item)
log("Getting handler %s\n" % os.getenv("WSGI_ALT_VIRTUALENV_HANDLER"))
handler = get_wsgi_handler(os.getenv("WSGI_ALT_VIRTUALENV_HANDLER"))
log("Got handler: %r\n" % handler)
return handler

View File

@ -0,0 +1,452 @@
# frozen_string_literal: true
require "fileutils"
require "pathname"
require "rbconfig"
require "thread"
require "bundler/environment_preserver"
require "bundler/gem_remote_fetcher"
require "bundler/rubygems_ext"
require "bundler/rubygems_integration"
require "bundler/version"
require "bundler/constants"
require "bundler/current_ruby"
require "bundler/errors"
module Bundler
environment_preserver = EnvironmentPreserver.new(ENV, %w(PATH GEM_PATH))
ORIGINAL_ENV = environment_preserver.restore
ENV.replace(environment_preserver.backup)
SUDO_MUTEX = Mutex.new
autoload :Definition, "bundler/definition"
autoload :Dependency, "bundler/dependency"
autoload :DepProxy, "bundler/dep_proxy"
autoload :Deprecate, "bundler/deprecate"
autoload :Dsl, "bundler/dsl"
autoload :EndpointSpecification, "bundler/endpoint_specification"
autoload :Environment, "bundler/environment"
autoload :Env, "bundler/env"
autoload :Fetcher, "bundler/fetcher"
autoload :GemHelper, "bundler/gem_helper"
autoload :GemHelpers, "bundler/gem_helpers"
autoload :Graph, "bundler/graph"
autoload :Index, "bundler/index"
autoload :Installer, "bundler/installer"
autoload :Injector, "bundler/injector"
autoload :LazySpecification, "bundler/lazy_specification"
autoload :LockfileParser, "bundler/lockfile_parser"
autoload :MatchPlatform, "bundler/match_platform"
autoload :Mirror, "bundler/mirror"
autoload :Mirrors, "bundler/mirror"
autoload :RemoteSpecification, "bundler/remote_specification"
autoload :Resolver, "bundler/resolver"
autoload :Retry, "bundler/retry"
autoload :RubyVersion, "bundler/ruby_version"
autoload :RubyDsl, "bundler/ruby_dsl"
autoload :Runtime, "bundler/runtime"
autoload :Settings, "bundler/settings"
autoload :SharedHelpers, "bundler/shared_helpers"
autoload :SpecSet, "bundler/spec_set"
autoload :StubSpecification, "bundler/stub_specification"
autoload :Source, "bundler/source"
autoload :SourceList, "bundler/source_list"
autoload :RubyGemsGemInstaller, "bundler/rubygems_gem_installer"
autoload :UI, "bundler/ui"
class << self
attr_writer :bundle_path
def configure
@configured ||= configure_gem_home_and_path
end
def ui
(defined?(@ui) && @ui) || (self.ui = UI::Silent.new)
end
def ui=(ui)
Bundler.rubygems.ui = ui ? UI::RGProxy.new(ui) : nil
@ui = ui
end
# Returns absolute path of where gems are installed on the filesystem.
def bundle_path
@bundle_path ||= Pathname.new(settings.path).expand_path(root)
end
# Returns absolute location of where binstubs are installed to.
def bin_path
@bin_path ||= begin
path = settings[:bin] || "bin"
path = Pathname.new(path).expand_path(root).expand_path
SharedHelpers.filesystem_access(path) { |p| FileUtils.mkdir_p(p) }
path
end
end
def setup(*groups)
# Return if all groups are already loaded
return @setup if defined?(@setup)
definition.validate_ruby!
if groups.empty?
# Load all groups, but only once
@setup = load.setup
else
load.setup(*groups)
end
end
def require(*groups)
setup(*groups).require(*groups)
end
def load
@load ||= Runtime.new(root, definition)
end
def environment
Bundler::Environment.new(root, definition)
end
# Returns an instance of Bundler::Definition for given Gemfile and lockfile
#
# @param unlock [Hash, Boolean, nil] Gems that have been requested
# to be updated or true if all gems should be updated
# @return [Bundler::Definition]
def definition(unlock = nil)
@definition = nil if unlock
@definition ||= begin
configure
upgrade_lockfile
Definition.build(default_gemfile, default_lockfile, unlock)
end
end
def locked_gems
return @locked_gems if defined?(@locked_gems)
if Bundler.default_lockfile.exist?
lock = Bundler.read_file(Bundler.default_lockfile)
@locked_gems = LockfileParser.new(lock)
else
@locked_gems = nil
end
end
def ruby_scope
"#{Bundler.rubygems.ruby_engine}/#{Bundler.rubygems.config_map[:ruby_version]}"
end
def user_bundle_path
Pathname.new(Bundler.rubygems.user_home).join(".bundle")
end
def home
bundle_path.join("bundler")
end
def install_path
home.join("gems")
end
def specs_path
bundle_path.join("specifications")
end
def cache
bundle_path.join("cache/bundler")
end
def user_cache
user_bundle_path.join("cache")
end
def root
@root ||= begin
default_gemfile.dirname.expand_path
rescue GemfileNotFound
bundle_dir = default_bundle_dir
raise GemfileNotFound, "Could not locate Gemfile or .bundle/ directory" unless bundle_dir
Pathname.new(File.expand_path("..", bundle_dir))
end
end
def app_config_path
if ENV["BUNDLE_APP_CONFIG"]
Pathname.new(ENV["BUNDLE_APP_CONFIG"]).expand_path(root)
else
root.join(".bundle")
end
end
def app_cache(custom_path = nil)
path = custom_path || root
path.join(settings.app_cache_path)
end
def tmp(name = Process.pid.to_s)
Pathname.new(Dir.mktmpdir(["bundler", name]))
end
def rm_rf(path)
FileUtils.remove_entry_secure(path) if path && File.exist?(path)
end
def settings
return @settings if defined?(@settings)
@settings = Settings.new(app_config_path)
rescue GemfileNotFound
@settings = Settings.new(Pathname.new(".bundle").expand_path)
end
# @return [Hash] Environment present before Bundler was activated
def original_env
ORIGINAL_ENV.clone
end
# @deprecated Use `original_env` instead
# @return [Hash] Environment with all bundler-related variables removed
def clean_env
env = original_env
if env.key?("BUNDLE_ORIG_MANPATH")
env["MANPATH"] = env["BUNDLE_ORIG_MANPATH"]
end
env.delete_if { |k, _| k[0, 7] == "BUNDLE_" }
if env.key?("RUBYOPT")
env["RUBYOPT"] = env["RUBYOPT"].sub "-rbundler/setup", ""
end
if env.key?("RUBYLIB")
rubylib = env["RUBYLIB"].split(File::PATH_SEPARATOR)
rubylib.delete(File.expand_path("..", __FILE__))
env["RUBYLIB"] = rubylib.join(File::PATH_SEPARATOR)
end
env
end
def with_original_env
with_env(original_env) { yield }
end
def with_clean_env
with_env(clean_env) { yield }
end
def clean_system(*args)
with_clean_env { Kernel.system(*args) }
end
def clean_exec(*args)
with_clean_env { Kernel.exec(*args) }
end
def default_gemfile
SharedHelpers.default_gemfile
end
def default_lockfile
SharedHelpers.default_lockfile
end
def default_bundle_dir
SharedHelpers.default_bundle_dir
end
def system_bindir
# Gem.bindir doesn't always return the location that Rubygems will install
# system binaries. If you put '-n foo' in your .gemrc, Rubygems will
# install binstubs there instead. Unfortunately, Rubygems doesn't expose
# that directory at all, so rather than parse .gemrc ourselves, we allow
# the directory to be set as well, via `bundle config bindir foo`.
Bundler.settings[:system_bindir] || Bundler.rubygems.gem_bindir
end
def requires_sudo?
return @requires_sudo if defined?(@requires_sudo_ran)
sudo_present = which "sudo" if settings.allow_sudo?
if sudo_present
# the bundle path and subdirectories need to be writable for Rubygems
# to be able to unpack and install gems without exploding
path = bundle_path
path = path.parent until path.exist?
# bins are written to a different location on OS X
bin_dir = Pathname.new(Bundler.system_bindir)
bin_dir = bin_dir.parent until bin_dir.exist?
# if any directory is not writable, we need sudo
files = [path, bin_dir] | Dir[path.join("build_info/*").to_s] | Dir[path.join("*").to_s]
sudo_needed = files.any? { |f| !File.writable?(f) }
end
@requires_sudo_ran = true
@requires_sudo = settings.allow_sudo? && sudo_present && sudo_needed
end
def mkdir_p(path)
if requires_sudo?
sudo "mkdir -p '#{path}'" unless File.exist?(path)
else
SharedHelpers.filesystem_access(path, :write) do |p|
FileUtils.mkdir_p(p)
end
end
end
def which(executable)
if File.file?(executable) && File.executable?(executable)
executable
elsif paths = ENV["PATH"]
quote = '"'.freeze
paths.split(File::PATH_SEPARATOR).find do |path|
path = path[1..-2] if path.start_with?(quote) && path.end_with?(quote)
executable_path = File.expand_path(executable, path)
return executable_path if File.file?(executable_path) && File.executable?(executable_path)
end
end
end
def sudo(str)
SUDO_MUTEX.synchronize do
prompt = "\n\n" + <<-PROMPT.gsub(/^ {6}/, "").strip + " "
Your user account isn't allowed to install to the system Rubygems.
You can cancel this installation and run:
bundle install --path vendor/bundle
to install the gems into ./vendor/bundle/, or you can enter your password
and install the bundled gems to Rubygems using sudo.
Password:
PROMPT
`sudo -p "#{prompt}" #{str}`
end
end
def read_file(file)
File.open(file, "rb", &:read)
end
def load_marshal(data)
Marshal.load(data)
rescue => e
raise MarshalError, "#{e.class}: #{e.message}"
end
def load_gemspec(file, validate = false)
@gemspec_cache ||= {}
key = File.expand_path(file)
@gemspec_cache[key] ||= load_gemspec_uncached(file, validate)
# Protect against caching side-effected gemspecs by returning a
# new instance each time.
@gemspec_cache[key].dup if @gemspec_cache[key]
end
def load_gemspec_uncached(file, validate = false)
path = Pathname.new(file)
# Eval the gemspec from its parent directory, because some gemspecs
# depend on "./" relative paths.
SharedHelpers.chdir(path.dirname.to_s) do
contents = path.read
spec = if contents[0..2] == "---" # YAML header
eval_yaml_gemspec(path, contents)
else
eval_gemspec(path, contents)
end
return unless spec
spec.loaded_from = path.expand_path.to_s
Bundler.rubygems.validate(spec) if validate
spec
end
end
def clear_gemspec_cache
@gemspec_cache = {}
end
def git_present?
return @git_present if defined?(@git_present)
@git_present = Bundler.which("git") || Bundler.which("git.exe")
end
def reset!
@definition = nil
end
private
def eval_yaml_gemspec(path, contents)
# If the YAML is invalid, Syck raises an ArgumentError, and Psych
# raises a Psych::SyntaxError. See psyched_yaml.rb for more info.
Gem::Specification.from_yaml(contents)
rescue YamlLibrarySyntaxError, ArgumentError, Gem::EndOfYAMLException, Gem::Exception
eval_gemspec(path, contents)
end
def eval_gemspec(path, contents)
eval(contents, TOPLEVEL_BINDING, path.expand_path.to_s)
rescue ScriptError, StandardError => e
original_line = e.backtrace.find { |line| line.include?(path.to_s) }
msg = String.new
msg << "There was a #{e.class} while loading #{path.basename}: \n#{e.message}"
msg << " from\n #{original_line}" if original_line
msg << "\n"
if e.is_a?(LoadError) && RUBY_VERSION >= "1.9"
msg << "\nDoes it try to require a relative path? That's been removed in Ruby 1.9."
end
raise GemspecError, msg
end
def configure_gem_home_and_path
blank_home = ENV["GEM_HOME"].nil? || ENV["GEM_HOME"].empty?
if settings[:disable_shared_gems]
ENV["GEM_PATH"] = ""
elsif blank_home || Bundler.rubygems.gem_dir != bundle_path.to_s
possibles = [Bundler.rubygems.gem_dir, Bundler.rubygems.gem_path]
paths = possibles.flatten.compact.uniq.reject(&:empty?)
ENV["GEM_PATH"] = paths.join(File::PATH_SEPARATOR)
end
configure_gem_home
bundle_path
end
def configure_gem_home
# TODO: This mkdir_p is only needed for JRuby <= 1.5 and should go away (GH #602)
begin
FileUtils.mkdir_p bundle_path.to_s
rescue
nil
end
ENV["GEM_HOME"] = File.expand_path(bundle_path, root)
Bundler.rubygems.clear_paths
end
def upgrade_lockfile
lockfile = default_lockfile
return unless lockfile.exist? && lockfile.read(3) == "---"
Bundler.ui.warn "Detected Gemfile.lock generated by 0.9, deleting..."
lockfile.rmtree
end
# @param env [Hash]
def with_env(env)
backup = ENV.to_hash
ENV.replace(env)
yield
ensure
ENV.replace(backup)
end
end
end

View File

@ -0,0 +1,9 @@
[package]
name = "rust"
version = "0.1.0"
authors = ["Andika Demas Riyandi <andika.riyan@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}

8
test/examples/shell/foo.sh Executable file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
hello() {
echo "Hello"
}
hello

View File

@ -0,0 +1,4 @@
resource "my_resource" "xxx" {
option = [1, 2, 3]
}

View File

@ -0,0 +1,4 @@
resource "other_resource" "xxx" {
xxx = "xxx"
}

82
test/treefmt.toml Normal file
View File

@ -0,0 +1,82 @@
# One CLI to format the code tree - https://github.com/numtide/treefmt
[formatter.python]
command = "black"
includes = ["*.py"]
[formatter.elm]
command = "elm-format"
options = ["--yes"]
includes = ["*.elm"]
[formatter.go]
command = "gofmt"
options = ["-w"]
includes = ["*.go"]
[formatter.haskell]
command = "ormolu"
options = [
"--ghc-opt", "-XBangPatterns",
"--ghc-opt", "-XPatternSynonyms",
"--ghc-opt", "-XTypeApplications",
"--mode", "inplace",
"--check-idempotence",
]
includes = ["*.hs"]
excludes = ["examples/haskell/"]
[formatter.nix]
command = "nixpkgs-fmt"
includes = ["*.nix"]
# Act as an example on how to exclude specific files
excludes = ["examples/nix/sources.nix"]
[formatter.ruby]
command = "rufo"
options = ["-x"]
includes = ["*.rb"]
[formatter.prettier]
command = "prettier"
options = ["--write"]
includes = [
"*.css",
"*.html",
"*.js",
"*.json",
"*.jsx",
"*.md",
"*.mdx",
"*.scss",
"*.ts",
"*.yaml",
]
excludes = ["CHANGELOG.md"]
[formatter.rust]
command = "rustfmt"
options = ["--edition", "2018"]
includes = ["*.rs"]
[formatter.shell]
command = "/bin/sh"
options = [
"-euc",
"""
# First lint all the scripts
shellcheck "$@"
# Then format them
shfmt -i 2 -s -w "$@"
""",
"--", # bash swallows the second argument when using -c
]
includes = ["*.sh"]
[formatter.terraform]
# Careful, only terraform 1.3.0 or later accept a list of files.
# see https://github.com/numtide/treefmt/issues/97
command = "terraform"
options = ["fmt"]
includes = ["*.tf"]