Cargo: Kargo: menghasilkan nama file deterministik untuk `build --test` dan `test --no-run`

Dibuat pada 20 Agu 2015  ·  51Komentar  ·  Sumber: rust-lang/cargo

Saya sedang melakukan integrasi IDE, dan saya ingin IDE saya dapat men-debug binari pengujian - di mana IDE harus meluncurkan program itu sendiri, seharusnya tidak menggunakan cargo test . Namun (tidak seperti --bin misalnya) baik build --test maupun test --no-run menghasilkan nama file deterministik, tetapi sesuatu yang acak seperti test1-748b2ca97d589628.exe .

C-feature-request Command-test

Komentar yang paling membantu

Sekedar catatan bahwa JSON bukan solusi untuk VSCode launch.json / "program", AFAIK. Kami benar-benar membutuhkan jalur biner tetap di sana.

Semua 51 komentar

Masalah yang harus dihadapi Cargo di sini adalah Anda dapat menguji banyak target yang semuanya bernama sama. Misalnya Anda dapat memiliki biner bernama foo , perpustakaan bernama foo , dan tes integrasi juga disebut foo . Semua kasus ini perlu menghasilkan binari dengan nama unik sehingga mereka dapat hidup berdampingan.

Saya setuju meskipun menjengkelkan karena pada dasarnya harus melakukan diff direktori output sebelum dan sesudah uji coba untuk melihat binari apa yang dihasilkan.

Mengapa tidak meletakkan binari uji di direktori mereka sendiri, seperti target/debug/tests/ ?
Atau awali nama yang dapat dieksekusi dengan test. sehingga pengujian integrasi foo akan menghasilkan target/debug/test.foo.exe ? (nama target tidak boleh memiliki titik, jadi tidak akan ada konflik jika test. digunakan sebagai awalan file)

Masalahnya adalah Anda dapat memiliki beberapa binari yang disebut foo . Kita membutuhkan awalan seperti test.bin , test.lib , test.test , dll.

Masalahnya adalah Anda dapat memiliki banyak binari yang disebut foo. Kami membutuhkan awalan seperti test.bin, test.lib, test.test, dll.

Yang merupakan solusi yang sangat baik, bukan?
Atau sebagai alternatif, varian kecil di atas:
test.bin.<binName> , test.lib.<libName> , test.<testName>
yang kurang bertele-tele untuk nama-nama binari dari target pengujian.

Namun solusi lain adalah membuat target build Cargo semuanya berbagi namespace yang sama. Sepertinya solusi yang bagus jika Cargo baru saja memulai, tetapi pada titik ini itu akan menjadi perubahan besar - jadi tidak ideal, saya rasa ...

Mungkin ada kemungkinan yang lebih ergonomis daripada test.$type.$name , tetapi secara keseluruhan saya pikir itu akan berhasil setidaknya dalam hal disambiguasi.

Mungkin ada kemungkinan yang lebih ergonomis daripada test.$type.$name, tapi secara keseluruhan saya pikir itu akan berhasil setidaknya dalam hal disambiguasi.

Lalu bagaimana dengan test.$testname , dan menjadikan bin dan lib sebagai nama pengujian yang dicadangkan/tidak valid untuk target pengujian Kargo khusus?

Hm sebenarnya sekarang saya memikirkannya, kami mungkin ingin melanjutkan pola <name>-* sehingga skrip sebelumnya yang menggunakan glob semacam itu hari ini akan terus berfungsi, dan itu berarti namanya bisa seperti <name>-test.<kind> . Saya pikir tidak apa-apa untuk meninggalkan <kind> di sana karena memesan nama mungkin agak terlambat dalam permainan saat ini.

Saya pikir tidak apa-apa untuk meninggalkandi sana sebagai nama pemesanan mungkin agak terlambat dalam permainan saat ini.

