mirror of
https://github.com/0xrsydn/idx-cli.git
synced 2026-11-07 01:35:36 +00:00
Phase 2 of docs/DESIGN.md, no behavior change: - crates/idx-core (library): api, analysis, cache, config file handling and provider selection, curl_impersonate, error, ownership, runtime, plus the shared test fixtures. clap derives are behind an optional `clap` feature so the library does not require clap. - crates/idx-cli (binary `idx`): cli/, output/, and IdxConfig (output format and color resolution). Package and binary names are unchanged. - config.rs is split: file read/write and validation move to core; a CLI test keeps core's OUTPUT_VALUES in sync with OutputSetting. - ownership::db::open_db/db_path drop their unused IdxConfig argument. - One workspace version; shared dependency versions; no third-party version changes in Cargo.lock. LICENSE is symlinked into each crate. - flake: workspace version, new source paths, and a per-crate package check (idx-cli is built from its tarball against packaged idx-core, since idx-core is not on crates.io yet). CI cache key, release path filter, and the golden whitespace-hook exclusion follow the new layout. Parity: all 143 golden outputs match byte for byte without regeneration; 157 core + 17 CLI unit tests (173 before plus the new OUTPUT_VALUES sync test), 62 CLI tests pass. Live A/B against main: 16/16 stocks cases identical; ownership discover got IDX 403 on both (exit 4 vs 1 is the phase 1 exit-code change). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
276 lines
11 KiB
Nix
276 lines
11 KiB
Nix
{
|
|
description = "idx-cli — CLI tool for Indonesian stock market (IDX) analysis";
|
|
|
|
inputs = {
|
|
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
|
flake-utils.url = "github:numtide/flake-utils";
|
|
crane.url = "github:ipetkov/crane";
|
|
rust-overlay = {
|
|
url = "github:oxalica/rust-overlay";
|
|
inputs.nixpkgs.follows = "nixpkgs";
|
|
};
|
|
};
|
|
|
|
outputs = { self, nixpkgs, flake-utils, crane, rust-overlay }:
|
|
flake-utils.lib.eachDefaultSystem (system:
|
|
let
|
|
overlays = [ (import rust-overlay) ];
|
|
pkgs = import nixpkgs { inherit system overlays; };
|
|
lib = pkgs.lib;
|
|
cargoManifest = builtins.fromTOML (builtins.readFile ./Cargo.toml);
|
|
version = cargoManifest.workspace.package.version;
|
|
rustToolchain = pkgs.rust-bin.stable.latest.default.override {
|
|
extensions = [ "rust-src" "rust-analyzer" ];
|
|
};
|
|
craneLib = (crane.mkLib pkgs).overrideToolchain (_: rustToolchain);
|
|
runtimeDeps = with pkgs; [
|
|
curl-impersonate
|
|
mupdf
|
|
];
|
|
# Keep integration-test edits out of the installed package's inputs.
|
|
# Fixtures stay here because provider code embeds some of them.
|
|
rustFiles = [
|
|
./Cargo.toml
|
|
./Cargo.lock
|
|
./crates/idx-core/Cargo.toml
|
|
./crates/idx-core/src
|
|
./crates/idx-core/tests/fixtures
|
|
./crates/idx-cli/Cargo.toml
|
|
./crates/idx-cli/src
|
|
];
|
|
testSrc = lib.fileset.toSource {
|
|
root = ./.;
|
|
fileset = lib.fileset.unions (rustFiles ++ [ ./crates/idx-cli/tests ]);
|
|
};
|
|
src = lib.fileset.toSource {
|
|
root = ./.;
|
|
fileset = lib.fileset.unions rustFiles;
|
|
};
|
|
commonArgs = {
|
|
inherit src;
|
|
pname = "idx-cli";
|
|
inherit version;
|
|
CARGO_PROFILE = "dev";
|
|
strictDeps = true;
|
|
nativeBuildInputs = with pkgs; [ pkg-config ];
|
|
buildInputs = with pkgs; [ openssl ];
|
|
};
|
|
# Checks and cargo package verification use dev artifacts; the shipped
|
|
# application has a separate release dependency cache.
|
|
cargoArtifacts = craneLib.buildDepsOnly (commonArgs // { src = testSrc; });
|
|
releaseCargoArtifacts = craneLib.buildDepsOnly (commonArgs // {
|
|
CARGO_PROFILE = "release";
|
|
doCheck = false;
|
|
});
|
|
idxPackage = craneLib.buildPackage (commonArgs // {
|
|
cargoArtifacts = releaseCargoArtifacts;
|
|
CARGO_PROFILE = "release";
|
|
doCheck = false;
|
|
nativeBuildInputs = commonArgs.nativeBuildInputs ++ [ pkgs.makeWrapper ];
|
|
postInstall = ''
|
|
wrapProgram "$out/bin/idx" \
|
|
--prefix PATH : "${lib.makeBinPath runtimeDeps}"
|
|
'';
|
|
});
|
|
# Self-contained ownership snapshot publisher for scheduled hosts
|
|
# (e.g. a NixOS systemd timer): no checkout, `nix develop` or cargo
|
|
# build at run time. Wraps the repo scripts with a pinned `idx`.
|
|
publisherTools = with pkgs; [
|
|
bash
|
|
coreutils
|
|
curl
|
|
gawk
|
|
gh
|
|
gnugrep
|
|
gnused
|
|
jq
|
|
sqlite
|
|
];
|
|
publisherScripts = [
|
|
./scripts/build-ownership-snapshot.sh
|
|
./scripts/build-latest-ownership-snapshot.sh
|
|
./scripts/publish-ownership-snapshot.sh
|
|
./scripts/check-ownership-snapshot-freshness.sh
|
|
];
|
|
ownershipPublisher = pkgs.stdenvNoCC.mkDerivation {
|
|
pname = "idx-ownership-publisher";
|
|
inherit version;
|
|
src = lib.fileset.toSource {
|
|
root = ./.;
|
|
fileset = lib.fileset.unions publisherScripts;
|
|
};
|
|
nativeBuildInputs = [ pkgs.makeWrapper ];
|
|
dontBuild = true;
|
|
installPhase = ''
|
|
runHook preInstall
|
|
mkdir -p "$out/libexec/idx-ownership" "$out/bin"
|
|
cp ${lib.concatMapStringsSep " " (script: "scripts/${baseNameOf script}") publisherScripts} \
|
|
"$out/libexec/idx-ownership/"
|
|
chmod +x "$out"/libexec/idx-ownership/*.sh
|
|
patchShebangs "$out/libexec/idx-ownership"
|
|
|
|
makeWrapper "$out/libexec/idx-ownership/publish-ownership-snapshot.sh" \
|
|
"$out/bin/idx-ownership-publish" \
|
|
--prefix PATH : "${lib.makeBinPath ([ idxPackage ] ++ publisherTools)}" \
|
|
--add-flags "--idx-bin ${idxPackage}/bin/idx"
|
|
makeWrapper "$out/libexec/idx-ownership/check-ownership-snapshot-freshness.sh" \
|
|
"$out/bin/idx-ownership-freshness" \
|
|
--prefix PATH : "${lib.makeBinPath publisherTools}"
|
|
runHook postInstall
|
|
'';
|
|
meta.mainProgram = "idx-ownership-publish";
|
|
};
|
|
installerSrc = lib.fileset.toSource {
|
|
root = ./.;
|
|
fileset = lib.fileset.unions [ ./install.sh ./scripts/install-sh-test.sh ];
|
|
};
|
|
installerCheck = shell: pkgs.runCommand "idx-installer-${shell}" {
|
|
nativeBuildInputs = with pkgs; [
|
|
bash coreutils curl dash findutils gnugrep gnused gawk python3
|
|
];
|
|
} ''
|
|
cp -r ${installerSrc}/. .
|
|
chmod -R u+w scripts
|
|
patchShebangs scripts
|
|
export HOME="$TMPDIR"
|
|
INSTALL_SH_SHELL=${shell} bash scripts/install-sh-test.sh
|
|
touch "$out"
|
|
'';
|
|
publisherTestSrc = lib.fileset.toSource {
|
|
root = ./.;
|
|
fileset = lib.fileset.unions [
|
|
./scripts/publish-ownership-snapshot-test.sh
|
|
./scripts/publish-ownership-snapshot.sh
|
|
./scripts/build-ownership-snapshot.sh
|
|
];
|
|
};
|
|
in
|
|
{
|
|
packages.default = idxPackage;
|
|
packages.ownership-publisher = ownershipPublisher;
|
|
apps.default = {
|
|
type = "app";
|
|
program = "${idxPackage}/bin/idx";
|
|
meta.description = "idx CLI";
|
|
};
|
|
checks = {
|
|
default = idxPackage;
|
|
ownership-publisher = pkgs.runCommand "idx-ownership-publisher-smoke" { } ''
|
|
${ownershipPublisher}/bin/idx-ownership-publish --help
|
|
touch "$out"
|
|
'';
|
|
fmt = craneLib.cargoFmt { src = testSrc; pname = "idx-cli"; inherit version; };
|
|
clippy = craneLib.cargoClippy (commonArgs // {
|
|
inherit cargoArtifacts;
|
|
src = testSrc;
|
|
doInstallCargoArtifacts = false;
|
|
installPhaseCommand = "touch $out";
|
|
cargoClippyExtraArgs = "--all-targets -- -D warnings";
|
|
});
|
|
test = craneLib.cargoTest (commonArgs // {
|
|
inherit cargoArtifacts;
|
|
src = testSrc;
|
|
doInstallCargoArtifacts = false;
|
|
installPhaseCommand = "touch $out";
|
|
# Ownership discover tests point IDX_CURL_IMPERSONATE_BIN at plain
|
|
# `curl` against a local fixture server.
|
|
nativeCheckInputs = [ pkgs.curl ];
|
|
});
|
|
# `cargo package` verification: each published crate (per the
|
|
# `include` lists in crates/*/Cargo.toml) must build on its own.
|
|
package = craneLib.mkCargoDerivation (commonArgs // {
|
|
inherit cargoArtifacts;
|
|
pnameSuffix = "-package";
|
|
src = lib.fileset.toSource {
|
|
root = ./.;
|
|
fileset = lib.fileset.unions (rustFiles ++ [
|
|
./crates/idx-cli/tests
|
|
./crates/idx-core/LICENSE
|
|
./crates/idx-cli/LICENSE
|
|
./LICENSE
|
|
./README.md
|
|
]);
|
|
};
|
|
buildPhaseCargoCommand = ''
|
|
# idx-core: full `cargo package` verification.
|
|
cargo package -p idx-core --registry crates-io --locked --offline --allow-dirty
|
|
# idx-cli depends on idx-core, which is not on crates.io yet, so
|
|
# cargo cannot resolve it from the vendored registry. Package
|
|
# idx-cli without lockfile or verification, then build the
|
|
# extracted tarball against the packaged idx-core. Real releases
|
|
# publish idx-core first and package idx-cli normally.
|
|
cargo package -p idx-cli --registry crates-io --no-verify --exclude-lockfile --offline --allow-dirty
|
|
verify="$TMPDIR/package-verify"
|
|
mkdir -p "$verify"
|
|
tar -xzf target/package/idx-core-${version}.crate -C "$verify"
|
|
tar -xzf target/package/idx-cli-${version}.crate -C "$verify"
|
|
cp Cargo.lock "$verify/idx-cli-${version}/"
|
|
(cd "$verify/idx-cli-${version}" && cargo build --offline \
|
|
--config 'patch.crates-io.idx-core.path="../idx-core-${version}"' \
|
|
--target-dir "$verify/target")
|
|
'';
|
|
doInstallCargoArtifacts = false;
|
|
installPhaseCommand = "touch $out";
|
|
});
|
|
# Sanity check of the packaged (wrapped) binary; CLI behavior is
|
|
# covered by tests/cli.rs.
|
|
packaged-cli = pkgs.runCommand "idx-packaged-cli"
|
|
{ nativeBuildInputs = with pkgs; [ bash jq ]; }
|
|
''
|
|
# The mock provider reads fixtures relative to the working dir.
|
|
mkdir -p tests
|
|
cp -r ${./crates/idx-core/tests/fixtures} tests/fixtures
|
|
export HOME="$TMPDIR"
|
|
${idxPackage}/bin/idx -o json version | jq -e '.version | type == "string"'
|
|
${idxPackage}/bin/idx completions bash | bash -n
|
|
IDX_USE_MOCK_PROVIDER=1 ${idxPackage}/bin/idx -o json stocks quote BBCA \
|
|
| jq -e '.[0].price | type == "number"'
|
|
touch "$out"
|
|
'';
|
|
install-script-sh = installerCheck "sh";
|
|
install-script-dash = installerCheck "dash";
|
|
shellcheck = pkgs.runCommand "idx-shellcheck" {
|
|
nativeBuildInputs = [ pkgs.shellcheck ];
|
|
} ''
|
|
shellcheck -s sh ${installerSrc}/install.sh
|
|
shellcheck ${installerSrc}/scripts/install-sh-test.sh
|
|
shellcheck ${./scripts/live-smoke.sh}
|
|
touch "$out"
|
|
'';
|
|
publisher-test = pkgs.runCommand "idx-publisher-test" {
|
|
nativeBuildInputs = with pkgs; [
|
|
bash coreutils findutils gawk gnugrep gnused jq sqlite
|
|
];
|
|
} ''
|
|
cp -r ${publisherTestSrc}/. .
|
|
chmod -R u+w scripts
|
|
patchShebangs scripts
|
|
export HOME="$TMPDIR"
|
|
bash scripts/publish-ownership-snapshot-test.sh
|
|
touch "$out"
|
|
'';
|
|
};
|
|
|
|
devShells.default = pkgs.mkShell {
|
|
inputsFrom = [ idxPackage ];
|
|
packages = with pkgs; [
|
|
rustToolchain
|
|
nodejs_22
|
|
cargo-watch
|
|
cargo-nextest
|
|
prek
|
|
jq
|
|
diffutils
|
|
] ++ runtimeDeps;
|
|
|
|
shellHook = ''
|
|
export PATH="$PWD/target/debug:$PATH"
|
|
'';
|
|
|
|
env = {
|
|
RUST_BACKTRACE = "1";
|
|
};
|
|
};
|
|
}
|
|
);
|
|
}
|