Ya, Rust mungkin 1.0, tetapi Cargo hanya versi 0.2, jadi dapat dikatakan bahwa perubahan kecil dapat diterima. Tapi saya tidak tahu seberapa ketat kebijakan Anda terkait dengan melanggar perubahan dalam Kargo.
(secara pribadi, saya tidak terlalu mempermasalahkannya, selama itu menjadi skema penamaan deterministik)

Meskipun versi Cargo sebenarnya harus cukup stabil hari ini, jadi saya lebih memilih untuk mempertahankan setidaknya pola yang sama dengan yang kita miliki saat ini.

Bagaimana dengan (sebagai tambahan?) membuat cargo run --no-test output nama executable yang dibangun di stdout? Dengan cara ini, cargo test --no-run -q memberikan path ke executable (membangun kembali jika diperlukan).

@FlorentBecker preferensi saya di sini adalah hanya memiliki nama file deterministik untuk saat ini, tetapi itu adalah alternatif yang mungkin jika tidak berhasil!

Saya harus mengatakan bahwa saya lebih suka memiliki cara untuk mendapatkan nama file dari kargo daripada dapat menebaknya sendiri.

Saya harus setuju dengan @adrianheine dan @FlorentBecker. Akan sangat menyenangkan jika kargo memberikan hasil dari penemuan uji. Untuk membuat output dapat diuraikan dalam skrip dan sejenisnya, saya akan mengusulkan bahwa sesuatu seperti cargo test --print atau cargo test --discover ditambahkan yang hanya mencetak jalur relatif ke setiap pengujian yang dapat dieksekusi. Opsi ini dapat digunakan bersama dengan yang lain untuk membatasi ruang lingkup penemuan.

Saat ini, saya sedang mengerjakan penambahan infrastruktur ke nix berdasarkan libc. Tidak seperti libc, nix saat ini tidak memiliki sebagian besar pengujiannya yang dibangun secara terpisah dalam satu executable. Saat ini, setelah mengkompilasi silang executable, tidak ada cara yang bagus untuk mendapatkan path ke executable pengujian dan lulus mengeksekusinya di qemu. Saya bisa glob tetapi bahkan kemudian itu melibatkan pengulangan tes individu yang ada di root Cargo.toml.

@alexcrichton Jika kompatibilitas dengan skrip build yang ada penting (menyiratkan kelanjutan dari pola <name>-* ), mengapa tidak membuat nama file deterministik saja ketika flag tambahan ( --simple-filenames ?) diteruskan ke cargo test ? Dengan cara ini skrip build yang ada berfungsi sama, dan hanya alat baru yang menggunakan flag tambahan.

Saran tambahan

Ya pada titik ini saya pikir kita mungkin harus menciptakan beberapa skema yang memiliki nama yang dapat diprediksi tetapi tidak memiliki hash. Sejalan dengan itu, saya pada dasarnya akan baik-baik saja dengan apa pun yang mempertahankan konvensi <name>-* dan kemudian * baru saja digantikan oleh sesuatu yang deterministik.

Hum, jadi seperti <name>-test untuk pengujian gaya integrasi, <name>-test.lib untuk pengujian lib dan <name>-test.bin untuk pengujian bin?

Kedengarannya cukup masuk akal bagi saya, ya!

<name>-test.lib , <name>-test.bin

Saya mungkin akan menghindari . , yang mungkin agak membingungkan di Windows, dan menyarankan <name>-lib-test dan <name>-bin-test . Dengan -test selalu di akhir—atau di awal—sehingga *-test ( test-* ) cocok dengan semua binari pengujian.

Sayangnya menggunakan -test sebagai sufiks atau awalan dapat bertentangan dengan target lain. Misalnya jika Anda memiliki binari bernama test-foo-lib dan foo-lib-test , maka kami tidak dapat menghasilkan biner untuk perpustakaan terkait yang disebut foo (karena - valid dalam nama peti). Apa kebingungan pada Windows yang Anda pikirkan?

Kemudian <name>-test untuk pengujian di bawah tests/ juga tidak akan berhasil, bukan?

Kebingungan di bawah Windows yang saya khawatirkan adalah bahwa Windows secara default menyembunyikan ekstensi di berbagai tempat dan tidak melakukannya dengan cara yang sangat konsisten. Dan karena .bin dan .lib biasanya digunakan sebagai sufiks, terkadang Anda mungkin melihat foo-test.lib.exe dan bingung untuk foo-test.lib atau sebaliknya.

Jika Anda ingin memiliki . dalam nama untuk menghindari konflik, saya akan menyarankan: test. _name_( .exe ), test.bin. _name_( .exe ) dan test.lib. _name_( .exe ). Ini akan menjaga keuntungan bahwa test.* adalah semua tes, . masih harus mencegah konflik dan nama pada akhirnya tidak akan menyerupai ekstensi yang sebenarnya.

Hm ini benar-benar memberi saya ide! Jadi saya ingin mempertahankan nama yang sama dengan yang kita miliki saat ini jika ada skrip yang mengandalkannya, tetapi kita mungkin dapat melakukan sesuatu seperti:

  1. Hasilkan semua executable ke dalam direktori tests/ dengan nama deterministik
  2. Tautkan semua executable itu ke satu tingkat ke tempat mereka sekarang dengan nama hari ini

Dengan begitu kita bisa perlahan menghapus lokasi lama dan kita bisa terus menggunakan yang baru hari ini!

Kebingungan di bawah Windows yang saya khawatirkan adalah bahwa Windows secara default menyembunyikan ekstensi di berbagai tempat dan tidak melakukannya dengan cara yang sangat konsisten.

Jika itu membingungkan, pengguna Windows harus menonaktifkan opsi Windows Explorer yang menyembunyikan ekstensi file. Saya menduga sebagian besar pengembang Windows dan pengguna listrik sudah melakukannya (saya tentu saja melakukannya). Dan IDE tentu saja tidak menyembunyikan ekstensi.

@alexcrichton Yeeeesh, tautan keras... Anda yakin itu ide yang bagus? Kedengarannya seperti solusi tangan yang sangat berat. Apakah semua OS yang menjadi target Rust memiliki sistem file yang mendukung tautan keras? Bagaimana jika seseorang ingin menggunakan sistem file yang tidak mendukung tautan keras? Bayangkan misalnya seseorang memiliki proyek Rust pada stik USB FAT32 portabel atau semacamnya. Atau berbagi jaringan? Ini adalah skenario yang sangat aneh dan langka, tetapi saya pikir itu mungkin terjadi secara realistis.
Perpustakaan apa yang akan Anda gunakan untuk membuat tautan keras dengan cara portabel, apakah hal seperti itu ada di Rust?

Pustaka ulang untuk digunakan, std::fs::hard_link() ada :-)

@kamalmarhubi Oh keren, tidak tahu tentang itu.
Saya masih berpikir ini bukan solusi yang bersih, lebih baik untuk memperbaikinya dengan cara yang bekerja secara independen dari sistem file yang mendasarinya.

Bagaimana jika seseorang ingin menggunakan sistem file yang tidak mendukung tautan keras? Bayangkan misalnya seseorang memiliki proyek Rust pada stik USB FAT32 portabel atau semacamnya.

Saya belum memikirkan apakah hardlink adalah pendekatan yang tepat, tetapi ini adalah masalah nyata. Saya pikir antara dukungan FS dan default Explorer yang membingungkan, saya lebih suka kebingungan daripada dukungan FS yang berkurang.

Saya masih berpikir ini bukan solusi yang bersih, lebih baik untuk memperbaikinya dengan cara yang bekerja secara independen dari sistem file yang mendasarinya.

Ya, saya juga tidak. Saya tidak bisa memikirkan alat pengembang di Unix yang menyiapkan tautan keras. _Symlinks_ akan lebih normal di sana, dan dapat berfungsi untuk tujuan ini. Tapi itu berpotensi bahkan kurang portabel daripada tautan keras.

Saya pikir antara dukungan FS dan default Explorer yang membingungkan, saya lebih suka kebingungan daripada dukungan FS yang berkurang.

Kedua hal tersebut bersifat independen.

Default penjelajah yang membingungkan dapat dengan mudah dihindari dengan memilih nama. Dan sufiks .bin dan .lib sangat disayangkan, jadi hampir semua hal lain akan baik-baik saja.

Tautan keras adalah untuk menjaga kompatibilitas ke belakang jika ada skrip aneh (yang saya ragu ada karena nama saat ini non-deterministik) menggunakan nama saat ini dan memberikan yang baru dan deterministik pada saat yang bersamaan.

Melangkah mundur, posting pembuka untuk masalah ini menetapkan persyaratan bahwa IDE atau alat lain perlu mengetahui lokasi keluaran biner untuk menjalankannya secara independen dari perintah Cargo, misalnya untuk dijalankan di bawah debugger.

Itu juga menyarankan atau menyiratkan implementasi yang berputar di sekitar _mengubah lokasi_ menjadi transformasi tetap dari nama pengujian. Diskusi berikut telah menyentuh berbagai tata letak keluaran, dan masalah yang mungkin muncul dengannya.

Berikut ini alternatifnya: sebagai gantinya berikan perintah untuk IDE untuk menanyakan artefak keluaran yang sesuai dengan target. Kita sudah bisa mendapatkan informasi tentang target melalui cargo read-manifest (lihat di bawah untuk output dari. Perintah serupa dapat memberikan nama binari yang dikunci pada nama target.

Ini memecahkan masalah awal, dan memberikan kebebasan kepada kargo untuk mengubah tata letak keluaran pada disk di masa mendatang. Sementara itu, itu tidak mengubah penamaan, sehingga skrip dan alat apa pun yang bergantung pada tata letak keluaran saat ini dapat diubah.

Perintah baru dapat menjadi cara yang didukung secara resmi untuk mengakses informasi ini.

Untuk kemudahan penggunaan dalam skrip, perintah baru dapat menerima target pada baris perintah, dan hanya mencetak lokasi keluarannya. Sesuatu seperti:

$ cargo output-artifact lib
target/debug/path/to/libfoo.rlib
$ cargo output-artifact example.awesome-example
target/debug/examples/awesome-example

Saya baru menyadari bahwa saat ini tes biner untuk #[test] tes tidak termasuk dalam cargo read-manifest output. Saya kira itu masuk akal karena mereka bukan target eksplisit. Kami masih bisa menyediakan cara untuk mencapai lokasi keluaran artefak itu.

@bruno-medeiros

Yeeeesh, tautan keras ... Anda yakin itu ide yang bagus?

Ini mungkin atau mungkin tidak berhasil, tapi itu hanya sebuah ide. Kami selalu dapat melakukan sesuatu seperti hard_link(a, b).or_else(|_| copy(a, b)) .

@kamalmarhubi

Berikut ini alternatifnya: sebagai gantinya berikan perintah untuk IDE untuk menanyakan artefak keluaran yang sesuai dengan target.

Namun, ini memiliki beberapa kelemahan, termasuk lebih banyak area permukaan API di Cargo dan sub-perintah baru untuk menstabilkan (dan memiliki bug, dll). Itu juga mungkin tidak menguntungkan skrip shell atau hanya dengan mudah menjalankan sesuatu secara lokal jika Anda masih harus menggunakan perintah untuk mengintrospeksi sesuatu.

Secara keseluruhan saya pikir memiliki nama deterministik memang merupakan tindakan terbaik di sini, kita hanya perlu cara berprinsip untuk memberi nama artefak. Sesuatu seperti ini tampaknya masuk akal bagi saya:

target/debug/test/test-<target-type>-<target-name>

# for example ...

target/debug/test/test-lib-foo
target/debug/test/test-bin-foo
target/debug/test/test-test-foo
target/debug/test/test-example-foo

Kita bahkan dapat menghapus awalan test- jika tidak diinginkan.

@kamalmarhubi @alexcrichton -- Lihatlah kegilaan (yang mungkin masih rusak dalam banyak kasus) yang diciptakan oleh kurangnya solusi yang layak di sini. Saya menyertakan target "lib" untuk mencakup tes yang dikemas bersama dengan lib seperti yang dicatat oleh @kamalmarhubi .

# This is a hack as we cannot currently
# ask cargo what test files it generated:
# https://github.com/rust-lang/cargo/issues/1924
find_binaries() {
  target_base_dir="${BUILD_DIR}/${TARGET}/debug"

  # find all test or lib as candidate files
  for target in $(cargo read-manifest |
                       jq -r '.targets[] | select(.kind | contains(["lib"]) or contains(["test"])) | .name' |
                       tr '-' '_'); do
    possible_bin_root="${target_base_dir}/${target}"
    for possibility in $possible_bin_root*; do
      if [ -x $possibility ] && [[ $possibility != *.d ]]; then
          echo $possibility
      fi
    done
  done
}

Dari perspektif penulisan alat semacam ini (dalam hal ini, kode untuk mengumpulkan tes bersama sehingga mereka dapat dieksekusi di dalam lingkungan emulator untuk pengujian), saya masih lebih suka cara yang waras untuk mengumpulkan tes ini. Bahkan dengan penamaan deterministik, itu hanya menyelesaikan setengah dari masalah.

@posborne oh wow itu memang terlihat sangat degil! Saya menduga kita mungkin bisa melemparkan beberapa konteks yang berbeda dalam cargo metadata untuk mendukung pembelajaran tentang ini dari baris perintah dengan cara terprogram.

@posborne oh wow itu memang terlihat sangat degil! Saya menduga kita mungkin bisa melemparkan beberapa konteks yang berbeda dalam metadata kargo untuk mendukung pembelajaran tentang ini dari baris perintah secara terprogram.

Ini adalah aspek yang terkait dan penting, tetapi ini adalah masalah yang cukup ortogonal. Saya telah membuka: https://github.com/rust-lang/cargo/issues/2508

Saya sedang melakukan integrasi IDE, dan saya ingin IDE saya dapat men-debug binari pengujian - di mana IDE harus meluncurkan program itu sendiri

Hm, saya tidak punya pengalaman dalam mengintegrasikan debugger, tetapi dapatkah ini dicapai melalui semacam pelari uji khusus?

@matklad

Hm, saya tidak punya pengalaman dalam mengintegrasikan debugger, tetapi dapatkah ini dicapai melalui semacam pelari uji khusus?

Saya pikir masalahnya adalah bahwa biner uji harus dipanggil oleh debugger. Namun sekarang bahkan tidak mudah untuk mengetahui apa yang disebut tes biner dalam beberapa kasus.

Salah satu pendekatannya adalah agar Cargo menampilkan semua nama file yang dihasilkannya dalam file JSON.

Saya sedang mengerjakan #3111 untuk mengatasi #3109 tetapi sepertinya itu akan membantu kasus penggunaan ini juga.

@jsgf , ini sedikit berbeda. Setidaknya pustaka bersama harus berisi bagian metadata untuk pembuatan versi. Tetapi contoh dan tes tidak dan akan jauh lebih berguna jika tidak, itulah yang diminta oleh masalah ini.

Kasus penggunaan yang ada dalam pikiran saya adalah menguji contoh. Sebuah tes akan ditulis yang akan mengeksekusi contoh dan memeriksa outputnya. Untuk itu ia dapat menggunakan cargo run --example dalam build asli, tetapi dalam kompilasi silang cargo tidak dapat dijangkau—jadi cargo manifest tidak membantu.

Saya juga mengalami ini ketika mencoba mengumpulkan binari uji untuk pengujian cakupan.

Saya menggunakan perintah ini untuk menemukan binari setelah cargo test --no-run :

find target/debug/deps/ -maxdepth 1 -type f -executable -regextype sed -regex '.*/[a-z_]*-[0-9a-f]*'

Masalahnya, ini mengembalikan banyak binari, karena saya memiliki peti yang menyediakan lib.rs dan main.rs. Selain itu, saya memiliki tes integrasi yang juga menghasilkan biner.

Solusi saya saat ini adalah melakukan hal berikut:

  • Jalankan cargo build
  • Jalankan perintah find atas, simpan binari yang ditemukan
  • Jalankan cargo test --no-run
  • Jalankan kembali perintah find
  • Hapus kumpulan binari pertama dari kumpulan binari kedua

Dukungan yang lebih baik untuk ini akan diterima.

Milik saya menjalankan cargo clean dan kemudian menggunakan cargo test --no-run , jadi cakupan membuat waktu kompilasi Rust semakin menyakitkan dan pengulangan pada cakupan pengujian menjadi kerumitan besar.

@dbrgn , @ssokolow cargo test --no-run --message-format=json menghasilkan daftar binari yang baru saja dibuat dalam format JSON.

Hmm. Aku harus memikirkan itu.

Saya tidak keberatan menggunakan Python shebang di justfile saya untuk proyek saya sendiri, tetapi, untuk salinan resmi boilerplate, satu-satunya bahasa skrip eksternal yang saat ini digunakan untuk tugas adalah bash dan saya enggan menambahkan ke daftar dependensi hanya untuk mengurai JSON.

Oh, itu luar biasa dalam kombinasi dengan jq !

$ cargo test --no-run --message-format=json | jq -r "select(.profile.test == true) | .filenames[]"

Tapi saya setuju dengan @ssokolow tentang dependensi tambahan.

Ya, Cargo saat ini memiliki beberapa dukungan luar biasa untuk membuang semua jenis info menarik seperti JSON (http://doc.crates.io/external-tools.html), tetapi sangat tidak nyaman digunakan dari bash. Tentu saja relatif mudah untuk membuat dan menginstal subperintah khusus untuk menangani JSON, jika Anda setuju dengan menambahkan dependensi.

Omong-omong, @bruno-medeiros, masalah asli "Saya perlu cara menjalankan uji kargo / kargo" dari IDE akan diselesaikan dengan https://github.com/rust-lang/cargo/issues /3670 melalui https://github.com/rust-lang/cargo/pull/3866 segera.

Kami (Fuchsia) sangat menginginkan solusi untuk ini, sehingga kami dapat menghasilkan binari uji yang dikompilasi silang menggunakan build GN dan, dan kemudian menggunakan mekanisme (non-kargo) lain untuk menyalin binari ke perangkat dan menjalankannya di sana.

Perasaan saya, setelah menjelajahi banyak opsi, adalah bahwa cara terbaik untuk melakukannya adalah dengan menambahkan tanda ke cargo rust yang memungkinkan penggantian opsi -extra-filename (default -). Saya akan mulai menyusun PR untuk ini sekarang, tetapi sementara itu saya akan menyukai umpan balik tentang apakah ini tampak seperti pendekatan yang masuk akal.

@raphlinus , perlu diingat bahwa bisa ada target dari jenis yang berbeda, tetapi nama yang sama, jadi sufiksnya harus spesifik jenis.

Tim Kargo membahas masalah ini secara singkat dalam pertemuan kami hari ini, dan kami akan senang untuk mengambil PR untuk itu!

Sekedar catatan bahwa JSON bukan solusi untuk VSCode launch.json / "program", AFAIK. Kami benar-benar membutuhkan jalur biner tetap di sana.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat